velocious 1.0.674 → 1.0.676

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 (31) hide show
  1. package/README.md +4 -2
  2. package/build/database/query/model-class-query.js +25 -2
  3. package/build/database/query/order-base.js +9 -0
  4. package/build/database/query/order-column.js +10 -0
  5. package/build/database/query/order-plain.js +16 -0
  6. package/build/src/database/query/model-class-query.d.ts +10 -0
  7. package/build/src/database/query/model-class-query.d.ts.map +1 -1
  8. package/build/src/database/query/model-class-query.js +24 -3
  9. package/build/src/database/query/order-base.d.ts +6 -0
  10. package/build/src/database/query/order-base.d.ts.map +1 -1
  11. package/build/src/database/query/order-base.js +9 -1
  12. package/build/src/database/query/order-column.d.ts +5 -0
  13. package/build/src/database/query/order-column.d.ts.map +1 -1
  14. package/build/src/database/query/order-column.js +9 -1
  15. package/build/src/database/query/order-plain.d.ts +5 -0
  16. package/build/src/database/query/order-plain.d.ts.map +1 -1
  17. package/build/src/database/query/order-plain.js +14 -1
  18. package/build/src/testing/browser-frontend-tenant-database-scenarios.d.ts +11 -0
  19. package/build/src/testing/browser-frontend-tenant-database-scenarios.d.ts.map +1 -0
  20. package/build/src/testing/browser-frontend-tenant-database-scenarios.js +147 -0
  21. package/build/src/testing/browser-test-app.js +3 -1
  22. package/build/testing/browser-frontend-tenant-database-scenarios.js +158 -0
  23. package/build/testing/browser-test-app.js +2 -0
  24. package/package.json +1 -1
  25. package/scripts/test-browser.js +5 -0
  26. package/src/database/query/model-class-query.js +25 -2
  27. package/src/database/query/order-base.js +9 -0
  28. package/src/database/query/order-column.js +10 -0
  29. package/src/database/query/order-plain.js +16 -0
  30. package/src/testing/browser-frontend-tenant-database-scenarios.js +158 -0
  31. package/src/testing/browser-test-app.js +2 -0
@@ -17,6 +17,12 @@ export default class VelociousDatabaseQueryOrderBase {
17
17
  * @returns {void} - No return value.
18
18
  */
19
19
  setReverseOrder(_reverseOrder: boolean): void;
20
+ /**
21
+ * Runs reversed copy.
22
+ * @abstract
23
+ * @returns {import("./order-base.js").default} - A new independent order with the direction reversed.
24
+ */
25
+ reversedCopy(): import("./order-base.js").default;
20
26
  toSql(): void;
21
27
  }
22
28
  //# sourceMappingURL=order-base.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"order-base.d.ts","sourceRoot":"","sources":["../../../../src/database/query/order-base.js"],"names":[],"mappings":"AAEA,MAAM,CAAC,OAAO,OAAO,+BAA+B;IAM3C,KAAK;IALZ;;;OAGG;IACH,YAAY,KAAK,EAFN,OAAO,YAAY,EAAE,OAEf,EAEhB;IAED;;;OAGG;IACH,UAAU,IAFG,OAAO,4BAA4B,EAAE,OAAO,CAIxD;IAED;;;;;OAKG;IACH,eAAe,CAAC,aAAa,EAHlB,OAGkB,GAFhB,IAAI,CAIhB;IAED,KAAK,SAEJ;CACF"}
1
+ {"version":3,"file":"order-base.d.ts","sourceRoot":"","sources":["../../../../src/database/query/order-base.js"],"names":[],"mappings":"AAEA,MAAM,CAAC,OAAO,OAAO,+BAA+B;IAM3C,KAAK;IALZ;;;OAGG;IACH,YAAY,KAAK,EAFN,OAAO,YAAY,EAAE,OAEf,EAEhB;IAED;;;OAGG;IACH,UAAU,IAFG,OAAO,4BAA4B,EAAE,OAAO,CAIxD;IAED;;;;;OAKG;IACH,eAAe,CAAC,aAAa,EAHlB,OAGkB,GAFhB,IAAI,CAIhB;IAED;;;;OAIG;IACH,YAAY,IAFC,OAAO,iBAAiB,EAAE,OAAO,CAI7C;IAED,KAAK,SAEJ;CACF"}
@@ -23,8 +23,16 @@ export default class VelociousDatabaseQueryOrderBase {
23
23
  setReverseOrder(_reverseOrder) {
24
24
  throw new Error("setReverseOrder not implemented");
25
25
  }
26
+ /**
27
+ * Runs reversed copy.
28
+ * @abstract
29
+ * @returns {import("./order-base.js").default} - A new independent order with the direction reversed.
30
+ */
31
+ reversedCopy() {
32
+ throw new Error("reversedCopy not implemented");
33
+ }
26
34
  toSql() {
27
35
  throw new Error("'toSql' wasn't implemented");
28
36
  }
29
37
  }
