quiverdb 0.6.1 → 0.9.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.
Files changed (88) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +95 -17
  3. package/libs/linux-x86_64/libquiver.so +0 -0
  4. package/libs/linux-x86_64/libquiver.so.0 +0 -0
  5. package/libs/linux-x86_64/libquiver_c.so +0 -0
  6. package/libs/windows-x86_64/libquiver.dll +0 -0
  7. package/libs/windows-x86_64/libquiver_c.dll +0 -0
  8. package/mod.ts +25 -0
  9. package/package.json +17 -30
  10. package/src/composites.ts +89 -0
  11. package/src/create.ts +152 -0
  12. package/src/csv.ts +118 -0
  13. package/src/database.ts +171 -0
  14. package/src/errors.ts +21 -0
  15. package/src/ffi-helpers.ts +157 -0
  16. package/src/index.ts +17 -0
  17. package/src/introspection.ts +33 -0
  18. package/src/loader.ts +285 -0
  19. package/src/lua-runner.ts +48 -0
  20. package/src/metadata.ts +218 -0
  21. package/src/query.ts +160 -0
  22. package/src/read.ts +572 -0
  23. package/src/time-series.ts +291 -0
  24. package/src/transaction.ts +27 -0
  25. package/{dist/types.d.ts → src/types.ts} +8 -1
  26. package/dist/composites.d.ts +0 -9
  27. package/dist/composites.d.ts.map +0 -1
  28. package/dist/composites.js +0 -69
  29. package/dist/composites.js.map +0 -1
  30. package/dist/create.d.ts +0 -9
  31. package/dist/create.d.ts.map +0 -1
  32. package/dist/create.js +0 -104
  33. package/dist/create.js.map +0 -1
  34. package/dist/csv.d.ts +0 -11
  35. package/dist/csv.d.ts.map +0 -1
  36. package/dist/csv.js +0 -67
  37. package/dist/csv.js.map +0 -1
  38. package/dist/database.d.ts +0 -13
  39. package/dist/database.d.ts.map +0 -1
  40. package/dist/database.js +0 -42
  41. package/dist/database.js.map +0 -1
  42. package/dist/errors.d.ts +0 -5
  43. package/dist/errors.d.ts.map +0 -1
  44. package/dist/errors.js +0 -18
  45. package/dist/errors.js.map +0 -1
  46. package/dist/ffi-helpers.d.ts +0 -57
  47. package/dist/ffi-helpers.d.ts.map +0 -1
  48. package/dist/ffi-helpers.js +0 -136
  49. package/dist/ffi-helpers.js.map +0 -1
  50. package/dist/index.d.ts +0 -17
  51. package/dist/index.d.ts.map +0 -1
  52. package/dist/index.js +0 -13
  53. package/dist/index.js.map +0 -1
  54. package/dist/introspection.d.ts +0 -10
  55. package/dist/introspection.d.ts.map +0 -1
  56. package/dist/introspection.js +0 -27
  57. package/dist/introspection.js.map +0 -1
  58. package/dist/loader.d.ts +0 -7
  59. package/dist/loader.d.ts.map +0 -1
  60. package/dist/loader.js +0 -165
  61. package/dist/loader.js.map +0 -1
  62. package/dist/lua-runner.d.ts +0 -11
  63. package/dist/lua-runner.d.ts.map +0 -1
  64. package/dist/lua-runner.js +0 -43
  65. package/dist/lua-runner.js.map +0 -1
  66. package/dist/metadata.d.ts +0 -28
  67. package/dist/metadata.d.ts.map +0 -1
  68. package/dist/metadata.js +0 -100
  69. package/dist/metadata.js.map +0 -1
  70. package/dist/query.d.ts +0 -9
  71. package/dist/query.d.ts.map +0 -1
  72. package/dist/query.js +0 -90
  73. package/dist/query.js.map +0 -1
  74. package/dist/read.d.ts +0 -25
  75. package/dist/read.d.ts.map +0 -1
  76. package/dist/read.js +0 -220
  77. package/dist/read.js.map +0 -1
  78. package/dist/time-series.d.ts +0 -12
  79. package/dist/time-series.d.ts.map +0 -1
  80. package/dist/time-series.js +0 -155
  81. package/dist/time-series.js.map +0 -1
  82. package/dist/transaction.d.ts +0 -10
  83. package/dist/transaction.d.ts.map +0 -1
  84. package/dist/transaction.js +0 -22
  85. package/dist/transaction.js.map +0 -1
  86. package/dist/types.d.ts.map +0 -1
  87. package/dist/types.js +0 -2
  88. package/dist/types.js.map +0 -1
