@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.
Files changed (342) hide show
  1. package/LICENSE +21 -0
  2. package/dist/errors/crud-errors.d.ts +98 -0
  3. package/dist/errors/crud-errors.d.ts.map +1 -0
  4. package/dist/errors/crud-errors.js +23 -0
  5. package/dist/errors/crud-errors.js.map +1 -0
  6. package/dist/errors/index.d.ts +16 -0
  7. package/dist/errors/index.d.ts.map +1 -0
  8. package/dist/errors/index.js +12 -0
  9. package/dist/errors/index.js.map +1 -0
  10. package/dist/errors/migration-errors.d.ts +22 -0
  11. package/dist/errors/migration-errors.d.ts.map +1 -0
  12. package/dist/errors/migration-errors.js +14 -0
  13. package/dist/errors/migration-errors.js.map +1 -0
  14. package/dist/errors/plugin-errors.d.ts +15 -0
  15. package/dist/errors/plugin-errors.d.ts.map +1 -0
  16. package/dist/errors/plugin-errors.js +11 -0
  17. package/dist/errors/plugin-errors.js.map +1 -0
  18. package/dist/errors/query-errors.d.ts +31 -0
  19. package/dist/errors/query-errors.d.ts.map +1 -0
  20. package/dist/errors/query-errors.js +11 -0
  21. package/dist/errors/query-errors.js.map +1 -0
  22. package/dist/errors/storage-errors.d.ts +30 -0
  23. package/dist/errors/storage-errors.d.ts.map +1 -0
  24. package/dist/errors/storage-errors.js +11 -0
  25. package/dist/errors/storage-errors.js.map +1 -0
  26. package/dist/factories/crud-factory-with-relationships.d.ts +28 -0
  27. package/dist/factories/crud-factory-with-relationships.d.ts.map +1 -0
  28. package/dist/factories/crud-factory-with-relationships.js +8 -0
  29. package/dist/factories/crud-factory-with-relationships.js.map +1 -0
  30. package/dist/factories/crud-factory.d.ts +25 -0
  31. package/dist/factories/crud-factory.d.ts.map +1 -0
  32. package/dist/factories/crud-factory.js +8 -0
  33. package/dist/factories/crud-factory.js.map +1 -0
  34. package/dist/factories/database-effect.d.ts +241 -0
  35. package/dist/factories/database-effect.d.ts.map +1 -0
  36. package/dist/factories/database-effect.js +859 -0
  37. package/dist/factories/database-effect.js.map +1 -0
  38. package/dist/hooks/hook-runner.d.ts +60 -0
  39. package/dist/hooks/hook-runner.d.ts.map +1 -0
  40. package/dist/hooks/hook-runner.js +107 -0
  41. package/dist/hooks/hook-runner.js.map +1 -0
  42. package/dist/index.d.ts +84 -0
  43. package/dist/index.d.ts.map +1 -0
  44. package/dist/index.js +110 -0
  45. package/dist/index.js.map +1 -0
  46. package/dist/indexes/index-lookup.d.ts +33 -0
  47. package/dist/indexes/index-lookup.d.ts.map +1 -0
  48. package/dist/indexes/index-lookup.js +180 -0
  49. package/dist/indexes/index-lookup.js.map +1 -0
  50. package/dist/indexes/index-manager.d.ts +118 -0
  51. package/dist/indexes/index-manager.d.ts.map +1 -0
  52. package/dist/indexes/index-manager.js +345 -0
  53. package/dist/indexes/index-manager.js.map +1 -0
  54. package/dist/indexes/search-index.d.ts +179 -0
  55. package/dist/indexes/search-index.d.ts.map +1 -0
  56. package/dist/indexes/search-index.js +405 -0
  57. package/dist/indexes/search-index.js.map +1 -0
  58. package/dist/migrations/migration-runner.d.ts +70 -0
  59. package/dist/migrations/migration-runner.d.ts.map +1 -0
  60. package/dist/migrations/migration-runner.js +271 -0
  61. package/dist/migrations/migration-runner.js.map +1 -0
  62. package/dist/migrations/migration-types.d.ts +63 -0
  63. package/dist/migrations/migration-types.d.ts.map +1 -0
  64. package/dist/migrations/migration-types.js +5 -0
  65. package/dist/migrations/migration-types.js.map +1 -0
  66. package/dist/operations/crud/create-with-relationships.d.ts +44 -0
  67. package/dist/operations/crud/create-with-relationships.d.ts.map +1 -0
  68. package/dist/operations/crud/create-with-relationships.js +483 -0
  69. package/dist/operations/crud/create-with-relationships.js.map +1 -0
  70. package/dist/operations/crud/create.d.ts +48 -0
  71. package/dist/operations/crud/create.d.ts.map +1 -0
  72. package/dist/operations/crud/create.js +333 -0
  73. package/dist/operations/crud/create.js.map +1 -0
  74. package/dist/operations/crud/delete-with-relationships.d.ts +63 -0
  75. package/dist/operations/crud/delete-with-relationships.d.ts.map +1 -0
  76. package/dist/operations/crud/delete-with-relationships.js +395 -0
  77. package/dist/operations/crud/delete-with-relationships.js.map +1 -0
  78. package/dist/operations/crud/delete.d.ts +58 -0
  79. package/dist/operations/crud/delete.d.ts.map +1 -0
  80. package/dist/operations/crud/delete.js +267 -0
  81. package/dist/operations/crud/delete.js.map +1 -0
  82. package/dist/operations/crud/unique-check.d.ts +114 -0
  83. package/dist/operations/crud/unique-check.d.ts.map +1 -0
  84. package/dist/operations/crud/unique-check.js +383 -0
  85. package/dist/operations/crud/unique-check.js.map +1 -0
  86. package/dist/operations/crud/update-with-relationships.d.ts +45 -0
  87. package/dist/operations/crud/update-with-relationships.d.ts.map +1 -0
  88. package/dist/operations/crud/update-with-relationships.js +516 -0
  89. package/dist/operations/crud/update-with-relationships.js.map +1 -0
  90. package/dist/operations/crud/update.d.ts +91 -0
  91. package/dist/operations/crud/update.d.ts.map +1 -0
  92. package/dist/operations/crud/update.js +505 -0
  93. package/dist/operations/crud/update.js.map +1 -0
  94. package/dist/operations/crud/upsert.d.ts +52 -0
  95. package/dist/operations/crud/upsert.d.ts.map +1 -0
  96. package/dist/operations/crud/upsert.js +386 -0
  97. package/dist/operations/crud/upsert.js.map +1 -0
  98. package/dist/operations/query/aggregate.d.ts +30 -0
  99. package/dist/operations/query/aggregate.d.ts.map +1 -0
  100. package/dist/operations/query/aggregate.js +227 -0
  101. package/dist/operations/query/aggregate.js.map +1 -0
  102. package/dist/operations/query/cursor-stream.d.ts +18 -0
  103. package/dist/operations/query/cursor-stream.d.ts.map +1 -0
  104. package/dist/operations/query/cursor-stream.js +199 -0
  105. package/dist/operations/query/cursor-stream.js.map +1 -0
  106. package/dist/operations/query/filter-stream.d.ts +12 -0
  107. package/dist/operations/query/filter-stream.d.ts.map +1 -0
  108. package/dist/operations/query/filter-stream.js +167 -0
  109. package/dist/operations/query/filter-stream.js.map +1 -0
  110. package/dist/operations/query/filter.d.ts +13 -0
  111. package/dist/operations/query/filter.d.ts.map +1 -0
  112. package/dist/operations/query/filter.js +267 -0
  113. package/dist/operations/query/filter.js.map +1 -0
  114. package/dist/operations/query/paginate-stream.d.ts +11 -0
  115. package/dist/operations/query/paginate-stream.d.ts.map +1 -0
  116. package/dist/operations/query/paginate-stream.js +22 -0
  117. package/dist/operations/query/paginate-stream.js.map +1 -0
  118. package/dist/operations/query/query-helpers.d.ts +14 -0
  119. package/dist/operations/query/query-helpers.d.ts.map +1 -0
  120. package/dist/operations/query/query-helpers.js +22 -0
  121. package/dist/operations/query/query-helpers.js.map +1 -0
  122. package/dist/operations/query/resolve-computed.d.ts +142 -0
  123. package/dist/operations/query/resolve-computed.d.ts.map +1 -0
  124. package/dist/operations/query/resolve-computed.js +197 -0
  125. package/dist/operations/query/resolve-computed.js.map +1 -0
  126. package/dist/operations/query/search.d.ts +110 -0
  127. package/dist/operations/query/search.d.ts.map +1 -0
  128. package/dist/operations/query/search.js +188 -0
  129. package/dist/operations/query/search.js.map +1 -0
  130. package/dist/operations/query/select-stream.d.ts +27 -0
  131. package/dist/operations/query/select-stream.d.ts.map +1 -0
  132. package/dist/operations/query/select-stream.js +88 -0
  133. package/dist/operations/query/select-stream.js.map +1 -0
  134. package/dist/operations/query/select.d.ts +54 -0
  135. package/dist/operations/query/select.d.ts.map +1 -0
  136. package/dist/operations/query/select.js +159 -0
  137. package/dist/operations/query/select.js.map +1 -0
  138. package/dist/operations/query/sort-stream.d.ts +46 -0
  139. package/dist/operations/query/sort-stream.d.ts.map +1 -0
  140. package/dist/operations/query/sort-stream.js +158 -0
  141. package/dist/operations/query/sort-stream.js.map +1 -0
  142. package/dist/operations/query/sort.d.ts +9 -0
  143. package/dist/operations/query/sort.d.ts.map +1 -0
  144. package/dist/operations/query/sort.js +58 -0
  145. package/dist/operations/query/sort.js.map +1 -0
  146. package/dist/operations/relationships/populate-stream.d.ts +29 -0
  147. package/dist/operations/relationships/populate-stream.d.ts.map +1 -0
  148. package/dist/operations/relationships/populate-stream.js +159 -0
  149. package/dist/operations/relationships/populate-stream.js.map +1 -0
  150. package/dist/operations/relationships/populate.d.ts +15 -0
  151. package/dist/operations/relationships/populate.d.ts.map +1 -0
  152. package/dist/operations/relationships/populate.js +228 -0
  153. package/dist/operations/relationships/populate.js.map +1 -0
  154. package/dist/plugins/plugin-hooks.d.ts +25 -0
  155. package/dist/plugins/plugin-hooks.d.ts.map +1 -0
  156. package/dist/plugins/plugin-hooks.js +64 -0
  157. package/dist/plugins/plugin-hooks.js.map +1 -0
  158. package/dist/plugins/plugin-registry.d.ts +26 -0
  159. package/dist/plugins/plugin-registry.d.ts.map +1 -0
  160. package/dist/plugins/plugin-registry.js +150 -0
  161. package/dist/plugins/plugin-registry.js.map +1 -0
  162. package/dist/plugins/plugin-types.d.ts +95 -0
  163. package/dist/plugins/plugin-types.d.ts.map +1 -0
  164. package/dist/plugins/plugin-types.js +6 -0
  165. package/dist/plugins/plugin-types.js.map +1 -0
  166. package/dist/plugins/plugin-validation.d.ts +49 -0
  167. package/dist/plugins/plugin-validation.d.ts.map +1 -0
  168. package/dist/plugins/plugin-validation.js +295 -0
  169. package/dist/plugins/plugin-validation.js.map +1 -0
  170. package/dist/reactive/change-event.d.ts +44 -0
  171. package/dist/reactive/change-event.d.ts.map +1 -0
  172. package/dist/reactive/change-event.js +49 -0
  173. package/dist/reactive/change-event.js.map +1 -0
  174. package/dist/reactive/change-pubsub.d.ts +32 -0
  175. package/dist/reactive/change-pubsub.d.ts.map +1 -0
  176. package/dist/reactive/change-pubsub.js +31 -0
  177. package/dist/reactive/change-pubsub.js.map +1 -0
  178. package/dist/reactive/evaluate-query.d.ts +62 -0
  179. package/dist/reactive/evaluate-query.d.ts.map +1 -0
  180. package/dist/reactive/evaluate-query.js +57 -0
  181. package/dist/reactive/evaluate-query.js.map +1 -0
  182. package/dist/reactive/watch-by-id.d.ts +53 -0
  183. package/dist/reactive/watch-by-id.d.ts.map +1 -0
  184. package/dist/reactive/watch-by-id.js +55 -0
  185. package/dist/reactive/watch-by-id.js.map +1 -0
  186. package/dist/reactive/watch.d.ts +78 -0
  187. package/dist/reactive/watch.d.ts.map +1 -0
  188. package/dist/reactive/watch.js +133 -0
  189. package/dist/reactive/watch.js.map +1 -0
  190. package/dist/serializers/codecs/hjson.d.ts +33 -0
  191. package/dist/serializers/codecs/hjson.d.ts.map +1 -0
  192. package/dist/serializers/codecs/hjson.js +40 -0
  193. package/dist/serializers/codecs/hjson.js.map +1 -0
  194. package/dist/serializers/codecs/json.d.ts +22 -0
  195. package/dist/serializers/codecs/json.d.ts.map +1 -0
  196. package/dist/serializers/codecs/json.js +28 -0
  197. package/dist/serializers/codecs/json.js.map +1 -0
  198. package/dist/serializers/codecs/json5.d.ts +26 -0
  199. package/dist/serializers/codecs/json5.d.ts.map +1 -0
  200. package/dist/serializers/codecs/json5.js +33 -0
  201. package/dist/serializers/codecs/json5.js.map +1 -0
  202. package/dist/serializers/codecs/jsonc.d.ts +29 -0
  203. package/dist/serializers/codecs/jsonc.d.ts.map +1 -0
  204. package/dist/serializers/codecs/jsonc.js +38 -0
  205. package/dist/serializers/codecs/jsonc.js.map +1 -0
  206. package/dist/serializers/codecs/jsonl.d.ts +17 -0
  207. package/dist/serializers/codecs/jsonl.d.ts.map +1 -0
  208. package/dist/serializers/codecs/jsonl.js +31 -0
  209. package/dist/serializers/codecs/jsonl.js.map +1 -0
  210. package/dist/serializers/codecs/prose.d.ts +419 -0
  211. package/dist/serializers/codecs/prose.d.ts.map +1 -0
  212. package/dist/serializers/codecs/prose.js +1060 -0
  213. package/dist/serializers/codecs/prose.js.map +1 -0
  214. package/dist/serializers/codecs/toml.d.ts +23 -0
  215. package/dist/serializers/codecs/toml.d.ts.map +1 -0
  216. package/dist/serializers/codecs/toml.js +66 -0
  217. package/dist/serializers/codecs/toml.js.map +1 -0
  218. package/dist/serializers/codecs/toon.d.ts +20 -0
  219. package/dist/serializers/codecs/toon.d.ts.map +1 -0
  220. package/dist/serializers/codecs/toon.js +33 -0
  221. package/dist/serializers/codecs/toon.js.map +1 -0
  222. package/dist/serializers/codecs/yaml.d.ts +24 -0
  223. package/dist/serializers/codecs/yaml.d.ts.map +1 -0
  224. package/dist/serializers/codecs/yaml.js +31 -0
  225. package/dist/serializers/codecs/yaml.js.map +1 -0
  226. package/dist/serializers/format-codec.d.ts +53 -0
  227. package/dist/serializers/format-codec.d.ts.map +1 -0
  228. package/dist/serializers/format-codec.js +148 -0
  229. package/dist/serializers/format-codec.js.map +1 -0
  230. package/dist/serializers/presets.d.ts +48 -0
  231. package/dist/serializers/presets.d.ts.map +1 -0
  232. package/dist/serializers/presets.js +72 -0
  233. package/dist/serializers/presets.js.map +1 -0
  234. package/dist/serializers/serializer-service.d.ts +11 -0
  235. package/dist/serializers/serializer-service.d.ts.map +1 -0
  236. package/dist/serializers/serializer-service.js +4 -0
  237. package/dist/serializers/serializer-service.js.map +1 -0
  238. package/dist/state/collection-state.d.ts +19 -0
  239. package/dist/state/collection-state.d.ts.map +1 -0
  240. package/dist/state/collection-state.js +15 -0
  241. package/dist/state/collection-state.js.map +1 -0
  242. package/dist/state/state-operations.d.ts +38 -0
  243. package/dist/state/state-operations.d.ts.map +1 -0
  244. package/dist/state/state-operations.js +65 -0
  245. package/dist/state/state-operations.js.map +1 -0
  246. package/dist/storage/in-memory-adapter-layer.d.ts +16 -0
  247. package/dist/storage/in-memory-adapter-layer.d.ts.map +1 -0
  248. package/dist/storage/in-memory-adapter-layer.js +81 -0
  249. package/dist/storage/in-memory-adapter-layer.js.map +1 -0
  250. package/dist/storage/persistence-effect.d.ts +244 -0
  251. package/dist/storage/persistence-effect.d.ts.map +1 -0
  252. package/dist/storage/persistence-effect.js +551 -0
  253. package/dist/storage/persistence-effect.js.map +1 -0
  254. package/dist/storage/storage-service.d.ts +22 -0
  255. package/dist/storage/storage-service.d.ts.map +1 -0
  256. package/dist/storage/storage-service.js +4 -0
  257. package/dist/storage/storage-service.js.map +1 -0
  258. package/dist/storage/transforms.d.ts +183 -0
  259. package/dist/storage/transforms.d.ts.map +1 -0
  260. package/dist/storage/transforms.js +263 -0
  261. package/dist/storage/transforms.js.map +1 -0
  262. package/dist/transactions/transaction.d.ts +87 -0
  263. package/dist/transactions/transaction.d.ts.map +1 -0
  264. package/dist/transactions/transaction.js +240 -0
  265. package/dist/transactions/transaction.js.map +1 -0
  266. package/dist/types/aggregate-types.d.ts +73 -0
  267. package/dist/types/aggregate-types.d.ts.map +1 -0
  268. package/dist/types/aggregate-types.js +14 -0
  269. package/dist/types/aggregate-types.js.map +1 -0
  270. package/dist/types/computed-types.d.ts +71 -0
  271. package/dist/types/computed-types.d.ts.map +1 -0
  272. package/dist/types/computed-types.js +8 -0
  273. package/dist/types/computed-types.js.map +1 -0
  274. package/dist/types/crud-relationship-types.d.ts +180 -0
  275. package/dist/types/crud-relationship-types.d.ts.map +1 -0
  276. package/dist/types/crud-relationship-types.js +17 -0
  277. package/dist/types/crud-relationship-types.js.map +1 -0
  278. package/dist/types/crud-types.d.ts +343 -0
  279. package/dist/types/crud-types.d.ts.map +1 -0
  280. package/dist/types/crud-types.js +43 -0
  281. package/dist/types/crud-types.js.map +1 -0
  282. package/dist/types/cursor-types.d.ts +52 -0
  283. package/dist/types/cursor-types.d.ts.map +1 -0
  284. package/dist/types/cursor-types.js +2 -0
  285. package/dist/types/cursor-types.js.map +1 -0
  286. package/dist/types/database-config-types.d.ts +196 -0
  287. package/dist/types/database-config-types.d.ts.map +1 -0
  288. package/dist/types/database-config-types.js +11 -0
  289. package/dist/types/database-config-types.js.map +1 -0
  290. package/dist/types/hook-types.d.ts +158 -0
  291. package/dist/types/hook-types.d.ts.map +1 -0
  292. package/dist/types/hook-types.js +6 -0
  293. package/dist/types/hook-types.js.map +1 -0
  294. package/dist/types/index-types.d.ts +42 -0
  295. package/dist/types/index-types.d.ts.map +1 -0
  296. package/dist/types/index-types.js +8 -0
  297. package/dist/types/index-types.js.map +1 -0
  298. package/dist/types/operators.d.ts +5 -0
  299. package/dist/types/operators.d.ts.map +1 -0
  300. package/dist/types/operators.js +297 -0
  301. package/dist/types/operators.js.map +1 -0
  302. package/dist/types/query-overloads.d.ts +54 -0
  303. package/dist/types/query-overloads.d.ts.map +1 -0
  304. package/dist/types/query-overloads.js +3 -0
  305. package/dist/types/query-overloads.js.map +1 -0
  306. package/dist/types/reactive-types.d.ts +75 -0
  307. package/dist/types/reactive-types.d.ts.map +1 -0
  308. package/dist/types/reactive-types.js +7 -0
  309. package/dist/types/reactive-types.js.map +1 -0
  310. package/dist/types/schema-types.d.ts +56 -0
  311. package/dist/types/schema-types.d.ts.map +1 -0
  312. package/dist/types/schema-types.js +8 -0
  313. package/dist/types/schema-types.js.map +1 -0
  314. package/dist/types/search-types.d.ts +82 -0
  315. package/dist/types/search-types.d.ts.map +1 -0
  316. package/dist/types/search-types.js +110 -0
  317. package/dist/types/search-types.js.map +1 -0
  318. package/dist/types/types.d.ts +286 -0
  319. package/dist/types/types.d.ts.map +1 -0
  320. package/dist/types/types.js +2 -0
  321. package/dist/types/types.js.map +1 -0
  322. package/dist/utils/id-generator.d.ts +97 -0
  323. package/dist/utils/id-generator.d.ts.map +1 -0
  324. package/dist/utils/id-generator.js +247 -0
  325. package/dist/utils/id-generator.js.map +1 -0
  326. package/dist/utils/nested-path.d.ts +56 -0
  327. package/dist/utils/nested-path.d.ts.map +1 -0
  328. package/dist/utils/nested-path.js +119 -0
  329. package/dist/utils/nested-path.js.map +1 -0
  330. package/dist/utils/path.d.ts +16 -0
  331. package/dist/utils/path.d.ts.map +1 -0
  332. package/dist/utils/path.js +24 -0
  333. package/dist/utils/path.js.map +1 -0
  334. package/dist/validators/foreign-key.d.ts +49 -0
  335. package/dist/validators/foreign-key.d.ts.map +1 -0
  336. package/dist/validators/foreign-key.js +153 -0
  337. package/dist/validators/foreign-key.js.map +1 -0
  338. package/dist/validators/schema-validator.d.ts +19 -0
  339. package/dist/validators/schema-validator.d.ts.map +1 -0
  340. package/dist/validators/schema-validator.js +34 -0
  341. package/dist/validators/schema-validator.js.map +1 -0
  342. 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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"}