in pkg/data-query/parser.go [210:279]
func readFilters(list []*fastjson.Value, query *Query) error {
for _, v := range list {
t := QueryFilter{
Field: string(v.GetStringBytes("f")),
Sql: string(v.GetStringBytes("q")),
Operator: string(v.GetStringBytes("o")),
Split: false,
}
if t.Sql == "" {
t.Sql = string(v.GetStringBytes("sql"))
}
value := v.Get("v")
t.Split = v.GetBool("s")
if value == nil {
value = v.Get("value")
}
if !isValidFilterFieldName(t.Field) && t.Sql == "" {
return http_error.NewHttpError(400, t.Field+" is not a valid filter field name")
}
if t.Sql == "" && value == nil {
return errors.New("filter value is not specified")
}
if t.Sql == "" {
switch value.Type() {
case fastjson.TypeString:
t.Value = string(value.GetStringBytes())
case fastjson.TypeNumber:
number, err := value.Float64()
if err != nil {
return fmt.Errorf("cannot parse filter value %s: %w", value, err)
}
if number == math.Trunc(number) {
// convert to int (to be able to use time unix timestamps from client side)
t.Value = int(number)
} else {
t.Value = number
}
case fastjson.TypeArray:
t.Value = readArray(value)
case fastjson.TypeFalse:
t.Value = value.GetBool()
case fastjson.TypeTrue:
t.Value = value.GetBool()
default:
return fmt.Errorf("filter value %v is not supported", value)
}
if t.Operator == "" {
t.Operator = "="
} else if t.Operator != ">" && t.Operator != "<" && t.Operator != "=" && t.Operator != "!=" && t.Operator != "like" {
return fmt.Errorf("operator %s is not supported", t.Operator)
}
} else {
// by intention sql string is not validated
if t.Operator != "" {
return http_error.NewHttpError(400, fmt.Sprintf("sql and operator are mutually exclusive (filter=%s)", t.Field))
}
if t.Value != nil {
return http_error.NewHttpError(400, fmt.Sprintf("sql and value are mutually exclusive (filter=%s)", t.Field))
}
}
query.Filters = append(query.Filters, t)
}
return nil
}