@@ -3407,7 +3407,7 @@ func (q *FakeQuerier) GetTemplateInsights(_ context.Context, arg database.GetTem
3407
3407
return row , nil
3408
3408
}
3409
3409
3410
- func (q * FakeQuerier ) GetTemplateInsightsByInterval (ctx context.Context , arg database.GetTemplateInsightsByIntervalParams ) ([]database.GetTemplateInsightsByIntervalRow , error ) {
3410
+ func (q * FakeQuerier ) GetTemplateInsightsByInterval (_ context.Context , arg database.GetTemplateInsightsByIntervalParams ) ([]database.GetTemplateInsightsByIntervalRow , error ) {
3411
3411
err := validateDatabaseType (arg )
3412
3412
if err != nil {
3413
3413
return nil , err
@@ -3416,82 +3416,89 @@ func (q *FakeQuerier) GetTemplateInsightsByInterval(ctx context.Context, arg dat
3416
3416
q .mutex .RLock ()
3417
3417
defer q .mutex .RUnlock ()
3418
3418
3419
- type statByInterval struct {
3420
- startTime , endTime time.Time
3421
- userSet map [uuid.UUID ]struct {}
3422
- templateIDSet map [uuid.UUID ]struct {}
3423
- }
3419
+ /*
3420
+ WITH
3421
+ ts AS (
3422
+ SELECT
3423
+ d::timestamptz AS from_,
3424
+ CASE
3425
+ WHEN (d::timestamptz + (@interval_days::int || ' day')::interval) <= @end_time::timestamptz
3426
+ THEN (d::timestamptz + (@interval_days::int || ' day')::interval)
3427
+ ELSE @end_time::timestamptz
3428
+ END AS to_
3429
+ FROM
3430
+ -- Subtract 1 microsecond from end_time to avoid including the next interval in the results.
3431
+ generate_series(@start_time::timestamptz, (@end_time::timestamptz) - '1 microsecond'::interval, (@interval_days::int || ' day')::interval) AS d
3432
+ )
3424
3433
3425
- statsByInterval := []statByInterval {{arg .StartTime , arg .StartTime .AddDate (0 , 0 , int (arg .IntervalDays )), make (map [uuid.UUID ]struct {}), make (map [uuid.UUID ]struct {})}}
3426
- for statsByInterval [len (statsByInterval )- 1 ].endTime .Before (arg .EndTime ) {
3427
- statsByInterval = append (statsByInterval , statByInterval {statsByInterval [len (statsByInterval )- 1 ].endTime , statsByInterval [len (statsByInterval )- 1 ].endTime .AddDate (0 , 0 , int (arg .IntervalDays )), make (map [uuid.UUID ]struct {}), make (map [uuid.UUID ]struct {})})
3428
- }
3429
- if statsByInterval [len (statsByInterval )- 1 ].endTime .After (arg .EndTime ) {
3430
- statsByInterval [len (statsByInterval )- 1 ].endTime = arg .EndTime
3431
- }
3434
+ SELECT
3435
+ ts.from_ AS start_time,
3436
+ ts.to_ AS end_time,
3437
+ array_remove(array_agg(DISTINCT tus.template_id), NULL)::uuid[] AS template_ids,
3438
+ COUNT(DISTINCT tus.user_id) AS active_users
3439
+ FROM
3440
+ ts
3441
+ LEFT JOIN
3442
+ template_usage_stats AS tus
3443
+ ON
3444
+ tus.start_time >= ts.from_
3445
+ AND tus.end_time <= ts.to_
3446
+ AND CASE WHEN COALESCE(array_length(@template_ids::uuid[], 1), 0) > 0 THEN tus.template_id = ANY(@template_ids::uuid[]) ELSE TRUE END
3447
+ GROUP BY
3448
+ ts.from_, ts.to_;
3449
+ */
3432
3450
3433
- for _ , s := range q . workspaceAgentStats {
3434
- if s . CreatedAt . Before ( arg . StartTime ) || s . CreatedAt . Equal ( arg . EndTime ) || s . CreatedAt . After ( arg . EndTime ) {
3435
- continue
3436
- }
3437
- if len ( arg . TemplateIDs ) > 0 && ! slices . Contains ( arg . TemplateIDs , s . TemplateID ) {
3438
- continue
3439
- }
3440
- if s . ConnectionCount == 0 {
3441
- continue
3451
+ type interval struct {
3452
+ From time. Time
3453
+ To time. Time
3454
+ }
3455
+ var ts [] interval
3456
+ for d := arg . StartTime ; d . Before ( arg . EndTime ); d = d . AddDate ( 0 , 0 , int ( arg . IntervalDays )) {
3457
+ to := d . AddDate ( 0 , 0 , int ( arg . IntervalDays ))
3458
+ if to . After ( arg . EndTime ) {
3459
+ to = arg . EndTime
3442
3460
}
3461
+ ts = append (ts , interval {From : d , To : to })
3462
+ }
3443
3463
3444
- for _ , ds := range statsByInterval {
3445
- if s .CreatedAt .Before (ds .startTime ) || s .CreatedAt .Equal (ds .endTime ) || s .CreatedAt .After (ds .endTime ) {
3464
+ type grouped struct {
3465
+ TemplateIDs map [uuid.UUID ]struct {}
3466
+ UserIDs map [uuid.UUID ]struct {}
3467
+ }
3468
+ groupedByInterval := make (map [interval ]grouped )
3469
+ for _ , tus := range q .templateUsageStats {
3470
+ for _ , t := range ts {
3471
+ if tus .StartTime .Before (t .From ) || tus .EndTime .After (t .To ) {
3446
3472
continue
3447
3473
}
3448
- ds .userSet [s .UserID ] = struct {}{}
3449
- ds .templateIDSet [s .TemplateID ] = struct {}{}
3450
- }
3451
- }
3452
-
3453
- for _ , s := range q .workspaceAppStats {
3454
- w , err := q .getWorkspaceByIDNoLock (ctx , s .WorkspaceID )
3455
- if err != nil {
3456
- return nil , err
3457
- }
3458
-
3459
- if len (arg .TemplateIDs ) > 0 && ! slices .Contains (arg .TemplateIDs , w .TemplateID ) {
3460
- continue
3461
- }
3462
-
3463
- for _ , ds := range statsByInterval {
3464
- // (was.session_started_at >= ts.from_ AND was.session_started_at < ts.to_)
3465
- // OR (was.session_ended_at > ts.from_ AND was.session_ended_at < ts.to_)
3466
- // OR (was.session_started_at < ts.from_ AND was.session_ended_at >= ts.to_)
3467
- if ! (((s .SessionStartedAt .After (ds .startTime ) || s .SessionStartedAt .Equal (ds .startTime )) && s .SessionStartedAt .Before (ds .endTime )) ||
3468
- (s .SessionEndedAt .After (ds .startTime ) && s .SessionEndedAt .Before (ds .endTime )) ||
3469
- (s .SessionStartedAt .Before (ds .startTime ) && (s .SessionEndedAt .After (ds .endTime ) || s .SessionEndedAt .Equal (ds .endTime )))) {
3474
+ if len (arg .TemplateIDs ) > 0 && ! slices .Contains (arg .TemplateIDs , tus .TemplateID ) {
3470
3475
continue
3471
3476
}
3472
-
3473
- ds .userSet [s .UserID ] = struct {}{}
3474
- ds .templateIDSet [w .TemplateID ] = struct {}{}
3477
+ g , ok := groupedByInterval [t ]
3478
+ if ! ok {
3479
+ g = grouped {
3480
+ TemplateIDs : make (map [uuid.UUID ]struct {}),
3481
+ UserIDs : make (map [uuid.UUID ]struct {}),
3482
+ }
3483
+ }
3484
+ g .TemplateIDs [tus .TemplateID ] = struct {}{}
3485
+ g .UserIDs [tus .UserID ] = struct {}{}
3486
+ groupedByInterval [t ] = g
3475
3487
}
3476
3488
}
3477
3489
3478
- var result []database.GetTemplateInsightsByIntervalRow
3479
- for _ , ds := range statsByInterval {
3480
- templateIDs := make ([]uuid. UUID , 0 , len ( ds . templateIDSet ))
3481
- for templateID := range ds . templateIDSet {
3482
- templateIDs = append ( templateIDs , templateID )
3490
+ var rows []database.GetTemplateInsightsByIntervalRow
3491
+ for _ , t := range ts { // Ordered by interval.
3492
+ row := database. GetTemplateInsightsByIntervalRow {
3493
+ StartTime : t . From ,
3494
+ EndTime : t . To ,
3483
3495
}
3484
- slices .SortFunc (templateIDs , func (a , b uuid.UUID ) int {
3485
- return slice .Ascending (a .String (), b .String ())
3486
- })
3487
- result = append (result , database.GetTemplateInsightsByIntervalRow {
3488
- StartTime : ds .startTime ,
3489
- EndTime : ds .endTime ,
3490
- TemplateIDs : templateIDs ,
3491
- ActiveUsers : int64 (len (ds .userSet )),
3492
- })
3496
+ row .TemplateIDs = uniqueSortedUUIDs (maps .Keys (groupedByInterval [t ].TemplateIDs ))
3497
+ row .ActiveUsers = int64 (len (groupedByInterval [t ].UserIDs ))
3498
+ rows = append (rows , row )
3493
3499
}
3494
- return result , nil
3500
+
3501
+ return rows , nil
3495
3502
}
3496
3503
3497
3504
func (q * FakeQuerier ) GetTemplateInsightsByTemplate (_ context.Context , arg database.GetTemplateInsightsByTemplateParams ) ([]database.GetTemplateInsightsByTemplateRow , error ) {
0 commit comments