Multiple implementations of the same back-end application. The aim is to provide quick, side-by-side comparisons of different technologies (languages, frameworks, libraries) while preserving consistent business logic across all implementations.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

219 lines
3.9 KiB

package specifications
const (
GROUP_AND = "AND"
GROUP_OR = "OR"
GROUP_NOT = "NOT"
)
const (
OP_EQ = "="
OP_NEQ = "!="
OP_GT = ">"
OP_GTE = ">="
OP_LT = "<"
OP_LTE = "<="
OP_IN = "IN"
OP_NIN = "NOT IN"
)
type Condition struct {
Field string `json:"field"`
Operator string `json:"operator"`
Value interface{} `json:"value"`
}
type LogicalGroup struct {
Operator string `json:"operator"`
Conditions []Condition `json:"conditions"`
Spec *Spec `json:"spec"`
}
type Spec struct {
Condition *Condition `json:"condition,omitempty"`
LogicalGroup *LogicalGroup `json:"logicalGroup,omitempty"`
}
func And(conditions ...*Spec) *Spec {
if len(conditions) == 0 {
return nil
}
if len(conditions) == 1 {
return conditions[0]
}
var flatConditions []Condition
var nestedSpecs []*Spec
for _, spec := range conditions {
if spec.Condition != nil {
flatConditions = append(flatConditions, *spec.Condition)
} else {
nestedSpecs = append(nestedSpecs, spec)
}
}
result := &Spec{
LogicalGroup: &LogicalGroup{
Operator: GROUP_AND,
Conditions: flatConditions,
},
}
if len(nestedSpecs) == 1 {
result.LogicalGroup.Spec = nestedSpecs[0]
} else if len(nestedSpecs) > 1 {
result.LogicalGroup.Spec = And(nestedSpecs...)
}
return result
}
func Or(conditions ...*Spec) *Spec {
if len(conditions) == 0 {
return nil
}
if len(conditions) == 1 {
return conditions[0]
}
var flatConditions []Condition
var nestedSpecs []*Spec
for _, spec := range conditions {
if spec.Condition != nil {
flatConditions = append(flatConditions, *spec.Condition)
} else {
nestedSpecs = append(nestedSpecs, spec)
}
}
result := &Spec{
LogicalGroup: &LogicalGroup{
Operator: GROUP_OR,
Conditions: flatConditions,
},
}
if len(nestedSpecs) == 1 {
result.LogicalGroup.Spec = nestedSpecs[0]
} else if len(nestedSpecs) > 1 {
result.LogicalGroup.Spec = Or(nestedSpecs...)
}
return result
}
func Not(condition *Spec) *Spec {
return &Spec{
LogicalGroup: &LogicalGroup{
Operator: GROUP_NOT,
Spec: condition,
},
}
}
func Eq(field string, value interface{}) *Spec {
return &Spec{
Condition: &Condition{
Field: field,
Operator: OP_EQ,
Value: value,
},
}
}
func Neq(field string, value interface{}) *Spec {
return &Spec{
Condition: &Condition{
Field: field,
Operator: OP_NEQ,
Value: value,
},
}
}
func Gt(field string, value interface{}) *Spec {
return &Spec{
Condition: &Condition{
Field: field,
Operator: OP_GT,
Value: value,
},
}
}
func Gte(field string, value interface{}) *Spec {
return &Spec{
Condition: &Condition{
Field: field,
Operator: OP_GTE,
Value: value,
},
}
}
func Lt(field string, value interface{}) *Spec {
return &Spec{
Condition: &Condition{
Field: field,
Operator: OP_LT,
Value: value,
},
}
}
func Lte(field string, value interface{}) *Spec {
return &Spec{
Condition: &Condition{
Field: field,
Operator: OP_LTE,
Value: value,
},
}
}
func In(field string, values []interface{}) *Spec {
return &Spec{
Condition: &Condition{
Field: field,
Operator: OP_IN,
Value: values,
},
}
}
func Nin(field string, values []interface{}) *Spec {
return &Spec{
Condition: &Condition{
Field: field,
Operator: OP_NIN,
Value: values,
},
}
}
func GetConditions(spec *Spec) []Condition {
var conditions []Condition
flattenConditions(spec, &conditions)
return conditions
}
func flattenConditions(spec *Spec, conditions *[]Condition) {
if spec == nil {
return
}
if spec.Condition != nil {
*conditions = append(*conditions, *spec.Condition)
}
if spec.LogicalGroup != nil {
for _, cond := range spec.LogicalGroup.Conditions {
*conditions = append(*conditions, cond)
}
if spec.LogicalGroup.Spec != nil {
flattenConditions(spec.LogicalGroup.Spec, conditions)
}
}
}