forked from vikunja/vikunja
konrad
0ba121fdfb
Fix not returning errors Fix integration tests Add more tests Make task filtering actually work Change tests Fix using filter conditions Fix test Remove unused fields Fix static check Remove start and end date fields on task collection Fix misspell add filter logic when getting tasks Add parsing filter query parameters into task filters Start adding support for filters Co-authored-by: kolaente <k@knt.li> Reviewed-on: vikunja/api#243
155 lines
4.3 KiB
Go
155 lines
4.3 KiB
Go
// Copyright 2020 Vikunja and contriubtors. All rights reserved.
|
|
//
|
|
// This file is part of Vikunja.
|
|
//
|
|
// Vikunja is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// Vikunja is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with Vikunja. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
package models
|
|
|
|
import (
|
|
"github.com/iancoleman/strcase"
|
|
"reflect"
|
|
"strconv"
|
|
)
|
|
|
|
type taskFilterComparator string
|
|
|
|
const (
|
|
taskFilterComparatorInvalid taskFilterComparator = "invalid"
|
|
|
|
taskFilterComparatorEquals taskFilterComparator = "="
|
|
taskFilterComparatorGreater taskFilterComparator = ">"
|
|
taskFilterComparatorGreateEquals taskFilterComparator = ">="
|
|
taskFilterComparatorLess taskFilterComparator = "<"
|
|
taskFilterComparatorLessEquals taskFilterComparator = "<="
|
|
taskFilterComparatorNotEquals taskFilterComparator = "!="
|
|
)
|
|
|
|
type taskFilter struct {
|
|
field string
|
|
value interface{} // Needs to be an interface to be able to hold the field's native value
|
|
comparator taskFilterComparator
|
|
}
|
|
|
|
func getTaskFiltersByCollections(c *TaskCollection) (filters []*taskFilter, err error) {
|
|
|
|
if len(c.FilterByArr) > 0 {
|
|
c.FilterBy = append(c.FilterBy, c.FilterByArr...)
|
|
}
|
|
|
|
if len(c.FilterValueArr) > 0 {
|
|
c.FilterValue = append(c.FilterValue, c.FilterValueArr...)
|
|
}
|
|
|
|
if len(c.FilterComparatorArr) > 0 {
|
|
c.FilterValue = append(c.FilterValue, c.FilterComparatorArr...)
|
|
}
|
|
|
|
filters = make([]*taskFilter, 0, len(c.FilterBy))
|
|
for i, f := range c.FilterBy {
|
|
filter := &taskFilter{
|
|
field: f,
|
|
comparator: taskFilterComparatorEquals,
|
|
}
|
|
|
|
if len(c.FilterComparator) > i {
|
|
filter.comparator, err = getFilterComparatorFromString(c.FilterComparator[i])
|
|
if err != nil {
|
|
return
|
|
}
|
|
}
|
|
|
|
err = validateTaskFieldComparator(filter.comparator)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
// Cast the field value to its native type
|
|
if len(c.FilterValue) > i {
|
|
filter.value, err = getNativeValueForTaskField(filter.field, c.FilterValue[i])
|
|
if err != nil {
|
|
return
|
|
}
|
|
}
|
|
|
|
// Special case for pseudo date fields
|
|
// FIXME: This is really dirty, to fix this the db fields should be renamed
|
|
if filter.field+"_unix" == taskPropertyDoneAtUnix ||
|
|
filter.field+"_unix" == taskPropertyDueDateUnix ||
|
|
filter.field+"_unix" == taskPropertyStartDateUnix ||
|
|
filter.field+"_unix" == taskPropertyEndDateUnix {
|
|
filter.field += "_unix"
|
|
}
|
|
|
|
filters = append(filters, filter)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func validateTaskFieldComparator(comparator taskFilterComparator) error {
|
|
switch comparator {
|
|
case
|
|
taskFilterComparatorEquals,
|
|
taskFilterComparatorGreater,
|
|
taskFilterComparatorGreateEquals,
|
|
taskFilterComparatorLess,
|
|
taskFilterComparatorLessEquals,
|
|
taskFilterComparatorNotEquals:
|
|
return nil
|
|
default:
|
|
return ErrInvalidTaskFilterComparator{Comparator: comparator}
|
|
}
|
|
}
|
|
|
|
func getFilterComparatorFromString(comparator string) (taskFilterComparator, error) {
|
|
switch comparator {
|
|
case "equals":
|
|
return taskFilterComparatorEquals, nil
|
|
case "greater":
|
|
return taskFilterComparatorGreater, nil
|
|
case "greater_equals":
|
|
return taskFilterComparatorGreateEquals, nil
|
|
case "less":
|
|
return taskFilterComparatorLess, nil
|
|
case "less_equals":
|
|
return taskFilterComparatorLessEquals, nil
|
|
case "not_equals":
|
|
return taskFilterComparatorNotEquals, nil
|
|
default:
|
|
return taskFilterComparatorInvalid, ErrInvalidTaskFilterComparator{Comparator: taskFilterComparator(comparator)}
|
|
}
|
|
}
|
|
|
|
func getNativeValueForTaskField(fieldName, value string) (nativeValue interface{}, err error) {
|
|
field, ok := reflect.TypeOf(&Task{}).Elem().FieldByName(strcase.ToCamel(fieldName))
|
|
if !ok {
|
|
return nil, ErrInvalidTaskField{TaskField: fieldName}
|
|
}
|
|
|
|
switch field.Type.Kind() {
|
|
case reflect.Int64:
|
|
nativeValue, err = strconv.ParseInt(value, 10, 64)
|
|
case reflect.Float64:
|
|
nativeValue, err = strconv.ParseFloat(value, 64)
|
|
case reflect.String:
|
|
nativeValue = value
|
|
case reflect.Bool:
|
|
nativeValue, err = strconv.ParseBool(value)
|
|
default:
|
|
}
|
|
|
|
return
|
|
}
|