30
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3JkZXItYmFzZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9kYXRhYmFzZS9xdWVyeS9vcmRlci1iYXNlLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLFlBQVk7QUFFWixNQUFNLENBQUMsT0FBTyxPQUFPLCtCQUErQjtJQUNsRDs7O09BR0c7SUFDSCxZQUFZLEtBQUs7UUFDZixJQUFJLENBQUMsS0FBSyxHQUFHLEtBQUssQ0FBQTtJQUNwQixDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsVUFBVTtRQUNSLE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsT0FBTyxFQUFFLENBQUE7SUFDcEMsQ0FBQztJQUVEOzs7OztPQUtHO0lBQ0gsZUFBZSxDQUFDLGFBQWE7UUFDM0IsTUFBTSxJQUFJLEtBQUssQ0FBQyxpQ0FBaUMsQ0FBQyxDQUFBO0lBQ3BELENBQUM7SUFFRCxLQUFLO1FBQ0gsTUFBTSxJQUFJLEtBQUssQ0FBQyw0QkFBNEIsQ0FBQyxDQUFBO0lBQy9DLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8vIEB0cy1jaGVja1xuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBWZWxvY2lvdXNEYXRhYmFzZVF1ZXJ5T3JkZXJCYXNlIHtcbiAgLyoqXG4gICAqIFJ1bnMgY29uc3RydWN0b3IuXG4gICAqIEBwYXJhbSB7aW1wb3J0KFwiLi9pbmRleC5qc1wiKS5kZWZhdWx0fSBxdWVyeSAtIFF1ZXJ5IGluc3RhbmNlLlxuICAgKi9cbiAgY29uc3RydWN0b3IocXVlcnkpIHtcbiAgICB0aGlzLnF1ZXJ5ID0gcXVlcnlcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGdldCBvcHRpb25zLlxuICAgKiBAcmV0dXJucyB7aW1wb3J0KFwiLi4vcXVlcnktcGFyc2VyL29wdGlvbnMuanNcIikuZGVmYXVsdH0gLSBUaGUgb3B0aW9ucyBvcHRpb25zLlxuICAgKi9cbiAgZ2V0T3B0aW9ucygpIHtcbiAgICByZXR1cm4gdGhpcy5xdWVyeS5kcml2ZXIub3B0aW9ucygpXG4gIH1cblxuICAvKipcbiAgICogUnVucyBzZXQgcmV2ZXJzZSBvcmRlci5cbiAgICogQGFic3RyYWN0XG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gX3JldmVyc2VPcmRlciAtIFdoZXRoZXIgcmV2ZXJzZSBvcmRlci5cbiAgICogQHJldHVybnMge3ZvaWR9IC0gTm8gcmV0dXJuIHZhbHVlLlxuICAgKi9cbiAgc2V0UmV2ZXJzZU9yZGVyKF9yZXZlcnNlT3JkZXIpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXCJzZXRSZXZlcnNlT3JkZXIgbm90IGltcGxlbWVudGVkXCIpXG4gIH1cblxuICB0b1NxbCgpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXCIndG9TcWwnIHdhc24ndCBpbXBsZW1lbnRlZFwiKVxuICB9XG59XG4iXX0=
38
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3JkZXItYmFzZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9kYXRhYmFzZS9xdWVyeS9vcmRlci1iYXNlLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLFlBQVk7QUFFWixNQUFNLENBQUMsT0FBTyxPQUFPLCtCQUErQjtJQUNsRDs7O09BR0c7SUFDSCxZQUFZLEtBQUs7UUFDZixJQUFJLENBQUMsS0FBSyxHQUFHLEtBQUssQ0FBQTtJQUNwQixDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsVUFBVTtRQUNSLE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsT0FBTyxFQUFFLENBQUE7SUFDcEMsQ0FBQztJQUVEOzs7OztPQUtHO0lBQ0gsZUFBZSxDQUFDLGFBQWE7UUFDM0IsTUFBTSxJQUFJLEtBQUssQ0FBQyxpQ0FBaUMsQ0FBQyxDQUFBO0lBQ3BELENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsWUFBWTtRQUNWLE1BQU0sSUFBSSxLQUFLLENBQUMsOEJBQThCLENBQUMsQ0FBQTtJQUNqRCxDQUFDO0lBRUQsS0FBSztRQUNILE1BQU0sSUFBSSxLQUFLLENBQUMsNEJBQTRCLENBQUMsQ0FBQTtJQUMvQyxDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBAdHMtY2hlY2tcblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgVmVsb2Npb3VzRGF0YWJhc2VRdWVyeU9yZGVyQmFzZSB7XG4gIC8qKlxuICAgKiBSdW5zIGNvbnN0cnVjdG9yLlxuICAgKiBAcGFyYW0ge2ltcG9ydChcIi4vaW5kZXguanNcIikuZGVmYXVsdH0gcXVlcnkgLSBRdWVyeSBpbnN0YW5jZS5cbiAgICovXG4gIGNvbnN0cnVjdG9yKHF1ZXJ5KSB7XG4gICAgdGhpcy5xdWVyeSA9IHF1ZXJ5XG4gIH1cblxuICAvKipcbiAgICogUnVucyBnZXQgb3B0aW9ucy5cbiAgICogQHJldHVybnMge2ltcG9ydChcIi4uL3F1ZXJ5LXBhcnNlci9vcHRpb25zLmpzXCIpLmRlZmF1bHR9IC0gVGhlIG9wdGlvbnMgb3B0aW9ucy5cbiAgICovXG4gIGdldE9wdGlvbnMoKSB7XG4gICAgcmV0dXJuIHRoaXMucXVlcnkuZHJpdmVyLm9wdGlvbnMoKVxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgc2V0IHJldmVyc2Ugb3JkZXIuXG4gICAqIEBhYnN0cmFjdFxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IF9yZXZlcnNlT3JkZXIgLSBXaGV0aGVyIHJldmVyc2Ugb3JkZXIuXG4gICAqIEByZXR1cm5zIHt2b2lkfSAtIE5vIHJldHVybiB2YWx1ZS5cbiAgICovXG4gIHNldFJldmVyc2VPcmRlcihfcmV2ZXJzZU9yZGVyKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFwic2V0UmV2ZXJzZU9yZGVyIG5vdCBpbXBsZW1lbnRlZFwiKVxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgcmV2ZXJzZWQgY29weS5cbiAgICogQGFic3RyYWN0XG4gICAqIEByZXR1cm5zIHtpbXBvcnQoXCIuL29yZGVyLWJhc2UuanNcIikuZGVmYXVsdH0gLSBBIG5ldyBpbmRlcGVuZGVudCBvcmRlciB3aXRoIHRoZSBkaXJlY3Rpb24gcmV2ZXJzZWQuXG4gICAqL1xuICByZXZlcnNlZENvcHkoKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFwicmV2ZXJzZWRDb3B5IG5vdCBpbXBsZW1lbnRlZFwiKVxuICB9XG5cbiAgdG9TcWwoKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFwiJ3RvU3FsJyB3YXNuJ3QgaW1wbGVtZW50ZWRcIilcbiAgfVxufVxuIl19
@@ -30,6 +30,11 @@ export default class VelociousDatabaseQueryOrderColumn extends OrderBase {
30
30
  * @returns {void}
31
31
  */
32
32
  setReverseOrder(reverseOrder?: boolean): void;
33
+ /**
34
+ * Runs reversed copy.
35
+ * @returns {VelociousDatabaseQueryOrderColumn} - A new independent order reversing the effective (rendered) direction.
36
+ */
37
+ reversedCopy(): VelociousDatabaseQueryOrderColumn;
33
38
  /**
34
39
  * Runs to sql.
35
40
  * @returns {string} - SQL string.
@@ -1 +1 @@
1
- {"version":3,"file":"order-column.d.ts","sourceRoot":"","sources":["../../../../src/database/query/order-column.js"],"names":[],"mappings":"AAEA,OAAO,SAAS,MAAM,iBAAiB,CAAA;AAIpC,YAAkB,gBAAgB,GAClC;;;;IAAmB,MAAM,EAAd,MAAM,CACjB;;;;IAA6C,SAAS,AAAtD,CACA,EADW,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,CAC1C;;;;IAAoB,SAAS,AAA7B,CACF,EADa,MAAM,CACnB;CAAA,CAAA;AAyBD,MAAM,CAAC,OAAO,OAAO,iCAAkC,SAAQ,SAAS;IAW/D,MAAM;IACN,SAAS;IACT,YAAY;IACZ,SAAS;IAbhB;;;;OAIG;IACH,YAAY,KAAK,EAHN,OAAO,YAAY,EAAE,OAGf,EAAE,KAAK,EAFb,gBAEa,EASvB;IAED;;;;OAIG;IACH,eAAe,CAAC,YAAY,AAHzB,CACA,EADQ,OAGwB,GAFtB,IAAI,CAIhB;IAED;;;OAGG;IACH,KAAK,IAFQ,MAAM,CAYlB;CACF"}
1
+ {"version":3,"file":"order-column.d.ts","sourceRoot":"","sources":["../../../../src/database/query/order-column.js"],"names":[],"mappings":"AAEA,OAAO,SAAS,MAAM,iBAAiB,CAAA;AAIpC,YAAkB,gBAAgB,GAClC;;;;IAAmB,MAAM,EAAd,MAAM,CACjB;;;;IAA6C,SAAS,AAAtD,CACA,EADW,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,CAC1C;;;;IAAoB,SAAS,AAA7B,CACF,EADa,MAAM,CACnB;CAAA,CAAA;AAyBD,MAAM,CAAC,OAAO,OAAO,iCAAkC,SAAQ,SAAS;IAW/D,MAAM;IACN,SAAS;IACT,YAAY;IACZ,SAAS;IAbhB;;;;OAIG;IACH,YAAY,KAAK,EAHN,OAAO,YAAY,EAAE,OAGf,EAAE,KAAK,EAFb,gBAEa,EASvB;IAED;;;;OAIG;IACH,eAAe,CAAC,YAAY,AAHzB,CACA,EADQ,OAGwB,GAFtB,IAAI,CAIhB;IAED;;;OAGG;IACH,YAAY,IAFC,iCAAiC,CAM7C;IAED;;;OAGG;IACH,KAAK,IAFQ,MAAM,CAYlB;CACF"}
@@ -51,6 +51,14 @@ export default class VelociousDatabaseQueryOrderColumn extends OrderBase {
51
51
  setReverseOrder(reverseOrder = true) {
52
52
  this.reverseOrder = reverseOrder;
53
53
  }
54
+ /**
55
+ * Runs reversed copy.
56
+ * @returns {VelociousDatabaseQueryOrderColumn} - A new independent order reversing the effective (rendered) direction.
57
+ */
58
+ reversedCopy() {
59
+ const direction = this.reverseOrder ? this.direction : reverseDirection(this.direction);
60
+ return new VelociousDatabaseQueryOrderColumn(this.query, { column: this.column, direction, tableName: this.tableName });
61
+ }
54
62
  /**
55
63
  * Runs to sql.
56
64
  * @returns {string} - SQL string.
@@ -65,4 +73,4 @@ export default class VelociousDatabaseQueryOrderColumn extends OrderBase {
65
73
  return sql;
66
74
  }
67
75
  }
68
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3JkZXItY29sdW1uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2RhdGFiYXNlL3F1ZXJ5L29yZGVyLWNvbHVtbi5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxZQUFZO0FBRVosT0FBTyxTQUFTLE1BQU0saUJBQWlCLENBQUE7QUFFdkM7Ozs7OztHQU1HO0FBRUg7Ozs7R0FJRztBQUNILFNBQVMsa0JBQWtCLENBQUMsU0FBUztJQUNuQyxJQUFJLE9BQU8sU0FBUyxJQUFJLFdBQVc7UUFBRSxPQUFPLEtBQUssQ0FBQTtJQUVqRCxNQUFNLFVBQVUsR0FBRyxTQUFTLENBQUMsV0FBVyxFQUFFLENBQUE7SUFDMUMsSUFBSSxVQUFVLElBQUksS0FBSyxJQUFJLFVBQVUsSUFBSSxNQUFNO1FBQUUsT0FBTyxVQUFVLENBQUE7SUFFbEUsTUFBTSxJQUFJLEtBQUssQ0FBQyw0QkFBNEIsU0FBUyxFQUFFLENBQUMsQ0FBQTtBQUMxRCxDQUFDO0FBRUQ7Ozs7R0FJRztBQUNILFNBQVMsZ0JBQWdCLENBQUMsU0FBUztJQUNqQyxPQUFPLFNBQVMsSUFBSSxLQUFLLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFBO0FBQzVDLENBQUM7QUFFRCxNQUFNLENBQUMsT0FBTyxPQUFPLGlDQUFrQyxTQUFRLFNBQVM7SUFDdEU7Ozs7T0FJRztJQUNILFlBQVksS0FBSyxFQUFFLEtBQUs7UUFDdEIsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFBO1FBRVosSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNO1lBQUUsTUFBTSxJQUFJLEtBQUssQ0FBQywwQkFBMEIsQ0FBQyxDQUFBO1FBRTlELElBQUksQ0FBQyxNQUFNLEdBQUcsS0FBSyxDQUFDLE1BQU0sQ0FBQTtRQUMxQixJQUFJLENBQUMsU0FBUyxHQUFHLGtCQUFrQixDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsQ0FBQTtRQUNwRCxJQUFJLENBQUMsWUFBWSxHQUFHLEtBQUssQ0FBQTtRQUN6QixJQUFJLENBQUMsU0FBUyxHQUFHLEtBQUssQ0FBQyxTQUFTLENBQUE7SUFDbEMsQ0FBQztJQUVEOzs7O09BSUc7SUFDSCxlQUFlLENBQUMsWUFBWSxHQUFHLElBQUk7UUFDakMsSUFBSSxDQUFDLFlBQVksR0FBRyxZQUFZLENBQUE7SUFDbEMsQ0FBQztJQUVEOzs7T0FHRztJQUNILEtBQUs7UUFDSCxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUE7UUFDakMsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFBO1FBQ3ZGLElBQUksR0FBRyxHQUFHLEVBQUUsQ0FBQTtRQUVaLElBQUksSUFBSSxDQUFDLFNBQVM7WUFBRSxHQUFHLElBQUksR0FBRyxPQUFPLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFBO1FBRXZFLEdBQUcsSUFBSSxHQUFHLE9BQU8sQ0FBQyxlQUFlLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLFNBQVMsRUFBRSxDQUFBO1FBRTdELE9BQU8sR0FBRyxDQUFBO0lBQ1osQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQHRzLWNoZWNrXG5cbmltcG9ydCBPcmRlckJhc2UgZnJvbSBcIi4vb3JkZXItYmFzZS5qc1wiXG5cbi8qKlxuICogT3JkZXJDb2x1bW5JbnB1dCB0eXBlLlxuICogQHR5cGVkZWYge29iamVjdH0gT3JkZXJDb2x1bW5JbnB1dFxuICogQHByb3BlcnR5IHtzdHJpbmd9IGNvbHVtbiAtIENvbHVtbiBuYW1lLlxuICogQHByb3BlcnR5IHtcIkFTQ1wiIHwgXCJERVNDXCIgfCBcImFzY1wiIHwgXCJkZXNjXCJ9IFtkaXJlY3Rpb25dIC0gU29ydCBkaXJlY3Rpb24uXG4gKiBAcHJvcGVydHkge3N0cmluZ30gW3RhYmxlTmFtZV0gLSBPcHRpb25hbCB0YWJsZSBvciBhbGlhcyBuYW1lLlxuICovXG5cbi8qKlxuICogUnVucyBub3JtYWxpemUgZGlyZWN0aW9uLlxuICogQHBhcmFtIHtzdHJpbmcgfCB1bmRlZmluZWR9IGRpcmVjdGlvbiAtIERpcmVjdGlvbiBpbnB1dC5cbiAqIEByZXR1cm5zIHtcIkFTQ1wiIHwgXCJERVNDXCJ9IC0gTm9ybWFsaXplZCBkaXJlY3Rpb24uXG4gKi9cbmZ1bmN0aW9uIG5vcm1hbGl6ZURpcmVjdGlvbihkaXJlY3Rpb24pIHtcbiAgaWYgKHR5cGVvZiBkaXJlY3Rpb24gPT0gXCJ1bmRlZmluZWRcIikgcmV0dXJuIFwiQVNDXCJcblxuICBjb25zdCBub3JtYWxpemVkID0gZGlyZWN0aW9uLnRvVXBwZXJDYXNlKClcbiAgaWYgKG5vcm1hbGl6ZWQgPT0gXCJBU0NcIiB8fCBub3JtYWxpemVkID09IFwiREVTQ1wiKSByZXR1cm4gbm9ybWFsaXplZFxuXG4gIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCBvcmRlciBkaXJlY3Rpb246ICR7ZGlyZWN0aW9ufWApXG59XG5cbi8qKlxuICogUnVucyByZXZlcnNlIGRpcmVjdGlvbi5cbiAqIEBwYXJhbSB7XCJBU0NcIiB8IFwiREVTQ1wifSBkaXJlY3Rpb24gLSBEaXJlY3Rpb24uXG4gKiBAcmV0dXJucyB7XCJBU0NcIiB8IFwiREVTQ1wifSAtIFJldmVyc2VkIGRpcmVjdGlvbi5cbiAqL1xuZnVuY3Rpb24gcmV2ZXJzZURpcmVjdGlvbihkaXJlY3Rpb24pIHtcbiAgcmV0dXJuIGRpcmVjdGlvbiA9PSBcIkFTQ1wiID8gXCJERVNDXCIgOiBcIkFTQ1wiXG59XG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFZlbG9jaW91c0RhdGFiYXNlUXVlcnlPcmRlckNvbHVtbiBleHRlbmRzIE9yZGVyQmFzZSB7XG4gIC8qKlxuICAgKiBSdW5zIGNvbnN0cnVjdG9yLlxuICAgKiBAcGFyYW0ge2ltcG9ydChcIi4vaW5kZXguanNcIikuZGVmYXVsdH0gcXVlcnkgLSBRdWVyeSBpbnN0YW5jZS5cbiAgICogQHBhcmFtIHtPcmRlckNvbHVtbklucHV0fSBpbnB1dCAtIENvbHVtbiBvcmRlciBpbnB1dC5cbiAgICovXG4gIGNvbnN0cnVjdG9yKHF1ZXJ5LCBpbnB1dCkge1xuICAgIHN1cGVyKHF1ZXJ5KVxuXG4gICAgaWYgKCFpbnB1dC5jb2x1bW4pIHRocm93IG5ldyBFcnJvcihcIk9yZGVyIGNvbHVtbiBpcyByZXF1aXJlZFwiKVxuXG4gICAgdGhpcy5jb2x1bW4gPSBpbnB1dC5jb2x1bW5cbiAgICB0aGlzLmRpcmVjdGlvbiA9IG5vcm1hbGl6ZURpcmVjdGlvbihpbnB1dC5kaXJlY3Rpb24pXG4gICAgdGhpcy5yZXZlcnNlT3JkZXIgPSBmYWxzZVxuICAgIHRoaXMudGFibGVOYW1lID0gaW5wdXQudGFibGVOYW1lXG4gIH1cblxuICAvKipcbiAgICogUnVucyBzZXQgcmV2ZXJzZSBvcmRlci5cbiAgICogQHBhcmFtIHtib29sZWFufSBbcmV2ZXJzZU9yZGVyXSAtIFdoZXRoZXIgdG8gcmV2ZXJzZSB0aGUgb3JkZXIuXG4gICAqIEByZXR1cm5zIHt2b2lkfVxuICAgKi9cbiAgc2V0UmV2ZXJzZU9yZGVyKHJldmVyc2VPcmRlciA9IHRydWUpIHtcbiAgICB0aGlzLnJldmVyc2VPcmRlciA9IHJldmVyc2VPcmRlclxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgdG8gc3FsLlxuICAgKiBAcmV0dXJucyB7c3RyaW5nfSAtIFNRTCBzdHJpbmcuXG4gICAqL1xuICB0b1NxbCgpIHtcbiAgICBjb25zdCBvcHRpb25zID0gdGhpcy5nZXRPcHRpb25zKClcbiAgICBjb25zdCBkaXJlY3Rpb24gPSB0aGlzLnJldmVyc2VPcmRlciA/IHJldmVyc2VEaXJlY3Rpb24odGhpcy5kaXJlY3Rpb24pIDogdGhpcy5kaXJlY3Rpb25cbiAgICBsZXQgc3FsID0gXCJcIlxuXG4gICAgaWYgKHRoaXMudGFibGVOYW1lKSBzcWwgKz0gYCR7b3B0aW9ucy5xdW90ZVRhYmxlTmFtZSh0aGlzLnRhYmxlTmFtZSl9LmBcblxuICAgIHNxbCArPSBgJHtvcHRpb25zLnF1b3RlQ29sdW1uTmFtZSh0aGlzLmNvbHVtbil9ICR7ZGlyZWN0aW9ufWBcblxuICAgIHJldHVybiBzcWxcbiAgfVxufVxuIl19
76
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3JkZXItY29sdW1uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2RhdGFiYXNlL3F1ZXJ5L29yZGVyLWNvbHVtbi5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxZQUFZO0FBRVosT0FBTyxTQUFTLE1BQU0saUJBQWlCLENBQUE7QUFFdkM7Ozs7OztHQU1HO0FBRUg7Ozs7R0FJRztBQUNILFNBQVMsa0JBQWtCLENBQUMsU0FBUztJQUNuQyxJQUFJLE9BQU8sU0FBUyxJQUFJLFdBQVc7UUFBRSxPQUFPLEtBQUssQ0FBQTtJQUVqRCxNQUFNLFVBQVUsR0FBRyxTQUFTLENBQUMsV0FBVyxFQUFFLENBQUE7SUFDMUMsSUFBSSxVQUFVLElBQUksS0FBSyxJQUFJLFVBQVUsSUFBSSxNQUFNO1FBQUUsT0FBTyxVQUFVLENBQUE7SUFFbEUsTUFBTSxJQUFJLEtBQUssQ0FBQyw0QkFBNEIsU0FBUyxFQUFFLENBQUMsQ0FBQTtBQUMxRCxDQUFDO0FBRUQ7Ozs7R0FJRztBQUNILFNBQVMsZ0JBQWdCLENBQUMsU0FBUztJQUNqQyxPQUFPLFNBQVMsSUFBSSxLQUFLLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFBO0FBQzVDLENBQUM7QUFFRCxNQUFNLENBQUMsT0FBTyxPQUFPLGlDQUFrQyxTQUFRLFNBQVM7SUFDdEU7Ozs7T0FJRztJQUNILFlBQVksS0FBSyxFQUFFLEtBQUs7UUFDdEIsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFBO1FBRVosSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNO1lBQUUsTUFBTSxJQUFJLEtBQUssQ0FBQywwQkFBMEIsQ0FBQyxDQUFBO1FBRTlELElBQUksQ0FBQyxNQUFNLEdBQUcsS0FBSyxDQUFDLE1BQU0sQ0FBQTtRQUMxQixJQUFJLENBQUMsU0FBUyxHQUFHLGtCQUFrQixDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsQ0FBQTtRQUNwRCxJQUFJLENBQUMsWUFBWSxHQUFHLEtBQUssQ0FBQTtRQUN6QixJQUFJLENBQUMsU0FBUyxHQUFHLEtBQUssQ0FBQyxTQUFTLENBQUE7SUFDbEMsQ0FBQztJQUVEOzs7O09BSUc7SUFDSCxlQUFlLENBQUMsWUFBWSxHQUFHLElBQUk7UUFDakMsSUFBSSxDQUFDLFlBQVksR0FBRyxZQUFZLENBQUE7SUFDbEMsQ0FBQztJQUVEOzs7T0FHRztJQUNILFlBQVk7UUFDVixNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUE7UUFFdkYsT0FBTyxJQUFJLGlDQUFpQyxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsRUFBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLE1BQU0sRUFBRSxTQUFTLEVBQUUsU0FBUyxFQUFFLElBQUksQ0FBQyxTQUFTLEVBQUMsQ0FBQyxDQUFBO0lBQ3ZILENBQUM7SUFFRDs7O09BR0c7SUFDSCxLQUFLO1FBQ0gsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFBO1FBQ2pDLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLGdCQUFnQixDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQTtRQUN2RixJQUFJLEdBQUcsR0FBRyxFQUFFLENBQUE7UUFFWixJQUFJLElBQUksQ0FBQyxTQUFTO1lBQUUsR0FBRyxJQUFJLEdBQUcsT0FBTyxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQTtRQUV2RSxHQUFHLElBQUksR0FBRyxPQUFPLENBQUMsZUFBZSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxTQUFTLEVBQUUsQ0FBQTtRQUU3RCxPQUFPLEdBQUcsQ0FBQTtJQUNaLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8vIEB0cy1jaGVja1xuXG5pbXBvcnQgT3JkZXJCYXNlIGZyb20gXCIuL29yZGVyLWJhc2UuanNcIlxuXG4vKipcbiAqIE9yZGVyQ29sdW1uSW5wdXQgdHlwZS5cbiAqIEB0eXBlZGVmIHtvYmplY3R9IE9yZGVyQ29sdW1uSW5wdXRcbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBjb2x1bW4gLSBDb2x1bW4gbmFtZS5cbiAqIEBwcm9wZXJ0eSB7XCJBU0NcIiB8IFwiREVTQ1wiIHwgXCJhc2NcIiB8IFwiZGVzY1wifSBbZGlyZWN0aW9uXSAtIFNvcnQgZGlyZWN0aW9uLlxuICogQHByb3BlcnR5IHtzdHJpbmd9IFt0YWJsZU5hbWVdIC0gT3B0aW9uYWwgdGFibGUgb3IgYWxpYXMgbmFtZS5cbiAqL1xuXG4vKipcbiAqIFJ1bnMgbm9ybWFsaXplIGRpcmVjdGlvbi5cbiAqIEBwYXJhbSB7c3RyaW5nIHwgdW5kZWZpbmVkfSBkaXJlY3Rpb24gLSBEaXJlY3Rpb24gaW5wdXQuXG4gKiBAcmV0dXJucyB7XCJBU0NcIiB8IFwiREVTQ1wifSAtIE5vcm1hbGl6ZWQgZGlyZWN0aW9uLlxuICovXG5mdW5jdGlvbiBub3JtYWxpemVEaXJlY3Rpb24oZGlyZWN0aW9uKSB7XG4gIGlmICh0eXBlb2YgZGlyZWN0aW9uID09IFwidW5kZWZpbmVkXCIpIHJldHVybiBcIkFTQ1wiXG5cbiAgY29uc3Qgbm9ybWFsaXplZCA9IGRpcmVjdGlvbi50b1VwcGVyQ2FzZSgpXG4gIGlmIChub3JtYWxpemVkID09IFwiQVNDXCIgfHwgbm9ybWFsaXplZCA9PSBcIkRFU0NcIikgcmV0dXJuIG5vcm1hbGl6ZWRcblxuICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgb3JkZXIgZGlyZWN0aW9uOiAke2RpcmVjdGlvbn1gKVxufVxuXG4vKipcbiAqIFJ1bnMgcmV2ZXJzZSBkaXJlY3Rpb24uXG4gKiBAcGFyYW0ge1wiQVNDXCIgfCBcIkRFU0NcIn0gZGlyZWN0aW9uIC0gRGlyZWN0aW9uLlxuICogQHJldHVybnMge1wiQVNDXCIgfCBcIkRFU0NcIn0gLSBSZXZlcnNlZCBkaXJlY3Rpb24uXG4gKi9cbmZ1bmN0aW9uIHJldmVyc2VEaXJlY3Rpb24oZGlyZWN0aW9uKSB7XG4gIHJldHVybiBkaXJlY3Rpb24gPT0gXCJBU0NcIiA/IFwiREVTQ1wiIDogXCJBU0NcIlxufVxuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBWZWxvY2lvdXNEYXRhYmFzZVF1ZXJ5T3JkZXJDb2x1bW4gZXh0ZW5kcyBPcmRlckJhc2Uge1xuICAvKipcbiAgICogUnVucyBjb25zdHJ1Y3Rvci5cbiAgICogQHBhcmFtIHtpbXBvcnQoXCIuL2luZGV4LmpzXCIpLmRlZmF1bHR9IHF1ZXJ5IC0gUXVlcnkgaW5zdGFuY2UuXG4gICAqIEBwYXJhbSB7T3JkZXJDb2x1bW5JbnB1dH0gaW5wdXQgLSBDb2x1bW4gb3JkZXIgaW5wdXQuXG4gICAqL1xuICBjb25zdHJ1Y3RvcihxdWVyeSwgaW5wdXQpIHtcbiAgICBzdXBlcihxdWVyeSlcblxuICAgIGlmICghaW5wdXQuY29sdW1uKSB0aHJvdyBuZXcgRXJyb3IoXCJPcmRlciBjb2x1bW4gaXMgcmVxdWlyZWRcIilcblxuICAgIHRoaXMuY29sdW1uID0gaW5wdXQuY29sdW1uXG4gICAgdGhpcy5kaXJlY3Rpb24gPSBub3JtYWxpemVEaXJlY3Rpb24oaW5wdXQuZGlyZWN0aW9uKVxuICAgIHRoaXMucmV2ZXJzZU9yZGVyID0gZmFsc2VcbiAgICB0aGlzLnRhYmxlTmFtZSA9IGlucHV0LnRhYmxlTmFtZVxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgc2V0IHJldmVyc2Ugb3JkZXIuXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gW3JldmVyc2VPcmRlcl0gLSBXaGV0aGVyIHRvIHJldmVyc2UgdGhlIG9yZGVyLlxuICAgKiBAcmV0dXJucyB7dm9pZH1cbiAgICovXG4gIHNldFJldmVyc2VPcmRlcihyZXZlcnNlT3JkZXIgPSB0cnVlKSB7XG4gICAgdGhpcy5yZXZlcnNlT3JkZXIgPSByZXZlcnNlT3JkZXJcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIHJldmVyc2VkIGNvcHkuXG4gICAqIEByZXR1cm5zIHtWZWxvY2lvdXNEYXRhYmFzZVF1ZXJ5T3JkZXJDb2x1bW59IC0gQSBuZXcgaW5kZXBlbmRlbnQgb3JkZXIgcmV2ZXJzaW5nIHRoZSBlZmZlY3RpdmUgKHJlbmRlcmVkKSBkaXJlY3Rpb24uXG4gICAqL1xuICByZXZlcnNlZENvcHkoKSB7XG4gICAgY29uc3QgZGlyZWN0aW9uID0gdGhpcy5yZXZlcnNlT3JkZXIgPyB0aGlzLmRpcmVjdGlvbiA6IHJldmVyc2VEaXJlY3Rpb24odGhpcy5kaXJlY3Rpb24pXG5cbiAgICByZXR1cm4gbmV3IFZlbG9jaW91c0RhdGFiYXNlUXVlcnlPcmRlckNvbHVtbih0aGlzLnF1ZXJ5LCB7Y29sdW1uOiB0aGlzLmNvbHVtbiwgZGlyZWN0aW9uLCB0YWJsZU5hbWU6IHRoaXMudGFibGVOYW1lfSlcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIHRvIHNxbC5cbiAgICogQHJldHVybnMge3N0cmluZ30gLSBTUUwgc3RyaW5nLlxuICAgKi9cbiAgdG9TcWwoKSB7XG4gICAgY29uc3Qgb3B0aW9ucyA9IHRoaXMuZ2V0T3B0aW9ucygpXG4gICAgY29uc3QgZGlyZWN0aW9uID0gdGhpcy5yZXZlcnNlT3JkZXIgPyByZXZlcnNlRGlyZWN0aW9uKHRoaXMuZGlyZWN0aW9uKSA6IHRoaXMuZGlyZWN0aW9uXG4gICAgbGV0IHNxbCA9IFwiXCJcblxuICAgIGlmICh0aGlzLnRhYmxlTmFtZSkgc3FsICs9IGAke29wdGlvbnMucXVvdGVUYWJsZU5hbWUodGhpcy50YWJsZU5hbWUpfS5gXG5cbiAgICBzcWwgKz0gYCR7b3B0aW9ucy5xdW90ZUNvbHVtbk5hbWUodGhpcy5jb2x1bW4pfSAke2RpcmVjdGlvbn1gXG5cbiAgICByZXR1cm4gc3FsXG4gIH1cbn1cbiJdfQ==
@@ -9,6 +9,11 @@ export default class VelociousDatabaseQueryOrderPlain extends OrderBase {
9
9
  */
10
10
  constructor(query: import("./index.js").default, plain: string);
11
11
  setReverseOrder(): void;
12
+ /**
13
+ * Runs reversed copy.
14
+ * @returns {VelociousDatabaseQueryOrderPlain} - A new independent order reversing the effective (rendered) direction; a directionless plain order renders DESC.
15
+ */
16
+ reversedCopy(): VelociousDatabaseQueryOrderPlain;
12
17
  toSql(): string;
13
18
  }
