390 lines
10 KiB
Go
390 lines
10 KiB
Go
|
package mongo_test
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"reflect"
|
||
|
"testing"
|
||
|
|
||
|
"github.com/sunboyy/repogen/internal/code"
|
||
|
"github.com/sunboyy/repogen/internal/codegen"
|
||
|
"github.com/sunboyy/repogen/internal/mongo"
|
||
|
"github.com/sunboyy/repogen/internal/spec"
|
||
|
"github.com/sunboyy/repogen/internal/testutils"
|
||
|
)
|
||
|
|
||
|
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.TypeBool,
|
||
|
code.TypeError,
|
||
|
},
|
||
|
Operation: spec.UpdateOperation{
|
||
|
Update: spec.UpdateModel{},
|
||
|
Mode: spec.QueryModeOne,
|
||
|
Query: spec.QuerySpec{
|
||
|
Predicates: []spec.Predicate{
|
||
|
{
|
||
|
FieldReference: spec.FieldReference{idField},
|
||
|
Comparator: spec.ComparatorEqual,
|
||
|
ParamIndex: 2,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
ExpectedBody: ` result, err := r.collection.UpdateOne(arg0, bson.M{
|
||
|
"_id": arg2,
|
||
|
}, bson.M{
|
||
|
"$set": arg1,
|
||
|
})
|
||
|
if err != nil {
|
||
|
return false, err
|
||
|
}
|
||
|
return result.MatchedCount > 0, nil`,
|
||
|
},
|
||
|
{
|
||
|
Name: "simple update one method",
|
||
|
MethodSpec: spec.MethodSpec{
|
||
|
Name: "UpdateAgeByID",
|
||
|
Params: []code.Param{
|
||
|
{Name: "ctx", Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||
|
{Name: "age", Type: code.TypeInt},
|
||
|
{Name: "id", Type: code.ExternalType{PackageAlias: "primitive", Name: "ObjectID"}},
|
||
|
},
|
||
|
Returns: []code.Type{
|
||
|
code.TypeBool,
|
||
|
code.TypeError,
|
||
|
},
|
||
|
Operation: spec.UpdateOperation{
|
||
|
Update: spec.UpdateFields{
|
||
|
spec.UpdateField{
|
||
|
FieldReference: spec.FieldReference{ageField},
|
||
|
ParamIndex: 1,
|
||
|
Operator: spec.UpdateOperatorSet,
|
||
|
},
|
||
|
},
|
||
|
Mode: spec.QueryModeOne,
|
||
|
Query: spec.QuerySpec{
|
||
|
Predicates: []spec.Predicate{
|
||
|
{
|
||
|
FieldReference: spec.FieldReference{idField},
|
||
|
Comparator: spec.ComparatorEqual,
|
||
|
ParamIndex: 2,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
ExpectedBody: ` result, err := r.collection.UpdateOne(arg0, bson.M{
|
||
|
"_id": arg2,
|
||
|
}, bson.M{
|
||
|
"$set": bson.M{
|
||
|
"age": arg1,
|
||
|
},
|
||
|
})
|
||
|
if err != nil {
|
||
|
return false, err
|
||
|
}
|
||
|
return result.MatchedCount > 0, nil`,
|
||
|
},
|
||
|
{
|
||
|
Name: "simple update many method",
|
||
|
MethodSpec: spec.MethodSpec{
|
||
|
Name: "UpdateAgeByGender",
|
||
|
Params: []code.Param{
|
||
|
{Name: "ctx", Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||
|
{Name: "age", Type: code.TypeInt},
|
||
|
{Name: "gender", Type: code.SimpleType("Gender")},
|
||
|
},
|
||
|
Returns: []code.Type{
|
||
|
code.TypeInt,
|
||
|
code.TypeError,
|
||
|
},
|
||
|
Operation: spec.UpdateOperation{
|
||
|
Update: spec.UpdateFields{
|
||
|
spec.UpdateField{
|
||
|
FieldReference: spec.FieldReference{ageField},
|
||
|
ParamIndex: 1,
|
||
|
Operator: spec.UpdateOperatorSet,
|
||
|
},
|
||
|
},
|
||
|
Mode: spec.QueryModeMany,
|
||
|
Query: spec.QuerySpec{
|
||
|
Predicates: []spec.Predicate{
|
||
|
{
|
||
|
FieldReference: spec.FieldReference{genderField},
|
||
|
Comparator: spec.ComparatorEqual,
|
||
|
ParamIndex: 2,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
ExpectedBody: ` result, err := r.collection.UpdateMany(arg0, bson.M{
|
||
|
"gender": arg2,
|
||
|
}, bson.M{
|
||
|
"$set": bson.M{
|
||
|
"age": arg1,
|
||
|
},
|
||
|
})
|
||
|
if err != nil {
|
||
|
return 0, err
|
||
|
}
|
||
|
return int(result.MatchedCount), nil`,
|
||
|
},
|
||
|
{
|
||
|
Name: "simple update push method",
|
||
|
MethodSpec: spec.MethodSpec{
|
||
|
Name: "UpdateConsentHistoryPushByID",
|
||
|
Params: []code.Param{
|
||
|
{Name: "ctx", Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||
|
{Name: "consentHistory", Type: code.SimpleType("ConsentHistory")},
|
||
|
{Name: "id", Type: code.ExternalType{PackageAlias: "primitive", Name: "ObjectID"}},
|
||
|
},
|
||
|
Returns: []code.Type{
|
||
|
code.TypeBool,
|
||
|
code.TypeError,
|
||
|
},
|
||
|
Operation: spec.UpdateOperation{
|
||
|
Update: spec.UpdateFields{
|
||
|
spec.UpdateField{
|
||
|
FieldReference: spec.FieldReference{consentHistoryField},
|
||
|
ParamIndex: 1,
|
||
|
Operator: spec.UpdateOperatorPush,
|
||
|
},
|
||
|
},
|
||
|
Mode: spec.QueryModeOne,
|
||
|
Query: spec.QuerySpec{
|
||
|
Predicates: []spec.Predicate{
|
||
|
{
|
||
|
FieldReference: spec.FieldReference{idField},
|
||
|
Comparator: spec.ComparatorEqual,
|
||
|
ParamIndex: 2,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
ExpectedBody: ` result, err := r.collection.UpdateOne(arg0, bson.M{
|
||
|
"_id": arg2,
|
||
|
}, bson.M{
|
||
|
"$push": bson.M{
|
||
|
"consent_history": arg1,
|
||
|
},
|
||
|
})
|
||
|
if err != nil {
|
||
|
return false, err
|
||
|
}
|
||
|
return result.MatchedCount > 0, nil`,
|
||
|
},
|
||
|
{
|
||
|
Name: "simple update inc method",
|
||
|
MethodSpec: spec.MethodSpec{
|
||
|
Name: "UpdateAgeIncByID",
|
||
|
Params: []code.Param{
|
||
|
{Name: "ctx", Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||
|
{Name: "age", Type: code.TypeInt},
|
||
|
{Name: "id", Type: code.ExternalType{PackageAlias: "primitive", Name: "ObjectID"}},
|
||
|
},
|
||
|
Returns: []code.Type{
|
||
|
code.TypeBool,
|
||
|
code.TypeError,
|
||
|
},
|
||
|
Operation: spec.UpdateOperation{
|
||
|
Update: spec.UpdateFields{
|
||
|
spec.UpdateField{
|
||
|
FieldReference: spec.FieldReference{ageField},
|
||
|
ParamIndex: 1,
|
||
|
Operator: spec.UpdateOperatorInc,
|
||
|
},
|
||
|
},
|
||
|
Mode: spec.QueryModeOne,
|
||
|
Query: spec.QuerySpec{
|
||
|
Predicates: []spec.Predicate{
|
||
|
{
|
||
|
FieldReference: spec.FieldReference{idField},
|
||
|
Comparator: spec.ComparatorEqual,
|
||
|
ParamIndex: 2,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
ExpectedBody: ` result, err := r.collection.UpdateOne(arg0, bson.M{
|
||
|
"_id": arg2,
|
||
|
}, bson.M{
|
||
|
"$inc": bson.M{
|
||
|
"age": arg1,
|
||
|
},
|
||
|
})
|
||
|
if err != nil {
|
||
|
return false, err
|
||
|
}
|
||
|
return result.MatchedCount > 0, nil`,
|
||
|
},
|
||
|
{
|
||
|
Name: "simple update set and push method",
|
||
|
MethodSpec: spec.MethodSpec{
|
||
|
Name: "UpdateEnabledAndConsentHistoryPushByID",
|
||
|
Params: []code.Param{
|
||
|
{Name: "ctx", Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||
|
{Name: "enabled", Type: code.TypeBool},
|
||
|
{Name: "consentHistory", Type: code.SimpleType("ConsentHistory")},
|
||
|
{Name: "gender", Type: code.ExternalType{PackageAlias: "primitive", Name: "ObjectID"}},
|
||
|
},
|
||
|
Returns: []code.Type{
|
||
|
code.TypeBool,
|
||
|
code.TypeError,
|
||
|
},
|
||
|
Operation: spec.UpdateOperation{
|
||
|
Update: spec.UpdateFields{
|
||
|
spec.UpdateField{
|
||
|
FieldReference: spec.FieldReference{enabledField},
|
||
|
ParamIndex: 1,
|
||
|
Operator: spec.UpdateOperatorSet,
|
||
|
},
|
||
|
spec.UpdateField{
|
||
|
FieldReference: spec.FieldReference{consentHistoryField},
|
||
|
ParamIndex: 2,
|
||
|
Operator: spec.UpdateOperatorPush,
|
||
|
},
|
||
|
},
|
||
|
Mode: spec.QueryModeOne,
|
||
|
Query: spec.QuerySpec{
|
||
|
Predicates: []spec.Predicate{
|
||
|
{
|
||
|
FieldReference: spec.FieldReference{idField},
|
||
|
Comparator: spec.ComparatorEqual,
|
||
|
ParamIndex: 3,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
ExpectedBody: ` result, err := r.collection.UpdateOne(arg0, bson.M{
|
||
|
"_id": arg3,
|
||
|
}, bson.M{
|
||
|
"$push": bson.M{
|
||
|
"consent_history": arg2,
|
||
|
},
|
||
|
"$set": bson.M{
|
||
|
"enabled": arg1,
|
||
|
},
|
||
|
})
|
||
|
if err != nil {
|
||
|
return false, err
|
||
|
}
|
||
|
return result.MatchedCount > 0, nil`,
|
||
|
},
|
||
|
{
|
||
|
Name: "update with deeply referenced field",
|
||
|
MethodSpec: spec.MethodSpec{
|
||
|
Name: "UpdateNameFirstByID",
|
||
|
Params: []code.Param{
|
||
|
{Name: "ctx", Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
||
|
{Name: "firstName", Type: code.TypeString},
|
||
|
{Name: "id", Type: code.ExternalType{PackageAlias: "primitive", Name: "ObjectID"}},
|
||
|
},
|
||
|
Returns: []code.Type{
|
||
|
code.TypeBool,
|
||
|
code.TypeError,
|
||
|
},
|
||
|
Operation: spec.UpdateOperation{
|
||
|
Update: spec.UpdateFields{
|
||
|
spec.UpdateField{
|
||
|
FieldReference: spec.FieldReference{nameField, firstNameField},
|
||
|
ParamIndex: 1,
|
||
|
Operator: spec.UpdateOperatorSet,
|
||
|
},
|
||
|
},
|
||
|
Mode: spec.QueryModeOne,
|
||
|
Query: spec.QuerySpec{
|
||
|
Predicates: []spec.Predicate{
|
||
|
{
|
||
|
FieldReference: spec.FieldReference{idField},
|
||
|
Comparator: spec.ComparatorEqual,
|
||
|
ParamIndex: 2,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
ExpectedBody: ` result, err := r.collection.UpdateOne(arg0, bson.M{
|
||
|
"_id": arg2,
|
||
|
}, bson.M{
|
||
|
"$set": bson.M{
|
||
|
"name.first": arg1,
|
||
|
},
|
||
|
})
|
||
|
if err != nil {
|
||
|
return false, err
|
||
|
}
|
||
|
return result.MatchedCount > 0, nil`,
|
||
|
},
|
||
|
}
|
||
|
|
||
|
for _, testCase := range testTable {
|
||
|
t.Run(testCase.Name, func(t *testing.T) {
|
||
|
generator := mongo.NewGenerator(userModel, "UserRepository")
|
||
|
expectedReceiver := codegen.MethodReceiver{
|
||
|
Name: "r",
|
||
|
Type: "UserRepositoryMongo",
|
||
|
Pointer: true,
|
||
|
}
|
||
|
var expectedParams []code.Param
|
||
|
for i, param := range testCase.MethodSpec.Params {
|
||
|
expectedParams = append(expectedParams, code.Param{
|
||
|
Name: fmt.Sprintf("arg%d", i),
|
||
|
Type: param.Type,
|
||
|
})
|
||
|
}
|
||
|
|
||
|
actual, err := generator.GenerateMethod(testCase.MethodSpec)
|
||
|
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
if expectedReceiver != actual.Receiver {
|
||
|
t.Errorf(
|
||
|
"incorrect method receiver: expected %+v, got %+v",
|
||
|
expectedReceiver,
|
||
|
actual.Receiver,
|
||
|
)
|
||
|
}
|
||
|
if testCase.MethodSpec.Name != actual.Name {
|
||
|
t.Errorf(
|
||
|
"incorrect method name: expected %s, got %s",
|
||
|
testCase.MethodSpec.Name,
|
||
|
actual.Name,
|
||
|
)
|
||
|
}
|
||
|
if !reflect.DeepEqual(expectedParams, actual.Params) {
|
||
|
t.Errorf(
|
||
|
"incorrect struct params: expected %+v, got %+v",
|
||
|
expectedParams,
|
||
|
actual.Params,
|
||
|
)
|
||
|
}
|
||
|
if !reflect.DeepEqual(testCase.MethodSpec.Returns, actual.Returns) {
|
||
|
t.Errorf(
|
||
|
"incorrect struct returns: expected %+v, got %+v",
|
||
|
testCase.MethodSpec.Returns,
|
||
|
actual.Returns,
|
||
|
)
|
||
|
}
|
||
|
if err := testutils.ExpectMultiLineString(testCase.ExpectedBody, actual.Body.Code()); err != nil {
|
||
|
t.Error(err)
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
}
|