json-fs-query 3.2.0 → 3.3.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 (121) hide show
  1. package/README.md +257 -15
  2. package/browser/jsonFsQuery.js +2253 -293
  3. package/browser/jsonFsQuery.min.js +1 -1
  4. package/dist/data/introspect/alter.d.ts +12 -0
  5. package/dist/data/introspect/alter.js +304 -0
  6. package/dist/data/introspect/alter.min.js +1 -0
  7. package/dist/data/introspect/create.d.ts +10 -0
  8. package/dist/data/introspect/create.js +2 -1
  9. package/dist/data/introspect/create.min.js +1 -1
  10. package/dist/data/introspect/drop.js +2 -0
  11. package/dist/data/introspect/drop.min.js +1 -1
  12. package/dist/data/introspect/formatDatabase.d.ts +17 -0
  13. package/dist/data/introspect/formatDatabase.js +56 -0
  14. package/dist/data/introspect/formatDatabase.min.js +1 -0
  15. package/dist/data/introspect/index.d.ts +9 -0
  16. package/dist/data/introspect/index.js +18 -5
  17. package/dist/data/introspect/index.min.js +1 -1
  18. package/dist/data/introspect/packDatabase.d.ts +27 -0
  19. package/dist/data/introspect/packDatabase.js +113 -0
  20. package/dist/data/introspect/packDatabase.min.js +1 -0
  21. package/dist/data/queries/databaseStatements.d.ts +31 -0
  22. package/dist/data/queries/databaseStatements.js +97 -0
  23. package/dist/data/queries/databaseStatements.min.js +1 -0
  24. package/dist/data/queries/deleteEntity.js +6 -1
  25. package/dist/data/queries/deleteEntity.min.js +1 -1
  26. package/dist/data/queries/insertEntity.d.ts +8 -0
  27. package/dist/data/queries/insertEntity.js +338 -33
  28. package/dist/data/queries/insertEntity.min.js +1 -1
  29. package/dist/data/queries/query.d.ts +2 -1
  30. package/dist/data/queries/query.js +5 -2
  31. package/dist/data/queries/query.min.js +1 -1
  32. package/dist/data/queries/selectFields.d.ts +5 -4
  33. package/dist/data/queries/selectFields.js +25 -11
  34. package/dist/data/queries/selectFields.min.js +1 -1
  35. package/dist/data/queries/updateEntity.js +39 -5
  36. package/dist/data/queries/updateEntity.min.js +1 -1
  37. package/dist/data/storage/databases.d.ts +32 -0
  38. package/dist/data/storage/databases.js +93 -0
  39. package/dist/data/storage/databases.min.js +1 -0
  40. package/dist/data/storage/fileExists.d.ts +2 -1
  41. package/dist/data/storage/fileExists.js +9 -2
  42. package/dist/data/storage/fileExists.min.js +1 -1
  43. package/dist/data/storage/index.d.ts +5 -2
  44. package/dist/data/storage/index.js +64 -1
  45. package/dist/data/storage/index.min.js +1 -1
  46. package/dist/data/storage/listFiles.d.ts +8 -0
  47. package/dist/data/storage/listFiles.js +52 -0
  48. package/dist/data/storage/listFiles.min.js +1 -0
  49. package/dist/data/storage/makeDirectory.d.ts +2 -1
  50. package/dist/data/storage/makeDirectory.js +8 -2
  51. package/dist/data/storage/makeDirectory.min.js +1 -1
  52. package/dist/data/storage/readJson.d.ts +9 -1
  53. package/dist/data/storage/readJson.js +20 -7
  54. package/dist/data/storage/readJson.min.js +1 -1
  55. package/dist/data/storage/removeDirectory.d.ts +3 -1
  56. package/dist/data/storage/removeDirectory.js +7 -1
  57. package/dist/data/storage/removeDirectory.min.js +1 -1
  58. package/dist/data/storage/removeFile.d.ts +2 -1
  59. package/dist/data/storage/removeFile.js +10 -1
  60. package/dist/data/storage/removeFile.min.js +1 -1
  61. package/dist/data/storage/storagePath.js +1 -1
  62. package/dist/data/storage/storagePath.min.js +1 -1
  63. package/dist/data/storage/writeJson.d.ts +12 -3
  64. package/dist/data/storage/writeJson.js +21 -7
  65. package/dist/data/storage/writeJson.min.js +1 -1
  66. package/dist/data/storage/writeSet.d.ts +64 -0
  67. package/dist/data/storage/writeSet.js +306 -0
  68. package/dist/data/storage/writeSet.min.js +1 -0
  69. package/dist/data/utilities/config.d.ts +37 -0
  70. package/dist/data/utilities/config.js +77 -5
  71. package/dist/data/utilities/config.min.js +1 -1
  72. package/dist/data/utilities/databaseLock.d.ts +5 -0
  73. package/dist/data/utilities/databaseLock.js +15 -3
  74. package/dist/data/utilities/databaseLock.min.js +1 -1
  75. package/dist/data/utilities/getConditionIndexedList.js +3 -4
  76. package/dist/data/utilities/getConditionIndexedList.min.js +1 -1
  77. package/dist/data/utilities/indexBuffer.d.ts +35 -0
  78. package/dist/data/utilities/indexBuffer.js +139 -0
  79. package/dist/data/utilities/indexBuffer.min.js +1 -0
  80. package/dist/data/utilities/joinBases.js +2 -10
  81. package/dist/data/utilities/joinBases.min.js +1 -1
  82. package/dist/data/utilities/knownFields.d.ts +26 -0
  83. package/dist/data/utilities/knownFields.js +128 -0
  84. package/dist/data/utilities/knownFields.min.js +1 -0
  85. package/dist/data/utilities/packedTable.d.ts +34 -0
  86. package/dist/data/utilities/packedTable.js +60 -0
  87. package/dist/data/utilities/packedTable.min.js +1 -0
  88. package/dist/data/utilities/parsers/findInsertValues.d.ts +3 -3
  89. package/dist/data/utilities/parsers/findInsertValues.js +28 -12
  90. package/dist/data/utilities/parsers/findInsertValues.min.js +1 -1
  91. package/dist/data/utilities/parsers/maskStrings.js +11 -2
  92. package/dist/data/utilities/parsers/maskStrings.min.js +1 -1
  93. package/dist/data/utilities/parsers/parseAlter.d.ts +33 -0
  94. package/dist/data/utilities/parsers/parseAlter.js +84 -0
  95. package/dist/data/utilities/parsers/parseAlter.min.js +1 -0
  96. package/dist/data/utilities/parsers/parseCreate.d.ts +14 -0
  97. package/dist/data/utilities/parsers/parseCreate.js +13 -5
  98. package/dist/data/utilities/parsers/parseCreate.min.js +1 -1
  99. package/dist/data/utilities/parsers/parseDatabaseStatement.d.ts +17 -0
  100. package/dist/data/utilities/parsers/parseDatabaseStatement.js +82 -0
  101. package/dist/data/utilities/parsers/parseDatabaseStatement.min.js +1 -0
  102. package/dist/data/utilities/parsers/parseQuery.d.ts +3 -0
  103. package/dist/data/utilities/parsers/parseQuery.js +24 -0
  104. package/dist/data/utilities/parsers/parseQuery.min.js +1 -1
  105. package/dist/data/utilities/parsers/startsQuery.js +1 -1
  106. package/dist/data/utilities/parsers/startsQuery.min.js +1 -1
  107. package/dist/data/utilities/retrieveFiles.d.ts +15 -0
  108. package/dist/data/utilities/retrieveFiles.js +48 -0
  109. package/dist/data/utilities/retrieveFiles.min.js +1 -0
  110. package/dist/data/utilities/retrieveRecord.d.ts +6 -0
  111. package/dist/data/utilities/retrieveRecord.js +24 -1
  112. package/dist/data/utilities/retrieveRecord.min.js +1 -1
  113. package/dist/data/utilities/retrieveRecords.d.ts +22 -0
  114. package/dist/data/utilities/retrieveRecords.js +60 -10
  115. package/dist/data/utilities/retrieveRecords.min.js +1 -1
  116. package/dist/data/utilities/runQuery.js +27 -2
  117. package/dist/data/utilities/runQuery.min.js +1 -1
  118. package/dist/index.d.ts +1 -1
  119. package/dist/index.js +24 -0
  120. package/dist/index.min.js +1 -1
  121. package/package.json +7 -3
@@ -3375,11 +3375,18 @@ var jsonFsQuery = (() => {
3375
3375
  }
3376
3376
  }
3377
3377
  }
3378
- return strings.reduceRight((masked, {
3378
+ const parts = [];
3379
+ let copied = 0;
3380
+ for (const {
3379
3381
  start,
3380
3382
  end,
3381
3383
  value
3382
- }) => `${masked.slice(0, start)}\0${toHex(value)}\0${masked.slice(end)}`, query);
3384
+ } of strings) {
3385
+ parts.push(query.slice(copied, start), `\0${toHex(value)}\0`);
3386
+ copied = end;
3387
+ }
3388
+ parts.push(query.slice(copied));
3389
+ return parts.join("");
3383
3390
  };
3384
3391
  exports.maskStrings = maskStrings;
