-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathschema.ts
More file actions
92 lines (83 loc) · 2.15 KB
/
Copy pathschema.ts
File metadata and controls
92 lines (83 loc) · 2.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import type { ClickHouseClient } from "@clickhouse/client";
import path from "path";
function stripSqlComments(sql: string): string {
return sql.replace(/--[^\n]*/g, "");
}
function splitSqlStatements(sql: string): string[] {
const cleaned = stripSqlComments(sql);
const statements: string[] = [];
let depth = 0;
let current = "";
for (const char of cleaned) {
current += char;
if (char === "(") {
depth += 1;
} else if (char === ")") {
depth = Math.max(0, depth - 1);
} else if (char === ";" && depth === 0) {
const statement = current.trim();
if (statement.length > 1) {
statements.push(statement);
}
current = "";
}
}
const trailing = current.trim();
if (trailing.length > 0) {
statements.push(trailing);
}
return statements;
}
function isIdempotentSchemaError(error: unknown): boolean {
const message =
error instanceof Error
? error.message
: typeof error === "string"
? error
: String(error);
const normalized = message.toLowerCase();
return (
normalized.includes("already exists") ||
normalized.includes("table already exists") ||
normalized.includes("table_exists") ||
normalized.includes("database already exists")
);
}
// Every archive database owned by the forwarder. Each file self-creates its
// database and tables idempotently; the forwarder fail-closes if any cannot be
// applied (see index.ts).
const ARCHIVE_SCHEMA_FILES = [
"market_data.sql",
"broker_execution.sql",
"broker_account.sql",
"broker_stream_health.sql",
"strategy_data.sql",
] as const;
async function applySchemaFile(
client: ClickHouseClient,
fileName: string,
): Promise<void> {
const schemaPath = path.resolve(
import.meta.dir,
"../../schema/clickhouse",
fileName,
);
const sql = await Bun.file(schemaPath).text();
for (const statement of splitSqlStatements(sql)) {
try {
await client.command({ query: statement });
} catch (error) {
if (isIdempotentSchemaError(error)) {
continue;
}
throw error;
}
}
}
export async function ensureArchiveSchema(
client: ClickHouseClient,
): Promise<void> {
for (const fileName of ARCHIVE_SCHEMA_FILES) {
await applySchemaFile(client, fileName);
}
}