Add Or operator

This commit is contained in:
sunboyy 2021-01-19 19:35:54 +07:00
parent bc878c778c
commit 153deb8f7d
8 changed files with 178 additions and 47 deletions

View file

@ -41,6 +41,7 @@ type FindOperation struct {
// QuerySpec is a set of conditions of querying the database
type QuerySpec struct {
Operator Operator
Predicates []Predicate
}
@ -49,42 +50,51 @@ func (q QuerySpec) NumberOfArguments() int {
return len(q.Predicates)
}
// Operator is an operator of the condition to query the data
// Operator is a boolean operator for merging conditions
type Operator string
// operator constants
// boolean operator types
const (
OperatorEqual Operator = "EQUAL"
OperatorNot Operator = "NOT"
OperatorLessThan Operator = "LESS_THAN"
OperatorLessThanEqual Operator = "LESS_THAN_EQUAL"
OperatorGreaterThan Operator = "GREATER_THAN"
OperatorGreaterThanEqual Operator = "GREATER_THAN_EQUAL"
OperatorAnd Operator = "AND"
OperatorOr Operator = "OR"
)
// Comparator is a comparison operator of the condition to query the data
type Comparator string
// comparator types
const (
ComparatorNot Comparator = "NOT"
ComparatorEqual Comparator = "EQUAL"
ComparatorLessThan Comparator = "LESS_THAN"
ComparatorLessThanEqual Comparator = "LESS_THAN_EQUAL"
ComparatorGreaterThan Comparator = "GREATER_THAN"
ComparatorGreaterThanEqual Comparator = "GREATER_THAN_EQUAL"
)
// Predicate is a criteria for querying a field
type Predicate struct {
Field string
Operator Operator
Field string
Comparator Comparator
}
type predicateToken []string
func (t predicateToken) ToPredicate() Predicate {
if len(t) > 1 && t[len(t)-1] == "Not" {
return Predicate{Field: strings.Join(t[:len(t)-1], ""), Operator: OperatorNot}
return Predicate{Field: strings.Join(t[:len(t)-1], ""), Comparator: ComparatorNot}
}
if len(t) > 2 && t[len(t)-2] == "Less" && t[len(t)-1] == "Than" {
return Predicate{Field: strings.Join(t[:len(t)-2], ""), Operator: OperatorLessThan}
return Predicate{Field: strings.Join(t[:len(t)-2], ""), Comparator: ComparatorLessThan}
}
if len(t) > 3 && t[len(t)-3] == "Less" && t[len(t)-2] == "Than" && t[len(t)-1] == "Equal" {
return Predicate{Field: strings.Join(t[:len(t)-3], ""), Operator: OperatorLessThanEqual}
return Predicate{Field: strings.Join(t[:len(t)-3], ""), Comparator: ComparatorLessThanEqual}
}
if len(t) > 2 && t[len(t)-2] == "Greater" && t[len(t)-1] == "Than" {
return Predicate{Field: strings.Join(t[:len(t)-2], ""), Operator: OperatorGreaterThan}
return Predicate{Field: strings.Join(t[:len(t)-2], ""), Comparator: ComparatorGreaterThan}
}
if len(t) > 3 && t[len(t)-3] == "Greater" && t[len(t)-2] == "Than" && t[len(t)-1] == "Equal" {
return Predicate{Field: strings.Join(t[:len(t)-3], ""), Operator: OperatorGreaterThanEqual}
return Predicate{Field: strings.Join(t[:len(t)-3], ""), Comparator: ComparatorGreaterThanEqual}
}
return Predicate{Field: strings.Join(t, ""), Operator: OperatorEqual}
return Predicate{Field: strings.Join(t, ""), Comparator: ComparatorEqual}
}

View file

@ -127,18 +127,26 @@ func (p repositoryInterfaceParser) parseQuery(tokens []string) (QuerySpec, error
tokens = tokens[1:]
}
if tokens[0] == "And" {
if tokens[0] == "And" || tokens[0] == "Or" {
return QuerySpec{}, errors.New("method name not supported")
}
var operator Operator
var predicates []Predicate
var aggregatedToken predicateToken
for _, token := range tokens {
if token != "And" {
if token != "And" && token != "Or" {
aggregatedToken = append(aggregatedToken, token)
} else {
} else if token == "And" && operator != OperatorOr {
operator = OperatorAnd
predicates = append(predicates, aggregatedToken.ToPredicate())
aggregatedToken = predicateToken{}
} else if token == "Or" && operator != OperatorAnd {
operator = OperatorOr
predicates = append(predicates, aggregatedToken.ToPredicate())
aggregatedToken = predicateToken{}
} else {
return QuerySpec{}, errors.New("method name contains ambiguous query")
}
}
if len(aggregatedToken) == 0 {
@ -146,5 +154,5 @@ func (p repositoryInterfaceParser) parseQuery(tokens []string) (QuerySpec, error
}
predicates = append(predicates, aggregatedToken.ToPredicate())
return QuerySpec{Predicates: predicates}, nil
return QuerySpec{Operator: operator, Predicates: predicates}, nil
}

View file

@ -59,7 +59,7 @@ func TestParseRepositoryInterface(t *testing.T) {
Operation: spec.FindOperation{
Mode: spec.QueryModeOne,
Query: spec.QuerySpec{Predicates: []spec.Predicate{
{Field: "ID", Operator: spec.OperatorEqual},
{Field: "ID", Comparator: spec.ComparatorEqual},
}},
},
},
@ -100,7 +100,7 @@ func TestParseRepositoryInterface(t *testing.T) {
Operation: spec.FindOperation{
Mode: spec.QueryModeOne,
Query: spec.QuerySpec{Predicates: []spec.Predicate{
{Field: "PhoneNumber", Operator: spec.OperatorEqual},
{Field: "PhoneNumber", Comparator: spec.ComparatorEqual},
}},
},
},
@ -141,7 +141,7 @@ func TestParseRepositoryInterface(t *testing.T) {
Operation: spec.FindOperation{
Mode: spec.QueryModeMany,
Query: spec.QuerySpec{Predicates: []spec.Predicate{
{Field: "City", Operator: spec.OperatorEqual},
{Field: "City", Comparator: spec.ComparatorEqual},
}},
},
},
@ -219,10 +219,60 @@ func TestParseRepositoryInterface(t *testing.T) {
},
Operation: spec.FindOperation{
Mode: spec.QueryModeMany,
Query: spec.QuerySpec{Predicates: []spec.Predicate{
{Field: "City", Operator: spec.OperatorEqual},
{Field: "Gender", Operator: spec.OperatorEqual},
}},
Query: spec.QuerySpec{
Operator: spec.OperatorAnd,
Predicates: []spec.Predicate{
{Field: "City", Comparator: spec.ComparatorEqual},
{Field: "Gender", Comparator: spec.ComparatorEqual},
},
},
},
},
},
},
},
{
Name: "FindByArgOrArg method",
Interface: code.Interface{
Name: "UserRepository",
Methods: []code.Method{
{
Name: "FindByCityOrGender",
Params: []code.Param{
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
{Type: code.SimpleType("string")},
{Type: code.SimpleType("Gender")},
},
Returns: []code.Type{
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
code.SimpleType("error"),
},
},
},
},
ExpectedOutput: spec.RepositorySpec{
InterfaceName: "UserRepository",
Methods: []spec.MethodSpec{
{
Name: "FindByCityOrGender",
Params: []code.Param{
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
{Type: code.SimpleType("string")},
{Type: code.SimpleType("Gender")},
},
Returns: []code.Type{
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
code.SimpleType("error"),
},
Operation: spec.FindOperation{
Mode: spec.QueryModeMany,
Query: spec.QuerySpec{
Operator: spec.OperatorOr,
Predicates: []spec.Predicate{
{Field: "City", Comparator: spec.ComparatorEqual},
{Field: "Gender", Comparator: spec.ComparatorEqual},
},
},
},
},
},
@ -262,7 +312,7 @@ func TestParseRepositoryInterface(t *testing.T) {
Operation: spec.FindOperation{
Mode: spec.QueryModeMany,
Query: spec.QuerySpec{Predicates: []spec.Predicate{
{Field: "City", Operator: spec.OperatorNot},
{Field: "City", Comparator: spec.ComparatorNot},
}},
},
},
@ -303,7 +353,7 @@ func TestParseRepositoryInterface(t *testing.T) {
Operation: spec.FindOperation{
Mode: spec.QueryModeMany,
Query: spec.QuerySpec{Predicates: []spec.Predicate{
{Field: "Age", Operator: spec.OperatorLessThan},
{Field: "Age", Comparator: spec.ComparatorLessThan},
}},
},
},
@ -344,7 +394,7 @@ func TestParseRepositoryInterface(t *testing.T) {
Operation: spec.FindOperation{
Mode: spec.QueryModeMany,
Query: spec.QuerySpec{Predicates: []spec.Predicate{
{Field: "Age", Operator: spec.OperatorLessThanEqual},
{Field: "Age", Comparator: spec.ComparatorLessThanEqual},
}},
},
},
@ -385,7 +435,7 @@ func TestParseRepositoryInterface(t *testing.T) {
Operation: spec.FindOperation{
Mode: spec.QueryModeMany,
Query: spec.QuerySpec{Predicates: []spec.Predicate{
{Field: "Age", Operator: spec.OperatorGreaterThan},
{Field: "Age", Comparator: spec.ComparatorGreaterThan},
}},
},
},
@ -426,7 +476,7 @@ func TestParseRepositoryInterface(t *testing.T) {
Operation: spec.FindOperation{
Mode: spec.QueryModeMany,
Query: spec.QuerySpec{Predicates: []spec.Predicate{
{Field: "Age", Operator: spec.OperatorGreaterThanEqual},
{Field: "Age", Comparator: spec.ComparatorGreaterThanEqual},
}},
},
},