quiverdb 0.12.3 → 0.12.4
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/libs/linux-x86_64/libquiver.so +0 -0
- package/libs/linux-x86_64/libquiver.so.0 +0 -0
- package/libs/linux-x86_64/libquiver_c.so +0 -0
- package/libs/macos-aarch64/libquiver.0.dylib +0 -0
- package/libs/macos-aarch64/libquiver_c.dylib +0 -0
- package/libs/windows-x86_64/libquiver.dll +0 -0
- package/libs/windows-x86_64/libquiver_c.dll +0 -0
- package/package.json +1 -1
- package/src/composites.ts +4 -4
- package/src/create.ts +9 -0
- package/src/database.ts +56 -18
- package/src/loader.ts +9 -8
- package/src/lua-api.ts +25 -15
- package/src/read.ts +78 -37
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
package/src/composites.ts
CHANGED
|
@@ -39,9 +39,9 @@ Database.prototype.readVectorsById = function (
|
|
|
39
39
|
this: Database,
|
|
40
40
|
collection: string,
|
|
41
41
|
id: number,
|
|
42
|
-
): Record<string, number[] | string[]> {
|
|
42
|
+
): Record<string, (number | null)[] | (string | null)[]> {
|
|
43
43
|
const groups = this.listVectorGroups(collection);
|
|
44
|
-
const result: Record<string, number[] | string[]> = {};
|
|
44
|
+
const result: Record<string, (number | null)[] | (string | null)[]> = {};
|
|
45
45
|
|
|
46
46
|
for (const group of groups) {
|
|
47
47
|
for (const col of group.valueColumns) {
|
|
@@ -69,9 +69,9 @@ Database.prototype.readSetsById = function (
|
|
|
69
69
|
this: Database,
|
|
70
70
|
collection: string,
|
|
71
71
|
id: number,
|
|
72
|
-
): Record<string, number[] | string[]> {
|
|
72
|
+
): Record<string, (number | null)[] | (string | null)[]> {
|
|
73
73
|
const groups = this.listSetGroups(collection);
|
|
74
|
-
const result: Record<string, number[] | string[]> = {};
|
|
74
|
+
const result: Record<string, (number | null)[] | (string | null)[]> = {};
|
|
75
75
|
|
|
76
76
|
for (const group of groups) {
|
|
77
77
|
for (const col of group.valueColumns) {
|
package/src/create.ts
CHANGED
|
@@ -29,6 +29,15 @@ function setElementArray(
|
|
|
29
29
|
|
|
30
30
|
const first = values[0];
|
|
31
31
|
|
|
32
|
+
// A vector/set read returns a NULL cell as null. The element surface is non-null (NULL cells go
|
|
33
|
+
// through updateVectorGroup / updateSetGroup), and the numeric setters below would store a null
|
|
34
|
+
// as 0 / false. A string array keeps its NULL-pointer path, which the C setter reads as NULL.
|
|
35
|
+
if (typeof first !== "string" && values.some((v) => v === null || v === undefined)) {
|
|
36
|
+
throw new QuiverError(
|
|
37
|
+
`Unsupported null cell in array '${name}': write NULL cells with updateVectorGroup or updateSetGroup`,
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
32
41
|
if (typeof first === "bigint") {
|
|
33
42
|
const arr = allocNativeInt64(values as bigint[]);
|
|
34
43
|
check(lib.quiver_element_set_array_integer(elemPtr, nameBuf.buf, arr.buf, values.length, null));
|
package/src/database.ts
CHANGED
|
@@ -138,22 +138,54 @@ export class Database {
|
|
|
138
138
|
) => string | null;
|
|
139
139
|
declare readElementIds: (collection: string) => number[];
|
|
140
140
|
declare numberOfElements: (collection: string) => number;
|
|
141
|
-
declare readVectorIntegers: (collection: string, attribute: string) => number[][];
|
|
142
|
-
declare readVectorBooleans: (collection: string, attribute: string) => boolean[][];
|
|
143
|
-
declare readVectorFloats: (collection: string, attribute: string) => number[][];
|
|
144
|
-
declare readVectorStrings: (collection: string, attribute: string) => string[][];
|
|
145
|
-
declare readVectorIntegersById: (
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
declare
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
declare
|
|
156
|
-
|
|
141
|
+
declare readVectorIntegers: (collection: string, attribute: string) => (number | null)[][];
|
|
142
|
+
declare readVectorBooleans: (collection: string, attribute: string) => (boolean | null)[][];
|
|
143
|
+
declare readVectorFloats: (collection: string, attribute: string) => (number | null)[][];
|
|
144
|
+
declare readVectorStrings: (collection: string, attribute: string) => (string | null)[][];
|
|
145
|
+
declare readVectorIntegersById: (
|
|
146
|
+
collection: string,
|
|
147
|
+
attribute: string,
|
|
148
|
+
id: number,
|
|
149
|
+
) => (number | null)[];
|
|
150
|
+
declare readVectorBooleansById: (
|
|
151
|
+
collection: string,
|
|
152
|
+
attribute: string,
|
|
153
|
+
id: number,
|
|
154
|
+
) => (boolean | null)[];
|
|
155
|
+
declare readVectorFloatsById: (
|
|
156
|
+
collection: string,
|
|
157
|
+
attribute: string,
|
|
158
|
+
id: number,
|
|
159
|
+
) => (number | null)[];
|
|
160
|
+
declare readVectorStringsById: (
|
|
161
|
+
collection: string,
|
|
162
|
+
attribute: string,
|
|
163
|
+
id: number,
|
|
164
|
+
) => (string | null)[];
|
|
165
|
+
declare readSetIntegers: (collection: string, attribute: string) => (number | null)[][];
|
|
166
|
+
declare readSetBooleans: (collection: string, attribute: string) => (boolean | null)[][];
|
|
167
|
+
declare readSetFloats: (collection: string, attribute: string) => (number | null)[][];
|
|
168
|
+
declare readSetStrings: (collection: string, attribute: string) => (string | null)[][];
|
|
169
|
+
declare readSetIntegersById: (
|
|
170
|
+
collection: string,
|
|
171
|
+
attribute: string,
|
|
172
|
+
id: number,
|
|
173
|
+
) => (number | null)[];
|
|
174
|
+
declare readSetBooleansById: (
|
|
175
|
+
collection: string,
|
|
176
|
+
attribute: string,
|
|
177
|
+
id: number,
|
|
178
|
+
) => (boolean | null)[];
|
|
179
|
+
declare readSetFloatsById: (
|
|
180
|
+
collection: string,
|
|
181
|
+
attribute: string,
|
|
182
|
+
id: number,
|
|
183
|
+
) => (number | null)[];
|
|
184
|
+
declare readSetStringsById: (
|
|
185
|
+
collection: string,
|
|
186
|
+
attribute: string,
|
|
187
|
+
id: number,
|
|
188
|
+
) => (string | null)[];
|
|
157
189
|
|
|
158
190
|
// --- Queries (implemented in query.ts) ---
|
|
159
191
|
declare queryString: (sql: string, parameters?: QueryParam[]) => string | null;
|
|
@@ -268,6 +300,12 @@ export class Database {
|
|
|
268
300
|
collection: string,
|
|
269
301
|
id: number,
|
|
270
302
|
) => Record<string, number | string | null>;
|
|
271
|
-
declare readVectorsById: (
|
|
272
|
-
|
|
303
|
+
declare readVectorsById: (
|
|
304
|
+
collection: string,
|
|
305
|
+
id: number,
|
|
306
|
+
) => Record<string, (number | null)[] | (string | null)[]>;
|
|
307
|
+
declare readSetsById: (
|
|
308
|
+
collection: string,
|
|
309
|
+
id: number,
|
|
310
|
+
) => Record<string, (number | null)[] | (string | null)[]>;
|
|
273
311
|
}
|
package/src/loader.ts
CHANGED
|
@@ -73,17 +73,17 @@ const readSymbols = {
|
|
|
73
73
|
quiver_database_read_scalar_integer_by_id: { args: [P, BUF, BUF, I64, P, P], returns: I32 },
|
|
74
74
|
quiver_database_read_scalar_float_by_id: { args: [P, BUF, BUF, I64, P, P], returns: I32 },
|
|
75
75
|
quiver_database_read_scalar_string_by_id: { args: [P, BUF, BUF, I64, P, P], returns: I32 },
|
|
76
|
-
quiver_database_read_vector_integers: { args: [P, BUF, BUF, P, P, P], returns: I32 },
|
|
77
|
-
quiver_database_read_vector_floats: { args: [P, BUF, BUF, P, P, P], returns: I32 },
|
|
76
|
+
quiver_database_read_vector_integers: { args: [P, BUF, BUF, P, P, P, P], returns: I32 },
|
|
77
|
+
quiver_database_read_vector_floats: { args: [P, BUF, BUF, P, P, P, P], returns: I32 },
|
|
78
78
|
quiver_database_read_vector_strings: { args: [P, BUF, BUF, P, P, P], returns: I32 },
|
|
79
|
-
quiver_database_read_set_integers: { args: [P, BUF, BUF, P, P, P], returns: I32 },
|
|
80
|
-
quiver_database_read_set_floats: { args: [P, BUF, BUF, P, P, P], returns: I32 },
|
|
79
|
+
quiver_database_read_set_integers: { args: [P, BUF, BUF, P, P, P, P], returns: I32 },
|
|
80
|
+
quiver_database_read_set_floats: { args: [P, BUF, BUF, P, P, P, P], returns: I32 },
|
|
81
81
|
quiver_database_read_set_strings: { args: [P, BUF, BUF, P, P, P], returns: I32 },
|
|
82
|
-
quiver_database_read_vector_integers_by_id: { args: [P, BUF, BUF, I64, P, P], returns: I32 },
|
|
83
|
-
quiver_database_read_vector_floats_by_id: { args: [P, BUF, BUF, I64, P, P], returns: I32 },
|
|
82
|
+
quiver_database_read_vector_integers_by_id: { args: [P, BUF, BUF, I64, P, P, P], returns: I32 },
|
|
83
|
+
quiver_database_read_vector_floats_by_id: { args: [P, BUF, BUF, I64, P, P, P], returns: I32 },
|
|
84
84
|
quiver_database_read_vector_strings_by_id: { args: [P, BUF, BUF, I64, P, P], returns: I32 },
|
|
85
|
-
quiver_database_read_set_integers_by_id: { args: [P, BUF, BUF, I64, P, P], returns: I32 },
|
|
86
|
-
quiver_database_read_set_floats_by_id: { args: [P, BUF, BUF, I64, P, P], returns: I32 },
|
|
85
|
+
quiver_database_read_set_integers_by_id: { args: [P, BUF, BUF, I64, P, P, P], returns: I32 },
|
|
86
|
+
quiver_database_read_set_floats_by_id: { args: [P, BUF, BUF, I64, P, P, P], returns: I32 },
|
|
87
87
|
quiver_database_read_set_strings_by_id: { args: [P, BUF, BUF, I64, P, P], returns: I32 },
|
|
88
88
|
quiver_database_read_element_ids: { args: [P, BUF, P, P], returns: I32 },
|
|
89
89
|
quiver_database_number_of_elements: { args: [P, BUF, P], returns: I32 },
|
|
@@ -181,6 +181,7 @@ const freeSymbols = {
|
|
|
181
181
|
quiver_database_free_integer_array: { args: [P], returns: I32 },
|
|
182
182
|
quiver_database_free_float_array: { args: [P], returns: I32 },
|
|
183
183
|
quiver_database_free_mask: { args: [P], returns: I32 },
|
|
184
|
+
quiver_database_free_masks: { args: [P, USIZE], returns: I32 },
|
|
184
185
|
quiver_database_free_string_array: { args: [P, USIZE], returns: I32 },
|
|
185
186
|
quiver_database_free_string: { args: [P], returns: I32 },
|
|
186
187
|
quiver_database_free_integer_vectors: { args: [P, P, USIZE], returns: I32 },
|
package/src/lua-api.ts
CHANGED
|
@@ -127,9 +127,14 @@ midnight.
|
|
|
127
127
|
|
|
128
128
|
**A table with holes is an object, not an array.** A bulk read of a nullable column returns
|
|
129
129
|
\`nil\` holes (see Reading), so \`return db:read_scalar_integers(c, a)\` encodes as
|
|
130
|
-
\`{"1":10,"3":30}\` — not \`[10,null,30]\` — and the keys sort as text (\`"1","11","2"\`). When the
|
|
131
|
-
needs positional data, return the ids alongside and fill the holes yourself:
|
|
130
|
+
\`{"1":10,"3":30}\` — not \`[10,null,30]\` — and the keys sort as text (\`"1","11","2"\`). When the
|
|
131
|
+
host needs positional scalar data, return the ids alongside and fill the holes yourself:
|
|
132
132
|
\`local v = db:read_scalar_integers(c, a); local out = {}; for i in ipairs(ids) do out[i] = v[i] or false end\`.
|
|
133
|
+
**Inside** a vector/set read an inner list with an interior NULL cell encodes as an object nested
|
|
134
|
+
in the outer array (\`[{"1":10,"3":30},[]]\`), but a trailing NULL cell leaves no trace at all:
|
|
135
|
+
\`[10, NULL]\` encodes as the plain \`[10]\`. The ids count elements, not rows, so they cannot
|
|
136
|
+
restore inner positions — take the row count from a \`NOT NULL\` column of the group (see
|
|
137
|
+
*Vector reads*), or do that read in the host binding.
|
|
133
138
|
|
|
134
139
|
Returning a function, a coroutine, or a userdata (including \`db\` itself) raises
|
|
135
140
|
\`Cannot run: script returned an unsupported Lua type\`; nesting deeper than 32 levels raises
|
|
@@ -280,6 +285,10 @@ Notes:
|
|
|
280
285
|
\`Cannot update_element: ...\`.
|
|
281
286
|
- **Empty arrays are skipped.** An attribute whose value is \`{}\` writes no vector/set (the element
|
|
282
287
|
type can't be inferred from an empty array), so it is silently dropped.
|
|
288
|
+
- **Arrays must be dense.** A vector/set read returns a NULL cell as a \`nil\` hole, but an element
|
|
289
|
+
array cannot carry one: \`create_element\` / \`update_element\` throw \`array '<name>' has a nil
|
|
290
|
+
hole ...\` rather than cut the array short at the hole. Write NULL cells with
|
|
291
|
+
\`update_vector_group\` / \`update_set_group\`, which write a hole as NULL.
|
|
283
292
|
- **No \`nil\` scalar attributes.** In Lua a key set to \`nil\` is dropped from the table, so
|
|
284
293
|
\`{ x = nil }\` is identical to \`{}\`; an update/create table that ends up with no attributes
|
|
285
294
|
**throws** (\`...must have at least one scalar attribute\` on create, \`...at least one attribute
|
|
@@ -314,10 +323,13 @@ db:read_scalar_strings(collection, attribute) -- { "Item 1", "Item 2", ... }
|
|
|
314
323
|
|
|
315
324
|
## Vector reads (bulk)
|
|
316
325
|
|
|
317
|
-
Each returns an array of arrays — one inner array per element
|
|
326
|
+
Each returns an array of arrays — one inner array per element, aligned with
|
|
327
|
+
\`db:read_element_ids\`; an element with no rows is \`{}\`. A NULL cell is a \`nil\` hole, so on a
|
|
328
|
+
nullable column \`#\` and \`ipairs\` are unreliable on an inner list, and a trailing NULL is
|
|
329
|
+
invisible (\`[10, NULL]\` reads as \`{10}\`; a NULL-only row reads as \`{}\`).
|
|
318
330
|
|
|
319
331
|
\`\`\`lua
|
|
320
|
-
db:read_vector_integers(collection, attribute) -- { {1,2,3}, {
|
|
332
|
+
db:read_vector_integers(collection, attribute) -- { {1,2,3}, {10,nil,30}, {}, ... }
|
|
321
333
|
db:read_vector_floats(collection, attribute)
|
|
322
334
|
db:read_vector_strings(collection, attribute)
|
|
323
335
|
\`\`\`
|
|
@@ -326,7 +338,7 @@ db:read_vector_strings(collection, attribute)
|
|
|
326
338
|
|
|
327
339
|
## Set reads (bulk)
|
|
328
340
|
|
|
329
|
-
Same shape as vector reads — an array of arrays.
|
|
341
|
+
Same shape and NULL handling as vector reads — an array of arrays with \`nil\` holes.
|
|
330
342
|
|
|
331
343
|
\`\`\`lua
|
|
332
344
|
db:read_set_integers(collection, attribute)
|
|
@@ -358,7 +370,8 @@ rewriting groups you never named. \`(collection, group)\` names exactly one tabl
|
|
|
358
370
|
|
|
359
371
|
Rules:
|
|
360
372
|
- **Row count is the largest index any column reaches.** Shorter or sparse columns write NULL in
|
|
361
|
-
the gaps, so \`nil\` holes from a read round-trip.
|
|
373
|
+
the gaps, so interior \`nil\` holes from a read round-trip. A trailing row that is NULL in every
|
|
374
|
+
column is invisible to a read (see *Vector reads*), so writing a read back drops it.
|
|
362
375
|
- **\`{}\` (no columns) clears the group.** Naming a column whose array is empty is an error, not a
|
|
363
376
|
clear — a typo'd column name must not destroy data.
|
|
364
377
|
- **\`id\` and \`vector_index\` are managed by the group** (the element and the row's position) and
|
|
@@ -376,20 +389,17 @@ Rules:
|
|
|
376
389
|
db:read_element_ids(collection) -- { 1, 2, 3, ... }
|
|
377
390
|
|
|
378
391
|
db:read_scalars_by_id(collection, id) -- { attr = value, ... } (missing -> nil)
|
|
379
|
-
db:read_vectors_by_id(collection, id) -- { column = { v1,
|
|
380
|
-
db:read_sets_by_id(collection, id) -- { column = { v1,
|
|
392
|
+
db:read_vectors_by_id(collection, id) -- { column = { v1, nil, v3, ... }, ... }
|
|
393
|
+
db:read_sets_by_id(collection, id) -- { column = { v1, nil, v3, ... }, ... }
|
|
381
394
|
db:read_element_by_id(collection, id) -- scalars + vectors + sets merged into one table
|
|
382
395
|
\`\`\`
|
|
383
396
|
|
|
384
397
|
\`read_element_by_id\` merges every scalar, vector, and set for the element into a single table.
|
|
385
398
|
Scalar attributes with no value come back as \`nil\`.
|
|
386
399
|
|
|
387
|
-
**Group columns
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
nullable (e.g. an \`ON DELETE SET NULL\` relation). Do not zip them into rows. There is no
|
|
391
|
-
row-aligned group read in Lua; if you need per-row alignment across a nullable group, do that read
|
|
392
|
-
in the host binding instead.
|
|
400
|
+
**Group columns keep NULL cells as \`nil\` holes**, so cell *i* of every column of one group is
|
|
401
|
+
the same row. Zipping them needs the row count: \`#\` of a \`NOT NULL\` column of the group.
|
|
402
|
+
There is no row-shaped group read in Lua.
|
|
393
403
|
|
|
394
404
|
---
|
|
395
405
|
|
|
@@ -856,6 +866,6 @@ and \`unit\` default to \`""\`; \`labels\`, \`dimensions\`, \`dimension_sizes\`,
|
|
|
856
866
|
DateTime wrapper helpers (Lua uses ISO 8601 strings), boolean *reader* helpers (a stored flag reads
|
|
857
867
|
back as \`0\`/\`1\` — writing a boolean is supported), \`_by_id\` single-scalar variants (use the
|
|
858
868
|
composite by-id readers or the bulk readers instead), and the row-aligned whole-group readers the
|
|
859
|
-
other bindings have (hence the
|
|
869
|
+
other bindings have (hence the row-count caveat under composite by-id reads). Everything else
|
|
860
870
|
the native binding exposes — CRUD, reads, time series, metadata, query, CSV, and the
|
|
861
871
|
binary/expression subsystems — is documented above and callable.`;
|
package/src/read.ts
CHANGED
|
@@ -8,7 +8,6 @@ import {
|
|
|
8
8
|
decodeFloat64Array,
|
|
9
9
|
decodeInt64Array,
|
|
10
10
|
decodePtrArray,
|
|
11
|
-
decodeStringArray,
|
|
12
11
|
decodeStringFromBuf,
|
|
13
12
|
decodeUint64Array,
|
|
14
13
|
readPtrOut,
|
|
@@ -251,10 +250,11 @@ function readBulkIntegers(
|
|
|
251
250
|
fn: string,
|
|
252
251
|
collection: string,
|
|
253
252
|
attribute: string,
|
|
254
|
-
): number[][] {
|
|
253
|
+
): (number | null)[][] {
|
|
255
254
|
const collBuf = toCString(collection);
|
|
256
255
|
const attrBuf = toCString(attribute);
|
|
257
256
|
const outVectors = allocPtrOut();
|
|
257
|
+
const outMasks = allocPtrOut();
|
|
258
258
|
const outSizes = allocPtrOut();
|
|
259
259
|
const outCount = allocUint64Out();
|
|
260
260
|
check(
|
|
@@ -263,6 +263,7 @@ function readBulkIntegers(
|
|
|
263
263
|
collBuf.buf,
|
|
264
264
|
attrBuf.buf,
|
|
265
265
|
outVectors.buf,
|
|
266
|
+
outMasks.buf,
|
|
266
267
|
outSizes.buf,
|
|
267
268
|
outCount.buf,
|
|
268
269
|
),
|
|
@@ -270,14 +271,23 @@ function readBulkIntegers(
|
|
|
270
271
|
const count = readUint64Out(outCount);
|
|
271
272
|
if (count === 0) return [];
|
|
272
273
|
const vectorsPtr = readPtrOut(outVectors);
|
|
274
|
+
const masksPtr = readPtrOut(outMasks);
|
|
273
275
|
const sizesPtr = readPtrOut(outSizes);
|
|
274
276
|
const vectorPtrs = decodePtrArray(vectorsPtr, count);
|
|
277
|
+
const maskPtrs = decodePtrArray(masksPtr, count);
|
|
275
278
|
const sizes = decodeUint64Array(sizesPtr, count);
|
|
276
|
-
const result: number[][] = new Array(count);
|
|
279
|
+
const result: (number | null)[][] = new Array(count);
|
|
277
280
|
for (let i = 0; i < count; i++) {
|
|
278
|
-
|
|
281
|
+
if (sizes[i] === 0) {
|
|
282
|
+
result[i] = [];
|
|
283
|
+
continue;
|
|
284
|
+
}
|
|
285
|
+
const values = decodeInt64Array(vectorPtrs[i], sizes[i]);
|
|
286
|
+
const mask = new Uint8Array(toArrayBuffer(maskPtrs[i] as Pointer, 0, sizes[i]));
|
|
287
|
+
result[i] = values.map((v, j) => (mask[j] ? v : null));
|
|
279
288
|
}
|
|
280
289
|
lib.quiver_database_free_integer_vectors(vectorsPtr, sizesPtr, BigInt(count));
|
|
290
|
+
lib.quiver_database_free_masks(masksPtr, BigInt(count));
|
|
281
291
|
return result;
|
|
282
292
|
}
|
|
283
293
|
|
|
@@ -287,10 +297,11 @@ function readBulkFloats(
|
|
|
287
297
|
fn: string,
|
|
288
298
|
collection: string,
|
|
289
299
|
attribute: string,
|
|
290
|
-
): number[][] {
|
|
300
|
+
): (number | null)[][] {
|
|
291
301
|
const collBuf = toCString(collection);
|
|
292
302
|
const attrBuf = toCString(attribute);
|
|
293
303
|
const outVectors = allocPtrOut();
|
|
304
|
+
const outMasks = allocPtrOut();
|
|
294
305
|
const outSizes = allocPtrOut();
|
|
295
306
|
const outCount = allocUint64Out();
|
|
296
307
|
check(
|
|
@@ -299,6 +310,7 @@ function readBulkFloats(
|
|
|
299
310
|
collBuf.buf,
|
|
300
311
|
attrBuf.buf,
|
|
301
312
|
outVectors.buf,
|
|
313
|
+
outMasks.buf,
|
|
302
314
|
outSizes.buf,
|
|
303
315
|
outCount.buf,
|
|
304
316
|
),
|
|
@@ -306,14 +318,23 @@ function readBulkFloats(
|
|
|
306
318
|
const count = readUint64Out(outCount);
|
|
307
319
|
if (count === 0) return [];
|
|
308
320
|
const vectorsPtr = readPtrOut(outVectors);
|
|
321
|
+
const masksPtr = readPtrOut(outMasks);
|
|
309
322
|
const sizesPtr = readPtrOut(outSizes);
|
|
310
323
|
const vectorPtrs = decodePtrArray(vectorsPtr, count);
|
|
324
|
+
const maskPtrs = decodePtrArray(masksPtr, count);
|
|
311
325
|
const sizes = decodeUint64Array(sizesPtr, count);
|
|
312
|
-
const result: number[][] = new Array(count);
|
|
326
|
+
const result: (number | null)[][] = new Array(count);
|
|
313
327
|
for (let i = 0; i < count; i++) {
|
|
314
|
-
|
|
328
|
+
if (sizes[i] === 0) {
|
|
329
|
+
result[i] = [];
|
|
330
|
+
continue;
|
|
331
|
+
}
|
|
332
|
+
const values = decodeFloat64Array(vectorPtrs[i], sizes[i]);
|
|
333
|
+
const mask = new Uint8Array(toArrayBuffer(maskPtrs[i] as Pointer, 0, sizes[i]));
|
|
334
|
+
result[i] = values.map((v, j) => (mask[j] ? v : null));
|
|
315
335
|
}
|
|
316
336
|
lib.quiver_database_free_float_vectors(vectorsPtr, sizesPtr, BigInt(count));
|
|
337
|
+
lib.quiver_database_free_masks(masksPtr, BigInt(count));
|
|
317
338
|
return result;
|
|
318
339
|
}
|
|
319
340
|
|
|
@@ -323,7 +344,7 @@ function readBulkStrings(
|
|
|
323
344
|
fn: string,
|
|
324
345
|
collection: string,
|
|
325
346
|
attribute: string,
|
|
326
|
-
): string[][] {
|
|
347
|
+
): (string | null)[][] {
|
|
327
348
|
const collBuf = toCString(collection);
|
|
328
349
|
const attrBuf = toCString(attribute);
|
|
329
350
|
const outVectors = allocPtrOut();
|
|
@@ -345,9 +366,16 @@ function readBulkStrings(
|
|
|
345
366
|
const sizesPtr = readPtrOut(outSizes);
|
|
346
367
|
const vectorPtrs = decodePtrArray(vectorsPtr, count);
|
|
347
368
|
const sizes = decodeUint64Array(sizesPtr, count);
|
|
348
|
-
const result: string[][] = new Array(count);
|
|
369
|
+
const result: (string | null)[][] = new Array(count);
|
|
349
370
|
for (let i = 0; i < count; i++) {
|
|
350
|
-
|
|
371
|
+
// A NULL cell is a NULL char* entry, so decode the pointer array and map NULL -> null
|
|
372
|
+
// (decodeStringArray would construct "" from a NULL pointer instead).
|
|
373
|
+
result[i] =
|
|
374
|
+
sizes[i] === 0
|
|
375
|
+
? []
|
|
376
|
+
: decodePtrArray(vectorPtrs[i], sizes[i]).map((cell) =>
|
|
377
|
+
cell === null ? null : new CString(cell).toString(),
|
|
378
|
+
);
|
|
351
379
|
}
|
|
352
380
|
lib.quiver_database_free_string_vectors(vectorsPtr, sizesPtr, BigInt(count));
|
|
353
381
|
return result;
|
|
@@ -357,7 +385,7 @@ Database.prototype.readVectorIntegers = function (
|
|
|
357
385
|
this: Database,
|
|
358
386
|
collection: string,
|
|
359
387
|
attribute: string,
|
|
360
|
-
): number[][] {
|
|
388
|
+
): (number | null)[][] {
|
|
361
389
|
return readBulkIntegers(
|
|
362
390
|
getSymbols(),
|
|
363
391
|
this._handle,
|
|
@@ -366,15 +394,12 @@ Database.prototype.readVectorIntegers = function (
|
|
|
366
394
|
attribute,
|
|
367
395
|
);
|
|
368
396
|
};
|
|
369
|
-
/**
|
|
370
|
-
* NULL cells are dropped and only elements that own rows are returned, so the result is not
|
|
371
|
-
* positionally aligned with `readElementIds` (unlike `readScalarBooleans`).
|
|
372
|
-
*/
|
|
397
|
+
/** One entry per element; within an entry a SQL NULL cell is `null`. */
|
|
373
398
|
Database.prototype.readVectorBooleans = function (
|
|
374
399
|
this: Database,
|
|
375
400
|
collection: string,
|
|
376
401
|
attribute: string,
|
|
377
|
-
): boolean[][] {
|
|
402
|
+
): (boolean | null)[][] {
|
|
378
403
|
return this.readVectorIntegers(collection, attribute).map((values) =>
|
|
379
404
|
values.map((value) => integerToBoolean(value, collection, attribute)),
|
|
380
405
|
);
|
|
@@ -383,7 +408,7 @@ Database.prototype.readVectorFloats = function (
|
|
|
383
408
|
this: Database,
|
|
384
409
|
collection: string,
|
|
385
410
|
attribute: string,
|
|
386
|
-
): number[][] {
|
|
411
|
+
): (number | null)[][] {
|
|
387
412
|
return readBulkFloats(
|
|
388
413
|
getSymbols(),
|
|
389
414
|
this._handle,
|
|
@@ -396,7 +421,7 @@ Database.prototype.readVectorStrings = function (
|
|
|
396
421
|
this: Database,
|
|
397
422
|
collection: string,
|
|
398
423
|
attribute: string,
|
|
399
|
-
): string[][] {
|
|
424
|
+
): (string | null)[][] {
|
|
400
425
|
return readBulkStrings(
|
|
401
426
|
getSymbols(),
|
|
402
427
|
this._handle,
|
|
@@ -409,7 +434,7 @@ Database.prototype.readSetIntegers = function (
|
|
|
409
434
|
this: Database,
|
|
410
435
|
collection: string,
|
|
411
436
|
attribute: string,
|
|
412
|
-
): number[][] {
|
|
437
|
+
): (number | null)[][] {
|
|
413
438
|
return readBulkIntegers(
|
|
414
439
|
getSymbols(),
|
|
415
440
|
this._handle,
|
|
@@ -418,12 +443,12 @@ Database.prototype.readSetIntegers = function (
|
|
|
418
443
|
attribute,
|
|
419
444
|
);
|
|
420
445
|
};
|
|
421
|
-
/** Same
|
|
446
|
+
/** Same contract as `readVectorBooleans`: one entry per element, and a NULL cell is `null`. */
|
|
422
447
|
Database.prototype.readSetBooleans = function (
|
|
423
448
|
this: Database,
|
|
424
449
|
collection: string,
|
|
425
450
|
attribute: string,
|
|
426
|
-
): boolean[][] {
|
|
451
|
+
): (boolean | null)[][] {
|
|
427
452
|
return this.readSetIntegers(collection, attribute).map((values) =>
|
|
428
453
|
values.map((value) => integerToBoolean(value, collection, attribute)),
|
|
429
454
|
);
|
|
@@ -432,7 +457,7 @@ Database.prototype.readSetFloats = function (
|
|
|
432
457
|
this: Database,
|
|
433
458
|
collection: string,
|
|
434
459
|
attribute: string,
|
|
435
|
-
): number[][] {
|
|
460
|
+
): (number | null)[][] {
|
|
436
461
|
return readBulkFloats(
|
|
437
462
|
getSymbols(),
|
|
438
463
|
this._handle,
|
|
@@ -445,7 +470,7 @@ Database.prototype.readSetStrings = function (
|
|
|
445
470
|
this: Database,
|
|
446
471
|
collection: string,
|
|
447
472
|
attribute: string,
|
|
448
|
-
): string[][] {
|
|
473
|
+
): (string | null)[][] {
|
|
449
474
|
return readBulkStrings(
|
|
450
475
|
getSymbols(),
|
|
451
476
|
this._handle,
|
|
@@ -464,10 +489,11 @@ function readByIdIntegers(
|
|
|
464
489
|
collection: string,
|
|
465
490
|
attribute: string,
|
|
466
491
|
id: number,
|
|
467
|
-
): number[] {
|
|
492
|
+
): (number | null)[] {
|
|
468
493
|
const collBuf = toCString(collection);
|
|
469
494
|
const attrBuf = toCString(attribute);
|
|
470
495
|
const outValues = allocPtrOut();
|
|
496
|
+
const outMask = allocPtrOut();
|
|
471
497
|
const outCount = allocUint64Out();
|
|
472
498
|
check(
|
|
473
499
|
(lib as Record<string, Function>)[fn](
|
|
@@ -476,14 +502,19 @@ function readByIdIntegers(
|
|
|
476
502
|
attrBuf.buf,
|
|
477
503
|
BigInt(id),
|
|
478
504
|
outValues.buf,
|
|
505
|
+
outMask.buf,
|
|
479
506
|
outCount.buf,
|
|
480
507
|
),
|
|
481
508
|
);
|
|
482
509
|
const count = readUint64Out(outCount);
|
|
483
510
|
if (count === 0) return [];
|
|
484
511
|
const arrPtr = readPtrOut(outValues);
|
|
485
|
-
const
|
|
512
|
+
const maskPtr = readPtrOut(outMask);
|
|
513
|
+
const values = decodeInt64Array(arrPtr, count);
|
|
514
|
+
const mask = new Uint8Array(toArrayBuffer(maskPtr as Pointer, 0, count));
|
|
515
|
+
const result = values.map((v, i) => (mask[i] ? v : null));
|
|
486
516
|
lib.quiver_database_free_integer_array(arrPtr);
|
|
517
|
+
lib.quiver_database_free_mask(maskPtr);
|
|
487
518
|
return result;
|
|
488
519
|
}
|
|
489
520
|
|
|
@@ -494,10 +525,11 @@ function readByIdFloats(
|
|
|
494
525
|
collection: string,
|
|
495
526
|
attribute: string,
|
|
496
527
|
id: number,
|
|
497
|
-
): number[] {
|
|
528
|
+
): (number | null)[] {
|
|
498
529
|
const collBuf = toCString(collection);
|
|
499
530
|
const attrBuf = toCString(attribute);
|
|
500
531
|
const outValues = allocPtrOut();
|
|
532
|
+
const outMask = allocPtrOut();
|
|
501
533
|
const outCount = allocUint64Out();
|
|
502
534
|
check(
|
|
503
535
|
(lib as Record<string, Function>)[fn](
|
|
@@ -506,14 +538,19 @@ function readByIdFloats(
|
|
|
506
538
|
attrBuf.buf,
|
|
507
539
|
BigInt(id),
|
|
508
540
|
outValues.buf,
|
|
541
|
+
outMask.buf,
|
|
509
542
|
outCount.buf,
|
|
510
543
|
),
|
|
511
544
|
);
|
|
512
545
|
const count = readUint64Out(outCount);
|
|
513
546
|
if (count === 0) return [];
|
|
514
547
|
const arrPtr = readPtrOut(outValues);
|
|
515
|
-
const
|
|
548
|
+
const maskPtr = readPtrOut(outMask);
|
|
549
|
+
const values = decodeFloat64Array(arrPtr, count);
|
|
550
|
+
const mask = new Uint8Array(toArrayBuffer(maskPtr as Pointer, 0, count));
|
|
551
|
+
const result = values.map((v, i) => (mask[i] ? v : null));
|
|
516
552
|
lib.quiver_database_free_float_array(arrPtr);
|
|
553
|
+
lib.quiver_database_free_mask(maskPtr);
|
|
517
554
|
return result;
|
|
518
555
|
}
|
|
519
556
|
|
|
@@ -524,7 +561,7 @@ function readByIdStrings(
|
|
|
524
561
|
collection: string,
|
|
525
562
|
attribute: string,
|
|
526
563
|
id: number,
|
|
527
|
-
): string[] {
|
|
564
|
+
): (string | null)[] {
|
|
528
565
|
const collBuf = toCString(collection);
|
|
529
566
|
const attrBuf = toCString(attribute);
|
|
530
567
|
const outValues = allocPtrOut();
|
|
@@ -542,7 +579,11 @@ function readByIdStrings(
|
|
|
542
579
|
const count = readUint64Out(outCount);
|
|
543
580
|
if (count === 0) return [];
|
|
544
581
|
const arrPtr = readPtrOut(outValues);
|
|
545
|
-
|
|
582
|
+
// A NULL cell is a NULL char* entry, so decode the pointer array and map NULL -> null
|
|
583
|
+
// (decodeStringArray would construct "" from a NULL pointer instead).
|
|
584
|
+
const result = decodePtrArray(arrPtr, count).map((cell) =>
|
|
585
|
+
cell === null ? null : new CString(cell).toString(),
|
|
586
|
+
);
|
|
546
587
|
lib.quiver_database_free_string_array(arrPtr, BigInt(count));
|
|
547
588
|
return result;
|
|
548
589
|
}
|
|
@@ -552,7 +593,7 @@ Database.prototype.readVectorIntegersById = function (
|
|
|
552
593
|
collection: string,
|
|
553
594
|
attribute: string,
|
|
554
595
|
id: number,
|
|
555
|
-
): number[] {
|
|
596
|
+
): (number | null)[] {
|
|
556
597
|
return readByIdIntegers(
|
|
557
598
|
getSymbols(),
|
|
558
599
|
this._handle,
|
|
@@ -567,7 +608,7 @@ Database.prototype.readVectorBooleansById = function (
|
|
|
567
608
|
collection: string,
|
|
568
609
|
attribute: string,
|
|
569
610
|
id: number,
|
|
570
|
-
): boolean[] {
|
|
611
|
+
): (boolean | null)[] {
|
|
571
612
|
return this.readVectorIntegersById(collection, attribute, id).map((value) =>
|
|
572
613
|
integerToBoolean(value, collection, attribute),
|
|
573
614
|
);
|
|
@@ -577,7 +618,7 @@ Database.prototype.readVectorFloatsById = function (
|
|
|
577
618
|
collection: string,
|
|
578
619
|
attribute: string,
|
|
579
620
|
id: number,
|
|
580
|
-
): number[] {
|
|
621
|
+
): (number | null)[] {
|
|
581
622
|
return readByIdFloats(
|
|
582
623
|
getSymbols(),
|
|
583
624
|
this._handle,
|
|
@@ -592,7 +633,7 @@ Database.prototype.readVectorStringsById = function (
|
|
|
592
633
|
collection: string,
|
|
593
634
|
attribute: string,
|
|
594
635
|
id: number,
|
|
595
|
-
): string[] {
|
|
636
|
+
): (string | null)[] {
|
|
596
637
|
return readByIdStrings(
|
|
597
638
|
getSymbols(),
|
|
598
639
|
this._handle,
|
|
@@ -607,7 +648,7 @@ Database.prototype.readSetIntegersById = function (
|
|
|
607
648
|
collection: string,
|
|
608
649
|
attribute: string,
|
|
609
650
|
id: number,
|
|
610
|
-
): number[] {
|
|
651
|
+
): (number | null)[] {
|
|
611
652
|
return readByIdIntegers(
|
|
612
653
|
getSymbols(),
|
|
613
654
|
this._handle,
|
|
@@ -622,7 +663,7 @@ Database.prototype.readSetBooleansById = function (
|
|
|
622
663
|
collection: string,
|
|
623
664
|
attribute: string,
|
|
624
665
|
id: number,
|
|
625
|
-
): boolean[] {
|
|
666
|
+
): (boolean | null)[] {
|
|
626
667
|
return this.readSetIntegersById(collection, attribute, id).map((value) =>
|
|
627
668
|
integerToBoolean(value, collection, attribute),
|
|
628
669
|
);
|
|
@@ -632,7 +673,7 @@ Database.prototype.readSetFloatsById = function (
|
|
|
632
673
|
collection: string,
|
|
633
674
|
attribute: string,
|
|
634
675
|
id: number,
|
|
635
|
-
): number[] {
|
|
676
|
+
): (number | null)[] {
|
|
636
677
|
return readByIdFloats(
|
|
637
678
|
getSymbols(),
|
|
638
679
|
this._handle,
|
|
@@ -647,7 +688,7 @@ Database.prototype.readSetStringsById = function (
|
|
|
647
688
|
collection: string,
|
|
648
689
|
attribute: string,
|
|
649
690
|
id: number,
|
|
650
|
-
): string[] {
|
|
691
|
+
): (string | null)[] {
|
|
651
692
|
return readByIdStrings(
|
|
652
693
|
getSymbols(),
|
|
653
694
|
this._handle,
|