joist-core 2.3.0-next.97 → 2.3.0-next.99

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 (747) hide show
  1. package/build/BaseEntity.cjs.map +1 -1
  2. package/build/BaseEntity.js.map +1 -1
  3. package/build/Entity.cjs.map +1 -1
  4. package/build/Entity.js.map +1 -1
  5. package/build/EntityManager.cjs +45 -46
  6. package/build/EntityManager.cjs.map +1 -1
  7. package/build/EntityManager.d.cts +7 -7
  8. package/build/EntityManager.d.cts.map +1 -1
  9. package/build/EntityManager.d.mts +7 -7
  10. package/build/EntityManager.d.mts.map +1 -1
  11. package/build/EntityManager.js +27 -28
  12. package/build/EntityManager.js.map +1 -1
  13. package/build/EntityMetadata.cjs +0 -2
  14. package/build/EntityMetadata.cjs.map +1 -1
  15. package/build/EntityMetadata.d.cts +3 -3
  16. package/build/EntityMetadata.d.mts +3 -3
  17. package/build/EntityMetadata.js +0 -2
  18. package/build/EntityMetadata.js.map +1 -1
  19. package/build/IndexManager.cjs +1 -1
  20. package/build/IndexManager.cjs.map +1 -1
  21. package/build/IndexManager.js +1 -1
  22. package/build/IndexManager.js.map +1 -1
  23. package/build/InstanceData.cjs.map +1 -1
  24. package/build/InstanceData.js.map +1 -1
  25. package/build/PluginManager.cjs +0 -1
  26. package/build/PluginManager.cjs.map +1 -1
  27. package/build/PluginManager.d.cts +1 -1
  28. package/build/PluginManager.d.mts +1 -1
  29. package/build/PluginManager.js +0 -1
  30. package/build/PluginManager.js.map +1 -1
  31. package/build/batchloaders/enumCollectionBatchLoader.cjs +1 -1
  32. package/build/batchloaders/enumCollectionBatchLoader.cjs.map +1 -1
  33. package/build/batchloaders/enumCollectionBatchLoader.d.cts +1 -1
  34. package/build/batchloaders/enumCollectionBatchLoader.d.mts +1 -1
  35. package/build/batchloaders/enumCollectionBatchLoader.js +1 -1
  36. package/build/batchloaders/enumCollectionBatchLoader.js.map +1 -1
  37. package/build/batchloaders/loadBatchLoader.cjs +3 -4
  38. package/build/batchloaders/loadBatchLoader.cjs.map +1 -1
  39. package/build/batchloaders/loadBatchLoader.d.cts +1 -1
  40. package/build/batchloaders/loadBatchLoader.d.mts +1 -1
  41. package/build/batchloaders/loadBatchLoader.js +2 -3
  42. package/build/batchloaders/loadBatchLoader.js.map +1 -1
  43. package/build/batchloaders/manyToManyBatchLoader.cjs +1 -1
  44. package/build/batchloaders/manyToManyBatchLoader.cjs.map +1 -1
  45. package/build/batchloaders/manyToManyBatchLoader.d.cts +1 -1
  46. package/build/batchloaders/manyToManyBatchLoader.d.mts +1 -1
  47. package/build/batchloaders/manyToManyBatchLoader.js +1 -1
  48. package/build/batchloaders/manyToManyBatchLoader.js.map +1 -1
  49. package/build/batchloaders/oneToManyBatchLoader.cjs +1 -1
  50. package/build/batchloaders/oneToManyBatchLoader.cjs.map +1 -1
  51. package/build/batchloaders/oneToManyBatchLoader.js +1 -1
  52. package/build/batchloaders/oneToManyBatchLoader.js.map +1 -1
  53. package/build/batchloaders/oneToOneBatchLoader.cjs +1 -1
  54. package/build/batchloaders/oneToOneBatchLoader.cjs.map +1 -1
  55. package/build/batchloaders/oneToOneBatchLoader.js +1 -1
  56. package/build/batchloaders/oneToOneBatchLoader.js.map +1 -1
  57. package/build/batchloaders/populateBatchLoader.cjs +11 -12
  58. package/build/batchloaders/populateBatchLoader.cjs.map +1 -1
  59. package/build/batchloaders/populateBatchLoader.d.cts +1 -1
  60. package/build/batchloaders/populateBatchLoader.d.mts +1 -1
  61. package/build/batchloaders/populateBatchLoader.js +7 -8
  62. package/build/batchloaders/populateBatchLoader.js.map +1 -1
  63. package/build/batchloaders/recursiveChildrenBatchLoader.cjs +2 -2
  64. package/build/batchloaders/recursiveChildrenBatchLoader.cjs.map +1 -1
  65. package/build/batchloaders/recursiveChildrenBatchLoader.js +2 -2
  66. package/build/batchloaders/recursiveChildrenBatchLoader.js.map +1 -1
  67. package/build/batchloaders/recursiveM2mBatchLoader.cjs +2 -2
  68. package/build/batchloaders/recursiveM2mBatchLoader.cjs.map +1 -1
  69. package/build/batchloaders/recursiveM2mBatchLoader.js +2 -2
  70. package/build/batchloaders/recursiveM2mBatchLoader.js.map +1 -1
  71. package/build/batchloaders/recursiveParentsBatchLoader.cjs +2 -2
  72. package/build/batchloaders/recursiveParentsBatchLoader.cjs.map +1 -1
  73. package/build/batchloaders/recursiveParentsBatchLoader.js +2 -2
  74. package/build/batchloaders/recursiveParentsBatchLoader.js.map +1 -1
  75. package/build/changes.cjs +2 -3
  76. package/build/changes.cjs.map +1 -1
  77. package/build/changes.js +2 -3
  78. package/build/changes.js.map +1 -1
  79. package/build/config.cjs +3 -3
  80. package/build/config.cjs.map +1 -1
  81. package/build/config.d.cts +2 -2
  82. package/build/config.d.mts +2 -2
  83. package/build/config.js +1 -1
  84. package/build/config.js.map +1 -1
  85. package/build/configure.cjs +10 -10
  86. package/build/configure.cjs.map +1 -1
  87. package/build/configure.js +5 -5
  88. package/build/configure.js.map +1 -1
  89. package/build/dataloaders/fastWhereFilterHash.cjs +8 -8
  90. package/build/dataloaders/fastWhereFilterHash.cjs.map +1 -1
  91. package/build/dataloaders/fastWhereFilterHash.d.cts.map +1 -1
  92. package/build/dataloaders/fastWhereFilterHash.d.mts.map +1 -1
  93. package/build/dataloaders/fastWhereFilterHash.js +3 -3
  94. package/build/dataloaders/fastWhereFilterHash.js.map +1 -1
  95. package/build/dataloaders/findByUniqueDataLoader.cjs.map +1 -1
  96. package/build/dataloaders/findByUniqueDataLoader.d.cts.map +1 -1
  97. package/build/dataloaders/findByUniqueDataLoader.d.mts.map +1 -1
  98. package/build/dataloaders/findByUniqueDataLoader.js.map +1 -1
  99. package/build/dataloaders/findCountDataLoader.cjs +2 -2
  100. package/build/dataloaders/findCountDataLoader.cjs.map +1 -1
  101. package/build/dataloaders/findCountDataLoader.js +1 -1
  102. package/build/dataloaders/findCountDataLoader.js.map +1 -1
  103. package/build/dataloaders/findDataLoader.cjs +6 -6
  104. package/build/dataloaders/findDataLoader.cjs.map +1 -1
  105. package/build/dataloaders/findDataLoader.d.cts +1 -1
  106. package/build/dataloaders/findDataLoader.d.mts +1 -1
  107. package/build/dataloaders/findDataLoader.js +3 -3
  108. package/build/dataloaders/findDataLoader.js.map +1 -1
  109. package/build/dataloaders/findIdsDataLoader.cjs +3 -3
  110. package/build/dataloaders/findIdsDataLoader.cjs.map +1 -1
  111. package/build/dataloaders/findIdsDataLoader.js +2 -2
  112. package/build/dataloaders/findIdsDataLoader.js.map +1 -1
  113. package/build/dataloaders/findOrCreateDataLoader.cjs +1 -1
  114. package/build/dataloaders/findOrCreateDataLoader.cjs.map +1 -1
  115. package/build/dataloaders/findOrCreateDataLoader.d.cts.map +1 -1
  116. package/build/dataloaders/findOrCreateDataLoader.d.mts.map +1 -1
  117. package/build/dataloaders/findOrCreateDataLoader.js +1 -1
  118. package/build/dataloaders/findOrCreateDataLoader.js.map +1 -1
  119. package/build/dataloaders/findPaginatedDataLoader.cjs +6 -6
  120. package/build/dataloaders/findPaginatedDataLoader.cjs.map +1 -1
  121. package/build/dataloaders/findPaginatedDataLoader.d.cts +1 -1
  122. package/build/dataloaders/findPaginatedDataLoader.d.mts +1 -1
  123. package/build/dataloaders/findPaginatedDataLoader.js +3 -3
  124. package/build/dataloaders/findPaginatedDataLoader.js.map +1 -1
  125. package/build/dataloaders/lensDataLoader.cjs +3 -3
  126. package/build/dataloaders/lensDataLoader.cjs.map +1 -1
  127. package/build/dataloaders/lensDataLoader.d.cts.map +1 -1
  128. package/build/dataloaders/lensDataLoader.d.mts.map +1 -1
  129. package/build/dataloaders/lensDataLoader.js +2 -2
  130. package/build/dataloaders/lensDataLoader.js.map +1 -1
  131. package/build/dataloaders/manyToManyFindDataLoader.cjs +1 -1
  132. package/build/dataloaders/manyToManyFindDataLoader.cjs.map +1 -1
  133. package/build/dataloaders/manyToManyFindDataLoader.d.cts.map +1 -1
  134. package/build/dataloaders/manyToManyFindDataLoader.d.mts.map +1 -1
  135. package/build/dataloaders/manyToManyFindDataLoader.js +1 -1
  136. package/build/dataloaders/manyToManyFindDataLoader.js.map +1 -1
  137. package/build/dataloaders/oneToManyFindDataLoader.cjs +1 -1
  138. package/build/dataloaders/oneToManyFindDataLoader.cjs.map +1 -1
  139. package/build/dataloaders/oneToManyFindDataLoader.d.cts.map +1 -1
  140. package/build/dataloaders/oneToManyFindDataLoader.d.mts.map +1 -1
  141. package/build/dataloaders/oneToManyFindDataLoader.js +1 -1
  142. package/build/dataloaders/oneToManyFindDataLoader.js.map +1 -1
  143. package/build/defaults.cjs +5 -5
  144. package/build/defaults.cjs.map +1 -1
  145. package/build/defaults.d.cts +1 -1
  146. package/build/defaults.d.cts.map +1 -1
  147. package/build/defaults.d.mts +1 -1
  148. package/build/defaults.d.mts.map +1 -1
  149. package/build/defaults.js +4 -4
  150. package/build/defaults.js.map +1 -1
  151. package/build/drivers/Driver.cjs +0 -1
  152. package/build/drivers/Driver.d.cts +1 -1
  153. package/build/drivers/Driver.d.mts +1 -1
  154. package/build/drivers/Driver.js +0 -1
  155. package/build/drivers/EntityWriter.cjs +6 -7
  156. package/build/drivers/EntityWriter.cjs.map +1 -1
  157. package/build/drivers/EntityWriter.d.cts +1 -1
  158. package/build/drivers/EntityWriter.d.mts +1 -1
  159. package/build/drivers/EntityWriter.js +2 -3
  160. package/build/drivers/EntityWriter.js.map +1 -1
  161. package/build/drivers/IdAssigner.cjs +0 -1
  162. package/build/drivers/IdAssigner.cjs.map +1 -1
  163. package/build/drivers/IdAssigner.d.cts +1 -1
  164. package/build/drivers/IdAssigner.d.mts +1 -1
  165. package/build/drivers/IdAssigner.js +0 -1
  166. package/build/drivers/IdAssigner.js.map +1 -1
  167. package/build/drivers/driverApi.cjs +19 -0
  168. package/build/drivers/driverApi.cjs.map +1 -0
  169. package/build/drivers/driverApi.d.cts +22 -0
  170. package/build/drivers/driverApi.d.cts.map +1 -0
  171. package/build/drivers/driverApi.d.mts +22 -0
  172. package/build/drivers/driverApi.d.mts.map +1 -0
  173. package/build/drivers/driverApi.js +18 -0
  174. package/build/drivers/driverApi.js.map +1 -0
  175. package/build/fields.cjs +3 -3
  176. package/build/fields.cjs.map +1 -1
  177. package/build/fields.js +2 -2
  178. package/build/fields.js.map +1 -1
  179. package/build/{FlushLock.cjs → flush/FlushLock.cjs} +1 -1
  180. package/build/flush/FlushLock.cjs.map +1 -0
  181. package/build/{FlushLock.d.cts → flush/FlushLock.d.cts} +1 -1
  182. package/build/flush/FlushLock.d.cts.map +1 -0
  183. package/build/{FlushLock.d.mts → flush/FlushLock.d.mts} +1 -1
  184. package/build/flush/FlushLock.d.mts.map +1 -0
  185. package/build/{FlushLock.js → flush/FlushLock.js} +1 -1
  186. package/build/flush/FlushLock.js.map +1 -0
  187. package/build/{JoinRows.cjs → flush/JoinRows.cjs} +5 -8
  188. package/build/flush/JoinRows.cjs.map +1 -0
  189. package/build/{JoinRows.d.cts → flush/JoinRows.d.cts} +5 -5
  190. package/build/flush/JoinRows.d.cts.map +1 -0
  191. package/build/{JoinRows.d.mts → flush/JoinRows.d.mts} +5 -5
  192. package/build/flush/JoinRows.d.mts.map +1 -0
  193. package/build/{JoinRows.js → flush/JoinRows.js} +5 -8
  194. package/build/flush/JoinRows.js.map +1 -0
  195. package/build/{PendingChanges.cjs → flush/PendingChanges.cjs} +0 -1
  196. package/build/{PendingChanges.d.cts → flush/PendingChanges.d.cts} +2 -2
  197. package/build/flush/PendingChanges.d.cts.map +1 -0
  198. package/build/{PendingChanges.d.mts → flush/PendingChanges.d.mts} +2 -2
  199. package/build/flush/PendingChanges.d.mts.map +1 -0
  200. package/build/flush/PendingChanges.js +1 -0
  201. package/build/{Todo.cjs → flush/Todo.cjs} +4 -6
  202. package/build/flush/Todo.cjs.map +1 -0
  203. package/build/{Todo.d.cts → flush/Todo.d.cts} +3 -3
  204. package/build/flush/Todo.d.cts.map +1 -0
  205. package/build/{Todo.d.mts → flush/Todo.d.mts} +3 -3
  206. package/build/flush/Todo.d.mts.map +1 -0
  207. package/build/{Todo.js → flush/Todo.js} +4 -6
  208. package/build/flush/Todo.js.map +1 -0
  209. package/build/getProperties.cjs.map +1 -1
  210. package/build/getProperties.js.map +1 -1
  211. package/build/index.cjs +100 -100
  212. package/build/index.cjs.map +1 -1
  213. package/build/index.d.cts +15 -15
  214. package/build/index.d.mts +15 -15
  215. package/build/index.js +42 -42
  216. package/build/index.js.map +1 -1
  217. package/build/json.cjs +4 -4
  218. package/build/json.cjs.map +1 -1
  219. package/build/json.js +3 -3
  220. package/build/json.js.map +1 -1
  221. package/build/keys.cjs +1 -1
  222. package/build/keys.cjs.map +1 -1
  223. package/build/keys.js +1 -1
  224. package/build/keys.js.map +1 -1
  225. package/build/{HintTree.cjs → loading/HintTree.cjs} +2 -5
  226. package/build/loading/HintTree.cjs.map +1 -0
  227. package/build/{HintTree.d.cts → loading/HintTree.d.cts} +3 -3
  228. package/build/loading/HintTree.d.cts.map +1 -0
  229. package/build/{HintTree.d.mts → loading/HintTree.d.mts} +3 -3
  230. package/build/loading/HintTree.d.mts.map +1 -0
  231. package/build/{HintTree.js → loading/HintTree.js} +2 -5
  232. package/build/loading/HintTree.js.map +1 -0
  233. package/build/{IsLoadedCache.cjs → loading/IsLoadedCache.cjs} +2 -3
  234. package/build/loading/IsLoadedCache.cjs.map +1 -0
  235. package/build/{IsLoadedCache.d.cts → loading/IsLoadedCache.d.cts} +2 -2
  236. package/build/loading/IsLoadedCache.d.cts.map +1 -0
  237. package/build/{IsLoadedCache.d.mts → loading/IsLoadedCache.d.mts} +2 -2
  238. package/build/loading/IsLoadedCache.d.mts.map +1 -0
  239. package/build/{IsLoadedCache.js → loading/IsLoadedCache.js} +2 -3
  240. package/build/{IsLoadedCache.cjs.map → loading/IsLoadedCache.js.map} +1 -1
  241. package/build/{loadHints.cjs → loading/loadHints.cjs} +6 -11
  242. package/build/loading/loadHints.cjs.map +1 -0
  243. package/build/{loadHints.d.cts → loading/loadHints.d.cts} +14 -14
  244. package/build/loading/loadHints.d.cts.map +1 -0
  245. package/build/{loadHints.d.mts → loading/loadHints.d.mts} +14 -14
  246. package/build/loading/loadHints.d.mts.map +1 -0
  247. package/build/{loadHints.js → loading/loadHints.js} +3 -8
  248. package/build/loading/loadHints.js.map +1 -0
  249. package/build/{loadLens.cjs → loading/loadLens.cjs} +8 -9
  250. package/build/loading/loadLens.cjs.map +1 -0
  251. package/build/{loadLens.d.cts → loading/loadLens.d.cts} +3 -3
  252. package/build/loading/loadLens.d.cts.map +1 -0
  253. package/build/{loadLens.d.mts → loading/loadLens.d.mts} +3 -3
  254. package/build/loading/loadLens.d.mts.map +1 -0
  255. package/build/{loadLens.js → loading/loadLens.js} +8 -9
  256. package/build/loading/loadLens.js.map +1 -0
  257. package/build/{withLoaded.cjs → loading/withLoaded.cjs} +12 -13
  258. package/build/loading/withLoaded.cjs.map +1 -0
  259. package/build/{withLoaded.d.cts → loading/withLoaded.d.cts} +9 -9
  260. package/build/loading/withLoaded.d.cts.map +1 -0
  261. package/build/{withLoaded.d.mts → loading/withLoaded.d.mts} +9 -9
  262. package/build/loading/withLoaded.d.mts.map +1 -0
  263. package/build/{withLoaded.js → loading/withLoaded.js} +10 -11
  264. package/build/loading/withLoaded.js.map +1 -0
  265. package/build/logging/FactoryLogger.cjs.map +1 -1
  266. package/build/logging/FactoryLogger.d.cts.map +1 -1
  267. package/build/logging/FactoryLogger.d.mts.map +1 -1
  268. package/build/logging/FactoryLogger.js.map +1 -1
  269. package/build/logging/FieldLogger.cjs.map +1 -1
  270. package/build/logging/FieldLogger.d.cts.map +1 -1
  271. package/build/logging/FieldLogger.d.mts.map +1 -1
  272. package/build/logging/FieldLogger.js.map +1 -1
  273. package/build/logging/ReactionLogger.cjs +0 -2
  274. package/build/logging/ReactionLogger.cjs.map +1 -1
  275. package/build/logging/ReactionLogger.d.cts +2 -2
  276. package/build/logging/ReactionLogger.d.cts.map +1 -1
  277. package/build/logging/ReactionLogger.d.mts +2 -2
  278. package/build/logging/ReactionLogger.d.mts.map +1 -1
  279. package/build/logging/ReactionLogger.js +0 -2
  280. package/build/logging/ReactionLogger.js.map +1 -1
  281. package/build/newEntity.cjs.map +1 -1
  282. package/build/newEntity.js.map +1 -1
  283. package/build/newTestInstance.cjs +3 -3
  284. package/build/newTestInstance.cjs.map +1 -1
  285. package/build/newTestInstance.d.cts +1 -1
  286. package/build/newTestInstance.d.cts.map +1 -1
  287. package/build/newTestInstance.d.mts +1 -1
  288. package/build/newTestInstance.d.mts.map +1 -1
  289. package/build/newTestInstance.js +2 -2
  290. package/build/newTestInstance.js.map +1 -1
  291. package/build/normalizeHints.cjs +0 -2
  292. package/build/normalizeHints.cjs.map +1 -1
  293. package/build/normalizeHints.d.cts +2 -2
  294. package/build/normalizeHints.d.mts +2 -2
  295. package/build/normalizeHints.js +0 -2
  296. package/build/normalizeHints.js.map +1 -1
  297. package/build/nowUTC.cjs +2 -2
  298. package/build/nowUTC.cjs.map +1 -1
  299. package/build/nowUTC.d.cts +1 -1
  300. package/build/nowUTC.d.mts +1 -1
  301. package/build/nowUTC.js +1 -1
  302. package/build/nowUTC.js.map +1 -1
  303. package/build/plugins/ImmutableEntitiesPlugin.cjs.map +1 -1
  304. package/build/plugins/ImmutableEntitiesPlugin.js.map +1 -1
  305. package/build/plugins/PreloadPlugin.cjs +0 -2
  306. package/build/plugins/PreloadPlugin.d.cts +2 -2
  307. package/build/plugins/PreloadPlugin.d.mts +2 -2
  308. package/build/plugins/PreloadPlugin.js +0 -2
  309. package/build/preloading/JsonAggregatePreloader.cjs +1 -4
  310. package/build/preloading/JsonAggregatePreloader.cjs.map +1 -1
  311. package/build/preloading/JsonAggregatePreloader.d.cts +2 -2
  312. package/build/preloading/JsonAggregatePreloader.d.cts.map +1 -1
  313. package/build/preloading/JsonAggregatePreloader.d.mts +2 -2
  314. package/build/preloading/JsonAggregatePreloader.d.mts.map +1 -1
  315. package/build/preloading/JsonAggregatePreloader.js +1 -4
  316. package/build/preloading/JsonAggregatePreloader.js.map +1 -1
  317. package/build/preloading/canPreload.cjs.map +1 -1
  318. package/build/preloading/canPreload.js.map +1 -1
  319. package/build/preloading/partitionHint.cjs +2 -3
  320. package/build/preloading/partitionHint.cjs.map +1 -1
  321. package/build/preloading/partitionHint.d.cts +1 -1
  322. package/build/preloading/partitionHint.d.mts +1 -1
  323. package/build/preloading/partitionHint.js +2 -3
  324. package/build/preloading/partitionHint.js.map +1 -1
  325. package/build/queries/ConditionBuilder.cjs.map +1 -1
  326. package/build/queries/ConditionBuilder.d.cts +1 -1
  327. package/build/queries/ConditionBuilder.d.mts +1 -1
  328. package/build/queries/ConditionBuilder.js.map +1 -1
  329. package/build/queries/conditions.cjs.map +1 -1
  330. package/build/queries/conditions.js.map +1 -1
  331. package/build/queries/entityQueryUtils.cjs.map +1 -1
  332. package/build/queries/entityQueryUtils.js.map +1 -1
  333. package/build/queries/find/Aliases.cjs +1 -1
  334. package/build/queries/find/Aliases.cjs.map +1 -1
  335. package/build/queries/find/Aliases.d.cts.map +1 -1
  336. package/build/queries/find/Aliases.d.mts.map +1 -1
  337. package/build/queries/find/Aliases.js +1 -1
  338. package/build/queries/find/Aliases.js.map +1 -1
  339. package/build/queries/find/DeferredAlias.cjs.map +1 -1
  340. package/build/queries/find/DeferredAlias.js.map +1 -1
  341. package/build/queries/find/EntityFilter.cjs.map +1 -1
  342. package/build/queries/find/EntityFilter.js.map +1 -1
  343. package/build/queries/find/EntityGraphQLFilter.cjs.map +1 -1
  344. package/build/queries/find/EntityGraphQLFilter.js.map +1 -1
  345. package/build/queries/find/QueryParser.cjs +2 -2
  346. package/build/queries/find/QueryParser.cjs.map +1 -1
  347. package/build/queries/find/QueryParser.collectionJoins.cjs.map +1 -1
  348. package/build/queries/find/QueryParser.collectionJoins.js.map +1 -1
  349. package/build/queries/find/QueryParser.d.cts.map +1 -1
  350. package/build/queries/find/QueryParser.d.mts.map +1 -1
  351. package/build/queries/find/QueryParser.js +2 -2
  352. package/build/queries/find/QueryParser.js.map +1 -1
  353. package/build/queries/find/QueryParser.pruning.cjs.map +1 -1
  354. package/build/queries/find/QueryParser.pruning.js.map +1 -1
  355. package/build/queries/find/QueryVisitor.cjs.map +1 -1
  356. package/build/queries/find/QueryVisitor.js.map +1 -1
  357. package/build/queries/find/buildFindQuery.cjs.map +1 -1
  358. package/build/queries/find/buildFindQuery.js.map +1 -1
  359. package/build/queries/find/scopes.cjs.map +1 -1
  360. package/build/queries/find/scopes.d.cts +1 -1
  361. package/build/queries/find/scopes.d.mts +1 -1
  362. package/build/queries/find/scopes.js.map +1 -1
  363. package/build/queries/parsedConditions.cjs.map +1 -1
  364. package/build/queries/parsedConditions.js.map +1 -1
  365. package/build/queries/renderConditions.cjs.map +1 -1
  366. package/build/queries/renderConditions.js.map +1 -1
  367. package/build/queries/skipCondition.cjs.map +1 -1
  368. package/build/queries/skipCondition.js.map +1 -1
  369. package/build/queries/sql/AliasAssigner.cjs.map +1 -1
  370. package/build/queries/sql/AliasAssigner.js.map +1 -1
  371. package/build/queries/sql/Expr.cjs +2 -2
  372. package/build/queries/sql/Expr.cjs.map +1 -1
  373. package/build/queries/sql/Expr.d.cts +1 -1
  374. package/build/queries/sql/Expr.d.mts +1 -1
  375. package/build/queries/sql/Expr.js +1 -1
  376. package/build/queries/sql/Expr.js.map +1 -1
  377. package/build/queries/sql/Tables.cjs +1 -1
  378. package/build/queries/sql/Tables.cjs.map +1 -1
  379. package/build/queries/sql/Tables.d.cts.map +1 -1
  380. package/build/queries/sql/Tables.d.mts.map +1 -1
  381. package/build/queries/sql/Tables.js +1 -1
  382. package/build/queries/sql/Tables.js.map +1 -1
  383. package/build/queries/sql/execute.cjs +1 -1
  384. package/build/queries/sql/execute.cjs.map +1 -1
  385. package/build/queries/sql/execute.js +1 -1
  386. package/build/queries/sql/execute.js.map +1 -1
  387. package/build/queries/sql/expressions/arrayAgg.cjs.map +1 -1
  388. package/build/queries/sql/expressions/arrayAgg.js.map +1 -1
  389. package/build/queries/sql/expressions/case.cjs.map +1 -1
  390. package/build/queries/sql/expressions/case.js.map +1 -1
  391. package/build/queries/sql/expressions/coalesce.cjs.map +1 -1
  392. package/build/queries/sql/expressions/coalesce.js.map +1 -1
  393. package/build/queries/sql/expressions/codecs.cjs +2 -2
  394. package/build/queries/sql/expressions/codecs.cjs.map +1 -1
  395. package/build/queries/sql/expressions/codecs.js +1 -1
  396. package/build/queries/sql/expressions/codecs.js.map +1 -1
  397. package/build/queries/sql/expressions/expression.cjs.map +1 -1
  398. package/build/queries/sql/expressions/expression.d.cts.map +1 -1
  399. package/build/queries/sql/expressions/expression.d.mts.map +1 -1
  400. package/build/queries/sql/expressions/expression.js.map +1 -1
  401. package/build/queries/sql/expressions/greatest.cjs.map +1 -1
  402. package/build/queries/sql/expressions/greatest.js.map +1 -1
  403. package/build/queries/sql/expressions/least.cjs.map +1 -1
  404. package/build/queries/sql/expressions/least.js.map +1 -1
  405. package/build/queries/sql/expressions/nullIf.cjs.map +1 -1
  406. package/build/queries/sql/expressions/nullIf.js.map +1 -1
  407. package/build/queries/sql/expressions/parseExpression.cjs.map +1 -1
  408. package/build/queries/sql/expressions/parseExpression.js.map +1 -1
  409. package/build/queries/sql/expressions/types.d.cts.map +1 -1
  410. package/build/queries/sql/expressions/types.d.mts.map +1 -1
  411. package/build/queries/sql/query.cjs +1 -1
  412. package/build/queries/sql/query.cjs.map +1 -1
  413. package/build/queries/sql/query.d.cts +1 -1
  414. package/build/queries/sql/query.d.mts +1 -1
  415. package/build/queries/sql/query.js +1 -1
  416. package/build/queries/sql/query.js.map +1 -1
  417. package/build/{unnest.cjs → queries/unnest.cjs} +1 -2
  418. package/build/queries/unnest.cjs.map +1 -0
  419. package/build/{unnest.d.cts → queries/unnest.d.cts} +3 -3
  420. package/build/queries/unnest.d.cts.map +1 -0
  421. package/build/{unnest.d.mts → queries/unnest.d.mts} +3 -3
  422. package/build/queries/unnest.d.mts.map +1 -0
  423. package/build/{unnest.js → queries/unnest.js} +1 -2
  424. package/build/queries/unnest.js.map +1 -0
  425. package/build/queries/valueFilters.cjs.map +1 -1
  426. package/build/queries/valueFilters.d.cts +1 -1
  427. package/build/queries/valueFilters.d.cts.map +1 -1
  428. package/build/queries/valueFilters.d.mts +1 -1
  429. package/build/queries/valueFilters.d.mts.map +1 -1
  430. package/build/queries/valueFilters.js.map +1 -1
  431. package/build/{ReactionsManager.cjs → reactivity/ReactionsManager.cjs} +8 -10
  432. package/build/reactivity/ReactionsManager.cjs.map +1 -0
  433. package/build/{ReactionsManager.d.cts → reactivity/ReactionsManager.d.cts} +5 -6
  434. package/build/reactivity/ReactionsManager.d.cts.map +1 -0
  435. package/build/{ReactionsManager.d.mts → reactivity/ReactionsManager.d.mts} +5 -6
  436. package/build/reactivity/ReactionsManager.d.mts.map +1 -0
  437. package/build/{ReactionsManager.js → reactivity/ReactionsManager.js} +6 -8
  438. package/build/reactivity/ReactionsManager.js.map +1 -0
  439. package/build/{reactiveHints.cjs → reactivity/reactiveHints.cjs} +12 -16
  440. package/build/reactivity/reactiveHints.cjs.map +1 -0
  441. package/build/{reactiveHints.d.cts → reactivity/reactiveHints.d.cts} +17 -17
  442. package/build/reactivity/reactiveHints.d.cts.map +1 -0
  443. package/build/{reactiveHints.d.mts → reactivity/reactiveHints.d.mts} +17 -17
  444. package/build/reactivity/reactiveHints.d.mts.map +1 -0
  445. package/build/{reactiveHints.js → reactivity/reactiveHints.js} +12 -16
  446. package/build/reactivity/reactiveHints.js.map +1 -0
  447. package/build/relations/AbstractRelationImpl.cjs.map +1 -1
  448. package/build/relations/AbstractRelationImpl.js.map +1 -1
  449. package/build/relations/AsyncProperty.cjs.map +1 -1
  450. package/build/relations/AsyncProperty.js.map +1 -1
  451. package/build/relations/AsyncReactiveField.cjs +6 -6
  452. package/build/relations/AsyncReactiveField.cjs.map +1 -1
  453. package/build/relations/AsyncReactiveField.d.cts +1 -1
  454. package/build/relations/AsyncReactiveField.d.mts +1 -1
  455. package/build/relations/AsyncReactiveField.js +4 -4
  456. package/build/relations/AsyncReactiveField.js.map +1 -1
  457. package/build/relations/Collection.cjs +1 -1
  458. package/build/relations/Collection.cjs.map +1 -1
  459. package/build/relations/Collection.js +1 -1
  460. package/build/relations/Collection.js.map +1 -1
  461. package/build/relations/CustomCollection.cjs.map +1 -1
  462. package/build/relations/CustomCollection.d.cts +1 -1
  463. package/build/relations/CustomCollection.d.mts +1 -1
  464. package/build/relations/CustomCollection.js.map +1 -1
  465. package/build/relations/CustomReference.cjs +1 -1
  466. package/build/relations/CustomReference.cjs.map +1 -1
  467. package/build/relations/CustomReference.d.cts +1 -1
  468. package/build/relations/CustomReference.d.mts +1 -1
  469. package/build/relations/CustomReference.js +1 -1
  470. package/build/relations/CustomReference.js.map +1 -1
  471. package/build/relations/EnumCollection.cjs.map +1 -1
  472. package/build/relations/EnumCollection.d.cts +1 -1
  473. package/build/relations/EnumCollection.d.mts +1 -1
  474. package/build/relations/EnumCollection.js.map +1 -1
  475. package/build/relations/LazyField.cjs +4 -4
  476. package/build/relations/LazyField.cjs.map +1 -1
  477. package/build/relations/LazyField.js +4 -4
  478. package/build/relations/LazyField.js.map +1 -1
  479. package/build/relations/ManyToManyCollection.cjs +3 -3
  480. package/build/relations/ManyToManyCollection.cjs.map +1 -1
  481. package/build/relations/ManyToManyCollection.js +3 -3
  482. package/build/relations/ManyToManyCollection.js.map +1 -1
  483. package/build/relations/ManyToManyLargeCollection.cjs +3 -3
  484. package/build/relations/ManyToManyLargeCollection.cjs.map +1 -1
  485. package/build/relations/ManyToManyLargeCollection.js +3 -3
  486. package/build/relations/ManyToManyLargeCollection.js.map +1 -1
  487. package/build/relations/ManyToOneReference.cjs +4 -4
  488. package/build/relations/ManyToOneReference.cjs.map +1 -1
  489. package/build/relations/ManyToOneReference.js +4 -4
  490. package/build/relations/ManyToOneReference.js.map +1 -1
  491. package/build/relations/OneToManyCollection.cjs +1 -2
  492. package/build/relations/OneToManyCollection.cjs.map +1 -1
  493. package/build/relations/OneToManyCollection.d.cts +1 -1
  494. package/build/relations/OneToManyCollection.d.mts +1 -1
  495. package/build/relations/OneToManyCollection.js +1 -2
  496. package/build/relations/OneToManyCollection.js.map +1 -1
  497. package/build/relations/OneToManyLargeCollection.cjs +1 -1
  498. package/build/relations/OneToManyLargeCollection.cjs.map +1 -1
  499. package/build/relations/OneToManyLargeCollection.js +1 -1
  500. package/build/relations/OneToManyLargeCollection.js.map +1 -1
  501. package/build/relations/OneToOneReference.cjs +5 -5
  502. package/build/relations/OneToOneReference.cjs.map +1 -1
  503. package/build/relations/OneToOneReference.js +5 -5
  504. package/build/relations/OneToOneReference.js.map +1 -1
  505. package/build/relations/PolymorphicReference.cjs +3 -3
  506. package/build/relations/PolymorphicReference.cjs.map +1 -1
  507. package/build/relations/PolymorphicReference.js +3 -3
  508. package/build/relations/PolymorphicReference.js.map +1 -1
  509. package/build/relations/ReactiveField.cjs +5 -6
  510. package/build/relations/ReactiveField.cjs.map +1 -1
  511. package/build/relations/ReactiveField.d.cts +2 -2
  512. package/build/relations/ReactiveField.d.mts +2 -2
  513. package/build/relations/ReactiveField.js +3 -4
  514. package/build/relations/ReactiveField.js.map +1 -1
  515. package/build/relations/ReactiveGetter.cjs +0 -1
  516. package/build/relations/ReactiveGetter.cjs.map +1 -1
  517. package/build/relations/ReactiveGetter.d.cts +1 -1
  518. package/build/relations/ReactiveGetter.d.mts +1 -1
  519. package/build/relations/ReactiveGetter.js +0 -1
  520. package/build/relations/ReactiveGetter.js.map +1 -1
  521. package/build/relations/ReactiveManyToMany.cjs +5 -6
  522. package/build/relations/ReactiveManyToMany.cjs.map +1 -1
  523. package/build/relations/ReactiveManyToMany.d.cts +2 -2
  524. package/build/relations/ReactiveManyToMany.d.cts.map +1 -1
  525. package/build/relations/ReactiveManyToMany.d.mts +2 -2
  526. package/build/relations/ReactiveManyToMany.d.mts.map +1 -1
  527. package/build/relations/ReactiveManyToMany.js +3 -4
  528. package/build/relations/ReactiveManyToMany.js.map +1 -1
  529. package/build/relations/ReactiveManyToManyOtherSide.cjs +1 -3
  530. package/build/relations/ReactiveManyToManyOtherSide.cjs.map +1 -1
  531. package/build/relations/ReactiveManyToManyOtherSide.d.cts +2 -2
  532. package/build/relations/ReactiveManyToManyOtherSide.d.mts +2 -2
  533. package/build/relations/ReactiveManyToManyOtherSide.js +1 -3
  534. package/build/relations/ReactiveManyToManyOtherSide.js.map +1 -1
  535. package/build/relations/ReactiveReference.cjs +8 -9
  536. package/build/relations/ReactiveReference.cjs.map +1 -1
  537. package/build/relations/ReactiveReference.d.cts +2 -2
  538. package/build/relations/ReactiveReference.d.cts.map +1 -1
  539. package/build/relations/ReactiveReference.d.mts +2 -2
  540. package/build/relations/ReactiveReference.d.mts.map +1 -1
  541. package/build/relations/ReactiveReference.js +6 -7
  542. package/build/relations/ReactiveReference.js.map +1 -1
  543. package/build/relations/ReadOnlyCollection.cjs.map +1 -1
  544. package/build/relations/ReadOnlyCollection.js.map +1 -1
  545. package/build/relations/RecursiveCollection.cjs +3 -4
  546. package/build/relations/RecursiveCollection.cjs.map +1 -1
  547. package/build/relations/RecursiveCollection.d.cts +1 -1
  548. package/build/relations/RecursiveCollection.d.mts +1 -1
  549. package/build/relations/RecursiveCollection.js +3 -4
  550. package/build/relations/RecursiveCollection.js.map +1 -1
  551. package/build/relations/RecursiveCycleError.cjs.map +1 -1
  552. package/build/relations/RecursiveCycleError.js.map +1 -1
  553. package/build/relations/Reference.cjs +1 -1
  554. package/build/relations/Reference.cjs.map +1 -1
  555. package/build/relations/Reference.js +1 -1
  556. package/build/relations/Reference.js.map +1 -1
  557. package/build/relations/Relation.cjs.map +1 -1
  558. package/build/relations/Relation.js.map +1 -1
  559. package/build/relations/hasAsyncMethod.cjs +2 -2
  560. package/build/relations/hasAsyncMethod.cjs.map +1 -1
  561. package/build/relations/hasAsyncMethod.d.cts +1 -1
  562. package/build/relations/hasAsyncMethod.d.mts +1 -1
  563. package/build/relations/hasAsyncMethod.js +1 -1
  564. package/build/relations/hasAsyncMethod.js.map +1 -1
  565. package/build/relations/hasManyDerived.cjs +3 -3
  566. package/build/relations/hasManyDerived.cjs.map +1 -1
  567. package/build/relations/hasManyDerived.d.cts +1 -1
  568. package/build/relations/hasManyDerived.d.mts +1 -1
  569. package/build/relations/hasManyDerived.js +2 -2
  570. package/build/relations/hasManyDerived.js.map +1 -1
  571. package/build/relations/hasManyThrough.cjs +6 -6
  572. package/build/relations/hasManyThrough.cjs.map +1 -1
  573. package/build/relations/hasManyThrough.d.cts +1 -1
  574. package/build/relations/hasManyThrough.d.mts +1 -1
  575. package/build/relations/hasManyThrough.js +2 -2
  576. package/build/relations/hasManyThrough.js.map +1 -1
  577. package/build/relations/hasOneDerived.cjs +3 -3
  578. package/build/relations/hasOneDerived.cjs.map +1 -1
  579. package/build/relations/hasOneDerived.d.cts +1 -1
  580. package/build/relations/hasOneDerived.d.mts +1 -1
  581. package/build/relations/hasOneDerived.js +2 -2
  582. package/build/relations/hasOneDerived.js.map +1 -1
  583. package/build/relations/hasOneThrough.cjs +7 -7
  584. package/build/relations/hasOneThrough.cjs.map +1 -1
  585. package/build/relations/hasOneThrough.d.cts +1 -1
  586. package/build/relations/hasOneThrough.d.mts +1 -1
  587. package/build/relations/hasOneThrough.js +2 -2
  588. package/build/relations/hasOneThrough.js.map +1 -1
  589. package/build/relations/hasProperty.cjs +4 -4
  590. package/build/relations/hasProperty.cjs.map +1 -1
  591. package/build/relations/hasProperty.d.cts +2 -2
  592. package/build/relations/hasProperty.d.mts +2 -2
  593. package/build/relations/hasProperty.js +2 -2
  594. package/build/relations/hasProperty.js.map +1 -1
  595. package/build/relations/index.cjs +10 -10
  596. package/build/relations/index.js +10 -10
  597. package/build/relations/isCascadeDelete.cjs.map +1 -1
  598. package/build/relations/isCascadeDelete.js.map +1 -1
  599. package/build/resurrection.cjs.map +1 -1
  600. package/build/resurrection.js.map +1 -1
  601. package/build/rules.cjs +3 -4
  602. package/build/rules.cjs.map +1 -1
  603. package/build/rules.d.cts +1 -1
  604. package/build/rules.d.mts +1 -1
  605. package/build/rules.js +3 -4
  606. package/build/rules.js.map +1 -1
  607. package/build/runtimeConfig.cjs.map +1 -1
  608. package/build/runtimeConfig.js.map +1 -1
  609. package/build/{TypeInfo.cjs → serde/TypeInfo.cjs} +1 -1
  610. package/build/serde/TypeInfo.cjs.map +1 -0
  611. package/build/{TypeInfo.d.cts → serde/TypeInfo.d.cts} +2 -2
  612. package/build/serde/TypeInfo.d.cts.map +1 -0
  613. package/build/{TypeInfo.d.mts → serde/TypeInfo.d.mts} +2 -2
  614. package/build/serde/TypeInfo.d.mts.map +1 -0
  615. package/build/{TypeInfo.js → serde/TypeInfo.js} +1 -1
  616. package/build/serde/TypeInfo.js.map +1 -0
  617. package/build/{columns.cjs → serde/columns.cjs} +1 -1
  618. package/build/serde/columns.cjs.map +1 -0
  619. package/build/{columns.d.cts → serde/columns.d.cts} +2 -2
  620. package/build/serde/columns.d.cts.map +1 -0
  621. package/build/{columns.d.mts → serde/columns.d.mts} +2 -2
  622. package/build/serde/columns.d.mts.map +1 -0
  623. package/build/{columns.js → serde/columns.js} +1 -1
  624. package/build/serde/columns.js.map +1 -0
  625. package/build/{fieldSerde.cjs → serde/fieldSerde.cjs} +6 -6
  626. package/build/serde/fieldSerde.cjs.map +1 -0
  627. package/build/{fieldSerde.d.cts → serde/fieldSerde.d.cts} +5 -5
  628. package/build/serde/fieldSerde.d.cts.map +1 -0
  629. package/build/{fieldSerde.d.mts → serde/fieldSerde.d.mts} +5 -5
  630. package/build/serde/fieldSerde.d.mts.map +1 -0
  631. package/build/{fieldSerde.js → serde/fieldSerde.js} +6 -6
  632. package/build/serde/fieldSerde.js.map +1 -0
  633. package/build/{serde.cjs → serde/serde.cjs} +25 -26
  634. package/build/serde/serde.cjs.map +1 -0
  635. package/build/{serde.d.cts → serde/serde.d.cts} +1 -1
  636. package/build/serde/serde.d.cts.map +1 -0
  637. package/build/{serde.d.mts → serde/serde.d.mts} +1 -1
  638. package/build/serde/serde.d.mts.map +1 -0
  639. package/build/{serde.js → serde/serde.js} +4 -5
  640. package/build/serde/serde.js.map +1 -0
  641. package/build/{temporal.cjs → serde/temporal.cjs} +1 -1
  642. package/build/serde/temporal.cjs.map +1 -0
  643. package/build/{temporal.d.cts → serde/temporal.d.cts} +1 -1
  644. package/build/serde/temporal.d.cts.map +1 -0
  645. package/build/{temporal.d.mts → serde/temporal.d.mts} +1 -1
  646. package/build/serde/temporal.d.mts.map +1 -0
  647. package/build/{temporal.js → serde/temporal.js} +1 -1
  648. package/build/serde/temporal.js.map +1 -0
  649. package/build/{temporalMappers.cjs → serde/temporalMappers.cjs} +4 -5
  650. package/build/serde/temporalMappers.cjs.map +1 -0
  651. package/build/{temporalMappers.d.cts → serde/temporalMappers.d.cts} +1 -1
  652. package/build/serde/temporalMappers.d.cts.map +1 -0
  653. package/build/{temporalMappers.d.mts → serde/temporalMappers.d.mts} +1 -1
  654. package/build/serde/temporalMappers.d.mts.map +1 -0
  655. package/build/{temporalMappers.js → serde/temporalMappers.js} +2 -3
  656. package/build/serde/temporalMappers.js.map +1 -0
  657. package/build/upsert.cjs +1 -1
  658. package/build/upsert.cjs.map +1 -1
  659. package/build/upsert.d.cts.map +1 -1
  660. package/build/upsert.d.mts.map +1 -1
  661. package/build/upsert.js +1 -1
  662. package/build/upsert.js.map +1 -1
  663. package/build/utils.cjs +0 -1
  664. package/build/utils.cjs.map +1 -1
  665. package/build/utils.d.cts +1 -1
  666. package/build/utils.d.mts +1 -1
  667. package/build/utils.js +0 -1
  668. package/build/utils.js.map +1 -1
  669. package/package.json +2 -2
  670. package/build/FlushLock.cjs.map +0 -1
  671. package/build/FlushLock.d.cts.map +0 -1
  672. package/build/FlushLock.d.mts.map +0 -1
  673. package/build/FlushLock.js.map +0 -1
  674. package/build/HintTree.cjs.map +0 -1
  675. package/build/HintTree.d.cts.map +0 -1
  676. package/build/HintTree.d.mts.map +0 -1
  677. package/build/HintTree.js.map +0 -1
  678. package/build/IsLoadedCache.d.cts.map +0 -1
  679. package/build/IsLoadedCache.d.mts.map +0 -1
  680. package/build/IsLoadedCache.js.map +0 -1
  681. package/build/JoinRows.cjs.map +0 -1
  682. package/build/JoinRows.d.cts.map +0 -1
  683. package/build/JoinRows.d.mts.map +0 -1
  684. package/build/JoinRows.js.map +0 -1
  685. package/build/PendingChanges.d.cts.map +0 -1
  686. package/build/PendingChanges.d.mts.map +0 -1
  687. package/build/PendingChanges.js +0 -2
  688. package/build/ReactionsManager.cjs.map +0 -1
  689. package/build/ReactionsManager.d.cts.map +0 -1
  690. package/build/ReactionsManager.d.mts.map +0 -1
  691. package/build/ReactionsManager.js.map +0 -1
  692. package/build/Todo.cjs.map +0 -1
  693. package/build/Todo.d.cts.map +0 -1
  694. package/build/Todo.d.mts.map +0 -1
  695. package/build/Todo.js.map +0 -1
  696. package/build/TypeInfo.cjs.map +0 -1
  697. package/build/TypeInfo.d.cts.map +0 -1
  698. package/build/TypeInfo.d.mts.map +0 -1
  699. package/build/TypeInfo.js.map +0 -1
  700. package/build/columns.cjs.map +0 -1
  701. package/build/columns.d.cts.map +0 -1
  702. package/build/columns.d.mts.map +0 -1
  703. package/build/columns.js.map +0 -1
  704. package/build/driverApi.cjs +0 -18
  705. package/build/driverApi.cjs.map +0 -1
  706. package/build/driverApi.d.cts +0 -22
  707. package/build/driverApi.d.cts.map +0 -1
  708. package/build/driverApi.d.mts +0 -22
  709. package/build/driverApi.d.mts.map +0 -1
  710. package/build/driverApi.js +0 -18
  711. package/build/driverApi.js.map +0 -1
  712. package/build/fieldSerde.cjs.map +0 -1
  713. package/build/fieldSerde.d.cts.map +0 -1
  714. package/build/fieldSerde.d.mts.map +0 -1
  715. package/build/fieldSerde.js.map +0 -1
  716. package/build/loadHints.cjs.map +0 -1
  717. package/build/loadHints.d.cts.map +0 -1
  718. package/build/loadHints.d.mts.map +0 -1
  719. package/build/loadHints.js.map +0 -1
  720. package/build/loadLens.cjs.map +0 -1
  721. package/build/loadLens.d.cts.map +0 -1
  722. package/build/loadLens.d.mts.map +0 -1
  723. package/build/loadLens.js.map +0 -1
  724. package/build/reactiveHints.cjs.map +0 -1
  725. package/build/reactiveHints.d.cts.map +0 -1
  726. package/build/reactiveHints.d.mts.map +0 -1
  727. package/build/reactiveHints.js.map +0 -1
  728. package/build/serde.cjs.map +0 -1
  729. package/build/serde.d.cts.map +0 -1
  730. package/build/serde.d.mts.map +0 -1
  731. package/build/serde.js.map +0 -1
  732. package/build/temporal.cjs.map +0 -1
  733. package/build/temporal.d.cts.map +0 -1
  734. package/build/temporal.d.mts.map +0 -1
  735. package/build/temporal.js.map +0 -1
  736. package/build/temporalMappers.cjs.map +0 -1
  737. package/build/temporalMappers.d.cts.map +0 -1
  738. package/build/temporalMappers.d.mts.map +0 -1
  739. package/build/temporalMappers.js.map +0 -1
  740. package/build/unnest.cjs.map +0 -1
  741. package/build/unnest.d.cts.map +0 -1
  742. package/build/unnest.d.mts.map +0 -1
  743. package/build/unnest.js.map +0 -1
  744. package/build/withLoaded.cjs.map +0 -1
  745. package/build/withLoaded.d.cts.map +0 -1
  746. package/build/withLoaded.d.mts.map +0 -1
  747. package/build/withLoaded.js.map +0 -1
