Add functionality to update the whole model
This commit is contained in:
parent
f7b0df5463
commit
87ecd3704b
10 changed files with 310 additions and 55 deletions
|
@ -2,6 +2,8 @@ package mongo
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/sunboyy/repogen/internal/spec"
|
||||
)
|
||||
|
||||
// NewOperationNotSupportedError creates operationNotSupportedError
|
||||
|
@ -29,3 +31,16 @@ type bsonTagNotFoundError struct {
|
|||
func (err bsonTagNotFoundError) Error() string {
|
||||
return fmt.Sprintf("bson tag of field '%s' not found", err.FieldName)
|
||||
}
|
||||
|
||||
// NewUpdateTypeNotSupportedError creates updateTypeNotSupportedError
|
||||
func NewUpdateTypeNotSupportedError(update spec.Update) error {
|
||||
return updateTypeNotSupportedError{Update: update}
|
||||
}
|
||||
|
||||
type updateTypeNotSupportedError struct {
|
||||
Update spec.Update
|
||||
}
|
||||
|
||||
func (err updateTypeNotSupportedError) Error() string {
|
||||
return fmt.Sprintf("update type %s not supported", err.Update.Name())
|
||||
}
|
||||
|
|
|
@ -12,6 +12,17 @@ type ErrorTestCase struct {
|
|||
ExpectedString string
|
||||
}
|
||||
|
||||
type StubUpdate struct {
|
||||
}
|
||||
|
||||
func (update StubUpdate) Name() string {
|
||||
return "Stub"
|
||||
}
|
||||
|
||||
func (update StubUpdate) NumberOfArguments() int {
|
||||
return 1
|
||||
}
|
||||
|
||||
func TestError(t *testing.T) {
|
||||
testTable := []ErrorTestCase{
|
||||
{
|
||||
|
@ -24,6 +35,11 @@ func TestError(t *testing.T) {
|
|||
Error: mongo.NewBsonTagNotFoundError("AccessToken"),
|
||||
ExpectedString: "bson tag of field 'AccessToken' not found",
|
||||
},
|
||||
{
|
||||
Name: "UpdateTypeNotSupportedError",
|
||||
Error: mongo.NewUpdateTypeNotSupportedError(StubUpdate{}),
|
||||
ExpectedString: "update type Stub not supported",
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testTable {
|
||||
|
|
|
@ -117,13 +117,9 @@ func (g RepositoryGenerator) generateFindImplementation(operation spec.FindOpera
|
|||
}
|
||||
|
||||
func (g RepositoryGenerator) generateUpdateImplementation(operation spec.UpdateOperation) (string, error) {
|
||||
var fields []updateField
|
||||
for _, field := range operation.Fields {
|
||||
bsonTag, err := g.bsonTagFromFieldName(field.Name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
fields = append(fields, updateField{BsonTag: bsonTag, ParamIndex: field.ParamIndex})
|
||||
update, err := g.getMongoUpdate(operation.Update)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
querySpec, err := g.mongoQuerySpec(operation.Query)
|
||||
|
@ -132,8 +128,8 @@ func (g RepositoryGenerator) generateUpdateImplementation(operation spec.UpdateO
|
|||
}
|
||||
|
||||
tmplData := mongoUpdateTemplateData{
|
||||
UpdateFields: fields,
|
||||
QuerySpec: querySpec,
|
||||
Update: update,
|
||||
QuerySpec: querySpec,
|
||||
}
|
||||
|
||||
if operation.Mode == spec.QueryModeOne {
|
||||
|
@ -142,6 +138,25 @@ func (g RepositoryGenerator) generateUpdateImplementation(operation spec.UpdateO
|
|||
return generateFromTemplate("mongo_repository_updatemany", updateManyTemplate, tmplData)
|
||||
}
|
||||
|
||||
func (g RepositoryGenerator) getMongoUpdate(updateSpec spec.Update) (update, error) {
|
||||
switch updateSpec := updateSpec.(type) {
|
||||
case spec.UpdateModel:
|
||||
return updateModel{}, nil
|
||||
case spec.UpdateFields:
|
||||
var update updateFields
|
||||
for _, field := range updateSpec {
|
||||
bsonTag, err := g.bsonTagFromFieldName(field.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
update.Fields = append(update.Fields, updateField{BsonTag: bsonTag, ParamIndex: field.ParamIndex})
|
||||
}
|
||||
return update, nil
|
||||
default:
|
||||
return nil, NewUpdateTypeNotSupportedError(updateSpec)
|
||||
}
|
||||
}
|
||||
|
||||
func (g RepositoryGenerator) generateDeleteImplementation(operation spec.DeleteOperation) (string, error) {
|
||||
querySpec, err := g.mongoQuerySpec(operation.Query)
|
||||
if err != nil {
|
||||
|
|
|
@ -712,6 +712,43 @@ func (r *UserRepositoryMongo) FindByEnabledFalse(arg0 context.Context) ([]*UserM
|
|||
|
||||
func TestGenerateMethod_Update(t *testing.T) {
|
||||
testTable := []GenerateMethodTestCase{
|
||||
{
|
||||
Name: "update model method",
|
||||
MethodSpec: spec.MethodSpec{
|
||||
Name: "UpdateByID",
|
||||
Params: []code.Param{
|
||||
{Name: "ctx", Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Name: "model", Type: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
||||
{Name: "id", Type: code.ExternalType{PackageAlias: "primitive", Name: "ObjectID"}},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("bool"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
Operation: spec.UpdateOperation{
|
||||
Update: spec.UpdateModel{},
|
||||
Mode: spec.QueryModeOne,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{Field: "ID", Comparator: spec.ComparatorEqual, ParamIndex: 2},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ExpectedCode: `
|
||||
func (r *UserRepositoryMongo) UpdateByID(arg0 context.Context, arg1 *UserModel, arg2 primitive.ObjectID) (bool, error) {
|
||||
result, err := r.collection.UpdateOne(arg0, bson.M{
|
||||
"_id": arg2,
|
||||
}, bson.M{
|
||||
"$set": arg1,
|
||||
})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return result.MatchedCount > 0, err
|
||||
}
|
||||
`,
|
||||
},
|
||||
{
|
||||
Name: "simple update one method",
|
||||
MethodSpec: spec.MethodSpec{
|
||||
|
@ -726,7 +763,7 @@ func TestGenerateMethod_Update(t *testing.T) {
|
|||
code.SimpleType("error"),
|
||||
},
|
||||
Operation: spec.UpdateOperation{
|
||||
Fields: []spec.UpdateField{
|
||||
Update: spec.UpdateFields{
|
||||
{Name: "Age", ParamIndex: 1},
|
||||
},
|
||||
Mode: spec.QueryModeOne,
|
||||
|
@ -767,7 +804,7 @@ func (r *UserRepositoryMongo) UpdateAgeByID(arg0 context.Context, arg1 int, arg2
|
|||
code.SimpleType("error"),
|
||||
},
|
||||
Operation: spec.UpdateOperation{
|
||||
Fields: []spec.UpdateField{
|
||||
Update: spec.UpdateFields{
|
||||
{Name: "Age", ParamIndex: 1},
|
||||
},
|
||||
Mode: spec.QueryModeMany,
|
||||
|
@ -1629,7 +1666,7 @@ func TestGenerateMethod_Invalid(t *testing.T) {
|
|||
code.SimpleType("error"),
|
||||
},
|
||||
Operation: spec.UpdateOperation{
|
||||
Fields: []spec.UpdateField{
|
||||
Update: spec.UpdateFields{
|
||||
{Name: "AccessToken", ParamIndex: 1},
|
||||
},
|
||||
Mode: spec.QueryModeOne,
|
||||
|
@ -1642,6 +1679,31 @@ func TestGenerateMethod_Invalid(t *testing.T) {
|
|||
},
|
||||
ExpectedError: mongo.NewBsonTagNotFoundError("AccessToken"),
|
||||
},
|
||||
{
|
||||
Name: "update type not supported",
|
||||
Method: spec.MethodSpec{
|
||||
Name: "UpdateAgeByID",
|
||||
Params: []code.Param{
|
||||
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||||
{Type: code.SimpleType("int")},
|
||||
{Type: code.ExternalType{PackageAlias: "primitive", Name: "ObjectID"}},
|
||||
},
|
||||
Returns: []code.Type{
|
||||
code.SimpleType("bool"),
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
Operation: spec.UpdateOperation{
|
||||
Update: StubUpdate{},
|
||||
Mode: spec.QueryModeOne,
|
||||
Query: spec.QuerySpec{
|
||||
Predicates: []spec.Predicate{
|
||||
{Field: "ID", Comparator: spec.ComparatorEqual, ParamIndex: 2},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ExpectedError: mongo.NewUpdateTypeNotSupportedError(StubUpdate{}),
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testTable {
|
||||
|
|
|
@ -12,6 +12,30 @@ type updateField struct {
|
|||
ParamIndex int
|
||||
}
|
||||
|
||||
type update interface {
|
||||
Code() string
|
||||
}
|
||||
|
||||
type updateModel struct {
|
||||
}
|
||||
|
||||
func (u updateModel) Code() string {
|
||||
return ` "$set": arg1,`
|
||||
}
|
||||
|
||||
type updateFields struct {
|
||||
Fields []updateField
|
||||
}
|
||||
|
||||
func (u updateFields) Code() string {
|
||||
lines := []string{` "$set": bson.M{`}
|
||||
for _, field := range u.Fields {
|
||||
lines = append(lines, fmt.Sprintf(` "%s": arg%d,`, field.BsonTag, field.ParamIndex))
|
||||
}
|
||||
lines = append(lines, ` },`)
|
||||
return strings.Join(lines, "\n")
|
||||
}
|
||||
|
||||
type querySpec struct {
|
||||
Operator spec.Operator
|
||||
Predicates []predicate
|
||||
|
|
|
@ -112,16 +112,14 @@ const findManyTemplate = ` cursor, err := r.collection.Find(arg0, bson.M{
|
|||
return entities, nil`
|
||||
|
||||
type mongoUpdateTemplateData struct {
|
||||
UpdateFields []updateField
|
||||
QuerySpec querySpec
|
||||
Update update
|
||||
QuerySpec querySpec
|
||||
}
|
||||
|
||||
const updateOneTemplate = ` result, err := r.collection.UpdateOne(arg0, bson.M{
|
||||
{{.QuerySpec.Code}}
|
||||
}, bson.M{
|
||||
"$set": bson.M{
|
||||
{{range $index, $element := .UpdateFields}} "{{$element.BsonTag}}": arg{{$element.ParamIndex}},
|
||||
{{end}} },
|
||||
{{.Update.Code}}
|
||||
})
|
||||
if err != nil {
|
||||
return false, err
|
||||
|
@ -131,9 +129,7 @@ const updateOneTemplate = ` result, err := r.collection.UpdateOne(arg0, bson.M{
|
|||
const updateManyTemplate = ` result, err := r.collection.UpdateMany(arg0, bson.M{
|
||||
{{.QuerySpec.Code}}
|
||||
}, bson.M{
|
||||
"$set": bson.M{
|
||||
{{range $index, $element := .UpdateFields}} "{{$element.BsonTag}}": arg{{$element.ParamIndex}},
|
||||
{{end}} },
|
||||
{{.Update.Code}}
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue