@@ -1972,7 +1972,117 @@ func (q *FakeQuerier) GetTemplateAppInsights(ctx context.Context, arg database.G
1972
1972
return nil , err
1973
1973
}
1974
1974
1975
- panic ("not implemented" )
1975
+ q .mutex .RLock ()
1976
+ defer q .mutex .RUnlock ()
1977
+
1978
+ type appKey struct {
1979
+ AccessMethod string
1980
+ SlugOrPort string
1981
+ Slug string
1982
+ DisplayName string
1983
+ Icon string
1984
+ }
1985
+ type uniqueKey struct {
1986
+ TemplateID uuid.UUID
1987
+ UserID uuid.UUID
1988
+ AgentID uuid.UUID
1989
+ AppKey appKey
1990
+ }
1991
+
1992
+ appUsageIntervalsByUserAgentApp := make (map [uniqueKey ]map [time.Time ]int64 )
1993
+ for _ , s := range q .workspaceAppStats {
1994
+ // (was.session_started_at >= ts.from_ AND was.session_started_at < ts.to_)
1995
+ // OR (was.session_ended_at > ts.from_ AND was.session_ended_at < ts.to_)
1996
+ // OR (was.session_started_at < ts.from_ AND was.session_ended_at >= ts.to_)
1997
+ if ! (((s .SessionStartedAt .After (arg .StartTime ) || s .SessionStartedAt .Equal (arg .StartTime )) && s .SessionStartedAt .Before (arg .EndTime )) ||
1998
+ (s .SessionEndedAt .After (arg .StartTime ) && s .SessionEndedAt .Before (arg .EndTime )) ||
1999
+ (s .SessionStartedAt .Before (arg .StartTime ) && (s .SessionEndedAt .After (arg .EndTime ) || s .SessionEndedAt .Equal (arg .EndTime )))) {
2000
+ continue
2001
+ }
2002
+
2003
+ w , err := q .getWorkspaceByIDNoLock (ctx , s .WorkspaceID )
2004
+ if err != nil {
2005
+ return nil , err
2006
+ }
2007
+
2008
+ app , _ := q .getWorkspaceAppByAgentIDAndSlugNoLock (ctx , database.GetWorkspaceAppByAgentIDAndSlugParams {
2009
+ AgentID : s .AgentID ,
2010
+ Slug : s .SlugOrPort ,
2011
+ })
2012
+
2013
+ key := uniqueKey {
2014
+ TemplateID : w .TemplateID ,
2015
+ UserID : s .UserID ,
2016
+ AgentID : s .AgentID ,
2017
+ AppKey : appKey {
2018
+ AccessMethod : s .AccessMethod ,
2019
+ SlugOrPort : s .SlugOrPort ,
2020
+ Slug : app .Slug ,
2021
+ DisplayName : app .DisplayName ,
2022
+ Icon : app .Icon ,
2023
+ },
2024
+ }
2025
+ if appUsageIntervalsByUserAgentApp [key ] == nil {
2026
+ appUsageIntervalsByUserAgentApp [key ] = make (map [time.Time ]int64 )
2027
+ }
2028
+
2029
+ t := s .SessionStartedAt .Truncate (5 * time .Minute )
2030
+ if t .Before (arg .StartTime ) {
2031
+ t = arg .StartTime
2032
+ }
2033
+ for t .Before (s .SessionEndedAt ) && t .Before (arg .EndTime ) {
2034
+ appUsageIntervalsByUserAgentApp [key ][t ] = 300 // 5 minutes.
2035
+ t = t .Add (5 * time .Minute )
2036
+ }
2037
+ }
2038
+
2039
+ appUsageTemplateIDs := make (map [appKey ]map [uuid.UUID ]struct {})
2040
+ appUsageUserIDs := make (map [appKey ]map [uuid.UUID ]struct {})
2041
+ appUsage := make (map [appKey ]int64 )
2042
+ for uniqueKey , usage := range appUsageIntervalsByUserAgentApp {
2043
+ for _ , seconds := range usage {
2044
+ if appUsageTemplateIDs [uniqueKey .AppKey ] == nil {
2045
+ appUsageTemplateIDs [uniqueKey .AppKey ] = make (map [uuid.UUID ]struct {})
2046
+ }
2047
+ appUsageTemplateIDs [uniqueKey.AppKey ][uniqueKey.TemplateID ] = struct {}{}
2048
+ if appUsageUserIDs [uniqueKey .AppKey ] == nil {
2049
+ appUsageUserIDs [uniqueKey .AppKey ] = make (map [uuid.UUID ]struct {})
2050
+ }
2051
+ appUsageUserIDs [uniqueKey.AppKey ][uniqueKey.UserID ] = struct {}{}
2052
+ appUsage [uniqueKey .AppKey ] += seconds
2053
+ }
2054
+ }
2055
+
2056
+ var rows []database.GetTemplateAppInsightsRow
2057
+ for appKey , usage := range appUsage {
2058
+ templateIDs := make ([]uuid.UUID , 0 , len (appUsageTemplateIDs [appKey ]))
2059
+ for templateID := range appUsageTemplateIDs [appKey ] {
2060
+ templateIDs = append (templateIDs , templateID )
2061
+ }
2062
+ slices .SortFunc (templateIDs , func (a , b uuid.UUID ) int {
2063
+ return slice .Ascending (a .String (), b .String ())
2064
+ })
2065
+ activeUserIDs := make ([]uuid.UUID , 0 , len (appUsageUserIDs [appKey ]))
2066
+ for userID := range appUsageUserIDs [appKey ] {
2067
+ activeUserIDs = append (activeUserIDs , userID )
2068
+ }
2069
+ slices .SortFunc (activeUserIDs , func (a , b uuid.UUID ) int {
2070
+ return slice .Ascending (a .String (), b .String ())
2071
+ })
2072
+
2073
+ rows = append (rows , database.GetTemplateAppInsightsRow {
2074
+ TemplateIDs : templateIDs ,
2075
+ ActiveUserIDs : activeUserIDs ,
2076
+ AccessMethod : appKey .AccessMethod ,
2077
+ SlugOrPort : appKey .SlugOrPort ,
2078
+ DisplayName : sql.NullString {String : appKey .DisplayName , Valid : appKey .DisplayName != "" },
2079
+ Icon : sql.NullString {String : appKey .Icon , Valid : appKey .Icon != "" },
2080
+ IsApp : appKey .Slug != "" ,
2081
+ UsageSeconds : usage ,
2082
+ })
2083
+ }
2084
+
2085
+ return rows , nil
1976
2086
}
1977
2087
1978
2088
func (q * FakeQuerier ) GetTemplateAverageBuildTime (ctx context.Context , arg database.GetTemplateAverageBuildTimeParams ) (database.GetTemplateAverageBuildTimeRow , error ) {
@@ -2102,12 +2212,15 @@ func (q *FakeQuerier) GetTemplateDAUs(_ context.Context, arg database.GetTemplat
2102
2212
return rs , nil
2103
2213
}
2104
2214
2105
- func (q * FakeQuerier ) GetTemplateDailyInsights (_ context.Context , arg database.GetTemplateDailyInsightsParams ) ([]database.GetTemplateDailyInsightsRow , error ) {
2215
+ func (q * FakeQuerier ) GetTemplateDailyInsights (ctx context.Context , arg database.GetTemplateDailyInsightsParams ) ([]database.GetTemplateDailyInsightsRow , error ) {
2106
2216
err := validateDatabaseType (arg )
2107
2217
if err != nil {
2108
2218
return nil , err
2109
2219
}
2110
2220
2221
+ q .mutex .RLock ()
2222
+ defer q .mutex .RUnlock ()
2223
+
2111
2224
type dailyStat struct {
2112
2225
startTime , endTime time.Time
2113
2226
userSet map [uuid.UUID ]struct {}
@@ -2142,6 +2255,37 @@ func (q *FakeQuerier) GetTemplateDailyInsights(_ context.Context, arg database.G
2142
2255
}
2143
2256
}
2144
2257
2258
+ for _ , s := range q .workspaceAppStats {
2259
+ // (was.session_started_at >= ts.from_ AND was.session_started_at < ts.to_)
2260
+ // OR (was.session_ended_at > ts.from_ AND was.session_ended_at < ts.to_)
2261
+ // OR (was.session_started_at < ts.from_ AND was.session_ended_at >= ts.to_)
2262
+ if ! (((s .SessionStartedAt .After (arg .StartTime ) || s .SessionStartedAt .Equal (arg .StartTime )) && s .SessionStartedAt .Before (arg .EndTime )) ||
2263
+ (s .SessionEndedAt .After (arg .StartTime ) && s .SessionEndedAt .Before (arg .EndTime )) ||
2264
+ (s .SessionStartedAt .Before (arg .StartTime ) && (s .SessionEndedAt .After (arg .EndTime ) || s .SessionEndedAt .Equal (arg .EndTime )))) {
2265
+ continue
2266
+ }
2267
+
2268
+ for _ , ds := range dailyStats {
2269
+ // (was.session_started_at >= ts.from_ AND was.session_started_at < ts.to_)
2270
+ // OR (was.session_ended_at > ts.from_ AND was.session_ended_at < ts.to_)
2271
+ // OR (was.session_started_at < ts.from_ AND was.session_ended_at >= ts.to_)
2272
+ if ! (((s .SessionStartedAt .After (arg .StartTime ) || s .SessionStartedAt .Equal (arg .StartTime )) && s .SessionStartedAt .Before (arg .EndTime )) ||
2273
+ (s .SessionEndedAt .After (arg .StartTime ) && s .SessionEndedAt .Before (arg .EndTime )) ||
2274
+ (s .SessionStartedAt .Before (arg .StartTime ) && (s .SessionEndedAt .After (arg .EndTime ) || s .SessionEndedAt .Equal (arg .EndTime )))) {
2275
+ continue
2276
+ }
2277
+
2278
+ w , err := q .getWorkspaceByIDNoLock (ctx , s .WorkspaceID )
2279
+ if err != nil {
2280
+ return nil , err
2281
+ }
2282
+
2283
+ ds .userSet [s .UserID ] = struct {}{}
2284
+ ds .templateIDSet [w .TemplateID ] = struct {}{}
2285
+ break
2286
+ }
2287
+ }
2288
+
2145
2289
var result []database.GetTemplateDailyInsightsRow
2146
2290
for _ , ds := range dailyStats {
2147
2291
templateIDs := make ([]uuid.UUID , 0 , len (ds .templateIDSet ))
@@ -3089,14 +3233,18 @@ func (q *FakeQuerier) GetWorkspaceAgentsInLatestBuildByWorkspaceID(ctx context.C
3089
3233
return agents , nil
3090
3234
}
3091
3235
3092
- func (q * FakeQuerier ) GetWorkspaceAppByAgentIDAndSlug (_ context.Context , arg database.GetWorkspaceAppByAgentIDAndSlugParams ) (database.WorkspaceApp , error ) {
3236
+ func (q * FakeQuerier ) GetWorkspaceAppByAgentIDAndSlug (ctx context.Context , arg database.GetWorkspaceAppByAgentIDAndSlugParams ) (database.WorkspaceApp , error ) {
3093
3237
if err := validateDatabaseType (arg ); err != nil {
3094
3238
return database.WorkspaceApp {}, err
3095
3239
}
3096
3240
3097
3241
q .mutex .RLock ()
3098
3242
defer q .mutex .RUnlock ()
3099
3243
3244
+ return q .getWorkspaceAppByAgentIDAndSlugNoLock (ctx , arg )
3245
+ }
3246
+
3247
+ func (q * FakeQuerier ) getWorkspaceAppByAgentIDAndSlugNoLock (_ context.Context , arg database.GetWorkspaceAppByAgentIDAndSlugParams ) (database.WorkspaceApp , error ) {
3100
3248
for _ , app := range q .workspaceApps {
3101
3249
if app .AgentID != arg .AgentID {
3102
3250
continue
0 commit comments