Skip to content

Commit

Permalink
(feature) Cumulative mode (#197)
Browse files Browse the repository at this point in the history
* added support for cumulative mode

* added custom events & selfhosted support

* fix unreachable code after return
  • Loading branch information
Blaumaus authored Oct 15, 2023
1 parent 9238275 commit 469ee8f
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 10 deletions.
7 changes: 6 additions & 1 deletion apps/production/src/analytics/analytics.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ import { DEFAULT_TIMEZONE } from '../user/entities/user.entity'
import { RolesGuard } from '../auth/guards/roles.guard'
import { PageviewsDTO } from './dto/pageviews.dto'
import { EventsDTO } from './dto/events.dto'
import { AnalyticsGET_DTO } from './dto/getData.dto'
import { AnalyticsGET_DTO, ChartRenderMode } from './dto/getData.dto'
import { GetCustomEventMetadata } from './dto/get-custom-event-meta.dto'
import { GetUserFlowDTO } from './dto/getUserFlow.dto'
import { AppLoggerService } from '../logger/logger.service'
Expand Down Expand Up @@ -296,6 +296,7 @@ export class AnalyticsController {
to,
filters,
timezone = DEFAULT_TIMEZONE,
mode = ChartRenderMode.PERIODICAL,
} = data
this.analyticsService.validatePID(pid)

Expand Down Expand Up @@ -378,6 +379,7 @@ export class AnalyticsController {
filtersQuery,
paramsData,
safeTimezone,
mode,
)
} else {
result = await this.analyticsService.groupByTimeBucket(
Expand All @@ -390,6 +392,7 @@ export class AnalyticsController {
safeTimezone,
customEVFilterApplied,
appliedFilters,
mode,
)
}

Expand Down Expand Up @@ -471,6 +474,7 @@ export class AnalyticsController {
to,
filters,
timezone = DEFAULT_TIMEZONE,
mode = ChartRenderMode.PERIODICAL,
} = data
this.analyticsService.validatePID(pid)

Expand Down Expand Up @@ -520,6 +524,7 @@ export class AnalyticsController {
paramsData,
safeTimezone,
customEVFilterApplied,
mode,
)

return {
Expand Down
53 changes: 49 additions & 4 deletions apps/production/src/analytics/analytics.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ import { PageviewsDTO } from './dto/pageviews.dto'
import { EventsDTO } from './dto/events.dto'
import { ProjectService } from '../project/project.service'
import { Project } from '../project/entity/project.entity'
import { TimeBucketType } from './dto/getData.dto'
import { ChartRenderMode, TimeBucketType } from './dto/getData.dto'
import { GetCustomEventMetadata } from './dto/get-custom-event-meta.dto'
import {
PerformanceCHResponse,
Expand Down Expand Up @@ -1225,13 +1225,14 @@ export class AnalyticsService {
timeBucket: TimeBucketType,
filtersQuery: string,
safeTimezone: string,
mode: ChartRenderMode,
): string {
const timeBucketFunc = timeBucketConversion[timeBucket]
const [selector, groupBy] = this.getGroupSubquery(timeBucket)
const tzFromDate = `toTimeZone(parseDateTimeBestEffort({groupFrom:String}), '${safeTimezone}')`
const tzToDate = `toTimeZone(parseDateTimeBestEffort({groupTo:String}), '${safeTimezone}')`

return `
const baseQuery = `
SELECT
${selector},
avg(sdur) as sdur,
Expand All @@ -1248,20 +1249,33 @@ export class AnalyticsService {
) as subquery
GROUP BY ${groupBy}
ORDER BY ${groupBy}
`

if (mode === ChartRenderMode.CUMULATIVE) {
return `
SELECT
*,
sum(pageviews) OVER (ORDER BY ${groupBy}) as pageviews,
sum(uniques) OVER (ORDER BY ${groupBy}) as uniques
FROM (${baseQuery})
`
}

return baseQuery
}

generateCustomEventsAggregationQuery(
timeBucket: TimeBucketType,
filtersQuery: string,
safeTimezone: string,
mode: ChartRenderMode,
): string {
const timeBucketFunc = timeBucketConversion[timeBucket]
const [selector, groupBy] = this.getGroupSubquery(timeBucket)
const tzFromDate = `toTimeZone(parseDateTimeBestEffort({groupFrom:String}), '${safeTimezone}')`
const tzToDate = `toTimeZone(parseDateTimeBestEffort({groupTo:String}), '${safeTimezone}')`

return `
const baseQuery = `
SELECT
${selector},
count() as count
Expand All @@ -1276,6 +1290,17 @@ export class AnalyticsService {
GROUP BY ${groupBy}
ORDER BY ${groupBy}
`

if (mode === ChartRenderMode.CUMULATIVE) {
return `
SELECT
*,
sum(count) OVER (ORDER BY ${groupBy}) as count
FROM (${baseQuery})
`
}

return baseQuery
}

generatePerformanceAggregationQuery(
Expand Down Expand Up @@ -1316,13 +1341,14 @@ export class AnalyticsService {
timeBucket: TimeBucketType,
filtersQuery: string,
safeTimezone: string,
mode: ChartRenderMode,
): string {
const timeBucketFunc = timeBucketConversion[timeBucket]
const [selector, groupBy] = this.getGroupSubquery(timeBucket)
const tzFromDate = `toTimeZone(parseDateTimeBestEffort({groupFrom:String}), '${safeTimezone}')`
const tzToDate = `toTimeZone(parseDateTimeBestEffort({groupTo:String}), '${safeTimezone}')`

return `
const baseQuery = `
SELECT
${selector},
count() as count
Expand All @@ -1337,7 +1363,19 @@ export class AnalyticsService {
) as subquery
GROUP BY ${groupBy}
ORDER BY ${groupBy}
`

if (mode === ChartRenderMode.CUMULATIVE) {
return `
SELECT
*,
sum(pageviews) OVER (ORDER BY ${groupBy}) as pageviews,
sum(uniques) OVER (ORDER BY ${groupBy}) as uniques
FROM (${baseQuery})
`
}

return baseQuery
}

async groupByTimeBucket(
Expand All @@ -1350,6 +1388,7 @@ export class AnalyticsService {
safeTimezone: string,
customEVFilterApplied: boolean,
parsedFilters: Array<{ [key: string]: string }>,
mode: ChartRenderMode,
): Promise<object | void> {
let params: unknown = {}
let chart: unknown = {}
Expand Down Expand Up @@ -1383,6 +1422,7 @@ export class AnalyticsService {
paramsData,
safeTimezone,
customEVFilterApplied,
mode,
)

// @ts-ignore
Expand Down Expand Up @@ -1427,6 +1467,7 @@ export class AnalyticsService {
paramsData: any,
safeTimezone: string,
customEVFilterApplied: boolean,
mode: ChartRenderMode,
): Promise<object | void> {
const avgSdur = customEVFilterApplied
? 0
Expand All @@ -1439,6 +1480,7 @@ export class AnalyticsService {
timeBucket,
filtersQuery,
safeTimezone,
mode,
)

const result = <Array<TrafficCEFilterCHResponse>>(
Expand Down Expand Up @@ -1466,6 +1508,7 @@ export class AnalyticsService {
timeBucket,
filtersQuery,
safeTimezone,
mode,
)

const result = <Array<TrafficCHResponse>>(
Expand Down Expand Up @@ -1511,6 +1554,7 @@ export class AnalyticsService {
filtersQuery: string,
paramsData: object,
safeTimezone: string,
mode: ChartRenderMode,
): Promise<object | void> {
let params: unknown = {}
let chart: unknown = {}
Expand Down Expand Up @@ -1547,6 +1591,7 @@ export class AnalyticsService {
timeBucket,
filtersQuery,
safeTimezone,
mode,
)

const result = <Array<TrafficCEFilterCHResponse>>(
Expand Down
12 changes: 12 additions & 0 deletions apps/production/src/analytics/dto/getData.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ export enum TimeBucketType {
YEAR = 'year',
}

export enum ChartRenderMode {
PERIODICAL = 'periodical',
CUMULATIVE = 'cumulative',
}

// eslint-disable-next-line @typescript-eslint/naming-convention
export class AnalyticsGET_DTO {
@ApiProperty()
Expand Down Expand Up @@ -40,4 +45,11 @@ export class AnalyticsGET_DTO {
default: DEFAULT_TIMEZONE,
})
timezone: string

@ApiProperty({
description:
'Mode in which data in chart should be rendered, may be either periodical or cumulative',
default: ChartRenderMode.PERIODICAL,
})
mode?: ChartRenderMode
}
6 changes: 5 additions & 1 deletion apps/selfhosted/src/analytics/analytics.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ import { DEFAULT_TIMEZONE } from '../user/entities/user.entity'
import { RolesGuard } from '../auth/guards/roles.guard'
import { PageviewsDTO } from './dto/pageviews.dto'
import { EventsDTO } from './dto/events.dto'
import { AnalyticsGET_DTO } from './dto/getData.dto'
import { AnalyticsGET_DTO, ChartRenderMode } from './dto/getData.dto'
import { GetFiltersDto } from './dto/get-filters.dto'
import { GetCustomEventMetadata } from './dto/get-custom-event-meta.dto'
import { GetUserFlowDTO } from './dto/getUserFlow.dto'
Expand Down Expand Up @@ -288,6 +288,7 @@ export class AnalyticsController {
to,
filters,
timezone = DEFAULT_TIMEZONE,
mode = ChartRenderMode.PERIODICAL,
} = data
this.analyticsService.validatePID(pid)

Expand Down Expand Up @@ -360,6 +361,7 @@ export class AnalyticsController {
safeTimezone,
customEVFilterApplied,
parsedFilters,
mode,
)

const customs = await this.analyticsService.processCustomEV(
Expand Down Expand Up @@ -421,6 +423,7 @@ export class AnalyticsController {
to,
filters,
timezone = DEFAULT_TIMEZONE,
mode = ChartRenderMode.PERIODICAL,
} = data
this.analyticsService.validatePID(pid)

Expand Down Expand Up @@ -466,6 +469,7 @@ export class AnalyticsController {
paramsData,
safeTimezone,
customEVFilterApplied,
mode,
)

return {
Expand Down
Loading

0 comments on commit 469ee8f

Please sign in to comment.