@proseql/core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/errors/crud-errors.d.ts +98 -0
- package/dist/errors/crud-errors.d.ts.map +1 -0
- package/dist/errors/crud-errors.js +23 -0
- package/dist/errors/crud-errors.js.map +1 -0
- package/dist/errors/index.d.ts +16 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +12 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/errors/migration-errors.d.ts +22 -0
- package/dist/errors/migration-errors.d.ts.map +1 -0
- package/dist/errors/migration-errors.js +14 -0
- package/dist/errors/migration-errors.js.map +1 -0
- package/dist/errors/plugin-errors.d.ts +15 -0
- package/dist/errors/plugin-errors.d.ts.map +1 -0
- package/dist/errors/plugin-errors.js +11 -0
- package/dist/errors/plugin-errors.js.map +1 -0
- package/dist/errors/query-errors.d.ts +31 -0
- package/dist/errors/query-errors.d.ts.map +1 -0
- package/dist/errors/query-errors.js +11 -0
- package/dist/errors/query-errors.js.map +1 -0
- package/dist/errors/storage-errors.d.ts +30 -0
- package/dist/errors/storage-errors.d.ts.map +1 -0
- package/dist/errors/storage-errors.js +11 -0
- package/dist/errors/storage-errors.js.map +1 -0
- package/dist/factories/crud-factory-with-relationships.d.ts +28 -0
- package/dist/factories/crud-factory-with-relationships.d.ts.map +1 -0
- package/dist/factories/crud-factory-with-relationships.js +8 -0
- package/dist/factories/crud-factory-with-relationships.js.map +1 -0
- package/dist/factories/crud-factory.d.ts +25 -0
- package/dist/factories/crud-factory.d.ts.map +1 -0
- package/dist/factories/crud-factory.js +8 -0
- package/dist/factories/crud-factory.js.map +1 -0
- package/dist/factories/database-effect.d.ts +241 -0
- package/dist/factories/database-effect.d.ts.map +1 -0
- package/dist/factories/database-effect.js +859 -0
- package/dist/factories/database-effect.js.map +1 -0
- package/dist/hooks/hook-runner.d.ts +60 -0
- package/dist/hooks/hook-runner.d.ts.map +1 -0
- package/dist/hooks/hook-runner.js +107 -0
- package/dist/hooks/hook-runner.js.map +1 -0
- package/dist/index.d.ts +84 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +110 -0
- package/dist/index.js.map +1 -0
- package/dist/indexes/index-lookup.d.ts +33 -0
- package/dist/indexes/index-lookup.d.ts.map +1 -0
- package/dist/indexes/index-lookup.js +180 -0
- package/dist/indexes/index-lookup.js.map +1 -0
- package/dist/indexes/index-manager.d.ts +118 -0
- package/dist/indexes/index-manager.d.ts.map +1 -0
- package/dist/indexes/index-manager.js +345 -0
- package/dist/indexes/index-manager.js.map +1 -0
- package/dist/indexes/search-index.d.ts +179 -0
- package/dist/indexes/search-index.d.ts.map +1 -0
- package/dist/indexes/search-index.js +405 -0
- package/dist/indexes/search-index.js.map +1 -0
- package/dist/migrations/migration-runner.d.ts +70 -0
- package/dist/migrations/migration-runner.d.ts.map +1 -0
- package/dist/migrations/migration-runner.js +271 -0
- package/dist/migrations/migration-runner.js.map +1 -0
- package/dist/migrations/migration-types.d.ts +63 -0
- package/dist/migrations/migration-types.d.ts.map +1 -0
- package/dist/migrations/migration-types.js +5 -0
- package/dist/migrations/migration-types.js.map +1 -0
- package/dist/operations/crud/create-with-relationships.d.ts +44 -0
- package/dist/operations/crud/create-with-relationships.d.ts.map +1 -0
- package/dist/operations/crud/create-with-relationships.js +483 -0
- package/dist/operations/crud/create-with-relationships.js.map +1 -0
- package/dist/operations/crud/create.d.ts +48 -0
- package/dist/operations/crud/create.d.ts.map +1 -0
- package/dist/operations/crud/create.js +333 -0
- package/dist/operations/crud/create.js.map +1 -0
- package/dist/operations/crud/delete-with-relationships.d.ts +63 -0
- package/dist/operations/crud/delete-with-relationships.d.ts.map +1 -0
- package/dist/operations/crud/delete-with-relationships.js +395 -0
- package/dist/operations/crud/delete-with-relationships.js.map +1 -0
- package/dist/operations/crud/delete.d.ts +58 -0
- package/dist/operations/crud/delete.d.ts.map +1 -0
- package/dist/operations/crud/delete.js +267 -0
- package/dist/operations/crud/delete.js.map +1 -0
- package/dist/operations/crud/unique-check.d.ts +114 -0
- package/dist/operations/crud/unique-check.d.ts.map +1 -0
- package/dist/operations/crud/unique-check.js +383 -0
- package/dist/operations/crud/unique-check.js.map +1 -0
- package/dist/operations/crud/update-with-relationships.d.ts +45 -0
- package/dist/operations/crud/update-with-relationships.d.ts.map +1 -0
- package/dist/operations/crud/update-with-relationships.js +516 -0
- package/dist/operations/crud/update-with-relationships.js.map +1 -0
- package/dist/operations/crud/update.d.ts +91 -0
- package/dist/operations/crud/update.d.ts.map +1 -0
- package/dist/operations/crud/update.js +505 -0
- package/dist/operations/crud/update.js.map +1 -0
- package/dist/operations/crud/upsert.d.ts +52 -0
- package/dist/operations/crud/upsert.d.ts.map +1 -0
- package/dist/operations/crud/upsert.js +386 -0
- package/dist/operations/crud/upsert.js.map +1 -0
- package/dist/operations/query/aggregate.d.ts +30 -0
- package/dist/operations/query/aggregate.d.ts.map +1 -0
- package/dist/operations/query/aggregate.js +227 -0
- package/dist/operations/query/aggregate.js.map +1 -0
- package/dist/operations/query/cursor-stream.d.ts +18 -0
- package/dist/operations/query/cursor-stream.d.ts.map +1 -0
- package/dist/operations/query/cursor-stream.js +199 -0
- package/dist/operations/query/cursor-stream.js.map +1 -0
- package/dist/operations/query/filter-stream.d.ts +12 -0
- package/dist/operations/query/filter-stream.d.ts.map +1 -0
- package/dist/operations/query/filter-stream.js +167 -0
- package/dist/operations/query/filter-stream.js.map +1 -0
- package/dist/operations/query/filter.d.ts +13 -0
- package/dist/operations/query/filter.d.ts.map +1 -0
- package/dist/operations/query/filter.js +267 -0
- package/dist/operations/query/filter.js.map +1 -0
- package/dist/operations/query/paginate-stream.d.ts +11 -0
- package/dist/operations/query/paginate-stream.d.ts.map +1 -0
- package/dist/operations/query/paginate-stream.js +22 -0
- package/dist/operations/query/paginate-stream.js.map +1 -0
- package/dist/operations/query/query-helpers.d.ts +14 -0
- package/dist/operations/query/query-helpers.d.ts.map +1 -0
- package/dist/operations/query/query-helpers.js +22 -0
- package/dist/operations/query/query-helpers.js.map +1 -0
- package/dist/operations/query/resolve-computed.d.ts +142 -0
- package/dist/operations/query/resolve-computed.d.ts.map +1 -0
- package/dist/operations/query/resolve-computed.js +197 -0
- package/dist/operations/query/resolve-computed.js.map +1 -0
- package/dist/operations/query/search.d.ts +110 -0
- package/dist/operations/query/search.d.ts.map +1 -0
- package/dist/operations/query/search.js +188 -0
- package/dist/operations/query/search.js.map +1 -0
- package/dist/operations/query/select-stream.d.ts +27 -0
- package/dist/operations/query/select-stream.d.ts.map +1 -0
- package/dist/operations/query/select-stream.js +88 -0
- package/dist/operations/query/select-stream.js.map +1 -0
- package/dist/operations/query/select.d.ts +54 -0
- package/dist/operations/query/select.d.ts.map +1 -0
- package/dist/operations/query/select.js +159 -0
- package/dist/operations/query/select.js.map +1 -0
- package/dist/operations/query/sort-stream.d.ts +46 -0
- package/dist/operations/query/sort-stream.d.ts.map +1 -0
- package/dist/operations/query/sort-stream.js +158 -0
- package/dist/operations/query/sort-stream.js.map +1 -0
- package/dist/operations/query/sort.d.ts +9 -0
- package/dist/operations/query/sort.d.ts.map +1 -0
- package/dist/operations/query/sort.js +58 -0
- package/dist/operations/query/sort.js.map +1 -0
- package/dist/operations/relationships/populate-stream.d.ts +29 -0
- package/dist/operations/relationships/populate-stream.d.ts.map +1 -0
- package/dist/operations/relationships/populate-stream.js +159 -0
- package/dist/operations/relationships/populate-stream.js.map +1 -0
- package/dist/operations/relationships/populate.d.ts +15 -0
- package/dist/operations/relationships/populate.d.ts.map +1 -0
- package/dist/operations/relationships/populate.js +228 -0
- package/dist/operations/relationships/populate.js.map +1 -0
- package/dist/plugins/plugin-hooks.d.ts +25 -0
- package/dist/plugins/plugin-hooks.d.ts.map +1 -0
- package/dist/plugins/plugin-hooks.js +64 -0
- package/dist/plugins/plugin-hooks.js.map +1 -0
- package/dist/plugins/plugin-registry.d.ts +26 -0
- package/dist/plugins/plugin-registry.d.ts.map +1 -0
- package/dist/plugins/plugin-registry.js +150 -0
- package/dist/plugins/plugin-registry.js.map +1 -0
- package/dist/plugins/plugin-types.d.ts +95 -0
- package/dist/plugins/plugin-types.d.ts.map +1 -0
- package/dist/plugins/plugin-types.js +6 -0
- package/dist/plugins/plugin-types.js.map +1 -0
- package/dist/plugins/plugin-validation.d.ts +49 -0
- package/dist/plugins/plugin-validation.d.ts.map +1 -0
- package/dist/plugins/plugin-validation.js +295 -0
- package/dist/plugins/plugin-validation.js.map +1 -0
- package/dist/reactive/change-event.d.ts +44 -0
- package/dist/reactive/change-event.d.ts.map +1 -0
- package/dist/reactive/change-event.js +49 -0
- package/dist/reactive/change-event.js.map +1 -0
- package/dist/reactive/change-pubsub.d.ts +32 -0
- package/dist/reactive/change-pubsub.d.ts.map +1 -0
- package/dist/reactive/change-pubsub.js +31 -0
- package/dist/reactive/change-pubsub.js.map +1 -0
- package/dist/reactive/evaluate-query.d.ts +62 -0
- package/dist/reactive/evaluate-query.d.ts.map +1 -0
- package/dist/reactive/evaluate-query.js +57 -0
- package/dist/reactive/evaluate-query.js.map +1 -0
- package/dist/reactive/watch-by-id.d.ts +53 -0
- package/dist/reactive/watch-by-id.d.ts.map +1 -0
- package/dist/reactive/watch-by-id.js +55 -0
- package/dist/reactive/watch-by-id.js.map +1 -0
- package/dist/reactive/watch.d.ts +78 -0
- package/dist/reactive/watch.d.ts.map +1 -0
- package/dist/reactive/watch.js +133 -0
- package/dist/reactive/watch.js.map +1 -0
- package/dist/serializers/codecs/hjson.d.ts +33 -0
- package/dist/serializers/codecs/hjson.d.ts.map +1 -0
- package/dist/serializers/codecs/hjson.js +40 -0
- package/dist/serializers/codecs/hjson.js.map +1 -0
- package/dist/serializers/codecs/json.d.ts +22 -0
- package/dist/serializers/codecs/json.d.ts.map +1 -0
- package/dist/serializers/codecs/json.js +28 -0
- package/dist/serializers/codecs/json.js.map +1 -0
- package/dist/serializers/codecs/json5.d.ts +26 -0
- package/dist/serializers/codecs/json5.d.ts.map +1 -0
- package/dist/serializers/codecs/json5.js +33 -0
- package/dist/serializers/codecs/json5.js.map +1 -0
- package/dist/serializers/codecs/jsonc.d.ts +29 -0
- package/dist/serializers/codecs/jsonc.d.ts.map +1 -0
- package/dist/serializers/codecs/jsonc.js +38 -0
- package/dist/serializers/codecs/jsonc.js.map +1 -0
- package/dist/serializers/codecs/jsonl.d.ts +17 -0
- package/dist/serializers/codecs/jsonl.d.ts.map +1 -0
- package/dist/serializers/codecs/jsonl.js +31 -0
- package/dist/serializers/codecs/jsonl.js.map +1 -0
- package/dist/serializers/codecs/prose.d.ts +419 -0
- package/dist/serializers/codecs/prose.d.ts.map +1 -0
- package/dist/serializers/codecs/prose.js +1060 -0
- package/dist/serializers/codecs/prose.js.map +1 -0
- package/dist/serializers/codecs/toml.d.ts +23 -0
- package/dist/serializers/codecs/toml.d.ts.map +1 -0
- package/dist/serializers/codecs/toml.js +66 -0
- package/dist/serializers/codecs/toml.js.map +1 -0
- package/dist/serializers/codecs/toon.d.ts +20 -0
- package/dist/serializers/codecs/toon.d.ts.map +1 -0
- package/dist/serializers/codecs/toon.js +33 -0
- package/dist/serializers/codecs/toon.js.map +1 -0
- package/dist/serializers/codecs/yaml.d.ts +24 -0
- package/dist/serializers/codecs/yaml.d.ts.map +1 -0
- package/dist/serializers/codecs/yaml.js +31 -0
- package/dist/serializers/codecs/yaml.js.map +1 -0
- package/dist/serializers/format-codec.d.ts +53 -0
- package/dist/serializers/format-codec.d.ts.map +1 -0
- package/dist/serializers/format-codec.js +148 -0
- package/dist/serializers/format-codec.js.map +1 -0
- package/dist/serializers/presets.d.ts +48 -0
- package/dist/serializers/presets.d.ts.map +1 -0
- package/dist/serializers/presets.js +72 -0
- package/dist/serializers/presets.js.map +1 -0
- package/dist/serializers/serializer-service.d.ts +11 -0
- package/dist/serializers/serializer-service.d.ts.map +1 -0
- package/dist/serializers/serializer-service.js +4 -0
- package/dist/serializers/serializer-service.js.map +1 -0
- package/dist/state/collection-state.d.ts +19 -0
- package/dist/state/collection-state.d.ts.map +1 -0
- package/dist/state/collection-state.js +15 -0
- package/dist/state/collection-state.js.map +1 -0
- package/dist/state/state-operations.d.ts +38 -0
- package/dist/state/state-operations.d.ts.map +1 -0
- package/dist/state/state-operations.js +65 -0
- package/dist/state/state-operations.js.map +1 -0
- package/dist/storage/in-memory-adapter-layer.d.ts +16 -0
- package/dist/storage/in-memory-adapter-layer.d.ts.map +1 -0
- package/dist/storage/in-memory-adapter-layer.js +81 -0
- package/dist/storage/in-memory-adapter-layer.js.map +1 -0
- package/dist/storage/persistence-effect.d.ts +244 -0
- package/dist/storage/persistence-effect.d.ts.map +1 -0
- package/dist/storage/persistence-effect.js +551 -0
- package/dist/storage/persistence-effect.js.map +1 -0
- package/dist/storage/storage-service.d.ts +22 -0
- package/dist/storage/storage-service.d.ts.map +1 -0
- package/dist/storage/storage-service.js +4 -0
- package/dist/storage/storage-service.js.map +1 -0
- package/dist/storage/transforms.d.ts +183 -0
- package/dist/storage/transforms.d.ts.map +1 -0
- package/dist/storage/transforms.js +263 -0
- package/dist/storage/transforms.js.map +1 -0
- package/dist/transactions/transaction.d.ts +87 -0
- package/dist/transactions/transaction.d.ts.map +1 -0
- package/dist/transactions/transaction.js +240 -0
- package/dist/transactions/transaction.js.map +1 -0
- package/dist/types/aggregate-types.d.ts +73 -0
- package/dist/types/aggregate-types.d.ts.map +1 -0
- package/dist/types/aggregate-types.js +14 -0
- package/dist/types/aggregate-types.js.map +1 -0
- package/dist/types/computed-types.d.ts +71 -0
- package/dist/types/computed-types.d.ts.map +1 -0
- package/dist/types/computed-types.js +8 -0
- package/dist/types/computed-types.js.map +1 -0
- package/dist/types/crud-relationship-types.d.ts +180 -0
- package/dist/types/crud-relationship-types.d.ts.map +1 -0
- package/dist/types/crud-relationship-types.js +17 -0
- package/dist/types/crud-relationship-types.js.map +1 -0
- package/dist/types/crud-types.d.ts +343 -0
- package/dist/types/crud-types.d.ts.map +1 -0
- package/dist/types/crud-types.js +43 -0
- package/dist/types/crud-types.js.map +1 -0
- package/dist/types/cursor-types.d.ts +52 -0
- package/dist/types/cursor-types.d.ts.map +1 -0
- package/dist/types/cursor-types.js +2 -0
- package/dist/types/cursor-types.js.map +1 -0
- package/dist/types/database-config-types.d.ts +196 -0
- package/dist/types/database-config-types.d.ts.map +1 -0
- package/dist/types/database-config-types.js +11 -0
- package/dist/types/database-config-types.js.map +1 -0
- package/dist/types/hook-types.d.ts +158 -0
- package/dist/types/hook-types.d.ts.map +1 -0
- package/dist/types/hook-types.js +6 -0
- package/dist/types/hook-types.js.map +1 -0
- package/dist/types/index-types.d.ts +42 -0
- package/dist/types/index-types.d.ts.map +1 -0
- package/dist/types/index-types.js +8 -0
- package/dist/types/index-types.js.map +1 -0
- package/dist/types/operators.d.ts +5 -0
- package/dist/types/operators.d.ts.map +1 -0
- package/dist/types/operators.js +297 -0
- package/dist/types/operators.js.map +1 -0
- package/dist/types/query-overloads.d.ts +54 -0
- package/dist/types/query-overloads.d.ts.map +1 -0
- package/dist/types/query-overloads.js +3 -0
- package/dist/types/query-overloads.js.map +1 -0
- package/dist/types/reactive-types.d.ts +75 -0
- package/dist/types/reactive-types.d.ts.map +1 -0
- package/dist/types/reactive-types.js +7 -0
- package/dist/types/reactive-types.js.map +1 -0
- package/dist/types/schema-types.d.ts +56 -0
- package/dist/types/schema-types.d.ts.map +1 -0
- package/dist/types/schema-types.js +8 -0
- package/dist/types/schema-types.js.map +1 -0
- package/dist/types/search-types.d.ts +82 -0
- package/dist/types/search-types.d.ts.map +1 -0
- package/dist/types/search-types.js +110 -0
- package/dist/types/search-types.js.map +1 -0
- package/dist/types/types.d.ts +286 -0
- package/dist/types/types.d.ts.map +1 -0
- package/dist/types/types.js +2 -0
- package/dist/types/types.js.map +1 -0
- package/dist/utils/id-generator.d.ts +97 -0
- package/dist/utils/id-generator.d.ts.map +1 -0
- package/dist/utils/id-generator.js +247 -0
- package/dist/utils/id-generator.js.map +1 -0
- package/dist/utils/nested-path.d.ts +56 -0
- package/dist/utils/nested-path.d.ts.map +1 -0
- package/dist/utils/nested-path.js +119 -0
- package/dist/utils/nested-path.js.map +1 -0
- package/dist/utils/path.d.ts +16 -0
- package/dist/utils/path.d.ts.map +1 -0
- package/dist/utils/path.js +24 -0
- package/dist/utils/path.js.map +1 -0
- package/dist/validators/foreign-key.d.ts +49 -0
- package/dist/validators/foreign-key.d.ts.map +1 -0
- package/dist/validators/foreign-key.js +153 -0
- package/dist/validators/foreign-key.js.map +1 -0
- package/dist/validators/schema-validator.d.ts +19 -0
- package/dist/validators/schema-validator.d.ts.map +1 -0
- package/dist/validators/schema-validator.js +34 -0
- package/dist/validators/schema-validator.js.map +1 -0
- package/package.json +57 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { Effect, Ref, Stream } from "effect";
|
|
2
|
+
import { DanglingReferenceError } from "../../errors/query-errors.js";
|
|
3
|
+
/**
|
|
4
|
+
* Maximum recursion depth for nested population (mirrors PopulateConfig type depth limit).
|
|
5
|
+
*/
|
|
6
|
+
const MAX_POPULATE_DEPTH = 5;
|
|
7
|
+
/**
|
|
8
|
+
* Type guard: is value a non-null, non-array object?
|
|
9
|
+
*/
|
|
10
|
+
function isRecord(value) {
|
|
11
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Type guard for populate config objects.
|
|
15
|
+
*/
|
|
16
|
+
function isPopulateConfig(value) {
|
|
17
|
+
return isRecord(value);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Derive the foreign key field for an inverse relationship.
|
|
21
|
+
*
|
|
22
|
+
* Priority:
|
|
23
|
+
* 1. Explicit `foreignKey` on the inverse relationship definition
|
|
24
|
+
* 2. Explicit `foreignKey` on the corresponding ref relationship in the target collection
|
|
25
|
+
* 3. Default naming convention: singularize source collection name + "Id"
|
|
26
|
+
*/
|
|
27
|
+
function resolveInverseForeignKey(relationship, collectionName, dbConfig) {
|
|
28
|
+
if (relationship.foreignKey) {
|
|
29
|
+
return relationship.foreignKey;
|
|
30
|
+
}
|
|
31
|
+
const targetConfig = dbConfig[relationship.target];
|
|
32
|
+
if (targetConfig) {
|
|
33
|
+
const reverseRel = Object.entries(targetConfig.relationships).find(([, rel]) => rel.type === "ref" && rel.target === collectionName);
|
|
34
|
+
if (reverseRel?.[1].foreignKey) {
|
|
35
|
+
return reverseRel[1].foreignKey;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
// Default: singularize collection name + "Id"
|
|
39
|
+
const singularName = collectionName.endsWith("ies")
|
|
40
|
+
? `${collectionName.slice(0, -3)}y`
|
|
41
|
+
: collectionName.replace(/s$/, "");
|
|
42
|
+
return `${singularName}Id`;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Populate a single item's relationships recursively.
|
|
46
|
+
*
|
|
47
|
+
* For each relationship key in the populate config:
|
|
48
|
+
* - `ref`: look up a single entity in the target collection by foreign key
|
|
49
|
+
* - `inverse`: find all entities whose foreign key points back to this item
|
|
50
|
+
*
|
|
51
|
+
* When the populate value is a nested config object (not just `true`),
|
|
52
|
+
* recursively populate the related entity's relationships using the
|
|
53
|
+
* target collection's relationship definitions.
|
|
54
|
+
*
|
|
55
|
+
* Recursion stops at MAX_POPULATE_DEPTH (5) to prevent infinite loops
|
|
56
|
+
* in circular relationship graphs.
|
|
57
|
+
*/
|
|
58
|
+
function populateItem(item, populateConfig, stateRefs, dbConfig, collectionName, depth) {
|
|
59
|
+
return Effect.gen(function* () {
|
|
60
|
+
const sourceConfig = dbConfig[collectionName];
|
|
61
|
+
if (!sourceConfig)
|
|
62
|
+
return item;
|
|
63
|
+
const relationships = sourceConfig.relationships;
|
|
64
|
+
const populateEntries = Object.entries(populateConfig).filter(([key]) => relationships[key] !== undefined);
|
|
65
|
+
if (populateEntries.length === 0)
|
|
66
|
+
return item;
|
|
67
|
+
const populated = { ...item };
|
|
68
|
+
for (const [key, value] of populateEntries) {
|
|
69
|
+
const relationship = relationships[key];
|
|
70
|
+
const targetRef = stateRefs[relationship.target];
|
|
71
|
+
if (!targetRef)
|
|
72
|
+
continue;
|
|
73
|
+
const targetMap = yield* Ref.get(targetRef);
|
|
74
|
+
if (relationship.type === "ref") {
|
|
75
|
+
const foreignKeyField = relationship.foreignKey || `${key}Id`;
|
|
76
|
+
const foreignKeyValue = item[foreignKeyField];
|
|
77
|
+
if (typeof foreignKeyValue === "string") {
|
|
78
|
+
const related = targetMap.get(foreignKeyValue);
|
|
79
|
+
if (related) {
|
|
80
|
+
populated[key] = yield* maybeRecurse(related, value, relationship.target, stateRefs, dbConfig, depth);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
yield* new DanglingReferenceError({
|
|
84
|
+
collection: relationship.target,
|
|
85
|
+
field: foreignKeyField,
|
|
86
|
+
targetId: foreignKeyValue,
|
|
87
|
+
message: `Entity in "${collectionName}" references missing "${relationship.target}" with ${foreignKeyField}="${foreignKeyValue}"`,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
populated[key] = undefined;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
else if (relationship.type === "inverse") {
|
|
96
|
+
const foreignKeyField = resolveInverseForeignKey(relationship, collectionName, dbConfig);
|
|
97
|
+
const relatedItems = [];
|
|
98
|
+
for (const entity of targetMap.values()) {
|
|
99
|
+
if (entity[foreignKeyField] === item.id) {
|
|
100
|
+
relatedItems.push(entity);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (value === true || !isRecord(value)) {
|
|
104
|
+
populated[key] = relatedItems;
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
const populatedRelated = [];
|
|
108
|
+
for (const relItem of relatedItems) {
|
|
109
|
+
populatedRelated.push(yield* maybeRecurse(relItem, value, relationship.target, stateRefs, dbConfig, depth));
|
|
110
|
+
}
|
|
111
|
+
populated[key] = populatedRelated;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return populated;
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* If the populate value is a nested config and we haven't hit the depth limit,
|
|
120
|
+
* recursively populate the related entity. Otherwise return the entity as-is.
|
|
121
|
+
*/
|
|
122
|
+
function maybeRecurse(entity, value, targetCollectionName, stateRefs, dbConfig, depth) {
|
|
123
|
+
if (value === true ||
|
|
124
|
+
!isPopulateConfig(value) ||
|
|
125
|
+
depth >= MAX_POPULATE_DEPTH) {
|
|
126
|
+
return Effect.succeed(entity);
|
|
127
|
+
}
|
|
128
|
+
return populateItem(entity, value, stateRefs, dbConfig, targetCollectionName, depth + 1);
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Apply relationship population as a Stream combinator.
|
|
132
|
+
*
|
|
133
|
+
* For each item in the stream, resolves relationships by reading related
|
|
134
|
+
* entities from collection Refs. Supports nested population recursively
|
|
135
|
+
* up to a depth of 5.
|
|
136
|
+
*
|
|
137
|
+
* - `ref` relationships: look up a single entity in the target collection
|
|
138
|
+
* using the foreign key field (default: `<relationName>Id`)
|
|
139
|
+
* - `inverse` relationships: find all entities in the target collection
|
|
140
|
+
* whose foreign key points back to this item's `id`
|
|
141
|
+
*
|
|
142
|
+
* @param populateConfig - Which relationships to populate (e.g. `{ company: true }`)
|
|
143
|
+
* @param stateRefs - Map of collection name → Ref<ReadonlyMap<string, entity>>
|
|
144
|
+
* @param dbConfig - Full database config with relationship definitions
|
|
145
|
+
* @param collectionName - Name of the source collection being queried
|
|
146
|
+
*/
|
|
147
|
+
export const applyPopulate = (populateConfig, stateRefs, dbConfig, collectionName) => (stream) => {
|
|
148
|
+
if (!populateConfig || !isPopulateConfig(populateConfig))
|
|
149
|
+
return stream;
|
|
150
|
+
const sourceConfig = dbConfig[collectionName];
|
|
151
|
+
if (!sourceConfig)
|
|
152
|
+
return stream;
|
|
153
|
+
const relationships = sourceConfig.relationships;
|
|
154
|
+
const populateEntries = Object.entries(populateConfig).filter(([key]) => relationships[key] !== undefined);
|
|
155
|
+
if (populateEntries.length === 0)
|
|
156
|
+
return stream;
|
|
157
|
+
return Stream.mapEffect(stream, (item) => populateItem(item, populateConfig, stateRefs, dbConfig, collectionName, 0));
|
|
158
|
+
};
|
|
159
|
+
//# sourceMappingURL=populate-stream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"populate-stream.js","sourceRoot":"","sources":["../../../src/operations/relationships/populate-stream.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
type RelationshipType = "ref" | "inverse";
|
|
2
|
+
interface Relationship {
|
|
3
|
+
type: RelationshipType;
|
|
4
|
+
target: string;
|
|
5
|
+
foreignKey?: string;
|
|
6
|
+
}
|
|
7
|
+
interface CollectionConfig {
|
|
8
|
+
relationships: Record<string, Relationship>;
|
|
9
|
+
}
|
|
10
|
+
export type PopulateValue = boolean | Record<string, unknown>;
|
|
11
|
+
export declare function isPopulateConfig(value: unknown): value is Record<string, PopulateValue>;
|
|
12
|
+
export declare function applyPopulate<T extends Record<string, unknown>>(item: T, populateConfig: Record<string, PopulateValue>, allData: Record<string, unknown[]>, relationships: Record<string, Relationship>, collectionName: string, config: Record<string, CollectionConfig>): T;
|
|
13
|
+
export declare function populateRelationships<T extends Record<string, unknown>>(items: T[], populateConfig: Record<string, PopulateValue> | undefined, allData: Record<string, unknown[]>, relationships: Record<string, Relationship>, collectionName: string, config: Record<string, CollectionConfig>): T[];
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=populate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"populate.d.ts","sourceRoot":"","sources":["../../../src/operations/relationships/populate.ts"],"names":[],"mappings":"AAIA,KAAK,gBAAgB,GAAG,KAAK,GAAG,SAAS,CAAC;AAE1C,UAAU,YAAY;IACrB,IAAI,EAAE,gBAAgB,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,UAAU,gBAAgB;IACzB,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;CAC5C;AAED,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAG9D,wBAAgB,gBAAgB,CAC/B,KAAK,EAAE,OAAO,GACZ,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAExC;AAwFD,wBAAgB,aAAa,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9D,IAAI,EAAE,CAAC,EACP,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,EAC7C,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,EAClC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,EAC3C,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,GACtC,CAAC,CA2MH;AAGD,wBAAgB,qBAAqB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACtE,KAAK,EAAE,CAAC,EAAE,EACV,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,GAAG,SAAS,EACzD,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,EAClC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,EAC3C,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,GACtC,CAAC,EAAE,CAaL"}
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import { isValidWhereClause } from "../query/filter.js";
|
|
2
|
+
import { applyObjectSelection } from "../query/select.js";
|
|
3
|
+
// Type guard for populate config objects
|
|
4
|
+
export function isPopulateConfig(value) {
|
|
5
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
6
|
+
}
|
|
7
|
+
// Type guard to check if value is a record
|
|
8
|
+
function isRecord(value) {
|
|
9
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
10
|
+
}
|
|
11
|
+
// Type guard for string arrays
|
|
12
|
+
function isStringArray(value) {
|
|
13
|
+
return (Array.isArray(value) && value.every((item) => typeof item === "string"));
|
|
14
|
+
}
|
|
15
|
+
function isSelectionConfig(value) {
|
|
16
|
+
return isStringArray(value) || isRecord(value);
|
|
17
|
+
}
|
|
18
|
+
// Safe extraction of nested populate configuration
|
|
19
|
+
function extractNestedConfig(value) {
|
|
20
|
+
const { select, populate, ...otherProps } = value;
|
|
21
|
+
const validNestedPopulate = {};
|
|
22
|
+
// Safely copy otherProps that are valid PopulateValue types
|
|
23
|
+
for (const [key, value] of Object.entries(otherProps)) {
|
|
24
|
+
if (typeof value === "boolean" || isRecord(value)) {
|
|
25
|
+
validNestedPopulate[key] = value;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
// Safely merge populate if it's valid
|
|
29
|
+
if (isPopulateConfig(populate)) {
|
|
30
|
+
for (const [key, value] of Object.entries(populate)) {
|
|
31
|
+
if (typeof value === "boolean" || isRecord(value)) {
|
|
32
|
+
validNestedPopulate[key] = value;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const result = {
|
|
37
|
+
nestedPopulate: validNestedPopulate,
|
|
38
|
+
};
|
|
39
|
+
if (isSelectionConfig(select)) {
|
|
40
|
+
result.select = select;
|
|
41
|
+
}
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
44
|
+
// Helper function to find a single related item
|
|
45
|
+
function findRelatedItem(item, foreignKeyField, targetData) {
|
|
46
|
+
if (!targetData || !isValidWhereClause(item))
|
|
47
|
+
return undefined;
|
|
48
|
+
return targetData.find((target) => {
|
|
49
|
+
if (!isValidWhereClause(target))
|
|
50
|
+
return false;
|
|
51
|
+
return target.id === item[foreignKeyField];
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
// Helper function to find multiple related items
|
|
55
|
+
function findRelatedItems(item, foreignKeyField, targetData) {
|
|
56
|
+
if (!targetData || !isValidWhereClause(item))
|
|
57
|
+
return [];
|
|
58
|
+
return targetData.filter((target) => {
|
|
59
|
+
if (!isValidWhereClause(target))
|
|
60
|
+
return false;
|
|
61
|
+
return target[foreignKeyField] === item.id;
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
// Helper function to apply populate configuration recursively
|
|
65
|
+
export function applyPopulate(item, populateConfig, allData, relationships, collectionName, config) {
|
|
66
|
+
const populated = { ...item };
|
|
67
|
+
for (const [key, value] of Object.entries(populateConfig)) {
|
|
68
|
+
const relationship = relationships[key];
|
|
69
|
+
if (!relationship)
|
|
70
|
+
continue;
|
|
71
|
+
const targetData = allData[relationship.target];
|
|
72
|
+
if (relationship.type === "ref") {
|
|
73
|
+
// Handle ref relationships
|
|
74
|
+
const foreignKeyField = relationship.foreignKey || `${key}Id`;
|
|
75
|
+
const relatedItem = findRelatedItem(populated, foreignKeyField, targetData);
|
|
76
|
+
if (relatedItem && value === true) {
|
|
77
|
+
Object.assign(populated, { [key]: relatedItem });
|
|
78
|
+
}
|
|
79
|
+
else if (relatedItem && isPopulateConfig(value)) {
|
|
80
|
+
// Recursively populate nested config
|
|
81
|
+
const targetConfig = config[relationship.target];
|
|
82
|
+
if (targetConfig) {
|
|
83
|
+
// Extract nested populate config and select from value safely
|
|
84
|
+
const { select, nestedPopulate } = extractNestedConfig(value);
|
|
85
|
+
// Apply nested population first
|
|
86
|
+
let populatedRelated = relatedItem;
|
|
87
|
+
if (Object.keys(nestedPopulate).length > 0) {
|
|
88
|
+
populatedRelated = applyPopulate(relatedItem, nestedPopulate, allData, targetConfig.relationships, relationship.target, config);
|
|
89
|
+
}
|
|
90
|
+
// Apply field selection if specified (supports both array and object-based)
|
|
91
|
+
if (select) {
|
|
92
|
+
let selectedFields;
|
|
93
|
+
if (isStringArray(select)) {
|
|
94
|
+
// Convert array to object format
|
|
95
|
+
const objectSelect = {};
|
|
96
|
+
for (const field of select) {
|
|
97
|
+
objectSelect[field] = true;
|
|
98
|
+
}
|
|
99
|
+
selectedFields = applyObjectSelection(populatedRelated, objectSelect);
|
|
100
|
+
}
|
|
101
|
+
else if (isRecord(select)) {
|
|
102
|
+
selectedFields = applyObjectSelection(populatedRelated, select);
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
// Invalid select format, skip selection
|
|
106
|
+
selectedFields = populatedRelated;
|
|
107
|
+
}
|
|
108
|
+
// For object-based selection, the nested fields are already handled by applyObjectSelection
|
|
109
|
+
// For array-based selection, preserve any populated fields that are defined in relationships
|
|
110
|
+
let finalResult = selectedFields;
|
|
111
|
+
if (isStringArray(select)) {
|
|
112
|
+
// Only for array-based selection, we need to preserve populated relationships
|
|
113
|
+
finalResult = { ...selectedFields };
|
|
114
|
+
// Check relationships in the target config to know which fields are populated
|
|
115
|
+
for (const [relKey, _relDef] of Object.entries(targetConfig.relationships)) {
|
|
116
|
+
if (nestedPopulate[relKey] && relKey in populatedRelated) {
|
|
117
|
+
finalResult[relKey] = populatedRelated[relKey];
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
populatedRelated = finalResult;
|
|
122
|
+
}
|
|
123
|
+
Object.assign(populated, { [key]: populatedRelated });
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
Object.assign(populated, { [key]: undefined });
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
else if (relationship.type === "inverse") {
|
|
131
|
+
// Handle inverse relationships
|
|
132
|
+
// For inverse relationships, we need to find items in the target collection
|
|
133
|
+
// that have a foreign key pointing back to this collection
|
|
134
|
+
// First, check if there's a specific foreignKey configured
|
|
135
|
+
let foreignKeyField;
|
|
136
|
+
if (relationship.foreignKey) {
|
|
137
|
+
foreignKeyField = relationship.foreignKey;
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
// Look for the corresponding ref relationship in the target collection
|
|
141
|
+
const targetConfig = config[relationship.target];
|
|
142
|
+
if (targetConfig) {
|
|
143
|
+
// Find the relationship that points back to our collection
|
|
144
|
+
const reverseRelationship = Object.entries(targetConfig.relationships).find(([, rel]) => rel.type === "ref" && rel.target === collectionName);
|
|
145
|
+
if (reverseRelationship?.[1].foreignKey) {
|
|
146
|
+
foreignKeyField = reverseRelationship[1].foreignKey;
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
// Fall back to the default naming convention
|
|
150
|
+
const singularName = collectionName.endsWith("ies")
|
|
151
|
+
? `${collectionName.slice(0, -3)}y` // companies -> company, industries -> industry
|
|
152
|
+
: collectionName.replace(/s$/, ""); // users -> user, posts -> post
|
|
153
|
+
foreignKeyField = `${singularName}Id`;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
// Fall back to the default naming convention
|
|
158
|
+
const singularName = collectionName.endsWith("ies")
|
|
159
|
+
? `${collectionName.slice(0, -3)}y` // companies -> company, industries -> industry
|
|
160
|
+
: collectionName.replace(/s$/, ""); // users -> user, posts -> post
|
|
161
|
+
foreignKeyField = `${singularName}Id`;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
const relatedItems = findRelatedItems(populated, foreignKeyField, targetData);
|
|
165
|
+
if (value === true) {
|
|
166
|
+
Object.assign(populated, { [key]: relatedItems });
|
|
167
|
+
}
|
|
168
|
+
else if (isPopulateConfig(value)) {
|
|
169
|
+
// Recursively populate each item in the array
|
|
170
|
+
const targetConfig = config[relationship.target];
|
|
171
|
+
if (targetConfig) {
|
|
172
|
+
// Extract nested populate config and select from value safely
|
|
173
|
+
const { select, nestedPopulate } = extractNestedConfig(value);
|
|
174
|
+
const populatedItems = relatedItems.map((relItem) => {
|
|
175
|
+
// Apply nested population first
|
|
176
|
+
let populatedItem = relItem;
|
|
177
|
+
if (Object.keys(nestedPopulate).length > 0) {
|
|
178
|
+
populatedItem = applyPopulate(relItem, nestedPopulate, allData, targetConfig.relationships, relationship.target, config);
|
|
179
|
+
}
|
|
180
|
+
// Apply field selection if specified (supports both array and object-based)
|
|
181
|
+
if (select) {
|
|
182
|
+
let selectedFields;
|
|
183
|
+
if (isStringArray(select)) {
|
|
184
|
+
// Convert array to object format
|
|
185
|
+
const objectSelect = {};
|
|
186
|
+
for (const field of select) {
|
|
187
|
+
objectSelect[field] = true;
|
|
188
|
+
}
|
|
189
|
+
selectedFields = applyObjectSelection(populatedItem, objectSelect);
|
|
190
|
+
}
|
|
191
|
+
else if (isRecord(select)) {
|
|
192
|
+
selectedFields = applyObjectSelection(populatedItem, select);
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
// Invalid select format, skip selection
|
|
196
|
+
selectedFields = populatedItem;
|
|
197
|
+
}
|
|
198
|
+
// For object-based selection, the nested fields are already handled by applyObjectSelection
|
|
199
|
+
// For array-based selection, preserve any populated fields that are defined in relationships
|
|
200
|
+
let finalResult = selectedFields;
|
|
201
|
+
if (isStringArray(select)) {
|
|
202
|
+
// Only for array-based selection, we need to preserve populated relationships
|
|
203
|
+
finalResult = { ...selectedFields };
|
|
204
|
+
// Check relationships in the target config to know which fields are populated
|
|
205
|
+
for (const [relKey, _relDef] of Object.entries(targetConfig.relationships)) {
|
|
206
|
+
if (nestedPopulate[relKey] && relKey in populatedItem) {
|
|
207
|
+
finalResult[relKey] = populatedItem[relKey];
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
populatedItem = finalResult;
|
|
212
|
+
}
|
|
213
|
+
return populatedItem;
|
|
214
|
+
});
|
|
215
|
+
Object.assign(populated, { [key]: populatedItems });
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return populated;
|
|
221
|
+
}
|
|
222
|
+
// Helper function to populate relationships
|
|
223
|
+
export function populateRelationships(items, populateConfig, allData, relationships, collectionName, config) {
|
|
224
|
+
if (!populateConfig || !isPopulateConfig(populateConfig))
|
|
225
|
+
return items;
|
|
226
|
+
return items.map((item) => applyPopulate(item, populateConfig, allData, relationships, collectionName, config));
|
|
227
|
+
}
|
|
228
|
+
//# sourceMappingURL=populate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"populate.js","sourceRoot":"","sources":["../../../src/operations/relationships/populate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin hooks utilities for merging global hooks with collection hooks.
|
|
3
|
+
*
|
|
4
|
+
* Global plugin hooks run before collection-specific hooks because they represent
|
|
5
|
+
* cross-cutting concerns (audit logging, encryption) that should see data before
|
|
6
|
+
* collection-specific transformations.
|
|
7
|
+
*/
|
|
8
|
+
import type { HooksConfig } from "../types/hook-types.js";
|
|
9
|
+
import type { GlobalHooksConfig } from "./plugin-types.js";
|
|
10
|
+
/**
|
|
11
|
+
* Merges global plugin hooks with collection-specific hooks.
|
|
12
|
+
*
|
|
13
|
+
* For each hook type, global hooks are prepended before collection hooks.
|
|
14
|
+
* This ensures global hooks (cross-cutting concerns) run first.
|
|
15
|
+
*
|
|
16
|
+
* Type narrowing: Global hooks are `HooksConfig<Record<string, unknown>>`,
|
|
17
|
+
* collection hooks are `HooksConfig<T>`. The merged result is `HooksConfig<T>`
|
|
18
|
+
* with global hooks cast appropriately.
|
|
19
|
+
*
|
|
20
|
+
* @param globalHooks - Global hooks from plugin registry (may be empty/undefined)
|
|
21
|
+
* @param collectionHooks - Collection-specific hooks (may be empty/undefined)
|
|
22
|
+
* @returns Merged hooks config with global hooks first
|
|
23
|
+
*/
|
|
24
|
+
export declare const mergeGlobalHooks: <T extends Record<string, unknown>>(globalHooks: GlobalHooksConfig | undefined, collectionHooks: HooksConfig<T> | undefined) => HooksConfig<T>;
|
|
25
|
+
//# sourceMappingURL=plugin-hooks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-hooks.d.ts","sourceRoot":"","sources":["../../src/plugins/plugin-hooks.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE3D;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,gBAAgB,GAAI,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjE,aAAa,iBAAiB,GAAG,SAAS,EAC1C,iBAAiB,WAAW,CAAC,CAAC,CAAC,GAAG,SAAS,KACzC,WAAW,CAAC,CAAC,CA6Cf,CAAC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin hooks utilities for merging global hooks with collection hooks.
|
|
3
|
+
*
|
|
4
|
+
* Global plugin hooks run before collection-specific hooks because they represent
|
|
5
|
+
* cross-cutting concerns (audit logging, encryption) that should see data before
|
|
6
|
+
* collection-specific transformations.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Merges global plugin hooks with collection-specific hooks.
|
|
10
|
+
*
|
|
11
|
+
* For each hook type, global hooks are prepended before collection hooks.
|
|
12
|
+
* This ensures global hooks (cross-cutting concerns) run first.
|
|
13
|
+
*
|
|
14
|
+
* Type narrowing: Global hooks are `HooksConfig<Record<string, unknown>>`,
|
|
15
|
+
* collection hooks are `HooksConfig<T>`. The merged result is `HooksConfig<T>`
|
|
16
|
+
* with global hooks cast appropriately.
|
|
17
|
+
*
|
|
18
|
+
* @param globalHooks - Global hooks from plugin registry (may be empty/undefined)
|
|
19
|
+
* @param collectionHooks - Collection-specific hooks (may be empty/undefined)
|
|
20
|
+
* @returns Merged hooks config with global hooks first
|
|
21
|
+
*/
|
|
22
|
+
export const mergeGlobalHooks = (globalHooks, collectionHooks) => {
|
|
23
|
+
// If no global hooks, return collection hooks as-is (or empty object)
|
|
24
|
+
if (!globalHooks) {
|
|
25
|
+
return collectionHooks ?? {};
|
|
26
|
+
}
|
|
27
|
+
// If no collection hooks, cast global hooks to the collection type
|
|
28
|
+
if (!collectionHooks) {
|
|
29
|
+
return globalHooks;
|
|
30
|
+
}
|
|
31
|
+
// Merge each hook array: global first, then collection
|
|
32
|
+
// Note: Global hooks have Record<string, unknown> type and need casting
|
|
33
|
+
// to the specific collection type T. This is safe because global hooks
|
|
34
|
+
// operate on any entity shape and T extends Record<string, unknown>.
|
|
35
|
+
return {
|
|
36
|
+
beforeCreate: mergeHookArrays(globalHooks.beforeCreate, collectionHooks.beforeCreate),
|
|
37
|
+
afterCreate: mergeHookArrays(globalHooks.afterCreate, collectionHooks.afterCreate),
|
|
38
|
+
beforeUpdate: mergeHookArrays(globalHooks.beforeUpdate, collectionHooks.beforeUpdate),
|
|
39
|
+
afterUpdate: mergeHookArrays(globalHooks.afterUpdate, collectionHooks.afterUpdate),
|
|
40
|
+
beforeDelete: mergeHookArrays(globalHooks.beforeDelete, collectionHooks.beforeDelete),
|
|
41
|
+
afterDelete: mergeHookArrays(globalHooks.afterDelete, collectionHooks.afterDelete),
|
|
42
|
+
onChange: mergeHookArrays(globalHooks.onChange, collectionHooks.onChange),
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Helper to merge two optional hook arrays.
|
|
47
|
+
* Global hooks come first, then collection hooks.
|
|
48
|
+
* Returns undefined if both are empty/undefined.
|
|
49
|
+
*/
|
|
50
|
+
const mergeHookArrays = (global, collection) => {
|
|
51
|
+
const hasGlobal = global && global.length > 0;
|
|
52
|
+
const hasCollection = collection && collection.length > 0;
|
|
53
|
+
if (!hasGlobal && !hasCollection) {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
if (!hasGlobal) {
|
|
57
|
+
return collection;
|
|
58
|
+
}
|
|
59
|
+
if (!hasCollection) {
|
|
60
|
+
return global;
|
|
61
|
+
}
|
|
62
|
+
return [...global, ...collection];
|
|
63
|
+
};
|
|
64
|
+
//# sourceMappingURL=plugin-hooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-hooks.js","sourceRoot":"","sources":["../../src/plugins/plugin-hooks.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAC/B,WAA0C,EAC1C,eAA2C,EAC1B,EAAE;IACnB,sEAAsE;IACtE,IAAI,CAAC,WAAW,EAAE,CAAC;QAClB,OAAO,eAAe,IAAI,EAAE,CAAC;IAC9B,CAAC;IAED,mEAAmE;IACnE,IAAI,CAAC,eAAe,EAAE,CAAC;QACtB,OAAO,WAA6B,CAAC;IACtC,CAAC;IAED,uDAAuD;IACvD,wEAAwE;IACxE,uEAAuE;IACvE,qEAAqE;IACrE,OAAO;QACN,YAAY,EAAE,eAAe,CAC5B,WAAW,CAAC,YAA8C,EAC1D,eAAe,CAAC,YAAY,CAC5B;QACD,WAAW,EAAE,eAAe,CAC3B,WAAW,CAAC,WAA4C,EACxD,eAAe,CAAC,WAAW,CAC3B;QACD,YAAY,EAAE,eAAe,CAC5B,WAAW,CAAC,YAA8C,EAC1D,eAAe,CAAC,YAAY,CAC5B;QACD,WAAW,EAAE,eAAe,CAC3B,WAAW,CAAC,WAA4C,EACxD,eAAe,CAAC,WAAW,CAC3B;QACD,YAAY,EAAE,eAAe,CAC5B,WAAW,CAAC,YAA8C,EAC1D,eAAe,CAAC,YAAY,CAC5B;QACD,WAAW,EAAE,eAAe,CAC3B,WAAW,CAAC,WAA4C,EACxD,eAAe,CAAC,WAAW,CAC3B;QACD,QAAQ,EAAE,eAAe,CACxB,WAAW,CAAC,QAAsC,EAClD,eAAe,CAAC,QAAQ,CACxB;KACiB,CAAC;AACrB,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,eAAe,GAAG,CACvB,MAAoC,EACpC,UAAwC,EACT,EAAE;IACjC,MAAM,SAAS,GAAG,MAAM,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;IAC9C,MAAM,aAAa,GAAG,UAAU,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC;IAE1D,IAAI,CAAC,SAAS,IAAI,CAAC,aAAa,EAAE,CAAC;QAClC,OAAO,SAAS,CAAC;IAClB,CAAC;IAED,IAAI,CAAC,SAAS,EAAE,CAAC;QAChB,OAAO,UAAU,CAAC;IACnB,CAAC;IAED,IAAI,CAAC,aAAa,EAAE,CAAC;QACpB,OAAO,MAAM,CAAC;IACf,CAAC;IAED,OAAO,CAAC,GAAG,MAAM,EAAE,GAAG,UAAU,CAAC,CAAC;AACnC,CAAC,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin registry builder.
|
|
3
|
+
* Validates plugins and merges their contributions into a single registry.
|
|
4
|
+
*/
|
|
5
|
+
import { Effect } from "effect";
|
|
6
|
+
import type { PluginError } from "../errors/plugin-errors.js";
|
|
7
|
+
import type { PluginRegistry, ProseQLPlugin } from "./plugin-types.js";
|
|
8
|
+
/**
|
|
9
|
+
* Builds a PluginRegistry from an array of plugins.
|
|
10
|
+
*
|
|
11
|
+
* This function:
|
|
12
|
+
* 1. Validates each plugin individually (structure, codecs, operators, generators)
|
|
13
|
+
* 2. Validates operator conflicts (between plugins and with built-in operators)
|
|
14
|
+
* 3. Validates dependencies (all declared dependencies must exist)
|
|
15
|
+
* 4. Merges codecs (append in registration order)
|
|
16
|
+
* 5. Merges operators into a Map (O(1) lookup)
|
|
17
|
+
* 6. Merges ID generators into a Map (O(1) lookup)
|
|
18
|
+
* 7. Merges global hooks (concatenate arrays in registration order)
|
|
19
|
+
*
|
|
20
|
+
* If plugins is undefined or empty, returns an empty registry.
|
|
21
|
+
*
|
|
22
|
+
* @param plugins - Array of plugins to validate and merge (optional)
|
|
23
|
+
* @returns Effect<PluginRegistry, PluginError> - The merged registry or validation error
|
|
24
|
+
*/
|
|
25
|
+
export declare const buildPluginRegistry: (plugins?: ReadonlyArray<ProseQLPlugin>) => Effect.Effect<PluginRegistry, PluginError>;
|
|
26
|
+
//# sourceMappingURL=plugin-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-registry.d.ts","sourceRoot":"","sources":["../../src/plugins/plugin-registry.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,KAAK,EAIX,cAAc,EACd,aAAa,EACb,MAAM,mBAAmB,CAAC;AA0B3B;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,mBAAmB,GAC/B,UAAU,aAAa,CAAC,aAAa,CAAC,KACpC,MAAM,CAAC,MAAM,CAAC,cAAc,EAAE,WAAW,CAmD3C,CAAC"}
|