@owlmeans/mongo-resource 0.1.18-rc.9 → 0.1.18

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 (115) hide show
  1. package/README.md +232 -71
  2. package/agent-meta/manifest.json +3 -3
  3. package/agent-meta/skills/mongo-resource/SKILL.md +89 -44
  4. package/build/consts.d.ts +8 -4
  5. package/build/consts.d.ts.map +1 -1
  6. package/build/consts.js +8 -4
  7. package/build/consts.js.map +1 -1
  8. package/build/declarations/types.d.ts +12 -0
  9. package/build/declarations/types.d.ts.map +1 -0
  10. package/build/declarations/types.js +2 -0
  11. package/build/declarations/types.js.map +1 -0
  12. package/build/declarations.d.ts +4 -9
  13. package/build/declarations.d.ts.map +1 -1
  14. package/build/declarations.js +28 -21
  15. package/build/declarations.js.map +1 -1
  16. package/build/index.d.ts +4 -0
  17. package/build/index.d.ts.map +1 -1
  18. package/build/index.js +1 -0
  19. package/build/index.js.map +1 -1
  20. package/build/resource.d.ts +2 -2
  21. package/build/resource.d.ts.map +1 -1
  22. package/build/resource.js +100 -130
  23. package/build/resource.js.map +1 -1
  24. package/build/types.d.ts +11 -5
  25. package/build/types.d.ts.map +1 -1
  26. package/build/types.local.d.ts +4 -0
  27. package/build/types.local.d.ts.map +1 -0
  28. package/build/types.local.js +2 -0
  29. package/build/types.local.js.map +1 -0
  30. package/build/utils/consts.local.d.ts +25 -0
  31. package/build/utils/consts.local.d.ts.map +1 -0
  32. package/build/utils/consts.local.js +31 -0
  33. package/build/utils/consts.local.js.map +1 -0
  34. package/build/utils/criteria/types.d.ts +27 -0
  35. package/build/utils/criteria/types.d.ts.map +1 -0
  36. package/build/utils/criteria/types.js +2 -0
  37. package/build/utils/criteria/types.js.map +1 -0
  38. package/build/utils/criteria.d.ts +9 -0
  39. package/build/utils/criteria.d.ts.map +1 -0
  40. package/build/utils/criteria.js +204 -0
  41. package/build/utils/criteria.js.map +1 -0
  42. package/build/utils/index.d.ts +1 -0
  43. package/build/utils/index.d.ts.map +1 -1
  44. package/build/utils/index.js +1 -0
  45. package/build/utils/index.js.map +1 -1
  46. package/build/utils/indexes/types.d.ts +19 -0
  47. package/build/utils/indexes/types.d.ts.map +1 -0
  48. package/build/utils/indexes/types.js +2 -0
  49. package/build/utils/indexes/types.js.map +1 -0
  50. package/build/utils/indexes.d.ts +3 -4
  51. package/build/utils/indexes.d.ts.map +1 -1
  52. package/build/utils/indexes.js +44 -28
  53. package/build/utils/indexes.js.map +1 -1
  54. package/build/utils/life-cycle/types.d.ts +36 -0
  55. package/build/utils/life-cycle/types.d.ts.map +1 -0
  56. package/build/utils/life-cycle/types.js +2 -0
  57. package/build/utils/life-cycle/types.js.map +1 -0
  58. package/build/utils/life-cycle.d.ts +3 -30
  59. package/build/utils/life-cycle.d.ts.map +1 -1
  60. package/build/utils/life-cycle.js +96 -112
  61. package/build/utils/life-cycle.js.map +1 -1
  62. package/build/utils/migrations.d.ts.map +1 -1
  63. package/build/utils/migrations.js +1 -2
  64. package/build/utils/migrations.js.map +1 -1
  65. package/build/utils/name.d.ts.map +1 -1
  66. package/build/utils/name.js +1 -5
  67. package/build/utils/name.js.map +1 -1
  68. package/build/utils/refs/types.d.ts +78 -0
  69. package/build/utils/refs/types.d.ts.map +1 -0
  70. package/build/utils/refs/types.js +2 -0
  71. package/build/utils/refs/types.js.map +1 -0
  72. package/build/utils/refs.d.ts +13 -67
  73. package/build/utils/refs.d.ts.map +1 -1
  74. package/build/utils/refs.js +115 -158
  75. package/build/utils/refs.js.map +1 -1
  76. package/build/utils/schema/types.d.ts +16 -0
  77. package/build/utils/schema/types.d.ts.map +1 -0
  78. package/build/utils/schema/types.js +2 -0
  79. package/build/utils/schema/types.js.map +1 -0
  80. package/build/utils/schema.d.ts +3 -11
  81. package/build/utils/schema.d.ts.map +1 -1
  82. package/build/utils/schema.js +86 -88
  83. package/build/utils/schema.js.map +1 -1
  84. package/build/utils/types.local.d.ts +13 -0
  85. package/build/utils/types.local.d.ts.map +1 -0
  86. package/build/utils/types.local.js +2 -0
  87. package/build/utils/types.local.js.map +1 -0
  88. package/package.json +10 -9
  89. package/src/consts.ts +8 -4
  90. package/src/declarations/types.ts +12 -0
  91. package/src/declarations.ts +32 -28
  92. package/src/index.ts +4 -0
  93. package/src/resource.ts +121 -163
  94. package/src/types.local.ts +5 -0
  95. package/src/types.ts +13 -7
  96. package/src/utils/consts.local.ts +35 -0
  97. package/src/utils/criteria/types.ts +28 -0
  98. package/src/utils/criteria.ts +235 -0
  99. package/src/utils/index.ts +1 -0
  100. package/src/utils/indexes/types.ts +20 -0
  101. package/src/utils/indexes.ts +48 -28
  102. package/src/utils/life-cycle/types.ts +39 -0
  103. package/src/utils/life-cycle.ts +120 -134
  104. package/src/utils/migrations.ts +3 -17
  105. package/src/utils/name.ts +1 -6
  106. package/src/utils/refs/types.ts +79 -0
  107. package/src/utils/refs.ts +147 -189
  108. package/src/utils/schema/types.ts +17 -0
  109. package/src/utils/schema.ts +92 -91
  110. package/src/utils/types.local.ts +13 -0
  111. package/tests/context.ts +3 -3
  112. package/tests/criteria.spec.ts +116 -0
  113. package/tests/crud.spec.ts +2 -2
  114. package/tests/indexes.spec.ts +42 -0
  115. package/tests/refs.spec.ts +5 -3
package/build/types.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { Resource, ResourceRecord, ResourceDbService, DbLocker, ResourceLocker, MigratableResource } from '@owlmeans/resource';
1
+ import type { Resource, ResourceRecord, ResourceDbService, DbLocker, LockableResource, MigratableResource, MigrationRegistry } from '@owlmeans/resource';
2
2
  import type { Collection, CreateIndexesOptions, Db, IndexSpecification, MongoClient } from 'mongodb';
3
3
  import type { AnySchema } from 'ajv';
4
4
  /**
@@ -38,7 +38,7 @@ export interface MongoRefOptions {
38
38
  resource?: string;
39
39
  noIndex?: boolean;
40
40
  }
41
- export interface MongoResource<T extends ResourceRecord> extends Resource<T>, ResourceLocker<T>, MigratableResource<MongoTx> {
41
+ export interface MongoResource<T extends ResourceRecord> extends Resource<T>, LockableResource<T>, MigratableResource<MongoTx, MongoResource<T>> {
42
42
  name?: string;
43
43
  /**
44
44
  * The db-config alias this resource was registered against.
@@ -59,13 +59,14 @@ export interface MongoResource<T extends ResourceRecord> extends Resource<T>, Re
59
59
  collection: Collection;
60
60
  db: () => Promise<Db>;
61
61
  client: () => Promise<MongoClient>;
62
- index: <Type extends MongoResource<T>>(name: string, index: IndexSpecification, options?: CreateIndexesOptions) => Type;
62
+ index: (name: string, index: IndexSpecification, options?: CreateIndexesOptions) => this;
63
63
  /**
64
64
  * Declare that a field stores another record's id.
65
65
  *
66
66
  * Chainable and idempotent like {@link MigratableResource.migration}, and stored the same
67
- * way — per alias at module scope — because losing the declaration to a context rebuild
68
- * would silently stop the string/ObjectId conversion for the field.
67
+ * way — per alias at module scope — so a maker that runs more than once for the same alias
68
+ * re-declares the same entry rather than losing it. A lost declaration would silently stop
69
+ * the string/ObjectId conversion for the field.
69
70
  *
70
71
  * Declare only fields whose values really are mongo ids (assigned from another record's
71
72
  * `id`). Composite keys, external provider ids, DIDs and business slugs must stay
@@ -78,4 +79,9 @@ export interface MongoResource<T extends ResourceRecord> extends Resource<T>, Re
78
79
  }
79
80
  export interface MongoDbService extends ResourceDbService<Db, MongoClient>, DbLocker<ResourceRecord> {
80
81
  }
82
+ export interface MongoDeclaration {
83
+ migrations: MigrationRegistry<MongoTx>;
84
+ /** Declared ObjectId references, keyed by field. Registered via `resource.reference()`. */
85
+ references: Map<string, MongoReference>;
86
+ }
81
87
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,QAAQ,EAAE,cAAc,EAAE,iBAAiB,EAAE,QAAQ,EAAE,cAAc,EAAE,kBAAkB,EAC1F,MAAM,oBAAoB,CAAA;AAC3B,OAAO,KAAK,EAAE,UAAU,EAAE,oBAAoB,EAAE,EAAE,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AACpG,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,KAAK,CAAA;AAEpC;;;;;;;GAOG;AACH,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,EAAE,CAAA;IACN,wCAAwC;IACxC,UAAU,EAAE,UAAU,CAAA;IACtB,yFAAyF;IACzF,GAAG,EAAE,CAAC,KAAK,CAAC,EAAE,MAAM,KAAK,UAAU,CAAA;IACnC,mGAAmG;IACnG,GAAG,EAAE,CAAC,KAAK,CAAC,EAAE,MAAM,KAAK,MAAM,CAAA;CAChC;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,cAAc;IAC7B,wFAAwF;IACxF,KAAK,EAAE,MAAM,CAAA;IACb,sFAAsF;IACtF,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,iDAAiD;IACjD,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,MAAM,WAAW,aAAa,CAAC,CAAC,SAAS,cAAc,CAAE,SAAQ,QAAQ,CAAC,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC,CAAC,EAAE,kBAAkB,CAAC,OAAO,CAAC;IAC1H,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,kBAAkB,CAAC;QAAC,OAAO,CAAC,EAAE,oBAAoB,CAAA;KAAE,CAAC,CAAA;IAC5F,UAAU,EAAE,UAAU,CAAA;IACtB,EAAE,EAAE,MAAM,OAAO,CAAC,EAAE,CAAC,CAAA;IACrB,MAAM,EAAE,MAAM,OAAO,CAAC,WAAW,CAAC,CAAA;IAClC,KAAK,EAAE,CAAC,IAAI,SAAS,aAAa,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,kBAAkB,EAAE,OAAO,CAAC,EAAE,oBAAoB,KAAK,IAAI,CAAA;IACvH;;;;;;;;;;OAUG;IACH,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,eAAe,KAAK,IAAI,CAAA;IACnE,6CAA6C;IAC7C,UAAU,EAAE,MAAM,cAAc,EAAE,CAAA;IAClC,WAAW,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,CAAA;CAC9B;AAED,MAAM,WAAW,cAAe,SAAQ,iBAAiB,CAAC,EAAE,EAAE,WAAW,CAAC,EAAE,QAAQ,CAAC,cAAc,CAAC;CACnG"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,iBAAiB,EAAE,QAAQ,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AACxJ,OAAO,KAAK,EAAE,UAAU,EAAE,oBAAoB,EAAE,EAAE,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AACpG,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,KAAK,CAAA;AAEpC;;;;;;;GAOG;AACH,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,EAAE,CAAA;IACN,wCAAwC;IACxC,UAAU,EAAE,UAAU,CAAA;IACtB,yFAAyF;IACzF,GAAG,EAAE,CAAC,KAAK,CAAC,EAAE,MAAM,KAAK,UAAU,CAAA;IACnC,mGAAmG;IACnG,GAAG,EAAE,CAAC,KAAK,CAAC,EAAE,MAAM,KAAK,MAAM,CAAA;CAChC;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,cAAc;IAC7B,wFAAwF;IACxF,KAAK,EAAE,MAAM,CAAA;IACb,sFAAsF;IACtF,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,iDAAiD;IACjD,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,MAAM,WAAW,aAAa,CAAC,CAAC,SAAS,cAAc,CAAE,SAAQ,QAAQ,CAAC,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAC/F,kBAAkB,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC;IAC7C,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,kBAAkB,CAAC;QAAC,OAAO,CAAC,EAAE,oBAAoB,CAAA;KAAE,CAAC,CAAA;IAC5F,UAAU,EAAE,UAAU,CAAA;IACtB,EAAE,EAAE,MAAM,OAAO,CAAC,EAAE,CAAC,CAAA;IACrB,MAAM,EAAE,MAAM,OAAO,CAAC,WAAW,CAAC,CAAA;IAClC,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,kBAAkB,EAAE,OAAO,CAAC,EAAE,oBAAoB,KAAK,IAAI,CAAA;IACxF;;;;;;;;;;;OAWG;IACH,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,eAAe,KAAK,IAAI,CAAA;IACnE,6CAA6C;IAC7C,UAAU,EAAE,MAAM,cAAc,EAAE,CAAA;IAClC,WAAW,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,CAAA;CAC9B;AAED,MAAM,WAAW,cAAe,SAAQ,iBAAiB,CAAC,EAAE,EAAE,WAAW,CAAC,EAAE,QAAQ,CAAC,cAAc,CAAC;CACnG;AAED,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,iBAAiB,CAAC,OAAO,CAAC,CAAA;IACtC,2FAA2F;IAC3F,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAA;CACxC"}
@@ -0,0 +1,4 @@
1
+ import type { ServerConfig, ServerContext } from '@owlmeans/server-context';
2
+ export type Config = ServerConfig;
3
+ export type Context<C extends Config = Config> = ServerContext<C>;
4
+ //# sourceMappingURL=types.local.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.local.d.ts","sourceRoot":"","sources":["../src/types.local.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAE3E,MAAM,MAAM,MAAM,GAAG,YAAY,CAAA;AAEjC,MAAM,MAAM,OAAO,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI,aAAa,CAAC,CAAC,CAAC,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.local.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.local.js","sourceRoot":"","sources":["../src/types.local.ts"],"names":[],"mappings":""}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Operators mongo speaks natively and that mean the same thing here as they do in SQL and in
3
+ * the in-memory engine. Everything else in the shared vocabulary is rewritten below into a
4
+ * mongo expression with the same meaning — a criteria object has to answer identically
5
+ * whichever store it reaches.
6
+ */
7
+ export declare const NATIVE: Set<string>;
8
+ /** What the SERVER reports about an index rather than what a declaration asks for — never a
9
+ * reason to recreate one. `collation` is here because a collection's default collation is
10
+ * reported on every index in it, including the ones declared without any. */
11
+ export declare const REPORTED_FIELDS: Set<string>;
12
+ export declare const VALID_COLLECTION_NAME: RegExp;
13
+ /**
14
+ * The only shape a stored reference is converted from. Deliberately stricter than
15
+ * `ObjectId.isValid`, which also accepts any 12 character string and would silently
16
+ * swallow short business keys.
17
+ */
18
+ export declare const HEX24: RegExp;
19
+ /**
20
+ * Operators whose operand is never an id — a 24 hex string under `$regex` is a pattern,
21
+ * not a reference.
22
+ */
23
+ export declare const OPAQUE_OPERATORS: string[];
24
+ export declare const LOGICAL_OPERATORS: string[];
25
+ //# sourceMappingURL=consts.local.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consts.local.d.ts","sourceRoot":"","sources":["../../src/utils/consts.local.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,eAAO,MAAM,MAAM,aAAiF,CAAA;AAEpG;;8EAE8E;AAC9E,eAAO,MAAM,eAAe,aAE1B,CAAA;AAMF,eAAO,MAAM,qBAAqB,QAAqB,CAAA;AAEvD;;;;GAIG;AACH,eAAO,MAAM,KAAK,QAAsB,CAAA;AAExC;;;GAGG;AACH,eAAO,MAAM,gBAAgB,UAAwE,CAAA;AAErG,eAAO,MAAM,iBAAiB,UAA0B,CAAA"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Operators mongo speaks natively and that mean the same thing here as they do in SQL and in
3
+ * the in-memory engine. Everything else in the shared vocabulary is rewritten below into a
4
+ * mongo expression with the same meaning — a criteria object has to answer identically
5
+ * whichever store it reaches.
6
+ */
7
+ export const NATIVE = new Set(['$eq', '$ne', '$gt', '$gte', '$lt', '$lte', '$in', '$nin', '$regex']);
8
+ /** What the SERVER reports about an index rather than what a declaration asks for — never a
9
+ * reason to recreate one. `collation` is here because a collection's default collation is
10
+ * reported on every index in it, including the ones declared without any. */
11
+ export const REPORTED_FIELDS = new Set([
12
+ 'v', 'ns', 'name', 'collation', 'textIndexVersion', '2dsphereIndexVersion', 'background'
13
+ ]);
14
+ // Collection names must use only alphanumeric characters, underscore, and hyphen — no
15
+ // colons or other delimiters. This guard enforces the rule for every collection created
16
+ // through makeMongoResource across all projects (common/internal/app), failing fast at
17
+ // initialization rather than silently creating a badly-named collection.
18
+ export const VALID_COLLECTION_NAME = /^[a-zA-Z0-9_-]+$/;
19
+ /**
20
+ * The only shape a stored reference is converted from. Deliberately stricter than
21
+ * `ObjectId.isValid`, which also accepts any 12 character string and would silently
22
+ * swallow short business keys.
23
+ */
24
+ export const HEX24 = /^[0-9a-fA-F]{24}$/;
25
+ /**
26
+ * Operators whose operand is never an id — a 24 hex string under `$regex` is a pattern,
27
+ * not a reference.
28
+ */
29
+ export const OPAQUE_OPERATORS = ['$regex', '$options', '$type', '$size', '$mod', '$exists', '$where'];
30
+ export const LOGICAL_OPERATORS = ['$and', '$or', '$nor'];
31
+ //# sourceMappingURL=consts.local.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consts.local.js","sourceRoot":"","sources":["../../src/utils/consts.local.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAA;AAEpG;;8EAE8E;AAC9E,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC;IACrC,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,YAAY;CACzF,CAAC,CAAA;AAEF,sFAAsF;AACtF,wFAAwF;AACxF,uFAAuF;AACvF,yEAAyE;AACzE,MAAM,CAAC,MAAM,qBAAqB,GAAG,kBAAkB,CAAA;AAEvD;;;;GAIG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,mBAAmB,CAAA;AAExC;;;GAGG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAA;AAErG,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAAA"}
@@ -0,0 +1,27 @@
1
+ import type { Criteria, Sort } from '@owlmeans/resource';
2
+ import type { Document } from 'mongodb';
3
+ import type { MongoReference } from '../../types.js';
4
+ /** The portable criteria and sort vocabulary, as the documents a collection takes. */
5
+ export interface MongoCriteriaHelper {
6
+ /**
7
+ * Translate `Criteria<T>` into the filter a collection takes.
8
+ *
9
+ * Two passes: the shared operator vocabulary becomes mongo expressions, then
10
+ * `mongoRefHelper.marshalCriteria` converts the values addressed at `_id` or at a declared
11
+ * reference into `ObjectId`s and maps the `id` alias onto `_id`. Both halves are needed — a
12
+ * criteria object carries string ids and portable operators, a collection stores neither.
13
+ *
14
+ * An empty result is an empty filter, which matches everything. Callers that must not act on
15
+ * "everything" — `purge` — check for it themselves.
16
+ *
17
+ * @throws {UnsupportedArgumentError}
18
+ */
19
+ criteriaToFilter: (criteria: Criteria<any> | undefined, refs: Map<string, MongoReference>) => Document;
20
+ /**
21
+ * Translate `Sort<T>[]` into a mongo sort document. A bare field name is ascending, and `id`
22
+ * addresses `_id` — documents never store an `id` field, so sorting by the name records carry
23
+ * would silently order by nothing.
24
+ */
25
+ sortToMongo: (sort?: Sort<any>[]) => Document | undefined;
26
+ }
27
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/utils/criteria/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAA;AACxD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAEvC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAEpD,sFAAsF;AACtF,MAAM,WAAW,mBAAmB;IAClC;;;;;;;;;;;;OAYG;IACH,gBAAgB,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,GAAG,SAAS,EAAE,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,KAAK,QAAQ,CAAA;IACtG;;;;OAIG;IACH,WAAW,EAAE,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,KAAK,QAAQ,GAAG,SAAS,CAAA;CAC1D"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/utils/criteria/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,9 @@
1
+ import { type Criteria } from '@owlmeans/resource';
2
+ import type { Document } from 'mongodb';
3
+ import type { MongoReference } from '../types.js';
4
+ import type { MongoCriteriaHelper } from './criteria/types.js';
5
+ export declare const createMongoCriteriaHelper: () => MongoCriteriaHelper;
6
+ export declare const mongoCriteriaHelper: MongoCriteriaHelper;
7
+ /** @deprecated compat:factory-refactor — use `mongoCriteriaHelper.criteriaToFilter(…)` */
8
+ export declare const criteriaToFilter: (criteria: Criteria<any> | undefined, refs: Map<string, MongoReference>) => Document;
9
+ //# sourceMappingURL=criteria.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"criteria.d.ts","sourceRoot":"","sources":["../../src/utils/criteria.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,KAAK,QAAQ,EAAa,MAAM,oBAAoB,CAAA;AACvF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAEvC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAGjD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AAsF9D,eAAO,MAAM,yBAAyB,QAAO,mBAwI5C,CAAA;AAED,eAAO,MAAM,mBAAmB,qBAA8B,CAAA;AAE9D,0FAA0F;AAC1F,eAAO,MAAM,gBAAgB,aAAc,QAAQ,CAAC,GAAG,CAAC,GAAG,SAAS,QAAQ,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,KAAG,QACpD,CAAA"}
@@ -0,0 +1,204 @@
1
+ import { UnsupportedArgumentError } from '@owlmeans/resource';
2
+ import { mongoRefHelper } from './refs.js';
3
+ import { NATIVE } from './consts.local.js';
4
+ const escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
5
+ /**
6
+ * A SQL `LIKE` pattern as an anchored regular expression: `%` is any run, `_` is one
7
+ * character, and `\` escapes either. The mapping is the one the in-memory engine applies, so
8
+ * the same pattern selects the same records against a collection.
9
+ */
10
+ const likeToRegExp = (pattern) => {
11
+ let source = '';
12
+ for (let index = 0; index < pattern.length; index++) {
13
+ const char = pattern[index];
14
+ if (char === '\\' && index + 1 < pattern.length) {
15
+ source += escapeRegExp(pattern[++index]);
16
+ continue;
17
+ }
18
+ if (char === '%') {
19
+ source += '.*';
20
+ continue;
21
+ }
22
+ if (char === '_') {
23
+ source += '.';
24
+ continue;
25
+ }
26
+ source += escapeRegExp(char);
27
+ }
28
+ return `^${source}$`;
29
+ };
30
+ const asArray = (operand) => Array.isArray(operand) ? operand : [operand];
31
+ /**
32
+ * One operator as the mongo field expression that answers it.
33
+ *
34
+ * `$exists` and `$null` both become a comparison against `null`, not mongo's own `$exists`:
35
+ * the shared vocabulary asks whether a field *has a value*, which the relational and
36
+ * in-memory stores answer as `IS NULL` / `value == null`. Mongo's `$exists` answers a
37
+ * different question — whether the key is present — and a key present but null would part
38
+ * the three stores over one criteria object.
39
+ *
40
+ * @throws {UnsupportedArgumentError} on an operator this store cannot answer.
41
+ */
42
+ const operatorToFilter = (field, operator, operand) => {
43
+ if (NATIVE.has(operator)) {
44
+ return { [operator]: operand };
45
+ }
46
+ switch (operator) {
47
+ case '$exists':
48
+ return operand === false ? { $eq: null } : { $ne: null };
49
+ case '$null':
50
+ return operand === false ? { $ne: null } : { $eq: null };
51
+ case '$like':
52
+ return { $regex: likeToRegExp(`${operand}`) };
53
+ case '$ilike':
54
+ return { $regex: likeToRegExp(`${operand}`), $options: 'i' };
55
+ case '$startsWith':
56
+ return { $regex: `^${escapeRegExp(`${operand}`)}` };
57
+ case '$endsWith':
58
+ return { $regex: `${escapeRegExp(`${operand}`)}$` };
59
+ case '$between':
60
+ if (!Array.isArray(operand) || operand.length !== 2) {
61
+ throw new UnsupportedArgumentError(`criteria:$between:${field}`);
62
+ }
63
+ return { $gte: operand[0], $lte: operand[1] };
64
+ /** Array membership, mirroring the postgres array operators `@>`, `<@` and `&&`. */
65
+ case '$contains':
66
+ return { $all: asArray(operand) };
67
+ case '$contained':
68
+ /**
69
+ * Nothing outside the operand list may appear in the field. The `$ne: null` keeps an
70
+ * absent field out of the result — `$not` alone is satisfied by a document that has no
71
+ * such field at all, where the relational store answers NULL and matches nothing.
72
+ */
73
+ return { $not: { $elemMatch: { $nin: asArray(operand) } }, $ne: null };
74
+ case '$overlaps':
75
+ return { $in: asArray(operand) };
76
+ default:
77
+ throw new UnsupportedArgumentError(`criteria-operator:${operator}`);
78
+ }
79
+ };
80
+ /**
81
+ * An object naming at least one `$` key is a spec, not a value to compare against. A Date and
82
+ * an array are values even though both are objects.
83
+ */
84
+ const isOperatorSpec = (value) => value != null && typeof value === 'object' && !Array.isArray(value) && !(value instanceof Date)
85
+ && Object.keys(value).some(key => key.startsWith('$'));
86
+ export const createMongoCriteriaHelper = () => {
87
+ const { marshalCriteria } = mongoRefHelper;
88
+ /**
89
+ * One field's criteria as mongo conditions. Operators that translate into the same mongo key —
90
+ * `$like` and `$startsWith` both produce `$regex` — are emitted as separate conditions rather
91
+ * than merged, so neither silently overwrites the other.
92
+ */
93
+ const fieldConditions = (field, spec) => {
94
+ const merged = {};
95
+ const conditions = [];
96
+ for (const [operator, operand] of Object.entries(spec)) {
97
+ if (operand === undefined) {
98
+ continue;
99
+ }
100
+ const fragment = operatorToFilter(field, operator, operand);
101
+ if (Object.keys(fragment).some(key => key in merged)) {
102
+ conditions.push({ [field]: fragment });
103
+ continue;
104
+ }
105
+ Object.assign(merged, fragment);
106
+ }
107
+ if (Object.keys(merged).length > 0) {
108
+ conditions.unshift({ [field]: merged });
109
+ }
110
+ return conditions;
111
+ };
112
+ /**
113
+ * Flatten the conditions into one filter document. Mongo reads sibling keys as a conjunction,
114
+ * so only the ones that would overwrite an earlier key — two `$regex` expressions over the
115
+ * same field, say — need an explicit `$and`.
116
+ */
117
+ const flatten = (conditions) => {
118
+ const filter = {};
119
+ const conflicting = [];
120
+ for (const condition of conditions) {
121
+ if (Object.keys(condition).some(key => key in filter)) {
122
+ conflicting.push(condition);
123
+ continue;
124
+ }
125
+ Object.assign(filter, condition);
126
+ }
127
+ if (conflicting.length > 0) {
128
+ filter.$and = [...(Array.isArray(filter.$and) ? filter.$and : []), ...conflicting];
129
+ }
130
+ return filter;
131
+ };
132
+ const build = (criteria) => {
133
+ const conditions = [];
134
+ for (const [key, raw] of Object.entries(criteria ?? {})) {
135
+ /**
136
+ * An untouched filter must never empty a list, so `undefined` is skipped rather than
137
+ * compared. `null` asks for the absence of a value.
138
+ */
139
+ if (raw === undefined) {
140
+ continue;
141
+ }
142
+ if (key === '$and' || key === '$or') {
143
+ const parts = (Array.isArray(raw) ? raw : [raw])
144
+ .map(part => build(part))
145
+ .filter(part => part.length > 0)
146
+ .map(part => flatten(part));
147
+ if (parts.length > 0) {
148
+ conditions.push(key === '$and' ? { $and: parts } : { $or: parts });
149
+ }
150
+ continue;
151
+ }
152
+ if (key === '$not') {
153
+ const inner = build(raw);
154
+ if (inner.length > 0) {
155
+ /** Mongo has no top level `$not`; `$nor` over a single branch is its negation. */
156
+ conditions.push({ $nor: [flatten(inner)] });
157
+ }
158
+ continue;
159
+ }
160
+ if (raw === null) {
161
+ conditions.push({ [key]: { $eq: null } });
162
+ continue;
163
+ }
164
+ if (isOperatorSpec(raw)) {
165
+ conditions.push(...fieldConditions(key, raw));
166
+ continue;
167
+ }
168
+ if (Array.isArray(raw)) {
169
+ /**
170
+ * A bare array means "any of these", exactly as it does against a relational store.
171
+ * Exact array equality stays reachable as `{ $eq: [...] }`.
172
+ */
173
+ conditions.push({ [key]: { $in: raw } });
174
+ continue;
175
+ }
176
+ conditions.push({ [key]: raw });
177
+ }
178
+ return conditions;
179
+ };
180
+ const criteriaToFilter = (criteria, refs) => {
181
+ const conditions = build(criteria);
182
+ if (conditions.length < 1) {
183
+ return {};
184
+ }
185
+ return marshalCriteria(flatten(conditions), refs) ?? {};
186
+ };
187
+ const sortToMongo = (sort) => {
188
+ if (sort == null || sort.length < 1) {
189
+ return undefined;
190
+ }
191
+ return sort.reduce((order, entry) => {
192
+ const [field, direction] = typeof entry === 'string'
193
+ ? [entry, 1]
194
+ : [entry.field, entry.order === 'desc' ? -1 : 1];
195
+ order[field === 'id' ? '_id' : field] = direction;
196
+ return order;
197
+ }, {});
198
+ };
199
+ return { criteriaToFilter, sortToMongo };
200
+ };
201
+ export const mongoCriteriaHelper = createMongoCriteriaHelper();
202
+ /** @deprecated compat:factory-refactor — use `mongoCriteriaHelper.criteriaToFilter(…)` */
203
+ export const criteriaToFilter = (criteria, refs) => mongoCriteriaHelper.criteriaToFilter(criteria, refs);
204
+ //# sourceMappingURL=criteria.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"criteria.js","sourceRoot":"","sources":["../../src/utils/criteria.ts"],"names":[],"mappings":"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"}
@@ -4,4 +4,5 @@ export * from './name.js';
4
4
  export * from './life-cycle.js';
5
5
  export * from './migrations.js';
6
6
  export * from './refs.js';
7
+ export * from './criteria.js';
7
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AACA,cAAc,cAAc,CAAA;AAC5B,cAAc,aAAa,CAAA;AAC3B,cAAc,WAAW,CAAA;AACzB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,WAAW,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AACA,cAAc,cAAc,CAAA;AAC5B,cAAc,aAAa,CAAA;AAC3B,cAAc,WAAW,CAAA;AACzB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,WAAW,CAAA;AACzB,cAAc,eAAe,CAAA"}
@@ -4,4 +4,5 @@ export * from './name.js';
4
4
  export * from './life-cycle.js';
5
5
  export * from './migrations.js';
6
6
  export * from './refs.js';
7
+ export * from './criteria.js';
7
8
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AACA,cAAc,cAAc,CAAA;AAC5B,cAAc,aAAa,CAAA;AAC3B,cAAc,WAAW,CAAA;AACzB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,WAAW,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AACA,cAAc,cAAc,CAAA;AAC5B,cAAc,aAAa,CAAA;AAC3B,cAAc,WAAW,CAAA;AACzB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,WAAW,CAAA;AACzB,cAAc,eAAe,CAAA"}
@@ -0,0 +1,19 @@
1
+ import type { ResourceRecord } from '@owlmeans/resource';
2
+ import type { Collection, Document } from 'mongodb';
3
+ import type { MongoResource } from '../../types.js';
4
+ /** A collection's indexes against the ones its resource declares. */
5
+ export interface MongoIndexUtils {
6
+ /**
7
+ * Whether an index the database already holds differs from the one declared.
8
+ *
9
+ * Mongo returns an index's options in ITS order, not the declaration's, so comparing the two
10
+ * documents as JSON reported every index as changed — and every boot then dropped and recreated
11
+ * every index. That is invisible until two processes boot at once, when the second one's drop
12
+ * fails with `IndexNotFound` and takes the service down with it. Only the KEY is order-sensitive
13
+ * (a compound index is its key order); options are a set.
14
+ */
15
+ indexChanged: (existing: Document, proposed: Document) => boolean;
16
+ /** Create the declared indexes the collection lacks and recreate the ones that changed. */
17
+ updateIndexes: (collection: Collection, resource: MongoResource<ResourceRecord>) => Promise<void>;
18
+ }
19
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/utils/indexes/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAEnD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAEnD,qEAAqE;AACrE,MAAM,WAAW,eAAe;IAC9B;;;;;;;;OAQG;IACH,YAAY,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,KAAK,OAAO,CAAA;IACjE,2FAA2F;IAC3F,aAAa,EAAE,CAAC,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,aAAa,CAAC,cAAc,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAClG"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/utils/indexes/types.ts"],"names":[],"mappings":""}
@@ -1,5 +1,4 @@
1
- import type { ResourceRecord } from '@owlmeans/resource';
2
- import type { MongoResource } from '../types.js';
3
- import type { Collection } from 'mongodb';
4
- export declare const updateIndexes: (collection: Collection, resource: MongoResource<ResourceRecord>) => Promise<void>;
1
+ import type { MongoIndexUtils } from './indexes/types.js';
2
+ export declare const createMongoIndexUtils: () => MongoIndexUtils;
3
+ export declare const mongoIndexUtils: MongoIndexUtils;
5
4
  //# sourceMappingURL=indexes.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"indexes.d.ts","sourceRoot":"","sources":["../../src/utils/indexes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACxD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAEzC,eAAO,MAAM,aAAa,eAAsB,UAAU,YAAY,aAAa,CAAC,cAAc,CAAC,kBAiClG,CAAA"}
