Add functionality to sort in find operation
This commit is contained in:
parent
6c00fa860b
commit
962779ce40
10 changed files with 460 additions and 31 deletions
|
@ -48,6 +48,19 @@ func (err invalidQueryError) Error() string {
|
|||
return fmt.Sprintf("invalid query '%s'", err.QueryString)
|
||||
}
|
||||
|
||||
// NewInvalidSortError creates invalidSortError
|
||||
func NewInvalidSortError(sortTokens []string) error {
|
||||
return invalidSortError{SortString: strings.Join(sortTokens, "")}
|
||||
}
|
||||
|
||||
type invalidSortError struct {
|
||||
SortString string
|
||||
}
|
||||
|
||||
func (err invalidSortError) Error() string {
|
||||
return fmt.Sprintf("invalid sort '%s'", err.SortString)
|
||||
}
|
||||
|
||||
// NewUnknownOperationError creates unknownOperationError
|
||||
func NewUnknownOperationError(operationName string) error {
|
||||
return unknownOperationError{OperationName: operationName}
|
||||
|
|
|
@ -38,6 +38,11 @@ func TestError(t *testing.T) {
|
|||
}),
|
||||
ExpectedString: "cannot use comparator EQUAL_TRUE with struct field 'Age' of type 'int'",
|
||||
},
|
||||
{
|
||||
Name: "InvalidSortError",
|
||||
Error: spec.NewInvalidSortError([]string{"Order", "By"}),
|
||||
ExpectedString: "invalid sort 'OrderBy'",
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testTable {
|
||||
|
|
|
@ -40,6 +40,7 @@ func (o InsertOperation) Name() string {
|
|||
type FindOperation struct {
|
||||
Mode QueryMode
|
||||
Query QuerySpec
|
||||
Sorts []Sort
|
||||
}
|
||||
|
||||
// Name returns "Find" operation name
|
||||
|
@ -47,6 +48,21 @@ func (o FindOperation) Name() string {
|
|||
return "Find"
|
||||
}
|
||||
|
||||
// Sort is a detail of sorting find result
|
||||
type Sort struct {
|
||||
FieldName string
|
||||
Ordering Ordering
|
||||
}
|
||||
|
||||
// Ordering is a sort order
|
||||
type Ordering string
|
||||
|
||||
// Ordering constants
|
||||
const (
|
||||
OrderingAscending = "ASC"
|
||||
OrderingDescending = "DESC"
|
||||
)
|
||||
|
||||
// UpdateOperation is a method specification for update operations
|
||||
type UpdateOperation struct {
|
||||
Update Update
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package spec
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/fatih/camelcase"
|
||||
"github.com/sunboyy/repogen/internal/code"
|
||||
)
|
||||
|
@ -111,7 +113,14 @@ func (p interfaceMethodParser) parseFindOperation(tokens []string) (Operation, e
|
|||
return nil, err
|
||||
}
|
||||
|
||||
querySpec, err := parseQuery(tokens, 1)
|
||||
queryTokens, sortTokens := p.splitQueryAndSortTokens(tokens)
|
||||
|
||||
querySpec, err := parseQuery(queryTokens, 1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sorts, err := p.parseSort(sortTokens)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -127,9 +136,65 @@ func (p interfaceMethodParser) parseFindOperation(tokens []string) (Operation, e
|
|||
return FindOperation{
|
||||
Mode: mode,
|
||||
Query: querySpec,
|
||||
Sorts: sorts,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (p interfaceMethodParser) parseSort(rawTokens []string) ([]Sort, error) {
|
||||
if len(rawTokens) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
sortTokens := rawTokens[2:]
|
||||
|
||||
var sorts []Sort
|
||||
var aggregatedToken sortToken
|
||||
for _, token := range sortTokens {
|
||||
if token != "And" {
|
||||
aggregatedToken = append(aggregatedToken, token)
|
||||
} else if len(aggregatedToken) == 0 {
|
||||
return nil, NewInvalidSortError(rawTokens)
|
||||
} else {
|
||||
sorts = append(sorts, aggregatedToken.ToSort())
|
||||
aggregatedToken = sortToken{}
|
||||
}
|
||||
}
|
||||
if len(aggregatedToken) == 0 {
|
||||
return nil, NewInvalidSortError(rawTokens)
|
||||
}
|
||||
sorts = append(sorts, aggregatedToken.ToSort())
|
||||
|
||||
return sorts, nil
|
||||
}
|
||||
|
||||
type sortToken []string
|
||||
|
||||
func (t sortToken) ToSort() Sort {
|
||||
if len(t) > 1 && t[len(t)-1] == "Asc" {
|
||||
return Sort{FieldName: strings.Join(t[:len(t)-1], ""), Ordering: OrderingAscending}
|
||||
}
|
||||
if len(t) > 1 && t[len(t)-1] == "Desc" {
|
||||
return Sort{FieldName: strings.Join(t[:len(t)-1], ""), Ordering: OrderingDescending}
|
||||
}
|
||||
return Sort{FieldName: strings.Join(t, ""), Ordering: OrderingAscending}
|
||||
}
|
||||
|
||||
func (p interfaceMethodParser) splitQueryAndSortTokens(tokens []string) ([]string, []string) {
|
||||
var queryTokens []string
|
||||
var sortTokens []string
|
||||
|
||||
for i, token := range tokens {
|
||||
if len(tokens) > i && token == "Order" && tokens[i+1] == "By" {
|
||||
sortTokens = tokens[i:]
|
||||
break
|
||||
} else {
|
||||
queryTokens = append(queryTokens, token)
|
||||
}
|
||||
}
|
||||
|
||||
return queryTokens, sortTokens
|
||||
}
|
||||
|
||||
func (p interfaceMethodParser) extractModelOrSliceReturns(returns []code.Type) (QueryMode, error) {
|
||||
if len(returns) != 2 {
|
||||
return "", UnsupportedReturnError
|
||||
|
|
|
@ -429,6 +429,99 @@ func TestParseInterfaceMethod_Find(t *testing.T) {
|
|||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "FindByArgOrderByArg method",
|
||||
Method: code.Method{
|
||||
Name: "FindByCityOrderByAge",
|
||||
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"),
|
||||
},
|
||||
},
|
||||
ExpectedOperation: spec.FindOperation{
|
||||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
||||
{Field: "City", Comparator: spec.ComparatorEqual, ParamIndex: 1},
|
||||
}},
|
||||
Sorts: []spec.Sort{
|
||||
{FieldName: "Age", Ordering: spec.OrderingAscending},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "FindByArgOrderByArgAsc method",
|
||||
Method: code.Method{
|
||||
Name: "FindByCityOrderByAgeAsc",
|
||||
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"),
|
||||
},
|
||||
},
|
||||
ExpectedOperation: spec.FindOperation{
|
||||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
||||
{Field: "City", Comparator: spec.ComparatorEqual, ParamIndex: 1},
|
||||
}},
|
||||
Sorts: []spec.Sort{
|
||||
{FieldName: "Age", Ordering: spec.OrderingAscending},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "FindByArgOrderByArgDesc method",
|
||||
Method: code.Method{
|
||||
Name: "FindByCityOrderByAgeDesc",
|
||||
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"),
|
||||
},
|
||||
},
|
||||
ExpectedOperation: spec.FindOperation{
|
||||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
||||
{Field: "City", Comparator: spec.ComparatorEqual, ParamIndex: 1},
|
||||
}},
|
||||
Sorts: []spec.Sort{
|
||||
{FieldName: "Age", Ordering: spec.OrderingDescending},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "FindByArgOrderByArgAndArg method",
|
||||
Method: code.Method{
|
||||
Name: "FindByCityOrderByCityAndAgeDesc",
|
||||
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"),
|
||||
},
|
||||
},
|
||||
ExpectedOperation: spec.FindOperation{
|
||||
Mode: spec.QueryModeMany,
|
||||
Query: spec.QuerySpec{Predicates: []spec.Predicate{
|
||||
{Field: "City", Comparator: spec.ComparatorEqual, ParamIndex: 1},
|
||||
}},
|
||||
Sorts: []spec.Sort{
|
||||
{FieldName: "City", Ordering: spec.OrderingAscending},
|
||||
{FieldName: "Age", Ordering: spec.OrderingDescending},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testTable {
|
||||
|
@ -1248,6 +1341,39 @@ func TestParseInterfaceMethod_Find_Invalid(t *testing.T) {
|
|||
},
|
||||
ExpectedError: spec.InvalidParamError,
|
||||
},
|
||||
{
|
||||
Name: "misplaced operator token (leftmost)",
|
||||
Method: code.Method{
|
||||
Name: "FindAllOrderByAndAge",
|
||||
Returns: []code.Type{
|
||||
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
},
|
||||
ExpectedError: spec.NewInvalidSortError([]string{"Order", "By", "And", "Age"}),
|
||||
},
|
||||
{
|
||||
Name: "misplaced operator token (rightmost)",
|
||||
Method: code.Method{
|
||||
Name: "FindAllOrderByAgeAnd",
|
||||
Returns: []code.Type{
|
||||
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
},
|
||||
ExpectedError: spec.NewInvalidSortError([]string{"Order", "By", "Age", "And"}),
|
||||
},
|
||||
{
|
||||
Name: "misplaced operator token (double operator)",
|
||||
Method: code.Method{
|
||||
Name: "FindAllOrderByAgeAndAndGender",
|
||||
Returns: []code.Type{
|
||||
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
||||
code.SimpleType("error"),
|
||||
},
|
||||
},
|
||||
ExpectedError: spec.NewInvalidSortError([]string{"Order", "By", "Age", "And", "And", "Gender"}),
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testTable {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue