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