Skip to content

Commit 476553b

Browse files
committed
refactor: rename warehouse to warehouse long table and extract some logic
1 parent 88940e2 commit 476553b

File tree

7 files changed

+113
-95
lines changed

7 files changed

+113
-95
lines changed

src/server/model/insights/__snapshots__/warehouse.spec.ts.snap

Lines changed: 0 additions & 11 deletions
This file was deleted.

src/server/model/insights/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { insightsSurvey } from './survey.js';
88
import { insightsAIGateway } from './aiGateway.js';
99
import { compact, omit } from 'lodash-es';
1010
import { prisma } from '../_client.js';
11-
import { insightsWarehouse } from './warehouse.js';
11+
import { insightsWarehouse } from './warehouse/longTable.js';
1212
import { INIT_WORKSPACE_ID } from '../../utils/const.js';
1313

1414
export function queryInsight(
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2+
3+
exports[`WarehouseInsightsSqlBuilder > default > sql 1`] = `
4+
"select
5+
DATE_FORMAT(CONVERT_TZ(FROM_UNIXTIME("events"."event_timestamp" / 1000), '+00:00', 'UTC'), '%Y-%m-%d') date , count(1) as "$all_event"
6+
from "events"
7+
where "events"."event_timestamp" BETWEEN '1753977600000' AND '1754064000000' AND (1 = 1)
8+
group by 1
9+
order by 1 desc
10+
limit 1000"
11+
`;
12+
13+
exports[`WarehouseInsightsSqlBuilder > with filter > sql 1`] = `
14+
"select
15+
DATE_FORMAT(CONVERT_TZ(FROM_UNIXTIME("events"."event_timestamp" / 1000), '+00:00', 'UTC'), '%Y-%m-%d') date , count(1) as "$all_event"
16+
from "events" INNER JOIN "event_parameters" ON "events"."event_name" = "event_parameters"."event_name" AND "event_parameters"."event_param_value" = 'value'
17+
where "events"."event_timestamp" BETWEEN '1753977600000' AND '1754064000000' AND (1 = 1)
18+
group by 1
19+
order by 1 desc
20+
limit 1000"
21+
`;

src/server/model/insights/warehouse.spec.ts renamed to src/server/model/insights/warehouse/longTable.spec.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { beforeAll, describe, expect, test } from 'vitest';
2-
import { WarehouseInsightsSqlBuilder } from './warehouse.js';
3-
import { unwrapSQL } from '../../utils/prisma.js';
2+
import { WarehouseLongTableInsightsSqlBuilder } from './longTable.js';
3+
import { unwrapSQL } from '../../../utils/prisma.js';
44
import dayjs from 'dayjs';
5-
import { env } from '../../utils/env.js';
5+
import { env } from '../../../utils/env.js';
66

77
describe('WarehouseInsightsSqlBuilder', () => {
88
const insightId = 'test'; // application name
@@ -29,7 +29,7 @@ describe('WarehouseInsightsSqlBuilder', () => {
2929
});
3030

3131
test('default', () => {
32-
const builder = new WarehouseInsightsSqlBuilder(
32+
const builder = new WarehouseLongTableInsightsSqlBuilder(
3333
{
3434
insightId,
3535
insightType,
@@ -58,7 +58,7 @@ describe('WarehouseInsightsSqlBuilder', () => {
5858
});
5959

6060
test('with filter', () => {
61-
const builder = new WarehouseInsightsSqlBuilder(
61+
const builder = new WarehouseLongTableInsightsSqlBuilder(
6262
{
6363
insightId,
6464
insightType,

src/server/model/insights/warehouse.ts renamed to src/server/model/insights/warehouse/longTable.ts

Lines changed: 13 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -3,85 +3,22 @@
33
*/
44

55
import { Prisma } from '@prisma/client';
6-
import { InsightsSqlBuilder } from './shared.js';
7-
import { createPool, Pool } from 'mysql2/promise';
8-
import { insightsQuerySchema } from '../../utils/schema.js';
6+
import { InsightsSqlBuilder } from '../shared.js';
7+
import { insightsQuerySchema } from '../../../utils/schema.js';
98
import { z } from 'zod';
109
import dayjs from 'dayjs';
11-
import { processGroupedTimeSeriesData } from './utils.js';
12-
import { env } from '../../utils/env.js';
10+
import { processGroupedTimeSeriesData } from '../utils.js';
1311
import { FilterInfoType, FilterInfoValue } from '@tianji/shared';
1412
import { compact, get } from 'lodash-es';
15-
16-
// MySQL date formats for different time units
17-
const MYSQL_DATE_FORMATS = {
18-
minute: '%Y-%m-%d %H:%i:00',
19-
hour: '%Y-%m-%d %H:00:00',
20-
day: '%Y-%m-%d',
21-
month: '%Y-%m-01',
22-
year: '%Y-01-01',
23-
} as const;
24-
25-
const dateTypeSchema = z.enum([
26-
'timestamp', // for example: 1739203200
27-
'timestampMs', // for example: 1739203200000
28-
'date', // for example: 2025-08-01
29-
'datetime', // for example: 2025-08-01 00:00:00
30-
]);
31-
32-
export const warehouseInsightsApplicationSchema = z.object({
33-
name: z.string(),
34-
type: z.enum(['longTable', 'wideTable']).default('longTable'), // long table or wide table, TODO: implement wide table support
35-
eventTable: z.object({
36-
name: z.string(),
37-
eventNameField: z.string(),
38-
createdAtField: z.string(),
39-
createdAtFieldType: dateTypeSchema.default('timestampMs'),
40-
dateBasedCreatedAtField: z.string().optional(), // for improve performance, treat as date type
41-
}),
42-
eventParametersTable: z.object({
43-
name: z.string(),
44-
eventNameField: z.string(),
45-
paramsNameField: z.string(),
46-
paramsValueField: z.string(),
47-
paramsValueNumberField: z.string().optional(),
48-
paramsValueStringField: z.string().optional(),
49-
paramsValueDateField: z.string().optional(),
50-
createdAtField: z.string(),
51-
createdAtFieldType: dateTypeSchema.default('timestampMs'),
52-
dateBasedCreatedAtField: z.string().optional(), // for improve performance, treat as date type
53-
}),
54-
});
55-
56-
export type WarehouseInsightsApplication = z.infer<
57-
typeof warehouseInsightsApplicationSchema
58-
>;
59-
60-
let applications: WarehouseInsightsApplication[] | null = null;
61-
export function getWarehouseApplications() {
62-
if (!applications) {
63-
applications = warehouseInsightsApplicationSchema
64-
.array()
65-
.parse(JSON.parse(env.insights.warehouse.applicationsJson || '[]'));
66-
}
67-
68-
return applications;
69-
}
70-
71-
let connection: Pool | null = null;
72-
export function getWarehouseConnection() {
73-
if (!env.insights.warehouse.enable || !env.insights.warehouse.url) {
74-
throw new Error('Warehouse is not enabled');
75-
}
76-
77-
if (!connection) {
78-
connection = createPool(env.insights.warehouse.url);
79-
}
80-
81-
return connection;
82-
}
83-
84-
export class WarehouseInsightsSqlBuilder extends InsightsSqlBuilder {
13+
import {
14+
dateTypeSchema,
15+
getWarehouseApplications,
16+
getWarehouseConnection,
17+
MYSQL_DATE_FORMATS,
18+
WarehouseInsightsApplication,
19+
} from './utils.js';
20+
21+
export class WarehouseLongTableInsightsSqlBuilder extends InsightsSqlBuilder {
8522
getApplication(): WarehouseInsightsApplication {
8623
const name = this.query.insightId;
8724

@@ -430,7 +367,7 @@ export async function insightsWarehouse(
430367
query: z.infer<typeof insightsQuerySchema>,
431368
context: { timezone: string }
432369
) {
433-
const builder = new WarehouseInsightsSqlBuilder(query, context);
370+
const builder = new WarehouseLongTableInsightsSqlBuilder(query, context);
434371
const sql = builder.build();
435372

436373
const data = await builder.executeQuery(sql);
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { z } from 'zod';
2+
import { createPool, Pool } from 'mysql2/promise';
3+
import { env } from '../../../utils/env.js';
4+
5+
// MySQL date formats for different time units
6+
export const MYSQL_DATE_FORMATS = {
7+
minute: '%Y-%m-%d %H:%i:00',
8+
hour: '%Y-%m-%d %H:00:00',
9+
day: '%Y-%m-%d',
10+
month: '%Y-%m-01',
11+
year: '%Y-01-01',
12+
} as const;
13+
14+
export const dateTypeSchema = z.enum([
15+
'timestamp', // for example: 1739203200
16+
'timestampMs', // for example: 1739203200000
17+
'date', // for example: 2025-08-01
18+
'datetime', // for example: 2025-08-01 00:00:00
19+
]);
20+
21+
export const warehouseInsightsApplicationSchema = z.object({
22+
name: z.string(),
23+
type: z.enum(['longTable', 'wideTable']).default('longTable'), // long table or wide table, TODO: implement wide table support
24+
eventTable: z.object({
25+
name: z.string(),
26+
eventNameField: z.string(),
27+
createdAtField: z.string(),
28+
createdAtFieldType: dateTypeSchema.default('timestampMs'),
29+
dateBasedCreatedAtField: z.string().optional(), // for improve performance, treat as date type
30+
}),
31+
eventParametersTable: z.object({
32+
name: z.string(),
33+
eventNameField: z.string(),
34+
paramsNameField: z.string(),
35+
paramsValueField: z.string(),
36+
paramsValueNumberField: z.string().optional(),
37+
paramsValueStringField: z.string().optional(),
38+
paramsValueDateField: z.string().optional(),
39+
createdAtField: z.string(),
40+
createdAtFieldType: dateTypeSchema.default('timestampMs'),
41+
dateBasedCreatedAtField: z.string().optional(), // for improve performance, treat as date type
42+
}),
43+
});
44+
45+
export type WarehouseInsightsApplication = z.infer<
46+
typeof warehouseInsightsApplicationSchema
47+
>;
48+
49+
let applications: WarehouseInsightsApplication[] | null = null;
50+
export function getWarehouseApplications() {
51+
if (!applications) {
52+
applications = warehouseInsightsApplicationSchema
53+
.array()
54+
.parse(JSON.parse(env.insights.warehouse.applicationsJson || '[]'));
55+
}
56+
57+
return applications;
58+
}
59+
60+
let connection: Pool | null = null;
61+
export function getWarehouseConnection() {
62+
if (!env.insights.warehouse.enable || !env.insights.warehouse.url) {
63+
throw new Error('Warehouse is not enabled');
64+
}
65+
66+
if (!connection) {
67+
connection = createPool(env.insights.warehouse.url);
68+
}
69+
70+
return connection;
71+
}

src/server/trpc/routers/insights.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ import { queryEvents, queryInsight } from '../../model/insights/index.js';
1212
import { insightsSurveyBuiltinFields } from '../../model/insights/utils.js';
1313
import { uniq } from 'lodash-es';
1414
import {
15-
getWarehouseApplications,
1615
insightsWarehouseEvents,
1716
insightsWarehouseFilterParams,
18-
} from '../../model/insights/warehouse.js';
17+
} from '../../model/insights/warehouse/longTable.js';
18+
import { getWarehouseApplications } from '../../model/insights/warehouse/utils.js';
1919

2020
export const insightsRouter = router({
2121
query: workspaceProcedure

0 commit comments

Comments
 (0)