flatsql 0.4.3 → 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.
Files changed (143) hide show
  1. package/README.md +116 -6
  2. package/dist/artifacts/builder.d.ts +31 -0
  3. package/dist/artifacts/builder.d.ts.map +1 -0
  4. package/dist/artifacts/builder.js +514 -0
  5. package/dist/artifacts/builder.js.map +1 -0
  6. package/dist/artifacts/demo-extractors.d.ts +15 -0
  7. package/dist/artifacts/demo-extractors.d.ts.map +1 -0
  8. package/dist/artifacts/demo-extractors.js +238 -0
  9. package/dist/artifacts/demo-extractors.js.map +1 -0
  10. package/dist/artifacts/index.d.ts +5 -0
  11. package/dist/artifacts/index.d.ts.map +1 -0
  12. package/dist/artifacts/index.js +5 -0
  13. package/dist/artifacts/index.js.map +1 -0
  14. package/dist/artifacts/standalone-builder.d.ts +62 -0
  15. package/dist/artifacts/standalone-builder.d.ts.map +1 -0
  16. package/dist/artifacts/standalone-builder.js +144 -0
  17. package/dist/artifacts/standalone-builder.js.map +1 -0
  18. package/dist/artifacts/transport.d.ts +5 -0
  19. package/dist/artifacts/transport.d.ts.map +1 -0
  20. package/dist/artifacts/transport.js +45 -0
  21. package/dist/artifacts/transport.js.map +1 -0
  22. package/dist/artifacts/types.d.ts +34 -0
  23. package/dist/artifacts/types.d.ts.map +1 -0
  24. package/dist/artifacts/types.js +2 -0
  25. package/dist/artifacts/types.js.map +1 -0
  26. package/dist/artifacts/worker-client.d.ts +32 -0
  27. package/dist/artifacts/worker-client.d.ts.map +1 -0
  28. package/dist/artifacts/worker-client.js +415 -0
  29. package/dist/artifacts/worker-client.js.map +1 -0
  30. package/dist/btree/btree.d.ts.map +1 -1
  31. package/dist/btree/btree.js +13 -14
  32. package/dist/btree/btree.js.map +1 -1
  33. package/dist/core/database.d.ts +2 -0
  34. package/dist/core/database.d.ts.map +1 -1
  35. package/dist/core/database.js +18 -0
  36. package/dist/core/database.js.map +1 -1
  37. package/dist/core/table-store.d.ts +1 -0
  38. package/dist/core/table-store.d.ts.map +1 -1
  39. package/dist/core/table-store.js +31 -0
  40. package/dist/core/table-store.js.map +1 -1
  41. package/dist/index.d.ts +3 -0
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +3 -0
  44. package/dist/index.js.map +1 -1
  45. package/dist/response/artifact.d.ts +5 -0
  46. package/dist/response/artifact.d.ts.map +1 -0
  47. package/dist/response/artifact.js +102 -0
  48. package/dist/response/artifact.js.map +1 -0
  49. package/dist/response/cache-key.d.ts +6 -0
  50. package/dist/response/cache-key.d.ts.map +1 -0
  51. package/dist/response/cache-key.js +114 -0
  52. package/dist/response/cache-key.js.map +1 -0
  53. package/dist/response/index.d.ts +5 -0
  54. package/dist/response/index.d.ts.map +1 -0
  55. package/dist/response/index.js +5 -0
  56. package/dist/response/index.js.map +1 -0
  57. package/dist/response/memory-cache.d.ts +17 -0
  58. package/dist/response/memory-cache.d.ts.map +1 -0
  59. package/dist/response/memory-cache.js +76 -0
  60. package/dist/response/memory-cache.js.map +1 -0
  61. package/dist/response/types.d.ts +51 -0
  62. package/dist/response/types.d.ts.map +1 -0
  63. package/dist/response/types.js +2 -0
  64. package/dist/response/types.js.map +1 -0
  65. package/dist/standalone/index.d.ts +3 -0
  66. package/dist/standalone/index.d.ts.map +1 -0
  67. package/dist/standalone/index.js +3 -0
  68. package/dist/standalone/index.js.map +1 -0
  69. package/dist/standalone/process-client.d.ts +85 -0
  70. package/dist/standalone/process-client.d.ts.map +1 -0
  71. package/dist/standalone/process-client.js +537 -0
  72. package/dist/standalone/process-client.js.map +1 -0
  73. package/dist/standalone/wasmedge-runner.d.ts +19 -0
  74. package/dist/standalone/wasmedge-runner.d.ts.map +1 -0
  75. package/dist/standalone/wasmedge-runner.js +108 -0
  76. package/dist/standalone/wasmedge-runner.js.map +1 -0
  77. package/dist/stress/aggregate.d.ts +3 -0
  78. package/dist/stress/aggregate.d.ts.map +1 -0
  79. package/dist/stress/aggregate.js +61 -0
  80. package/dist/stress/aggregate.js.map +1 -0
  81. package/dist/stress/docker-compose.d.ts +17 -0
  82. package/dist/stress/docker-compose.d.ts.map +1 -0
  83. package/dist/stress/docker-compose.js +156 -0
  84. package/dist/stress/docker-compose.js.map +1 -0
  85. package/dist/stress/index.d.ts +11 -0
  86. package/dist/stress/index.d.ts.map +1 -0
  87. package/dist/stress/index.js +11 -0
  88. package/dist/stress/index.js.map +1 -0
  89. package/dist/stress/metrics.d.ts +3 -0
  90. package/dist/stress/metrics.d.ts.map +1 -0
  91. package/dist/stress/metrics.js +83 -0
  92. package/dist/stress/metrics.js.map +1 -0
  93. package/dist/stress/native-publish-event-workload.d.ts +3 -0
  94. package/dist/stress/native-publish-event-workload.d.ts.map +1 -0
  95. package/dist/stress/native-publish-event-workload.js +455 -0
  96. package/dist/stress/native-publish-event-workload.js.map +1 -0
  97. package/dist/stress/production-gate.d.ts +4 -0
  98. package/dist/stress/production-gate.d.ts.map +1 -0
  99. package/dist/stress/production-gate.js +12 -0
  100. package/dist/stress/production-gate.js.map +1 -0
  101. package/dist/stress/publish-event-workload.d.ts +3 -0
  102. package/dist/stress/publish-event-workload.d.ts.map +1 -0
  103. package/dist/stress/publish-event-workload.js +467 -0
  104. package/dist/stress/publish-event-workload.js.map +1 -0
  105. package/dist/stress/report.d.ts +3 -0
  106. package/dist/stress/report.d.ts.map +1 -0
  107. package/dist/stress/report.js +174 -0
  108. package/dist/stress/report.js.map +1 -0
  109. package/dist/stress/sds-discovery.d.ts +4 -0
  110. package/dist/stress/sds-discovery.d.ts.map +1 -0
  111. package/dist/stress/sds-discovery.js +40 -0
  112. package/dist/stress/sds-discovery.js.map +1 -0
  113. package/dist/stress/smoke-runner.d.ts +3 -0
  114. package/dist/stress/smoke-runner.d.ts.map +1 -0
  115. package/dist/stress/smoke-runner.js +63 -0
  116. package/dist/stress/smoke-runner.js.map +1 -0
  117. package/dist/stress/types.d.ts +219 -0
  118. package/dist/stress/types.d.ts.map +1 -0
  119. package/dist/stress/types.js +2 -0
  120. package/dist/stress/types.js.map +1 -0
  121. package/dist/stress/workload.d.ts +6 -0
  122. package/dist/stress/workload.d.ts.map +1 -0
  123. package/dist/stress/workload.js +144 -0
  124. package/dist/stress/workload.js.map +1 -0
  125. package/docs/agents/response-artifacts.md +65 -0
  126. package/docs/response-artifacts.md +86 -0
  127. package/package.json +36 -6
  128. package/scripts/stress-docker.sh +279 -0
  129. package/sdm/flatsql-spatial.wasm +0 -0
  130. package/stress/docker/Dockerfile +11 -0
  131. package/stress/docker/docker-compose.yml +51 -0
  132. package/stress/sds/aggregate.mjs +97 -0
  133. package/stress/sds/run.mjs +105 -0
  134. package/stress/sds/write-compose.mjs +96 -0
  135. package/wasm/flatsql-artifact.worker.js +847 -0
  136. package/wasm/flatsql-wasi.wasm +0 -0
  137. package/wasm/flatsql.js +2 -16
  138. package/wasm/flatsql.wasm +0 -0
  139. package/wasm/index.d.ts +117 -2
  140. package/wasm/index.js +410 -42
  141. package/wasm/native/flatsql_wasmedge_runner.cpp +858 -0
  142. package/wasm/standalone.d.ts +91 -0
  143. package/wasm/standalone.js +740 -0
package/wasm/index.js CHANGED
@@ -5,6 +5,14 @@ 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;
@@ -253,6 +261,22 @@ export async function initFlatSQL(moduleFactoryOrOptions) {
253
261
 
254
262
  // Query execution
255
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']),
256
280
  getError: Module.cwrap('flatsql_get_error', 'string', []),
257
281
 
258
282
  // Result access
@@ -264,17 +288,25 @@ export async function initFlatSQL(moduleFactoryOrOptions) {
264
288
  resultCellString: Module.cwrap('flatsql_result_cell_string', 'string', ['number', 'number']),
265
289
  resultCellBlob: Module.cwrap('flatsql_result_cell_blob', 'number', ['number', 'number']),
266
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', []),
267
296
 
268
297
  // Export/Import
269
298
  exportData: Module.cwrap('flatsql_export_data', 'number', ['number']),
270
299
  exportSize: Module.cwrap('flatsql_export_size', 'number', []),
271
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']),
272
303
 
273
304
  // Test helpers
274
305
  createTestUser: Module.cwrap('flatsql_create_test_user', 'number', ['number', 'string', 'string', 'number']),
275
306
  createTestPost: Module.cwrap('flatsql_create_test_post', 'number', ['number', 'number', 'string']),
276
307
  createTestMPE: Module.cwrap('flatsql_create_test_mpe', 'number', ['string', 'number', 'number', 'number', 'number', 'number', 'number', 'number', 'number', 'number']),
277
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']),
278
310
  testBufferSize: Module.cwrap('flatsql_test_buffer_size', 'number', []),
279
311
 
280
312
  // Stats
@@ -294,6 +326,15 @@ export async function initFlatSQL(moduleFactoryOrOptions) {
294
326
  getDeletedCount: Module.cwrap('flatsql_get_deleted_count', 'number', ['number', 'string']),
295
327
  clearTombstones: Module.cwrap('flatsql_clear_tombstones', null, ['number', 'string']),
296
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
+
297
338
  // Encryption
298
339
  setEncryptionKey: Module.cwrap('flatsql_set_encryption_key', 'number', ['number', 'number', 'number']),
299
340
  isEncrypted: Module.cwrap('flatsql_is_encrypted', 'number', ['number']),
@@ -328,6 +369,134 @@ function withHeapBytes(data, callback) {
328
369
  }
329
370
  }
330
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
+
331
500
  function buildSizePrefixedStream(buffers) {
332
501
  let total = 0;
333
502
  for (const buffer of buffers) {
@@ -365,6 +534,12 @@ export class FlatSQL {
365
534
  return new Uint8Array(Module.HEAPU8.buffer, ptr, size).slice();
366
535
  }
367
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
+
368
543
  createTestMPE(entityId, epoch, meanMotion, eccentricity, inclination,
369
544
  raOfAscNode, argOfPericenter, meanAnomaly, bstar, meanElementTheory = 0) {
370
545
  const ptr = api.createTestMPE(
@@ -396,6 +571,58 @@ export class FlatSQL {
396
571
  wasIntegrityVerified() {
397
572
  return integrityVerified;
398
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
+ }
399
626
  }
400
627
 
401
628
  // Database wrapper class
@@ -465,58 +692,114 @@ export class FlatSQLDatabase {
465
692
  return sources;
466
693
  }
467
694
 
468
- query(sql) {
469
- const success = api.query(this._handle, sql);
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
+ })();
708
+ if (!success) {
709
+ throw new Error(api.getError());
710
+ }
711
+ return readQueryResult();
712
+ }
713
+
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
+ }
720
+
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
+ );
470
729
  if (!success) {
471
730
  throw new Error(api.getError());
472
731
  }
732
+ return readQueryResult();
733
+ }
473
734
 
474
- // Read results
475
- const colCount = api.resultColumnCount();
476
- const rowCount = api.resultRowCount();
735
+ clearQueryCache() {
736
+ api.clearQueryCache(this._handle);
737
+ }
477
738
 
478
- const columns = [];
479
- for (let i = 0; i < colCount; i++) {
480
- columns.push(api.resultColumnName(i));
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());
481
749
  }
