Implement FindTopN to limit number of results in find many operations ()

This commit is contained in:
sunboyy 2023-05-21 22:34:30 +07:00 committed by GitHub
parent 021de6214c
commit d2338b8f46
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 162 additions and 9 deletions

View file

@ -14,6 +14,9 @@ var (
ErrInvalidParam = errors.New("spec: parameters do not match the query")
ErrInvalidUpdateFields = errors.New("spec: update fields are invalid")
ErrContextParamRequired = errors.New("spec: context parameter is required")
ErrLimitAmountRequired = errors.New("spec: limit amount is required")
ErrLimitNonPositive = errors.New("spec: limit value must be positive")
ErrLimitOnFindOne = errors.New("spec: cannot specify limit on find one")
)
// NewUnsupportedReturnError creates unsupportedReturnError

View file

@ -41,6 +41,7 @@ type FindOperation struct {
Mode QueryMode
Query QuerySpec
Sorts []Sort
Limit int
}
// Name returns "Find" operation name

View file

@ -1,6 +1,8 @@
package spec
import (
"strconv"
"github.com/fatih/camelcase"
"github.com/sunboyy/repogen/internal/code"
)
@ -114,6 +116,14 @@ func (p interfaceMethodParser) parseFindOperation(tokens []string) (Operation, e
return nil, err
}
limit, tokens, err := p.parseFindTop(tokens)
if err != nil {
return nil, err
}
if mode == QueryModeOne && limit != 0 {
return nil, ErrLimitOnFindOne
}
queryTokens, sortTokens := p.splitQueryAndSortTokens(tokens)
querySpec, err := p.parseQuery(queryTokens, 1)
@ -138,9 +148,32 @@ func (p interfaceMethodParser) parseFindOperation(tokens []string) (Operation, e
Mode: mode,
Query: querySpec,
Sorts: sorts,
Limit: limit,
}, nil
}
func (p interfaceMethodParser) parseFindTop(tokens []string) (int, []string,
error) {
if len(tokens) >= 1 && tokens[0] == "Top" {
if len(tokens) < 2 {
return 0, nil, ErrLimitAmountRequired
}
limit, err := strconv.Atoi(tokens[1])
if err != nil {
return 0, nil, ErrLimitAmountRequired
}
if limit <= 0 {
return 0, nil, ErrLimitNonPositive
}
return limit, tokens[2:], nil
}
return 0, tokens, nil
}
func (p interfaceMethodParser) parseSort(rawTokens []string) ([]Sort, error) {
if len(rawTokens) == 0 {
return nil, nil

View file

@ -745,6 +745,30 @@ func TestParseInterfaceMethod_Find(t *testing.T) {
},
},
},
{
Name: "FindTopNByArg method",
Method: code.Method{
Name: "FindTop5ByGenderOrderByAgeDesc",
Params: []code.Param{
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
{Type: code.SimpleType("Gender")},
},
Returns: []code.Type{
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
code.TypeError,
},
},
ExpectedOperation: spec.FindOperation{
Mode: spec.QueryModeMany,
Query: spec.QuerySpec{Predicates: []spec.Predicate{
{FieldReference: spec.FieldReference{genderField}, Comparator: spec.ComparatorEqual, ParamIndex: 1},
}},
Sorts: []spec.Sort{
{FieldReference: spec.FieldReference{ageField}, Ordering: spec.OrderingDescending},
},
Limit: 5,
},
},
}
for _, testCase := range testTable {
@ -1603,6 +1627,50 @@ func TestParseInterfaceMethod_Find_Invalid(t *testing.T) {
},
ExpectedError: spec.NewUnsupportedReturnError(code.TypeInt, 1),
},
{
Name: "find method with Top keyword but no number and query",
Method: code.Method{
Name: "FindTop",
Returns: []code.Type{
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
code.TypeError,
},
},
ExpectedError: spec.ErrLimitAmountRequired,
},
{
Name: "find method with Top keyword but no number",
Method: code.Method{
Name: "FindTopAll",
Returns: []code.Type{
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
code.TypeError,
},
},
ExpectedError: spec.ErrLimitAmountRequired,
},
{
Name: "find method with TopN keyword where N is not positive",
Method: code.Method{
Name: "FindTop0All",
Returns: []code.Type{
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
code.TypeError,
},
},
ExpectedError: spec.ErrLimitNonPositive,
},
{
Name: "find one method with TopN keyword",
Method: code.Method{
Name: "FindTop5All",
Returns: []code.Type{
code.PointerType{ContainedType: code.SimpleType("UserModel")},
code.TypeError,
},
},
ExpectedError: spec.ErrLimitOnFindOne,
},
{
Name: "find method without query",
Method: code.Method{