@@ -0,0 +1,48 @@
1
+ import type { Database } from "./database.ts";
2
+ import { check, QuiverError } from "./errors.ts";
3
+ import { allocPtrOut, decodeStringFromBuf, readPtrOut, toCString } from "./ffi-helpers.ts";
4
+ import type { NativePointer } from "./loader.ts";
5
+ import { getSymbols } from "./loader.ts";
6
+
7
+ export class LuaRunner {
8
+ private _ptr: NativePointer;
9
+ private _db: Database;
10
+ private _closed = false;
11
+
12
+ constructor(db: Database) {
13
+ this._db = db;
14
+ const lib = getSymbols();
15
+ const outRunner = allocPtrOut();
16
+ check(lib.quiver_lua_runner_new(db._handle, outRunner.ptr));
17
+ this._ptr = readPtrOut(outRunner);
18
+ }
19
+
20
+ run(script: string): void {
21
+ this.ensureOpen();
22
+ const lib = getSymbols();
23
+ const scriptBuf = toCString(script);
24
+ const err = lib.quiver_lua_runner_run(this._ptr, scriptBuf.buf);
25
+ if (err !== 0) {
26
+ const outError = allocPtrOut();
27
+ const getErr = lib.quiver_lua_runner_get_error(this._ptr, outError.ptr);
28
+ if (getErr === 0 && readPtrOut(outError)) {
29
+ const msg = decodeStringFromBuf(outError);
30
+ if (msg) throw new QuiverError(msg);
31
+ }
32
+ check(err);
33
+ }
34
+ }
35
+
36
+ close(): void {
37
+ if (this._closed) return;
38
+ const lib = getSymbols();
39
+ check(lib.quiver_lua_runner_free(this._ptr));
40
+ this._closed = true;
41
+ }
42
+
43
+ private ensureOpen(): void {
44
+ if (this._closed) {
45
+ throw new QuiverError("LuaRunner is closed");
46
+ }
47
+ }
48
+ }
@@ -0,0 +1,218 @@
1
+ import { CString, type Pointer, ptr, read } from "bun:ffi";
2
+ import { Database } from "./database.ts";
3
+ import { check } from "./errors.ts";
4
+ import {
5
+ allocPtrOut,
6
+ allocUint64Out,
7
+ readPtrOut,
8
+ readUint64Out,
9
+ toCString,
10
+ } from "./ffi-helpers.ts";
11
+ import { getSymbols, type NativePointer } from "./loader.ts";
12
+
13
+ export interface ScalarMetadata {
14
+ name: string;
15
+ dataType: number;
16
+ notNull: boolean;
17
+ primaryKey: boolean;
18
+ defaultValue: string | null;
19
+ isForeignKey: boolean;
20
+ referencesCollection: string | null;
21
+ referencesColumn: string | null;
22
+ }
23
+
24
+ export interface GroupMetadata {
25
+ groupName: string;
26
+ dimensionColumn: string | null;
27
+ valueColumns: ScalarMetadata[];
28
+ }
29
+
30
+ const SCALAR_METADATA_SIZE = 56;
31
+ const GROUP_METADATA_SIZE = 32;
32
+
33
+ function readNullableString(base: Pointer, offset: number): string | null {
34
+ const p = read.ptr(base, offset);
35
+ if (p === 0) return null;
36
+ return new CString(p as Pointer).toString();
37
+ }
38
+
39
+ function readScalarMetadataAt(base: Pointer, byteOffset: number): ScalarMetadata {
40
+ const namePtr = read.ptr(base, byteOffset + 0);
41
+ return {
42
+ name: namePtr === 0 ? "" : new CString(namePtr as Pointer).toString(),
43
+ dataType: read.i32(base, byteOffset + 8),
44
+ notNull: read.i32(base, byteOffset + 12) !== 0,
45
+ primaryKey: read.i32(base, byteOffset + 16) !== 0,
46
+ defaultValue: readNullableString(base, byteOffset + 24),
47
+ isForeignKey: read.i32(base, byteOffset + 32) !== 0,
48
+ referencesCollection: readNullableString(base, byteOffset + 40),
49
+ referencesColumn: readNullableString(base, byteOffset + 48),
50
+ };
51
+ }
52
+
53
+ function readGroupMetadataAt(base: Pointer, byteOffset: number): GroupMetadata {
54
+ const groupNamePtr = read.ptr(base, byteOffset + 0);
55
+ const dimColPtr = read.ptr(base, byteOffset + 8);
56
+ const valueColumnsPtr = read.ptr(base, byteOffset + 16);
57
+ const valueColumnCount = Number(read.u64(base, byteOffset + 24));
58
+
59
+ const valueColumns: ScalarMetadata[] = new Array(valueColumnCount);
60
+ if (valueColumnsPtr !== 0 && valueColumnCount > 0) {
61
+ for (let i = 0; i < valueColumnCount; i++) {
62
+ valueColumns[i] = readScalarMetadataAt(valueColumnsPtr as Pointer, i * SCALAR_METADATA_SIZE);
63
+ }
64
+ }
65
+
66
+ return {
67
+ groupName: groupNamePtr === 0 ? "" : new CString(groupNamePtr as Pointer).toString(),
68
+ dimensionColumn: dimColPtr === 0 ? null : new CString(dimColPtr as Pointer).toString(),
69
+ valueColumns,
70
+ };
71
+ }
72
+
73
+ Database.prototype.getScalarMetadata = function (
74
+ this: Database,
75
+ collection: string,
76
+ attribute: string,
77
+ ): ScalarMetadata {
78
+ const lib = getSymbols();
79
+ const collBuf = toCString(collection);
80
+ const attrBuf = toCString(attribute);
81
+ const outBuf = new Uint8Array(SCALAR_METADATA_SIZE);
82
+ const outPtr = ptr(outBuf);
83
+ check(lib.quiver_database_get_scalar_metadata(this._handle, collBuf.buf, attrBuf.buf, outPtr));
84
+ const result = readScalarMetadataAt(outPtr, 0);
85
+ lib.quiver_database_free_scalar_metadata(outPtr);
86
+ return result;
87
+ };
88
+
89
+ Database.prototype.getVectorMetadata = function (
90
+ this: Database,
91
+ collection: string,
92
+ groupName: string,
93
+ ): GroupMetadata {
94
+ const lib = getSymbols();
95
+ const collBuf = toCString(collection);
96
+ const groupBuf = toCString(groupName);
97
+ const outBuf = new Uint8Array(GROUP_METADATA_SIZE);
98
+ const outPtr = ptr(outBuf);
99
+ check(lib.quiver_database_get_vector_metadata(this._handle, collBuf.buf, groupBuf.buf, outPtr));
100
+ const result = readGroupMetadataAt(outPtr, 0);
101
+ lib.quiver_database_free_group_metadata(outPtr);
102
+ return result;
103
+ };
104
+
105
+ Database.prototype.getSetMetadata = function (
106
+ this: Database,
107
+ collection: string,
108
+ groupName: string,
109
+ ): GroupMetadata {
110
+ const lib = getSymbols();
111
+ const collBuf = toCString(collection);
112
+ const groupBuf = toCString(groupName);
113
+ const outBuf = new Uint8Array(GROUP_METADATA_SIZE);
114
+ const outPtr = ptr(outBuf);
115
+ check(lib.quiver_database_get_set_metadata(this._handle, collBuf.buf, groupBuf.buf, outPtr));
116
+ const result = readGroupMetadataAt(outPtr, 0);
117
+ lib.quiver_database_free_group_metadata(outPtr);
118
+ return result;
119
+ };
120
+
121
+ Database.prototype.getTimeSeriesMetadata = function (
122
+ this: Database,
123
+ collection: string,
124
+ groupName: string,
125
+ ): GroupMetadata {
126
+ const lib = getSymbols();
127
+ const collBuf = toCString(collection);
128
+ const groupBuf = toCString(groupName);
129
+ const outBuf = new Uint8Array(GROUP_METADATA_SIZE);
130
+ const outPtr = ptr(outBuf);
131
+ check(
132
+ lib.quiver_database_get_time_series_metadata(this._handle, collBuf.buf, groupBuf.buf, outPtr),
133
+ );
134
+ const result = readGroupMetadataAt(outPtr, 0);
135
+ lib.quiver_database_free_group_metadata(outPtr);
136
+ return result;
137
+ };
138
+
139
+ function listMetadata<T>(
140
+ lib: ReturnType<typeof getSymbols>,
141
+ handle: NativePointer,
142
+ fn: string,
143
+ collection: string,
144
+ structSize: number,
145
+ reader: (base: Pointer, offset: number) => T,
146
+ freeFn: string,
147
+ ): T[] {
148
+ const collBuf = toCString(collection);
149
+ const outArray = allocPtrOut();
150
+ const outCount = allocUint64Out();
151
+ check((lib as Record<string, Function>)[fn](handle, collBuf.buf, outArray.ptr, outCount.ptr));
152
+ const count = readUint64Out(outCount);
153
+ if (count === 0) return [];
154
+ const arrPtr = readPtrOut(outArray);
155
+ const result: T[] = new Array(count);
156
+ for (let i = 0; i < count; i++) {
157
+ result[i] = reader(arrPtr as Pointer, i * structSize);
158
+ }
159
+ (lib as Record<string, Function>)[freeFn](arrPtr, BigInt(count));
160
+ return result;
161
+ }
162
+
163
+ Database.prototype.listScalarAttributes = function (
164
+ this: Database,
165
+ collection: string,
166
+ ): ScalarMetadata[] {
167
+ return listMetadata(
168
+ getSymbols(),
169
+ this._handle,
170
+ "quiver_database_list_scalar_attributes",
171
+ collection,
172
+ SCALAR_METADATA_SIZE,
173
+ readScalarMetadataAt,
174
+ "quiver_database_free_scalar_metadata_array",
175
+ );
176
+ };
177
+
178
+ Database.prototype.listVectorGroups = function (
179
+ this: Database,
180
+ collection: string,
181
+ ): GroupMetadata[] {
182
+ return listMetadata(
183
+ getSymbols(),
184
+ this._handle,
185
+ "quiver_database_list_vector_groups",
186
+ collection,
187
+ GROUP_METADATA_SIZE,
188
+ readGroupMetadataAt,
189
+ "quiver_database_free_group_metadata_array",
190
+ );
191
+ };
192
+
193
+ Database.prototype.listSetGroups = function (this: Database, collection: string): GroupMetadata[] {
194
+ return listMetadata(
195
+ getSymbols(),
196
+ this._handle,
197
+ "quiver_database_list_set_groups",
198
+ collection,
199
+ GROUP_METADATA_SIZE,
200
+ readGroupMetadataAt,
201
+ "quiver_database_free_group_metadata_array",
202
+ );
203
+ };
204
+
205
+ Database.prototype.listTimeSeriesGroups = function (
206
+ this: Database,
207
+ collection: string,
208
+ ): GroupMetadata[] {
209
+ return listMetadata(
210
+ getSymbols(),
211
+ this._handle,
212
+ "quiver_database_list_time_series_groups",
213
+ collection,
214
+ GROUP_METADATA_SIZE,
215
+ readGroupMetadataAt,
216
+ "quiver_database_free_group_metadata_array",
217
+ );
218
+ };
package/src/query.ts ADDED
@@ -0,0 +1,160 @@
1
+ import { ptr } from "bun:ffi";
2
+ import { Database } from "./database.ts";
3
+ import { check, QuiverError } from "./errors.ts";
4
+ import {
5
+ allocNativeFloat64,
6
+ allocNativeInt64,
7
+ allocNativeString,
8
+ allocPtrOut,
9
+ decodeStringFromBuf,
10
+ nativeAddress,
11
+ readPtrOut,
12
+ toCString,
13
+ } from "./ffi-helpers.ts";
14
+ import { getSymbols } from "./loader.ts";
15
+ import type { Allocation, QueryParam } from "./types.ts";
16
+
17
+ const DATA_TYPE_INTEGER = 0;
18
+ const DATA_TYPE_FLOAT = 1;
19
+ const DATA_TYPE_STRING = 2;
20
+ const DATA_TYPE_NULL = 4;
21
+
22
+ function marshalParams(parameters: QueryParam[]): {
23
+ types: Allocation;
24
+ values: Allocation;
25
+ _keepalive: Allocation[];
26
+ } {
27
+ const n = parameters.length;
28
+ const typesBuf = new Uint8Array(n * 4);
29
+ const typesDv = new DataView(typesBuf.buffer);
30
+ const valuesBuf = new Uint8Array(n * 8);
31
+ const valuesDv = new DataView(valuesBuf.buffer);
32
+ const keepalive: Allocation[] = [];
33
+
34
+ for (let i = 0; i < n; i++) {
35
+ const p = parameters[i];
36
+ if (p === null) {
37
+ typesDv.setInt32(i * 4, DATA_TYPE_NULL, true);
38
+ valuesDv.setBigInt64(i * 8, 0n, true);
39
+ } else if (typeof p === "number") {
40
+ if (Number.isInteger(p)) {
41
+ typesDv.setInt32(i * 4, DATA_TYPE_INTEGER, true);
42
+ const native = allocNativeInt64([p]);
43
+ keepalive.push(native);
44
+ valuesDv.setBigInt64(i * 8, nativeAddress(native.ptr), true);
45
+ } else {
46
+ typesDv.setInt32(i * 4, DATA_TYPE_FLOAT, true);
47
+ const native = allocNativeFloat64([p]);
48
+ keepalive.push(native);
49
+ valuesDv.setBigInt64(i * 8, nativeAddress(native.ptr), true);
50
+ }
51
+ } else if (typeof p === "string") {
52
+ typesDv.setInt32(i * 4, DATA_TYPE_STRING, true);
53
+ const native = allocNativeString(p);
54
+ keepalive.push(native);
55
+ valuesDv.setBigInt64(i * 8, nativeAddress(native.ptr), true);
56
+ } else {
57
+ throw new QuiverError(`Unsupported query parameter type at index ${i}: ${typeof p}`);
58
+ }
59
+ }
60
+
61
+ const types: Allocation = { ptr: ptr(typesBuf), buf: typesBuf };
62
+ const values: Allocation = { ptr: ptr(valuesBuf), buf: valuesBuf };
63
+ keepalive.push(types, values);
64
+ return { types, values, _keepalive: keepalive };
65
+ }
66
+
67
+ Database.prototype.queryString = function (
68
+ this: Database,
69
+ sql: string,
70
+ parameters?: QueryParam[],
71
+ ): string | null {
72
+ const lib = getSymbols();
73
+ const sqlBuf = toCString(sql);
74
+ const outValue = allocPtrOut();
75
+ const outHasValue = new Uint8Array(4);
76
+
77
+ if (parameters && parameters.length > 0) {
78
+ const m = marshalParams(parameters);
79
+ check(
80
+ lib.quiver_database_query_string_params(
81
+ this._handle,
82
+ sqlBuf.buf,
83
+ m.types.buf,
84
+ m.values.buf,
85
+ BigInt(parameters.length),
86
+ outValue.buf,
87
+ outHasValue,
88
+ ),
89
+ );
90
+ } else {
91
+ check(lib.quiver_database_query_string(this._handle, sqlBuf.buf, outValue.buf, outHasValue));
92
+ }
93
+
94
+ if (new DataView(outHasValue.buffer).getInt32(0, true) === 0) return null;
95
+ const result = decodeStringFromBuf(outValue);
96
+ lib.quiver_database_free_string(readPtrOut(outValue));
97
+ return result;
98
+ };
99
+
100
+ Database.prototype.queryInteger = function (
101
+ this: Database,
102
+ sql: string,
103
+ parameters?: QueryParam[],
104
+ ): number | null {
105
+ const lib = getSymbols();
106
+ const sqlBuf = toCString(sql);
107
+ const outValue = new Uint8Array(8);
108
+ const outHasValue = new Uint8Array(4);
109
+
110
+ if (parameters && parameters.length > 0) {
111
+ const m = marshalParams(parameters);
112
+ check(
113
+ lib.quiver_database_query_integer_params(
114
+ this._handle,
115
+ sqlBuf.buf,
116
+ m.types.buf,
117
+ m.values.buf,
118
+ BigInt(parameters.length),
119
+ outValue,
120
+ outHasValue,
121
+ ),
122
+ );
123
+ } else {
124
+ check(lib.quiver_database_query_integer(this._handle, sqlBuf.buf, outValue, outHasValue));
125
+ }
126
+
127
+ if (new DataView(outHasValue.buffer).getInt32(0, true) === 0) return null;
128
+ return Number(new DataView(outValue.buffer).getBigInt64(0, true));
129
+ };
130
+
131
+ Database.prototype.queryFloat = function (
132
+ this: Database,
133
+ sql: string,
134
+ parameters?: QueryParam[],
135
+ ): number | null {
136
+ const lib = getSymbols();
137
+ const sqlBuf = toCString(sql);
138
+ const outValue = new Uint8Array(8);
139
+ const outHasValue = new Uint8Array(4);
140
+
141
+ if (parameters && parameters.length > 0) {
142
+ const m = marshalParams(parameters);
143
+ check(
144
+ lib.quiver_database_query_float_params(
145
+ this._handle,
146
+ sqlBuf.buf,
147
+ m.types.buf,
148
+ m.values.buf,
149
+ BigInt(parameters.length),
150
+ outValue,
151
+ outHasValue,
152
+ ),
153
+ );
154
+ } else {
155
+ check(lib.quiver_database_query_float(this._handle, sqlBuf.buf, outValue, outHasValue));
156
+ }
157
+
158
+ if (new DataView(outHasValue.buffer).getInt32(0, true) === 0) return null;
159
+ return new DataView(outValue.buffer).getFloat64(0, true);
160
+ };