feat: add date math for filters #1086
1
go.mod
1
go.mod
|
@ -59,6 +59,7 @@ require (
|
|||
github.com/swaggo/swag v1.8.0
|
||||
github.com/tkuchiki/go-timezone v0.2.2
|
||||
github.com/ulule/limiter/v3 v3.10.0
|
||||
github.com/vectordotdev/go-datemath v0.1.1-0.20211214182920-0a4ac8742b93
|
||||
github.com/yuin/goldmark v1.4.8
|
||||
golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70
|
||||
golang.org/x/image v0.0.0-20220302094943-723b81ca9867
|
||||
|
|
2
go.sum
2
go.sum
|
@ -769,6 +769,8 @@ github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52
|
|||
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
|
||||
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
|
||||
github.com/vectordotdev/go-datemath v0.1.1-0.20211214182920-0a4ac8742b93 h1:bT0ZMfsMi2Xh8dopgxhFT+OJH88QITHpdppdkG1rXJQ=
|
||||
github.com/vectordotdev/go-datemath v0.1.1-0.20211214182920-0a4ac8742b93/go.mod h1:PnwzbSst7KD3vpBzzlntZU5gjVa455Uqa5QPiKSYJzQ=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||
|
|
|
@ -244,12 +244,37 @@ func TestTaskCollection(t *testing.T) {
|
|||
// the current date.
|
||||
assert.Equal(t, "[]\n", rec.Body.String())
|
||||
})
|
||||
t.Run("unix timestamps", func(t *testing.T) {
|
||||
rec, err := testHandler.testReadAllWithUser(
|
||||
url.Values{
|
||||
"filter_by": []string{"start_date", "end_date", "due_date"},
|
||||
"filter_value": []string{"1544500000", "1513164001", "1543500000"},
|
||||
"filter_comparator": []string{"greater", "less", "greater"},
|
||||
},
|
||||
urlParams,
|
||||
)
|
||||
assert.NoError(t, err)
|
||||
assert.NotContains(t, rec.Body.String(), `task #1`)
|
||||
assert.NotContains(t, rec.Body.String(), `task #2`)
|
||||
assert.NotContains(t, rec.Body.String(), `task #3`)
|
||||
assert.NotContains(t, rec.Body.String(), `task #4`)
|
||||
assert.Contains(t, rec.Body.String(), `task #5`)
|
||||
assert.Contains(t, rec.Body.String(), `task #6`)
|
||||
assert.Contains(t, rec.Body.String(), `task #7`)
|
||||
assert.NotContains(t, rec.Body.String(), `task #8`)
|
||||
assert.Contains(t, rec.Body.String(), `task #9`)
|
||||
assert.NotContains(t, rec.Body.String(), `task #10`)
|
||||
assert.NotContains(t, rec.Body.String(), `task #11`)
|
||||
assert.NotContains(t, rec.Body.String(), `task #12`)
|
||||
assert.NotContains(t, rec.Body.String(), `task #13`)
|
||||
assert.NotContains(t, rec.Body.String(), `task #14`)
|
||||
})
|
||||
})
|
||||
t.Run("invalid date", func(t *testing.T) {
|
||||
_, err := testHandler.testReadAllWithUser(
|
||||
url.Values{
|
||||
"filter_by": []string{"due_date"},
|
||||
"filter_value": []string{"1540000000"},
|
||||
"filter_value": []string{"invalid"},
|
||||
"filter_comparator": []string{"greater"},
|
||||
},
|
||||
nil,
|
||||
|
@ -451,7 +476,7 @@ func TestTaskCollection(t *testing.T) {
|
|||
_, err := testHandler.testReadAllWithUser(
|
||||
url.Values{
|
||||
"filter_by": []string{"due_date"},
|
||||
"filter_value": []string{"1540000000"},
|
||||
"filter_value": []string{"invalid"},
|
||||
"filter_comparator": []string{"greater"},
|
||||
},
|
||||
nil,
|
||||
|
|
|
@ -131,7 +131,7 @@ func getTaskFilterOptsFromCollection(tf *TaskCollection) (opts *taskOptions, err
|
|||
// @Param sort_by query string false "The sorting parameter. You can pass this multiple times to get the tasks ordered by multiple different parametes, along with `order_by`. Possible values to sort by are `id`, `title`, `description`, `done`, `done_at`, `due_date`, `created_by_id`, `list_id`, `repeat_after`, `priority`, `start_date`, `end_date`, `hex_color`, `percent_done`, `uid`, `created`, `updated`. Default is `id`."
|
||||
// @Param order_by query string false "The ordering parameter. Possible values to order by are `asc` or `desc`. Default is `asc`."
|
||||
// @Param filter_by query string false "The name of the field to filter by. Allowed values are all task properties. Task properties which are their own object require passing in the id of that entity. Accepts an array for multiple filters which will be chanied together, all supplied filter must match."
|
||||
// @Param filter_value query string false "The value to filter for."
|
||||
// @Param filter_value query string false "The value to filter for. You can use [grafana](https://grafana.com/docs/grafana/latest/dashboards/time-range-controls)- or [elasticsearch](https://www.elastic.co/guide/en/elasticsearch/reference/7.3/common-options.html#date-math)-style relative dates for all date fields like `due_date`, `start_date`, `end_date`, etc."
|
||||
// @Param filter_comparator query string false "The comparator to use for a filter. Available values are `equals`, `greater`, `greater_equals`, `less`, `less_equals`, `like` and `in`. `in` expects comma-separated values in `filter_value`. Defaults to `equals`"
|
||||
// @Param filter_concat query string false "The concatinator to use for filters. Available values are `and` or `or`. Defaults to `or`."
|
||||
// @Param filter_include_nulls query string false "If set to true the result will include filtered fields whose value is set to `null`. Available values are `true` or `false`. Defaults to `false`."
|
||||
|
|
|
@ -25,6 +25,7 @@ import (
|
|||
|
||||
"code.vikunja.io/api/pkg/config"
|
||||
"github.com/iancoleman/strcase"
|
||||
"github.com/vectordotdev/go-datemath"
|
||||
"xorm.io/xorm/schemas"
|
||||
)
|
||||
|
||||
|
@ -159,8 +160,14 @@ func getValueForField(field reflect.StructField, rawValue string) (value interfa
|
|||
value, err = strconv.ParseBool(rawValue)
|
||||
case reflect.Struct:
|
||||
if field.Type == schemas.TimeType {
|
||||
value, err = time.Parse(time.RFC3339, rawValue)
|
||||
value = value.(time.Time).In(config.GetTimeZone())
|
||||
var t datemath.Expression
|
||||
t, err = datemath.Parse(rawValue)
|
||||
if err == nil {
|
||||
value = t.Time(datemath.WithLocation(config.GetTimeZone()))
|
||||
} else {
|
||||
value, err = time.Parse(time.RFC3339, rawValue)
|
||||
value = value.(time.Time).In(config.GetTimeZone())
|
||||
}
|
||||
}
|
||||
case reflect.Slice:
|
||||
// If this is a slice of pointers we're dealing with some property which is a relation
|
||||
|
|
|
@ -1995,7 +1995,7 @@ var doc = `{
|
|||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "The value to filter for.",
|
||||
"description": "The value to filter for. You can use [grafana](https://grafana.com/docs/grafana/latest/dashboards/time-range-controls)- or [elasticsearch](https://www.elastic.co/guide/en/elasticsearch/reference/7.3/common-options.html#date-math)-style relative dates for all date fields like ` + "`" + `due_date` + "`" + `, ` + "`" + `start_date` + "`" + `, ` + "`" + `end_date` + "`" + `, etc.",
|
||||
"name": "filter_value",
|
||||
"in": "query"
|
||||
},
|
||||
|
|
|
@ -1979,7 +1979,7 @@
|
|||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "The value to filter for.",
|
||||
"description": "The value to filter for. You can use [grafana](https://grafana.com/docs/grafana/latest/dashboards/time-range-controls)- or [elasticsearch](https://www.elastic.co/guide/en/elasticsearch/reference/7.3/common-options.html#date-math)-style relative dates for all date fields like `due_date`, `start_date`, `end_date`, etc.",
|
||||
"name": "filter_value",
|
||||
"in": "query"
|
||||
},
|
||||
|
|
|
@ -2898,7 +2898,10 @@ paths:
|
|||
in: query
|
||||
name: filter_by
|
||||
type: string
|
||||
- description: The value to filter for.
|
||||
- description: The value to filter for. You can use [grafana](https://grafana.com/docs/grafana/latest/dashboards/time-range-controls)-
|
||||
or [elasticsearch](https://www.elastic.co/guide/en/elasticsearch/reference/7.3/common-options.html#date-math)-style
|
||||
relative dates for all date fields like `due_date`, `start_date`, `end_date`,
|
||||
etc.
|
||||
in: query
|
||||
name: filter_value
|
||||
type: string
|
||||
|
|
Loading…
Reference in New Issue
Block a user