Add insert operation

This commit is contained in:
sunboyy 2021-02-01 21:39:20 +07:00
parent 7f07de08af
commit 25e1b2aa85
13 changed files with 509 additions and 38 deletions

View file

@ -9,14 +9,14 @@ func (err ParsingError) Error() string {
return "unknown operation"
case UnsupportedNameError:
return "method name is not supported"
case UnsupportedReturnError:
return "this type of return is not supported"
case InvalidQueryError:
return "invalid query"
case InvalidParamError:
return "parameters do not match the query"
case InvalidUpdateFieldsError:
return "update fields is invalid"
case UnsupportedReturnError:
return "this type of return is not supported"
case ContextParamRequiredError:
return "context parameter is required"
case StructFieldNotFoundError:
@ -29,10 +29,10 @@ func (err ParsingError) Error() string {
const (
UnknownOperationError ParsingError = "ERROR_UNKNOWN_OPERATION"
UnsupportedNameError ParsingError = "ERROR_UNSUPPORTED"
UnsupportedReturnError ParsingError = "ERROR_UNSUPPORTED_RETURN"
InvalidQueryError ParsingError = "ERROR_INVALID_QUERY"
InvalidParamError ParsingError = "ERROR_INVALID_PARAM"
InvalidUpdateFieldsError ParsingError = "ERROR_INVALID_UPDATE_FIELDS"
UnsupportedReturnError ParsingError = "ERROR_INVALID_RETURN"
ContextParamRequiredError ParsingError = "ERROR_CONTEXT_PARAM_REQUIRED"
StructFieldNotFoundError ParsingError = "ERROR_STRUCT_FIELD_NOT_FOUND"
)

View file

@ -27,6 +27,11 @@ type MethodSpec struct {
type Operation interface {
}
// InsertOperation is a method specification for insert operations
type InsertOperation struct {
Mode QueryMode
}
// FindOperation is a method specification for find operations
type FindOperation struct {
Mode QueryMode

View file

@ -23,6 +23,8 @@ type interfaceMethodParser struct {
func (p interfaceMethodParser) Parse() (MethodSpec, error) {
methodNameTokens := camelcase.Split(p.Method.Name)
switch methodNameTokens[0] {
case "Insert":
return p.parseInsertMethod(methodNameTokens[1:])
case "Find":
return p.parseFindMethod(methodNameTokens[1:])
case "Update":
@ -33,6 +35,65 @@ func (p interfaceMethodParser) Parse() (MethodSpec, error) {
return MethodSpec{}, UnknownOperationError
}
func (p interfaceMethodParser) parseInsertMethod(tokens []string) (MethodSpec, error) {
mode, err := p.extractInsertReturns(p.Method.Returns)
if err != nil {
return MethodSpec{}, err
}
if err := p.validateContextParam(); err != nil {
return MethodSpec{}, err
}
pointerType := code.PointerType{ContainedType: p.StructModel.ReferencedType()}
if mode == QueryModeOne && p.Method.Params[1].Type != pointerType {
return MethodSpec{}, InvalidParamError
}
arrayType := code.ArrayType{ContainedType: pointerType}
if mode == QueryModeMany && p.Method.Params[1].Type != arrayType {
return MethodSpec{}, InvalidParamError
}
return MethodSpec{
Name: p.Method.Name,
Params: p.Method.Params,
Returns: p.Method.Returns,
Operation: InsertOperation{
Mode: mode,
},
}, nil
}
func (p interfaceMethodParser) extractInsertReturns(returns []code.Type) (QueryMode, error) {
if len(returns) != 2 {
return "", UnsupportedReturnError
}
if returns[1] != code.SimpleType("error") {
return "", UnsupportedReturnError
}
interfaceType, ok := returns[0].(code.InterfaceType)
if ok {
if len(interfaceType.Methods) != 0 {
return "", UnsupportedReturnError
}
return QueryModeOne, nil
}
arrayType, ok := returns[0].(code.ArrayType)
if ok {
interfaceType, ok := arrayType.ContainedType.(code.InterfaceType)
if !ok || len(interfaceType.Methods) != 0 {
return "", UnsupportedReturnError
}
return QueryModeMany, nil
}
return "", UnsupportedReturnError
}
func (p interfaceMethodParser) parseFindMethod(tokens []string) (MethodSpec, error) {
if len(tokens) == 0 {
return MethodSpec{}, UnsupportedNameError

View file

@ -40,6 +40,64 @@ type ParseInterfaceMethodTestCase struct {
ExpectedOperation spec.Operation
}
func TestParseInterfaceMethod_Insert(t *testing.T) {
testTable := []ParseInterfaceMethodTestCase{
{
Name: "InsertOne method",
Method: code.Method{
Name: "InsertOne",
Params: []code.Param{
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
{Type: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
},
Returns: []code.Type{
code.InterfaceType{},
code.SimpleType("error"),
},
},
ExpectedOperation: spec.InsertOperation{
Mode: spec.QueryModeOne,
},
},
{
Name: "InsertMany method",
Method: code.Method{
Name: "InsertMany",
Params: []code.Param{
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
{Type: code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}}},
},
Returns: []code.Type{
code.ArrayType{ContainedType: code.InterfaceType{}},
code.SimpleType("error"),
},
},
ExpectedOperation: spec.InsertOperation{
Mode: spec.QueryModeMany,
},
},
}
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)
}
expectedOutput := spec.MethodSpec{
Name: testCase.Method.Name,
Params: testCase.Method.Params,
Returns: testCase.Method.Returns,
Operation: testCase.ExpectedOperation,
}
if !reflect.DeepEqual(actualSpec, expectedOutput) {
t.Errorf("Expected = %v\nReceived = %v", expectedOutput, actualSpec)
}
})
}
}
func TestParseInterfaceMethod_Find(t *testing.T) {
testTable := []ParseInterfaceMethodTestCase{
{
@ -736,6 +794,114 @@ func TestParseInterfaceMethod_Invalid(t *testing.T) {
}
}
func TestParseInterfaceMethod_Insert_Invalid(t *testing.T) {
testTable := []ParseInterfaceMethodInvalidTestCase{
{
Name: "invalid number of returns",
Method: code.Method{
Name: "Insert",
Returns: []code.Type{
code.PointerType{ContainedType: code.SimpleType("UserModel")},
code.InterfaceType{},
code.SimpleType("error"),
},
},
ExpectedError: spec.UnsupportedReturnError,
},
{
Name: "unsupported return types from insert method",
Method: code.Method{
Name: "Insert",
Returns: []code.Type{
code.PointerType{ContainedType: code.SimpleType("UserModel")},
code.SimpleType("error"),
},
},
ExpectedError: spec.UnsupportedReturnError,
},
{
Name: "unempty interface return from insert method",
Method: code.Method{
Name: "Insert",
Returns: []code.Type{
code.InterfaceType{
Methods: []code.Method{
{Name: "DoSomething"},
},
},
code.SimpleType("error"),
},
},
ExpectedError: spec.UnsupportedReturnError,
},
{
Name: "error return not provided",
Method: code.Method{
Name: "Insert",
Returns: []code.Type{
code.PointerType{ContainedType: code.SimpleType("UserModel")},
code.InterfaceType{},
},
},
ExpectedError: spec.UnsupportedReturnError,
},
{
Name: "no context parameter",
Method: code.Method{
Name: "Insert",
Params: []code.Param{
{Name: "userModel", Type: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
},
Returns: []code.Type{
code.InterfaceType{},
code.SimpleType("error"),
},
},
ExpectedError: spec.ContextParamRequiredError,
},
{
Name: "mismatched model parameter for one mode",
Method: code.Method{
Name: "Insert",
Params: []code.Param{
{Name: "ctx", Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
{Name: "userModel", Type: code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}}},
},
Returns: []code.Type{
code.InterfaceType{},
code.SimpleType("error"),
},
},
ExpectedError: spec.InvalidParamError,
},
{
Name: "mismatched model parameter for many mode",
Method: code.Method{
Name: "Insert",
Params: []code.Param{
{Name: "ctx", Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
{Name: "userModel", Type: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
},
Returns: []code.Type{
code.ArrayType{ContainedType: code.InterfaceType{}},
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)
}
})
}
}
func TestParseInterfaceMethod_Find_Invalid(t *testing.T) {
testTable := []ParseInterfaceMethodInvalidTestCase{
{
@ -758,7 +924,7 @@ func TestParseInterfaceMethod_Find_Invalid(t *testing.T) {
ExpectedError: spec.UnsupportedReturnError,
},
{
Name: "unsupported return values from find method",
Name: "unsupported return types from find method",
Method: code.Method{
Name: "FindOneByID",
Returns: []code.Type{
@ -933,7 +1099,7 @@ func TestParseInterfaceMethod_Update_Invalid(t *testing.T) {
ExpectedError: spec.UnsupportedReturnError,
},
{
Name: "unsupported return values from find method",
Name: "unsupported return types from update method",
Method: code.Method{
Name: "UpdateAgeByID",
Returns: []code.Type{
@ -1085,7 +1251,7 @@ func TestParseInterfaceMethod_Delete_Invalid(t *testing.T) {
ExpectedError: spec.UnsupportedReturnError,
},
{
Name: "unsupported return values from find method",
Name: "unsupported return types from delete method",
Method: code.Method{
Name: "DeleteOneByID",
Returns: []code.Type{