Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit afe54e5

Browse files
author
Faith Chikwekwe
committedSep 3, 2020
feat(execute): support duration for agg window
1 parent fdaccd9 commit afe54e5

19 files changed

+168
-130
lines changed
 

‎execute/bounds.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ func (b Bounds) Shift(d Duration) Bounds {
7878

7979
func (b Bounds) Duration() Duration {
8080
if b.IsEmpty() {
81-
return values.ConvertDuration(0)
81+
return values.ConvertDurationNsecs(0)
8282
}
8383
return b.Stop.Sub(b.Start)
8484
}

‎execute/window.go

+5-4
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,11 @@ type Window struct {
1818
// and normalizes the offset to a small positive duration.
1919
// It also validates that the durations are valid when
2020
// used within a window.
21-
func NewWindow(every, period, offset Duration) (Window, error) {
22-
// Normalize the offset to a small positive duration
23-
offset = offset.Normalize(every)
24-
21+
func NewWindow(every, period, offset Duration, months bool) (Window, error) {
22+
if !months {
23+
// Normalize nanosecond offsets to a small positive duration
24+
offset = offset.Normalize(every)
25+
}
2526
w := Window{
2627
Every: every,
2728
Period: period,

‎execute/window_test.go

+77-53
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@ import (
1414
func TestNewWindow(t *testing.T) {
1515
t.Run("normal offset", func(t *testing.T) {
1616
want := execute.Window{
17-
Every: values.ConvertDuration(time.Minute),
18-
Period: values.ConvertDuration(time.Minute),
19-
Offset: values.ConvertDuration(time.Second),
17+
Every: values.ConvertDurationNsecs(time.Minute),
18+
Period: values.ConvertDurationNsecs(time.Minute),
19+
Offset: values.ConvertDurationNsecs(time.Second),
2020
}
21-
got := MustWindow(values.ConvertDuration(time.Minute), values.ConvertDuration(time.Minute), values.ConvertDuration(time.Second))
21+
got := MustWindow(values.ConvertDurationNsecs(time.Minute), values.ConvertDurationNsecs(time.Minute), values.ConvertDurationNsecs(time.Second), false)
2222
if !cmp.Equal(want, got) {
2323
t.Errorf("window different; -want/+got:\n%v\n", cmp.Diff(want, got))
2424
}
@@ -27,14 +27,14 @@ func TestNewWindow(t *testing.T) {
2727
// offset larger than "every" duration will be normalized
2828
t.Run("larger offset", func(t *testing.T) {
2929
want := execute.Window{
30-
Every: values.ConvertDuration(time.Minute),
31-
Period: values.ConvertDuration(time.Minute),
32-
Offset: values.ConvertDuration(30 * time.Second),
30+
Every: values.ConvertDurationNsecs(time.Minute),
31+
Period: values.ConvertDurationNsecs(time.Minute),
32+
Offset: values.ConvertDurationNsecs(30 * time.Second),
3333
}
3434
got := MustWindow(
35-
values.ConvertDuration(time.Minute),
36-
values.ConvertDuration(time.Minute),
37-
values.ConvertDuration(2*time.Minute+30*time.Second))
35+
values.ConvertDurationNsecs(time.Minute),
36+
values.ConvertDurationNsecs(time.Minute),
37+
values.ConvertDurationNsecs(2*time.Minute+30*time.Second), false)
3838
if !cmp.Equal(want, got) {
3939
t.Errorf("window different; -want/+got:\n%v\n", cmp.Diff(want, got))
4040
}
@@ -43,14 +43,14 @@ func TestNewWindow(t *testing.T) {
4343
// Negative offset will be normalized
4444
t.Run("negative offset", func(t *testing.T) {
4545
want := execute.Window{
46-
Every: values.ConvertDuration(time.Minute),
47-
Period: values.ConvertDuration(time.Minute),
48-
Offset: values.ConvertDuration(30 * time.Second),
46+
Every: values.ConvertDurationNsecs(time.Minute),
47+
Period: values.ConvertDurationNsecs(time.Minute),
48+
Offset: values.ConvertDurationNsecs(30 * time.Second),
4949
}
5050
got := MustWindow(
51-
values.ConvertDuration(time.Minute),
52-
values.ConvertDuration(time.Minute),
53-
values.ConvertDuration(-2*time.Minute+30*time.Second))
51+
values.ConvertDurationNsecs(time.Minute),
52+
values.ConvertDurationNsecs(time.Minute),
53+
values.ConvertDurationNsecs(-2*time.Minute+30*time.Second), false)
5454
if !cmp.Equal(want, got) {
5555
t.Errorf("window different; -want/+got:\n%v\n", cmp.Diff(want, got))
5656
}
@@ -63,7 +63,7 @@ func TestNewWindow(t *testing.T) {
6363
mustParseDuration("1mo2w"),
6464
mustParseDuration("1mo2w"),
6565
values.Duration{},
66-
)
66+
false)
6767
if want, got := errAsString(wantErr), errAsString(gotErr); want != got {
6868
t.Errorf("window error different; -want/+got:\n%v\n", cmp.Diff(want, got))
6969
}
@@ -76,7 +76,7 @@ func TestNewWindow(t *testing.T) {
7676
values.Duration{},
7777
values.Duration{},
7878
values.Duration{},
79-
)
79+
false)
8080
if want, got := errAsString(wantErr), errAsString(gotErr); want != got {
8181
t.Errorf("window error different; -want/+got:\n%v\n", cmp.Diff(want, got))
8282
}
@@ -93,9 +93,9 @@ func TestWindow_GetEarliestBounds(t *testing.T) {
9393
{
9494
name: "simple",
9595
w: MustWindow(
96-
values.ConvertDuration(5*time.Minute),
97-
values.ConvertDuration(5*time.Minute),
98-
values.ConvertDuration(0)),
96+
values.ConvertDurationNsecs(5*time.Minute),
97+
values.ConvertDurationNsecs(5*time.Minute),
98+
values.ConvertDurationNsecs(0), false),
9999
t: execute.Time(6 * time.Minute),
100100
want: execute.Bounds{
101101
Start: execute.Time(5 * time.Minute),
@@ -105,21 +105,45 @@ func TestWindow_GetEarliestBounds(t *testing.T) {
105105
{
106106
name: "simple with offset",
107107
w: MustWindow(
108-
values.ConvertDuration(5*time.Minute),
109-
values.ConvertDuration(5*time.Minute),
110-
values.ConvertDuration(30*time.Second)),
108+
values.ConvertDurationNsecs(5*time.Minute),
109+
values.ConvertDurationNsecs(5*time.Minute),
110+
values.ConvertDurationNsecs(30*time.Second), false),
111111
t: execute.Time(5 * time.Minute),
112112
want: execute.Bounds{
113113
Start: execute.Time(30 * time.Second),
114114
Stop: execute.Time(5*time.Minute + 30*time.Second),
115115
},
116116
},
117+
{
118+
name: "simple months",
119+
w: MustWindow(
120+
values.ConvertDurationMonths(5),
121+
values.ConvertDurationMonths(5),
122+
values.ConvertDurationMonths(0), true),
123+
t: values.ConvertTime(time.Date(1970, time.January, 1, 0, 0, 0, 0, time.UTC)),
124+
want: execute.Bounds{
125+
Start: values.ConvertTime(time.Date(1970, time.January, 1, 0, 0, 0, 0, time.UTC)),
126+
Stop: values.ConvertTime(time.Date(1970, time.June, 1, 0, 0, 0, 0, time.UTC)),
127+
},
128+
},
129+
{
130+
name: "simple months with offset",
131+
w: MustWindow(
132+
values.ConvertDurationMonths(3),
133+
values.ConvertDurationMonths(3),
134+
values.ConvertDurationMonths(1), true),
135+
t: values.ConvertTime(time.Date(1970, time.January, 1, 0, 0, 0, 0, time.UTC)),
136+
want: execute.Bounds{
137+
Start: values.ConvertTime(time.Date(1969, time.November, 1, 0, 0, 0, 0, time.UTC)),
138+
Stop: values.ConvertTime(time.Date(1970, time.February, 1, 0, 0, 0, 0, time.UTC)),
139+
},
140+
},
117141
{
118142
name: "underlapping",
119143
w: MustWindow(
120-
values.ConvertDuration(2*time.Minute),
121-
values.ConvertDuration(1*time.Minute),
122-
values.ConvertDuration(30*time.Second)),
144+
values.ConvertDurationNsecs(2*time.Minute),
145+
values.ConvertDurationNsecs(1*time.Minute),
146+
values.ConvertDurationNsecs(30*time.Second), false),
123147
t: execute.Time(3 * time.Minute),
124148
want: execute.Bounds{
125149
Start: execute.Time(3*time.Minute + 30*time.Second),
@@ -129,9 +153,9 @@ func TestWindow_GetEarliestBounds(t *testing.T) {
129153
{
130154
name: "underlapping not contained",
131155
w: MustWindow(
132-
values.ConvertDuration(2*time.Minute),
133-
values.ConvertDuration(1*time.Minute),
134-
values.ConvertDuration(30*time.Second)),
156+
values.ConvertDurationNsecs(2*time.Minute),
157+
values.ConvertDurationNsecs(1*time.Minute),
158+
values.ConvertDurationNsecs(30*time.Second), false),
135159
t: execute.Time(2*time.Minute + 45*time.Second),
136160
want: execute.Bounds{
137161
Start: execute.Time(3*time.Minute + 30*time.Second),
@@ -141,9 +165,9 @@ func TestWindow_GetEarliestBounds(t *testing.T) {
141165
{
142166
name: "overlapping",
143167
w: MustWindow(
144-
values.ConvertDuration(1*time.Minute),
145-
values.ConvertDuration(2*time.Minute),
146-
values.ConvertDuration(30*time.Second)),
168+
values.ConvertDurationNsecs(1*time.Minute),
169+
values.ConvertDurationNsecs(2*time.Minute),
170+
values.ConvertDurationNsecs(30*time.Second), false),
147171
t: execute.Time(30 * time.Second),
148172
want: execute.Bounds{
149173
Start: execute.Time(-30 * time.Second),
@@ -153,9 +177,9 @@ func TestWindow_GetEarliestBounds(t *testing.T) {
153177
{
154178
name: "partially overlapping",
155179
w: MustWindow(
156-
values.ConvertDuration(1*time.Minute),
157-
values.ConvertDuration(3*time.Minute+30*time.Second),
158-
values.ConvertDuration(30*time.Second)),
180+
values.ConvertDurationNsecs(1*time.Minute),
181+
values.ConvertDurationNsecs(3*time.Minute+30*time.Second),
182+
values.ConvertDurationNsecs(30*time.Second), false),
159183
t: execute.Time(5*time.Minute + 45*time.Second),
160184
want: execute.Bounds{
161185
Start: execute.Time(3 * time.Minute),
@@ -165,9 +189,9 @@ func TestWindow_GetEarliestBounds(t *testing.T) {
165189
{
166190
name: "partially overlapping (t on boundary)",
167191
w: MustWindow(
168-
values.ConvertDuration(1*time.Minute),
169-
values.ConvertDuration(3*time.Minute+30*time.Second),
170-
values.ConvertDuration(30*time.Second)),
192+
values.ConvertDurationNsecs(1*time.Minute),
193+
values.ConvertDurationNsecs(3*time.Minute+30*time.Second),
194+
values.ConvertDurationNsecs(30*time.Second), false),
171195
t: execute.Time(5 * time.Minute),
172196
want: execute.Bounds{
173197
Start: execute.Time(2 * time.Minute),
@@ -198,8 +222,8 @@ func TestWindow_GetOverlappingBounds(t *testing.T) {
198222
{
199223
name: "simple",
200224
w: execute.Window{
201-
Every: values.ConvertDuration(time.Minute),
202-
Period: values.ConvertDuration(time.Minute),
225+
Every: values.ConvertDurationNsecs(time.Minute),
226+
Period: values.ConvertDurationNsecs(time.Minute),
203227
},
204228
b: execute.Bounds{
205229
Start: execute.Time(5 * time.Minute),
@@ -214,9 +238,9 @@ func TestWindow_GetOverlappingBounds(t *testing.T) {
214238
{
215239
name: "simple with offset",
216240
w: execute.Window{
217-
Every: values.ConvertDuration(time.Minute),
218-
Period: values.ConvertDuration(time.Minute),
219-
Offset: values.ConvertDuration(15 * time.Second),
241+
Every: values.ConvertDurationNsecs(time.Minute),
242+
Period: values.ConvertDurationNsecs(time.Minute),
243+
Offset: values.ConvertDurationNsecs(15 * time.Second),
220244
},
221245
b: execute.Bounds{
222246
Start: execute.Time(5 * time.Minute),
@@ -240,8 +264,8 @@ func TestWindow_GetOverlappingBounds(t *testing.T) {
240264
{
241265
name: "underlapping, bounds in gap",
242266
w: execute.Window{
243-
Every: values.ConvertDuration(2 * time.Minute),
244-
Period: values.ConvertDuration(time.Minute),
267+
Every: values.ConvertDurationNsecs(2 * time.Minute),
268+
Period: values.ConvertDurationNsecs(time.Minute),
245269
},
246270
b: execute.Bounds{
247271
Start: execute.Time(30 * time.Second),
@@ -252,9 +276,9 @@ func TestWindow_GetOverlappingBounds(t *testing.T) {
252276
{
253277
name: "underlapping",
254278
w: execute.Window{
255-
Every: values.ConvertDuration(2 * time.Minute),
256-
Period: values.ConvertDuration(time.Minute),
257-
Offset: values.ConvertDuration(30 * time.Second),
279+
Every: values.ConvertDurationNsecs(2 * time.Minute),
280+
Period: values.ConvertDurationNsecs(time.Minute),
281+
Offset: values.ConvertDurationNsecs(30 * time.Second),
258282
},
259283
b: execute.Bounds{
260284
Start: execute.Time(time.Minute + 45*time.Second),
@@ -274,8 +298,8 @@ func TestWindow_GetOverlappingBounds(t *testing.T) {
274298
{
275299
name: "overlapping",
276300
w: execute.Window{
277-
Every: values.ConvertDuration(1 * time.Minute),
278-
Period: values.ConvertDuration(2*time.Minute + 15*time.Second),
301+
Every: values.ConvertDurationNsecs(1 * time.Minute),
302+
Period: values.ConvertDurationNsecs(2*time.Minute + 15*time.Second),
279303
},
280304
b: execute.Bounds{
281305
Start: execute.Time(10 * time.Minute),
@@ -385,8 +409,8 @@ func TestWindow_GetOverlappingBounds(t *testing.T) {
385409
}
386410
}
387411

388-
func MustWindow(every, period, offset execute.Duration) execute.Window {
389-
w, err := execute.NewWindow(every, period, offset)
412+
func MustWindow(every, period, offset execute.Duration, months bool) execute.Window {
413+
w, err := execute.NewWindow(every, period, offset, months)
390414
if err != nil {
391415
panic(err)
392416
}

‎internal/gen/input.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ func Input(ctx context.Context, schema Schema) (flux.TableIterator, error) {
147147

148148
g := &dataGenerator{
149149
Context: ctx,
150-
Period: values.ConvertDuration(period),
150+
Period: values.ConvertDurationNsecs(period),
151151
NumPoints: numPoints,
152152
Nulls: schema.Nulls,
153153
Allocator: alloc,

‎plan/bounds_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ func TestBounds_ComputePlanBounds(t *testing.T) {
390390
spec: &plantest.PlanSpec{
391391
Nodes: []plan.Node{
392392
plantest.CreatePhysicalMockNode("0"),
393-
makeShiftNode("1", values.ConvertDuration(5)),
393+
makeShiftNode("1", values.ConvertDurationNsecs(5)),
394394
plantest.CreatePhysicalMockNode("2"),
395395
},
396396
Edges: [][2]int{
@@ -412,7 +412,7 @@ func TestBounds_ComputePlanBounds(t *testing.T) {
412412
plantest.CreatePhysicalMockNode("0"),
413413
makeBoundsNode("1", bounds(5, 10)),
414414
plantest.CreatePhysicalMockNode("2"),
415-
makeShiftNode("3", values.ConvertDuration(5)),
415+
makeShiftNode("3", values.ConvertDurationNsecs(5)),
416416
plantest.CreatePhysicalMockNode("4"),
417417
},
418418
Edges: [][2]int{

‎stdlib/date/date.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ func init() {
393393

394394
if values.IsTimeable(v) && u.Type().Nature() == semantic.Duration {
395395
if v.Type().Nature() == semantic.Time {
396-
w, err := execute.NewWindow(u.Duration(), u.Duration(), execute.Duration{})
396+
w, err := execute.NewWindow(u.Duration(), u.Duration(), execute.Duration{}, false)
397397
if err != nil {
398398
return nil, err
399399
}
@@ -403,7 +403,7 @@ func init() {
403403

404404
if v.Type().Nature() == semantic.Duration {
405405

406-
w, err := execute.NewWindow(u.Duration(), u.Duration(), execute.Duration{})
406+
w, err := execute.NewWindow(u.Duration(), u.Duration(), execute.Duration{}, false)
407407
if err != nil {
408408
return nil, err
409409
}

‎stdlib/experimental/http/http_experimental.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ var get = values.NewFunction(
4343
}
4444

4545
// http.NewDefaultClient() does default to 30
46-
var theTimeout = values.ConvertDuration(30 * time.Second)
46+
var theTimeout = values.ConvertDurationNsecs(30 * time.Second)
4747
tv, ok := args.Get("timeout")
4848
if !ok {
4949
// default timeout

‎stdlib/sql/to_privates_test.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -297,11 +297,11 @@ func TestMssqlTranslation(t *testing.T) {
297297

298298
func TestBigQueryTranslation(t *testing.T) {
299299
bigqueryTypeTranslations := map[string]flux.ColType{
300-
"FLOAT64": flux.TFloat,
301-
"INT64": flux.TInt,
302-
"STRING": flux.TString,
303-
"TIMESTAMP": flux.TTime,
304-
"BOOL": flux.TBool,
300+
"FLOAT64": flux.TFloat,
301+
"INT64": flux.TInt,
302+
"STRING": flux.TString,
303+
"TIMESTAMP": flux.TTime,
304+
"BOOL": flux.TBool,
305305
}
306306

307307
columnLabel := "apples"

‎stdlib/universe/sleep_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ func TestSleep(t *testing.T) {
1717
args := values.NewObjectWithValues(
1818
map[string]values.Value{
1919
"v": myval,
20-
"duration": values.NewDuration(values.ConvertDuration(time.Microsecond)),
20+
"duration": values.NewDuration(values.ConvertDurationNsecs(time.Microsecond)),
2121
},
2222
)
2323
v, err := sleepFunc.Call(ctx, args)
@@ -38,7 +38,7 @@ func TestSleep(t *testing.T) {
3838
args := values.NewObjectWithValues(
3939
map[string]values.Value{
4040
"v": myval,
41-
"duration": values.NewDuration(values.ConvertDuration(200 * time.Millisecond)),
41+
"duration": values.NewDuration(values.ConvertDurationNsecs(200 * time.Millisecond)),
4242
},
4343
)
4444
_, err := sleepFunc.Call(ctx, args)

‎stdlib/universe/typeconv.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -659,9 +659,9 @@ func (c *durationConv) Call(ctx context.Context, args values.Object) (values.Val
659659
}
660660
d = n
661661
case semantic.Int:
662-
d = values.ConvertDuration(time.Duration(v.Int()))
662+
d = values.ConvertDurationNsecs(time.Duration(v.Int()))
663663
case semantic.UInt:
664-
d = values.ConvertDuration(time.Duration(v.UInt()))
664+
d = values.ConvertDurationNsecs(time.Duration(v.UInt()))
665665
case semantic.Duration:
666666
d = v.Duration()
667667
default:

0 commit comments

Comments
 (0)
Please sign in to comment.