@querypanel/node-sdk 1.0.17 → 1.0.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/__tests__/ingest.test.d.ts +5 -0
- package/dist/cjs/__tests__/ingest.test.d.ts.map +1 -0
- package/dist/cjs/__tests__/ingest.test.js +95 -0
- package/dist/cjs/__tests__/ingest.test.js.map +1 -0
- package/dist/cjs/connectors/__tests__/clickhouse.introspect.test.d.ts +2 -0
- package/dist/cjs/connectors/__tests__/clickhouse.introspect.test.d.ts.map +1 -0
- package/dist/cjs/connectors/__tests__/clickhouse.introspect.test.js +119 -0
- package/dist/cjs/connectors/__tests__/clickhouse.introspect.test.js.map +1 -0
- package/dist/cjs/connectors/base.d.ts +2 -3
- package/dist/cjs/connectors/base.d.ts.map +1 -1
- package/dist/cjs/connectors/clickhouse.d.ts +28 -10
- package/dist/cjs/connectors/clickhouse.d.ts.map +1 -1
- package/dist/cjs/connectors/clickhouse.js +55 -77
- package/dist/cjs/connectors/clickhouse.js.map +1 -1
- package/dist/cjs/index.d.ts +26 -0
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +114 -5
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/tenant-isolation.spec.d.ts +2 -0
- package/dist/cjs/tenant-isolation.spec.d.ts.map +1 -0
- package/dist/cjs/tenant-isolation.spec.js +366 -0
- package/dist/cjs/tenant-isolation.spec.js.map +1 -0
- package/dist/esm/connectors/clickhouse.d.ts +4 -4
- package/dist/esm/connectors/clickhouse.d.ts.map +1 -1
- package/dist/esm/connectors/clickhouse.js +25 -32
- package/dist/esm/connectors/clickhouse.js.map +1 -1
- package/dist/esm/index.d.ts +26 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +114 -5
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/tenant-isolation.spec.d.ts +2 -0
- package/dist/esm/tenant-isolation.spec.d.ts.map +1 -0
- package/dist/esm/tenant-isolation.spec.js +364 -0
- package/dist/esm/tenant-isolation.spec.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ingest.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/ingest.test.ts"],"names":[],"mappings":"AAKA,OAAO,CAAC,MAAM,CAAC;IAEX,IAAI,KAAK,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CACtC"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
const index_js_1 = require("../index.js");
|
|
5
|
+
const noop = () => { };
|
|
6
|
+
class StubConnector {
|
|
7
|
+
constructor(introspection) {
|
|
8
|
+
this.introspection = introspection;
|
|
9
|
+
this.connect = vitest_1.vi.fn(async () => { });
|
|
10
|
+
this.close = vitest_1.vi.fn(async () => { });
|
|
11
|
+
this.executeQuery = vitest_1.vi.fn(async () => []);
|
|
12
|
+
this.introspect = vitest_1.vi.fn(async (_options) => this.introspection);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
(0, vitest_1.describe)('Ingestion API', () => {
|
|
16
|
+
const originalFetch = globalThis.fetch;
|
|
17
|
+
const fakeResponse = {
|
|
18
|
+
ok: true,
|
|
19
|
+
status: 200,
|
|
20
|
+
text: async () => JSON.stringify({ message: 'ok', ingestedTables: 1 }),
|
|
21
|
+
};
|
|
22
|
+
let fetchMock;
|
|
23
|
+
(0, vitest_1.beforeEach)(() => {
|
|
24
|
+
fetchMock = vitest_1.vi.fn().mockResolvedValue(fakeResponse);
|
|
25
|
+
globalThis.fetch = fetchMock;
|
|
26
|
+
});
|
|
27
|
+
(0, vitest_1.afterEach)(() => {
|
|
28
|
+
fetchMock.mockReset();
|
|
29
|
+
if (originalFetch) {
|
|
30
|
+
globalThis.fetch = originalFetch;
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
delete globalThis.fetch;
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
(0, vitest_1.it)('posts schema introspection payloads with merged metadata', async () => {
|
|
37
|
+
const sdk = new index_js_1.QueryPanelSdkAPI('https://example.com', 'token');
|
|
38
|
+
const introspection = {
|
|
39
|
+
db: { kind: 'clickhouse', name: 'analytics' },
|
|
40
|
+
tables: [],
|
|
41
|
+
introspectedAt: new Date().toISOString(),
|
|
42
|
+
metadata: { existing: true },
|
|
43
|
+
};
|
|
44
|
+
const response = await sdk.ingestSchema(introspection, {
|
|
45
|
+
tenantId: 'tenant-1',
|
|
46
|
+
metadata: { triggeredBy: 'test' },
|
|
47
|
+
});
|
|
48
|
+
(0, vitest_1.expect)(response).toMatchObject({ message: 'ok', ingestedTables: 1 });
|
|
49
|
+
(0, vitest_1.expect)(fetchMock).toHaveBeenCalledTimes(1);
|
|
50
|
+
const [url, init] = fetchMock.mock.calls[0];
|
|
51
|
+
(0, vitest_1.expect)(url).toBe('https://example.com/ingest/schema');
|
|
52
|
+
(0, vitest_1.expect)(init.method).toBe('POST');
|
|
53
|
+
(0, vitest_1.expect)(init.headers).toMatchObject({
|
|
54
|
+
Authorization: 'Bearer token',
|
|
55
|
+
'Content-Type': 'application/json',
|
|
56
|
+
});
|
|
57
|
+
const body = JSON.parse(init.body);
|
|
58
|
+
(0, vitest_1.expect)(body.metadata).toEqual({ existing: true, triggeredBy: 'test' });
|
|
59
|
+
});
|
|
60
|
+
(0, vitest_1.it)('introspects via connector and closes connections by default', async () => {
|
|
61
|
+
const sdk = new index_js_1.QueryPanelSdkAPI('https://example.com', 'token');
|
|
62
|
+
const introspection = {
|
|
63
|
+
db: { kind: 'clickhouse', name: 'analytics' },
|
|
64
|
+
tables: [],
|
|
65
|
+
introspectedAt: new Date().toISOString(),
|
|
66
|
+
};
|
|
67
|
+
const connector = new StubConnector(introspection);
|
|
68
|
+
const response = await sdk.introspectAndIngest(connector, {
|
|
69
|
+
tenantId: 'tenant-1',
|
|
70
|
+
metadata: { flow: 'batch' },
|
|
71
|
+
tables: ['events'],
|
|
72
|
+
});
|
|
73
|
+
(0, vitest_1.expect)(response.message).toBe('ok');
|
|
74
|
+
(0, vitest_1.expect)(connector.connect).toHaveBeenCalledTimes(1);
|
|
75
|
+
(0, vitest_1.expect)(connector.introspect).toHaveBeenCalledWith({ tables: ['events'] });
|
|
76
|
+
(0, vitest_1.expect)(connector.close).toHaveBeenCalledTimes(1);
|
|
77
|
+
const [, init] = fetchMock.mock.calls[0];
|
|
78
|
+
const body = JSON.parse(init.body);
|
|
79
|
+
(0, vitest_1.expect)(body.metadata).toEqual({ flow: 'batch' });
|
|
80
|
+
});
|
|
81
|
+
(0, vitest_1.it)('respects keepConnectionOpen option', async () => {
|
|
82
|
+
const sdk = new index_js_1.QueryPanelSdkAPI('https://example.com', 'token');
|
|
83
|
+
const connector = new StubConnector({
|
|
84
|
+
db: { kind: 'clickhouse', name: 'analytics' },
|
|
85
|
+
tables: [],
|
|
86
|
+
introspectedAt: new Date().toISOString(),
|
|
87
|
+
});
|
|
88
|
+
await sdk.introspectAndIngest(connector, {
|
|
89
|
+
tenantId: 'tenant-1',
|
|
90
|
+
keepConnectionOpen: true,
|
|
91
|
+
});
|
|
92
|
+
(0, vitest_1.expect)(connector.close).not.toHaveBeenCalled();
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
//# sourceMappingURL=ingest.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ingest.test.js","sourceRoot":"","sources":["../../../src/__tests__/ingest.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clickhouse.introspect.test.d.ts","sourceRoot":"","sources":["../../../../src/connectors/__tests__/clickhouse.introspect.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
const clickhouse_js_1 = require("../clickhouse.js");
|
|
5
|
+
class StubResultSet {
|
|
6
|
+
constructor(payload) {
|
|
7
|
+
this.payload = payload;
|
|
8
|
+
}
|
|
9
|
+
async json() {
|
|
10
|
+
return this.payload;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
class StubClickHouseClient {
|
|
14
|
+
constructor(responses) {
|
|
15
|
+
this.queries = [];
|
|
16
|
+
this.responses = responses;
|
|
17
|
+
}
|
|
18
|
+
async query(params) {
|
|
19
|
+
this.queries.push({ query: params.query, params: params.query_params });
|
|
20
|
+
const responseKey = params.query.includes('system.tables') ? 'tables' : 'columns';
|
|
21
|
+
const payload = this.responses.get(responseKey);
|
|
22
|
+
if (!payload) {
|
|
23
|
+
throw new Error(`No stub response registered for ${responseKey}`);
|
|
24
|
+
}
|
|
25
|
+
return new StubResultSet(payload);
|
|
26
|
+
}
|
|
27
|
+
async ping() {
|
|
28
|
+
return { success: true };
|
|
29
|
+
}
|
|
30
|
+
async close() { }
|
|
31
|
+
}
|
|
32
|
+
(0, vitest_1.describe)('ClickHouseConnector', () => {
|
|
33
|
+
(0, vitest_1.it)('introspects tables with large column counts', async () => {
|
|
34
|
+
const tableRows = [
|
|
35
|
+
{
|
|
36
|
+
name: 'events',
|
|
37
|
+
engine: 'MergeTree',
|
|
38
|
+
comment: 'User event stream',
|
|
39
|
+
total_rows: '424242',
|
|
40
|
+
total_bytes: '1024',
|
|
41
|
+
is_view: 0,
|
|
42
|
+
primary_key: 'tuple(event_id, occurred_at)',
|
|
43
|
+
sorting_key: 'tuple(occurred_at)',
|
|
44
|
+
},
|
|
45
|
+
];
|
|
46
|
+
const columnRows = Array.from({ length: 120 }, (_, index) => ({
|
|
47
|
+
table: 'events',
|
|
48
|
+
name: `column_${index}`,
|
|
49
|
+
type: index % 2 === 0 ? 'Nullable(String)' : 'UInt32',
|
|
50
|
+
position: index + 1,
|
|
51
|
+
default_kind: index % 10 === 0 ? 'DEFAULT' : null,
|
|
52
|
+
default_expression: index % 10 === 0 ? `'value_${index}'` : null,
|
|
53
|
+
comment: index % 15 === 0 ? `Column ${index}` : null,
|
|
54
|
+
codec_expression: index % 20 === 0 ? 'ZSTD(3)' : null,
|
|
55
|
+
ttl_expression: null,
|
|
56
|
+
is_in_primary_key: index === 0 ? 1 : 0,
|
|
57
|
+
data_compressed_bytes: '128',
|
|
58
|
+
data_uncompressed_bytes: '256',
|
|
59
|
+
}));
|
|
60
|
+
const responses = new Map([
|
|
61
|
+
['tables', tableRows],
|
|
62
|
+
['columns', columnRows],
|
|
63
|
+
]);
|
|
64
|
+
const stubClient = new StubClickHouseClient(responses);
|
|
65
|
+
const connector = new clickhouse_js_1.ClickHouseConnector({
|
|
66
|
+
database: 'analytics',
|
|
67
|
+
}, { client: stubClient });
|
|
68
|
+
const introspection = await connector.introspect();
|
|
69
|
+
(0, vitest_1.expect)(introspection.db).toEqual({ kind: 'clickhouse', name: 'analytics' });
|
|
70
|
+
(0, vitest_1.expect)(introspection.tables).toHaveLength(1);
|
|
71
|
+
const [table] = introspection.tables;
|
|
72
|
+
(0, vitest_1.expect)(table.name).toBe('events');
|
|
73
|
+
(0, vitest_1.expect)(table.columns).toHaveLength(120);
|
|
74
|
+
(0, vitest_1.expect)(table.columns[0]).toMatchObject({
|
|
75
|
+
name: 'column_0',
|
|
76
|
+
nullable: true,
|
|
77
|
+
type: 'String',
|
|
78
|
+
rawType: 'Nullable(String)',
|
|
79
|
+
defaultKind: 'DEFAULT',
|
|
80
|
+
defaultExpression: `'value_0'`,
|
|
81
|
+
statistics: { compressedBytes: 128, uncompressedBytes: 256 },
|
|
82
|
+
});
|
|
83
|
+
(0, vitest_1.expect)(table.columns.at(-1)).toMatchObject({
|
|
84
|
+
nullable: false,
|
|
85
|
+
type: 'UInt32',
|
|
86
|
+
});
|
|
87
|
+
(0, vitest_1.expect)(table.statistics).toEqual({ totalRows: 424242, totalBytes: 1024 });
|
|
88
|
+
(0, vitest_1.expect)(table.indexes).toEqual([
|
|
89
|
+
{
|
|
90
|
+
name: 'primary_key',
|
|
91
|
+
columns: ['event_id', 'occurred_at'],
|
|
92
|
+
unique: true,
|
|
93
|
+
type: 'PRIMARY KEY',
|
|
94
|
+
definition: 'tuple(event_id, occurred_at)',
|
|
95
|
+
},
|
|
96
|
+
]);
|
|
97
|
+
(0, vitest_1.expect)(table.constraints[0]).toMatchObject({
|
|
98
|
+
type: 'PRIMARY KEY',
|
|
99
|
+
columns: ['event_id', 'occurred_at'],
|
|
100
|
+
});
|
|
101
|
+
(0, vitest_1.expect)(new Date(introspection.introspectedAt).toISOString()).toBe(introspection.introspectedAt);
|
|
102
|
+
(0, vitest_1.expect)(stubClient.queries).toHaveLength(2);
|
|
103
|
+
(0, vitest_1.expect)(stubClient.queries[0].params).toEqual({ db: 'analytics' });
|
|
104
|
+
});
|
|
105
|
+
(0, vitest_1.it)('applies table filters when provided', async () => {
|
|
106
|
+
const responses = new Map([
|
|
107
|
+
['tables', [{ name: 'events', engine: 'MergeTree', is_view: 0 }]],
|
|
108
|
+
['columns', [{ table: 'events', name: 'column_1', type: 'UInt64', position: 1 }]],
|
|
109
|
+
]);
|
|
110
|
+
const stubClient = new StubClickHouseClient(responses);
|
|
111
|
+
const connector = new clickhouse_js_1.ClickHouseConnector({ database: 'analytics' }, { client: stubClient });
|
|
112
|
+
await connector.introspect({ tables: ['analytics.events', 'events'] });
|
|
113
|
+
(0, vitest_1.expect)(stubClient.queries).toHaveLength(2);
|
|
114
|
+
for (const query of stubClient.queries) {
|
|
115
|
+
(0, vitest_1.expect)(query.params).toEqual({ db: 'analytics', tables: ['events'] });
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
//# sourceMappingURL=clickhouse.introspect.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clickhouse.introspect.test.js","sourceRoot":"","sources":["../../../../src/connectors/__tests__/clickhouse.introspect.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import type { DataFormat } from '@clickhouse/client';
|
|
2
1
|
import type { IntrospectOptions, SchemaIntrospection } from '../schema/types.js';
|
|
3
2
|
export interface QueryOptions {
|
|
4
3
|
params?: Record<string, unknown>;
|
|
5
|
-
format?:
|
|
4
|
+
format?: string;
|
|
6
5
|
settings?: Record<string, unknown>;
|
|
7
6
|
}
|
|
8
7
|
export interface DatabaseConnector {
|
|
9
8
|
connect(): Promise<void>;
|
|
10
|
-
|
|
9
|
+
executeQuery<T = Record<string, unknown>>(query: string, options?: QueryOptions): Promise<T[]>;
|
|
11
10
|
introspect(options?: IntrospectOptions): Promise<SchemaIntrospection>;
|
|
12
11
|
close(): Promise<void>;
|
|
13
12
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../src/connectors/base.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../src/connectors/base.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAEjF,MAAM,WAAW,YAAY;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED,MAAM,WAAW,iBAAiB;IAC9B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACzB,YAAY,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;IAC/F,UAAU,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;IACtE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B"}
|
|
@@ -1,12 +1,30 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
import type { IntrospectOptions, SchemaIntrospection } from
|
|
3
|
-
import type { DatabaseConnector, QueryOptions } from
|
|
1
|
+
import { type ClickHouseClientConfigOptions, type ClickHouseSettings } from '@clickhouse/client';
|
|
2
|
+
import type { IntrospectOptions, SchemaIntrospection } from '../schema/types.js';
|
|
3
|
+
import type { DatabaseConnector, QueryOptions } from './base.js';
|
|
4
|
+
interface ResultSetLike {
|
|
5
|
+
json<T = unknown>(): Promise<T>;
|
|
6
|
+
}
|
|
7
|
+
interface ClickHouseClientLike {
|
|
8
|
+
query(params: {
|
|
9
|
+
query: string;
|
|
10
|
+
format?: string;
|
|
11
|
+
query_params?: Record<string, unknown>;
|
|
12
|
+
clickhouse_settings?: ClickHouseSettings;
|
|
13
|
+
}): Promise<ResultSetLike>;
|
|
14
|
+
ping(): Promise<{
|
|
15
|
+
success: boolean;
|
|
16
|
+
error?: Error;
|
|
17
|
+
} | {
|
|
18
|
+
success?: boolean;
|
|
19
|
+
}>;
|
|
20
|
+
close(): Promise<void>;
|
|
21
|
+
}
|
|
4
22
|
export interface ClickHouseConnectorConfig {
|
|
5
23
|
/** Fully qualified ClickHouse URL. Overrides host/port/protocol when provided. */
|
|
6
24
|
url?: string;
|
|
7
25
|
host?: string;
|
|
8
26
|
port?: number;
|
|
9
|
-
protocol?:
|
|
27
|
+
protocol?: 'http' | 'https';
|
|
10
28
|
database: string;
|
|
11
29
|
username?: string;
|
|
12
30
|
password?: string;
|
|
@@ -15,21 +33,21 @@ export interface ClickHouseConnectorConfig {
|
|
|
15
33
|
clientOptions?: Partial<ClickHouseClientConfigOptions>;
|
|
16
34
|
}
|
|
17
35
|
export interface ClickHouseConnectorOverrides {
|
|
18
|
-
client?:
|
|
19
|
-
clientFactory?: () =>
|
|
36
|
+
client?: ClickHouseClientLike;
|
|
37
|
+
clientFactory?: () => ClickHouseClientLike;
|
|
20
38
|
}
|
|
21
39
|
export declare class ClickHouseConnector implements DatabaseConnector {
|
|
40
|
+
private client;
|
|
22
41
|
private readonly config;
|
|
23
42
|
private readonly overrides;
|
|
24
|
-
private
|
|
25
|
-
private readonly defaultFormat;
|
|
43
|
+
private defaultFormat;
|
|
26
44
|
constructor(config: ClickHouseConnectorConfig, overrides?: ClickHouseConnectorOverrides);
|
|
27
45
|
connect(): Promise<void>;
|
|
28
|
-
|
|
46
|
+
executeQuery<T = Record<string, unknown>>(query: string, options?: QueryOptions): Promise<T[]>;
|
|
29
47
|
introspect(options?: IntrospectOptions): Promise<SchemaIntrospection>;
|
|
30
48
|
close(): Promise<void>;
|
|
31
49
|
private ensureClient;
|
|
32
|
-
private safePing;
|
|
33
50
|
private buildClientConfig;
|
|
34
51
|
}
|
|
52
|
+
export {};
|
|
35
53
|
//# sourceMappingURL=clickhouse.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clickhouse.d.ts","sourceRoot":"","sources":["../../../src/connectors/clickhouse.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"clickhouse.d.ts","sourceRoot":"","sources":["../../../src/connectors/clickhouse.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,6BAA6B,EAAE,KAAK,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAC/G,OAAO,KAAK,EAAgB,iBAAiB,EAAE,mBAAmB,EAAe,MAAM,oBAAoB,CAAC;AAE5G,OAAO,KAAK,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEjE,UAAU,aAAa;IACnB,IAAI,CAAC,CAAC,GAAG,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;CACnC;AAED,UAAU,oBAAoB;IAC1B,KAAK,CAAC,MAAM,EAAE;QACV,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACvC,mBAAmB,CAAC,EAAE,kBAAkB,CAAC;KAC5C,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IAC3B,IAAI,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,KAAK,CAAA;KAAE,GAAG;QAAE,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAC7E,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAED,MAAM,WAAW,yBAAyB;IACtC,kFAAkF;IAClF,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC7C,aAAa,CAAC,EAAE,OAAO,CAAC,6BAA6B,CAAC,CAAC;CAC1D;AAED,MAAM,WAAW,4BAA4B;IACzC,MAAM,CAAC,EAAE,oBAAoB,CAAC;IAC9B,aAAa,CAAC,EAAE,MAAM,oBAAoB,CAAC;CAC9C;AA4BD,qBAAa,mBAAoB,YAAW,iBAAiB;IACzD,OAAO,CAAC,MAAM,CAA8B;IAC5C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA4B;IACnD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAoC;IAC9D,OAAO,CAAC,aAAa,CAAyB;gBAElC,MAAM,EAAE,yBAAyB,EAAE,SAAS,CAAC,EAAE,4BAA4B;IAQjF,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAIxB,YAAY,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;IAsB9F,UAAU,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAqGrE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YAMd,YAAY;IAY1B,OAAO,CAAC,iBAAiB;CA+B5B"}
|
|
@@ -4,38 +4,32 @@ exports.ClickHouseConnector = void 0;
|
|
|
4
4
|
const client_1 = require("@clickhouse/client");
|
|
5
5
|
const clickhouse_js_1 = require("../utils/clickhouse.js");
|
|
6
6
|
class ClickHouseConnector {
|
|
7
|
-
constructor(config, overrides
|
|
7
|
+
constructor(config, overrides) {
|
|
8
|
+
this.overrides = {};
|
|
9
|
+
this.defaultFormat = 'JSONEachRow';
|
|
8
10
|
this.config = config;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
if (overrides) {
|
|
12
|
+
this.overrides = overrides;
|
|
13
|
+
}
|
|
14
|
+
this.client = overrides?.client ?? null;
|
|
12
15
|
}
|
|
13
16
|
async connect() {
|
|
14
17
|
await this.ensureClient();
|
|
15
18
|
}
|
|
16
|
-
async query
|
|
19
|
+
async executeQuery(query, options) {
|
|
17
20
|
const client = await this.ensureClient();
|
|
18
|
-
const params = {
|
|
19
|
-
query: sql,
|
|
20
|
-
};
|
|
21
21
|
const format = options?.format ?? this.defaultFormat;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
if (options?.settings) {
|
|
29
|
-
Object.assign(params, {
|
|
30
|
-
clickhouse_settings: options.settings,
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
const result = await client.query(params);
|
|
22
|
+
const result = await client.query({
|
|
23
|
+
query,
|
|
24
|
+
format,
|
|
25
|
+
query_params: options?.params,
|
|
26
|
+
clickhouse_settings: options?.settings,
|
|
27
|
+
});
|
|
34
28
|
const payload = await result.json();
|
|
35
29
|
if (Array.isArray(payload)) {
|
|
36
30
|
return payload;
|
|
37
31
|
}
|
|
38
|
-
if (payload && typeof payload ===
|
|
32
|
+
if (payload && typeof payload === 'object') {
|
|
39
33
|
const maybeData = payload.data;
|
|
40
34
|
if (Array.isArray(maybeData)) {
|
|
41
35
|
return maybeData;
|
|
@@ -52,42 +46,45 @@ class ClickHouseConnector {
|
|
|
52
46
|
if (hasFilter) {
|
|
53
47
|
queryParams.tables = allowTables;
|
|
54
48
|
}
|
|
55
|
-
const filterClause = hasFilter ?
|
|
56
|
-
const tables = await this.
|
|
49
|
+
const filterClause = hasFilter ? ' AND name IN {tables:Array(String)}' : '';
|
|
50
|
+
const tables = await this.executeQuery(`SELECT name, engine, comment, total_rows, total_bytes, is_view, primary_key, sorting_key
|
|
57
51
|
FROM system.tables
|
|
58
52
|
WHERE database = {db:String}${filterClause}
|
|
59
53
|
ORDER BY name`, { params: queryParams });
|
|
60
|
-
const columnFilterClause = hasFilter
|
|
61
|
-
|
|
62
|
-
: "";
|
|
63
|
-
const columns = await this.query(`SELECT table, name, type, position, default_kind, default_expression, comment,
|
|
54
|
+
const columnFilterClause = hasFilter ? ' AND table IN {tables:Array(String)}' : '';
|
|
55
|
+
const columns = await this.executeQuery(`SELECT table, name, type, position, default_kind, default_expression, comment,
|
|
64
56
|
codec_expression, ttl_expression, is_in_primary_key,
|
|
65
57
|
data_compressed_bytes, data_uncompressed_bytes
|
|
66
58
|
FROM system.columns
|
|
67
59
|
WHERE database = {db:String}${columnFilterClause}
|
|
68
60
|
ORDER BY table, position`, { params: queryParams });
|
|
69
61
|
const columnsByTable = new Map();
|
|
70
|
-
for (const
|
|
71
|
-
const list = columnsByTable.get(
|
|
72
|
-
list.push(transformColumnRow(
|
|
73
|
-
columnsByTable.set(
|
|
62
|
+
for (const col of columns) {
|
|
63
|
+
const list = columnsByTable.get(col.table) ?? [];
|
|
64
|
+
list.push(transformColumnRow(col));
|
|
65
|
+
columnsByTable.set(col.table, list);
|
|
74
66
|
}
|
|
75
67
|
const tableSchemas = tables.map((table) => {
|
|
76
68
|
const tableColumns = columnsByTable.get(table.name) ?? [];
|
|
77
69
|
const primaryKeyColumns = (0, clickhouse_js_1.parseKeyExpression)(table.primary_key);
|
|
78
70
|
const totalRows = toNumber(table.total_rows);
|
|
79
71
|
const totalBytes = toNumber(table.total_bytes);
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
72
|
+
let statistics;
|
|
73
|
+
if (totalRows !== undefined || totalBytes !== undefined) {
|
|
74
|
+
const s = {};
|
|
75
|
+
if (totalRows !== undefined)
|
|
76
|
+
s.totalRows = totalRows;
|
|
77
|
+
if (totalBytes !== undefined)
|
|
78
|
+
s.totalBytes = totalBytes;
|
|
79
|
+
statistics = s;
|
|
83
80
|
}
|
|
84
81
|
const indexes = primaryKeyColumns.length
|
|
85
82
|
? [
|
|
86
83
|
{
|
|
87
|
-
name:
|
|
84
|
+
name: 'primary_key',
|
|
88
85
|
columns: primaryKeyColumns,
|
|
89
86
|
unique: true,
|
|
90
|
-
type:
|
|
87
|
+
type: 'PRIMARY KEY',
|
|
91
88
|
...(table.primary_key ? { definition: table.primary_key } : {}),
|
|
92
89
|
},
|
|
93
90
|
]
|
|
@@ -95,12 +92,15 @@ class ClickHouseConnector {
|
|
|
95
92
|
const constraints = primaryKeyColumns.length
|
|
96
93
|
? [
|
|
97
94
|
{
|
|
98
|
-
name:
|
|
99
|
-
type:
|
|
95
|
+
name: 'primary_key',
|
|
96
|
+
type: 'PRIMARY KEY',
|
|
100
97
|
columns: primaryKeyColumns,
|
|
101
98
|
},
|
|
102
99
|
]
|
|
103
100
|
: [];
|
|
101
|
+
for (const column of tableColumns) {
|
|
102
|
+
column.isPrimaryKey = column.isPrimaryKey || primaryKeyColumns.includes(column.name);
|
|
103
|
+
}
|
|
104
104
|
const base = {
|
|
105
105
|
name: table.name,
|
|
106
106
|
schema: this.config.database,
|
|
@@ -114,7 +114,6 @@ class ClickHouseConnector {
|
|
|
114
114
|
if (comment !== undefined) {
|
|
115
115
|
base.comment = comment;
|
|
116
116
|
}
|
|
117
|
-
const statistics = buildTableStatistics(totalRows, totalBytes);
|
|
118
117
|
if (statistics) {
|
|
119
118
|
base.statistics = statistics;
|
|
120
119
|
}
|
|
@@ -122,7 +121,7 @@ class ClickHouseConnector {
|
|
|
122
121
|
});
|
|
123
122
|
return {
|
|
124
123
|
db: {
|
|
125
|
-
kind:
|
|
124
|
+
kind: 'clickhouse',
|
|
126
125
|
name: this.config.database,
|
|
127
126
|
},
|
|
128
127
|
tables: tableSchemas,
|
|
@@ -139,35 +138,23 @@ class ClickHouseConnector {
|
|
|
139
138
|
if (this.client) {
|
|
140
139
|
return this.client;
|
|
141
140
|
}
|
|
142
|
-
this.client =
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
if (pingResult && "success" in pingResult && pingResult.success === false) {
|
|
147
|
-
throw pingResult.error ?? new Error("ClickHouse ping failed");
|
|
141
|
+
this.client = this.overrides?.clientFactory?.() ?? (0, client_1.createClient)(this.buildClientConfig());
|
|
142
|
+
const pingResult = await this.client.ping();
|
|
143
|
+
if ('success' in pingResult && pingResult.success === false) {
|
|
144
|
+
throw pingResult.error ?? new Error('ClickHouse ping failed');
|
|
148
145
|
}
|
|
149
146
|
return this.client;
|
|
150
147
|
}
|
|
151
|
-
async safePing(client) {
|
|
152
|
-
try {
|
|
153
|
-
return await client.ping();
|
|
154
|
-
}
|
|
155
|
-
catch (error) {
|
|
156
|
-
await client.close();
|
|
157
|
-
this.client = null;
|
|
158
|
-
throw error;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
148
|
buildClientConfig() {
|
|
162
149
|
const merged = {
|
|
163
|
-
...
|
|
150
|
+
...this.config.clientOptions,
|
|
164
151
|
};
|
|
165
152
|
if (this.config.url) {
|
|
166
153
|
merged.url = this.config.url;
|
|
167
154
|
}
|
|
168
155
|
else if (this.config.host) {
|
|
169
|
-
const protocol = this.config.protocol ??
|
|
170
|
-
const port = this.config.port ?? (protocol ===
|
|
156
|
+
const protocol = this.config.protocol ?? 'https';
|
|
157
|
+
const port = this.config.port ?? (protocol === 'https' ? 8443 : 8123);
|
|
171
158
|
merged.url = `${protocol}://${this.config.host}:${port}`;
|
|
172
159
|
}
|
|
173
160
|
merged.database = this.config.database;
|
|
@@ -201,7 +188,7 @@ function normalizeTableFilter(tables) {
|
|
|
201
188
|
const trimmed = table.trim();
|
|
202
189
|
if (!trimmed)
|
|
203
190
|
continue;
|
|
204
|
-
const parts = trimmed.split(
|
|
191
|
+
const parts = trimmed.split('.');
|
|
205
192
|
const tableName = parts[parts.length - 1];
|
|
206
193
|
if (!tableName || seen.has(tableName))
|
|
207
194
|
continue;
|
|
@@ -224,6 +211,7 @@ function transformColumnRow(row) {
|
|
|
224
211
|
isPrimaryKey: Boolean(toNumber(row.is_in_primary_key)),
|
|
225
212
|
isForeignKey: false,
|
|
226
213
|
};
|
|
214
|
+
// Always safe to set defined optional string properties
|
|
227
215
|
column.rawType = row.type;
|
|
228
216
|
const defaultKind = sanitize(row.default_kind);
|
|
229
217
|
if (defaultKind !== undefined)
|
|
@@ -258,9 +246,9 @@ function transformColumnRow(row) {
|
|
|
258
246
|
function toNumber(value) {
|
|
259
247
|
if (value === null || value === undefined)
|
|
260
248
|
return undefined;
|
|
261
|
-
if (typeof value ===
|
|
249
|
+
if (typeof value === 'number')
|
|
262
250
|
return value;
|
|
263
|
-
const parsed = Number.parseFloat(
|
|
251
|
+
const parsed = Number.parseFloat(value);
|
|
264
252
|
return Number.isNaN(parsed) ? undefined : parsed;
|
|
265
253
|
}
|
|
266
254
|
function sanitize(value) {
|
|
@@ -270,23 +258,13 @@ function sanitize(value) {
|
|
|
270
258
|
return trimmed.length ? trimmed : undefined;
|
|
271
259
|
}
|
|
272
260
|
function asTableType(isView) {
|
|
273
|
-
if (typeof isView ===
|
|
274
|
-
return isView > 0 ?
|
|
261
|
+
if (typeof isView === 'number') {
|
|
262
|
+
return isView > 0 ? 'view' : 'table';
|
|
275
263
|
}
|
|
276
|
-
if (typeof isView ===
|
|
264
|
+
if (typeof isView === 'string') {
|
|
277
265
|
const normalized = isView.toLowerCase();
|
|
278
|
-
return normalized ===
|
|
266
|
+
return normalized === '1' || normalized === 'true' ? 'view' : 'table';
|
|
279
267
|
}
|
|
280
|
-
return
|
|
281
|
-
}
|
|
282
|
-
function buildTableStatistics(totalRows, totalBytes) {
|
|
283
|
-
if (totalRows === undefined && totalBytes === undefined)
|
|
284
|
-
return undefined;
|
|
285
|
-
const stats = {};
|
|
286
|
-
if (totalRows !== undefined)
|
|
287
|
-
stats.totalRows = totalRows;
|
|
288
|
-
if (totalBytes !== undefined)
|
|
289
|
-
stats.totalBytes = totalBytes;
|
|
290
|
-
return stats;
|
|
268
|
+
return 'table';
|
|
291
269
|
}
|
|
292
270
|
//# sourceMappingURL=clickhouse.js.map
|