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) } } }