@querypanel/node-sdk 1.0.24 → 1.0.26
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/README.md +62 -267
- 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 +1 -9
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +1 -7
- package/dist/cjs/index.js.map +1 -1
- 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 +1 -9
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +1 -7
- package/dist/esm/index.js.map +1 -1
- package/package.json +38 -28
package/README.md
CHANGED
|
@@ -1,323 +1,118 @@
|
|
|
1
1
|
# QueryPanel Node SDK
|
|
2
2
|
|
|
3
|
-
A
|
|
3
|
+
A TypeScript-first client for the QueryPanel Bun/Hono API. It signs JWTs with your service private key, syncs database schemas, enforces tenant isolation, and wraps every public route under `src/routes/` (query, ingest, charts, active charts, and knowledge base).
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
|
|
8
|
+
bun add @querypanel/sdk
|
|
9
|
+
# or
|
|
10
|
+
npm install @querypanel/sdk
|
|
9
11
|
```
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
- `@clickhouse/client` is a peer dependency for ClickHouse integrations.
|
|
13
|
+
> **Runtime:** Node.js 18+ (or Bun). The SDK relies on the native `fetch` API.
|
|
13
14
|
|
|
14
|
-
##
|
|
15
|
+
## Quickstart
|
|
15
16
|
|
|
16
17
|
```ts
|
|
17
|
-
import { QueryPanelSdkAPI } from "@querypanel/
|
|
18
|
-
import {
|
|
18
|
+
import { QueryPanelSdkAPI } from "@querypanel/sdk";
|
|
19
|
+
import { Pool } from "pg";
|
|
19
20
|
|
|
20
21
|
const qp = new QueryPanelSdkAPI(
|
|
21
22
|
process.env.QUERYPANEL_URL!,
|
|
22
|
-
process.env.
|
|
23
|
-
process.env.
|
|
24
|
-
);
|
|
25
|
-
|
|
26
|
-
// Attach a ClickHouse database (use the SDK-supplied adapter)
|
|
27
|
-
const clickhouse = createClient({
|
|
28
|
-
url: process.env.CLICKHOUSE_URL!,
|
|
29
|
-
username: process.env.CLICKHOUSE_USER,
|
|
30
|
-
password: process.env.CLICKHOUSE_PASSWORD,
|
|
31
|
-
database: "analytics",
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
qp.attachClickhouse(
|
|
35
|
-
"analytics",
|
|
36
|
-
(params) => clickhouse.query(params),
|
|
23
|
+
process.env.PRIVATE_KEY!,
|
|
24
|
+
process.env.ORGANIZATION_ID!,
|
|
37
25
|
{
|
|
38
|
-
|
|
39
|
-
tenantFieldName: "customer_id", // Enable tenant isolation
|
|
40
|
-
tenantFieldType: "String", // ClickHouse type
|
|
26
|
+
defaultTenantId: process.env.DEFAULT_TENANT_ID,
|
|
41
27
|
},
|
|
42
28
|
);
|
|
43
29
|
|
|
44
|
-
|
|
45
|
-
const response = await qp.ask("Top countries by revenue", { tenantId: "tenant_123" });
|
|
46
|
-
console.log(response.sql); // Includes WHERE customer_id = {customer_id:String}
|
|
47
|
-
console.log(response.params); // { customer_id: "tenant_123", ... }
|
|
48
|
-
console.table(response.rows);
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
## Authentication modes
|
|
52
|
-
|
|
53
|
-
The constructor accepts a private key/organization pair for on-the-fly token generation:
|
|
54
|
-
|
|
55
|
-
```ts
|
|
56
|
-
|
|
57
|
-
// provide an RSA private key and organization ID (recommended)
|
|
58
|
-
// and save the public key on the querypanel ui
|
|
59
|
-
const qp = new QueryPanelSdkAPI(baseUrl, privateKeyPem, organizationId);
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
## V3 Bedrock Integration
|
|
63
|
-
|
|
64
|
-
The SDK provides methods to generate schema exports compatible with AWS Bedrock knowledge bases:
|
|
65
|
-
|
|
66
|
-
### introspectV3
|
|
67
|
-
|
|
68
|
-
Generate a simplified schema export format suitable for Bedrock ingestion:
|
|
69
|
-
|
|
70
|
-
```ts
|
|
71
|
-
const schema = await qp.introspectV3("analytics", {
|
|
72
|
-
tenantId: "tenant-123",
|
|
73
|
-
tables: ["orders", "customers"], // Optional: filter specific tables
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
// Output matches schema_export.json format
|
|
77
|
-
console.log(JSON.stringify(schema, null, 2));
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
### ingestSchemaV3
|
|
30
|
+
const pool = new Pool({ connectionString: process.env.POSTGRES_URL });
|
|
81
31
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
```ts
|
|
85
|
-
const result = await qp.ingestSchemaV3("analytics", {
|
|
86
|
-
tenantId: "tenant-123",
|
|
87
|
-
tables: ["orders", "customers"], // Optional
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
console.log(`Ingested ${result.total_documents} documents`);
|
|
91
|
-
console.log(`Failed: ${result.failed.length}`);
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
The V3 format includes:
|
|
95
|
-
- Table overviews with column summaries and statistics
|
|
96
|
-
- Individual column metadata documents
|
|
97
|
-
- Foreign key relationships
|
|
98
|
-
- Primary key indicators
|
|
99
|
-
|
|
100
|
-
This data powers the Bedrock-backed `/v3/generate-sql` endpoint using Claude Haiku 4.5.
|
|
101
|
-
|
|
102
|
-
## Working with databases
|
|
103
|
-
|
|
104
|
-
Adapters mediate between the SDK and your data sources. Two helpers are bundled:
|
|
105
|
-
|
|
106
|
-
### ClickHouse
|
|
107
|
-
|
|
108
|
-
```ts
|
|
109
|
-
import {
|
|
110
|
-
ClickHouseAdapter,
|
|
111
|
-
type ClickHouseClientFn,
|
|
112
|
-
} from "@querypanel/node-sdk";
|
|
113
|
-
import { createClient } from "@clickhouse/client";
|
|
114
|
-
|
|
115
|
-
const clickhouseClient = createClient({ url: "https://ch.example.com", database: "analytics" });
|
|
116
|
-
const clickhouseFn: ClickHouseClientFn = (params) => clickhouseClient.query(params);
|
|
117
|
-
const clickhouseAdapter = new ClickHouseAdapter(clickhouseFn, { database: "analytics" });
|
|
118
|
-
|
|
119
|
-
// Optional introspection before attaching
|
|
120
|
-
const schema = await clickhouseAdapter.introspect();
|
|
121
|
-
console.log(schema.tables.map((t) => t.name));
|
|
122
|
-
|
|
123
|
-
qp.attachDatabase("analytics", clickhouseAdapter);
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
### Postgres
|
|
127
|
-
|
|
128
|
-
```ts
|
|
129
|
-
import { Pool } from "pg";
|
|
130
|
-
import {
|
|
131
|
-
PostgresAdapter,
|
|
132
|
-
type PostgresClientFn,
|
|
133
|
-
} from "@querypanel/node-sdk";
|
|
134
|
-
|
|
135
|
-
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
|
|
136
|
-
const pgFn: PostgresClientFn = async (sql) => {
|
|
32
|
+
const createPostgresClient = () => async (sql: string, params?: unknown[]) => {
|
|
137
33
|
const client = await pool.connect();
|
|
138
34
|
try {
|
|
139
|
-
const result = await client.query(sql);
|
|
35
|
+
const result = await client.query(sql, params);
|
|
140
36
|
return {
|
|
141
37
|
rows: result.rows,
|
|
142
|
-
fields: result.fields.map((
|
|
38
|
+
fields: result.fields.map((field) => ({ name: field.name })),
|
|
143
39
|
};
|
|
144
40
|
} finally {
|
|
145
41
|
client.release();
|
|
146
42
|
}
|
|
147
43
|
};
|
|
148
44
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
45
|
+
qp.attachPostgres("analytics", createPostgresClient(), {
|
|
46
|
+
description: "Primary analytics warehouse",
|
|
47
|
+
tenantFieldName: "tenant_id",
|
|
152
48
|
});
|
|
153
49
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
## SDK helpers
|
|
165
|
-
|
|
166
|
-
Once at least one adapter is attached you can call:
|
|
167
|
-
|
|
168
|
-
- `ask(question, options)` – generate SQL, validate it, execute through the adapter, and retrieve a matching Vega-Lite chart spec.
|
|
169
|
-
- `train(payload, { tenantId, userId, scopes })` – submit curated glossary entries, metric docs, and gold SQL examples.
|
|
170
|
-
- `stats({ tenantId, userId, scopes })` – fetch ingestion statistics.
|
|
171
|
-
- Chart helpers: `listCharts`, `getChart`, `createChart`, `updateChart`, `deleteChart`, `listActiveCharts`, `getActiveChart`, `createActiveChart`, `updateActiveChart`, `deleteActiveChart`.
|
|
172
|
-
|
|
173
|
-
Every SDK call automatically attaches the correct authentication headers and forwards optional `tenantId`, `userId`, and `scopes` when provided.
|
|
174
|
-
|
|
175
|
-
### Using V3 SQL generation
|
|
50
|
+
qp.attachClickhouse(
|
|
51
|
+
"clicks",
|
|
52
|
+
(params) => clickhouse.query(params),
|
|
53
|
+
{
|
|
54
|
+
database: "analytics",
|
|
55
|
+
tenantFieldName: "customer_id",
|
|
56
|
+
tenantFieldType: "String",
|
|
57
|
+
},
|
|
58
|
+
);
|
|
176
59
|
|
|
177
|
-
|
|
60
|
+
await qp.syncSchema("analytics", { tenantId: "tenant_123" });
|
|
178
61
|
|
|
179
|
-
```ts
|
|
180
62
|
const response = await qp.ask("Top countries by revenue", {
|
|
181
63
|
tenantId: "tenant_123",
|
|
182
|
-
|
|
183
|
-
});
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
**Important**: The `useV3` flag controls both:
|
|
187
|
-
1. **SQL generation endpoint**: Uses `/v3/generate-sql` instead of `/v2/generate-sql`
|
|
188
|
-
2. **Schema introspection**: On first use, auto-syncs schema via `/v3/ingest` (Bedrock knowledge base) instead of `/v2/vectorize-schema` (pgvector)
|
|
189
|
-
|
|
190
|
-
Both endpoints support the same request/response format, making migration seamless.
|
|
191
|
-
|
|
192
|
-
### Manual sync control
|
|
193
|
-
|
|
194
|
-
By default, the SDK automatically syncs your database schema on the first `ask()` call. You can disable this and sync manually:
|
|
195
|
-
|
|
196
|
-
```ts
|
|
197
|
-
// Manual sync workflow
|
|
198
|
-
await qp.ingestSchemaV3("analytics", {
|
|
199
|
-
tenantId: "tenant_123",
|
|
200
|
-
tables: ["orders", "customers"], // Optional: sync specific tables
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
// Now ask questions with auto-sync disabled
|
|
204
|
-
const response = await qp.ask("Top revenue by country", {
|
|
205
|
-
tenantId: "tenant_123",
|
|
206
|
-
useV3: true,
|
|
207
|
-
disableAutoSync: true, // ⚠️ Requires manual sync first
|
|
208
|
-
});
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
**Why disable auto-sync?**
|
|
212
|
-
- 🎯 Control when schema updates happen
|
|
213
|
-
- ⚡ Faster `ask()` calls (no sync overhead)
|
|
214
|
-
- 💰 Reduce API calls to Bedrock
|
|
215
|
-
- 🔧 Better for production deployments (sync on app startup, not on every request)
|
|
216
|
-
|
|
217
|
-
**Recommended pattern for production:**
|
|
218
|
-
|
|
219
|
-
```ts
|
|
220
|
-
// On app startup (once)
|
|
221
|
-
await qp.ingestSchemaV3("analytics", { tenantId: "..." });
|
|
222
|
-
|
|
223
|
-
// In request handlers (many times)
|
|
224
|
-
app.post("/query", async (req, res) => {
|
|
225
|
-
const result = await qp.ask(req.body.question, {
|
|
226
|
-
tenantId: req.user.tenantId,
|
|
227
|
-
useV3: true,
|
|
228
|
-
disableAutoSync: true, // Already synced at startup
|
|
229
|
-
});
|
|
230
|
-
res.json(result);
|
|
231
|
-
});
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
## Multi-database support
|
|
235
|
-
|
|
236
|
-
The SDK keeps a registry of adapters. The first attached database becomes the default, but you can switch per request:
|
|
237
|
-
|
|
238
|
-
```ts
|
|
239
|
-
qp.attachPostgres("users", pgFn, { database: "users" });
|
|
240
|
-
qp.attachClickhouse("analytics", clickhouseFn);
|
|
241
|
-
|
|
242
|
-
await qp.ask("Top spenders", {
|
|
243
|
-
tenantId: "tenant_123",
|
|
244
|
-
database: "analytics", // override default database for this request
|
|
64
|
+
database: "analytics",
|
|
245
65
|
});
|
|
246
|
-
```
|
|
247
|
-
|
|
248
|
-
The `available_databases` array is forwarded to the `/v2/generate-sql` endpoint so the service can pick the right dialect when it suggests queries.
|
|
249
|
-
|
|
250
|
-
## Schema introspection
|
|
251
|
-
|
|
252
|
-
Both adapters can produce consistent metadata that matches `node-sdk/src/schema/types.ts`:
|
|
253
66
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
}
|
|
67
|
+
console.log(response.sql);
|
|
68
|
+
console.log(response.params);
|
|
69
|
+
console.table(response.rows);
|
|
70
|
+
console.log(response.chart.vegaLiteSpec);
|
|
259
71
|
```
|
|
260
72
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
## Local introspection script
|
|
264
|
-
|
|
265
|
-
Test V3 introspection locally without calling the API:
|
|
73
|
+
## Building locally
|
|
266
74
|
|
|
267
75
|
```bash
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
# With custom database
|
|
272
|
-
CLICKHOUSE_URL=http://localhost:8123 \
|
|
273
|
-
CLICKHOUSE_DATABASE=analytics \
|
|
274
|
-
TENANT_ID=my-tenant \
|
|
275
|
-
npm run introspect:local
|
|
276
|
-
|
|
277
|
-
# Filter specific tables
|
|
278
|
-
TABLES="orders,customers" npm run introspect:local
|
|
76
|
+
cd node-sdk
|
|
77
|
+
bun install
|
|
78
|
+
bun run build
|
|
279
79
|
```
|
|
280
80
|
|
|
281
|
-
This
|
|
282
|
-
1. Review locally before ingestion
|
|
283
|
-
2. Upload manually via `/v3/ingest`
|
|
284
|
-
3. Use for testing and CI/CD
|
|
81
|
+
This runs `tsup` which emits dual ESM/CJS bundles plus type declarations to `dist/`.
|
|
285
82
|
|
|
286
|
-
|
|
83
|
+
## Authentication model
|
|
287
84
|
|
|
288
|
-
|
|
85
|
+
Every request is signed with `RS256` using the private key you pass to the constructor. The payload always includes `organizationId` and `tenantId`; `userId` and `scopes` are added when provided per call. If you still need service tokens or custom middleware, pass additional headers via the constructor.
|
|
289
86
|
|
|
290
|
-
|
|
291
|
-
# run unit tests
|
|
292
|
-
npm --prefix node-sdk test
|
|
87
|
+
## Error handling
|
|
293
88
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
## Tenant Isolation
|
|
89
|
+
- HTTP errors propagate as thrown `Error` instances that include `status` (and `details` when available).
|
|
90
|
+
- Schema ingestion failures are logged to `console.warn` during auto-sync, but you can call `syncSchema(..., { force: true })` to surface them directly.
|
|
91
|
+
- `ask()` raises immediately for guardrail/moderation errors because `/query` responds with 4xx/5xx.
|
|
299
92
|
|
|
300
|
-
|
|
93
|
+
### Automatic SQL repair and retry
|
|
301
94
|
|
|
302
|
-
|
|
303
|
-
- ✅ Validate that generated SQL includes tenant filters
|
|
304
|
-
- ✅ Auto-fix SQL missing tenant isolation by adding WHERE clauses
|
|
305
|
-
- ✅ Support ClickHouse typed parameters (`{customer_id:String}`)
|
|
95
|
+
When SQL execution fails (e.g., invalid column name, syntax error), the SDK can automatically retry with a repaired query:
|
|
306
96
|
|
|
307
|
-
```
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
enforceTenantIsolation: true, // Default: true (auto-fix missing filters)
|
|
97
|
+
```ts
|
|
98
|
+
const response = await qp.ask("Show revenue by country", {
|
|
99
|
+
tenantId: "tenant_123",
|
|
100
|
+
maxRetry: 3, // Automatically retry up to 3 times on execution error
|
|
312
101
|
});
|
|
102
|
+
|
|
103
|
+
console.log(`Query succeeded after ${response.attempts} attempt(s)`);
|
|
104
|
+
console.table(response.rows);
|
|
313
105
|
```
|
|
314
106
|
|
|
315
|
-
|
|
107
|
+
The SDK will:
|
|
108
|
+
1. Execute the generated SQL
|
|
109
|
+
2. If execution fails, send the error back to the server with the failed SQL
|
|
110
|
+
3. Get a repaired SQL query from the server
|
|
111
|
+
4. Execute the repaired query
|
|
112
|
+
5. Repeat up to `maxRetry` times
|
|
316
113
|
|
|
317
|
-
|
|
114
|
+
Without `maxRetry`, execution errors throw immediately (default behavior).
|
|
318
115
|
|
|
319
|
-
|
|
320
|
-
- `SDK-API.md` – REST endpoint reference used by the SDK
|
|
321
|
-
- `MULTI_DATABASE.md` – Notes on attaching multiple adapters
|
|
116
|
+
## Need more?
|
|
322
117
|
|
|
323
|
-
|
|
118
|
+
Open an issue or extend `node-sdk/src/index.ts`—every route lives in one file. Pull requests are welcome for additional adapters, richer param coercion, or convenience helpers around charts/annotations.
|
|
@@ -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
|
}
|