Merge pull request #10 from sunboyy/operation-delete
Add delete operation
This commit is contained in:
commit
11e62de57c
8 changed files with 1278 additions and 88 deletions
|
@ -3,7 +3,7 @@ coverage:
|
|||
project:
|
||||
default:
|
||||
target: 75%
|
||||
threshold: 5%
|
||||
threshold: 4%
|
||||
patch:
|
||||
default:
|
||||
target: 50%
|
||||
|
|
20
internal/mongo/errors.go
Normal file
20
internal/mongo/errors.go
Normal file
|
@ -0,0 +1,20 @@
|
|||
package mongo
|
||||
|
||||
// GenerationError is an error from generating MongoDB repository
|
||||
type GenerationError string
|
||||
|
||||
func (err GenerationError) Error() string {
|
||||
switch err {
|
||||
case OperationNotSupportedError:
|
||||
return "operation not supported"
|
||||
case BsonTagNotFoundError:
|
||||
return "bson tag not found"
|
||||
}
|
||||
return string(err)
|
||||
}
|
||||
|
||||
// generation error constants
|
||||
const (
|
||||
OperationNotSupportedError GenerationError = "ERROR_OPERATION_NOT_SUPPORTED"
|
||||
BsonTagNotFoundError GenerationError = "ERROR_BSON_TAG_NOT_FOUND"
|
||||
)
|
|
@ -2,7 +2,6 @@ package mongo
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"text/template"
|
||||
|
@ -80,35 +79,24 @@ func (g RepositoryGenerator) generateMethodImplementation(methodSpec spec.Method
|
|||
switch operation := methodSpec.Operation.(type) {
|
||||
case spec.FindOperation:
|
||||
return g.generateFindImplementation(operation)
|
||||
case spec.DeleteOperation:
|
||||
return g.generateDeleteImplementation(operation)
|
||||
}
|
||||
|
||||
return "", errors.New("method spec not supported")
|
||||
return "", OperationNotSupportedError
|
||||
}
|
||||
|
||||
func (g RepositoryGenerator) generateFindImplementation(operation spec.FindOperation) (string, error) {
|
||||
buffer := new(bytes.Buffer)
|
||||
|
||||
var predicates []predicate
|
||||
for _, predicateSpec := range operation.Query.Predicates {
|
||||
structField, ok := g.StructModel.Fields.ByName(predicateSpec.Field)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("struct field %s not found", predicateSpec.Field)
|
||||
}
|
||||
|
||||
bsonTag, ok := structField.Tags["bson"]
|
||||
if !ok {
|
||||
return "", fmt.Errorf("struct field %s does not have bson tag", predicateSpec.Field)
|
||||
}
|
||||
|
||||
predicates = append(predicates, predicate{Field: bsonTag[0], Comparator: predicateSpec.Comparator})
|
||||
querySpec, err := g.mongoQuerySpec(operation.Query)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
tmplData := mongoFindTemplateData{
|
||||
EntityType: g.StructModel.Name,
|
||||
QuerySpec: querySpec{
|
||||
Operator: operation.Query.Operator,
|
||||
Predicates: predicates,
|
||||
},
|
||||
QuerySpec: querySpec,
|
||||
}
|
||||
|
||||
if operation.Mode == spec.QueryModeOne {
|
||||
|
@ -134,6 +122,64 @@ func (g RepositoryGenerator) generateFindImplementation(operation spec.FindOpera
|
|||
return buffer.String(), nil
|
||||
}
|
||||
|
||||
func (g RepositoryGenerator) generateDeleteImplementation(operation spec.DeleteOperation) (string, error) {
|
||||
buffer := new(bytes.Buffer)
|
||||
|
||||
querySpec, err := g.mongoQuerySpec(operation.Query)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
tmplData := mongoDeleteTemplateData{
|
||||
QuerySpec: querySpec,
|
||||
}
|
||||
|
||||
if operation.Mode == spec.QueryModeOne {
|
||||
tmpl, err := template.New("mongo_repository_deleteone").Parse(deleteOneTemplate)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if err := tmpl.Execute(buffer, tmplData); err != nil {
|
||||
return "", err
|
||||
}
|
||||
} else {
|
||||
tmpl, err := template.New("mongo_repository_deletemany").Parse(deleteManyTemplate)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if err := tmpl.Execute(buffer, tmplData); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
return buffer.String(), nil
|
||||
}
|
||||
|
||||
func (g RepositoryGenerator) mongoQuerySpec(query spec.QuerySpec) (querySpec, error) {
|
||||
var predicates []predicate
|
||||
|
||||
for _, predicateSpec := range query.Predicates {
|
||||
structField, ok := g.StructModel.Fields.ByName(predicateSpec.Field)
|
||||
if !ok {
|
||||
return querySpec{}, fmt.Errorf("struct field %s not found", predicateSpec.Field)
|
||||
}
|
||||
|
||||
bsonTag, ok := structField.Tags["bson"]
|
||||
if !ok {
|
||||
return querySpec{}, BsonTagNotFoundError
|
||||
}
|
||||
|
||||
predicates = append(predicates, predicate{Field: bsonTag[0], Comparator: predicateSpec.Comparator})
|
||||
}
|
||||
|
||||
return querySpec{
|
||||
Operator: query.Operator,
|
||||
Predicates: predicates,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (g RepositoryGenerator) structName() string {
|
||||
return g.InterfaceName + "Mongo"
|
||||
}
|
||||
|
|
|
@ -10,28 +10,7 @@ import (
|
|||
"github.com/sunboyy/repogen/internal/testutils"
|
||||
)
|
||||
|
||||
const expectedConstructorResult = `
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
)
|
||||
|
||||
func NewUserRepository(collection *mongo.Collection) UserRepository {
|
||||
return &UserRepositoryMongo{
|
||||
collection: collection,
|
||||
}
|
||||
}
|
||||
|
||||
type UserRepositoryMongo struct {
|
||||
collection *mongo.Collection
|
||||
}
|
||||
`
|
||||
|
||||
func TestGenerateConstructor(t *testing.T) {
|
||||
userModel := code.Struct{
|
||||
var userModel = code.Struct{
|
||||
Name: "UserModel",
|
||||
Fields: code.StructFields{
|
||||
{
|
||||
|
@ -54,8 +33,34 @@ func TestGenerateConstructor(t *testing.T) {
|
|||
Type: code.SimpleType("int"),
|
||||
Tags: map[string][]string{"bson": {"age"}},
|
||||
},
|
||||
{
|
||||
Name: "AccessToken",
|
||||
Type: code.SimpleType("string"),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const expectedConstructorResult = `
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
)
|
||||
|
||||
func NewUserRepository(collection *mongo.Collection) UserRepository {
|
||||
return &UserRepositoryMongo{
|
||||
collection: collection,
|
||||
}
|
||||
}
|
||||
|
||||
type UserRepositoryMongo struct {
|
||||
collection *mongo.Collection
|
||||
}
|
||||
`
|
||||
|
||||
func TestGenerateConstructor(t *testing.T) {
|
||||
generator := mongo.NewGenerator(userModel, "UserRepository")
|
||||
buffer := new(bytes.Buffer)
|
||||
|
||||
|
@ -75,7 +80,7 @@ type GenerateMethodTestCase struct {
|
|||
ExpectedCode string
|
||||
}
|
||||
|
||||
func TestGenerateMethod(t *testing.T) {
|
||||
func TestGenerateMethod_Find(t *testing.T) {
|
||||
testTable := []GenerateMethodTestCase{
|
||||
{
|
||||
Name: "simple find one method",
|
||||
|
@ -489,33 +494,9 @@ func (r *UserRepositoryMongo) FindByGenderIn(ctx context.Context, arg0 []Gender)
|
|||
`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testTable {
|
||||
t.Run(testCase.Name, func(t *testing.T) {
|
||||
userModel := code.Struct{
|
||||
Name: "UserModel",
|
||||
Fields: code.StructFields{
|
||||
{
|
||||
Name: "ID",
|
||||
Type: code.ExternalType{PackageAlias: "primitive", Name: "ObjectID"},
|
||||
Tags: map[string][]string{"bson": {"_id", "omitempty"}},
|
||||
},
|
||||
{
|
||||
Name: "Username",
|
||||
Type: code.SimpleType("string"),
|
||||
Tags: map[string][]string{"bson": {"username"}},
|
||||
},
|
||||
{
|
||||
Name: "Gender",
|
||||
Type: code.SimpleType("Gender"),
|
||||
Tags: map[string][]string{"bson": {"gender"}},
|
||||
},
|
||||
{
|
||||
Name: "Age",
|
||||
Type: code.SimpleType("int"),
|
||||
Tags: map[string][]string{"bson": {"age"}},
|
||||
},
|
||||
},
|
||||
}
|
||||
generator := mongo.NewGenerator(userModel, "UserRepository")
|
||||
buffer := new(bytes.Buffer)
|
||||
|
||||
|
@ -530,3 +511,458 @@ func (r *UserRepositoryMongo) FindByGenderIn(ctx context.Context, arg0 []Gender)
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateMethod_Delete(t *testing.T) {
|
||||
testTable := []GenerateMethodTestCase{
|
||||
{
|
||||
Name: "simple delete one method",
|
||||
MethodSpec: spec.MethodSpec{
|
||||
Name: "DeleteByID",
|
||||
Params: []code.Param{
|
||||
{Name: "ctx", Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Name: "id", Type: code.ExternalType{PackageAlias: "primitive", Name: "ObjectID"}},
|
||||
},
|
||||
Returns: []code.Type{code.SimpleType("bool"), code.SimpleType("error")},
|
||||
Operation: spec.DeleteOperation{
|
||||
Mode: spec.QueryModeOne,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{Comparator: spec.ComparatorEqual, Field: "ID"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ExpectedCode: `
|
||||
func (r *UserRepositoryMongo) DeleteByID(ctx context.Context, arg0 primitive.ObjectID) (bool, error) {
|
||||
result, err := r.collection.DeleteOne(ctx, bson.M{
|
||||
"_id": arg0,
|
||||
})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return result.DeletedCount > 0, nil
|
||||
}
|
||||
`,
|
||||
},
|
||||
{
|
||||
Name: "simple delete many method",
|
||||
MethodSpec: spec.MethodSpec{
|
||||
Name: "DeleteByGender",
|
||||
Params: []code.Param{
|
||||
{Name: "ctx", Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Name: "gender", Type: code.SimpleType("Gender")},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("int"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
Operation: spec.DeleteOperation{
|
||||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{Comparator: spec.ComparatorEqual, Field: "Gender"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ExpectedCode: `
|
||||
func (r *UserRepositoryMongo) DeleteByGender(ctx context.Context, arg0 Gender) (int, error) {
|
||||
result, err := r.collection.DeleteMany(ctx, bson.M{
|
||||
"gender": arg0,
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return int(result.DeletedCount), nil
|
||||
}
|
||||
`,
|
||||
},
|
||||
{
|
||||
Name: "delete with And operator",
|
||||
MethodSpec: spec.MethodSpec{
|
||||
Name: "DeleteByGenderAndAge",
|
||||
Params: []code.Param{
|
||||
{Name: "ctx", Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Name: "gender", Type: code.SimpleType("Gender")},
|
||||
{Name: "age", Type: code.SimpleType("int")},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("int"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
Operation: spec.DeleteOperation{
|
||||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{
|
||||
Operator: spec.OperatorAnd,
|
||||
Predicates: []spec.Predicate{
|
||||
{Comparator: spec.ComparatorEqual, Field: "Gender"},
|
||||
{Comparator: spec.ComparatorEqual, Field: "Age"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ExpectedCode: `
|
||||
func (r *UserRepositoryMongo) DeleteByGenderAndAge(ctx context.Context, arg0 Gender, arg1 int) (int, error) {
|
||||
result, err := r.collection.DeleteMany(ctx, bson.M{
|
||||
"gender": arg0,
|
||||
"age": arg1,
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return int(result.DeletedCount), nil
|
||||
}
|
||||
`,
|
||||
},
|
||||
{
|
||||
Name: "delete with Or operator",
|
||||
MethodSpec: spec.MethodSpec{
|
||||
Name: "DeleteByGenderOrAge",
|
||||
Params: []code.Param{
|
||||
{Name: "ctx", Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Name: "gender", Type: code.SimpleType("Gender")},
|
||||
{Name: "age", Type: code.SimpleType("int")},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("int"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
Operation: spec.DeleteOperation{
|
||||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{
|
||||
Operator: spec.OperatorOr,
|
||||
Predicates: []spec.Predicate{
|
||||
{Comparator: spec.ComparatorEqual, Field: "Gender"},
|
||||
{Comparator: spec.ComparatorEqual, Field: "Age"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ExpectedCode: `
|
||||
func (r *UserRepositoryMongo) DeleteByGenderOrAge(ctx context.Context, arg0 Gender, arg1 int) (int, error) {
|
||||
result, err := r.collection.DeleteMany(ctx, bson.M{
|
||||
"$or": []bson.M{
|
||||
{"gender": arg0},
|
||||
{"age": arg1},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return int(result.DeletedCount), nil
|
||||
}
|
||||
`,
|
||||
},
|
||||
{
|
||||
Name: "delete with Not comparator",
|
||||
MethodSpec: spec.MethodSpec{
|
||||
Name: "DeleteByGenderNot",
|
||||
Params: []code.Param{
|
||||
{Name: "ctx", Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Name: "gender", Type: code.SimpleType("Gender")},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("int"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
Operation: spec.DeleteOperation{
|
||||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{Comparator: spec.ComparatorNot, Field: "Gender"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ExpectedCode: `
|
||||
func (r *UserRepositoryMongo) DeleteByGenderNot(ctx context.Context, arg0 Gender) (int, error) {
|
||||
result, err := r.collection.DeleteMany(ctx, bson.M{
|
||||
"gender": bson.M{"$ne": arg0},
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return int(result.DeletedCount), nil
|
||||
}
|
||||
`,
|
||||
},
|
||||
{
|
||||
Name: "delete with LessThan comparator",
|
||||
MethodSpec: spec.MethodSpec{
|
||||
Name: "DeleteByAgeLessThan",
|
||||
Params: []code.Param{
|
||||
{Name: "ctx", Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Name: "age", Type: code.SimpleType("int")},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("int"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
Operation: spec.DeleteOperation{
|
||||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{Comparator: spec.ComparatorLessThan, Field: "Age"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ExpectedCode: `
|
||||
func (r *UserRepositoryMongo) DeleteByAgeLessThan(ctx context.Context, arg0 int) (int, error) {
|
||||
result, err := r.collection.DeleteMany(ctx, bson.M{
|
||||
"age": bson.M{"$lt": arg0},
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return int(result.DeletedCount), nil
|
||||
}
|
||||
`,
|
||||
},
|
||||
{
|
||||
Name: "delete with LessThanEqual comparator",
|
||||
MethodSpec: spec.MethodSpec{
|
||||
Name: "DeleteByAgeLessThanEqual",
|
||||
Params: []code.Param{
|
||||
{Name: "ctx", Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Name: "age", Type: code.SimpleType("int")},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("int"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
Operation: spec.DeleteOperation{
|
||||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{Comparator: spec.ComparatorLessThanEqual, Field: "Age"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ExpectedCode: `
|
||||
func (r *UserRepositoryMongo) DeleteByAgeLessThanEqual(ctx context.Context, arg0 int) (int, error) {
|
||||
result, err := r.collection.DeleteMany(ctx, bson.M{
|
||||
"age": bson.M{"$lte": arg0},
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return int(result.DeletedCount), nil
|
||||
}
|
||||
`,
|
||||
},
|
||||
{
|
||||
Name: "delete with GreaterThan comparator",
|
||||
MethodSpec: spec.MethodSpec{
|
||||
Name: "DeleteByAgeGreaterThan",
|
||||
Params: []code.Param{
|
||||
{Name: "ctx", Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Name: "age", Type: code.SimpleType("int")},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("int"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
Operation: spec.DeleteOperation{
|
||||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{Comparator: spec.ComparatorGreaterThan, Field: "Age"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ExpectedCode: `
|
||||
func (r *UserRepositoryMongo) DeleteByAgeGreaterThan(ctx context.Context, arg0 int) (int, error) {
|
||||
result, err := r.collection.DeleteMany(ctx, bson.M{
|
||||
"age": bson.M{"$gt": arg0},
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return int(result.DeletedCount), nil
|
||||
}
|
||||
`,
|
||||
},
|
||||
{
|
||||
Name: "delete with GreaterThanEqual comparator",
|
||||
MethodSpec: spec.MethodSpec{
|
||||
Name: "DeleteByAgeGreaterThanEqual",
|
||||
Params: []code.Param{
|
||||
{Name: "ctx", Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Name: "age", Type: code.SimpleType("int")},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("int"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
Operation: spec.DeleteOperation{
|
||||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{Comparator: spec.ComparatorGreaterThanEqual, Field: "Age"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ExpectedCode: `
|
||||
func (r *UserRepositoryMongo) DeleteByAgeGreaterThanEqual(ctx context.Context, arg0 int) (int, error) {
|
||||
result, err := r.collection.DeleteMany(ctx, bson.M{
|
||||
"age": bson.M{"$gte": arg0},
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return int(result.DeletedCount), nil
|
||||
}
|
||||
`,
|
||||
},
|
||||
{
|
||||
Name: "delete with Between comparator",
|
||||
MethodSpec: spec.MethodSpec{
|
||||
Name: "DeleteByAgeBetween",
|
||||
Params: []code.Param{
|
||||
{Name: "ctx", Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Name: "fromAge", Type: code.SimpleType("int")},
|
||||
{Name: "toAge", Type: code.SimpleType("int")},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("int"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
Operation: spec.DeleteOperation{
|
||||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{Comparator: spec.ComparatorBetween, Field: "Age"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ExpectedCode: `
|
||||
func (r *UserRepositoryMongo) DeleteByAgeBetween(ctx context.Context, arg0 int, arg1 int) (int, error) {
|
||||
result, err := r.collection.DeleteMany(ctx, bson.M{
|
||||
"age": bson.M{"$gte": arg0, "$lte": arg1},
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return int(result.DeletedCount), nil
|
||||
}
|
||||
`,
|
||||
},
|
||||
{
|
||||
Name: "delete with In comparator",
|
||||
MethodSpec: spec.MethodSpec{
|
||||
Name: "DeleteByGenderIn",
|
||||
Params: []code.Param{
|
||||
{Name: "ctx", Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Name: "gender", Type: code.ArrayType{ContainedType: code.SimpleType("Gender")}},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("int"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
Operation: spec.DeleteOperation{
|
||||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{Comparator: spec.ComparatorIn, Field: "Gender"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ExpectedCode: `
|
||||
func (r *UserRepositoryMongo) DeleteByGenderIn(ctx context.Context, arg0 []Gender) (int, error) {
|
||||
result, err := r.collection.DeleteMany(ctx, bson.M{
|
||||
"gender": bson.M{"$in": arg0},
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return int(result.DeletedCount), nil
|
||||
}
|
||||
`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testTable {
|
||||
t.Run(testCase.Name, func(t *testing.T) {
|
||||
generator := mongo.NewGenerator(userModel, "UserRepository")
|
||||
buffer := new(bytes.Buffer)
|
||||
|
||||
err := generator.GenerateMethod(testCase.MethodSpec, buffer)
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if err := testutils.ExpectMultiLineString(testCase.ExpectedCode, buffer.String()); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type GenerateMethodInvalidTestCase struct {
|
||||
Name string
|
||||
Method spec.MethodSpec
|
||||
ExpectedError error
|
||||
}
|
||||
|
||||
func TestGenerateMethod_Invalid(t *testing.T) {
|
||||
testTable := []GenerateMethodInvalidTestCase{
|
||||
{
|
||||
Name: "operation not supported",
|
||||
Method: spec.MethodSpec{
|
||||
Name: "SearchByID",
|
||||
Params: []code.Param{
|
||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Type: code.ExternalType{PackageAlias: "primitive", Name: "ObjectID"}},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
Operation: "search",
|
||||
},
|
||||
ExpectedError: mongo.OperationNotSupportedError,
|
||||
},
|
||||
{
|
||||
Name: "bson tag not found",
|
||||
Method: spec.MethodSpec{
|
||||
Name: "FindByAccessToken",
|
||||
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"),
|
||||
},
|
||||
Operation: spec.FindOperation{
|
||||
Mode: spec.QueryModeOne,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{Field: "AccessToken", Comparator: spec.ComparatorEqual},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ExpectedError: mongo.BsonTagNotFoundError,
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testTable {
|
||||
t.Run(testCase.Name, func(t *testing.T) {
|
||||
generator := mongo.NewGenerator(userModel, "UserRepository")
|
||||
buffer := new(bytes.Buffer)
|
||||
|
||||
err := generator.GenerateMethod(testCase.Method, buffer)
|
||||
|
||||
if err != testCase.ExpectedError {
|
||||
t.Errorf("\nExpected = %v\nReceived = %v", testCase.ExpectedError, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,19 +70,19 @@ func (data mongoMethodTemplateData) Returns() string {
|
|||
return fmt.Sprintf(" (%s)", strings.Join(returns, ", "))
|
||||
}
|
||||
|
||||
const findOneTemplate = ` var entity {{.EntityType}}
|
||||
if err := r.collection.FindOne(ctx, bson.M{
|
||||
{{range $index, $field := .QuerySpec.Predicates}} {{$field.Code $index}},
|
||||
{{end}} }).Decode(&entity); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &entity, nil`
|
||||
|
||||
type mongoFindTemplateData struct {
|
||||
EntityType string
|
||||
QuerySpec querySpec
|
||||
}
|
||||
|
||||
const findOneTemplate = ` var entity {{.EntityType}}
|
||||
if err := r.collection.FindOne(ctx, bson.M{
|
||||
{{.QuerySpec.Code}}
|
||||
}).Decode(&entity); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &entity, nil`
|
||||
|
||||
const findManyTemplate = ` cursor, err := r.collection.Find(ctx, bson.M{
|
||||
{{.QuerySpec.Code}}
|
||||
})
|
||||
|
@ -94,3 +94,23 @@ const findManyTemplate = ` cursor, err := r.collection.Find(ctx, bson.M{
|
|||
return nil, err
|
||||
}
|
||||
return entities, nil`
|
||||
|
||||
type mongoDeleteTemplateData struct {
|
||||
QuerySpec querySpec
|
||||
}
|
||||
|
||||
const deleteOneTemplate = ` result, err := r.collection.DeleteOne(ctx, bson.M{
|
||||
{{.QuerySpec.Code}}
|
||||
})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return result.DeletedCount > 0, nil`
|
||||
|
||||
const deleteManyTemplate = ` result, err := r.collection.DeleteMany(ctx, bson.M{
|
||||
{{.QuerySpec.Code}}
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return int(result.DeletedCount), nil`
|
||||
|
|
|
@ -33,6 +33,12 @@ type FindOperation struct {
|
|||
Query QuerySpec
|
||||
}
|
||||
|
||||
// DeleteOperation is a method specification for delete operations
|
||||
type DeleteOperation struct {
|
||||
Mode QueryMode
|
||||
Query QuerySpec
|
||||
}
|
||||
|
||||
// QuerySpec is a set of conditions of querying the database
|
||||
type QuerySpec struct {
|
||||
Operator Operator
|
||||
|
|
|
@ -25,6 +25,8 @@ func (p interfaceMethodParser) Parse() (MethodSpec, error) {
|
|||
switch methodNameTokens[0] {
|
||||
case "Find":
|
||||
return p.parseFindMethod(methodNameTokens[1:])
|
||||
case "Delete":
|
||||
return p.parseDeleteMethod(methodNameTokens[1:])
|
||||
}
|
||||
return MethodSpec{}, UnknownOperationError
|
||||
}
|
||||
|
@ -92,6 +94,58 @@ func (p interfaceMethodParser) extractFindReturns(returns []code.Type) (QueryMod
|
|||
return "", UnsupportedReturnError
|
||||
}
|
||||
|
||||
func (p interfaceMethodParser) parseDeleteMethod(tokens []string) (MethodSpec, error) {
|
||||
if len(tokens) == 0 {
|
||||
return MethodSpec{}, UnsupportedNameError
|
||||
}
|
||||
|
||||
mode, err := p.extractDeleteReturns(p.Method.Returns)
|
||||
if err != nil {
|
||||
return MethodSpec{}, err
|
||||
}
|
||||
|
||||
querySpec, err := p.parseQuery(tokens)
|
||||
if err != nil {
|
||||
return MethodSpec{}, err
|
||||
}
|
||||
|
||||
if err := p.validateMethodSignature(querySpec); err != nil {
|
||||
return MethodSpec{}, err
|
||||
}
|
||||
|
||||
return MethodSpec{
|
||||
Name: p.Method.Name,
|
||||
Params: p.Method.Params,
|
||||
Returns: p.Method.Returns,
|
||||
Operation: DeleteOperation{
|
||||
Mode: mode,
|
||||
Query: querySpec,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (p interfaceMethodParser) extractDeleteReturns(returns []code.Type) (QueryMode, error) {
|
||||
if len(returns) != 2 {
|
||||
return "", UnsupportedReturnError
|
||||
}
|
||||
|
||||
if returns[1] != code.SimpleType("error") {
|
||||
return "", UnsupportedReturnError
|
||||
}
|
||||
|
||||
simpleType, ok := returns[0].(code.SimpleType)
|
||||
if ok {
|
||||
if simpleType == code.SimpleType("bool") {
|
||||
return QueryModeOne, nil
|
||||
}
|
||||
if simpleType == code.SimpleType("int") {
|
||||
return QueryModeMany, nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", UnsupportedReturnError
|
||||
}
|
||||
|
||||
func (p interfaceMethodParser) parseQuery(tokens []string) (QuerySpec, error) {
|
||||
if len(tokens) == 0 {
|
||||
return QuerySpec{}, InvalidQueryError
|
||||
|
|
|
@ -40,7 +40,7 @@ type ParseInterfaceMethodTestCase struct {
|
|||
ExpectedOutput spec.MethodSpec
|
||||
}
|
||||
|
||||
func TestParseInterfaceMethod(t *testing.T) {
|
||||
func TestParseInterfaceMethod_Find(t *testing.T) {
|
||||
testTable := []ParseInterfaceMethodTestCase{
|
||||
{
|
||||
Name: "FindOneByArg method",
|
||||
|
@ -470,21 +470,454 @@ func TestParseInterfaceMethod(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestParseInterfaceMethod_Delete(t *testing.T) {
|
||||
testTable := []ParseInterfaceMethodTestCase{
|
||||
{
|
||||
Name: "DeleteOneByArg method",
|
||||
Method: code.Method{
|
||||
Name: "DeleteOneByID",
|
||||
Params: []code.Param{
|
||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Type: code.ExternalType{PackageAlias: "primitive", Name: "ObjectID"}},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("bool"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
},
|
||||
ExpectedOutput: spec.MethodSpec{
|
||||
Name: "DeleteOneByID",
|
||||
Params: []code.Param{
|
||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Type: code.ExternalType{PackageAlias: "primitive", Name: "ObjectID"}},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("bool"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
Operation: spec.DeleteOperation{
|
||||
Mode: spec.QueryModeOne,
|
||||
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
||||
{Field: "ID", Comparator: spec.ComparatorEqual},
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "DeleteOneByMultiWordArg method",
|
||||
Method: code.Method{
|
||||
Name: "DeleteOneByPhoneNumber",
|
||||
Params: []code.Param{
|
||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Type: code.SimpleType("string")},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("bool"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
},
|
||||
ExpectedOutput: spec.MethodSpec{
|
||||
Name: "DeleteOneByPhoneNumber",
|
||||
Params: []code.Param{
|
||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Type: code.SimpleType("string")},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("bool"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
Operation: spec.DeleteOperation{
|
||||
Mode: spec.QueryModeOne,
|
||||
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
||||
{Field: "PhoneNumber", Comparator: spec.ComparatorEqual},
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "DeleteByArg method",
|
||||
Method: code.Method{
|
||||
Name: "DeleteByCity",
|
||||
Params: []code.Param{
|
||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Type: code.SimpleType("string")},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("int"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
},
|
||||
ExpectedOutput: spec.MethodSpec{
|
||||
Name: "DeleteByCity",
|
||||
Params: []code.Param{
|
||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Type: code.SimpleType("string")},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("int"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
Operation: spec.DeleteOperation{
|
||||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
||||
{Field: "City", Comparator: spec.ComparatorEqual},
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "DeleteAll method",
|
||||
Method: code.Method{
|
||||
Name: "DeleteAll",
|
||||
Params: []code.Param{
|
||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("int"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
},
|
||||
ExpectedOutput: spec.MethodSpec{
|
||||
Name: "DeleteAll",
|
||||
Params: []code.Param{
|
||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("int"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
Operation: spec.DeleteOperation{
|
||||
Mode: spec.QueryModeMany,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "DeleteByArgAndArg method",
|
||||
Method: code.Method{
|
||||
Name: "DeleteByCityAndGender",
|
||||
Params: []code.Param{
|
||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Type: code.SimpleType("string")},
|
||||
{Type: code.SimpleType("Gender")},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("int"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
},
|
||||
ExpectedOutput: spec.MethodSpec{
|
||||
Name: "DeleteByCityAndGender",
|
||||
Params: []code.Param{
|
||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Type: code.SimpleType("string")},
|
||||
{Type: code.SimpleType("Gender")},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("int"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
Operation: spec.DeleteOperation{
|
||||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{
|
||||
Operator: spec.OperatorAnd,
|
||||
Predicates: []spec.Predicate{
|
||||
{Field: "City", Comparator: spec.ComparatorEqual},
|
||||
{Field: "Gender", Comparator: spec.ComparatorEqual},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "DeleteByArgOrArg method",
|
||||
Method: code.Method{
|
||||
Name: "DeleteByCityOrGender",
|
||||
Params: []code.Param{
|
||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Type: code.SimpleType("string")},
|
||||
{Type: code.SimpleType("Gender")},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("int"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
},
|
||||
ExpectedOutput: spec.MethodSpec{
|
||||
Name: "DeleteByCityOrGender",
|
||||
Params: []code.Param{
|
||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Type: code.SimpleType("string")},
|
||||
{Type: code.SimpleType("Gender")},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("int"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
Operation: spec.DeleteOperation{
|
||||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{
|
||||
Operator: spec.OperatorOr,
|
||||
Predicates: []spec.Predicate{
|
||||
{Field: "City", Comparator: spec.ComparatorEqual},
|
||||
{Field: "Gender", Comparator: spec.ComparatorEqual},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "DeleteByArgNot method",
|
||||
Method: code.Method{
|
||||
Name: "DeleteByCityNot",
|
||||
Params: []code.Param{
|
||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Type: code.SimpleType("string")},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("int"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
},
|
||||
ExpectedOutput: spec.MethodSpec{
|
||||
Name: "DeleteByCityNot",
|
||||
Params: []code.Param{
|
||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Type: code.SimpleType("string")},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("int"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
Operation: spec.DeleteOperation{
|
||||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
||||
{Field: "City", Comparator: spec.ComparatorNot},
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "DeleteByArgLessThan method",
|
||||
Method: code.Method{
|
||||
Name: "DeleteByAgeLessThan",
|
||||
Params: []code.Param{
|
||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Type: code.SimpleType("int")},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("int"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
},
|
||||
ExpectedOutput: spec.MethodSpec{
|
||||
Name: "DeleteByAgeLessThan",
|
||||
Params: []code.Param{
|
||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Type: code.SimpleType("int")},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("int"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
Operation: spec.DeleteOperation{
|
||||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
||||
{Field: "Age", Comparator: spec.ComparatorLessThan},
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "DeleteByArgLessThanEqual method",
|
||||
Method: code.Method{
|
||||
Name: "DeleteByAgeLessThanEqual",
|
||||
Params: []code.Param{
|
||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Type: code.SimpleType("int")},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("int"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
},
|
||||
ExpectedOutput: spec.MethodSpec{
|
||||
Name: "DeleteByAgeLessThanEqual",
|
||||
Params: []code.Param{
|
||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Type: code.SimpleType("int")},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("int"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
Operation: spec.DeleteOperation{
|
||||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
||||
{Field: "Age", Comparator: spec.ComparatorLessThanEqual},
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "DeleteByArgGreaterThan method",
|
||||
Method: code.Method{
|
||||
Name: "DeleteByAgeGreaterThan",
|
||||
Params: []code.Param{
|
||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Type: code.SimpleType("int")},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("int"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
},
|
||||
ExpectedOutput: spec.MethodSpec{
|
||||
Name: "DeleteByAgeGreaterThan",
|
||||
Params: []code.Param{
|
||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Type: code.SimpleType("int")},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("int"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
Operation: spec.DeleteOperation{
|
||||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
||||
{Field: "Age", Comparator: spec.ComparatorGreaterThan},
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "DeleteByArgGreaterThanEqual method",
|
||||
Method: code.Method{
|
||||
Name: "DeleteByAgeGreaterThanEqual",
|
||||
Params: []code.Param{
|
||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Type: code.SimpleType("int")},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("int"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
},
|
||||
ExpectedOutput: spec.MethodSpec{
|
||||
Name: "DeleteByAgeGreaterThanEqual",
|
||||
Params: []code.Param{
|
||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Type: code.SimpleType("int")},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("int"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
Operation: spec.DeleteOperation{
|
||||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
||||
{Field: "Age", Comparator: spec.ComparatorGreaterThanEqual},
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "DeleteByArgBetween method",
|
||||
Method: code.Method{
|
||||
Name: "DeleteByAgeBetween",
|
||||
Params: []code.Param{
|
||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Type: code.SimpleType("int")},
|
||||
{Type: code.SimpleType("int")},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("int"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
},
|
||||
ExpectedOutput: spec.MethodSpec{
|
||||
Name: "DeleteByAgeBetween",
|
||||
Params: []code.Param{
|
||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Type: code.SimpleType("int")},
|
||||
{Type: code.SimpleType("int")},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("int"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
Operation: spec.DeleteOperation{
|
||||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
||||
{Field: "Age", Comparator: spec.ComparatorBetween},
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "DeleteByArgIn method",
|
||||
Method: code.Method{
|
||||
Name: "DeleteByCityIn",
|
||||
Params: []code.Param{
|
||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Type: code.ArrayType{ContainedType: code.SimpleType("string")}},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("int"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
},
|
||||
ExpectedOutput: spec.MethodSpec{
|
||||
Name: "DeleteByCityIn",
|
||||
Params: []code.Param{
|
||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Type: code.ArrayType{ContainedType: code.SimpleType("string")}},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("int"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
Operation: spec.DeleteOperation{
|
||||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
||||
{Field: "City", Comparator: spec.ComparatorIn},
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testTable {
|
||||
t.Run(testCase.Name, func(t *testing.T) {
|
||||
actualSpec, err := spec.ParseInterfaceMethod(structModel, testCase.Method)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Error = %s", err)
|
||||
}
|
||||
if !reflect.DeepEqual(actualSpec, testCase.ExpectedOutput) {
|
||||
t.Errorf("Expected = %v\nReceived = %v", testCase.ExpectedOutput, actualSpec)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type ParseInterfaceMethodInvalidTestCase struct {
|
||||
Name string
|
||||
Method code.Method
|
||||
ExpectedError error
|
||||
}
|
||||
|
||||
func TestParseInterfaceMethodInvalid(t *testing.T) {
|
||||
testTable := []ParseInterfaceMethodInvalidTestCase{
|
||||
{
|
||||
Name: "unknown operation",
|
||||
Method: code.Method{
|
||||
func TestParseInterfaceMethod_Invalid(t *testing.T) {
|
||||
_, err := spec.ParseInterfaceMethod(structModel, code.Method{
|
||||
Name: "SearchByID",
|
||||
},
|
||||
ExpectedError: spec.UnknownOperationError,
|
||||
},
|
||||
})
|
||||
|
||||
if err != spec.UnknownOperationError {
|
||||
t.Errorf("\nExpected = %v\nReceived = %v", spec.UnknownOperationError, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseInterfaceMethod_Find_Invalid(t *testing.T) {
|
||||
testTable := []ParseInterfaceMethodInvalidTestCase{
|
||||
{
|
||||
Name: "unsupported find method name",
|
||||
Method: code.Method{
|
||||
|
@ -657,3 +1090,178 @@ func TestParseInterfaceMethodInvalid(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseInterfaceMethod_Delete_Invalid(t *testing.T) {
|
||||
testTable := []ParseInterfaceMethodInvalidTestCase{
|
||||
{
|
||||
Name: "unsupported delete method name",
|
||||
Method: code.Method{
|
||||
Name: "Delete",
|
||||
},
|
||||
ExpectedError: spec.UnsupportedNameError,
|
||||
},
|
||||
{
|
||||
Name: "invalid number of returns",
|
||||
Method: code.Method{
|
||||
Name: "DeleteOneByID",
|
||||
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: "DeleteOneByID",
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("float64"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
},
|
||||
ExpectedError: spec.UnsupportedReturnError,
|
||||
},
|
||||
{
|
||||
Name: "error return not provided",
|
||||
Method: code.Method{
|
||||
Name: "DeleteOneByID",
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("int"),
|
||||
code.SimpleType("bool"),
|
||||
},
|
||||
},
|
||||
ExpectedError: spec.UnsupportedReturnError,
|
||||
},
|
||||
{
|
||||
Name: "misplaced operator token (leftmost)",
|
||||
Method: code.Method{
|
||||
Name: "DeleteByAndGender",
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("int"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
},
|
||||
ExpectedError: spec.InvalidQueryError,
|
||||
},
|
||||
{
|
||||
Name: "misplaced operator token (rightmost)",
|
||||
Method: code.Method{
|
||||
Name: "DeleteByGenderAnd",
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("int"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
},
|
||||
ExpectedError: spec.InvalidQueryError,
|
||||
},
|
||||
{
|
||||
Name: "misplaced operator token (double operator)",
|
||||
Method: code.Method{
|
||||
Name: "DeleteByGenderAndAndCity",
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("int"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
},
|
||||
ExpectedError: spec.InvalidQueryError,
|
||||
},
|
||||
{
|
||||
Name: "ambiguous query",
|
||||
Method: code.Method{
|
||||
Name: "DeleteByGenderAndCityOrAge",
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("int"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
},
|
||||
ExpectedError: spec.InvalidQueryError,
|
||||
},
|
||||
{
|
||||
Name: "no context parameter",
|
||||
Method: code.Method{
|
||||
Name: "DeleteByGender",
|
||||
Params: []code.Param{
|
||||
{Type: code.SimpleType("Gender")},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("int"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
},
|
||||
ExpectedError: spec.ContextParamRequiredError,
|
||||
},
|
||||
{
|
||||
Name: "mismatched number of parameters",
|
||||
Method: code.Method{
|
||||
Name: "DeleteByCountry",
|
||||
Params: []code.Param{
|
||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Type: code.SimpleType("string")},
|
||||
{Type: code.SimpleType("string")},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("int"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
},
|
||||
ExpectedError: spec.InvalidParamError,
|
||||
},
|
||||
{
|
||||
Name: "struct field not found",
|
||||
Method: code.Method{
|
||||
Name: "DeleteByCountry",
|
||||
Params: []code.Param{
|
||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Type: code.SimpleType("string")},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("int"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
},
|
||||
ExpectedError: spec.StructFieldNotFoundError,
|
||||
},
|
||||
{
|
||||
Name: "mismatched method parameter type",
|
||||
Method: code.Method{
|
||||
Name: "DeleteByGender",
|
||||
Params: []code.Param{
|
||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Type: code.SimpleType("string")},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("int"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
},
|
||||
ExpectedError: spec.InvalidParamError,
|
||||
},
|
||||
{
|
||||
Name: "mismatched method parameter type for special case",
|
||||
Method: code.Method{
|
||||
Name: "DeleteByCityIn",
|
||||
Params: []code.Param{
|
||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Type: code.SimpleType("string")},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("int"),
|
||||
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