1
+ {"version":3,"file":"indexes.d.ts","sourceRoot":"","sources":["../../src/utils/indexes.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAQzD,eAAO,MAAM,qBAAqB,QAAO,eA0CxC,CAAA;AAED,eAAO,MAAM,eAAe,iBAA0B,CAAA"}
@@ -1,34 +1,50 @@
1
- export const updateIndexes = async (collection, resource) => {
2
- if (resource.indexes != null) {
1
+ import { logger } from '@owlmeans/log';
2
+ import { REPORTED_FIELDS } from './consts.local.js';
3
+ const log = logger('mongo-resource');
4
+ const options = (spec) => Object.entries(spec)
5
+ .filter(([field]) => field !== 'key' && !REPORTED_FIELDS.has(field))
6
+ .sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
7
+ export const createMongoIndexUtils = () => {
8
+ const indexChanged = (existing, proposed) => {
9
+ // We do not recreate text indexes.
10
+ if ('weights' in existing)
11
+ return false;
12
+ if (JSON.stringify(existing.key) !== JSON.stringify(proposed.key))
13
+ return true;
14
+ return JSON.stringify(options(existing)) !== JSON.stringify(options(proposed));
15
+ };
16
+ const updateIndexes = async (collection, resource) => {
17
+ if (resource.indexes == null) {
18
+ return;
19
+ }
20
+ const present = await collection.indexes();
3
21
  await Promise.all(resource.indexes.map(async (index) => {
4
- const _index = (await collection.indexes()).find(_index => _index.name === index.name);
5
- if (_index != null) {
6
- const existing = { ..._index };
7
- if ('name' in existing) {
8
- delete existing.name;
9
- }
10
- if ('v' in existing) {
11
- delete existing.v;
12
- }
13
- const propsed = { key: index.index, ...index.options };
14
- // We do not recreate text indexes
15
- if (JSON.stringify(existing) !== JSON.stringify(propsed) && !('weights' in existing)) {
16
- console.info(JSON.stringify(existing));
17
- console.info(JSON.stringify(propsed));
18
- console.debug(`Recreate index ${resource.alias} : ${index.name}`);
19
- await collection.dropIndex(index.name);
20
- await collection.createIndex(index.index, {
21
- name: index.name, ...((index.options != null) ? index.options : {})
22
- });
23
- }
22
+ const create = async () => await collection.createIndex(index.index, {
23
+ name: index.name, ...((index.options != null) ? index.options : {})
24
+ });
25
+ const existing = present.find(_index => _index.name === index.name);
26
+ if (existing == null) {
27
+ log.debug('Create index', { resource: resource.alias, index: index.name });
28
+ await create();
29
+ return;
24
30
  }
25
- else {
26
- console.debug(`Create index ${resource.alias} : ${index.name}`);
27
- await collection.createIndex(index.index, {
28
- name: index.name, ...((index.options != null) ? index.options : {})
29
- });
31
+ if (!indexChanged(existing, { key: index.index, ...index.options })) {
32
+ return;
30
33
  }
34
+ log.debug('Recreate index', { resource: resource.alias, index: index.name });
35
+ try {
36
+ await collection.dropIndex(index.name);
37
+ }
38
+ catch (e) {
39
+ // IndexNotFound: another process booting alongside this one dropped it first — it is
40
+ // recreating the same declaration, so there is nothing here to fail over.
41
+ if (e.code !== 27)
42
+ throw e;
43
+ }
44
+ await create();
31
45
  }));
32
- }
46
+ };
47
+ return { indexChanged, updateIndexes };
33
48
  };
49
+ export const mongoIndexUtils = createMongoIndexUtils();
34
50
  //# sourceMappingURL=indexes.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"indexes.js","sourceRoot":"","sources":["../../src/utils/indexes.ts"],"names":[],"mappings":"AAIA,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,EAAE,UAAsB,EAAE,QAAuC,EAAE,EAAE;IACrG,IAAI,QAAQ,CAAC,OAAO,IAAI,IAAI,EAAE,CAAC;QAC7B,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CACpC,KAAK,EAAC,KAAK,EAAC,EAAE;YACZ,MAAM,MAAM,GAAG,CAAC,MAAM,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI,CAAC,CAAA;YACtF,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;gBACnB,MAAM,QAAQ,GAAG,EAAE,GAAG,MAAM,EAAE,CAAA;gBAC9B,IAAI,MAAM,IAAI,QAAQ,EAAE,CAAC;oBACvB,OAAO,QAAQ,CAAC,IAAI,CAAA;gBACtB,CAAC;gBACD,IAAI,GAAG,IAAI,QAAQ,EAAE,CAAC;oBACpB,OAAO,QAAQ,CAAC,CAAC,CAAA;gBACnB,CAAC;gBACD,MAAM,OAAO,GAAG,EAAE,GAAG,EAAE,KAAK,CAAC,KAAK,EAAE,GAAG,KAAK,CAAC,OAAO,EAAE,CAAA;gBACtD,kCAAkC;gBAClC,IAAI,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,SAAS,IAAI,QAAQ,CAAC,EAAE,CAAC;oBACrF,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAA;oBACtC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAA;oBACrC,OAAO,CAAC,KAAK,CAAC,kBAAkB,QAAQ,CAAC,KAAK,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC,CAAA;oBACjE,MAAM,UAAU,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;oBACtC,MAAM,UAAU,CAAC,WAAW,CAAC,KAAK,CAAC,KAAK,EAAE;wBACxC,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;qBACpE,CAAC,CAAA;gBACJ,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,KAAK,CAAC,gBAAgB,QAAQ,CAAC,KAAK,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC,CAAA;gBAC/D,MAAM,UAAU,CAAC,WAAW,CAAC,KAAK,CAAC,KAAK,EAAE;oBACxC,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;iBACpE,CAAC,CAAA;YACJ,CAAC;QACH,CAAC,CACF,CAAC,CAAA;IACJ,CAAC;AACH,CAAC,CAAA"}
1
+ {"version":3,"file":"indexes.js","sourceRoot":"","sources":["../../src/utils/indexes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ import type { BasicContext } from '@owlmeans/context';
2
+ import type { DbConfig, ResourceRecord } from '@owlmeans/resource';
3
+ import type { Collection } from 'mongodb';
4
+ import type { MongoResource } from '../../types.js';
5
+ /** A resource collection's initialization over one database. */
6
+ export interface MongoLifeCycleUtils {
7
+ /**
8
+ * Bring a resource's collection to the shape its schema declares.
9
+ *
10
+ * Order is deliberate, and matches the Postgres counterpart:
11
+ *
12
+ * 1. probe for the collection
13
+ * 2. absent → *baseline* every registered migration; present → run the `pre` ones
14
+ * (including the system `$ref:` migrations that convert declared references)
15
+ * 3. create the collection, or update its validator and indexes
16
+ * 4. present → run the `post` migrations
17
+ * 5. reconcile declared references — the second half of their double check: the ledger
18
+ * said whether the `$ref:` migration ran, this probes the collection itself and
19
+ * converts whatever strings still slipped through
20
+ *
21
+ * Step 2 is what stops the two mechanisms colliding. A `pre` migration runs before the
22
+ * validator is tightened, so it can reshape documents the new validator would reject. On a
23
+ * collection this call just created there is nothing to reshape — replaying a historical
24
+ * migration against a collection born in its final shape would at best scan for nothing —
25
+ * so the migrations are recorded as satisfied instead of run.
26
+ *
27
+ * `context` is optional so the existing three-argument call keeps working; without it a
28
+ * migration's `use`/`ref` can only address the owning resource.
29
+ */
30
+ initializeCollection: (config: DbConfig, resource: MongoResource<ResourceRecord>, context?: BasicContext<any>) => Promise<Collection>;
31
+ /** Create the collection with its validator and its declared indexes. */
32
+ createCollection: (name: string, resource: MongoResource<ResourceRecord>) => Promise<Collection>;
33
+ /** Replace the validator of an existing collection and bring its indexes up to date. */
34
+ updateCollection: (name: string, resource: MongoResource<ResourceRecord>) => Promise<Collection>;
35
+ }
36
+ //# sourceMappingURL=types.d.ts.map