3385
3392
  var unmaskStrings = (text, quote = "json") => text.replace(placeholderMatch, (placeholder, hex) => {
@@ -3486,20 +3493,31 @@ var jsonFsQuery = (() => {
3486
3493
  var _parseLiteralValue = require_parseLiteralValue();
3487
3494
  var _maskStrings = require_maskStrings();
3488
3495
  var literal = `(?:${_maskStrings.placeholderSource.replace("(", "(?:")}|${_parseLiteralValue.numberSource}|${_maskStrings.arraySource.replace("(", "(?:")}|null|true|false)`;
3489
- var valuesMatch = new RegExp(`^([a-z0-9_-]+\\s*=\\s*${literal}(?:\\s*,\\s*[a-z0-9_-]+\\s*=\\s*${literal})*)`, "i");
3496
+ var assignments = `[a-z0-9_-]+\\s*=\\s*${literal}(?:\\s*,\\s*[a-z0-9_-]+\\s*=\\s*${literal})*`;
3497
+ var valuesMatch = new RegExp(`^(${assignments})`, "i");
3498
+ var rowSource = `\\(\\s*(${assignments})\\s*\\)`;
3499
+ var rowsMatch = new RegExp(`^${rowSource}(?:\\s*,\\s*${rowSource.replace("(" + assignments, "(?:" + assignments)})*`, "i");
3500
+ var rowMatch = new RegExp(rowSource, "ig");
3490
3501
  var assignmentMatch = new RegExp(`([a-z0-9_-]+)\\s*=\\s*(${_maskStrings.placeholderSource}|(${_parseLiteralValue.numberSource})|${_maskStrings.arraySource}|(null)|(true)|(false))`, "ig");
3502
+ var parseRow = (assignments2) => {
3503
+ const row = {};
3504
+ for (const assignment of assignments2.matchAll(assignmentMatch)) {
3505
+ row[assignment[1]] = (0, _parseLiteralValue.parseLiteralValue)(assignment, 3);
3506
+ }
3507
+ return row;
3508
+ };
3491
3509
  var findInsertValues = (parsed, body) => {
3492
- const clauseFound = body.match(valuesMatch);
3493
3510
  parsed["insertValues"] = [];
3511
+ const rowsFound = body.match(rowsMatch);
3512
+ if (rowsFound) {
3513
+ parsed["insertValues"] = [...rowsFound[0].matchAll(rowMatch)].map((row) => parseRow(row[1]));
3514
+ return body.slice(rowsFound[0].length).trim();
3515
+ }
3516
+ const clauseFound = body.match(valuesMatch);
3494
3517
  if (!clauseFound) {
3495
3518
  return body;
3496
3519
  }
3497
- const row = {};
3498
- const assignmentsFound = clauseFound[1].matchAll(assignmentMatch);
3499
- for (const assignment of assignmentsFound) {
3500
- row[assignment[1]] = (0, _parseLiteralValue.parseLiteralValue)(assignment, 3);
3501
- }
3502
- parsed["insertValues"] = [row];
3520
+ parsed["insertValues"] = [parseRow(clauseFound[1])];
3503
3521
  return body.slice(clauseFound[0].length).trim();
3504
3522
  };
3505
3523
  exports.findInsertValues = findInsertValues;
@@ -5022,7 +5040,7 @@ var jsonFsQuery = (() => {
5022
5040
  value: true
5023
5041
  });
5024
5042
  exports.startsQueryMatch = void 0;
5025
- var startsQueryMatch = exports.startsQueryMatch = /^\s*(create|delete|describe|drop|insert|read|show|update)(?![a-z0-9_-])/i;
5043
+ var startsQueryMatch = exports.startsQueryMatch = /^\s*(alter|create|delete|describe|drop|insert|read|show|update|use)(?![a-z0-9_-])/i;
5026
5044
  }
5027
5045
  });
5028
5046
 
@@ -5034,7 +5052,7 @@ var jsonFsQuery = (() => {
5034
5052
  Object.defineProperty(exports, "__esModule", {
5035
5053
  value: true
5036
5054
  });
5037
- exports.parseCreate = exports.createMatch = void 0;
5055
+ exports.parseField = exports.parseCreate = exports.nameSource = exports.nameMatch = exports.keyLookup = exports.fieldMatch = exports.createMatch = void 0;
5038
5056
  require_es_array_includes();
5039
5057
  require_esnext_iterator_constructor();
5040
5058
  require_esnext_iterator_filter();
@@ -5063,10 +5081,10 @@ var jsonFsQuery = (() => {
5063
5081
  var _startsQuery = require_startsQuery();
5064
5082
  var createMatch = exports.createMatch = /^\s*create(?![a-z0-9_-])/i;
5065
5083
  var headMatch = /^\s*create\s+(if\s+not\s+exists\s+)?([a-z0-9_-]+)\s*\(/i;
5066
- var nameSource = "[a-z0-9_-]+";
5067
- var nameMatch = new RegExp(`^${nameSource}$`, "i");
5084
+ var nameSource = exports.nameSource = "[a-z0-9_-]+";
5085
+ var nameMatch = exports.nameMatch = new RegExp(`^${nameSource}$`, "i");
5068
5086
  var numberMatch = new RegExp(`^${_parseLiteralValue.numberSource}$`, "i");
5069
- var fieldMatch = new RegExp(`^(${nameSource})\\s+(${nameSource})((?:\\s[\\s\\S]*)?)$`, "i");
5087
+ var fieldMatch = exports.fieldMatch = new RegExp(`^(${nameSource})\\s+(${nameSource})((?:\\s[\\s\\S]*)?)$`, "i");
5070
5088
  var primaryMatch = /^primary\s+key\s*\(([^()]*)\)$/i;
5071
5089
  var uniqueMatch = /^unique\s*\(([^()]*)\)$/i;
5072
5090
  var indexMatch = /^index\s*\(([^()]*)\)$/i;
@@ -5079,6 +5097,8 @@ var jsonFsQuery = (() => {
5079
5097
  index: "index",
5080
5098
  foreign: "fk"
5081
5099
  };
5100
+ var keyLookup = (type, fields) => `${lookupPrefix[type]}_${fields.join("_")}.json`;
5101
+ exports.keyLookup = keyLookup;
5082
5102
  var shown = (text) => (0, _maskStrings.unmaskStrings)(text.trim(), "'");
5083
5103
  var findClose = (text, open) => {
5084
5104
  let depth = 0;
@@ -5197,6 +5217,7 @@ var jsonFsQuery = (() => {
5197
5217
  }
5198
5218
  return field;
5199
5219
  };
5220
+ exports.parseField = parseField;
5200
5221
  var parseKey = (item) => {
5201
5222
  let found = item.match(primaryMatch);
5202
5223
  if (found) {
@@ -5248,7 +5269,7 @@ var jsonFsQuery = (() => {
5248
5269
  if (missing) {
5249
5270
  throw new Error(`The ${key.type} key (${key.fields.join(", ")}) names "${missing}", which is not a field`);
5250
5271
  }
5251
- const lookup = `${lookupPrefix[key.type]}_${key.fields.join("_")}.json`;
5272
+ const lookup = keyLookup(key.type, key.fields);
5252
5273
  if (lookups.has(lookup)) {
5253
5274
  throw new Error(`The same ${key.type} key on "${key.fields.join(", ")}" is given twice`);
5254
5275
  }
@@ -5394,6 +5415,162 @@ var jsonFsQuery = (() => {
5394
5415
  }
5395
5416
  });
5396
5417
 
5418
+ // dist/data/utilities/parsers/parseAlter.js
5419
+ var require_parseAlter = __commonJS({
5420
+ "dist/data/utilities/parsers/parseAlter.js"(exports) {
5421
+ "use strict";
5422
+ init_process();
5423
+ Object.defineProperty(exports, "__esModule", {
5424
+ value: true
5425
+ });
5426
+ exports.parseAlter = exports.alterMatch = void 0;
5427
+ var _parseCreate = require_parseCreate();
5428
+ var _maskStrings = require_maskStrings();
5429
+ var _startsQuery = require_startsQuery();
5430
+ var alterMatch = exports.alterMatch = /^\s*alter(?![a-z0-9_-])/i;
5431
+ var headMatch = new RegExp(`^\\s*alter\\s+(${_parseCreate.nameSource})\\s+(add|drop|rename|modify)(?![a-z0-9_-])([\\s\\S]*)$`, "i");
5432
+ var renameMatch = new RegExp(`^\\s*(${_parseCreate.nameSource})\\s+to\\s+(${_parseCreate.nameSource})\\s*$`, "i");
5433
+ var expected = "Expected: alter <record> add <field> <type> ..., drop <field>, rename <field> to <name>, or modify <field> <type> ...";
5434
+ var shown = (text) => (0, _maskStrings.unmaskStrings)(text.trim(), "'");
5435
+ var fieldSpec = (text) => {
5436
+ const found = text.trim().match(_parseCreate.fieldMatch);
5437
+ if (!found) {
5438
+ throw new Error(`Expected a field (<name> <type> ...) in: ${shown(text)}`);
5439
+ }
5440
+ return (0, _parseCreate.parseField)(found);
5441
+ };
5442
+ var parseAlter = (query) => {
5443
+ const head = query.match(headMatch);
5444
+ if (!head) {
5445
+ throw new Error(expected);
5446
+ }
5447
+ const [, entity, actionWord, rest] = head;
5448
+ if (entity === "__RECORDS") {
5449
+ throw new Error("__RECORDS is reserved for the list of records");
5450
+ }
5451
+ const action = actionWord.toLowerCase();
5452
+ if (_startsQuery.startsQueryMatch.test(rest.trim()) && !/^\s*(add|drop|rename|modify)\b/i.test(rest)) {
5453
+ throw new Error(`Missing ; before: ${shown(rest)}`);
5454
+ }
5455
+ switch (action) {
5456
+ case "add":
5457
+ case "modify":
5458
+ return {
5459
+ entity,
5460
+ alter: {
5461
+ action,
5462
+ field: fieldSpec(rest)
5463
+ }
5464
+ };
5465
+ case "drop": {
5466
+ const name = rest.trim();
5467
+ if (!_parseCreate.nameMatch.test(name)) {
5468
+ throw new Error(`Expected: alter ${entity} drop <field>${name ? ` (got: ${shown(name)})` : ""}`);
5469
+ }
5470
+ return {
5471
+ entity,
5472
+ alter: {
5473
+ action,
5474
+ name
5475
+ }
5476
+ };
5477
+ }
5478
+ default: {
5479
+ const found = rest.match(renameMatch);
5480
+ if (!found) {
5481
+ throw new Error(`Expected: alter ${entity} rename <field> to <name>${rest.trim() ? ` (got: ${shown(rest)})` : ""}`);
5482
+ }
5483
+ return {
5484
+ entity,
5485
+ alter: {
5486
+ action: "rename",
5487
+ name: found[1],
5488
+ to: found[2]
5489
+ }
5490
+ };
5491
+ }
5492
+ }
5493
+ };
5494
+ exports.parseAlter = parseAlter;
5495
+ }
5496
+ });
5497
+
5498
+ // dist/data/utilities/parsers/parseDatabaseStatement.js
5499
+ var require_parseDatabaseStatement = __commonJS({
5500
+ "dist/data/utilities/parsers/parseDatabaseStatement.js"(exports) {
5501
+ "use strict";
5502
+ init_process();
5503
+ Object.defineProperty(exports, "__esModule", {
5504
+ value: true
5505
+ });
5506
+ exports.parseDatabaseStatement = exports.databaseStatementMatch = void 0;
5507
+ var _maskStrings = require_maskStrings();
5508
+ var _startsQuery = require_startsQuery();
5509
+ var databaseStatementMatch = exports.databaseStatementMatch = /^\s*(?:(?:create|drop)\s+database\s+(?!\()[a-z0-9_-]|show\s+databases(?![a-z0-9_-])|use(?![a-z0-9_.-]))/i;
5510
+ var createMatch = /^\s*create\s+database\s+(if\s+not\s+exists\s+)?([a-z0-9_-]+)/i;
5511
+ var dropMatch = /^\s*drop\s+database\s+(if\s+exists\s+)?([a-z0-9_-]+)/i;
5512
+ var useMatch = /^\s*use\s+([a-z0-9_-]+)/i;
5513
+ var showMatch = /^\s*show\s+databases/i;
5514
+ var assertNothingAfter = (rest) => {
5515
+ const after = rest.trim();
5516
+ if (!after) {
5517
+ return;
5518
+ }
5519
+ const shown = (0, _maskStrings.unmaskStrings)(after, "'");
5520
+ if (_startsQuery.startsQueryMatch.test(after)) {
5521
+ throw new Error(`Missing ; before: ${shown}`);
5522
+ }
5523
+ throw new Error(`Unrecognized query value: ${shown}`);
5524
+ };
5525
+ var parseDatabaseStatement = (query) => {
5526
+ const statement = {
5527
+ ifExists: false,
5528
+ ifNotExists: false
5529
+ };
5530
+ let found = query.match(createMatch);
5531
+ if (found) {
5532
+ assertNothingAfter(query.slice(found[0].length));
5533
+ return {
5534
+ ...statement,
5535
+ command: "create database",
5536
+ entity: found[2],
5537
+ ifNotExists: Boolean(found[1])
5538
+ };
5539
+ }
5540
+ found = query.match(dropMatch);
5541
+ if (found) {
5542
+ assertNothingAfter(query.slice(found[0].length));
5543
+ return {
5544
+ ...statement,
5545
+ command: "drop database",
5546
+ entity: found[2],
5547
+ ifExists: Boolean(found[1])
5548
+ };
5549
+ }
5550
+ found = query.match(showMatch);
5551
+ if (found) {
5552
+ assertNothingAfter(query.slice(found[0].length));
5553
+ return {
5554
+ ...statement,
5555
+ command: "show databases",
5556
+ entity: "__DATABASES"
5557
+ };
5558
+ }
5559
+ found = query.match(useMatch);
5560
+ if (!found) {
5561
+ throw new Error("Expected: use <database>");
5562
+ }
5563
+ assertNothingAfter(query.slice(found[0].length));
5564
+ return {
5565
+ ...statement,
5566
+ command: "use",
5567
+ entity: found[1]
5568
+ };
5569
+ };
5570
+ exports.parseDatabaseStatement = parseDatabaseStatement;
5571
+ }
5572
+ });
5573
+
5397
5574
  // dist/data/utilities/parsers/parseQuery.js
5398
5575
  var require_parseQuery = __commonJS({
5399
5576
  "dist/data/utilities/parsers/parseQuery.js"(exports) {
@@ -5419,6 +5596,8 @@ var jsonFsQuery = (() => {
5419
5596
  var _maskStrings = require_maskStrings();
5420
5597
  var _parseCreate = require_parseCreate();
5421
5598
  var _parseSchemaStatement = require_parseSchemaStatement();
5599
+ var _parseAlter = require_parseAlter();
5600
+ var _parseDatabaseStatement = require_parseDatabaseStatement();
5422
5601
  var _splitClauses = require_splitClauses();
5423
5602
  var _startsQuery = require_startsQuery();
5424
5603
  var clauseSteps = {
@@ -5489,6 +5668,9 @@ var jsonFsQuery = (() => {
5489
5668
  ifExists: void 0
5490
5669
  };
5491
5670
  query = (0, _maskStrings.maskArrays)((0, _maskStrings.maskStrings)(query));
5671
+ if (_parseDatabaseStatement.databaseStatementMatch.test(query)) {
5672
+ return Object.assign(parsedQuery, (0, _parseDatabaseStatement.parseDatabaseStatement)(query));
5673
+ }
5492
5674
  if (_parseCreate.createMatch.test(query)) {
5493
5675
  const {
5494
5676
  entity,
@@ -5503,6 +5685,17 @@ var jsonFsQuery = (() => {
5503
5685
  if (_parseSchemaStatement.schemaStatementMatch.test(query)) {
5504
5686
  return Object.assign(parsedQuery, (0, _parseSchemaStatement.parseSchemaStatement)(query));
5505
5687
  }
5688
+ if (_parseAlter.alterMatch.test(query)) {
5689
+ const {
5690
+ entity,
5691
+ alter
5692
+ } = (0, _parseAlter.parseAlter)(query);
5693
+ return Object.assign(parsedQuery, {
5694
+ command: "alter",
5695
+ entity,
5696
+ alter
5697
+ });
5698
+ }
5506
5699
  const split = (0, _splitClauses.splitClauses)(query);
5507
5700
  if (!split) {
5508
5701
  query = query.trim();
@@ -5532,6 +5725,9 @@ var jsonFsQuery = (() => {
5532
5725
  throw leftoverError(rest, `${keyword} ${body.slice(0, body.length - rest.length).trim()}`);
5533
5726
  }
5534
5727
  }
5728
+ if ((parsedQuery.joinClauses || []).length && !parsedQuery.joinEntity) {
5729
+ throw new Error(`"on" needs the record to join, after the one read: ${parsedQuery.command} ${parsedQuery.entity}.<record> on ...`);
5730
+ }
5535
5731
  return parsedQuery;
5536
5732
  };
5537
5733
  exports.parseQuery = parseQuery;
@@ -6086,16 +6282,39 @@ var jsonFsQuery = (() => {
6086
6282
  Object.defineProperty(exports, "__esModule", {
6087
6283
  value: true
6088
6284
  });
6089
- exports.trackDatabaseCall = exports.resolveDatabasePath = exports.getSetting = exports.configure = void 0;
6285
+ exports.trackDatabaseCall = exports.switchDatabase = exports.resolveDatabasePath = exports.lockPath = exports.getSetting = exports.databasesFolder = exports.configure = exports.activeDatabasePath = void 0;
6286
+ require_es_json_stringify();
6090
6287
  var defaults = {
6091
6288
  databasePath: "database/",
6092
6289
  relativePath: "",
6093
- enforceForeignKeys: true
6290
+ enforceForeignKeys: true,
6291
+ readConcurrency: 16,
6292
+ format: "compact"
6094
6293
  };
6095
6294
  var settings = {
6096
6295
  ...defaults
6097
6296
  };
6098
6297
  var activeCalls = 0;
6298
+ var databaseNameMatch = /^[a-z0-9_-]+$/i;
6299
+ var withSlash = (path) => path.endsWith("/") ? path : `${path}/`;
6300
+ var activeDatabasePath = () => settings.databasesPath && settings.database ? `${withSlash(settings.databasesPath)}${settings.database}/` : getSetting("databasePath", "database/");
6301
+ exports.activeDatabasePath = activeDatabasePath;
6302
+ var lockPath = () => settings.databasesPath ? withSlash(settings.databasesPath) : activeDatabasePath();
6303
+ exports.lockPath = lockPath;
6304
+ var databasesFolder = () => {
6305
+ if (!settings.databasesPath) {
6306
+ throw new Error("Several databases need a folder to hold them: configure({ databasesPath: 'databases/' }) first");
6307
+ }
6308
+ return withSlash(settings.databasesPath);
6309
+ };
6310
+ exports.databasesFolder = databasesFolder;
6311
+ var switchDatabase = (name) => {
6312
+ settings = {
6313
+ ...settings,
6314
+ database: name
6315
+ };
6316
+ };
6317
+ exports.switchDatabase = switchDatabase;
6099
6318
  var resolveDatabasePath = (databasePath) => require_path_browserify().resolve(databasePath);
6100
6319
  exports.resolveDatabasePath = resolveDatabasePath;
6101
6320
  var trackDatabaseCall = () => {
@@ -6110,13 +6329,34 @@ var jsonFsQuery = (() => {
6110
6329
  };
6111
6330
  exports.trackDatabaseCall = trackDatabaseCall;
6112
6331
  var configure = (newSettings) => {
6113
- if (activeCalls > 0 && typeof newSettings.databasePath !== "undefined" && resolveDatabasePath(newSettings.databasePath) !== resolveDatabasePath(settings.databasePath)) {
6114
- throw new Error(`Can't change databasePath while ${activeCalls} database call(s) are still running or queued: await them first`);
6332
+ if (typeof newSettings.format !== "undefined" && newSettings.format !== "compact" && newSettings.format !== "pretty") {
6333
+ throw new Error(`Unknown format "${newSettings.format}": use 'compact' or 'pretty'`);
6115
6334
  }
6116
- settings = {
6335
+ if (typeof newSettings.database !== "undefined" && newSettings.database !== null && !databaseNameMatch.test(newSettings.database)) {
6336
+ throw new Error(`Invalid database name ${JSON.stringify(newSettings.database)}: names use letters, digits, _ and - only`);
6337
+ }
6338
+ const next = {
6117
6339
  ...settings,
6118
6340
  ...newSettings
6119
6341
  };
6342
+ if (next.database && !next.databasesPath) {
6343
+ throw new Error("A database name needs the folder that holds the databases: configure({ databasesPath: 'databases/', database: '...' })");
6344
+ }
6345
+ if (activeCalls > 0) {
6346
+ const before = {
6347
+ active: resolveDatabasePath(activeDatabasePath()),
6348
+ lock: resolveDatabasePath(lockPath())
6349
+ };
6350
+ const previous = settings;
6351
+ settings = next;
6352
+ const changed = resolveDatabasePath(activeDatabasePath()) !== before.active || resolveDatabasePath(lockPath()) !== before.lock;
6353
+ settings = previous;
6354
+ if (changed) {
6355
+ const named = ["databasePath", "databasesPath", "database"].filter((key) => typeof newSettings[key] !== "undefined").join(" / ");
6356
+ throw new Error(`Can't change ${named} while ${activeCalls} database call(s) are still running or queued: await them first`);
6357
+ }
6358
+ }
6359
+ settings = next;
6120
6360
  };
6121
6361
  exports.configure = configure;
6122
6362
  var getSetting = (key, defaultValue) => {
@@ -6152,7 +6392,7 @@ var jsonFsQuery = (() => {
6152
6392
  }
6153
6393
  var storagePath = (path = "") => {
6154
6394
  const relativePath = jsEnv.isBrowser ? (0, _config.getSetting)("relativePath", "") : "";
6155
- return `${relativePath}${(0, _config.getSetting)("databasePath", "database/")}${path}`;
6395
+ return `${relativePath}${(0, _config.activeDatabasePath)()}${path}`;
6156
6396
  };
6157
6397
  exports.storagePath = storagePath;
6158
6398
  }
@@ -6644,6 +6884,248 @@ var jsonFsQuery = (() => {
6644
6884
  }
6645
6885
  });
6646
6886
 
6887
+ // dist/data/storage/writeSet.js
6888
+ var require_writeSet = __commonJS({
6889
+ "dist/data/storage/writeSet.js"(exports) {
6890
+ "use strict";
6891
+ init_process();
6892
+ require_esnext_weak_map_delete_all();
6893
+ Object.defineProperty(exports, "__esModule", {
6894
+ value: true
6895
+ });
6896
+ exports.writeAtomically = exports.withWriteSet = exports.stageWrite = exports.stageRemoveDirectory = exports.stageRemove = exports.stageMakeDirectory = exports.pendingListing = exports.pendingFile = exports.pendingExists = void 0;
6897
+ require_esnext_iterator_constructor();
6898
+ require_esnext_iterator_filter();
6899
+ require_esnext_map_delete_all();
6900
+ require_esnext_map_every();
6901
+ require_esnext_map_filter();
6902
+ require_esnext_map_find();
6903
+ require_esnext_map_find_key();
6904
+ require_esnext_map_includes();
6905
+ require_esnext_map_key_of();
6906
+ require_esnext_map_map_keys();
6907
+ require_esnext_map_map_values();
6908
+ require_esnext_map_merge();
6909
+ require_esnext_map_reduce();
6910
+ require_esnext_map_some();
6911
+ require_esnext_map_update();
6912
+ require_esnext_set_add_all();
6913
+ require_esnext_set_delete_all();
6914
+ require_esnext_set_difference();
6915
+ require_esnext_set_every();
6916
+ require_esnext_set_filter();
6917
+ require_esnext_set_find();
6918
+ require_esnext_set_intersection();
6919
+ require_esnext_set_is_disjoint_from();
6920
+ require_esnext_set_is_subset_of();
6921
+ require_esnext_set_is_superset_of();
6922
+ require_esnext_set_join();
6923
+ require_esnext_set_map();
6924
+ require_esnext_set_reduce();
6925
+ require_esnext_set_some();
6926
+ require_esnext_set_symmetric_difference();
6927
+ require_esnext_set_union();
6928
+ var jsEnv = _interopRequireWildcard(require_dist());
6929
+ var _storagePath = require_storagePath();
6930
+ var _nodeFiles = require_nodeFiles();
6931
+ var _readCache = require_readCache();
6932
+ var e;
6933
+ function _interopRequireWildcard(t, r) {
6934
+ if (!r && t && t.__esModule) return t;
6935
+ var n, a, o = Object.defineProperty, f = { __proto__: null, default: t };
6936
+ if (Object(t) !== t) return f;
6937
+ if (e || "function" != typeof WeakMap || (e = /* @__PURE__ */ new WeakMap()), e) {
6938
+ if (e.has(t)) return e.get(t);
6939
+ e.set(t, f);
6940
+ }
6941
+ for (a in t) "default" !== a && {}.hasOwnProperty.call(t, a) && ((n = o && Object.getOwnPropertyDescriptor(t, a)) && (n.get || n.set) ? o(f, a, n) : f[a] = t[a]);
6942
+ return f;
6943
+ }
6944
+ var writeSets = /* @__PURE__ */ new Map();
6945
+ var currentWriteSet = () => writeSets.get((0, _storagePath.storagePath)());
6946
+ var folderPrefix = (location) => location.endsWith("/") ? location : `${location}/`;
6947
+ var insideAny = (location, folders) => {
6948
+ for (const folder of folders) {
6949
+ if (location === folder || location.startsWith(folderPrefix(folder))) {
6950
+ return true;
6951
+ }
6952
+ }
6953
+ return false;
6954
+ };
6955
+ var writeAtomically = async (location, text) => {
6956
+ const temporary = `${location}.${crypto.randomUUID()}.tmp`;
6957
+ const files = (0, _nodeFiles.nodeFiles)();
6958
+ try {
6959
+ await files.writeFile(temporary, text);
6960
+ await files.rename(temporary, location);
6961
+ } catch (error) {
6962
+ await files.rm(temporary, {
6963
+ force: true
6964
+ }).catch(() => void 0);
6965
+ throw error;
6966
+ }
6967
+ };
6968
+ exports.writeAtomically = writeAtomically;
6969
+ var removeFolder = async (location) => {
6970
+ (0, _readCache.cacheRemove)(location, true);
6971
+ await (0, _nodeFiles.nodeFiles)().rm(location, {
6972
+ recursive: true,
6973
+ force: true
6974
+ });
6975
+ (0, _readCache.cacheRemove)(location, true);
6976
+ };
6977
+ var commit = async (writeSet) => {
6978
+ const files = (0, _nodeFiles.nodeFiles)();
6979
+ const writtenInto = (folder) => {
6980
+ const prefix = folderPrefix(folder);
6981
+ return [...writeSet.madeFolders].some((made) => made === folder || made.startsWith(prefix)) || [...writeSet.files].some(([location, text]) => text !== null && location.startsWith(prefix));
6982
+ };
6983
+ const removedFolders = [...writeSet.removedFolders];
6984
+ for (const folder of removedFolders.filter(writtenInto)) {
6985
+ await removeFolder(folder);
6986
+ }
6987
+ for (const folder of writeSet.madeFolders) {
6988
+ await files.mkdir(folder, {
6989
+ recursive: true
6990
+ });
6991
+ }
6992
+ for (const [location, text] of writeSet.files) {
6993
+ if (text !== null) {
6994
+ await writeAtomically(location, text);
6995
+ (0, _readCache.cacheWrite)(location, text);
6996
+ }
6997
+ }
6998
+ for (const [location, text] of writeSet.files) {
6999
+ if (text === null) {
7000
+ (0, _readCache.cacheRemove)(location);
7001
+ await files.rm(location, {
7002
+ force: true
7003
+ });
7004
+ (0, _readCache.cacheRemove)(location);
7005
+ }
7006
+ }
7007
+ for (const folder of removedFolders.filter((folder2) => !writtenInto(folder2))) {
7008
+ await removeFolder(folder);
7009
+ }
7010
+ };
7011
+ var withWriteSet = async (task) => {
7012
+ const database = (0, _storagePath.storagePath)();
7013
+ if (!jsEnv.isNode || writeSets.has(database)) {
7014
+ return task();
7015
+ }
7016
+ const writeSet = {
7017
+ files: /* @__PURE__ */ new Map(),
7018
+ madeFolders: /* @__PURE__ */ new Set(),
7019
+ removedFolders: /* @__PURE__ */ new Set()
7020
+ };
7021
+ writeSets.set(database, writeSet);
7022
+ let result;
7023
+ try {
7024
+ result = await task();
7025
+ } finally {
7026
+ writeSets.delete(database);
7027
+ }
7028
+ await commit(writeSet);
7029
+ return result;
7030
+ };
7031
+ exports.withWriteSet = withWriteSet;
7032
+ var pendingFile = (location) => {
7033
+ const writeSet = currentWriteSet();
7034
+ if (!writeSet) {
7035
+ return void 0;
7036
+ }
7037
+ if (writeSet.files.has(location)) {
7038
+ return writeSet.files.get(location);
7039
+ }
7040
+ return insideAny(location, writeSet.removedFolders) ? null : void 0;
7041
+ };
7042
+ exports.pendingFile = pendingFile;
7043
+ var pendingExists = (location) => {
7044
+ const writeSet = currentWriteSet();
7045
+ if (!writeSet) {
7046
+ return void 0;
7047
+ }
7048
+ if (writeSet.files.has(location)) {
7049
+ return writeSet.files.get(location) !== null;
7050
+ }
7051
+ const prefix = folderPrefix(location);
7052
+ const madeInside = (path) => path === location || path.startsWith(prefix);
7053
+ if ([...writeSet.madeFolders].some(madeInside) || [...writeSet.files].some(([path, text]) => text !== null && path.startsWith(prefix))) {
7054
+ return true;
7055
+ }
7056
+ return insideAny(location, writeSet.removedFolders) ? false : void 0;
7057
+ };
7058
+ exports.pendingExists = pendingExists;
7059
+ var pendingListing = (folder, onDisk) => {
7060
+ const writeSet = currentWriteSet();
7061
+ if (!writeSet) {
7062
+ return onDisk;
7063
+ }
7064
+ const prefix = folderPrefix(folder);
7065
+ const listed = new Set(onDisk.filter((location) => !insideAny(location, writeSet.removedFolders)));
7066
+ for (const [location, text] of writeSet.files) {
7067
+ if (location.startsWith(prefix)) {
7068
+ if (text === null) {
7069
+ listed.delete(location);
7070
+ } else {
7071
+ listed.add(location);
7072
+ }
7073
+ }
7074
+ }
7075
+ return [...listed];
7076
+ };
7077
+ exports.pendingListing = pendingListing;
7078
+ var stageWrite = (location, text) => {
7079
+ const writeSet = currentWriteSet();
7080
+ if (!writeSet) {
7081
+ return false;
7082
+ }
7083
+ writeSet.files.delete(location);
7084
+ writeSet.files.set(location, text);
7085
+ return true;
7086
+ };
7087
+ exports.stageWrite = stageWrite;
7088
+ var stageRemove = (location) => {
7089
+ const writeSet = currentWriteSet();
7090
+ if (!writeSet) {
7091
+ return false;
7092
+ }
7093
+ writeSet.files.delete(location);
7094
+ writeSet.files.set(location, null);
7095
+ return true;
7096
+ };
7097
+ exports.stageRemove = stageRemove;
7098
+ var stageMakeDirectory = (location) => {
7099
+ const writeSet = currentWriteSet();
7100
+ if (!writeSet) {
7101
+ return false;
7102
+ }
7103
+ writeSet.madeFolders.add(location);
7104
+ return true;
7105
+ };
7106
+ exports.stageMakeDirectory = stageMakeDirectory;
7107
+ var stageRemoveDirectory = (location) => {
7108
+ const writeSet = currentWriteSet();
7109
+ if (!writeSet) {
7110
+ return false;
7111
+ }
7112
+ for (const file of [...writeSet.files.keys()]) {
7113
+ if (insideAny(file, /* @__PURE__ */ new Set([location]))) {
7114
+ writeSet.files.delete(file);
7115
+ }
7116
+ }
7117
+ for (const folder of [...writeSet.madeFolders]) {
7118
+ if (insideAny(folder, /* @__PURE__ */ new Set([location]))) {
7119
+ writeSet.madeFolders.delete(folder);
7120
+ }
7121
+ }
7122
+ writeSet.removedFolders.add(location);
7123
+ return true;
7124
+ };
7125
+ exports.stageRemoveDirectory = stageRemoveDirectory;
7126
+ }
7127
+ });
7128
+
6647
7129
  // dist/data/storage/readJson.js
6648
7130
  var require_readJson = __commonJS({
6649
7131
  "dist/data/storage/readJson.js"(exports) {
@@ -6653,11 +7135,12 @@ var jsonFsQuery = (() => {
6653
7135
  Object.defineProperty(exports, "__esModule", {
6654
7136
  value: true
6655
7137
  });
6656
- exports.readJson = void 0;
7138
+ exports.readText = exports.readJson = void 0;
6657
7139
  var jsEnv = _interopRequireWildcard(require_dist());
6658
7140
  var _storagePath = require_storagePath();
6659
7141
  var _nodeFiles = require_nodeFiles();
6660
7142
  var _readCache = require_readCache();
7143
+ var _writeSet = require_writeSet();
6661
7144
  var e;
6662
7145
  function _interopRequireWildcard(t, r) {
6663
7146
  if (!r && t && t.__esModule) return t;
@@ -6670,11 +7153,16 @@ var jsonFsQuery = (() => {
6670
7153
  for (a in t) "default" !== a && {}.hasOwnProperty.call(t, a) && ((n = o && Object.getOwnPropertyDescriptor(t, a)) && (n.get || n.set) ? o(f, a, n) : f[a] = t[a]);
6671
7154
  return f;
6672
7155
  }
6673
- var readJson = async (path) => {
7156
+ var readText = async (path) => {
6674
7157
  const location = (0, _storagePath.storagePath)(path);
6675
- const text = await (0, _readCache.cachedRead)(location, () => jsEnv.isNode ? (0, _nodeFiles.nodeFiles)().readFile(location, "utf8") : fetch(location).then((response) => response.text()));
6676
- return JSON.parse(text);
7158
+ const pending = (0, _writeSet.pendingFile)(location);
7159
+ if (pending === null) {
7160
+ throw new Error(`ENOENT: no such file or directory, open '${location}' (deleted by this statement)`);
7161
+ }
7162
+ return typeof pending === "string" ? pending : (0, _readCache.cachedRead)(location, () => jsEnv.isNode ? (0, _nodeFiles.nodeFiles)().readFile(location, "utf8") : fetch(location).then((response) => response.text()));
6677
7163
  };
7164
+ exports.readText = readText;
7165
+ var readJson = async (path) => JSON.parse(await readText(path));
6678
7166
  exports.readJson = readJson;
6679
7167
  }
6680
7168
  });
@@ -6687,15 +7175,21 @@ var jsonFsQuery = (() => {
6687
7175
  Object.defineProperty(exports, "__esModule", {
6688
7176
  value: true
6689
7177
  });
6690
- exports.writeJson = void 0;
7178
+ exports.writeJson = exports.jsonText = void 0;
6691
7179
  require_es_json_stringify();
6692
7180
  var _storagePath = require_storagePath();
6693
- var _nodeFiles = require_nodeFiles();
6694
7181
  var _readCache = require_readCache();
6695
- var writeJson = async (path, content) => {
7182
+ var _writeSet = require_writeSet();
7183
+ var _config = require_config();
7184
+ var jsonText = (content, format = (0, _config.getSetting)("format", "compact")) => format === "pretty" ? JSON.stringify(content, null, 2) : JSON.stringify(content);
7185
+ exports.jsonText = jsonText;
7186
+ var writeJson = async (path, content, format) => {
6696
7187
  const location = (0, _storagePath.storagePath)(path);
6697
- const text = JSON.stringify(content, null, 2);
6698
- await (0, _nodeFiles.nodeFiles)().writeFile(location, text);
7188
+ const text = jsonText(content, format);
7189
+ if ((0, _writeSet.stageWrite)(location, text)) {
7190
+ return;
7191
+ }
7192
+ await (0, _writeSet.writeAtomically)(location, text);
6699
7193
  (0, _readCache.cacheWrite)(location, text);
6700
7194
  };
6701
7195
  exports.writeJson = writeJson;
@@ -6713,8 +7207,13 @@ var jsonFsQuery = (() => {
6713
7207
  exports.makeDirectory = void 0;
6714
7208
  var _storagePath = require_storagePath();
6715
7209
  var _nodeFiles = require_nodeFiles();
7210
+ var _writeSet = require_writeSet();
6716
7211
  var makeDirectory = async (path = "") => {
6717
- await (0, _nodeFiles.nodeFiles)().mkdir((0, _storagePath.storagePath)(path), {
7212
+ const location = (0, _storagePath.storagePath)(path);
7213
+ if ((0, _writeSet.stageMakeDirectory)(location)) {
7214
+ return;
7215
+ }
7216
+ await (0, _nodeFiles.nodeFiles)().mkdir(location, {
6718
7217
  recursive: true
6719
7218
  });
6720
7219
  };
@@ -6722,6 +7221,14 @@ var jsonFsQuery = (() => {
6722
7221
  }
6723
7222
  });
6724
7223
 
7224
+ // js-build-tools-empty:fs
7225
+ var require_fs = __commonJS({
7226
+ "js-build-tools-empty:fs"(exports, module) {
7227
+ init_process();
7228
+ module.exports = {};
7229
+ }
7230
+ });
7231
+
6725
7232
  // dist/data/storage/removeFile.js
6726
7233
  var require_removeFile = __commonJS({
6727
7234
  "dist/data/storage/removeFile.js"(exports) {
@@ -6734,8 +7241,16 @@ var jsonFsQuery = (() => {
6734
7241
  var _storagePath = require_storagePath();
6735
7242
  var _nodeFiles = require_nodeFiles();
6736
7243
  var _readCache = require_readCache();
7244
+ var _writeSet = require_writeSet();
6737
7245
  var removeFile = async (path) => {
6738
7246
  const location = (0, _storagePath.storagePath)(path);
7247
+ const pending = (0, _writeSet.pendingFile)(location);
7248
+ if (pending === null || pending === void 0 && !require_fs().existsSync(location)) {
7249
+ throw new Error(`ENOENT: no such file or directory, rm '${location}'`);
7250
+ }
7251
+ if ((0, _writeSet.stageRemove)(location)) {
7252
+ return;
7253
+ }
6739
7254
  (0, _readCache.cacheRemove)(location);
6740
7255
  await (0, _nodeFiles.nodeFiles)().rm(location);
6741
7256
  (0, _readCache.cacheRemove)(location);
@@ -6756,8 +7271,12 @@ var jsonFsQuery = (() => {
6756
7271
  var _storagePath = require_storagePath();
6757
7272
  var _nodeFiles = require_nodeFiles();
6758
7273
  var _readCache = require_readCache();
7274
+ var _writeSet = require_writeSet();
6759
7275
  var removeDirectory = async (path) => {
6760
7276
  const location = (0, _storagePath.storagePath)(path);
7277
+ if ((0, _writeSet.stageRemoveDirectory)(location)) {
7278
+ return;
7279
+ }
6761
7280
  (0, _readCache.cacheRemove)(location, true);
6762
7281
  await (0, _nodeFiles.nodeFiles)().rm(location, {
6763
7282
  recursive: true,
@@ -6769,14 +7288,6 @@ var jsonFsQuery = (() => {
6769
7288
  }
6770
7289
  });
6771
7290
 
6772
- // js-build-tools-empty:fs
6773
- var require_fs = __commonJS({
6774
- "js-build-tools-empty:fs"(exports, module) {
6775
- init_process();
6776
- module.exports = {};
6777
- }
6778
- });
6779
-
6780
7291
  // dist/data/storage/fileExists.js
6781
7292
  var require_fileExists = __commonJS({
6782
7293
  "dist/data/storage/fileExists.js"(exports) {
@@ -6787,16 +7298,151 @@ var jsonFsQuery = (() => {
6787
7298
  });
6788
7299
  exports.fileExists = void 0;
6789
7300
  var _storagePath = require_storagePath();
7301
+ var _writeSet = require_writeSet();
6790
7302
  var fileExists = (path) => {
7303
+ const location = (0, _storagePath.storagePath)(path);
7304
+ const pending = (0, _writeSet.pendingExists)(location);
7305
+ if (pending !== void 0) {
7306
+ return pending;
7307
+ }
6791
7308
  const {
6792
7309
  existsSync
6793
7310
  } = require_fs();
6794
- return existsSync((0, _storagePath.storagePath)(path));
7311
+ return existsSync(location);
6795
7312
  };
6796
7313
  exports.fileExists = fileExists;
6797
7314
  }
6798
7315
  });
6799
7316
 
7317
+ // dist/data/storage/listFiles.js
7318
+ var require_listFiles = __commonJS({
7319
+ "dist/data/storage/listFiles.js"(exports) {
7320
+ "use strict";
7321
+ init_process();
7322
+ Object.defineProperty(exports, "__esModule", {
7323
+ value: true
7324
+ });
7325
+ exports.listFiles = void 0;
7326
+ require_esnext_iterator_constructor();
7327
+ require_esnext_iterator_map();
7328
+ var _storagePath = require_storagePath();
7329
+ var _nodeFiles = require_nodeFiles();
7330
+ var _writeSet = require_writeSet();
7331
+ var walk = async (base) => {
7332
+ let entries;
7333
+ try {
7334
+ entries = await (0, _nodeFiles.nodeFiles)().readdir((0, _storagePath.storagePath)(base), {
7335
+ withFileTypes: true
7336
+ });
7337
+ } catch (error) {
7338
+ if (error?.code === "ENOENT") {
7339
+ return [];
7340
+ }
7341
+ throw error;
7342
+ }
7343
+ const paths = [];
7344
+ for (const entry of entries) {
7345
+ if (entry.isDirectory()) {
7346
+ paths.push(...await walk(`${base}${entry.name}/`));
7347
+ } else if (entry.isFile()) {
7348
+ paths.push(`${base}${entry.name}`);
7349
+ }
7350
+ }
7351
+ return paths;
7352
+ };
7353
+ var listFiles = async (path = "") => {
7354
+ const base = path ? `${path.replace(/\/+$/, "")}/` : "";
7355
+ const onDisk = (await walk(base)).map((file) => (0, _storagePath.storagePath)(file));
7356
+ const root = (0, _storagePath.storagePath)();
7357
+ return (0, _writeSet.pendingListing)((0, _storagePath.storagePath)(path), onDisk).map((location) => location.slice(root.length)).sort();
7358
+ };
7359
+ exports.listFiles = listFiles;
7360
+ }
7361
+ });
7362
+
7363
+ // dist/data/storage/databases.js
7364
+ var require_databases = __commonJS({
7365
+ "dist/data/storage/databases.js"(exports) {
7366
+ "use strict";
7367
+ init_process();
7368
+ require_esnext_weak_map_delete_all();
7369
+ Object.defineProperty(exports, "__esModule", {
7370
+ value: true
7371
+ });
7372
+ exports.writeDatabaseList = exports.removeDatabaseFolder = exports.readDatabaseList = exports.makeDatabaseFolder = exports.databasesLocation = exports.databaseFolderExists = void 0;
7373
+ require_es_json_stringify();
7374
+ var jsEnv = _interopRequireWildcard(require_dist());
7375
+ var _config = require_config();
7376
+ var _nodeFiles = require_nodeFiles();
7377
+ var _readCache = require_readCache();
7378
+ var _writeSet = require_writeSet();
7379
+ var e;
7380
+ function _interopRequireWildcard(t, r) {
7381
+ if (!r && t && t.__esModule) return t;
7382
+ var n, a, o = Object.defineProperty, f = { __proto__: null, default: t };
7383
+ if (Object(t) !== t) return f;
7384
+ if (e || "function" != typeof WeakMap || (e = /* @__PURE__ */ new WeakMap()), e) {
7385
+ if (e.has(t)) return e.get(t);
7386
+ e.set(t, f);
7387
+ }
7388
+ for (a in t) "default" !== a && {}.hasOwnProperty.call(t, a) && ((n = o && Object.getOwnPropertyDescriptor(t, a)) && (n.get || n.set) ? o(f, a, n) : f[a] = t[a]);
7389
+ return f;
7390
+ }
7391
+ var databasesLocation = (path = "") => {
7392
+ const relativePath = jsEnv.isBrowser ? (0, _config.getSetting)("relativePath", "") : "";
7393
+ return `${relativePath}${(0, _config.databasesFolder)()}${path}`;
7394
+ };
7395
+ exports.databasesLocation = databasesLocation;
7396
+ var listLocation = () => databasesLocation("__DATABASES.json");
7397
+ var readDatabaseList = async () => {
7398
+ let text;
7399
+ try {
7400
+ text = jsEnv.isNode ? await (0, _nodeFiles.nodeFiles)().readFile(listLocation(), "utf8") : await fetch(listLocation()).then((response) => response.ok === false ? "[]" : response.text());
7401
+ } catch (error) {
7402
+ if (jsEnv.isNode && error?.code !== "ENOENT") {
7403
+ throw error;
7404
+ }
7405
+ return [];
7406
+ }
7407
+ try {
7408
+ const names = JSON.parse(text);
7409
+ return Array.isArray(names) ? names : [];
7410
+ } catch (error) {
7411
+ if (!jsEnv.isNode) {
7412
+ return [];
7413
+ }
7414
+ throw new Error(`Could not read ${listLocation()}: ${error.message}`);
7415
+ }
7416
+ };
7417
+ exports.readDatabaseList = readDatabaseList;
7418
+ var writeDatabaseList = async (names) => {
7419
+ await (0, _nodeFiles.nodeFiles)().mkdir(databasesLocation(), {
7420
+ recursive: true
7421
+ });
7422
+ await (0, _writeSet.writeAtomically)(listLocation(), JSON.stringify(names));
7423
+ };
7424
+ exports.writeDatabaseList = writeDatabaseList;
7425
+ var databaseFolderExists = (name) => require_fs().existsSync(databasesLocation(name));
7426
+ exports.databaseFolderExists = databaseFolderExists;
7427
+ var makeDatabaseFolder = async (name) => {
7428
+ await (0, _nodeFiles.nodeFiles)().mkdir(databasesLocation(name), {
7429
+ recursive: true
7430
+ });
7431
+ };
7432
+ exports.makeDatabaseFolder = makeDatabaseFolder;
7433
+ var removeDatabaseFolder = async (name) => {
7434
+ const location = databasesLocation(name);
7435
+ (0, _readCache.cacheRemove)(location, true);
7436
+ await (0, _nodeFiles.nodeFiles)().rm(location, {
7437
+ recursive: true,
7438
+ force: true
7439
+ });
7440
+ (0, _readCache.cacheRemove)(location, true);
7441
+ };
7442
+ exports.removeDatabaseFolder = removeDatabaseFolder;
7443
+ }
7444
+ });
7445
+
6800
7446
  // dist/data/storage/index.js
6801
7447
  var require_storage = __commonJS({
6802
7448
  "dist/data/storage/index.js"(exports) {
@@ -6805,24 +7451,72 @@ var jsonFsQuery = (() => {
6805
7451
  Object.defineProperty(exports, "__esModule", {
6806
7452
  value: true
6807
7453
  });
7454
+ Object.defineProperty(exports, "databaseFolderExists", {
7455
+ enumerable: true,
7456
+ get: function() {
7457
+ return _databases.databaseFolderExists;
7458
+ }
7459
+ });
7460
+ Object.defineProperty(exports, "databasesLocation", {
7461
+ enumerable: true,
7462
+ get: function() {
7463
+ return _databases.databasesLocation;
7464
+ }
7465
+ });
6808
7466
  Object.defineProperty(exports, "fileExists", {
6809
7467
  enumerable: true,
6810
7468
  get: function() {
6811
7469
  return _fileExists.fileExists;
6812
7470
  }
6813
7471
  });
7472
+ Object.defineProperty(exports, "jsonText", {
7473
+ enumerable: true,
7474
+ get: function() {
7475
+ return _writeJson.jsonText;
7476
+ }
7477
+ });
7478
+ Object.defineProperty(exports, "listFiles", {
7479
+ enumerable: true,
7480
+ get: function() {
7481
+ return _listFiles.listFiles;
7482
+ }
7483
+ });
7484
+ Object.defineProperty(exports, "makeDatabaseFolder", {
7485
+ enumerable: true,
7486
+ get: function() {
7487
+ return _databases.makeDatabaseFolder;
7488
+ }
7489
+ });
6814
7490
  Object.defineProperty(exports, "makeDirectory", {
6815
7491
  enumerable: true,
6816
7492
  get: function() {
6817
7493
  return _makeDirectory.makeDirectory;
6818
7494
  }
6819
7495
  });
7496
+ Object.defineProperty(exports, "readDatabaseList", {
7497
+ enumerable: true,
7498
+ get: function() {
7499
+ return _databases.readDatabaseList;
7500
+ }
7501
+ });
6820
7502
  Object.defineProperty(exports, "readJson", {
6821
7503
  enumerable: true,
6822
7504
  get: function() {
6823
7505
  return _readJson.readJson;
6824
7506
  }
6825
7507
  });
7508
+ Object.defineProperty(exports, "readText", {
7509
+ enumerable: true,
7510
+ get: function() {
7511
+ return _readJson.readText;
7512
+ }
7513
+ });
7514
+ Object.defineProperty(exports, "removeDatabaseFolder", {
7515
+ enumerable: true,
7516
+ get: function() {
7517
+ return _databases.removeDatabaseFolder;
7518
+ }
7519
+ });
6826
7520
  Object.defineProperty(exports, "removeDirectory", {
6827
7521
  enumerable: true,
6828
7522
  get: function() {
@@ -6847,6 +7541,18 @@ var jsonFsQuery = (() => {
6847
7541
  return _readCache.withReadCache;
6848
7542
  }
6849
7543
  });
7544
+ Object.defineProperty(exports, "withWriteSet", {
7545
+ enumerable: true,
7546
+ get: function() {
7547
+ return _writeSet.withWriteSet;
7548
+ }
7549
+ });
7550
+ Object.defineProperty(exports, "writeDatabaseList", {
7551
+ enumerable: true,
7552
+ get: function() {
7553
+ return _databases.writeDatabaseList;
7554
+ }
7555
+ });
6850
7556
  Object.defineProperty(exports, "writeJson", {
6851
7557
  enumerable: true,
6852
7558
  get: function() {
@@ -6860,7 +7566,10 @@ var jsonFsQuery = (() => {
6860
7566
  var _removeFile = require_removeFile();
6861
7567
  var _removeDirectory = require_removeDirectory();
6862
7568
  var _fileExists = require_fileExists();
7569
+ var _listFiles = require_listFiles();
7570
+ var _databases = require_databases();
6863
7571
  var _readCache = require_readCache();
7572
+ var _writeSet = require_writeSet();
6864
7573
  }
6865
7574
  });
6866
7575
 
@@ -6885,17 +7594,59 @@ var jsonFsQuery = (() => {
6885
7594
  }
6886
7595
  });
6887
7596
 
7597
+ // dist/data/utilities/recordExists.js
7598
+ var require_recordExists = __commonJS({
7599
+ "dist/data/utilities/recordExists.js"(exports) {
7600
+ "use strict";
7601
+ init_process();
7602
+ Object.defineProperty(exports, "__esModule", {
7603
+ value: true
7604
+ });
7605
+ exports.recordExists = void 0;
7606
+ var _storage = require_storage();
7607
+ var recordExists = (entity) => (0, _storage.fileExists)(`${entity}.json`);
7608
+ exports.recordExists = recordExists;
7609
+ }
7610
+ });
7611
+
6888
7612
  // dist/data/utilities/retrieveRecord.js
6889
7613
  var require_retrieveRecord = __commonJS({
6890
7614
  "dist/data/utilities/retrieveRecord.js"(exports) {
6891
7615
  "use strict";
6892
7616
  init_process();
7617
+ require_esnext_weak_map_delete_all();
6893
7618
  Object.defineProperty(exports, "__esModule", {
6894
7619
  value: true
6895
7620
  });
6896
7621
  exports.retrieveRecord = void 0;
7622
+ var jsEnv = _interopRequireWildcard(require_dist());
6897
7623
  var _retrieveFile = require_retrieveFile();
6898
- var retrieveRecord = async (entity = "") => await (0, _retrieveFile.retrieveFile)(`${entity}.json`);
7624
+ var _recordExists = require_recordExists();
7625
+ var e;
7626
+ function _interopRequireWildcard(t, r) {
7627
+ if (!r && t && t.__esModule) return t;
7628
+ var n, a, o = Object.defineProperty, f = { __proto__: null, default: t };
7629
+ if (Object(t) !== t) return f;
7630
+ if (e || "function" != typeof WeakMap || (e = /* @__PURE__ */ new WeakMap()), e) {
7631
+ if (e.has(t)) return e.get(t);
7632
+ e.set(t, f);
7633
+ }
7634
+ for (a in t) "default" !== a && {}.hasOwnProperty.call(t, a) && ((n = o && Object.getOwnPropertyDescriptor(t, a)) && (n.get || n.set) ? o(f, a, n) : f[a] = t[a]);
7635
+ return f;
7636
+ }
7637
+ var retrieveRecord = async (entity = "") => {
7638
+ if (jsEnv.isNode && !(0, _recordExists.recordExists)(entity)) {
7639
+ throw new Error(`Record "${entity}" doesn't exist`);
7640
+ }
7641
+ try {
7642
+ return await (0, _retrieveFile.retrieveFile)(`${entity}.json`);
7643
+ } catch (error) {
7644
+ if (!jsEnv.isNode) {
7645
+ throw new Error(`Record "${entity}" doesn't exist, or ${entity}.json can't be read`);
7646
+ }
7647
+ throw error;
7648
+ }
7649
+ };
6899
7650
  exports.retrieveRecord = retrieveRecord;
6900
7651
  }
6901
7652
  });
@@ -7042,6 +7793,104 @@ var jsonFsQuery = (() => {
7042
7793
  }
7043
7794
  });
7044
7795
 
7796
+ // dist/data/utilities/retrieveFiles.js
7797
+ var require_retrieveFiles = __commonJS({
7798
+ "dist/data/utilities/retrieveFiles.js"(exports) {
7799
+ "use strict";
7800
+ init_process();
7801
+ Object.defineProperty(exports, "__esModule", {
7802
+ value: true
7803
+ });
7804
+ exports.retrieveFiles = void 0;
7805
+ var _retrieveFile = require_retrieveFile();
7806
+ var _config = require_config();
7807
+ var retrieveFiles = async (paths, read = _retrieveFile.retrieveFile) => {
7808
+ const limit = Math.max(1, Math.floor((0, _config.getSetting)("readConcurrency", 16)) || 1);
7809
+ const contents = new Array(paths.length);
7810
+ const failures = [];
7811
+ let next = 0;
7812
+ const worker = async () => {
7813
+ while (next < paths.length && !failures.length) {
7814
+ const position = next++;
7815
+ try {
7816
+ contents[position] = await read(paths[position]);
7817
+ } catch (error) {
7818
+ failures.push({
7819
+ position,
7820
+ error
7821
+ });
7822
+ }
7823
+ }
7824
+ };
7825
+ await Promise.all(Array.from({
7826
+ length: Math.min(limit, paths.length)
7827
+ }, worker));
7828
+ if (failures.length) {
7829
+ throw failures.reduce((first, failure) => failure.position < first.position ? failure : first).error;
7830
+ }
7831
+ return contents;
7832
+ };
7833
+ exports.retrieveFiles = retrieveFiles;
7834
+ }
7835
+ });
7836
+
7837
+ // dist/data/utilities/packedTable.js
7838
+ var require_packedTable = __commonJS({
7839
+ "dist/data/utilities/packedTable.js"(exports) {
7840
+ "use strict";
7841
+ init_process();
7842
+ require_esnext_weak_map_delete_all();
7843
+ Object.defineProperty(exports, "__esModule", {
7844
+ value: true
7845
+ });
7846
+ exports.usesPackedReads = exports.retrievePacked = exports.packedPath = exports.discardPacked = void 0;
7847
+ require_esnext_iterator_constructor();
7848
+ require_esnext_iterator_some();
7849
+ var jsEnv = _interopRequireWildcard(require_dist());
7850
+ var _storage = require_storage();
7851
+ var _config = require_config();
7852
+ var e;
7853
+ function _interopRequireWildcard(t, r) {
7854
+ if (!r && t && t.__esModule) return t;
7855
+ var n, a, o = Object.defineProperty, f = { __proto__: null, default: t };
7856
+ if (Object(t) !== t) return f;
7857
+ if (e || "function" != typeof WeakMap || (e = /* @__PURE__ */ new WeakMap()), e) {
7858
+ if (e.has(t)) return e.get(t);
7859
+ e.set(t, f);
7860
+ }
7861
+ for (a in t) "default" !== a && {}.hasOwnProperty.call(t, a) && ((n = o && Object.getOwnPropertyDescriptor(t, a)) && (n.get || n.set) ? o(f, a, n) : f[a] = t[a]);
7862
+ return f;
7863
+ }
7864
+ var packedPath = (recordPath) => `__packed/${recordPath}.json`;
7865
+ exports.packedPath = packedPath;
7866
+ var usesPackedReads = () => (0, _config.getSetting)("packedReads", !jsEnv.isNode);
7867
+ exports.usesPackedReads = usesPackedReads;
7868
+ var retrievePacked = async (record) => {
7869
+ if (!usesPackedReads()) {
7870
+ return void 0;
7871
+ }
7872
+ let packed;
7873
+ try {
7874
+ packed = await (0, _storage.readJson)(packedPath(record.path));
7875
+ } catch (error) {
7876
+ return void 0;
7877
+ }
7878
+ const entries = record.entries || [];
7879
+ if (!packed || !Array.isArray(packed.entries) || !Array.isArray(packed.rows) || packed.entries.length !== entries.length || packed.rows.length !== entries.length || packed.entries.some((entry, position) => entry !== entries[position])) {
7880
+ return void 0;
7881
+ }
7882
+ return packed;
7883
+ };
7884
+ exports.retrievePacked = retrievePacked;
7885
+ var discardPacked = async (recordPath) => {
7886
+ if ((0, _storage.fileExists)(packedPath(recordPath))) {
7887
+ await (0, _storage.removeFile)(packedPath(recordPath));
7888
+ }
7889
+ };
7890
+ exports.discardPacked = discardPacked;
7891
+ }
7892
+ });
7893
+
7045
7894
  // dist/data/utilities/retrieveRecords.js
7046
7895
  var require_retrieveRecords = __commonJS({
7047
7896
  "dist/data/utilities/retrieveRecords.js"(exports) {
@@ -7050,20 +7899,51 @@ var jsonFsQuery = (() => {
7050
7899
  Object.defineProperty(exports, "__esModule", {
7051
7900
  value: true
7052
7901
  });
7053
- exports.retrieveRecords = void 0;
7902
+ exports.retrieveRecords = exports.retrieveEntryRows = exports.retrieveEntry = void 0;
7903
+ require_esnext_iterator_constructor();
7904
+ require_esnext_iterator_filter();
7905
+ require_esnext_iterator_map();
7906
+ require_esnext_map_delete_all();
7907
+ require_esnext_map_every();
7908
+ require_esnext_map_filter();
7909
+ require_esnext_map_find();
7910
+ require_esnext_map_find_key();
7911
+ require_esnext_map_includes();
7912
+ require_esnext_map_key_of();
7913
+ require_esnext_map_map_keys();
7914
+ require_esnext_map_map_values();
7915
+ require_esnext_map_merge();
7916
+ require_esnext_map_reduce();
7917
+ require_esnext_map_some();
7918
+ require_esnext_map_update();
7054
7919
  var _retrieveFile = require_retrieveFile();
7055
7920
  var _retrieveRecord = require_retrieveRecord();
7921
+ var _retrieveFiles = require_retrieveFiles();
7922
+ var _packedTable = require_packedTable();
7923
+ var _config = require_config();
7924
+ var retrieveEntry = async (path) => {
7925
+ const data = await (0, _retrieveFile.retrieveFile)(path).catch((err) => console.error(err));
7926
+ if (!data) {
7927
+ throw new Error(`Could not read entity ${path.slice(path.lastIndexOf("/") + 1)}`);
7928
+ }
7929
+ return data;
7930
+ };
7931
+ exports.retrieveEntry = retrieveEntry;
7932
+ var retrieveEntryRows = async (record, files, read = retrieveEntry) => {
7933
+ const packed = files.length > (0, _config.getSetting)("readConcurrency", 16) ? await (0, _packedTable.retrievePacked)(record) : void 0;
7934
+ if (!packed) {
7935
+ return (0, _retrieveFiles.retrieveFiles)(files.map((file) => `${record.path}/${file}`), read);
7936
+ }
7937
+ const positions = new Map(packed.entries.map((entry, position) => [entry, position]));
7938
+ const unpacked = files.filter((file) => !positions.has(file));
7939
+ const readRows = unpacked.length ? await (0, _retrieveFiles.retrieveFiles)(unpacked.map((file) => `${record.path}/${file}`), read) : [];
7940
+ const fromFiles = new Map(unpacked.map((file, position) => [file, readRows[position]]));
7941
+ return files.map((file) => positions.has(file) ? packed.rows[positions.get(file)] : fromFiles.get(file));
7942
+ };
7943
+ exports.retrieveEntryRows = retrieveEntryRows;
7056
7944
  var retrieveRecords = async (entity = "") => {
7057
7945
  const recordFile = await (0, _retrieveRecord.retrieveRecord)(entity);
7058
- const dataSet = [];
7059
- for (const file of recordFile.entries) {
7060
- const data = await (0, _retrieveFile.retrieveFile)(`${recordFile.path}/${file}`).catch((err) => console.error(err));
7061
- if (!data) {
7062
- throw new Error(`Could not read entity ${file}`);
7063
- }
7064
- dataSet.push(data);
7065
- }
7066
- return dataSet;
7946
+ return retrieveEntryRows(recordFile, recordFile.entries);
7067
7947
  };
7068
7948
  exports.retrieveRecords = retrieveRecords;
7069
7949
  }
@@ -7482,6 +8362,7 @@ var jsonFsQuery = (() => {
7482
8362
  var _config = require_config();
7483
8363
  var _keyIndexFiles = require_keyIndexFiles();
7484
8364
  var _storage = require_storage();
8365
+ var _packedTable = require_packedTable();
7485
8366
  var assertNoDependents = async (entity, primaryKey, toDelete) => {
7486
8367
  if (!(0, _config.getSetting)("enforceForeignKeys", true) || primaryKey.fields.length !== 1) {
7487
8368
  return;
@@ -7531,7 +8412,11 @@ var jsonFsQuery = (() => {
7531
8412
  }
7532
8413
  await assertNoDependents(entity, primaryKey, toDelete);
7533
8414
  const deletedValues = new Set(toDelete.map((row) => (0, _computeKeyValue.computeKeyValue)(primaryKey.fields, row)));
7534
- record.entries = await removeMatchingEntries(entity, record, primaryKey, deletedValues);
8415
+ const remaining = await removeMatchingEntries(entity, record, primaryKey, deletedValues);
8416
+ if (remaining.length !== record.entries.length) {
8417
+ await (0, _packedTable.discardPacked)(record.path);
8418
+ }
8419
+ record.entries = remaining;
7535
8420
  await (0, _storage.writeJson)(`${record.path}.json`, record);
7536
8421
  return dataSet;
7537
8422
  };
@@ -7539,48 +8424,45 @@ var jsonFsQuery = (() => {
7539
8424
  }
7540
8425
  });
7541
8426
 
7542
- // dist/data/utilities/updateIndex.js
7543
- var require_updateIndex = __commonJS({
7544
- "dist/data/utilities/updateIndex.js"(exports) {
8427
+ // node_modules/core-js/modules/es.iterator.every.js
8428
+ var require_es_iterator_every = __commonJS({
8429
+ "node_modules/core-js/modules/es.iterator.every.js"() {
7545
8430
  "use strict";
7546
8431
  init_process();
7547
- Object.defineProperty(exports, "__esModule", {
7548
- value: true
7549
- });
7550
- exports.updateIndex = void 0;
7551
- require_es_array_includes();
7552
- require_esnext_iterator_constructor();
7553
- require_esnext_iterator_find();
7554
- var _compareAs = require_compareAs();
7555
- var _storage = require_storage();
7556
- var updateIndex = async (path = "", key = null, value = void 0, fileName = "", type = void 0) => {
7557
- if (!key || !key.lookup) {
7558
- return null;
7559
- }
7560
- const indexDir = `__indexes/${path}`;
7561
- const indexPath = `${indexDir}/${key.lookup}`;
7562
- let index = [];
7563
- try {
7564
- index = await (0, _storage.readJson)(indexPath);
7565
- } catch (err) {
7566
- index = [];
7567
- }
7568
- const existingEntry = index.find((entry) => (0, _compareAs.sameValue)(type, entry.value, value));
7569
- if (existingEntry) {
7570
- if (!existingEntry.record.includes(fileName)) {
7571
- existingEntry.record.push(fileName);
8432
+ var $ = require_export();
8433
+ var call = require_function_call();
8434
+ var iterate = require_iterate();
8435
+ var aCallable = require_a_callable();
8436
+ var anObject = require_an_object();
8437
+ var getIteratorDirect = require_get_iterator_direct();
8438
+ var iteratorClose = require_iterator_close();
8439
+ var iteratorHelperWithoutClosingOnEarlyError = require_iterator_helper_without_closing_on_early_error();
8440
+ var everyWithoutClosingOnEarlyError = iteratorHelperWithoutClosingOnEarlyError("every", TypeError);
8441
+ $({ target: "Iterator", proto: true, real: true, forced: everyWithoutClosingOnEarlyError }, {
8442
+ every: function every(predicate) {
8443
+ anObject(this);
8444
+ try {
8445
+ aCallable(predicate);
8446
+ } catch (error) {
8447
+ iteratorClose(this, "throw", error);
7572
8448
  }
7573
- } else {
7574
- index.push({
7575
- value,
7576
- record: [fileName]
7577
- });
8449
+ if (everyWithoutClosingOnEarlyError) return call(everyWithoutClosingOnEarlyError, this, predicate);
8450
+ var record = getIteratorDirect(this);
8451
+ var counter = 0;
8452
+ return !iterate(record, function(value, stop) {
8453
+ if (!predicate(value, counter++)) return stop();
8454
+ }, { IS_RECORD: true, INTERRUPTED: true }).stopped;
7578
8455
  }
7579
- await (0, _storage.makeDirectory)(indexDir);
7580
- await (0, _storage.writeJson)(indexPath, index);
7581
- return index;
7582
- };
7583
- exports.updateIndex = updateIndex;
8456
+ });
8457
+ }
8458
+ });
8459
+
8460
+ // node_modules/core-js/modules/esnext.iterator.every.js
8461
+ var require_esnext_iterator_every = __commonJS({
8462
+ "node_modules/core-js/modules/esnext.iterator.every.js"() {
8463
+ "use strict";
8464
+ init_process();
8465
+ require_es_iterator_every();
7584
8466
  }
7585
8467
  });
7586
8468
 
@@ -7624,29 +8506,6 @@ var jsonFsQuery = (() => {
7624
8506
  }
7625
8507
  });
7626
8508
 
7627
- // dist/data/introspect/policies/keyGenerate.js
7628
- var require_keyGenerate = __commonJS({
7629
- "dist/data/introspect/policies/keyGenerate.js"(exports) {
7630
- "use strict";
7631
- init_process();
7632
- Object.defineProperty(exports, "__esModule", {
7633
- value: true
7634
- });
7635
- exports.keyGenerate = void 0;
7636
- var _keyUnique = require_keyUnique();
7637
- var keyGenerate = async (entity, references = []) => {
7638
- let uuid = null;
7639
- let isUnique = false;
7640
- while (!isUnique) {
7641
- uuid = crypto.randomUUID();
7642
- isUnique = await (0, _keyUnique.keyUnique)(entity, references, [uuid]);
7643
- }
7644
- return uuid;
7645
- };
7646
- exports.keyGenerate = keyGenerate;
7647
- }
7648
- });
7649
-
7650
8509
  // dist/data/introspect/policies/useDefault.js
7651
8510
  var require_useDefault = __commonJS({
7652
8511
  "dist/data/introspect/policies/useDefault.js"(exports) {
@@ -7698,6 +8557,253 @@ var jsonFsQuery = (() => {
7698
8557
  }
7699
8558
  });
7700
8559
 
8560
+ // dist/data/utilities/indexBuffer.js
8561
+ var require_indexBuffer = __commonJS({
8562
+ "dist/data/utilities/indexBuffer.js"(exports) {
8563
+ "use strict";
8564
+ init_process();
8565
+ Object.defineProperty(exports, "__esModule", {
8566
+ value: true
8567
+ });
8568
+ exports.IndexBuffer = void 0;
8569
+ require_es_array_includes();
8570
+ require_esnext_iterator_constructor();
8571
+ require_esnext_iterator_find();
8572
+ require_esnext_iterator_some();
8573
+ require_esnext_map_delete_all();
8574
+ require_esnext_map_every();
8575
+ require_esnext_map_filter();
8576
+ require_esnext_map_find();
8577
+ require_esnext_map_find_key();
8578
+ require_esnext_map_includes();
8579
+ require_esnext_map_key_of();
8580
+ require_esnext_map_map_keys();
8581
+ require_esnext_map_map_values();
8582
+ require_esnext_map_merge();
8583
+ require_esnext_map_reduce();
8584
+ require_esnext_map_some();
8585
+ require_esnext_map_update();
8586
+ require_esnext_set_add_all();
8587
+ require_esnext_set_delete_all();
8588
+ require_esnext_set_difference();
8589
+ require_esnext_set_every();
8590
+ require_esnext_set_filter();
8591
+ require_esnext_set_find();
8592
+ require_esnext_set_intersection();
8593
+ require_esnext_set_is_disjoint_from();
8594
+ require_esnext_set_is_subset_of();
8595
+ require_esnext_set_is_superset_of();
8596
+ require_esnext_set_join();
8597
+ require_esnext_set_map();
8598
+ require_esnext_set_reduce();
8599
+ require_esnext_set_some();
8600
+ require_esnext_set_symmetric_difference();
8601
+ require_esnext_set_union();
8602
+ require_esnext_weak_map_delete_all();
8603
+ var _compareAs = require_compareAs();
8604
+ var unkeyed = /* @__PURE__ */ Symbol("unkeyed");
8605
+ var keyOf = (type, value) => {
8606
+ if (!_compareAs.comparableTypes.includes(type)) {
8607
+ return unkeyed;
8608
+ }
8609
+ const key = (0, _compareAs.compareAs)(type, value);
8610
+ return typeof key === "object" && key !== null ? unkeyed : key;
8611
+ };
8612
+ var IndexBuffer = class {
8613
+ /**
8614
+ * @param entries - The index as read from its file ([] when there's none yet).
8615
+ * @param type - The key's value type (see keyValueType).
8616
+ */
8617
+ constructor(entries, type) {
8618
+ this.byKey = /* @__PURE__ */ new Map();
8619
+ this.listed = /* @__PURE__ */ new WeakMap();
8620
+ this.entries = entries;
8621
+ this.type = type;
8622
+ for (const entry of entries) {
8623
+ const key = keyOf(type, entry.value);
8624
+ if (key !== unkeyed && !this.byKey.has(key)) {
8625
+ this.byKey.set(key, entry);
8626
+ }
8627
+ }
8628
+ }
8629
+ /**
8630
+ * The entry for `value`, as updateIndex finds it.
8631
+ * @param value
8632
+ */
8633
+ find(value) {
8634
+ const key = keyOf(this.type, value);
8635
+ return key === unkeyed ? this.entries.find((entry) => (0, _compareAs.sameValue)(this.type, entry.value, value)) : this.byKey.get(key);
8636
+ }
8637
+ /**
8638
+ * Whether a row holds `value`, as indexHas answers it: an entry for it lists a file (never for null or undefined).
8639
+ * @param value
8640
+ */
8641
+ has(value) {
8642
+ if (value === null || typeof value === "undefined") {
8643
+ return false;
8644
+ }
8645
+ const listsFiles = (entry) => Boolean(entry && Array.isArray(entry.record) && entry.record.length);
8646
+ const first = this.find(value);
8647
+ if (!first || listsFiles(first)) {
8648
+ return listsFiles(first);
8649
+ }
8650
+ return this.entries.some((entry) => (0, _compareAs.sameValue)(this.type, entry.value, value) && listsFiles(entry));
8651
+ }
8652
+ /**
8653
+ * List `fileName` under `value`, as updateIndex does.
8654
+ * @param value
8655
+ * @param fileName
8656
+ */
8657
+ add(value, fileName) {
8658
+ const existing = this.find(value);
8659
+ if (existing) {
8660
+ if (!this.listed.has(existing)) {
8661
+ this.listed.set(existing, new Set(existing.record));
8662
+ }
8663
+ const files = this.listed.get(existing);
8664
+ if (!files.has(fileName)) {
8665
+ files.add(fileName);
8666
+ existing.record.push(fileName);
8667
+ }
8668
+ return;
8669
+ }
8670
+ const entry = {
8671
+ value,
8672
+ record: [fileName]
8673
+ };
8674
+ this.entries.push(entry);
8675
+ this.listed.set(entry, new Set(entry.record));
8676
+ const key = keyOf(this.type, value);
8677
+ if (key !== unkeyed) {
8678
+ this.byKey.set(key, entry);
8679
+ }
8680
+ }
8681
+ };
8682
+ exports.IndexBuffer = IndexBuffer;
8683
+ }
8684
+ });
8685
+
8686
+ // dist/data/utilities/parsers/isEntityProperty.js
8687
+ var require_isEntityProperty = __commonJS({
8688
+ "dist/data/utilities/parsers/isEntityProperty.js"(exports) {
8689
+ "use strict";
8690
+ init_process();
8691
+ Object.defineProperty(exports, "__esModule", {
8692
+ value: true
8693
+ });
8694
+ exports.isEntityProperty = void 0;
8695
+ var isEntityProperty = (property) => /^[a-z0-9_-]+\.([a-z0-9_-]+)$/i.test(property);
8696
+ exports.isEntityProperty = isEntityProperty;
8697
+ }
8698
+ });
8699
+
8700
+ // dist/data/utilities/knownFields.js
8701
+ var require_knownFields = __commonJS({
8702
+ "dist/data/utilities/knownFields.js"(exports) {
8703
+ "use strict";
8704
+ init_process();
8705
+ Object.defineProperty(exports, "__esModule", {
8706
+ value: true
8707
+ });
8708
+ exports.assertKnownFields = exports.assertFieldsDefined = void 0;
8709
+ require_esnext_iterator_constructor();
8710
+ require_esnext_iterator_filter();
8711
+ require_esnext_iterator_find();
8712
+ require_esnext_iterator_flat_map();
8713
+ require_esnext_iterator_map();
8714
+ require_esnext_set_add_all();
8715
+ require_esnext_set_delete_all();
8716
+ require_esnext_set_difference();
8717
+ require_esnext_set_every();
8718
+ require_esnext_set_filter();
8719
+ require_esnext_set_find();
8720
+ require_esnext_set_intersection();
8721
+ require_esnext_set_is_disjoint_from();
8722
+ require_esnext_set_is_subset_of();
8723
+ require_esnext_set_is_superset_of();
8724
+ require_esnext_set_join();
8725
+ require_esnext_set_map();
8726
+ require_esnext_set_reduce();
8727
+ require_esnext_set_some();
8728
+ require_esnext_set_symmetric_difference();
8729
+ require_esnext_set_union();
8730
+ var _retrieveRecord = require_retrieveRecord();
8731
+ var _isEntityProperty = require_isEntityProperty();
8732
+ var _splitEntityProperty = require_splitEntityProperty();
8733
+ var _conditionTree = require_conditionTree();
8734
+ var fieldList = (record) => record.definition.map((field) => field.name).join(", ");
8735
+ var assertFieldsDefined = (entity, record, fields, where) => {
8736
+ const defined = new Set(record.definition.map((field) => field.name));
8737
+ const unknown = fields.find((field) => !defined.has(field));
8738
+ if (typeof unknown !== "undefined") {
8739
+ throw new Error(`Unknown field "${unknown}" in ${where}: ${entity} has ${fieldList(record)}`);
8740
+ }
8741
+ };
8742
+ exports.assertFieldsDefined = assertFieldsDefined;
8743
+ var assertKnownFields = async (parsed, recordData) => {
8744
+ const merged = new Set((parsed.mergeJoins || []).map((merge) => (0, _splitEntityProperty.splitEntityProperty)(merge.propertyB).entity));
8745
+ const named = [...(0, _conditionTree.conditionsOf)(parsed.where).map((condition) => ({
8746
+ property: condition.property,
8747
+ clause: "where"
8748
+ })), ...(parsed.sortClauses || []).map((sort) => ({
8749
+ property: sort.property,
8750
+ clause: "sort"
8751
+ })), ...(parsed.groupBy || []).map((property) => ({
8752
+ property,
8753
+ clause: "group by"
8754
+ })), ...(parsed.selectClauses || []).filter((select) => select.property !== parsed.joinEntity).map((select) => ({
8755
+ property: select.property,
8756
+ clause: "select"
8757
+ })), ...(parsed.insertValues || []).flatMap((row) => Object.keys(row || {}).map((property) => ({
8758
+ property,
8759
+ clause: "insert",
8760
+ own: true
8761
+ }))), ...Object.keys(parsed.updateValues || {}).map((property) => ({
8762
+ property,
8763
+ clause: "set",
8764
+ own: true
8765
+ })), ...(parsed.joinClauses || []).flatMap((join) => [{
8766
+ property: join.propertyA,
8767
+ clause: "on"
8768
+ }, {
8769
+ property: join.propertyB,
8770
+ clause: "on"
8771
+ }]), ...(parsed.mergeJoins || []).flatMap((merge) => [{
8772
+ property: merge.propertyA,
8773
+ clause: "merge"
8774
+ }, {
8775
+ property: merge.propertyB,
8776
+ clause: "merge"
8777
+ }])];
8778
+ for (const {
8779
+ property,
8780
+ clause,
8781
+ own
8782
+ } of named) {
8783
+ if (typeof property !== "string") {
8784
+ continue;
8785
+ }
8786
+ let entity = parsed.entity;
8787
+ let field = property;
8788
+ if (!own && (0, _isEntityProperty.isEntityProperty)(property)) {
8789
+ ({
8790
+ entity,
8791
+ property: field
8792
+ } = (0, _splitEntityProperty.splitEntityProperty)(property));
8793
+ }
8794
+ if (clause === "select" && entity !== parsed.entity && !merged.has(entity)) {
8795
+ throw new Error(`Can't select "${property}": a joined record's rows are a list under its name (select ${entity}), and its fields are on each row only when merged (merge ... with ${entity}.<field>)`);
8796
+ }
8797
+ if (!Object.prototype.hasOwnProperty.call(recordData, entity)) {
8798
+ recordData[entity] = await (0, _retrieveRecord.retrieveRecord)(entity);
8799
+ }
8800
+ assertFieldsDefined(entity, recordData[entity], [field], clause);
8801
+ }
8802
+ };
8803
+ exports.assertKnownFields = assertKnownFields;
8804
+ }
8805
+ });
8806
+
7701
8807
  // dist/data/queries/insertEntity.js
7702
8808
  var require_insertEntity = __commonJS({
7703
8809
  "dist/data/queries/insertEntity.js"(exports) {
@@ -7707,13 +8813,44 @@ var jsonFsQuery = (() => {
7707
8813
  value: true
7708
8814
  });
7709
8815
  exports.insertEntity = void 0;
8816
+ require_es_array_includes();
8817
+ require_es_json_stringify();
7710
8818
  require_esnext_iterator_constructor();
8819
+ require_esnext_iterator_every();
7711
8820
  require_esnext_iterator_find();
8821
+ require_esnext_iterator_for_each();
7712
8822
  require_esnext_iterator_map();
7713
8823
  require_esnext_iterator_some();
8824
+ require_esnext_map_delete_all();
8825
+ require_esnext_map_every();
8826
+ require_esnext_map_filter();
8827
+ require_esnext_map_find();
8828
+ require_esnext_map_find_key();
8829
+ require_esnext_map_includes();
8830
+ require_esnext_map_key_of();
8831
+ require_esnext_map_map_keys();
8832
+ require_esnext_map_map_values();
8833
+ require_esnext_map_merge();
8834
+ require_esnext_map_reduce();
8835
+ require_esnext_map_some();
8836
+ require_esnext_map_update();
8837
+ require_esnext_set_add_all();
8838
+ require_esnext_set_delete_all();
8839
+ require_esnext_set_difference();
8840
+ require_esnext_set_every();
8841
+ require_esnext_set_filter();
8842
+ require_esnext_set_find();
8843
+ require_esnext_set_intersection();
8844
+ require_esnext_set_is_disjoint_from();
8845
+ require_esnext_set_is_subset_of();
8846
+ require_esnext_set_is_superset_of();
8847
+ require_esnext_set_join();
8848
+ require_esnext_set_map();
8849
+ require_esnext_set_reduce();
8850
+ require_esnext_set_some();
8851
+ require_esnext_set_symmetric_difference();
8852
+ require_esnext_set_union();
7714
8853
  var _retrieveRecord = require_retrieveRecord();
7715
- var _updateIndex = require_updateIndex();
7716
- var _keyGenerate = require_keyGenerate();
7717
8854
  var _keyUnique = require_keyUnique();
7718
8855
  var _useDefault = require_useDefault();
7719
8856
  var _typeCheck = require_typeCheck();
@@ -7721,19 +8858,260 @@ var jsonFsQuery = (() => {
7721
8858
  var _splitEntityProperty = require_splitEntityProperty();
7722
8859
  var _computeKeyValue = require_computeKeyValue();
7723
8860
  var _fieldType = require_fieldType();
8861
+ var _compareAs = require_compareAs();
8862
+ var _retrieveRecords = require_retrieveRecords();
8863
+ var _isSingleFieldKey = require_isSingleFieldKey();
8864
+ var _indexBuffer = require_indexBuffer();
7724
8865
  var _storage = require_storage();
7725
- var buildEntityValues = async (entity, record, rowValues = {}) => {
8866
+ var _packedTable = require_packedTable();
8867
+ var _knownFields = require_knownFields();
8868
+ var RowValues = class {
8869
+ constructor(record, fields) {
8870
+ this.seen = /* @__PURE__ */ new Set();
8871
+ this.fields = fields;
8872
+ this.types = fields.map((field) => (0, _fieldType.fieldType)(record, field));
8873
+ }
8874
+ /**
8875
+ * Whether these fields' values can be compared this way: every field of a comparable type (see compareAs).
8876
+ * @param record
8877
+ * @param fields
8878
+ */
8879
+ static usable(record, fields) {
8880
+ return fields.every((field) => _compareAs.comparableTypes.includes((0, _fieldType.fieldType)(record, field)));
8881
+ }
8882
+ /**
8883
+ * The values' key, or undefined when one is null or missing (where's = never matches those) or compareAs leaves it an
8884
+ * object (compared by identity, so not by a key).
8885
+ * @param row
8886
+ */
8887
+ keyOf(row) {
8888
+ const typed = [];
8889
+ for (let position = 0; position < this.fields.length; position++) {
8890
+ const value = row[this.fields[position]];
8891
+ if (value === null || typeof value === "undefined") {
8892
+ return void 0;
8893
+ }
8894
+ const key = (0, _compareAs.compareAs)(this.types[position], value);
8895
+ if (typeof key === "object") {
8896
+ return void 0;
8897
+ }
8898
+ typed.push([typeof key, key]);
8899
+ }
8900
+ return JSON.stringify(typed);
8901
+ }
8902
+ add(row) {
8903
+ const key = this.keyOf(row);
8904
+ if (typeof key !== "undefined") {
8905
+ this.seen.add(key);
8906
+ }
8907
+ }
8908
+ has(row) {
8909
+ const key = this.keyOf(row);
8910
+ return typeof key !== "undefined" && this.seen.has(key);
8911
+ }
8912
+ };
8913
+ var InsertStatement = class {
8914
+ constructor(entity, record) {
8915
+ this.rows = [];
8916
+ this.buffers = /* @__PURE__ */ new Map();
8917
+ this.unreadable = /* @__PURE__ */ new Set();
8918
+ this.otherLookups = /* @__PURE__ */ new Map();
8919
+ this.scans = /* @__PURE__ */ new Map();
8920
+ this.entity = entity;
8921
+ this.record = record;
8922
+ this.hadEntries = (record.entries || []).length > 0;
8923
+ }
8924
+ /**
8925
+ * Read the record's index files, once. An index that can't be read starts empty (as updateIndex starts one) and its
8926
+ * key is checked by looking at every row.
8927
+ */
8928
+ async load() {
8929
+ for (const key of this.record.keys) {
8930
+ if (!key.lookup) {
8931
+ continue;
8932
+ }
8933
+ let entries = [];
8934
+ try {
8935
+ entries = await (0, _storage.readJson)(`__indexes/${this.record.path}/${key.lookup}`);
8936
+ } catch (error) {
8937
+ this.unreadable.add(key);
8938
+ }
8939
+ this.buffers.set(key, new _indexBuffer.IndexBuffer(Array.isArray(entries) ? entries : [], (0, _fieldType.keyValueType)(this.record, key)));
8940
+ }
8941
+ }
8942
+ /**
8943
+ * How to look up a non-null value of `property` in the record being inserted into: through its index buffer, which
8944
+ * holds the statement's rows so far. indexHas reads a record with no entries as holding nothing, whatever its index
8945
+ * file says, so until this statement adds a row to a record that had none, nothing is found.
8946
+ * @param property
8947
+ */
8948
+ ownLookup(property) {
8949
+ const key = this.record.keys.find((key2) => (0, _isSingleFieldKey.isSingleFieldKey)(key2, property) && key2.lookup);
8950
+ if (!key || this.unreadable.has(key)) {
8951
+ return () => void 0;
8952
+ }
8953
+ const buffer = this.buffers.get(key);
8954
+ return (value) => (this.hadEntries || this.rows.length > 0) && buffer.has(value);
8955
+ }
8956
+ /**
8957
+ * How to look up a non-null value of `property` in another record, read once (an insert doesn't change it).
8958
+ * @param entity
8959
+ * @param property
8960
+ */
8961
+ otherLookup(entity, property) {
8962
+ const name = `${entity}\0${property}`;
8963
+ if (!this.otherLookups.has(name)) {
8964
+ this.otherLookups.set(name, (async () => {
8965
+ const record = await (0, _retrieveRecord.retrieveRecord)(entity);
8966
+ const key = record.keys.find((key2) => (0, _isSingleFieldKey.isSingleFieldKey)(key2, property) && key2.lookup);
8967
+ if (!key) {
8968
+ return () => void 0;
8969
+ }
8970
+ if (!(record.entries || []).length) {
8971
+ return () => false;
8972
+ }
8973
+ let entries;
8974
+ try {
8975
+ entries = await (0, _storage.readJson)(`__indexes/${record.path}/${key.lookup}`);
8976
+ } catch (error) {
8977
+ return () => void 0;
8978
+ }
8979
+ const buffer = new _indexBuffer.IndexBuffer(Array.isArray(entries) ? entries : [], (0, _fieldType.fieldType)(record, property));
8980
+ return (value) => buffer.has(value);
8981
+ })());
8982
+ }
8983
+ return this.otherLookups.get(name);
8984
+ }
8985
+ /**
8986
+ * The values of these fields in every row of `entity` (read once per statement), plus, for the record being inserted
8987
+ * into, every row this statement adds; undefined when a field's type can't be compared by key.
8988
+ * @param entity
8989
+ * @param fields
8990
+ */
8991
+ scan(entity, fields) {
8992
+ const name = `${entity}\0${fields.join("\0")}`;
8993
+ if (!this.scans.has(name)) {
8994
+ this.scans.set(name, (async () => {
8995
+ const record = entity === this.entity ? this.record : await (0, _retrieveRecord.retrieveRecord)(entity);
8996
+ if (!RowValues.usable(record, fields)) {
8997
+ return void 0;
8998
+ }
8999
+ const values = new RowValues(record, fields);
9000
+ for (const row of await (0, _retrieveRecords.retrieveRecords)(entity)) {
9001
+ values.add(row);
9002
+ }
9003
+ if (entity === this.entity) {
9004
+ this.rows.forEach((row) => values.add(row));
9005
+ }
9006
+ return values;
9007
+ })());
9008
+ }
9009
+ return this.scans.get(name);
9010
+ }
9011
+ /**
9012
+ * Whether one of this statement's rows already holds these values in every one of these fields (none of them null).
9013
+ * @param fields
9014
+ * @param values
9015
+ */
9016
+ claimed(fields, values) {
9017
+ return this.rows.some((row) => fields.every((field) => row[field] !== null && typeof row[field] !== "undefined" && (0, _compareAs.sameValue)((0, _fieldType.fieldType)(this.record, field), row[field], values[field])));
9018
+ }
9019
+ /**
9020
+ * Whether no row (in storage or earlier in this statement) holds these values for these fields, as keyUnique answers
9021
+ * it after each earlier row is written.
9022
+ * @param fields
9023
+ * @param values
9024
+ */
9025
+ async isUnique(fields, values) {
9026
+ if (fields.length === 1) {
9027
+ const found = this.ownLookup(fields[0])(values[fields[0]]);
9028
+ if (typeof found !== "undefined") {
9029
+ return !found;
9030
+ }
9031
+ }
9032
+ const scanned = await this.scan(this.entity, fields);
9033
+ if (scanned) {
9034
+ return !scanned.has(values);
9035
+ }
9036
+ return await (0, _keyUnique.keyUnique)(this.entity, fields, fields.map((field) => values[field])) && !this.claimed(fields, values);
9037
+ }
9038
+ /**
9039
+ * Whether `entity` holds `value` in `property`, as foreignKeyExists answers it after each earlier row is written: a
9040
+ * row may reference one added earlier in the same statement when the key points at its own record.
9041
+ * @param entity
9042
+ * @param property
9043
+ * @param value
9044
+ */
9045
+ async exists(entity, property, value) {
9046
+ const own = entity === this.entity;
9047
+ const found = own ? this.ownLookup(property)(value) : (await this.otherLookup(entity, property))(value);
9048
+ if (typeof found !== "undefined") {
9049
+ return found;
9050
+ }
9051
+ const scanned = await this.scan(entity, [property]);
9052
+ if (scanned) {
9053
+ return scanned.has({
9054
+ [property]: value
9055
+ });
9056
+ }
9057
+ return await (0, _foreignKeyExists.foreignKeyExists)(entity, property, value) || own && this.claimed([property], {
9058
+ [property]: value
9059
+ });
9060
+ }
9061
+ /**
9062
+ * Note a row added to the statement, filed under `fileName`, in the record's entries and every index buffer.
9063
+ * @param entityValues
9064
+ * @param fileName
9065
+ */
9066
+ async add(entityValues, fileName) {
9067
+ this.rows.push(entityValues);
9068
+ for (const [name, scanned] of this.scans) {
9069
+ if (name.startsWith(`${this.entity}\0`)) {
9070
+ (await scanned)?.add(entityValues);
9071
+ }
9072
+ }
9073
+ this.record.entries.push(fileName);
9074
+ for (const [key, buffer] of this.buffers) {
9075
+ buffer.add((0, _computeKeyValue.computeKeyValue)(key.fields, entityValues), fileName);
9076
+ }
9077
+ }
9078
+ /**
9079
+ * Write the record file and each index once, with every row the statement added.
9080
+ */
9081
+ async write() {
9082
+ await (0, _storage.writeJson)(`${this.record.path}.json`, this.record);
9083
+ if (this.buffers.size) {
9084
+ await (0, _storage.makeDirectory)(`__indexes/${this.record.path}`);
9085
+ }
9086
+ for (const [key, buffer] of this.buffers) {
9087
+ await (0, _storage.writeJson)(`__indexes/${this.record.path}/${key.lookup}`, buffer.entries);
9088
+ }
9089
+ }
9090
+ };
9091
+ var generateKey = async (statement, field) => {
9092
+ let uuid;
9093
+ do {
9094
+ uuid = crypto.randomUUID();
9095
+ } while (!await statement.isUnique([field], {
9096
+ [field]: uuid
9097
+ }));
9098
+ return uuid;
9099
+ };
9100
+ var buildEntityValues = async (statement, rowValues = {}) => {
7726
9101
  const entityValues = {};
7727
- for (const field of record.definition) {
9102
+ for (const field of statement.record.definition) {
7728
9103
  let value = rowValues[field.name];
9104
+ if (value === null && field.optional && !field.nullable) {
9105
+ value = void 0;
9106
+ }
7729
9107
  if (field.autoGenerate) {
7730
- value = await (0, _keyGenerate.keyGenerate)(entity, [field.name]);
9108
+ value = await generateKey(statement, field.name);
7731
9109
  } else if (Object.prototype.hasOwnProperty.call(field, "default")) {
7732
9110
  value = (0, _useDefault.useDefault)(field["default"], value);
7733
9111
  }
7734
9112
  if (typeof value === "undefined") {
7735
9113
  if (!field.optional) {
7736
- throw new Error(`Missing required field "${field.name}" for ${entity}`);
9114
+ throw new Error(`Missing required field "${field.name}" for ${statement.entity}`);
7737
9115
  }
7738
9116
  continue;
7739
9117
  }
@@ -7741,23 +9119,21 @@ var jsonFsQuery = (() => {
7741
9119
  }
7742
9120
  return entityValues;
7743
9121
  };
7744
- var assertUnique = async (entity, record, entityValues) => {
7745
- for (const key of record.keys) {
9122
+ var assertUnique = async (statement, entityValues) => {
9123
+ for (const key of statement.record.keys) {
7746
9124
  if (key.type !== "primary" && key.type !== "unique") {
7747
9125
  continue;
7748
9126
  }
7749
- const checkKeys = key.fields.map((field) => entityValues[field]);
7750
- if (checkKeys.some((value) => value === null)) {
9127
+ if (key.fields.some((field) => entityValues[field] === null)) {
7751
9128
  continue;
7752
9129
  }
7753
- const isUnique = await (0, _keyUnique.keyUnique)(entity, key.fields, checkKeys);
7754
- if (!isUnique) {
7755
- throw new Error(`Duplicate value for ${key.type} key "${key.fields.join(", ")}" on ${entity}`);
9130
+ if (!await statement.isUnique(key.fields, entityValues)) {
9131
+ throw new Error(`Duplicate value for ${key.type} key "${key.fields.join(", ")}" on ${statement.entity}`);
7756
9132
  }
7757
9133
  }
7758
9134
  };
7759
- var assertForeignKeys = async (entity, record, entityValues) => {
7760
- for (const key of record.keys) {
9135
+ var assertForeignKeys = async (statement, entityValues) => {
9136
+ for (const key of statement.record.keys) {
7761
9137
  if (key.type !== "foreign" || key.fields.length !== 1 || !key.references || key.references.length !== 1) {
7762
9138
  continue;
7763
9139
  }
@@ -7769,9 +9145,8 @@ var jsonFsQuery = (() => {
7769
9145
  entity: refEntity,
7770
9146
  property: refProperty
7771
9147
  } = (0, _splitEntityProperty.splitEntityProperty)(key.references[0].fields[0]);
7772
- const exists = await (0, _foreignKeyExists.foreignKeyExists)(refEntity, refProperty, entityValues[field]);
7773
- if (!exists) {
7774
- throw new Error(`Foreign key "${field}" on ${entity} references a nonexistent ${refEntity}.${refProperty} = ${entityValues[field]}`);
9148
+ if (!await statement.exists(refEntity, refProperty, entityValues[field])) {
9149
+ throw new Error(`Foreign key "${field}" on ${statement.entity} references a nonexistent ${refEntity}.${refProperty} = ${entityValues[field]}`);
7775
9150
  }
7776
9151
  }
7777
9152
  };
@@ -7782,19 +9157,25 @@ var jsonFsQuery = (() => {
7782
9157
  dataSet[entity] = [];
7783
9158
  }
7784
9159
  await (0, _storage.makeDirectory)(record.path);
9160
+ if (!values.length) {
9161
+ return dataSet;
9162
+ }
7785
9163
  for (const rowValues of values) {
7786
- const entityValues = await buildEntityValues(entity, record, rowValues);
7787
- await assertUnique(entity, record, entityValues);
7788
- await assertForeignKeys(entity, record, entityValues);
9164
+ (0, _knownFields.assertFieldsDefined)(entity, record, Object.keys(rowValues || {}), "insert");
9165
+ }
9166
+ await (0, _packedTable.discardPacked)(record.path);
9167
+ const statement = new InsertStatement(entity, record);
9168
+ await statement.load();
9169
+ for (const rowValues of values) {
9170
+ const entityValues = await buildEntityValues(statement, rowValues);
9171
+ await assertUnique(statement, entityValues);
9172
+ await assertForeignKeys(statement, entityValues);
7789
9173
  const fileName = `${primaryKey ? entityValues[primaryKey.fields[0]] : crypto.randomUUID()}.json`;
7790
9174
  await (0, _storage.writeJson)(`${record.path}/${fileName}`, entityValues);
7791
- record.entries.push(fileName);
7792
- await (0, _storage.writeJson)(`${record.path}.json`, record);
7793
- for (const key of record.keys) {
7794
- await (0, _updateIndex.updateIndex)(record.path, key, (0, _computeKeyValue.computeKeyValue)(key.fields, entityValues), fileName, (0, _fieldType.keyValueType)(record, key));
7795
- }
9175
+ await statement.add(entityValues, fileName);
7796
9176
  dataSet[entity].push(entityValues);
7797
9177
  }
9178
+ await statement.write();
7798
9179
  return dataSet;
7799
9180
  };
7800
9181
  exports.insertEntity = insertEntity;
@@ -7821,6 +9202,51 @@ var jsonFsQuery = (() => {
7821
9202
  }
7822
9203
  });
7823
9204
 
9205
+ // dist/data/utilities/updateIndex.js
9206
+ var require_updateIndex = __commonJS({
9207
+ "dist/data/utilities/updateIndex.js"(exports) {
9208
+ "use strict";
9209
+ init_process();
9210
+ Object.defineProperty(exports, "__esModule", {
9211
+ value: true
9212
+ });
9213
+ exports.updateIndex = void 0;
9214
+ require_es_array_includes();
9215
+ require_esnext_iterator_constructor();
9216
+ require_esnext_iterator_find();
9217
+ var _compareAs = require_compareAs();
9218
+ var _storage = require_storage();
9219
+ var updateIndex = async (path = "", key = null, value = void 0, fileName = "", type = void 0) => {
9220
+ if (!key || !key.lookup) {
9221
+ return null;
9222
+ }
9223
+ const indexDir = `__indexes/${path}`;
9224
+ const indexPath = `${indexDir}/${key.lookup}`;
9225
+ let index = [];
9226
+ try {
9227
+ index = await (0, _storage.readJson)(indexPath);
9228
+ } catch (err) {
9229
+ index = [];
9230
+ }
9231
+ const existingEntry = index.find((entry) => (0, _compareAs.sameValue)(type, entry.value, value));
9232
+ if (existingEntry) {
9233
+ if (!existingEntry.record.includes(fileName)) {
9234
+ existingEntry.record.push(fileName);
9235
+ }
9236
+ } else {
9237
+ index.push({
9238
+ value,
9239
+ record: [fileName]
9240
+ });
9241
+ }
9242
+ await (0, _storage.makeDirectory)(indexDir);
9243
+ await (0, _storage.writeJson)(indexPath, index);
9244
+ return index;
9245
+ };
9246
+ exports.updateIndex = updateIndex;
9247
+ }
9248
+ });
9249
+
7824
9250
  // dist/data/queries/updateEntity.js
7825
9251
  var require_updateEntity = __commonJS({
7826
9252
  "dist/data/queries/updateEntity.js"(exports) {
@@ -7849,6 +9275,8 @@ var jsonFsQuery = (() => {
7849
9275
  var _config = require_config();
7850
9276
  var _keyIndexFiles = require_keyIndexFiles();
7851
9277
  var _storage = require_storage();
9278
+ var _packedTable = require_packedTable();
9279
+ var _knownFields = require_knownFields();
7852
9280
  var findEntryFile = async (record, primaryKey, primaryValue) => {
7853
9281
  const type = (0, _fieldType.keyValueType)(record, primaryKey);
7854
9282
  const isMatch = async (fileName) => (0, _compareAs.sameValue)(type, (0, _computeKeyValue.computeKeyValue)(primaryKey.fields, await (0, _retrieveFile.retrieveFile)(`${record.path}/${fileName}`)), primaryValue);
@@ -7871,7 +9299,7 @@ var jsonFsQuery = (() => {
7871
9299
  continue;
7872
9300
  }
7873
9301
  const checkKeys = key.fields.map((field) => newData[field]);
7874
- if (checkKeys.some((value) => value === null)) {
9302
+ if (checkKeys.some((value) => value === null || typeof value === "undefined")) {
7875
9303
  continue;
7876
9304
  }
7877
9305
  const isUnique = await (0, _keyUnique.keyUnique)(entity, key.fields, checkKeys);
@@ -7886,7 +9314,7 @@ var jsonFsQuery = (() => {
7886
9314
  continue;
7887
9315
  }
7888
9316
  const field = key.fields[0];
7889
- if (!Object.prototype.hasOwnProperty.call(newValues, field) || newValues[field] === null || (0, _compareAs.sameValue)((0, _fieldType.fieldType)(record, field), newValues[field], oldData[field])) {
9317
+ if (!Object.prototype.hasOwnProperty.call(newValues, field) || newValues[field] === null || typeof newValues[field] === "undefined" || (0, _compareAs.sameValue)((0, _fieldType.fieldType)(record, field), newValues[field], oldData[field])) {
7890
9318
  continue;
7891
9319
  }
7892
9320
  const {
@@ -7927,7 +9355,7 @@ var jsonFsQuery = (() => {
7927
9355
  oldData,
7928
9356
  newData
7929
9357
  } of planned) {
7930
- if (!keyFieldsChanged(record, key, oldData, newValues) || key.fields.some((field) => newData[field] === null)) {
9358
+ if (!keyFieldsChanged(record, key, oldData, newValues) || key.fields.some((field) => newData[field] === null || typeof newData[field] === "undefined")) {
7931
9359
  continue;
7932
9360
  }
7933
9361
  const value = (0, _computeKeyValue.computeKeyValue)(key.fields, newData);
@@ -7949,18 +9377,33 @@ var jsonFsQuery = (() => {
7949
9377
  const typedValues = Object.assign({}, values);
7950
9378
  for (const field of record.definition) {
7951
9379
  if (Object.prototype.hasOwnProperty.call(typedValues, field.name)) {
7952
- typedValues[field.name] = (0, _typeCheck.typeCheck)(field.type, typedValues[field.name], field.nullable);
9380
+ typedValues[field.name] = typedValues[field.name] === null && field.optional && !field.nullable ? void 0 : (0, _typeCheck.typeCheck)(field.type, typedValues[field.name], field.nullable);
7953
9381
  }
7954
9382
  }
7955
9383
  return typedValues;
7956
9384
  };
9385
+ var withoutRemoved = (row, typedValues) => {
9386
+ const kept = Object.assign({}, row);
9387
+ for (const field of Object.keys(typedValues)) {
9388
+ if (typeof typedValues[field] === "undefined") {
9389
+ delete kept[field];
9390
+ }
9391
+ }
9392
+ return kept;
9393
+ };
7957
9394
  var updateEntity = async (entity = "", values = {}, dataSet = {}) => {
7958
9395
  const record = await (0, _retrieveRecord.retrieveRecord)(entity);
7959
9396
  const primaryKey = record.keys.find((key) => key.type === "primary");
7960
9397
  if (!primaryKey) {
7961
9398
  throw new Error(`Cannot update "${entity}" without a primary key`);
7962
9399
  }
9400
+ (0, _knownFields.assertFieldsDefined)(entity, record, Object.keys(values || {}), "set");
7963
9401
  const typedValues = applyFieldTypes(record, values);
9402
+ for (const field of primaryKey.fields) {
9403
+ if (Object.prototype.hasOwnProperty.call(typedValues, field) && typeof typedValues[field] === "undefined") {
9404
+ throw new Error(`Cannot clear "${field}" on ${entity}: it's part of the primary key`);
9405
+ }
9406
+ }
7964
9407
  const planned = [];
7965
9408
  for (const row of dataSet[entity] || []) {
7966
9409
  const fileName = await findEntryFile(record, primaryKey, (0, _computeKeyValue.computeKeyValue)(primaryKey.fields, row));
@@ -7971,7 +9414,7 @@ var jsonFsQuery = (() => {
7971
9414
  continue;
7972
9415
  }
7973
9416
  const oldData = await (0, _retrieveFile.retrieveFile)(`${record.path}/${fileName}`);
7974
- const newData = Object.assign({}, oldData, typedValues);
9417
+ const newData = withoutRemoved(Object.assign({}, oldData, typedValues), typedValues);
7975
9418
  await assertUniqueForUpdate(entity, record, oldData, newData, typedValues);
7976
9419
  await assertForeignKeysForUpdate(entity, record, oldData, typedValues);
7977
9420
  await assertNoDependentsForUpdate(entity, record, primaryKey, oldData, typedValues);
@@ -7983,6 +9426,9 @@ var jsonFsQuery = (() => {
7983
9426
  });
7984
9427
  }
7985
9428
  assertUniqueWithinUpdate(entity, record, planned, typedValues);
9429
+ if (planned.length) {
9430
+ await (0, _packedTable.discardPacked)(record.path);
9431
+ }
7986
9432
  for (const {
7987
9433
  fileName,
7988
9434
  oldData,
@@ -8233,7 +9679,7 @@ var jsonFsQuery = (() => {
8233
9679
  Object.defineProperty(exports, "__esModule", {
8234
9680
  value: true
8235
9681
  });
8236
- exports.create = void 0;
9682
+ exports.create = exports.assertValidDefinition = void 0;
8237
9683
  require_es_array_includes();
8238
9684
  require_esnext_iterator_constructor();
8239
9685
  require_esnext_iterator_filter();
@@ -8282,6 +9728,7 @@ var jsonFsQuery = (() => {
8282
9728
  }
8283
9729
  }
8284
9730
  };
9731
+ exports.assertValidDefinition = assertValidDefinition;
8285
9732
  var create = async (recordName, definition = [], keys = []) => {
8286
9733
  (0, _requireNode.requireNode)("create()");
8287
9734
  if (recordName === "__RECORDS") {
@@ -8314,21 +9761,6 @@ var jsonFsQuery = (() => {
8314
9761
  }
8315
9762
  });
8316
9763
 
8317
- // dist/data/utilities/recordExists.js
8318
- var require_recordExists = __commonJS({
8319
- "dist/data/utilities/recordExists.js"(exports) {
8320
- "use strict";
8321
- init_process();
8322
- Object.defineProperty(exports, "__esModule", {
8323
- value: true
8324
- });
8325
- exports.recordExists = void 0;
8326
- var _storage = require_storage();
8327
- var recordExists = (entity) => (0, _storage.fileExists)(`${entity}.json`);
8328
- exports.recordExists = recordExists;
8329
- }
8330
- });
8331
-
8332
9764
  // dist/data/queries/createRecord.js
8333
9765
  var require_createRecord = __commonJS({
8334
9766
  "dist/data/queries/createRecord.js"(exports) {
@@ -8426,6 +9858,7 @@ var jsonFsQuery = (() => {
8426
9858
  var _deregisterRecord = require_deregisterRecord();
8427
9859
  var _requireNode = require_requireNode();
8428
9860
  var _storage = require_storage();
9861
+ var _packedTable = require_packedTable();
8429
9862
  var drop = async (record) => {
8430
9863
  (0, _requireNode.requireNode)("drop()");
8431
9864
  if (record === "__RECORDS") {
@@ -8437,6 +9870,7 @@ var jsonFsQuery = (() => {
8437
9870
  }
8438
9871
  await (0, _storage.removeDirectory)(recordFile.path);
8439
9872
  await (0, _storage.removeDirectory)(`__indexes/${recordFile.path}`);
9873
+ await (0, _packedTable.discardPacked)(recordFile.path);
8440
9874
  await (0, _storage.removeFile)(`${record}.json`);
8441
9875
  await (0, _deregisterRecord.deregisterRecord)(record);
8442
9876
  };
@@ -8514,41 +9948,446 @@ var jsonFsQuery = (() => {
8514
9948
  if (!(0, _recordExists.recordExists)(entity)) {
8515
9949
  throw new Error(`Record "${entity}" doesn't exist`);
8516
9950
  }
8517
- const {
8518
- path,
8519
- definition,
8520
- keys
8521
- } = await (0, _retrieveRecord.retrieveRecord)(entity);
8522
- return {
8523
- path,
8524
- definition,
8525
- keys
8526
- };
9951
+ const {
9952
+ path,
9953
+ definition,
9954
+ keys
9955
+ } = await (0, _retrieveRecord.retrieveRecord)(entity);
9956
+ return {
9957
+ path,
9958
+ definition,
9959
+ keys
9960
+ };
9961
+ };
9962
+ exports.describeRecord = describeRecord;
9963
+ }
9964
+ });
9965
+
9966
+ // dist/data/queries/showRecords.js
9967
+ var require_showRecords = __commonJS({
9968
+ "dist/data/queries/showRecords.js"(exports) {
9969
+ "use strict";
9970
+ init_process();
9971
+ Object.defineProperty(exports, "__esModule", {
9972
+ value: true
9973
+ });
9974
+ exports.showRecords = void 0;
9975
+ require_esnext_iterator_constructor();
9976
+ require_esnext_iterator_map();
9977
+ var _retrieveRecord = require_retrieveRecord();
9978
+ var _recordExists = require_recordExists();
9979
+ var showRecords = async () => {
9980
+ if (!(0, _recordExists.recordExists)("__RECORDS")) {
9981
+ return [];
9982
+ }
9983
+ return (await (0, _retrieveRecord.retrieveRecord)("__RECORDS")).entries.map((fileName) => fileName.replace(/\.json$/, ""));
9984
+ };
9985
+ exports.showRecords = showRecords;
9986
+ }
9987
+ });
9988
+
9989
+ // dist/data/introspect/alter.js
9990
+ var require_alter = __commonJS({
9991
+ "dist/data/introspect/alter.js"(exports) {
9992
+ "use strict";
9993
+ init_process();
9994
+ Object.defineProperty(exports, "__esModule", {
9995
+ value: true
9996
+ });
9997
+ exports.alter = void 0;
9998
+ require_es_array_includes();
9999
+ require_es_json_stringify();
10000
+ require_esnext_iterator_constructor();
10001
+ require_esnext_iterator_filter();
10002
+ require_esnext_iterator_find();
10003
+ require_esnext_iterator_map();
10004
+ require_esnext_iterator_some();
10005
+ var _field = require_field();
10006
+ var _create = require_create();
10007
+ var _parseCreate = require_parseCreate();
10008
+ var _retrieveRecord = require_retrieveRecord();
10009
+ var _retrieveFiles = require_retrieveFiles();
10010
+ var _retrieveRecords = require_retrieveRecords();
10011
+ var _knownFields = require_knownFields();
10012
+ var _packedTable = require_packedTable();
10013
+ var _requireNode = require_requireNode();
10014
+ var _showRecords = require_showRecords();
10015
+ var _updateEntity = require_updateEntity();
10016
+ var _typeCheck = require_typeCheck();
10017
+ var _storage = require_storage();
10018
+ var rowsOf = async (record) => {
10019
+ const rows = await (0, _retrieveFiles.retrieveFiles)(record.entries.map((file) => `${record.path}/${file}`), _retrieveRecords.retrieveEntry);
10020
+ return rows.map((data, position) => ({
10021
+ fileName: record.entries[position],
10022
+ data
10023
+ }));
10024
+ };
10025
+ var has = (row, name) => Object.prototype.hasOwnProperty.call(row, name);
10026
+ var keysUsing = (record, name) => record.keys.filter((key) => key.fields.includes(name));
10027
+ var describeKey = (key) => `${key.type} key (${key.fields.join(", ")})`;
10028
+ var referencesTo = async (entity, name) => {
10029
+ const found = [];
10030
+ for (const other of await (0, _showRecords.showRecords)()) {
10031
+ const record = await (0, _retrieveRecord.retrieveRecord)(other);
10032
+ for (const key of record.keys) {
10033
+ if (key.type === "foreign" && (key.references || []).some((reference) => reference.fields.includes(`${entity}.${name}`))) {
10034
+ found.push({
10035
+ entity: other,
10036
+ record,
10037
+ key
10038
+ });
10039
+ }
10040
+ }
10041
+ }
10042
+ return found;
10043
+ };
10044
+ var writeRecord = async (entity, record) => {
10045
+ (0, _create.assertValidDefinition)(entity, record);
10046
+ await (0, _storage.writeJson)(`${entity}.json`, record);
10047
+ };
10048
+ var setField = async (entity, record, rows, name, value) => {
10049
+ if (!rows.length) {
10050
+ return;
10051
+ }
10052
+ await (0, _packedTable.discardPacked)(record.path);
10053
+ if (keysUsing(record, name).length && typeof value !== "function") {
10054
+ if (!record.keys.some((key) => key.type === "primary")) {
10055
+ throw new Error(`Can't change "${name}" on ${entity}'s rows: a key uses it, and rows are found by the primary key, which ${entity} doesn't have`);
10056
+ }
10057
+ await (0, _updateEntity.updateEntity)(entity, {
10058
+ [name]: typeof value === "undefined" ? null : value
10059
+ }, {
10060
+ [entity]: rows.map((row) => row.data)
10061
+ });
10062
+ return;
10063
+ }
10064
+ for (const row of rows) {
10065
+ const changed = Object.assign({}, row.data);
10066
+ const next = typeof value === "function" ? value(row) : value;
10067
+ if (typeof next === "undefined") {
10068
+ delete changed[name];
10069
+ } else {
10070
+ changed[name] = next;
10071
+ }
10072
+ await (0, _storage.writeJson)(`${record.path}/${row.fileName}`, changed);
10073
+ }
10074
+ };
10075
+ var addField = async (entity, record, added) => {
10076
+ if (record.definition.some((field) => field.name === added.name)) {
10077
+ throw new Error(`Field "${added.name}" already exists on ${entity}`);
10078
+ }
10079
+ const updated = {
10080
+ ...record,
10081
+ definition: [...record.definition, added]
10082
+ };
10083
+ const rows = await rowsOf(record);
10084
+ for (const row of rows.filter((row2) => has(row2.data, added.name))) {
10085
+ try {
10086
+ (0, _typeCheck.typeCheck)(added.type, row.data[added.name], added.nullable);
10087
+ } catch (error) {
10088
+ throw new Error(`Can't add "${added.name}" to ${entity}: row ${row.fileName} already holds a value for it that doesn't fit (${error.message})`);
10089
+ }
10090
+ }
10091
+ const missing = rows.filter((row) => !has(row.data, added.name));
10092
+ const hasDefault = has(added, "default");
10093
+ if (missing.length && !added.optional && !hasDefault && !added.autoGenerate) {
10094
+ throw new Error(`Can't add required field "${added.name}" to ${entity}: its ${missing.length} row(s) have no value for it (give it a default, or make it optional)`);
10095
+ }
10096
+ await writeRecord(entity, updated);
10097
+ if (added.autoGenerate) {
10098
+ await setField(entity, updated, missing, added.name, () => crypto.randomUUID());
10099
+ } else if (hasDefault) {
10100
+ await setField(entity, updated, missing, added.name, added["default"]);
10101
+ }
10102
+ return updated;
10103
+ };
10104
+ var dropField = async (entity, record, name) => {
10105
+ (0, _knownFields.assertFieldsDefined)(entity, record, [name], "alter");
10106
+ const key = keysUsing(record, name)[0];
10107
+ if (key) {
10108
+ throw new Error(`Can't drop "${name}" from ${entity}: its ${describeKey(key)} uses it`);
10109
+ }
10110
+ const reference = (await referencesTo(entity, name))[0];
10111
+ if (reference) {
10112
+ throw new Error(`Can't drop "${name}" from ${entity}: ${reference.entity}'s foreign key "${reference.key.fields[0]}" references it`);
10113
+ }
10114
+ const updated = {
10115
+ ...record,
10116
+ definition: record.definition.filter((field) => field.name !== name)
10117
+ };
10118
+ await writeRecord(entity, updated);
10119
+ await setField(entity, updated, (await rowsOf(record)).filter((row) => has(row.data, name)), name, void 0);
10120
+ return updated;
10121
+ };
10122
+ var renameField = async (entity, record, name, to) => {
10123
+ (0, _knownFields.assertFieldsDefined)(entity, record, [name], "alter");
10124
+ if (record.definition.some((field) => field.name === to)) {
10125
+ throw new Error(`Can't rename "${name}" on ${entity} to "${to}": a field of that name already exists`);
10126
+ }
10127
+ const references = await referencesTo(entity, name);
10128
+ const keys = record.keys.map((key) => {
10129
+ if (!key.fields.includes(name)) {
10130
+ return key;
10131
+ }
10132
+ const fields = key.fields.map((field) => field === name ? to : field);
10133
+ const lookup = key.lookup && key.lookup === (0, _parseCreate.keyLookup)(key.type, key.fields) ? (0, _parseCreate.keyLookup)(key.type, fields) : key.lookup;
10134
+ return {
10135
+ ...key,
10136
+ fields,
10137
+ lookup
10138
+ };
10139
+ });
10140
+ const renameReferences = (key) => key.type !== "foreign" ? key : {
10141
+ ...key,
10142
+ references: (key.references || []).map((reference) => ({
10143
+ ...reference,
10144
+ fields: reference.fields.map((field) => field === `${entity}.${name}` ? `${entity}.${to}` : field)
10145
+ }))
10146
+ };
10147
+ const updated = {
10148
+ ...record,
10149
+ definition: record.definition.map((field) => field.name === name ? {
10150
+ ...field,
10151
+ name: to
10152
+ } : field),
10153
+ keys: keys.map(renameReferences)
10154
+ };
10155
+ for (const [position, key] of record.keys.entries()) {
10156
+ const moved = keys[position].lookup;
10157
+ if (key.lookup && moved !== key.lookup && (0, _storage.fileExists)(`__indexes/${record.path}/${key.lookup}`)) {
10158
+ await (0, _storage.writeJson)(`__indexes/${record.path}/${moved}`, await (0, _storage.readJson)(`__indexes/${record.path}/${key.lookup}`));
10159
+ await (0, _storage.removeFile)(`__indexes/${record.path}/${key.lookup}`);
10160
+ }
10161
+ }
10162
+ await writeRecord(entity, updated);
10163
+ for (const reference of references.filter((reference2) => reference2.entity !== entity)) {
10164
+ await (0, _storage.writeJson)(`${reference.entity}.json`, {
10165
+ ...reference.record,
10166
+ keys: reference.record.keys.map(renameReferences)
10167
+ });
10168
+ }
10169
+ const rows = (await rowsOf(record)).filter((row) => has(row.data, name));
10170
+ if (rows.length) {
10171
+ await (0, _packedTable.discardPacked)(record.path);
10172
+ }
10173
+ for (const row of rows) {
10174
+ const moved = Object.assign({}, row.data);
10175
+ moved[to] = moved[name];
10176
+ delete moved[name];
10177
+ await (0, _storage.writeJson)(`${record.path}/${row.fileName}`, moved);
10178
+ }
10179
+ return updated;
10180
+ };
10181
+ var modifyField = async (entity, record, changed) => {
10182
+ (0, _knownFields.assertFieldsDefined)(entity, record, [changed.name], "alter");
10183
+ const current = record.definition.find((field) => field.name === changed.name);
10184
+ if (current.type !== changed.type) {
10185
+ throw new Error(`Can't change the type of "${changed.name}" on ${entity} (${current.type} to ${changed.type}): only optional, null and default can change`);
10186
+ }
10187
+ if (Boolean(current.autoGenerate) !== Boolean(changed.autoGenerate)) {
10188
+ throw new Error(`Can't change whether "${changed.name}" on ${entity} is auto: only optional, null and default can change`);
10189
+ }
10190
+ const updated = {
10191
+ ...record,
10192
+ definition: record.definition.map((field) => field.name === changed.name ? changed : field)
10193
+ };
10194
+ const rows = await rowsOf(record);
10195
+ const hasDefault = has(changed, "default");
10196
+ const holdsNull = changed.nullable ? [] : rows.filter((row) => row.data[changed.name] === null);
10197
+ const missing = changed.optional ? [] : rows.filter((row) => !has(row.data, changed.name));
10198
+ const unfillable = changed.optional ? [] : holdsNull;
10199
+ if ((missing.length || unfillable.length) && !hasDefault) {
10200
+ throw missing.length ? new Error(`Can't make "${changed.name}" required on ${entity}: ${missing.length} row(s) have no value for it (give it a default to fill them in)`) : new Error(`Can't make "${changed.name}" not null on ${entity}: ${unfillable.length} row(s) hold null (give it a default to fill them in, or make it optional)`);
10201
+ }
10202
+ await writeRecord(entity, updated);
10203
+ if (hasDefault) {
10204
+ await setField(entity, updated, [...missing, ...unfillable], changed.name, changed["default"]);
10205
+ }
10206
+ if (changed.optional && holdsNull.length) {
10207
+ await setField(entity, updated, holdsNull, changed.name, void 0);
10208
+ }
10209
+ return updated;
10210
+ };
10211
+ var alter = async (entity, change) => {
10212
+ (0, _requireNode.requireNode)("alter");
10213
+ if (entity === "__RECORDS") {
10214
+ throw new Error("__RECORDS is reserved for the list of records");
10215
+ }
10216
+ const names = [entity, ..."field" in change ? [change.field?.name] : [], ..."name" in change ? [change.name] : [], ..."to" in change ? [change.to] : []];
10217
+ const invalid = names.findIndex((name) => typeof name !== "string" || !_parseCreate.nameMatch.test(name));
10218
+ if (invalid !== -1) {
10219
+ throw new Error(`Invalid name ${JSON.stringify(names[invalid]) ?? "undefined"} in alter: names use letters, digits, _ and - only`);
10220
+ }
10221
+ const record = await (0, _retrieveRecord.retrieveRecord)(entity);
10222
+ switch (change.action) {
10223
+ case "add":
10224
+ return (await addField(entity, record, (0, _field.field)(change.field))).definition;
10225
+ case "drop":
10226
+ return (await dropField(entity, record, change.name)).definition;
10227
+ case "rename":
10228
+ return (await renameField(entity, record, change.name, change.to)).definition;
10229
+ case "modify":
10230
+ return (await modifyField(entity, record, (0, _field.field)(change.field))).definition;
10231
+ default:
10232
+ throw new Error(`Unknown alter action: ${change.action}`);
10233
+ }
10234
+ };
10235
+ exports.alter = alter;
10236
+ }
10237
+ });
10238
+
10239
+ // dist/data/utilities/databaseLock.js
10240
+ var require_databaseLock = __commonJS({
10241
+ "dist/data/utilities/databaseLock.js"(exports) {
10242
+ "use strict";
10243
+ init_process();
10244
+ require_esnext_weak_map_delete_all();
10245
+ Object.defineProperty(exports, "__esModule", {
10246
+ value: true
10247
+ });
10248
+ exports.withDatabaseLock = exports.browserCallsRunning = void 0;
10249
+ require_esnext_map_delete_all();
10250
+ require_esnext_map_every();
10251
+ require_esnext_map_filter();
10252
+ require_esnext_map_find();
10253
+ require_esnext_map_find_key();
10254
+ require_esnext_map_includes();
10255
+ require_esnext_map_key_of();
10256
+ require_esnext_map_map_keys();
10257
+ require_esnext_map_map_values();
10258
+ require_esnext_map_merge();
10259
+ require_esnext_map_reduce();
10260
+ require_esnext_map_some();
10261
+ require_esnext_map_update();
10262
+ var jsEnv = _interopRequireWildcard(require_dist());
10263
+ var _config = require_config();
10264
+ var _storage = require_storage();
10265
+ var e;
10266
+ function _interopRequireWildcard(t, r) {
10267
+ if (!r && t && t.__esModule) return t;
10268
+ var n, a, o = Object.defineProperty, f = { __proto__: null, default: t };
10269
+ if (Object(t) !== t) return f;
10270
+ if (e || "function" != typeof WeakMap || (e = /* @__PURE__ */ new WeakMap()), e) {
10271
+ if (e.has(t)) return e.get(t);
10272
+ e.set(t, f);
10273
+ }
10274
+ for (a in t) "default" !== a && {}.hasOwnProperty.call(t, a) && ((n = o && Object.getOwnPropertyDescriptor(t, a)) && (n.get || n.set) ? o(f, a, n) : f[a] = t[a]);
10275
+ return f;
10276
+ }
10277
+ var queues = /* @__PURE__ */ new Map();
10278
+ var browserCalls = 0;
10279
+ var browserCallsRunning = () => browserCalls;
10280
+ exports.browserCallsRunning = browserCallsRunning;
10281
+ var withDatabaseLock = async (task) => {
10282
+ if (!jsEnv.isNode) {
10283
+ browserCalls++;
10284
+ try {
10285
+ return await (0, _storage.withReadCache)(task);
10286
+ } finally {
10287
+ browserCalls--;
10288
+ }
10289
+ }
10290
+ const database = (0, _config.resolveDatabasePath)((0, _config.lockPath)());
10291
+ const ended = (0, _config.trackDatabaseCall)();
10292
+ const previous = queues.get(database) || Promise.resolve();
10293
+ let release;
10294
+ const turn = new Promise((resolve) => {
10295
+ release = resolve;
10296
+ });
10297
+ const queued = previous.then(() => turn);
10298
+ queues.set(database, queued);
10299
+ await previous;
10300
+ try {
10301
+ return await (0, _storage.withReadCache)(task);
10302
+ } finally {
10303
+ ended();
10304
+ release();
10305
+ if (queues.get(database) === queued) {
10306
+ queues.delete(database);
10307
+ }
10308
+ }
8527
10309
  };
8528
- exports.describeRecord = describeRecord;
10310
+ exports.withDatabaseLock = withDatabaseLock;
8529
10311
  }
8530
10312
  });
8531
10313
 
8532
- // dist/data/queries/showRecords.js
8533
- var require_showRecords = __commonJS({
8534
- "dist/data/queries/showRecords.js"(exports) {
10314
+ // dist/data/queries/databaseStatements.js
10315
+ var require_databaseStatements = __commonJS({
10316
+ "dist/data/queries/databaseStatements.js"(exports) {
8535
10317
  "use strict";
8536
10318
  init_process();
10319
+ require_esnext_weak_map_delete_all();
8537
10320
  Object.defineProperty(exports, "__esModule", {
8538
10321
  value: true
8539
10322
  });
8540
- exports.showRecords = void 0;
10323
+ exports.useDatabase = exports.showDatabases = exports.dropDatabase = exports.createDatabase = void 0;
10324
+ require_es_array_includes();
8541
10325
  require_esnext_iterator_constructor();
8542
- require_esnext_iterator_map();
8543
- var _retrieveRecord = require_retrieveRecord();
8544
- var _recordExists = require_recordExists();
8545
- var showRecords = async () => {
8546
- if (!(0, _recordExists.recordExists)("__RECORDS")) {
8547
- return [];
10326
+ require_esnext_iterator_filter();
10327
+ var jsEnv = _interopRequireWildcard(require_dist());
10328
+ var _config = require_config();
10329
+ var _requireNode = require_requireNode();
10330
+ var _databaseLock = require_databaseLock();
10331
+ var _storage = require_storage();
10332
+ var e;
10333
+ function _interopRequireWildcard(t, r) {
10334
+ if (!r && t && t.__esModule) return t;
10335
+ var n, a, o = Object.defineProperty, f = { __proto__: null, default: t };
10336
+ if (Object(t) !== t) return f;
10337
+ if (e || "function" != typeof WeakMap || (e = /* @__PURE__ */ new WeakMap()), e) {
10338
+ if (e.has(t)) return e.get(t);
10339
+ e.set(t, f);
8548
10340
  }
8549
- return (await (0, _retrieveRecord.retrieveRecord)("__RECORDS")).entries.map((fileName) => fileName.replace(/\.json$/, ""));
10341
+ for (a in t) "default" !== a && {}.hasOwnProperty.call(t, a) && ((n = o && Object.getOwnPropertyDescriptor(t, a)) && (n.get || n.set) ? o(f, a, n) : f[a] = t[a]);
10342
+ return f;
10343
+ }
10344
+ var databaseExists = async (name) => (await (0, _storage.readDatabaseList)()).includes(name) || jsEnv.isNode && (0, _storage.databaseFolderExists)(name);
10345
+ var createDatabase = async (name, ifNotExists = false) => {
10346
+ (0, _requireNode.requireNode)('"create database"');
10347
+ const listed = await (0, _storage.readDatabaseList)();
10348
+ if (listed.includes(name) || (0, _storage.databaseFolderExists)(name)) {
10349
+ if (!ifNotExists) {
10350
+ throw new Error(listed.includes(name) ? `Database "${name}" already exists` : `Database "${name}" already exists as a folder that isn't listed: create database if not exists ${name} lists it`);
10351
+ }
10352
+ if (!listed.includes(name)) {
10353
+ await (0, _storage.writeDatabaseList)([...listed, name]);
10354
+ }
10355
+ return null;
10356
+ }
10357
+ await (0, _storage.writeDatabaseList)([...listed, name]);
10358
+ await (0, _storage.makeDatabaseFolder)(name);
10359
+ return name;
8550
10360
  };
8551
- exports.showRecords = showRecords;
10361
+ exports.createDatabase = createDatabase;
10362
+ var dropDatabase = async (name, ifExists = false) => {
10363
+ (0, _requireNode.requireNode)('"drop database"');
10364
+ if (!await databaseExists(name)) {
10365
+ if (ifExists) {
10366
+ return null;
10367
+ }
10368
+ throw new Error(`Database "${name}" doesn't exist`);
10369
+ }
10370
+ if ((0, _config.getSetting)("database", void 0) === name) {
10371
+ throw new Error(`Can't drop the database in use ("${name}"): use another one first`);
10372
+ }
10373
+ await (0, _storage.writeDatabaseList)((await (0, _storage.readDatabaseList)()).filter((listed) => listed !== name));
10374
+ await (0, _storage.removeDatabaseFolder)(name);
10375
+ return name;
10376
+ };
10377
+ exports.dropDatabase = dropDatabase;
10378
+ var useDatabase = async (name) => {
10379
+ if (!jsEnv.isNode && (0, _databaseLock.browserCallsRunning)() > 1) {
10380
+ throw new Error(`Can't use "${name}" while other calls are running in this page: await them first, or pick the database with configure({ database }) between calls`);
10381
+ }
10382
+ if (!await databaseExists(name)) {
10383
+ throw new Error(`Database "${name}" doesn't exist${jsEnv.isNode ? "" : " (or isn't listed in __DATABASES.json)"}`);
10384
+ }
10385
+ (0, _config.switchDatabase)(name);
10386
+ return name;
10387
+ };
10388
+ exports.useDatabase = useDatabase;
10389
+ var showDatabases = async () => (0, _storage.readDatabaseList)();
10390
+ exports.showDatabases = showDatabases;
8552
10391
  }
8553
10392
  });
8554
10393
 
@@ -8824,7 +10663,7 @@ var jsonFsQuery = (() => {
8824
10663
  require_esnext_set_union();
8825
10664
  var _readEntity = require_readEntity();
8826
10665
  var _retrieveRecord = require_retrieveRecord();
8827
- var _retrieveFile = require_retrieveFile();
10666
+ var _retrieveRecords = require_retrieveRecords();
8828
10667
  var _retrieveIndexes = require_retrieveIndexes();
8829
10668
  var _joinKey = require_joinKey();
8830
10669
  var _rowLookup = require_rowLookup();
@@ -8841,15 +10680,7 @@ var jsonFsQuery = (() => {
8841
10680
  }
8842
10681
  }
8843
10682
  const record = await (0, _retrieveRecord.retrieveRecord)(entity);
8844
- const rows = [];
8845
- for (const file of record.entries.filter((entry) => files.has(entry))) {
8846
- const data = await (0, _retrieveFile.retrieveFile)(`${record.path}/${file}`).catch((err) => console.error(err));
8847
- if (!data) {
8848
- throw new Error(`Could not read entity ${file}`);
8849
- }
8850
- rows.push(data);
8851
- }
8852
- return rows;
10683
+ return (0, _retrieveRecords.retrieveEntryRows)(record, record.entries.filter((entry) => files.has(entry)));
8853
10684
  };
8854
10685
  var joinBases = async (entity, joinEntity, dataSets, steps, joinAlreadyResolved) => {
8855
10686
  const bases = /* @__PURE__ */ new Map();
@@ -9289,47 +11120,39 @@ var jsonFsQuery = (() => {
9289
11120
  require_esnext_iterator_constructor();
9290
11121
  require_esnext_iterator_map();
9291
11122
  require_esnext_iterator_reduce();
9292
- var shapeRow = (row, selectClauses) => selectClauses.reduce((shaped, {
11123
+ var pick = (row, property, entity) => {
11124
+ if (Object.prototype.hasOwnProperty.call(row, property) || typeof entity === "undefined" || !property.startsWith(`${entity}.`)) {
11125
+ return row[property];
11126
+ }
11127
+ return row[property.slice(entity.length + 1)];
11128
+ };
11129
+ var shapeRow = (row, selectClauses, entity) => selectClauses.reduce((shaped, {
9293
11130
  property,
9294
11131
  alias
9295
11132
  }) => {
9296
- shaped[alias || property] = row[property];
11133
+ shaped[alias || property] = pick(row, property, entity);
9297
11134
  return shaped;
9298
11135
  }, {});
9299
- var shapeGroup = (group, selectClauses) => group.groups ? {
11136
+ var shapeGroup = (group, selectClauses, entity) => group.groups ? {
9300
11137
  ...group,
9301
- groups: group.groups.map((inner) => shapeGroup(inner, selectClauses))
11138
+ groups: group.groups.map((inner) => shapeGroup(inner, selectClauses, entity))
9302
11139
  } : {
9303
11140
  ...group,
9304
- rows: group.rows.map((row) => shapeRow(row, selectClauses))
11141
+ rows: group.rows.map((row) => shapeRow(row, selectClauses, entity))
9305
11142
  };
9306
- var selectFields = (dataSet = [], selectClauses = [], grouped = false) => {
11143
+ var selectFields = (dataSet = [], selectClauses = [], grouped = false, entity) => {
9307
11144
  if (!selectClauses.length) {
9308
11145
  return dataSet;
9309
11146
  }
9310
11147
  if (grouped) {
9311
- return dataSet.map((group) => shapeGroup(group, selectClauses));
11148
+ return dataSet.map((group) => shapeGroup(group, selectClauses, entity));
9312
11149
  }
9313
- return dataSet.map((row) => shapeRow(row, selectClauses));
11150
+ return dataSet.map((row) => shapeRow(row, selectClauses, entity));
9314
11151
  };
9315
11152
  exports.selectFields = selectFields;
9316
11153
  }
9317
11154
  });
9318
11155
 
9319
- // dist/data/utilities/parsers/isEntityProperty.js
9320
- var require_isEntityProperty = __commonJS({
9321
- "dist/data/utilities/parsers/isEntityProperty.js"(exports) {
9322
- "use strict";
9323
- init_process();
9324
- Object.defineProperty(exports, "__esModule", {
9325
- value: true
9326
- });
9327
- exports.isEntityProperty = void 0;
9328
- var isEntityProperty = (property) => /^[a-z0-9_-]+\.([a-z0-9_-]+)$/i.test(property);
9329
- exports.isEntityProperty = isEntityProperty;
9330
- }
9331
- });
9332
-
9333
11156
  // dist/data/utilities/getConditionIndexedList.js
9334
11157
  var require_getConditionIndexedList = __commonJS({
9335
11158
  "dist/data/utilities/getConditionIndexedList.js"(exports) {
@@ -9363,6 +11186,7 @@ var jsonFsQuery = (() => {
9363
11186
  var _splitEntityProperty = require_splitEntityProperty();
9364
11187
  var _retrieveRecord = require_retrieveRecord();
9365
11188
  var _where = require_where();
11189
+ var _retrieveRecords = require_retrieveRecords();
9366
11190
  var _retrieveFile = require_retrieveFile();
9367
11191
  var _retrieveIndexes = require_retrieveIndexes();
9368
11192
  var _isSingleFieldKey = require_isSingleFieldKey();
@@ -9445,10 +11269,8 @@ var jsonFsQuery = (() => {
9445
11269
  }
9446
11270
  for (const entity of Object.keys(matchedFiles)) {
9447
11271
  resolved.add(entity);
9448
- dataSet[entity] = [];
9449
- for (const file of matchedFiles[entity]) {
9450
- dataSet[entity].push(await (0, _retrieveFile.retrieveFile)(`${entity}/${file}`));
9451
- }
11272
+ const record = recordData[entity] || await (0, _retrieveRecord.retrieveRecord)(entity);
11273
+ dataSet[entity] = await (0, _retrieveRecords.retrieveEntryRows)(record, [...matchedFiles[entity]], _retrieveFile.retrieveFile);
9452
11274
  }
9453
11275
  return parsed;
9454
11276
  };
@@ -9563,6 +11385,8 @@ var jsonFsQuery = (() => {
9563
11385
  var _createRecord = require_createRecord();
9564
11386
  var _dropRecord = require_dropRecord();
9565
11387
  var _describeRecord = require_describeRecord();
11388
+ var _alter = require_alter();
11389
+ var _databaseStatements = require_databaseStatements();
9566
11390
  var _showRecords = require_showRecords();
9567
11391
  var _joinEntity = require_joinEntity();
9568
11392
  var _mergeJoins = require_mergeJoins();
@@ -9579,6 +11403,7 @@ var jsonFsQuery = (() => {
9579
11403
  var _conditionTree = require_conditionTree();
9580
11404
  var _conditionEntities = require_conditionEntities();
9581
11405
  var _requireNode = require_requireNode();
11406
+ var _knownFields = require_knownFields();
9582
11407
  var typeClauses = async (parsed, recordData) => {
9583
11408
  for (const clause of [...(0, _conditionTree.conditionsOf)(parsed.where), ...parsed.sortClauses]) {
9584
11409
  let entity = parsed.entity;
@@ -9597,7 +11422,7 @@ var jsonFsQuery = (() => {
9597
11422
  };
9598
11423
  var runQuery = async (parsed) => {
9599
11424
  const perPair = typeof parsed.where !== "undefined" && (0, _conditionEntities.conditionEntities)(parsed);
9600
- if (["insert", "update", "delete", "create", "drop"].includes(parsed.command)) {
11425
+ if (["insert", "update", "delete", "create", "drop", "alter"].includes(parsed.command)) {
9601
11426
  (0, _requireNode.requireNode)(`"${parsed.command}"`);
9602
11427
  }
9603
11428
  switch (parsed.command) {
@@ -9613,6 +11438,26 @@ var jsonFsQuery = (() => {
9613
11438
  return {
9614
11439
  [parsed.entity]: await (0, _describeRecord.describeRecord)(parsed.entity)
9615
11440
  };
11441
+ case "alter":
11442
+ return {
11443
+ [parsed.entity]: await (0, _alter.alter)(parsed.entity, parsed.alter)
11444
+ };
11445
+ case "create database":
11446
+ return {
11447
+ [parsed.entity]: await (0, _databaseStatements.createDatabase)(parsed.entity, parsed.ifNotExists)
11448
+ };
11449
+ case "drop database":
11450
+ return {
11451
+ [parsed.entity]: await (0, _databaseStatements.dropDatabase)(parsed.entity, parsed.ifExists)
11452
+ };
11453
+ case "use":
11454
+ return {
11455
+ [parsed.entity]: await (0, _databaseStatements.useDatabase)(parsed.entity)
11456
+ };
11457
+ case "show databases":
11458
+ return {
11459
+ [parsed.entity]: await (0, _databaseStatements.showDatabases)()
11460
+ };
9616
11461
  case "show":
9617
11462
  return {
9618
11463
  [parsed.entity]: await (0, _showRecords.showRecords)()
@@ -9624,6 +11469,7 @@ var jsonFsQuery = (() => {
9624
11469
  if (typeof parsed.joinEntity !== "undefined") {
9625
11470
  recordData[parsed.joinEntity] = await (0, _retrieveRecord.retrieveRecord)(parsed.joinEntity);
9626
11471
  }
11472
+ await (0, _knownFields.assertKnownFields)(parsed, recordData);
9627
11473
  await typeClauses(parsed, recordData);
9628
11474
  let dataSet = {
9629
11475
  [parsed.entity]: []
@@ -9663,80 +11509,13 @@ var jsonFsQuery = (() => {
9663
11509
  dataSet[parsed.entity] = (0, _sortBy.sortBy)(dataSet[parsed.entity], parsed.sortClauses);
9664
11510
  dataSet[parsed.entity] = (0, _groupBy.groupBy)(dataSet[parsed.entity], parsed.groupBy);
9665
11511
  dataSet[parsed.entity] = (0, _limitOffset.limitOffset)(dataSet[parsed.entity], parsed.offset, parsed.limit);
9666
- dataSet[parsed.entity] = (0, _selectFields.selectFields)(dataSet[parsed.entity], parsed.selectClauses, Boolean(parsed.groupBy?.length));
11512
+ dataSet[parsed.entity] = (0, _selectFields.selectFields)(dataSet[parsed.entity], parsed.selectClauses, Boolean(parsed.groupBy?.length), parsed.entity);
9667
11513
  return dataSet;
9668
11514
  };
9669
11515
  exports.runQuery = runQuery;
9670
11516
  }
9671
11517
  });
9672
11518
 
9673
- // dist/data/utilities/databaseLock.js
9674
- var require_databaseLock = __commonJS({
9675
- "dist/data/utilities/databaseLock.js"(exports) {
9676
- "use strict";
9677
- init_process();
9678
- require_esnext_weak_map_delete_all();
9679
- Object.defineProperty(exports, "__esModule", {
9680
- value: true
9681
- });
9682
- exports.withDatabaseLock = void 0;
9683
- require_esnext_map_delete_all();
9684
- require_esnext_map_every();
9685
- require_esnext_map_filter();
9686
- require_esnext_map_find();
9687
- require_esnext_map_find_key();
9688
- require_esnext_map_includes();
9689
- require_esnext_map_key_of();
9690
- require_esnext_map_map_keys();
9691
- require_esnext_map_map_values();
9692
- require_esnext_map_merge();
9693
- require_esnext_map_reduce();
9694
- require_esnext_map_some();
9695
- require_esnext_map_update();
9696
- var jsEnv = _interopRequireWildcard(require_dist());
9697
- var _config = require_config();
9698
- var _storage = require_storage();
9699
- var e;
9700
- function _interopRequireWildcard(t, r) {
9701
- if (!r && t && t.__esModule) return t;
9702
- var n, a, o = Object.defineProperty, f = { __proto__: null, default: t };
9703
- if (Object(t) !== t) return f;
9704
- if (e || "function" != typeof WeakMap || (e = /* @__PURE__ */ new WeakMap()), e) {
9705
- if (e.has(t)) return e.get(t);
9706
- e.set(t, f);
9707
- }
9708
- for (a in t) "default" !== a && {}.hasOwnProperty.call(t, a) && ((n = o && Object.getOwnPropertyDescriptor(t, a)) && (n.get || n.set) ? o(f, a, n) : f[a] = t[a]);
9709
- return f;
9710
- }
9711
- var queues = /* @__PURE__ */ new Map();
9712
- var withDatabaseLock = async (task) => {
9713
- if (!jsEnv.isNode) {
9714
- return (0, _storage.withReadCache)(task);
9715
- }
9716
- const database = (0, _config.resolveDatabasePath)((0, _config.getSetting)("databasePath", "database/"));
9717
- const ended = (0, _config.trackDatabaseCall)();
9718
- const previous = queues.get(database) || Promise.resolve();
9719
- let release;
9720
- const turn = new Promise((resolve) => {
9721
- release = resolve;
9722
- });
9723
- const queued = previous.then(() => turn);
9724
- queues.set(database, queued);
9725
- await previous;
9726
- try {
9727
- return await (0, _storage.withReadCache)(task);
9728
- } finally {
9729
- ended();
9730
- release();
9731
- if (queues.get(database) === queued) {
9732
- queues.delete(database);
9733
- }
9734
- }
9735
- };
9736
- exports.withDatabaseLock = withDatabaseLock;
9737
- }
9738
- });
9739
-
9740
11519
  // dist/data/queries/query.js
9741
11520
  var require_query = __commonJS({
9742
11521
  "dist/data/queries/query.js"(exports) {
@@ -9749,12 +11528,13 @@ var jsonFsQuery = (() => {
9749
11528
  var _parser = require_parser();
9750
11529
  var _runQuery = require_runQuery();
9751
11530
  var _databaseLock = require_databaseLock();
11531
+ var _storage = require_storage();
9752
11532
  var query = async (queryString = "") => {
9753
11533
  const parsedQueries = (0, _parser.parser)(queryString);
9754
11534
  return (0, _databaseLock.withDatabaseLock)(async () => {
9755
11535
  const queryResults = [];
9756
11536
  for (const parsed of parsedQueries) {
9757
- const dataSet = await (0, _runQuery.runQuery)(parsed);
11537
+ const dataSet = await (0, _storage.withWriteSet)(() => (0, _runQuery.runQuery)(parsed));
9758
11538
  queryResults.push(dataSet[parsed.entity]);
9759
11539
  }
9760
11540
  return queryResults;
@@ -9827,6 +11607,150 @@ var jsonFsQuery = (() => {
9827
11607
  }
9828
11608
  });
9829
11609
 
11610
+ // dist/data/introspect/formatDatabase.js
11611
+ var require_formatDatabase = __commonJS({
11612
+ "dist/data/introspect/formatDatabase.js"(exports) {
11613
+ "use strict";
11614
+ init_process();
11615
+ Object.defineProperty(exports, "__esModule", {
11616
+ value: true
11617
+ });
11618
+ exports.formatDatabase = void 0;
11619
+ require_esnext_iterator_constructor();
11620
+ require_esnext_iterator_filter();
11621
+ var _storage = require_storage();
11622
+ var _config = require_config();
11623
+ var _requireNode = require_requireNode();
11624
+ var formatDatabase = async (format = (0, _config.getSetting)("format", "compact")) => {
11625
+ (0, _requireNode.requireNode)("formatDatabase");
11626
+ if (format !== "compact" && format !== "pretty") {
11627
+ throw new Error(`Unknown format "${format}": use 'compact' or 'pretty'`);
11628
+ }
11629
+ const paths = (await (0, _storage.listFiles)()).filter((path) => path.endsWith(".json"));
11630
+ const changes = [];
11631
+ for (const path of paths) {
11632
+ const text = await (0, _storage.readText)(path);
11633
+ let content;
11634
+ try {
11635
+ content = JSON.parse(text);
11636
+ } catch (error) {
11637
+ throw new Error(`Could not format ${path}: ${error.message}`);
11638
+ }
11639
+ if ((0, _storage.jsonText)(content, format) !== text) {
11640
+ changes.push({
11641
+ path,
11642
+ content
11643
+ });
11644
+ }
11645
+ }
11646
+ for (const {
11647
+ path,
11648
+ content
11649
+ } of changes) {
11650
+ await (0, _storage.writeJson)(path, content, format);
11651
+ }
11652
+ return {
11653
+ files: paths.length,
11654
+ rewritten: changes.length
11655
+ };
11656
+ };
11657
+ exports.formatDatabase = formatDatabase;
11658
+ }
11659
+ });
11660
+
11661
+ // dist/data/introspect/packDatabase.js
11662
+ var require_packDatabase = __commonJS({
11663
+ "dist/data/introspect/packDatabase.js"(exports) {
11664
+ "use strict";
11665
+ init_process();
11666
+ Object.defineProperty(exports, "__esModule", {
11667
+ value: true
11668
+ });
11669
+ exports.packDatabase = exports.checkPacked = void 0;
11670
+ require_es_json_stringify();
11671
+ require_esnext_iterator_constructor();
11672
+ require_esnext_iterator_filter();
11673
+ require_esnext_iterator_map();
11674
+ require_esnext_set_add_all();
11675
+ require_esnext_set_delete_all();
11676
+ require_esnext_set_difference();
11677
+ require_esnext_set_every();
11678
+ require_esnext_set_filter();
11679
+ require_esnext_set_find();
11680
+ require_esnext_set_intersection();
11681
+ require_esnext_set_is_disjoint_from();
11682
+ require_esnext_set_is_subset_of();
11683
+ require_esnext_set_is_superset_of();
11684
+ require_esnext_set_join();
11685
+ require_esnext_set_map();
11686
+ require_esnext_set_reduce();
11687
+ require_esnext_set_some();
11688
+ require_esnext_set_symmetric_difference();
11689
+ require_esnext_set_union();
11690
+ var _storage = require_storage();
11691
+ var _retrieveRecord = require_retrieveRecord();
11692
+ var _retrieveFiles = require_retrieveFiles();
11693
+ var _retrieveRecords = require_retrieveRecords();
11694
+ var _packedTable = require_packedTable();
11695
+ var _showRecords = require_showRecords();
11696
+ var _requireNode = require_requireNode();
11697
+ var packedText = async (name) => {
11698
+ const record = await (0, _retrieveRecord.retrieveRecord)(name);
11699
+ const entries = record.entries || [];
11700
+ const rows = await (0, _retrieveFiles.retrieveFiles)(entries.map((file) => `${record.path}/${file}`), _retrieveRecords.retrieveEntry);
11701
+ const packed = {
11702
+ entries,
11703
+ rows
11704
+ };
11705
+ return {
11706
+ path: (0, _packedTable.packedPath)(record.path),
11707
+ text: (0, _storage.jsonText)(packed, "compact"),
11708
+ rows: entries.length
11709
+ };
11710
+ };
11711
+ var orphanedPacks = async (names) => {
11712
+ const expected = new Set(names.map((name) => (0, _packedTable.packedPath)(name)));
11713
+ return (await (0, _storage.listFiles)("__packed")).filter((path) => !expected.has(path));
11714
+ };
11715
+ var packDatabase = async () => {
11716
+ (0, _requireNode.requireNode)("packDatabase");
11717
+ const names = await (0, _showRecords.showRecords)();
11718
+ let rows = 0;
11719
+ for (const name of names) {
11720
+ const packed = await packedText(name);
11721
+ await (0, _storage.makeDirectory)(packed.path.slice(0, packed.path.lastIndexOf("/")));
11722
+ await (0, _storage.writeJson)(packed.path, JSON.parse(packed.text), "compact");
11723
+ rows += packed.rows;
11724
+ }
11725
+ for (const path of await orphanedPacks(names)) {
11726
+ await (0, _storage.removeFile)(path);
11727
+ }
11728
+ return {
11729
+ records: names.length,
11730
+ rows
11731
+ };
11732
+ };
11733
+ exports.packDatabase = packDatabase;
11734
+ var checkPacked = async () => {
11735
+ (0, _requireNode.requireNode)("checkPacked");
11736
+ const names = await (0, _showRecords.showRecords)();
11737
+ const stale = [];
11738
+ for (const name of names) {
11739
+ const packed = await packedText(name);
11740
+ const current = (0, _storage.fileExists)(packed.path) ? await (0, _storage.readText)(packed.path).catch(() => void 0) : void 0;
11741
+ if (typeof current === "undefined" || JSON.stringify(JSON.parse(current)) !== packed.text) {
11742
+ stale.push(name);
11743
+ }
11744
+ }
11745
+ return {
11746
+ stale,
11747
+ orphaned: await orphanedPacks(names)
11748
+ };
11749
+ };
11750
+ exports.checkPacked = checkPacked;
11751
+ }
11752
+ });
11753
+
9830
11754
  // dist/data/introspect/index.js
9831
11755
  var require_introspect = __commonJS({
9832
11756
  "dist/data/introspect/index.js"(exports) {
@@ -9839,17 +11763,29 @@ var jsonFsQuery = (() => {
9839
11763
  Object.defineProperty(exports, "__esModule", {
9840
11764
  value: true
9841
11765
  });
9842
- exports.drop = exports.describe = exports.create = void 0;
11766
+ exports.packDatabase = exports.formatDatabase = exports.drop = exports.describe = exports.create = exports.checkPacked = exports.alter = void 0;
9843
11767
  var _create = require_create();
9844
11768
  var _drop = require_drop();
9845
11769
  var _describe = require_describe();
11770
+ var _formatDatabase = require_formatDatabase();
11771
+ var _alter = require_alter();
11772
+ var _packDatabase = require_packDatabase();
9846
11773
  var _databaseLock = require_databaseLock();
9847
- var create = (...args) => (0, _databaseLock.withDatabaseLock)(() => (0, _create.create)(...args));
11774
+ var _storage = require_storage();
11775
+ var create = (...args) => (0, _databaseLock.withDatabaseLock)(() => (0, _storage.withWriteSet)(() => (0, _create.create)(...args)));
9848
11776
  exports.create = create;
9849
- var drop = (...args) => (0, _databaseLock.withDatabaseLock)(() => (0, _drop.drop)(...args));
11777
+ var drop = (...args) => (0, _databaseLock.withDatabaseLock)(() => (0, _storage.withWriteSet)(() => (0, _drop.drop)(...args)));
9850
11778
  exports.drop = drop;
11779
+ var alter = (...args) => (0, _databaseLock.withDatabaseLock)(() => (0, _storage.withWriteSet)(() => (0, _alter.alter)(...args)));
11780
+ exports.alter = alter;
9851
11781
  var describe = (...args) => (0, _databaseLock.withDatabaseLock)(() => (0, _describe.describe)(...args));
9852
11782
  exports.describe = describe;
11783
+ var formatDatabase = (...args) => (0, _databaseLock.withDatabaseLock)(() => (0, _storage.withWriteSet)(() => (0, _formatDatabase.formatDatabase)(...args)));
11784
+ exports.formatDatabase = formatDatabase;
11785
+ var packDatabase = () => (0, _databaseLock.withDatabaseLock)(() => (0, _storage.withWriteSet)(() => (0, _packDatabase.packDatabase)()));
11786
+ exports.packDatabase = packDatabase;
11787
+ var checkPacked = () => (0, _databaseLock.withDatabaseLock)(() => (0, _packDatabase.checkPacked)());
11788
+ exports.checkPacked = checkPacked;
9853
11789
  }
9854
11790
  });
9855
11791
 
@@ -9864,6 +11800,18 @@ var jsonFsQuery = (() => {
9864
11800
  Object.defineProperty(exports, "__esModule", {
9865
11801
  value: true
9866
11802
  });
11803
+ Object.defineProperty(exports, "alter", {
11804
+ enumerable: true,
11805
+ get: function() {
11806
+ return _introspect.alter;
11807
+ }
11808
+ });
11809
+ Object.defineProperty(exports, "checkPacked", {
11810
+ enumerable: true,
11811
+ get: function() {
11812
+ return _introspect.checkPacked;
11813
+ }
11814
+ });
9867
11815
  Object.defineProperty(exports, "configure", {
9868
11816
  enumerable: true,
9869
11817
  get: function() {
@@ -9888,6 +11836,18 @@ var jsonFsQuery = (() => {
9888
11836
  return _introspect.drop;
9889
11837
  }
9890
11838
  });
11839
+ Object.defineProperty(exports, "formatDatabase", {
11840
+ enumerable: true,
11841
+ get: function() {
11842
+ return _introspect.formatDatabase;
11843
+ }
11844
+ });
11845
+ Object.defineProperty(exports, "packDatabase", {
11846
+ enumerable: true,
11847
+ get: function() {
11848
+ return _introspect.packDatabase;
11849
+ }
11850
+ });
9891
11851
  Object.defineProperty(exports, "query", {
9892
11852
  enumerable: true,
9893
11853
  get: function() {