repogen/internal/mongo/generator.go
2023-05-24 14:04:29 +03:00

145 lines
3.8 KiB
Go

package mongo
import (
"fmt"
"git.kmsign.ru/royalcat/repogen/internal/code"
"git.kmsign.ru/royalcat/repogen/internal/codegen"
"git.kmsign.ru/royalcat/repogen/internal/spec"
)
// NewGenerator creates a new instance of MongoDB repository generator
func NewGenerator(structModel code.Struct, interfaceName string) RepositoryGenerator {
return RepositoryGenerator{
baseMethodGenerator: baseMethodGenerator{
structModel: structModel,
},
InterfaceName: interfaceName,
}
}
// RepositoryGenerator is a MongoDB repository generator that provides
// necessary information required to construct an implementation.
type RepositoryGenerator struct {
baseMethodGenerator
InterfaceName string
}
// Imports returns necessary imports for the mongo repository implementation.
func (g RepositoryGenerator) Imports() [][]code.Import {
return [][]code.Import{
{
{Path: "context"},
},
{
{Path: "go.mongodb.org/mongo-driver/bson"},
{Path: "go.mongodb.org/mongo-driver/bson/primitive"},
{Path: "go.mongodb.org/mongo-driver/mongo"},
{Path: "go.mongodb.org/mongo-driver/mongo/options"},
},
}
}
// GenerateStruct creates codegen.StructBuilder of mongo repository
// implementation struct.
func (g RepositoryGenerator) GenerateStruct() codegen.StructBuilder {
return codegen.StructBuilder{
Name: g.repoImplStructName(),
Fields: code.StructFields{
{
Name: "collection",
Type: code.PointerType{
ContainedType: code.ExternalType{
PackageAlias: "mongo",
Name: "Collection",
},
},
},
},
}
}
// GenerateConstructor creates codegen.FunctionBuilder of a constructor for
// mongo repository implementation struct.
func (g RepositoryGenerator) GenerateConstructor() (codegen.FunctionBuilder, error) {
return codegen.FunctionBuilder{
Name: "New" + g.InterfaceName,
Params: []code.Param{
{
Name: "collection",
Type: code.PointerType{
ContainedType: code.ExternalType{
PackageAlias: "mongo",
Name: "Collection",
},
},
},
},
Returns: []code.Type{
code.SimpleType(g.InterfaceName),
},
Body: codegen.FunctionBody{
codegen.ReturnStatement{
codegen.StructStatement{
Type: fmt.Sprintf("&%s", g.repoImplStructName()),
Pairs: []codegen.StructFieldPair{{
Key: "collection",
Value: codegen.Identifier("collection"),
}},
},
},
},
}, nil
}
// GenerateMethod creates codegen.MethodBuilder of repository method from the
// provided method specification.
func (g RepositoryGenerator) GenerateMethod(methodSpec spec.MethodSpec) (codegen.MethodBuilder, error) {
var params []code.Param
for i, param := range methodSpec.Params {
params = append(params, code.Param{
Name: fmt.Sprintf("arg%d", i),
Type: param.Type,
})
}
implementation, err := g.generateMethodImplementation(methodSpec)
if err != nil {
return codegen.MethodBuilder{}, err
}
return codegen.MethodBuilder{
Receiver: codegen.MethodReceiver{
Name: "r",
Type: code.SimpleType(g.repoImplStructName()),
Pointer: true,
},
Name: methodSpec.Name,
Params: params,
Returns: methodSpec.Returns,
Body: implementation,
}, nil
}
func (g RepositoryGenerator) generateMethodImplementation(
methodSpec spec.MethodSpec) (codegen.FunctionBody, error) {
switch operation := methodSpec.Operation.(type) {
case spec.InsertOperation:
return g.generateInsertBody(operation), nil
case spec.FindOperation:
return g.generateFindBody(operation)
case spec.UpdateOperation:
return g.generateUpdateBody(operation)
case spec.DeleteOperation:
return g.generateDeleteBody(operation)
case spec.CountOperation:
return g.generateCountBody(operation)
default:
return nil, NewOperationNotSupportedError(operation.Name())
}
}
func (g RepositoryGenerator) repoImplStructName() string {
return g.InterfaceName + "Mongo"
}