Validate parameter types in method signature
This commit is contained in:
parent
26feb0e0e3
commit
f799a284b1
7 changed files with 587 additions and 488 deletions
|
@ -2,7 +2,7 @@ coverage:
|
||||||
status:
|
status:
|
||||||
project:
|
project:
|
||||||
default:
|
default:
|
||||||
target: 65%
|
target: 70%
|
||||||
threshold: 5%
|
threshold: 5%
|
||||||
patch:
|
patch:
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -13,15 +13,20 @@ import (
|
||||||
|
|
||||||
// GenerateMongoRepository generates mongodb repository
|
// GenerateMongoRepository generates mongodb repository
|
||||||
func GenerateMongoRepository(packageName string, structModel code.Struct, intf code.Interface) (string, error) {
|
func GenerateMongoRepository(packageName string, structModel code.Struct, intf code.Interface) (string, error) {
|
||||||
repositorySpec, err := spec.ParseRepositoryInterface(structModel, intf)
|
var methodSpecs []spec.MethodSpec
|
||||||
if err != nil {
|
for _, method := range intf.Methods {
|
||||||
return "", err
|
methodSpec, err := spec.ParseInterfaceMethod(structModel, method)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
methodSpecs = append(methodSpecs, methodSpec)
|
||||||
}
|
}
|
||||||
|
|
||||||
generator := mongoRepositoryGenerator{
|
generator := mongoRepositoryGenerator{
|
||||||
PackageName: packageName,
|
PackageName: packageName,
|
||||||
StructModel: structModel,
|
StructModel: structModel,
|
||||||
RepositorySpec: repositorySpec,
|
InterfaceName: intf.Name,
|
||||||
|
MethodSpecs: methodSpecs,
|
||||||
}
|
}
|
||||||
|
|
||||||
output, err := generator.Generate()
|
output, err := generator.Generate()
|
||||||
|
@ -33,9 +38,10 @@ func GenerateMongoRepository(packageName string, structModel code.Struct, intf c
|
||||||
}
|
}
|
||||||
|
|
||||||
type mongoRepositoryGenerator struct {
|
type mongoRepositoryGenerator struct {
|
||||||
PackageName string
|
PackageName string
|
||||||
StructModel code.Struct
|
StructModel code.Struct
|
||||||
RepositorySpec spec.RepositorySpec
|
InterfaceName string
|
||||||
|
MethodSpecs []spec.MethodSpec
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g mongoRepositoryGenerator) Generate() (string, error) {
|
func (g mongoRepositoryGenerator) Generate() (string, error) {
|
||||||
|
@ -44,7 +50,7 @@ func (g mongoRepositoryGenerator) Generate() (string, error) {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, method := range g.RepositorySpec.Methods {
|
for _, method := range g.MethodSpecs {
|
||||||
if err := g.generateMethod(buffer, method); err != nil {
|
if err := g.generateMethod(buffer, method); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -66,7 +72,7 @@ func (g mongoRepositoryGenerator) generateBaseContent(buffer *bytes.Buffer) erro
|
||||||
|
|
||||||
tmplData := mongoBaseTemplateData{
|
tmplData := mongoBaseTemplateData{
|
||||||
PackageName: g.PackageName,
|
PackageName: g.PackageName,
|
||||||
InterfaceName: g.RepositorySpec.InterfaceName,
|
InterfaceName: g.InterfaceName,
|
||||||
StructName: g.structName(),
|
StructName: g.structName(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,5 +173,5 @@ func (g mongoRepositoryGenerator) generateFindImplementation(operation spec.Find
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g mongoRepositoryGenerator) structName() string {
|
func (g mongoRepositoryGenerator) structName() string {
|
||||||
return g.RepositorySpec.InterfaceName + "Mongo"
|
return g.InterfaceName + "Mongo"
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,7 +83,7 @@ func TestGenerateMongoRepository(t *testing.T) {
|
||||||
Name: "FindByGenderNot",
|
Name: "FindByGenderNot",
|
||||||
Params: []code.Param{
|
Params: []code.Param{
|
||||||
{Name: "ctx", Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
{Name: "ctx", Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||||
{Name: "gender", Type: code.SimpleType("int")},
|
{Name: "gender", Type: code.SimpleType("Gender")},
|
||||||
},
|
},
|
||||||
Returns: []code.Type{
|
Returns: []code.Type{
|
||||||
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
||||||
|
@ -220,7 +220,7 @@ func (r *UserRepositoryMongo) FindByIDAndUsername(ctx context.Context, arg0 prim
|
||||||
return &entity, nil
|
return &entity, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *UserRepositoryMongo) FindByGenderNot(ctx context.Context, arg0 int) ([]*UserModel, error) {
|
func (r *UserRepositoryMongo) FindByGenderNot(ctx context.Context, arg0 Gender) ([]*UserModel, error) {
|
||||||
cursor, err := r.collection.Find(ctx, bson.M{
|
cursor, err := r.collection.Find(ctx, bson.M{
|
||||||
"gender": bson.M{"$ne": arg0},
|
"gender": bson.M{"$ne": arg0},
|
||||||
})
|
})
|
||||||
|
|
35
internal/spec/errors.go
Normal file
35
internal/spec/errors.go
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
package spec
|
||||||
|
|
||||||
|
// ParsingError is an error from parsing interface methods
|
||||||
|
type ParsingError string
|
||||||
|
|
||||||
|
func (err ParsingError) Error() string {
|
||||||
|
switch err {
|
||||||
|
case UnknownOperationError:
|
||||||
|
return "unknown operation"
|
||||||
|
case UnsupportedNameError:
|
||||||
|
return "method name is not supported"
|
||||||
|
case InvalidQueryError:
|
||||||
|
return "invalid query"
|
||||||
|
case InvalidParamError:
|
||||||
|
return "parameters do not match the query"
|
||||||
|
case UnsupportedReturnError:
|
||||||
|
return "this type of return is not supported"
|
||||||
|
case ContextParamRequiredError:
|
||||||
|
return "context parameter is required"
|
||||||
|
case StructFieldNotFoundError:
|
||||||
|
return "struct field not found"
|
||||||
|
}
|
||||||
|
return string(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// parsing error constants
|
||||||
|
const (
|
||||||
|
UnknownOperationError ParsingError = "ERROR_UNKNOWN_OPERATION"
|
||||||
|
UnsupportedNameError ParsingError = "ERROR_UNSUPPORTED"
|
||||||
|
InvalidQueryError ParsingError = "ERROR_INVALID_QUERY"
|
||||||
|
InvalidParamError ParsingError = "ERROR_INVALID_PARAM"
|
||||||
|
UnsupportedReturnError ParsingError = "ERROR_INVALID_RETURN"
|
||||||
|
ContextParamRequiredError ParsingError = "ERROR_CONTEXT_PARAM_REQUIRED"
|
||||||
|
StructFieldNotFoundError ParsingError = "ERROR_STRUCT_FIELD_NOT_FOUND"
|
||||||
|
)
|
|
@ -15,12 +15,6 @@ const (
|
||||||
QueryModeMany QueryMode = "MANY"
|
QueryModeMany QueryMode = "MANY"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RepositorySpec is a specification generated from the repository interface
|
|
||||||
type RepositorySpec struct {
|
|
||||||
InterfaceName string
|
|
||||||
Methods []MethodSpec
|
|
||||||
}
|
|
||||||
|
|
||||||
// MethodSpec is a method specification inside repository specification
|
// MethodSpec is a method specification inside repository specification
|
||||||
type MethodSpec struct {
|
type MethodSpec struct {
|
||||||
Name string
|
Name string
|
||||||
|
|
|
@ -1,59 +1,40 @@
|
||||||
package spec
|
package spec
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/fatih/camelcase"
|
"github.com/fatih/camelcase"
|
||||||
"github.com/sunboyy/repogen/internal/code"
|
"github.com/sunboyy/repogen/internal/code"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ParseRepositoryInterface returns repository spec from declared repository interface
|
// ParseInterfaceMethod returns repository method spec from declared interface method
|
||||||
func ParseRepositoryInterface(structModel code.Struct, intf code.Interface) (RepositorySpec, error) {
|
func ParseInterfaceMethod(structModel code.Struct, method code.Method) (MethodSpec, error) {
|
||||||
parser := repositoryInterfaceParser{
|
parser := interfaceMethodParser{
|
||||||
StructModel: structModel,
|
StructModel: structModel,
|
||||||
Interface: intf,
|
Method: method,
|
||||||
}
|
}
|
||||||
|
|
||||||
return parser.Parse()
|
return parser.Parse()
|
||||||
}
|
}
|
||||||
|
|
||||||
type repositoryInterfaceParser struct {
|
type interfaceMethodParser struct {
|
||||||
StructModel code.Struct
|
StructModel code.Struct
|
||||||
Interface code.Interface
|
Method code.Method
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p repositoryInterfaceParser) Parse() (RepositorySpec, error) {
|
func (p interfaceMethodParser) Parse() (MethodSpec, error) {
|
||||||
repositorySpec := RepositorySpec{
|
methodNameTokens := camelcase.Split(p.Method.Name)
|
||||||
InterfaceName: p.Interface.Name,
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, method := range p.Interface.Methods {
|
|
||||||
methodSpec, err := p.parseMethod(method)
|
|
||||||
if err != nil {
|
|
||||||
return RepositorySpec{}, err
|
|
||||||
}
|
|
||||||
repositorySpec.Methods = append(repositorySpec.Methods, methodSpec)
|
|
||||||
}
|
|
||||||
|
|
||||||
return repositorySpec, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p repositoryInterfaceParser) parseMethod(method code.Method) (MethodSpec, error) {
|
|
||||||
methodNameTokens := camelcase.Split(method.Name)
|
|
||||||
switch methodNameTokens[0] {
|
switch methodNameTokens[0] {
|
||||||
case "Find":
|
case "Find":
|
||||||
return p.parseFindMethod(method, methodNameTokens[1:])
|
return p.parseFindMethod(methodNameTokens[1:])
|
||||||
}
|
}
|
||||||
return MethodSpec{}, errors.New("method name not supported")
|
return MethodSpec{}, UnknownOperationError
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p repositoryInterfaceParser) parseFindMethod(method code.Method, tokens []string) (MethodSpec, error) {
|
func (p interfaceMethodParser) parseFindMethod(tokens []string) (MethodSpec, error) {
|
||||||
if len(tokens) == 0 {
|
if len(tokens) == 0 {
|
||||||
return MethodSpec{}, errors.New("method name not supported")
|
return MethodSpec{}, UnsupportedNameError
|
||||||
}
|
}
|
||||||
|
|
||||||
mode, err := p.extractFindReturns(method.Returns)
|
mode, err := p.extractFindReturns(p.Method.Returns)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return MethodSpec{}, err
|
return MethodSpec{}, err
|
||||||
}
|
}
|
||||||
|
@ -63,14 +44,14 @@ func (p repositoryInterfaceParser) parseFindMethod(method code.Method, tokens []
|
||||||
return MethodSpec{}, err
|
return MethodSpec{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if querySpec.NumberOfArguments()+1 != len(method.Params) {
|
if err := p.validateMethodSignature(querySpec); err != nil {
|
||||||
return MethodSpec{}, errors.New("method parameter not supported")
|
return MethodSpec{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return MethodSpec{
|
return MethodSpec{
|
||||||
Name: method.Name,
|
Name: p.Method.Name,
|
||||||
Params: method.Params,
|
Params: p.Method.Params,
|
||||||
Returns: method.Returns,
|
Returns: p.Method.Returns,
|
||||||
Operation: FindOperation{
|
Operation: FindOperation{
|
||||||
Mode: mode,
|
Mode: mode,
|
||||||
Query: querySpec,
|
Query: querySpec,
|
||||||
|
@ -78,13 +59,13 @@ func (p repositoryInterfaceParser) parseFindMethod(method code.Method, tokens []
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p repositoryInterfaceParser) extractFindReturns(returns []code.Type) (QueryMode, error) {
|
func (p interfaceMethodParser) extractFindReturns(returns []code.Type) (QueryMode, error) {
|
||||||
if len(returns) != 2 {
|
if len(returns) != 2 {
|
||||||
return "", errors.New("method return not supported")
|
return "", UnsupportedReturnError
|
||||||
}
|
}
|
||||||
|
|
||||||
if returns[1] != code.SimpleType("error") {
|
if returns[1] != code.SimpleType("error") {
|
||||||
return "", errors.New("method return not supported")
|
return "", UnsupportedReturnError
|
||||||
}
|
}
|
||||||
|
|
||||||
pointerType, ok := returns[0].(code.PointerType)
|
pointerType, ok := returns[0].(code.PointerType)
|
||||||
|
@ -93,7 +74,7 @@ func (p repositoryInterfaceParser) extractFindReturns(returns []code.Type) (Quer
|
||||||
if simpleType == code.SimpleType(p.StructModel.Name) {
|
if simpleType == code.SimpleType(p.StructModel.Name) {
|
||||||
return QueryModeOne, nil
|
return QueryModeOne, nil
|
||||||
}
|
}
|
||||||
return "", fmt.Errorf("invalid return type %s", pointerType.Code())
|
return "", UnsupportedReturnError
|
||||||
}
|
}
|
||||||
|
|
||||||
arrayType, ok := returns[0].(code.ArrayType)
|
arrayType, ok := returns[0].(code.ArrayType)
|
||||||
|
@ -104,16 +85,16 @@ func (p repositoryInterfaceParser) extractFindReturns(returns []code.Type) (Quer
|
||||||
if simpleType == code.SimpleType(p.StructModel.Name) {
|
if simpleType == code.SimpleType(p.StructModel.Name) {
|
||||||
return QueryModeMany, nil
|
return QueryModeMany, nil
|
||||||
}
|
}
|
||||||
return "", fmt.Errorf("invalid return type %s", pointerType.Code())
|
return "", UnsupportedReturnError
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return "", errors.New("method return not supported")
|
return "", UnsupportedReturnError
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p repositoryInterfaceParser) parseQuery(tokens []string) (QuerySpec, error) {
|
func (p interfaceMethodParser) parseQuery(tokens []string) (QuerySpec, error) {
|
||||||
if len(tokens) == 0 {
|
if len(tokens) == 0 {
|
||||||
return QuerySpec{}, errors.New("method name not supported")
|
return QuerySpec{}, InvalidQueryError
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(tokens) == 1 && tokens[0] == "All" {
|
if len(tokens) == 1 && tokens[0] == "All" {
|
||||||
|
@ -128,7 +109,7 @@ func (p repositoryInterfaceParser) parseQuery(tokens []string) (QuerySpec, error
|
||||||
}
|
}
|
||||||
|
|
||||||
if tokens[0] == "And" || tokens[0] == "Or" {
|
if tokens[0] == "And" || tokens[0] == "Or" {
|
||||||
return QuerySpec{}, errors.New("method name not supported")
|
return QuerySpec{}, InvalidQueryError
|
||||||
}
|
}
|
||||||
|
|
||||||
var operator Operator
|
var operator Operator
|
||||||
|
@ -137,6 +118,8 @@ func (p repositoryInterfaceParser) parseQuery(tokens []string) (QuerySpec, error
|
||||||
for _, token := range tokens {
|
for _, token := range tokens {
|
||||||
if token != "And" && token != "Or" {
|
if token != "And" && token != "Or" {
|
||||||
aggregatedToken = append(aggregatedToken, token)
|
aggregatedToken = append(aggregatedToken, token)
|
||||||
|
} else if len(aggregatedToken) == 0 {
|
||||||
|
return QuerySpec{}, InvalidQueryError
|
||||||
} else if token == "And" && operator != OperatorOr {
|
} else if token == "And" && operator != OperatorOr {
|
||||||
operator = OperatorAnd
|
operator = OperatorAnd
|
||||||
predicates = append(predicates, aggregatedToken.ToPredicate())
|
predicates = append(predicates, aggregatedToken.ToPredicate())
|
||||||
|
@ -146,13 +129,40 @@ func (p repositoryInterfaceParser) parseQuery(tokens []string) (QuerySpec, error
|
||||||
predicates = append(predicates, aggregatedToken.ToPredicate())
|
predicates = append(predicates, aggregatedToken.ToPredicate())
|
||||||
aggregatedToken = predicateToken{}
|
aggregatedToken = predicateToken{}
|
||||||
} else {
|
} else {
|
||||||
return QuerySpec{}, errors.New("method name contains ambiguous query")
|
return QuerySpec{}, InvalidQueryError
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(aggregatedToken) == 0 {
|
if len(aggregatedToken) == 0 {
|
||||||
return QuerySpec{}, errors.New("method name not supported")
|
return QuerySpec{}, InvalidQueryError
|
||||||
}
|
}
|
||||||
predicates = append(predicates, aggregatedToken.ToPredicate())
|
predicates = append(predicates, aggregatedToken.ToPredicate())
|
||||||
|
|
||||||
return QuerySpec{Operator: operator, Predicates: predicates}, nil
|
return QuerySpec{Operator: operator, Predicates: predicates}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p interfaceMethodParser) validateMethodSignature(querySpec QuerySpec) error {
|
||||||
|
contextType := code.ExternalType{PackageAlias: "context", Name: "Context"}
|
||||||
|
if len(p.Method.Params) == 0 || p.Method.Params[0].Type != contextType {
|
||||||
|
return ContextParamRequiredError
|
||||||
|
}
|
||||||
|
|
||||||
|
if querySpec.NumberOfArguments()+1 != len(p.Method.Params) {
|
||||||
|
return InvalidParamError
|
||||||
|
}
|
||||||
|
|
||||||
|
currentParamIndex := 1
|
||||||
|
for _, predicate := range querySpec.Predicates {
|
||||||
|
structField, ok := p.StructModel.Fields.ByName(predicate.Field)
|
||||||
|
if !ok {
|
||||||
|
return StructFieldNotFoundError
|
||||||
|
}
|
||||||
|
|
||||||
|
if structField.Type != p.Method.Params[currentParamIndex].Type {
|
||||||
|
return InvalidParamError
|
||||||
|
}
|
||||||
|
|
||||||
|
currentParamIndex++
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -8,224 +8,191 @@ import (
|
||||||
"github.com/sunboyy/repogen/internal/spec"
|
"github.com/sunboyy/repogen/internal/spec"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TestCase struct {
|
var structModel = code.Struct{
|
||||||
Name string
|
Name: "UserModel",
|
||||||
Interface code.Interface
|
Fields: code.StructFields{
|
||||||
ExpectedOutput spec.RepositorySpec
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestParseRepositoryInterface(t *testing.T) {
|
|
||||||
testTable := []TestCase{
|
|
||||||
{
|
{
|
||||||
Name: "interface spec",
|
Name: "ID",
|
||||||
Interface: code.Interface{
|
Type: code.ExternalType{PackageAlias: "primitive", Name: "ObjectID"},
|
||||||
Name: "UserRepository",
|
|
||||||
},
|
|
||||||
ExpectedOutput: spec.RepositorySpec{
|
|
||||||
InterfaceName: "UserRepository",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "PhoneNumber",
|
||||||
|
Type: code.SimpleType("string"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Gender",
|
||||||
|
Type: code.SimpleType("Gender"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "City",
|
||||||
|
Type: code.SimpleType("string"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Age",
|
||||||
|
Type: code.SimpleType("int"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
type ParseInterfaceMethodTestCase struct {
|
||||||
|
Name string
|
||||||
|
Method code.Method
|
||||||
|
ExpectedOutput spec.MethodSpec
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseInterfaceMethod(t *testing.T) {
|
||||||
|
testTable := []ParseInterfaceMethodTestCase{
|
||||||
{
|
{
|
||||||
Name: "FindOneByArg method",
|
Name: "FindOneByArg method",
|
||||||
Interface: code.Interface{
|
Method: code.Method{
|
||||||
Name: "UserRepository",
|
Name: "FindOneByID",
|
||||||
Methods: []code.Method{
|
Params: []code.Param{
|
||||||
{
|
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||||
Name: "FindOneByID",
|
{Type: code.ExternalType{PackageAlias: "primitive", Name: "ObjectID"}},
|
||||||
Params: []code.Param{
|
},
|
||||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
Returns: []code.Type{
|
||||||
{Type: code.ExternalType{PackageAlias: "primitive", Name: "ObjectID"}},
|
code.PointerType{ContainedType: code.SimpleType("UserModel")},
|
||||||
},
|
code.SimpleType("error"),
|
||||||
Returns: []code.Type{
|
|
||||||
code.PointerType{ContainedType: code.SimpleType("UserModel")},
|
|
||||||
code.SimpleType("error"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ExpectedOutput: spec.RepositorySpec{
|
ExpectedOutput: spec.MethodSpec{
|
||||||
InterfaceName: "UserRepository",
|
Name: "FindOneByID",
|
||||||
Methods: []spec.MethodSpec{
|
Params: []code.Param{
|
||||||
{
|
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||||
Name: "FindOneByID",
|
{Type: code.ExternalType{PackageAlias: "primitive", Name: "ObjectID"}},
|
||||||
Params: []code.Param{
|
},
|
||||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
Returns: []code.Type{
|
||||||
{Type: code.ExternalType{PackageAlias: "primitive", Name: "ObjectID"}},
|
code.PointerType{ContainedType: code.SimpleType("UserModel")},
|
||||||
},
|
code.SimpleType("error"),
|
||||||
Returns: []code.Type{
|
},
|
||||||
code.PointerType{ContainedType: code.SimpleType("UserModel")},
|
Operation: spec.FindOperation{
|
||||||
code.SimpleType("error"),
|
Mode: spec.QueryModeOne,
|
||||||
},
|
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
||||||
Operation: spec.FindOperation{
|
{Field: "ID", Comparator: spec.ComparatorEqual},
|
||||||
Mode: spec.QueryModeOne,
|
}},
|
||||||
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
|
||||||
{Field: "ID", Comparator: spec.ComparatorEqual},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "FindOneByMultiWordArg method",
|
Name: "FindOneByMultiWordArg method",
|
||||||
Interface: code.Interface{
|
Method: code.Method{
|
||||||
Name: "UserRepository",
|
Name: "FindOneByPhoneNumber",
|
||||||
Methods: []code.Method{
|
Params: []code.Param{
|
||||||
{
|
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||||
Name: "FindOneByPhoneNumber",
|
{Type: code.SimpleType("string")},
|
||||||
Params: []code.Param{
|
},
|
||||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
Returns: []code.Type{
|
||||||
{Type: code.SimpleType("string")},
|
code.PointerType{ContainedType: code.SimpleType("UserModel")},
|
||||||
},
|
code.SimpleType("error"),
|
||||||
Returns: []code.Type{
|
|
||||||
code.PointerType{ContainedType: code.SimpleType("UserModel")},
|
|
||||||
code.SimpleType("error"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ExpectedOutput: spec.RepositorySpec{
|
ExpectedOutput: spec.MethodSpec{
|
||||||
InterfaceName: "UserRepository",
|
Name: "FindOneByPhoneNumber",
|
||||||
Methods: []spec.MethodSpec{
|
Params: []code.Param{
|
||||||
{
|
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||||
Name: "FindOneByPhoneNumber",
|
{Type: code.SimpleType("string")},
|
||||||
Params: []code.Param{
|
},
|
||||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
Returns: []code.Type{
|
||||||
{Type: code.SimpleType("string")},
|
code.PointerType{ContainedType: code.SimpleType("UserModel")},
|
||||||
},
|
code.SimpleType("error"),
|
||||||
Returns: []code.Type{
|
},
|
||||||
code.PointerType{ContainedType: code.SimpleType("UserModel")},
|
Operation: spec.FindOperation{
|
||||||
code.SimpleType("error"),
|
Mode: spec.QueryModeOne,
|
||||||
},
|
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
||||||
Operation: spec.FindOperation{
|
{Field: "PhoneNumber", Comparator: spec.ComparatorEqual},
|
||||||
Mode: spec.QueryModeOne,
|
}},
|
||||||
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
|
||||||
{Field: "PhoneNumber", Comparator: spec.ComparatorEqual},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "FindByArg method",
|
Name: "FindByArg method",
|
||||||
Interface: code.Interface{
|
Method: code.Method{
|
||||||
Name: "UserRepository",
|
Name: "FindByCity",
|
||||||
Methods: []code.Method{
|
Params: []code.Param{
|
||||||
{
|
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||||
Name: "FindByCity",
|
{Type: code.SimpleType("string")},
|
||||||
Params: []code.Param{
|
},
|
||||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
Returns: []code.Type{
|
||||||
{Type: code.SimpleType("string")},
|
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
||||||
},
|
code.SimpleType("error"),
|
||||||
Returns: []code.Type{
|
|
||||||
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
|
||||||
code.SimpleType("error"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ExpectedOutput: spec.RepositorySpec{
|
ExpectedOutput: spec.MethodSpec{
|
||||||
InterfaceName: "UserRepository",
|
Name: "FindByCity",
|
||||||
Methods: []spec.MethodSpec{
|
Params: []code.Param{
|
||||||
{
|
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||||
Name: "FindByCity",
|
{Type: code.SimpleType("string")},
|
||||||
Params: []code.Param{
|
},
|
||||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
Returns: []code.Type{
|
||||||
{Type: code.SimpleType("string")},
|
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
||||||
},
|
code.SimpleType("error"),
|
||||||
Returns: []code.Type{
|
},
|
||||||
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
Operation: spec.FindOperation{
|
||||||
code.SimpleType("error"),
|
Mode: spec.QueryModeMany,
|
||||||
},
|
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
||||||
Operation: spec.FindOperation{
|
{Field: "City", Comparator: spec.ComparatorEqual},
|
||||||
Mode: spec.QueryModeMany,
|
}},
|
||||||
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
|
||||||
{Field: "City", Comparator: spec.ComparatorEqual},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "FindAll method",
|
Name: "FindAll method",
|
||||||
Interface: code.Interface{
|
Method: code.Method{
|
||||||
Name: "UserRepository",
|
Name: "FindAll",
|
||||||
Methods: []code.Method{
|
Params: []code.Param{
|
||||||
{
|
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||||
Name: "FindAll",
|
},
|
||||||
Params: []code.Param{
|
Returns: []code.Type{
|
||||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
||||||
},
|
code.SimpleType("error"),
|
||||||
Returns: []code.Type{
|
|
||||||
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
|
||||||
code.SimpleType("error"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ExpectedOutput: spec.RepositorySpec{
|
ExpectedOutput: spec.MethodSpec{
|
||||||
InterfaceName: "UserRepository",
|
Name: "FindAll",
|
||||||
Methods: []spec.MethodSpec{
|
Params: []code.Param{
|
||||||
{
|
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||||
Name: "FindAll",
|
},
|
||||||
Params: []code.Param{
|
Returns: []code.Type{
|
||||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
||||||
},
|
code.SimpleType("error"),
|
||||||
Returns: []code.Type{
|
},
|
||||||
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
Operation: spec.FindOperation{
|
||||||
code.SimpleType("error"),
|
Mode: spec.QueryModeMany,
|
||||||
},
|
|
||||||
Operation: spec.FindOperation{
|
|
||||||
Mode: spec.QueryModeMany,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "FindByArgAndArg method",
|
Name: "FindByArgAndArg method",
|
||||||
Interface: code.Interface{
|
Method: code.Method{
|
||||||
Name: "UserRepository",
|
Name: "FindByCityAndGender",
|
||||||
Methods: []code.Method{
|
Params: []code.Param{
|
||||||
{
|
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||||
Name: "FindByCityAndGender",
|
{Type: code.SimpleType("string")},
|
||||||
Params: []code.Param{
|
{Type: code.SimpleType("Gender")},
|
||||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
},
|
||||||
{Type: code.SimpleType("string")},
|
Returns: []code.Type{
|
||||||
{Type: code.SimpleType("Gender")},
|
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
||||||
},
|
code.SimpleType("error"),
|
||||||
Returns: []code.Type{
|
|
||||||
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
|
||||||
code.SimpleType("error"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ExpectedOutput: spec.RepositorySpec{
|
ExpectedOutput: spec.MethodSpec{
|
||||||
InterfaceName: "UserRepository",
|
Name: "FindByCityAndGender",
|
||||||
Methods: []spec.MethodSpec{
|
Params: []code.Param{
|
||||||
{
|
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||||
Name: "FindByCityAndGender",
|
{Type: code.SimpleType("string")},
|
||||||
Params: []code.Param{
|
{Type: code.SimpleType("Gender")},
|
||||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
},
|
||||||
{Type: code.SimpleType("string")},
|
Returns: []code.Type{
|
||||||
{Type: code.SimpleType("Gender")},
|
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
||||||
},
|
code.SimpleType("error"),
|
||||||
Returns: []code.Type{
|
},
|
||||||
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
Operation: spec.FindOperation{
|
||||||
code.SimpleType("error"),
|
Mode: spec.QueryModeMany,
|
||||||
},
|
Query: spec.QuerySpec{
|
||||||
Operation: spec.FindOperation{
|
Operator: spec.OperatorAnd,
|
||||||
Mode: spec.QueryModeMany,
|
Predicates: []spec.Predicate{
|
||||||
Query: spec.QuerySpec{
|
{Field: "City", Comparator: spec.ComparatorEqual},
|
||||||
Operator: spec.OperatorAnd,
|
{Field: "Gender", Comparator: spec.ComparatorEqual},
|
||||||
Predicates: []spec.Predicate{
|
|
||||||
{Field: "City", Comparator: spec.ComparatorEqual},
|
|
||||||
{Field: "Gender", Comparator: spec.ComparatorEqual},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -233,46 +200,36 @@ func TestParseRepositoryInterface(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "FindByArgOrArg method",
|
Name: "FindByArgOrArg method",
|
||||||
Interface: code.Interface{
|
Method: code.Method{
|
||||||
Name: "UserRepository",
|
Name: "FindByCityOrGender",
|
||||||
Methods: []code.Method{
|
Params: []code.Param{
|
||||||
{
|
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||||
Name: "FindByCityOrGender",
|
{Type: code.SimpleType("string")},
|
||||||
Params: []code.Param{
|
{Type: code.SimpleType("Gender")},
|
||||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
},
|
||||||
{Type: code.SimpleType("string")},
|
Returns: []code.Type{
|
||||||
{Type: code.SimpleType("Gender")},
|
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
||||||
},
|
code.SimpleType("error"),
|
||||||
Returns: []code.Type{
|
|
||||||
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
|
||||||
code.SimpleType("error"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ExpectedOutput: spec.RepositorySpec{
|
ExpectedOutput: spec.MethodSpec{
|
||||||
InterfaceName: "UserRepository",
|
Name: "FindByCityOrGender",
|
||||||
Methods: []spec.MethodSpec{
|
Params: []code.Param{
|
||||||
{
|
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||||
Name: "FindByCityOrGender",
|
{Type: code.SimpleType("string")},
|
||||||
Params: []code.Param{
|
{Type: code.SimpleType("Gender")},
|
||||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
},
|
||||||
{Type: code.SimpleType("string")},
|
Returns: []code.Type{
|
||||||
{Type: code.SimpleType("Gender")},
|
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
||||||
},
|
code.SimpleType("error"),
|
||||||
Returns: []code.Type{
|
},
|
||||||
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
Operation: spec.FindOperation{
|
||||||
code.SimpleType("error"),
|
Mode: spec.QueryModeMany,
|
||||||
},
|
Query: spec.QuerySpec{
|
||||||
Operation: spec.FindOperation{
|
Operator: spec.OperatorOr,
|
||||||
Mode: spec.QueryModeMany,
|
Predicates: []spec.Predicate{
|
||||||
Query: spec.QuerySpec{
|
{Field: "City", Comparator: spec.ComparatorEqual},
|
||||||
Operator: spec.OperatorOr,
|
{Field: "Gender", Comparator: spec.ComparatorEqual},
|
||||||
Predicates: []spec.Predicate{
|
|
||||||
{Field: "City", Comparator: spec.ComparatorEqual},
|
|
||||||
{Field: "Gender", Comparator: spec.ComparatorEqual},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -280,240 +237,164 @@ func TestParseRepositoryInterface(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "FindByArgNot method",
|
Name: "FindByArgNot method",
|
||||||
Interface: code.Interface{
|
Method: code.Method{
|
||||||
Name: "UserRepository",
|
Name: "FindByCityNot",
|
||||||
Methods: []code.Method{
|
Params: []code.Param{
|
||||||
{
|
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||||
Name: "FindByCityNot",
|
{Type: code.SimpleType("string")},
|
||||||
Params: []code.Param{
|
},
|
||||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
Returns: []code.Type{
|
||||||
{Type: code.SimpleType("string")},
|
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
||||||
},
|
code.SimpleType("error"),
|
||||||
Returns: []code.Type{
|
|
||||||
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
|
||||||
code.SimpleType("error"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ExpectedOutput: spec.RepositorySpec{
|
ExpectedOutput: spec.MethodSpec{
|
||||||
InterfaceName: "UserRepository",
|
Name: "FindByCityNot",
|
||||||
Methods: []spec.MethodSpec{
|
Params: []code.Param{
|
||||||
{
|
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||||
Name: "FindByCityNot",
|
{Type: code.SimpleType("string")},
|
||||||
Params: []code.Param{
|
},
|
||||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
Returns: []code.Type{
|
||||||
{Type: code.SimpleType("string")},
|
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
||||||
},
|
code.SimpleType("error"),
|
||||||
Returns: []code.Type{
|
},
|
||||||
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
Operation: spec.FindOperation{
|
||||||
code.SimpleType("error"),
|
Mode: spec.QueryModeMany,
|
||||||
},
|
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
||||||
Operation: spec.FindOperation{
|
{Field: "City", Comparator: spec.ComparatorNot},
|
||||||
Mode: spec.QueryModeMany,
|
}},
|
||||||
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
|
||||||
{Field: "City", Comparator: spec.ComparatorNot},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "FindByArgLessThan method",
|
Name: "FindByArgLessThan method",
|
||||||
Interface: code.Interface{
|
Method: code.Method{
|
||||||
Name: "UserRepository",
|
Name: "FindByAgeLessThan",
|
||||||
Methods: []code.Method{
|
Params: []code.Param{
|
||||||
{
|
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||||
Name: "FindByAgeLessThan",
|
{Type: code.SimpleType("int")},
|
||||||
Params: []code.Param{
|
},
|
||||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
Returns: []code.Type{
|
||||||
{Type: code.SimpleType("string")},
|
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
||||||
},
|
code.SimpleType("error"),
|
||||||
Returns: []code.Type{
|
|
||||||
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
|
||||||
code.SimpleType("error"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ExpectedOutput: spec.RepositorySpec{
|
ExpectedOutput: spec.MethodSpec{
|
||||||
InterfaceName: "UserRepository",
|
Name: "FindByAgeLessThan",
|
||||||
Methods: []spec.MethodSpec{
|
Params: []code.Param{
|
||||||
{
|
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||||
Name: "FindByAgeLessThan",
|
{Type: code.SimpleType("int")},
|
||||||
Params: []code.Param{
|
},
|
||||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
Returns: []code.Type{
|
||||||
{Type: code.SimpleType("string")},
|
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
||||||
},
|
code.SimpleType("error"),
|
||||||
Returns: []code.Type{
|
},
|
||||||
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
Operation: spec.FindOperation{
|
||||||
code.SimpleType("error"),
|
Mode: spec.QueryModeMany,
|
||||||
},
|
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
||||||
Operation: spec.FindOperation{
|
{Field: "Age", Comparator: spec.ComparatorLessThan},
|
||||||
Mode: spec.QueryModeMany,
|
}},
|
||||||
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
|
||||||
{Field: "Age", Comparator: spec.ComparatorLessThan},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "FindByArgLessThanEqual method",
|
Name: "FindByArgLessThanEqual method",
|
||||||
Interface: code.Interface{
|
Method: code.Method{
|
||||||
Name: "UserRepository",
|
Name: "FindByAgeLessThanEqual",
|
||||||
Methods: []code.Method{
|
Params: []code.Param{
|
||||||
{
|
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||||
Name: "FindByAgeLessThanEqual",
|
{Type: code.SimpleType("int")},
|
||||||
Params: []code.Param{
|
},
|
||||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
Returns: []code.Type{
|
||||||
{Type: code.SimpleType("string")},
|
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
||||||
},
|
code.SimpleType("error"),
|
||||||
Returns: []code.Type{
|
|
||||||
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
|
||||||
code.SimpleType("error"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ExpectedOutput: spec.RepositorySpec{
|
ExpectedOutput: spec.MethodSpec{
|
||||||
InterfaceName: "UserRepository",
|
Name: "FindByAgeLessThanEqual",
|
||||||
Methods: []spec.MethodSpec{
|
Params: []code.Param{
|
||||||
{
|
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||||
Name: "FindByAgeLessThanEqual",
|
{Type: code.SimpleType("int")},
|
||||||
Params: []code.Param{
|
},
|
||||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
Returns: []code.Type{
|
||||||
{Type: code.SimpleType("string")},
|
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
||||||
},
|
code.SimpleType("error"),
|
||||||
Returns: []code.Type{
|
},
|
||||||
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
Operation: spec.FindOperation{
|
||||||
code.SimpleType("error"),
|
Mode: spec.QueryModeMany,
|
||||||
},
|
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
||||||
Operation: spec.FindOperation{
|
{Field: "Age", Comparator: spec.ComparatorLessThanEqual},
|
||||||
Mode: spec.QueryModeMany,
|
}},
|
||||||
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
|
||||||
{Field: "Age", Comparator: spec.ComparatorLessThanEqual},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "FindByArgGreaterThan method",
|
Name: "FindByArgGreaterThan method",
|
||||||
Interface: code.Interface{
|
Method: code.Method{
|
||||||
Name: "UserRepository",
|
Name: "FindByAgeGreaterThan",
|
||||||
Methods: []code.Method{
|
Params: []code.Param{
|
||||||
{
|
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||||
Name: "FindByAgeGreaterThan",
|
{Type: code.SimpleType("int")},
|
||||||
Params: []code.Param{
|
},
|
||||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
Returns: []code.Type{
|
||||||
{Type: code.SimpleType("string")},
|
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
||||||
},
|
code.SimpleType("error"),
|
||||||
Returns: []code.Type{
|
|
||||||
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
|
||||||
code.SimpleType("error"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ExpectedOutput: spec.RepositorySpec{
|
ExpectedOutput: spec.MethodSpec{
|
||||||
InterfaceName: "UserRepository",
|
Name: "FindByAgeGreaterThan",
|
||||||
Methods: []spec.MethodSpec{
|
Params: []code.Param{
|
||||||
{
|
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||||
Name: "FindByAgeGreaterThan",
|
{Type: code.SimpleType("int")},
|
||||||
Params: []code.Param{
|
},
|
||||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
Returns: []code.Type{
|
||||||
{Type: code.SimpleType("string")},
|
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
||||||
},
|
code.SimpleType("error"),
|
||||||
Returns: []code.Type{
|
},
|
||||||
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
Operation: spec.FindOperation{
|
||||||
code.SimpleType("error"),
|
Mode: spec.QueryModeMany,
|
||||||
},
|
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
||||||
Operation: spec.FindOperation{
|
{Field: "Age", Comparator: spec.ComparatorGreaterThan},
|
||||||
Mode: spec.QueryModeMany,
|
}},
|
||||||
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
|
||||||
{Field: "Age", Comparator: spec.ComparatorGreaterThan},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "FindByArgGreaterThanEqual method",
|
Name: "FindByArgGreaterThanEqual method",
|
||||||
Interface: code.Interface{
|
Method: code.Method{
|
||||||
Name: "UserRepository",
|
Name: "FindByAgeGreaterThanEqual",
|
||||||
Methods: []code.Method{
|
Params: []code.Param{
|
||||||
{
|
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||||
Name: "FindByAgeGreaterThanEqual",
|
{Type: code.SimpleType("int")},
|
||||||
Params: []code.Param{
|
},
|
||||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
Returns: []code.Type{
|
||||||
{Type: code.SimpleType("string")},
|
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
||||||
},
|
code.SimpleType("error"),
|
||||||
Returns: []code.Type{
|
|
||||||
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
|
||||||
code.SimpleType("error"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ExpectedOutput: spec.RepositorySpec{
|
ExpectedOutput: spec.MethodSpec{
|
||||||
InterfaceName: "UserRepository",
|
Name: "FindByAgeGreaterThanEqual",
|
||||||
Methods: []spec.MethodSpec{
|
Params: []code.Param{
|
||||||
{
|
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||||
Name: "FindByAgeGreaterThanEqual",
|
{Type: code.SimpleType("int")},
|
||||||
Params: []code.Param{
|
},
|
||||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
Returns: []code.Type{
|
||||||
{Type: code.SimpleType("string")},
|
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
||||||
},
|
code.SimpleType("error"),
|
||||||
Returns: []code.Type{
|
},
|
||||||
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
Operation: spec.FindOperation{
|
||||||
code.SimpleType("error"),
|
Mode: spec.QueryModeMany,
|
||||||
},
|
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
||||||
Operation: spec.FindOperation{
|
{Field: "Age", Comparator: spec.ComparatorGreaterThanEqual},
|
||||||
Mode: spec.QueryModeMany,
|
}},
|
||||||
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
|
||||||
{Field: "Age", Comparator: spec.ComparatorGreaterThanEqual},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
structModel := code.Struct{
|
|
||||||
Name: "UserModel",
|
|
||||||
Fields: code.StructFields{
|
|
||||||
{
|
|
||||||
Name: "ID",
|
|
||||||
Type: code.ExternalType{PackageAlias: "primitive", Name: "ObjectID"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "PhoneNumber",
|
|
||||||
Type: code.SimpleType("string"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "Gender",
|
|
||||||
Type: code.SimpleType("Gender"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "City",
|
|
||||||
Type: code.SimpleType("string"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "Age",
|
|
||||||
Type: code.SimpleType("int"),
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, testCase := range testTable {
|
for _, testCase := range testTable {
|
||||||
t.Run(testCase.Name, func(t *testing.T) {
|
t.Run(testCase.Name, func(t *testing.T) {
|
||||||
actualSpec, err := spec.ParseRepositoryInterface(structModel, testCase.Interface)
|
actualSpec, err := spec.ParseInterfaceMethod(structModel, testCase.Method)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Error = %s", err)
|
t.Errorf("Error = %s", err)
|
||||||
|
@ -524,3 +405,176 @@ func TestParseRepositoryInterface(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ParseInterfaceMethodInvalidTestCase struct {
|
||||||
|
Name string
|
||||||
|
Method code.Method
|
||||||
|
ExpectedError error
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseInterfaceMethodInvalid(t *testing.T) {
|
||||||
|
testTable := []ParseInterfaceMethodInvalidTestCase{
|
||||||
|
{
|
||||||
|
Name: "unknown operation",
|
||||||
|
Method: code.Method{
|
||||||
|
Name: "SearchByID",
|
||||||
|
},
|
||||||
|
ExpectedError: spec.UnknownOperationError,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "unsupported find method name",
|
||||||
|
Method: code.Method{
|
||||||
|
Name: "Find",
|
||||||
|
},
|
||||||
|
ExpectedError: spec.UnsupportedNameError,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "invalid number of returns",
|
||||||
|
Method: code.Method{
|
||||||
|
Name: "FindOneByID",
|
||||||
|
Returns: []code.Type{
|
||||||
|
code.SimpleType("UserModel"),
|
||||||
|
code.SimpleType("int"),
|
||||||
|
code.SimpleType("error"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ExpectedError: spec.UnsupportedReturnError,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "unsupported return values from find method",
|
||||||
|
Method: code.Method{
|
||||||
|
Name: "FindOneByID",
|
||||||
|
Returns: []code.Type{
|
||||||
|
code.SimpleType("UserModel"),
|
||||||
|
code.SimpleType("error"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ExpectedError: spec.UnsupportedReturnError,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "error return not provided",
|
||||||
|
Method: code.Method{
|
||||||
|
Name: "FindOneByID",
|
||||||
|
Returns: []code.Type{
|
||||||
|
code.SimpleType("UserModel"),
|
||||||
|
code.SimpleType("int"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ExpectedError: spec.UnsupportedReturnError,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "misplaced operator token (leftmost)",
|
||||||
|
Method: code.Method{
|
||||||
|
Name: "FindByAndGender",
|
||||||
|
Returns: []code.Type{
|
||||||
|
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
||||||
|
code.SimpleType("error"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ExpectedError: spec.InvalidQueryError,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "misplaced operator token (rightmost)",
|
||||||
|
Method: code.Method{
|
||||||
|
Name: "FindByGenderAnd",
|
||||||
|
Returns: []code.Type{
|
||||||
|
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
||||||
|
code.SimpleType("error"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ExpectedError: spec.InvalidQueryError,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "misplaced operator token (double operator)",
|
||||||
|
Method: code.Method{
|
||||||
|
Name: "FindByGenderAndAndCity",
|
||||||
|
Returns: []code.Type{
|
||||||
|
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
||||||
|
code.SimpleType("error"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ExpectedError: spec.InvalidQueryError,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ambiguous query",
|
||||||
|
Method: code.Method{
|
||||||
|
Name: "FindByGenderAndCityOrAge",
|
||||||
|
Returns: []code.Type{
|
||||||
|
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
||||||
|
code.SimpleType("error"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ExpectedError: spec.InvalidQueryError,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "no context parameter",
|
||||||
|
Method: code.Method{
|
||||||
|
Name: "FindByGender",
|
||||||
|
Params: []code.Param{
|
||||||
|
{Type: code.SimpleType("Gender")},
|
||||||
|
},
|
||||||
|
Returns: []code.Type{
|
||||||
|
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
||||||
|
code.SimpleType("error"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ExpectedError: spec.ContextParamRequiredError,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "mismatched number of parameters",
|
||||||
|
Method: code.Method{
|
||||||
|
Name: "FindByCountry",
|
||||||
|
Params: []code.Param{
|
||||||
|
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||||
|
{Type: code.SimpleType("string")},
|
||||||
|
{Type: code.SimpleType("string")},
|
||||||
|
},
|
||||||
|
Returns: []code.Type{
|
||||||
|
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
||||||
|
code.SimpleType("error"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ExpectedError: spec.InvalidParamError,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "struct field not found",
|
||||||
|
Method: code.Method{
|
||||||
|
Name: "FindByCountry",
|
||||||
|
Params: []code.Param{
|
||||||
|
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||||
|
{Type: code.SimpleType("string")},
|
||||||
|
},
|
||||||
|
Returns: []code.Type{
|
||||||
|
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
||||||
|
code.SimpleType("error"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ExpectedError: spec.StructFieldNotFoundError,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "mismatched method parameter type",
|
||||||
|
Method: code.Method{
|
||||||
|
Name: "FindByGender",
|
||||||
|
Params: []code.Param{
|
||||||
|
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||||
|
{Type: code.SimpleType("string")},
|
||||||
|
},
|
||||||
|
Returns: []code.Type{
|
||||||
|
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
||||||
|
code.SimpleType("error"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ExpectedError: spec.InvalidParamError,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, testCase := range testTable {
|
||||||
|
t.Run(testCase.Name, func(t *testing.T) {
|
||||||
|
_, err := spec.ParseInterfaceMethod(structModel, testCase.Method)
|
||||||
|
|
||||||
|
if err != testCase.ExpectedError {
|
||||||
|
t.Errorf("\nExpected = %v\nReceived = %v", testCase.ExpectedError, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue