@peerbit/indexer-sqlite3 1.1.3 → 1.1.4-5cf61cb

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 (46) hide show
  1. package/dist/peerbit/sqlite3-bundler-friendly.mjs +7 -7
  2. package/dist/peerbit/sqlite3-node.mjs +7 -7
  3. package/dist/peerbit/sqlite3.js +7 -7
  4. package/dist/peerbit/sqlite3.min.js +651 -163
  5. package/dist/peerbit/sqlite3.mjs +7 -7
  6. package/dist/peerbit/sqlite3.wasm +0 -0
  7. package/dist/peerbit/sqlite3.worker.min.js +19 -5
  8. package/dist/src/engine.d.ts +4 -1
  9. package/dist/src/engine.d.ts.map +1 -1
  10. package/dist/src/engine.js +125 -48
  11. package/dist/src/engine.js.map +1 -1
  12. package/dist/src/query-planner.d.ts +47 -0
  13. package/dist/src/query-planner.d.ts.map +1 -0
  14. package/dist/src/query-planner.js +290 -0
  15. package/dist/src/query-planner.js.map +1 -0
  16. package/dist/src/schema.d.ts +29 -7
  17. package/dist/src/schema.d.ts.map +1 -1
  18. package/dist/src/schema.js +354 -119
  19. package/dist/src/schema.js.map +1 -1
  20. package/dist/src/sqlite3-messages.worker.d.ts +4 -1
  21. package/dist/src/sqlite3-messages.worker.d.ts.map +1 -1
  22. package/dist/src/sqlite3-messages.worker.js.map +1 -1
  23. package/dist/src/sqlite3.browser.d.ts.map +1 -1
  24. package/dist/src/sqlite3.browser.js +7 -0
  25. package/dist/src/sqlite3.browser.js.map +1 -1
  26. package/dist/src/sqlite3.d.ts.map +1 -1
  27. package/dist/src/sqlite3.js +24 -14
  28. package/dist/src/sqlite3.js.map +1 -1
  29. package/dist/src/sqlite3.wasm.d.ts +1 -0
  30. package/dist/src/sqlite3.wasm.d.ts.map +1 -1
  31. package/dist/src/sqlite3.wasm.js +9 -1
  32. package/dist/src/sqlite3.wasm.js.map +1 -1
  33. package/dist/src/sqlite3.worker.js +7 -0
  34. package/dist/src/sqlite3.worker.js.map +1 -1
  35. package/dist/src/types.d.ts +1 -0
  36. package/dist/src/types.d.ts.map +1 -1
  37. package/package.json +78 -78
  38. package/src/engine.ts +143 -68
  39. package/src/query-planner.ts +334 -0
  40. package/src/schema.ts +498 -160
  41. package/src/sqlite3-messages.worker.ts +5 -0
  42. package/src/sqlite3.browser.ts +8 -0
  43. package/src/sqlite3.ts +24 -13
  44. package/src/sqlite3.wasm.ts +11 -1
  45. package/src/sqlite3.worker.ts +6 -1
  46. package/src/types.ts +1 -0
@@ -7234,6 +7234,7 @@ function hashBlocks(w, v2, p, pos, len) {
7234
7234
 
7235
7235
  // ../../crypto/dist/src/utils.js
7236
7236
  var import_libsodium_wrappers = __toESM(require_libsodium_wrappers(), 1);
7237
+ var fromHexString = (hexString) => import_libsodium_wrappers.default.from_hex(hexString);
7237
7238
  var toHexString = (bytes) => import_libsodium_wrappers.default.to_hex(bytes);
7238
7239
  var toBase64 = (arr) => {
7239
7240
  return import_libsodium_wrappers.default.to_base64(arr, import_libsodium_wrappers.default.base64_variants.ORIGINAL);
@@ -7243,6 +7244,7 @@ var toBase58 = (arr) => {
7243
7244
  };
7244
7245
 
7245
7246
  // ../../crypto/dist/src/hash.browser.js
7247
+ var sha256Base64Sync = (bytes) => toBase64(new SHA256().update(bytes).digest());
7246
7248
  var sha256Sync = (bytes) => new SHA256().update(bytes).digest();
7247
7249
 
7248
7250
  // ../../../../node_modules/uint8-varint/dist/src/index.js
@@ -7409,7 +7411,7 @@ var UnsignedIntegerValue = class UnsignedIntegerValue2 extends IntegerValue {
7409
7411
  constructor(number) {
7410
7412
  super();
7411
7413
  if (!Number.isInteger(number) || number > 4294967295 || number < 0) {
7412
- throw new Error("Number is not u32");
7414
+ throw new Error("Number is not u32: " + number);
7413
7415
  }
7414
7416
  this.number = number;
7415
7417
  }
@@ -7870,7 +7872,7 @@ var Nested = class Nested2 extends Query {
7870
7872
  query;
7871
7873
  constructor(props) {
7872
7874
  super();
7873
- this.path = props.path;
7875
+ this.path = Array.isArray(props.path) ? props.path : [props.path];
7874
7876
  this.id = props.id ?? v4_default();
7875
7877
  this.query = toQuery(props.query);
7876
7878
  }
@@ -7880,8 +7882,8 @@ __decorate2([
7880
7882
  __metadata2("design:type", String)
7881
7883
  ], Nested.prototype, "id", void 0);
7882
7884
  __decorate2([
7883
- field({ type: "string" }),
7884
- __metadata2("design:type", String)
7885
+ field({ type: vec("string") }),
7886
+ __metadata2("design:type", Array)
7885
7887
  ], Nested.prototype, "path", void 0);
7886
7888
  __decorate2([
7887
7889
  field({ type: vec(Query) }),
@@ -7952,6 +7954,35 @@ var getIdProperty = (clazz) => {
7952
7954
  return [property];
7953
7955
  };
7954
7956
 
7957
+ // ../interface/dist/src/errors.js
7958
+ var NotStartedError = class extends Error {
7959
+ constructor() {
7960
+ super("Not started");
7961
+ }
7962
+ };
7963
+
7964
+ // ../../time/dist/src/hrtime.browser.js
7965
+ var hrtime = (previousTimestamp) => {
7966
+ const baseNow = Math.floor((Date.now() - performance.now()) * 1e-3);
7967
+ const clocktime = performance.now() * 1e-3;
7968
+ let seconds = Math.floor(clocktime) + baseNow;
7969
+ let nanoseconds = Math.floor(clocktime % 1 * 1e9);
7970
+ if (previousTimestamp) {
7971
+ seconds = seconds - previousTimestamp[0];
7972
+ nanoseconds = nanoseconds - previousTimestamp[1];
7973
+ if (nanoseconds < 0) {
7974
+ seconds--;
7975
+ nanoseconds += 1e9;
7976
+ }
7977
+ }
7978
+ return [seconds, nanoseconds];
7979
+ };
7980
+ var NS_PER_SEC = 1e9;
7981
+ hrtime.bigint = (time) => {
7982
+ const diff = hrtime(time);
7983
+ return BigInt(diff[0] * NS_PER_SEC + diff[1]);
7984
+ };
7985
+
7955
7986
  // dist/src/schema.js
7956
7987
  var __decorate3 = function(decorators, target, key, desc) {
7957
7988
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
@@ -7979,6 +8010,8 @@ var SQLConversionMap = {
7979
8010
  Date: "TEXT"
7980
8011
  };
7981
8012
  var WRAPPED_SIMPLE_VALUE_VARIANT = "wrapped";
8013
+ var JSON_GROUP_ARRAY = "json_group_array";
8014
+ var JSON_OBJECT = "distinct json_object";
7982
8015
  var u64ToI64 = (u64) => {
7983
8016
  return (typeof u64 === "number" ? BigInt(u64) : u64) - 9223372036854775808n;
7984
8017
  };
@@ -7995,7 +8028,7 @@ var convertToSQLType = (value, type) => {
7995
8028
  return value;
7996
8029
  };
7997
8030
  var nullAsUndefined = (value) => value === null ? void 0 : value;
7998
- var escapeColumnName = (name) => `"${name}"`;
8031
+ var escapeColumnName = (name, char = '"') => `${char}${name}${char}`;
7999
8032
  var MissingFieldError = class extends Error {
8000
8033
  constructor(message) {
8001
8034
  super(message);
@@ -8066,7 +8099,8 @@ var getSQLTable = (ctor, path, primary, inline, addJoinField, fromOptionalField
8066
8099
  parent: void 0,
8067
8100
  referencedInArray: false,
8068
8101
  isSimpleValue: false,
8069
- inline
8102
+ inline,
8103
+ indices: /* @__PURE__ */ new Set()
8070
8104
  };
8071
8105
  ret.push(table);
8072
8106
  for (const dep of dependencies) {
@@ -8092,8 +8126,18 @@ var getNameOfClass = (ctor) => {
8092
8126
  return name;
8093
8127
  };
8094
8128
  var getTableName = (path = [], clazz) => {
8129
+ let pathKey = path.length > 0 ? path.join("__") + "__" : "";
8130
+ if (typeof clazz !== "string") {
8131
+ const tableName = clazz["__table_" + pathKey];
8132
+ if (tableName) {
8133
+ return tableName;
8134
+ }
8135
+ }
8095
8136
  let name = typeof clazz === "string" ? clazz : getNameOfClass(clazz);
8096
- const ret = (path.length > 0 ? path.join("__") + "__" : "") + name.replace(/[^a-zA-Z0-9_]/g, "_");
8137
+ const ret = pathKey + name.replace(/[^a-zA-Z0-9_]/g, "_");
8138
+ if (typeof clazz !== "string") {
8139
+ clazz["__table_" + pathKey] = ret;
8140
+ }
8097
8141
  return ret;
8098
8142
  };
8099
8143
  var CHILD_TABLE_ID = "__id";
@@ -8113,9 +8157,9 @@ var getSQLFields = (tableName, path, ctor, primary, addJoinFieldFromParent, tabl
8113
8157
  const sqlConstraints = [];
8114
8158
  let foundPrimary = false;
8115
8159
  const addJoinFields = primary === false ? addJoinFieldFromParent : (fields2, contstraints) => {
8116
- const primaryField = primary != null ? sqlFields.find((field2) => field2.name === primary) : void 0;
8117
- const parentPrimaryFieldName = primaryField?.key || CHILD_TABLE_ID;
8118
- const parentPrimaryFieldType = primaryField ? primaryField.type : "INTEGER";
8160
+ const parentPrimaryField = primary != null ? sqlFields.find((field2) => field2.name === primary) : void 0;
8161
+ const parentPrimaryFieldName = parentPrimaryField?.key || CHILD_TABLE_ID;
8162
+ const parentPrimaryFieldType = parentPrimaryField ? parentPrimaryField.type : "INTEGER";
8119
8163
  fields2.unshift(
8120
8164
  {
8121
8165
  name: CHILD_TABLE_ID,
@@ -8124,6 +8168,7 @@ var getSQLFields = (tableName, path, ctor, primary, addJoinFieldFromParent, tabl
8124
8168
  type: "INTEGER",
8125
8169
  isPrimary: true,
8126
8170
  from: void 0,
8171
+ unwrappedType: void 0,
8127
8172
  path: [CHILD_TABLE_ID]
8128
8173
  },
8129
8174
  // foreign key parent document
@@ -8132,8 +8177,9 @@ var getSQLFields = (tableName, path, ctor, primary, addJoinFieldFromParent, tabl
8132
8177
  key: PARENT_TABLE_ID,
8133
8178
  definition: `${PARENT_TABLE_ID} ${parentPrimaryFieldType}`,
8134
8179
  type: parentPrimaryFieldType,
8180
+ from: parentPrimaryField?.from,
8181
+ unwrappedType: parentPrimaryField?.unwrappedType,
8135
8182
  isPrimary: false,
8136
- from: void 0,
8137
8183
  path: [PARENT_TABLE_ID]
8138
8184
  }
8139
8185
  );
@@ -8191,6 +8237,7 @@ var getSQLFields = (tableName, path, ctor, primary, addJoinFieldFromParent, tabl
8191
8237
  type: "INTEGER",
8192
8238
  isPrimary: false,
8193
8239
  from: void 0,
8240
+ unwrappedType: void 0,
8194
8241
  path: [ARRAY_INDEX_COLUMN]
8195
8242
  },
8196
8243
  ...table.fields.slice(2)
@@ -8213,6 +8260,7 @@ var getSQLFields = (tableName, path, ctor, primary, addJoinFieldFromParent, tabl
8213
8260
  type: fieldType,
8214
8261
  isPrimary,
8215
8262
  from: field2,
8263
+ unwrappedType: unwrapNestedType(field2.type),
8216
8264
  path: [...path.slice(1), key]
8217
8265
  });
8218
8266
  };
@@ -8274,6 +8322,7 @@ var getSQLFields = (tableName, path, ctor, primary, addJoinFieldFromParent, tabl
8274
8322
  type: "bool",
8275
8323
  isPrimary: false,
8276
8324
  from: void 0,
8325
+ unwrappedType: void 0,
8277
8326
  path: [...path.slice(1), key],
8278
8327
  describesExistenceOfAnother: path[path.length - 1]
8279
8328
  });
@@ -8358,7 +8407,7 @@ var getTableFromValue = (parentTable, tables, field2, value) => {
8358
8407
  continue;
8359
8408
  }
8360
8409
  if (ctor) {
8361
- clazzName = getNameOfClass(ctor);
8410
+ clazzName = ctor;
8362
8411
  break;
8363
8412
  }
8364
8413
  }
@@ -8437,14 +8486,14 @@ var insert = async (insertFn, obj, tables, table, fields, handleNestedCallback,
8437
8486
  for (const _field of subTable.fields) {
8438
8487
  bindableValues.push(null);
8439
8488
  }
8440
- bindableValues[bindableValues.length - 1] = false;
8489
+ bindableValues[bindableValues.length - 1] = 0;
8441
8490
  continue;
8442
8491
  }
8443
8492
  await insert((values, table2) => {
8444
8493
  if (table2.inline) {
8445
8494
  bindableValues.push(...values);
8446
8495
  if (field2.type instanceof OptionKind) {
8447
- bindableValues.push(true);
8496
+ bindableValues.push(1);
8448
8497
  }
8449
8498
  return void 0;
8450
8499
  } else {
@@ -8513,13 +8562,13 @@ var matchFieldInShape = (shape, path, field2) => {
8513
8562
  };
8514
8563
  var selectChildren = (childrenTable) => "select * from " + childrenTable.name + " where " + PARENT_TABLE_ID + " = ?";
8515
8564
  var generateSelectQuery = (table, selects) => {
8516
- return `SELECT ${selects.map((x) => `${x.from} as ${x.as}`).join(", ")} FROM ${table.name}`;
8565
+ return `select ${selects.map((x) => `${x.from} as ${x.as}`).join(", ")} FROM ${table.name}`;
8517
8566
  };
8518
8567
  var selectAllFieldsFromTables = (tables, shape) => {
8519
8568
  const selectsPerTable = [];
8520
8569
  for (const table of tables) {
8521
- const { selects, join: joinFromSelect } = selectAllFieldsFromTable(table, shape);
8522
- selectsPerTable.push({ selects, joins: joinFromSelect });
8570
+ const { selects, join: joinFromSelect, groupBy } = selectAllFieldsFromTable(table, shape);
8571
+ selectsPerTable.push({ selects, joins: joinFromSelect, groupBy });
8523
8572
  }
8524
8573
  let newSelects = [];
8525
8574
  for (const [i, selects] of selectsPerTable.entries()) {
@@ -8544,8 +8593,50 @@ var selectAllFieldsFromTable = (table, shape) => {
8544
8593
  let stack = [{ table, shape }];
8545
8594
  let join = /* @__PURE__ */ new Map();
8546
8595
  const fieldResolvers = [];
8596
+ let groupByParentId = false;
8547
8597
  for (const tableAndShape of stack) {
8548
- if (!tableAndShape.table.inline) {
8598
+ if (tableAndShape.table.referencedInArray) {
8599
+ let selectBuilder = `${JSON_GROUP_ARRAY}(${JSON_OBJECT}(`;
8600
+ groupByParentId = true;
8601
+ let first = false;
8602
+ const as = createReconstructReferenceName(tableAndShape.table);
8603
+ for (const field2 of tableAndShape.table.fields) {
8604
+ if ((field2.isPrimary || !tableAndShape.shape || matchFieldInShape(tableAndShape.shape, [], field2) || // also always include the index field
8605
+ field2.name === ARRAY_INDEX_COLUMN) && field2.name !== PARENT_TABLE_ID) {
8606
+ let resolveField = `${as}.${escapeColumnName(field2.name)}`;
8607
+ if (field2.unwrappedType === "u64") {
8608
+ resolveField = `CAST(${resolveField} AS TEXT)`;
8609
+ }
8610
+ if (field2.type === "BLOB") {
8611
+ resolveField = `HEX(${resolveField})`;
8612
+ }
8613
+ if (first) {
8614
+ selectBuilder += `, `;
8615
+ }
8616
+ first = true;
8617
+ selectBuilder += `${escapeColumnName(field2.name, "'")}, ${resolveField}`;
8618
+ }
8619
+ }
8620
+ selectBuilder += `)) `;
8621
+ fieldResolvers.push({
8622
+ from: selectBuilder,
8623
+ as
8624
+ });
8625
+ join.set(createReconstructReferenceName(tableAndShape.table), {
8626
+ as,
8627
+ table: tableAndShape.table,
8628
+ type: "left",
8629
+ columns: []
8630
+ });
8631
+ } else if (!tableAndShape.table.inline) {
8632
+ if (tableAndShape.table.parent != null) {
8633
+ join.set(createReconstructReferenceName(tableAndShape.table), {
8634
+ as: tableAndShape.table.name,
8635
+ table: tableAndShape.table,
8636
+ type: "left",
8637
+ columns: []
8638
+ });
8639
+ }
8549
8640
  for (const field2 of tableAndShape.table.fields) {
8550
8641
  if (field2.isPrimary || !tableAndShape.shape || matchFieldInShape(tableAndShape.shape, [], field2)) {
8551
8642
  fieldResolvers.push({
@@ -8556,9 +8647,6 @@ var selectAllFieldsFromTable = (table, shape) => {
8556
8647
  }
8557
8648
  }
8558
8649
  for (const child of tableAndShape.table.children) {
8559
- if (child.referencedInArray) {
8560
- continue;
8561
- }
8562
8650
  let childShape = void 0;
8563
8651
  if (tableAndShape.shape) {
8564
8652
  const parentPath = child.parentPath?.slice(1);
@@ -8569,15 +8657,13 @@ var selectAllFieldsFromTable = (table, shape) => {
8569
8657
  childShape = maybeShape === true ? void 0 : Array.isArray(maybeShape) ? maybeShape[0] : maybeShape;
8570
8658
  }
8571
8659
  stack.push({ table: child, shape: childShape });
8572
- if (!child.inline) {
8573
- join.set(child.name, { as: child.name, table: child });
8574
- }
8575
8660
  }
8576
8661
  }
8577
8662
  if (fieldResolvers.length === 0) {
8578
8663
  throw new Error("No fields to resolve");
8579
8664
  }
8580
8665
  return {
8666
+ groupBy: groupByParentId ? `${table.name}.${escapeColumnName(table.primary)}` || void 0 : void 0,
8581
8667
  selects: fieldResolvers,
8582
8668
  // `SELECT ${fieldResolvers.join(", ")} FROM ${table.name}`,
8583
8669
  join
@@ -8605,13 +8691,37 @@ var resolveInstanceFromValue = async (fromTablePrefixedValues, tables, table, re
8605
8691
  }
8606
8692
  let subshape = maybeShape === true ? void 0 : subshapeIsArray ? maybeShape[0] : maybeShape;
8607
8693
  if (isArray) {
8608
- let once = false;
8609
8694
  let resolvedArr = [];
8610
8695
  for (const subtable of subTables) {
8611
- let rootTable = getNonInlinedTable(table);
8612
- const arr = await resolveChildren(fromTablePrefixedValues[getTablePrefixedField(rootTable, rootTable.primary, !tablePrefixed)], subtable);
8613
- if (arr) {
8614
- once = true;
8696
+ let arr = void 0;
8697
+ const tableName = createReconstructReferenceName(subtable);
8698
+ if (fromTablePrefixedValues[tableName]) {
8699
+ arr = JSON.parse(fromTablePrefixedValues[tableName]);
8700
+ arr = arr.filter((x) => x[subtable.primary] != null);
8701
+ for (const field3 of subtable.fields) {
8702
+ if (field3.name === PARENT_TABLE_ID) {
8703
+ continue;
8704
+ }
8705
+ if (field3.unwrappedType === "u64") {
8706
+ for (const item of arr) {
8707
+ item[field3.name] = BigInt(item[field3.name]);
8708
+ }
8709
+ } else if (field3.type === "BLOB") {
8710
+ for (const item of arr) {
8711
+ item[field3.name] = fromHexString(item[field3.name]);
8712
+ }
8713
+ }
8714
+ }
8715
+ } else {
8716
+ if (subtable.children) {
8717
+ let rootTable = getNonInlinedTable(table);
8718
+ const parentId = fromTablePrefixedValues[getTablePrefixedField(rootTable, rootTable.primary, !tablePrefixed)];
8719
+ arr = await resolveChildren(parentId, subtable);
8720
+ } else {
8721
+ arr = [];
8722
+ }
8723
+ }
8724
+ if (arr && arr.length > 0) {
8615
8725
  for (const element of arr) {
8616
8726
  const resolved = await resolveInstanceFromValue(
8617
8727
  element,
@@ -8626,11 +8736,7 @@ var resolveInstanceFromValue = async (fromTablePrefixedValues, tables, table, re
8626
8736
  }
8627
8737
  }
8628
8738
  }
8629
- if (!once) {
8630
- obj[field2.key] = void 0;
8631
- } else {
8632
- obj[field2.key] = resolvedArr;
8633
- }
8739
+ obj[field2.key] = resolvedArr;
8634
8740
  } else {
8635
8741
  let subTable = void 0;
8636
8742
  if (subTables.length > 1) {
@@ -8688,14 +8794,14 @@ var resolveInstanceFromValue = async (fromTablePrefixedValues, tables, table, re
8688
8794
  return Object.assign(Object.create(table.ctor.prototype), obj);
8689
8795
  };
8690
8796
  var convertDeleteRequestToQuery = (request, tables, table) => {
8691
- const { query, bindable } = convertRequestToQuery("delete", request, tables, table);
8797
+ const { query, bindable } = convertRequestToQuery("delete", { query: toQuery(request.query) }, tables, table);
8692
8798
  return {
8693
8799
  sql: `DELETE FROM ${table.name} WHERE ${table.primary} IN (SELECT ${table.primary} from ${table.name} ${query}) returning ${table.primary}`,
8694
8800
  bindable
8695
8801
  };
8696
8802
  };
8697
8803
  var convertSumRequestToQuery = (request, tables, table) => {
8698
- const { query, bindable } = convertRequestToQuery("sum", request, tables, table);
8804
+ const { query, bindable } = convertRequestToQuery("sum", { query: toQuery(request.query), key: request.key }, tables, table);
8699
8805
  const inlineName = getInlineTableFieldName(request.key);
8700
8806
  const field2 = table.fields.find((x) => x.name === inlineName);
8701
8807
  if (unwrapNestedType(field2.from.type) === "u64") {
@@ -8708,12 +8814,41 @@ var convertSumRequestToQuery = (request, tables, table) => {
8708
8814
  };
8709
8815
  };
8710
8816
  var convertCountRequestToQuery = (request, tables, table) => {
8711
- const { query, bindable } = convertRequestToQuery("count", request, tables, table);
8817
+ const { query, bindable } = convertRequestToQuery("count", { query: request?.query ? toQuery(request.query) : void 0 }, tables, table);
8712
8818
  return {
8713
8819
  sql: `SELECT count(*) as count FROM ${table.name} ${query}`,
8714
8820
  bindable
8715
8821
  };
8716
8822
  };
8823
+ var buildOrderBy = (sort, tables, table, joinBuilder, resolverBuilder, path = [], options) => {
8824
+ let orderByBuilder = void 0;
8825
+ if ((!sort || Array.isArray(sort) && sort.length === 0) && !options?.fetchAll) {
8826
+ sort = table.primary && path.length === 0 ? [{ key: [table.primary], direction: SortDirection.ASC }] : void 0;
8827
+ }
8828
+ if (sort) {
8829
+ let sortArr = Array.isArray(sort) ? sort : [sort];
8830
+ if (sortArr.length > 0) {
8831
+ orderByBuilder = "";
8832
+ let once = false;
8833
+ for (const sort2 of sortArr) {
8834
+ const { foreignTables, queryKey } = resolveTableToQuery(table, tables, joinBuilder, [...path, ...sort2.key], void 0, true);
8835
+ for (const foreignTable of foreignTables) {
8836
+ if (once) {
8837
+ orderByBuilder += ", ";
8838
+ }
8839
+ once = true;
8840
+ foreignTable.columns.push(queryKey);
8841
+ orderByBuilder += `"${foreignTable.as}#${queryKey}" ${sort2.direction === SortDirection.ASC ? "ASC" : "DESC"}`;
8842
+ resolverBuilder.push({
8843
+ from: `${table.name}.${escapeColumnName(queryKey)}`,
8844
+ as: `'${foreignTable.as}#${queryKey}'`
8845
+ });
8846
+ }
8847
+ }
8848
+ }
8849
+ }
8850
+ return { orderByBuilder };
8851
+ };
8717
8852
  var convertSearchRequestToQuery = (request, tables, rootTables, options) => {
8718
8853
  let unionBuilder = "";
8719
8854
  let orderByClause = "";
@@ -8722,16 +8857,12 @@ var convertSearchRequestToQuery = (request, tables, rootTables, options) => {
8722
8857
  const selectsPerTable = selectAllFieldsFromTables(rootTables, options?.shape);
8723
8858
  let bindableBuilder = [];
8724
8859
  for (const [i, table] of rootTables.entries()) {
8725
- const { selects, joins: joinFromSelect } = selectsPerTable[i];
8726
- const selectQuery = generateSelectQuery(table, selects);
8860
+ const { selects, joins, groupBy } = selectsPerTable[i];
8727
8861
  try {
8728
- const { orderBy, query, bindable } = convertRequestToQuery("iterate", request, tables, table, joinFromSelect, [], {
8729
- stable: options?.stable
8730
- });
8731
- unionBuilder += `${unionBuilder.length > 0 ? " UNION ALL " : ""} ${selectQuery} ${query}`;
8732
- orderByClause = orderBy?.length > 0 ? orderByClause.length > 0 ? orderByClause + ", " + orderBy : orderBy : orderByClause;
8733
- matchedOnce = true;
8734
- bindableBuilder.push(...bindable);
8862
+ const { orderByBuilder } = buildOrderBy(request?.sort, tables, table, joins, selects, [], options);
8863
+ if (!orderByClause && orderByBuilder) {
8864
+ orderByClause = orderByBuilder.length > 0 ? orderByClause.length > 0 ? orderByClause + ", " + orderByBuilder : orderByBuilder : orderByClause;
8865
+ }
8735
8866
  } catch (error2) {
8736
8867
  if (error2 instanceof MissingFieldError) {
8737
8868
  lastError = error2;
@@ -8739,122 +8870,159 @@ var convertSearchRequestToQuery = (request, tables, rootTables, options) => {
8739
8870
  }
8740
8871
  throw error2;
8741
8872
  }
8873
+ const selectQuery = generateSelectQuery(table, selects);
8874
+ for (const flattenRequest of flattenQuery(request)) {
8875
+ try {
8876
+ const { query, bindable } = convertRequestToQuery(
8877
+ "iterate",
8878
+ flattenRequest,
8879
+ tables,
8880
+ table,
8881
+ new Map(joins),
8882
+ // copy the map, else we might might do unececessary joins
8883
+ [],
8884
+ options
8885
+ );
8886
+ unionBuilder += `${unionBuilder.length > 0 ? " UNION " : ""} ${selectQuery} ${query} ${groupBy ? "GROUP BY " + groupBy : ""}`;
8887
+ matchedOnce = true;
8888
+ bindableBuilder.push(...bindable);
8889
+ } catch (error2) {
8890
+ if (error2 instanceof MissingFieldError) {
8891
+ lastError = error2;
8892
+ orderByClause = "";
8893
+ continue;
8894
+ }
8895
+ throw error2;
8896
+ }
8897
+ }
8742
8898
  }
8743
8899
  if (!matchedOnce) {
8744
8900
  throw lastError;
8745
8901
  }
8746
8902
  return {
8747
- sql: `${unionBuilder} ${orderByClause ? "ORDER BY " + orderByClause : ""} limit ? offset ?`,
8903
+ sql: `${unionBuilder} ${orderByClause ? "ORDER BY " + orderByClause : ""} ${options?.fetchAll ? "" : "limit ? offset ?"}`,
8748
8904
  bindable: bindableBuilder
8749
8905
  };
8750
8906
  };
8751
- function isIterateRequest(request, type) {
8752
- return type === "iterate";
8753
- }
8907
+ var getOrSetRootTable = (joinBuilder, table) => {
8908
+ const refName = createQueryTableReferenceName(table);
8909
+ let ref = joinBuilder.get(refName);
8910
+ if (ref) {
8911
+ return ref;
8912
+ }
8913
+ const join = {
8914
+ // add the root as a join even though it is not, just so we can collect the columns it will be queried
8915
+ table,
8916
+ type: "root",
8917
+ as: table.name,
8918
+ columns: []
8919
+ };
8920
+ joinBuilder.set(refName, join);
8921
+ return join;
8922
+ };
8754
8923
  var convertRequestToQuery = (type, request, tables, table, extraJoin, path = [], options) => {
8755
8924
  let whereBuilder = "";
8756
8925
  let bindableBuilder = [];
8757
- let orderByBuilder = void 0;
8758
8926
  let joinBuilder = extraJoin || /* @__PURE__ */ new Map();
8927
+ getOrSetRootTable(joinBuilder, table);
8759
8928
  const coercedQuery = toQuery(request?.query);
8760
8929
  if (coercedQuery.length === 1) {
8761
- const { where: where2, bindable } = convertQueryToSQLQuery(coercedQuery[0], tables, table, joinBuilder, path);
8930
+ const { where: where2, bindable } = convertQueryToSQLQuery(coercedQuery[0], tables, table, joinBuilder, path, void 0, 0);
8762
8931
  whereBuilder += where2;
8763
8932
  bindableBuilder.push(...bindable);
8764
8933
  } else if (coercedQuery.length > 1) {
8765
- const { where: where2, bindable } = convertQueryToSQLQuery(new And(coercedQuery), tables, table, joinBuilder, path);
8934
+ const { where: where2, bindable } = convertQueryToSQLQuery(new And(coercedQuery), tables, table, joinBuilder, path, void 0, 0);
8766
8935
  whereBuilder += where2;
8767
8936
  bindableBuilder.push(...bindable);
8768
8937
  }
8769
- if (isIterateRequest(request, type)) {
8770
- let sort = request?.sort;
8771
- if (!sort && options?.stable) {
8772
- sort = table.primary && path.length === 0 ? [{ key: [table.primary], direction: SortDirection.ASC }] : void 0;
8773
- }
8774
- if (sort) {
8775
- let sortArr = Array.isArray(sort) ? sort : [sort];
8776
- if (sortArr.length > 0) {
8777
- orderByBuilder = "";
8778
- let once = false;
8779
- for (const sort2 of sortArr) {
8780
- const { foreignTables, queryKey } = resolveTableToQuery(table, tables, joinBuilder, [...path, ...sort2.key], void 0, true);
8781
- for (const table2 of foreignTables) {
8782
- if (once) {
8783
- orderByBuilder += ", ";
8784
- }
8785
- once = true;
8786
- orderByBuilder += `${table2.as}.${queryKey} ${sort2.direction === SortDirection.ASC ? "ASC" : "DESC"}`;
8787
- }
8788
- }
8789
- }
8790
- }
8791
- }
8792
8938
  const where = whereBuilder.length > 0 ? "where " + whereBuilder : void 0;
8793
8939
  if (extraJoin && extraJoin.size > 0) {
8794
8940
  insertMapIntoMap(joinBuilder, extraJoin);
8795
8941
  }
8796
- let join = buildJoin(joinBuilder, type === "iterate" ? true : false);
8942
+ let { join } = buildJoin(joinBuilder, options);
8797
8943
  const query = `${join ? join : ""} ${where ? where : ""}`;
8798
8944
  return {
8799
8945
  query,
8800
- orderBy: orderByBuilder,
8946
+ /* orderBy: orderByBuilder, */
8801
8947
  bindable: bindableBuilder
8802
8948
  };
8803
8949
  };
8804
- var buildJoin = (joinBuilder, resolveAllColumns) => {
8805
- let joinTypeDefault = resolveAllColumns ? (
8806
- /* "FULL OUTER JOIN" */
8807
- "LEFT OUTER JOIN"
8808
- ) : "JOIN";
8950
+ var buildJoin = (joinBuilder, options) => {
8809
8951
  let join = "";
8810
8952
  for (const [_key, table] of joinBuilder) {
8953
+ if (table.type !== "root") {
8954
+ continue;
8955
+ }
8956
+ const out = _buildJoin(table, options);
8957
+ join += out.join;
8958
+ }
8959
+ for (const [_key, table] of joinBuilder) {
8960
+ if (table.type === "root") {
8961
+ continue;
8962
+ }
8963
+ const out = _buildJoin(table, options);
8964
+ join += out.join;
8965
+ }
8966
+ return { join };
8967
+ };
8968
+ var _buildJoin = (table, options) => {
8969
+ let join = "";
8970
+ let indexedBy = void 0;
8971
+ if (table.type !== "root") {
8972
+ table.columns.push(PARENT_TABLE_ID);
8973
+ }
8974
+ if (table.columns.length > 0) {
8975
+ const usedColumns = removeDuplicatesOrdered(table.columns);
8976
+ indexedBy = options?.planner ? ` INDEXED BY ${options.planner.resolveIndex(table.table.name, usedColumns)} ` : "";
8977
+ }
8978
+ if (table.type !== "root") {
8811
8979
  let nonInlinedParent = table.table.parent && getNonInlinedTable(table.table.parent);
8812
8980
  if (!nonInlinedParent) {
8813
8981
  throw new Error("Unexpected: missing parent");
8814
8982
  }
8815
- let joinType = table.table.referencedInArray ? (
8816
- /* "FULL OUTER JOIN" */
8817
- "LEFT OUTER JOIN"
8818
- ) : joinTypeDefault;
8819
- join += `${joinType} ${table.table.name} AS ${table.as} ON ${nonInlinedParent.name}.${nonInlinedParent.primary} = ${table.as}.${PARENT_TABLE_ID} `;
8983
+ let joinType = table.type === "cross" ? "LEFT JOIN" : "LEFT JOIN";
8984
+ join += ` ${joinType} ${table.table.name} AS ${table.as} ${indexedBy} ON ${nonInlinedParent.name}.${nonInlinedParent.primary} = ${table.as}.${PARENT_TABLE_ID} `;
8985
+ } else if (indexedBy) {
8986
+ join += indexedBy;
8820
8987
  }
8821
- return join;
8988
+ return { join };
8822
8989
  };
8823
8990
  var insertMapIntoMap = (map, insert2) => {
8824
8991
  for (const [key, value] of insert2) {
8825
8992
  map.set(key, value);
8826
8993
  }
8827
8994
  };
8828
- var convertQueryToSQLQuery = (query, tables, table, joinBuilder, path = [], tableAlias = void 0) => {
8995
+ var convertQueryToSQLQuery = (query, tables, table, joinBuilder, path, tableAlias, skipKeys) => {
8829
8996
  let whereBuilder = "";
8830
8997
  let bindableBuilder = [];
8831
- const handleAnd = (queries, path2, tableAlias2) => {
8998
+ const handleAnd = (queries, path2, tableAlias2, keysOffset) => {
8832
8999
  for (const query2 of queries) {
8833
- const { where, bindable } = convertQueryToSQLQuery(query2, tables, table, joinBuilder, path2, tableAlias2);
9000
+ const { where, bindable } = convertQueryToSQLQuery(query2, tables, table, joinBuilder, path2, tableAlias2, keysOffset);
8834
9001
  whereBuilder = whereBuilder.length > 0 ? `(${whereBuilder}) AND (${where})` : where;
8835
9002
  bindableBuilder.push(...bindable);
8836
9003
  }
8837
9004
  };
8838
9005
  if (query instanceof StateFieldQuery) {
8839
- const { where, bindable } = convertStateFieldQuery(query, tables, table, joinBuilder, path, tableAlias);
9006
+ const { where, bindable } = convertStateFieldQuery(query, tables, table, joinBuilder, path, tableAlias, skipKeys);
8840
9007
  whereBuilder += where;
8841
9008
  bindableBuilder.push(...bindable);
8842
9009
  } else if (query instanceof Nested) {
8843
9010
  let joinPrefix = "__" + String(tables.size);
8844
- path = [...path, query.path];
8845
- handleAnd(query.query, path, joinPrefix);
9011
+ path = [...path, ...query.path];
9012
+ let newSkipKeys = skipKeys + query.path.length;
9013
+ handleAnd(query.query, path, joinPrefix, newSkipKeys);
8846
9014
  } else if (query instanceof LogicalQuery) {
8847
9015
  if (query instanceof And) {
8848
- handleAnd(query.and, path, tableAlias);
9016
+ handleAnd(query.and, path, tableAlias, skipKeys);
8849
9017
  } else if (query instanceof Or) {
8850
9018
  for (const subquery of query.or) {
8851
- const { where, bindable } = convertQueryToSQLQuery(subquery, tables, table, joinBuilder, path, tableAlias);
8852
- whereBuilder = whereBuilder.length > 0 ? `(${whereBuilder}) OR (${where})` : where;
9019
+ const { where, bindable } = convertQueryToSQLQuery(subquery, tables, table, joinBuilder, path, tableAlias, skipKeys);
9020
+ whereBuilder = whereBuilder.length > 0 ? `(${whereBuilder}) OR(${where})` : where;
8853
9021
  bindableBuilder.push(...bindable);
8854
9022
  }
8855
9023
  } else if (query instanceof Not) {
8856
- const { where, bindable } = convertQueryToSQLQuery(query.not, tables, table, joinBuilder, path, tableAlias);
8857
- whereBuilder = `NOT (${where})`;
9024
+ const { where, bindable } = convertQueryToSQLQuery(query.not, tables, table, joinBuilder, path, tableAlias, skipKeys);
9025
+ whereBuilder = `NOT(${where})`;
8858
9026
  bindableBuilder.push(...bindable);
8859
9027
  } else {
8860
9028
  throw new Error("Unsupported query type: " + query.constructor.name);
@@ -8870,13 +9038,11 @@ var convertQueryToSQLQuery = (query, tables, table, joinBuilder, path = [], tabl
8870
9038
  var cloneQuery = (query) => {
8871
9039
  return deserialize(serialize(query), StateFieldQuery);
8872
9040
  };
8873
- var createTableReferenceName = (table, alias, fieldType, joinSize) => {
8874
- if (!alias && (fieldType instanceof VecKind || fieldType instanceof OptionKind && fieldType.elementType instanceof VecKind)) {
8875
- let aliasSuffix = "_" + String(joinSize);
8876
- alias = aliasSuffix;
8877
- }
8878
- const tableNameAs = alias ? alias + "_" + table.name : table.name;
8879
- return tableNameAs;
9041
+ var createQueryTableReferenceName = (table) => {
9042
+ return table.parent == null ? table.name : "_query_" + table.name;
9043
+ };
9044
+ var createReconstructReferenceName = (table) => {
9045
+ return table.name;
8880
9046
  };
8881
9047
  var resolveTableToQuery = (table, tables, join, path, alias, searchSelf) => {
8882
9048
  if (searchSelf) {
@@ -8885,11 +9051,18 @@ var resolveTableToQuery = (table, tables, join, path, alias, searchSelf) => {
8885
9051
  if (field2) {
8886
9052
  return {
8887
9053
  queryKey: field2.name,
8888
- foreignTables: [{ table, as: table.name }]
9054
+ foreignTables: [getOrSetRootTable(join, table)]
8889
9055
  };
8890
9056
  }
8891
9057
  }
8892
- let currentTables = [{ table, as: alias || table.name }];
9058
+ let currentTables = [
9059
+ {
9060
+ table,
9061
+ as: alias || table.name,
9062
+ type: "cross",
9063
+ columns: []
9064
+ }
9065
+ ];
8893
9066
  let prevTables = void 0;
8894
9067
  for (const [_i, key] of path.entries()) {
8895
9068
  let newTables = [];
@@ -8897,13 +9070,18 @@ var resolveTableToQuery = (table, tables, join, path, alias, searchSelf) => {
8897
9070
  const schema = getSchema(currentTable.ctor);
8898
9071
  const field2 = schema.fields.find((x) => x.key === key);
8899
9072
  if (!field2 && currentTable.children.length > 0) {
8900
- throw new MissingFieldError(`Property with key "${key}" is not found in the schema ${JSON.stringify(schema.fields.map((x) => x.key))}`);
9073
+ throw new MissingFieldError(`Property with key "${key}" is not found in the schema ${JSON.stringify(schema.fields.map((x) => x.key))} `);
8901
9074
  }
8902
9075
  for (const child of currentTable.children) {
8903
- const tableNameAs = createTableReferenceName(child, alias, field2.type, join.size);
9076
+ const tableNameAs = createQueryTableReferenceName(child);
8904
9077
  let isMatching = child.parentPath[child.parentPath.length - 1] === key;
8905
9078
  if (isMatching) {
8906
- const tableWithAlias = { table: child, as: tableNameAs };
9079
+ const tableWithAlias = {
9080
+ columns: [],
9081
+ table: child,
9082
+ as: tableNameAs,
9083
+ type: currentTable.children.length > 1 ? "left" : "cross"
9084
+ };
8907
9085
  if (child.isSimpleValue) {
8908
9086
  if (!child.inline) {
8909
9087
  join.set(tableNameAs, tableWithAlias);
@@ -8943,12 +9121,16 @@ var resolveTableToQuery = (table, tables, join, path, alias, searchSelf) => {
8943
9121
  let queryKey = queryKeyPath.length > 0 ? getInlineTableFieldName(queryKeyPath) : FOREIGN_VALUE_PROPERTY;
8944
9122
  return { queryKey, foreignTables };
8945
9123
  };
8946
- var convertStateFieldQuery = (query, tables, table, join, path, tableAlias = void 0) => {
9124
+ var convertStateFieldQuery = (query, tables, table, join, path, tableAlias, skipKeys) => {
8947
9125
  const inlinedName = getInlineTableFieldName(query.key);
8948
9126
  const tableField = table.fields.find((x) => x.name === inlinedName);
8949
9127
  const isForeign = !tableField;
8950
9128
  if (isForeign) {
8951
- const { queryKey, foreignTables } = resolveTableToQuery(table, tables, join, [...path, ...query.key], tableAlias, false);
9129
+ const tablePath = [...path];
9130
+ for (let i = skipKeys; i < query.key.length; i++) {
9131
+ tablePath.push(query.key[i]);
9132
+ }
9133
+ const { queryKey, foreignTables } = resolveTableToQuery(table, tables, join, tablePath, tableAlias, false);
8952
9134
  query = cloneQuery(query);
8953
9135
  query.key = [queryKey];
8954
9136
  let whereBuilder = [];
@@ -8957,7 +9139,7 @@ var convertStateFieldQuery = (query, tables, table, join, path, tableAlias = voi
8957
9139
  if (ftable.table === table) {
8958
9140
  throw new Error("Unexpected");
8959
9141
  }
8960
- const { where: where2, bindable: bindable2 } = convertQueryToSQLQuery(query, tables, ftable.table, join, path, ftable.as);
9142
+ const { where: where2, bindable: bindable2 } = convertQueryToSQLQuery(query, tables, ftable.table, join, path, ftable.as, skipKeys);
8961
9143
  whereBuilder.push(where2);
8962
9144
  bindableBuilder.push(bindable2);
8963
9145
  }
@@ -8966,16 +9148,21 @@ var convertStateFieldQuery = (query, tables, table, join, path, tableAlias = voi
8966
9148
  bindable: bindableBuilder.flat()
8967
9149
  };
8968
9150
  }
9151
+ const columnAggregator = join.get(createQueryTableReferenceName(table));
9152
+ if (!columnAggregator) {
9153
+ throw new Error("Unexpected");
9154
+ }
9155
+ columnAggregator.columns.push(inlinedName);
8969
9156
  let bindable = [];
8970
9157
  const keyWithTable = (tableAlias || table.name) + "." + escapeColumnName(inlinedName);
8971
9158
  let where;
8972
9159
  if (query instanceof StringMatch) {
8973
9160
  let statement = "";
8974
9161
  if (query.method === StringMatchMethod.contains) {
8975
- statement = `${keyWithTable} LIKE ?`;
9162
+ statement = `${keyWithTable} LIKE ? `;
8976
9163
  bindable.push(`%${query.value}%`);
8977
9164
  } else if (query.method === StringMatchMethod.prefix) {
8978
- statement = `${keyWithTable} LIKE ?`;
9165
+ statement = `${keyWithTable} LIKE ? `;
8979
9166
  bindable.push(`${query.value}%`);
8980
9167
  } else if (query.method === StringMatchMethod.exact) {
8981
9168
  statement = `${keyWithTable} = ?`;
@@ -8991,21 +9178,21 @@ var convertStateFieldQuery = (query, tables, table, join, path, tableAlias = voi
8991
9178
  where = statement;
8992
9179
  } else if (query instanceof IntegerCompare) {
8993
9180
  if (tableField.type === "BLOB") {
8994
- where = `hex(${keyWithTable}) LIKE ?`;
9181
+ where = `hex(${keyWithTable}) LIKE ? `;
8995
9182
  bindable.push(`%${toHexString(new Uint8Array([Number(query.value.value)]))}%`);
8996
9183
  } else {
8997
9184
  if (query.compare === Compare.Equal) {
8998
9185
  where = `${keyWithTable} = ?`;
8999
9186
  } else if (query.compare === Compare.Greater) {
9000
- where = `${keyWithTable} > ?`;
9187
+ where = `${keyWithTable} > ? `;
9001
9188
  } else if (query.compare === Compare.Less) {
9002
- where = `${keyWithTable} < ?`;
9189
+ where = `${keyWithTable} <?`;
9003
9190
  } else if (query.compare === Compare.GreaterOrEqual) {
9004
- where = `${keyWithTable} >= ?`;
9191
+ where = `${keyWithTable} >= ? `;
9005
9192
  } else if (query.compare === Compare.LessOrEqual) {
9006
- where = `${keyWithTable} <= ?`;
9193
+ where = `${keyWithTable} <= ? `;
9007
9194
  } else {
9008
- throw new Error(`Unsupported compare type: ${query.compare}`);
9195
+ throw new Error(`Unsupported compare type: ${query.compare} `);
9009
9196
  }
9010
9197
  if (unwrapNestedType(tableField.from.type) === "u64") {
9011
9198
  bindable.push(u64ToI64(query.value.value));
@@ -9023,6 +9210,253 @@ var convertStateFieldQuery = (query, tables, table, join, path, tableAlias = voi
9023
9210
  }
9024
9211
  return { where, bindable };
9025
9212
  };
9213
+ var removeDuplicatesOrdered = (arr) => {
9214
+ let seen = /* @__PURE__ */ new Set();
9215
+ return arr.filter((item) => {
9216
+ if (seen.has(item)) {
9217
+ return false;
9218
+ }
9219
+ seen.add(item);
9220
+ return true;
9221
+ });
9222
+ };
9223
+
9224
+ // dist/src/query-planner.js
9225
+ var __decorate4 = function(decorators, target, key, desc) {
9226
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
9227
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
9228
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
9229
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
9230
+ };
9231
+ var __metadata4 = function(k, v2) {
9232
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v2);
9233
+ };
9234
+ var getSortedNameKey = (tableName, names) => [tableName, ...names.sort()].join(",");
9235
+ var createIndexKey = (tableName, fields) => `${tableName}_index_${fields.map((x) => x).join("_")}`;
9236
+ var HALF_MAX_U32 = 2147483647;
9237
+ var HALF_MAX_U64 = 9223372036854775807n;
9238
+ var flattenQuery = function* (props) {
9239
+ if (!props) {
9240
+ return yield props;
9241
+ }
9242
+ let ors = [];
9243
+ let ands = [];
9244
+ let stack = [...props.query];
9245
+ let foundOr = false;
9246
+ for (const q of stack) {
9247
+ if (q instanceof Or) {
9248
+ if (foundOr) {
9249
+ yield props;
9250
+ return;
9251
+ }
9252
+ ors = q.or;
9253
+ foundOr = true;
9254
+ } else if (q instanceof And) {
9255
+ for (const a of q.and) {
9256
+ stack.push(a);
9257
+ }
9258
+ } else {
9259
+ ands.push(q);
9260
+ }
9261
+ }
9262
+ let maxFlatten = 4;
9263
+ if (ors.length === 0 || ors.length >= maxFlatten) {
9264
+ yield {
9265
+ query: ands,
9266
+ sort: props.sort
9267
+ };
9268
+ return;
9269
+ }
9270
+ for (const or2 of ors) {
9271
+ yield {
9272
+ query: [...ands, ...Array.isArray(or2) ? or2 : [or2]],
9273
+ sort: props.sort
9274
+ };
9275
+ }
9276
+ };
9277
+ var reduceResolution = (value) => {
9278
+ if (value instanceof UnsignedIntegerValue) {
9279
+ return value.number > HALF_MAX_U32 ? new UnsignedIntegerValue(HALF_MAX_U32) : new UnsignedIntegerValue(0);
9280
+ }
9281
+ if (value instanceof BigUnsignedIntegerValue) {
9282
+ return value.value > HALF_MAX_U64 ? new BigUnsignedIntegerValue(HALF_MAX_U64) : new BigUnsignedIntegerValue(0n);
9283
+ }
9284
+ throw new Error("Unknown integer value type: " + value?.constructor.name);
9285
+ };
9286
+ var nullifyQuery = (query) => {
9287
+ if (query instanceof IntegerCompare) {
9288
+ return new IntegerCompare({
9289
+ compare: Compare.Equal,
9290
+ value: reduceResolution(query.value),
9291
+ key: query.key
9292
+ });
9293
+ } else if (query instanceof StringMatch) {
9294
+ return new StringMatch({
9295
+ key: query.key,
9296
+ value: "",
9297
+ method: query.method
9298
+ });
9299
+ } else if (query instanceof ByteMatchQuery) {
9300
+ return new ByteMatchQuery({
9301
+ key: query.key,
9302
+ value: new Uint8Array()
9303
+ });
9304
+ } else if (query instanceof BoolQuery) {
9305
+ return new BoolQuery({
9306
+ key: query.key,
9307
+ value: false
9308
+ });
9309
+ } else if (query instanceof And) {
9310
+ let and = [];
9311
+ for (const condition of query.and) {
9312
+ and.push(nullifyQuery(condition));
9313
+ }
9314
+ return new And(and);
9315
+ } else if (query instanceof Or) {
9316
+ let or2 = [];
9317
+ for (const condition of query.or) {
9318
+ or2.push(nullifyQuery(condition));
9319
+ }
9320
+ return new Or(or2);
9321
+ } else if (query instanceof Not) {
9322
+ return new Not(nullifyQuery(query.not));
9323
+ } else if (query instanceof IsNull) {
9324
+ return query;
9325
+ } else if (query instanceof Nested) {
9326
+ throw new Error("Unsupported query type, deprecated");
9327
+ }
9328
+ throw new Error("Unknown query type: " + query?.constructor.name);
9329
+ };
9330
+ var PlannableQuery = class _PlannableQuery {
9331
+ query;
9332
+ sort;
9333
+ constructor(props) {
9334
+ this.query = props.query;
9335
+ this.sort = Array.isArray(props.sort) ? props.sort : props.sort ? [props.sort] : [];
9336
+ }
9337
+ get key() {
9338
+ let query = this.query.map((x) => nullifyQuery(x));
9339
+ let nullifiedPlannableQuery = new _PlannableQuery({
9340
+ query,
9341
+ sort: this.sort
9342
+ });
9343
+ return sha256Base64Sync(serialize(nullifiedPlannableQuery));
9344
+ }
9345
+ };
9346
+ __decorate4([
9347
+ field({ type: vec(Query) }),
9348
+ __metadata4("design:type", Array)
9349
+ ], PlannableQuery.prototype, "query", void 0);
9350
+ __decorate4([
9351
+ field({ type: vec(Sort) }),
9352
+ __metadata4("design:type", Array)
9353
+ ], PlannableQuery.prototype, "sort", void 0);
9354
+ var QueryPlanner = class {
9355
+ props;
9356
+ stats = /* @__PURE__ */ new Map();
9357
+ pendingIndexCreation = /* @__PURE__ */ new Map();
9358
+ constructor(props) {
9359
+ this.props = props;
9360
+ }
9361
+ async stop() {
9362
+ for (const promise of this.pendingIndexCreation.values()) {
9363
+ await promise.catch(() => {
9364
+ });
9365
+ }
9366
+ this.stats.clear();
9367
+ }
9368
+ scope(query) {
9369
+ let obj = this.stats.get(query.key);
9370
+ if (obj === void 0) {
9371
+ obj = {
9372
+ columnsToIndexes: /* @__PURE__ */ new Map()
9373
+ };
9374
+ this.stats.set(query.key, obj);
9375
+ }
9376
+ let indexCreateCommands = void 0;
9377
+ let pickedIndexKeys = /* @__PURE__ */ new Map();
9378
+ return {
9379
+ beforePrepare: async () => {
9380
+ if (indexCreateCommands != null) {
9381
+ for (const { key, cmd } of indexCreateCommands) {
9382
+ if (this.pendingIndexCreation.has(key)) {
9383
+ await this.pendingIndexCreation.get(key);
9384
+ }
9385
+ const promise = this.props.exec(cmd);
9386
+ this.pendingIndexCreation.set(key, promise);
9387
+ await promise;
9388
+ this.pendingIndexCreation.delete(key);
9389
+ }
9390
+ }
9391
+ if (this.pendingIndexCreation.size > 0) {
9392
+ for (const picked of pickedIndexKeys.keys()) {
9393
+ await this.pendingIndexCreation.get(picked);
9394
+ }
9395
+ }
9396
+ },
9397
+ resolveIndex: (tableName, columns) => {
9398
+ const sortedNameKey = getSortedNameKey(tableName, columns);
9399
+ let indexStats = obj.columnsToIndexes.get(sortedNameKey);
9400
+ if (indexStats === void 0) {
9401
+ indexStats = {
9402
+ results: []
9403
+ };
9404
+ obj.columnsToIndexes.set(sortedNameKey, indexStats);
9405
+ }
9406
+ if (indexStats.results.length === 0) {
9407
+ const permutations = generatePermutations(columns);
9408
+ for (const columns2 of permutations) {
9409
+ const indexKey = createIndexKey(tableName, columns2);
9410
+ const command = `create index if not exists ${indexKey} on ${tableName} (${columns2.map((n) => escapeColumnName(n)).join(", ")})`;
9411
+ (indexCreateCommands || (indexCreateCommands = [])).push({
9412
+ cmd: command,
9413
+ key: indexKey
9414
+ });
9415
+ indexStats.results.push({
9416
+ used: 0,
9417
+ times: [],
9418
+ avg: -1,
9419
+ // setting -1 will force the first time to be the fastest (i.e. new indices are always tested once)
9420
+ indexKey
9421
+ });
9422
+ }
9423
+ }
9424
+ let fastestIndex = indexStats.results[0];
9425
+ fastestIndex.used++;
9426
+ pickedIndexKeys.set(fastestIndex.indexKey, sortedNameKey);
9427
+ return fastestIndex.indexKey;
9428
+ },
9429
+ perform: async (fn) => {
9430
+ let t0 = hrtime.bigint();
9431
+ const out = await fn();
9432
+ let t1 = hrtime.bigint();
9433
+ const time = Number(t1 - t0);
9434
+ for (const [indexKey, columnsKey] of pickedIndexKeys) {
9435
+ const indexStats = obj.columnsToIndexes.get(columnsKey);
9436
+ if (indexStats === void 0) {
9437
+ throw new Error("index stats not found");
9438
+ }
9439
+ const index = indexStats.results.find((x) => x.indexKey === indexKey);
9440
+ if (index === void 0) {
9441
+ throw new Error("index not found");
9442
+ }
9443
+ index.times.push(time);
9444
+ if (index.times.length > 20) {
9445
+ index.times.shift();
9446
+ }
9447
+ index.avg = index.times.reduce((a, b) => a + b, 0) / index.times.length;
9448
+ indexStats.results.sort((a, b) => a.avg - b.avg);
9449
+ }
9450
+ return out;
9451
+ }
9452
+ };
9453
+ }
9454
+ };
9455
+ var generatePermutations = (list) => {
9456
+ if (list.length === 1)
9457
+ return [list];
9458
+ return [list, [...list].reverse()];
9459
+ };
9026
9460
 
9027
9461
  // dist/src/engine.js
9028
9462
  var escapePathToSQLName = (path) => {
@@ -9035,11 +9469,13 @@ var SQLLiteIndex = class {
9035
9469
  properties;
9036
9470
  primaryKeyArr;
9037
9471
  primaryKeyString;
9472
+ planner;
9038
9473
  scopeString;
9039
9474
  _rootTables;
9040
9475
  _tables;
9041
9476
  _cursor;
9042
9477
  // TODO choose limit better
9478
+ cursorPruner;
9043
9479
  iteratorTimeout;
9044
9480
  closed = true;
9045
9481
  id;
@@ -9049,22 +9485,25 @@ var SQLLiteIndex = class {
9049
9485
  this.id = v4_default();
9050
9486
  this.scopeString = properties.scope.length > 0 ? "_" + escapePathToSQLName(properties.scope).join("_") : void 0;
9051
9487
  this.iteratorTimeout = options?.iteratorTimeout || 6e4;
9488
+ this.planner = new QueryPlanner({
9489
+ exec: this.properties.db.exec.bind(this.properties.db)
9490
+ });
9052
9491
  }
9053
9492
  get tables() {
9054
9493
  if (this.closed) {
9055
- throw new Error("Not started");
9494
+ throw new NotStartedError();
9056
9495
  }
9057
9496
  return this._tables;
9058
9497
  }
9059
9498
  get rootTables() {
9060
9499
  if (this.closed) {
9061
- throw new Error("Not started");
9500
+ throw new NotStartedError();
9062
9501
  }
9063
9502
  return this._rootTables;
9064
9503
  }
9065
9504
  get cursor() {
9066
9505
  if (this.closed) {
9067
- throw new Error("Not started");
9506
+ throw new NotStartedError();
9068
9507
  }
9069
9508
  return this._cursor;
9070
9509
  }
@@ -9114,9 +9553,7 @@ var SQLLiteIndex = class {
9114
9553
  continue;
9115
9554
  }
9116
9555
  const sqlCreateTable = `create table if not exists ${table.name} (${[...table.fields, ...table.constraints].map((s) => s.definition).join(", ")}) strict`;
9117
- const sqlCreateIndex = `create index if not exists ${table.name}_index on ${table.name} (${table.fields.map((field2) => escapeColumnName(field2.name)).join(", ")})`;
9118
9556
  this.properties.db.exec(sqlCreateTable);
9119
- this.properties.db.exec(sqlCreateIndex);
9120
9557
  let sqlPut = `insert into ${table.name} (${table.fields.map((field2) => escapeColumnName(field2.name)).join(", ")}) VALUES (${table.fields.map((_x) => "?").join(", ")}) RETURNING ${table.primary};`;
9121
9558
  let sqlReplace = `insert or replace into ${table.name} (${table.fields.map((field2) => escapeColumnName(field2.name)).join(", ")}) VALUES (${table.fields.map((_x) => "?").join(", ")});`;
9122
9559
  await this.properties.db.prepare(sqlPut, putStatementKey(table));
@@ -9125,6 +9562,14 @@ var SQLLiteIndex = class {
9125
9562
  await this.properties.db.prepare(selectChildren(table), resolveChildrenStatement(table));
9126
9563
  }
9127
9564
  }
9565
+ this.cursorPruner = setInterval(() => {
9566
+ const now = Date.now();
9567
+ for (const [k, v2] of this._cursor) {
9568
+ if (v2.expire < now) {
9569
+ this.clearupIterator(k);
9570
+ }
9571
+ }
9572
+ }, this.iteratorTimeout);
9128
9573
  this.closed = false;
9129
9574
  }
9130
9575
  async clearStatements() {
@@ -9137,14 +9582,20 @@ var SQLLiteIndex = class {
9137
9582
  return;
9138
9583
  }
9139
9584
  this.closed = true;
9585
+ clearInterval(this.cursorPruner);
9140
9586
  await this.clearStatements();
9141
9587
  this._tables.clear();
9142
9588
  for (const [k, _v] of this._cursor) {
9143
9589
  await this.clearupIterator(k);
9144
9590
  }
9591
+ await this.planner.stop();
9145
9592
  }
9146
9593
  async drop() {
9594
+ if (this.closed) {
9595
+ throw new Error(`Already closed index ${this.id}, can not drop`);
9596
+ }
9147
9597
  this.closed = true;
9598
+ clearInterval(this.cursorPruner);
9148
9599
  await this.clearStatements();
9149
9600
  for (const table of this._rootTables) {
9150
9601
  await this.properties.db.exec(`drop table if exists ${table.name}`);
@@ -9153,6 +9604,7 @@ var SQLLiteIndex = class {
9153
9604
  for (const [k, _v] of this._cursor) {
9154
9605
  await this.clearupIterator(k);
9155
9606
  }
9607
+ await this.planner.stop();
9156
9608
  }
9157
9609
  async resolveDependencies(parentId, table) {
9158
9610
  const stmt = this.properties.db.statements.get(resolveChildrenStatement(table));
@@ -9163,33 +9615,40 @@ var SQLLiteIndex = class {
9163
9615
  async get(id, options) {
9164
9616
  for (const table of this._rootTables) {
9165
9617
  const { join: joinMap, selects } = selectAllFieldsFromTable(table, options?.shape);
9166
- const sql = `${generateSelectQuery(table, selects)} ${buildJoin(joinMap, true)} where ${this.primaryKeyString} = ? limit 1`;
9167
- const stmt = await this.properties.db.prepare(sql, sql);
9168
- const rows = await stmt.get([
9169
- table.primaryField?.from?.type ? convertToSQLType(id.key, table.primaryField.from.type) : id.key
9170
- ]);
9171
- if (!rows) {
9172
- continue;
9618
+ const sql = `${generateSelectQuery(table, selects)} ${buildJoin(joinMap).join} where ${this.primaryKeyString} = ? limit 1`;
9619
+ try {
9620
+ const stmt = await this.properties.db.prepare(sql, sql);
9621
+ const rows = await stmt.get([
9622
+ table.primaryField?.from?.type ? convertToSQLType(id.key, table.primaryField.from.type) : id.key
9623
+ ]);
9624
+ if (rows?.[getTablePrefixedField(table, table.primary)] == null) {
9625
+ continue;
9626
+ }
9627
+ return {
9628
+ value: await resolveInstanceFromValue(rows, this.tables, table, this.resolveDependencies.bind(this), true, options?.shape),
9629
+ id
9630
+ };
9631
+ } catch (error2) {
9632
+ if (this.closed) {
9633
+ throw new NotStartedError();
9634
+ }
9635
+ throw error2;
9173
9636
  }
9174
- return {
9175
- value: await resolveInstanceFromValue(rows, this.tables, table, this.resolveDependencies.bind(this), true, options?.shape),
9176
- id
9177
- };
9178
9637
  }
9179
9638
  return void 0;
9180
9639
  }
9181
9640
  async put(value, _id) {
9182
9641
  const classOfValue = value.constructor;
9183
9642
  return insert(async (values, table) => {
9184
- const preId = values[table.primaryIndex];
9643
+ let preId = values[table.primaryIndex];
9185
9644
  if (preId != null) {
9186
9645
  const statement = this.properties.db.statements.get(replaceStatementKey(table));
9187
- await statement.run(values.map((x) => typeof x === "boolean" ? x ? 1 : 0 : x));
9646
+ await statement.run(values);
9188
9647
  await statement.reset?.();
9189
9648
  return preId;
9190
9649
  } else {
9191
9650
  const statement = this.properties.db.statements.get(putStatementKey(table));
9192
- const out = await statement.get(values.map((x) => typeof x === "boolean" ? x ? 1 : 0 : x));
9651
+ const out = await statement.get(values);
9193
9652
  await statement.reset?.();
9194
9653
  if (out == null) {
9195
9654
  return void 0;
@@ -9209,26 +9668,35 @@ var SQLLiteIndex = class {
9209
9668
  let kept = void 0;
9210
9669
  let bindable = [];
9211
9670
  let sqlFetch = void 0;
9671
+ const normalizedQuery = new PlannableQuery({
9672
+ query: toQuery(request?.query),
9673
+ sort: request?.sort
9674
+ });
9675
+ let planningScope;
9212
9676
  const fetch2 = async (amount) => {
9213
9677
  kept = void 0;
9214
9678
  if (!once) {
9215
- let { sql, bindable: toBind } = convertSearchRequestToQuery(request, this.tables, this._rootTables, {
9679
+ planningScope = this.planner.scope(normalizedQuery);
9680
+ let { sql, bindable: toBind } = convertSearchRequestToQuery(normalizedQuery, this.tables, this._rootTables, {
9681
+ planner: planningScope,
9216
9682
  shape: options?.shape,
9217
- stable: typeof amount === "number"
9683
+ fetchAll: amount === "all"
9218
9684
  // if we are to fetch all, we dont need stable sorting
9219
9685
  });
9220
9686
  sqlFetch = sql;
9221
9687
  bindable = toBind;
9688
+ await planningScope.beforePrepare();
9222
9689
  stmt = await this.properties.db.prepare(sqlFetch, sqlFetch);
9223
- clearTimeout(iterator.timeout);
9224
- iterator.timeout = setTimeout(() => this.clearupIterator(requestId), this.iteratorTimeout);
9690
+ iterator.expire = Date.now() + this.iteratorTimeout;
9225
9691
  }
9226
9692
  once = true;
9227
- const allResults = await stmt.all([
9228
- ...bindable,
9229
- amount === "all" ? Number.MAX_SAFE_INTEGER : amount,
9230
- offset
9231
- ]);
9693
+ const allResults = await planningScope.perform(async () => {
9694
+ const allResults2 = await stmt.all([
9695
+ ...bindable,
9696
+ ...amount !== "all" ? [amount, offset] : []
9697
+ ]);
9698
+ return allResults2;
9699
+ });
9232
9700
  let results = await Promise.all(allResults.map(async (row) => {
9233
9701
  let selectedTable = this._rootTables.find((table) => row[getTablePrefixedField(table, this.primaryKeyString)] != null);
9234
9702
  const value = await resolveInstanceFromValue(row, this.tables, selectedTable, this.resolveDependencies.bind(this), true, options?.shape);
@@ -9241,14 +9709,13 @@ var SQLLiteIndex = class {
9241
9709
  if (amount === "all" || results.length < amount) {
9242
9710
  hasMore = false;
9243
9711
  await this.clearupIterator(requestId);
9244
- clearTimeout(iterator.timeout);
9245
9712
  }
9246
9713
  return results;
9247
9714
  };
9248
9715
  const iterator = {
9249
9716
  fetch: fetch2,
9250
9717
  /* countStatement: countStmt, */
9251
- timeout: setTimeout(() => this.clearupIterator(requestId), this.iteratorTimeout)
9718
+ expire: Date.now() + this.iteratorTimeout
9252
9719
  };
9253
9720
  this.cursor.set(requestId, iterator);
9254
9721
  let totalCount = void 0;
@@ -9256,9 +9723,9 @@ var SQLLiteIndex = class {
9256
9723
  all: async () => {
9257
9724
  const results = [];
9258
9725
  while (true) {
9259
- const res = await fetch2(100);
9726
+ const res = await fetch2("all");
9260
9727
  results.push(...res);
9261
- if (res.length === 0) {
9728
+ if (hasMore === false) {
9262
9729
  break;
9263
9730
  }
9264
9731
  }
@@ -9290,7 +9757,6 @@ var SQLLiteIndex = class {
9290
9757
  if (!cache) {
9291
9758
  return;
9292
9759
  }
9293
- clearTimeout(cache.timeout);
9294
9760
  this._cursor.delete(id);
9295
9761
  }
9296
9762
  async getSize() {
@@ -9460,8 +9926,15 @@ var SQLiteIndices = class _SQLiteIndices {
9460
9926
  for (const scope of this.scopes.values()) {
9461
9927
  await scope.drop();
9462
9928
  }
9463
- for (const index of this.indices) {
9464
- await index.index.drop();
9929
+ if (!this.properties.parent) {
9930
+ for (const index of this.indices) {
9931
+ await index.index.stop();
9932
+ }
9933
+ await this.properties.db.drop();
9934
+ } else {
9935
+ for (const index of this.indices) {
9936
+ await index.index.drop();
9937
+ }
9465
9938
  }
9466
9939
  this.scopes.clear();
9467
9940
  }
@@ -17428,10 +17901,10 @@ var sqlite3InitModule = (() => {
17428
17901
  });
17429
17902
  globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite32) {
17430
17903
  sqlite32.version = {
17431
- libVersion: "3.47.0",
17432
- libVersionNumber: 3047e3,
17433
- sourceId: "2024-10-21 16:30:22 03a9703e27c44437c39363d0baf82db4ebc94538a0f28411c85dda156f82636e",
17434
- downloadVersion: 347e4
17904
+ libVersion: "3.47.2",
17905
+ libVersionNumber: 3047002,
17906
+ sourceId: "2024-12-07 20:39:59 2aabe05e2e8cae4847a802ee2daddc1d7413d8fc560254d93ee3e72c14685b6c",
17907
+ downloadVersion: 3470200
17435
17908
  };
17436
17909
  });
17437
17910
  globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite32) {
@@ -20951,13 +21424,20 @@ var create = async (directory) => {
20951
21424
  await sqliteDb?.close();
20952
21425
  sqliteDb = void 0;
20953
21426
  };
21427
+ let dbFileName;
21428
+ let drop = async () => {
21429
+ if (poolUtil && dbFileName != null) {
21430
+ poolUtil.unlink(dbFileName);
21431
+ }
21432
+ return close();
21433
+ };
20954
21434
  let open = async () => {
20955
21435
  if (sqliteDb) {
20956
21436
  return sqliteDb;
20957
21437
  }
20958
21438
  if (directory) {
20959
21439
  directory = directory.replace(/^\./, "");
20960
- let dbFileName = `${directory}/db.sqlite`;
21440
+ dbFileName = `${directory}/db.sqlite`;
20961
21441
  poolUtil = poolUtil || await sqlite3.installOpfsSAHPoolVfs({
20962
21442
  directory: "peerbit/sqlite"
20963
21443
  // encodeName("peerbit")
@@ -20976,6 +21456,7 @@ var create = async (directory) => {
20976
21456
  return sqliteDb.exec(sql);
20977
21457
  },
20978
21458
  open,
21459
+ drop,
20979
21460
  prepare: async (sql, id) => {
20980
21461
  if (id == null) {
20981
21462
  id = v4_default();
@@ -21127,6 +21608,13 @@ var ProxyDatabase = class {
21127
21608
  databaseId: this.databaseId
21128
21609
  });
21129
21610
  }
21611
+ async drop() {
21612
+ return this.send({
21613
+ type: "drop",
21614
+ id: v4_default(),
21615
+ databaseId: this.databaseId
21616
+ });
21617
+ }
21130
21618
  async status() {
21131
21619
  return this.send({
21132
21620
  type: "status",