flatsql 0.4.2 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +116 -6
- package/dist/artifacts/builder.d.ts +31 -0
- package/dist/artifacts/builder.d.ts.map +1 -0
- package/dist/artifacts/builder.js +514 -0
- package/dist/artifacts/builder.js.map +1 -0
- package/dist/artifacts/demo-extractors.d.ts +15 -0
- package/dist/artifacts/demo-extractors.d.ts.map +1 -0
- package/dist/artifacts/demo-extractors.js +238 -0
- package/dist/artifacts/demo-extractors.js.map +1 -0
- package/dist/artifacts/index.d.ts +5 -0
- package/dist/artifacts/index.d.ts.map +1 -0
- package/dist/artifacts/index.js +5 -0
- package/dist/artifacts/index.js.map +1 -0
- package/dist/artifacts/standalone-builder.d.ts +62 -0
- package/dist/artifacts/standalone-builder.d.ts.map +1 -0
- package/dist/artifacts/standalone-builder.js +144 -0
- package/dist/artifacts/standalone-builder.js.map +1 -0
- package/dist/artifacts/transport.d.ts +5 -0
- package/dist/artifacts/transport.d.ts.map +1 -0
- package/dist/artifacts/transport.js +45 -0
- package/dist/artifacts/transport.js.map +1 -0
- package/dist/artifacts/types.d.ts +34 -0
- package/dist/artifacts/types.d.ts.map +1 -0
- package/dist/artifacts/types.js +2 -0
- package/dist/artifacts/types.js.map +1 -0
- package/dist/artifacts/worker-client.d.ts +32 -0
- package/dist/artifacts/worker-client.d.ts.map +1 -0
- package/dist/artifacts/worker-client.js +415 -0
- package/dist/artifacts/worker-client.js.map +1 -0
- package/dist/btree/btree.d.ts.map +1 -1
- package/dist/btree/btree.js +13 -14
- package/dist/btree/btree.js.map +1 -1
- package/dist/core/database.d.ts +2 -0
- package/dist/core/database.d.ts.map +1 -1
- package/dist/core/database.js +18 -0
- package/dist/core/database.js.map +1 -1
- package/dist/core/table-store.d.ts +1 -0
- package/dist/core/table-store.d.ts.map +1 -1
- package/dist/core/table-store.js +31 -0
- package/dist/core/table-store.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/response/artifact.d.ts +5 -0
- package/dist/response/artifact.d.ts.map +1 -0
- package/dist/response/artifact.js +102 -0
- package/dist/response/artifact.js.map +1 -0
- package/dist/response/cache-key.d.ts +6 -0
- package/dist/response/cache-key.d.ts.map +1 -0
- package/dist/response/cache-key.js +114 -0
- package/dist/response/cache-key.js.map +1 -0
- package/dist/response/index.d.ts +5 -0
- package/dist/response/index.d.ts.map +1 -0
- package/dist/response/index.js +5 -0
- package/dist/response/index.js.map +1 -0
- package/dist/response/memory-cache.d.ts +17 -0
- package/dist/response/memory-cache.d.ts.map +1 -0
- package/dist/response/memory-cache.js +76 -0
- package/dist/response/memory-cache.js.map +1 -0
- package/dist/response/types.d.ts +51 -0
- package/dist/response/types.d.ts.map +1 -0
- package/dist/response/types.js +2 -0
- package/dist/response/types.js.map +1 -0
- package/dist/standalone/index.d.ts +3 -0
- package/dist/standalone/index.d.ts.map +1 -0
- package/dist/standalone/index.js +3 -0
- package/dist/standalone/index.js.map +1 -0
- package/dist/standalone/process-client.d.ts +85 -0
- package/dist/standalone/process-client.d.ts.map +1 -0
- package/dist/standalone/process-client.js +537 -0
- package/dist/standalone/process-client.js.map +1 -0
- package/dist/standalone/wasmedge-runner.d.ts +19 -0
- package/dist/standalone/wasmedge-runner.d.ts.map +1 -0
- package/dist/standalone/wasmedge-runner.js +108 -0
- package/dist/standalone/wasmedge-runner.js.map +1 -0
- package/dist/stress/aggregate.d.ts +3 -0
- package/dist/stress/aggregate.d.ts.map +1 -0
- package/dist/stress/aggregate.js +61 -0
- package/dist/stress/aggregate.js.map +1 -0
- package/dist/stress/docker-compose.d.ts +17 -0
- package/dist/stress/docker-compose.d.ts.map +1 -0
- package/dist/stress/docker-compose.js +156 -0
- package/dist/stress/docker-compose.js.map +1 -0
- package/dist/stress/index.d.ts +11 -0
- package/dist/stress/index.d.ts.map +1 -0
- package/dist/stress/index.js +11 -0
- package/dist/stress/index.js.map +1 -0
- package/dist/stress/metrics.d.ts +3 -0
- package/dist/stress/metrics.d.ts.map +1 -0
- package/dist/stress/metrics.js +83 -0
- package/dist/stress/metrics.js.map +1 -0
- package/dist/stress/native-publish-event-workload.d.ts +3 -0
- package/dist/stress/native-publish-event-workload.d.ts.map +1 -0
- package/dist/stress/native-publish-event-workload.js +455 -0
- package/dist/stress/native-publish-event-workload.js.map +1 -0
- package/dist/stress/production-gate.d.ts +4 -0
- package/dist/stress/production-gate.d.ts.map +1 -0
- package/dist/stress/production-gate.js +12 -0
- package/dist/stress/production-gate.js.map +1 -0
- package/dist/stress/publish-event-workload.d.ts +3 -0
- package/dist/stress/publish-event-workload.d.ts.map +1 -0
- package/dist/stress/publish-event-workload.js +467 -0
- package/dist/stress/publish-event-workload.js.map +1 -0
- package/dist/stress/report.d.ts +3 -0
- package/dist/stress/report.d.ts.map +1 -0
- package/dist/stress/report.js +174 -0
- package/dist/stress/report.js.map +1 -0
- package/dist/stress/sds-discovery.d.ts +4 -0
- package/dist/stress/sds-discovery.d.ts.map +1 -0
- package/dist/stress/sds-discovery.js +40 -0
- package/dist/stress/sds-discovery.js.map +1 -0
- package/dist/stress/smoke-runner.d.ts +3 -0
- package/dist/stress/smoke-runner.d.ts.map +1 -0
- package/dist/stress/smoke-runner.js +63 -0
- package/dist/stress/smoke-runner.js.map +1 -0
- package/dist/stress/types.d.ts +219 -0
- package/dist/stress/types.d.ts.map +1 -0
- package/dist/stress/types.js +2 -0
- package/dist/stress/types.js.map +1 -0
- package/dist/stress/workload.d.ts +6 -0
- package/dist/stress/workload.d.ts.map +1 -0
- package/dist/stress/workload.js +144 -0
- package/dist/stress/workload.js.map +1 -0
- package/docs/agents/response-artifacts.md +65 -0
- package/docs/response-artifacts.md +86 -0
- package/package.json +37 -7
- package/scripts/stress-docker.sh +279 -0
- package/sdm/flatsql-spatial.wasm +0 -0
- package/stress/docker/Dockerfile +11 -0
- package/stress/docker/docker-compose.yml +51 -0
- package/stress/sds/aggregate.mjs +97 -0
- package/stress/sds/run.mjs +105 -0
- package/stress/sds/write-compose.mjs +96 -0
- package/wasm/flatsql-artifact.worker.js +847 -0
- package/wasm/flatsql-wasi.wasm +0 -0
- package/wasm/flatsql.js +2 -16
- package/wasm/flatsql.wasm +0 -0
- package/wasm/index.d.ts +127 -2
- package/wasm/index.js +459 -61
- package/wasm/native/flatsql_wasmedge_runner.cpp +858 -0
- package/wasm/standalone.d.ts +91 -0
- package/wasm/standalone.js +740 -0
package/wasm/index.js
CHANGED
|
@@ -5,34 +5,72 @@ import FlatSQLModule from './flatsql.js';
|
|
|
5
5
|
|
|
6
6
|
let Module = null;
|
|
7
7
|
let api = null;
|
|
8
|
+
const textEncoder = new TextEncoder();
|
|
9
|
+
|
|
10
|
+
const PARAM_NULL = 0;
|
|
11
|
+
const PARAM_BOOL = 1;
|
|
12
|
+
const PARAM_INT64 = 2;
|
|
13
|
+
const PARAM_FLOAT64 = 3;
|
|
14
|
+
const PARAM_STRING = 4;
|
|
15
|
+
const PARAM_BYTES = 5;
|
|
8
16
|
|
|
9
17
|
// Security: Track if integrity was verified
|
|
10
18
|
let integrityVerified = false;
|
|
11
19
|
|
|
20
|
+
function toBase64(bytes) {
|
|
21
|
+
if (typeof Buffer !== 'undefined') {
|
|
22
|
+
return Buffer.from(bytes).toString('base64');
|
|
23
|
+
}
|
|
24
|
+
let binary = '';
|
|
25
|
+
for (let offset = 0; offset < bytes.length; offset += 0x8000) {
|
|
26
|
+
binary += String.fromCharCode(...bytes.subarray(offset, offset + 0x8000));
|
|
27
|
+
}
|
|
28
|
+
return btoa(binary);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function normalizeHashResult(value) {
|
|
32
|
+
if (typeof value === 'string') {
|
|
33
|
+
return value;
|
|
34
|
+
}
|
|
35
|
+
if (value instanceof Uint8Array) {
|
|
36
|
+
return toBase64(value);
|
|
37
|
+
}
|
|
38
|
+
if (ArrayBuffer.isView(value)) {
|
|
39
|
+
return toBase64(new Uint8Array(value.buffer, value.byteOffset, value.byteLength));
|
|
40
|
+
}
|
|
41
|
+
if (value instanceof ArrayBuffer) {
|
|
42
|
+
return toBase64(new Uint8Array(value));
|
|
43
|
+
}
|
|
44
|
+
throw new Error('SHA-384 provider must return a base64 string or binary digest');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function hasNodeProcess() {
|
|
48
|
+
return typeof process !== 'undefined' &&
|
|
49
|
+
process.versions !== undefined &&
|
|
50
|
+
typeof process.versions.node === 'string';
|
|
51
|
+
}
|
|
52
|
+
|
|
12
53
|
/**
|
|
13
|
-
* Compute SHA-384 hash of data and return as base64
|
|
14
|
-
*
|
|
54
|
+
* Compute SHA-384 hash of data and return as base64.
|
|
55
|
+
* Browser WebCrypto is intentionally not used; browser callers that require
|
|
56
|
+
* integrity verification must pass computeSHA384 backed by WASM/native crypto.
|
|
15
57
|
* @param {ArrayBuffer} data
|
|
58
|
+
* @param {(data: ArrayBuffer) => Promise<string|Uint8Array|ArrayBuffer>|string|Uint8Array|ArrayBuffer} [provider]
|
|
16
59
|
* @returns {Promise<string>}
|
|
17
60
|
*/
|
|
18
|
-
async function computeSHA384(data) {
|
|
19
|
-
if (typeof
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
if (typeof btoa !== 'undefined') {
|
|
25
|
-
return btoa(String.fromCharCode(...hashArray));
|
|
26
|
-
} else {
|
|
27
|
-
return Buffer.from(hashArray).toString('base64');
|
|
28
|
-
}
|
|
29
|
-
} else {
|
|
30
|
-
// Node.js fallback using dynamic import
|
|
31
|
-
const cryptoModule = await import('crypto');
|
|
61
|
+
async function computeSHA384(data, provider) {
|
|
62
|
+
if (typeof provider === 'function') {
|
|
63
|
+
return normalizeHashResult(await provider(data));
|
|
64
|
+
}
|
|
65
|
+
if (hasNodeProcess()) {
|
|
66
|
+
const cryptoModule = await import('node:crypto');
|
|
32
67
|
const hash = cryptoModule.createHash('sha384');
|
|
33
68
|
hash.update(Buffer.from(data));
|
|
34
69
|
return hash.digest('base64');
|
|
35
70
|
}
|
|
71
|
+
throw new Error(
|
|
72
|
+
'WASM integrity verification requires a computeSHA384 option backed by WASM/native crypto; browser WebCrypto is intentionally not used.'
|
|
73
|
+
);
|
|
36
74
|
}
|
|
37
75
|
|
|
38
76
|
/**
|
|
@@ -41,8 +79,8 @@ async function computeSHA384(data) {
|
|
|
41
79
|
* @param {string} expectedHash - Expected SHA-384 hash (base64)
|
|
42
80
|
* @returns {Promise<boolean>}
|
|
43
81
|
*/
|
|
44
|
-
async function verifyWASMIntegrity(wasmBinary, expectedHash) {
|
|
45
|
-
const computedHash = await computeSHA384(wasmBinary);
|
|
82
|
+
async function verifyWASMIntegrity(wasmBinary, expectedHash, options = {}) {
|
|
83
|
+
const computedHash = await computeSHA384(wasmBinary, options.computeSHA384);
|
|
46
84
|
return computedHash === expectedHash;
|
|
47
85
|
}
|
|
48
86
|
|
|
@@ -177,7 +215,7 @@ export async function initFlatSQL(moduleFactoryOrOptions) {
|
|
|
177
215
|
}
|
|
178
216
|
|
|
179
217
|
// Verify integrity
|
|
180
|
-
const isValid = await verifyWASMIntegrity(wasmBinary, expectedIntegrity);
|
|
218
|
+
const isValid = await verifyWASMIntegrity(wasmBinary, expectedIntegrity, options);
|
|
181
219
|
if (!isValid) {
|
|
182
220
|
throw new Error(
|
|
183
221
|
'WASM integrity check failed: hash mismatch. ' +
|
|
@@ -223,6 +261,22 @@ export async function initFlatSQL(moduleFactoryOrOptions) {
|
|
|
223
261
|
|
|
224
262
|
// Query execution
|
|
225
263
|
query: Module.cwrap('flatsql_query', 'number', ['number', 'string']),
|
|
264
|
+
queryParams: Module.cwrap('flatsql_query_params', 'number', ['number', 'string', 'number', 'number', 'number']),
|
|
265
|
+
queryMany: Module.cwrap('flatsql_query_many', 'number', ['number', 'number', 'number', 'number']),
|
|
266
|
+
buildQueryCacheKey: Module.cwrap('flatsql_build_query_cache_key', 'string', ['string', 'string', 'string', 'number', 'number', 'number']),
|
|
267
|
+
buildResponseArtifactCacheKey: Module.cwrap('flatsql_build_response_artifact_cache_key', 'string', ['string', 'string', 'string', 'string', 'string', 'string', 'number', 'number', 'number']),
|
|
268
|
+
registerQueryTemplate: Module.cwrap('flatsql_register_query_template', 'number', ['number', 'string', 'string', 'number']),
|
|
269
|
+
queryTemplate: Module.cwrap('flatsql_query_template', 'number', ['number', 'string', 'number', 'number', 'number']),
|
|
270
|
+
clearQueryCache: Module.cwrap('flatsql_clear_query_cache', null, ['number']),
|
|
271
|
+
configureQueryCache: Module.cwrap('flatsql_configure_query_cache', 'number', ['number', 'number', 'number']),
|
|
272
|
+
queryCacheHits: Module.cwrap('flatsql_query_cache_hits', 'number', ['number']),
|
|
273
|
+
queryCacheMisses: Module.cwrap('flatsql_query_cache_misses', 'number', ['number']),
|
|
274
|
+
queryCacheSize: Module.cwrap('flatsql_query_cache_size', 'number', ['number']),
|
|
275
|
+
queryCacheGeneration: Module.cwrap('flatsql_query_cache_generation', 'number', ['number']),
|
|
276
|
+
queryCacheMaxEntries: Module.cwrap('flatsql_query_cache_max_entries', 'number', ['number']),
|
|
277
|
+
queryCacheMaxRows: Module.cwrap('flatsql_query_cache_max_rows', 'number', ['number']),
|
|
278
|
+
batchResultCount: Module.cwrap('flatsql_batch_result_count', 'number', []),
|
|
279
|
+
selectBatchResult: Module.cwrap('flatsql_select_batch_result', 'number', ['number']),
|
|
226
280
|
getError: Module.cwrap('flatsql_get_error', 'string', []),
|
|
227
281
|
|
|
228
282
|
// Result access
|
|
@@ -234,17 +288,25 @@ export async function initFlatSQL(moduleFactoryOrOptions) {
|
|
|
234
288
|
resultCellString: Module.cwrap('flatsql_result_cell_string', 'string', ['number', 'number']),
|
|
235
289
|
resultCellBlob: Module.cwrap('flatsql_result_cell_blob', 'number', ['number', 'number']),
|
|
236
290
|
resultCellBlobSize: Module.cwrap('flatsql_result_cell_blob_size', 'number', ['number', 'number']),
|
|
291
|
+
queryRawFlatBufferStream: Module.cwrap('flatsql_query_raw_flatbuffer_stream', 'number', ['number', 'string', 'number', 'number', 'number']),
|
|
292
|
+
responseArtifactData: Module.cwrap('flatsql_response_artifact_data', 'number', []),
|
|
293
|
+
responseArtifactSize: Module.cwrap('flatsql_response_artifact_size', 'number', []),
|
|
294
|
+
responseArtifactRowCount: Module.cwrap('flatsql_response_artifact_row_count', 'number', []),
|
|
295
|
+
responseArtifactColumnCount: Module.cwrap('flatsql_response_artifact_column_count', 'number', []),
|
|
237
296
|
|
|
238
297
|
// Export/Import
|
|
239
298
|
exportData: Module.cwrap('flatsql_export_data', 'number', ['number']),
|
|
240
299
|
exportSize: Module.cwrap('flatsql_export_size', 'number', []),
|
|
241
300
|
loadAndRebuild: Module.cwrap('flatsql_load_and_rebuild', null, ['number', 'number', 'number']),
|
|
301
|
+
reserveStorage: Module.cwrap('flatsql_reserve_storage', null, ['number', 'number']),
|
|
302
|
+
loadFromDb: Module.cwrap('flatsql_load_from_db', null, ['number', 'number']),
|
|
242
303
|
|
|
243
304
|
// Test helpers
|
|
244
305
|
createTestUser: Module.cwrap('flatsql_create_test_user', 'number', ['number', 'string', 'string', 'number']),
|
|
245
306
|
createTestPost: Module.cwrap('flatsql_create_test_post', 'number', ['number', 'number', 'string']),
|
|
246
307
|
createTestMPE: Module.cwrap('flatsql_create_test_mpe', 'number', ['string', 'number', 'number', 'number', 'number', 'number', 'number', 'number', 'number', 'number']),
|
|
247
308
|
createTestTelemetry: Module.cwrap('flatsql_create_test_telemetry', 'number', ['number', 'string', 'string', 'string', 'number', 'number', 'number']),
|
|
309
|
+
createTestPublishEvent: Module.cwrap('flatsql_create_test_publish_event', 'number', ['string', 'string', 'number', 'number']),
|
|
248
310
|
testBufferSize: Module.cwrap('flatsql_test_buffer_size', 'number', []),
|
|
249
311
|
|
|
250
312
|
// Stats
|
|
@@ -264,6 +326,15 @@ export async function initFlatSQL(moduleFactoryOrOptions) {
|
|
|
264
326
|
getDeletedCount: Module.cwrap('flatsql_get_deleted_count', 'number', ['number', 'string']),
|
|
265
327
|
clearTombstones: Module.cwrap('flatsql_clear_tombstones', null, ['number', 'string']),
|
|
266
328
|
|
|
329
|
+
// Raw FlatBuffer access
|
|
330
|
+
getFlatBufferById: Module.cwrap('flatsql_get_flatbuffer_by_id', 'number', ['number', 'string', 'number']),
|
|
331
|
+
getFlatBufferByEmail: Module.cwrap('flatsql_get_flatbuffer_by_email', 'number', ['number', 'string', 'string']),
|
|
332
|
+
getFlatBufferByIndex: Module.cwrap('flatsql_get_flatbuffer_by_index', 'number', ['number', 'string', 'string', 'number', 'number', 'number']),
|
|
333
|
+
getRawFlatBufferSize: Module.cwrap('flatsql_get_raw_flatbuffer_size', 'number', []),
|
|
334
|
+
getRawFlatBufferSequence: Module.cwrap('flatsql_get_raw_flatbuffer_sequence', 'number', []),
|
|
335
|
+
getStorageBuffer: Module.cwrap('flatsql_get_storage_buffer', 'number', ['number']),
|
|
336
|
+
getStorageSize: Module.cwrap('flatsql_get_storage_size', 'number', ['number']),
|
|
337
|
+
|
|
267
338
|
// Encryption
|
|
268
339
|
setEncryptionKey: Module.cwrap('flatsql_set_encryption_key', 'number', ['number', 'number', 'number']),
|
|
269
340
|
isEncrypted: Module.cwrap('flatsql_is_encrypted', 'number', ['number']),
|
|
@@ -298,6 +369,134 @@ function withHeapBytes(data, callback) {
|
|
|
298
369
|
}
|
|
299
370
|
}
|
|
300
371
|
|
|
372
|
+
function encodeQueryParams(params) {
|
|
373
|
+
const parts = [];
|
|
374
|
+
let total = 0;
|
|
375
|
+
|
|
376
|
+
for (const value of params) {
|
|
377
|
+
let tag;
|
|
378
|
+
let payload;
|
|
379
|
+
|
|
380
|
+
if (value === null) {
|
|
381
|
+
tag = PARAM_NULL;
|
|
382
|
+
payload = new Uint8Array(0);
|
|
383
|
+
} else if (typeof value === 'boolean') {
|
|
384
|
+
tag = PARAM_BOOL;
|
|
385
|
+
payload = Uint8Array.of(value ? 1 : 0);
|
|
386
|
+
} else if (typeof value === 'number' && Number.isInteger(value)) {
|
|
387
|
+
if (!Number.isSafeInteger(value)) {
|
|
388
|
+
throw new TypeError('Integer query parameters must be safe integers');
|
|
389
|
+
}
|
|
390
|
+
tag = PARAM_INT64;
|
|
391
|
+
payload = new Uint8Array(8);
|
|
392
|
+
new DataView(payload.buffer, payload.byteOffset, payload.byteLength).setBigInt64(0, BigInt(value), true);
|
|
393
|
+
} else if (typeof value === 'number') {
|
|
394
|
+
tag = PARAM_FLOAT64;
|
|
395
|
+
payload = new Uint8Array(8);
|
|
396
|
+
new DataView(payload.buffer, payload.byteOffset, payload.byteLength).setFloat64(0, value, true);
|
|
397
|
+
} else if (typeof value === 'string') {
|
|
398
|
+
tag = PARAM_STRING;
|
|
399
|
+
payload = textEncoder.encode(value);
|
|
400
|
+
} else if (value instanceof Uint8Array) {
|
|
401
|
+
tag = PARAM_BYTES;
|
|
402
|
+
payload = value;
|
|
403
|
+
} else {
|
|
404
|
+
throw new TypeError(`Unsupported query parameter type: ${typeof value}`);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
const header = new Uint8Array(5);
|
|
408
|
+
const view = new DataView(header.buffer);
|
|
409
|
+
view.setUint8(0, tag);
|
|
410
|
+
view.setUint32(1, payload.length, true);
|
|
411
|
+
|
|
412
|
+
parts.push(header, payload);
|
|
413
|
+
total += header.length + payload.length;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
const encoded = new Uint8Array(total);
|
|
417
|
+
let offset = 0;
|
|
418
|
+
for (const part of parts) {
|
|
419
|
+
encoded.set(part, offset);
|
|
420
|
+
offset += part.length;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
return encoded;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
function encodeQueryRequests(queries) {
|
|
427
|
+
const parts = [];
|
|
428
|
+
let total = 0;
|
|
429
|
+
|
|
430
|
+
for (const query of queries) {
|
|
431
|
+
const sqlBytes = textEncoder.encode(query.sql);
|
|
432
|
+
const paramList = query.params ?? [];
|
|
433
|
+
const paramBytes = encodeQueryParams(paramList);
|
|
434
|
+
const header = new Uint8Array(12);
|
|
435
|
+
const view = new DataView(header.buffer);
|
|
436
|
+
view.setUint32(0, sqlBytes.length, true);
|
|
437
|
+
view.setUint32(4, paramList.length, true);
|
|
438
|
+
view.setUint32(8, paramBytes.length, true);
|
|
439
|
+
|
|
440
|
+
parts.push(header, sqlBytes, paramBytes);
|
|
441
|
+
total += header.length + sqlBytes.length + paramBytes.length;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
const encoded = new Uint8Array(total);
|
|
445
|
+
let offset = 0;
|
|
446
|
+
for (const part of parts) {
|
|
447
|
+
encoded.set(part, offset);
|
|
448
|
+
offset += part.length;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
return encoded;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
function readCellValue(row, col) {
|
|
455
|
+
const type = api.resultCellType(row, col);
|
|
456
|
+
switch (type) {
|
|
457
|
+
case 0:
|
|
458
|
+
return null;
|
|
459
|
+
case 1:
|
|
460
|
+
return api.resultCellNumber(row, col) !== 0;
|
|
461
|
+
case 2:
|
|
462
|
+
case 3:
|
|
463
|
+
case 4:
|
|
464
|
+
return api.resultCellNumber(row, col);
|
|
465
|
+
case 5:
|
|
466
|
+
return api.resultCellString(row, col);
|
|
467
|
+
case 6: {
|
|
468
|
+
const blobPtr = api.resultCellBlob(row, col);
|
|
469
|
+
const blobSize = api.resultCellBlobSize(row, col);
|
|
470
|
+
return blobPtr && blobSize > 0
|
|
471
|
+
? Array.from(new Uint8Array(Module.HEAPU8.buffer, blobPtr, blobSize))
|
|
472
|
+
: [];
|
|
473
|
+
}
|
|
474
|
+
default:
|
|
475
|
+
return null;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
function readQueryResult() {
|
|
480
|
+
const colCount = api.resultColumnCount();
|
|
481
|
+
const rowCount = api.resultRowCount();
|
|
482
|
+
|
|
483
|
+
const columns = [];
|
|
484
|
+
for (let i = 0; i < colCount; i++) {
|
|
485
|
+
columns.push(api.resultColumnName(i));
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
const rows = [];
|
|
489
|
+
for (let r = 0; r < rowCount; r++) {
|
|
490
|
+
const row = [];
|
|
491
|
+
for (let c = 0; c < colCount; c++) {
|
|
492
|
+
row.push(readCellValue(r, c));
|
|
493
|
+
}
|
|
494
|
+
rows.push(row);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
return { columns, rows };
|
|
498
|
+
}
|
|
499
|
+
|
|
301
500
|
function buildSizePrefixedStream(buffers) {
|
|
302
501
|
let total = 0;
|
|
303
502
|
for (const buffer of buffers) {
|
|
@@ -335,6 +534,12 @@ export class FlatSQL {
|
|
|
335
534
|
return new Uint8Array(Module.HEAPU8.buffer, ptr, size).slice();
|
|
336
535
|
}
|
|
337
536
|
|
|
537
|
+
createTestPublishEvent(fileId, recordId, eventIndex, payloadSize) {
|
|
538
|
+
const ptr = api.createTestPublishEvent(fileId, recordId, eventIndex, payloadSize);
|
|
539
|
+
const size = api.testBufferSize();
|
|
540
|
+
return new Uint8Array(Module.HEAPU8.buffer, ptr, size).slice();
|
|
541
|
+
}
|
|
542
|
+
|
|
338
543
|
createTestMPE(entityId, epoch, meanMotion, eccentricity, inclination,
|
|
339
544
|
raOfAscNode, argOfPericenter, meanAnomaly, bstar, meanElementTheory = 0) {
|
|
340
545
|
const ptr = api.createTestMPE(
|
|
@@ -366,6 +571,58 @@ export class FlatSQL {
|
|
|
366
571
|
wasIntegrityVerified() {
|
|
367
572
|
return integrityVerified;
|
|
368
573
|
}
|
|
574
|
+
|
|
575
|
+
buildQueryCacheKey(dataset, artifactVersion, queryId, params = []) {
|
|
576
|
+
const encodedParams = encodeQueryParams(params);
|
|
577
|
+
const key = encodedParams.length === 0
|
|
578
|
+
? api.buildQueryCacheKey(dataset, artifactVersion, queryId, 0, 0, 0)
|
|
579
|
+
: withHeapBytes(
|
|
580
|
+
encodedParams,
|
|
581
|
+
(ptr) => api.buildQueryCacheKey(dataset, artifactVersion, queryId, ptr, encodedParams.length, params.length)
|
|
582
|
+
);
|
|
583
|
+
if (!key) {
|
|
584
|
+
throw new Error(api.getError());
|
|
585
|
+
}
|
|
586
|
+
return key;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
buildResponseArtifactCacheKey(schemaName, schemaVersion, sql, options = {}) {
|
|
590
|
+
const format = options.format ?? 'json';
|
|
591
|
+
const publishEventKey = options.publishEventKey ?? '';
|
|
592
|
+
const projectionList = (options.projection ?? []).join('\n');
|
|
593
|
+
const params = options.params ?? [];
|
|
594
|
+
const encodedParams = encodeQueryParams(params);
|
|
595
|
+
const key = encodedParams.length === 0
|
|
596
|
+
? api.buildResponseArtifactCacheKey(
|
|
597
|
+
schemaName,
|
|
598
|
+
schemaVersion,
|
|
599
|
+
sql,
|
|
600
|
+
format,
|
|
601
|
+
publishEventKey,
|
|
602
|
+
projectionList,
|
|
603
|
+
0,
|
|
604
|
+
0,
|
|
605
|
+
0
|
|
606
|
+
)
|
|
607
|
+
: withHeapBytes(
|
|
608
|
+
encodedParams,
|
|
609
|
+
(ptr) => api.buildResponseArtifactCacheKey(
|
|
610
|
+
schemaName,
|
|
611
|
+
schemaVersion,
|
|
612
|
+
sql,
|
|
613
|
+
format,
|
|
614
|
+
publishEventKey,
|
|
615
|
+
projectionList,
|
|
616
|
+
ptr,
|
|
617
|
+
encodedParams.length,
|
|
618
|
+
params.length
|
|
619
|
+
)
|
|
620
|
+
);
|
|
621
|
+
if (!key) {
|
|
622
|
+
throw new Error(api.getError());
|
|
623
|
+
}
|
|
624
|
+
return key;
|
|
625
|
+
}
|
|
369
626
|
}
|
|
370
627
|
|
|
371
628
|
// Database wrapper class
|
|
@@ -435,58 +692,114 @@ export class FlatSQLDatabase {
|
|
|
435
692
|
return sources;
|
|
436
693
|
}
|
|
437
694
|
|
|
438
|
-
query(sql) {
|
|
439
|
-
const success =
|
|
695
|
+
query(sql, params = undefined) {
|
|
696
|
+
const success = params === undefined
|
|
697
|
+
? api.query(this._handle, sql)
|
|
698
|
+
: (() => {
|
|
699
|
+
const encodedParams = encodeQueryParams(params);
|
|
700
|
+
if (encodedParams.length === 0) {
|
|
701
|
+
return api.queryParams(this._handle, sql, 0, 0, 0);
|
|
702
|
+
}
|
|
703
|
+
return withHeapBytes(
|
|
704
|
+
encodedParams,
|
|
705
|
+
(ptr) => api.queryParams(this._handle, sql, ptr, encodedParams.length, params.length)
|
|
706
|
+
);
|
|
707
|
+
})();
|
|
440
708
|
if (!success) {
|
|
441
709
|
throw new Error(api.getError());
|
|
442
710
|
}
|
|
711
|
+
return readQueryResult();
|
|
712
|
+
}
|
|
443
713
|
|
|
444
|
-
|
|
445
|
-
const
|
|
446
|
-
|
|
714
|
+
registerQueryTemplate(queryId, sql, cacheable = true) {
|
|
715
|
+
const success = api.registerQueryTemplate(this._handle, queryId, sql, cacheable ? 1 : 0);
|
|
716
|
+
if (!success) {
|
|
717
|
+
throw new Error(api.getError());
|
|
718
|
+
}
|
|
719
|
+
}
|
|
447
720
|
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
721
|
+
queryTemplate(queryId, params = []) {
|
|
722
|
+
const encodedParams = encodeQueryParams(params);
|
|
723
|
+
const success = encodedParams.length === 0
|
|
724
|
+
? api.queryTemplate(this._handle, queryId, 0, 0, 0)
|
|
725
|
+
: withHeapBytes(
|
|
726
|
+
encodedParams,
|
|
727
|
+
(ptr) => api.queryTemplate(this._handle, queryId, ptr, encodedParams.length, params.length)
|
|
728
|
+
);
|
|
729
|
+
if (!success) {
|
|
730
|
+
throw new Error(api.getError());
|
|
451
731
|
}
|
|
732
|
+
return readQueryResult();
|
|
733
|
+
}
|
|
452
734
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
735
|
+
clearQueryCache() {
|
|
736
|
+
api.clearQueryCache(this._handle);
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
configureQueryCache({ maxEntries, maxRows }) {
|
|
740
|
+
if (!Number.isSafeInteger(maxEntries) || maxEntries <= 0) {
|
|
741
|
+
throw new TypeError(`maxEntries must be a positive safe integer, received: ${maxEntries}`);
|
|
742
|
+
}
|
|
743
|
+
if (!Number.isSafeInteger(maxRows) || maxRows <= 0) {
|
|
744
|
+
throw new TypeError(`maxRows must be a positive safe integer, received: ${maxRows}`);
|
|
745
|
+
}
|
|
746
|
+
const success = api.configureQueryCache(this._handle, maxEntries, maxRows);
|
|
747
|
+
if (!success) {
|
|
748
|
+
throw new Error(api.getError());
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
getQueryCacheStats() {
|
|
753
|
+
return {
|
|
754
|
+
hits: api.queryCacheHits(this._handle),
|
|
755
|
+
misses: api.queryCacheMisses(this._handle),
|
|
756
|
+
size: api.queryCacheSize(this._handle),
|
|
757
|
+
generation: api.queryCacheGeneration(this._handle),
|
|
758
|
+
maxEntries: api.queryCacheMaxEntries(this._handle),
|
|
759
|
+
maxRows: api.queryCacheMaxRows(this._handle)
|
|
760
|
+
};
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
queryMany(queries) {
|
|
764
|
+
if (queries.length === 0) {
|
|
765
|
+
return [];
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
const encodedRequests = encodeQueryRequests(queries);
|
|
769
|
+
const success = withHeapBytes(
|
|
770
|
+
encodedRequests,
|
|
771
|
+
(ptr) => api.queryMany(this._handle, ptr, encodedRequests.length, queries.length)
|
|
772
|
+
);
|
|
773
|
+
if (!success) {
|
|
774
|
+
throw new Error(api.getError());
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
const resultCount = api.batchResultCount();
|
|
778
|
+
const results = [];
|
|
779
|
+
for (let index = 0; index < resultCount; index++) {
|
|
780
|
+
if (!api.selectBatchResult(index)) {
|
|
781
|
+
throw new Error(`Failed to select batch result ${index}`);
|
|
485
782
|
}
|
|
486
|
-
|
|
783
|
+
results.push(readQueryResult());
|
|
784
|
+
}
|
|
785
|
+
return results;
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
queryRawFlatBufferStream(sql, params = []) {
|
|
789
|
+
const encodedParams = encodeQueryParams(params);
|
|
790
|
+
const success = encodedParams.length === 0
|
|
791
|
+
? api.queryRawFlatBufferStream(this._handle, sql, 0, 0, 0)
|
|
792
|
+
: withHeapBytes(
|
|
793
|
+
encodedParams,
|
|
794
|
+
(ptr) => api.queryRawFlatBufferStream(this._handle, sql, ptr, encodedParams.length, params.length)
|
|
795
|
+
);
|
|
796
|
+
if (!success) {
|
|
797
|
+
throw new Error(api.getError());
|
|
487
798
|
}
|
|
488
799
|
|
|
489
|
-
|
|
800
|
+
const ptr = api.responseArtifactData();
|
|
801
|
+
const size = api.responseArtifactSize();
|
|
802
|
+
return ptr && size > 0 ? new Uint8Array(Module.HEAPU8.buffer, ptr, size).slice() : new Uint8Array();
|
|
490
803
|
}
|
|
491
804
|
|
|
492
805
|
exportData() {
|
|
@@ -502,6 +815,17 @@ export class FlatSQLDatabase {
|
|
|
502
815
|
Module._free(ptr);
|
|
503
816
|
}
|
|
504
817
|
|
|
818
|
+
reserveStorageBytes(bytes) {
|
|
819
|
+
api.reserveStorage(this._handle, bytes);
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
loadAndRebuildFrom(sourceDb) {
|
|
823
|
+
if (!sourceDb?._handle) {
|
|
824
|
+
throw new TypeError('loadAndRebuildFrom requires a FlatSQL WASM database.');
|
|
825
|
+
}
|
|
826
|
+
api.loadFromDb(this._handle, sourceDb._handle);
|
|
827
|
+
}
|
|
828
|
+
|
|
505
829
|
getStats() {
|
|
506
830
|
const count = api.getStatsCount(this._handle);
|
|
507
831
|
const stats = [];
|
|
@@ -541,6 +865,80 @@ export class FlatSQLDatabase {
|
|
|
541
865
|
api.clearTombstones(this._handle, tableName);
|
|
542
866
|
}
|
|
543
867
|
|
|
868
|
+
getFlatBufferById(tableName, id) {
|
|
869
|
+
const ptr = api.getFlatBufferById(this._handle, tableName, id);
|
|
870
|
+
if (!ptr) {
|
|
871
|
+
return null;
|
|
872
|
+
}
|
|
873
|
+
return {
|
|
874
|
+
ptr,
|
|
875
|
+
size: api.getRawFlatBufferSize(),
|
|
876
|
+
sequence: api.getRawFlatBufferSequence()
|
|
877
|
+
};
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
getFlatBufferByEmail(tableName, email) {
|
|
881
|
+
const ptr = api.getFlatBufferByEmail(this._handle, tableName, email);
|
|
882
|
+
if (!ptr) {
|
|
883
|
+
return null;
|
|
884
|
+
}
|
|
885
|
+
return {
|
|
886
|
+
ptr,
|
|
887
|
+
size: api.getRawFlatBufferSize(),
|
|
888
|
+
sequence: api.getRawFlatBufferSequence()
|
|
889
|
+
};
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
getFlatBufferByIndex(tableName, columnName, value) {
|
|
893
|
+
const encodedParams = encodeQueryParams([value]);
|
|
894
|
+
const ptr = withHeapBytes(
|
|
895
|
+
encodedParams,
|
|
896
|
+
(paramPtr) => api.getFlatBufferByIndex(
|
|
897
|
+
this._handle,
|
|
898
|
+
tableName,
|
|
899
|
+
columnName,
|
|
900
|
+
paramPtr,
|
|
901
|
+
encodedParams.length,
|
|
902
|
+
1
|
|
903
|
+
)
|
|
904
|
+
);
|
|
905
|
+
if (!ptr) {
|
|
906
|
+
const error = api.getError();
|
|
907
|
+
if (error) {
|
|
908
|
+
throw new Error(error);
|
|
909
|
+
}
|
|
910
|
+
return null;
|
|
911
|
+
}
|
|
912
|
+
return {
|
|
913
|
+
ptr,
|
|
914
|
+
size: api.getRawFlatBufferSize(),
|
|
915
|
+
sequence: api.getRawFlatBufferSequence()
|
|
916
|
+
};
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
getFlatBufferDataById(tableName, id) {
|
|
920
|
+
const record = this.getFlatBufferById(tableName, id);
|
|
921
|
+
if (!record) {
|
|
922
|
+
return null;
|
|
923
|
+
}
|
|
924
|
+
return new Uint8Array(Module.HEAPU8.buffer, record.ptr, record.size).slice();
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
getFlatBufferDataByIndex(tableName, columnName, value) {
|
|
928
|
+
const record = this.getFlatBufferByIndex(tableName, columnName, value);
|
|
929
|
+
if (!record) {
|
|
930
|
+
return null;
|
|
931
|
+
}
|
|
932
|
+
return new Uint8Array(Module.HEAPU8.buffer, record.ptr, record.size).slice();
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
getStorageInfo() {
|
|
936
|
+
return {
|
|
937
|
+
ptr: api.getStorageBuffer(this._handle),
|
|
938
|
+
size: api.getStorageSize(this._handle)
|
|
939
|
+
};
|
|
940
|
+
}
|
|
941
|
+
|
|
544
942
|
// ==================== Encryption API ====================
|
|
545
943
|
|
|
546
944
|
/**
|