@wavehouse/sdk 0.1.1 → 0.2.0
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 +8 -4
- package/dist/cli/codegen.js +63 -12
- package/dist/index.cjs +183 -86
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +146 -72
- package/dist/index.d.ts +146 -72
- package/dist/index.global.js +11 -11
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +182 -85
- package/dist/index.js.map +1 -1
- package/package.json +12 -6
package/dist/index.js
CHANGED
|
@@ -7,10 +7,11 @@ async function parseErrorResponse(res) {
|
|
|
7
7
|
body = void 0;
|
|
8
8
|
}
|
|
9
9
|
const message = typeof body?.error === "string" ? body.error : typeof body?.message === "string" ? body.message : res.statusText;
|
|
10
|
-
const
|
|
10
|
+
const code = typeof body?.code === "string" && body.code !== "" ? body.code : `HTTP_${res.status}`;
|
|
11
|
+
const retryable = typeof body?.retryable === "boolean" ? body.retryable : res.status >= 500;
|
|
11
12
|
return {
|
|
12
13
|
status: res.status,
|
|
13
|
-
code
|
|
14
|
+
code,
|
|
14
15
|
message,
|
|
15
16
|
details: body,
|
|
16
17
|
retryable
|
|
@@ -66,6 +67,9 @@ function mergeHeaders(base, extra) {
|
|
|
66
67
|
}
|
|
67
68
|
return merged;
|
|
68
69
|
}
|
|
70
|
+
function tenantParam(opts) {
|
|
71
|
+
return opts?.tenant === void 0 ? void 0 : { tenant: opts.tenant };
|
|
72
|
+
}
|
|
69
73
|
function abortedResult() {
|
|
70
74
|
return {
|
|
71
75
|
data: null,
|
|
@@ -169,22 +173,26 @@ var DLQNamespace = class {
|
|
|
169
173
|
this._ctx = ctx;
|
|
170
174
|
this._createStream = createStream;
|
|
171
175
|
}
|
|
172
|
-
/**
|
|
176
|
+
/**
|
|
177
|
+
* Get DLQ statistics (message counts per table) — of `opts.tenant`, the
|
|
178
|
+
* default tenant without it. A tenant with no dead-letter queue is a `404`.
|
|
179
|
+
*/
|
|
173
180
|
async list(opts) {
|
|
174
181
|
const { data, error } = await request(this._ctx, {
|
|
175
182
|
method: "GET",
|
|
176
183
|
path: "/v1/ops/dlq/stats",
|
|
184
|
+
params: tenantParam(opts),
|
|
177
185
|
signal: opts?.signal
|
|
178
186
|
});
|
|
179
187
|
if (error) return err(error);
|
|
180
188
|
return ok(data);
|
|
181
189
|
}
|
|
182
|
-
/** Get DLQ stats filtered by table name. */
|
|
190
|
+
/** Get DLQ stats filtered by table name — of `opts.tenant`, the default tenant without it. */
|
|
183
191
|
async table(name, opts) {
|
|
184
192
|
const { data, error } = await request(this._ctx, {
|
|
185
193
|
method: "GET",
|
|
186
194
|
path: "/v1/ops/dlq/stats",
|
|
187
|
-
params: { table: name },
|
|
195
|
+
params: { table: name, ...tenantParam(opts) },
|
|
188
196
|
signal: opts?.signal
|
|
189
197
|
});
|
|
190
198
|
if (error) return err(error);
|
|
@@ -239,82 +247,23 @@ var PipesNamespace = class {
|
|
|
239
247
|
constructor(ctx) {
|
|
240
248
|
this._ctx = ctx;
|
|
241
249
|
}
|
|
242
|
-
/** List all registered pipes. */
|
|
250
|
+
/** List all registered pipes — of `opts.tenant`, the default tenant without it. */
|
|
243
251
|
async list(opts) {
|
|
244
252
|
const { data, error } = await request(this._ctx, {
|
|
245
253
|
method: "GET",
|
|
246
254
|
path: "/v1/ops/pipes",
|
|
255
|
+
params: tenantParam(opts),
|
|
247
256
|
signal: opts?.signal
|
|
248
257
|
});
|
|
249
258
|
if (error) return err(error);
|
|
250
259
|
return ok(data);
|
|
251
260
|
}
|
|
252
|
-
/** Get a single pipe definition by name. */
|
|
261
|
+
/** Get a single pipe definition by name — of `opts.tenant`, the default tenant without it. */
|
|
253
262
|
async get(name, opts) {
|
|
254
263
|
const { data, error } = await request(this._ctx, {
|
|
255
264
|
method: "GET",
|
|
256
265
|
path: `/v1/ops/pipes/${encodeURIComponent(name)}`,
|
|
257
|
-
|
|
258
|
-
});
|
|
259
|
-
if (error) return err(error);
|
|
260
|
-
return ok(data);
|
|
261
|
-
}
|
|
262
|
-
/** Create or update a pipe. */
|
|
263
|
-
async set(name, def, opts) {
|
|
264
|
-
const { error } = await request(this._ctx, {
|
|
265
|
-
method: "PUT",
|
|
266
|
-
path: `/v1/ops/pipes/${encodeURIComponent(name)}`,
|
|
267
|
-
body: def,
|
|
268
|
-
signal: opts?.signal
|
|
269
|
-
});
|
|
270
|
-
if (error) return err(error);
|
|
271
|
-
return ok(void 0);
|
|
272
|
-
}
|
|
273
|
-
/** Delete a pipe by name. */
|
|
274
|
-
async delete(name, opts) {
|
|
275
|
-
const { error } = await request(this._ctx, {
|
|
276
|
-
method: "DELETE",
|
|
277
|
-
path: `/v1/ops/pipes/${encodeURIComponent(name)}`,
|
|
278
|
-
signal: opts?.signal
|
|
279
|
-
});
|
|
280
|
-
if (error) return err(error);
|
|
281
|
-
return ok(void 0);
|
|
282
|
-
}
|
|
283
|
-
};
|
|
284
|
-
|
|
285
|
-
// src/policy.ts
|
|
286
|
-
var PolicyNamespace = class {
|
|
287
|
-
_ctx;
|
|
288
|
-
constructor(ctx) {
|
|
289
|
-
this._ctx = ctx;
|
|
290
|
-
}
|
|
291
|
-
/** Get the current access control policy. */
|
|
292
|
-
async get(opts) {
|
|
293
|
-
const { data, error } = await request(this._ctx, {
|
|
294
|
-
method: "GET",
|
|
295
|
-
path: "/v1/ops/policy",
|
|
296
|
-
signal: opts?.signal
|
|
297
|
-
});
|
|
298
|
-
if (error) return err(error);
|
|
299
|
-
return ok(data);
|
|
300
|
-
}
|
|
301
|
-
/** Replace the entire access control policy. */
|
|
302
|
-
async set(policy, opts) {
|
|
303
|
-
const { error } = await request(this._ctx, {
|
|
304
|
-
method: "PUT",
|
|
305
|
-
path: "/v1/ops/policy",
|
|
306
|
-
body: policy,
|
|
307
|
-
signal: opts?.signal
|
|
308
|
-
});
|
|
309
|
-
if (error) return err(error);
|
|
310
|
-
return ok(void 0);
|
|
311
|
-
}
|
|
312
|
-
/** Validate a policy without applying it (dry run). */
|
|
313
|
-
async validate(policy, opts) {
|
|
314
|
-
const { data, error } = await request(this._ctx, {
|
|
315
|
-
method: "POST",
|
|
316
|
-
path: "/v1/ops/policy/validate",
|
|
317
|
-
body: policy,
|
|
266
|
+
params: tenantParam(opts),
|
|
318
267
|
signal: opts?.signal
|
|
319
268
|
});
|
|
320
269
|
if (error) return err(error);
|
|
@@ -328,11 +277,16 @@ var SchemaNamespace = class {
|
|
|
328
277
|
constructor(ctx) {
|
|
329
278
|
this._ctx = ctx;
|
|
330
279
|
}
|
|
331
|
-
/**
|
|
280
|
+
/**
|
|
281
|
+
* List all table schemas discovered from ClickHouse — `opts.tenant`'s, the
|
|
282
|
+
* default tenant's without it. A `503` with `Retry-After` is a tenant whose
|
|
283
|
+
* first discovery has not succeeded yet.
|
|
284
|
+
*/
|
|
332
285
|
async list(opts) {
|
|
333
286
|
const { data, error } = await request(this._ctx, {
|
|
334
287
|
method: "GET",
|
|
335
288
|
path: "/v1/ops/schema",
|
|
289
|
+
params: tenantParam(opts),
|
|
336
290
|
signal: opts?.signal
|
|
337
291
|
});
|
|
338
292
|
if (error) return err(error);
|
|
@@ -349,11 +303,15 @@ var SchemaNamespace = class {
|
|
|
349
303
|
}
|
|
350
304
|
return ok(schemas);
|
|
351
305
|
}
|
|
352
|
-
/**
|
|
306
|
+
/**
|
|
307
|
+
* Force a schema refresh from ClickHouse system.columns — of `opts.tenant`,
|
|
308
|
+
* the default tenant without it.
|
|
309
|
+
*/
|
|
353
310
|
async refresh(opts) {
|
|
354
311
|
const { error } = await request(this._ctx, {
|
|
355
312
|
method: "POST",
|
|
356
313
|
path: "/v1/ops/schema/refresh",
|
|
314
|
+
params: tenantParam(opts),
|
|
357
315
|
signal: opts?.signal
|
|
358
316
|
});
|
|
359
317
|
if (error) return err(error);
|
|
@@ -361,11 +319,40 @@ var SchemaNamespace = class {
|
|
|
361
319
|
}
|
|
362
320
|
};
|
|
363
321
|
|
|
322
|
+
// src/settings.ts
|
|
323
|
+
var SettingsNamespace = class {
|
|
324
|
+
_ctx;
|
|
325
|
+
constructor(ctx) {
|
|
326
|
+
this._ctx = ctx;
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Re-validate and adopt the settings directory (POST /v1/ops/settings/reload).
|
|
330
|
+
* Resolves with `{ adopted: true, findings }` when adopted (warnings
|
|
331
|
+
* included); a rejected directory is a 422 error whose `details` carries the
|
|
332
|
+
* same `{ adopted: false, findings }` body, and the previous settings stay
|
|
333
|
+
* in effect.
|
|
334
|
+
*
|
|
335
|
+
* `opts.tenant` reloads that tenant's folder alone; without it the whole
|
|
336
|
+
* directory is reloaded.
|
|
337
|
+
*/
|
|
338
|
+
async reload(opts) {
|
|
339
|
+
const { data, error } = await request(this._ctx, {
|
|
340
|
+
method: "POST",
|
|
341
|
+
path: "/v1/ops/settings/reload",
|
|
342
|
+
params: tenantParam(opts),
|
|
343
|
+
signal: opts?.signal
|
|
344
|
+
});
|
|
345
|
+
if (error) return err(error);
|
|
346
|
+
return ok(data);
|
|
347
|
+
}
|
|
348
|
+
};
|
|
349
|
+
|
|
364
350
|
// src/sql.ts
|
|
365
351
|
async function sql(ctx, query, opts) {
|
|
366
352
|
const { data, error } = await request(ctx, {
|
|
367
353
|
method: "POST",
|
|
368
354
|
path: "/v1/ops/query",
|
|
355
|
+
params: tenantParam(opts),
|
|
369
356
|
body: { sql: query },
|
|
370
357
|
signal: opts?.signal
|
|
371
358
|
});
|
|
@@ -572,6 +559,30 @@ var SSETransport = class {
|
|
|
572
559
|
_retryFloorMs = 0;
|
|
573
560
|
/** Cuts a reconnect gap short when set — see `_sleep`. */
|
|
574
561
|
_wake = null;
|
|
562
|
+
/**
|
|
563
|
+
* Column names for the rows currently arriving, from the most recent
|
|
564
|
+
* `event: schema` frame. Rows travel positionally, so this is what turns one
|
|
565
|
+
* back into an object; `null` means none has been announced yet, and a data
|
|
566
|
+
* frame arriving in that state is unreadable rather than merely unlabeled.
|
|
567
|
+
*
|
|
568
|
+
* Reset at the start of every connection attempt: a reconnect re-announces,
|
|
569
|
+
* and zipping a new connection's rows under the previous one's list would
|
|
570
|
+
* silently mislabel every value.
|
|
571
|
+
*/
|
|
572
|
+
_columns = null;
|
|
573
|
+
/**
|
|
574
|
+
* Per-cause warning budget for the current connection. A server that predates
|
|
575
|
+
* the positional wire sends every row without a schema event, so an unbounded
|
|
576
|
+
* `console.warn` per row floods the console for the whole connection — and so
|
|
577
|
+
* does any other per-frame warn against a server sending something the reader
|
|
578
|
+
* cannot use. Every PER-FRAME warn site is bounded, but keyed by CAUSE so a row
|
|
579
|
+
* with no announcement, a short row, a long row, a non-array row, a malformed
|
|
580
|
+
* schema frame and unparseable JSON stay individually visible: collapsing them
|
|
581
|
+
* behind one flag would hide the distinct failures the warning exists to
|
|
582
|
+
* surface. Reset per attempt. (The per-connect() notices are not per-frame and
|
|
583
|
+
* are not bounded here.)
|
|
584
|
+
*/
|
|
585
|
+
_warnBudget = /* @__PURE__ */ new Map();
|
|
575
586
|
onEvent = null;
|
|
576
587
|
onStatus = null;
|
|
577
588
|
onError = null;
|
|
@@ -637,10 +648,26 @@ var SSETransport = class {
|
|
|
637
648
|
attempt++;
|
|
638
649
|
}
|
|
639
650
|
}
|
|
651
|
+
/**
|
|
652
|
+
* Warn at most `LIMIT` times per cause per connection, then once more to say
|
|
653
|
+
* how many were suppressed. Returns nothing — callers warn and bail as before.
|
|
654
|
+
*/
|
|
655
|
+
_warnBounded(cause, message, data) {
|
|
656
|
+
const LIMIT = 3;
|
|
657
|
+
const seen = (this._warnBudget.get(cause) ?? 0) + 1;
|
|
658
|
+
this._warnBudget.set(cause, seen);
|
|
659
|
+
if (seen <= LIMIT) {
|
|
660
|
+
console.warn(message, data);
|
|
661
|
+
} else if (seen === LIMIT + 1) {
|
|
662
|
+
console.warn(`${message} \u2014 further occurrences suppressed for this connection`);
|
|
663
|
+
}
|
|
664
|
+
}
|
|
640
665
|
/** One connection attempt: request, validate, then pump frames until it ends. */
|
|
641
666
|
async _attempt() {
|
|
642
667
|
const ac = new AbortController();
|
|
643
668
|
this._abort = ac;
|
|
669
|
+
this._columns = null;
|
|
670
|
+
this._warnBudget.clear();
|
|
644
671
|
let target;
|
|
645
672
|
try {
|
|
646
673
|
target = this._url();
|
|
@@ -802,6 +829,10 @@ var SSETransport = class {
|
|
|
802
829
|
onEvent: (msg) => {
|
|
803
830
|
if (msg.id) this._lastEventId = msg.id;
|
|
804
831
|
if (!msg.data) return;
|
|
832
|
+
if (msg.event === "schema") {
|
|
833
|
+
this._applySchema(msg.data);
|
|
834
|
+
return;
|
|
835
|
+
}
|
|
805
836
|
this._dispatch(msg.data);
|
|
806
837
|
},
|
|
807
838
|
onRetry: (ms) => {
|
|
@@ -840,9 +871,39 @@ var SSETransport = class {
|
|
|
840
871
|
});
|
|
841
872
|
}
|
|
842
873
|
}
|
|
874
|
+
/**
|
|
875
|
+
* Record the column list an `event: schema` frame announces. Rows that follow
|
|
876
|
+
* are zipped against it, so a malformed announcement drops the list rather
|
|
877
|
+
* than keeping a stale one: mislabeling values is worse than delivering none.
|
|
878
|
+
*/
|
|
879
|
+
_applySchema(data) {
|
|
880
|
+
try {
|
|
881
|
+
const msg = JSON.parse(data);
|
|
882
|
+
if (!Array.isArray(msg.columns) || msg.columns.some((c) => typeof c !== "string")) {
|
|
883
|
+
throw new Error("columns must be an array of strings");
|
|
884
|
+
}
|
|
885
|
+
if (new Set(msg.columns).size !== msg.columns.length) {
|
|
886
|
+
throw new Error("columns contains a duplicate name");
|
|
887
|
+
}
|
|
888
|
+
this._columns = msg.columns;
|
|
889
|
+
} catch {
|
|
890
|
+
this._columns = null;
|
|
891
|
+
this._warnBounded(
|
|
892
|
+
"bad-schema-frame",
|
|
893
|
+
"[wavehouse] SSE received a malformed schema event:",
|
|
894
|
+
data
|
|
895
|
+
);
|
|
896
|
+
}
|
|
897
|
+
}
|
|
843
898
|
/**
|
|
844
899
|
* Turn one frame's `data` into a StreamEvent.
|
|
845
900
|
*
|
|
901
|
+
* The row arrives positionally — a JSON array — and is zipped back into an
|
|
902
|
+
* object against the announced column list, so the public API still yields
|
|
903
|
+
* row objects. A row with no announcement, or one whose length disagrees with
|
|
904
|
+
* the list, cannot be read: there is no way to say which value is which, so
|
|
905
|
+
* it is dropped rather than delivered under guessed names.
|
|
906
|
+
*
|
|
846
907
|
* Guarded like `_emitError` and `_emitStatus`: `parser.feed()` dispatches
|
|
847
908
|
* every complete frame in a chunk synchronously, so a subscriber that closes
|
|
848
909
|
* from inside its own `next` — "read until I see my event, then stop" —
|
|
@@ -855,9 +916,34 @@ var SSETransport = class {
|
|
|
855
916
|
let event;
|
|
856
917
|
try {
|
|
857
918
|
const msg = JSON.parse(data);
|
|
858
|
-
|
|
919
|
+
const columns = this._columns;
|
|
920
|
+
if (!columns) {
|
|
921
|
+
this._warnBounded(
|
|
922
|
+
"no-schema",
|
|
923
|
+
"[wavehouse] SSE received a row before any schema event:",
|
|
924
|
+
data
|
|
925
|
+
);
|
|
926
|
+
return;
|
|
927
|
+
}
|
|
928
|
+
if (!Array.isArray(msg.row)) {
|
|
929
|
+
this._warnBounded("row-not-array", "[wavehouse] SSE row is not an array:", data);
|
|
930
|
+
return;
|
|
931
|
+
}
|
|
932
|
+
if (msg.row.length !== columns.length) {
|
|
933
|
+
this._warnBounded(
|
|
934
|
+
msg.row.length < columns.length ? "row-short" : "row-long",
|
|
935
|
+
`[wavehouse] SSE row has ${msg.row.length} value(s) but ${columns.length} column(s) were announced:`,
|
|
936
|
+
data
|
|
937
|
+
);
|
|
938
|
+
return;
|
|
939
|
+
}
|
|
940
|
+
const row = /* @__PURE__ */ Object.create(null);
|
|
941
|
+
for (let i = 0; i < columns.length; i++) {
|
|
942
|
+
row[columns[i]] = msg.row[i];
|
|
943
|
+
}
|
|
944
|
+
event = { table: msg.table_name, timestamp: msg.received_timestamp, data: row };
|
|
859
945
|
} catch {
|
|
860
|
-
|
|
946
|
+
this._warnBounded("bad-json", "[wavehouse] SSE received malformed message:", data);
|
|
861
947
|
return;
|
|
862
948
|
}
|
|
863
949
|
try {
|
|
@@ -1243,7 +1329,7 @@ function compareOrdered(actual, expected, cmp) {
|
|
|
1243
1329
|
return false;
|
|
1244
1330
|
}
|
|
1245
1331
|
function projectColumns(row, columns) {
|
|
1246
|
-
const result =
|
|
1332
|
+
const result = /* @__PURE__ */ Object.create(null);
|
|
1247
1333
|
for (const col of columns) {
|
|
1248
1334
|
if (col in row) result[col] = row[col];
|
|
1249
1335
|
}
|
|
@@ -1251,6 +1337,7 @@ function projectColumns(row, columns) {
|
|
|
1251
1337
|
}
|
|
1252
1338
|
|
|
1253
1339
|
// src/table.ts
|
|
1340
|
+
var JSON_CONTENT_TYPE = "application/json";
|
|
1254
1341
|
var NDJSON_CONTENT_TYPE = "application/x-ndjson";
|
|
1255
1342
|
async function ndjsonSourceToString(source) {
|
|
1256
1343
|
if (typeof source === "string") return source;
|
|
@@ -1302,8 +1389,10 @@ var TableRef = class {
|
|
|
1302
1389
|
* rest of the batch — per-record outcomes come back in the result
|
|
1303
1390
|
* (`failed` / `results`), and `ok` is true only when every record succeeded.
|
|
1304
1391
|
*
|
|
1305
|
-
* The array path sends one request regardless of size
|
|
1306
|
-
*
|
|
1392
|
+
* The array path sends one request regardless of size, so it is bound by the
|
|
1393
|
+
* server's 16 MiB request-body cap (an over-cap array is a `413` with nothing
|
|
1394
|
+
* ingested); bounded-concurrency chunking of very large arrays is tracked
|
|
1395
|
+
* separately (#196). For NDJSON you
|
|
1307
1396
|
* already have (a file or stream), use {@link insertNDJSON}.
|
|
1308
1397
|
*/
|
|
1309
1398
|
async insert(data, opts) {
|
|
@@ -1318,6 +1407,9 @@ var TableRef = class {
|
|
|
1318
1407
|
method: "POST",
|
|
1319
1408
|
path: `/v1/ingest?table=${encodeURIComponent(this._table)}`,
|
|
1320
1409
|
body: data,
|
|
1410
|
+
// Ingest requires a declared format — an undeclared Content-Type is a
|
|
1411
|
+
// 415 — so state it here rather than leaning on the request default.
|
|
1412
|
+
contentType: JSON_CONTENT_TYPE,
|
|
1321
1413
|
signal: opts?.signal
|
|
1322
1414
|
});
|
|
1323
1415
|
if (error) return err(error);
|
|
@@ -1331,9 +1423,11 @@ var TableRef = class {
|
|
|
1331
1423
|
* file or a stream produced by another system. For in-memory rows, prefer
|
|
1332
1424
|
* {@link insert}.
|
|
1333
1425
|
*
|
|
1334
|
-
* Non-string sources are read fully into memory before sending
|
|
1335
|
-
*
|
|
1336
|
-
* `
|
|
1426
|
+
* Non-string sources are read fully into memory before sending. The server
|
|
1427
|
+
* buffers the whole body too, so the request-body cap applies to NDJSON
|
|
1428
|
+
* exactly as to any other shape — an upload over it is a `413` with nothing
|
|
1429
|
+
* ingested, and must be split across several calls. Returns the same
|
|
1430
|
+
* per-record batch summary as an array `insert`.
|
|
1337
1431
|
*/
|
|
1338
1432
|
async insertNDJSON(source, opts) {
|
|
1339
1433
|
const ndjson = await ndjsonSourceToString(source);
|
|
@@ -1365,11 +1459,12 @@ var TableRef = class {
|
|
|
1365
1459
|
if (r.results && r.results.length > 0) result.results = r.results;
|
|
1366
1460
|
return ok(result);
|
|
1367
1461
|
}
|
|
1368
|
-
/** Fetch the schema for this table. */
|
|
1462
|
+
/** Fetch the schema for this table — under `opts.tenant`, the default tenant without it. */
|
|
1369
1463
|
async schema(opts) {
|
|
1370
1464
|
const { data, error } = await request(this._ctx, {
|
|
1371
1465
|
method: "GET",
|
|
1372
|
-
path:
|
|
1466
|
+
path: "/v1/ops/schema",
|
|
1467
|
+
params: { table: this._table, ...tenantParam(opts) },
|
|
1373
1468
|
signal: opts?.signal
|
|
1374
1469
|
});
|
|
1375
1470
|
if (error) return err(error);
|
|
@@ -1387,14 +1482,14 @@ var WaveHouseClient = class {
|
|
|
1387
1482
|
_ctx;
|
|
1388
1483
|
/** Schema introspection namespace. */
|
|
1389
1484
|
schema;
|
|
1390
|
-
/** Access control policy namespace (admin). */
|
|
1391
|
-
policy;
|
|
1392
1485
|
/** Dead Letter Queue namespace. */
|
|
1393
1486
|
dlq;
|
|
1394
1487
|
/** System health/readiness namespace. */
|
|
1395
1488
|
sys;
|
|
1396
1489
|
/** Named query pipes admin namespace. */
|
|
1397
1490
|
pipes;
|
|
1491
|
+
/** Settings directory namespace (admin). */
|
|
1492
|
+
settings;
|
|
1398
1493
|
constructor(config) {
|
|
1399
1494
|
this._ctx = {
|
|
1400
1495
|
baseURL: config.baseURL.replace(/\/+$/, ""),
|
|
@@ -1407,10 +1502,10 @@ var WaveHouseClient = class {
|
|
|
1407
1502
|
}
|
|
1408
1503
|
};
|
|
1409
1504
|
this.schema = new SchemaNamespace(this._ctx);
|
|
1410
|
-
this.policy = new PolicyNamespace(this._ctx);
|
|
1411
1505
|
this.dlq = new DLQNamespace(this._ctx, (table, opts) => this._createStream(table, opts));
|
|
1412
1506
|
this.sys = new SysNamespace(this._ctx);
|
|
1413
1507
|
this.pipes = new PipesNamespace(this._ctx);
|
|
1508
|
+
this.settings = new SettingsNamespace(this._ctx);
|
|
1414
1509
|
}
|
|
1415
1510
|
/** Get a table reference for building queries, inserts, and streams. */
|
|
1416
1511
|
from(table) {
|
|
@@ -1430,7 +1525,9 @@ var WaveHouseClient = class {
|
|
|
1430
1525
|
* `service` role). The endpoint proxies straight to ClickHouse's HTTP
|
|
1431
1526
|
* interface so any ClickHouse-accepted SQL works; positional `?` param
|
|
1432
1527
|
* binding is NOT supported — inline literals or use the structured query
|
|
1433
|
-
* builder for safe binding. See sql.ts for details.
|
|
1528
|
+
* builder for safe binding. See sql.ts for details. `opts.tenant` names the
|
|
1529
|
+
* tenant whose ClickHouse the SQL runs against, the default tenant without
|
|
1530
|
+
* it.
|
|
1434
1531
|
*/
|
|
1435
1532
|
sql(query, opts) {
|
|
1436
1533
|
if (Array.isArray(opts)) {
|
|
@@ -1464,9 +1561,9 @@ export {
|
|
|
1464
1561
|
LiveQuery,
|
|
1465
1562
|
PipeRef,
|
|
1466
1563
|
PipesNamespace,
|
|
1467
|
-
PolicyNamespace,
|
|
1468
1564
|
QueryBuilder,
|
|
1469
1565
|
SchemaNamespace,
|
|
1566
|
+
SettingsNamespace,
|
|
1470
1567
|
StreamController,
|
|
1471
1568
|
SysNamespace,
|
|
1472
1569
|
TableRef,
|