@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,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Index lookup for query acceleration.
|
|
3
|
+
*
|
|
4
|
+
* Provides functions for resolving entities using indexes when the query's
|
|
5
|
+
* where clause contains equality conditions on indexed fields.
|
|
6
|
+
*/
|
|
7
|
+
import { Effect, Ref } from "effect";
|
|
8
|
+
/**
|
|
9
|
+
* Resolve entities using an index if the where clause is eligible.
|
|
10
|
+
*
|
|
11
|
+
* Checks the where clause for equality conditions (direct value, $eq, or $in)
|
|
12
|
+
* on indexed fields. If a usable index is found, returns the matching entities.
|
|
13
|
+
* Otherwise returns undefined, signaling that the caller should fall back to
|
|
14
|
+
* a full scan.
|
|
15
|
+
*
|
|
16
|
+
* The where clause is NOT modified — the filter stage should still run on the
|
|
17
|
+
* returned entities to apply any remaining conditions.
|
|
18
|
+
*
|
|
19
|
+
* @param where - The where clause from the query (may be undefined)
|
|
20
|
+
* @param indexes - The collection's indexes
|
|
21
|
+
* @param map - The entity data map (id -> entity)
|
|
22
|
+
* @returns Effect producing Array<T> if index was used, undefined if no usable index
|
|
23
|
+
*/
|
|
24
|
+
export const resolveWithIndex = (where, indexes, map) => Effect.gen(function* () {
|
|
25
|
+
// No where clause means no index can help
|
|
26
|
+
if (where === undefined || Object.keys(where).length === 0) {
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
// Skip if where contains logical operators at top level
|
|
30
|
+
if ("$or" in where || "$and" in where || "$not" in where) {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
// No indexes configured
|
|
34
|
+
if (indexes.size === 0) {
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
// Find the best usable index
|
|
38
|
+
const eligibleIndex = findEligibleIndex(where, indexes);
|
|
39
|
+
if (eligibleIndex === undefined) {
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
const { indexKey, fields, conditions } = eligibleIndex;
|
|
43
|
+
const indexRef = indexes.get(indexKey);
|
|
44
|
+
if (indexRef === undefined) {
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
// Get the current index state
|
|
48
|
+
const indexMap = yield* Ref.get(indexRef);
|
|
49
|
+
// Resolve entity IDs from the index
|
|
50
|
+
const entityIds = resolveEntityIds(fields, conditions, indexMap);
|
|
51
|
+
// Load entities from the map
|
|
52
|
+
const entities = [];
|
|
53
|
+
for (const id of entityIds) {
|
|
54
|
+
const entity = map.get(id);
|
|
55
|
+
if (entity !== undefined) {
|
|
56
|
+
entities.push(entity);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return entities;
|
|
60
|
+
});
|
|
61
|
+
/**
|
|
62
|
+
* Extract the equality condition from a where clause field value.
|
|
63
|
+
*
|
|
64
|
+
* Returns undefined if the field value is not an equality condition
|
|
65
|
+
* (e.g., it uses $ne, $gt, etc.).
|
|
66
|
+
*/
|
|
67
|
+
const extractEqualityCondition = (fieldValue) => {
|
|
68
|
+
// Direct equality: { email: "alice@example.com" }
|
|
69
|
+
if (fieldValue === null ||
|
|
70
|
+
typeof fieldValue !== "object" ||
|
|
71
|
+
Array.isArray(fieldValue)) {
|
|
72
|
+
return { type: "direct", values: [fieldValue] };
|
|
73
|
+
}
|
|
74
|
+
const obj = fieldValue;
|
|
75
|
+
// Check for $eq: { email: { $eq: "alice@example.com" } }
|
|
76
|
+
if ("$eq" in obj && Object.keys(obj).length === 1) {
|
|
77
|
+
return { type: "$eq", values: [obj.$eq] };
|
|
78
|
+
}
|
|
79
|
+
// Check for $in: { email: { $in: ["a@b.com", "c@d.com"] } }
|
|
80
|
+
if ("$in" in obj && Object.keys(obj).length === 1 && Array.isArray(obj.$in)) {
|
|
81
|
+
return { type: "$in", values: obj.$in };
|
|
82
|
+
}
|
|
83
|
+
// Other operators ($ne, $gt, etc.) are not index-eligible
|
|
84
|
+
return undefined;
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* Find the best index that can serve the given where clause.
|
|
88
|
+
*
|
|
89
|
+
* An index is eligible when all its fields have equality conditions
|
|
90
|
+
* (direct, $eq, or $in) in the where clause.
|
|
91
|
+
*
|
|
92
|
+
* When multiple indexes match, prefer the one with more fields (compound
|
|
93
|
+
* over single-field) as it narrows the result set more aggressively.
|
|
94
|
+
*/
|
|
95
|
+
const findEligibleIndex = (where, indexes) => {
|
|
96
|
+
let bestMatch;
|
|
97
|
+
for (const indexKey of indexes.keys()) {
|
|
98
|
+
const fields = JSON.parse(indexKey);
|
|
99
|
+
// Check if all fields in this index have equality conditions
|
|
100
|
+
const conditions = [];
|
|
101
|
+
let allFieldsMatch = true;
|
|
102
|
+
for (const field of fields) {
|
|
103
|
+
if (!(field in where)) {
|
|
104
|
+
allFieldsMatch = false;
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
const condition = extractEqualityCondition(where[field]);
|
|
108
|
+
if (condition === undefined) {
|
|
109
|
+
allFieldsMatch = false;
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
conditions.push(condition);
|
|
113
|
+
}
|
|
114
|
+
if (!allFieldsMatch) {
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
// This index is eligible
|
|
118
|
+
// Prefer indexes with more fields (compound over single)
|
|
119
|
+
if (bestMatch === undefined || fields.length > bestMatch.fields.length) {
|
|
120
|
+
bestMatch = { indexKey, fields, conditions };
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return bestMatch;
|
|
124
|
+
};
|
|
125
|
+
/**
|
|
126
|
+
* Resolve entity IDs from the index using the extracted conditions.
|
|
127
|
+
*
|
|
128
|
+
* For single-field indexes with direct/$eq, returns the Set from the index.
|
|
129
|
+
* For $in conditions, returns the union of Sets for each value.
|
|
130
|
+
* For compound indexes, computes the Cartesian product of $in values.
|
|
131
|
+
*/
|
|
132
|
+
const resolveEntityIds = (fields, conditions, indexMap) => {
|
|
133
|
+
const result = new Set();
|
|
134
|
+
if (fields.length === 1) {
|
|
135
|
+
// Single-field index
|
|
136
|
+
const condition = conditions[0];
|
|
137
|
+
for (const value of condition.values) {
|
|
138
|
+
const ids = indexMap.get(value);
|
|
139
|
+
if (ids !== undefined) {
|
|
140
|
+
for (const id of ids) {
|
|
141
|
+
result.add(id);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
// Compound index — compute Cartesian product of all condition values
|
|
148
|
+
const allValueCombinations = cartesianProduct(conditions.map((c) => c.values));
|
|
149
|
+
for (const combination of allValueCombinations) {
|
|
150
|
+
const compoundKey = JSON.stringify(combination);
|
|
151
|
+
const ids = indexMap.get(compoundKey);
|
|
152
|
+
if (ids !== undefined) {
|
|
153
|
+
for (const id of ids) {
|
|
154
|
+
result.add(id);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return result;
|
|
160
|
+
};
|
|
161
|
+
/**
|
|
162
|
+
* Compute the Cartesian product of arrays.
|
|
163
|
+
*
|
|
164
|
+
* cartesianProduct([["a", "b"], [1, 2]]) => [["a", 1], ["a", 2], ["b", 1], ["b", 2]]
|
|
165
|
+
*/
|
|
166
|
+
const cartesianProduct = (arrays) => {
|
|
167
|
+
if (arrays.length === 0) {
|
|
168
|
+
return [[]];
|
|
169
|
+
}
|
|
170
|
+
const [first, ...rest] = arrays;
|
|
171
|
+
const restProduct = cartesianProduct(rest);
|
|
172
|
+
const result = [];
|
|
173
|
+
for (const value of first) {
|
|
174
|
+
for (const restCombination of restProduct) {
|
|
175
|
+
result.push([value, ...restCombination]);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return result;
|
|
179
|
+
};
|
|
180
|
+
//# sourceMappingURL=index-lookup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-lookup.js","sourceRoot":"","sources":["../../src/indexes/index-lookup.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Index management for in-memory database.
|
|
3
|
+
*
|
|
4
|
+
* Provides functions for building and maintaining indexes that accelerate
|
|
5
|
+
* equality queries. Supports both single-field and compound indexes.
|
|
6
|
+
*/
|
|
7
|
+
import { Effect } from "effect";
|
|
8
|
+
import type { CollectionIndexes, NormalizedIndex } from "../types/index-types.js";
|
|
9
|
+
/**
|
|
10
|
+
* Entity constraint: must have a readonly string `id` field.
|
|
11
|
+
*/
|
|
12
|
+
type HasId = {
|
|
13
|
+
readonly id: string;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Build all indexes for a collection from initial data.
|
|
17
|
+
*
|
|
18
|
+
* For each normalized index, creates a Ref<IndexMap> containing the mapping
|
|
19
|
+
* from field values to entity IDs. The returned CollectionIndexes map is keyed
|
|
20
|
+
* by the JSON.stringify'd field array (e.g., '["email"]' or '["userId","category"]').
|
|
21
|
+
*
|
|
22
|
+
* @param normalizedIndexes - Array of normalized index definitions
|
|
23
|
+
* @param initialData - Array of entities to build indexes from
|
|
24
|
+
* @returns Effect producing a CollectionIndexes map
|
|
25
|
+
*/
|
|
26
|
+
export declare const buildIndexes: <T extends HasId>(normalizedIndexes: ReadonlyArray<NormalizedIndex>, initialData: ReadonlyArray<T>) => Effect.Effect<CollectionIndexes>;
|
|
27
|
+
/**
|
|
28
|
+
* Normalize index definitions from user config format to internal format.
|
|
29
|
+
*
|
|
30
|
+
* User config can specify indexes as:
|
|
31
|
+
* - Single field: "email"
|
|
32
|
+
* - Compound: ["userId", "category"]
|
|
33
|
+
*
|
|
34
|
+
* This function normalizes all indexes to arrays:
|
|
35
|
+
* - "email" -> ["email"]
|
|
36
|
+
* - ["userId", "category"] -> ["userId", "category"]
|
|
37
|
+
*
|
|
38
|
+
* @param indexes - Raw index definitions from collection config
|
|
39
|
+
* @returns Normalized array of index field arrays
|
|
40
|
+
*/
|
|
41
|
+
export declare const normalizeIndexes: (indexes: ReadonlyArray<string | ReadonlyArray<string>> | undefined) => ReadonlyArray<NormalizedIndex>;
|
|
42
|
+
/**
|
|
43
|
+
* Add an entity to all applicable indexes.
|
|
44
|
+
*
|
|
45
|
+
* For each index in the collection, computes the index key from the entity's
|
|
46
|
+
* field values and adds the entity's ID to the corresponding Set in the index.
|
|
47
|
+
*
|
|
48
|
+
* Entities with null/undefined values in indexed fields are skipped for that index.
|
|
49
|
+
*
|
|
50
|
+
* @param indexes - The collection's indexes
|
|
51
|
+
* @param entity - The entity to add
|
|
52
|
+
* @returns Effect that updates all index Refs
|
|
53
|
+
*/
|
|
54
|
+
export declare const addToIndex: <T extends HasId>(indexes: CollectionIndexes, entity: T) => Effect.Effect<void>;
|
|
55
|
+
/**
|
|
56
|
+
* Remove an entity from all applicable indexes.
|
|
57
|
+
*
|
|
58
|
+
* For each index in the collection, computes the index key from the entity's
|
|
59
|
+
* field values and removes the entity's ID from the corresponding Set.
|
|
60
|
+
* Empty Sets are cleaned up (deleted from the index).
|
|
61
|
+
*
|
|
62
|
+
* Entities with null/undefined values in indexed fields are skipped for that index
|
|
63
|
+
* (they wouldn't have been indexed in the first place).
|
|
64
|
+
*
|
|
65
|
+
* @param indexes - The collection's indexes
|
|
66
|
+
* @param entity - The entity to remove
|
|
67
|
+
* @returns Effect that updates all index Refs
|
|
68
|
+
*/
|
|
69
|
+
export declare const removeFromIndex: <T extends HasId>(indexes: CollectionIndexes, entity: T) => Effect.Effect<void>;
|
|
70
|
+
/**
|
|
71
|
+
* Add multiple entities to all applicable indexes in a single batch.
|
|
72
|
+
*
|
|
73
|
+
* For each index in the collection, computes all index keys and applies
|
|
74
|
+
* all additions in one Ref.update call per index. This is more efficient
|
|
75
|
+
* than calling addToIndex for each entity individually.
|
|
76
|
+
*
|
|
77
|
+
* Entities with null/undefined values in indexed fields are skipped for that index.
|
|
78
|
+
*
|
|
79
|
+
* @param indexes - The collection's indexes
|
|
80
|
+
* @param entities - The entities to add
|
|
81
|
+
* @returns Effect that updates all index Refs
|
|
82
|
+
*/
|
|
83
|
+
export declare const addManyToIndex: <T extends HasId>(indexes: CollectionIndexes, entities: ReadonlyArray<T>) => Effect.Effect<void>;
|
|
84
|
+
/**
|
|
85
|
+
* Remove multiple entities from all applicable indexes in a single batch.
|
|
86
|
+
*
|
|
87
|
+
* For each index in the collection, computes all index keys and applies
|
|
88
|
+
* all removals in one Ref.update call per index. This is more efficient
|
|
89
|
+
* than calling removeFromIndex for each entity individually.
|
|
90
|
+
* Empty Sets are cleaned up (deleted from the index).
|
|
91
|
+
*
|
|
92
|
+
* Entities with null/undefined values in indexed fields are skipped for that index
|
|
93
|
+
* (they wouldn't have been indexed in the first place).
|
|
94
|
+
*
|
|
95
|
+
* @param indexes - The collection's indexes
|
|
96
|
+
* @param entities - The entities to remove
|
|
97
|
+
* @returns Effect that updates all index Refs
|
|
98
|
+
*/
|
|
99
|
+
export declare const removeManyFromIndex: <T extends HasId>(indexes: CollectionIndexes, entities: ReadonlyArray<T>) => Effect.Effect<void>;
|
|
100
|
+
/**
|
|
101
|
+
* Update an entity's position in all applicable indexes after a mutation.
|
|
102
|
+
*
|
|
103
|
+
* For each index in the collection:
|
|
104
|
+
* - Computes the old and new index keys
|
|
105
|
+
* - If keys are the same (or both undefined), no action needed
|
|
106
|
+
* - If keys differ, removes the old entry and adds the new entry
|
|
107
|
+
*
|
|
108
|
+
* This efficiently handles the common case where most indexed fields don't
|
|
109
|
+
* change during an update.
|
|
110
|
+
*
|
|
111
|
+
* @param indexes - The collection's indexes
|
|
112
|
+
* @param oldEntity - The entity before the update
|
|
113
|
+
* @param newEntity - The entity after the update
|
|
114
|
+
* @returns Effect that updates all affected index Refs
|
|
115
|
+
*/
|
|
116
|
+
export declare const updateInIndex: <T extends HasId>(indexes: CollectionIndexes, oldEntity: T, newEntity: T) => Effect.Effect<void>;
|
|
117
|
+
export {};
|
|
118
|
+
//# sourceMappingURL=index-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-manager.d.ts","sourceRoot":"","sources":["../../src/indexes/index-manager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,MAAM,EAAO,MAAM,QAAQ,CAAC;AACrC,OAAO,KAAK,EACX,iBAAiB,EAEjB,eAAe,EACf,MAAM,yBAAyB,CAAC;AAGjC;;GAEG;AACH,KAAK,KAAK,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AA8DrC;;;;;;;;;;GAUG;AACH,eAAO,MAAM,YAAY,GAAI,CAAC,SAAS,KAAK,EAC3C,mBAAmB,aAAa,CAAC,eAAe,CAAC,EACjD,aAAa,aAAa,CAAC,CAAC,CAAC,KAC3B,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAY/B,CAAC;AAEJ;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,gBAAgB,GAC5B,SAAS,aAAa,CAAC,MAAM,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,GAAG,SAAS,KAChE,aAAa,CAAC,eAAe,CAW/B,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,UAAU,GAAI,CAAC,SAAS,KAAK,EACzC,SAAS,iBAAiB,EAC1B,QAAQ,CAAC,KACP,MAAM,CAAC,MAAM,CAAC,IAAI,CAuBlB,CAAC;AAEJ;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,eAAe,GAAI,CAAC,SAAS,KAAK,EAC9C,SAAS,iBAAiB,EAC1B,QAAQ,CAAC,KACP,MAAM,CAAC,MAAM,CAAC,IAAI,CA4BlB,CAAC;AAEJ;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,cAAc,GAAI,CAAC,SAAS,KAAK,EAC7C,SAAS,iBAAiB,EAC1B,UAAU,aAAa,CAAC,CAAC,CAAC,KACxB,MAAM,CAAC,MAAM,CAAC,IAAI,CAsClB,CAAC;AAEJ;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,mBAAmB,GAAI,CAAC,SAAS,KAAK,EAClD,SAAS,iBAAiB,EAC1B,UAAU,aAAa,CAAC,CAAC,CAAC,KACxB,MAAM,CAAC,MAAM,CAAC,IAAI,CA2ClB,CAAC;AAWJ;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,aAAa,GAAI,CAAC,SAAS,KAAK,EAC5C,SAAS,iBAAiB,EAC1B,WAAW,CAAC,EACZ,WAAW,CAAC,KACV,MAAM,CAAC,MAAM,CAAC,IAAI,CAoDlB,CAAC"}
|
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Index management for in-memory database.
|
|
3
|
+
*
|
|
4
|
+
* Provides functions for building and maintaining indexes that accelerate
|
|
5
|
+
* equality queries. Supports both single-field and compound indexes.
|
|
6
|
+
*/
|
|
7
|
+
import { Effect, Ref } from "effect";
|
|
8
|
+
import { getNestedValue } from "../utils/nested-path.js";
|
|
9
|
+
/**
|
|
10
|
+
* Compute the index key for an entity given the index fields.
|
|
11
|
+
*
|
|
12
|
+
* For single-field indexes, returns the raw field value.
|
|
13
|
+
* For compound indexes, returns a JSON.stringify'd array of field values.
|
|
14
|
+
*
|
|
15
|
+
* Returns undefined if any indexed field is null or undefined (entity should not be indexed).
|
|
16
|
+
*/
|
|
17
|
+
const computeIndexKey = (entity, fields) => {
|
|
18
|
+
const values = fields.map((field) => getNestedValue(entity, field));
|
|
19
|
+
// Skip if any indexed field is null or undefined
|
|
20
|
+
if (values.some((v) => v === null || v === undefined)) {
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
// Single-field: use raw value
|
|
24
|
+
if (fields.length === 1) {
|
|
25
|
+
return values[0];
|
|
26
|
+
}
|
|
27
|
+
// Compound: use JSON.stringify'd array
|
|
28
|
+
return JSON.stringify(values);
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Build an IndexMap for a single index from initial data.
|
|
32
|
+
*
|
|
33
|
+
* @param fields - The normalized index fields
|
|
34
|
+
* @param entities - All entities in the collection
|
|
35
|
+
* @returns The populated IndexMap
|
|
36
|
+
*/
|
|
37
|
+
const buildSingleIndex = (fields, entities) => {
|
|
38
|
+
const indexMap = new Map();
|
|
39
|
+
for (const entity of entities) {
|
|
40
|
+
const key = computeIndexKey(entity, fields);
|
|
41
|
+
if (key === undefined) {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
const existing = indexMap.get(key);
|
|
45
|
+
if (existing) {
|
|
46
|
+
existing.add(entity.id);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
indexMap.set(key, new Set([entity.id]));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return indexMap;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Build all indexes for a collection from initial data.
|
|
56
|
+
*
|
|
57
|
+
* For each normalized index, creates a Ref<IndexMap> containing the mapping
|
|
58
|
+
* from field values to entity IDs. The returned CollectionIndexes map is keyed
|
|
59
|
+
* by the JSON.stringify'd field array (e.g., '["email"]' or '["userId","category"]').
|
|
60
|
+
*
|
|
61
|
+
* @param normalizedIndexes - Array of normalized index definitions
|
|
62
|
+
* @param initialData - Array of entities to build indexes from
|
|
63
|
+
* @returns Effect producing a CollectionIndexes map
|
|
64
|
+
*/
|
|
65
|
+
export const buildIndexes = (normalizedIndexes, initialData) => Effect.gen(function* () {
|
|
66
|
+
const collectionIndexes = new Map();
|
|
67
|
+
for (const fields of normalizedIndexes) {
|
|
68
|
+
const indexKey = JSON.stringify(fields);
|
|
69
|
+
const indexMap = buildSingleIndex(fields, initialData);
|
|
70
|
+
const indexRef = yield* Ref.make(indexMap);
|
|
71
|
+
collectionIndexes.set(indexKey, indexRef);
|
|
72
|
+
}
|
|
73
|
+
return collectionIndexes;
|
|
74
|
+
});
|
|
75
|
+
/**
|
|
76
|
+
* Normalize index definitions from user config format to internal format.
|
|
77
|
+
*
|
|
78
|
+
* User config can specify indexes as:
|
|
79
|
+
* - Single field: "email"
|
|
80
|
+
* - Compound: ["userId", "category"]
|
|
81
|
+
*
|
|
82
|
+
* This function normalizes all indexes to arrays:
|
|
83
|
+
* - "email" -> ["email"]
|
|
84
|
+
* - ["userId", "category"] -> ["userId", "category"]
|
|
85
|
+
*
|
|
86
|
+
* @param indexes - Raw index definitions from collection config
|
|
87
|
+
* @returns Normalized array of index field arrays
|
|
88
|
+
*/
|
|
89
|
+
export const normalizeIndexes = (indexes) => {
|
|
90
|
+
if (indexes === undefined || indexes.length === 0) {
|
|
91
|
+
return [];
|
|
92
|
+
}
|
|
93
|
+
return indexes.map((index) => {
|
|
94
|
+
if (typeof index === "string") {
|
|
95
|
+
return [index];
|
|
96
|
+
}
|
|
97
|
+
return index;
|
|
98
|
+
});
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* Add an entity to all applicable indexes.
|
|
102
|
+
*
|
|
103
|
+
* For each index in the collection, computes the index key from the entity's
|
|
104
|
+
* field values and adds the entity's ID to the corresponding Set in the index.
|
|
105
|
+
*
|
|
106
|
+
* Entities with null/undefined values in indexed fields are skipped for that index.
|
|
107
|
+
*
|
|
108
|
+
* @param indexes - The collection's indexes
|
|
109
|
+
* @param entity - The entity to add
|
|
110
|
+
* @returns Effect that updates all index Refs
|
|
111
|
+
*/
|
|
112
|
+
export const addToIndex = (indexes, entity) => Effect.gen(function* () {
|
|
113
|
+
for (const [indexKey, indexRef] of indexes) {
|
|
114
|
+
const fields = JSON.parse(indexKey);
|
|
115
|
+
const key = computeIndexKey(entity, fields);
|
|
116
|
+
if (key === undefined) {
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
yield* Ref.update(indexRef, (indexMap) => {
|
|
120
|
+
const newMap = new Map(indexMap);
|
|
121
|
+
const existing = newMap.get(key);
|
|
122
|
+
if (existing) {
|
|
123
|
+
const newSet = new Set(existing);
|
|
124
|
+
newSet.add(entity.id);
|
|
125
|
+
newMap.set(key, newSet);
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
newMap.set(key, new Set([entity.id]));
|
|
129
|
+
}
|
|
130
|
+
return newMap;
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
/**
|
|
135
|
+
* Remove an entity from all applicable indexes.
|
|
136
|
+
*
|
|
137
|
+
* For each index in the collection, computes the index key from the entity's
|
|
138
|
+
* field values and removes the entity's ID from the corresponding Set.
|
|
139
|
+
* Empty Sets are cleaned up (deleted from the index).
|
|
140
|
+
*
|
|
141
|
+
* Entities with null/undefined values in indexed fields are skipped for that index
|
|
142
|
+
* (they wouldn't have been indexed in the first place).
|
|
143
|
+
*
|
|
144
|
+
* @param indexes - The collection's indexes
|
|
145
|
+
* @param entity - The entity to remove
|
|
146
|
+
* @returns Effect that updates all index Refs
|
|
147
|
+
*/
|
|
148
|
+
export const removeFromIndex = (indexes, entity) => Effect.gen(function* () {
|
|
149
|
+
for (const [indexKey, indexRef] of indexes) {
|
|
150
|
+
const fields = JSON.parse(indexKey);
|
|
151
|
+
const key = computeIndexKey(entity, fields);
|
|
152
|
+
if (key === undefined) {
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
yield* Ref.update(indexRef, (indexMap) => {
|
|
156
|
+
const existing = indexMap.get(key);
|
|
157
|
+
if (!existing) {
|
|
158
|
+
return indexMap;
|
|
159
|
+
}
|
|
160
|
+
const newMap = new Map(indexMap);
|
|
161
|
+
const newSet = new Set(existing);
|
|
162
|
+
newSet.delete(entity.id);
|
|
163
|
+
if (newSet.size === 0) {
|
|
164
|
+
newMap.delete(key);
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
newMap.set(key, newSet);
|
|
168
|
+
}
|
|
169
|
+
return newMap;
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
/**
|
|
174
|
+
* Add multiple entities to all applicable indexes in a single batch.
|
|
175
|
+
*
|
|
176
|
+
* For each index in the collection, computes all index keys and applies
|
|
177
|
+
* all additions in one Ref.update call per index. This is more efficient
|
|
178
|
+
* than calling addToIndex for each entity individually.
|
|
179
|
+
*
|
|
180
|
+
* Entities with null/undefined values in indexed fields are skipped for that index.
|
|
181
|
+
*
|
|
182
|
+
* @param indexes - The collection's indexes
|
|
183
|
+
* @param entities - The entities to add
|
|
184
|
+
* @returns Effect that updates all index Refs
|
|
185
|
+
*/
|
|
186
|
+
export const addManyToIndex = (indexes, entities) => Effect.gen(function* () {
|
|
187
|
+
if (entities.length === 0) {
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
for (const [indexKey, indexRef] of indexes) {
|
|
191
|
+
const fields = JSON.parse(indexKey);
|
|
192
|
+
// Collect all additions for this index
|
|
193
|
+
const additions = [];
|
|
194
|
+
for (const entity of entities) {
|
|
195
|
+
const key = computeIndexKey(entity, fields);
|
|
196
|
+
if (key !== undefined) {
|
|
197
|
+
additions.push({ key, id: entity.id });
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
if (additions.length === 0) {
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
// Apply all additions in one update
|
|
204
|
+
yield* Ref.update(indexRef, (indexMap) => {
|
|
205
|
+
const newMap = new Map(indexMap);
|
|
206
|
+
for (const { key, id } of additions) {
|
|
207
|
+
const existing = newMap.get(key);
|
|
208
|
+
if (existing) {
|
|
209
|
+
const newSet = new Set(existing);
|
|
210
|
+
newSet.add(id);
|
|
211
|
+
newMap.set(key, newSet);
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
newMap.set(key, new Set([id]));
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return newMap;
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
/**
|
|
222
|
+
* Remove multiple entities from all applicable indexes in a single batch.
|
|
223
|
+
*
|
|
224
|
+
* For each index in the collection, computes all index keys and applies
|
|
225
|
+
* all removals in one Ref.update call per index. This is more efficient
|
|
226
|
+
* than calling removeFromIndex for each entity individually.
|
|
227
|
+
* Empty Sets are cleaned up (deleted from the index).
|
|
228
|
+
*
|
|
229
|
+
* Entities with null/undefined values in indexed fields are skipped for that index
|
|
230
|
+
* (they wouldn't have been indexed in the first place).
|
|
231
|
+
*
|
|
232
|
+
* @param indexes - The collection's indexes
|
|
233
|
+
* @param entities - The entities to remove
|
|
234
|
+
* @returns Effect that updates all index Refs
|
|
235
|
+
*/
|
|
236
|
+
export const removeManyFromIndex = (indexes, entities) => Effect.gen(function* () {
|
|
237
|
+
if (entities.length === 0) {
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
for (const [indexKey, indexRef] of indexes) {
|
|
241
|
+
const fields = JSON.parse(indexKey);
|
|
242
|
+
// Collect all removals for this index
|
|
243
|
+
const removals = [];
|
|
244
|
+
for (const entity of entities) {
|
|
245
|
+
const key = computeIndexKey(entity, fields);
|
|
246
|
+
if (key !== undefined) {
|
|
247
|
+
removals.push({ key, id: entity.id });
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
if (removals.length === 0) {
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
// Apply all removals in one update
|
|
254
|
+
yield* Ref.update(indexRef, (indexMap) => {
|
|
255
|
+
const newMap = new Map(indexMap);
|
|
256
|
+
for (const { key, id } of removals) {
|
|
257
|
+
const existing = newMap.get(key);
|
|
258
|
+
if (!existing) {
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
261
|
+
const newSet = new Set(existing);
|
|
262
|
+
newSet.delete(id);
|
|
263
|
+
if (newSet.size === 0) {
|
|
264
|
+
newMap.delete(key);
|
|
265
|
+
}
|
|
266
|
+
else {
|
|
267
|
+
newMap.set(key, newSet);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return newMap;
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
/**
|
|
275
|
+
* Compare two index keys for equality.
|
|
276
|
+
*
|
|
277
|
+
* Uses strict equality for primitives. For compound indexes (string keys),
|
|
278
|
+
* this works directly since JSON.stringify produces identical strings for
|
|
279
|
+
* identical value arrays.
|
|
280
|
+
*/
|
|
281
|
+
const keysEqual = (a, b) => a === b;
|
|
282
|
+
/**
|
|
283
|
+
* Update an entity's position in all applicable indexes after a mutation.
|
|
284
|
+
*
|
|
285
|
+
* For each index in the collection:
|
|
286
|
+
* - Computes the old and new index keys
|
|
287
|
+
* - If keys are the same (or both undefined), no action needed
|
|
288
|
+
* - If keys differ, removes the old entry and adds the new entry
|
|
289
|
+
*
|
|
290
|
+
* This efficiently handles the common case where most indexed fields don't
|
|
291
|
+
* change during an update.
|
|
292
|
+
*
|
|
293
|
+
* @param indexes - The collection's indexes
|
|
294
|
+
* @param oldEntity - The entity before the update
|
|
295
|
+
* @param newEntity - The entity after the update
|
|
296
|
+
* @returns Effect that updates all affected index Refs
|
|
297
|
+
*/
|
|
298
|
+
export const updateInIndex = (indexes, oldEntity, newEntity) => Effect.gen(function* () {
|
|
299
|
+
for (const [indexKey, indexRef] of indexes) {
|
|
300
|
+
const fields = JSON.parse(indexKey);
|
|
301
|
+
const oldKey = computeIndexKey(oldEntity, fields);
|
|
302
|
+
const newKey = computeIndexKey(newEntity, fields);
|
|
303
|
+
// Both undefined or both equal - no change needed
|
|
304
|
+
if (oldKey === undefined && newKey === undefined) {
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
307
|
+
if (oldKey !== undefined &&
|
|
308
|
+
newKey !== undefined &&
|
|
309
|
+
keysEqual(oldKey, newKey)) {
|
|
310
|
+
continue;
|
|
311
|
+
}
|
|
312
|
+
// Keys differ - update the index
|
|
313
|
+
yield* Ref.update(indexRef, (indexMap) => {
|
|
314
|
+
const newMap = new Map(indexMap);
|
|
315
|
+
// Remove from old key if it existed
|
|
316
|
+
if (oldKey !== undefined) {
|
|
317
|
+
const oldSet = newMap.get(oldKey);
|
|
318
|
+
if (oldSet) {
|
|
319
|
+
const updatedSet = new Set(oldSet);
|
|
320
|
+
updatedSet.delete(oldEntity.id);
|
|
321
|
+
if (updatedSet.size === 0) {
|
|
322
|
+
newMap.delete(oldKey);
|
|
323
|
+
}
|
|
324
|
+
else {
|
|
325
|
+
newMap.set(oldKey, updatedSet);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
// Add to new key if indexable
|
|
330
|
+
if (newKey !== undefined) {
|
|
331
|
+
const existingSet = newMap.get(newKey);
|
|
332
|
+
if (existingSet) {
|
|
333
|
+
const updatedSet = new Set(existingSet);
|
|
334
|
+
updatedSet.add(newEntity.id);
|
|
335
|
+
newMap.set(newKey, updatedSet);
|
|
336
|
+
}
|
|
337
|
+
else {
|
|
338
|
+
newMap.set(newKey, new Set([newEntity.id]));
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
return newMap;
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
//# sourceMappingURL=index-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-manager.js","sourceRoot":"","sources":["../../src/indexes/index-manager.ts"],"names":[],"mappings":"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"}
|