@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,267 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Effect-based delete operations for entities.
|
|
3
|
+
*
|
|
4
|
+
* Uses Ref<ReadonlyMap> for atomic state mutation and typed errors
|
|
5
|
+
* (NotFoundError, OperationError, ForeignKeyError).
|
|
6
|
+
*
|
|
7
|
+
* Preserves soft delete support, foreign key constraint checking,
|
|
8
|
+
* and cascade handling from the legacy implementation.
|
|
9
|
+
*/
|
|
10
|
+
import { Effect, PubSub, Ref } from "effect";
|
|
11
|
+
import { NotFoundError, OperationError, } from "../../errors/crud-errors.js";
|
|
12
|
+
import { runAfterDeleteHooks, runBeforeDeleteHooks, runOnChangeHooks, } from "../../hooks/hook-runner.js";
|
|
13
|
+
import { removeFromIndex, removeManyFromIndex, } from "../../indexes/index-manager.js";
|
|
14
|
+
import { removeFromSearchIndex } from "../../indexes/search-index.js";
|
|
15
|
+
import { checkDeleteConstraintsEffect } from "../../validators/foreign-key.js";
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// Delete Single Entity
|
|
18
|
+
// ============================================================================
|
|
19
|
+
/**
|
|
20
|
+
* Delete a single entity by ID with optional soft delete.
|
|
21
|
+
*
|
|
22
|
+
* Steps:
|
|
23
|
+
* 1. Look up entity by ID in Ref state (O(1))
|
|
24
|
+
* 2. Run beforeDelete hooks (can reject)
|
|
25
|
+
* 3. If soft delete requested, verify entity has deletedAt field
|
|
26
|
+
* 4. Check foreign key constraints across all collections
|
|
27
|
+
* 5. Soft delete: update entity with deletedAt timestamp
|
|
28
|
+
* Hard delete: remove entity from Ref state
|
|
29
|
+
*/
|
|
30
|
+
export const del = (collectionName, allRelationships, ref, stateRefs, supportsSoftDelete = false, indexes, hooks, searchIndexRef, searchIndexFields, changePubSub) => (id, options) => Effect.gen(function* () {
|
|
31
|
+
// Look up entity by ID (O(1))
|
|
32
|
+
const currentMap = yield* Ref.get(ref);
|
|
33
|
+
const entity = currentMap.get(id);
|
|
34
|
+
if (entity === undefined) {
|
|
35
|
+
return yield* Effect.fail(new NotFoundError({
|
|
36
|
+
collection: collectionName,
|
|
37
|
+
id,
|
|
38
|
+
message: `Entity '${id}' not found in collection '${collectionName}'`,
|
|
39
|
+
}));
|
|
40
|
+
}
|
|
41
|
+
// Run beforeDelete hooks (can reject the delete)
|
|
42
|
+
yield* runBeforeDeleteHooks(hooks?.beforeDelete, {
|
|
43
|
+
operation: "delete",
|
|
44
|
+
collection: collectionName,
|
|
45
|
+
id,
|
|
46
|
+
entity,
|
|
47
|
+
});
|
|
48
|
+
const isSoft = options?.soft === true;
|
|
49
|
+
// Check if soft delete is requested but entity doesn't support it
|
|
50
|
+
if (isSoft && !supportsSoftDelete) {
|
|
51
|
+
return yield* Effect.fail(new OperationError({
|
|
52
|
+
operation: "soft delete",
|
|
53
|
+
reason: "Entity does not have a deletedAt field",
|
|
54
|
+
message: "Entity does not have a deletedAt field",
|
|
55
|
+
}));
|
|
56
|
+
}
|
|
57
|
+
// Check foreign key constraints
|
|
58
|
+
yield* checkDeleteConstraintsEffect(id, collectionName, allRelationships, stateRefs);
|
|
59
|
+
if (isSoft) {
|
|
60
|
+
// Soft delete: mark with deletedAt timestamp
|
|
61
|
+
// If already soft-deleted, preserve the original deletedAt
|
|
62
|
+
const existingDeletedAt = entity.deletedAt;
|
|
63
|
+
const now = new Date().toISOString();
|
|
64
|
+
const softDeleted = {
|
|
65
|
+
...entity,
|
|
66
|
+
deletedAt: existingDeletedAt || now,
|
|
67
|
+
updatedAt: existingDeletedAt
|
|
68
|
+
? entity.updatedAt
|
|
69
|
+
: now,
|
|
70
|
+
};
|
|
71
|
+
yield* Ref.update(ref, (map) => {
|
|
72
|
+
const next = new Map(map);
|
|
73
|
+
next.set(id, softDeleted);
|
|
74
|
+
return next;
|
|
75
|
+
});
|
|
76
|
+
// Run afterDelete hooks (fire-and-forget, errors swallowed)
|
|
77
|
+
yield* runAfterDeleteHooks(hooks?.afterDelete, {
|
|
78
|
+
operation: "delete",
|
|
79
|
+
collection: collectionName,
|
|
80
|
+
id,
|
|
81
|
+
entity: softDeleted,
|
|
82
|
+
});
|
|
83
|
+
// Run onChange hooks with type: "delete" (fire-and-forget, errors swallowed)
|
|
84
|
+
yield* runOnChangeHooks(hooks?.onChange, {
|
|
85
|
+
type: "delete",
|
|
86
|
+
collection: collectionName,
|
|
87
|
+
id,
|
|
88
|
+
entity: softDeleted,
|
|
89
|
+
});
|
|
90
|
+
// Publish change event to reactive subscribers
|
|
91
|
+
if (changePubSub) {
|
|
92
|
+
yield* PubSub.publish(changePubSub, {
|
|
93
|
+
collection: collectionName,
|
|
94
|
+
operation: "delete",
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
return softDeleted;
|
|
98
|
+
}
|
|
99
|
+
// Hard delete: remove from indexes first (while entity is still accessible)
|
|
100
|
+
if (indexes && indexes.size > 0) {
|
|
101
|
+
yield* removeFromIndex(indexes, entity);
|
|
102
|
+
}
|
|
103
|
+
// Hard delete: remove from search index first (while entity is still accessible)
|
|
104
|
+
if (searchIndexRef && searchIndexFields && searchIndexFields.length > 0) {
|
|
105
|
+
yield* removeFromSearchIndex(searchIndexRef, entity, searchIndexFields);
|
|
106
|
+
}
|
|
107
|
+
// Hard delete: remove from state
|
|
108
|
+
yield* Ref.update(ref, (map) => {
|
|
109
|
+
const next = new Map(map);
|
|
110
|
+
next.delete(id);
|
|
111
|
+
return next;
|
|
112
|
+
});
|
|
113
|
+
// Run afterDelete hooks (fire-and-forget, errors swallowed)
|
|
114
|
+
yield* runAfterDeleteHooks(hooks?.afterDelete, {
|
|
115
|
+
operation: "delete",
|
|
116
|
+
collection: collectionName,
|
|
117
|
+
id,
|
|
118
|
+
entity,
|
|
119
|
+
});
|
|
120
|
+
// Run onChange hooks with type: "delete" (fire-and-forget, errors swallowed)
|
|
121
|
+
yield* runOnChangeHooks(hooks?.onChange, {
|
|
122
|
+
type: "delete",
|
|
123
|
+
collection: collectionName,
|
|
124
|
+
id,
|
|
125
|
+
entity,
|
|
126
|
+
});
|
|
127
|
+
// Publish change event to reactive subscribers
|
|
128
|
+
if (changePubSub) {
|
|
129
|
+
yield* PubSub.publish(changePubSub, {
|
|
130
|
+
collection: collectionName,
|
|
131
|
+
operation: "delete",
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
return entity;
|
|
135
|
+
});
|
|
136
|
+
// ============================================================================
|
|
137
|
+
// Delete Multiple Entities
|
|
138
|
+
// ============================================================================
|
|
139
|
+
/**
|
|
140
|
+
* Delete multiple entities matching a predicate with optional soft delete.
|
|
141
|
+
*
|
|
142
|
+
* Uses a predicate function to select which entities to delete.
|
|
143
|
+
* The caller (database factory) can use the Stream-based filter pipeline
|
|
144
|
+
* to build the predicate from a WhereClause.
|
|
145
|
+
*
|
|
146
|
+
* Runs hooks per entity: beforeDelete can reject deletion,
|
|
147
|
+
* afterDelete and onChange run after state mutation.
|
|
148
|
+
*
|
|
149
|
+
* All matching entities are deleted atomically in a single Ref.update call.
|
|
150
|
+
*/
|
|
151
|
+
export const deleteMany = (collectionName, allRelationships, ref, stateRefs, supportsSoftDelete = false, indexes, hooks, searchIndexRef, searchIndexFields, changePubSub) => (predicate, options) => Effect.gen(function* () {
|
|
152
|
+
// Get current state and find matching entities
|
|
153
|
+
const currentMap = yield* Ref.get(ref);
|
|
154
|
+
let matchingEntities = [];
|
|
155
|
+
for (const entity of currentMap.values()) {
|
|
156
|
+
if (predicate(entity)) {
|
|
157
|
+
matchingEntities.push(entity);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
// Apply limit if specified
|
|
161
|
+
if (options?.limit !== undefined && options.limit > 0) {
|
|
162
|
+
matchingEntities = matchingEntities.slice(0, options.limit);
|
|
163
|
+
}
|
|
164
|
+
if (matchingEntities.length === 0) {
|
|
165
|
+
return { count: 0, deleted: [] };
|
|
166
|
+
}
|
|
167
|
+
const isSoft = options?.soft === true;
|
|
168
|
+
// Check if soft delete is requested but entities don't support it
|
|
169
|
+
if (isSoft && !supportsSoftDelete) {
|
|
170
|
+
return yield* Effect.fail(new OperationError({
|
|
171
|
+
operation: "soft delete",
|
|
172
|
+
reason: "Entities do not have a deletedAt field",
|
|
173
|
+
message: "Entities do not have a deletedAt field",
|
|
174
|
+
}));
|
|
175
|
+
}
|
|
176
|
+
// Run beforeDelete hooks for each entity (can reject deletion)
|
|
177
|
+
for (const entity of matchingEntities) {
|
|
178
|
+
yield* runBeforeDeleteHooks(hooks?.beforeDelete, {
|
|
179
|
+
operation: "delete",
|
|
180
|
+
collection: collectionName,
|
|
181
|
+
id: entity.id,
|
|
182
|
+
entity,
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
// Check foreign key constraints for all entities (only for hard delete)
|
|
186
|
+
if (!isSoft) {
|
|
187
|
+
for (const entity of matchingEntities) {
|
|
188
|
+
yield* checkDeleteConstraintsEffect(entity.id, collectionName, allRelationships, stateRefs);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
const now = new Date().toISOString();
|
|
192
|
+
const deleted = [];
|
|
193
|
+
if (isSoft) {
|
|
194
|
+
// Soft delete: update matching entities with deletedAt
|
|
195
|
+
const updatedEntities = new Map();
|
|
196
|
+
for (const entity of matchingEntities) {
|
|
197
|
+
const existingDeletedAt = entity
|
|
198
|
+
.deletedAt;
|
|
199
|
+
const softDeleted = {
|
|
200
|
+
...entity,
|
|
201
|
+
deletedAt: existingDeletedAt || now,
|
|
202
|
+
updatedAt: existingDeletedAt
|
|
203
|
+
? entity.updatedAt
|
|
204
|
+
: now,
|
|
205
|
+
};
|
|
206
|
+
updatedEntities.set(entity.id, softDeleted);
|
|
207
|
+
deleted.push(softDeleted);
|
|
208
|
+
}
|
|
209
|
+
yield* Ref.update(ref, (map) => {
|
|
210
|
+
const next = new Map(map);
|
|
211
|
+
for (const [id, entity] of updatedEntities) {
|
|
212
|
+
next.set(id, entity);
|
|
213
|
+
}
|
|
214
|
+
return next;
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
// Hard delete: remove from indexes first (while entities are still accessible)
|
|
219
|
+
if (indexes && indexes.size > 0) {
|
|
220
|
+
yield* removeManyFromIndex(indexes, matchingEntities);
|
|
221
|
+
}
|
|
222
|
+
// Hard delete: remove from search index first (while entities are still accessible)
|
|
223
|
+
if (searchIndexRef &&
|
|
224
|
+
searchIndexFields &&
|
|
225
|
+
searchIndexFields.length > 0) {
|
|
226
|
+
for (const entity of matchingEntities) {
|
|
227
|
+
yield* removeFromSearchIndex(searchIndexRef, entity, searchIndexFields);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
// Hard delete: remove matching entities from state
|
|
231
|
+
const deletedIds = new Set(matchingEntities.map((e) => e.id));
|
|
232
|
+
deleted.push(...matchingEntities);
|
|
233
|
+
yield* Ref.update(ref, (map) => {
|
|
234
|
+
const next = new Map(map);
|
|
235
|
+
for (const id of deletedIds) {
|
|
236
|
+
next.delete(id);
|
|
237
|
+
}
|
|
238
|
+
return next;
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
// Run afterDelete and onChange hooks for each deleted entity
|
|
242
|
+
for (const entity of deleted) {
|
|
243
|
+
// Run afterDelete hooks (fire-and-forget, errors swallowed)
|
|
244
|
+
yield* runAfterDeleteHooks(hooks?.afterDelete, {
|
|
245
|
+
operation: "delete",
|
|
246
|
+
collection: collectionName,
|
|
247
|
+
id: entity.id,
|
|
248
|
+
entity,
|
|
249
|
+
});
|
|
250
|
+
// Run onChange hooks with type: "delete" (fire-and-forget, errors swallowed)
|
|
251
|
+
yield* runOnChangeHooks(hooks?.onChange, {
|
|
252
|
+
type: "delete",
|
|
253
|
+
collection: collectionName,
|
|
254
|
+
id: entity.id,
|
|
255
|
+
entity,
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
// Publish a single change event after all deletes are complete
|
|
259
|
+
if (changePubSub && deleted.length > 0) {
|
|
260
|
+
yield* PubSub.publish(changePubSub, {
|
|
261
|
+
collection: collectionName,
|
|
262
|
+
operation: "delete",
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
return { count: deleted.length, deleted };
|
|
266
|
+
});
|
|
267
|
+
//# sourceMappingURL=delete.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delete.js","sourceRoot":"","sources":["../../../src/operations/crud/delete.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unique constraint checking utilities for CRUD operations.
|
|
3
|
+
*
|
|
4
|
+
* Handles both single-field constraints (e.g., "email") and compound constraints
|
|
5
|
+
* (e.g., ["userId", "settingKey"]). All constraints are normalized to arrays internally.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Unique fields configuration as declared in collection config.
|
|
9
|
+
* Can be single field names or arrays of field names for compound constraints.
|
|
10
|
+
*
|
|
11
|
+
* Example: ["email", ["userId", "settingKey"]]
|
|
12
|
+
*/
|
|
13
|
+
export type UniqueFieldsConfig = ReadonlyArray<string | ReadonlyArray<string>>;
|
|
14
|
+
/**
|
|
15
|
+
* Normalized constraints where all entries are arrays of field names.
|
|
16
|
+
*
|
|
17
|
+
* Example: [["email"], ["userId", "settingKey"]]
|
|
18
|
+
*/
|
|
19
|
+
export type NormalizedConstraints = ReadonlyArray<ReadonlyArray<string>>;
|
|
20
|
+
/**
|
|
21
|
+
* Normalize unique fields configuration to a consistent array-of-arrays format.
|
|
22
|
+
*
|
|
23
|
+
* Converts:
|
|
24
|
+
* ["email", ["userId", "settingKey"]]
|
|
25
|
+
* To:
|
|
26
|
+
* [["email"], ["userId", "settingKey"]]
|
|
27
|
+
*
|
|
28
|
+
* This allows a single code path to handle both single and compound constraints.
|
|
29
|
+
*
|
|
30
|
+
* @param uniqueFields - Configuration from CollectionConfig.uniqueFields
|
|
31
|
+
* @returns Normalized constraints where each constraint is an array of field names
|
|
32
|
+
*/
|
|
33
|
+
export declare const normalizeConstraints: (uniqueFields: UniqueFieldsConfig | undefined) => NormalizedConstraints;
|
|
34
|
+
import { Effect } from "effect";
|
|
35
|
+
import { UniqueConstraintError, ValidationError } from "../../errors/crud-errors.js";
|
|
36
|
+
type HasId = {
|
|
37
|
+
readonly id: string;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Check for unique constraint violations when creating or updating an entity.
|
|
41
|
+
*
|
|
42
|
+
* For each normalized constraint (array of field names):
|
|
43
|
+
* 1. Extract the values for all fields in the constraint from the entity
|
|
44
|
+
* 2. Skip if any field value is null or undefined (nulls are not unique-checked)
|
|
45
|
+
* 3. Check if any existing entity (excluding the same ID) has matching values for ALL fields
|
|
46
|
+
* 4. Fail-fast on first violation with UniqueConstraintError
|
|
47
|
+
*
|
|
48
|
+
* @param entity - The entity being created or updated
|
|
49
|
+
* @param existingMap - Current state of the collection
|
|
50
|
+
* @param constraints - Normalized constraints (array of field name arrays)
|
|
51
|
+
* @param collectionName - Name of the collection for error messages
|
|
52
|
+
* @returns Effect that succeeds with void or fails with UniqueConstraintError
|
|
53
|
+
*/
|
|
54
|
+
export declare const checkUniqueConstraints: <T extends HasId>(entity: T, existingMap: ReadonlyMap<string, T>, constraints: NormalizedConstraints, collectionName: string) => Effect.Effect<void, UniqueConstraintError>;
|
|
55
|
+
/**
|
|
56
|
+
* Check for unique constraint violations when creating multiple entities in a batch.
|
|
57
|
+
*
|
|
58
|
+
* This function performs two types of checks:
|
|
59
|
+
* 1. Each entity against the existing map (same as checkUniqueConstraints)
|
|
60
|
+
* 2. Each entity against other entities in the batch (inter-batch check)
|
|
61
|
+
*
|
|
62
|
+
* The inter-batch check ensures that if entities at index 3 and 7 both have
|
|
63
|
+
* email: "alice@example.com", entity 7 fails (the later one in the batch).
|
|
64
|
+
*
|
|
65
|
+
* @param entities - The entities being created in the batch
|
|
66
|
+
* @param existingMap - Current state of the collection
|
|
67
|
+
* @param constraints - Normalized constraints (array of field name arrays)
|
|
68
|
+
* @param collectionName - Name of the collection for error messages
|
|
69
|
+
* @returns Effect that succeeds with void or fails with UniqueConstraintError
|
|
70
|
+
*/
|
|
71
|
+
export declare const checkBatchUniqueConstraints: <T extends HasId>(entities: ReadonlyArray<T>, existingMap: ReadonlyMap<string, T>, constraints: NormalizedConstraints, collectionName: string) => Effect.Effect<void, UniqueConstraintError>;
|
|
72
|
+
/**
|
|
73
|
+
* Check a single entity against unique constraints, including a batch index of
|
|
74
|
+
* previously-checked entities. Used by createMany with skipDuplicates.
|
|
75
|
+
*
|
|
76
|
+
* @param entity - The entity being checked
|
|
77
|
+
* @param entityRecord - The entity as a record for field access
|
|
78
|
+
* @param existingMap - Current state of the collection
|
|
79
|
+
* @param constraints - Normalized constraints
|
|
80
|
+
* @param collectionName - Name of the collection for error messages
|
|
81
|
+
* @param batchIndex - Map of constraint keys to entity IDs from prior entities in the batch
|
|
82
|
+
* @returns Effect that succeeds with void or fails with UniqueConstraintError
|
|
83
|
+
*/
|
|
84
|
+
export declare const checkEntityUniqueConstraints: <T extends HasId>(entity: T, entityRecord: Record<string, unknown>, existingMap: ReadonlyMap<string, T>, constraints: NormalizedConstraints, collectionName: string, batchIndex: Map<string, string>) => Effect.Effect<void, UniqueConstraintError>;
|
|
85
|
+
/**
|
|
86
|
+
* Add an entity's unique constraint values to the batch index.
|
|
87
|
+
* Called after an entity passes unique constraint checks.
|
|
88
|
+
*
|
|
89
|
+
* @param entity - The entity to add
|
|
90
|
+
* @param entityRecord - The entity as a record for field access
|
|
91
|
+
* @param constraints - Normalized constraints
|
|
92
|
+
* @param batchIndex - Map to populate with constraint keys -> entity IDs
|
|
93
|
+
*/
|
|
94
|
+
export declare const addEntityToBatchIndex: <T extends HasId>(entity: T, entityRecord: Record<string, unknown>, constraints: NormalizedConstraints, batchIndex: Map<string, string>) => void;
|
|
95
|
+
/**
|
|
96
|
+
* Validate that an upsert where clause targets a declared unique field or id.
|
|
97
|
+
*
|
|
98
|
+
* The where clause must fully cover at least one declared constraint:
|
|
99
|
+
* - `{ id: "..." }` — always valid (id is implicitly unique)
|
|
100
|
+
* - `{ email: "..." }` — valid if `[["email"]]` is in constraints
|
|
101
|
+
* - `{ userId: "u1", settingKey: "theme" }` — valid if `[["userId", "settingKey"]]` is in constraints
|
|
102
|
+
* - Extra fields beyond the constraint are allowed (for additional filtering)
|
|
103
|
+
*
|
|
104
|
+
* If no constraint is fully covered by the where clause, fail with ValidationError
|
|
105
|
+
* listing the valid unique fields.
|
|
106
|
+
*
|
|
107
|
+
* @param where - The where clause object from upsert
|
|
108
|
+
* @param constraints - Normalized constraints (array of field name arrays)
|
|
109
|
+
* @param collectionName - Name of the collection for error messages
|
|
110
|
+
* @returns Effect that succeeds with void or fails with ValidationError
|
|
111
|
+
*/
|
|
112
|
+
export declare const validateUpsertWhere: (where: Readonly<Record<string, unknown>>, constraints: NormalizedConstraints, collectionName: string) => Effect.Effect<void, ValidationError>;
|
|
113
|
+
export {};
|
|
114
|
+
//# sourceMappingURL=unique-check.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unique-check.d.ts","sourceRoot":"","sources":["../../../src/operations/crud/unique-check.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH;;;;;GAKG;AACH,MAAM,MAAM,kBAAkB,GAAG,aAAa,CAAC,MAAM,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC;AAE/E;;;;GAIG;AACH,MAAM,MAAM,qBAAqB,GAAG,aAAa,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC;AAMzE;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,oBAAoB,GAChC,cAAc,kBAAkB,GAAG,SAAS,KAC1C,qBAQF,CAAC;AAMF,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EACN,qBAAqB,EACrB,eAAe,EACf,MAAM,6BAA6B,CAAC;AAErC,KAAK,KAAK,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAErC;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,sBAAsB,GAAI,CAAC,SAAS,KAAK,EACrD,QAAQ,CAAC,EACT,aAAa,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC,EACnC,aAAa,qBAAqB,EAClC,gBAAgB,MAAM,KACpB,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,qBAAqB,CAgE3C,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,2BAA2B,GAAI,CAAC,SAAS,KAAK,EAC1D,UAAU,aAAa,CAAC,CAAC,CAAC,EAC1B,aAAa,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC,EACnC,aAAa,qBAAqB,EAClC,gBAAgB,MAAM,KACpB,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,qBAAqB,CAkG3C,CAAC;AAMF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,4BAA4B,GAAI,CAAC,SAAS,KAAK,EAC3D,QAAQ,CAAC,EACT,cAAc,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACrC,aAAa,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC,EACnC,aAAa,qBAAqB,EAClC,gBAAgB,MAAM,EACtB,YAAY,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,KAC7B,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,qBAAqB,CAkF3C,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,GAAI,CAAC,SAAS,KAAK,EACpD,QAAQ,CAAC,EACT,cAAc,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACrC,aAAa,qBAAqB,EAClC,YAAY,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,KAC7B,IA6BF,CAAC;AAMF;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,mBAAmB,GAC/B,OAAO,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACxC,aAAa,qBAAqB,EAClC,gBAAgB,MAAM,KACpB,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,eAAe,CAkCrC,CAAC"}
|