package/build/upsert.cjs CHANGED
@@ -1,7 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- require("./typeMap.cjs");
3
2
  const require_utils = require("./utils.cjs");
4
3
  const require_getProperties = require("./getProperties.cjs");
4
+ require("./typeMap.cjs");
5
5
  const require_configure = require("./configure.cjs");
6
6
  const require_EntityMetadata = require("./EntityMetadata.cjs");
7
7
  const require_defaults = require("./defaults.cjs");
@@ -1 +1 @@
1
- {"version":3,"file":"upsert.cjs","names":["getMetadata","getProperties","isEntity","isKey","getConstructorFromTaggedId","isPlainObject","toArray","findExistingIfUniqueBy","asConcreteCstr"],"sources":["../src/upsert.ts"],"sourcesContent":["import { isPlainObject } from \"joist-utils\";\n\nimport { setSyncDefaults } from \"./defaults.ts\";\nimport { type Entity, isEntity } from \"./Entity.ts\";\nimport { type EntityManager, type IdOf, type MaybeAbstractEntityConstructor, isKey } from \"./EntityManager.ts\";\nimport {\n type ManyToManyField,\n type ManyToOneField,\n type OneToManyField,\n type OneToOneField,\n getMetadata,\n} from \"./EntityMetadata.ts\";\nimport {\n type PartialOrNull,\n type TimestampSerde,\n asConcreteCstr,\n getConstructorFromTaggedId,\n getProperties,\n setOpt,\n} from \"./index.ts\";\nimport { findExistingIfUniqueBy } from \"./resurrection.ts\";\nimport { type OptIdsOf, type OptsOf } from \"./typeMap.ts\";\nimport { type NullOrDefinedOr, toArray } from \"./utils.ts\";\n\n/**\n * The type for `EntityManager.createOrUpdateUnsafe` that allows \"upsert\"-ish behavior.\n *\n * I.e. `T` is an entity with an optional id (create if unset, update if set), and we recurse\n * into any relations (references or collections) to allow those relations themselves to be\n * any combination of 1) ids to existing entities, 2) entities directly, 3) null/undefined\n * with the appropriate partial-update behavior, or 4) partials.\n */\nexport type DeepPartialOrNull<T extends Entity> = { id?: IdOf<T> | null } & AllowRelationsToBeIdsOrEntitiesOrPartials<\n PartialOrNull<OptsOf<T> & OptIdsOf<T>>\n> &\n OptIdsOf<T>;\n\n/** Flags that allow `upsert` to delete or remove entities. */\ntype CollectionFlags = {\n delete?: boolean | null;\n remove?: boolean | null;\n op?: \"remove\" | \"delete\" | \"include\" | \"incremental\";\n};\n\n/** Flag that allows `upsert` to delete. */\ntype DeleteFlag = {\n delete?: boolean | null;\n};\n\ntype AllowRelationsToBeIdsOrEntitiesOrPartials<T> = {\n [P in keyof T]: T[P] extends NullOrDefinedOr<infer U>\n ? U extends Array<infer V>\n ? V extends Entity\n ? Array<V | (DeepPartialOrNull<V> & CollectionFlags) | IdOf<V>> | null\n : T[P]\n : U extends Entity\n ? U | (DeepPartialOrNull<U> & DeleteFlag) | IdOf<U> | null\n : T[P]\n : T[P];\n};\n\n/**\n * A utility function to do partial-update style updates.\n *\n * The difference between this and `Entity.setPartial` is that we accept `DeepPartialOrNull`\n * updates, similar to `createOrUpdateUnsafe`, instead of just a flat/shallow list of opts.\n */\nexport async function updatePartial<T extends Entity>(entity: T, input: DeepPartialOrNull<T>): Promise<void> {\n if (Object.keys(input).length === 0) return;\n const meta = getMetadata(entity);\n const { em } = entity;\n // Do a Promise.all so we .load() relations in parallel\n await Promise.all(\n Object.entries(input).map(async ([key, value]) => {\n // setPartial ==> `undefined` is a noop\n if (value === undefined) return;\n\n // Watch for the `bookId` / `bookIds` aliases\n const field = meta.allFields[key] || Object.values(meta.allFields).find((f) => f.fieldIdName === key);\n\n if (!field) {\n // Allow (ignore here) delete/remove flags that we assume the API layer (i.e. GraphQL) will have specifically\n // allowed, i.e. this isn't the Rails form bug where users can POST in any random field they want.\n const flagField = key === \"delete\" || key === \"remove\" || key === \"op\";\n if (flagField) return;\n // Look for non-field properties like a fullName setter\n const prop = getProperties(meta)[key];\n if (prop) {\n setOpt(meta, entity, key, value);\n return;\n } else {\n throw new Error(`Unknown field ${key}`);\n }\n }\n\n // Don't use key b/c it might be the bookId alias\n const name = field.fieldName;\n\n if (field.kind === \"poly\" && value && !isEntity(value)) {\n // Resolve non-entity poly values\n if (isKey(value)) {\n setOpt(meta, entity, name, await em.load(getConstructorFromTaggedId(value), value));\n } else {\n throw new Error(`Cannot use partial value for polymorphic field `);\n }\n } else if (field.kind === \"m2o\" && value && !isEntity(value)) {\n // This is a many-to-one reference\n if (isKey(value)) {\n setOpt(meta, entity, name, await em.load(field.otherMetadata().cstr, value));\n } else if (typeof value === \"object\" && value) {\n let other: any;\n if (\"id\" in value) {\n // This is a many-to-one partial update to an existing entity (they passed an id)\n other = await upsert(em, field.otherMetadata().cstr, value as any);\n } else {\n // This is a many-to-one partial w/o passing an id, i.e. `upsert(Author, { id: \"a:1\", publisher: { name: \"p1\" } })`\n if (entity.isNewEntity) {\n // If we're brand new, our child/other has to be brand new as well\n other = await upsert(em, field.otherMetadata().cstr, value);\n } else {\n // the o2o upsert hash didn't have an id, so find-or-create it\n other = await (entity as any)[name].load();\n if (other) {\n await updatePartial(other, value);\n } else {\n other = await upsert(em, field.otherMetadata().cstr, value);\n }\n }\n }\n const deleteMarker = getDeleteMarker(field, value);\n if (deleteMarker) {\n em.delete(other);\n other = undefined;\n }\n setOpt(meta, entity, name, other);\n }\n } else if (field.kind === \"o2o\") {\n // ^-- o2o always need loaded to be set, so don't fall through\n if (value === null || isEntity(value)) {\n await (entity as any)[name].load();\n setOpt(meta, entity, name, value);\n } else if (isKey(value)) {\n const [, other] = await Promise.all([\n (entity as any)[name].load(),\n em.load(field.otherMetadata().cstr, value),\n ]);\n setOpt(meta, entity, name, other);\n } else if (typeof value === \"object\" && isPlainObject(value)) {\n const deleteMarker = getDeleteMarker(field, value);\n // Always load the o2o so we can set it\n const current = await (entity as any)[name].load();\n let other: any;\n if (\"id\" in value) {\n // The o2o upsert hash was passed an id, so load it\n other = await upsert(em, field.otherMetadata().cstr, value as any);\n } else {\n // the o2o upsert hash didn't have an id, so find-or-create it\n other = current;\n if (other) {\n await updatePartial(other, value);\n } else {\n other = await upsert(em, field.otherMetadata().cstr, value);\n }\n }\n if (deleteMarker) {\n em.delete(other);\n } else {\n setOpt(meta, entity, name, other);\n }\n } else {\n throw new Error(`Invalid value ${value}`);\n }\n } else if (field.kind === \"o2m\" || field.kind === \"m2m\") {\n // Look for one-to-many/many-to-many partials\n // `null` is handled later, and treated as `[]`, which needs the collection loaded\n\n const values = toArray(value);\n const otherMeta = field.otherMetadata();\n const maybeSoftDelete = otherMeta.timestampFields?.deletedAt;\n\n // Incremental handling. Detect incremental mode by a meaningful `op` value--`op: undefined`/`op: null`\n // is the natural shape of an optional field and must behave like \"no op\", consistent with how\n // updatePartial treats `value === undefined` and how delete/remove are read by truthiness.\n const anyValueHasOp = values.some((v: any) => v && typeof v === \"object\" && !isEntity(v) && v.op != null);\n if (anyValueHasOp) {\n let anyValueMissingOp = false;\n const current = (entity as any)[name];\n // The `op` behavior means incremental and wants to do this:\n await Promise.all(\n values.map(async (value: any) => {\n const [, , op] = getCollectionMarkers(field, value);\n if (op === \"delete\") {\n const other = await upsert(em, otherMeta.cstr, withOwnerField(field, value, entity));\n // We need to check if this is a soft-deletable entity, and if so, we will soft-delete it.\n if (maybeSoftDelete) {\n const serde = otherMeta.fields[maybeSoftDelete].serde as TimestampSerde<unknown>;\n const now = new Date();\n other.set({ [maybeSoftDelete]: serde.mapFromNow(now) });\n } else {\n entity.em.delete(other);\n }\n } else if (op === \"remove\") {\n const other = await upsert(em, otherMeta.cstr, withOwnerField(field, value, entity));\n current.remove(other);\n } else if (op === \"include\") {\n const other = await upsert(em, otherMeta.cstr, withOwnerField(field, value, entity));\n current.add(other);\n } else if (op === \"incremental\") {\n // This is a marker entry, just ignore it\n } else {\n // A child entered incremental mode (a sibling had a real op) but has no op of its own;\n // never silently skip it--flag it so the guard below throws instead of dropping the row.\n anyValueMissingOp = true;\n }\n }),\n );\n if (anyValueMissingOp) {\n throw new Error(\"If any child sets the `op` key, then all children must have the `op` key.\");\n }\n return; // return from the op-based incremental behavior\n }\n\n // Otherwise we do exhaustive sets, will still looking for `delete`/`remove` markers\n const others = await Promise.all(\n values.map(async (value: any) => {\n if (isEntity(value)) {\n return value;\n } else if (isKey(value)) {\n return em.load(field.otherMetadata().cstr, value);\n } else if (value === null || value === undefined) {\n return undefined;\n } else if (!isPlainObject(value)) {\n throw new Error(`Invalid value ${value}`);\n } else {\n // Look for `delete: true/false` and `remove: true/false` markers\n const [deleteMarker, removeMarker] = getCollectionMarkers(field, value);\n const other = await upsert(em, field.otherMetadata().cstr, withOwnerField(field, value, entity));\n if (deleteMarker) {\n // if (maybeSoftDelete) {\n // const serde = meta.fields[maybeSoftDelete].serde as TimestampSerde<unknown>;\n // const now = new Date();\n // other.set({ [maybeSoftDelete]: serde.mapFromNow(now) });\n // } else {\n // }\n em.delete(other);\n return other;\n } else if (removeMarker) {\n return undefined;\n } else {\n return other;\n }\n }\n }),\n );\n\n await (entity as any)[name].load();\n setOpt(\n meta,\n entity,\n name,\n others.filter((v) => v !== undefined),\n );\n } else {\n // If we get here, value should be a vanilla value that `setOpt` can handle/pass through as-is\n setOpt(meta, entity, name, value);\n }\n }),\n );\n}\n\n/**\n * A utility function to create-or-update/upsert entities coming from a partial-update style API.\n */\nexport async function upsert<T extends Entity>(\n em: EntityManager<any, any, any>,\n constructor: MaybeAbstractEntityConstructor<T>,\n input: DeepPartialOrNull<T>,\n): Promise<T> {\n const { id, ...rest } = input;\n const entity =\n id !== null && id !== undefined\n ? await em.load(constructor, id)\n : // Look for an existing entity we could resurrect\n ((id === undefined ? await findExistingIfUniqueBy(em, constructor, rest) : undefined) ??\n em.createPartial(asConcreteCstr(constructor), {}));\n await updatePartial(entity, rest as any);\n // Do this manually since we're not going through setOpts anymore\n if (entity.isNewEntity) {\n setSyncDefaults(entity);\n }\n return entity;\n}\n\n/**\n * Adds the o2m owner field so child resurrection can find rows whose `uniqueBy` includes their parent.\n * I.e. upserting `Author.books: [{ title: \"b1\" }]` should lookup `Book.uniqueBy = [[\"author\", \"title\"]]`.\n */\nfunction withOwnerField(field: OneToManyField | ManyToManyField, value: any, owner: Entity): any {\n if (field.kind !== \"o2m\" || !isPlainObject(value)) return value;\n const ownerField = field.otherFieldName;\n const ownerFieldId = field.otherMetadata().allFields[ownerField]?.fieldIdName;\n if (Object.hasOwn(value, ownerField) || (ownerFieldId && Object.hasOwn(value, ownerFieldId))) return value;\n if (ownerFieldId && !owner.isNewEntity) return { ...value, [ownerFieldId]: owner.id };\n return { ...value, [ownerField]: owner };\n}\n\nfunction getCollectionMarkers(field: OneToManyField | ManyToManyField, value: any): [any, any, any] {\n const allowDelete = !field.otherMetadata().fields[\"delete\"];\n const allowRemove = !field.otherMetadata().fields[\"remove\"];\n const allowOp = !field.otherMetadata().fields[\"op\"];\n\n // Look for `delete: true/false` and `remove: true/false` markers\n const deleteMarker: any = allowDelete && value[\"delete\"];\n const removeMarker: any = allowRemove && value[\"remove\"];\n const opMarker: any = allowOp && value[\"op\"];\n\n // Remove the markers, regardless of true/false, before recursing into upsert to avoid unknown fields\n if (deleteMarker !== undefined) delete value.delete;\n if (removeMarker !== undefined) delete value.remove;\n if (opMarker !== undefined) delete value.op;\n\n return [deleteMarker, removeMarker, opMarker];\n}\nfunction getDeleteMarker(field: OneToOneField | ManyToOneField, value: any): boolean {\n const allowDelete = !field.otherMetadata().fields[\"delete\"];\n const deleteMarker: any = allowDelete && value[\"delete\"];\n if (deleteMarker !== undefined) delete value.delete;\n return deleteMarker;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"upsert.cjs","names":["getMetadata","getProperties","isEntity","isKey","getConstructorFromTaggedId","isPlainObject","toArray","findExistingIfUniqueBy","asConcreteCstr"],"sources":["../src/upsert.ts"],"sourcesContent":["import { isPlainObject } from \"joist-utils\";\nimport { setSyncDefaults } from \"src/defaults.ts\";\nimport { type Entity, isEntity } from \"src/Entity.ts\";\nimport { type EntityManager, type IdOf, type MaybeAbstractEntityConstructor, isKey } from \"src/EntityManager.ts\";\nimport {\n type ManyToManyField,\n type ManyToOneField,\n type OneToManyField,\n type OneToOneField,\n getMetadata,\n} from \"src/EntityMetadata.ts\";\nimport {\n type PartialOrNull,\n type TimestampSerde,\n asConcreteCstr,\n getConstructorFromTaggedId,\n getProperties,\n setOpt,\n} from \"src/index.ts\";\nimport { findExistingIfUniqueBy } from \"src/resurrection.ts\";\nimport { type OptIdsOf, type OptsOf } from \"src/typeMap.ts\";\nimport { type NullOrDefinedOr, toArray } from \"src/utils.ts\";\n\n/**\n * The type for `EntityManager.createOrUpdateUnsafe` that allows \"upsert\"-ish behavior.\n *\n * I.e. `T` is an entity with an optional id (create if unset, update if set), and we recurse\n * into any relations (references or collections) to allow those relations themselves to be\n * any combination of 1) ids to existing entities, 2) entities directly, 3) null/undefined\n * with the appropriate partial-update behavior, or 4) partials.\n */\nexport type DeepPartialOrNull<T extends Entity> = { id?: IdOf<T> | null } & AllowRelationsToBeIdsOrEntitiesOrPartials<\n PartialOrNull<OptsOf<T> & OptIdsOf<T>>\n> &\n OptIdsOf<T>;\n\n/** Flags that allow `upsert` to delete or remove entities. */\ntype CollectionFlags = {\n delete?: boolean | null;\n remove?: boolean | null;\n op?: \"remove\" | \"delete\" | \"include\" | \"incremental\";\n};\n\n/** Flag that allows `upsert` to delete. */\ntype DeleteFlag = {\n delete?: boolean | null;\n};\n\ntype AllowRelationsToBeIdsOrEntitiesOrPartials<T> = {\n [P in keyof T]: T[P] extends NullOrDefinedOr<infer U>\n ? U extends Array<infer V>\n ? V extends Entity\n ? Array<V | (DeepPartialOrNull<V> & CollectionFlags) | IdOf<V>> | null\n : T[P]\n : U extends Entity\n ? U | (DeepPartialOrNull<U> & DeleteFlag) | IdOf<U> | null\n : T[P]\n : T[P];\n};\n\n/**\n * A utility function to do partial-update style updates.\n *\n * The difference between this and `Entity.setPartial` is that we accept `DeepPartialOrNull`\n * updates, similar to `createOrUpdateUnsafe`, instead of just a flat/shallow list of opts.\n */\nexport async function updatePartial<T extends Entity>(entity: T, input: DeepPartialOrNull<T>): Promise<void> {\n if (Object.keys(input).length === 0) return;\n const meta = getMetadata(entity);\n const { em } = entity;\n // Do a Promise.all so we .load() relations in parallel\n await Promise.all(\n Object.entries(input).map(async ([key, value]) => {\n // setPartial ==> `undefined` is a noop\n if (value === undefined) return;\n\n // Watch for the `bookId` / `bookIds` aliases\n const field = meta.allFields[key] || Object.values(meta.allFields).find((f) => f.fieldIdName === key);\n\n if (!field) {\n // Allow (ignore here) delete/remove flags that we assume the API layer (i.e. GraphQL) will have specifically\n // allowed, i.e. this isn't the Rails form bug where users can POST in any random field they want.\n const flagField = key === \"delete\" || key === \"remove\" || key === \"op\";\n if (flagField) return;\n // Look for non-field properties like a fullName setter\n const prop = getProperties(meta)[key];\n if (prop) {\n setOpt(meta, entity, key, value);\n return;\n } else {\n throw new Error(`Unknown field ${key}`);\n }\n }\n\n // Don't use key b/c it might be the bookId alias\n const name = field.fieldName;\n\n if (field.kind === \"poly\" && value && !isEntity(value)) {\n // Resolve non-entity poly values\n if (isKey(value)) {\n setOpt(meta, entity, name, await em.load(getConstructorFromTaggedId(value), value));\n } else {\n throw new Error(`Cannot use partial value for polymorphic field `);\n }\n } else if (field.kind === \"m2o\" && value && !isEntity(value)) {\n // This is a many-to-one reference\n if (isKey(value)) {\n setOpt(meta, entity, name, await em.load(field.otherMetadata().cstr, value));\n } else if (typeof value === \"object\" && value) {\n let other: any;\n if (\"id\" in value) {\n // This is a many-to-one partial update to an existing entity (they passed an id)\n other = await upsert(em, field.otherMetadata().cstr, value as any);\n } else {\n // This is a many-to-one partial w/o passing an id, i.e. `upsert(Author, { id: \"a:1\", publisher: { name: \"p1\" } })`\n if (entity.isNewEntity) {\n // If we're brand new, our child/other has to be brand new as well\n other = await upsert(em, field.otherMetadata().cstr, value);\n } else {\n // the o2o upsert hash didn't have an id, so find-or-create it\n other = await (entity as any)[name].load();\n if (other) {\n await updatePartial(other, value);\n } else {\n other = await upsert(em, field.otherMetadata().cstr, value);\n }\n }\n }\n const deleteMarker = getDeleteMarker(field, value);\n if (deleteMarker) {\n em.delete(other);\n other = undefined;\n }\n setOpt(meta, entity, name, other);\n }\n } else if (field.kind === \"o2o\") {\n // ^-- o2o always need loaded to be set, so don't fall through\n if (value === null || isEntity(value)) {\n await (entity as any)[name].load();\n setOpt(meta, entity, name, value);\n } else if (isKey(value)) {\n const [, other] = await Promise.all([\n (entity as any)[name].load(),\n em.load(field.otherMetadata().cstr, value),\n ]);\n setOpt(meta, entity, name, other);\n } else if (typeof value === \"object\" && isPlainObject(value)) {\n const deleteMarker = getDeleteMarker(field, value);\n // Always load the o2o so we can set it\n const current = await (entity as any)[name].load();\n let other: any;\n if (\"id\" in value) {\n // The o2o upsert hash was passed an id, so load it\n other = await upsert(em, field.otherMetadata().cstr, value as any);\n } else {\n // the o2o upsert hash didn't have an id, so find-or-create it\n other = current;\n if (other) {\n await updatePartial(other, value);\n } else {\n other = await upsert(em, field.otherMetadata().cstr, value);\n }\n }\n if (deleteMarker) {\n em.delete(other);\n } else {\n setOpt(meta, entity, name, other);\n }\n } else {\n throw new Error(`Invalid value ${value}`);\n }\n } else if (field.kind === \"o2m\" || field.kind === \"m2m\") {\n // Look for one-to-many/many-to-many partials\n // `null` is handled later, and treated as `[]`, which needs the collection loaded\n\n const values = toArray(value);\n const otherMeta = field.otherMetadata();\n const maybeSoftDelete = otherMeta.timestampFields?.deletedAt;\n\n // Incremental handling. Detect incremental mode by a meaningful `op` value--`op: undefined`/`op: null`\n // is the natural shape of an optional field and must behave like \"no op\", consistent with how\n // updatePartial treats `value === undefined` and how delete/remove are read by truthiness.\n const anyValueHasOp = values.some((v: any) => v && typeof v === \"object\" && !isEntity(v) && v.op != null);\n if (anyValueHasOp) {\n let anyValueMissingOp = false;\n const current = (entity as any)[name];\n // The `op` behavior means incremental and wants to do this:\n await Promise.all(\n values.map(async (value: any) => {\n const [, , op] = getCollectionMarkers(field, value);\n if (op === \"delete\") {\n const other = await upsert(em, otherMeta.cstr, withOwnerField(field, value, entity));\n // We need to check if this is a soft-deletable entity, and if so, we will soft-delete it.\n if (maybeSoftDelete) {\n const serde = otherMeta.fields[maybeSoftDelete].serde as TimestampSerde<unknown>;\n const now = new Date();\n other.set({ [maybeSoftDelete]: serde.mapFromNow(now) });\n } else {\n entity.em.delete(other);\n }\n } else if (op === \"remove\") {\n const other = await upsert(em, otherMeta.cstr, withOwnerField(field, value, entity));\n current.remove(other);\n } else if (op === \"include\") {\n const other = await upsert(em, otherMeta.cstr, withOwnerField(field, value, entity));\n current.add(other);\n } else if (op === \"incremental\") {\n // This is a marker entry, just ignore it\n } else {\n // A child entered incremental mode (a sibling had a real op) but has no op of its own;\n // never silently skip it--flag it so the guard below throws instead of dropping the row.\n anyValueMissingOp = true;\n }\n }),\n );\n if (anyValueMissingOp) {\n throw new Error(\"If any child sets the `op` key, then all children must have the `op` key.\");\n }\n return; // return from the op-based incremental behavior\n }\n\n // Otherwise we do exhaustive sets, will still looking for `delete`/`remove` markers\n const others = await Promise.all(\n values.map(async (value: any) => {\n if (isEntity(value)) {\n return value;\n } else if (isKey(value)) {\n return em.load(field.otherMetadata().cstr, value);\n } else if (value === null || value === undefined) {\n return undefined;\n } else if (!isPlainObject(value)) {\n throw new Error(`Invalid value ${value}`);\n } else {\n // Look for `delete: true/false` and `remove: true/false` markers\n const [deleteMarker, removeMarker] = getCollectionMarkers(field, value);\n const other = await upsert(em, field.otherMetadata().cstr, withOwnerField(field, value, entity));\n if (deleteMarker) {\n // if (maybeSoftDelete) {\n // const serde = meta.fields[maybeSoftDelete].serde as TimestampSerde<unknown>;\n // const now = new Date();\n // other.set({ [maybeSoftDelete]: serde.mapFromNow(now) });\n // } else {\n // }\n em.delete(other);\n return other;\n } else if (removeMarker) {\n return undefined;\n } else {\n return other;\n }\n }\n }),\n );\n\n await (entity as any)[name].load();\n setOpt(\n meta,\n entity,\n name,\n others.filter((v) => v !== undefined),\n );\n } else {\n // If we get here, value should be a vanilla value that `setOpt` can handle/pass through as-is\n setOpt(meta, entity, name, value);\n }\n }),\n );\n}\n\n/**\n * A utility function to create-or-update/upsert entities coming from a partial-update style API.\n */\nexport async function upsert<T extends Entity>(\n em: EntityManager<any, any, any>,\n constructor: MaybeAbstractEntityConstructor<T>,\n input: DeepPartialOrNull<T>,\n): Promise<T> {\n const { id, ...rest } = input;\n const entity =\n id !== null && id !== undefined\n ? await em.load(constructor, id)\n : // Look for an existing entity we could resurrect\n ((id === undefined ? await findExistingIfUniqueBy(em, constructor, rest) : undefined) ??\n em.createPartial(asConcreteCstr(constructor), {}));\n await updatePartial(entity, rest as any);\n // Do this manually since we're not going through setOpts anymore\n if (entity.isNewEntity) {\n setSyncDefaults(entity);\n }\n return entity;\n}\n\n/**\n * Adds the o2m owner field so child resurrection can find rows whose `uniqueBy` includes their parent.\n * I.e. upserting `Author.books: [{ title: \"b1\" }]` should lookup `Book.uniqueBy = [[\"author\", \"title\"]]`.\n */\nfunction withOwnerField(field: OneToManyField | ManyToManyField, value: any, owner: Entity): any {\n if (field.kind !== \"o2m\" || !isPlainObject(value)) return value;\n const ownerField = field.otherFieldName;\n const ownerFieldId = field.otherMetadata().allFields[ownerField]?.fieldIdName;\n if (Object.hasOwn(value, ownerField) || (ownerFieldId && Object.hasOwn(value, ownerFieldId))) return value;\n if (ownerFieldId && !owner.isNewEntity) return { ...value, [ownerFieldId]: owner.id };\n return { ...value, [ownerField]: owner };\n}\n\nfunction getCollectionMarkers(field: OneToManyField | ManyToManyField, value: any): [any, any, any] {\n const allowDelete = !field.otherMetadata().fields[\"delete\"];\n const allowRemove = !field.otherMetadata().fields[\"remove\"];\n const allowOp = !field.otherMetadata().fields[\"op\"];\n\n // Look for `delete: true/false` and `remove: true/false` markers\n const deleteMarker: any = allowDelete && value[\"delete\"];\n const removeMarker: any = allowRemove && value[\"remove\"];\n const opMarker: any = allowOp && value[\"op\"];\n\n // Remove the markers, regardless of true/false, before recursing into upsert to avoid unknown fields\n if (deleteMarker !== undefined) delete value.delete;\n if (removeMarker !== undefined) delete value.remove;\n if (opMarker !== undefined) delete value.op;\n\n return [deleteMarker, removeMarker, opMarker];\n}\nfunction getDeleteMarker(field: OneToOneField | ManyToOneField, value: any): boolean {\n const allowDelete = !field.otherMetadata().fields[\"delete\"];\n const deleteMarker: any = allowDelete && value[\"delete\"];\n if (deleteMarker !== undefined) delete value.delete;\n return deleteMarker;\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"upsert.d.cts","names":[],"sources":["../src/upsert.ts"],"mappings":";;;;;;;;;;;;;;KAgCY,kBAAkB,UAAU;EAAY,KAAK,KAAK;IAAc,0CAC1E,cAAc,OAAO,KAAK,SAAS,OAEnC,SAAS;;KAGN;EACH;EACA;EACA;;;KAIG;EACH;;KAGG,0CAA0C,QAC5C,WAAW,IAAI,EAAE,WAAW,sBAAsB,KAC/C,UAAU,YAAY,KACpB,UAAU,SACR,MAAM,KAAK,kBAAkB,KAAK,mBAAmB,KAAK,aAC1D,EAAE,KACJ,UAAU,SACR,KAAK,kBAAkB,KAAK,cAAc,KAAK,YAC/C,EAAE,KACN,EAAE;;;;;;;iBASc,cAAc,UAAU,QAAQ,QAAQ,GAAG,OAAO,kBAAkB,KAAK;;;;iBA8MzE,OAAO,UAAU,QACrC,IAAI,8BACJ,aAAa,+BAA+B,IAC5C,OAAO,kBAAkB,KACxB,QAAQ"}
1
+ {"version":3,"file":"upsert.d.cts","names":[],"sources":["../src/upsert.ts"],"mappings":";;;;;;;;;;;;;;KA+BY,kBAAkB,UAAU;EAAY,KAAK,KAAK;IAAc,0CAC1E,cAAc,OAAO,KAAK,SAAS,OAEnC,SAAS;;KAGN;EACH;EACA;EACA;;;KAIG;EACH;;KAGG,0CAA0C,QAC5C,WAAW,IAAI,EAAE,WAAW,sBAAsB,KAC/C,UAAU,YAAY,KACpB,UAAU,SACR,MAAM,KAAK,kBAAkB,KAAK,mBAAmB,KAAK,aAC1D,EAAE,KACJ,UAAU,SACR,KAAK,kBAAkB,KAAK,cAAc,KAAK,YAC/C,EAAE,KACN,EAAE;;;;;;;iBASc,cAAc,UAAU,QAAQ,QAAQ,GAAG,OAAO,kBAAkB,KAAK;;;;iBA8MzE,OAAO,UAAU,QACrC,IAAI,8BACJ,aAAa,+BAA+B,IAC5C,OAAO,kBAAkB,KACxB,QAAQ"}
@@ -1 +1 @@
1
- {"version":3,"file":"upsert.d.mts","names":[],"sources":["../src/upsert.ts"],"mappings":";;;;;;;;;;;;;;KAgCY,kBAAkB,UAAU;EAAY,KAAK,KAAK;IAAc,0CAC1E,cAAc,OAAO,KAAK,SAAS,OAEnC,SAAS;;KAGN;EACH;EACA;EACA;;;KAIG;EACH;;KAGG,0CAA0C,QAC5C,WAAW,IAAI,EAAE,WAAW,sBAAsB,KAC/C,UAAU,YAAY,KACpB,UAAU,SACR,MAAM,KAAK,kBAAkB,KAAK,mBAAmB,KAAK,aAC1D,EAAE,KACJ,UAAU,SACR,KAAK,kBAAkB,KAAK,cAAc,KAAK,YAC/C,EAAE,KACN,EAAE;;;;;;;iBASc,cAAc,UAAU,QAAQ,QAAQ,GAAG,OAAO,kBAAkB,KAAK;;;;iBA8MzE,OAAO,UAAU,QACrC,IAAI,8BACJ,aAAa,+BAA+B,IAC5C,OAAO,kBAAkB,KACxB,QAAQ"}
1
+ {"version":3,"file":"upsert.d.mts","names":[],"sources":["../src/upsert.ts"],"mappings":";;;;;;;;;;;;;;KA+BY,kBAAkB,UAAU;EAAY,KAAK,KAAK;IAAc,0CAC1E,cAAc,OAAO,KAAK,SAAS,OAEnC,SAAS;;KAGN;EACH;EACA;EACA;;;KAIG;EACH;;KAGG,0CAA0C,QAC5C,WAAW,IAAI,EAAE,WAAW,sBAAsB,KAC/C,UAAU,YAAY,KACpB,UAAU,SACR,MAAM,KAAK,kBAAkB,KAAK,mBAAmB,KAAK,aAC1D,EAAE,KACJ,UAAU,SACR,KAAK,kBAAkB,KAAK,cAAc,KAAK,YAC/C,EAAE,KACN,EAAE;;;;;;;iBASc,cAAc,UAAU,QAAQ,QAAQ,GAAG,OAAO,kBAAkB,KAAK;;;;iBA8MzE,OAAO,UAAU,QACrC,IAAI,8BACJ,aAAa,+BAA+B,IAC5C,OAAO,kBAAkB,KACxB,QAAQ"}
package/build/upsert.js CHANGED
@@ -1,6 +1,6 @@
1
- import "./typeMap.js";
2
1
  import { toArray } from "./utils.js";
3
2
  import { getProperties } from "./getProperties.js";
3
+ import "./typeMap.js";
4
4
  import { getConstructorFromTaggedId } from "./configure.js";
5
5
  import { getMetadata } from "./EntityMetadata.js";
6
6
  import { setSyncDefaults } from "./defaults.js";
@@ -1 +1 @@
1
- {"version":3,"file":"upsert.js","names":[],"sources":["../src/upsert.ts"],"sourcesContent":["import { isPlainObject } from \"joist-utils\";\n\nimport { setSyncDefaults } from \"./defaults.ts\";\nimport { type Entity, isEntity } from \"./Entity.ts\";\nimport { type EntityManager, type IdOf, type MaybeAbstractEntityConstructor, isKey } from \"./EntityManager.ts\";\nimport {\n type ManyToManyField,\n type ManyToOneField,\n type OneToManyField,\n type OneToOneField,\n getMetadata,\n} from \"./EntityMetadata.ts\";\nimport {\n type PartialOrNull,\n type TimestampSerde,\n asConcreteCstr,\n getConstructorFromTaggedId,\n getProperties,\n setOpt,\n} from \"./index.ts\";\nimport { findExistingIfUniqueBy } from \"./resurrection.ts\";\nimport { type OptIdsOf, type OptsOf } from \"./typeMap.ts\";\nimport { type NullOrDefinedOr, toArray } from \"./utils.ts\";\n\n/**\n * The type for `EntityManager.createOrUpdateUnsafe` that allows \"upsert\"-ish behavior.\n *\n * I.e. `T` is an entity with an optional id (create if unset, update if set), and we recurse\n * into any relations (references or collections) to allow those relations themselves to be\n * any combination of 1) ids to existing entities, 2) entities directly, 3) null/undefined\n * with the appropriate partial-update behavior, or 4) partials.\n */\nexport type DeepPartialOrNull<T extends Entity> = { id?: IdOf<T> | null } & AllowRelationsToBeIdsOrEntitiesOrPartials<\n PartialOrNull<OptsOf<T> & OptIdsOf<T>>\n> &\n OptIdsOf<T>;\n\n/** Flags that allow `upsert` to delete or remove entities. */\ntype CollectionFlags = {\n delete?: boolean | null;\n remove?: boolean | null;\n op?: \"remove\" | \"delete\" | \"include\" | \"incremental\";\n};\n\n/** Flag that allows `upsert` to delete. */\ntype DeleteFlag = {\n delete?: boolean | null;\n};\n\ntype AllowRelationsToBeIdsOrEntitiesOrPartials<T> = {\n [P in keyof T]: T[P] extends NullOrDefinedOr<infer U>\n ? U extends Array<infer V>\n ? V extends Entity\n ? Array<V | (DeepPartialOrNull<V> & CollectionFlags) | IdOf<V>> | null\n : T[P]\n : U extends Entity\n ? U | (DeepPartialOrNull<U> & DeleteFlag) | IdOf<U> | null\n : T[P]\n : T[P];\n};\n\n/**\n * A utility function to do partial-update style updates.\n *\n * The difference between this and `Entity.setPartial` is that we accept `DeepPartialOrNull`\n * updates, similar to `createOrUpdateUnsafe`, instead of just a flat/shallow list of opts.\n */\nexport async function updatePartial<T extends Entity>(entity: T, input: DeepPartialOrNull<T>): Promise<void> {\n if (Object.keys(input).length === 0) return;\n const meta = getMetadata(entity);\n const { em } = entity;\n // Do a Promise.all so we .load() relations in parallel\n await Promise.all(\n Object.entries(input).map(async ([key, value]) => {\n // setPartial ==> `undefined` is a noop\n if (value === undefined) return;\n\n // Watch for the `bookId` / `bookIds` aliases\n const field = meta.allFields[key] || Object.values(meta.allFields).find((f) => f.fieldIdName === key);\n\n if (!field) {\n // Allow (ignore here) delete/remove flags that we assume the API layer (i.e. GraphQL) will have specifically\n // allowed, i.e. this isn't the Rails form bug where users can POST in any random field they want.\n const flagField = key === \"delete\" || key === \"remove\" || key === \"op\";\n if (flagField) return;\n // Look for non-field properties like a fullName setter\n const prop = getProperties(meta)[key];\n if (prop) {\n setOpt(meta, entity, key, value);\n return;\n } else {\n throw new Error(`Unknown field ${key}`);\n }\n }\n\n // Don't use key b/c it might be the bookId alias\n const name = field.fieldName;\n\n if (field.kind === \"poly\" && value && !isEntity(value)) {\n // Resolve non-entity poly values\n if (isKey(value)) {\n setOpt(meta, entity, name, await em.load(getConstructorFromTaggedId(value), value));\n } else {\n throw new Error(`Cannot use partial value for polymorphic field `);\n }\n } else if (field.kind === \"m2o\" && value && !isEntity(value)) {\n // This is a many-to-one reference\n if (isKey(value)) {\n setOpt(meta, entity, name, await em.load(field.otherMetadata().cstr, value));\n } else if (typeof value === \"object\" && value) {\n let other: any;\n if (\"id\" in value) {\n // This is a many-to-one partial update to an existing entity (they passed an id)\n other = await upsert(em, field.otherMetadata().cstr, value as any);\n } else {\n // This is a many-to-one partial w/o passing an id, i.e. `upsert(Author, { id: \"a:1\", publisher: { name: \"p1\" } })`\n if (entity.isNewEntity) {\n // If we're brand new, our child/other has to be brand new as well\n other = await upsert(em, field.otherMetadata().cstr, value);\n } else {\n // the o2o upsert hash didn't have an id, so find-or-create it\n other = await (entity as any)[name].load();\n if (other) {\n await updatePartial(other, value);\n } else {\n other = await upsert(em, field.otherMetadata().cstr, value);\n }\n }\n }\n const deleteMarker = getDeleteMarker(field, value);\n if (deleteMarker) {\n em.delete(other);\n other = undefined;\n }\n setOpt(meta, entity, name, other);\n }\n } else if (field.kind === \"o2o\") {\n // ^-- o2o always need loaded to be set, so don't fall through\n if (value === null || isEntity(value)) {\n await (entity as any)[name].load();\n setOpt(meta, entity, name, value);\n } else if (isKey(value)) {\n const [, other] = await Promise.all([\n (entity as any)[name].load(),\n em.load(field.otherMetadata().cstr, value),\n ]);\n setOpt(meta, entity, name, other);\n } else if (typeof value === \"object\" && isPlainObject(value)) {\n const deleteMarker = getDeleteMarker(field, value);\n // Always load the o2o so we can set it\n const current = await (entity as any)[name].load();\n let other: any;\n if (\"id\" in value) {\n // The o2o upsert hash was passed an id, so load it\n other = await upsert(em, field.otherMetadata().cstr, value as any);\n } else {\n // the o2o upsert hash didn't have an id, so find-or-create it\n other = current;\n if (other) {\n await updatePartial(other, value);\n } else {\n other = await upsert(em, field.otherMetadata().cstr, value);\n }\n }\n if (deleteMarker) {\n em.delete(other);\n } else {\n setOpt(meta, entity, name, other);\n }\n } else {\n throw new Error(`Invalid value ${value}`);\n }\n } else if (field.kind === \"o2m\" || field.kind === \"m2m\") {\n // Look for one-to-many/many-to-many partials\n // `null` is handled later, and treated as `[]`, which needs the collection loaded\n\n const values = toArray(value);\n const otherMeta = field.otherMetadata();\n const maybeSoftDelete = otherMeta.timestampFields?.deletedAt;\n\n // Incremental handling. Detect incremental mode by a meaningful `op` value--`op: undefined`/`op: null`\n // is the natural shape of an optional field and must behave like \"no op\", consistent with how\n // updatePartial treats `value === undefined` and how delete/remove are read by truthiness.\n const anyValueHasOp = values.some((v: any) => v && typeof v === \"object\" && !isEntity(v) && v.op != null);\n if (anyValueHasOp) {\n let anyValueMissingOp = false;\n const current = (entity as any)[name];\n // The `op` behavior means incremental and wants to do this:\n await Promise.all(\n values.map(async (value: any) => {\n const [, , op] = getCollectionMarkers(field, value);\n if (op === \"delete\") {\n const other = await upsert(em, otherMeta.cstr, withOwnerField(field, value, entity));\n // We need to check if this is a soft-deletable entity, and if so, we will soft-delete it.\n if (maybeSoftDelete) {\n const serde = otherMeta.fields[maybeSoftDelete].serde as TimestampSerde<unknown>;\n const now = new Date();\n other.set({ [maybeSoftDelete]: serde.mapFromNow(now) });\n } else {\n entity.em.delete(other);\n }\n } else if (op === \"remove\") {\n const other = await upsert(em, otherMeta.cstr, withOwnerField(field, value, entity));\n current.remove(other);\n } else if (op === \"include\") {\n const other = await upsert(em, otherMeta.cstr, withOwnerField(field, value, entity));\n current.add(other);\n } else if (op === \"incremental\") {\n // This is a marker entry, just ignore it\n } else {\n // A child entered incremental mode (a sibling had a real op) but has no op of its own;\n // never silently skip it--flag it so the guard below throws instead of dropping the row.\n anyValueMissingOp = true;\n }\n }),\n );\n if (anyValueMissingOp) {\n throw new Error(\"If any child sets the `op` key, then all children must have the `op` key.\");\n }\n return; // return from the op-based incremental behavior\n }\n\n // Otherwise we do exhaustive sets, will still looking for `delete`/`remove` markers\n const others = await Promise.all(\n values.map(async (value: any) => {\n if (isEntity(value)) {\n return value;\n } else if (isKey(value)) {\n return em.load(field.otherMetadata().cstr, value);\n } else if (value === null || value === undefined) {\n return undefined;\n } else if (!isPlainObject(value)) {\n throw new Error(`Invalid value ${value}`);\n } else {\n // Look for `delete: true/false` and `remove: true/false` markers\n const [deleteMarker, removeMarker] = getCollectionMarkers(field, value);\n const other = await upsert(em, field.otherMetadata().cstr, withOwnerField(field, value, entity));\n if (deleteMarker) {\n // if (maybeSoftDelete) {\n // const serde = meta.fields[maybeSoftDelete].serde as TimestampSerde<unknown>;\n // const now = new Date();\n // other.set({ [maybeSoftDelete]: serde.mapFromNow(now) });\n // } else {\n // }\n em.delete(other);\n return other;\n } else if (removeMarker) {\n return undefined;\n } else {\n return other;\n }\n }\n }),\n );\n\n await (entity as any)[name].load();\n setOpt(\n meta,\n entity,\n name,\n others.filter((v) => v !== undefined),\n );\n } else {\n // If we get here, value should be a vanilla value that `setOpt` can handle/pass through as-is\n setOpt(meta, entity, name, value);\n }\n }),\n );\n}\n\n/**\n * A utility function to create-or-update/upsert entities coming from a partial-update style API.\n */\nexport async function upsert<T extends Entity>(\n em: EntityManager<any, any, any>,\n constructor: MaybeAbstractEntityConstructor<T>,\n input: DeepPartialOrNull<T>,\n): Promise<T> {\n const { id, ...rest } = input;\n const entity =\n id !== null && id !== undefined\n ? await em.load(constructor, id)\n : // Look for an existing entity we could resurrect\n ((id === undefined ? await findExistingIfUniqueBy(em, constructor, rest) : undefined) ??\n em.createPartial(asConcreteCstr(constructor), {}));\n await updatePartial(entity, rest as any);\n // Do this manually since we're not going through setOpts anymore\n if (entity.isNewEntity) {\n setSyncDefaults(entity);\n }\n return entity;\n}\n\n/**\n * Adds the o2m owner field so child resurrection can find rows whose `uniqueBy` includes their parent.\n * I.e. upserting `Author.books: [{ title: \"b1\" }]` should lookup `Book.uniqueBy = [[\"author\", \"title\"]]`.\n */\nfunction withOwnerField(field: OneToManyField | ManyToManyField, value: any, owner: Entity): any {\n if (field.kind !== \"o2m\" || !isPlainObject(value)) return value;\n const ownerField = field.otherFieldName;\n const ownerFieldId = field.otherMetadata().allFields[ownerField]?.fieldIdName;\n if (Object.hasOwn(value, ownerField) || (ownerFieldId && Object.hasOwn(value, ownerFieldId))) return value;\n if (ownerFieldId && !owner.isNewEntity) return { ...value, [ownerFieldId]: owner.id };\n return { ...value, [ownerField]: owner };\n}\n\nfunction getCollectionMarkers(field: OneToManyField | ManyToManyField, value: any): [any, any, any] {\n const allowDelete = !field.otherMetadata().fields[\"delete\"];\n const allowRemove = !field.otherMetadata().fields[\"remove\"];\n const allowOp = !field.otherMetadata().fields[\"op\"];\n\n // Look for `delete: true/false` and `remove: true/false` markers\n const deleteMarker: any = allowDelete && value[\"delete\"];\n const removeMarker: any = allowRemove && value[\"remove\"];\n const opMarker: any = allowOp && value[\"op\"];\n\n // Remove the markers, regardless of true/false, before recursing into upsert to avoid unknown fields\n if (deleteMarker !== undefined) delete value.delete;\n if (removeMarker !== undefined) delete value.remove;\n if (opMarker !== undefined) delete value.op;\n\n return [deleteMarker, removeMarker, opMarker];\n}\nfunction getDeleteMarker(field: OneToOneField | ManyToOneField, value: any): boolean {\n const allowDelete = !field.otherMetadata().fields[\"delete\"];\n const deleteMarker: any = allowDelete && value[\"delete\"];\n if (deleteMarker !== undefined) delete value.delete;\n return deleteMarker;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"upsert.js","names":[],"sources":["../src/upsert.ts"],"sourcesContent":["import { isPlainObject } from \"joist-utils\";\nimport { setSyncDefaults } from \"src/defaults.ts\";\nimport { type Entity, isEntity } from \"src/Entity.ts\";\nimport { type EntityManager, type IdOf, type MaybeAbstractEntityConstructor, isKey } from \"src/EntityManager.ts\";\nimport {\n type ManyToManyField,\n type ManyToOneField,\n type OneToManyField,\n type OneToOneField,\n getMetadata,\n} from \"src/EntityMetadata.ts\";\nimport {\n type PartialOrNull,\n type TimestampSerde,\n asConcreteCstr,\n getConstructorFromTaggedId,\n getProperties,\n setOpt,\n} from \"src/index.ts\";\nimport { findExistingIfUniqueBy } from \"src/resurrection.ts\";\nimport { type OptIdsOf, type OptsOf } from \"src/typeMap.ts\";\nimport { type NullOrDefinedOr, toArray } from \"src/utils.ts\";\n\n/**\n * The type for `EntityManager.createOrUpdateUnsafe` that allows \"upsert\"-ish behavior.\n *\n * I.e. `T` is an entity with an optional id (create if unset, update if set), and we recurse\n * into any relations (references or collections) to allow those relations themselves to be\n * any combination of 1) ids to existing entities, 2) entities directly, 3) null/undefined\n * with the appropriate partial-update behavior, or 4) partials.\n */\nexport type DeepPartialOrNull<T extends Entity> = { id?: IdOf<T> | null } & AllowRelationsToBeIdsOrEntitiesOrPartials<\n PartialOrNull<OptsOf<T> & OptIdsOf<T>>\n> &\n OptIdsOf<T>;\n\n/** Flags that allow `upsert` to delete or remove entities. */\ntype CollectionFlags = {\n delete?: boolean | null;\n remove?: boolean | null;\n op?: \"remove\" | \"delete\" | \"include\" | \"incremental\";\n};\n\n/** Flag that allows `upsert` to delete. */\ntype DeleteFlag = {\n delete?: boolean | null;\n};\n\ntype AllowRelationsToBeIdsOrEntitiesOrPartials<T> = {\n [P in keyof T]: T[P] extends NullOrDefinedOr<infer U>\n ? U extends Array<infer V>\n ? V extends Entity\n ? Array<V | (DeepPartialOrNull<V> & CollectionFlags) | IdOf<V>> | null\n : T[P]\n : U extends Entity\n ? U | (DeepPartialOrNull<U> & DeleteFlag) | IdOf<U> | null\n : T[P]\n : T[P];\n};\n\n/**\n * A utility function to do partial-update style updates.\n *\n * The difference between this and `Entity.setPartial` is that we accept `DeepPartialOrNull`\n * updates, similar to `createOrUpdateUnsafe`, instead of just a flat/shallow list of opts.\n */\nexport async function updatePartial<T extends Entity>(entity: T, input: DeepPartialOrNull<T>): Promise<void> {\n if (Object.keys(input).length === 0) return;\n const meta = getMetadata(entity);\n const { em } = entity;\n // Do a Promise.all so we .load() relations in parallel\n await Promise.all(\n Object.entries(input).map(async ([key, value]) => {\n // setPartial ==> `undefined` is a noop\n if (value === undefined) return;\n\n // Watch for the `bookId` / `bookIds` aliases\n const field = meta.allFields[key] || Object.values(meta.allFields).find((f) => f.fieldIdName === key);\n\n if (!field) {\n // Allow (ignore here) delete/remove flags that we assume the API layer (i.e. GraphQL) will have specifically\n // allowed, i.e. this isn't the Rails form bug where users can POST in any random field they want.\n const flagField = key === \"delete\" || key === \"remove\" || key === \"op\";\n if (flagField) return;\n // Look for non-field properties like a fullName setter\n const prop = getProperties(meta)[key];\n if (prop) {\n setOpt(meta, entity, key, value);\n return;\n } else {\n throw new Error(`Unknown field ${key}`);\n }\n }\n\n // Don't use key b/c it might be the bookId alias\n const name = field.fieldName;\n\n if (field.kind === \"poly\" && value && !isEntity(value)) {\n // Resolve non-entity poly values\n if (isKey(value)) {\n setOpt(meta, entity, name, await em.load(getConstructorFromTaggedId(value), value));\n } else {\n throw new Error(`Cannot use partial value for polymorphic field `);\n }\n } else if (field.kind === \"m2o\" && value && !isEntity(value)) {\n // This is a many-to-one reference\n if (isKey(value)) {\n setOpt(meta, entity, name, await em.load(field.otherMetadata().cstr, value));\n } else if (typeof value === \"object\" && value) {\n let other: any;\n if (\"id\" in value) {\n // This is a many-to-one partial update to an existing entity (they passed an id)\n other = await upsert(em, field.otherMetadata().cstr, value as any);\n } else {\n // This is a many-to-one partial w/o passing an id, i.e. `upsert(Author, { id: \"a:1\", publisher: { name: \"p1\" } })`\n if (entity.isNewEntity) {\n // If we're brand new, our child/other has to be brand new as well\n other = await upsert(em, field.otherMetadata().cstr, value);\n } else {\n // the o2o upsert hash didn't have an id, so find-or-create it\n other = await (entity as any)[name].load();\n if (other) {\n await updatePartial(other, value);\n } else {\n other = await upsert(em, field.otherMetadata().cstr, value);\n }\n }\n }\n const deleteMarker = getDeleteMarker(field, value);\n if (deleteMarker) {\n em.delete(other);\n other = undefined;\n }\n setOpt(meta, entity, name, other);\n }\n } else if (field.kind === \"o2o\") {\n // ^-- o2o always need loaded to be set, so don't fall through\n if (value === null || isEntity(value)) {\n await (entity as any)[name].load();\n setOpt(meta, entity, name, value);\n } else if (isKey(value)) {\n const [, other] = await Promise.all([\n (entity as any)[name].load(),\n em.load(field.otherMetadata().cstr, value),\n ]);\n setOpt(meta, entity, name, other);\n } else if (typeof value === \"object\" && isPlainObject(value)) {\n const deleteMarker = getDeleteMarker(field, value);\n // Always load the o2o so we can set it\n const current = await (entity as any)[name].load();\n let other: any;\n if (\"id\" in value) {\n // The o2o upsert hash was passed an id, so load it\n other = await upsert(em, field.otherMetadata().cstr, value as any);\n } else {\n // the o2o upsert hash didn't have an id, so find-or-create it\n other = current;\n if (other) {\n await updatePartial(other, value);\n } else {\n other = await upsert(em, field.otherMetadata().cstr, value);\n }\n }\n if (deleteMarker) {\n em.delete(other);\n } else {\n setOpt(meta, entity, name, other);\n }\n } else {\n throw new Error(`Invalid value ${value}`);\n }\n } else if (field.kind === \"o2m\" || field.kind === \"m2m\") {\n // Look for one-to-many/many-to-many partials\n // `null` is handled later, and treated as `[]`, which needs the collection loaded\n\n const values = toArray(value);\n const otherMeta = field.otherMetadata();\n const maybeSoftDelete = otherMeta.timestampFields?.deletedAt;\n\n // Incremental handling. Detect incremental mode by a meaningful `op` value--`op: undefined`/`op: null`\n // is the natural shape of an optional field and must behave like \"no op\", consistent with how\n // updatePartial treats `value === undefined` and how delete/remove are read by truthiness.\n const anyValueHasOp = values.some((v: any) => v && typeof v === \"object\" && !isEntity(v) && v.op != null);\n if (anyValueHasOp) {\n let anyValueMissingOp = false;\n const current = (entity as any)[name];\n // The `op` behavior means incremental and wants to do this:\n await Promise.all(\n values.map(async (value: any) => {\n const [, , op] = getCollectionMarkers(field, value);\n if (op === \"delete\") {\n const other = await upsert(em, otherMeta.cstr, withOwnerField(field, value, entity));\n // We need to check if this is a soft-deletable entity, and if so, we will soft-delete it.\n if (maybeSoftDelete) {\n const serde = otherMeta.fields[maybeSoftDelete].serde as TimestampSerde<unknown>;\n const now = new Date();\n other.set({ [maybeSoftDelete]: serde.mapFromNow(now) });\n } else {\n entity.em.delete(other);\n }\n } else if (op === \"remove\") {\n const other = await upsert(em, otherMeta.cstr, withOwnerField(field, value, entity));\n current.remove(other);\n } else if (op === \"include\") {\n const other = await upsert(em, otherMeta.cstr, withOwnerField(field, value, entity));\n current.add(other);\n } else if (op === \"incremental\") {\n // This is a marker entry, just ignore it\n } else {\n // A child entered incremental mode (a sibling had a real op) but has no op of its own;\n // never silently skip it--flag it so the guard below throws instead of dropping the row.\n anyValueMissingOp = true;\n }\n }),\n );\n if (anyValueMissingOp) {\n throw new Error(\"If any child sets the `op` key, then all children must have the `op` key.\");\n }\n return; // return from the op-based incremental behavior\n }\n\n // Otherwise we do exhaustive sets, will still looking for `delete`/`remove` markers\n const others = await Promise.all(\n values.map(async (value: any) => {\n if (isEntity(value)) {\n return value;\n } else if (isKey(value)) {\n return em.load(field.otherMetadata().cstr, value);\n } else if (value === null || value === undefined) {\n return undefined;\n } else if (!isPlainObject(value)) {\n throw new Error(`Invalid value ${value}`);\n } else {\n // Look for `delete: true/false` and `remove: true/false` markers\n const [deleteMarker, removeMarker] = getCollectionMarkers(field, value);\n const other = await upsert(em, field.otherMetadata().cstr, withOwnerField(field, value, entity));\n if (deleteMarker) {\n // if (maybeSoftDelete) {\n // const serde = meta.fields[maybeSoftDelete].serde as TimestampSerde<unknown>;\n // const now = new Date();\n // other.set({ [maybeSoftDelete]: serde.mapFromNow(now) });\n // } else {\n // }\n em.delete(other);\n return other;\n } else if (removeMarker) {\n return undefined;\n } else {\n return other;\n }\n }\n }),\n );\n\n await (entity as any)[name].load();\n setOpt(\n meta,\n entity,\n name,\n others.filter((v) => v !== undefined),\n );\n } else {\n // If we get here, value should be a vanilla value that `setOpt` can handle/pass through as-is\n setOpt(meta, entity, name, value);\n }\n }),\n );\n}\n\n/**\n * A utility function to create-or-update/upsert entities coming from a partial-update style API.\n */\nexport async function upsert<T extends Entity>(\n em: EntityManager<any, any, any>,\n constructor: MaybeAbstractEntityConstructor<T>,\n input: DeepPartialOrNull<T>,\n): Promise<T> {\n const { id, ...rest } = input;\n const entity =\n id !== null && id !== undefined\n ? await em.load(constructor, id)\n : // Look for an existing entity we could resurrect\n ((id === undefined ? await findExistingIfUniqueBy(em, constructor, rest) : undefined) ??\n em.createPartial(asConcreteCstr(constructor), {}));\n await updatePartial(entity, rest as any);\n // Do this manually since we're not going through setOpts anymore\n if (entity.isNewEntity) {\n setSyncDefaults(entity);\n }\n return entity;\n}\n\n/**\n * Adds the o2m owner field so child resurrection can find rows whose `uniqueBy` includes their parent.\n * I.e. upserting `Author.books: [{ title: \"b1\" }]` should lookup `Book.uniqueBy = [[\"author\", \"title\"]]`.\n */\nfunction withOwnerField(field: OneToManyField | ManyToManyField, value: any, owner: Entity): any {\n if (field.kind !== \"o2m\" || !isPlainObject(value)) return value;\n const ownerField = field.otherFieldName;\n const ownerFieldId = field.otherMetadata().allFields[ownerField]?.fieldIdName;\n if (Object.hasOwn(value, ownerField) || (ownerFieldId && Object.hasOwn(value, ownerFieldId))) return value;\n if (ownerFieldId && !owner.isNewEntity) return { ...value, [ownerFieldId]: owner.id };\n return { ...value, [ownerField]: owner };\n}\n\nfunction getCollectionMarkers(field: OneToManyField | ManyToManyField, value: any): [any, any, any] {\n const allowDelete = !field.otherMetadata().fields[\"delete\"];\n const allowRemove = !field.otherMetadata().fields[\"remove\"];\n const allowOp = !field.otherMetadata().fields[\"op\"];\n\n // Look for `delete: true/false` and `remove: true/false` markers\n const deleteMarker: any = allowDelete && value[\"delete\"];\n const removeMarker: any = allowRemove && value[\"remove\"];\n const opMarker: any = allowOp && value[\"op\"];\n\n // Remove the markers, regardless of true/false, before recursing into upsert to avoid unknown fields\n if (deleteMarker !== undefined) delete value.delete;\n if (removeMarker !== undefined) delete value.remove;\n if (opMarker !== undefined) delete value.op;\n\n return [deleteMarker, removeMarker, opMarker];\n}\nfunction getDeleteMarker(field: OneToOneField | ManyToOneField, value: any): boolean {\n const allowDelete = !field.otherMetadata().fields[\"delete\"];\n const deleteMarker: any = allowDelete && value[\"delete\"];\n if (deleteMarker !== undefined) delete value.delete;\n return deleteMarker;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAkEA,eAAsB,cAAgC,QAAW,OAA4C;CAC3G,IAAI,OAAO,KAAK,KAAK,CAAC,CAAC,WAAW,GAAG;CACrC,MAAM,OAAO,YAAY,MAAM;CAC/B,MAAM,EAAE,OAAO;CAEf,MAAM,QAAQ,IACZ,OAAO,QAAQ,KAAK,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,WAAW;EAEhD,IAAI,UAAU,KAAA,GAAW;EAGzB,MAAM,QAAQ,KAAK,UAAU,QAAQ,OAAO,OAAO,KAAK,SAAS,CAAC,CAAC,MAAM,MAAM,EAAE,gBAAgB,GAAG;EAEpG,IAAI,CAAC,OAAO;GAIV,IADkB,QAAQ,YAAY,QAAQ,YAAY,QAAQ,MACnD;GAGf,IADa,cAAc,IAAI,CAAC,CAAC,MACvB;IACR,OAAO,MAAM,QAAQ,KAAK,KAAK;IAC/B;GACF,OACE,MAAM,IAAI,MAAM,iBAAiB,KAAK;EAE1C;EAGA,MAAM,OAAO,MAAM;EAEnB,IAAI,MAAM,SAAS,UAAU,SAAS,CAAC,SAAS,KAAK,GAAG;GAEtD,IAAI,MAAM,KAAK,GACb,OAAO,MAAM,QAAQ,MAAM,MAAM,GAAG,KAAK,2BAA2B,KAAK,GAAG,KAAK,CAAC;QAElF,MAAM,IAAI,MAAM,iDAAiD;EAErE,OAAO,IAAI,MAAM,SAAS,SAAS,SAAS,CAAC,SAAS,KAAK,GAAG;GAE5D,IAAI,MAAM,KAAK,GACb,OAAO,MAAM,QAAQ,MAAM,MAAM,GAAG,KAAK,MAAM,cAAc,CAAC,CAAC,MAAM,KAAK,CAAC;QACtE,IAAI,OAAO,UAAU,YAAY,OAAO;IAC7C,IAAI;IACJ,IAAI,QAAQ,OAEV,QAAQ,MAAM,OAAO,IAAI,MAAM,cAAc,CAAC,CAAC,MAAM,KAAY;SAGjE,IAAI,OAAO,aAET,QAAQ,MAAM,OAAO,IAAI,MAAM,cAAc,CAAC,CAAC,MAAM,KAAK;SACrD;KAEL,QAAQ,MAAO,OAAe,KAAK,CAAC,KAAK;KACzC,IAAI,OACF,MAAM,cAAc,OAAO,KAAK;UAEhC,QAAQ,MAAM,OAAO,IAAI,MAAM,cAAc,CAAC,CAAC,MAAM,KAAK;IAE9D;IAGF,IADqB,gBAAgB,OAAO,KAC7B,GAAG;KAChB,GAAG,OAAO,KAAK;KACf,QAAQ,KAAA;IACV;IACA,OAAO,MAAM,QAAQ,MAAM,KAAK;GAClC;EACF,OAAO,IAAI,MAAM,SAAS,OAAO;GAE/B,IAAI,UAAU,QAAQ,SAAS,KAAK,GAAG;IACrC,MAAO,OAAe,KAAK,CAAC,KAAK;IACjC,OAAO,MAAM,QAAQ,MAAM,KAAK;GAClC,OAAO,IAAI,MAAM,KAAK,GAAG;IACvB,MAAM,GAAG,SAAS,MAAM,QAAQ,IAAI,CACjC,OAAe,KAAK,CAAC,KAAK,GAC3B,GAAG,KAAK,MAAM,cAAc,CAAC,CAAC,MAAM,KAAK,CAC3C,CAAC;IACD,OAAO,MAAM,QAAQ,MAAM,KAAK;GAClC,OAAO,IAAI,OAAO,UAAU,YAAY,cAAc,KAAK,GAAG;IAC5D,MAAM,eAAe,gBAAgB,OAAO,KAAK;IAEjD,MAAM,UAAU,MAAO,OAAe,KAAK,CAAC,KAAK;IACjD,IAAI;IACJ,IAAI,QAAQ,OAEV,QAAQ,MAAM,OAAO,IAAI,MAAM,cAAc,CAAC,CAAC,MAAM,KAAY;SAC5D;KAEL,QAAQ;KACR,IAAI,OACF,MAAM,cAAc,OAAO,KAAK;UAEhC,QAAQ,MAAM,OAAO,IAAI,MAAM,cAAc,CAAC,CAAC,MAAM,KAAK;IAE9D;IACA,IAAI,cACF,GAAG,OAAO,KAAK;SAEf,OAAO,MAAM,QAAQ,MAAM,KAAK;GAEpC,OACE,MAAM,IAAI,MAAM,iBAAiB,OAAO;EAE5C,OAAO,IAAI,MAAM,SAAS,SAAS,MAAM,SAAS,OAAO;GAIvD,MAAM,SAAS,QAAQ,KAAK;GAC5B,MAAM,YAAY,MAAM,cAAc;GACtC,MAAM,kBAAkB,UAAU,iBAAiB;GAMnD,IADsB,OAAO,MAAM,MAAW,KAAK,OAAO,MAAM,YAAY,CAAC,SAAS,CAAC,KAAK,EAAE,MAAM,IACpF,GAAG;IACjB,IAAI,oBAAoB;IACxB,MAAM,UAAW,OAAe;IAEhC,MAAM,QAAQ,IACZ,OAAO,IAAI,OAAO,UAAe;KAC/B,MAAM,KAAK,MAAM,qBAAqB,OAAO,KAAK;KAClD,IAAI,OAAO,UAAU;MACnB,MAAM,QAAQ,MAAM,OAAO,IAAI,UAAU,MAAM,eAAe,OAAO,OAAO,MAAM,CAAC;MAEnF,IAAI,iBAAiB;OACnB,MAAM,QAAQ,UAAU,OAAO,gBAAgB,CAAC;OAChD,MAAM,sBAAM,IAAI,KAAK;OACrB,MAAM,IAAI,GAAG,kBAAkB,MAAM,WAAW,GAAG,EAAE,CAAC;MACxD,OACE,OAAO,GAAG,OAAO,KAAK;KAE1B,OAAO,IAAI,OAAO,UAAU;MAC1B,MAAM,QAAQ,MAAM,OAAO,IAAI,UAAU,MAAM,eAAe,OAAO,OAAO,MAAM,CAAC;MACnF,QAAQ,OAAO,KAAK;KACtB,OAAO,IAAI,OAAO,WAAW;MAC3B,MAAM,QAAQ,MAAM,OAAO,IAAI,UAAU,MAAM,eAAe,OAAO,OAAO,MAAM,CAAC;MACnF,QAAQ,IAAI,KAAK;KACnB,OAAO,IAAI,OAAO,eAAe,CAEjC,OAGE,oBAAoB;IAExB,CAAC,CACH;IACA,IAAI,mBACF,MAAM,IAAI,MAAM,2EAA2E;IAE7F;GACF;GAGA,MAAM,SAAS,MAAM,QAAQ,IAC3B,OAAO,IAAI,OAAO,UAAe;IAC/B,IAAI,SAAS,KAAK,GAChB,OAAO;SACF,IAAI,MAAM,KAAK,GACpB,OAAO,GAAG,KAAK,MAAM,cAAc,CAAC,CAAC,MAAM,KAAK;SAC3C,IAAI,UAAU,QAAQ,UAAU,KAAA,GACrC;SACK,IAAI,CAAC,cAAc,KAAK,GAC7B,MAAM,IAAI,MAAM,iBAAiB,OAAO;SACnC;KAEL,MAAM,CAAC,cAAc,gBAAgB,qBAAqB,OAAO,KAAK;KACtE,MAAM,QAAQ,MAAM,OAAO,IAAI,MAAM,cAAc,CAAC,CAAC,MAAM,eAAe,OAAO,OAAO,MAAM,CAAC;KAC/F,IAAI,cAAc;MAOhB,GAAG,OAAO,KAAK;MACf,OAAO;KACT,OAAO,IAAI,cACT;UAEA,OAAO;IAEX;GACF,CAAC,CACH;GAEA,MAAO,OAAe,KAAK,CAAC,KAAK;GACjC,OACE,MACA,QACA,MACA,OAAO,QAAQ,MAAM,MAAM,KAAA,CAAS,CACtC;EACF,OAEE,OAAO,MAAM,QAAQ,MAAM,KAAK;CAEpC,CAAC,CACH;AACF;;;;AAKA,eAAsB,OACpB,IACA,aACA,OACY;CACZ,MAAM,EAAE,IAAI,GAAG,SAAS;CACxB,MAAM,SACJ,OAAO,QAAQ,OAAO,KAAA,IAClB,MAAM,GAAG,KAAK,aAAa,EAAE,KAE3B,OAAO,KAAA,IAAY,MAAM,uBAAuB,IAAI,aAAa,IAAI,IAAI,KAAA,MAC3E,GAAG,cAAc,eAAe,WAAW,GAAG,CAAC,CAAC;CACtD,MAAM,cAAc,QAAQ,IAAW;CAEvC,IAAI,OAAO,aACT,gBAAgB,MAAM;CAExB,OAAO;AACT;;;;;AAMA,SAAS,eAAe,OAAyC,OAAY,OAAoB;CAC/F,IAAI,MAAM,SAAS,SAAS,CAAC,cAAc,KAAK,GAAG,OAAO;CAC1D,MAAM,aAAa,MAAM;CACzB,MAAM,eAAe,MAAM,cAAc,CAAC,CAAC,UAAU,WAAW,EAAE;CAClE,IAAI,OAAO,OAAO,OAAO,UAAU,KAAM,gBAAgB,OAAO,OAAO,OAAO,YAAY,GAAI,OAAO;CACrG,IAAI,gBAAgB,CAAC,MAAM,aAAa,OAAO;EAAE,GAAG;GAAQ,eAAe,MAAM;CAAG;CACpF,OAAO;EAAE,GAAG;GAAQ,aAAa;CAAM;AACzC;AAEA,SAAS,qBAAqB,OAAyC,OAA6B;CAClG,MAAM,cAAc,CAAC,MAAM,cAAc,CAAC,CAAC,OAAO;CAClD,MAAM,cAAc,CAAC,MAAM,cAAc,CAAC,CAAC,OAAO;CAClD,MAAM,UAAU,CAAC,MAAM,cAAc,CAAC,CAAC,OAAO;CAG9C,MAAM,eAAoB,eAAe,MAAM;CAC/C,MAAM,eAAoB,eAAe,MAAM;CAC/C,MAAM,WAAgB,WAAW,MAAM;CAGvC,IAAI,iBAAiB,KAAA,GAAW,OAAO,MAAM;CAC7C,IAAI,iBAAiB,KAAA,GAAW,OAAO,MAAM;CAC7C,IAAI,aAAa,KAAA,GAAW,OAAO,MAAM;CAEzC,OAAO;EAAC;EAAc;EAAc;CAAQ;AAC9C;AACA,SAAS,gBAAgB,OAAuC,OAAqB;CAEnF,MAAM,eAAoB,CADL,MAAM,cAAc,CAAC,CAAC,OAAO,aACT,MAAM;CAC/C,IAAI,iBAAiB,KAAA,GAAW,OAAO,MAAM;CAC7C,OAAO;AACT"}
package/build/utils.cjs CHANGED
@@ -1,6 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_relations_Reference = require("./relations/Reference.cjs");
3
- require("./loadHints.cjs");
4
3
  const require_relations_ReactiveField = require("./relations/ReactiveField.cjs");
5
4
  require("./relations/index.cjs");
6
5
  const require_EntityManager = require("./EntityManager.cjs");
@@ -1 +1 @@
1
- {"version":3,"file":"utils.cjs","names":["isReactiveField","isReference","isDefined"],"sources":["../src/utils.ts"],"sourcesContent":["import { type Entity } from \"./Entity.ts\";\nimport { isDefined } from \"./EntityManager.ts\";\nimport { type New } from \"./loadHints.ts\";\nimport type { OrderBy } from \"./queries/find/EntityFilter.ts\";\nimport { isReactiveField, isReference } from \"./relations/index.ts\";\n\nexport type MaybePromise<T> = T | Promise<T>;\n\n/**\n * Given a `MaybePromise` of T, invoke `callback` against `T` either immediately or via `then`.\n *\n * This is the same as:\n *\n * ```\n * const r = await maybePromise;\n * return callback(r;;\n * ```\n *\n * But saves an `await` if `maybePromise` is not actually a promise.\n */\nexport function maybePromiseThen<T, U>(promiseOrObj: MaybePromise<T>, callback: (obj: T) => U): MaybePromise<U> {\n return promiseOrObj instanceof Promise ? promiseOrObj.then(callback) : callback(promiseOrObj);\n}\n\nexport function failIfAnyRejected<T>(results: PromiseSettledResult<T>[]): T[] {\n const rejects = results.filter((r) => r.status === \"rejected\");\n // For now just throw the 1st rejection; this should be pretty rare\n if (rejects.length > 0 && rejects[0].status === \"rejected\") {\n throw rejects[0].reason;\n }\n return results.map((r) => (r as PromiseFulfilledResult<T>).value);\n}\n\nexport function getOrSet<T extends Record<keyof unknown, unknown>>(\n record: T,\n key: keyof T,\n defaultValue: T[keyof T] | (() => T[keyof T]),\n): T[keyof T] {\n if (record[key] === undefined) {\n record[key] = defaultValue instanceof Function ? defaultValue() : defaultValue;\n }\n return record[key];\n}\n\n/** Defines a getter that replaces itself with its computed value on first access. */\nexport function defineLazyGetter<T extends object, K extends keyof T>(obj: T, key: K, build: () => T[K]): void {\n Object.defineProperty(obj, key, {\n configurable: true,\n get: function getLazyProperty() {\n const value = build();\n Object.defineProperty(obj, key, { configurable: true, value });\n return value;\n },\n });\n}\n\n/**\n * A utility to ensure a Promise-returning method actually returns a promise and doesn't\n * early exit. Using `async function` guarantees these semantics, but sometimes we avoid\n * `async` as a likely-premature optimization to avoid the overhead.\n */\nexport function tryResolve<T>(fn: () => T): Promise<T> {\n try {\n return Promise.resolve(fn());\n } catch (e) {\n return Promise.reject(e);\n }\n}\n\n/** Returns whether `obj` has at least one key, without allocating a keys array. */\nexport function hasAnyKey(obj: Record<any, any> | undefined): boolean {\n for (const _ in obj) return true;\n return false;\n}\n\nexport function fail(message?: string): never {\n throw new Error(message || \"Failed\");\n}\n\nexport function remove<T>(array: T[], t: T): void {\n const index = array.indexOf(t);\n if (index > -1) {\n array.splice(index, 1);\n }\n}\n\nexport function maybeRemove<T>(array: T[] | undefined, t: T): void {\n if (array) remove(array, t);\n}\n\nexport function maybeAdd<T>(array: T[], t: T): void {\n if (!array.includes(t)) {\n array.push(t);\n }\n}\n\nexport function clear<T>(array: T[]): void {\n array.splice(0, array.length);\n}\n\n/** Returns 0 inclusive to n exclusive. */\nexport function zeroTo(n: number): number[] {\n return [...Array(n).keys()];\n}\n\nexport function groupBy<T, Y = T, K = string>(list: readonly T[], fn: (x: T) => K, valueFn?: (x: T) => Y): Map<K, Y[]> {\n const result = new Map<K, Y[]>();\n list.forEach((o) => {\n const group = fn(o);\n if (!result.has(group)) {\n result.set(group, []);\n }\n result.get(group)!.push(valueFn === undefined ? (o as any as Y) : valueFn(o));\n });\n return result;\n}\n\nexport function indexBy<T, Y = T, K = string>(list: T[], fn: (x: T) => K, valueFn?: (x: T) => Y): Map<K, Y> {\n const result = new Map<K, Y>();\n list.forEach((o) => {\n const group = fn(o);\n result.set(group, valueFn === undefined ? (o as any as Y) : valueFn(o));\n });\n return result;\n}\n\nexport function batched<T>(list: Array<T>, n: number): T[][] {\n const result = [] as T[][];\n for (let i = 0; i < list.length; i += n) {\n result.push(list.slice(i, i + n));\n }\n return result;\n}\n\nexport function partition<T>(array: ReadonlyArray<T>, f: (el: T) => boolean): [T[], T[]] {\n const trueElements: T[] = [];\n const falseElements: T[] = [];\n array.forEach((el) => {\n if (f(el)) {\n trueElements.push(el);\n } else {\n falseElements.push(el);\n }\n });\n return [trueElements, falseElements];\n}\n\n// Utility function to wrap an object or value in an array, unless it's already an array\nexport function toArray<T>(maybeArray: T | T[] | undefined | null): T[] {\n return Array.isArray(maybeArray) ? maybeArray : maybeArray === undefined || maybeArray === null ? [] : [maybeArray];\n}\n\n// Utility type to strip off null and defined and infer only T.\nexport type NullOrDefinedOr<T> = T | null | undefined;\n\nexport function assertNever(x: never): never {\n throw new Error(\"Unexpected object: \" + x);\n}\n\nexport function abbreviation(tableName: string): string {\n return tableName\n .split(\"_\")\n .map((w) => w[0])\n .join(\"\");\n}\n\n/**\n * Utility method for casting `entity` to a `New` entity.\n *\n * Note that we don't actually do any runtime checks; a very simple one would be if the id is undefined,\n * but we want this method to be used in tests that are post-`flush` but still \"know\" the entity is\n * effectively new / fully loaded.\n *\n * Granted, we could do a runtime check that all relations are loaded.\n */\nexport function asNew<T extends Entity>(entity: T): New<T> {\n return entity as New<T>;\n}\n\nexport function compareValues(av: any, bv: any, direction: OrderBy): number {\n const d = direction === \"ASC\" ? 1 : -1;\n if (isReactiveField(av)) {\n av = !av.isSet ? -1 : av.get;\n }\n if (isReactiveField(bv)) {\n bv = !bv.isSet ? -1 : bv.get;\n }\n if (isReference(av) && isReference(bv)) {\n const aIsNew = av.isLoaded && (av as any).get?.isNewEntity;\n const bIsNew = bv.isLoaded && (bv as any).get?.isNewEntity;\n const bothSame = (aIsNew && bIsNew) || (!aIsNew && !bIsNew);\n if (!bothSame) {\n if (aIsNew) return 1 * d; // New entities are always \"greater than\" loaded entities\n if (bIsNew) return -1 * d; // Loaded entities are always \"less than\" new entities\n }\n av = av.idTaggedMaybe ?? (av.isLoaded && (av as any).get?.toString()) ?? undefined;\n bv = bv.idTaggedMaybe ?? (bv.isLoaded && (bv as any).get?.toString()) ?? undefined;\n }\n if (!isDefined(av) || !isDefined(bv)) {\n return !av && !bv ? 0 : (!av ? 1 : -1) * d;\n } else if (typeof av === \"number\" && typeof bv === \"number\") {\n return (av - bv) * d;\n } else if (typeof av === \"string\" && typeof bv === \"string\") {\n return av.localeCompare(bv) * d;\n } else if (av instanceof Date && bv instanceof Date) {\n return ((av as Date).getTime() - (bv as Date).getTime()) * d;\n } else {\n throw new Error(`Unsupported sortBy values ${av}, ${bv}`);\n }\n}\n\n/** A ~naive deep merge that requires already-normalized hints and will mutate `source`. */\n// https://gist.github.com/ahtcx/0cd94e62691f539160b32ecda18af3d6\nexport function mergeNormalizedHints(target: any, source: any): void {\n for (const key of Object.keys(source)) {\n // We assume both target & source are already normalized, i.e. we won't have\n // source=\"books\" and target={books: \"title\"}. They will both be {books: ...}.\n if (target[key]) {\n mergeNormalizedHints(source[key], target[key]);\n }\n }\n Object.assign(target, source);\n}\n\nconst newLine = /\\n/g;\nconst doubleSpace = / +/g;\n\nexport function cleanStringValue(value: unknown): string | undefined {\n // If this is not a string, coerce it -- or maybe fail?\n let s = typeof value !== \"string\" && value !== undefined && value !== null ? String(value) : value;\n // We always trim to remove leading/trailing spaces\n s = typeof s === \"string\" ? s.trim() : s;\n // And if it's empty string, we swap to undefined (null in the db)\n return s === \"\" || s === null ? undefined : s;\n}\n\n/** Strips new lines/indentation from our `UPDATE` string; doesn't do any actual SQL param escaping/etc. */\nexport function cleanSql(sql: string): string {\n return sql.trim().replace(newLine, \"\").replace(doubleSpace, \" \");\n}\n\n// Collections return an array, so do a hot-path `.flat()`\nexport function flatAndUnique<T extends unknown>(list: (T | T[] | undefined)[]): Set<T> {\n const result = new Set<T>();\n for (const c of list) {\n if (Array.isArray(c)) {\n for (const e of c) result.add(e);\n } else if (c) {\n result.add(c);\n }\n }\n return result;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"utils.cjs","names":["isReactiveField","isReference","isDefined"],"sources":["../src/utils.ts"],"sourcesContent":["import { type Entity } from \"src/Entity.ts\";\nimport { isDefined } from \"src/EntityManager.ts\";\nimport type { New } from \"src/loading/loadHints.ts\";\nimport type { OrderBy } from \"src/queries/find/EntityFilter.ts\";\nimport { isReactiveField, isReference } from \"src/relations/index.ts\";\n\nexport type MaybePromise<T> = T | Promise<T>;\n\n/**\n * Given a `MaybePromise` of T, invoke `callback` against `T` either immediately or via `then`.\n *\n * This is the same as:\n *\n * ```\n * const r = await maybePromise;\n * return callback(r;;\n * ```\n *\n * But saves an `await` if `maybePromise` is not actually a promise.\n */\nexport function maybePromiseThen<T, U>(promiseOrObj: MaybePromise<T>, callback: (obj: T) => U): MaybePromise<U> {\n return promiseOrObj instanceof Promise ? promiseOrObj.then(callback) : callback(promiseOrObj);\n}\n\nexport function failIfAnyRejected<T>(results: PromiseSettledResult<T>[]): T[] {\n const rejects = results.filter((r) => r.status === \"rejected\");\n // For now just throw the 1st rejection; this should be pretty rare\n if (rejects.length > 0 && rejects[0].status === \"rejected\") {\n throw rejects[0].reason;\n }\n return results.map((r) => (r as PromiseFulfilledResult<T>).value);\n}\n\nexport function getOrSet<T extends Record<keyof unknown, unknown>>(\n record: T,\n key: keyof T,\n defaultValue: T[keyof T] | (() => T[keyof T]),\n): T[keyof T] {\n if (record[key] === undefined) {\n record[key] = defaultValue instanceof Function ? defaultValue() : defaultValue;\n }\n return record[key];\n}\n\n/** Defines a getter that replaces itself with its computed value on first access. */\nexport function defineLazyGetter<T extends object, K extends keyof T>(obj: T, key: K, build: () => T[K]): void {\n Object.defineProperty(obj, key, {\n configurable: true,\n get: function getLazyProperty() {\n const value = build();\n Object.defineProperty(obj, key, { configurable: true, value });\n return value;\n },\n });\n}\n\n/**\n * A utility to ensure a Promise-returning method actually returns a promise and doesn't\n * early exit. Using `async function` guarantees these semantics, but sometimes we avoid\n * `async` as a likely-premature optimization to avoid the overhead.\n */\nexport function tryResolve<T>(fn: () => T): Promise<T> {\n try {\n return Promise.resolve(fn());\n } catch (e) {\n return Promise.reject(e);\n }\n}\n\n/** Returns whether `obj` has at least one key, without allocating a keys array. */\nexport function hasAnyKey(obj: Record<any, any> | undefined): boolean {\n for (const _ in obj) return true;\n return false;\n}\n\nexport function fail(message?: string): never {\n throw new Error(message || \"Failed\");\n}\n\nexport function remove<T>(array: T[], t: T): void {\n const index = array.indexOf(t);\n if (index > -1) {\n array.splice(index, 1);\n }\n}\n\nexport function maybeRemove<T>(array: T[] | undefined, t: T): void {\n if (array) remove(array, t);\n}\n\nexport function maybeAdd<T>(array: T[], t: T): void {\n if (!array.includes(t)) {\n array.push(t);\n }\n}\n\nexport function clear<T>(array: T[]): void {\n array.splice(0, array.length);\n}\n\n/** Returns 0 inclusive to n exclusive. */\nexport function zeroTo(n: number): number[] {\n return [...Array(n).keys()];\n}\n\nexport function groupBy<T, Y = T, K = string>(list: readonly T[], fn: (x: T) => K, valueFn?: (x: T) => Y): Map<K, Y[]> {\n const result = new Map<K, Y[]>();\n list.forEach((o) => {\n const group = fn(o);\n if (!result.has(group)) {\n result.set(group, []);\n }\n result.get(group)!.push(valueFn === undefined ? (o as any as Y) : valueFn(o));\n });\n return result;\n}\n\nexport function indexBy<T, Y = T, K = string>(list: T[], fn: (x: T) => K, valueFn?: (x: T) => Y): Map<K, Y> {\n const result = new Map<K, Y>();\n list.forEach((o) => {\n const group = fn(o);\n result.set(group, valueFn === undefined ? (o as any as Y) : valueFn(o));\n });\n return result;\n}\n\nexport function batched<T>(list: Array<T>, n: number): T[][] {\n const result = [] as T[][];\n for (let i = 0; i < list.length; i += n) {\n result.push(list.slice(i, i + n));\n }\n return result;\n}\n\nexport function partition<T>(array: ReadonlyArray<T>, f: (el: T) => boolean): [T[], T[]] {\n const trueElements: T[] = [];\n const falseElements: T[] = [];\n array.forEach((el) => {\n if (f(el)) {\n trueElements.push(el);\n } else {\n falseElements.push(el);\n }\n });\n return [trueElements, falseElements];\n}\n\n// Utility function to wrap an object or value in an array, unless it's already an array\nexport function toArray<T>(maybeArray: T | T[] | undefined | null): T[] {\n return Array.isArray(maybeArray) ? maybeArray : maybeArray === undefined || maybeArray === null ? [] : [maybeArray];\n}\n\n// Utility type to strip off null and defined and infer only T.\nexport type NullOrDefinedOr<T> = T | null | undefined;\n\nexport function assertNever(x: never): never {\n throw new Error(\"Unexpected object: \" + x);\n}\n\nexport function abbreviation(tableName: string): string {\n return tableName\n .split(\"_\")\n .map((w) => w[0])\n .join(\"\");\n}\n\n/**\n * Utility method for casting `entity` to a `New` entity.\n *\n * Note that we don't actually do any runtime checks; a very simple one would be if the id is undefined,\n * but we want this method to be used in tests that are post-`flush` but still \"know\" the entity is\n * effectively new / fully loaded.\n *\n * Granted, we could do a runtime check that all relations are loaded.\n */\nexport function asNew<T extends Entity>(entity: T): New<T> {\n return entity as New<T>;\n}\n\nexport function compareValues(av: any, bv: any, direction: OrderBy): number {\n const d = direction === \"ASC\" ? 1 : -1;\n if (isReactiveField(av)) {\n av = !av.isSet ? -1 : av.get;\n }\n if (isReactiveField(bv)) {\n bv = !bv.isSet ? -1 : bv.get;\n }\n if (isReference(av) && isReference(bv)) {\n const aIsNew = av.isLoaded && (av as any).get?.isNewEntity;\n const bIsNew = bv.isLoaded && (bv as any).get?.isNewEntity;\n const bothSame = (aIsNew && bIsNew) || (!aIsNew && !bIsNew);\n if (!bothSame) {\n if (aIsNew) return 1 * d; // New entities are always \"greater than\" loaded entities\n if (bIsNew) return -1 * d; // Loaded entities are always \"less than\" new entities\n }\n av = av.idTaggedMaybe ?? (av.isLoaded && (av as any).get?.toString()) ?? undefined;\n bv = bv.idTaggedMaybe ?? (bv.isLoaded && (bv as any).get?.toString()) ?? undefined;\n }\n if (!isDefined(av) || !isDefined(bv)) {\n return !av && !bv ? 0 : (!av ? 1 : -1) * d;\n } else if (typeof av === \"number\" && typeof bv === \"number\") {\n return (av - bv) * d;\n } else if (typeof av === \"string\" && typeof bv === \"string\") {\n return av.localeCompare(bv) * d;\n } else if (av instanceof Date && bv instanceof Date) {\n return ((av as Date).getTime() - (bv as Date).getTime()) * d;\n } else {\n throw new Error(`Unsupported sortBy values ${av}, ${bv}`);\n }\n}\n\n/** A ~naive deep merge that requires already-normalized hints and will mutate `source`. */\n// https://gist.github.com/ahtcx/0cd94e62691f539160b32ecda18af3d6\nexport function mergeNormalizedHints(target: any, source: any): void {\n for (const key of Object.keys(source)) {\n // We assume both target & source are already normalized, i.e. we won't have\n // source=\"books\" and target={books: \"title\"}. They will both be {books: ...}.\n if (target[key]) {\n mergeNormalizedHints(source[key], target[key]);\n }\n }\n Object.assign(target, source);\n}\n\nconst newLine = /\\n/g;\nconst doubleSpace = / +/g;\n\nexport function cleanStringValue(value: unknown): string | undefined {\n // If this is not a string, coerce it -- or maybe fail?\n let s = typeof value !== \"string\" && value !== undefined && value !== null ? String(value) : value;\n // We always trim to remove leading/trailing spaces\n s = typeof s === \"string\" ? s.trim() : s;\n // And if it's empty string, we swap to undefined (null in the db)\n return s === \"\" || s === null ? undefined : s;\n}\n\n/** Strips new lines/indentation from our `UPDATE` string; doesn't do any actual SQL param escaping/etc. */\nexport function cleanSql(sql: string): string {\n return sql.trim().replace(newLine, \"\").replace(doubleSpace, \" \");\n}\n\n// Collections return an array, so do a hot-path `.flat()`\nexport function flatAndUnique<T extends unknown>(list: (T | T[] | undefined)[]): Set<T> {\n const result = new Set<T>();\n for (const c of list) {\n if (Array.isArray(c)) {\n for (const e of c) result.add(e);\n } else if (c) {\n result.add(c);\n }\n }\n return result;\n}\n"],"mappings":"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"}
package/build/utils.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { OrderBy } from "./queries/find/EntityFilter.cjs";
2
- import { New } from "./loadHints.cjs";
2
+ import { New } from "./loading/loadHints.cjs";
3
3
  import { Entity } from "./Entity.cjs";
4
4
  //#region src/utils.d.ts
5
5
  type MaybePromise<T> = T | Promise<T>;
package/build/utils.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { OrderBy } from "./queries/find/EntityFilter.mjs";
2
- import { New } from "./loadHints.mjs";
2
+ import { New } from "./loading/loadHints.mjs";
3
3
  import { Entity } from "./Entity.mjs";
4
4
  //#region src/utils.d.ts
5
5
  type MaybePromise<T> = T | Promise<T>;
package/build/utils.js CHANGED
@@ -1,5 +1,4 @@
1
1
  import { isReference } from "./relations/Reference.js";
2
- import "./loadHints.js";
3
2
  import { isReactiveField } from "./relations/ReactiveField.js";
4
3
  import "./relations/index.js";
5
4
  import { isDefined } from "./EntityManager.js";
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","names":[],"sources":["../src/utils.ts"],"sourcesContent":["import { type Entity } from \"./Entity.ts\";\nimport { isDefined } from \"./EntityManager.ts\";\nimport { type New } from \"./loadHints.ts\";\nimport type { OrderBy } from \"./queries/find/EntityFilter.ts\";\nimport { isReactiveField, isReference } from \"./relations/index.ts\";\n\nexport type MaybePromise<T> = T | Promise<T>;\n\n/**\n * Given a `MaybePromise` of T, invoke `callback` against `T` either immediately or via `then`.\n *\n * This is the same as:\n *\n * ```\n * const r = await maybePromise;\n * return callback(r;;\n * ```\n *\n * But saves an `await` if `maybePromise` is not actually a promise.\n */\nexport function maybePromiseThen<T, U>(promiseOrObj: MaybePromise<T>, callback: (obj: T) => U): MaybePromise<U> {\n return promiseOrObj instanceof Promise ? promiseOrObj.then(callback) : callback(promiseOrObj);\n}\n\nexport function failIfAnyRejected<T>(results: PromiseSettledResult<T>[]): T[] {\n const rejects = results.filter((r) => r.status === \"rejected\");\n // For now just throw the 1st rejection; this should be pretty rare\n if (rejects.length > 0 && rejects[0].status === \"rejected\") {\n throw rejects[0].reason;\n }\n return results.map((r) => (r as PromiseFulfilledResult<T>).value);\n}\n\nexport function getOrSet<T extends Record<keyof unknown, unknown>>(\n record: T,\n key: keyof T,\n defaultValue: T[keyof T] | (() => T[keyof T]),\n): T[keyof T] {\n if (record[key] === undefined) {\n record[key] = defaultValue instanceof Function ? defaultValue() : defaultValue;\n }\n return record[key];\n}\n\n/** Defines a getter that replaces itself with its computed value on first access. */\nexport function defineLazyGetter<T extends object, K extends keyof T>(obj: T, key: K, build: () => T[K]): void {\n Object.defineProperty(obj, key, {\n configurable: true,\n get: function getLazyProperty() {\n const value = build();\n Object.defineProperty(obj, key, { configurable: true, value });\n return value;\n },\n });\n}\n\n/**\n * A utility to ensure a Promise-returning method actually returns a promise and doesn't\n * early exit. Using `async function` guarantees these semantics, but sometimes we avoid\n * `async` as a likely-premature optimization to avoid the overhead.\n */\nexport function tryResolve<T>(fn: () => T): Promise<T> {\n try {\n return Promise.resolve(fn());\n } catch (e) {\n return Promise.reject(e);\n }\n}\n\n/** Returns whether `obj` has at least one key, without allocating a keys array. */\nexport function hasAnyKey(obj: Record<any, any> | undefined): boolean {\n for (const _ in obj) return true;\n return false;\n}\n\nexport function fail(message?: string): never {\n throw new Error(message || \"Failed\");\n}\n\nexport function remove<T>(array: T[], t: T): void {\n const index = array.indexOf(t);\n if (index > -1) {\n array.splice(index, 1);\n }\n}\n\nexport function maybeRemove<T>(array: T[] | undefined, t: T): void {\n if (array) remove(array, t);\n}\n\nexport function maybeAdd<T>(array: T[], t: T): void {\n if (!array.includes(t)) {\n array.push(t);\n }\n}\n\nexport function clear<T>(array: T[]): void {\n array.splice(0, array.length);\n}\n\n/** Returns 0 inclusive to n exclusive. */\nexport function zeroTo(n: number): number[] {\n return [...Array(n).keys()];\n}\n\nexport function groupBy<T, Y = T, K = string>(list: readonly T[], fn: (x: T) => K, valueFn?: (x: T) => Y): Map<K, Y[]> {\n const result = new Map<K, Y[]>();\n list.forEach((o) => {\n const group = fn(o);\n if (!result.has(group)) {\n result.set(group, []);\n }\n result.get(group)!.push(valueFn === undefined ? (o as any as Y) : valueFn(o));\n });\n return result;\n}\n\nexport function indexBy<T, Y = T, K = string>(list: T[], fn: (x: T) => K, valueFn?: (x: T) => Y): Map<K, Y> {\n const result = new Map<K, Y>();\n list.forEach((o) => {\n const group = fn(o);\n result.set(group, valueFn === undefined ? (o as any as Y) : valueFn(o));\n });\n return result;\n}\n\nexport function batched<T>(list: Array<T>, n: number): T[][] {\n const result = [] as T[][];\n for (let i = 0; i < list.length; i += n) {\n result.push(list.slice(i, i + n));\n }\n return result;\n}\n\nexport function partition<T>(array: ReadonlyArray<T>, f: (el: T) => boolean): [T[], T[]] {\n const trueElements: T[] = [];\n const falseElements: T[] = [];\n array.forEach((el) => {\n if (f(el)) {\n trueElements.push(el);\n } else {\n falseElements.push(el);\n }\n });\n return [trueElements, falseElements];\n}\n\n// Utility function to wrap an object or value in an array, unless it's already an array\nexport function toArray<T>(maybeArray: T | T[] | undefined | null): T[] {\n return Array.isArray(maybeArray) ? maybeArray : maybeArray === undefined || maybeArray === null ? [] : [maybeArray];\n}\n\n// Utility type to strip off null and defined and infer only T.\nexport type NullOrDefinedOr<T> = T | null | undefined;\n\nexport function assertNever(x: never): never {\n throw new Error(\"Unexpected object: \" + x);\n}\n\nexport function abbreviation(tableName: string): string {\n return tableName\n .split(\"_\")\n .map((w) => w[0])\n .join(\"\");\n}\n\n/**\n * Utility method for casting `entity` to a `New` entity.\n *\n * Note that we don't actually do any runtime checks; a very simple one would be if the id is undefined,\n * but we want this method to be used in tests that are post-`flush` but still \"know\" the entity is\n * effectively new / fully loaded.\n *\n * Granted, we could do a runtime check that all relations are loaded.\n */\nexport function asNew<T extends Entity>(entity: T): New<T> {\n return entity as New<T>;\n}\n\nexport function compareValues(av: any, bv: any, direction: OrderBy): number {\n const d = direction === \"ASC\" ? 1 : -1;\n if (isReactiveField(av)) {\n av = !av.isSet ? -1 : av.get;\n }\n if (isReactiveField(bv)) {\n bv = !bv.isSet ? -1 : bv.get;\n }\n if (isReference(av) && isReference(bv)) {\n const aIsNew = av.isLoaded && (av as any).get?.isNewEntity;\n const bIsNew = bv.isLoaded && (bv as any).get?.isNewEntity;\n const bothSame = (aIsNew && bIsNew) || (!aIsNew && !bIsNew);\n if (!bothSame) {\n if (aIsNew) return 1 * d; // New entities are always \"greater than\" loaded entities\n if (bIsNew) return -1 * d; // Loaded entities are always \"less than\" new entities\n }\n av = av.idTaggedMaybe ?? (av.isLoaded && (av as any).get?.toString()) ?? undefined;\n bv = bv.idTaggedMaybe ?? (bv.isLoaded && (bv as any).get?.toString()) ?? undefined;\n }\n if (!isDefined(av) || !isDefined(bv)) {\n return !av && !bv ? 0 : (!av ? 1 : -1) * d;\n } else if (typeof av === \"number\" && typeof bv === \"number\") {\n return (av - bv) * d;\n } else if (typeof av === \"string\" && typeof bv === \"string\") {\n return av.localeCompare(bv) * d;\n } else if (av instanceof Date && bv instanceof Date) {\n return ((av as Date).getTime() - (bv as Date).getTime()) * d;\n } else {\n throw new Error(`Unsupported sortBy values ${av}, ${bv}`);\n }\n}\n\n/** A ~naive deep merge that requires already-normalized hints and will mutate `source`. */\n// https://gist.github.com/ahtcx/0cd94e62691f539160b32ecda18af3d6\nexport function mergeNormalizedHints(target: any, source: any): void {\n for (const key of Object.keys(source)) {\n // We assume both target & source are already normalized, i.e. we won't have\n // source=\"books\" and target={books: \"title\"}. They will both be {books: ...}.\n if (target[key]) {\n mergeNormalizedHints(source[key], target[key]);\n }\n }\n Object.assign(target, source);\n}\n\nconst newLine = /\\n/g;\nconst doubleSpace = / +/g;\n\nexport function cleanStringValue(value: unknown): string | undefined {\n // If this is not a string, coerce it -- or maybe fail?\n let s = typeof value !== \"string\" && value !== undefined && value !== null ? String(value) : value;\n // We always trim to remove leading/trailing spaces\n s = typeof s === \"string\" ? s.trim() : s;\n // And if it's empty string, we swap to undefined (null in the db)\n return s === \"\" || s === null ? undefined : s;\n}\n\n/** Strips new lines/indentation from our `UPDATE` string; doesn't do any actual SQL param escaping/etc. */\nexport function cleanSql(sql: string): string {\n return sql.trim().replace(newLine, \"\").replace(doubleSpace, \" \");\n}\n\n// Collections return an array, so do a hot-path `.flat()`\nexport function flatAndUnique<T extends unknown>(list: (T | T[] | undefined)[]): Set<T> {\n const result = new Set<T>();\n for (const c of list) {\n if (Array.isArray(c)) {\n for (const e of c) result.add(e);\n } else if (c) {\n result.add(c);\n }\n }\n return result;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"utils.js","names":[],"sources":["../src/utils.ts"],"sourcesContent":["import { type Entity } from \"src/Entity.ts\";\nimport { isDefined } from \"src/EntityManager.ts\";\nimport type { New } from \"src/loading/loadHints.ts\";\nimport type { OrderBy } from \"src/queries/find/EntityFilter.ts\";\nimport { isReactiveField, isReference } from \"src/relations/index.ts\";\n\nexport type MaybePromise<T> = T | Promise<T>;\n\n/**\n * Given a `MaybePromise` of T, invoke `callback` against `T` either immediately or via `then`.\n *\n * This is the same as:\n *\n * ```\n * const r = await maybePromise;\n * return callback(r;;\n * ```\n *\n * But saves an `await` if `maybePromise` is not actually a promise.\n */\nexport function maybePromiseThen<T, U>(promiseOrObj: MaybePromise<T>, callback: (obj: T) => U): MaybePromise<U> {\n return promiseOrObj instanceof Promise ? promiseOrObj.then(callback) : callback(promiseOrObj);\n}\n\nexport function failIfAnyRejected<T>(results: PromiseSettledResult<T>[]): T[] {\n const rejects = results.filter((r) => r.status === \"rejected\");\n // For now just throw the 1st rejection; this should be pretty rare\n if (rejects.length > 0 && rejects[0].status === \"rejected\") {\n throw rejects[0].reason;\n }\n return results.map((r) => (r as PromiseFulfilledResult<T>).value);\n}\n\nexport function getOrSet<T extends Record<keyof unknown, unknown>>(\n record: T,\n key: keyof T,\n defaultValue: T[keyof T] | (() => T[keyof T]),\n): T[keyof T] {\n if (record[key] === undefined) {\n record[key] = defaultValue instanceof Function ? defaultValue() : defaultValue;\n }\n return record[key];\n}\n\n/** Defines a getter that replaces itself with its computed value on first access. */\nexport function defineLazyGetter<T extends object, K extends keyof T>(obj: T, key: K, build: () => T[K]): void {\n Object.defineProperty(obj, key, {\n configurable: true,\n get: function getLazyProperty() {\n const value = build();\n Object.defineProperty(obj, key, { configurable: true, value });\n return value;\n },\n });\n}\n\n/**\n * A utility to ensure a Promise-returning method actually returns a promise and doesn't\n * early exit. Using `async function` guarantees these semantics, but sometimes we avoid\n * `async` as a likely-premature optimization to avoid the overhead.\n */\nexport function tryResolve<T>(fn: () => T): Promise<T> {\n try {\n return Promise.resolve(fn());\n } catch (e) {\n return Promise.reject(e);\n }\n}\n\n/** Returns whether `obj` has at least one key, without allocating a keys array. */\nexport function hasAnyKey(obj: Record<any, any> | undefined): boolean {\n for (const _ in obj) return true;\n return false;\n}\n\nexport function fail(message?: string): never {\n throw new Error(message || \"Failed\");\n}\n\nexport function remove<T>(array: T[], t: T): void {\n const index = array.indexOf(t);\n if (index > -1) {\n array.splice(index, 1);\n }\n}\n\nexport function maybeRemove<T>(array: T[] | undefined, t: T): void {\n if (array) remove(array, t);\n}\n\nexport function maybeAdd<T>(array: T[], t: T): void {\n if (!array.includes(t)) {\n array.push(t);\n }\n}\n\nexport function clear<T>(array: T[]): void {\n array.splice(0, array.length);\n}\n\n/** Returns 0 inclusive to n exclusive. */\nexport function zeroTo(n: number): number[] {\n return [...Array(n).keys()];\n}\n\nexport function groupBy<T, Y = T, K = string>(list: readonly T[], fn: (x: T) => K, valueFn?: (x: T) => Y): Map<K, Y[]> {\n const result = new Map<K, Y[]>();\n list.forEach((o) => {\n const group = fn(o);\n if (!result.has(group)) {\n result.set(group, []);\n }\n result.get(group)!.push(valueFn === undefined ? (o as any as Y) : valueFn(o));\n });\n return result;\n}\n\nexport function indexBy<T, Y = T, K = string>(list: T[], fn: (x: T) => K, valueFn?: (x: T) => Y): Map<K, Y> {\n const result = new Map<K, Y>();\n list.forEach((o) => {\n const group = fn(o);\n result.set(group, valueFn === undefined ? (o as any as Y) : valueFn(o));\n });\n return result;\n}\n\nexport function batched<T>(list: Array<T>, n: number): T[][] {\n const result = [] as T[][];\n for (let i = 0; i < list.length; i += n) {\n result.push(list.slice(i, i + n));\n }\n return result;\n}\n\nexport function partition<T>(array: ReadonlyArray<T>, f: (el: T) => boolean): [T[], T[]] {\n const trueElements: T[] = [];\n const falseElements: T[] = [];\n array.forEach((el) => {\n if (f(el)) {\n trueElements.push(el);\n } else {\n falseElements.push(el);\n }\n });\n return [trueElements, falseElements];\n}\n\n// Utility function to wrap an object or value in an array, unless it's already an array\nexport function toArray<T>(maybeArray: T | T[] | undefined | null): T[] {\n return Array.isArray(maybeArray) ? maybeArray : maybeArray === undefined || maybeArray === null ? [] : [maybeArray];\n}\n\n// Utility type to strip off null and defined and infer only T.\nexport type NullOrDefinedOr<T> = T | null | undefined;\n\nexport function assertNever(x: never): never {\n throw new Error(\"Unexpected object: \" + x);\n}\n\nexport function abbreviation(tableName: string): string {\n return tableName\n .split(\"_\")\n .map((w) => w[0])\n .join(\"\");\n}\n\n/**\n * Utility method for casting `entity` to a `New` entity.\n *\n * Note that we don't actually do any runtime checks; a very simple one would be if the id is undefined,\n * but we want this method to be used in tests that are post-`flush` but still \"know\" the entity is\n * effectively new / fully loaded.\n *\n * Granted, we could do a runtime check that all relations are loaded.\n */\nexport function asNew<T extends Entity>(entity: T): New<T> {\n return entity as New<T>;\n}\n\nexport function compareValues(av: any, bv: any, direction: OrderBy): number {\n const d = direction === \"ASC\" ? 1 : -1;\n if (isReactiveField(av)) {\n av = !av.isSet ? -1 : av.get;\n }\n if (isReactiveField(bv)) {\n bv = !bv.isSet ? -1 : bv.get;\n }\n if (isReference(av) && isReference(bv)) {\n const aIsNew = av.isLoaded && (av as any).get?.isNewEntity;\n const bIsNew = bv.isLoaded && (bv as any).get?.isNewEntity;\n const bothSame = (aIsNew && bIsNew) || (!aIsNew && !bIsNew);\n if (!bothSame) {\n if (aIsNew) return 1 * d; // New entities are always \"greater than\" loaded entities\n if (bIsNew) return -1 * d; // Loaded entities are always \"less than\" new entities\n }\n av = av.idTaggedMaybe ?? (av.isLoaded && (av as any).get?.toString()) ?? undefined;\n bv = bv.idTaggedMaybe ?? (bv.isLoaded && (bv as any).get?.toString()) ?? undefined;\n }\n if (!isDefined(av) || !isDefined(bv)) {\n return !av && !bv ? 0 : (!av ? 1 : -1) * d;\n } else if (typeof av === \"number\" && typeof bv === \"number\") {\n return (av - bv) * d;\n } else if (typeof av === \"string\" && typeof bv === \"string\") {\n return av.localeCompare(bv) * d;\n } else if (av instanceof Date && bv instanceof Date) {\n return ((av as Date).getTime() - (bv as Date).getTime()) * d;\n } else {\n throw new Error(`Unsupported sortBy values ${av}, ${bv}`);\n }\n}\n\n/** A ~naive deep merge that requires already-normalized hints and will mutate `source`. */\n// https://gist.github.com/ahtcx/0cd94e62691f539160b32ecda18af3d6\nexport function mergeNormalizedHints(target: any, source: any): void {\n for (const key of Object.keys(source)) {\n // We assume both target & source are already normalized, i.e. we won't have\n // source=\"books\" and target={books: \"title\"}. They will both be {books: ...}.\n if (target[key]) {\n mergeNormalizedHints(source[key], target[key]);\n }\n }\n Object.assign(target, source);\n}\n\nconst newLine = /\\n/g;\nconst doubleSpace = / +/g;\n\nexport function cleanStringValue(value: unknown): string | undefined {\n // If this is not a string, coerce it -- or maybe fail?\n let s = typeof value !== \"string\" && value !== undefined && value !== null ? String(value) : value;\n // We always trim to remove leading/trailing spaces\n s = typeof s === \"string\" ? s.trim() : s;\n // And if it's empty string, we swap to undefined (null in the db)\n return s === \"\" || s === null ? undefined : s;\n}\n\n/** Strips new lines/indentation from our `UPDATE` string; doesn't do any actual SQL param escaping/etc. */\nexport function cleanSql(sql: string): string {\n return sql.trim().replace(newLine, \"\").replace(doubleSpace, \" \");\n}\n\n// Collections return an array, so do a hot-path `.flat()`\nexport function flatAndUnique<T extends unknown>(list: (T | T[] | undefined)[]): Set<T> {\n const result = new Set<T>();\n for (const c of list) {\n if (Array.isArray(c)) {\n for (const e of c) result.add(e);\n } else if (c) {\n result.add(c);\n }\n }\n return result;\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "joist-core",
3
- "version": "2.3.0-next.97",
3
+ "version": "2.3.0-next.99",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "repository": {
@@ -42,7 +42,7 @@
42
42
  "build"
43
43
  ],
44
44
  "peerDependencies": {
45
- "joist-utils": "2.3.0-next.97"
45
+ "joist-utils": "2.3.0-next.99"
46
46
  },
47
47
  "dependencies": {
48
48
  "ansis": "^4.3.1",
@@ -1 +0,0 @@
1
- {"version":3,"file":"FlushLock.cjs","names":["AsyncLocalStorage","#isFlushing","#flushSecret"],"sources":["../src/FlushLock.ts"],"sourcesContent":["import { AsyncLocalStorage } from \"async_hooks\";\n\n/** A marker to prevent setter calls during `flush` calls. */\nconst currentFlushSecret = new AsyncLocalStorage<{ flushSecret: number }>();\n\n/**\n * Prevents entities being mutated mid-flush.\n *\n * The `flush` process does a dirty check + SQL flush and generally doesn't want\n * entities to re-dirtied after it's done the initial dirty check. So we'd like\n * to prevent all setter calls while `flush` is running.\n *\n * That said, lifecycle code like hooks actually can make setter calls b/c `flush`\n * invokes them at a specific point in its process.\n *\n * We solve this by using node's `AsyncLocalStorage` to mark certain callbacks (promise\n * handlers) as blessed / invoked-from-`flush`-itself, and they are allowed to call setters,\n * but any external callers (i.e. application code) will be rejected.\n */\nexport class FlushLock {\n #flushSecret: number = 0;\n #isFlushing: boolean = false;\n\n /** This will begin any non-hook restrictions on writing to entities. */\n startLock(): void {\n if (this.#isFlushing) {\n throw new Error(\"Cannot flush while another flush is already in progress\");\n }\n this.#isFlushing = true;\n }\n\n releaseLock(): void {\n this.#isFlushing = false;\n }\n\n /** Any writes that happen from `fn`, despite flush being locked, will be allowed. */\n allowWrites(fn: () => Promise<void>): Promise<void> {\n return currentFlushSecret.run({ flushSecret: this.#flushSecret }, () =>\n fn().then(() => {\n this.#flushSecret += 1;\n }),\n );\n }\n\n /** Blows up if writes are locked, i.e. we're flushing and the caller is not within an `allowWrites` block. */\n checkWritesAllowed(): void {\n if (this.#isFlushing) {\n const { flushSecret } = currentFlushSecret.getStore() || {};\n if (flushSecret === undefined) {\n throw new Error(`Cannot mutate an entity during an em.flush outside of a entity hook or from afterCommit`);\n } else if (flushSecret !== this.#flushSecret) {\n throw new Error(`Attempting to reuse a hook context outside its flush loop`);\n }\n }\n }\n\n get isFlushing(): boolean {\n return this.#isFlushing;\n }\n}\n"],"mappings":";;;AAGA,MAAM,qBAAqB,0BAAIA,EAAAA,CAAAA,kBAA2C;;;;;;;;;;;;;;;AAgB1E,IAAa,YAAb,MAAuB;CACrB,eAAuB;CACvB,cAAuB;;CAGvB,YAAkB;EAChB,IAAI,KAAKC,aACP,MAAM,IAAI,MAAM,yDAAyD;EAE3E,KAAKA,cAAc;CACrB;CAEA,cAAoB;EAClB,KAAKA,cAAc;CACrB;;CAGA,YAAY,IAAwC;EAClD,OAAO,mBAAmB,IAAI,EAAE,aAAa,KAAKC,aAAa,SAC7D,GAAG,CAAC,CAAC,WAAW;GACd,KAAKA,gBAAgB;EACvB,CAAC,CACH;CACF;;CAGA,qBAA2B;EACzB,IAAI,KAAKD,aAAa;GACpB,MAAM,EAAE,gBAAgB,mBAAmB,SAAS,KAAK,CAAC;GAC1D,IAAI,gBAAgB,KAAA,GAClB,MAAM,IAAI,MAAM,yFAAyF;QACpG,IAAI,gBAAgB,KAAKC,cAC9B,MAAM,IAAI,MAAM,2DAA2D;EAE/E;CACF;CAEA,IAAI,aAAsB;EACxB,OAAO,KAAKD;CACd;AACF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"FlushLock.d.cts","names":[],"sources":["../src/FlushLock.ts"],"mappings":";;;;;;;;;;;;;;;cAmBa;;;EAKX;EAOA;;EAKA,YAAY,UAAU,gBAAgB;;EAStC;MAWI"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"FlushLock.d.mts","names":[],"sources":["../src/FlushLock.ts"],"mappings":";;;;;;;;;;;;;;;cAmBa;;;EAKX;EAOA;;EAKA,YAAY,UAAU,gBAAgB;;EAStC;MAWI"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"FlushLock.js","names":["#isFlushing","#flushSecret"],"sources":["../src/FlushLock.ts"],"sourcesContent":["import { AsyncLocalStorage } from \"async_hooks\";\n\n/** A marker to prevent setter calls during `flush` calls. */\nconst currentFlushSecret = new AsyncLocalStorage<{ flushSecret: number }>();\n\n/**\n * Prevents entities being mutated mid-flush.\n *\n * The `flush` process does a dirty check + SQL flush and generally doesn't want\n * entities to re-dirtied after it's done the initial dirty check. So we'd like\n * to prevent all setter calls while `flush` is running.\n *\n * That said, lifecycle code like hooks actually can make setter calls b/c `flush`\n * invokes them at a specific point in its process.\n *\n * We solve this by using node's `AsyncLocalStorage` to mark certain callbacks (promise\n * handlers) as blessed / invoked-from-`flush`-itself, and they are allowed to call setters,\n * but any external callers (i.e. application code) will be rejected.\n */\nexport class FlushLock {\n #flushSecret: number = 0;\n #isFlushing: boolean = false;\n\n /** This will begin any non-hook restrictions on writing to entities. */\n startLock(): void {\n if (this.#isFlushing) {\n throw new Error(\"Cannot flush while another flush is already in progress\");\n }\n this.#isFlushing = true;\n }\n\n releaseLock(): void {\n this.#isFlushing = false;\n }\n\n /** Any writes that happen from `fn`, despite flush being locked, will be allowed. */\n allowWrites(fn: () => Promise<void>): Promise<void> {\n return currentFlushSecret.run({ flushSecret: this.#flushSecret }, () =>\n fn().then(() => {\n this.#flushSecret += 1;\n }),\n );\n }\n\n /** Blows up if writes are locked, i.e. we're flushing and the caller is not within an `allowWrites` block. */\n checkWritesAllowed(): void {\n if (this.#isFlushing) {\n const { flushSecret } = currentFlushSecret.getStore() || {};\n if (flushSecret === undefined) {\n throw new Error(`Cannot mutate an entity during an em.flush outside of a entity hook or from afterCommit`);\n } else if (flushSecret !== this.#flushSecret) {\n throw new Error(`Attempting to reuse a hook context outside its flush loop`);\n }\n }\n }\n\n get isFlushing(): boolean {\n return this.#isFlushing;\n }\n}\n"],"mappings":";;;AAGA,MAAM,qBAAqB,IAAI,kBAA2C;;;;;;;;;;;;;;;AAgB1E,IAAa,YAAb,MAAuB;CACrB,eAAuB;CACvB,cAAuB;;CAGvB,YAAkB;EAChB,IAAI,KAAKA,aACP,MAAM,IAAI,MAAM,yDAAyD;EAE3E,KAAKA,cAAc;CACrB;CAEA,cAAoB;EAClB,KAAKA,cAAc;CACrB;;CAGA,YAAY,IAAwC;EAClD,OAAO,mBAAmB,IAAI,EAAE,aAAa,KAAKC,aAAa,SAC7D,GAAG,CAAC,CAAC,WAAW;GACd,KAAKA,gBAAgB;EACvB,CAAC,CACH;CACF;;CAGA,qBAA2B;EACzB,IAAI,KAAKD,aAAa;GACpB,MAAM,EAAE,gBAAgB,mBAAmB,SAAS,KAAK,CAAC;GAC1D,IAAI,gBAAgB,KAAA,GAClB,MAAM,IAAI,MAAM,yFAAyF;QACpG,IAAI,gBAAgB,KAAKC,cAC9B,MAAM,IAAI,MAAM,2DAA2D;EAE/E;CACF;CAEA,IAAI,aAAsB;EACxB,OAAO,KAAKD;CACd;AACF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"HintTree.cjs","names":["normalizeHint"],"sources":["../src/HintTree.ts"],"sourcesContent":["import { type Entity } from \"./Entity.ts\";\nimport { type TaggedId } from \"./EntityManager.ts\";\nimport { type LoadHint } from \"./loadHints.ts\";\nimport { normalizeHint } from \"./normalizeHints.ts\";\n\n// We support preloading in `populate` with existing entities, or `load` with just ids.\n// (We could ask `populate` to convert its entities to ids, but it's convenient for it\n// to keep the HintTree populated with Entities so that newly-created entities can have\n// their collections marked as loaded.\nexport type EntityOrId = Entity | TaggedId;\n\nexport type HintNode<E extends EntityOrId> = {\n /** These entities are the root entities of our preload, i.e. we use them to trim the tree to prevent over-fetching. */\n entities: Set<E>;\n /** A runtime indication of the type of `E`. */\n entitiesKind: \"instances\" | \"ids\" | \"none\";\n /** The hints to preload at this node, i.e. if `E` is `Author`, the `books: \"reviews` or just `comments: {}`. */\n hints: { [key: string]: HintNode<E> };\n};\n\n/**\n * Given a number of potentially overlapping load hints, i.e. `{ authors: \"books\" }` and\n * `{ authors: \"reviews\" }`, combines them into a single `HintNode` tree, with bookkeeping\n * of which entities requested each specific node of the tree.\n *\n * I.e. if we're populating three publishers, two with `{ authors: \"books\" }` and one with\n * `{ authors: \"reviews\" }`, we'll end up with a tree like:\n *\n * ```\n * {\n * authors: {\n * entities: [p1, p2, p3],\n * hints: {\n * books: { entities: [p1, p2], hints: {} },\n * reviews: { entities: [p3], hints: {} },\n * }\n * }\n * }\n * ```\n *\n * Which will let us preload `authors` for all three publishers, but `books` only for the\n * first two, and `reviews` only for the third, i.e. we can prevent over-fetching.\n */\nexport function buildHintTree<E extends EntityOrId>(\n hints: readonly { entity: E; hint: LoadHint<any> | undefined }[] | LoadHint<any>,\n): HintNode<E> {\n if (Array.isArray(hints)) {\n // This might be a top-level LoadHint string[] like [\"books\"]\n const isLoadHint = hints.length > 0 && typeof hints[0] === \"string\";\n if (isLoadHint) {\n const root: HintNode<E> = { entitiesKind: \"none\", entities: new Set(), hints: {} };\n addHintNode(root, undefined, hints as LoadHint<any>);\n return root;\n } else {\n const entitiesKind = typeof hints[0].entity === \"string\" ? (\"ids\" as const) : (\"instances\" as const);\n const root: HintNode<E> = { entitiesKind, entities: new Set(), hints: {} };\n for (const { entity, hint } of hints) {\n addHintNode(root, entity, hint);\n }\n return root;\n }\n } else {\n const root: HintNode<E> = { entitiesKind: \"none\", entities: new Set(), hints: {} };\n addHintNode(root, undefined, hints as LoadHint<any>);\n return root;\n }\n}\n\nfunction addHintNode<E extends EntityOrId>(node: HintNode<E>, entity: E | undefined, hint: LoadHint<any> | undefined) {\n // It's tempting to filter out new entities here, but we need to call `.load()` on their\n // relations to ensure the `.get`s will later work, even if we don't look in the db for them.\n if (entity) node.entities.add(entity);\n if (hint) {\n for (const [key, nestedHint] of Object.entries(normalizeHint(hint))) {\n const child = (node.hints[key] ??= { entitiesKind: node.entitiesKind, entities: new Set(), hints: {} });\n addHintNode(child, entity, nestedHint);\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2CA,SAAgB,cACd,OACa;CACb,IAAI,MAAM,QAAQ,KAAK,GAAG;EAGxB,IADmB,MAAM,SAAS,KAAK,OAAO,MAAM,OAAO,UAC3C;GACd,MAAM,OAAoB;IAAE,cAAc;IAAQ,0BAAU,IAAI,IAAI;IAAG,OAAO,CAAC;GAAE;GACjF,YAAY,MAAM,KAAA,GAAW,KAAsB;GACnD,OAAO;EACT,OAAO;GAEL,MAAM,OAAoB;IAAE,cADP,OAAO,MAAM,EAAE,CAAC,WAAW,WAAY,QAAmB;IACrC,0BAAU,IAAI,IAAI;IAAG,OAAO,CAAC;GAAE;GACzE,KAAK,MAAM,EAAE,QAAQ,UAAU,OAC7B,YAAY,MAAM,QAAQ,IAAI;GAEhC,OAAO;EACT;CACF,OAAO;EACL,MAAM,OAAoB;GAAE,cAAc;GAAQ,0BAAU,IAAI,IAAI;GAAG,OAAO,CAAC;EAAE;EACjF,YAAY,MAAM,KAAA,GAAW,KAAsB;EACnD,OAAO;CACT;AACF;AAEA,SAAS,YAAkC,MAAmB,QAAuB,MAAiC;CAGpH,IAAI,QAAQ,KAAK,SAAS,IAAI,MAAM;CACpC,IAAI,MACF,KAAK,MAAM,CAAC,KAAK,eAAe,OAAO,QAAQA,uBAAAA,cAAc,IAAI,CAAC,GAEhE,YAAY,KADQ,MAAM,SAAS;EAAE,cAAc,KAAK;EAAc,0BAAU,IAAI,IAAI;EAAG,OAAO,CAAC;CAAE,GAClF,QAAQ,UAAU;AAG3C"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"HintTree.d.cts","names":[],"sources":["../src/HintTree.ts"],"mappings":";;;;KASY,aAAa,SAAS;KAEtB,SAAS,UAAU;;EAE7B,UAAU,IAAI;;EAEd;;EAEA;KAAU,cAAc,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;iBA0BnB,cAAc,UAAU,YACtC;EAAkB,QAAQ;EAAG,MAAM;MAAgC,gBAClE,SAAS"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"HintTree.d.mts","names":[],"sources":["../src/HintTree.ts"],"mappings":";;;;KASY,aAAa,SAAS;KAEtB,SAAS,UAAU;;EAE7B,UAAU,IAAI;;EAEd;;EAEA;KAAU,cAAc,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;iBA0BnB,cAAc,UAAU,YACtC;EAAkB,QAAQ;EAAG,MAAM;MAAgC,gBAClE,SAAS"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"HintTree.js","names":[],"sources":["../src/HintTree.ts"],"sourcesContent":["import { type Entity } from \"./Entity.ts\";\nimport { type TaggedId } from \"./EntityManager.ts\";\nimport { type LoadHint } from \"./loadHints.ts\";\nimport { normalizeHint } from \"./normalizeHints.ts\";\n\n// We support preloading in `populate` with existing entities, or `load` with just ids.\n// (We could ask `populate` to convert its entities to ids, but it's convenient for it\n// to keep the HintTree populated with Entities so that newly-created entities can have\n// their collections marked as loaded.\nexport type EntityOrId = Entity | TaggedId;\n\nexport type HintNode<E extends EntityOrId> = {\n /** These entities are the root entities of our preload, i.e. we use them to trim the tree to prevent over-fetching. */\n entities: Set<E>;\n /** A runtime indication of the type of `E`. */\n entitiesKind: \"instances\" | \"ids\" | \"none\";\n /** The hints to preload at this node, i.e. if `E` is `Author`, the `books: \"reviews` or just `comments: {}`. */\n hints: { [key: string]: HintNode<E> };\n};\n\n/**\n * Given a number of potentially overlapping load hints, i.e. `{ authors: \"books\" }` and\n * `{ authors: \"reviews\" }`, combines them into a single `HintNode` tree, with bookkeeping\n * of which entities requested each specific node of the tree.\n *\n * I.e. if we're populating three publishers, two with `{ authors: \"books\" }` and one with\n * `{ authors: \"reviews\" }`, we'll end up with a tree like:\n *\n * ```\n * {\n * authors: {\n * entities: [p1, p2, p3],\n * hints: {\n * books: { entities: [p1, p2], hints: {} },\n * reviews: { entities: [p3], hints: {} },\n * }\n * }\n * }\n * ```\n *\n * Which will let us preload `authors` for all three publishers, but `books` only for the\n * first two, and `reviews` only for the third, i.e. we can prevent over-fetching.\n */\nexport function buildHintTree<E extends EntityOrId>(\n hints: readonly { entity: E; hint: LoadHint<any> | undefined }[] | LoadHint<any>,\n): HintNode<E> {\n if (Array.isArray(hints)) {\n // This might be a top-level LoadHint string[] like [\"books\"]\n const isLoadHint = hints.length > 0 && typeof hints[0] === \"string\";\n if (isLoadHint) {\n const root: HintNode<E> = { entitiesKind: \"none\", entities: new Set(), hints: {} };\n addHintNode(root, undefined, hints as LoadHint<any>);\n return root;\n } else {\n const entitiesKind = typeof hints[0].entity === \"string\" ? (\"ids\" as const) : (\"instances\" as const);\n const root: HintNode<E> = { entitiesKind, entities: new Set(), hints: {} };\n for (const { entity, hint } of hints) {\n addHintNode(root, entity, hint);\n }\n return root;\n }\n } else {\n const root: HintNode<E> = { entitiesKind: \"none\", entities: new Set(), hints: {} };\n addHintNode(root, undefined, hints as LoadHint<any>);\n return root;\n }\n}\n\nfunction addHintNode<E extends EntityOrId>(node: HintNode<E>, entity: E | undefined, hint: LoadHint<any> | undefined) {\n // It's tempting to filter out new entities here, but we need to call `.load()` on their\n // relations to ensure the `.get`s will later work, even if we don't look in the db for them.\n if (entity) node.entities.add(entity);\n if (hint) {\n for (const [key, nestedHint] of Object.entries(normalizeHint(hint))) {\n const child = (node.hints[key] ??= { entitiesKind: node.entitiesKind, entities: new Set(), hints: {} });\n addHintNode(child, entity, nestedHint);\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2CA,SAAgB,cACd,OACa;CACb,IAAI,MAAM,QAAQ,KAAK,GAAG;EAGxB,IADmB,MAAM,SAAS,KAAK,OAAO,MAAM,OAAO,UAC3C;GACd,MAAM,OAAoB;IAAE,cAAc;IAAQ,0BAAU,IAAI,IAAI;IAAG,OAAO,CAAC;GAAE;GACjF,YAAY,MAAM,KAAA,GAAW,KAAsB;GACnD,OAAO;EACT,OAAO;GAEL,MAAM,OAAoB;IAAE,cADP,OAAO,MAAM,EAAE,CAAC,WAAW,WAAY,QAAmB;IACrC,0BAAU,IAAI,IAAI;IAAG,OAAO,CAAC;GAAE;GACzE,KAAK,MAAM,EAAE,QAAQ,UAAU,OAC7B,YAAY,MAAM,QAAQ,IAAI;GAEhC,OAAO;EACT;CACF,OAAO;EACL,MAAM,OAAoB;GAAE,cAAc;GAAQ,0BAAU,IAAI,IAAI;GAAG,OAAO,CAAC;EAAE;EACjF,YAAY,MAAM,KAAA,GAAW,KAAsB;EACnD,OAAO;CACT;AACF;AAEA,SAAS,YAAkC,MAAmB,QAAuB,MAAiC;CAGpH,IAAI,QAAQ,KAAK,SAAS,IAAI,MAAM;CACpC,IAAI,MACF,KAAK,MAAM,CAAC,KAAK,eAAe,OAAO,QAAQ,cAAc,IAAI,CAAC,GAEhE,YAAY,KADQ,MAAM,SAAS;EAAE,cAAc,KAAK;EAAc,0BAAU,IAAI,IAAI;EAAG,OAAO,CAAC;CAAE,GAClF,QAAQ,UAAU;AAG3C"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"IsLoadedCache.d.cts","names":[],"sources":["../src/IsLoadedCache.ts"],"mappings":";;;;;;;;;;;;;;;;;;UAmBiB;EACf,QAAQ;EACR;EACA;EACA;;cAGW;;;EAcX,IAAI,QAAQ;EASZ,SAAS,QAAQ;;EAMjB,cAAc,QAAQ,QAAQ"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"IsLoadedCache.d.mts","names":[],"sources":["../src/IsLoadedCache.ts"],"mappings":";;;;;;;;;;;;;;;;;;UAmBiB;EACf,QAAQ;EACR;EACA;EACA;;cAGW;;;EAcX,IAAI,QAAQ;EASZ,SAAS,QAAQ;;EAMjB,cAAc,QAAQ,QAAQ"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"IsLoadedCache.js","names":["#smartCache","#smartDirtySets","#naiveCache","#naiveDirtySets","#resetDownstreamReactables"],"sources":["../src/IsLoadedCache.ts"],"sourcesContent":["import { type Entity } from \"./Entity.ts\";\nimport { type EntityMetadata, getMetadata } from \"./EntityMetadata.ts\";\n\n/**\n * Interface for our relations that have dynamic & expensive `isLoaded` checks.\n *\n * ...and also `OneToManyCollection.get` calls.\n *\n * The primary m2o/o2m/m2m relations all have trivial `isLoaded` checks--are they\n * loaded or not.\n *\n * But for \"composite relations\", i.e. a ReactiveField or ReactiveRelation whose\n * \"load-ness\" is calculated by evaluating its load hint across a subgraph of entities\n * & relations, load-ness can be more dynamic true-then-false, as its subgraph changes.\n *\n * To avoid performance issues (see https://github.com/joist-orm/joist-orm/issues/1166),\n * we cache this dynamic/expensive `isLoaded` checks, and then do targeted, reactivity-driven\n * cache invalidation whenever relations are mutated (via a hook in `setField`).\n */\nexport interface IsLoadedCachable {\n entity: Entity;\n fieldName: string;\n isLoaded: boolean;\n resetIsLoaded(): void;\n}\n\nexport class IsLoadedCache {\n // Cache of `{ tag -> { fieldName -> Set<IsLoadedCachable> } }` to hold derived relations\n // we can selectively invalidate by walking from the mutated field to any downstream\n // cacheables.\n #smartCache: Record<string, Record<string, Set<IsLoadedCachable>>> = {};\n // A dumb cache for things that are hard selectively invalidate (o2m.get, recursive collections,\n // and custom references/collections), so any mutation resets these.\n #naiveCache = new Set<IsLoadedCachable>();\n // Counter to skip reactive hint walking when no smart cache sets are populated.\n #smartDirtySets = 0;\n // Counter to fast-path resetIsLoaded when the naive cache is empty.\n #naiveDirtySets = 0;\n\n /** Adds a ReactiveField/Relation/Collection to be invalidated when its dependencies change. */\n add(target: IsLoadedCachable): void {\n const meta = getMetadata(target.entity);\n const set = ((this.#smartCache[meta.tagName] ??= {})[target.fieldName] ??= new Set());\n if (set.size === 0) {\n this.#smartDirtySets++;\n }\n set.add(target);\n }\n\n addNaive(target: IsLoadedCachable): void {\n if (this.#naiveCache.size === 0) this.#naiveDirtySets++;\n this.#naiveCache.add(target);\n }\n\n /** Resets any in-memory #isLoaded/#isCached caches that depend on `entity.fieldName`. */\n resetIsLoaded(entity: Entity, fieldName: string): void {\n if (this.#smartDirtySets === 0 && this.#naiveDirtySets === 0) return;\n // Reset caches that we can deterministically find by walking the reactivity hints\n if (this.#smartDirtySets > 0) {\n this.#resetDownstreamReactables(getMetadata(entity), fieldName);\n }\n // We could use this to invalidate m2o.get, but it doesn't work for collections\n // with an orderBy, when the orderBy changes, so for now we use the blunt naiveCache.\n // const field = meta.allFields[fieldName];\n // if (field.kind === \"m2o\") {\n // const otherMeta = field.otherMetadata();\n // const set = this.smartCache[otherMeta.tagName]?.[field.otherFieldName];\n // if (set) {\n // for (const target of set) target.resetIsLoaded();\n // set.clear();\n // }\n // }\n if (this.#naiveCache.size > 0) {\n for (const target of this.#naiveCache.values()) target.resetIsLoaded();\n this.#naiveCache.clear();\n this.#naiveDirtySets--;\n }\n }\n\n /**\n * Given a `meta+field`, statically find all downstream Reactables, and if any of those\n * Reactables are a) in-memory already, and b) registered themselves as cached,\n * tell them to reset.\n */\n #resetDownstreamReactables(meta: EntityMetadata, fieldName: string): void {\n // These are reactables in other entities that are watching/reacting to this entity/fieldName\n const reactables = meta.reactablesIncludingReadOnlyByField!.get(fieldName);\n if (reactables === undefined) return;\n for (const r of reactables) {\n if (this.#smartDirtySets === 0) return;\n // I.e. we've written to Author.firstName, and this reactable in Book/otherMeta depends on it\n const otherMeta = getMetadata(r.cstr);\n // Find any cache entries for this cstr + name\n const set = this.#smartCache[otherMeta.tagName]?.[r.name];\n if (set?.size > 0) {\n for (const target of set) {\n target.resetIsLoaded();\n // Is this target itself a RF/RR? If so, transitively reset its cache as well.\n const otherMeta = getMetadata(target.entity);\n const otherField = otherMeta.allFields[target.fieldName];\n if (\"derived\" in otherField && otherField.derived) {\n this.#resetDownstreamReactables(otherMeta, otherField.fieldName);\n }\n }\n set.clear();\n this.#smartDirtySets--;\n }\n }\n }\n}\n"],"mappings":";;;AA0BA,IAAa,gBAAb,MAA2B;CAIzB,cAAqE,CAAC;CAGtE,8BAAc,IAAI,IAAsB;CAExC,kBAAkB;CAElB,kBAAkB;;CAGlB,IAAI,QAAgC;EAClC,MAAM,OAAO,YAAY,OAAO,MAAM;EACtC,MAAM,MAAO,CAAC,KAAKA,YAAY,KAAK,aAAa,CAAC,EAAA,CAAG,OAAO,+BAAe,IAAI,IAAI;EACnF,IAAI,IAAI,SAAS,GACf,KAAKC;EAEP,IAAI,IAAI,MAAM;CAChB;CAEA,SAAS,QAAgC;EACvC,IAAI,KAAKC,YAAY,SAAS,GAAG,KAAKC;EACtC,KAAKD,YAAY,IAAI,MAAM;CAC7B;;CAGA,cAAc,QAAgB,WAAyB;EACrD,IAAI,KAAKD,oBAAoB,KAAK,KAAKE,oBAAoB,GAAG;EAE9D,IAAI,KAAKF,kBAAkB,GACzB,KAAKG,2BAA2B,YAAY,MAAM,GAAG,SAAS;EAahE,IAAI,KAAKF,YAAY,OAAO,GAAG;GAC7B,KAAK,MAAM,UAAU,KAAKA,YAAY,OAAO,GAAG,OAAO,cAAc;GACrE,KAAKA,YAAY,MAAM;GACvB,KAAKC;EACP;CACF;;;;;;CAOA,2BAA2B,MAAsB,WAAyB;EAExE,MAAM,aAAa,KAAK,mCAAoC,IAAI,SAAS;EACzE,IAAI,eAAe,KAAA,GAAW;EAC9B,KAAK,MAAM,KAAK,YAAY;GAC1B,IAAI,KAAKF,oBAAoB,GAAG;GAEhC,MAAM,YAAY,YAAY,EAAE,IAAI;GAEpC,MAAM,MAAM,KAAKD,YAAY,UAAU,QAAQ,GAAG,EAAE;GACpD,IAAI,KAAK,OAAO,GAAG;IACjB,KAAK,MAAM,UAAU,KAAK;KACxB,OAAO,cAAc;KAErB,MAAM,YAAY,YAAY,OAAO,MAAM;KAC3C,MAAM,aAAa,UAAU,UAAU,OAAO;KAC9C,IAAI,aAAa,cAAc,WAAW,SACxC,KAAKI,2BAA2B,WAAW,WAAW,SAAS;IAEnE;IACA,IAAI,MAAM;IACV,KAAKH;GACP;EACF;CACF;AACF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"JoinRows.cjs","names":["#reactToChange","keyToTaggedId","#dbValue","keyToNumber","getEmInternalApi","getBaseAndSelfMetas","#doAdd","#doRemove"],"sources":["../src/JoinRows.ts"],"sourcesContent":["import { type Entity } from \"./Entity.ts\";\nimport { getEmInternalApi } from \"./EntityManager.ts\";\nimport { type EntityMetadata, getBaseAndSelfMetas } from \"./EntityMetadata.ts\";\nimport { type EnumMetadata } from \"./EnumMetadata.ts\";\nimport { keyToNumber, keyToTaggedId } from \"./keys.ts\";\nimport { type ReactionsManager } from \"./ReactionsManager.ts\";\nimport { type JoinRowTodo } from \"./Todo.ts\";\nimport { remove } from \"./utils.ts\";\n\n/**\n * A simplified interface for ManyToManyCollection-like relations.\n *\n * Specifically lets ReactiveManyToMany & ReactiveManyToManyOtherSide use JoinRows\n * as if they were full-fledged m2m relations.\n *\n * The \"other\" side of the join table is usually a second entity, but for `EnumCollection`s\n * (i.e. `Publisher.logoColors`) it is an enum table; in that case `otherEnum` is set and the\n * other column's value is the enum's numeric id rather than an `Entity` (there is also no\n * `otherMeta`/`otherFieldName`, since enums have no reverse collection to keep in sync).\n */\nexport type ManyToManyLike = {\n entity: Entity;\n joinTableName: string;\n columnName: string;\n otherColumnName: string;\n fieldName: string;\n meta: EntityMetadata;\n /** Undefined when the other side is an enum. */\n otherFieldName?: string;\n /** Undefined when the other side is an enum. */\n otherMeta?: EntityMetadata;\n /** Set when the other side is an enum table, for mapping enum codes <-> their numeric ids. */\n otherEnum?: EnumMetadata<any, any, number>;\n /** Whether the join table has a surrogate `id` PK; if false the FK pair is the composite PK. */\n hasJoinTableId: boolean;\n};\n\n/** The value of a join row's column: an `Entity`, or an enum's numeric id for `EnumCollection`s. */\nexport type JoinColumnValue = Entity | number;\n\n/** Whether a join column points at a not-yet-inserted entity (enum ids are never \"new\"). */\nfunction isNewColumn(value: JoinColumnValue): boolean {\n return typeof value !== \"number\" && value.isNewEntity;\n}\n\n/** A small holder around m2m join rows, which we treat as psuedo-entities. */\nexport class JoinRows {\n // The in-memory rows for our m2m table.\n private readonly rows: JoinRow[] = [];\n private readonly index: ManyToManyIndex;\n\n constructor(\n // This could be either side of the m2m relation, depending on which is accessed first.\n // Regardless of which m2m side, we still have a single `JoinRows` instance in memory per m2m table.\n readonly m2m: ManyToManyLike,\n private rm: ReactionsManager,\n ) {\n this.index = new ManyToManyIndex(m2m);\n }\n\n /** Adds a new join row to this table. */\n addNew(m2m: ManyToManyLike, e1: Entity, e2: JoinColumnValue): void {\n if (!e1) throw new Error(`Cannot add a m2m row with an entity that is ${e1}`);\n if (!e2) throw new Error(`Cannot add a m2m row with an entity that is ${e2}`);\n const existing = this.index.get(m2m, e1, e2);\n if (existing) {\n existing.deleted = false;\n existing.op = JoinRowOperation.Pending;\n } else {\n const row = {\n op: JoinRowOperation.Pending,\n id: undefined,\n persisted: false,\n columns: { [m2m.columnName]: e1, [m2m.otherColumnName]: e2 },\n } satisfies JoinRow;\n this.rows.push(row);\n this.index.add(m2m, e1, e2, row);\n }\n this.#reactToChange(m2m, e1, e2);\n }\n\n /** Adds a new remove to this table. */\n addRemove(m2m: ManyToManyLike, e1: Entity, e2: JoinColumnValue): void {\n const existing = this.index.get(m2m, e1, e2);\n if (existing) {\n if (!existing.persisted) {\n // It was only added in-memory and never persisted, so just drop it\n remove(this.rows, existing);\n this.index.remove(existing);\n } else {\n existing.deleted = true;\n }\n existing.op = JoinRowOperation.Pending;\n } else {\n // We're removing against an unloaded collection, so assume the row exists in the database\n // (persisted: true) and queue a delete; the delete keys off the (col1, col2) composite.\n const row = {\n op: JoinRowOperation.Pending,\n id: undefined,\n persisted: true,\n columns: { [m2m.columnName]: e1, [m2m.otherColumnName]: e2 },\n deleted: true,\n } satisfies JoinRow;\n this.rows.push(row);\n this.index.add(m2m, e1, e2, row);\n }\n this.#reactToChange(m2m, e1, e2);\n }\n\n /** Return any \"old values\" for a m2m collection that might need reactivity checks. */\n removedFor(m2m: ManyToManyLike, e1: Entity): JoinColumnValue[] {\n const { otherColumnName } = m2m;\n // I.e. if we did `t1.books.remove(b1)` find all join rows that have\n // `tag_id=t1`, are marked for deletion, and then `.map` them to the removed book.\n const removedRows = this.index.getOthers(m2m.columnName, e1).filter((r) => r.deleted);\n return removedRows.map((r) => r.columns[otherColumnName]);\n }\n\n addedFor(m2m: ManyToManyLike, e1: Entity): JoinColumnValue[] {\n const { otherColumnName } = m2m;\n const addedRows = this.index\n .getOthers(m2m.columnName, e1)\n .filter(\n (r) =>\n ((!r.persisted && r.op === JoinRowOperation.Pending) || r.op === JoinRowOperation.Flushed) &&\n r.deleted !== true,\n );\n return addedRows.map((r) => r.columns[otherColumnName]);\n }\n\n /** Adds an existing join row to this table. */\n addPreloadedRow(m2m: ManyToManyLike, id: number | undefined, e1: Entity, e2: JoinColumnValue): void {\n const existing = this.index.get(m2m, e1, e2);\n if (existing) {\n // Treat any existing WIP change as source-of-truth, so leave it alone\n } else {\n const row = {\n op: JoinRowOperation.Pending,\n id,\n persisted: true,\n columns: { [m2m.columnName]: e1, [m2m.otherColumnName]: e2 },\n } satisfies JoinRow;\n this.rows.push(row);\n this.index.add(m2m, e1, e2, row);\n }\n }\n\n /** Look up/create our internal JoinRow psuedo-entities for the db rows. */\n async loadRows(tuples: [string, string][], dbRows: any[]): Promise<void> {\n const { em } = this.m2m.entity;\n const { columnName: column1, otherColumnName: column2, meta: meta1, otherMeta: meta2, otherEnum } = this.m2m;\n\n const oneIds: string[] = [];\n // Tagged ids for an entity other-side, or raw enum ids for an enum other-side.\n const twoVals: JoinColumnValue[] = [];\n for (const dbRow of dbRows) {\n oneIds.push(keyToTaggedId(meta1, dbRow[column1])!);\n twoVals.push(\n otherEnum ? (dbRow[column2] as number) : (em.getEntity(keyToTaggedId(meta2!, dbRow[column2])!) as any),\n );\n }\n\n // Make sure we have entities in memory for all the joined-to tables. The enum side has no\n // entities to load; the entity sides do (and `twoVals` is re-resolved to entities below).\n await Promise.all([\n em.loadAll(meta1.cstr, oneIds),\n otherEnum\n ? Promise.resolve([])\n : em.loadAll(\n meta2!.cstr,\n dbRows.map((dbRow) => keyToTaggedId(meta2!, dbRow[column2])!),\n ),\n ]);\n\n // If we're doing a em.refresh/reload, we need to watch for rows that are no longer here. For an\n // enum other-side, only persisted rows are delete-candidates (pending in-memory adds are kept,\n // since `EnumCollection` relies on `JoinRows` to hold them rather than re-asserting on load).\n const existingRows = new Set<JoinRow>();\n for (const [columnName, id] of tuples) {\n const others = this.index.getOthers(columnName, em.getEntity(id)!);\n for (const row of others) if (!otherEnum || row.persisted) existingRows.add(row);\n }\n\n let i = 0;\n for (const dbRow of dbRows) {\n const e1 = em.getEntity(oneIds[i])!;\n const e2 = otherEnum ? (dbRow[column2] as number) : em.getEntity(keyToTaggedId(meta2!, dbRow[column2])!)!;\n i++;\n let row = this.index.get(this.m2m, e1, e2);\n if (!row) {\n row = {\n op: JoinRowOperation.Completed,\n id: dbRow.id,\n persisted: true,\n columns: { [column1]: e1, [column2]: e2 },\n created_at: dbRow.created_at,\n };\n this.rows.push(row);\n this.index.add(this.m2m, e1, e2, row);\n } else {\n // If a placeholder row was created while a ManyToManyCollection was unloaded, and we find it during\n // a subsequent load/query, update its id to be what is in the database and mark it persisted.\n row.id = dbRow.id;\n row.persisted = true;\n // Mark this row as still valid\n existingRows.delete(row);\n }\n }\n\n // Mark all no-longer-there rows as deleted\n for (const row of existingRows) row.deleted = true;\n }\n\n getOthers(columnName: string, entity: Entity): JoinColumnValue[] {\n const others = this.index.getOthers(columnName, entity);\n if (others.length === 0) return [];\n const [c1, c2] = Object.keys(others[0].columns);\n const c = others[0].columns[c1] === entity ? c2 : c1;\n return others.filter((o) => !o.deleted).map((row) => row.columns[c]);\n }\n\n /** Drops all in-memory rows where `entity` is on `columnName`, e.g. when it is being deleted. */\n removeAllFor(columnName: string, entity: Entity): void {\n for (const row of this.index.getOthers(columnName, entity)) {\n remove(this.rows, row);\n this.index.remove(row);\n }\n }\n\n /** Drops a single `(e1, e2)` row without queuing a flush, e.g. when mirroring another em's removal. */\n removePreloadedRow(m2m: ManyToManyLike, e1: Entity, e2: JoinColumnValue): void {\n const row = this.index.get(m2m, e1, e2);\n if (row) {\n remove(this.rows, row);\n this.index.remove(row);\n }\n }\n\n /** Scans our `rows` for newly-added/newly-deleted rows that need `INSERT`s/`UPDATE`s. */\n toTodo(): JoinRowTodo | undefined {\n const newRows = this.rows.filter((r) => !r.persisted && r.deleted !== true && r.op === \"pending\");\n const deletedRows = this.rows.filter((r) => r.persisted && r.deleted === true && r.op === \"pending\");\n if (newRows.length === 0 && deletedRows.length === 0) {\n return undefined;\n }\n return {\n m2m: this.m2m,\n newRows,\n deletedRows,\n resetAfterFlushed: () => {\n for (const row of this.rows) {\n if (row.op === JoinRowOperation.Pending || row.op === JoinRowOperation.Flushed)\n row.op = JoinRowOperation.Completed;\n }\n },\n // The driver flushes pure (int, int) FK pairs; resolve them here so it never has to know\n // whether a column points at an entity (use its id) or an enum (its value is already the id).\n dbValue: (row, columnName) => this.#dbValue(row, columnName),\n isNew: (row, columnName) => isNewColumn(row.columns[columnName]),\n };\n }\n\n get hasChanges() {\n return this.rows.some(({ op }) => op === JoinRowOperation.Pending || op === JoinRowOperation.Flushed);\n }\n\n /** The db int value for `row`'s `columnName`: an entity's id, or (for enums) the enum's id itself. */\n #dbValue(row: JoinRow, columnName: string): number {\n const value = row.columns[columnName];\n if (typeof value === \"number\") return value;\n const meta = columnName === this.m2m.columnName ? this.m2m.meta : this.m2m.otherMeta!;\n return keyToNumber(meta, value.idTagged)!;\n }\n\n /**\n * Invalidates caches & queues reactivity for a join-row change.\n *\n * The owning entity (`e1`) always reacts; the \"other\" side only reacts when it is an entity,\n * since enum other-sides have no `em`/reverse-field to keep in sync.\n */\n #reactToChange(m2m: ManyToManyLike, e1: Entity, e2: JoinColumnValue): void {\n const { em } = this.m2m.entity;\n const api = getEmInternalApi(e1.em);\n api.isLoadedCache.resetIsLoaded(e1, m2m.fieldName);\n this.rm.queueDownstreamReactables(e1, m2m.fieldName);\n if (getBaseAndSelfMetas(e1).some((meta) => meta.config.__data.touchOnChange.has(m2m.fieldName))) {\n em.touch(e1);\n }\n if (!m2m.otherEnum) {\n const other = e2 as Entity;\n const otherFieldName = m2m.otherFieldName!;\n api.isLoadedCache.resetIsLoaded(other, otherFieldName);\n this.rm.queueDownstreamReactables(other, otherFieldName);\n if (getBaseAndSelfMetas(other).some((meta) => meta.config.__data.touchOnChange.has(otherFieldName))) {\n em.touch(other);\n }\n }\n }\n}\n\n/**\n * A \"psuedo-entity\" for a join row.\n *\n * We treat this as a special entity, i.e. it has two \"relations\" to each entity for the current\n * row, an optional surrogate `id` primary key, and an optional `created_at` column.\n *\n * These rows are immutable, i.e. once created we don't change either FK, and instead make\n * collection changes only by inserting new rows and deleting old rows.\n *\n * This makes the column1+column2 combination a composite key. For id-less join tables, that\n * composite is the actual primary key and `id` is always undefined.\n */\nexport interface JoinRow {\n /**\n * Whether our relation has been processed or not.\n *\n * - `pending` means we've not flushed it to the Database\n * - `flushed` means we've flushed but `em.flush` hasn't fully completed yet, likely due to AsyncReactiveField calcs\n * - `completed` means we've been flushed and `em.flush` has completed\n */\n op: JoinRowOperation;\n /** The surrogate key for id-ful join tables; always undefined for id-less tables. */\n id: number | undefined;\n /**\n * Whether this row exists (or is assumed to exist) in the database.\n *\n * This is orthogonal to `op` (the flush lifecycle) and is what distinguishes a pending insert\n * from a pending delete: a `pending` row that is `!persisted` is a pending INSERT (added in\n * memory, not yet in the db), while a `pending` row that is `persisted` is a pending DELETE\n * (in the db, marked `deleted`). `op` alone cannot tell these apart, because both inserts and\n * deletes walk the same `pending -> flushed -> completed` progression.\n *\n * We track this as its own flag rather than inferring it from `id` being set/unset, because\n * id-less join tables (whose PK is just the composite of the two FKs) never have an `id` — so\n * `id === undefined` would be ambiguous. `persisted` is the id-agnostic generalization of the\n * `id`-is-set check that id-ful tables historically relied on.\n *\n * It must survive add/remove/re-add sequences: e.g. loading a row (persisted), removing it\n * (pending delete), then re-adding it (`deleted` flipped back to false, `op` back to `pending`)\n * leaves a `pending && !deleted` row that looks identical to a fresh insert — but it is still in\n * the db, so a subsequent remove must issue a DELETE, which only `persisted` can tell us.\n */\n persisted: boolean;\n /** Maps each FK column to its value: an `Entity`, or (for `EnumCollection`s) an enum's numeric id. */\n columns: Record<string, JoinColumnValue>;\n created_at?: Date;\n deleted?: boolean;\n}\n\n/** An enum to track our insert/delete state progression. */\nexport enum JoinRowOperation {\n Pending = \"pending\",\n Flushed = \"flushed\",\n Completed = \"completed\",\n}\n\n/** Keep an in-memory index to avoid sequentially scanning `rows`. */\nclass ManyToManyIndex {\n private indexes: Record<string, Map<JoinColumnValue, Map<JoinColumnValue, JoinRow>>> = {};\n\n constructor(private readonly m2m: ManyToManyLike) {\n this.indexes[m2m.columnName] = new Map();\n this.indexes[m2m.otherColumnName] = new Map();\n }\n\n add(m2m: ManyToManyLike, e1: JoinColumnValue, e2: JoinColumnValue, value: JoinRow): void {\n // Store both e1+e2 => value and e2+e1 => value so we can do lookups from either side\n this.#doAdd(this.indexes[m2m.columnName], e1, e2, value);\n this.#doAdd(this.indexes[m2m.otherColumnName], e2, e1, value);\n }\n\n remove(value: JoinRow): void {\n const [[column1, e1], [column2, e2]] = Object.entries(value.columns);\n this.#doRemove(this.indexes[column1], e1, e2);\n this.#doRemove(this.indexes[column2], e2, e1);\n }\n\n get(m2m: ManyToManyLike, e1: JoinColumnValue, e2: JoinColumnValue): JoinRow | undefined {\n return this.indexes[m2m.columnName].get(e1)?.get(e2);\n }\n\n /** Cheat and use the index to return \"the other entities\" for `entity`. */\n getOthers(columnName: string, entity: JoinColumnValue): JoinRow[] {\n // It's empty m2m collection won't have any other entities, and so no index entries\n const map = this.indexes[columnName].get(entity);\n if (!map) return [];\n // Sort for a stable order regardless of how many batches contributed rows — the underlying\n // Map preserves insertion order, which depends on DataLoader timing and is non-deterministic\n // across processes. New rows (no key yet) sort last.\n const rows = Array.from(map.values());\n if (this.m2m.hasJoinTableId) {\n // Sort by join-row id.\n return rows.sort((a, b) => (a.id ?? Infinity) - (b.id ?? Infinity));\n }\n // Id-less tables have no surrogate id, so sort by the other side's id.\n const otherColumn = columnName === this.m2m.columnName ? this.m2m.otherColumnName : this.m2m.columnName;\n if (this.m2m.otherEnum && otherColumn === this.m2m.otherColumnName) {\n // The other side is an enum, so its column value is already its numeric id.\n return rows.sort((a, b) => (a.columns[otherColumn] as number) - (b.columns[otherColumn] as number));\n }\n const otherMeta = columnName === this.m2m.columnName ? this.m2m.otherMeta! : this.m2m.meta;\n const key = (r: JoinRow) => {\n const other = r.columns[otherColumn] as Entity;\n return other.isNewEntity ? Infinity : keyToNumber(otherMeta, other.id)!;\n };\n return rows.sort((a, b) => key(a) - key(b));\n }\n\n #doAdd(\n index: Map<JoinColumnValue, Map<JoinColumnValue, JoinRow>>,\n e1: JoinColumnValue,\n e2: JoinColumnValue,\n value: JoinRow,\n ): void {\n const map = index.get(e1) ?? new Map();\n if (map.size === 0) index.set(e1, map);\n map.set(e2, value);\n }\n\n #doRemove(\n index: Map<JoinColumnValue, Map<JoinColumnValue, JoinRow>>,\n e1: JoinColumnValue,\n e2: JoinColumnValue,\n ): void {\n index.get(e1)?.delete(e2);\n }\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"JoinRows.d.cts","names":[],"sources":["../src/JoinRows.ts"],"mappings":";;;;;;;;;;;;;;;;;KAoBY;EACV,QAAQ;EACR;EACA;EACA;EACA;EACA,MAAM;;EAEN;;EAEA,YAAY;;EAEZ,YAAY;;EAEZ;;;KAIU,kBAAkB;;cAQjB;;WAQA,KAAK;UACN;mBAPO;mBACA;EAEjB,YAGW,KAAK,gBACN,IAAI;;EAMd,OAAO,KAAK,gBAAgB,IAAI,QAAQ,IAAI;;EAqB5C,UAAU,KAAK,gBAAgB,IAAI,QAAQ,IAAI;;EA4B/C,WAAW,KAAK,gBAAgB,IAAI,SAAS;EAQ7C,SAAS,KAAK,gBAAgB,IAAI,SAAS;;EAa3C,gBAAgB,KAAK,gBAAgB,wBAAwB,IAAI,QAAQ,IAAI;;EAiBvE,SAAS,4BAA4B,gBAAgB;EAiE3D,UAAU,oBAAoB,QAAQ,SAAS;;EAS/C,aAAa,oBAAoB,QAAQ;;EAQzC,mBAAmB,KAAK,gBAAgB,IAAI,QAAQ,IAAI;;EASxD,UAAU;MAuBN;;;;;;;;;;;;;;UAkDW;;;;;;;;EAQf,IAAI;;EAEJ;;;;;;;;;;;;;;;;;;;;EAoBA;;EAEA,SAAS,eAAe;EACxB,aAAa;EACb;;;aAIU;EACV;EACA;EACA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"JoinRows.d.mts","names":[],"sources":["../src/JoinRows.ts"],"mappings":";;;;;;;;;;;;;;;;;KAoBY;EACV,QAAQ;EACR;EACA;EACA;EACA;EACA,MAAM;;EAEN;;EAEA,YAAY;;EAEZ,YAAY;;EAEZ;;;KAIU,kBAAkB;;cAQjB;;WAQA,KAAK;UACN;mBAPO;mBACA;EAEjB,YAGW,KAAK,gBACN,IAAI;;EAMd,OAAO,KAAK,gBAAgB,IAAI,QAAQ,IAAI;;EAqB5C,UAAU,KAAK,gBAAgB,IAAI,QAAQ,IAAI;;EA4B/C,WAAW,KAAK,gBAAgB,IAAI,SAAS;EAQ7C,SAAS,KAAK,gBAAgB,IAAI,SAAS;;EAa3C,gBAAgB,KAAK,gBAAgB,wBAAwB,IAAI,QAAQ,IAAI;;EAiBvE,SAAS,4BAA4B,gBAAgB;EAiE3D,UAAU,oBAAoB,QAAQ,SAAS;;EAS/C,aAAa,oBAAoB,QAAQ;;EAQzC,mBAAmB,KAAK,gBAAgB,IAAI,QAAQ,IAAI;;EASxD,UAAU;MAuBN;;;;;;;;;;;;;;UAkDW;;;;;;;;EAQf,IAAI;;EAEJ;;;;;;;;;;;;;;;;;;;;EAoBA;;EAEA,SAAS,eAAe;EACxB,aAAa;EACb;;;aAIU;EACV;EACA;EACA"}