quiverdb 0.9.10 → 0.9.12

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.
Binary file
Binary file
Binary file
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "quiverdb",
3
- "version": "0.9.10",
3
+ "version": "0.9.12",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
package/src/database.ts CHANGED
@@ -88,9 +88,9 @@ export class Database {
88
88
  declare deleteElement: (collection: string, id: number) => void;
89
89
 
90
90
  // --- Reads (implemented in read.ts) ---
91
- declare readScalarIntegers: (collection: string, attribute: string) => number[];
92
- declare readScalarFloats: (collection: string, attribute: string) => number[];
93
- declare readScalarStrings: (collection: string, attribute: string) => string[];
91
+ declare readScalarIntegers: (collection: string, attribute: string) => (number | null)[];
92
+ declare readScalarFloats: (collection: string, attribute: string) => (number | null)[];
93
+ declare readScalarStrings: (collection: string, attribute: string) => (string | null)[];
94
94
  declare readScalarIntegerById: (
95
95
  collection: string,
96
96
  attribute: string,
@@ -151,7 +151,7 @@ export class Database {
151
151
  id: number,
152
152
  data: TimeSeriesData,
153
153
  ) => void;
154
- declare addTimeSeriesRow: (
154
+ declare upsertTimeSeriesRow: (
155
155
  collection: string,
156
156
  group: string,
157
157
  id: number,
package/src/loader.ts CHANGED
@@ -62,8 +62,8 @@ const crudSymbols = {
62
62
  } as const;
63
63
 
64
64
  const readSymbols = {
65
- quiver_database_read_scalar_integers: { args: [P, BUF, BUF, P, P], returns: I32 },
66
- quiver_database_read_scalar_floats: { args: [P, BUF, BUF, P, P], returns: I32 },
65
+ quiver_database_read_scalar_integers: { args: [P, BUF, BUF, P, P, P], returns: I32 },
66
+ quiver_database_read_scalar_floats: { args: [P, BUF, BUF, P, P, P], returns: I32 },
67
67
  quiver_database_read_scalar_strings: { args: [P, BUF, BUF, P, P], returns: I32 },
68
68
  quiver_database_read_scalar_integer_by_id: { args: [P, BUF, BUF, I64, P, P], returns: I32 },
69
69
  quiver_database_read_scalar_float_by_id: { args: [P, BUF, BUF, I64, P, P], returns: I32 },
@@ -123,7 +123,10 @@ const timeSeriesSymbols = {
123
123
  returns: I32,
124
124
  },
125
125
  quiver_database_read_time_series_row: { args: [P, BUF, BUF, BUF, BUF, P, P, P], returns: I32 },
126
- quiver_database_add_time_series_row: { args: [P, BUF, BUF, I64, P, P, P, USIZE], returns: I32 },
126
+ quiver_database_upsert_time_series_row: {
127
+ args: [P, BUF, BUF, I64, P, P, P, USIZE],
128
+ returns: I32,
129
+ },
127
130
  quiver_database_update_time_series_group: {
128
131
  args: [P, BUF, BUF, I64, P, P, P, P, USIZE, USIZE],
129
132
  returns: I32,
@@ -144,6 +147,7 @@ const csvSymbols = {
144
147
  const freeSymbols = {
145
148
  quiver_database_free_integer_array: { args: [P], returns: I32 },
146
149
  quiver_database_free_float_array: { args: [P], returns: I32 },
150
+ quiver_database_free_mask: { args: [P], returns: I32 },
147
151
  quiver_database_free_string_array: { args: [P, USIZE], returns: I32 },
148
152
  quiver_database_free_string: { args: [P], returns: I32 },
149
153
  quiver_database_free_integer_vectors: { args: [P, P, USIZE], returns: I32 },
package/src/lua-api.ts CHANGED
@@ -166,7 +166,7 @@ Notes:
166
166
  \`{ x = nil }\` is identical to \`{}\`; an update/create table that ends up with no attributes
167
167
  **throws** (\`element must have at least one attribute\`). To leave a column unchanged, omit the
168
168
  key — you cannot set a scalar to NULL via the element table. (\`nil\` → NULL is only accepted by
169
- \`add_time_series_row\` and \`update_time_series_files\`.)
169
+ \`upsert_time_series_row\` and \`update_time_series_files\`.)
170
170
 
171
171
  ---
172
172
 
@@ -274,7 +274,7 @@ db:update_time_series_group("Items", "data", id, ts) -- write the whole group
274
274
  \`\`\`
275
275
 
276
276
  **DO NOT pass an array of row tables** (\`{ { date_time = ..., value = ... }, ... }\`) — that is the
277
- \`add_time_series_row\` shape, not this one. Doing so raises
277
+ \`upsert_time_series_row\` shape, not this one. Doing so raises
278
278
  \`stack index -1, expected string, received number\` (the integer array indices 1, 2, 3 are not
279
279
  column names). Each value of the top-level table must be an **array**, not a scalar.
280
280
 
@@ -293,13 +293,13 @@ column names). Each value of the top-level table must be an **array**, not a sca
293
293
  - Integer values are accepted for REAL columns (converted on insert). Booleans, functions, and
294
294
  other unsupported Lua types throw \`column '...' has unsupported Lua type\`.
295
295
 
296
- ### Append/upsert a single row (\`add_time_series_row\` — ROW-oriented, the one exception)
296
+ ### Append/upsert a single row (\`upsert_time_series_row\` — ROW-oriented, the one exception)
297
297
 
298
298
  Unlike the column-oriented group update above, this takes **one row table of scalars** (dimension
299
299
  column + value column(s)), and upserts that single row:
300
300
 
301
301
  \`\`\`lua
302
- db:add_time_series_row("Items", "data", id, {
302
+ db:upsert_time_series_row("Items", "data", id, {
303
303
  date_time = "2024-01-04T00:00:00",
304
304
  value = 40.0,
305
305
  })
package/src/read.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { CString, type Pointer, toArrayBuffer } from "bun:ffi";
1
2
  import { Database } from "./database.ts";
2
3
  import { check } from "./errors.ts";
3
4
  import {
@@ -21,11 +22,12 @@ Database.prototype.readScalarIntegers = function (
21
22
  this: Database,
22
23
  collection: string,
23
24
  attribute: string,
24
- ): number[] {
25
+ ): (number | null)[] {
25
26
  const lib = getSymbols();
26
27
  const collBuf = toCString(collection);
27
28
  const attrBuf = toCString(attribute);
28
29
  const outValues = allocPtrOut();
30
+ const outMask = allocPtrOut();
29
31
  const outCount = allocUint64Out();
30
32
  check(
31
33
  lib.quiver_database_read_scalar_integers(
@@ -33,14 +35,20 @@ Database.prototype.readScalarIntegers = function (
33
35
  collBuf.buf,
34
36
  attrBuf.buf,
35
37
  outValues.buf,
38
+ outMask.buf,
36
39
  outCount.buf,
37
40
  ),
38
41
  );
39
42
  const count = readUint64Out(outCount);
40
43
  if (count === 0) return [];
41
44
  const arrPtr = readPtrOut(outValues);
42
- const result = decodeInt64Array(arrPtr, count);
45
+ const maskPtr = readPtrOut(outMask);
46
+ const vals = decodeInt64Array(arrPtr, count);
47
+ // mask[i] === 0 means SQL NULL; gate to null (never Number(placeholder)).
48
+ const mask = new Uint8Array(toArrayBuffer(maskPtr as Pointer, 0, count));
49
+ const result = vals.map((v, i) => (mask[i] ? v : null));
43
50
  lib.quiver_database_free_integer_array(arrPtr);
51
+ lib.quiver_database_free_mask(maskPtr);
44
52
  return result;
45
53
  };
46
54
 
@@ -48,11 +56,12 @@ Database.prototype.readScalarFloats = function (
48
56
  this: Database,
49
57
  collection: string,
50
58
  attribute: string,
51
- ): number[] {
59
+ ): (number | null)[] {
52
60
  const lib = getSymbols();
53
61
  const collBuf = toCString(collection);
54
62
  const attrBuf = toCString(attribute);
55
63
  const outValues = allocPtrOut();
64
+ const outMask = allocPtrOut();
56
65
  const outCount = allocUint64Out();
57
66
  check(
58
67
  lib.quiver_database_read_scalar_floats(
@@ -60,14 +69,19 @@ Database.prototype.readScalarFloats = function (
60
69
  collBuf.buf,
61
70
  attrBuf.buf,
62
71
  outValues.buf,
72
+ outMask.buf,
63
73
  outCount.buf,
64
74
  ),
65
75
  );
66
76
  const count = readUint64Out(outCount);
67
77
  if (count === 0) return [];
68
78
  const arrPtr = readPtrOut(outValues);
69
- const result = decodeFloat64Array(arrPtr, count);
79
+ const maskPtr = readPtrOut(outMask);
80
+ const vals = decodeFloat64Array(arrPtr, count);
81
+ const mask = new Uint8Array(toArrayBuffer(maskPtr as Pointer, 0, count));
82
+ const result = vals.map((v, i) => (mask[i] ? v : null));
70
83
  lib.quiver_database_free_float_array(arrPtr);
84
+ lib.quiver_database_free_mask(maskPtr);
71
85
  return result;
72
86
  };
73
87
 
@@ -75,7 +89,7 @@ Database.prototype.readScalarStrings = function (
75
89
  this: Database,
76
90
  collection: string,
77
91
  attribute: string,
78
- ): string[] {
92
+ ): (string | null)[] {
79
93
  const lib = getSymbols();
80
94
  const collBuf = toCString(collection);
81
95
  const attrBuf = toCString(attribute);
@@ -93,7 +107,11 @@ Database.prototype.readScalarStrings = function (
93
107
  const count = readUint64Out(outCount);
94
108
  if (count === 0) return [];
95
109
  const arrPtr = readPtrOut(outValues);
96
- const result = decodeStringArray(arrPtr, count);
110
+ // A NULL string is a NULL char* entry: decode the (null-guarded) pointer array and map
111
+ // NULL -> null (decodeStringArray would construct "" from a NULL pointer instead).
112
+ const result = decodePtrArray(arrPtr, count).map((p) =>
113
+ p === null ? null : new CString(p).toString(),
114
+ );
97
115
  lib.quiver_database_free_string_array(arrPtr, BigInt(count));
98
116
  return result;
99
117
  };
@@ -318,7 +318,7 @@ Database.prototype.updateTimeSeriesGroup = function (
318
318
  );
319
319
  };
320
320
 
321
- Database.prototype.addTimeSeriesRow = function (
321
+ Database.prototype.upsertTimeSeriesRow = function (
322
322
  this: Database,
323
323
  collection: string,
324
324
  group: string,
@@ -366,7 +366,7 @@ Database.prototype.addTimeSeriesRow = function (
366
366
  keepalive.push(dataTable);
367
367
 
368
368
  check(
369
- lib.quiver_database_add_time_series_row(
369
+ lib.quiver_database_upsert_time_series_row(
370
370
  this._handle,
371
371
  collBuf.buf,
372
372
  grpBuf.buf,