diff --git a/CHANGELOG.md b/CHANGELOG.md index cf17365b..426b8ef2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +### Features + +- Added `$__dateTimeFilter()` macro for conveniently filtering a PRIMARY KEY composed of Date and DateTime columns. + ## 4.1.0 ### Features diff --git a/README.md b/README.md index a1e7fe86..eb1b3f96 100644 --- a/README.md +++ b/README.md @@ -191,19 +191,20 @@ FROM test_data WHERE $__timeFilter(date_time) ``` -| Macro | Description | Output example | -|----------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------| -| *$__dateFilter(columnName)* | Replaced by a conditional that filters the data (using the provided column) based on the date range of the panel | `date >= toDate('2022-10-21') AND date <= toDate('2022-10-23')` | -| *$__timeFilter(columnName)* | Replaced by a conditional that filters the data (using the provided column) based on the time range of the panel in seconds | `time >= toDateTime(1415792726) AND time <= toDateTime(1447328726)` | -| *$__timeFilter_ms(columnName)* | Replaced by a conditional that filters the data (using the provided column) based on the time range of the panel in milliseconds | `time >= fromUnixTimestamp64Milli(1415792726123) AND time <= fromUnixTimestamp64Milli(1447328726456)` | -| *$__fromTime* | Replaced by the starting time of the range of the panel casted to `DateTime` | `toDateTime(1415792726)` | -| *$__toTime* | Replaced by the ending time of the range of the panel casted to `DateTime` | `toDateTime(1447328726)` | -| *$__fromTime_ms* | Replaced by the starting time of the range of the panel casted to `DateTime64(3)` | `fromUnixTimestamp64Milli(1415792726123)` | -| *$__toTime_ms* | Replaced by the ending time of the range of the panel casted to `DateTime64(3)` | `fromUnixTimestamp64Milli(1447328726456)` | -| *$__interval_s* | Replaced by the interval in seconds | `20` | -| *$__timeInterval(columnName)* | Replaced by a function calculating the interval based on window size in seconds, useful when grouping | `toStartOfInterval(toDateTime(column), INTERVAL 20 second)` | -| *$__timeInterval_ms(columnName)* | Replaced by a function calculating the interval based on window size in milliseconds, useful when grouping | `toStartOfInterval(toDateTime64(column, 3), INTERVAL 20 millisecond)` | -| *$__conditionalAll(condition, $templateVar)* | Replaced by the first parameter when the template variable in the second parameter does not select every value. Replaced by the 1=1 when the template variable selects every value. | `condition` or `1=1` | +| Macro | Description | Output example | +|----------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------| +| *$__dateFilter(columnName)* | Replaced by a conditional that filters the data (using the provided column) based on the date range of the panel | `date >= toDate('2022-10-21') AND date <= toDate('2022-10-23')` | +| *$__timeFilter(columnName)* | Replaced by a conditional that filters the data (using the provided column) based on the time range of the panel in seconds | `time >= toDateTime(1415792726) AND time <= toDateTime(1447328726)` | +| *$__timeFilter_ms(columnName)* | Replaced by a conditional that filters the data (using the provided column) based on the time range of the panel in milliseconds | `time >= fromUnixTimestamp64Milli(1415792726123) AND time <= fromUnixTimestamp64Milli(1447328726456)` | +| *$__dateTimeFilter(dateColumn, timeColumn)* | Shorthand that combines $__dateFilter() AND $__timeFilter() using separate Date and DateTime columns. | `$__dateFilter(dateColumn) AND $__timeFilter(timeColumn)` | +| *$__fromTime* | Replaced by the starting time of the range of the panel casted to `DateTime` | `toDateTime(1415792726)` | +| *$__toTime* | Replaced by the ending time of the range of the panel casted to `DateTime` | `toDateTime(1447328726)` | +| *$__fromTime_ms* | Replaced by the starting time of the range of the panel casted to `DateTime64(3)` | `fromUnixTimestamp64Milli(1415792726123)` | +| *$__toTime_ms* | Replaced by the ending time of the range of the panel casted to `DateTime64(3)` | `fromUnixTimestamp64Milli(1447328726456)` | +| *$__interval_s* | Replaced by the interval in seconds | `20` | +| *$__timeInterval(columnName)* | Replaced by a function calculating the interval based on window size in seconds, useful when grouping | `toStartOfInterval(toDateTime(column), INTERVAL 20 second)` | +| *$__timeInterval_ms(columnName)* | Replaced by a function calculating the interval based on window size in milliseconds, useful when grouping | `toStartOfInterval(toDateTime64(column, 3), INTERVAL 20 millisecond)` | +| *$__conditionalAll(condition, $templateVar)* | Replaced by the first parameter when the template variable in the second parameter does not select every value. Replaced by the 1=1 when the template variable selects every value. | `condition` or `1=1` | The plugin also supports notation using braces {}. Use this notation when queries are needed inside parameters. diff --git a/pkg/macros/macros.go b/pkg/macros/macros.go index 110cdb60..384efaf2 100644 --- a/pkg/macros/macros.go +++ b/pkg/macros/macros.go @@ -87,6 +87,22 @@ func DateFilter(query *sqlutil.Query, args []string) (string, error) { return fmt.Sprintf("%s >= %s AND %s <= %s", column, timeToDate(from), column, timeToDate(to)), nil } +func DateTimeFilter(query *sqlutil.Query, args []string) (string, error) { + if len(args) != 2 { + return "", fmt.Errorf("%w: expected 2 arguments, received %d", sqlds.ErrorBadArgumentCount, len(args)) + } + var ( + dateColumn = args[0] + timeColumn = args[1] + from = query.TimeRange.From + to = query.TimeRange.To + ) + + dateFilter := fmt.Sprintf("(%s >= %s AND %s <= %s)", dateColumn, timeToDate(from), dateColumn, timeToDate(to)) + timeFilter := fmt.Sprintf("(%s >= %s AND %s <= %s)", timeColumn, timeToDateTime(from), timeColumn, timeToDateTime(to)) + return fmt.Sprintf("%s AND %s", dateFilter, timeFilter), nil +} + func TimeInterval(query *sqlutil.Query, args []string) (string, error) { if len(args) != 1 { return "", fmt.Errorf("%w: expected 1 argument, received %d", sqlds.ErrorBadArgumentCount, len(args)) @@ -141,6 +157,8 @@ var Macros = map[string]sqlds.MacroFunc{ "timeFilter": TimeFilter, "timeFilter_ms": TimeFilterMs, "dateFilter": DateFilter, + "dateTimeFilter": DateTimeFilter, + "dt": DateTimeFilter, "timeInterval": TimeInterval, "timeInterval_ms": TimeIntervalMs, "interval_s": IntervalSeconds, diff --git a/pkg/macros/macros_test.go b/pkg/macros/macros_test.go index 28376783..8a8a3f5c 100644 --- a/pkg/macros/macros_test.go +++ b/pkg/macros/macros_test.go @@ -199,6 +199,20 @@ func TestMacroDateFilter(t *testing.T) { assert.Equal(t, "dateCol >= toDate('2014-11-12') AND dateCol <= toDate('2015-11-12')", got) } +func TestMacroDateTimeFilter(t *testing.T) { + from, _ := time.Parse("2006-01-02T15:04:05.000Z", "2014-11-12T11:45:26.371Z") + to, _ := time.Parse("2006-01-02T15:04:05.000Z", "2015-11-12T11:45:26.371Z") + query := sqlutil.Query{ + TimeRange: backend.TimeRange{ + From: from, + To: to, + }, + } + got, err := DateTimeFilter(&query, []string{"dateCol", "timeCol"}) + assert.Nil(t, err) + assert.Equal(t, "(dateCol >= toDate('2014-11-12') AND dateCol <= toDate('2015-11-12')) AND (timeCol >= toDateTime(1415792726) AND timeCol <= toDateTime(1447328726))", got) +} + func TestMacroTimeInterval(t *testing.T) { query := sqlutil.Query{ RawSQL: "select $__timeInterval(col) from foo",