@wavehouse/chtypes 0.5.2 → 1.0.2
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/CHANGELOG.md +34 -0
- package/README.md +34 -38
- package/dist/abi1/buildinfo.d.ts +40 -0
- package/dist/abi1/buildinfo.d.ts.map +1 -0
- package/dist/abi1/buildinfo.js +83 -0
- package/dist/abi1/buildinfo.js.map +1 -0
- package/dist/abi1/calls.gen.d.ts +55 -0
- package/dist/abi1/calls.gen.d.ts.map +1 -0
- package/dist/abi1/calls.gen.js +110 -0
- package/dist/abi1/calls.gen.js.map +1 -0
- package/dist/abi1/decls.gen.d.ts +115 -0
- package/dist/abi1/decls.gen.d.ts.map +1 -0
- package/dist/abi1/decls.gen.js +1613 -0
- package/dist/abi1/decls.gen.js.map +1 -0
- package/dist/abi1/errmap.gen.d.ts +18 -0
- package/dist/abi1/errmap.gen.d.ts.map +1 -0
- package/dist/abi1/errmap.gen.js +66 -0
- package/dist/abi1/errmap.gen.js.map +1 -0
- package/dist/abi1/errors.d.ts +107 -0
- package/dist/abi1/errors.d.ts.map +1 -0
- package/dist/abi1/errors.js +134 -0
- package/dist/abi1/errors.js.map +1 -0
- package/dist/abi1/handles.d.ts +31 -0
- package/dist/abi1/handles.d.ts.map +1 -0
- package/dist/abi1/handles.js +76 -0
- package/dist/abi1/handles.js.map +1 -0
- package/dist/abi1/index.d.ts +17 -0
- package/dist/abi1/index.d.ts.map +1 -0
- package/dist/abi1/index.js +17 -0
- package/dist/abi1/index.js.map +1 -0
- package/dist/abi1/libc.d.ts +54 -0
- package/dist/abi1/libc.d.ts.map +1 -0
- package/dist/abi1/libc.gen.d.ts +12 -0
- package/dist/abi1/libc.gen.d.ts.map +1 -0
- package/dist/abi1/libc.gen.js +75 -0
- package/dist/abi1/libc.gen.js.map +1 -0
- package/dist/abi1/libc.js +109 -0
- package/dist/abi1/libc.js.map +1 -0
- package/dist/abi1/loader.d.ts +101 -0
- package/dist/abi1/loader.d.ts.map +1 -0
- package/dist/abi1/loader.js +274 -0
- package/dist/abi1/loader.js.map +1 -0
- package/dist/abi1/raw.d.ts +104 -0
- package/dist/abi1/raw.d.ts.map +1 -0
- package/dist/abi1/raw.js +296 -0
- package/dist/abi1/raw.js.map +1 -0
- package/dist/abi1/strictjson.d.ts +19 -0
- package/dist/abi1/strictjson.d.ts.map +1 -0
- package/dist/abi1/strictjson.js +78 -0
- package/dist/abi1/strictjson.js.map +1 -0
- package/dist/abi1/vocab.gen.d.ts +169 -0
- package/dist/abi1/vocab.gen.d.ts.map +1 -0
- package/dist/abi1/vocab.gen.js +306 -0
- package/dist/abi1/vocab.gen.js.map +1 -0
- package/dist/cli.d.ts +25 -26
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +206 -218
- package/dist/cli.js.map +1 -1
- package/dist/documents.d.ts +195 -0
- package/dist/documents.d.ts.map +1 -0
- package/dist/documents.js +389 -0
- package/dist/documents.js.map +1 -0
- package/dist/env.d.ts +16 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +57 -0
- package/dist/env.js.map +1 -0
- package/dist/index.d.ts +19 -24
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -23
- package/dist/index.js.map +1 -1
- package/dist/json.d.ts +11 -89
- package/dist/json.d.ts.map +1 -1
- package/dist/json.js +16 -180
- package/dist/json.js.map +1 -1
- package/dist/library.d.ts +53 -309
- package/dist/library.d.ts.map +1 -1
- package/dist/library.js +77 -315
- package/dist/library.js.map +1 -1
- package/dist/ocifetch/constants.gen.d.ts +84 -0
- package/dist/ocifetch/constants.gen.d.ts.map +1 -0
- package/dist/ocifetch/constants.gen.js +92 -0
- package/dist/ocifetch/constants.gen.js.map +1 -0
- package/dist/ocifetch/dsse.d.ts +114 -0
- package/dist/ocifetch/dsse.d.ts.map +1 -0
- package/dist/ocifetch/dsse.js +331 -0
- package/dist/ocifetch/dsse.js.map +1 -0
- package/dist/ocifetch/ensure.d.ts +65 -0
- package/dist/ocifetch/ensure.d.ts.map +1 -0
- package/dist/ocifetch/ensure.js +775 -0
- package/dist/ocifetch/ensure.js.map +1 -0
- package/dist/ocifetch/errors.d.ts +92 -0
- package/dist/ocifetch/errors.d.ts.map +1 -0
- package/dist/ocifetch/errors.js +101 -0
- package/dist/ocifetch/errors.js.map +1 -0
- package/dist/ocifetch/goldens.d.ts +44 -0
- package/dist/ocifetch/goldens.d.ts.map +1 -0
- package/dist/ocifetch/goldens.js +62 -0
- package/dist/ocifetch/goldens.js.map +1 -0
- package/dist/ocifetch/http.d.ts +124 -0
- package/dist/ocifetch/http.d.ts.map +1 -0
- package/dist/ocifetch/http.js +549 -0
- package/dist/ocifetch/http.js.map +1 -0
- package/dist/ocifetch/index.d.ts +17 -0
- package/dist/ocifetch/index.d.ts.map +1 -0
- package/dist/ocifetch/index.js +14 -0
- package/dist/ocifetch/index.js.map +1 -0
- package/dist/ocifetch/layout.d.ts +126 -0
- package/dist/ocifetch/layout.d.ts.map +1 -0
- package/dist/ocifetch/layout.js +375 -0
- package/dist/ocifetch/layout.js.map +1 -0
- package/dist/ocifetch/localverify.d.ts +43 -0
- package/dist/ocifetch/localverify.d.ts.map +1 -0
- package/dist/ocifetch/localverify.js +164 -0
- package/dist/ocifetch/localverify.js.map +1 -0
- package/dist/ocifetch/lock.d.ts +39 -0
- package/dist/ocifetch/lock.d.ts.map +1 -0
- package/dist/ocifetch/lock.js +140 -0
- package/dist/ocifetch/lock.js.map +1 -0
- package/dist/ocifetch/oci.d.ts +100 -0
- package/dist/ocifetch/oci.d.ts.map +1 -0
- package/dist/ocifetch/oci.js +323 -0
- package/dist/ocifetch/oci.js.map +1 -0
- package/dist/ocifetch/referrers.d.ts +55 -0
- package/dist/ocifetch/referrers.d.ts.map +1 -0
- package/dist/ocifetch/referrers.js +132 -0
- package/dist/ocifetch/referrers.js.map +1 -0
- package/dist/ocifetch/types.d.ts +167 -0
- package/dist/ocifetch/types.d.ts.map +1 -0
- package/dist/ocifetch/types.js +88 -0
- package/dist/ocifetch/types.js.map +1 -0
- package/dist/ocifetch/unpack.d.ts +55 -0
- package/dist/ocifetch/unpack.d.ts.map +1 -0
- package/dist/ocifetch/unpack.js +205 -0
- package/dist/ocifetch/unpack.js.map +1 -0
- package/dist/registry.d.ts +38 -387
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +95 -819
- package/dist/registry.js.map +1 -1
- package/dist/schema.d.ts +77 -588
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +87 -549
- package/dist/schema.js.map +1 -1
- package/dist/settings.d.ts +27 -36
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js +75 -25
- package/dist/settings.js.map +1 -1
- package/dist/setup.d.ts +46 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +79 -0
- package/dist/setup.js.map +1 -0
- package/dist/tar.d.ts +27 -11
- package/dist/tar.d.ts.map +1 -1
- package/dist/tar.js +54 -32
- package/dist/tar.js.map +1 -1
- package/package.json +2 -2
- package/dist/discover.d.ts +0 -142
- package/dist/discover.d.ts.map +0 -1
- package/dist/discover.js +0 -288
- package/dist/discover.js.map +0 -1
- package/dist/error-codes.d.ts +0 -80
- package/dist/error-codes.d.ts.map +0 -1
- package/dist/error-codes.js +0 -139
- package/dist/error-codes.js.map +0 -1
- package/dist/errors.d.ts +0 -284
- package/dist/errors.d.ts.map +0 -1
- package/dist/errors.js +0 -321
- package/dist/errors.js.map +0 -1
- package/dist/fetch.d.ts +0 -382
- package/dist/fetch.d.ts.map +0 -1
- package/dist/fetch.js +0 -1498
- package/dist/fetch.js.map +0 -1
- package/dist/ffi.d.ts +0 -410
- package/dist/ffi.d.ts.map +0 -1
- package/dist/ffi.js +0 -1154
- package/dist/ffi.js.map +0 -1
- package/dist/format.d.ts +0 -128
- package/dist/format.d.ts.map +0 -1
- package/dist/format.js +0 -132
- package/dist/format.js.map +0 -1
- package/dist/numeric.d.ts +0 -20
- package/dist/numeric.d.ts.map +0 -1
- package/dist/numeric.js +0 -107
- package/dist/numeric.js.map +0 -1
- package/dist/paths.d.ts +0 -55
- package/dist/paths.d.ts.map +0 -1
- package/dist/paths.js +0 -87
- package/dist/paths.js.map +0 -1
- package/dist/results.d.ts +0 -495
- package/dist/results.d.ts.map +0 -1
- package/dist/results.js +0 -406
- package/dist/results.js.map +0 -1
- package/dist/transform.d.ts +0 -73
- package/dist/transform.d.ts.map +0 -1
- package/dist/transform.js +0 -533
- package/dist/transform.js.map +0 -1
package/dist/schema.js
CHANGED
|
@@ -1,571 +1,109 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* version's library, plus the engine and TTL declarations that make `rows()`
|
|
4
|
-
* answer with the storage layer's verdict as well as the type layer's.
|
|
5
|
-
*/
|
|
6
|
-
import { ChtypesError } from './errors.js';
|
|
7
|
-
import { DOC_ALL, EXPORT_NONE } from './format.js';
|
|
8
|
-
import { parseDocument } from './json.js';
|
|
9
|
-
import { batchResultOf, filterResultOf, rowResultOf, } from './results.js';
|
|
10
|
-
import { encodeSettings } from './settings.js';
|
|
11
|
-
const schemaFinalizer = new FinalizationRegistry((n) => {
|
|
12
|
-
if (n.handle === null)
|
|
13
|
-
return; // closed explicitly already
|
|
14
|
-
for (const h of n.openFilters)
|
|
15
|
-
n.native.filterFree(h);
|
|
16
|
-
n.openFilters.clear();
|
|
17
|
-
for (const h of n.openBlocks)
|
|
18
|
-
n.native.blockFree(h);
|
|
19
|
-
n.openBlocks.clear();
|
|
20
|
-
n.native.schemaFree(n.handle);
|
|
21
|
-
n.handle = null;
|
|
22
|
-
});
|
|
23
|
-
const filterFinalizer = new FinalizationRegistry((n) => {
|
|
24
|
-
if (n.handle === null)
|
|
25
|
-
return;
|
|
26
|
-
if (n.schema.openFilters.delete(n.handle))
|
|
27
|
-
n.native.filterFree(n.handle);
|
|
28
|
-
n.handle = null;
|
|
29
|
-
});
|
|
30
|
-
const blockFinalizer = new FinalizationRegistry((n) => {
|
|
31
|
-
if (n.handle === null)
|
|
32
|
-
return;
|
|
33
|
-
if (n.schema.openBlocks.delete(n.handle))
|
|
34
|
-
n.native.blockFree(n.handle);
|
|
35
|
-
n.handle = null;
|
|
36
|
-
});
|
|
37
|
-
/**
|
|
38
|
-
* A compiled schema — one tenant table's column list, compiled inside one
|
|
39
|
-
* version's library. Obtained from `Library#compileDdl`; never constructed
|
|
40
|
-
* directly. Release with `close()` (idempotent) or `using` / `Symbol.dispose`
|
|
41
|
-
* — `close()` stays the primary path; a GC finalizer that calls it for a
|
|
42
|
-
* schema nobody closed is a backstop, not a replacement, since there is no
|
|
43
|
-
* promise about WHEN (or, in principle, whether) it runs.
|
|
2
|
+
* `Schema`, `Filter` and `Block`: the compiled objects of `docs/reference/bindings-v1.md` §2.
|
|
44
3
|
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
* `
|
|
49
|
-
*/
|
|
50
|
-
export class Schema {
|
|
51
|
-
native;
|
|
52
|
-
ddl;
|
|
53
|
-
/**
|
|
54
|
-
* The declared columns as ClickHouse canonicalized them, in declaration
|
|
55
|
-
* order — flattened under `flatten_nested=1`, DEFAULT-rewritten types
|
|
56
|
-
* (`x Int64 DEFAULT NULL` compiles as `Nullable(Int64)`), ALIAS types
|
|
57
|
-
* inferred. A gateway detects EPHEMERAL columns here, at compile time
|
|
58
|
-
* (`defaultKind === 'EPHEMERAL'`), not per row.
|
|
59
|
-
*/
|
|
60
|
-
columns;
|
|
61
|
-
/** The handle plus the GC-finalizer coordination state; see `SchemaNative`. */
|
|
62
|
-
n;
|
|
63
|
-
/**
|
|
64
|
-
* Every open `Filter` compiled from this handle, so `close()` can free them
|
|
65
|
-
* FIRST — the C layer does not refcount, and freeing the schema under a
|
|
66
|
-
* live filter is use-after-free (the C ABI contract §Filters, handle lifetime).
|
|
67
|
-
*/
|
|
68
|
-
filters = new Set();
|
|
69
|
-
/**
|
|
70
|
-
* Every open `Block` parsed from this handle — the same non-owning rule,
|
|
71
|
-
* the same free-before-schema order (the C ABI contract §Blocks).
|
|
72
|
-
*/
|
|
73
|
-
blocks = new Set();
|
|
74
|
-
/** @internal — obtained from `Library#compileDdl`. */
|
|
75
|
-
constructor(native, handle,
|
|
76
|
-
/** The column-declaration list this schema was compiled from, verbatim. */
|
|
77
|
-
ddl) {
|
|
78
|
-
this.native = native;
|
|
79
|
-
this.ddl = ddl;
|
|
80
|
-
this.n = { native, handle, openFilters: new Set(), openBlocks: new Set() };
|
|
81
|
-
this.columns = native.columns(handle);
|
|
82
|
-
schemaFinalizer.register(this, this.n, this);
|
|
83
|
-
}
|
|
84
|
-
live() {
|
|
85
|
-
if (this.n.handle === null)
|
|
86
|
-
throw new ChtypesError('chtypes: schema is closed');
|
|
87
|
-
return this.n.handle;
|
|
88
|
-
}
|
|
89
|
-
/**
|
|
90
|
-
* Declare the table engine, so `rows()` applies the engine's own insert-time
|
|
91
|
-
* merge (`optimize_on_insert = 1`): a CollapsingMergeTree refusing an invalid
|
|
92
|
-
* Sign with code 117 before anything is stored, a SummingMergeTree summing
|
|
93
|
-
* equal keys and dropping all-zero rows, a ReplacingMergeTree deduplicating.
|
|
94
|
-
*
|
|
95
|
-
* `options.mergeTreeSettings` declares the table's MergeTree-namespace
|
|
96
|
-
* settings — see `EngineOptions` for the error contract (unknown name ⇒ the
|
|
97
|
-
* server's 115; non-default declared value ⇒ `unsupported`, never silently
|
|
98
|
-
* ignored). Absent/empty is structurally the plain engine declaration:
|
|
99
|
-
* `chs_schema_engine` takes "{}" either way.
|
|
100
|
-
*
|
|
101
|
-
* The two error classes here are the refusal/decline split and MUST be
|
|
102
|
-
* handled as peers — `UnsupportedError` is deliberately NOT
|
|
103
|
-
* `instanceof SchemaError` (docs/reference/bindings.md rule 12):
|
|
104
|
-
*
|
|
105
|
-
* @param engine - the engine expression, e.g. `"SummingMergeTree"`,
|
|
106
|
-
* `"CollapsingMergeTree(sign)"`.
|
|
107
|
-
* @param orderBy - the sorting key, e.g. `"(day, key)"`.
|
|
108
|
-
* @param options - the MergeTree-namespace `SETTINGS` clause, if any.
|
|
109
|
-
* @throws {SchemaError} when the SERVER refused (positive code): this DDL
|
|
110
|
-
* can never exist and the tenant has to be told. Today that is 115, an
|
|
111
|
-
* unknown MergeTree setting name, with the server's own message verbatim.
|
|
112
|
-
* @throws {UnsupportedError} when this LIBRARY declined: an engine or
|
|
113
|
-
* sorting key this build does not model, a known MergeTree setting
|
|
114
|
-
* declared at a non-default value, or a guarded exception. A real server
|
|
115
|
-
* might well have accepted it — validate cautiously, fall back to the
|
|
116
|
-
* server, and never present the decline as a rejection.
|
|
117
|
-
*/
|
|
118
|
-
setEngine(engine, orderBy, options) {
|
|
119
|
-
this.native.schemaEngine(this.live(), engine, orderBy, encodeSettings(options?.mergeTreeSettings));
|
|
120
|
-
}
|
|
121
|
-
/**
|
|
122
|
-
* Declare the table's rows TTL (`ts + INTERVAL 30 DAY`). An expired row is
|
|
123
|
-
* reported NOT STORED through the batch's `transformed` list.
|
|
124
|
-
*
|
|
125
|
-
* Column-level TTLs need no call: they are part of the declaration list.
|
|
126
|
-
*
|
|
127
|
-
* @param ttl - the rows-TTL expression, e.g. `"ts + INTERVAL 30 DAY"`. It is
|
|
128
|
-
* validated under the handle's declared compile profile when one exists.
|
|
129
|
-
* @throws {UnsupportedError} for a TTL form this build refuses rather than
|
|
130
|
-
* guesses: WHERE / GROUP BY TTLs, TO DISK/VOLUME moves, RECOMPRESS, any
|
|
131
|
-
* clock-reading TTL expression, and guarded exceptions. Fall back to the
|
|
132
|
-
* server; do not report a tenant error.
|
|
133
|
-
*/
|
|
134
|
-
setTtl(ttl) {
|
|
135
|
-
this.native.schemaTtl(this.live(), ttl);
|
|
136
|
-
}
|
|
137
|
-
/**
|
|
138
|
-
* Declare the table's partition key — the `PARTITION BY` clause after the
|
|
139
|
-
* engine, e.g. `"toYYYYMM(ts)"` or `"(toDate(ts), tenant)"`
|
|
140
|
-
* (`chs_schema_partition_by`, revision 6). The key is built by the server's
|
|
141
|
-
* own CREATE-path call over this schema's columns, under the handle's
|
|
142
|
-
* compile profile. A second call REPLACES the first; `""` removes the
|
|
143
|
-
* declaration, and the schema then answers exactly as one that never
|
|
144
|
-
* declared a key.
|
|
145
|
-
*
|
|
146
|
-
* With a key declared, `row` and `rows` answer `RowResult#partitionId` for
|
|
147
|
-
* every row that would be stored and `BatchResult#partitionCount` for the
|
|
148
|
-
* batch, and a body that would split into more partitions than the call's
|
|
149
|
-
* `max_partitions_per_insert_block` allows is an ordinary `'rejected'` with
|
|
150
|
-
* `errCode` 252 (TOO_MANY_PARTS), the server's own — a verdict, never a
|
|
151
|
-
* throw.
|
|
152
|
-
*
|
|
153
|
-
* @param expr - the partition key expression, or `""` to remove it.
|
|
154
|
-
* @throws {SchemaError} when the server's own CREATE path refuses the key
|
|
155
|
-
* (e.g. 36 BAD_ARGUMENTS for a non-deterministic key, 549
|
|
156
|
-
* DATA_TYPE_CANNOT_BE_USED_IN_KEY) — `setEngine`'s SIGN rule, not
|
|
157
|
-
* `setTtl`'s.
|
|
158
|
-
* @throws {UnsupportedError} when this build declines (-1, a guarded
|
|
159
|
-
* exception), or the artifact predates `chs_schema_partition_by`. -2 is a
|
|
160
|
-
* key the server accepts but this build will not evaluate; a
|
|
161
|
-
* non-deterministic key is the server's own rejection, 36 BAD_ARGUMENTS.
|
|
162
|
-
*/
|
|
163
|
-
setPartitionBy(expr) {
|
|
164
|
-
this.native.schemaPartitionBy(this.live(), expr);
|
|
165
|
-
}
|
|
166
|
-
/**
|
|
167
|
-
* Validate and coerce ONE row body, answering exactly as this ClickHouse
|
|
168
|
-
* version's insert path would.
|
|
169
|
-
*
|
|
170
|
-
* There is no exception for a bad row: rejection, poisoning and declines all
|
|
171
|
-
* arrive as the `RowResult`'s `outcome` (see `Outcome` for the taxonomy and
|
|
172
|
-
* the caller's obligations per arm).
|
|
173
|
-
*
|
|
174
|
-
* @param format - the wire format code (`Format`). Binary-format support
|
|
175
|
-
* depends on the loaded artifact — probe, don't assume.
|
|
176
|
-
* @param raw - the row's bytes, exactly as they would arrive in an INSERT
|
|
177
|
-
* body. Always bytes, never a JS string: binary formats contain NUL bytes
|
|
178
|
-
* and text rows can carry invalid UTF-8 on purpose.
|
|
179
|
-
* @param settings - per-call settings; they win over the compile profile and
|
|
180
|
-
* the library defaults (except a type gate the profile declared, which the
|
|
181
|
-
* handle has already settled, as a real server's CREATE does).
|
|
182
|
-
* @param options - `RowOptions#columns` (revision 5), the INSERT column
|
|
183
|
-
* list. `row()` takes `RowOptions`, not `RowsOptions`: the revision-3
|
|
184
|
-
* export/doc-flag channels are meaningless on a single row, so this
|
|
185
|
-
* method's options type simply does not offer them.
|
|
186
|
-
* @returns the `RowResult` — verdict, stored values, and every silent change.
|
|
187
|
-
* @throws {ChtypesError} when the schema is closed, or a settings value is a
|
|
188
|
-
* JS `number`.
|
|
189
|
-
* @throws {UnsupportedError} when the artifact predates `chs_row`.
|
|
190
|
-
*/
|
|
191
|
-
row(format, raw, settings, options) {
|
|
192
|
-
const doc = this.native.row(this.live(), format, raw, encodeSettings(settings), options?.columns);
|
|
193
|
-
return rowResultOf(parseDocument(doc));
|
|
194
|
-
}
|
|
195
|
-
/**
|
|
196
|
-
* Validate and coerce a whole request body, which may hold many rows.
|
|
197
|
-
*
|
|
198
|
-
* This is not `row()` in a loop and must never be implemented as one: row
|
|
199
|
-
* separation is format-specific (a quoted CSV field can contain a newline),
|
|
200
|
-
* `input_format_allow_errors_num` / `_ratio` decide whether a bad row is
|
|
201
|
-
* skipped or aborts the batch, and one batch is one clock instant for the
|
|
202
|
-
* volatile-DEFAULT guarantee.
|
|
203
|
-
*
|
|
204
|
-
* @param format - the wire format code (`Format`).
|
|
205
|
-
* @param body - the whole request body as bytes (never a JS string).
|
|
206
|
-
* @param settings - per-call settings; same precedence as `row`.
|
|
207
|
-
* @returns the `BatchResult`. When `engineRows` is present it — not `rows` —
|
|
208
|
-
* is the stored truth, and batch-level storage transforms (`ttl_expired`,
|
|
209
|
-
* `ttl_column_expired`) are folded into `transformed`.
|
|
210
|
-
* With `options.exportFormat` the same ONE call also serializes the batch's
|
|
211
|
-
* accepted rows through the vendored writer: `payload` carries the bytes
|
|
212
|
-
* (zero-length = emitted-empty, an accepted batch with zero accepted rows;
|
|
213
|
-
* `undefined` + `exportDeclined` = withheld, with the reason), and `spans`
|
|
214
|
-
* is index-aligned with `rows` — `payload.subarray(s.off, s.off + s.len)`
|
|
215
|
-
* IS row i's line. With `options.docFlags` the per-row documents are
|
|
216
|
-
* thinned to the selected groups; the verdict channel is never thinned.
|
|
217
|
-
* See `RowsOptions` for the defaults and `BatchResult` for the three
|
|
218
|
-
* payload states.
|
|
219
|
-
*
|
|
220
|
-
* @param format - the wire format code (`Format`).
|
|
221
|
-
* @param body - the whole request body as bytes (never a JS string).
|
|
222
|
-
* @param settings - per-call settings; same precedence as `row`.
|
|
223
|
-
* @param options - the revision-3 export/doc-flag channels, plus
|
|
224
|
-
* `columns` (revision 5), the INSERT column list, and `rowFilter`
|
|
225
|
-
* (revision 5, second half) — see `RowsOptions`; absent = today's full
|
|
226
|
-
* document, byte-identical to revision 2, no list, byte-identical to
|
|
227
|
-
* every revision before 5, and no filter, byte-identical byte for byte.
|
|
228
|
-
* @returns the `BatchResult`. When `engineRows` is present it — not `rows` —
|
|
229
|
-
* is the stored truth, and batch-level storage transforms (`ttl_expired`,
|
|
230
|
-
* `ttl_column_expired`) are folded into `transformed`. With
|
|
231
|
-
* `options.rowFilter`, `rowsPassed`/`rowsCut` join the result and every
|
|
232
|
-
* row carries its filter `verdict` beside its own `outcome`.
|
|
233
|
-
* @throws {ChtypesError} when the schema is closed, a settings value is a JS
|
|
234
|
-
* `number`, the artifact predates `chs_rows` (a mandatory symbol), the
|
|
235
|
-
* filter is closed, or the filter comes from a different loaded library.
|
|
236
|
-
*/
|
|
237
|
-
rows(format, body, settings, options) {
|
|
238
|
-
const exportFormat = options?.exportFormat ?? EXPORT_NONE;
|
|
239
|
-
const docFlags = options?.docFlags ?? (options?.exportFormat === undefined ? DOC_ALL : 0);
|
|
240
|
-
const rowFilter = options?.rowFilter;
|
|
241
|
-
let filterHandle;
|
|
242
|
-
if (rowFilter !== undefined) {
|
|
243
|
-
if (rowFilter.nativeLib !== this.native) {
|
|
244
|
-
throw new ChtypesError('chtypes: filter and schema come from different libraries');
|
|
245
|
-
}
|
|
246
|
-
filterHandle = rowFilter.liveHandle();
|
|
247
|
-
}
|
|
248
|
-
const { doc, payload } = this.native.rows(this.live(), format, body, encodeSettings(settings), exportFormat, docFlags, options?.columns, filterHandle);
|
|
249
|
-
return batchResultOf(parseDocument(doc), payload);
|
|
250
|
-
}
|
|
251
|
-
/**
|
|
252
|
-
* Compile one boolean SQL expression over this schema's PHYSICAL columns
|
|
253
|
-
* (ordinary + MATERIALIZED; naming an ALIAS/EPHEMERAL column fails with
|
|
254
|
-
* ClickHouse's own UNKNOWN_IDENTIFIER, exactly where a real CREATE fails) —
|
|
255
|
-
* the same TreeRewriter + ExpressionAnalyzer pipeline the CONSTRAINT CHECK
|
|
256
|
-
* path runs, so comparison semantics are WHERE-side by construction:
|
|
257
|
-
* `x = 256` over UInt8 promotes (false for every row), it never wraps
|
|
258
|
-
* (the C ABI contract §Filters).
|
|
259
|
-
*
|
|
260
|
-
* The expression may contain `{name:Type}` query parameters, bound with
|
|
261
|
-
* `options.params` (revision 4) — substitution is the server's own
|
|
262
|
-
* `ReplaceQueryParameterVisitor`, run before analysis, exactly where a
|
|
263
|
-
* real server runs it; see `CompileFilterOptions` for the injection-safety
|
|
264
|
-
* and cache-discipline contract. Close the filter when done (`close()` /
|
|
265
|
-
* `Symbol.dispose`); `schema.close()` also closes every open filter FIRST,
|
|
266
|
-
* so no caller ordering can free the schema under a live filter.
|
|
267
|
-
*
|
|
268
|
-
* ENFORCEMENT GATE: nothing may enforce read-side security on this surface
|
|
269
|
-
* until the WHERE-truth rig gates green (zero over-admit, zero over-hide);
|
|
270
|
-
* until then it is a shadow/replay surface.
|
|
271
|
-
*
|
|
272
|
-
* @param expr - one boolean expression, e.g. `"x = 256"` or
|
|
273
|
-
* `"tenant = {t:String}"`.
|
|
274
|
-
* @param options - the `{name:Type}` bindings, if any.
|
|
275
|
-
* @returns the compiled `Filter`.
|
|
276
|
-
* @throws {SchemaError} when ClickHouse itself refuses the expression —
|
|
277
|
-
* unknown identifier (47), unknown function, an analyzer-raised
|
|
278
|
-
* NO_COMMON_TYPE — and, since revision 4, the server's own parameter
|
|
279
|
-
* refusals: an UNBOUND `{name:Type}` is **456** UNKNOWN_QUERY_PARAMETER
|
|
280
|
-
* ("Substitution `name` is not set"), a value the declared type cannot
|
|
281
|
-
* parse completely is **457** BAD_QUERY_PARAMETER — the server's own
|
|
282
|
-
* code and message, verbatim. A bound name the expression never uses is
|
|
283
|
-
* ignored, as a live server ignores an unused `param_*`.
|
|
284
|
-
* @throws {UnsupportedError} when this build declines: a non-deterministic
|
|
285
|
-
* expression (clock reads — `now() > ts` —, `rand()`, server-constants;
|
|
286
|
-
* the scan runs AFTER substitution, so a value can never smuggle one
|
|
287
|
-
* in), or an artifact that predates the filter trio.
|
|
288
|
-
*/
|
|
289
|
-
compileFilter(expr, options) {
|
|
290
|
-
const handle = this.native.filterCompile(this.live(), expr, encodeSettings(options?.params));
|
|
291
|
-
this.n.openFilters.add(handle);
|
|
292
|
-
const filter = new Filter(this.native, this, this.n, handle, expr);
|
|
293
|
-
this.filters.add(filter);
|
|
294
|
-
return filter;
|
|
295
|
-
}
|
|
296
|
-
/** @internal — `Filter#close` deregisters itself here. */
|
|
297
|
-
forgetFilter(filter) {
|
|
298
|
-
this.filters.delete(filter);
|
|
299
|
-
}
|
|
300
|
-
/**
|
|
301
|
-
* Parse a body ONCE into a `Block` (`chs_block_parse`) — the parse half of
|
|
302
|
-
* `Filter#rows`, exported so K filters can evaluate one event with no
|
|
303
|
-
* re-parse (`Filter#eval`; the C ABI contract §Blocks). Same formats and
|
|
304
|
-
* settings contract as `rows` (`settings` is the PARSE-side map: format
|
|
305
|
-
* settings, clock keys; evaluation takes none). Volatile DEFAULTs resolve
|
|
306
|
-
* against THIS call's clock instant, so
|
|
307
|
-
* `filter.eval(schema.parseBlock(...))` ≡ `filter.rows(...)` exactly when
|
|
308
|
-
* the clock is pinned (`chtypes_now_epoch_nanos`) or the schema has no
|
|
309
|
-
* volatile DEFAULT.
|
|
310
|
-
*
|
|
311
|
-
* Per-row parse failures do NOT throw — they are recorded IN the block and
|
|
312
|
-
* answer `'d'` from every filter, with the recorded error. Release
|
|
313
|
-
* with `close()` / `Symbol.dispose`; `schema.close()` closes open blocks
|
|
314
|
-
* FIRST, the C-required order.
|
|
315
|
-
*
|
|
316
|
-
* @param format - the wire format code (`Format`).
|
|
317
|
-
* @param body - the rows as bytes (never a JS string).
|
|
318
|
-
* @param settings - parse-side settings; same precedence as `Schema#rows`.
|
|
319
|
-
* @param options - `RowOptions#columns` (revision 5), the INSERT column
|
|
320
|
-
* list read exactly as `Schema#row` reads it. `parseBlock()` takes
|
|
321
|
-
* `RowOptions`, not `RowsOptions`: the revision-3 export/doc-flag
|
|
322
|
-
* channels are meaningless here, so this method's options type simply
|
|
323
|
-
* does not offer them. Filters compiled against this schema still
|
|
324
|
-
* evaluate the schema's PHYSICAL columns, so a listed `EPHEMERAL`
|
|
325
|
-
* column stays unreferenceable in a filter.
|
|
326
|
-
* @returns the parsed `Block`.
|
|
327
|
-
* @throws {SchemaError} on a call-level failure — an unknown setting's
|
|
328
|
-
* 115, an unsplittable body, a binary decode fault, the deferred
|
|
329
|
-
* JSONEachRow framing verdict: a malformed body yields no block and no
|
|
330
|
-
* partial answers.
|
|
331
|
-
* @throws {UnsupportedError} when this build declines the call, or the
|
|
332
|
-
* artifact predates the block twin.
|
|
333
|
-
*/
|
|
334
|
-
parseBlock(format, body, settings, options) {
|
|
335
|
-
const handle = this.native.blockParse(this.live(), format, body, encodeSettings(settings), options?.columns);
|
|
336
|
-
this.n.openBlocks.add(handle);
|
|
337
|
-
const block = new Block(this.native, this, this.n, handle);
|
|
338
|
-
this.blocks.add(block);
|
|
339
|
-
return block;
|
|
340
|
-
}
|
|
341
|
-
/** @internal — `Block#close` deregisters itself here. */
|
|
342
|
-
forgetBlock(block) {
|
|
343
|
-
this.blocks.delete(block);
|
|
344
|
-
}
|
|
345
|
-
/**
|
|
346
|
-
* Release the native schema. Idempotent. After it, `row` / `rows` /
|
|
347
|
-
* `setEngine` / `setTtl` / `setPartitionBy` throw `ChtypesError` ("schema
|
|
348
|
-
* is closed").
|
|
349
|
-
* Any `Filter` or `Block` still open on this schema is closed FIRST, in
|
|
350
|
-
* the same call — the handles-before-schema free order the C layer
|
|
351
|
-
* requires, enforced here so no dispose ordering can get it backwards.
|
|
352
|
-
*/
|
|
353
|
-
close() {
|
|
354
|
-
for (const filter of this.filters)
|
|
355
|
-
filter.close();
|
|
356
|
-
this.filters.clear();
|
|
357
|
-
for (const block of this.blocks)
|
|
358
|
-
block.close();
|
|
359
|
-
this.blocks.clear();
|
|
360
|
-
if (this.n.handle === null)
|
|
361
|
-
return;
|
|
362
|
-
this.native.schemaFree(this.n.handle);
|
|
363
|
-
this.n.handle = null;
|
|
364
|
-
schemaFinalizer.unregister(this);
|
|
365
|
-
}
|
|
366
|
-
/** `using schema = lib.compileDdl(...)` releases it at scope exit. */
|
|
367
|
-
[Symbol.dispose]() {
|
|
368
|
-
this.close();
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
/**
|
|
372
|
-
* One boolean SQL expression compiled against a `Schema`'s columns
|
|
373
|
-
* (`chs_filter_compile`). Obtained from `Schema#compileFilter`; never
|
|
374
|
-
* constructed directly.
|
|
375
|
-
*
|
|
376
|
-
* LIFETIME: a filter REFERENCES its schema handle — the C layer does not copy
|
|
377
|
-
* and does not refcount (the C ABI contract §Filters). This binding enforces the
|
|
378
|
-
* free order structurally, both ways: the `Filter` holds its `Schema` (so the
|
|
379
|
-
* schema stays reachable), and `Schema#close` closes every open filter before
|
|
380
|
-
* freeing the schema. `close()` is idempotent, and `using` / `Symbol.dispose`
|
|
381
|
-
* work on both objects in any nesting — the schema's dispose runs the
|
|
382
|
-
* filter's first when the caller forgot. A filter compiled from a schema
|
|
383
|
-
* answers for THAT handle: recompile filters when the schema is recompiled.
|
|
384
|
-
* A filter nobody closed is also backed by a GC finalizer, coordinated with
|
|
385
|
-
* its schema's own (see `SchemaNative`) so the two can never free this
|
|
386
|
-
* filter's handle out of order or twice, whichever one the GC happens to run
|
|
387
|
-
* first.
|
|
4
|
+
* Every public call makes exactly one ABI call over the generated, typed
|
|
5
|
+
* layer, then decodes the document it returned (`./documents.ts`) and
|
|
6
|
+
* computes nothing. The per-call zone is the `session_timezone` key of the
|
|
7
|
+
* call's settings and nothing more (`./settings.ts`).
|
|
388
8
|
*
|
|
389
|
-
*
|
|
390
|
-
*
|
|
391
|
-
*
|
|
392
|
-
*
|
|
393
|
-
*
|
|
394
|
-
*
|
|
395
|
-
*
|
|
396
|
-
*
|
|
397
|
-
*
|
|
398
|
-
* enforce read-side security on this surface until the WHERE-truth rig gates
|
|
399
|
-
* green; until then it is a shadow/replay surface (the C ABI contract §Filters).
|
|
9
|
+
* Handles. Each object holds the generated layer's handle wrapper, whose
|
|
10
|
+
* `ptr` raises a `UsageError` naming the object once it is closed, before any
|
|
11
|
+
* C call. A filter or a block holds a counted reference to its schema inside
|
|
12
|
+
* the library, so a binding object neither holds its parent alive nor orders
|
|
13
|
+
* its frees: closing a schema while its filters are in use is legal, and
|
|
14
|
+
* `close` is idempotent. A `FinalizationRegistry` per handle class frees what
|
|
15
|
+
* the caller abandons. TypeScript runs every call synchronously on one
|
|
16
|
+
* thread, so the close guard of the other bindings reduces to this check: no
|
|
17
|
+
* call is ever in flight while `close` runs.
|
|
400
18
|
*/
|
|
19
|
+
import { DocFlags, EXPORT_NONE } from './abi1/index.js';
|
|
20
|
+
import { decodeBatch, decodeFilterResult, decodeRow, decodeSchemaDescription, } from './documents.js';
|
|
21
|
+
import { bytesIn, encodeColumns, encodeParams, encodeSettings } from './settings.js';
|
|
22
|
+
function bodyIn(body) {
|
|
23
|
+
if (typeof body === 'string')
|
|
24
|
+
throw new TypeError('chtypes: a body is bytes (a Uint8Array); it never accepts the text type');
|
|
25
|
+
return body;
|
|
26
|
+
}
|
|
27
|
+
const filterHandles = new WeakMap();
|
|
28
|
+
/** A compiled `WHERE`-style expression bound to a schema. It holds its own zone, fixed at compile. */
|
|
401
29
|
export class Filter {
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
this.
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
filterFinalizer.register(this, this.n, this);
|
|
416
|
-
}
|
|
417
|
-
/** @internal — the loaded library this filter's handle belongs to, for
|
|
418
|
-
* `Schema#rows(options.rowFilter)`'s cross-library check. */
|
|
419
|
-
get nativeLib() {
|
|
420
|
-
return this.native;
|
|
421
|
-
}
|
|
422
|
-
/** @internal — the live handle, for `Schema#rows(options.rowFilter)`. */
|
|
423
|
-
liveHandle() {
|
|
424
|
-
if (this.n.handle === null)
|
|
425
|
-
throw new ChtypesError('chtypes: filter is closed');
|
|
426
|
-
return this.n.handle;
|
|
427
|
-
}
|
|
428
|
-
/**
|
|
429
|
-
* Evaluate the filter over a body of rows (`chs_filter_rows`) — the same
|
|
430
|
-
* formats and settings contract as `Schema#rows`, ONE C call. Rows are
|
|
431
|
-
* evaluated INDEPENDENTLY (there is no INSERT to abort):
|
|
432
|
-
* `input_format_allow_errors_*` does not apply, a bad text row declines
|
|
433
|
-
* (`'d'`) and the tail resyncs so verdict indexes keep matching input
|
|
434
|
-
* rows, and volatile DEFAULTs resolve against one clock instant per call.
|
|
435
|
-
*
|
|
436
|
-
* @param format - the wire format code (`Format`).
|
|
437
|
-
* @param body - the rows as bytes (never a JS string).
|
|
438
|
-
* @param settings - per-call settings; same precedence as `Schema#rows`.
|
|
439
|
-
* @returns the `FilterResult` — the call-level outcome, and one verdict per
|
|
440
|
-
* row when it is `'ok'`.
|
|
441
|
-
* @throws {ChtypesError} when the filter is closed, or a settings value is
|
|
442
|
-
* a JS `number`.
|
|
443
|
-
*/
|
|
444
|
-
rows(format, body, settings) {
|
|
445
|
-
if (this.n.handle === null)
|
|
446
|
-
throw new ChtypesError('chtypes: filter is closed');
|
|
447
|
-
const doc = this.native.filterRows(this.n.handle, format, body, encodeSettings(settings));
|
|
448
|
-
return filterResultOf(parseDocument(doc));
|
|
449
|
-
}
|
|
450
|
-
/**
|
|
451
|
-
* Evaluate this filter over an already-parsed `Block` (`chs_filter_eval`)
|
|
452
|
-
* — the SAME result document `rows` returns: same `FilterResult` fields,
|
|
453
|
-
* same verdicts, same `errors` rule (a row the parse recorded as
|
|
454
|
-
* unparseable answers `'d'` with the recorded error). Evaluation is
|
|
455
|
-
* a pure function of (filter, block): no settings, and the block is
|
|
456
|
-
* neither consumed nor mutated, so one block can be evaluated by K filters
|
|
457
|
-
* sequentially with no re-parse — the live-SSE call shape.
|
|
458
|
-
*
|
|
459
|
-
* Filter and block MUST come from the SAME schema: a mismatched pair
|
|
460
|
-
* answers a REJECTED result (code 1002) — the C layer's loud refusal,
|
|
461
|
-
* never undefined behavior. A pair from two different libraries throws
|
|
462
|
-
* `ChtypesError`: no handle ever crosses a dlopen'd image boundary.
|
|
463
|
-
*
|
|
464
|
-
* @param block - a `Block` from `Schema#parseBlock`.
|
|
465
|
-
* @returns the `FilterResult`, exactly as `rows` would answer it.
|
|
466
|
-
* @throws {ChtypesError} when the filter or block is closed, or they come
|
|
467
|
-
* from two different libraries.
|
|
468
|
-
*/
|
|
30
|
+
#calls;
|
|
31
|
+
#h;
|
|
32
|
+
/** Not for callers: use `Schema.compileFilter`. */
|
|
33
|
+
constructor(calls, handle) {
|
|
34
|
+
this.#calls = calls;
|
|
35
|
+
this.#h = handle;
|
|
36
|
+
filterHandles.set(this, handle);
|
|
37
|
+
}
|
|
38
|
+
/** Evaluate over a body. */
|
|
39
|
+
rows(format, body, options = {}) {
|
|
40
|
+
return decodeFilterResult(this.#calls.filterEvalBody(this.#h, format, bodyIn(body), encodeSettings(options.settings, options.sessionTimezone)));
|
|
41
|
+
}
|
|
42
|
+
/** Evaluate over a parsed block. The filter brings its zone and the block brought its parse zone, so there are no settings here. */
|
|
469
43
|
eval(block) {
|
|
470
|
-
|
|
471
|
-
throw new ChtypesError('chtypes: filter is closed');
|
|
472
|
-
if (block.nativeLib !== this.native) {
|
|
473
|
-
throw new ChtypesError('chtypes: filter and block come from different libraries');
|
|
474
|
-
}
|
|
475
|
-
const doc = this.native.filterEval(this.n.handle, block.liveHandle());
|
|
476
|
-
return filterResultOf(parseDocument(doc));
|
|
44
|
+
return decodeFilterResult(this.#calls.filterEvalBlock(this.#h, blockHandles.get(block)));
|
|
477
45
|
}
|
|
478
|
-
/**
|
|
479
|
-
* Release the native filter (`chs_filter_free`). Idempotent, and also
|
|
480
|
-
* performed by the schema's own `close()` — filters first, then the schema,
|
|
481
|
-
* the C-required order. Also the backstop a GC finalizer calls for a filter
|
|
482
|
-
* nobody closed — see `SchemaNative`; the `openFilters.delete` guard is
|
|
483
|
-
* what makes it safe to run whether `close()`, this filter's own finalizer,
|
|
484
|
-
* or the schema's finalizer gets here first.
|
|
485
|
-
*/
|
|
46
|
+
/** Release this filter; idempotent. */
|
|
486
47
|
close() {
|
|
487
|
-
|
|
488
|
-
return;
|
|
489
|
-
if (this.n.schema.openFilters.delete(this.n.handle)) {
|
|
490
|
-
this.native.filterFree(this.n.handle);
|
|
491
|
-
}
|
|
492
|
-
this.n.handle = null;
|
|
493
|
-
this.schema.forgetFilter(this);
|
|
494
|
-
filterFinalizer.unregister(this);
|
|
48
|
+
this.#h.close();
|
|
495
49
|
}
|
|
496
|
-
/** `using filter = schema.compileFilter(...)` releases it at scope exit. */
|
|
497
50
|
[Symbol.dispose]() {
|
|
498
51
|
this.close();
|
|
499
52
|
}
|
|
500
53
|
}
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
* (`chs_block_parse`). Obtained from `Schema#parseBlock`; evaluated by
|
|
504
|
-
* `Filter#eval`. The parse-once/eval-many twin of `Filter#rows`
|
|
505
|
-
* (the C ABI contract §Blocks): the live-SSE hot path is K filters × 1 event, and
|
|
506
|
-
* the block sheds the re-parse.
|
|
507
|
-
*
|
|
508
|
-
* LIFETIME: a block REFERENCES its schema handle exactly as a filter does —
|
|
509
|
-
* the C layer does not copy and does not refcount. This binding enforces the
|
|
510
|
-
* free order structurally, both ways: the `Block` holds its `Schema` (so the
|
|
511
|
-
* schema stays reachable), and `Schema#close` closes every open block before
|
|
512
|
-
* freeing the schema — `using` / `Symbol.dispose` work on all three objects
|
|
513
|
-
* in any nesting, and the schema's dispose runs the block's first when the
|
|
514
|
-
* caller forgot. A block may be evaluated by MANY filters, sequentially;
|
|
515
|
-
* evaluation does not consume or mutate it. Recompile blocks when the schema
|
|
516
|
-
* is recompiled.
|
|
517
|
-
*
|
|
518
|
-
* THREADS: one block must not be used from two threads at once, and an eval
|
|
519
|
-
* is a use of BOTH handles. On a single JS thread every call here is
|
|
520
|
-
* synchronous, so ordinary Node code satisfies both by construction; do not
|
|
521
|
-
* share a `Block` — or its `Schema` — across `worker_threads`.
|
|
522
|
-
*
|
|
523
|
-
* A block nobody closed is also backed by a GC finalizer, coordinated with
|
|
524
|
-
* its schema's own (see `SchemaNative`) so the two can never free this
|
|
525
|
-
* block's handle out of order or twice, whichever one the GC happens to run
|
|
526
|
-
* first.
|
|
527
|
-
*/
|
|
54
|
+
const blockHandles = new WeakMap();
|
|
55
|
+
/** A body parsed once, evaluated by any number of filters. */
|
|
528
56
|
export class Block {
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
constructor(native, schema, schemaNative, handle) {
|
|
535
|
-
this.native = native;
|
|
536
|
-
this.schema = schema;
|
|
537
|
-
this.n = { native, schema: schemaNative, handle };
|
|
538
|
-
blockFinalizer.register(this, this.n, this);
|
|
57
|
+
#h;
|
|
58
|
+
/** Not for callers: use `Schema.parseBlock`. */
|
|
59
|
+
constructor(handle) {
|
|
60
|
+
this.#h = handle;
|
|
61
|
+
blockHandles.set(this, handle);
|
|
539
62
|
}
|
|
540
|
-
/**
|
|
541
|
-
|
|
542
|
-
|
|
63
|
+
/** Release this block; idempotent. */
|
|
64
|
+
close() {
|
|
65
|
+
this.#h.close();
|
|
543
66
|
}
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
if (this.n.handle === null)
|
|
547
|
-
throw new ChtypesError('chtypes: block is closed');
|
|
548
|
-
return this.n.handle;
|
|
67
|
+
[Symbol.dispose]() {
|
|
68
|
+
this.close();
|
|
549
69
|
}
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
70
|
+
}
|
|
71
|
+
/** A compiled `CREATE TABLE`: describe it, preview rows and bodies against it, compile filters and parse blocks over it. */
|
|
72
|
+
export class Schema {
|
|
73
|
+
#calls;
|
|
74
|
+
#h;
|
|
75
|
+
/** Not for callers: use `Library.compileTable`. */
|
|
76
|
+
constructor(calls, handle) {
|
|
77
|
+
this.#calls = calls;
|
|
78
|
+
this.#h = handle;
|
|
79
|
+
}
|
|
80
|
+
/** The columns, in declared order. */
|
|
81
|
+
describe() {
|
|
82
|
+
return decodeSchemaDescription(this.#calls.schemaDescribe(this.#h));
|
|
83
|
+
}
|
|
84
|
+
/** One row. */
|
|
85
|
+
row(format, body, options = {}) {
|
|
86
|
+
return decodeRow(this.#calls.previewRow(this.#h, format, bodyIn(body), encodeSettings(options.settings, options.sessionTimezone), encodeColumns(options.columns)));
|
|
87
|
+
}
|
|
88
|
+
/** A whole body. */
|
|
89
|
+
rows(format, body, options = {}) {
|
|
90
|
+
const filter = options.rowFilter === undefined ? null : filterHandles.get(options.rowFilter);
|
|
91
|
+
const exporting = options.exportFormat !== undefined;
|
|
92
|
+
const out = this.#calls.previewBatch(this.#h, format, bodyIn(body), encodeSettings(options.settings, options.sessionTimezone), encodeColumns(options.columns), filter, exporting ? options.exportFormat : EXPORT_NONE, options.docFlags ?? DocFlags.All);
|
|
93
|
+
return decodeBatch(out.out, exporting ? out.outExport : undefined);
|
|
94
|
+
}
|
|
95
|
+
/** Compile a filter. Its zone is fixed here. */
|
|
96
|
+
compileFilter(expr, options = {}) {
|
|
97
|
+
return new Filter(this.#calls, this.#calls.filterCreate(this.#h, bytesIn(expr), encodeParams(options.params), encodeSettings(options.settings, options.sessionTimezone)));
|
|
98
|
+
}
|
|
99
|
+
/** Parse a body once. */
|
|
100
|
+
parseBlock(format, body, options = {}) {
|
|
101
|
+
return new Block(this.#calls.blockCreate(this.#h, format, bodyIn(body), encodeSettings(options.settings, options.sessionTimezone), encodeColumns(options.columns)));
|
|
102
|
+
}
|
|
103
|
+
/** Release this schema; idempotent. Filters and blocks made from it keep working. */
|
|
558
104
|
close() {
|
|
559
|
-
|
|
560
|
-
return;
|
|
561
|
-
if (this.n.schema.openBlocks.delete(this.n.handle)) {
|
|
562
|
-
this.native.blockFree(this.n.handle);
|
|
563
|
-
}
|
|
564
|
-
this.n.handle = null;
|
|
565
|
-
this.schema.forgetBlock(this);
|
|
566
|
-
blockFinalizer.unregister(this);
|
|
105
|
+
this.#h.close();
|
|
567
106
|
}
|
|
568
|
-
/** `using block = schema.parseBlock(...)` releases it at scope exit. */
|
|
569
107
|
[Symbol.dispose]() {
|
|
570
108
|
this.close();
|
|
571
109
|
}
|