14
19
  //# sourceMappingURL=order-plain.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"order-plain.d.ts","sourceRoot":"","sources":["../../../../src/database/query/order-plain.js"],"names":[],"mappings":"AAEA,OAAO,SAAS,MAAM,iBAAiB,CAAA;AAEvC,MAAM,CAAC,OAAO,OAAO,gCAAiC,SAAQ,SAAS;IAQ9D,KAAK;IACL,YAAY;IARnB;;;;OAIG;IACH,YAAY,KAAK,EAHN,OAAO,YAAY,EAAE,OAGf,EAAE,KAAK,EAFb,MAEa,EAIvB;IAED,eAAe,SAEd;IAED,KAAK,WAMJ;CACF"}
1
+ {"version":3,"file":"order-plain.d.ts","sourceRoot":"","sources":["../../../../src/database/query/order-plain.js"],"names":[],"mappings":"AAEA,OAAO,SAAS,MAAM,iBAAiB,CAAA;AAEvC,MAAM,CAAC,OAAO,OAAO,gCAAiC,SAAQ,SAAS;IAQ9D,KAAK;IACL,YAAY;IARnB;;;;OAIG;IACH,YAAY,KAAK,EAHN,OAAO,YAAY,EAAE,OAGf,EAAE,KAAK,EAFb,MAEa,EAIvB;IAED,eAAe,SAEd;IAED;;;OAGG;IACH,YAAY,IAFC,gCAAgC,CAY5C;IAED,KAAK,WAMJ;CACF"}
@@ -14,6 +14,19 @@ export default class VelociousDatabaseQueryOrderPlain extends OrderBase {
14
14
  setReverseOrder() {
15
15
  this.reverseOrder = true;
16
16
  }
17
+ /**
18
+ * Runs reversed copy.
19
+ * @returns {VelociousDatabaseQueryOrderPlain} - A new independent order reversing the effective (rendered) direction; a directionless plain order renders DESC.
20
+ */
21
+ reversedCopy() {
22
+ const effective = this.reverseOrder ? `${this.plain} DESC` : this.plain;
23
+ const match = effective.match(/^(.*\S)\s+(ASC|DESC)$/i);
24
+ if (match) {
25
+ const direction = match[2].toUpperCase() == "ASC" ? "DESC" : "ASC";
26
+ return new VelociousDatabaseQueryOrderPlain(this.query, `${match[1]} ${direction}`);
27
+ }
28
+ return new VelociousDatabaseQueryOrderPlain(this.query, `${effective} DESC`);
29
+ }
17
30
  toSql() {
18
31
  if (this.reverseOrder) {
19
32
  return `${this.plain} DESC`;
@@ -21,4 +34,4 @@ export default class VelociousDatabaseQueryOrderPlain extends OrderBase {
21
34
  return this.plain;
22
35
  }
23
36
  }
24
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3JkZXItcGxhaW4uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvZGF0YWJhc2UvcXVlcnkvb3JkZXItcGxhaW4uanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsWUFBWTtBQUVaLE9BQU8sU0FBUyxNQUFNLGlCQUFpQixDQUFBO0FBRXZDLE1BQU0sQ0FBQyxPQUFPLE9BQU8sZ0NBQWlDLFNBQVEsU0FBUztJQUNyRTs7OztPQUlHO0lBQ0gsWUFBWSxLQUFLLEVBQUUsS0FBSztRQUN0QixLQUFLLENBQUMsS0FBSyxDQUFDLENBQUE7UUFDWixJQUFJLENBQUMsS0FBSyxHQUFHLEtBQUssQ0FBQTtRQUNsQixJQUFJLENBQUMsWUFBWSxHQUFHLEtBQUssQ0FBQTtJQUMzQixDQUFDO0lBRUQsZUFBZTtRQUNiLElBQUksQ0FBQyxZQUFZLEdBQUcsSUFBSSxDQUFBO0lBQzFCLENBQUM7SUFFRCxLQUFLO1FBQ0gsSUFBSSxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7WUFDdEIsT0FBTyxHQUFHLElBQUksQ0FBQyxLQUFLLE9BQU8sQ0FBQTtRQUM3QixDQUFDO1FBRUQsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFBO0lBQ25CLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8vIEB0cy1jaGVja1xuXG5pbXBvcnQgT3JkZXJCYXNlIGZyb20gXCIuL29yZGVyLWJhc2UuanNcIlxuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBWZWxvY2lvdXNEYXRhYmFzZVF1ZXJ5T3JkZXJQbGFpbiBleHRlbmRzIE9yZGVyQmFzZSB7XG4gIC8qKlxuICAgKiBSdW5zIGNvbnN0cnVjdG9yLlxuICAgKiBAcGFyYW0ge2ltcG9ydChcIi4vaW5kZXguanNcIikuZGVmYXVsdH0gcXVlcnkgLSBRdWVyeSBpbnN0YW5jZS5cbiAgICogQHBhcmFtIHtzdHJpbmd9IHBsYWluIC0gUGxhaW4uXG4gICAqL1xuICBjb25zdHJ1Y3RvcihxdWVyeSwgcGxhaW4pIHtcbiAgICBzdXBlcihxdWVyeSlcbiAgICB0aGlzLnBsYWluID0gcGxhaW5cbiAgICB0aGlzLnJldmVyc2VPcmRlciA9IGZhbHNlXG4gIH1cblxuICBzZXRSZXZlcnNlT3JkZXIoKSB7XG4gICAgdGhpcy5yZXZlcnNlT3JkZXIgPSB0cnVlXG4gIH1cblxuICB0b1NxbCgpIHtcbiAgICBpZiAodGhpcy5yZXZlcnNlT3JkZXIpIHtcbiAgICAgIHJldHVybiBgJHt0aGlzLnBsYWlufSBERVNDYFxuICAgIH1cblxuICAgIHJldHVybiB0aGlzLnBsYWluXG4gIH1cbn1cbiJdfQ==
37
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3JkZXItcGxhaW4uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvZGF0YWJhc2UvcXVlcnkvb3JkZXItcGxhaW4uanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsWUFBWTtBQUVaLE9BQU8sU0FBUyxNQUFNLGlCQUFpQixDQUFBO0FBRXZDLE1BQU0sQ0FBQyxPQUFPLE9BQU8sZ0NBQWlDLFNBQVEsU0FBUztJQUNyRTs7OztPQUlHO0lBQ0gsWUFBWSxLQUFLLEVBQUUsS0FBSztRQUN0QixLQUFLLENBQUMsS0FBSyxDQUFDLENBQUE7UUFDWixJQUFJLENBQUMsS0FBSyxHQUFHLEtBQUssQ0FBQTtRQUNsQixJQUFJLENBQUMsWUFBWSxHQUFHLEtBQUssQ0FBQTtJQUMzQixDQUFDO0lBRUQsZUFBZTtRQUNiLElBQUksQ0FBQyxZQUFZLEdBQUcsSUFBSSxDQUFBO0lBQzFCLENBQUM7SUFFRDs7O09BR0c7SUFDSCxZQUFZO1FBQ1YsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsS0FBSyxPQUFPLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUE7UUFDdkUsTUFBTSxLQUFLLEdBQUcsU0FBUyxDQUFDLEtBQUssQ0FBQyx3QkFBd0IsQ0FBQyxDQUFBO1FBRXZELElBQUksS0FBSyxFQUFFLENBQUM7WUFDVixNQUFNLFNBQVMsR0FBRyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsV0FBVyxFQUFFLElBQUksS0FBSyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQTtZQUNsRSxPQUFPLElBQUksZ0NBQWdDLENBQUMsSUFBSSxDQUFDLEtBQUssRUFBRSxHQUFHLEtBQUssQ0FBQyxDQUFDLENBQUMsSUFBSSxTQUFTLEVBQUUsQ0FBQyxDQUFBO1FBQ3JGLENBQUM7UUFFRCxPQUFPLElBQUksZ0NBQWdDLENBQUMsSUFBSSxDQUFDLEtBQUssRUFBRSxHQUFHLFNBQVMsT0FBTyxDQUFDLENBQUE7SUFDOUUsQ0FBQztJQUVELEtBQUs7UUFDSCxJQUFJLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQztZQUN0QixPQUFPLEdBQUcsSUFBSSxDQUFDLEtBQUssT0FBTyxDQUFBO1FBQzdCLENBQUM7UUFFRCxPQUFPLElBQUksQ0FBQyxLQUFLLENBQUE7SUFDbkIsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQHRzLWNoZWNrXG5cbmltcG9ydCBPcmRlckJhc2UgZnJvbSBcIi4vb3JkZXItYmFzZS5qc1wiXG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFZlbG9jaW91c0RhdGFiYXNlUXVlcnlPcmRlclBsYWluIGV4dGVuZHMgT3JkZXJCYXNlIHtcbiAgLyoqXG4gICAqIFJ1bnMgY29uc3RydWN0b3IuXG4gICAqIEBwYXJhbSB7aW1wb3J0KFwiLi9pbmRleC5qc1wiKS5kZWZhdWx0fSBxdWVyeSAtIFF1ZXJ5IGluc3RhbmNlLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gcGxhaW4gLSBQbGFpbi5cbiAgICovXG4gIGNvbnN0cnVjdG9yKHF1ZXJ5LCBwbGFpbikge1xuICAgIHN1cGVyKHF1ZXJ5KVxuICAgIHRoaXMucGxhaW4gPSBwbGFpblxuICAgIHRoaXMucmV2ZXJzZU9yZGVyID0gZmFsc2VcbiAgfVxuXG4gIHNldFJldmVyc2VPcmRlcigpIHtcbiAgICB0aGlzLnJldmVyc2VPcmRlciA9IHRydWVcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIHJldmVyc2VkIGNvcHkuXG4gICAqIEByZXR1cm5zIHtWZWxvY2lvdXNEYXRhYmFzZVF1ZXJ5T3JkZXJQbGFpbn0gLSBBIG5ldyBpbmRlcGVuZGVudCBvcmRlciByZXZlcnNpbmcgdGhlIGVmZmVjdGl2ZSAocmVuZGVyZWQpIGRpcmVjdGlvbjsgYSBkaXJlY3Rpb25sZXNzIHBsYWluIG9yZGVyIHJlbmRlcnMgREVTQy5cbiAgICovXG4gIHJldmVyc2VkQ29weSgpIHtcbiAgICBjb25zdCBlZmZlY3RpdmUgPSB0aGlzLnJldmVyc2VPcmRlciA/IGAke3RoaXMucGxhaW59IERFU0NgIDogdGhpcy5wbGFpblxuICAgIGNvbnN0IG1hdGNoID0gZWZmZWN0aXZlLm1hdGNoKC9eKC4qXFxTKVxccysoQVNDfERFU0MpJC9pKVxuXG4gICAgaWYgKG1hdGNoKSB7XG4gICAgICBjb25zdCBkaXJlY3Rpb24gPSBtYXRjaFsyXS50b1VwcGVyQ2FzZSgpID09IFwiQVNDXCIgPyBcIkRFU0NcIiA6IFwiQVNDXCJcbiAgICAgIHJldHVybiBuZXcgVmVsb2Npb3VzRGF0YWJhc2VRdWVyeU9yZGVyUGxhaW4odGhpcy5xdWVyeSwgYCR7bWF0Y2hbMV19ICR7ZGlyZWN0aW9ufWApXG4gICAgfVxuXG4gICAgcmV0dXJuIG5ldyBWZWxvY2lvdXNEYXRhYmFzZVF1ZXJ5T3JkZXJQbGFpbih0aGlzLnF1ZXJ5LCBgJHtlZmZlY3RpdmV9IERFU0NgKVxuICB9XG5cbiAgdG9TcWwoKSB7XG4gICAgaWYgKHRoaXMucmV2ZXJzZU9yZGVyKSB7XG4gICAgICByZXR1cm4gYCR7dGhpcy5wbGFpbn0gREVTQ2BcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcy5wbGFpblxuICB9XG59XG4iXX0=
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Exercises two durable physical tenant databases inside the real browser.
3
+ * @returns {Promise<{alphaNames: ReturnType<typeof JSON.parse>[], betaNames: ReturnType<typeof JSON.parse>[], identitiesAreDistinct: boolean, openCount: number}>} Serializable proof result.
4
+ */
5
+ export default function runFrontendTenantDatabasePersistenceScenario(): Promise<{
6
+ alphaNames: ReturnType<typeof JSON.parse>[];
7
+ betaNames: ReturnType<typeof JSON.parse>[];
8
+ identitiesAreDistinct: boolean;
9
+ openCount: number;
10
+ }>;
11
+ //# sourceMappingURL=browser-frontend-tenant-database-scenarios.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-frontend-tenant-database-scenarios.d.ts","sourceRoot":"","sources":["../../../src/testing/browser-frontend-tenant-database-scenarios.js"],"names":[],"mappings":"AAiEA;;;GAGG;AACH,wBAA8B,4CAA4C,IAF7D,OAAO,CAAC;IAAC,UAAU,EAAE,UAAU,CAAC,OAAO,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;IAAC,SAAS,EAAE,UAAU,CAAC,OAAO,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;IAAC,qBAAqB,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAC,CAAC,CA0FjK"}
@@ -0,0 +1,147 @@
1
+ // @ts-check
2
+ import Configuration, { CurrentConfigurationNotSetError } from "../configuration.js";
3
+ import DatabaseRecord from "../database/record/index.js";
4
+ import BrowserEnvironmentHandler from "../environment-handlers/browser.js";
5
+ import Migration from "../database/migration/index.js";
6
+ import SingleMultiUsePool from "../database/pool/single-multi-use.js";
7
+ import SqliteWebDriver from "../database/drivers/sqlite/index.web.js";
8
+ import Tenant from "../tenants/tenant.js";
9
+ const DATABASE_IDENTIFIER = "projectTenant";
10
+ const SCHEMA_GENERATION = "frontend-tenant-browser-persistence-1";
11
+ /**
12
+ * Returns the current configuration without requiring one to exist.
13
+ * @returns {Configuration | undefined} Current configuration when installed.
14
+ */
15
+ function currentConfigurationOrUndefined() {
16
+ try {
17
+ return Configuration.current();
18
+ }
19
+ catch (error) {
20
+ if (!(error instanceof CurrentConfigurationNotSetError))
21
+ throw error;
22
+ return undefined;
23
+ }
24
+ }
25
+ /**
26
+ * Builds the real browser-backed two-project configuration.
27
+ * @returns {Configuration} Browser tenant configuration.
28
+ */
29
+ function buildConfiguration() {
30
+ return new Configuration({
31
+ database: {
32
+ test: {
33
+ projectTenant: {
34
+ driver: SqliteWebDriver,
35
+ locateFile: () => "/sql-wasm.wasm",
36
+ migrations: true,
37
+ name: "velocious-browser-project-proof-template",
38
+ poolType: SingleMultiUsePool,
39
+ tenantOnly: true,
40
+ type: "sqlite"
41
+ }
42
+ }
43
+ },
44
+ directory: "/frontend-tenant-browser-persistence-scenario",
45
+ environment: "test",
46
+ environmentHandler: new BrowserEnvironmentHandler(),
47
+ frontendTenantSqlite: { maxOpenHandles: 2 },
48
+ initializeModels: async () => { },
49
+ locale: "en",
50
+ localeFallbacks: { en: ["en"] },
51
+ locales: ["en"],
52
+ tenantDatabaseResolver: ({ identifier, tenant }) => {
53
+ if (identifier !== DATABASE_IDENTIFIER || !tenant || typeof tenant !== "object")
54
+ return;
55
+ const projectSlug = /** @type {{projectSlug?: string}} */ (tenant).projectSlug;
56
+ if (projectSlug !== "alpha" && projectSlug !== "beta")
57
+ return;
58
+ return { name: `velocious-browser-project-proof-${projectSlug}` };
59
+ }
60
+ });
61
+ }
62
+ /**
63
+ * Exercises two durable physical tenant databases inside the real browser.
64
+ * @returns {Promise<{alphaNames: ReturnType<typeof JSON.parse>[], betaNames: ReturnType<typeof JSON.parse>[], identitiesAreDistinct: boolean, openCount: number}>} Serializable proof result.
65
+ */
66
+ export default async function runFrontendTenantDatabasePersistenceScenario() {
67
+ const previousConfiguration = currentConfigurationOrUndefined();
68
+ const configuration = buildConfiguration();
69
+ class BrowserProjectRecord extends DatabaseRecord {
70
+ }
71
+ class CreateBrowserProjectRecords extends Migration {
72
+ async up() {
73
+ await this.execute("CREATE TABLE browser_project_records(id integer PRIMARY KEY AUTOINCREMENT, name varchar(255) NOT NULL)");
74
+ }
75
+ }
76
+ BrowserProjectRecord.setTableName("browser_project_records");
77
+ BrowserProjectRecord.switchesTenantDatabase(DATABASE_IDENTIFIER);
78
+ BrowserProjectRecord.registerRecordClass({ configuration });
79
+ CreateBrowserProjectRecords.onDatabases([DATABASE_IDENTIFIER]);
80
+ const migrationFile = "20260919090000-create-browser-project-records.js";
81
+ /**
82
+ * Loads the one migration bundled into this browser proof.
83
+ * @type {import("../database/migrator/types.js").RequireMigrationContextType}
84
+ */
85
+ const migrations = (fileName) => {
86
+ if (fileName !== migrationFile)
87
+ throw new Error(`Unknown browser tenant proof migration: ${fileName}`);
88
+ return { default: CreateBrowserProjectRecords };
89
+ };
90
+ migrations.keys = () => [migrationFile];
91
+ migrations.id = "frontend-tenant-browser-persistence-scenario";
92
+ const alpha = Tenant.handle({ projectSlug: "alpha" }, configuration);
93
+ const beta = Tenant.handle({ projectSlug: "beta" }, configuration);
94
+ configuration.setCurrent();
95
+ try {
96
+ await Promise.all([
97
+ alpha.delete({ databaseIdentifier: DATABASE_IDENTIFIER }),
98
+ beta.delete({ databaseIdentifier: DATABASE_IDENTIFIER })
99
+ ]);
100
+ await Promise.all([
101
+ alpha.initialize({ databaseIdentifier: DATABASE_IDENTIFIER, migrations, schemaGeneration: SCHEMA_GENERATION }),
102
+ beta.initialize({ databaseIdentifier: DATABASE_IDENTIFIER, migrations, schemaGeneration: SCHEMA_GENERATION })
103
+ ]);
104
+ for (let index = 0; index < 12; index++) {
105
+ await Promise.all([
106
+ alpha.databaseOperation({ databaseIdentifier: DATABASE_IDENTIFIER }, async (operation) => {
107
+ await operation.forModel(BrowserProjectRecord).create({ name: `alpha-${index}` });
108
+ }),
109
+ beta.databaseOperation({ databaseIdentifier: DATABASE_IDENTIFIER }, async (operation) => {
110
+ await operation.forModel(BrowserProjectRecord).create({ name: `beta-${index}` });
111
+ })
112
+ ]);
113
+ }
114
+ await Promise.all([
115
+ alpha.close({ databaseIdentifier: DATABASE_IDENTIFIER, flush: true }),
116
+ beta.close({ databaseIdentifier: DATABASE_IDENTIFIER, flush: true })
117
+ ]);
118
+ await Promise.all([
119
+ alpha.initialize({ databaseIdentifier: DATABASE_IDENTIFIER, migrations, schemaGeneration: SCHEMA_GENERATION }),
120
+ beta.initialize({ databaseIdentifier: DATABASE_IDENTIFIER, migrations, schemaGeneration: SCHEMA_GENERATION })
121
+ ]);
122
+ const [alphaNames, betaNames] = await Promise.all([
123
+ alpha.databaseOperation({ databaseIdentifier: DATABASE_IDENTIFIER }, async (operation) => {
124
+ return await operation.forModel(BrowserProjectRecord).order("id").pluck("name");
125
+ }),
126
+ beta.databaseOperation({ databaseIdentifier: DATABASE_IDENTIFIER }, async (operation) => {
127
+ return await operation.forModel(BrowserProjectRecord).order("id").pluck("name");
128
+ })
129
+ ]);
130
+ return {
131
+ alphaNames,
132
+ betaNames,
133
+ identitiesAreDistinct: alpha.databaseIdentity(DATABASE_IDENTIFIER) !== beta.databaseIdentity(DATABASE_IDENTIFIER),
134
+ openCount: configuration.inspectFrontendTenantSqliteHandles().openCount
135
+ };
136
+ }
137
+ finally {
138
+ await Promise.all([
139
+ alpha.delete({ databaseIdentifier: DATABASE_IDENTIFIER }),
140
+ beta.delete({ databaseIdentifier: DATABASE_IDENTIFIER })
141
+ ]);
142
+ if (previousConfiguration)
143
+ previousConfiguration.setCurrent();
144
+ await configuration.closeDatabaseConnections();
145
+ }
146
+ }
147
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnJvd3Nlci1mcm9udGVuZC10ZW5hbnQtZGF0YWJhc2Utc2NlbmFyaW9zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3Rlc3RpbmcvYnJvd3Nlci1mcm9udGVuZC10ZW5hbnQtZGF0YWJhc2Utc2NlbmFyaW9zLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLFlBQVk7QUFFWixPQUFPLGFBQWEsRUFBRSxFQUFFLCtCQUErQixFQUFFLE1BQU0scUJBQXFCLENBQUE7QUFDcEYsT0FBTyxjQUFjLE1BQU0sNkJBQTZCLENBQUE7QUFDeEQsT0FBTyx5QkFBeUIsTUFBTSxvQ0FBb0MsQ0FBQTtBQUMxRSxPQUFPLFNBQVMsTUFBTSxnQ0FBZ0MsQ0FBQTtBQUN0RCxPQUFPLGtCQUFrQixNQUFNLHNDQUFzQyxDQUFBO0FBQ3JFLE9BQU8sZUFBZSxNQUFNLHlDQUF5QyxDQUFBO0FBQ3JFLE9BQU8sTUFBTSxNQUFNLHNCQUFzQixDQUFBO0FBRXpDLE1BQU0sbUJBQW1CLEdBQUcsZUFBZSxDQUFBO0FBQzNDLE1BQU0saUJBQWlCLEdBQUcsdUNBQXVDLENBQUE7QUFFakU7OztHQUdHO0FBQ0gsU0FBUywrQkFBK0I7SUFDdEMsSUFBSSxDQUFDO1FBQ0gsT0FBTyxhQUFhLENBQUMsT0FBTyxFQUFFLENBQUE7SUFDaEMsQ0FBQztJQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7UUFDZixJQUFJLENBQUMsQ0FBQyxLQUFLLFlBQVksK0JBQStCLENBQUM7WUFBRSxNQUFNLEtBQUssQ0FBQTtRQUVwRSxPQUFPLFNBQVMsQ0FBQTtJQUNsQixDQUFDO0FBQ0gsQ0FBQztBQUVEOzs7R0FHRztBQUNILFNBQVMsa0JBQWtCO0lBQ3pCLE9BQU8sSUFBSSxhQUFhLENBQUM7UUFDdkIsUUFBUSxFQUFFO1lBQ1IsSUFBSSxFQUFFO2dCQUNKLGFBQWEsRUFBRTtvQkFDYixNQUFNLEVBQUUsZUFBZTtvQkFDdkIsVUFBVSxFQUFFLEdBQUcsRUFBRSxDQUFDLGdC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QUFNLENBQUMsQ0FBQTtZQUNqRixDQUFDLENBQUM7U0FDSCxDQUFDLENBQUE7UUFFRixPQUFPO1lBQ0wsVUFBVTtZQUNWLFNBQVM7WUFDVCxxQkFBcUIsRUFBRSxLQUFLLENBQUMsZ0JBQWdCLENBQUMsbUJBQW1CLENBQUMsS0FBSyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsbUJBQW1CLENBQUM7WUFDakgsU0FBUyxFQUFFLGFBQWEsQ0FBQyxrQ0FBa0MsRUFBRSxDQUFDLFNBQVM7U0FDeEUsQ0FBQTtJQUNILENBQUM7WUFBUyxDQUFDO1FBQ1QsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUFDO1lBQ2hCLEtBQUssQ0FBQyxNQUFNLENBQUMsRUFBQyxrQkFBa0IsRUFBRSxtQkFBbUIsRUFBQyxDQUFDO1lBQ3ZELElBQUksQ0FBQyxNQUFNLENBQUMsRUFBQyxrQkFBa0IsRUFBRSxtQkFBbUIsRUFBQyxDQUFDO1NBQ3ZELENBQUMsQ0FBQTtRQUNGLElBQUkscUJBQXFCO1lBQUUscUJBQXFCLENBQUMsVUFBVSxFQUFFLENBQUE7UUFDN0QsTUFBTSxhQUFhLENBQUMsd0JBQXdCLEVBQUUsQ0FBQTtJQUNoRCxDQUFDO0FBQ0gsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIEB0cy1jaGVja1xuXG5pbXBvcnQgQ29uZmlndXJhdGlvbiwgeyBDdXJyZW50Q29uZmlndXJhdGlvbk5vdFNldEVycm9yIH0gZnJvbSBcIi4uL2NvbmZpZ3VyYXRpb24uanNcIlxuaW1wb3J0IERhdGFiYXNlUmVjb3JkIGZyb20gXCIuLi9kYXRhYmFzZS9yZWNvcmQvaW5kZXguanNcIlxuaW1wb3J0IEJyb3dzZXJFbnZpcm9ubWVudEhhbmRsZXIgZnJvbSBcIi4uL2Vudmlyb25tZW50LWhhbmRsZXJzL2Jyb3dzZXIuanNcIlxuaW1wb3J0IE1pZ3JhdGlvbiBmcm9tIFwiLi4vZGF0YWJhc2UvbWlncmF0aW9uL2luZGV4LmpzXCJcbmltcG9ydCBTaW5nbGVNdWx0aVVzZVBvb2wgZnJvbSBcIi4uL2RhdGFiYXNlL3Bvb2wvc2luZ2xlLW11bHRpLXVzZS5qc1wiXG5pbXBvcnQgU3FsaXRlV2ViRHJpdmVyIGZyb20gXCIuLi9kYXRhYmFzZS9kcml2ZXJzL3NxbGl0ZS9pbmRleC53ZWIuanNcIlxuaW1wb3J0IFRlbmFudCBmcm9tIFwiLi4vdGVuYW50cy90ZW5hbnQuanNcIlxuXG5jb25zdCBEQVRBQkFTRV9JREVOVElGSUVSID0gXCJwcm9qZWN0VGVuYW50XCJcbmNvbnN0IFNDSEVNQV9HRU5FUkFUSU9OID0gXCJmcm9udGVuZC10ZW5hbnQtYnJvd3Nlci1wZXJzaXN0ZW5jZS0xXCJcblxuLyoqXG4gKiBSZXR1cm5zIHRoZSBjdXJyZW50IGNvbmZpZ3VyYXRpb24gd2l0aG91dCByZXF1aXJpbmcgb25lIHRvIGV4aXN0LlxuICogQHJldHVybnMge0NvbmZpZ3VyYXRpb24gfCB1bmRlZmluZWR9IEN1cnJlbnQgY29uZmlndXJhdGlvbiB3aGVuIGluc3RhbGxlZC5cbiAqL1xuZnVuY3Rpb24gY3VycmVudENvbmZpZ3VyYXRpb25PclVuZGVmaW5lZCgpIHtcbiAgdHJ5IHtcbiAgICByZXR1cm4gQ29uZmlndXJhdGlvbi5jdXJyZW50KClcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBpZiAoIShlcnJvciBpbnN0YW5jZW9mIEN1cnJlbnRDb25maWd1cmF0aW9uTm90U2V0RXJyb3IpKSB0aHJvdyBlcnJvclxuXG4gICAgcmV0dXJuIHVuZGVmaW5lZFxuICB9XG59XG5cbi8qKlxuICogQnVpbGRzIHRoZSByZWFsIGJyb3dzZXItYmFja2VkIHR3by1wcm9qZWN0IGNvbmZpZ3VyYXRpb24uXG4gKiBAcmV0dXJucyB7Q29uZmlndXJhdGlvbn0gQnJvd3NlciB0ZW5hbnQgY29uZmlndXJhdGlvbi5cbiAqL1xuZnVuY3Rpb24gYnVpbGRDb25maWd1cmF0aW9uKCkge1xuICByZXR1cm4gbmV3IENvbmZpZ3VyYXRpb24oe1xuICAgIGRhdGFiYXNlOiB7XG4gICAgICB0ZXN0OiB7XG4gICAgICAgIHByb2plY3RUZW5hbnQ6IHtcbiAgICAgICAgICBkcml2ZXI6IFNxbGl0ZVdlYkRyaXZlcixcbiAgICAgICAgICBsb2NhdGVGaWxlOiAoKSA9PiBcIi9zcWwtd2FzbS53YXNtXCIsXG4gICAgICAgICAgbWlncmF0aW9uczogdHJ1ZSxcbiAgICAgICAgICBuYW1lOiBcInZlbG9jaW91cy1icm93c2VyLXByb2plY3QtcHJvb2YtdGVtcGxhdGVcIixcbiAgICAgICAgICBwb29sVHlwZTogU2luZ2xlTXVsdGlVc2VQb29sLFxuICAgICAgICAgIHRlbmFudE9ubHk6IHRydWUsXG4gICAgICAgICAgdHlwZTogXCJzcWxpdGVcIlxuICAgICAgICB9XG4gICAgICB9XG4gICAgfSxcbiAgICBkaXJlY3Rvcnk6IFwiL2Zyb250ZW5kLXRlbmFudC1icm93c2VyLXBlcnNpc3RlbmNlLXNjZW5hcmlvXCIsXG4gICAgZW52aXJvbm1lbnQ6IFwidGVzdFwiLFxuICAgIGVudmlyb25tZW50SGFuZGxlcjogbmV3IEJyb3dzZXJFbnZpcm9ubWVudEhhbmRsZXIoKSxcbiAgICBmcm9udGVuZFRlbmFudFNxbGl0ZToge21heE9wZW5IYW5kbGVzOiAyfSxcbiAgICBpbml0aWFsaXplTW9kZWxzOiBhc3luYyAoKSA9PiB7fSxcbiAgICBsb2NhbGU6IFwiZW5cIixcbiAgICBsb2NhbGVGYWxsYmFja3M6IHtlbjogW1wiZW5cIl19LFxuICAgIGxvY2FsZXM6IFtcImVuXCJdLFxuICAgIHRlbmFudERhdGFiYXNlUmVzb2x2ZXI6ICh7aWRlbnRpZmllciwgdGVuYW50fSkgPT4ge1xuICAgICAgaWYgKGlkZW50aWZpZXIgIT09IERBVEFCQVNFX0lERU5USUZJRVIgfHwgIXRlbmFudCB8fCB0eXBlb2YgdGVuYW50ICE9PSBcIm9iamVjdFwiKSByZXR1cm5cbiAgICAgIGNvbnN0IHByb2plY3RTbHVnID0gLyoqIEB0eXBlIHt7cHJvamVjdFNsdWc/OiBzdHJpbmd9fSAqLyAodGVuYW50KS5wcm9qZWN0U2x1Z1xuXG4gICAgICBpZiAocHJvamVjdFNsdWcgIT09IFwiYWxwaGFcIiAmJiBwcm9qZWN0U2x1ZyAhPT0gXCJiZXRhXCIpIHJldHVyblxuXG4gICAgICByZXR1cm4ge25hbWU6IGB2ZWxvY2lvdXMtYnJvd3Nlci1wcm9qZWN0LXByb29mLSR7cHJvamVjdFNsdWd9YH1cbiAgICB9XG4gIH0pXG59XG5cbi8qKlxuICogRXhlcmNpc2VzIHR3byBkdXJhYmxlIHBoeXNpY2FsIHRlbmFudCBkYXRhYmFzZXMgaW5zaWRlIHRoZSByZWFsIGJyb3dzZXIuXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx7YWxwaGFOYW1lczogUmV0dXJuVHlwZTx0eXBlb2YgSlNPTi5wYXJzZT5bXSwgYmV0YU5hbWVzOiBSZXR1cm5UeXBlPHR5cGVvZiBKU09OLnBhcnNlPltdLCBpZGVudGl0aWVzQXJlRGlzdGluY3Q6IGJvb2xlYW4sIG9wZW5Db3VudDogbnVtYmVyfT59IFNlcmlhbGl6YWJsZSBwcm9vZiByZXN1bHQuXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGFzeW5jIGZ1bmN0aW9uIHJ1bkZyb250ZW5kVGVuYW50RGF0YWJhc2VQZXJzaXN0ZW5jZVNjZW5hcmlvKCkge1xuICBjb25zdCBwcmV2aW91c0NvbmZpZ3VyYXRpb24gPSBjdXJyZW50Q29uZmlndXJhdGlvbk9yVW5kZWZpbmVkKClcbiAgY29uc3QgY29uZmlndXJhdGlvbiA9IGJ1aWxkQ29uZmlndXJhdGlvbigpXG5cbiAgY2xhc3MgQnJvd3NlclByb2plY3RSZWNvcmQgZXh0ZW5kcyBEYXRhYmFzZVJlY29yZCB7fVxuICBjbGFzcyBDcmVhdGVCcm93c2VyUHJvamVjdFJlY29yZHMgZXh0ZW5kcyBNaWdyYXRpb24ge1xuICAgIGFzeW5jIHVwKCkge1xuICAgICAgYXdhaXQgdGhpcy5leGVjdXRlKFwiQ1JFQVRFIFRBQkxFIGJyb3dzZXJfcHJvamVjdF9yZWNvcmRzKGlkIGludGVnZXIgUFJJTUFSWSBLRVkgQVVUT0lOQ1JFTUVOVCwgbmFtZSB2YXJjaGFyKDI1NSkgTk9UIE5VTEwpXCIpXG4gICAgfVxuICB9XG5cbiAgQnJvd3NlclByb2plY3RSZWNvcmQuc2V0VGFibGVOYW1lKFwiYnJvd3Nlcl9wcm9qZWN0X3JlY29yZHNcIilcbiAgQnJvd3NlclByb2plY3RSZWNvcmQuc3dpdGNoZXNUZW5hbnREYXRhYmFzZShEQVRBQkFTRV9JREVOVElGSUVSKVxuICBCcm93c2VyUHJvamVjdFJlY29yZC5yZWdpc3RlclJlY29yZENsYXNzKHtjb25maWd1cmF0aW9ufSlcbiAgQ3JlYXRlQnJvd3NlclByb2plY3RSZWNvcmRzLm9uRGF0YWJhc2VzKFtEQVRBQkFTRV9JREVOVElGSUVSXSlcblxuICBjb25zdCBtaWdyYXRpb25GaWxlID0gXCIyMDI2MDkxOTA5MDAwMC1jcmVhdGUtYnJvd3Nlci1wcm9qZWN0LXJlY29yZHMuanNcIlxuICAvKipcbiAgICogTG9hZHMgdGhlIG9uZSBtaWdyYXRpb24gYnVuZGxlZCBpbnRvIHRoaXMgYnJvd3NlciBwcm9vZi5cbiAgICogQHR5cGUge2ltcG9ydChcIi4uL2RhdGFiYXNlL21pZ3JhdG9yL3R5cGVzLmpzXCIpLlJlcXVpcmVNaWdyYXRpb25Db250ZXh0VHlwZX1cbiAgICovXG4gIGNvbnN0IG1pZ3JhdGlvbnMgPSAoZmlsZU5hbWUpID0+IHtcbiAgICBpZiAoZmlsZU5hbWUgIT09IG1pZ3JhdGlvbkZpbGUpIHRocm93IG5ldyBFcnJvcihgVW5rbm93biBicm93c2VyIHRlbmFudCBwcm9vZiBtaWdyYXRpb246ICR7ZmlsZU5hbWV9YClcblxuICAgIHJldHVybiB7ZGVmYXVsdDogQ3JlYXRlQnJvd3NlclByb2plY3RSZWNvcmRzfVxuICB9XG5cbiAgbWlncmF0aW9ucy5rZXlzID0gKCkgPT4gW21pZ3JhdGlvbkZpbGVdXG4gIG1pZ3JhdGlvbnMuaWQgPSBcImZyb250ZW5kLXRlbmFudC1icm93c2VyLXBlcnNpc3RlbmNlLXNjZW5hcmlvXCJcblxuICBjb25zdCBhbHBoYSA9IFRlbmFudC5oYW5kbGUoe3Byb2plY3RTbHVnOiBcImFscGhhXCJ9LCBjb25maWd1cmF0aW9uKVxuICBjb25zdCBiZXRhID0gVGVuYW50LmhhbmRsZSh7cHJvamVjdFNsdWc6IFwiYmV0YVwifSwgY29uZmlndXJhdGlvbilcblxuICBjb25maWd1cmF0aW9uLnNldEN1cnJlbnQoKVxuXG4gIHRyeSB7XG4gICAgYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgICAgYWxwaGEuZGVsZXRlKHtkYXRhYmFzZUlkZW50aWZpZXI6IERBVEFCQVNFX0lERU5USUZJRVJ9KSxcbiAgICAgIGJldGEuZGVsZXRlKHtkYXRhYmFzZUlkZW50aWZpZXI6IERBVEFCQVNFX0lERU5USUZJRVJ9KVxuICAgIF0pXG4gICAgYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgICAgYWxwaGEuaW5pdGlhbGl6ZSh7ZGF0YWJhc2VJZGVudGlmaWVyOiBEQVRBQkFTRV9JREVOVElGSUVSLCBtaWdyYXRpb25zLCBzY2hlbWFHZW5lcmF0aW9uOiBTQ0hFTUFfR0VORVJBVElPTn0pLFxuICAgICAgYmV0YS5pbml0aWFsaXplKHtkYXRhYmFzZUlkZW50aWZpZXI6IERBVEFCQVNFX0lERU5USUZJRVIsIG1pZ3JhdGlvbnMsIHNjaGVtYUdlbmVyYXRpb246IFNDSEVNQV9HRU5FUkFUSU9OfSlcbiAgICBdKVxuXG4gICAgZm9yIChsZXQgaW5kZXggPSAwOyBpbmRleCA8IDEyOyBpbmRleCsrKSB7XG4gICAgICBhd2FpdCBQcm9taXNlLmFsbChbXG4gICAgICAgIGFscGhhLmRhdGFiYXNlT3BlcmF0aW9uKHtkYXRhYmFzZUlkZW50aWZpZXI6IERBVEFCQVNFX0lERU5USUZJRVJ9LCBhc3luYyAob3BlcmF0aW9uKSA9PiB7XG4gICAgICAgICAgYXdhaXQgb3BlcmF0aW9uLmZvck1vZGVsKEJyb3dzZXJQcm9qZWN0UmVjb3JkKS5jcmVhdGUoe25hbWU6IGBhbHBoYS0ke2luZGV4fWB9KVxuICAgICAgICB9KSxcbiAgICAgICAgYmV0YS5kYXRhYmFzZU9wZXJhdGlvbih7ZGF0YWJhc2VJZGVudGlmaWVyOiBEQVRBQkFTRV9JREVOVElGSUVSfSwgYXN5bmMgKG9wZXJhdGlvbikgPT4ge1xuICAgICAgICAgIGF3YWl0IG9wZXJhdGlvbi5mb3JNb2RlbChCcm93c2VyUHJvamVjdFJlY29yZCkuY3JlYXRlKHtuYW1lOiBgYmV0YS0ke2luZGV4fWB9KVxuICAgICAgICB9KVxuICAgICAgXSlcbiAgICB9XG5cbiAgICBhd2FpdCBQcm9taXNlLmFsbChbXG4gICAgICBhbHBoYS5jbG9zZSh7ZGF0YWJhc2VJZGVudGlmaWVyOiBEQVRBQkFTRV9JREVOVElGSUVSLCBmbHVzaDogdHJ1ZX0pLFxuICAgICAgYmV0YS5jbG9zZSh7ZGF0YWJhc2VJZGVudGlmaWVyOiBEQVRBQkFTRV9JREVOVElGSUVSLCBmbHVzaDogdHJ1ZX0pXG4gICAgXSlcbiAgICBhd2FpdCBQcm9taXNlLmFsbChbXG4gICAgICBhbHBoYS5pbml0aWFsaXplKHtkYXRhYmFzZUlkZW50aWZpZXI6IERBVEFCQVNFX0lERU5USUZJRVIsIG1pZ3JhdGlvbnMsIHNjaGVtYUdlbmVyYXRpb246IFNDSEVNQV9HRU5FUkFUSU9OfSksXG4gICAgICBiZXRhLmluaXRpYWxpemUoe2RhdGFiYXNlSWRlbnRpZmllcjogREFUQUJBU0VfSURFTlRJRklFUiwgbWlncmF0aW9ucywgc2NoZW1hR2VuZXJhdGlvbjogU0NIRU1BX0dFTkVSQVRJT059KVxuICAgIF0pXG5cbiAgICBjb25zdCBbYWxwaGFOYW1lcywgYmV0YU5hbWVzXSA9IGF3YWl0IFByb21pc2UuYWxsKFtcbiAgICAgIGFscGhhLmRhdGFiYXNlT3BlcmF0aW9uKHtkYXRhYmFzZUlkZW50aWZpZXI6IERBVEFCQVNFX0lERU5USUZJRVJ9LCBhc3luYyAob3BlcmF0aW9uKSA9PiB7XG4gICAgICAgIHJldHVybiBhd2FpdCBvcGVyYXRpb24uZm9yTW9kZWwoQnJvd3NlclByb2plY3RSZWNvcmQpLm9yZGVyKFwiaWRcIikucGx1Y2soXCJuYW1lXCIpXG4gICAgICB9KSxcbiAgICAgIGJldGEuZGF0YWJhc2VPcGVyYXRpb24oe2RhdGFiYXNlSWRlbnRpZmllcjogREFUQUJBU0VfSURFTlRJRklFUn0sIGFzeW5jIChvcGVyYXRpb24pID0+IHtcbiAgICAgICAgcmV0dXJuIGF3YWl0IG9wZXJhdGlvbi5mb3JNb2RlbChCcm93c2VyUHJvamVjdFJlY29yZCkub3JkZXIoXCJpZFwiKS5wbHVjayhcIm5hbWVcIilcbiAgICAgIH0pXG4gICAgXSlcblxuICAgIHJldHVybiB7XG4gICAgICBhbHBoYU5hbWVzLFxuICAgICAgYmV0YU5hbWVzLFxuICAgICAgaWRlbnRpdGllc0FyZURpc3RpbmN0OiBhbHBoYS5kYXRhYmFzZUlkZW50aXR5KERBVEFCQVNFX0lERU5USUZJRVIpICE9PSBiZXRhLmRhdGFiYXNlSWRlbnRpdHkoREFUQUJBU0VfSURFTlRJRklFUiksXG4gICAgICBvcGVuQ291bnQ6IGNvbmZpZ3VyYXRpb24uaW5zcGVjdEZyb250ZW5kVGVuYW50U3FsaXRlSGFuZGxlcygpLm9wZW5Db3VudFxuICAgIH1cbiAgfSBmaW5hbGx5IHtcbiAgICBhd2FpdCBQcm9taXNlLmFsbChbXG4gICAgICBhbHBoYS5kZWxldGUoe2RhdGFiYXNlSWRlbnRpZmllcjogREFUQUJBU0VfSURFTlRJRklFUn0pLFxuICAgICAgYmV0YS5kZWxldGUoe2RhdGFiYXNlSWRlbnRpZmllcjogREFUQUJBU0VfSURFTlRJRklFUn0pXG4gICAgXSlcbiAgICBpZiAocHJldmlvdXNDb25maWd1cmF0aW9uKSBwcmV2aW91c0NvbmZpZ3VyYXRpb24uc2V0Q3VycmVudCgpXG4gICAgYXdhaXQgY29uZmlndXJhdGlvbi5jbG9zZURhdGFiYXNlQ29ubmVjdGlvbnMoKVxuICB9XG59XG4iXX0=
@@ -2,6 +2,7 @@
2
2
  import SystemTestBrowserHelper from "system-testing/build/system-test-browser-helper.js";
3
3
  import BrowserEnvironmentHandler from "../environment-handlers/browser.js";
4
4
  import runFrontendModelEventHookScenario from "./browser-frontend-model-event-hook-scenarios.js";
5
+ import runFrontendTenantDatabasePersistenceScenario from "./browser-frontend-tenant-database-scenarios.js";
5
6
  import runUseDatabaseSelectionTransitionScenario from "./browser-use-database-hook-scenarios.js";
6
7
  const root = document.getElementById("root") || (() => {
7
8
  const element = document.createElement("div");
@@ -22,7 +23,8 @@ systemTestBrowserHelper.enableOnBrowser();
22
23
  Object.assign(globalThis, { velociousBrowserTest: {
23
24
  BrowserEnvironmentHandler,
24
25
  runFrontendModelEventHookScenario,
26
+ runFrontendTenantDatabasePersistenceScenario,
25
27
  runUseDatabaseSelectionTransitionScenario,
26
28
  systemTestBrowserHelper
27
29
  } });
28
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnJvd3Nlci10ZXN0LWFwcC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy90ZXN0aW5nL2Jyb3dzZXItdGVzdC1hcHAuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsWUFBWTtBQUVaLE9BQU8sdUJBQXVCLE1BQU0sb0RBQW9ELENBQUE7QUFDeEYsT0FBTyx5QkFBeUIsTUFBTSxvQ0FBb0MsQ0FBQTtBQUMxRSxPQUFPLGlDQUFpQyxNQUFNLGtEQUFrRCxDQUFBO0FBQ2hHLE9BQU8seUNBQXlDLE1BQU0sMENBQTBDLENBQUE7QUFFaEcsTUFBTSxJQUFJLEdBQUcsUUFBUSxDQUFDLGNBQWMsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRTtJQUNwRCxNQUFNLE9BQU8sR0FBRyxRQUFRLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQyxDQUFBO0lBQzdDLE9BQU8sQ0FBQyxFQUFFLEdBQUcsTUFBTSxDQUFBO0lBQ25CLFFBQVEsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLE9BQU8sQ0FBQyxDQUFBO0lBQ2xDLE9BQU8sT0FBTyxDQUFBO0FBQ2hCLENBQUMsQ0FBQyxFQUFFLENBQUE7QUFFSixNQUFNLHNCQUFzQixHQUFHLFFBQVEsQ0FBQyxhQUFhLENBQUMsS0FBSyxDQUFDLENBQUE7QUFDNUQsc0JBQXNCLENBQUMsWUFBWSxDQUFDLGFBQWEsRUFBRSx3QkFBd0IsQ0FBQyxDQUFBO0FBQzVFLHNCQUFzQixDQUFDLFlBQVksQ0FBQyxlQUFlLEVBQUUsTUFBTSxDQUFDLENBQUE7QUFFNUQsTUFBTSxTQUFTLEdBQUcsUUFBUSxDQUFDLGFBQWEsQ0FBQyxLQUFLLENBQUMsQ0FBQTtBQUMvQyxTQUFTLENBQUMsWUFBWSxDQUFDLGFBQWEsRUFBRSxXQUFXLENBQUMsQ0FBQTtBQUNsRCxTQUFTLENBQUMsV0FBVyxHQUFHLE9BQU8sQ0FBQTtBQUUvQixzQkFBc0IsQ0FBQyxXQUFXLENBQUMsU0FBUyxDQUFDLENBQUE7QUFDN0MsSUFBSSxDQUFDLFdBQVcsQ0FBQyxzQkFBc0IsQ0FBQyxDQUFBO0FBRXhDLE1BQU0sdUJBQXVCLEdBQUcsSUFBSSx1QkFBdUIsRUFBRSxDQUFBO0FBQzdELHVCQUF1QixDQUFDLGVBQWUsRUFBRSxDQUFBO0FBRXpDLE1BQU0sQ0FBQyxNQUFNLENBQUMsVUFBVSxFQUFFLEVBQUMsb0JBQW9CLEVBQUU7UUFDL0MseUJBQXlCO1FBQ3pCLGlDQUFpQztRQUNqQyx5Q0FBeUM7UUFDekMsdUJBQXVCO0tBQ3hCLEVBQUMsQ0FBQyxDQUFBIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQHRzLWNoZWNrXG5cbmltcG9ydCBTeXN0ZW1UZXN0QnJvd3NlckhlbHBlciBmcm9tIFwic3lzdGVtLXRlc3RpbmcvYnVpbGQvc3lzdGVtLXRlc3QtYnJvd3Nlci1oZWxwZXIuanNcIlxuaW1wb3J0IEJyb3dzZXJFbnZpcm9ubWVudEhhbmRsZXIgZnJvbSBcIi4uL2Vudmlyb25tZW50LWhhbmRsZXJzL2Jyb3dzZXIuanNcIlxuaW1wb3J0IHJ1bkZyb250ZW5kTW9kZWxFdmVudEhvb2tTY2VuYXJpbyBmcm9tIFwiLi9icm93c2VyLWZyb250ZW5kLW1vZGVsLWV2ZW50LWhvb2stc2NlbmFyaW9zLmpzXCJcbmltcG9ydCBydW5Vc2VEYXRhYmFzZVNlbGVjdGlvblRyYW5zaXRpb25TY2VuYXJpbyBmcm9tIFwiLi9icm93c2VyLXVzZS1kYXRhYmFzZS1ob29rLXNjZW5hcmlvcy5qc1wiXG5cbmNvbnN0IHJvb3QgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChcInJvb3RcIikgfHwgKCgpID0+IHtcbiAgY29uc3QgZWxlbWVudCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJkaXZcIilcbiAgZWxlbWVudC5pZCA9IFwicm9vdFwiXG4gIGRvY3VtZW50LmJvZHkuYXBwZW5kQ2hpbGQoZWxlbWVudClcbiAgcmV0dXJuIGVsZW1lbnRcbn0pKClcblxuY29uc3Qgc3lzdGVtVGVzdGluZ0NvbXBvbmVudCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJkaXZcIilcbnN5c3RlbVRlc3RpbmdDb21wb25lbnQuc2V0QXR0cmlidXRlKFwiZGF0YS10ZXN0aWRcIiwgXCJzeXN0ZW1UZXN0aW5nQ29tcG9uZW50XCIpXG5zeXN0ZW1UZXN0aW5nQ29tcG9uZW50LnNldEF0dHJpYnV0ZShcImRhdGEtZm9jdXNzZWRcIiwgXCJ0cnVlXCIpXG5cbmNvbnN0IGJsYW5rVGV4dCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJkaXZcIilcbmJsYW5rVGV4dC5zZXRBdHRyaWJ1dGUoXCJkYXRhLXRlc3RpZFwiLCBcImJsYW5rVGV4dFwiKVxuYmxhbmtUZXh0LnRleHRDb250ZW50ID0gXCJibGFua1wiXG5cbnN5c3RlbVRlc3RpbmdDb21wb25lbnQuYXBwZW5kQ2hpbGQoYmxhbmtUZXh0KVxucm9vdC5hcHBlbmRDaGlsZChzeXN0ZW1UZXN0aW5nQ29tcG9uZW50KVxuXG5jb25zdCBzeXN0ZW1UZXN0QnJvd3NlckhlbHBlciA9IG5ldyBTeXN0ZW1UZXN0QnJvd3NlckhlbHBlcigpXG5zeXN0ZW1UZXN0QnJvd3NlckhlbHBlci5lbmFibGVPbkJyb3dzZXIoKVxuXG5PYmplY3QuYXNzaWduKGdsb2JhbFRoaXMsIHt2ZWxvY2lvdXNCcm93c2VyVGVzdDoge1xuICBCcm93c2VyRW52aXJvbm1lbnRIYW5kbGVyLFxuICBydW5Gcm9udGVuZE1vZGVsRXZlbnRIb29rU2NlbmFyaW8sXG4gIHJ1blVzZURhdGFiYXNlU2VsZWN0aW9uVHJhbnNpdGlvblNjZW5hcmlvLFxuICBzeXN0ZW1UZXN0QnJvd3NlckhlbHBlclxufX0pXG4iXX0=
30
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnJvd3Nlci10ZXN0LWFwcC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy90ZXN0aW5nL2Jyb3dzZXItdGVzdC1hcHAuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsWUFBWTtBQUVaLE9BQU8sdUJBQXVCLE1BQU0sb0RBQW9ELENBQUE7QUFDeEYsT0FBTyx5QkFBeUIsTUFBTSxvQ0FBb0MsQ0FBQTtBQUMxRSxPQUFPLGlDQUFpQyxNQUFNLGtEQUFrRCxDQUFBO0FBQ2hHLE9BQU8sNENBQTRDLE1BQU0saURBQWlELENBQUE7QUFDMUcsT0FBTyx5Q0FBeUMsTUFBTSwwQ0FBMEMsQ0FBQTtBQUVoRyxNQUFNLElBQUksR0FBRyxRQUFRLENBQUMsY0FBYyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFO0lBQ3BELE1BQU0sT0FBTyxHQUFHLFFBQVEsQ0FBQyxhQUFhLENBQUMsS0FBSyxDQUFDLENBQUE7SUFDN0MsT0FBTyxDQUFDLEVBQUUsR0FBRyxNQUFNLENBQUE7SUFDbkIsUUFBUSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsT0FBTyxDQUFDLENBQUE7SUFDbEMsT0FBTyxPQUFPLENBQUE7QUFDaEIsQ0FBQyxDQUFDLEVBQUUsQ0FBQTtBQUVKLE1BQU0sc0JBQXNCLEdBQUcsUUFBUSxDQUFDLGFBQWEsQ0FBQyxLQUFLLENBQUMsQ0FBQTtBQUM1RCxzQkFBc0IsQ0FBQyxZQUFZLENBQUMsYUFBYSxFQUFFLHdCQUF3QixDQUFDLENBQUE7QUFDNUUsc0JBQXNCLENBQUMsWUFBWSxDQUFDLGVBQWUsRUFBRSxNQUFNLENBQUMsQ0FBQTtBQUU1RCxNQUFNLFNBQVMsR0FBRyxRQUFRLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQyxDQUFBO0FBQy9DLFNBQVMsQ0FBQyxZQUFZLENBQUMsYUFBYSxFQUFFLFdBQVcsQ0FBQyxDQUFBO0FBQ2xELFNBQVMsQ0FBQyxXQUFXLEdBQUcsT0FBTyxDQUFBO0FBRS9CLHNCQUFzQixDQUFDLFdBQVcsQ0FBQyxTQUFTLENBQUMsQ0FBQTtBQUM3QyxJQUFJLENBQUMsV0FBVyxDQUFDLHNCQUFzQixDQUFDLENBQUE7QUFFeEMsTUFBTSx1QkFBdUIsR0FBRyxJQUFJLHVCQUF1QixFQUFFLENBQUE7QUFDN0QsdUJBQXVCLENBQUMsZUFBZSxFQUFFLENBQUE7QUFFekMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxVQUFVLEVBQUUsRUFBQyxvQkFBb0IsRUFBRTtRQUMvQyx5QkFBeUI7UUFDekIsaUNBQWlDO1FBQ2pDLDRDQUE0QztRQUM1Qyx5Q0FBeUM7UUFDekMsdUJBQXVCO0tBQ3hCLEVBQUMsQ0FBQyxDQUFBIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQHRzLWNoZWNrXG5cbmltcG9ydCBTeXN0ZW1UZXN0QnJvd3NlckhlbHBlciBmcm9tIFwic3lzdGVtLXRlc3RpbmcvYnVpbGQvc3lzdGVtLXRlc3QtYnJvd3Nlci1oZWxwZXIuanNcIlxuaW1wb3J0IEJyb3dzZXJFbnZpcm9ubWVudEhhbmRsZXIgZnJvbSBcIi4uL2Vudmlyb25tZW50LWhhbmRsZXJzL2Jyb3dzZXIuanNcIlxuaW1wb3J0IHJ1bkZyb250ZW5kTW9kZWxFdmVudEhvb2tTY2VuYXJpbyBmcm9tIFwiLi9icm93c2VyLWZyb250ZW5kLW1vZGVsLWV2ZW50LWhvb2stc2NlbmFyaW9zLmpzXCJcbmltcG9ydCBydW5Gcm9udGVuZFRlbmFudERhdGFiYXNlUGVyc2lzdGVuY2VTY2VuYXJpbyBmcm9tIFwiLi9icm93c2VyLWZyb250ZW5kLXRlbmFudC1kYXRhYmFzZS1zY2VuYXJpb3MuanNcIlxuaW1wb3J0IHJ1blVzZURhdGFiYXNlU2VsZWN0aW9uVHJhbnNpdGlvblNjZW5hcmlvIGZyb20gXCIuL2Jyb3dzZXItdXNlLWRhdGFiYXNlLWhvb2stc2NlbmFyaW9zLmpzXCJcblxuY29uc3Qgcm9vdCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKFwicm9vdFwiKSB8fCAoKCkgPT4ge1xuICBjb25zdCBlbGVtZW50ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcImRpdlwiKVxuICBlbGVtZW50LmlkID0gXCJyb290XCJcbiAgZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChlbGVtZW50KVxuICByZXR1cm4gZWxlbWVudFxufSkoKVxuXG5jb25zdCBzeXN0ZW1UZXN0aW5nQ29tcG9uZW50ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcImRpdlwiKVxuc3lzdGVtVGVzdGluZ0NvbXBvbmVudC5zZXRBdHRyaWJ1dGUoXCJkYXRhLXRlc3RpZFwiLCBcInN5c3RlbVRlc3RpbmdDb21wb25lbnRcIilcbnN5c3RlbVRlc3RpbmdDb21wb25lbnQuc2V0QXR0cmlidXRlKFwiZGF0YS1mb2N1c3NlZFwiLCBcInRydWVcIilcblxuY29uc3QgYmxhbmtUZXh0ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcImRpdlwiKVxuYmxhbmtUZXh0LnNldEF0dHJpYnV0ZShcImRhdGEtdGVzdGlkXCIsIFwiYmxhbmtUZXh0XCIpXG5ibGFua1RleHQudGV4dENvbnRlbnQgPSBcImJsYW5rXCJcblxuc3lzdGVtVGVzdGluZ0NvbXBvbmVudC5hcHBlbmRDaGlsZChibGFua1RleHQpXG5yb290LmFwcGVuZENoaWxkKHN5c3RlbVRlc3RpbmdDb21wb25lbnQpXG5cbmNvbnN0IHN5c3RlbVRlc3RCcm93c2VySGVscGVyID0gbmV3IFN5c3RlbVRlc3RCcm93c2VySGVscGVyKClcbnN5c3RlbVRlc3RCcm93c2VySGVscGVyLmVuYWJsZU9uQnJvd3NlcigpXG5cbk9iamVjdC5hc3NpZ24oZ2xvYmFsVGhpcywge3ZlbG9jaW91c0Jyb3dzZXJUZXN0OiB7XG4gIEJyb3dzZXJFbnZpcm9ubWVudEhhbmRsZXIsXG4gIHJ1bkZyb250ZW5kTW9kZWxFdmVudEhvb2tTY2VuYXJpbyxcbiAgcnVuRnJvbnRlbmRUZW5hbnREYXRhYmFzZVBlcnNpc3RlbmNlU2NlbmFyaW8sXG4gIHJ1blVzZURhdGFiYXNlU2VsZWN0aW9uVHJhbnNpdGlvblNjZW5hcmlvLFxuICBzeXN0ZW1UZXN0QnJvd3NlckhlbHBlclxufX0pXG4iXX0=
@@ -0,0 +1,158 @@
1
+ // @ts-check
2
+
3
+ import Configuration, { CurrentConfigurationNotSetError } from "../configuration.js"
4
+ import DatabaseRecord from "../database/record/index.js"
5
+ import BrowserEnvironmentHandler from "../environment-handlers/browser.js"
6
+ import Migration from "../database/migration/index.js"
7
+ import SingleMultiUsePool from "../database/pool/single-multi-use.js"
8
+ import SqliteWebDriver from "../database/drivers/sqlite/index.web.js"
9
+ import Tenant from "../tenants/tenant.js"
10
+
11
+ const DATABASE_IDENTIFIER = "projectTenant"
12
+ const SCHEMA_GENERATION = "frontend-tenant-browser-persistence-1"
13
+
14
+ /**
15
+ * Returns the current configuration without requiring one to exist.
16
+ * @returns {Configuration | undefined} Current configuration when installed.
17
+ */
18
+ function currentConfigurationOrUndefined() {
19
+ try {
20
+ return Configuration.current()
21
+ } catch (error) {
22
+ if (!(error instanceof CurrentConfigurationNotSetError)) throw error
23
+
24
+ return undefined
25
+ }
26
+ }
27
+
28
+ /**
29
+ * Builds the real browser-backed two-project configuration.
30
+ * @returns {Configuration} Browser tenant configuration.
31
+ */
32
+ function buildConfiguration() {
33
+ return new Configuration({
34
+ database: {
35
+ test: {
36
+ projectTenant: {
37
+ driver: SqliteWebDriver,
38
+ locateFile: () => "/sql-wasm.wasm",
39
+ migrations: true,
40
+ name: "velocious-browser-project-proof-template",
41
+ poolType: SingleMultiUsePool,
42
+ tenantOnly: true,
43
+ type: "sqlite"
44
+ }
45
+ }
46
+ },
47
+ directory: "/frontend-tenant-browser-persistence-scenario",
48
+ environment: "test",
49
+ environmentHandler: new BrowserEnvironmentHandler(),
50
+ frontendTenantSqlite: {maxOpenHandles: 2},
51
+ initializeModels: async () => {},
52
+ locale: "en",
53
+ localeFallbacks: {en: ["en"]},
54
+ locales: ["en"],
55
+ tenantDatabaseResolver: ({identifier, tenant}) => {
56
+ if (identifier !== DATABASE_IDENTIFIER || !tenant || typeof tenant !== "object") return
57
+ const projectSlug = /** @type {{projectSlug?: string}} */ (tenant).projectSlug
58
+
59
+ if (projectSlug !== "alpha" && projectSlug !== "beta") return
60
+
61
+ return {name: `velocious-browser-project-proof-${projectSlug}`}
62
+ }
63
+ })
64
+ }
65
+
66
+ /**
67
+ * Exercises two durable physical tenant databases inside the real browser.
68
+ * @returns {Promise<{alphaNames: ReturnType<typeof JSON.parse>[], betaNames: ReturnType<typeof JSON.parse>[], identitiesAreDistinct: boolean, openCount: number}>} Serializable proof result.
69
+ */
70
+ export default async function runFrontendTenantDatabasePersistenceScenario() {
71
+ const previousConfiguration = currentConfigurationOrUndefined()
72
+ const configuration = buildConfiguration()
73
+
74
+ class BrowserProjectRecord extends DatabaseRecord {}
75
+ class CreateBrowserProjectRecords extends Migration {
76
+ async up() {
77
+ await this.execute("CREATE TABLE browser_project_records(id integer PRIMARY KEY AUTOINCREMENT, name varchar(255) NOT NULL)")
78
+ }
79
+ }
80
+
81
+ BrowserProjectRecord.setTableName("browser_project_records")
82
+ BrowserProjectRecord.switchesTenantDatabase(DATABASE_IDENTIFIER)
83
+ BrowserProjectRecord.registerRecordClass({configuration})
84
+ CreateBrowserProjectRecords.onDatabases([DATABASE_IDENTIFIER])
85
+
86
+ const migrationFile = "20260919090000-create-browser-project-records.js"
87
+ /**
88
+ * Loads the one migration bundled into this browser proof.
89
+ * @type {import("../database/migrator/types.js").RequireMigrationContextType}
90
+ */
91
+ const migrations = (fileName) => {
92
+ if (fileName !== migrationFile) throw new Error(`Unknown browser tenant proof migration: ${fileName}`)
93
+
94
+ return {default: CreateBrowserProjectRecords}
95
+ }
96
+
97
+ migrations.keys = () => [migrationFile]
98
+ migrations.id = "frontend-tenant-browser-persistence-scenario"
99
+
100
+ const alpha = Tenant.handle({projectSlug: "alpha"}, configuration)
101
+ const beta = Tenant.handle({projectSlug: "beta"}, configuration)
102
+
103
+ configuration.setCurrent()
104
+
105
+ try {
106
+ await Promise.all([
107
+ alpha.delete({databaseIdentifier: DATABASE_IDENTIFIER}),
108
+ beta.delete({databaseIdentifier: DATABASE_IDENTIFIER})
109
+ ])
110
+ await Promise.all([
111
+ alpha.initialize({databaseIdentifier: DATABASE_IDENTIFIER, migrations, schemaGeneration: SCHEMA_GENERATION}),
112
+ beta.initialize({databaseIdentifier: DATABASE_IDENTIFIER, migrations, schemaGeneration: SCHEMA_GENERATION})
113
+ ])
114
+
115
+ for (let index = 0; index < 12; index++) {
116
+ await Promise.all([
117
+ alpha.databaseOperation({databaseIdentifier: DATABASE_IDENTIFIER}, async (operation) => {
118
+ await operation.forModel(BrowserProjectRecord).create({name: `alpha-${index}`})
119
+ }),
120
+ beta.databaseOperation({databaseIdentifier: DATABASE_IDENTIFIER}, async (operation) => {
121
+ await operation.forModel(BrowserProjectRecord).create({name: `beta-${index}`})
122
+ })
123
+ ])
124
+ }
125
+
126
+ await Promise.all([
127
+ alpha.close({databaseIdentifier: DATABASE_IDENTIFIER, flush: true}),
128
+ beta.close({databaseIdentifier: DATABASE_IDENTIFIER, flush: true})
129
+ ])
130
+ await Promise.all([
131
+ alpha.initialize({databaseIdentifier: DATABASE_IDENTIFIER, migrations, schemaGeneration: SCHEMA_GENERATION}),
132
+ beta.initialize({databaseIdentifier: DATABASE_IDENTIFIER, migrations, schemaGeneration: SCHEMA_GENERATION})
133
+ ])
134
+
135
+ const [alphaNames, betaNames] = await Promise.all([
136
+ alpha.databaseOperation({databaseIdentifier: DATABASE_IDENTIFIER}, async (operation) => {
137
+ return await operation.forModel(BrowserProjectRecord).order("id").pluck("name")
138
+ }),
139
+ beta.databaseOperation({databaseIdentifier: DATABASE_IDENTIFIER}, async (operation) => {
140
+ return await operation.forModel(BrowserProjectRecord).order("id").pluck("name")
141
+ })
142
+ ])
143
+
144
+ return {
145
+ alphaNames,
146
+ betaNames,
147
+ identitiesAreDistinct: alpha.databaseIdentity(DATABASE_IDENTIFIER) !== beta.databaseIdentity(DATABASE_IDENTIFIER),
148
+ openCount: configuration.inspectFrontendTenantSqliteHandles().openCount
149
+ }
150
+ } finally {
151
+ await Promise.all([
152
+ alpha.delete({databaseIdentifier: DATABASE_IDENTIFIER}),
153
+ beta.delete({databaseIdentifier: DATABASE_IDENTIFIER})
154
+ ])
155
+ if (previousConfiguration) previousConfiguration.setCurrent()
156
+ await configuration.closeDatabaseConnections()
157
+ }
158
+ }
@@ -3,6 +3,7 @@
3
3
  import SystemTestBrowserHelper from "system-testing/build/system-test-browser-helper.js"
4
4
  import BrowserEnvironmentHandler from "../environment-handlers/browser.js"
5
5
  import runFrontendModelEventHookScenario from "./browser-frontend-model-event-hook-scenarios.js"
6
+ import runFrontendTenantDatabasePersistenceScenario from "./browser-frontend-tenant-database-scenarios.js"
6
7
  import runUseDatabaseSelectionTransitionScenario from "./browser-use-database-hook-scenarios.js"
7
8
 
8
9
  const root = document.getElementById("root") || (() => {
@@ -29,6 +30,7 @@ systemTestBrowserHelper.enableOnBrowser()
29
30
  Object.assign(globalThis, {velociousBrowserTest: {
30
31
  BrowserEnvironmentHandler,
31
32
  runFrontendModelEventHookScenario,
33
+ runFrontendTenantDatabasePersistenceScenario,
32
34
  runUseDatabaseSelectionTransitionScenario,
33
35
  systemTestBrowserHelper
34
36
  }})
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "velocious": "build/bin/velocious.js"
4
4
  },
5
5
  "name": "velocious",
6
- "version": "1.0.674",
6
+ "version": "1.0.676",
7
7
  "main": "build/index.js",
8
8
  "types": "build/index.d.ts",
9
9
  "files": [
@@ -95,6 +95,11 @@ async function buildBrowserTestApp() {
95
95
  sourcemap: true
96
96
  })
97
97
 
98
+ await fs.copyFile(
99
+ path.join(rootDir, "node_modules", "sql.js", "dist", "sql-wasm.wasm"),
100
+ path.join(distDir, "sql-wasm.wasm")
101
+ )
102
+
98
103
  const html = `<!doctype html>
99
104
  <html lang="en">
100
105
  <head>
@@ -940,10 +940,17 @@ export default class VelociousDatabaseQueryModelClassQuery extends DatabaseQuery
940
940
 
941
941
  /**
942
942
  * Runs first.
943
+ *
944
+ * An explicitly set order is preserved; the deterministic identity order is
945
+ * only applied as a fallback when no order was set, so `LIMIT 1` never
946
+ * returns an arbitrary row.
943
947
  * @returns {Promise<InstanceType<MC> | null>} - Resolves with the first.
944
948
  */
945
949
  async first() {
946
- const newQuery = this.clone().limit(1).reorder(this._defaultIdentityOrder("ASC"))
950
+ const newQuery = this.clone().limit(1)
951
+
952
+ if (newQuery.getOrders().length == 0) newQuery.reorder(this._defaultIdentityOrder("ASC"))
953
+
947
954
  const results = await newQuery.toArray()
948
955
 
949
956
  return results[0] || null
@@ -951,10 +958,26 @@ export default class VelociousDatabaseQueryModelClassQuery extends DatabaseQuery
951
958
 
952
959
  /**
953
960
  * Runs last.
961
+ *
962
+ * An explicitly set order is preserved and read from its end; the
963
+ * deterministic identity order is only applied as a fallback when no order
964
+ * was set. The clone shares its order instances with the source query, so
965
+ * the explicit orders are replaced by independent reversed copies instead
966
+ * of mutating the shared ones.
954
967
  * @returns {Promise<InstanceType<MC> | null>} - Resolves with the last.
955
968
  */
956
969
  async last() {
957
- const results = await this.clone().reorder(this._defaultIdentityOrder("DESC")).limit(1).toArray()
970
+ const newQuery = this.clone().limit(1)
971
+
972
+ if (newQuery.getOrders().length == 0) {
973
+ newQuery.reorder(this._defaultIdentityOrder("DESC"))
974
+ } else {
975
+ const orders = newQuery.getOrders()
976
+
977
+ for (let i = 0; i < orders.length; i += 1) orders[i] = orders[i].reversedCopy()
978
+ }
979
+
980
+ const results = await newQuery.toArray()
958
981
 
959
982
  return results[0] || null
960
983
  }