MCPcopy Create free account
hub / github.com/Openpanel-dev/openpanel / up

Function up

packages/db/code-migrations/16-restructure-profiles.ts:66–210  ·  view source on GitHub ↗
()

Source from the content-addressed store, hash-verified

64const replicated = (table: string) => `${table}_replicated`;
65
66export async function up() {
67 const isClustered = getIsCluster();
68 const sqls: string[] = [];
69
70 // 1. New profiles table. ReplacingMergeTree's version is now `last_seen_at`,
71 // so the latest activity timestamp wins on dedup — and `created_at` is
72 // preserved naturally (no longer the version, no special merge handling).
73 const profileTables = createTable({
74 name: NEW_TABLE,
75 columns: [
76 '`id` String CODEC(ZSTD(3))',
77 '`is_external` Bool',
78 '`first_name` String CODEC(ZSTD(3))',
79 '`last_name` String CODEC(ZSTD(3))',
80 '`email` String CODEC(ZSTD(3))',
81 '`avatar` String CODEC(ZSTD(3))',
82 '`properties` Map(String, String) CODEC(ZSTD(3))',
83 '`project_id` String CODEC(ZSTD(3))',
84 '`groups` Array(String) DEFAULT [] CODEC(ZSTD(3))',
85 '`created_at` DateTime64(3) CODEC(Delta(4), LZ4)',
86 '`last_seen_at` DateTime64(3) CODEC(Delta(4), LZ4)',
87 ],
88 indices: [
89 'INDEX idx_first_name first_name TYPE bloom_filter GRANULARITY 1',
90 'INDEX idx_last_name last_name TYPE bloom_filter GRANULARITY 1',
91 'INDEX idx_email email TYPE bloom_filter GRANULARITY 1',
92 ],
93 engine: 'ReplacingMergeTree(last_seen_at)',
94 orderBy: ['project_id', 'id'],
95 partitionBy: 'toYYYYMM(created_at)',
96 settings: { index_granularity: 8192 },
97 distributionHash: 'cityHash64(project_id)',
98 replicatedVersion: '2',
99 isClustered,
100 });
101 sqls.push(...profileTables);
102
103 // 2. Find the oldest profile so we know how far back to batch.
104 const firstProfileResp = await chMigrationClient.query({
105 query: 'SELECT min(created_at) AS created_at FROM profiles',
106 format: 'JSONEachRow',
107 });
108 const firstProfileJson = await firstProfileResp.json<{
109 created_at: string;
110 }>();
111 const firstDate = firstProfileJson[0]?.created_at;
112
113 if (firstDate && !firstDate.startsWith('1970')) {
114 const startDate = new Date(firstDate);
115 const endDate = new Date();
116 endDate.setMonth(endDate.getMonth() + 1);
117 endDate.setDate(1);
118
119 const monthBoundary = (d: Date) =>
120 `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-01`;
121
122 let cursor = new Date(endDate);
123 while (true) {

Callers

nothing calls this directly

Calls 11

getIsClusterFunction · 0.90
createTableFunction · 0.90
renameTableFunction · 0.90
monthBoundaryFunction · 0.85
queryMethod · 0.80
joinMethod · 0.80
replaceMethod · 0.80
replicatedFunction · 0.70
pushMethod · 0.45
mapMethod · 0.45

Tested by

no test coverage detected