750
+ }
482
751
 
483
- const rows = [];
484
- for (let r = 0; r < rowCount; r++) {
485
- const row = [];
486
- for (let c = 0; c < colCount; c++) {
487
- const type = api.resultCellType(r, c);
488
- switch (type) {
489
- case 0: // null
490
- row.push(null);
491
- break;
492
- case 1: // bool
493
- row.push(api.resultCellNumber(r, c) !== 0);
494
- break;
495
- case 2: // int32
496
- case 3: // int64
497
- case 4: // double
498
- row.push(api.resultCellNumber(r, c));
499
- break;
500
- case 5: // string
501
- row.push(api.resultCellString(r, c));
502
- break;
503
- case 6: // blob
504
- const blobPtr = api.resultCellBlob(r, c);
505
- const blobSize = api.resultCellBlobSize(r, c);
506
- if (blobPtr && blobSize > 0) {
507
- row.push(Array.from(new Uint8Array(Module.HEAPU8.buffer, blobPtr, blobSize)));
508
- } else {
509
- row.push([]);
510
- }
511
- break;
512
- default:
513
- row.push(null);
514
- }
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}`);
515
782
  }
516
- rows.push(row);
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());
517
798
  }
518
799
 
519
- return { columns, rows };
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();
520
803
  }
521
804
 
522
805
  exportData() {
@@ -532,6 +815,17 @@ export class FlatSQLDatabase {
532
815
  Module._free(ptr);
533
816
  }
534
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
+
535
829
  getStats() {
536
830
  const count = api.getStatsCount(this._handle);
537
831
  const stats = [];
@@ -571,6 +865,80 @@ export class FlatSQLDatabase {
571
865
  api.clearTombstones(this._handle, tableName);
572
866
  }
573
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
+
574
942
  // ==================== Encryption API ====================
575
943
 
576
944
  /**