@warp-drive/core 5.9.0-alpha.19 → 5.9.0-alpha.20

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 (433) hide show
  1. package/declarations/aliases-BWYW5EhX.d.ts +17 -0
  2. package/declarations/aliases-BWYW5EhX.d.ts.map +1 -0
  3. package/declarations/build-config/babel-macros.d.ts +2 -1
  4. package/declarations/build-config/canary-features.d.ts +1 -1
  5. package/declarations/build-config/debugging.d.ts +1 -56
  6. package/declarations/build-config/deprecations.d.ts +1 -1
  7. package/declarations/build-config/env.d.ts +2 -1
  8. package/declarations/build-config/macros.d.ts +2 -1
  9. package/declarations/build-config.d.ts +2 -18
  10. package/declarations/change-WybCP5W2.d.ts +41 -0
  11. package/declarations/change-WybCP5W2.d.ts.map +1 -0
  12. package/declarations/concepts-CFfLCQr6.d.ts +77 -0
  13. package/declarations/concepts-CFfLCQr6.d.ts.map +1 -0
  14. package/declarations/configure-DI1HqQpX.d.ts +164 -0
  15. package/declarations/configure-DI1HqQpX.d.ts.map +1 -0
  16. package/declarations/configure.d.ts +2 -7
  17. package/declarations/document-CRPmGrsO.d.ts +129 -0
  18. package/declarations/document-CRPmGrsO.d.ts.map +1 -0
  19. package/declarations/error-50OSEhsF.d.ts +77 -0
  20. package/declarations/error-50OSEhsF.d.ts.map +1 -0
  21. package/declarations/fields-FM7peCiM.d.ts +2327 -0
  22. package/declarations/fields-FM7peCiM.d.ts.map +1 -0
  23. package/declarations/graph/-private.d.ts +2 -13
  24. package/declarations/graph-Di3nFhg0.d.ts +186 -0
  25. package/declarations/graph-Di3nFhg0.d.ts.map +1 -0
  26. package/declarations/identifier-DyEvjMjb.d.ts +120 -0
  27. package/declarations/identifier-DyEvjMjb.d.ts.map +1 -0
  28. package/declarations/index.d.ts +2 -105
  29. package/declarations/internal-DMxLqCZa.d.ts +9389 -0
  30. package/declarations/internal-DMxLqCZa.d.ts.map +1 -0
  31. package/declarations/json-api-raw-C5APJHHB.d.ts +378 -0
  32. package/declarations/json-api-raw-C5APJHHB.d.ts.map +1 -0
  33. package/declarations/mutations-al42_Yzp.d.ts +165 -0
  34. package/declarations/mutations-al42_Yzp.d.ts.map +1 -0
  35. package/declarations/operations-Do63dgrL.d.ts +244 -0
  36. package/declarations/operations-Do63dgrL.d.ts.map +1 -0
  37. package/declarations/params-DrEx3bf8.d.ts +41 -0
  38. package/declarations/params-DrEx3bf8.d.ts.map +1 -0
  39. package/declarations/raw-D5hnjiq7.d.ts +31 -0
  40. package/declarations/raw-D5hnjiq7.d.ts.map +1 -0
  41. package/declarations/reactive/-private.d.ts +2 -2
  42. package/declarations/reactive.d.ts +2 -286
  43. package/declarations/record-DCFv3y1J.d.ts +258 -0
  44. package/declarations/record-DCFv3y1J.d.ts.map +1 -0
  45. package/declarations/relationship-CT9mFtav.d.ts +65 -0
  46. package/declarations/relationship-CT9mFtav.d.ts.map +1 -0
  47. package/declarations/request.d.ts +2 -52
  48. package/declarations/signals/-leaked.d.ts +63 -2
  49. package/declarations/signals/-leaked.d.ts.map +1 -0
  50. package/declarations/store/-private.d.ts +2 -24
  51. package/declarations/store.d.ts +10363 -2
  52. package/declarations/store.d.ts.map +1 -0
  53. package/declarations/symbols-DjRDCeX0.d.ts +88 -0
  54. package/declarations/symbols-DjRDCeX0.d.ts.map +1 -0
  55. package/declarations/types/-private.d.ts +71 -17
  56. package/declarations/types/-private.d.ts.map +1 -0
  57. package/declarations/types/cache/aliases.d.ts +2 -1
  58. package/declarations/types/cache/change.d.ts +2 -6
  59. package/declarations/types/cache/mutations.d.ts +2 -38
  60. package/declarations/types/cache/operations.d.ts +2 -168
  61. package/declarations/types/cache/relationship.d.ts +2 -13
  62. package/declarations/types/cache.d.ts +2 -429
  63. package/declarations/types/graph.d.ts +2 -47
  64. package/declarations/types/identifier.d.ts +2 -86
  65. package/declarations/types/json/raw.d.ts +2 -6
  66. package/declarations/types/params.d.ts +2 -8
  67. package/declarations/types/record.d.ts +2 -269
  68. package/declarations/types/request.d.ts +2 -371
  69. package/declarations/types/runtime.d.ts +44 -26
  70. package/declarations/types/runtime.d.ts.map +1 -0
  71. package/declarations/types/schema/concepts.d.ts +2 -23
  72. package/declarations/types/schema/fields.d.ts +2 -2228
  73. package/declarations/types/schema/fields.type-test.d.ts +1 -1
  74. package/declarations/types/schema/schema-service.d.ts +2 -380
  75. package/declarations/types/spec/document.d.ts +2 -67
  76. package/declarations/types/spec/error.d.ts +2 -18
  77. package/declarations/types/spec/json-api-raw.d.ts +2 -139
  78. package/declarations/types/symbols.d.ts +2 -78
  79. package/declarations/types/utils.d.ts +2 -5
  80. package/declarations/types.d.ts +3 -11
  81. package/declarations/utils/string.d.ts +51 -44
  82. package/declarations/utils/string.d.ts.map +1 -0
  83. package/declarations/utils-BtURiy8l.d.ts +24 -0
  84. package/declarations/utils-BtURiy8l.d.ts.map +1 -0
  85. package/dist/-private-BMLlImW_.js +22 -0
  86. package/dist/-private-BMLlImW_.js.map +1 -0
  87. package/dist/-private-BOmEfTRr.js +120 -0
  88. package/dist/-private-BOmEfTRr.js.map +1 -0
  89. package/dist/-private-iwy-4PA-.js +1725 -0
  90. package/dist/-private-iwy-4PA-.js.map +1 -0
  91. package/dist/build-config/babel-macros.js +3 -1
  92. package/dist/build-config/canary-features.js +1 -1
  93. package/dist/build-config/debugging.js +1 -1
  94. package/dist/build-config/deprecations.js +1 -1
  95. package/dist/build-config/env.js +3 -1
  96. package/dist/build-config/macros.js +3 -1
  97. package/dist/build-config.js +3 -1
  98. package/dist/configure.js +3 -2
  99. package/dist/graph/-private.js +2183 -3207
  100. package/dist/graph/-private.js.map +1 -0
  101. package/dist/index.js +3 -8
  102. package/dist/reactive/-private.js +3 -1
  103. package/dist/reactive.js +5 -4
  104. package/dist/request-CFwrWpju.js +766 -0
  105. package/dist/request-CFwrWpju.js.map +1 -0
  106. package/dist/request.js +2 -48
  107. package/dist/signals/-leaked.js +3 -1
  108. package/dist/src-ey8lHsLt.js +9090 -0
  109. package/dist/src-ey8lHsLt.js.map +1 -0
  110. package/dist/store/-private.js +3 -1
  111. package/dist/store-DNF9Rgoh.js +462 -0
  112. package/dist/store-DNF9Rgoh.js.map +1 -0
  113. package/dist/store.js +3 -1
  114. package/dist/types/-private.js +1 -77
  115. package/dist/types/identifier.js +60 -52
  116. package/dist/types/identifier.js.map +1 -0
  117. package/dist/types/record.js +211 -181
  118. package/dist/types/record.js.map +1 -0
  119. package/dist/types/request.js +138 -69
  120. package/dist/types/request.js.map +1 -0
  121. package/dist/types/runtime.js +47 -42
  122. package/dist/types/runtime.js.map +1 -0
  123. package/dist/types/schema/fields.js +501 -495
  124. package/dist/types/schema/fields.js.map +1 -0
  125. package/dist/types/schema/fields.type-test.js +79 -0
  126. package/dist/types/schema/fields.type-test.js.map +1 -0
  127. package/dist/types/symbols.js +84 -77
  128. package/dist/types/symbols.js.map +1 -0
  129. package/dist/unpkg/dev/-private-DKY2dUvj.js +1714 -0
  130. package/dist/unpkg/dev/-private-DKY2dUvj.js.map +1 -0
  131. package/dist/unpkg/dev/-private-NQqjYTVp.js +22 -0
  132. package/dist/unpkg/dev/-private-NQqjYTVp.js.map +1 -0
  133. package/dist/unpkg/dev/-private-PzgOM6rk.js +111 -0
  134. package/dist/unpkg/dev/-private-PzgOM6rk.js.map +1 -0
  135. package/dist/unpkg/dev/build-config/babel-macros.js +3 -1
  136. package/dist/unpkg/dev/build-config/canary-features.js +1 -1
  137. package/dist/unpkg/dev/build-config/debugging.js +1 -1
  138. package/dist/unpkg/dev/build-config/deprecations.js +1 -1
  139. package/dist/unpkg/dev/build-config/env.js +3 -1
  140. package/dist/unpkg/dev/build-config/macros.js +3 -1
  141. package/dist/unpkg/dev/build-config.js +3 -1
  142. package/dist/unpkg/dev/configure.js +3 -1
  143. package/dist/unpkg/dev/graph/-private.js +1941 -2964
  144. package/dist/unpkg/dev/graph/-private.js.map +1 -0
  145. package/dist/unpkg/dev/index.js +3 -6
  146. package/dist/unpkg/dev/reactive/-private.js +3 -1
  147. package/dist/unpkg/dev/reactive.js +5 -3
  148. package/dist/unpkg/dev/request-BpCiytJk.js +756 -0
  149. package/dist/unpkg/dev/request-BpCiytJk.js.map +1 -0
  150. package/dist/unpkg/dev/request.js +2 -48
  151. package/dist/unpkg/dev/runtime-DCk-f6iq.js +110 -0
  152. package/dist/unpkg/dev/runtime-DCk-f6iq.js.map +1 -0
  153. package/dist/unpkg/dev/signals/-leaked.js +3 -1
  154. package/dist/unpkg/dev/src-jA0vdH79.js +8194 -0
  155. package/dist/unpkg/dev/src-jA0vdH79.js.map +1 -0
  156. package/dist/unpkg/dev/store/-private.js +3 -55
  157. package/dist/unpkg/dev/store-1Jt0pxEL.js +427 -0
  158. package/dist/unpkg/dev/store-1Jt0pxEL.js.map +1 -0
  159. package/dist/unpkg/dev/store.js +1 -556
  160. package/dist/unpkg/dev/types/-private.js +1 -67
  161. package/dist/unpkg/dev/types/identifier.js +63 -56
  162. package/dist/unpkg/dev/types/identifier.js.map +1 -0
  163. package/dist/unpkg/dev/types/record.js +211 -181
  164. package/dist/unpkg/dev/types/record.js.map +1 -0
  165. package/dist/unpkg/dev/types/request.js +138 -69
  166. package/dist/unpkg/dev/types/request.js.map +1 -0
  167. package/dist/unpkg/dev/types/runtime.js +47 -42
  168. package/dist/unpkg/dev/types/runtime.js.map +1 -0
  169. package/dist/unpkg/dev/types/schema/fields.js +501 -495
  170. package/dist/unpkg/dev/types/schema/fields.js.map +1 -0
  171. package/dist/unpkg/dev/types/schema/fields.type-test.js +79 -0
  172. package/dist/unpkg/dev/types/schema/fields.type-test.js.map +1 -0
  173. package/dist/unpkg/dev/types/symbols.js +84 -77
  174. package/dist/unpkg/dev/types/symbols.js.map +1 -0
  175. package/dist/unpkg/dev/utils/string.js +79 -85
  176. package/dist/unpkg/dev/utils/string.js.map +1 -0
  177. package/dist/unpkg/dev-deprecated/-private-DKY2dUvj.js +1714 -0
  178. package/dist/unpkg/dev-deprecated/-private-DKY2dUvj.js.map +1 -0
  179. package/dist/unpkg/dev-deprecated/-private-NQqjYTVp.js +22 -0
  180. package/dist/unpkg/dev-deprecated/-private-NQqjYTVp.js.map +1 -0
  181. package/dist/unpkg/dev-deprecated/-private-PzgOM6rk.js +111 -0
  182. package/dist/unpkg/dev-deprecated/-private-PzgOM6rk.js.map +1 -0
  183. package/dist/unpkg/dev-deprecated/build-config/babel-macros.js +3 -1
  184. package/dist/unpkg/dev-deprecated/build-config/canary-features.js +1 -1
  185. package/dist/unpkg/dev-deprecated/build-config/debugging.js +1 -1
  186. package/dist/unpkg/dev-deprecated/build-config/deprecations.js +1 -1
  187. package/dist/unpkg/dev-deprecated/build-config/env.js +3 -1
  188. package/dist/unpkg/dev-deprecated/build-config/macros.js +3 -1
  189. package/dist/unpkg/dev-deprecated/build-config.js +3 -1
  190. package/dist/unpkg/dev-deprecated/configure.js +3 -1
  191. package/dist/unpkg/dev-deprecated/graph/-private.js +2060 -3158
  192. package/dist/unpkg/dev-deprecated/graph/-private.js.map +1 -0
  193. package/dist/unpkg/dev-deprecated/index.js +3 -5
  194. package/dist/unpkg/dev-deprecated/reactive/-private.js +3 -1
  195. package/dist/unpkg/dev-deprecated/reactive.js +5 -3
  196. package/dist/unpkg/dev-deprecated/request-BpCiytJk.js +756 -0
  197. package/dist/unpkg/dev-deprecated/request-BpCiytJk.js.map +1 -0
  198. package/dist/unpkg/dev-deprecated/request.js +2 -48
  199. package/dist/unpkg/dev-deprecated/runtime-BmPBYlvC.js +110 -0
  200. package/dist/unpkg/dev-deprecated/runtime-BmPBYlvC.js.map +1 -0
  201. package/dist/unpkg/dev-deprecated/signals/-leaked.js +3 -1
  202. package/dist/unpkg/dev-deprecated/src-BTNdbQFd.js +8747 -0
  203. package/dist/unpkg/dev-deprecated/src-BTNdbQFd.js.map +1 -0
  204. package/dist/unpkg/dev-deprecated/store/-private.js +3 -1
  205. package/dist/unpkg/dev-deprecated/store-GrkCubY2.js +427 -0
  206. package/dist/unpkg/dev-deprecated/store-GrkCubY2.js.map +1 -0
  207. package/dist/unpkg/dev-deprecated/store.js +1 -556
  208. package/dist/unpkg/dev-deprecated/types/-private.js +1 -67
  209. package/dist/unpkg/dev-deprecated/types/identifier.js +63 -56
  210. package/dist/unpkg/dev-deprecated/types/identifier.js.map +1 -0
  211. package/dist/unpkg/dev-deprecated/types/record.js +211 -181
  212. package/dist/unpkg/dev-deprecated/types/record.js.map +1 -0
  213. package/dist/unpkg/dev-deprecated/types/request.js +138 -69
  214. package/dist/unpkg/dev-deprecated/types/request.js.map +1 -0
  215. package/dist/unpkg/dev-deprecated/types/runtime.js +47 -42
  216. package/dist/unpkg/dev-deprecated/types/runtime.js.map +1 -0
  217. package/dist/unpkg/dev-deprecated/types/schema/fields.js +501 -495
  218. package/dist/unpkg/dev-deprecated/types/schema/fields.js.map +1 -0
  219. package/dist/unpkg/dev-deprecated/types/schema/fields.type-test.js +79 -0
  220. package/dist/unpkg/dev-deprecated/types/schema/fields.type-test.js.map +1 -0
  221. package/dist/unpkg/dev-deprecated/types/symbols.js +84 -77
  222. package/dist/unpkg/dev-deprecated/types/symbols.js.map +1 -0
  223. package/dist/unpkg/dev-deprecated/utils/string.js +79 -85
  224. package/dist/unpkg/dev-deprecated/utils/string.js.map +1 -0
  225. package/dist/unpkg/prod/-private-2iPTxWpo.js +99 -0
  226. package/dist/unpkg/prod/-private-2iPTxWpo.js.map +1 -0
  227. package/dist/unpkg/prod/-private-CEvzP5HH.js +1524 -0
  228. package/dist/unpkg/prod/-private-CEvzP5HH.js.map +1 -0
  229. package/dist/unpkg/prod/-private-ecjmm5Ye.js +22 -0
  230. package/dist/unpkg/prod/-private-ecjmm5Ye.js.map +1 -0
  231. package/dist/unpkg/prod/build-config/babel-macros.js +3 -1
  232. package/dist/unpkg/prod/build-config/canary-features.js +1 -1
  233. package/dist/unpkg/prod/build-config/debugging.js +1 -1
  234. package/dist/unpkg/prod/build-config/deprecations.js +1 -1
  235. package/dist/unpkg/prod/build-config/env.js +3 -1
  236. package/dist/unpkg/prod/build-config/macros.js +3 -1
  237. package/dist/unpkg/prod/build-config.js +3 -1
  238. package/dist/unpkg/prod/configure.js +3 -2
  239. package/dist/unpkg/prod/graph/-private.js +1475 -2092
  240. package/dist/unpkg/prod/graph/-private.js.map +1 -0
  241. package/dist/unpkg/prod/index.js +3 -5
  242. package/dist/unpkg/prod/reactive/-private.js +3 -1
  243. package/dist/unpkg/prod/reactive.js +5 -4
  244. package/dist/unpkg/prod/request-Bdku5QJI.js +480 -0
  245. package/dist/unpkg/prod/request-Bdku5QJI.js.map +1 -0
  246. package/dist/unpkg/prod/request.js +3 -2
  247. package/dist/unpkg/prod/signals/-leaked.js +3 -1
  248. package/dist/unpkg/prod/src-DRk-mIOI.js +6801 -0
  249. package/dist/unpkg/prod/src-DRk-mIOI.js.map +1 -0
  250. package/dist/unpkg/prod/store/-private.js +3 -125
  251. package/dist/unpkg/prod/store-BWhmb7Ob.js +359 -0
  252. package/dist/unpkg/prod/store-BWhmb7Ob.js.map +1 -0
  253. package/dist/unpkg/prod/store.js +1 -435
  254. package/dist/unpkg/prod/types/-private.js +1 -47
  255. package/dist/unpkg/prod/types/identifier.js +63 -56
  256. package/dist/unpkg/prod/types/identifier.js.map +1 -0
  257. package/dist/unpkg/prod/types/record.js +211 -181
  258. package/dist/unpkg/prod/types/record.js.map +1 -0
  259. package/dist/unpkg/prod/types/request.js +138 -69
  260. package/dist/unpkg/prod/types/request.js.map +1 -0
  261. package/dist/unpkg/prod/types/runtime.js +47 -42
  262. package/dist/unpkg/prod/types/runtime.js.map +1 -0
  263. package/dist/unpkg/prod/types/schema/fields.js +501 -495
  264. package/dist/unpkg/prod/types/schema/fields.js.map +1 -0
  265. package/dist/unpkg/prod/types/schema/fields.type-test.js +79 -0
  266. package/dist/unpkg/prod/types/schema/fields.type-test.js.map +1 -0
  267. package/dist/unpkg/prod/types/symbols.js +84 -77
  268. package/dist/unpkg/prod/types/symbols.js.map +1 -0
  269. package/dist/unpkg/prod/utils/string.js +70 -66
  270. package/dist/unpkg/prod/utils/string.js.map +1 -0
  271. package/dist/unpkg/prod-deprecated/-private-2iPTxWpo.js +99 -0
  272. package/dist/unpkg/prod-deprecated/-private-2iPTxWpo.js.map +1 -0
  273. package/dist/unpkg/prod-deprecated/-private-CEvzP5HH.js +1524 -0
  274. package/dist/unpkg/prod-deprecated/-private-CEvzP5HH.js.map +1 -0
  275. package/dist/unpkg/prod-deprecated/-private-ecjmm5Ye.js +22 -0
  276. package/dist/unpkg/prod-deprecated/-private-ecjmm5Ye.js.map +1 -0
  277. package/dist/unpkg/prod-deprecated/build-config/babel-macros.js +3 -1
  278. package/dist/unpkg/prod-deprecated/build-config/canary-features.js +1 -1
  279. package/dist/unpkg/prod-deprecated/build-config/debugging.js +1 -1
  280. package/dist/unpkg/prod-deprecated/build-config/deprecations.js +1 -1
  281. package/dist/unpkg/prod-deprecated/build-config/env.js +3 -1
  282. package/dist/unpkg/prod-deprecated/build-config/macros.js +3 -1
  283. package/dist/unpkg/prod-deprecated/build-config.js +3 -1
  284. package/dist/unpkg/prod-deprecated/configure.js +3 -2
  285. package/dist/unpkg/prod-deprecated/graph/-private.js +1586 -2263
  286. package/dist/unpkg/prod-deprecated/graph/-private.js.map +1 -0
  287. package/dist/unpkg/prod-deprecated/index.js +3 -5
  288. package/dist/unpkg/prod-deprecated/reactive/-private.js +3 -1
  289. package/dist/unpkg/prod-deprecated/reactive.js +5 -4
  290. package/dist/unpkg/prod-deprecated/request-Bdku5QJI.js +480 -0
  291. package/dist/unpkg/prod-deprecated/request-Bdku5QJI.js.map +1 -0
  292. package/dist/unpkg/prod-deprecated/request.js +3 -2
  293. package/dist/unpkg/prod-deprecated/signals/-leaked.js +3 -1
  294. package/dist/unpkg/prod-deprecated/src-DYZ6ez03.js +7234 -0
  295. package/dist/unpkg/prod-deprecated/src-DYZ6ez03.js.map +1 -0
  296. package/dist/unpkg/prod-deprecated/store/-private.js +3 -87
  297. package/dist/unpkg/prod-deprecated/store-BWhmb7Ob.js +359 -0
  298. package/dist/unpkg/prod-deprecated/store-BWhmb7Ob.js.map +1 -0
  299. package/dist/unpkg/prod-deprecated/store.js +1 -435
  300. package/dist/unpkg/prod-deprecated/types/-private.js +1 -47
  301. package/dist/unpkg/prod-deprecated/types/identifier.js +63 -56
  302. package/dist/unpkg/prod-deprecated/types/identifier.js.map +1 -0
  303. package/dist/unpkg/prod-deprecated/types/record.js +211 -181
  304. package/dist/unpkg/prod-deprecated/types/record.js.map +1 -0
  305. package/dist/unpkg/prod-deprecated/types/request.js +138 -69
  306. package/dist/unpkg/prod-deprecated/types/request.js.map +1 -0
  307. package/dist/unpkg/prod-deprecated/types/runtime.js +47 -42
  308. package/dist/unpkg/prod-deprecated/types/runtime.js.map +1 -0
  309. package/dist/unpkg/prod-deprecated/types/schema/fields.js +501 -495
  310. package/dist/unpkg/prod-deprecated/types/schema/fields.js.map +1 -0
  311. package/dist/unpkg/prod-deprecated/types/schema/fields.type-test.js +79 -0
  312. package/dist/unpkg/prod-deprecated/types/schema/fields.type-test.js.map +1 -0
  313. package/dist/unpkg/prod-deprecated/types/symbols.js +84 -77
  314. package/dist/unpkg/prod-deprecated/types/symbols.js.map +1 -0
  315. package/dist/unpkg/prod-deprecated/utils/string.js +70 -66
  316. package/dist/unpkg/prod-deprecated/utils/string.js.map +1 -0
  317. package/dist/utils/string.js +84 -85
  318. package/dist/utils/string.js.map +1 -0
  319. package/package.json +8 -8
  320. package/declarations/graph/-private/-diff.d.ts +0 -19
  321. package/declarations/graph/-private/-edge-definition.d.ts +0 -149
  322. package/declarations/graph/-private/-state.d.ts +0 -10
  323. package/declarations/graph/-private/-utils.d.ts +0 -25
  324. package/declarations/graph/-private/coerce-id.d.ts +0 -4
  325. package/declarations/graph/-private/debug/assert-polymorphic-type.d.ts +0 -6
  326. package/declarations/graph/-private/edges/collection.d.ts +0 -39
  327. package/declarations/graph/-private/edges/implicit.d.ts +0 -43
  328. package/declarations/graph/-private/edges/resource.d.ts +0 -23
  329. package/declarations/graph/-private/graph.d.ts +0 -56
  330. package/declarations/graph/-private/normalize-link.d.ts +0 -2
  331. package/declarations/graph/-private/operations/add-to-related-records.d.ts +0 -4
  332. package/declarations/graph/-private/operations/merge-identifier.d.ts +0 -3
  333. package/declarations/graph/-private/operations/remove-from-related-records.d.ts +0 -4
  334. package/declarations/graph/-private/operations/replace-related-record.d.ts +0 -3
  335. package/declarations/graph/-private/operations/replace-related-records.d.ts +0 -7
  336. package/declarations/graph/-private/operations/update-relationship.d.ts +0 -9
  337. package/declarations/reactive/-private/default-mode.d.ts +0 -86
  338. package/declarations/reactive/-private/document.d.ts +0 -142
  339. package/declarations/reactive/-private/fields/extension.d.ts +0 -8
  340. package/declarations/reactive/-private/fields/get-field-key.d.ts +0 -8
  341. package/declarations/reactive/-private/fields/managed-array.d.ts +0 -18
  342. package/declarations/reactive/-private/fields/managed-object.d.ts +0 -17
  343. package/declarations/reactive/-private/fields/many-array-manager.d.ts +0 -19
  344. package/declarations/reactive/-private/hooks.d.ts +0 -5
  345. package/declarations/reactive/-private/kind/alias-field.d.ts +0 -4
  346. package/declarations/reactive/-private/kind/array-field.d.ts +0 -4
  347. package/declarations/reactive/-private/kind/attribute-field.d.ts +0 -4
  348. package/declarations/reactive/-private/kind/belongs-to-field.d.ts +0 -7
  349. package/declarations/reactive/-private/kind/collection-field.d.ts +0 -4
  350. package/declarations/reactive/-private/kind/derived-field.d.ts +0 -4
  351. package/declarations/reactive/-private/kind/generic-field.d.ts +0 -4
  352. package/declarations/reactive/-private/kind/has-many-field.d.ts +0 -4
  353. package/declarations/reactive/-private/kind/hash-field.d.ts +0 -4
  354. package/declarations/reactive/-private/kind/identity-field.d.ts +0 -4
  355. package/declarations/reactive/-private/kind/local-field.d.ts +0 -4
  356. package/declarations/reactive/-private/kind/object-field.d.ts +0 -4
  357. package/declarations/reactive/-private/kind/resource-field.d.ts +0 -4
  358. package/declarations/reactive/-private/kind/schema-array-field.d.ts +0 -4
  359. package/declarations/reactive/-private/kind/schema-object-field.d.ts +0 -4
  360. package/declarations/reactive/-private/record.d.ts +0 -83
  361. package/declarations/reactive/-private/schema.d.ts +0 -326
  362. package/declarations/reactive/-private/symbols.d.ts +0 -5
  363. package/declarations/request/-private/context.d.ts +0 -39
  364. package/declarations/request/-private/debug.d.ts +0 -4
  365. package/declarations/request/-private/fetch.d.ts +0 -33
  366. package/declarations/request/-private/future.d.ts +0 -7
  367. package/declarations/request/-private/manager.d.ts +0 -158
  368. package/declarations/request/-private/promise-cache.d.ts +0 -28
  369. package/declarations/request/-private/types.d.ts +0 -234
  370. package/declarations/request/-private/utils.d.ts +0 -57
  371. package/declarations/signals/-private.d.ts +0 -6
  372. package/declarations/signals/promise-state.d.ts +0 -264
  373. package/declarations/signals/reactivity/configure.d.ts +0 -138
  374. package/declarations/signals/reactivity/internal.d.ts +0 -154
  375. package/declarations/signals/reactivity/signal.d.ts +0 -56
  376. package/declarations/signals/request-state.d.ts +0 -372
  377. package/declarations/signals/request-subscription.d.ts +0 -177
  378. package/declarations/store/-private/cache-handler/handler.d.ts +0 -56
  379. package/declarations/store/-private/cache-handler/types.d.ts +0 -84
  380. package/declarations/store/-private/cache-handler/utils.d.ts +0 -31
  381. package/declarations/store/-private/caches/instance-cache.d.ts +0 -58
  382. package/declarations/store/-private/caches/resource-utils.d.ts +0 -9
  383. package/declarations/store/-private/debug/utils.d.ts +0 -7
  384. package/declarations/store/-private/default-cache-policy.d.ts +0 -387
  385. package/declarations/store/-private/managers/cache-capabilities-manager.d.ts +0 -34
  386. package/declarations/store/-private/managers/cache-key-manager.d.ts +0 -304
  387. package/declarations/store/-private/managers/cache-manager.d.ts +0 -367
  388. package/declarations/store/-private/managers/notification-manager.d.ts +0 -83
  389. package/declarations/store/-private/managers/record-array-manager.d.ts +0 -100
  390. package/declarations/store/-private/network/request-cache.d.ts +0 -103
  391. package/declarations/store/-private/record-arrays/-utils.d.ts +0 -80
  392. package/declarations/store/-private/record-arrays/legacy-live-array.d.ts +0 -81
  393. package/declarations/store/-private/record-arrays/legacy-many-array.d.ts +0 -133
  394. package/declarations/store/-private/record-arrays/legacy-query.d.ts +0 -81
  395. package/declarations/store/-private/record-arrays/native-proxy-type-fix.d.ts +0 -3
  396. package/declarations/store/-private/record-arrays/resource-array.d.ts +0 -67
  397. package/declarations/store/-private/store-service.d.ts +0 -874
  398. package/declarations/store/-private/utils/coerce-id.d.ts +0 -4
  399. package/declarations/store/-private/utils/construct-resource.d.ts +0 -6
  400. package/declarations/store/-private/utils/is-non-empty-string.d.ts +0 -1
  401. package/declarations/store/-private/utils/normalize-model-name.d.ts +0 -1
  402. package/declarations/store/-private/utils/uuid-polyfill.d.ts +0 -1
  403. package/declarations/store/-types/q/cache-capabilities-manager.d.ts +0 -90
  404. package/declarations/store/-types/q/identifier.d.ts +0 -23
  405. package/declarations/store/-types/q/record-instance.d.ts +0 -22
  406. package/declarations/store/-types/q/store.d.ts +0 -31
  407. package/declarations/store/deprecated/-private.d.ts +0 -223
  408. package/declarations/store/deprecated/store.d.ts +0 -784
  409. package/dist/configure-BMxnD2RJ.js +0 -1940
  410. package/dist/default-cache-policy-D7_u4YRH.js +0 -572
  411. package/dist/future-CPfkKOvf.js +0 -678
  412. package/dist/index-LI2ckwf9.js +0 -10322
  413. package/dist/symbols-3C1OkYtZ.js +0 -39
  414. package/dist/unpkg/dev/-leaked-BohmerbH.js +0 -1939
  415. package/dist/unpkg/dev/-private-sql1_mdx.js +0 -39
  416. package/dist/unpkg/dev/future-DUuPqyLj.js +0 -672
  417. package/dist/unpkg/dev/index-DU_HLpg-.js +0 -9732
  418. package/dist/unpkg/dev/runtime-DGG4CvlW.js +0 -135
  419. package/dist/unpkg/dev-deprecated/-leaked-C40gfiH-.js +0 -1939
  420. package/dist/unpkg/dev-deprecated/-private-3C1OkYtZ.js +0 -39
  421. package/dist/unpkg/dev-deprecated/future-DUuPqyLj.js +0 -672
  422. package/dist/unpkg/dev-deprecated/index-BYFUHVPd.js +0 -10347
  423. package/dist/unpkg/dev-deprecated/runtime-DfhJzpZH.js +0 -135
  424. package/dist/unpkg/prod/-leaked-DgjQ5X55.js +0 -1676
  425. package/dist/unpkg/prod/-private-sql1_mdx.js +0 -39
  426. package/dist/unpkg/prod/index-C-AhVafS.js +0 -7547
  427. package/dist/unpkg/prod/promise-cache-DUblkX-U.js +0 -19
  428. package/dist/unpkg/prod/request-eb7Zm-oS.js +0 -421
  429. package/dist/unpkg/prod-deprecated/-leaked-BNVttukY.js +0 -1676
  430. package/dist/unpkg/prod-deprecated/-private-3C1OkYtZ.js +0 -39
  431. package/dist/unpkg/prod-deprecated/index-CplZl2hv.js +0 -7985
  432. package/dist/unpkg/prod-deprecated/promise-cache-DUblkX-U.js +0 -19
  433. package/dist/unpkg/prod-deprecated/request-eb7Zm-oS.js +0 -421
@@ -1,2378 +1,1696 @@
1
- import { getOrSetGlobal, peekTransient, setTransient } from '../types/-private.js';
1
+ import { a as setTransient, r as peekTransient, t as getOrSetGlobal } from "../-private-2iPTxWpo.js";
2
+
3
+ //#region src/graph/-private/-utils.ts
4
+ /** Retrieves the private {@link Store} instance from a capabilities manager (or any object exposing `_store`). */
2
5
  function getStore(wrapper) {
3
- return wrapper._store;
6
+ return wrapper._store;
4
7
  }
8
+ /** Reads a value from a two-level keyed cache, without creating the first-level entry if it is missing. */
5
9
  function expandingGet(cache, key1, key2) {
6
- const mainCache = cache[key1] = cache[key1] || Object.create(null);
7
- return mainCache[key2];
10
+ return (cache[key1] = cache[key1] || Object.create(null))[key2];
8
11
  }
12
+ /** Writes a value into a two-level keyed cache, lazily creating the first-level entry if it does not yet exist. */
9
13
  function expandingSet(cache, key1, key2, value) {
10
- const mainCache = cache[key1] = cache[key1] || Object.create(null);
11
- mainCache[key2] = value;
14
+ const mainCache = cache[key1] = cache[key1] || Object.create(null);
15
+ mainCache[key2] = value;
12
16
  }
17
+ /** Returns whether the given resource is new, i.e. it has no `id` or is flagged as new by the cache. */
13
18
  function checkIfNew(store, resourceKey) {
14
- if (!resourceKey.id) {
15
- return true;
16
- }
17
- return store.cache.isNew(resourceKey);
19
+ if (!resourceKey.id) return true;
20
+ return store.cache.isNew(resourceKey);
18
21
  }
22
+ /** A type-guard returning whether the given edge is a `belongsTo` {@link ResourceEdge}. */
19
23
  function isBelongsTo(relationship) {
20
- return relationship.definition.kind === 'belongsTo';
24
+ return relationship.definition.kind === "belongsTo";
21
25
  }
26
+ /** A type-guard returning whether the given edge is an {@link ImplicitEdge}. */
22
27
  function isImplicit(relationship) {
23
- return relationship.definition.isImplicit;
28
+ return relationship.definition.isImplicit;
24
29
  }
30
+ /** A type-guard returning whether the given edge is a `hasMany` {@link CollectionEdge}. */
25
31
  function isHasMany(relationship) {
26
- return relationship.definition.kind === 'hasMany';
32
+ return relationship.definition.kind === "hasMany";
27
33
  }
34
+ /** Invokes `cb` for every resource identifier currently related through `rel`, covering both local and remote membership regardless of the edge's kind. */
28
35
  function forAllRelatedIdentifiers(rel, cb) {
29
- if (isBelongsTo(rel)) {
30
- if (rel.remoteState) {
31
- cb(rel.remoteState);
32
- }
33
- if (rel.localState && rel.localState !== rel.remoteState) {
34
- cb(rel.localState);
35
- }
36
- } else if (isHasMany(rel)) {
37
- // TODO
38
- // rel.remoteMembers.forEach(cb);
39
- // might be simpler if performance is not a concern
40
- for (let i = 0; i < rel.remoteState.length; i++) {
41
- const inverseIdentifier = rel.remoteState[i];
42
- cb(inverseIdentifier);
43
- }
44
- rel.additions?.forEach(cb);
45
- } else {
46
- rel.localMembers.forEach(cb);
47
- rel.remoteMembers.forEach(inverseIdentifier => {
48
- if (!rel.localMembers.has(inverseIdentifier)) {
49
- cb(inverseIdentifier);
50
- }
51
- });
52
- }
36
+ if (isBelongsTo(rel)) {
37
+ if (rel.remoteState) cb(rel.remoteState);
38
+ if (rel.localState && rel.localState !== rel.remoteState) cb(rel.localState);
39
+ } else if (isHasMany(rel)) {
40
+ for (let i = 0; i < rel.remoteState.length; i++) {
41
+ const inverseIdentifier = rel.remoteState[i];
42
+ cb(inverseIdentifier);
43
+ }
44
+ rel.additions?.forEach(cb);
45
+ } else {
46
+ rel.localMembers.forEach(cb);
47
+ rel.remoteMembers.forEach((inverseIdentifier) => {
48
+ if (!rel.localMembers.has(inverseIdentifier)) cb(inverseIdentifier);
49
+ });
50
+ }
53
51
  }
54
-
55
- /*
56
- Removes the given identifier from BOTH remote AND local state.
57
-
58
- This method is useful when either a deletion or a rollback on a new record
59
- needs to entirely purge itself from an inverse relationship.
60
- */
52
+ /**
53
+ * Removes the given identifier from BOTH remote AND local state.
54
+ *
55
+ * This method is useful when either a deletion or a rollback on a new record
56
+ * needs to entirely purge itself from an inverse relationship.
57
+ */
61
58
  function removeIdentifierCompletelyFromRelationship(graph, relationship, value, silenceNotifications) {
62
- if (isBelongsTo(relationship)) {
63
- if (relationship.remoteState === value) {
64
- relationship.remoteState = null;
65
- }
66
- if (relationship.localState === value) {
67
- relationship.localState = null;
68
- // This allows dematerialized inverses to be rematerialized
69
- // we shouldn't be notifying here though, figure out where
70
- // a notification was missed elsewhere.
71
- {
72
- notifyChange(graph, relationship);
73
- }
74
- }
75
- } else if (isHasMany(relationship)) {
76
- relationship.remoteMembers.delete(value);
77
- relationship.additions?.delete(value);
78
- const wasInRemovals = relationship.removals?.delete(value);
79
- const canonicalIndex = relationship.remoteState.indexOf(value);
80
- if (canonicalIndex !== -1) {
81
- relationship.remoteState.splice(canonicalIndex, 1);
82
- }
83
- if (!wasInRemovals) {
84
- const currentIndex = relationship.localState?.indexOf(value);
85
- if (currentIndex !== -1 && currentIndex !== undefined) {
86
- relationship.localState.splice(currentIndex, 1);
87
- // This allows dematerialized inverses to be rematerialized
88
- // we shouldn't be notifying here though, figure out where
89
- // a notification was missed elsewhere.
90
- {
91
- notifyChange(graph, relationship);
92
- }
93
- }
94
- }
95
- } else {
96
- relationship.remoteMembers.delete(value);
97
- relationship.localMembers.delete(value);
98
- }
99
- }
59
+ if (isBelongsTo(relationship)) {
60
+ if (relationship.remoteState === value) relationship.remoteState = null;
61
+ if (relationship.localState === value) {
62
+ relationship.localState = null;
63
+ if (!silenceNotifications) notifyChange(graph, relationship);
64
+ }
65
+ } else if (isHasMany(relationship)) {
66
+ relationship.remoteMembers.delete(value);
67
+ relationship.additions?.delete(value);
68
+ const wasInRemovals = relationship.removals?.delete(value);
69
+ const canonicalIndex = relationship.remoteState.indexOf(value);
70
+ if (canonicalIndex !== -1) relationship.remoteState.splice(canonicalIndex, 1);
71
+ if (!wasInRemovals) {
72
+ const currentIndex = relationship.localState?.indexOf(value);
73
+ if (currentIndex !== -1 && currentIndex !== void 0) {
74
+ relationship.localState.splice(currentIndex, 1);
75
+ if (!silenceNotifications) notifyChange(graph, relationship);
76
+ }
77
+ }
78
+ } else {
79
+ relationship.remoteMembers.delete(value);
80
+ relationship.localMembers.delete(value);
81
+ }
82
+ }
83
+ /** Notifies the store that a relationship has changed, provided the relationship has been accessed and is not currently being removed. */
100
84
  function notifyChange(graph, relationship) {
101
- if (!relationship.accessed) {
102
- return;
103
- }
104
- const resourceKey = relationship.identifier;
105
- const key = relationship.definition.key;
106
- if (resourceKey === graph._removing) {
107
- return;
108
- }
109
- graph.store.notifyChange(resourceKey, 'relationships', key);
110
- }
111
- function isLegacyField(field) {
112
- return field.kind === 'belongsTo' || field.kind === 'hasMany';
113
- }
114
- function temporaryConvertToLegacy(field) {
115
- return {
116
- kind: field.kind === 'resource' ? 'belongsTo' : 'hasMany',
117
- name: field.name,
118
- type: field.type,
119
- options: Object.assign({}, {
120
- async: false,
121
- inverse: null,
122
- resetOnRemoteUpdate: false
123
- }, field.options)
124
- };
85
+ if (!relationship.accessed) return;
86
+ const resourceKey = relationship.identifier;
87
+ const key = relationship.definition.key;
88
+ if (resourceKey === graph._removing) return;
89
+ graph.store.notifyChange(resourceKey, "relationships", key);
125
90
  }
126
91
 
127
- /**
128
- *
129
- * Given RHS (Right Hand Side)
130
- *
131
- * ```ts
132
- * class User extends Model {
133
- * @hasMany('animal', { async: false, inverse: 'owner' }) pets;
134
- * }
135
- * ```
136
- *
137
- * Given LHS (Left Hand Side)
138
- *
139
- * ```ts
140
- * class Animal extends Model {
141
- * @belongsTo('user', { async: false, inverse: 'pets' }) owner;
142
- * }
143
- * ```
144
- *
145
- * The UpgradedMeta for the RHS would be:
146
- *
147
- * ```ts
148
- * {
149
- * kind: 'hasMany',
150
- * key: 'pets',
151
- * type: 'animal',
152
- * isAsync: false,
153
- * isImplicit: false,
154
- * isCollection: true,
155
- * isPolymorphic: false,
156
- * inverseKind: 'belongsTo',
157
- * inverseKey: 'owner',
158
- * inverseType: 'user',
159
- * inverseIsAsync: false,
160
- * inverseIsImplicit: false,
161
- * inverseIsCollection: false,
162
- * inverseIsPolymorphic: false,
163
- * }
164
- * ```
165
- *
166
- * The UpgradeMeta for the LHS would be:
167
- *
168
- * ```ts
169
- * {
170
- * kind: 'belongsTo',
171
- * key: 'owner',
172
- * type: 'user',
173
- * isAsync: false,
174
- * isImplicit: false,
175
- * isCollection: false,
176
- * isPolymorphic: false,
177
- * inverseKind: 'hasMany',
178
- * inverseKey: 'pets',
179
- * inverseType: 'animal',
180
- * inverseIsAsync: false,
181
- * inverseIsImplicit: false,
182
- * inverseIsCollection: true,
183
- * inverseIsPolymorphic: false,
184
- * }
185
- * ```
186
- *
187
- * @private
188
- */
189
-
190
- const BOOL_LATER = null;
191
- const STR_LATER = '';
192
- const IMPLICIT_KEY_RAND = Date.now();
193
- function implicitKeyFor(type, key) {
194
- return `implicit-${type}:${key}${IMPLICIT_KEY_RAND}`;
195
- }
196
- function syncMeta(definition, inverseDefinition) {
197
- definition.inverseKind = inverseDefinition.kind;
198
- definition.inverseKey = inverseDefinition.key;
199
- definition.inverseName = inverseDefinition.name;
200
- definition.inverseType = inverseDefinition.type;
201
- definition.inverseIsAsync = inverseDefinition.isAsync;
202
- definition.inverseIsCollection = inverseDefinition.isCollection;
203
- definition.inverseIsPolymorphic = inverseDefinition.isPolymorphic;
204
- definition.inverseIsImplicit = inverseDefinition.isImplicit;
205
- definition.inverseIsLinksMode = inverseDefinition.isLinksMode;
206
- const resetOnRemoteUpdate = definition.resetOnRemoteUpdate === false || inverseDefinition.resetOnRemoteUpdate === false ? false : true;
207
- definition.resetOnRemoteUpdate = resetOnRemoteUpdate;
208
- inverseDefinition.resetOnRemoteUpdate = resetOnRemoteUpdate;
209
- }
210
- function upgradeMeta(meta) {
211
- if (!isLegacyField(meta)) {
212
- meta = temporaryConvertToLegacy(meta);
213
- }
214
- const niceMeta = {};
215
- const options = meta.options;
216
- niceMeta.kind = meta.kind;
217
- niceMeta.key = meta.sourceKey ?? meta.name;
218
- niceMeta.name = meta.name;
219
- niceMeta.type = meta.type;
220
- niceMeta.isAsync = options.async;
221
- niceMeta.isImplicit = false;
222
- niceMeta.isCollection = meta.kind === 'hasMany';
223
- niceMeta.isPolymorphic = options && !!options.polymorphic;
224
- niceMeta.isLinksMode = options.linksMode ?? false;
225
- niceMeta.inverseKey = options && options.inverse || STR_LATER;
226
- niceMeta.inverseName = options && options.inverse || STR_LATER;
227
- niceMeta.inverseType = STR_LATER;
228
- niceMeta.inverseIsAsync = BOOL_LATER;
229
- niceMeta.inverseIsImplicit = options && options.inverse === null || BOOL_LATER;
230
- niceMeta.inverseIsCollection = BOOL_LATER;
231
- niceMeta.inverseIsLinksMode = BOOL_LATER;
232
-
233
- // prettier-ignore
234
- niceMeta.resetOnRemoteUpdate = !isLegacyField(meta) ? false : meta.options?.linksMode ? false : meta.options?.resetOnRemoteUpdate === false ? false : true;
235
- return niceMeta;
236
- }
237
- function isLHS(info, type, key) {
238
- const isSelfReferential = info.isSelfReferential;
239
- const isRelationship = key === info.lhs_relationshipName;
240
- if (isRelationship === true) {
241
- return isSelfReferential === true ||
242
- // itself
243
- type === info.lhs_baseModelName ||
244
- // base or non-polymorphic
245
- // if the other side is polymorphic then we need to scan our modelNames
246
- info.rhs_isPolymorphic && info.lhs_modelNames.includes(type) // polymorphic
247
- ;
248
- }
249
- return false;
250
- }
251
- function upgradeDefinition(graph, key, propertyName, isImplicit = false) {
252
- const cache = graph._definitionCache;
253
- const storeWrapper = graph.store;
254
- const polymorphicLookup = graph._potentialPolymorphicTypes;
255
- const {
256
- type
257
- } = key;
258
- let cached = /*#__NOINLINE__*/expandingGet(cache, type, propertyName);
259
-
260
- // CASE: We have a cached resolution (null if no relationship exists)
261
- if (cached !== undefined) {
262
- return cached;
263
- }
264
- const relationships = storeWrapper.schema.fields(key);
265
- const relationshipsBySourceKey = storeWrapper.schema.cacheFields?.(key) ?? relationships;
266
- const meta = relationshipsBySourceKey.get(propertyName);
267
- if (!meta) {
268
- // TODO potentially we should just be permissive here since this is an implicit relationship
269
- // and not require the lookup table to be populated
270
- if (polymorphicLookup[type]) {
271
- const altTypes = Object.keys(polymorphicLookup[type]);
272
- for (let i = 0; i < altTypes.length; i++) {
273
- const _cached = expandingGet(cache, altTypes[i], propertyName);
274
- if (_cached) {
275
- /*#__NOINLINE__*/expandingSet(cache, type, propertyName, _cached);
276
- _cached.rhs_modelNames.push(type);
277
- return _cached;
278
- }
279
- }
280
- }
281
- cache[type][propertyName] = null;
282
- return null;
283
- }
284
- const definition = /*#__NOINLINE__*/upgradeMeta(meta);
285
- let inverseDefinition;
286
- let inverseKey;
287
- const inverseType = definition.type;
288
-
289
- // CASE: Inverse is explicitly null
290
- if (definition.inverseKey === null) {
291
- inverseDefinition = null;
292
- } else {
293
- inverseKey = /*#__NOINLINE__*/inverseForRelationship(getStore(storeWrapper), key, propertyName);
294
-
295
- // CASE: If we are polymorphic, and we declared an inverse that is non-null
296
- // we must assume that the lack of inverseKey means that there is no
297
- // concrete type as the baseType, so we must construct and artificial
298
- // placeholder
299
- if (!inverseKey && definition.isPolymorphic && definition.inverseKey) {
300
- inverseDefinition = {
301
- kind: 'belongsTo',
302
- // this must be updated when we find the first belongsTo or hasMany definition that matches
303
- key: definition.inverseKey,
304
- name: definition.inverseName,
305
- type: type,
306
- isAsync: false,
307
- // this must be updated when we find the first belongsTo or hasMany definition that matches
308
- isImplicit: false,
309
- isCollection: false,
310
- // this must be updated when we find the first belongsTo or hasMany definition that matches
311
- isPolymorphic: false
312
- }; // the rest of the fields are populated by syncMeta
313
-
314
- // CASE: Inverse resolves to null
315
- } else if (!inverseKey) {
316
- inverseDefinition = null;
317
- } else {
318
- // CASE: We have an explicit inverse or were able to resolve one
319
- // for the inverse we use "name" for lookup not "sourceKey"
320
- const inverseDefinitions = storeWrapper.schema.fields({
321
- type: inverseType
322
- });
323
- const metaFromInverse = inverseDefinitions.get(inverseKey);
324
- inverseDefinition = upgradeMeta(metaFromInverse);
325
- }
326
- }
327
-
328
- // CASE: We have no inverse
329
- if (!inverseDefinition) {
330
- // polish off meta
331
- inverseKey = /*#__NOINLINE__*/implicitKeyFor(type, propertyName);
332
- inverseDefinition = {
333
- kind: 'implicit',
334
- key: inverseKey,
335
- type: type,
336
- isAsync: false,
337
- isImplicit: true,
338
- isCollection: true,
339
- // with implicits any number of records could point at us
340
- isPolymorphic: false
341
- }; // the rest of the fields are populated by syncMeta
342
-
343
- syncMeta(definition, inverseDefinition);
344
- syncMeta(inverseDefinition, definition);
345
- const info = {
346
- lhs_key: `${type}:${propertyName}`,
347
- lhs_modelNames: [type],
348
- lhs_baseModelName: type,
349
- lhs_relationshipName: propertyName,
350
- lhs_definition: definition,
351
- lhs_isPolymorphic: definition.isPolymorphic,
352
- rhs_key: inverseDefinition.key,
353
- rhs_modelNames: [inverseType],
354
- rhs_baseModelName: inverseType,
355
- rhs_relationshipName: inverseDefinition.key,
356
- rhs_definition: inverseDefinition,
357
- rhs_isPolymorphic: false,
358
- hasInverse: false,
359
- isSelfReferential: type === inverseType,
360
- // this could be wrong if we are self-referential but also polymorphic
361
- isReflexive: false // we can't be reflexive if we don't define an inverse
362
- };
363
- expandingSet(cache, inverseType, inverseKey, info);
364
- expandingSet(cache, type, propertyName, info);
365
- return info;
366
- }
367
-
368
- // CASE: We do have an inverse
369
- const baseType = inverseDefinition.type;
370
- cached = expandingGet(cache, baseType, propertyName) || expandingGet(cache, inverseType, inverseKey);
371
- if (cached) {
372
- const _isLHS = cached.lhs_baseModelName === baseType;
373
- const modelNames = _isLHS ? cached.lhs_modelNames : cached.rhs_modelNames;
374
- // make this lookup easier in the future by caching the key
375
- modelNames.push(type);
376
- expandingSet(cache, type, propertyName, cached);
377
- return cached;
378
- }
379
-
380
- // this is our first time so polish off the metas
381
- syncMeta(definition, inverseDefinition);
382
- syncMeta(inverseDefinition, definition);
383
- const lhs_modelNames = [type];
384
- if (type !== baseType) {
385
- lhs_modelNames.push(baseType);
386
- }
387
- const isSelfReferential = baseType === inverseType;
388
- const info = {
389
- lhs_key: `${baseType}:${propertyName}`,
390
- lhs_modelNames,
391
- lhs_baseModelName: baseType,
392
- lhs_relationshipName: propertyName,
393
- lhs_definition: definition,
394
- lhs_isPolymorphic: definition.isPolymorphic,
395
- rhs_key: `${inverseType}:${inverseKey}`,
396
- rhs_modelNames: [inverseType],
397
- rhs_baseModelName: inverseType,
398
- rhs_relationshipName: inverseKey,
399
- rhs_definition: inverseDefinition,
400
- rhs_isPolymorphic: inverseDefinition.isPolymorphic,
401
- hasInverse: true,
402
- isSelfReferential,
403
- isReflexive: isSelfReferential && propertyName === inverseKey
404
- };
405
-
406
- // Create entries for the baseModelName as well as modelName to speed up
407
- // inverse lookups
408
- expandingSet(cache, baseType, propertyName, info);
409
- expandingSet(cache, type, propertyName, info);
410
-
411
- // Greedily populate the inverse
412
- expandingSet(cache, inverseType, inverseKey, info);
413
- return info;
414
- }
415
- function inverseForRelationship(store, resourceKey, key) {
416
- const fields = store.schema.fields(resourceKey);
417
- const definition = fields.get(key);
418
- if (!definition) {
419
- return null;
420
- }
421
- return definition.options.inverse;
422
- }
423
-
424
- /*
425
- case many:1
426
- ========
427
- In a bi-directional graph with Many:1 edges, adding a value
428
- results in up-to 3 discrete value transitions, while removing
429
- a value is only 2 transitions.
430
-
431
- For adding C to A
432
- If: A <<-> B, C <->> D is the initial state,
433
- and: B <->> A <<-> C, D is the final state
434
-
435
- then we would undergo the following transitions.
436
-
437
- add C to A
438
- remove C from D
439
- add A to C
440
-
441
- For removing B from A
442
- If: A <<-> B, C <->> D is the initial state,
443
- and: A, B, C <->> D is the final state
444
-
445
- then we would undergo the following transitions.
446
-
447
- remove B from A
448
- remove A from B
449
-
450
- case many:many
451
- ===========
452
- In a bi-directional graph with Many:Many edges, adding or
453
- removing a value requires only 2 value transitions.
454
-
455
- For Adding
456
- If: A<<->>B, C<<->>D is the initial state (double arrows representing the many side)
457
- And: D<<->>C<<->>A<<->>B is the final state
458
-
459
- Then we would undergo two transitions.
460
-
461
- add C to A.
462
- add A to C
463
-
464
- For Removing
465
- If: A<<->>B, C<<->>D is the initial state (double arrows representing the many side)
466
- And: A, B, C<<->>D is the final state
467
-
468
- Then we would undergo two transitions.
469
-
470
- remove B from A
471
- remove A from B
472
-
473
- case many:?
474
- ========
475
- In a uni-directional graph with Many:? edges (modeled in WarpDrive with `inverse:null`) with
476
- artificial (implicit) inverses, replacing a value results in 2 discrete value transitions.
477
- This is because a Many:? relationship is effectively Many:Many.
478
- */
92
+ //#endregion
93
+ //#region src/graph/-private/operations/replace-related-records.ts
479
94
  function replaceRelatedRecords(graph, op, isRemote) {
480
- if (isRemote) {
481
- replaceRelatedRecordsRemote(graph, op, isRemote);
482
- } else {
483
- replaceRelatedRecordsLocal(graph, op, isRemote);
484
- }
95
+ if (isRemote) replaceRelatedRecordsRemote(graph, op, isRemote);
96
+ else replaceRelatedRecordsLocal(graph, op, isRemote);
485
97
  }
486
98
  function replaceRelatedRecordsLocal(graph, op, isRemote) {
487
- const resourceKeys = op.value;
488
- const relationship = graph.get(op.record, op.field);
489
- relationship.state.hasReceivedData = true;
490
- const {
491
- additions,
492
- removals
493
- } = relationship;
494
- const {
495
- inverseKey,
496
- type
497
- } = relationship.definition;
498
- const {
499
- record
500
- } = op;
501
- const wasDirty = relationship.isDirty;
502
- let localBecameDirty = false;
503
- const onAdd = resourceKey => {
504
- // Since we are diffing against the remote state, we check
505
- // if our previous local state did not contain this ResourceKey
506
- const removalsHas = removals?.has(resourceKey);
507
- if (removalsHas || !additions?.has(resourceKey)) {
508
- if (type !== resourceKey.type) {
509
- graph.registerPolymorphicType(type, resourceKey.type);
510
- }
511
-
512
- // we've added a record locally that wasn't in the local state before
513
- localBecameDirty = true;
514
- addToInverse(graph, resourceKey, inverseKey, op.record, isRemote);
515
- if (removalsHas) {
516
- removals.delete(resourceKey);
517
- }
518
- }
519
- };
520
- const onRemove = resourceKey => {
521
- // Since we are diffing against the remote state, we check
522
- // if our previous local state had contained this ResourceKey
523
- const additionsHas = additions?.has(resourceKey);
524
- if (additionsHas || !removals?.has(resourceKey)) {
525
- // we've removed a record locally that was in the local state before
526
- localBecameDirty = true;
527
- removeFromInverse(graph, resourceKey, inverseKey, record, isRemote);
528
- if (additionsHas) {
529
- additions.delete(resourceKey);
530
- }
531
- }
532
- };
533
- const diff = diffCollection(resourceKeys, relationship, onAdd, onRemove);
534
-
535
- // any additions no longer in the local state
536
- // also need to be removed from the inverse
537
- if (additions && additions.size > 0) {
538
- additions.forEach(resourceKey => {
539
- if (!diff.add.has(resourceKey)) {
540
- localBecameDirty = true;
541
- onRemove(resourceKey);
542
- }
543
- });
544
- }
545
-
546
- // any removals no longer in the local state
547
- // also need to be added back to the inverse
548
- if (removals && removals.size > 0) {
549
- removals.forEach(resourceKey => {
550
- if (!diff.del.has(resourceKey)) {
551
- localBecameDirty = true;
552
- onAdd(resourceKey);
553
- }
554
- });
555
- }
556
- const becameDirty = diff.changed || localBecameDirty;
557
- relationship.additions = diff.add;
558
- relationship.removals = diff.del;
559
- relationship.localState = diff.finalState;
560
-
561
- // we only notify if the localState changed and were not already dirty before
562
- // because if we were already dirty then we have already notified
563
- if (becameDirty && !wasDirty) {
564
- notifyChange(graph, relationship);
565
- }
99
+ const resourceKeys = op.value;
100
+ const relationship = graph.get(op.record, op.field);
101
+ relationship.state.hasReceivedData = true;
102
+ const { additions, removals } = relationship;
103
+ const { inverseKey, type } = relationship.definition;
104
+ const { record } = op;
105
+ const wasDirty = relationship.isDirty;
106
+ let localBecameDirty = false;
107
+ const onAdd = (resourceKey) => {
108
+ const removalsHas = removals?.has(resourceKey);
109
+ if (removalsHas || !additions?.has(resourceKey)) {
110
+ if (type !== resourceKey.type) graph.registerPolymorphicType(type, resourceKey.type);
111
+ localBecameDirty = true;
112
+ addToInverse(graph, resourceKey, inverseKey, op.record, isRemote);
113
+ if (removalsHas) removals.delete(resourceKey);
114
+ }
115
+ };
116
+ const onRemove = (resourceKey) => {
117
+ const additionsHas = additions?.has(resourceKey);
118
+ if (additionsHas || !removals?.has(resourceKey)) {
119
+ localBecameDirty = true;
120
+ removeFromInverse(graph, resourceKey, inverseKey, record, isRemote);
121
+ if (additionsHas) additions.delete(resourceKey);
122
+ }
123
+ };
124
+ const diff = diffCollection(resourceKeys, relationship, onAdd, onRemove);
125
+ if (additions && additions.size > 0) additions.forEach((resourceKey) => {
126
+ if (!diff.add.has(resourceKey)) {
127
+ localBecameDirty = true;
128
+ onRemove(resourceKey);
129
+ }
130
+ });
131
+ if (removals && removals.size > 0) removals.forEach((resourceKey) => {
132
+ if (!diff.del.has(resourceKey)) {
133
+ localBecameDirty = true;
134
+ onAdd(resourceKey);
135
+ }
136
+ });
137
+ const becameDirty = diff.changed || localBecameDirty;
138
+ relationship.additions = diff.add;
139
+ relationship.removals = diff.del;
140
+ relationship.localState = diff.finalState;
141
+ if (becameDirty && !wasDirty) notifyChange(graph, relationship);
566
142
  }
567
143
  function replaceRelatedRecordsRemote(graph, op, isRemote) {
568
- const resourceKeys = op.value;
569
- const relationship = graph.get(op.record, op.field);
570
- if (isRemote) {
571
- graph._addToTransaction(relationship);
572
- }
573
- const wasDirty = relationship.isDirty;
574
- // if this is our first time receiving data
575
- // we need to mark the relationship as dirty
576
- // so that non-materializing APIs like `hasManyReference.value()`
577
- // will get notified and updated.
578
- if (!relationship.state.hasReceivedData) {
579
- relationship.isDirty = true;
580
- }
581
- relationship.state.hasReceivedData = true;
582
-
583
- // cache existing state
584
- const {
585
- definition
586
- } = relationship;
587
- const {
588
- type
589
- } = relationship.definition;
590
- const diff = diffCollection(resourceKeys, relationship, resourceKey => {
591
- if (type !== resourceKey.type) {
592
- graph.registerPolymorphicType(type, resourceKey.type);
593
- }
594
- // commit additions
595
- // TODO build this into the diff?
596
- // because we are not dirty if this was a committed local addition
597
- if (relationship.additions?.has(resourceKey)) {
598
- relationship.additions.delete(resourceKey);
599
- }
600
- addToInverse(graph, resourceKey, definition.inverseKey, op.record, isRemote);
601
- }, resourceKey => {
602
- // commit removals
603
- // TODO build this into the diff?
604
- // because we are not dirty if this was a committed local addition
605
- if (relationship.removals?.has(resourceKey)) {
606
- relationship.removals.delete(resourceKey);
607
- }
608
- removeFromInverse(graph, resourceKey, definition.inverseKey, op.record, isRemote);
609
- });
610
-
611
- // replace existing state
612
- relationship.remoteMembers = diff.finalSet;
613
- relationship.remoteState = diff.finalState;
614
-
615
- // changed also indicates a change in order
616
- if (diff.changed) {
617
- relationship.isDirty = true;
618
- }
619
-
620
- // TODO unsure if we need this but it
621
- // may allow us to more efficiently patch
622
- // the associated ManyArray
623
- relationship._diff = diff;
624
- {
625
- // only do this for legacy hasMany, not collection
626
- // and provide a way to incrementally migrate
627
- if (
628
- // we do not guard by diff.changed here
629
- // because we want to clear local changes even if
630
- // no change has occurred to preserve the legacy behavior
631
- relationship.definition.kind === 'hasMany' && relationship.definition.resetOnRemoteUpdate !== false && (diff.changed || wasDirty)) {
632
- if (relationship.removals) {
633
- relationship.isDirty = true;
634
- relationship.removals.forEach(resourceKey => {
635
- // reverse the removal
636
- // if we are still in removals at this point then
637
- // we were not "committed" which means we are present
638
- // in the remoteMembers. So we "add back" on the inverse.
639
- addToInverse(graph, resourceKey, definition.inverseKey, op.record, false);
640
- });
641
- relationship.removals = null;
642
- }
643
- if (relationship.additions) {
644
- relationship.additions.forEach(resourceKey => {
645
- // reverse the addition
646
- // if we are still in additions at this point then
647
- // we were not "committed" which means we are not present
648
- // in the remoteMembers. So we "remove" from the inverse.
649
- // however we only do this if we are not a "new" record.
650
- if (!checkIfNew(graph._realStore, resourceKey)) {
651
- relationship.isDirty = true;
652
- relationship.additions.delete(resourceKey);
653
- removeFromInverse(graph, resourceKey, definition.inverseKey, op.record, false);
654
- }
655
- });
656
- if (relationship.additions.size === 0) {
657
- relationship.additions = null;
658
- }
659
- }
660
- }
661
- }
662
- if (relationship.isDirty && !wasDirty) {
663
- flushCanonical(graph, relationship);
664
- }
144
+ const resourceKeys = op.value;
145
+ const relationship = graph.get(op.record, op.field);
146
+ if (isRemote) graph._addToTransaction(relationship);
147
+ const wasDirty = relationship.isDirty;
148
+ if (!relationship.state.hasReceivedData) relationship.isDirty = true;
149
+ relationship.state.hasReceivedData = true;
150
+ const { definition } = relationship;
151
+ const { type } = relationship.definition;
152
+ const diff = diffCollection(resourceKeys, relationship, (resourceKey) => {
153
+ if (type !== resourceKey.type) graph.registerPolymorphicType(type, resourceKey.type);
154
+ if (relationship.additions?.has(resourceKey)) relationship.additions.delete(resourceKey);
155
+ addToInverse(graph, resourceKey, definition.inverseKey, op.record, isRemote);
156
+ }, (resourceKey) => {
157
+ if (relationship.removals?.has(resourceKey)) relationship.removals.delete(resourceKey);
158
+ removeFromInverse(graph, resourceKey, definition.inverseKey, op.record, isRemote);
159
+ });
160
+ relationship.remoteMembers = diff.finalSet;
161
+ relationship.remoteState = diff.finalState;
162
+ if (diff.changed) relationship.isDirty = true;
163
+ relationship._diff = diff;
164
+ if (relationship.definition.kind === "hasMany" && relationship.definition.resetOnRemoteUpdate !== false && (diff.changed || wasDirty)) {
165
+ const deprecationInfo = {
166
+ removals: [],
167
+ additions: [],
168
+ triggered: false
169
+ };
170
+ if (relationship.removals) {
171
+ relationship.isDirty = true;
172
+ relationship.removals.forEach((resourceKey) => {
173
+ deprecationInfo.triggered = true;
174
+ deprecationInfo.removals.push(resourceKey);
175
+ addToInverse(graph, resourceKey, definition.inverseKey, op.record, false);
176
+ });
177
+ relationship.removals = null;
178
+ }
179
+ if (relationship.additions) {
180
+ relationship.additions.forEach((resourceKey) => {
181
+ if (!checkIfNew(graph._realStore, resourceKey)) {
182
+ deprecationInfo.triggered = true;
183
+ deprecationInfo.additions.push(resourceKey);
184
+ relationship.isDirty = true;
185
+ relationship.additions.delete(resourceKey);
186
+ removeFromInverse(graph, resourceKey, definition.inverseKey, op.record, false);
187
+ }
188
+ });
189
+ if (relationship.additions.size === 0) relationship.additions = null;
190
+ }
191
+ if (deprecationInfo.triggered) {}
192
+ }
193
+ if (relationship.isDirty && !wasDirty) flushCanonical(graph, relationship);
665
194
  }
666
195
  function addToInverse(graph, resourceKey, key, value, isRemote) {
667
- const relationship = graph.get(resourceKey, key);
668
- const {
669
- type
670
- } = relationship.definition;
671
- if (type !== value.type) {
672
- graph.registerPolymorphicType(type, value.type);
673
- }
674
- if (isBelongsTo(relationship)) {
675
- relationship.state.hasReceivedData = true;
676
- relationship.state.isEmpty = false;
677
- if (isRemote) {
678
- graph._addToTransaction(relationship);
679
- if (relationship.remoteState !== null) {
680
- removeFromInverse(graph, relationship.remoteState, relationship.definition.inverseKey, resourceKey, isRemote);
681
- }
682
- relationship.remoteState = value;
683
- }
684
- if (relationship.localState !== value) {
685
- if (!isRemote && relationship.localState) {
686
- removeFromInverse(graph, relationship.localState, relationship.definition.inverseKey, resourceKey, isRemote);
687
- }
688
- relationship.localState = value;
689
- notifyChange(graph, relationship);
690
- }
691
- } else if (isHasMany(relationship)) {
692
- if (isRemote) {
693
- // TODO this needs to alert stuffs
694
- // And patch state better
695
- // This is almost definitely wrong
696
- // WARNING WARNING WARNING
697
-
698
- if (!relationship.remoteMembers.has(value)) {
699
- graph._addToTransaction(relationship);
700
- relationship.remoteState.push(value);
701
- relationship.remoteMembers.add(value);
702
- if (relationship.additions?.has(value)) {
703
- relationship.additions.delete(value);
704
- } else {
705
- relationship.isDirty = true;
706
- relationship.state.hasReceivedData = true;
707
- flushCanonical(graph, relationship);
708
- }
709
- }
710
- } else {
711
- // if we are not dirty but have a null localState then we
712
- // are mutating a relationship that has never been fetched
713
- // so we initialize localState to an empty array
714
- if (!relationship.isDirty && !relationship.localState) {
715
- relationship.localState = [];
716
- }
717
- if (_add(graph, resourceKey, relationship, value, null, isRemote)) {
718
- notifyChange(graph, relationship);
719
- }
720
- }
721
- } else {
722
- if (isRemote) {
723
- if (!relationship.remoteMembers.has(value)) {
724
- relationship.remoteMembers.add(value);
725
- relationship.localMembers.add(value);
726
- }
727
- } else {
728
- if (!relationship.localMembers.has(value)) {
729
- relationship.localMembers.add(value);
730
- }
731
- }
732
- }
196
+ const relationship = graph.get(resourceKey, key);
197
+ const { type } = relationship.definition;
198
+ if (type !== value.type) graph.registerPolymorphicType(type, value.type);
199
+ if (isBelongsTo(relationship)) {
200
+ relationship.state.hasReceivedData = true;
201
+ relationship.state.isEmpty = false;
202
+ if (isRemote) {
203
+ graph._addToTransaction(relationship);
204
+ if (relationship.remoteState !== null) removeFromInverse(graph, relationship.remoteState, relationship.definition.inverseKey, resourceKey, isRemote);
205
+ relationship.remoteState = value;
206
+ }
207
+ if (relationship.localState !== value) {
208
+ if (!isRemote && relationship.localState) removeFromInverse(graph, relationship.localState, relationship.definition.inverseKey, resourceKey, isRemote);
209
+ relationship.localState = value;
210
+ notifyChange(graph, relationship);
211
+ }
212
+ } else if (isHasMany(relationship)) {
213
+ if (isRemote) {
214
+ if (!relationship.remoteMembers.has(value)) {
215
+ graph._addToTransaction(relationship);
216
+ relationship.remoteState.push(value);
217
+ relationship.remoteMembers.add(value);
218
+ if (relationship.additions?.has(value)) relationship.additions.delete(value);
219
+ else {
220
+ relationship.isDirty = true;
221
+ relationship.state.hasReceivedData = true;
222
+ flushCanonical(graph, relationship);
223
+ }
224
+ }
225
+ } else {
226
+ if (!relationship.isDirty && !relationship.localState) relationship.localState = [];
227
+ if (_add(graph, resourceKey, relationship, value, null, isRemote)) notifyChange(graph, relationship);
228
+ }
229
+ } else if (isRemote) {
230
+ if (!relationship.remoteMembers.has(value)) {
231
+ relationship.remoteMembers.add(value);
232
+ relationship.localMembers.add(value);
233
+ }
234
+ } else if (!relationship.localMembers.has(value)) relationship.localMembers.add(value);
733
235
  }
734
236
  function notifyInverseOfPotentialMaterialization(graph, resourceKey, key, value, isRemote) {
735
- const relationship = graph.get(resourceKey, key);
736
- if (isHasMany(relationship) && isRemote && relationship.remoteMembers.has(value)) {
737
- notifyChange(graph, relationship);
738
- }
237
+ const relationship = graph.get(resourceKey, key);
238
+ if (isHasMany(relationship) && isRemote && relationship.remoteMembers.has(value)) notifyChange(graph, relationship);
739
239
  }
740
240
  function removeFromInverse(graph, resourceKey, key, value, isRemote) {
741
- const relationship = graph.get(resourceKey, key);
742
- if (isBelongsTo(relationship)) {
743
- relationship.state.isEmpty = true;
744
- if (isRemote) {
745
- graph._addToTransaction(relationship);
746
- relationship.remoteState = null;
747
- }
748
- if (relationship.localState === value) {
749
- relationship.localState = null;
750
- notifyChange(graph, relationship);
751
- }
752
- } else if (isHasMany(relationship)) {
753
- if (isRemote) {
754
- graph._addToTransaction(relationship);
755
- if (_removeRemote(relationship, value)) {
756
- notifyChange(graph, relationship);
757
- }
758
- } else {
759
- if (_removeLocal(relationship, value)) {
760
- notifyChange(graph, relationship);
761
- }
762
- }
763
- } else {
764
- if (isRemote) {
765
- relationship.remoteMembers.delete(value);
766
- relationship.localMembers.delete(value);
767
- } else {
768
- if (value && relationship.localMembers.has(value)) {
769
- relationship.localMembers.delete(value);
770
- }
771
- }
772
- }
241
+ const relationship = graph.get(resourceKey, key);
242
+ if (isBelongsTo(relationship)) {
243
+ relationship.state.isEmpty = true;
244
+ if (isRemote) {
245
+ graph._addToTransaction(relationship);
246
+ relationship.remoteState = null;
247
+ }
248
+ if (relationship.localState === value) {
249
+ relationship.localState = null;
250
+ notifyChange(graph, relationship);
251
+ }
252
+ } else if (isHasMany(relationship)) {
253
+ if (isRemote) {
254
+ graph._addToTransaction(relationship);
255
+ if (_removeRemote(relationship, value)) notifyChange(graph, relationship);
256
+ } else if (_removeLocal(relationship, value)) notifyChange(graph, relationship);
257
+ } else if (isRemote) {
258
+ relationship.remoteMembers.delete(value);
259
+ relationship.localMembers.delete(value);
260
+ } else if (value && relationship.localMembers.has(value)) relationship.localMembers.delete(value);
773
261
  }
774
262
  function flushCanonical(graph, rel) {
775
- if (rel.accessed) {
776
- graph._scheduleLocalSync(rel);
777
- }
263
+ if (rel.accessed) graph._scheduleLocalSync(rel);
778
264
  }
779
- function replaceRelatedRecord(graph, op, isRemote = false) {
780
- const relationship = graph.get(op.record, op.field);
781
- if (isRemote) {
782
- graph._addToTransaction(relationship);
783
- }
784
- const {
785
- definition,
786
- state
787
- } = relationship;
788
- const prop = isRemote ? 'remoteState' : 'localState';
789
- const existingState = relationship[prop];
790
-
791
- /*
792
- case 1:1
793
- ========
794
- In a bi-directional graph with 1:1 edges, replacing a value
795
- results in up-to 4 discrete value transitions.
796
- If: A <-> B, C <-> D is the initial state,
797
- and: A <-> C, B, D is the final state
798
- then we would undergo the following 4 transitions.
799
- remove A from B
800
- add C to A
801
- remove C from D
802
- add A to C
803
- case 1:many
804
- ===========
805
- In a bi-directional graph with 1:Many edges, replacing a value
806
- results in up-to 3 discrete value transitions.
807
- If: A<->>B<<->D, C<<->D is the initial state (double arrows representing the many side)
808
- And: A<->>C<<->D, B<<->D is the final state
809
- Then we would undergo three transitions.
810
- remove A from B
811
- add C to A.
812
- add A to C
813
- case 1:?
814
- ========
815
- In a uni-directional graph with 1:? edges (modeled in WarpDrive with `inverse:null`) with
816
- artificial (implicit) inverses, replacing a value results in up-to 3 discrete value transitions.
817
- This is because a 1:? relationship is effectively 1:many.
818
- If: A->B, C->B is the initial state
819
- And: A->C, C->B is the final state
820
- Then we would undergo three transitions.
821
- Remove A from B
822
- Add C to A
823
- Add A to C
824
- */
825
-
826
- // nothing for us to do
827
- if (op.value === existingState) {
828
- // if we were empty before but now know we are empty this needs to be true
829
- state.hasReceivedData = true;
830
-
831
- // if this is a remote update we still sync
832
- if (isRemote) {
833
- state.hasReceivedRemoteData = true;
834
- const {
835
- localState
836
- } = relationship;
837
- // don't sync if localState is a new record and our remoteState is null
838
- if (localState && checkIfNew(graph._realStore, localState) && !existingState) {
839
- return;
840
- }
841
- if (existingState && localState === existingState) {
842
- notifyInverseOfPotentialMaterialization(graph, existingState, definition.inverseKey, op.record, isRemote);
843
- } else {
844
- // if localState does not match existingState then we know
845
- // we have a local mutation that has not been persisted yet
846
- if (localState !== op.value && relationship.definition.resetOnRemoteUpdate !== false) {
847
- relationship.localState = existingState;
848
- notifyChange(graph, relationship);
849
- }
850
- }
851
- }
852
- return;
853
- }
854
-
855
- // remove this value from the inverse if required
856
- if (existingState) {
857
- removeFromInverse(graph, existingState, definition.inverseKey, op.record, isRemote);
858
- }
859
-
860
- // update value to the new value
861
- relationship[prop] = op.value;
862
- state.hasReceivedData = true;
863
- /**
864
- * Local mutations never give us additional information about
865
- * whether the relationship has received *remote* data. This is
866
- * what `getRemoteRelationship` relies on to avoid reflecting
867
- * local-only edits.
868
- */
869
- if (isRemote) {
870
- state.hasReceivedRemoteData = true;
871
- }
872
- state.isEmpty = op.value === null;
873
- state.isStale = false;
874
- state.hasFailedLoadAttempt = false;
875
- if (op.value) {
876
- if (definition.type !== op.value.type) {
877
- // assert(
878
- // `The '<${definition.inverseType}>.${op.field}' relationship expects only '${definition.type}' records since it is not polymorphic. Received a Record of type '${op.value.type}'`,
879
- // definition.isPolymorphic
880
- // );
881
-
882
- // TODO this should now handle the deprecation warning if isPolymorphic is not set
883
- // but the record does turn out to be polymorphic
884
- // this should still assert if the user is relying on legacy inheritance/mixins to
885
- // provide polymorphic behavior and has not yet added the polymorphic flags
886
265
 
887
- graph.registerPolymorphicType(definition.type, op.value.type);
888
- }
889
- addToInverse(graph, op.value, definition.inverseKey, op.record, isRemote);
890
- }
891
- if (isRemote) {
892
- const {
893
- localState,
894
- remoteState
895
- } = relationship;
896
- if (localState && checkIfNew(graph._realStore, localState) && !remoteState) {
897
- return;
898
- }
899
- // when localState does not match the new remoteState and
900
- // localState === existingState then we had no local mutation
901
- // and we can safely sync the new remoteState to local
902
- if (localState !== remoteState && localState === existingState) {
903
- relationship.localState = remoteState;
904
- notifyChange(graph, relationship);
905
- // But when localState does not match the new remoteState and
906
- // and localState !== existingState then we know we have a local mutation
907
- // that has not been persisted yet.
908
- } else {
909
- if (localState !== remoteState && localState !== existingState && relationship.definition.resetOnRemoteUpdate !== false) {
910
- relationship.localState = remoteState;
911
- notifyChange(graph, relationship);
912
- }
913
- }
914
- } else {
915
- notifyChange(graph, relationship);
916
- }
917
- }
266
+ //#endregion
267
+ //#region src/graph/-private/operations/replace-related-record.ts
268
+ function replaceRelatedRecord(graph, op, isRemote = false) {
269
+ const relationship = graph.get(op.record, op.field);
270
+ if (isRemote) graph._addToTransaction(relationship);
271
+ const { definition, state } = relationship;
272
+ const prop = isRemote ? "remoteState" : "localState";
273
+ const existingState = relationship[prop];
274
+ if (op.value === existingState) {
275
+ state.hasReceivedData = true;
276
+ if (isRemote) {
277
+ state.hasReceivedRemoteData = true;
278
+ const { localState } = relationship;
279
+ if (localState && checkIfNew(graph._realStore, localState) && !existingState) return;
280
+ if (existingState && localState === existingState) notifyInverseOfPotentialMaterialization(graph, existingState, definition.inverseKey, op.record, isRemote);
281
+ else if (localState !== op.value && relationship.definition.resetOnRemoteUpdate !== false) {
282
+ relationship.localState = existingState;
283
+ notifyChange(graph, relationship);
284
+ }
285
+ }
286
+ return;
287
+ }
288
+ if (existingState) removeFromInverse(graph, existingState, definition.inverseKey, op.record, isRemote);
289
+ relationship[prop] = op.value;
290
+ state.hasReceivedData = true;
291
+ /**
292
+ * Local mutations never give us additional information about
293
+ * whether the relationship has received *remote* data. This is
294
+ * what `getRemoteRelationship` relies on to avoid reflecting
295
+ * local-only edits.
296
+ */
297
+ if (isRemote) state.hasReceivedRemoteData = true;
298
+ state.isEmpty = op.value === null;
299
+ state.isStale = false;
300
+ state.hasFailedLoadAttempt = false;
301
+ if (op.value) {
302
+ if (definition.type !== op.value.type) graph.registerPolymorphicType(definition.type, op.value.type);
303
+ addToInverse(graph, op.value, definition.inverseKey, op.record, isRemote);
304
+ }
305
+ if (isRemote) {
306
+ const { localState, remoteState } = relationship;
307
+ if (localState && checkIfNew(graph._realStore, localState) && !remoteState) return;
308
+ if (localState !== remoteState && localState === existingState) {
309
+ relationship.localState = remoteState;
310
+ notifyChange(graph, relationship);
311
+ } else if (localState !== remoteState && localState !== existingState && relationship.definition.resetOnRemoteUpdate !== false) {
312
+ relationship.localState = remoteState;
313
+ notifyChange(graph, relationship);
314
+ }
315
+ } else notifyChange(graph, relationship);
316
+ }
317
+
318
+ //#endregion
319
+ //#region src/graph/-private/-diff.ts
918
320
  function _deprecatedCompare(priorLocalState, newState, newMembers, prevState, prevSet, onAdd, onDel, remoteClearsLocal) {
919
- const newLength = newState.length;
920
- const prevLength = prevState.length;
921
- const iterationLength = Math.max(newLength, prevLength);
922
- let changed = newMembers.size !== prevSet.size;
923
- let remoteOrderChanged = false;
924
- const added = new Set();
925
- const removed = new Set();
926
- const duplicates = new Map();
927
- const finalSet = new Set();
928
- const finalState = [];
929
- const priorLocalLength = priorLocalState?.length ?? 0;
930
- for (let i = 0, j = 0; i < iterationLength; i++) {
931
- let adv = false;
932
- let member;
933
-
934
- // accumulate anything added
935
- if (i < newLength) {
936
- member = newState[i];
937
- if (!finalSet.has(member)) {
938
- finalState[j] = member;
939
- finalSet.add(member);
940
- adv = true;
941
- if (!prevSet.has(member)) {
942
- // Avoid unnecessarily notifying a change that already exists locally
943
- if (i < priorLocalLength) {
944
- const priorLocalMember = priorLocalState[i];
945
- if (priorLocalMember !== member) {
946
- changed = true;
947
- }
948
- }
949
- added.add(member);
950
- onAdd(member);
951
- }
952
- } else {
953
- let list = duplicates.get(member);
954
- if (list === undefined) {
955
- list = [];
956
- duplicates.set(member, list);
957
- }
958
- list.push(i);
959
- }
960
- }
961
-
962
- // accumulate anything removed
963
- if (i < prevLength) {
964
- const prevMember = prevState[i];
965
-
966
- // detect reordering, adjusting index for duplicates
967
- // j is always less than i and so if i < prevLength, j < prevLength
968
- if (member !== prevState[j]) {
969
- // the new remote order does not match the current remote order
970
- // indicating a change in membership or reordering
971
- remoteOrderChanged = true;
972
- // however: if the new remote order matches the current local order
973
- // we can disregard the change notification generation so long as
974
- // we are not configured to reset on remote update (which is deprecated)
975
- {
976
- if (!remoteClearsLocal && i < priorLocalLength) {
977
- const priorLocalMember = priorLocalState[j];
978
- if (priorLocalMember !== member) {
979
- changed = true;
980
- }
981
- } else {
982
- changed = true;
983
- }
984
- }
985
-
986
- // if remote order hasn't changed but local order differs
987
- // and we are configured to reset on remote update (which is deprecated)
988
- // then we still need to mark the relationship as changed
989
- } else {
990
- if (remoteClearsLocal) {
991
- if (!changed && j < priorLocalLength) {
992
- const priorLocalMember = priorLocalState[j];
993
- if (priorLocalMember !== member) {
994
- changed = true;
995
- }
996
- }
997
- }
998
- }
999
- if (!newMembers.has(prevMember)) {
1000
- changed = true;
1001
- removed.add(prevMember);
1002
- onDel(prevMember);
1003
- }
1004
- } else if (adv && j < prevLength && member !== prevState[j]) {
1005
- changed = true;
1006
- }
1007
- if (adv) {
1008
- j++;
1009
- }
1010
- }
1011
- const diff = {
1012
- add: added,
1013
- del: removed,
1014
- finalState,
1015
- finalSet,
1016
- changed,
1017
- remoteOrderChanged
1018
- };
1019
- return {
1020
- diff,
1021
- duplicates
1022
- };
321
+ const newLength = newState.length;
322
+ const prevLength = prevState.length;
323
+ const iterationLength = Math.max(newLength, prevLength);
324
+ let changed = newMembers.size !== prevSet.size;
325
+ let remoteOrderChanged = false;
326
+ const added = /* @__PURE__ */ new Set();
327
+ const removed = /* @__PURE__ */ new Set();
328
+ const duplicates = /* @__PURE__ */ new Map();
329
+ const finalSet = /* @__PURE__ */ new Set();
330
+ const finalState = [];
331
+ const priorLocalLength = priorLocalState?.length ?? 0;
332
+ for (let i = 0, j = 0; i < iterationLength; i++) {
333
+ let adv = false;
334
+ let member;
335
+ if (i < newLength) {
336
+ member = newState[i];
337
+ if (!finalSet.has(member)) {
338
+ finalState[j] = member;
339
+ finalSet.add(member);
340
+ adv = true;
341
+ if (!prevSet.has(member)) {
342
+ if (i < priorLocalLength) {
343
+ if (priorLocalState[i] !== member) changed = true;
344
+ }
345
+ added.add(member);
346
+ onAdd(member);
347
+ }
348
+ } else {
349
+ let list = duplicates.get(member);
350
+ if (list === void 0) {
351
+ list = [];
352
+ duplicates.set(member, list);
353
+ }
354
+ list.push(i);
355
+ }
356
+ }
357
+ if (i < prevLength) {
358
+ const prevMember = prevState[i];
359
+ if (member !== prevState[j]) {
360
+ remoteOrderChanged = true;
361
+ if (!remoteClearsLocal && i < priorLocalLength) {
362
+ if (priorLocalState[j] !== member) changed = true;
363
+ } else changed = true;
364
+ } else if (remoteClearsLocal) {
365
+ if (!changed && j < priorLocalLength) {
366
+ if (priorLocalState[j] !== member) changed = true;
367
+ }
368
+ }
369
+ if (!newMembers.has(prevMember)) {
370
+ changed = true;
371
+ removed.add(prevMember);
372
+ onDel(prevMember);
373
+ }
374
+ } else if (adv && j < prevLength && member !== prevState[j]) changed = true;
375
+ if (adv) j++;
376
+ }
377
+ return {
378
+ diff: {
379
+ add: added,
380
+ del: removed,
381
+ finalState,
382
+ finalSet,
383
+ changed,
384
+ remoteOrderChanged
385
+ },
386
+ duplicates
387
+ };
1023
388
  }
1024
389
  function _compare(priorLocalState, finalState, finalSet, prevState, prevSet, onAdd, onDel, remoteClearsLocal) {
1025
- const finalLength = finalState.length;
1026
- const prevLength = prevState.length;
1027
- const iterationLength = Math.max(finalLength, prevLength);
1028
- const equalLength = priorLocalState ? finalLength === priorLocalState.length : finalLength === prevLength;
1029
- let remoteOrderChanged = finalSet.size !== prevSet.size;
1030
- let changed = priorLocalState ? finalSet.size !== priorLocalState.length : remoteOrderChanged;
1031
- const added = new Set();
1032
- const removed = new Set();
1033
- const priorLocalLength = priorLocalState?.length ?? 0;
1034
- for (let i = 0; i < iterationLength; i++) {
1035
- let member;
1036
-
1037
- // accumulate anything added
1038
- if (i < finalLength) {
1039
- member = finalState[i];
1040
- if (!prevSet.has(member)) {
1041
- // Avoid unnecessarily notifying a change that already exists locally
1042
- if (i < priorLocalLength) {
1043
- const priorLocalMember = priorLocalState[i];
1044
- if (priorLocalMember !== member) {
1045
- changed = true;
1046
- }
1047
- }
1048
- added.add(member);
1049
- onAdd(member);
1050
- }
1051
- }
1052
-
1053
- // accumulate anything removed
1054
- if (i < prevLength) {
1055
- const prevMember = prevState[i];
1056
-
1057
- // detect reordering
1058
- if (equalLength && member !== prevMember) {
1059
- // the new remote order does not match the current remote order
1060
- // indicating a change in membership or reordering
1061
- remoteOrderChanged = true;
1062
- // however: if the new remote order matches the current local order
1063
- // we can disregard the change notification generation so long as
1064
- // we are not configured to reset on remote update (which is deprecated)
1065
-
1066
- if (i < priorLocalLength) {
1067
- const priorLocalMember = priorLocalState[i];
1068
- if (priorLocalMember !== member) {
1069
- changed = true;
1070
- }
1071
- } else if (i < finalLength) {
1072
- // if we have exceeded the length of priorLocalState and we are within the range
1073
- // of the finalState then we must have changed
1074
-
1075
- changed = true;
1076
- }
1077
-
1078
- // if remote order hasn't changed but local order differs
1079
- // and we are configured to reset on remote update (which is deprecated)
1080
- // then we still need to mark the relationship as changed
1081
- } else {
1082
- if (remoteClearsLocal) {
1083
- if (equalLength && !changed && i < priorLocalLength) {
1084
- const priorLocalMember = priorLocalState[i];
1085
- if (priorLocalMember !== prevMember) {
1086
- changed = true;
1087
- }
1088
- }
1089
- }
1090
- }
1091
- if (!finalSet.has(prevMember)) {
1092
- // if we are within finalLength, we can only be "changed" if we've already exceeded
1093
- // the index range of priorLocalState, as otherwise the previous member may still
1094
- // be removed.
1095
- //
1096
- // prior local: [1, 2, 3, 4]
1097
- // final state: [1, 2, 3]
1098
- // prev remote state: [1, 2, 5, 3, 4]
1099
- // i === 2
1100
- // prevMember === 5
1101
- // !finalSet.has(prevMember) === true
1102
- //
1103
- // because we will become changed at i===3,
1104
- // we do not need to worry about becoming changed at i===2
1105
- // as the arrays until now are still the same
1106
- //
1107
- // prior local: [1, 2, 3]
1108
- // final state: [1, 2, 3, 4]
1109
- // prev remote state: [1, 2, 5, 3, 4]
1110
- // i === 2
1111
- // prevMember === 5
1112
- // !finalSet.has(prevMember) === true
1113
- //
1114
- // because we will become changed at i===3
1115
- // we do not need to worry about becoming changed at i===2
1116
- //
1117
- // prior local: [1, 2, 3]
1118
- // final state: [1, 2, 3]
1119
- // prev remote state: [1, 2, 5, 3, 4]
1120
- // i === 2
1121
- // prevMember === 5
1122
- // !finalSet.has(prevMember) === true
1123
- //
1124
- // because we have same length and same membership order
1125
- // we do not need to worry about becoming changed at i===2
1126
- //
1127
- // if you do not have a priorLocalState you can't be changed
1128
- // ergo, we never need to set changed in this branch.
1129
- // this log can still be useful for debugging.
1130
-
1131
- //
1132
- // we do still set remoteOrderChanged as it has
1133
- remoteOrderChanged = true;
1134
- removed.add(prevMember);
1135
- onDel(prevMember);
1136
- }
1137
- }
1138
- }
1139
- return {
1140
- add: added,
1141
- del: removed,
1142
- finalState,
1143
- finalSet,
1144
- changed,
1145
- remoteOrderChanged
1146
- };
390
+ const finalLength = finalState.length;
391
+ const prevLength = prevState.length;
392
+ const iterationLength = Math.max(finalLength, prevLength);
393
+ const equalLength = priorLocalState ? finalLength === priorLocalState.length : finalLength === prevLength;
394
+ let remoteOrderChanged = finalSet.size !== prevSet.size;
395
+ let changed = priorLocalState ? finalSet.size !== priorLocalState.length : remoteOrderChanged;
396
+ const added = /* @__PURE__ */ new Set();
397
+ const removed = /* @__PURE__ */ new Set();
398
+ const priorLocalLength = priorLocalState?.length ?? 0;
399
+ for (let i = 0; i < iterationLength; i++) {
400
+ let member;
401
+ if (i < finalLength) {
402
+ member = finalState[i];
403
+ if (!prevSet.has(member)) {
404
+ if (i < priorLocalLength) {
405
+ if (priorLocalState[i] !== member) changed = true;
406
+ }
407
+ added.add(member);
408
+ onAdd(member);
409
+ }
410
+ }
411
+ if (i < prevLength) {
412
+ const prevMember = prevState[i];
413
+ if (equalLength && member !== prevMember) {
414
+ remoteOrderChanged = true;
415
+ if (i < priorLocalLength) {
416
+ if (priorLocalState[i] !== member) changed = true;
417
+ } else if (i < finalLength) changed = true;
418
+ } else if (remoteClearsLocal) {
419
+ if (equalLength && !changed && i < priorLocalLength) {
420
+ if (priorLocalState[i] !== prevMember) changed = true;
421
+ }
422
+ }
423
+ if (!finalSet.has(prevMember)) {
424
+ remoteOrderChanged = true;
425
+ removed.add(prevMember);
426
+ onDel(prevMember);
427
+ }
428
+ }
429
+ }
430
+ return {
431
+ add: added,
432
+ del: removed,
433
+ finalState,
434
+ finalSet,
435
+ changed,
436
+ remoteOrderChanged
437
+ };
1147
438
  }
1148
439
  function diffCollection(finalState, relationship, onAdd, onDel) {
1149
- const finalSet = new Set(finalState);
1150
- const {
1151
- localState: priorLocalState,
1152
- remoteState,
1153
- remoteMembers
1154
- } = relationship;
1155
- {
1156
- if (finalState.length !== finalSet.size) {
1157
- const {
1158
- diff
1159
- } = _deprecatedCompare(priorLocalState, finalState, finalSet, remoteState, remoteMembers, onAdd, onDel, relationship.definition.resetOnRemoteUpdate);
1160
- return diff;
1161
- }
1162
- }
1163
- return _compare(priorLocalState, finalState, finalSet, remoteState, remoteMembers, onAdd, onDel, relationship.definition.resetOnRemoteUpdate);
440
+ const finalSet = new Set(finalState);
441
+ const { localState: priorLocalState, remoteState, remoteMembers } = relationship;
442
+ if (finalState.length !== finalSet.size) {
443
+ const { diff, duplicates } = _deprecatedCompare(priorLocalState, finalState, finalSet, remoteState, remoteMembers, onAdd, onDel, relationship.definition.resetOnRemoteUpdate);
444
+ return diff;
445
+ }
446
+ return _compare(priorLocalState, finalState, finalSet, remoteState, remoteMembers, onAdd, onDel, relationship.definition.resetOnRemoteUpdate);
1164
447
  }
1165
448
  function computeLocalState(storage) {
1166
- // When the edge is clean and we already have a materialized localState we can
1167
- // return it directly. A clean edge can still have a `null` localState though:
1168
- // dematerializing an inverse member (e.g. when a route reloads its model)
1169
- // nulls out localState without dirtying the edge. In that case we fall through
1170
- // and recompute from remoteState rather than asserting.
1171
- if (!storage.isDirty && storage.localState) {
1172
- return storage.localState;
1173
- }
1174
- const state = storage.remoteState.slice();
1175
- storage.removals?.forEach(v => {
1176
- const index = state.indexOf(v);
1177
- state.splice(index, 1);
1178
- });
1179
- storage.additions?.forEach(v => {
1180
- state.push(v);
1181
- });
1182
- storage.localState = state;
1183
- storage.isDirty = false;
1184
- return state;
449
+ if (!storage.isDirty && storage.localState) return storage.localState;
450
+ const state = storage.remoteState.slice();
451
+ storage.removals?.forEach((v) => {
452
+ const index = state.indexOf(v);
453
+ state.splice(index, 1);
454
+ });
455
+ storage.additions?.forEach((v) => {
456
+ state.push(v);
457
+ });
458
+ storage.localState = state;
459
+ storage.isDirty = false;
460
+ return state;
1185
461
  }
1186
-
1187
462
  /**
1188
- * A function which attempts to add a value to the local state of a collection
1189
- * relationship, and returns true if the value was added, or false if it was
1190
- * already present.
1191
- *
1192
- * It will not generate a notification, will not update the relationships to dirty,
1193
- * and will not update the inverse relationships, making it suitable for use as
1194
- * an internal util to perform the just the addition to a specific side of a
1195
- * relationship.
1196
- *
1197
- * @internal
1198
- */
463
+ * A function which attempts to add a value to the local state of a collection
464
+ * relationship, and returns true if the value was added, or false if it was
465
+ * already present.
466
+ *
467
+ * It will not generate a notification, will not update the relationships to dirty,
468
+ * and will not update the inverse relationships, making it suitable for use as
469
+ * an internal util to perform the just the addition to a specific side of a
470
+ * relationship.
471
+ *
472
+ * @internal
473
+ */
1199
474
  function _add(graph, record, relationship, value, index, isRemote) {
1200
- return !isRemote ? _addLocal(graph, record, relationship, value, index) : _addRemote(graph, record, relationship, value, index);
475
+ return !isRemote ? _addLocal(graph, record, relationship, value, index) : _addRemote(graph, record, relationship, value, index);
1201
476
  }
1202
477
  function _addRemote(graph, record, relationship, value, index) {
1203
- const {
1204
- remoteMembers,
1205
- additions,
1206
- removals,
1207
- remoteState
1208
- } = relationship;
1209
- if (remoteMembers.has(value)) {
1210
- return false;
1211
- }
1212
-
1213
- // add to the remote state
1214
- remoteMembers.add(value);
1215
- const hasValidIndex = index !== null && index >= 0 && index < remoteState.length;
1216
- if (hasValidIndex) {
1217
- remoteState.splice(index, 0, value);
1218
- } else {
1219
- remoteState.push(value);
1220
- }
1221
-
1222
- // remove from additions if present
1223
- if (additions?.has(value)) {
1224
- additions.delete(value);
1225
-
1226
- // nothing more to do this was our state already
1227
- return false;
1228
- }
1229
-
1230
- // if the relationship already needs to recalc, we don't bother
1231
- // attempting to patch the localState
1232
- if (relationship.isDirty) {
1233
- return true;
1234
- }
1235
-
1236
- // if we have existing localState
1237
- // we attempt to patch it without blowing it away
1238
- // as this is more efficient than recomputing
1239
- // it allows us to preserve local ordering
1240
- // to a small extent. Local ordering should not
1241
- // be relied upon as any remote change could blow it away
1242
- if (relationship.localState) {
1243
- if (!hasValidIndex) {
1244
- relationship.localState.push(value);
1245
- } else if (index === 0) {
1246
- relationship.localState.unshift(value);
1247
- } else if (!removals?.size) {
1248
- relationship.localState.splice(index, 0, value);
1249
- } else {
1250
- relationship.isDirty = true;
1251
- }
1252
- }
1253
- return true;
478
+ const { remoteMembers, additions, removals, remoteState } = relationship;
479
+ if (remoteMembers.has(value)) return false;
480
+ remoteMembers.add(value);
481
+ const hasValidIndex = index !== null && index >= 0 && index < remoteState.length;
482
+ if (hasValidIndex) remoteState.splice(index, 0, value);
483
+ else remoteState.push(value);
484
+ if (additions?.has(value)) {
485
+ additions.delete(value);
486
+ return false;
487
+ }
488
+ if (relationship.isDirty) return true;
489
+ if (relationship.localState) {
490
+ if (!hasValidIndex) relationship.localState.push(value);
491
+ else if (index === 0) relationship.localState.unshift(value);
492
+ else if (!removals?.size) relationship.localState.splice(index, 0, value);
493
+ else relationship.isDirty = true;
494
+ }
495
+ return true;
1254
496
  }
1255
497
  function _addLocal(graph, record, relationship, value, index) {
1256
- const {
1257
- remoteMembers,
1258
- removals
1259
- } = relationship;
1260
- let additions = relationship.additions;
1261
- const hasPresence = remoteMembers.has(value) || additions?.has(value);
1262
- if (hasPresence && !removals?.has(value)) {
1263
- return false;
1264
- }
1265
- if (removals?.has(value)) {
1266
- removals.delete(value);
1267
- } else {
1268
- if (!additions) {
1269
- additions = relationship.additions = new Set();
1270
- }
1271
- relationship.state.hasReceivedData = true;
1272
- additions.add(value);
1273
- const {
1274
- type
1275
- } = relationship.definition;
1276
- if (type !== value.type) {
1277
- graph.registerPolymorphicType(value.type, type);
1278
- }
1279
- }
1280
-
1281
- // if we have existing localState
1282
- // and we have an index
1283
- // apply the change, as this is more efficient
1284
- // than recomputing localState and
1285
- // it allows us to preserve local ordering
1286
- // to a small extend. Local ordering should not
1287
- // be relied upon as any remote change will blow it away
1288
- if (relationship.localState) {
1289
- if (index !== null) {
1290
- relationship.localState.splice(index, 0, value);
1291
- } else {
1292
- relationship.localState.push(value);
1293
- }
1294
- }
1295
- return true;
498
+ const { remoteMembers, removals } = relationship;
499
+ let additions = relationship.additions;
500
+ if ((remoteMembers.has(value) || additions?.has(value)) && !removals?.has(value)) return false;
501
+ if (removals?.has(value)) removals.delete(value);
502
+ else {
503
+ if (!additions) additions = relationship.additions = /* @__PURE__ */ new Set();
504
+ relationship.state.hasReceivedData = true;
505
+ additions.add(value);
506
+ const { type } = relationship.definition;
507
+ if (type !== value.type) graph.registerPolymorphicType(value.type, type);
508
+ }
509
+ if (relationship.localState) {
510
+ if (index !== null) relationship.localState.splice(index, 0, value);
511
+ else relationship.localState.push(value);
512
+ }
513
+ return true;
1296
514
  }
1297
515
  function _remove(graph, record, relationship, value, index, isRemote) {
1298
- return !isRemote ? _removeLocal(relationship, value) : _removeRemote(relationship, value);
516
+ return !isRemote ? _removeLocal(relationship, value) : _removeRemote(relationship, value);
1299
517
  }
1300
518
  function _removeLocal(relationship, value) {
1301
- const {
1302
- remoteMembers,
1303
- additions
1304
- } = relationship;
1305
- let removals = relationship.removals;
1306
- const hasPresence = remoteMembers.has(value) || additions?.has(value);
1307
- if (!hasPresence || removals?.has(value)) {
1308
- return false;
1309
- }
1310
- if (additions?.has(value)) {
1311
- additions.delete(value);
1312
- } else {
1313
- if (!removals) {
1314
- removals = relationship.removals = new Set();
1315
- }
1316
- removals.add(value);
1317
- }
1318
-
1319
- // if we have existing localState
1320
- // apply the change, as this is more efficient
1321
- // than recomputing localState and
1322
- // it allows us to preserve local ordering
1323
- // to a small extend. Local ordering should not
1324
- // be relied upon as any remote change will blow it away
1325
- if (relationship.localState) {
1326
- const index = relationship.localState.indexOf(value);
1327
- relationship.localState.splice(index, 1);
1328
- }
1329
- return true;
519
+ const { remoteMembers, additions } = relationship;
520
+ let removals = relationship.removals;
521
+ if (!(remoteMembers.has(value) || additions?.has(value)) || removals?.has(value)) return false;
522
+ if (additions?.has(value)) additions.delete(value);
523
+ else {
524
+ if (!removals) removals = relationship.removals = /* @__PURE__ */ new Set();
525
+ removals.add(value);
526
+ }
527
+ if (relationship.localState) {
528
+ const index = relationship.localState.indexOf(value);
529
+ relationship.localState.splice(index, 1);
530
+ }
531
+ return true;
1330
532
  }
1331
533
  function _removeRemote(relationship, value) {
1332
- const {
1333
- remoteMembers,
1334
- additions,
1335
- removals,
1336
- remoteState
1337
- } = relationship;
1338
- if (!remoteMembers.has(value)) {
1339
- return false;
1340
- }
1341
-
1342
- // remove from remote state
1343
- remoteMembers.delete(value);
1344
- let index = remoteState.indexOf(value);
1345
- remoteState.splice(index, 1);
1346
-
1347
- // remove from removals if present
1348
- if (removals?.has(value)) {
1349
- removals.delete(value);
1350
-
1351
- // nothing more to do this was our state already
1352
- return false;
1353
- }
1354
-
1355
- // if we have existing localState
1356
- // and we have an index
1357
- // apply the change, as this is more efficient
1358
- // than recomputing localState and
1359
- // it allows us to preserve local ordering
1360
- // to a small extend. Local ordering should not
1361
- // be relied upon as any remote change will blow it away
1362
- if (relationship.localState) {
1363
- index = relationship.localState.indexOf(value);
1364
- relationship.localState.splice(index, 1);
1365
- }
1366
- return true;
534
+ const { remoteMembers, additions, removals, remoteState } = relationship;
535
+ if (!remoteMembers.has(value)) return false;
536
+ remoteMembers.delete(value);
537
+ let index = remoteState.indexOf(value);
538
+ remoteState.splice(index, 1);
539
+ if (removals?.has(value)) {
540
+ removals.delete(value);
541
+ return false;
542
+ }
543
+ if (relationship.localState) {
544
+ index = relationship.localState.indexOf(value);
545
+ relationship.localState.splice(index, 1);
546
+ }
547
+ return true;
1367
548
  }
1368
549
  function rollbackRelationship(graph, key, field, relationship) {
1369
- if (isBelongsTo(relationship)) {
1370
- replaceRelatedRecord(graph, {
1371
- record: key,
1372
- field,
1373
- value: relationship.remoteState
1374
- }, false);
1375
- } else {
1376
- replaceRelatedRecords(graph, {
1377
- record: key,
1378
- field,
1379
- value: relationship.remoteState.slice()
1380
- }, false);
1381
-
1382
- // when the change was a "reorder" only we wont have generated
1383
- // a notification yet.
1384
- // if we give rollback a unique operation we can use the ability of
1385
- // diff to report a separate `remoteOrderChanged` flag to trigger this
1386
- // if needed to avoid the duplicate.
1387
- notifyChange(graph, relationship);
1388
- }
550
+ if (isBelongsTo(relationship)) replaceRelatedRecord(graph, {
551
+ op: "replaceRelatedRecord",
552
+ record: key,
553
+ field,
554
+ value: relationship.remoteState
555
+ }, false);
556
+ else {
557
+ replaceRelatedRecords(graph, {
558
+ op: "replaceRelatedRecords",
559
+ record: key,
560
+ field,
561
+ value: relationship.remoteState.slice()
562
+ }, false);
563
+ notifyChange(graph, relationship);
564
+ }
565
+ }
566
+
567
+ //#endregion
568
+ //#region src/graph/-private/-edge-definition.ts
569
+ function isLegacyField(field) {
570
+ return field.kind === "belongsTo" || field.kind === "hasMany";
1389
571
  }
1390
- function createState() {
1391
- return {
1392
- hasReceivedData: false,
1393
- hasReceivedRemoteData: false,
1394
- isEmpty: true,
1395
- isStale: false,
1396
- hasFailedLoadAttempt: false,
1397
- shouldForceReload: false,
1398
- hasDematerializedInverse: false
1399
- };
572
+ function temporaryConvertToLegacy(field) {
573
+ return {
574
+ kind: field.kind === "resource" ? "belongsTo" : "hasMany",
575
+ name: field.name,
576
+ type: field.type,
577
+ options: Object.assign({}, {
578
+ async: false,
579
+ inverse: null,
580
+ resetOnRemoteUpdate: false
581
+ }, field.options)
582
+ };
583
+ }
584
+ /**
585
+ *
586
+ * Given RHS (Right Hand Side)
587
+ *
588
+ * ```ts
589
+ * class User extends Model {
590
+ * @hasMany('animal', { async: false, inverse: 'owner' }) pets;
591
+ * }
592
+ * ```
593
+ *
594
+ * Given LHS (Left Hand Side)
595
+ *
596
+ * ```ts
597
+ * class Animal extends Model {
598
+ * @belongsTo('user', { async: false, inverse: 'pets' }) owner;
599
+ * }
600
+ * ```
601
+ *
602
+ * The UpgradedMeta for the RHS would be:
603
+ *
604
+ * ```ts
605
+ * {
606
+ * kind: 'hasMany',
607
+ * key: 'pets',
608
+ * type: 'animal',
609
+ * isAsync: false,
610
+ * isImplicit: false,
611
+ * isCollection: true,
612
+ * isPolymorphic: false,
613
+ * inverseKind: 'belongsTo',
614
+ * inverseKey: 'owner',
615
+ * inverseType: 'user',
616
+ * inverseIsAsync: false,
617
+ * inverseIsImplicit: false,
618
+ * inverseIsCollection: false,
619
+ * inverseIsPolymorphic: false,
620
+ * }
621
+ * ```
622
+ *
623
+ * The UpgradeMeta for the LHS would be:
624
+ *
625
+ * ```ts
626
+ * {
627
+ * kind: 'belongsTo',
628
+ * key: 'owner',
629
+ * type: 'user',
630
+ * isAsync: false,
631
+ * isImplicit: false,
632
+ * isCollection: false,
633
+ * isPolymorphic: false,
634
+ * inverseKind: 'hasMany',
635
+ * inverseKey: 'pets',
636
+ * inverseType: 'animal',
637
+ * inverseIsAsync: false,
638
+ * inverseIsImplicit: false,
639
+ * inverseIsCollection: true,
640
+ * inverseIsPolymorphic: false,
641
+ * }
642
+ * ```
643
+ *
644
+ * @private
645
+ */
646
+ const BOOL_LATER = null;
647
+ const STR_LATER = "";
648
+ const IMPLICIT_KEY_RAND = Date.now();
649
+ function implicitKeyFor(type, key) {
650
+ return `implicit-${type}:${key}${IMPLICIT_KEY_RAND}`;
1400
651
  }
652
+ function syncMeta(definition, inverseDefinition) {
653
+ definition.inverseKind = inverseDefinition.kind;
654
+ definition.inverseKey = inverseDefinition.key;
655
+ definition.inverseName = inverseDefinition.name;
656
+ definition.inverseType = inverseDefinition.type;
657
+ definition.inverseIsAsync = inverseDefinition.isAsync;
658
+ definition.inverseIsCollection = inverseDefinition.isCollection;
659
+ definition.inverseIsPolymorphic = inverseDefinition.isPolymorphic;
660
+ definition.inverseIsImplicit = inverseDefinition.isImplicit;
661
+ definition.inverseIsLinksMode = inverseDefinition.isLinksMode;
662
+ const resetOnRemoteUpdate = definition.resetOnRemoteUpdate === false || inverseDefinition.resetOnRemoteUpdate === false ? false : true;
663
+ definition.resetOnRemoteUpdate = resetOnRemoteUpdate;
664
+ inverseDefinition.resetOnRemoteUpdate = resetOnRemoteUpdate;
665
+ }
666
+ function upgradeMeta(meta) {
667
+ if (!isLegacyField(meta)) meta = temporaryConvertToLegacy(meta);
668
+ const niceMeta = {};
669
+ const options = meta.options;
670
+ niceMeta.kind = meta.kind;
671
+ niceMeta.key = meta.sourceKey ?? meta.name;
672
+ niceMeta.name = meta.name;
673
+ niceMeta.type = meta.type;
674
+ niceMeta.isAsync = options.async;
675
+ niceMeta.isImplicit = false;
676
+ niceMeta.isCollection = meta.kind === "hasMany";
677
+ niceMeta.isPolymorphic = options && !!options.polymorphic;
678
+ niceMeta.isLinksMode = options.linksMode ?? false;
679
+ niceMeta.inverseKey = options && options.inverse || STR_LATER;
680
+ niceMeta.inverseName = options && options.inverse || STR_LATER;
681
+ niceMeta.inverseType = STR_LATER;
682
+ niceMeta.inverseIsAsync = BOOL_LATER;
683
+ niceMeta.inverseIsImplicit = options && options.inverse === null || BOOL_LATER;
684
+ niceMeta.inverseIsCollection = BOOL_LATER;
685
+ niceMeta.inverseIsLinksMode = BOOL_LATER;
686
+ niceMeta.resetOnRemoteUpdate = !isLegacyField(meta) ? false : meta.options?.linksMode ? false : meta.options?.resetOnRemoteUpdate === false ? false : true;
687
+ return niceMeta;
688
+ }
689
+ function isLHS(info, type, key) {
690
+ const isSelfReferential = info.isSelfReferential;
691
+ if (key === info.lhs_relationshipName === true) return isSelfReferential === true || type === info.lhs_baseModelName || info.rhs_isPolymorphic && info.lhs_modelNames.includes(type);
692
+ return false;
693
+ }
694
+ function upgradeDefinition(graph, key, propertyName, isImplicit = false) {
695
+ const cache = graph._definitionCache;
696
+ const storeWrapper = graph.store;
697
+ const polymorphicLookup = graph._potentialPolymorphicTypes;
698
+ const { type } = key;
699
+ let cached = expandingGet(cache, type, propertyName);
700
+ if (cached !== void 0) return cached;
701
+ const relationships = storeWrapper.schema.fields(key);
702
+ const meta = (storeWrapper.schema.cacheFields?.(key) ?? relationships).get(propertyName);
703
+ if (!meta) {
704
+ if (polymorphicLookup[type]) {
705
+ const altTypes = Object.keys(polymorphicLookup[type]);
706
+ for (let i = 0; i < altTypes.length; i++) {
707
+ const _cached = expandingGet(cache, altTypes[i], propertyName);
708
+ if (_cached) {
709
+ expandingSet(cache, type, propertyName, _cached);
710
+ _cached.rhs_modelNames.push(type);
711
+ return _cached;
712
+ }
713
+ }
714
+ }
715
+ cache[type][propertyName] = null;
716
+ return null;
717
+ }
718
+ const definition = upgradeMeta(meta);
719
+ let inverseDefinition;
720
+ let inverseKey;
721
+ const inverseType = definition.type;
722
+ if (definition.inverseKey === null) inverseDefinition = null;
723
+ else {
724
+ inverseKey = inverseForRelationship(getStore(storeWrapper), key, propertyName);
725
+ if (!inverseKey && definition.isPolymorphic && definition.inverseKey) inverseDefinition = {
726
+ kind: "belongsTo",
727
+ key: definition.inverseKey,
728
+ name: definition.inverseName,
729
+ type,
730
+ isAsync: false,
731
+ isImplicit: false,
732
+ isCollection: false,
733
+ isPolymorphic: false
734
+ };
735
+ else if (!inverseKey) inverseDefinition = null;
736
+ else inverseDefinition = upgradeMeta(storeWrapper.schema.fields({ type: inverseType }).get(inverseKey));
737
+ }
738
+ if (!inverseDefinition) {
739
+ inverseKey = implicitKeyFor(type, propertyName);
740
+ inverseDefinition = {
741
+ kind: "implicit",
742
+ key: inverseKey,
743
+ type,
744
+ isAsync: false,
745
+ isImplicit: true,
746
+ isCollection: true,
747
+ isPolymorphic: false
748
+ };
749
+ syncMeta(definition, inverseDefinition);
750
+ syncMeta(inverseDefinition, definition);
751
+ const info = {
752
+ lhs_key: `${type}:${propertyName}`,
753
+ lhs_modelNames: [type],
754
+ lhs_baseModelName: type,
755
+ lhs_relationshipName: propertyName,
756
+ lhs_definition: definition,
757
+ lhs_isPolymorphic: definition.isPolymorphic,
758
+ rhs_key: inverseDefinition.key,
759
+ rhs_modelNames: [inverseType],
760
+ rhs_baseModelName: inverseType,
761
+ rhs_relationshipName: inverseDefinition.key,
762
+ rhs_definition: inverseDefinition,
763
+ rhs_isPolymorphic: false,
764
+ hasInverse: false,
765
+ isSelfReferential: type === inverseType,
766
+ isReflexive: false
767
+ };
768
+ expandingSet(cache, inverseType, inverseKey, info);
769
+ expandingSet(cache, type, propertyName, info);
770
+ return info;
771
+ }
772
+ const baseType = inverseDefinition.type;
773
+ cached = expandingGet(cache, baseType, propertyName) || expandingGet(cache, inverseType, inverseKey);
774
+ if (cached) {
775
+ const _isLHS = cached.lhs_baseModelName === baseType;
776
+ _isLHS ? cached.lhs_relationshipName : cached.rhs_relationshipName;
777
+ cached.lhs_baseModelName === baseType && cached.lhs_relationshipName === propertyName || cached.rhs_baseModelName === baseType && cached.rhs_relationshipName;
778
+ (_isLHS ? cached.lhs_modelNames : cached.rhs_modelNames).push(type);
779
+ expandingSet(cache, type, propertyName, cached);
780
+ return cached;
781
+ }
782
+ syncMeta(definition, inverseDefinition);
783
+ syncMeta(inverseDefinition, definition);
784
+ const lhs_modelNames = [type];
785
+ if (type !== baseType) lhs_modelNames.push(baseType);
786
+ const isSelfReferential = baseType === inverseType;
787
+ const info = {
788
+ lhs_key: `${baseType}:${propertyName}`,
789
+ lhs_modelNames,
790
+ lhs_baseModelName: baseType,
791
+ lhs_relationshipName: propertyName,
792
+ lhs_definition: definition,
793
+ lhs_isPolymorphic: definition.isPolymorphic,
794
+ rhs_key: `${inverseType}:${inverseKey}`,
795
+ rhs_modelNames: [inverseType],
796
+ rhs_baseModelName: inverseType,
797
+ rhs_relationshipName: inverseKey,
798
+ rhs_definition: inverseDefinition,
799
+ rhs_isPolymorphic: inverseDefinition.isPolymorphic,
800
+ hasInverse: true,
801
+ isSelfReferential,
802
+ isReflexive: isSelfReferential && propertyName === inverseKey
803
+ };
804
+ expandingSet(cache, baseType, propertyName, info);
805
+ expandingSet(cache, type, propertyName, info);
806
+ expandingSet(cache, inverseType, inverseKey, info);
807
+ return info;
808
+ }
809
+ function inverseForRelationship(store, resourceKey, key) {
810
+ const definition = store.schema.fields(resourceKey).get(key);
811
+ if (!definition) return null;
812
+ return definition.options.inverse;
813
+ }
814
+
815
+ //#endregion
816
+ //#region src/graph/-private/-state.ts
817
+ function createState() {
818
+ return {
819
+ hasReceivedData: false,
820
+ hasReceivedRemoteData: false,
821
+ isEmpty: true,
822
+ isStale: false,
823
+ hasFailedLoadAttempt: false,
824
+ shouldForceReload: false,
825
+ hasDematerializedInverse: false
826
+ };
827
+ }
828
+
829
+ //#endregion
830
+ //#region src/graph/-private/edges/collection.ts
831
+ /**
832
+ * Stores the graph's internal state for one side of a collection (`hasMany`) relationship.
833
+ */
834
+ /** Creates a new {@link CollectionEdge} for the given definition and identifier. */
1401
835
  function createCollectionEdge(definition, identifier) {
1402
- return {
1403
- definition,
1404
- identifier,
1405
- state: createState(),
1406
- remoteMembers: new Set(),
1407
- remoteState: [],
1408
- additions: null,
1409
- removals: null,
1410
- meta: null,
1411
- links: null,
1412
- localState: null,
1413
- isDirty: false,
1414
- transactionRef: 0,
1415
- accessed: false,
1416
- _diff: undefined
1417
- };
836
+ return {
837
+ definition,
838
+ identifier,
839
+ state: createState(),
840
+ remoteMembers: /* @__PURE__ */ new Set(),
841
+ remoteState: [],
842
+ additions: null,
843
+ removals: null,
844
+ meta: null,
845
+ links: null,
846
+ localState: null,
847
+ isDirty: false,
848
+ transactionRef: 0,
849
+ accessed: false,
850
+ _diff: void 0
851
+ };
1418
852
  }
1419
853
  const cp = structuredClone;
854
+ /**
855
+ * Builds a legacy `{ data, links, meta }` {@link CollectionRelationship} payload for this edge,
856
+ * using either the remote or the computed local state, and marks the edge as accessed.
857
+ */
1420
858
  function legacyGetCollectionRelationshipData(source, getRemoteState) {
1421
- source.accessed = true;
1422
- const payload = {};
1423
- if (source.state.hasReceivedData) {
1424
- payload.data = getRemoteState ? source.remoteState.slice() : computeLocalState(source);
1425
- }
1426
- if (source.links) {
1427
- payload.links = cp(source.links);
1428
- }
1429
- if (source.meta) {
1430
- payload.meta = cp(source.meta);
1431
- }
1432
- return payload;
859
+ source.accessed = true;
860
+ const payload = {};
861
+ if (source.state.hasReceivedData) payload.data = getRemoteState ? source.remoteState.slice() : computeLocalState(source);
862
+ if (source.links) payload.links = cp(source.links);
863
+ if (source.meta) payload.meta = cp(source.meta);
864
+ return payload;
1433
865
  }
1434
866
 
867
+ //#endregion
868
+ //#region src/graph/-private/edges/implicit.ts
869
+ /**
870
+ * The relationship definition (schema metadata) backing an {@link ImplicitEdge}, tagging
871
+ * the {@link UpgradedMeta} as belonging to an implicit inverse relationship.
872
+ */
1435
873
  /**
1436
- Implicit relationships are relationships which have not been declared but the inverse side exists on
1437
- another record somewhere
874
+ Implicit relationships are relationships which have not been declared but the inverse side exists on
875
+ another record somewhere
1438
876
 
1439
- For example consider the following two models
877
+ For example consider the following two models
1440
878
 
1441
- ::: code-group
879
+ ::: code-group
1442
880
 
1443
- ```js [./models/comment.js]
1444
- import { Model, attr } from '@warp-drive/legacy/model';
881
+ ```js [./models/comment.js]
882
+ import { Model, attr } from '@warp-drive/legacy/model';
1445
883
 
1446
- export default class Comment extends Model {
1447
- @attr text;
1448
- }
1449
- ```
884
+ export default class Comment extends Model {
885
+ @attr text;
886
+ }
887
+ ```
1450
888
 
1451
- ```js [./models/post.js]
1452
- import { Model, attr, hasMany } from '@warp-drive/legacy/model';
889
+ ```js [./models/post.js]
890
+ import { Model, attr, hasMany } from '@warp-drive/legacy/model';
1453
891
 
1454
- export default class Post extends Model {
1455
- @attr title;
1456
- @hasMany('comment', { async: true, inverse: null }) comments;
1457
- }
1458
- ```
892
+ export default class Post extends Model {
893
+ @attr title;
894
+ @hasMany('comment', { async: true, inverse: null }) comments;
895
+ }
896
+ ```
1459
897
 
1460
- :::
898
+ :::
1461
899
 
1462
- Then we would have a implicit 'post' relationship for the comment record in order
1463
- to be do things like remove the comment from the post if the comment were to be deleted.
900
+ Then we would have a implicit 'post' relationship for the comment record in order
901
+ to be do things like remove the comment from the post if the comment were to be deleted.
1464
902
  */
1465
-
903
+ /** Creates a new {@link ImplicitEdge} for the given definition and identifier. */
1466
904
  function createImplicitEdge(definition, identifier) {
1467
- return {
1468
- definition,
1469
- identifier,
1470
- localMembers: new Set(),
1471
- remoteMembers: new Set()
1472
- };
905
+ return {
906
+ definition,
907
+ identifier,
908
+ localMembers: /* @__PURE__ */ new Set(),
909
+ remoteMembers: /* @__PURE__ */ new Set()
910
+ };
1473
911
  }
1474
912
 
1475
- /**
1476
- * Stores the data for one side of a "single" resource relationship.
1477
- *
1478
- * @private
1479
- */
1480
-
913
+ //#endregion
914
+ //#region src/graph/-private/edges/resource.ts
1481
915
  function createResourceEdge(definition, identifier) {
1482
- return {
1483
- definition,
1484
- identifier,
1485
- state: createState(),
1486
- transactionRef: 0,
1487
- localState: null,
1488
- remoteState: null,
1489
- meta: null,
1490
- links: null,
1491
- accessed: false
1492
- };
916
+ return {
917
+ definition,
918
+ identifier,
919
+ state: createState(),
920
+ transactionRef: 0,
921
+ localState: null,
922
+ remoteState: null,
923
+ meta: null,
924
+ links: null,
925
+ accessed: false
926
+ };
1493
927
  }
1494
928
  function legacyGetResourceRelationshipData(source, getRemoteState) {
1495
- source.accessed = true;
1496
- let data;
1497
- const payload = {};
1498
- if (getRemoteState && (source.remoteState || source.state.hasReceivedRemoteData)) {
1499
- data = source.remoteState ?? null;
1500
- } else if (!getRemoteState && (source.localState || source.state.hasReceivedData)) {
1501
- data = source.localState ?? null;
1502
- }
1503
- if (source.links) {
1504
- payload.links = source.links;
1505
- }
1506
- if (data !== undefined) {
1507
- payload.data = data;
1508
- }
1509
- if (source.meta) {
1510
- payload.meta = source.meta;
1511
- }
1512
- return payload;
1513
- }
929
+ source.accessed = true;
930
+ let data;
931
+ const payload = {};
932
+ if (getRemoteState && (source.remoteState || source.state.hasReceivedRemoteData)) data = source.remoteState ?? null;
933
+ else if (!getRemoteState && (source.localState || source.state.hasReceivedData)) data = source.localState ?? null;
934
+ if (source.links) payload.links = source.links;
935
+ if (data !== void 0) payload.data = data;
936
+ if (source.meta) payload.meta = source.meta;
937
+ return payload;
938
+ }
939
+
940
+ //#endregion
941
+ //#region src/graph/-private/operations/add-to-related-records.ts
1514
942
  function addToRelatedRecords(graph, op, isRemote) {
1515
- const {
1516
- record,
1517
- value,
1518
- index
1519
- } = op;
1520
- const relationship = graph.get(record, op.field);
1521
- const _isBelongsTo = isBelongsTo(relationship);
1522
- if (isRemote && _isBelongsTo) {
1523
- if (value !== relationship.remoteState) {
1524
- const newOp = {
1525
- record,
1526
- field: op.field,
1527
- value: value
1528
- };
1529
- return replaceRelatedRecord(graph, newOp, isRemote);
1530
- }
1531
- return;
1532
- }
1533
-
1534
- // if we are not dirty but have a null localState then we
1535
- // are mutating a relationship that has never been fetched
1536
- // so we initialize localState to an empty array
1537
- if (!relationship.isDirty && !relationship.localState) {
1538
- relationship.localState = [];
1539
- }
1540
- if (Array.isArray(value)) {
1541
- for (let i = 0; i < value.length; i++) {
1542
- addRelatedRecord(graph, relationship, record, value[i], index !== undefined ? index + i : null, isRemote);
1543
- }
1544
- } else {
1545
- addRelatedRecord(graph, relationship, record, value, index ?? null, isRemote);
1546
- }
1547
- notifyChange(graph, relationship);
943
+ const { record, value, index } = op;
944
+ const relationship = graph.get(record, op.field);
945
+ const _isBelongsTo = isBelongsTo(relationship);
946
+ if (isRemote && _isBelongsTo) {
947
+ if (value !== relationship.remoteState) {
948
+ const newOp = {
949
+ op: "replaceRelatedRecord",
950
+ record,
951
+ field: op.field,
952
+ value
953
+ };
954
+ return replaceRelatedRecord(graph, newOp, isRemote);
955
+ }
956
+ return;
957
+ }
958
+ if (!relationship.isDirty && !relationship.localState) relationship.localState = [];
959
+ if (Array.isArray(value)) for (let i = 0; i < value.length; i++) addRelatedRecord(graph, relationship, record, value[i], index !== void 0 ? index + i : null, isRemote);
960
+ else addRelatedRecord(graph, relationship, record, value, index ?? null, isRemote);
961
+ notifyChange(graph, relationship);
1548
962
  }
1549
963
  function addRelatedRecord(graph, relationship, record, value, index, isRemote) {
1550
- if (_add(graph, record, relationship, value, index, isRemote)) {
1551
- addToInverse(graph, value, relationship.definition.inverseKey, record, isRemote);
1552
- }
964
+ if (_add(graph, record, relationship, value, index, isRemote)) addToInverse(graph, value, relationship.definition.inverseKey, record, isRemote);
1553
965
  }
966
+
967
+ //#endregion
968
+ //#region src/graph/-private/operations/merge-identifier.ts
1554
969
  function mergeIdentifier(graph, op, relationships) {
1555
- Object.keys(relationships).forEach(key => {
1556
- const rel = relationships[key];
1557
- if (!rel) {
1558
- return;
1559
- }
1560
- mergeIdentifierForRelationship(graph, op, rel);
1561
- });
970
+ Object.keys(relationships).forEach((key) => {
971
+ const rel = relationships[key];
972
+ if (!rel) return;
973
+ mergeIdentifierForRelationship(graph, op, rel);
974
+ });
1562
975
  }
1563
976
  function mergeIdentifierForRelationship(graph, op, rel) {
1564
- rel.identifier = op.value;
1565
- forAllRelatedIdentifiers(rel, identifier => {
1566
- const inverse = graph.get(identifier, rel.definition.inverseKey);
1567
- mergeInRelationship(graph, inverse, op);
1568
- });
977
+ rel.identifier = op.value;
978
+ forAllRelatedIdentifiers(rel, (identifier) => {
979
+ mergeInRelationship(graph, graph.get(identifier, rel.definition.inverseKey), op);
980
+ });
1569
981
  }
1570
982
  function mergeInRelationship(graph, rel, op) {
1571
- if (isBelongsTo(rel)) {
1572
- mergeBelongsTo(graph, rel, op);
1573
- } else if (isHasMany(rel)) {
1574
- mergeHasMany(graph, rel, op);
1575
- } else {
1576
- mergeImplicit(graph, rel, op);
1577
- }
983
+ if (isBelongsTo(rel)) mergeBelongsTo(graph, rel, op);
984
+ else if (isHasMany(rel)) mergeHasMany(graph, rel, op);
985
+ else mergeImplicit(graph, rel, op);
1578
986
  }
1579
987
  function mergeBelongsTo(graph, rel, op) {
1580
- if (rel.remoteState === op.record) {
1581
- rel.remoteState = op.value;
1582
- }
1583
- if (rel.localState === op.record) {
1584
- rel.localState = op.value;
1585
- notifyChange(graph, rel);
1586
- }
988
+ if (rel.remoteState === op.record) rel.remoteState = op.value;
989
+ if (rel.localState === op.record) {
990
+ rel.localState = op.value;
991
+ notifyChange(graph, rel);
992
+ }
1587
993
  }
1588
994
  function mergeHasMany(graph, rel, op) {
1589
- if (rel.remoteMembers.has(op.record)) {
1590
- rel.remoteMembers.delete(op.record);
1591
- rel.remoteMembers.add(op.value);
1592
- const index = rel.remoteState.indexOf(op.record);
1593
- rel.remoteState.splice(index, 1, op.value);
1594
- rel.isDirty = true;
1595
- }
1596
- if (rel.additions?.has(op.record)) {
1597
- rel.additions.delete(op.record);
1598
- rel.additions.add(op.value);
1599
- rel.isDirty = true;
1600
- }
1601
- if (rel.removals?.has(op.record)) {
1602
- rel.removals.delete(op.record);
1603
- rel.removals.add(op.value);
1604
- rel.isDirty = true;
1605
- }
1606
- if (rel.isDirty) {
1607
- notifyChange(graph, rel);
1608
- }
995
+ if (rel.remoteMembers.has(op.record)) {
996
+ rel.remoteMembers.delete(op.record);
997
+ rel.remoteMembers.add(op.value);
998
+ const index = rel.remoteState.indexOf(op.record);
999
+ rel.remoteState.splice(index, 1, op.value);
1000
+ rel.isDirty = true;
1001
+ }
1002
+ if (rel.additions?.has(op.record)) {
1003
+ rel.additions.delete(op.record);
1004
+ rel.additions.add(op.value);
1005
+ rel.isDirty = true;
1006
+ }
1007
+ if (rel.removals?.has(op.record)) {
1008
+ rel.removals.delete(op.record);
1009
+ rel.removals.add(op.value);
1010
+ rel.isDirty = true;
1011
+ }
1012
+ if (rel.isDirty) notifyChange(graph, rel);
1609
1013
  }
1610
1014
  function mergeImplicit(graph, rel, op) {
1611
- if (rel.remoteMembers.has(op.record)) {
1612
- rel.remoteMembers.delete(op.record);
1613
- rel.remoteMembers.add(op.value);
1614
- }
1615
- if (rel.localMembers.has(op.record)) {
1616
- rel.localMembers.delete(op.record);
1617
- rel.localMembers.add(op.value);
1618
- }
1619
- }
1015
+ if (rel.remoteMembers.has(op.record)) {
1016
+ rel.remoteMembers.delete(op.record);
1017
+ rel.remoteMembers.add(op.value);
1018
+ }
1019
+ if (rel.localMembers.has(op.record)) {
1020
+ rel.localMembers.delete(op.record);
1021
+ rel.localMembers.add(op.value);
1022
+ }
1023
+ }
1024
+
1025
+ //#endregion
1026
+ //#region src/graph/-private/operations/remove-from-related-records.ts
1620
1027
  function removeFromRelatedRecords(graph, op, isRemote) {
1621
- const {
1622
- record,
1623
- value
1624
- } = op;
1625
- const relationship = graph.get(record, op.field);
1626
- const _isBelongsTo = isBelongsTo(relationship);
1627
- if (isRemote && _isBelongsTo) {
1628
- if (value === relationship.remoteState) {
1629
- const newOp = {
1630
- record,
1631
- field: op.field,
1632
- value: null
1633
- };
1634
- return replaceRelatedRecord(graph, newOp, isRemote);
1635
- }
1636
- return;
1637
- }
1638
- if (Array.isArray(value)) {
1639
- for (let i = 0; i < value.length; i++) {
1640
- removeRelatedRecord(graph, record, relationship, value[i], op.index ?? null, isRemote);
1641
- }
1642
- } else {
1643
- removeRelatedRecord(graph, record, relationship, value, op.index ?? null, isRemote);
1644
- }
1645
- notifyChange(graph, relationship);
1028
+ const { record, value } = op;
1029
+ const relationship = graph.get(record, op.field);
1030
+ const _isBelongsTo = isBelongsTo(relationship);
1031
+ if (isRemote && _isBelongsTo) {
1032
+ if (value === relationship.remoteState) {
1033
+ const newOp = {
1034
+ op: "replaceRelatedRecord",
1035
+ record,
1036
+ field: op.field,
1037
+ value: null
1038
+ };
1039
+ return replaceRelatedRecord(graph, newOp, isRemote);
1040
+ }
1041
+ return;
1042
+ }
1043
+ if (Array.isArray(value)) for (let i = 0; i < value.length; i++) removeRelatedRecord(graph, record, relationship, value[i], op.index ?? null, isRemote);
1044
+ else removeRelatedRecord(graph, record, relationship, value, op.index ?? null, isRemote);
1045
+ notifyChange(graph, relationship);
1646
1046
  }
1647
1047
  function removeRelatedRecord(graph, record, relationship, value, index, isRemote) {
1648
- if (_remove(graph, record, relationship, value, index, isRemote)) {
1649
- removeFromInverse(graph, value, relationship.definition.inverseKey, record, isRemote);
1650
- }
1048
+ if (_remove(graph, record, relationship, value, index, isRemote)) removeFromInverse(graph, value, relationship.definition.inverseKey, record, isRemote);
1651
1049
  }
1652
1050
 
1653
- /*
1654
- This method normalizes a link to an "links object". If the passed link is
1655
- already an object it's returned without any modifications.
1656
-
1657
- See http://jsonapi.org/format/#document-links for more information.
1658
- */
1051
+ //#endregion
1052
+ //#region src/graph/-private/normalize-link.ts
1659
1053
  function _normalizeLink(link) {
1660
- switch (typeof link) {
1661
- case 'object':
1662
- return link;
1663
- case 'string':
1664
- return {
1665
- href: link
1666
- };
1667
- }
1054
+ switch (typeof link) {
1055
+ case "object": return link;
1056
+ case "string": return { href: link };
1057
+ }
1668
1058
  }
1669
1059
 
1670
- /*
1671
- Updates the "canonical" or "remote" state of a relationship, replacing any existing
1672
- state and blowing away any local changes (excepting new records).
1673
- */
1060
+ //#endregion
1061
+ //#region src/graph/-private/operations/update-relationship.ts
1674
1062
  function updateRelationshipOperation(graph, op) {
1675
- const relationship = graph.get(op.record, op.field);
1676
- const {
1677
- definition,
1678
- identifier
1679
- } = relationship;
1680
- const {
1681
- isCollection
1682
- } = definition;
1683
- const payload = op.value;
1684
- let hasRelationshipDataProperty = false;
1685
- let hasUpdatedLink = false;
1686
- if (payload.meta) {
1687
- relationship.meta = payload.meta;
1688
- }
1689
- if (payload.data !== undefined) {
1690
- hasRelationshipDataProperty = true;
1691
- if (isCollection) {
1692
- // TODO deprecate this case. We
1693
- // have tests saying we support it.
1694
- if (payload.data === null) {
1695
- payload.data = [];
1696
- }
1697
- const cache = graph.store.cacheKeyManager;
1698
- graph.update({
1699
- op: 'replaceRelatedRecords',
1700
- record: identifier,
1701
- field: op.field,
1702
- value: upgradeIdentifiers(payload.data, cache)
1703
- }, true);
1704
- } else {
1705
- graph.update({
1706
- op: 'replaceRelatedRecord',
1707
- record: identifier,
1708
- field: op.field,
1709
- value: payload.data ? graph.store.cacheKeyManager.upgradeIdentifier(payload.data) : null
1710
- }, true);
1711
- }
1712
- }
1713
- if (payload.links) {
1714
- const originalLinks = relationship.links;
1715
- relationship.links = payload.links;
1716
- if (payload.links.related) {
1717
- const relatedLink = _normalizeLink(payload.links.related);
1718
- const currentLink = originalLinks && originalLinks.related ? _normalizeLink(originalLinks.related) : null;
1719
- const currentLinkHref = currentLink ? currentLink.href : null;
1720
- if (relatedLink && relatedLink.href && relatedLink.href !== currentLinkHref) {
1721
- hasUpdatedLink = true;
1722
- }
1723
- }
1724
- }
1725
-
1726
- /*
1727
- Data being pushed into the relationship might contain only data or links,
1728
- or a combination of both.
1729
- IF contains only data
1730
- IF contains both links and data
1731
- state.isEmpty -> true if is empty array (has-many) or is null (belongs-to)
1732
- state.hasReceivedData -> true
1733
- hasDematerializedInverse -> false
1734
- state.isStale -> false
1735
- allInverseRecordsAreLoaded -> run-check-to-determine
1736
- IF contains only links
1737
- state.isStale -> true
1738
- */
1739
- relationship.state.hasFailedLoadAttempt = false;
1740
- if (hasRelationshipDataProperty) {
1741
- const relationshipIsEmpty = payload.data === null || Array.isArray(payload.data) && payload.data.length === 0;
1742
-
1743
- // we don't need to notify here as the update op we pushed in above will notify once
1744
- // membership is in the correct state.
1745
- relationship.state.hasReceivedData = true;
1746
- relationship.state.hasReceivedRemoteData = true;
1747
- relationship.state.isStale = false;
1748
- relationship.state.hasDematerializedInverse = false;
1749
- relationship.state.isEmpty = relationshipIsEmpty;
1750
- } else if (hasUpdatedLink) {
1751
- // only notify stale if we have not previously received membership data.
1752
- // within this same transaction
1753
- // this prevents refetching when only one side of the relationship in the
1754
- // payload contains the info while the other side contains just a link
1755
- // this only works when the side with just a link is a belongsTo, as we
1756
- // don't know if a hasMany has full information or not.
1757
- // see #7049 for context.
1758
- if (isCollection || !relationship.state.hasReceivedData || isStaleTransaction(relationship.transactionRef, graph._transaction)) {
1759
- relationship.state.isStale = true;
1760
- notifyChange(graph, relationship);
1761
- } else {
1762
- relationship.state.isStale = false;
1763
- }
1764
- }
1063
+ const relationship = graph.get(op.record, op.field);
1064
+ const { definition, identifier } = relationship;
1065
+ const { isCollection } = definition;
1066
+ const payload = op.value;
1067
+ let hasRelationshipDataProperty = false;
1068
+ let hasUpdatedLink = false;
1069
+ if (payload.meta) relationship.meta = payload.meta;
1070
+ if (payload.data !== void 0) {
1071
+ hasRelationshipDataProperty = true;
1072
+ if (isCollection) {
1073
+ if (payload.data === null) payload.data = [];
1074
+ const cache = graph.store.cacheKeyManager;
1075
+ graph.update({
1076
+ op: "replaceRelatedRecords",
1077
+ record: identifier,
1078
+ field: op.field,
1079
+ value: upgradeIdentifiers(payload.data, cache)
1080
+ }, true);
1081
+ } else graph.update({
1082
+ op: "replaceRelatedRecord",
1083
+ record: identifier,
1084
+ field: op.field,
1085
+ value: payload.data ? graph.store.cacheKeyManager.upgradeIdentifier(payload.data) : null
1086
+ }, true);
1087
+ }
1088
+ if (payload.links) {
1089
+ const originalLinks = relationship.links;
1090
+ relationship.links = payload.links;
1091
+ if (payload.links.related) {
1092
+ const relatedLink = _normalizeLink(payload.links.related);
1093
+ const currentLink = originalLinks && originalLinks.related ? _normalizeLink(originalLinks.related) : null;
1094
+ const currentLinkHref = currentLink ? currentLink.href : null;
1095
+ if (relatedLink && relatedLink.href && relatedLink.href !== currentLinkHref) hasUpdatedLink = true;
1096
+ }
1097
+ }
1098
+ relationship.state.hasFailedLoadAttempt = false;
1099
+ if (hasRelationshipDataProperty) {
1100
+ const relationshipIsEmpty = payload.data === null || Array.isArray(payload.data) && payload.data.length === 0;
1101
+ relationship.state.hasReceivedData = true;
1102
+ relationship.state.hasReceivedRemoteData = true;
1103
+ relationship.state.isStale = false;
1104
+ relationship.state.hasDematerializedInverse = false;
1105
+ relationship.state.isEmpty = relationshipIsEmpty;
1106
+ } else if (hasUpdatedLink) {
1107
+ if (isCollection || !relationship.state.hasReceivedData || isStaleTransaction(relationship.transactionRef, graph._transaction)) {
1108
+ relationship.state.isStale = true;
1109
+ notifyChange(graph, relationship);
1110
+ } else relationship.state.isStale = false;
1111
+ }
1765
1112
  }
1766
1113
  function isStaleTransaction(relationshipTransactionId, graphTransactionId) {
1767
- return relationshipTransactionId === 0 ||
1768
- // relationship has never notified
1769
- graphTransactionId === null ||
1770
- // we are not in a transaction
1771
- relationshipTransactionId < graphTransactionId // we are not part of the current transaction
1772
- ;
1114
+ return relationshipTransactionId === 0 || graphTransactionId === null || relationshipTransactionId < graphTransactionId;
1773
1115
  }
1774
1116
  function upgradeIdentifiers(arr, cache) {
1775
- for (let i = 0; i < arr.length; i++) {
1776
- arr[i] = cache.upgradeIdentifier(arr[i]);
1777
- }
1778
- return arr;
1779
- }
1780
- const Graphs = getOrSetGlobal('Graphs', new Map());
1781
- /*
1782
- * Graph acts as the cache for relationship data. It allows for
1783
- * us to ask about and update relationships for a given Identifier
1784
- * without requiring other objects for that Identifier to be
1785
- * instantiated (such as `RecordData` or a `Record`)
1786
- *
1787
- * This also allows for us to make more substantive changes to relationships
1788
- * with increasingly minor alterations to other portions of the internals
1789
- * over time.
1790
- *
1791
- * The graph is made up of nodes and edges. Each unique identifier gets
1792
- * its own node, which is a dictionary with a list of that node's edges
1793
- * (or connections) to other nodes. In `Model` terms, a node represents a
1794
- * record instance, with each key (an edge) in the dictionary correlating
1795
- * to either a `hasMany` or `belongsTo` field on that record instance.
1796
- *
1797
- * The value for each key, or `edge` is the identifier(s) the node relates
1798
- * to in the graph from that key.
1799
- */
1800
- class Graph {
1801
- constructor(store) {
1802
- this._definitionCache = Object.create(null);
1803
- this._metaCache = Object.create(null);
1804
- this._potentialPolymorphicTypes = Object.create(null);
1805
- this.identifiers = new Map();
1806
- this.store = store;
1807
- this._realStore = store._store;
1808
- this.isDestroyed = false;
1809
- this._willSyncRemote = false;
1810
- this._willSyncLocal = false;
1811
- this._pushedUpdates = {
1812
- belongsTo: undefined,
1813
- hasMany: undefined,
1814
- deletions: []
1815
- };
1816
- this._updatedRelationships = new Set();
1817
- this._transaction = null;
1818
- this._removing = null;
1819
- this.silenceNotifications = false;
1820
- }
1821
- has(resourceKey, propertyName) {
1822
- const relationships = this.identifiers.get(resourceKey);
1823
- if (!relationships) {
1824
- return false;
1825
- }
1826
- return relationships[propertyName] !== undefined;
1827
- }
1828
- getDefinition(resourceKey, propertyName) {
1829
- let defs = this._metaCache[resourceKey.type];
1830
- let meta = defs?.[propertyName];
1831
- if (!meta) {
1832
- const info = /*#__NOINLINE__*/upgradeDefinition(this, resourceKey, propertyName);
1833
-
1834
- // if (info.rhs_definition?.kind === 'implicit') {
1835
- // we should possibly also do this
1836
- // but it would result in being extremely permissive for other relationships by accident
1837
- // this.registerPolymorphicType(info.rhs_baseModelName, identifier.type);
1838
- // }
1839
-
1840
- meta = /*#__NOINLINE__*/isLHS(info, resourceKey.type, propertyName) ? info.lhs_definition : info.rhs_definition;
1841
- defs = this._metaCache[resourceKey.type] = defs || {};
1842
- defs[propertyName] = meta;
1843
- }
1844
- return meta;
1845
- }
1846
- get(resourceKey, propertyName) {
1847
- let relationships = this.identifiers.get(resourceKey);
1848
- if (!relationships) {
1849
- relationships = Object.create(null);
1850
- this.identifiers.set(resourceKey, relationships);
1851
- }
1852
- let relationship = relationships[propertyName];
1853
- if (!relationship) {
1854
- const meta = this.getDefinition(resourceKey, propertyName);
1855
- if (meta.kind === 'belongsTo') {
1856
- relationship = relationships[propertyName] = createResourceEdge(meta, resourceKey);
1857
- } else if (meta.kind === 'hasMany') {
1858
- relationship = relationships[propertyName] = createCollectionEdge(meta, resourceKey);
1859
- } else {
1860
- relationship = relationships[propertyName] = createImplicitEdge(meta, resourceKey);
1861
- }
1862
- }
1863
- return relationship;
1864
- }
1865
- getData(resourceKey, propertyName) {
1866
- const relationship = this.get(resourceKey, propertyName);
1867
- if (isBelongsTo(relationship)) {
1868
- return legacyGetResourceRelationshipData(relationship, false);
1869
- }
1870
- return legacyGetCollectionRelationshipData(relationship, false);
1871
- }
1872
- getRemoteData(resourceKey, propertyName) {
1873
- const relationship = this.get(resourceKey, propertyName);
1874
- if (isBelongsTo(relationship)) {
1875
- return legacyGetResourceRelationshipData(relationship, true);
1876
- }
1877
- return legacyGetCollectionRelationshipData(relationship, true);
1878
- }
1879
-
1880
- /*
1881
- * Allows for the graph to dynamically discover polymorphic connections
1882
- * without needing to walk prototype chains.
1883
- *
1884
- * Used by edges when an added `type` does not match the expected `type`
1885
- * for that edge.
1886
- *
1887
- * Currently we assert before calling this. For a public API we will want
1888
- * to call out to the schema manager to ask if we should consider these
1889
- * types as equivalent for a given relationship.
1890
- */
1891
- registerPolymorphicType(type1, type2) {
1892
- const typeCache = this._potentialPolymorphicTypes;
1893
- let t1 = typeCache[type1];
1894
- if (!t1) {
1895
- t1 = typeCache[type1] = Object.create(null);
1896
- }
1897
- t1[type2] = true;
1898
- let t2 = typeCache[type2];
1899
- if (!t2) {
1900
- t2 = typeCache[type2] = Object.create(null);
1901
- }
1902
- t2[type1] = true;
1903
- }
1904
- isReleasable(resourceKey) {
1905
- const relationships = this.identifiers.get(resourceKey);
1906
- if (!relationships) {
1907
- return true;
1908
- }
1909
- const keys = Object.keys(relationships);
1910
- for (let i = 0; i < keys.length; i++) {
1911
- const relationship = relationships[keys[i]];
1912
- // account for previously unloaded relationships
1913
- // typically from a prior deletion of a record that pointed to this one implicitly
1914
- if (relationship === undefined) {
1915
- continue;
1916
- }
1917
- if (relationship.definition.inverseIsAsync && !checkIfNew(this._realStore, resourceKey)) {
1918
- return false;
1919
- }
1920
- }
1921
- return true;
1922
- }
1923
- unload(resourceKey, silenceNotifications) {
1924
- const relationships = this.identifiers.get(resourceKey);
1925
- if (relationships) {
1926
- // cleans up the graph but retains some nodes
1927
- // to allow for rematerialization
1928
- Object.keys(relationships).forEach(key => {
1929
- const rel = relationships[key];
1930
- if (!rel) {
1931
- return;
1932
- }
1933
- /*#__NOINLINE__*/
1934
- destroyRelationship(this, rel, silenceNotifications);
1935
- if (/*#__NOINLINE__*/isImplicit(rel)) {
1936
- // @ts-expect-error
1937
- relationships[key] = undefined;
1938
- }
1939
- });
1940
- }
1941
- }
1942
- _isDirty(resourceKey, field) {
1943
- const relationships = this.identifiers.get(resourceKey);
1944
- if (!relationships) {
1945
- return false;
1946
- }
1947
- const relationship = relationships[field];
1948
- if (!relationship) {
1949
- return false;
1950
- }
1951
- if (isBelongsTo(relationship)) {
1952
- return relationship.localState !== relationship.remoteState;
1953
- } else if (isHasMany(relationship)) {
1954
- const hasAdditions = relationship.additions !== null && relationship.additions.size > 0;
1955
- const hasRemovals = relationship.removals !== null && relationship.removals.size > 0;
1956
- return hasAdditions || hasRemovals || isReordered(relationship);
1957
- }
1958
- return false;
1959
- }
1960
- getChanged(resourceKey) {
1961
- const relationships = this.identifiers.get(resourceKey);
1962
- const changed = new Map();
1963
- if (!relationships) {
1964
- return changed;
1965
- }
1966
- const keys = Object.keys(relationships);
1967
- for (let i = 0; i < keys.length; i++) {
1968
- const field = keys[i];
1969
- const relationship = relationships[field];
1970
- if (!relationship) {
1971
- continue;
1972
- }
1973
- if (isBelongsTo(relationship)) {
1974
- if (relationship.localState !== relationship.remoteState) {
1975
- changed.set(field, {
1976
- kind: 'resource',
1977
- remoteState: relationship.remoteState,
1978
- localState: relationship.localState
1979
- });
1980
- }
1981
- } else if (isHasMany(relationship)) {
1982
- const hasAdditions = relationship.additions !== null && relationship.additions.size > 0;
1983
- const hasRemovals = relationship.removals !== null && relationship.removals.size > 0;
1984
- const reordered = isReordered(relationship);
1985
- if (hasAdditions || hasRemovals || reordered) {
1986
- changed.set(field, {
1987
- kind: 'collection',
1988
- additions: new Set(relationship.additions),
1989
- removals: new Set(relationship.removals),
1990
- remoteState: relationship.remoteState,
1991
- localState: legacyGetCollectionRelationshipData(relationship, false).data || [],
1992
- reordered
1993
- });
1994
- }
1995
- }
1996
- }
1997
- return changed;
1998
- }
1999
- hasChanged(resourceKey) {
2000
- const relationships = this.identifiers.get(resourceKey);
2001
- if (!relationships) {
2002
- return false;
2003
- }
2004
- const keys = Object.keys(relationships);
2005
- for (let i = 0; i < keys.length; i++) {
2006
- if (this._isDirty(resourceKey, keys[i])) {
2007
- return true;
2008
- }
2009
- }
2010
- return false;
2011
- }
2012
- rollback(resourceKey) {
2013
- const relationships = this.identifiers.get(resourceKey);
2014
- const changed = [];
2015
- if (!relationships) {
2016
- return changed;
2017
- }
2018
- const keys = Object.keys(relationships);
2019
- for (let i = 0; i < keys.length; i++) {
2020
- const field = keys[i];
2021
- const relationship = relationships[field];
2022
- if (!relationship) {
2023
- continue;
2024
- }
2025
- if (this._isDirty(resourceKey, field)) {
2026
- rollbackRelationship(this, resourceKey, field, relationship);
2027
- changed.push(field);
2028
- }
2029
- }
2030
- return changed;
2031
- }
2032
- remove(resourceKey) {
2033
- this._removing = resourceKey;
2034
- this.unload(resourceKey);
2035
- this.identifiers.delete(resourceKey);
2036
- this._removing = null;
2037
- }
2038
-
2039
- /*
2040
- * Remote state changes
2041
- */
2042
- push(op) {
2043
- if (op.op === 'deleteRecord') {
2044
- this._pushedUpdates.deletions.push(op);
2045
- } else {
2046
- const definition = this.getDefinition(op.record, op.field);
2047
- addPending(this._pushedUpdates, definition, op);
2048
- }
2049
- if (!this._willSyncRemote) {
2050
- this._willSyncRemote = true;
2051
- const store = getStore(this.store);
2052
- if (!store._cbs) {
2053
- store._run(() => this._flushRemoteQueue());
2054
- } else {
2055
- store._schedule('coalesce', () => this._flushRemoteQueue());
2056
- }
2057
- }
2058
- }
2059
-
2060
- /*
2061
- * Local state changes
2062
- */
2063
-
2064
- update(op, isRemote = false) {
2065
- switch (op.op) {
2066
- case 'mergeIdentifiers':
2067
- {
2068
- const relationships = this.identifiers.get(op.record);
2069
- if (relationships) {
2070
- /*#__NOINLINE__*/mergeIdentifier(this, op, relationships);
2071
- }
2072
- break;
2073
- }
2074
- case 'update':
2075
- case 'updateRelationship':
2076
- /*#__NOINLINE__*/updateRelationshipOperation(this, op);
2077
- break;
2078
- case 'deleteRecord':
2079
- {
2080
- const identifier = op.record;
2081
- const relationships = this.identifiers.get(identifier);
2082
- if (relationships) {
2083
- Object.keys(relationships).forEach(key => {
2084
- const rel = relationships[key];
2085
- if (!rel) {
2086
- return;
2087
- }
2088
- // works together with the has check
2089
- // @ts-expect-error
2090
- relationships[key] = undefined;
2091
- /*#__NOINLINE__*/
2092
- removeCompletelyFromInverse(this, rel);
2093
- });
2094
- this.identifiers.delete(identifier);
2095
- }
2096
- break;
2097
- }
2098
- case 'replaceRelatedRecord':
2099
- /*#__NOINLINE__*/replaceRelatedRecord(this, op, isRemote);
2100
- break;
2101
- case 'add':
2102
- /*#__NOINLINE__*/addToRelatedRecords(this, op, isRemote);
2103
- break;
2104
- case 'remove':
2105
- /*#__NOINLINE__*/removeFromRelatedRecords(this, op, isRemote);
2106
- break;
2107
- case 'replaceRelatedRecords':
2108
- /*#__NOINLINE__*/replaceRelatedRecords(this, op, isRemote);
2109
- break;
2110
- }
2111
- }
2112
- _scheduleLocalSync(relationship) {
2113
- this._updatedRelationships.add(relationship);
2114
- if (!this._willSyncLocal) {
2115
- this._willSyncLocal = true;
2116
- getStore(this.store)._schedule('sync', () => this._flushLocalQueue());
2117
- }
2118
- }
2119
- _flushRemoteQueue() {
2120
- if (!this._willSyncRemote) {
2121
- return;
2122
- }
2123
- let transactionRef = peekTransient('transactionRef') ?? 0;
2124
- this._transaction = ++transactionRef;
2125
- setTransient('transactionRef', transactionRef);
2126
- this._willSyncRemote = false;
2127
- const updates = this._pushedUpdates;
2128
- const {
2129
- deletions,
2130
- hasMany,
2131
- belongsTo
2132
- } = updates;
2133
- updates.deletions = [];
2134
- updates.hasMany = undefined;
2135
- updates.belongsTo = undefined;
2136
- for (let i = 0; i < deletions.length; i++) {
2137
- this.update(deletions[i], true);
2138
- }
2139
- if (hasMany) {
2140
- flushPending(this, hasMany);
2141
- }
2142
- if (belongsTo) {
2143
- flushPending(this, belongsTo);
2144
- }
2145
- this._transaction = null;
2146
- }
2147
- _addToTransaction(relationship) {
2148
- relationship.transactionRef = this._transaction;
2149
- }
2150
- _flushLocalQueue() {
2151
- if (!this._willSyncLocal) {
2152
- return;
2153
- }
2154
- if (this.silenceNotifications) {
2155
- this.silenceNotifications = false;
2156
- this._updatedRelationships = new Set();
2157
- return;
2158
- }
2159
- this._willSyncLocal = false;
2160
- const updated = this._updatedRelationships;
2161
- this._updatedRelationships = new Set();
2162
- updated.forEach(rel => notifyChange(this, rel));
2163
- }
2164
- destroy() {
2165
- Graphs.delete(this.store);
2166
- this.identifiers.clear();
2167
- this.store = null;
2168
- this.isDestroyed = true;
2169
- }
1117
+ for (let i = 0; i < arr.length; i++) arr[i] = cache.upgradeIdentifier(arr[i]);
1118
+ return arr;
2170
1119
  }
1120
+
1121
+ //#endregion
1122
+ //#region src/graph/-private/graph.ts
1123
+ /**
1124
+ * A single edge (relationship field) tracked by the {@link Graph} for a resource. Which kind of edge
1125
+ * a field is depends on its relationship definition:
1126
+ *
1127
+ * - {@link ResourceEdge}: the "one" side of a `belongsTo`/resource relationship
1128
+ * - {@link CollectionEdge}: the "many" side of a `hasMany`/collection relationship
1129
+ * - {@link ImplicitEdge}: a synthesized inverse used when a relationship has no field defined for its inverse
1130
+ */
1131
+ const Graphs = getOrSetGlobal("Graphs", /* @__PURE__ */ new Map());
1132
+ /**
1133
+ * Graph is WarpDrive's internal, private cache of all resource relationships.
1134
+ *
1135
+ * It acts as the cache for relationship data, allowing us to ask about and update
1136
+ * relationships for a given Identifier without requiring other objects for that
1137
+ * Identifier to be instantiated (such as `RecordData` or a `Record`).
1138
+ *
1139
+ * This also allows for us to make more substantive changes to relationships
1140
+ * with increasingly minor alterations to other portions of the internals
1141
+ * over time.
1142
+ *
1143
+ * The graph is made up of nodes and edges. Each unique identifier gets
1144
+ * its own node, which is a dictionary with a list of that node's edges
1145
+ * (or connections) to other nodes. In `Model` terms, a node represents a
1146
+ * record instance, with each key (an edge) in the dictionary correlating
1147
+ * to either a `hasMany` or `belongsTo` field on that record instance.
1148
+ *
1149
+ * The value for each key, or `edge` is the identifier(s) the node relates
1150
+ * to in the graph from that key.
1151
+ */
1152
+ var Graph = class {
1153
+ /**
1154
+ * Cache of resolved {@link EdgeDefinition}s (the paired LHS/RHS relationship definitions
1155
+ * for a `type` + `key`), keyed by resource `type` and then field name. Populated lazily by
1156
+ * `upgradeDefinition` and consulted by {@link Graph.getDefinition}.
1157
+ */
1158
+ /**
1159
+ * Cache of the resolved {@link UpgradedMeta} for a given resource `type` and field name, as
1160
+ * returned by {@link Graph.getDefinition}. Derived from `_definitionCache` the first time a
1161
+ * field's definition is looked up.
1162
+ */
1163
+ /**
1164
+ * Tracks pairs of resource types that have been discovered to be polymorphically related, so
1165
+ * that the graph can recognize this connection without needing to walk prototype/schema
1166
+ * inheritance chains. Populated by {@link Graph.registerPolymorphicType}.
1167
+ */
1168
+ /**
1169
+ * The nodes of the graph. Each {@link ResourceKey} maps to a dictionary of its relationship
1170
+ * fields (edges), keyed by field name.
1171
+ */
1172
+ /**
1173
+ * The `CacheCapabilitiesManager` (store wrapper) this graph was created for. Used to schedule
1174
+ * work and to notify of relationship changes.
1175
+ */
1176
+ /**
1177
+ * The real underlying `Store` instance backing {@link Graph.store}, used for capabilities
1178
+ * (such as checking whether a resource is a new/unsaved client-side record) that are not
1179
+ * exposed on `CacheCapabilitiesManager`.
1180
+ */
1181
+ /**
1182
+ * `true` once {@link Graph.destroy} has been called. After this point the graph should no
1183
+ * longer be used.
1184
+ */
1185
+ /**
1186
+ * `true` when a flush of the remote-update queue has been scheduled but has not yet run.
1187
+ * Set by {@link Graph.push} and cleared by {@link Graph._flushRemoteQueue}.
1188
+ */
1189
+ /**
1190
+ * `true` when a flush of the local-update notification queue has been scheduled but has not
1191
+ * yet run. Set by {@link Graph._scheduleLocalSync} and cleared by
1192
+ * {@link Graph._flushLocalQueue}.
1193
+ */
1194
+ /**
1195
+ * When `true`, the next scheduled local sync will be dropped without notifying subscribers of
1196
+ * the relationships that changed. Consumed and reset by {@link Graph._flushLocalQueue}.
1197
+ */
1198
+ /**
1199
+ * Remote relationship operations and record deletions that have been pushed via
1200
+ * {@link Graph.push} but not yet flushed into the graph by {@link Graph._flushRemoteQueue}.
1201
+ */
1202
+ /**
1203
+ * The set of {@link CollectionEdge}s that have local changes pending notification, scheduled
1204
+ * via {@link Graph._scheduleLocalSync} and drained by {@link Graph._flushLocalQueue}.
1205
+ */
1206
+ /**
1207
+ * The identifier of the current remote-update transaction, or `null` when no transaction is
1208
+ * in progress. Set by {@link Graph._flushRemoteQueue} and stamped onto edges via
1209
+ * {@link Graph._addToTransaction}.
1210
+ */
1211
+ /**
1212
+ * The {@link ResourceKey} currently being removed via {@link Graph.remove}, or `null`. Used to
1213
+ * guard against re-entrant removal of the same resource.
1214
+ */
1215
+ constructor(store) {
1216
+ this._definitionCache = Object.create(null);
1217
+ this._metaCache = Object.create(null);
1218
+ this._potentialPolymorphicTypes = Object.create(null);
1219
+ this.identifiers = /* @__PURE__ */ new Map();
1220
+ this.store = store;
1221
+ this._realStore = store._store;
1222
+ this.isDestroyed = false;
1223
+ this._willSyncRemote = false;
1224
+ this._willSyncLocal = false;
1225
+ this._pushedUpdates = {
1226
+ belongsTo: void 0,
1227
+ hasMany: void 0,
1228
+ deletions: []
1229
+ };
1230
+ this._updatedRelationships = /* @__PURE__ */ new Set();
1231
+ this._transaction = null;
1232
+ this._removing = null;
1233
+ this.silenceNotifications = false;
1234
+ }
1235
+ /**
1236
+ * Returns `true` if an edge has already been created in the graph for the given resource and
1237
+ * field name, without creating one if it does not yet exist.
1238
+ */
1239
+ has(resourceKey, propertyName) {
1240
+ const relationships = this.identifiers.get(resourceKey);
1241
+ if (!relationships) return false;
1242
+ return relationships[propertyName] !== void 0;
1243
+ }
1244
+ /**
1245
+ * Returns the resolved {@link UpgradedMeta} (relationship definition) for the given resource
1246
+ * `type` and field name, computing and caching it via `upgradeDefinition` on first access.
1247
+ */
1248
+ getDefinition(resourceKey, propertyName) {
1249
+ let defs = this._metaCache[resourceKey.type];
1250
+ let meta = defs?.[propertyName];
1251
+ if (!meta) {
1252
+ const info = upgradeDefinition(this, resourceKey, propertyName);
1253
+ meta = isLHS(info, resourceKey.type, propertyName) ? info.lhs_definition : info.rhs_definition;
1254
+ defs = this._metaCache[resourceKey.type] = defs || {};
1255
+ defs[propertyName] = meta;
1256
+ }
1257
+ return meta;
1258
+ }
1259
+ /**
1260
+ * Returns the {@link GraphEdge} for the given resource and field name, creating it (as a
1261
+ * {@link ResourceEdge}, {@link CollectionEdge}, or {@link ImplicitEdge} depending on the
1262
+ * field's kind) if it does not already exist.
1263
+ */
1264
+ get(resourceKey, propertyName) {
1265
+ let relationships = this.identifiers.get(resourceKey);
1266
+ if (!relationships) {
1267
+ relationships = Object.create(null);
1268
+ this.identifiers.set(resourceKey, relationships);
1269
+ }
1270
+ let relationship = relationships[propertyName];
1271
+ if (!relationship) {
1272
+ const meta = this.getDefinition(resourceKey, propertyName);
1273
+ if (meta.kind === "belongsTo") relationship = relationships[propertyName] = createResourceEdge(meta, resourceKey);
1274
+ else if (meta.kind === "hasMany") relationship = relationships[propertyName] = createCollectionEdge(meta, resourceKey);
1275
+ else relationship = relationships[propertyName] = createImplicitEdge(meta, resourceKey);
1276
+ }
1277
+ return relationship;
1278
+ }
1279
+ /**
1280
+ * Returns the local (current, potentially dirty) JSON:API relationship data for a `belongsTo`
1281
+ * or `hasMany` field. Asserts if the field is an implicit relationship.
1282
+ */
1283
+ getData(resourceKey, propertyName) {
1284
+ const relationship = this.get(resourceKey, propertyName);
1285
+ if (isBelongsTo(relationship)) return legacyGetResourceRelationshipData(relationship, false);
1286
+ return legacyGetCollectionRelationshipData(relationship, false);
1287
+ }
1288
+ /**
1289
+ * Returns the remote (last known server-confirmed) JSON:API relationship data for a
1290
+ * `belongsTo` or `hasMany` field. Asserts if the field is an implicit relationship.
1291
+ */
1292
+ getRemoteData(resourceKey, propertyName) {
1293
+ const relationship = this.get(resourceKey, propertyName);
1294
+ if (isBelongsTo(relationship)) return legacyGetResourceRelationshipData(relationship, true);
1295
+ return legacyGetCollectionRelationshipData(relationship, true);
1296
+ }
1297
+ /**
1298
+ * Allows for the graph to dynamically discover polymorphic connections
1299
+ * without needing to walk prototype chains.
1300
+ *
1301
+ * Used by edges when an added `type` does not match the expected `type`
1302
+ * for that edge.
1303
+ *
1304
+ * Currently we assert before calling this. For a public API we will want
1305
+ * to call out to the schema manager to ask if we should consider these
1306
+ * types as equivalent for a given relationship.
1307
+ */
1308
+ registerPolymorphicType(type1, type2) {
1309
+ const typeCache = this._potentialPolymorphicTypes;
1310
+ let t1 = typeCache[type1];
1311
+ if (!t1) t1 = typeCache[type1] = Object.create(null);
1312
+ t1[type2] = true;
1313
+ let t2 = typeCache[type2];
1314
+ if (!t2) t2 = typeCache[type2] = Object.create(null);
1315
+ t2[type1] = true;
1316
+ }
1317
+ /**
1318
+ * Determines whether a resource is safe to fully release from memory. A resource is not
1319
+ * releasable if it has a relationship whose inverse is async and the resource itself is not a
1320
+ * new (unsaved, client-only) record, since the inverse may still need to reference it.
1321
+ */
1322
+ isReleasable(resourceKey) {
1323
+ const relationships = this.identifiers.get(resourceKey);
1324
+ if (!relationships) return true;
1325
+ const keys = Object.keys(relationships);
1326
+ for (let i = 0; i < keys.length; i++) {
1327
+ const relationship = relationships[keys[i]];
1328
+ if (relationship === void 0) continue;
1329
+ if (relationship.definition.inverseIsAsync && !checkIfNew(this._realStore, resourceKey)) return false;
1330
+ }
1331
+ return true;
1332
+ }
1333
+ /**
1334
+ * Cleans up all relationships for a resource that is being dematerialized, notifying inverses
1335
+ * so they can update their own state. This retains the graph's node structure (so it can be
1336
+ * rematerialized later) except for implicit edges, which are discarded outright.
1337
+ */
1338
+ unload(resourceKey, silenceNotifications) {
1339
+ const relationships = this.identifiers.get(resourceKey);
1340
+ if (relationships) Object.keys(relationships).forEach((key) => {
1341
+ const rel = relationships[key];
1342
+ if (!rel) return;
1343
+ destroyRelationship(this, rel, silenceNotifications);
1344
+ if (isImplicit(rel)) relationships[key] = void 0;
1345
+ });
1346
+ }
1347
+ /**
1348
+ * Returns `true` if the given field on a resource has uncommitted local changes: for a
1349
+ * `belongsTo` this means local and remote state differ; for a `hasMany` this means there are
1350
+ * pending additions, removals, or a reordering relative to remote state.
1351
+ */
1352
+ _isDirty(resourceKey, field) {
1353
+ const relationships = this.identifiers.get(resourceKey);
1354
+ if (!relationships) return false;
1355
+ const relationship = relationships[field];
1356
+ if (!relationship) return false;
1357
+ if (isBelongsTo(relationship)) return relationship.localState !== relationship.remoteState;
1358
+ else if (isHasMany(relationship)) {
1359
+ const hasAdditions = relationship.additions !== null && relationship.additions.size > 0;
1360
+ const hasRemovals = relationship.removals !== null && relationship.removals.size > 0;
1361
+ return hasAdditions || hasRemovals || isReordered(relationship);
1362
+ }
1363
+ return false;
1364
+ }
1365
+ /**
1366
+ * Builds a map, keyed by field name, of every relationship on a resource that has uncommitted
1367
+ * local changes, describing each change as a {@link RelationshipDiff}.
1368
+ */
1369
+ getChanged(resourceKey) {
1370
+ const relationships = this.identifiers.get(resourceKey);
1371
+ const changed = /* @__PURE__ */ new Map();
1372
+ if (!relationships) return changed;
1373
+ const keys = Object.keys(relationships);
1374
+ for (let i = 0; i < keys.length; i++) {
1375
+ const field = keys[i];
1376
+ const relationship = relationships[field];
1377
+ if (!relationship) continue;
1378
+ if (isBelongsTo(relationship)) {
1379
+ if (relationship.localState !== relationship.remoteState) changed.set(field, {
1380
+ kind: "resource",
1381
+ remoteState: relationship.remoteState,
1382
+ localState: relationship.localState
1383
+ });
1384
+ } else if (isHasMany(relationship)) {
1385
+ const hasAdditions = relationship.additions !== null && relationship.additions.size > 0;
1386
+ const hasRemovals = relationship.removals !== null && relationship.removals.size > 0;
1387
+ const reordered = isReordered(relationship);
1388
+ if (hasAdditions || hasRemovals || reordered) changed.set(field, {
1389
+ kind: "collection",
1390
+ additions: new Set(relationship.additions),
1391
+ removals: new Set(relationship.removals),
1392
+ remoteState: relationship.remoteState,
1393
+ localState: legacyGetCollectionRelationshipData(relationship, false).data || [],
1394
+ reordered
1395
+ });
1396
+ }
1397
+ }
1398
+ return changed;
1399
+ }
1400
+ /**
1401
+ * Returns `true` if any relationship field on the resource has uncommitted local changes.
1402
+ */
1403
+ hasChanged(resourceKey) {
1404
+ const relationships = this.identifiers.get(resourceKey);
1405
+ if (!relationships) return false;
1406
+ const keys = Object.keys(relationships);
1407
+ for (let i = 0; i < keys.length; i++) if (this._isDirty(resourceKey, keys[i])) return true;
1408
+ return false;
1409
+ }
1410
+ /**
1411
+ * Reverts all locally dirty relationships on a resource back to their remote state, returning
1412
+ * the list of field names that were rolled back.
1413
+ */
1414
+ rollback(resourceKey) {
1415
+ const relationships = this.identifiers.get(resourceKey);
1416
+ const changed = [];
1417
+ if (!relationships) return changed;
1418
+ const keys = Object.keys(relationships);
1419
+ for (let i = 0; i < keys.length; i++) {
1420
+ const field = keys[i];
1421
+ const relationship = relationships[field];
1422
+ if (!relationship) continue;
1423
+ if (this._isDirty(resourceKey, field)) {
1424
+ rollbackRelationship(this, resourceKey, field, relationship);
1425
+ changed.push(field);
1426
+ }
1427
+ }
1428
+ return changed;
1429
+ }
1430
+ /**
1431
+ * Fully removes a resource and all of its relationships from the graph, unloading its edges
1432
+ * first so inverses are properly notified/cleaned up.
1433
+ */
1434
+ remove(resourceKey) {
1435
+ this._removing = resourceKey;
1436
+ this.unload(resourceKey);
1437
+ this.identifiers.delete(resourceKey);
1438
+ this._removing = null;
1439
+ }
1440
+ /**
1441
+ * Queues a remote relationship operation (or record deletion) to be applied to the graph.
1442
+ * Pushed operations are batched and flushed asynchronously (see {@link Graph._flushRemoteQueue})
1443
+ * rather than applied immediately.
1444
+ */
1445
+ push(op) {
1446
+ if (op.op === "deleteRecord") this._pushedUpdates.deletions.push(op);
1447
+ else {
1448
+ const definition = this.getDefinition(op.record, op.field);
1449
+ addPending(this._pushedUpdates, definition, op);
1450
+ }
1451
+ if (!this._willSyncRemote) {
1452
+ this._willSyncRemote = true;
1453
+ const store = getStore(this.store);
1454
+ if (!store._cbs) store._run(() => this._flushRemoteQueue());
1455
+ else store._schedule("coalesce", () => this._flushRemoteQueue());
1456
+ }
1457
+ }
1458
+ /**
1459
+ * Applies a remote relationship operation or identifier merge directly to the graph. Pass
1460
+ * `isRemote: true` to indicate the operation represents confirmed server state rather than a
1461
+ * local (client-side) change.
1462
+ */
1463
+ /**
1464
+ * Applies a local (client-side) relationship operation directly to the graph, such as adding,
1465
+ * removing, or replacing related records before it has been confirmed by the server.
1466
+ */
1467
+ /**
1468
+ * Implementation for both the remote and local {@link Graph.update} overloads: dispatches the
1469
+ * given operation (`mergeIdentifiers`, `updateRelationship`, `deleteRecord`, `add`, `remove`,
1470
+ * `replaceRelatedRecord`, or `replaceRelatedRecords`) to the appropriate handler.
1471
+ */
1472
+ update(op, isRemote = false) {
1473
+ switch (op.op) {
1474
+ case "mergeIdentifiers": {
1475
+ const relationships = this.identifiers.get(op.record);
1476
+ if (relationships) mergeIdentifier(this, op, relationships);
1477
+ break;
1478
+ }
1479
+ case "update":
1480
+ case "updateRelationship":
1481
+ updateRelationshipOperation(this, op);
1482
+ break;
1483
+ case "deleteRecord": {
1484
+ const identifier = op.record;
1485
+ const relationships = this.identifiers.get(identifier);
1486
+ if (relationships) {
1487
+ Object.keys(relationships).forEach((key) => {
1488
+ const rel = relationships[key];
1489
+ if (!rel) return;
1490
+ relationships[key] = void 0;
1491
+ removeCompletelyFromInverse(this, rel);
1492
+ });
1493
+ this.identifiers.delete(identifier);
1494
+ }
1495
+ break;
1496
+ }
1497
+ case "replaceRelatedRecord":
1498
+ replaceRelatedRecord(this, op, isRemote);
1499
+ break;
1500
+ case "add":
1501
+ addToRelatedRecords(this, op, isRemote);
1502
+ break;
1503
+ case "remove":
1504
+ removeFromRelatedRecords(this, op, isRemote);
1505
+ break;
1506
+ case "replaceRelatedRecords": replaceRelatedRecords(this, op, isRemote);
1507
+ }
1508
+ }
1509
+ /**
1510
+ * Marks a {@link CollectionEdge} as having local changes that need to be notified, and
1511
+ * schedules a flush of the local sync queue (see {@link Graph._flushLocalQueue}) if one is not
1512
+ * already pending.
1513
+ */
1514
+ _scheduleLocalSync(relationship) {
1515
+ this._updatedRelationships.add(relationship);
1516
+ if (!this._willSyncLocal) {
1517
+ this._willSyncLocal = true;
1518
+ getStore(this.store)._schedule("sync", () => this._flushLocalQueue());
1519
+ }
1520
+ }
1521
+ /**
1522
+ * Flushes all remote operations queued via {@link Graph.push}, applying them within a single
1523
+ * transaction (see {@link Graph._transaction} and {@link Graph._addToTransaction}) so that
1524
+ * dependent edges updated during the flush can be distinguished from those that were not.
1525
+ */
1526
+ _flushRemoteQueue() {
1527
+ if (!this._willSyncRemote) return;
1528
+ let transactionRef = peekTransient("transactionRef") ?? 0;
1529
+ this._transaction = ++transactionRef;
1530
+ setTransient("transactionRef", transactionRef);
1531
+ this._willSyncRemote = false;
1532
+ const updates = this._pushedUpdates;
1533
+ const { deletions, hasMany, belongsTo } = updates;
1534
+ updates.deletions = [];
1535
+ updates.hasMany = void 0;
1536
+ updates.belongsTo = void 0;
1537
+ for (let i = 0; i < deletions.length; i++) this.update(deletions[i], true);
1538
+ if (hasMany) flushPending(this, hasMany);
1539
+ if (belongsTo) flushPending(this, belongsTo);
1540
+ this._transaction = null;
1541
+ }
1542
+ /**
1543
+ * Stamps the current remote-update transaction id onto an edge, marking it as having been
1544
+ * touched during the in-progress {@link Graph._flushRemoteQueue} run. Must only be called while
1545
+ * a transaction is active.
1546
+ */
1547
+ _addToTransaction(relationship) {
1548
+ relationship.transactionRef = this._transaction;
1549
+ }
1550
+ /**
1551
+ * Flushes the queue of relationships scheduled via {@link Graph._scheduleLocalSync}, notifying
1552
+ * subscribers of each changed relationship — unless {@link Graph.silenceNotifications} is set,
1553
+ * in which case the queue is discarded without notifying.
1554
+ */
1555
+ _flushLocalQueue() {
1556
+ if (!this._willSyncLocal) return;
1557
+ if (this.silenceNotifications) {
1558
+ this.silenceNotifications = false;
1559
+ this._updatedRelationships = /* @__PURE__ */ new Set();
1560
+ return;
1561
+ }
1562
+ this._willSyncLocal = false;
1563
+ const updated = this._updatedRelationships;
1564
+ this._updatedRelationships = /* @__PURE__ */ new Set();
1565
+ updated.forEach((rel) => notifyChange(this, rel));
1566
+ }
1567
+ /**
1568
+ * Tears down the graph: clears all tracked identifiers/edges, removes it from the global
1569
+ * {@link Graphs} registry, and marks it as destroyed. In debug builds this also asserts that no
1570
+ * other live, non-destroying graphs remain registered, to help catch memory leaks from
1571
+ * improperly torn down store instances.
1572
+ */
1573
+ destroy() {
1574
+ Graphs.delete(this.store);
1575
+ this.identifiers.clear();
1576
+ this.store = null;
1577
+ this.isDestroyed = true;
1578
+ }
1579
+ };
2171
1580
  function flushPending(graph, ops) {
2172
- for (const type of ops.values()) {
2173
- for (const opList of type.values()) {
2174
- flushPendingList(graph, opList);
2175
- }
2176
- }
1581
+ for (const type of ops.values()) for (const opList of type.values()) flushPendingList(graph, opList);
2177
1582
  }
2178
1583
  function flushPendingList(graph, opList) {
2179
- for (let i = 0; i < opList.length; i++) {
2180
- graph.update(opList[i], true);
2181
- }
1584
+ for (let i = 0; i < opList.length; i++) graph.update(opList[i], true);
2182
1585
  }
2183
-
2184
- // Handle dematerialization for relationship `rel`. In all cases, notify the
2185
- // relationship of the dematerialization: this is done so the relationship can
2186
- // notify its inverse which needs to update state
2187
- //
2188
- // If the inverse is sync, unloading this record is treated as a client-side
2189
- // delete, so we remove the inverse records from this relationship to
2190
- // disconnect the graph. Because it's not async, we don't need to keep around
2191
- // the identifier as an id-wrapper for references
2192
1586
  function destroyRelationship(graph, rel, silenceNotifications) {
2193
- if (isImplicit(rel)) {
2194
- if (graph.isReleasable(rel.identifier)) {
2195
- /*#__NOINLINE__*/removeCompletelyFromInverse(graph, rel);
2196
- }
2197
- return;
2198
- }
2199
- const {
2200
- identifier
2201
- } = rel;
2202
- const {
2203
- inverseKey
2204
- } = rel.definition;
2205
- if (!rel.definition.inverseIsImplicit) {
2206
- /*#__NOINLINE__*/forAllRelatedIdentifiers(rel, inverseIdentifer => /*#__NOINLINE__*/notifyInverseOfDematerialization(graph, inverseIdentifer, inverseKey, identifier, silenceNotifications));
2207
- }
2208
- if (!rel.definition.inverseIsImplicit && !rel.definition.inverseIsAsync) {
2209
- rel.state.isStale = true;
2210
- /*#__NOINLINE__*/
2211
- clearRelationship(rel);
2212
-
2213
- // necessary to clear relationships in the ui from dematerialized records
2214
- // hasMany is managed by Model which calls `retreiveLatest` after
2215
- // dematerializing the resource-cache instance.
2216
- // but sync belongsTo requires this since they don't have a proxy to update.
2217
- // so we have to notify so it will "update" to null.
2218
- // we should discuss whether we still care about this, probably fine to just
2219
- // leave the ui relationship populated since the record is destroyed and
2220
- // internally we've fully cleaned up.
2221
- if (!rel.definition.isAsync && !silenceNotifications) {
2222
- /*#__NOINLINE__*/notifyChange(graph, rel);
2223
- }
2224
- }
1587
+ if (isImplicit(rel)) {
1588
+ if (graph.isReleasable(rel.identifier)) removeCompletelyFromInverse(graph, rel);
1589
+ return;
1590
+ }
1591
+ const { identifier } = rel;
1592
+ const { inverseKey } = rel.definition;
1593
+ if (!rel.definition.inverseIsImplicit) forAllRelatedIdentifiers(rel, (inverseIdentifer) => notifyInverseOfDematerialization(graph, inverseIdentifer, inverseKey, identifier, silenceNotifications));
1594
+ if (!rel.definition.inverseIsImplicit && !rel.definition.inverseIsAsync) {
1595
+ rel.state.isStale = true;
1596
+ clearRelationship(rel);
1597
+ if (!rel.definition.isAsync && !silenceNotifications) notifyChange(graph, rel);
1598
+ }
2225
1599
  }
2226
1600
  function notifyInverseOfDematerialization(graph, inverseIdentifier, inverseKey, resourceKey, silenceNotifications) {
2227
- if (!graph.has(inverseIdentifier, inverseKey)) {
2228
- return;
2229
- }
2230
- const relationship = graph.get(inverseIdentifier, inverseKey);
2231
-
2232
- // For remote members, it is possible that inverseRecordData has already been associated to
2233
- // to another record. For such cases, do not dematerialize the inverseRecordData
2234
- if (!isBelongsTo(relationship) || !relationship.localState || resourceKey === relationship.localState) {
2235
- /*#__NOINLINE__*/removeDematerializedInverse(graph, relationship, resourceKey, silenceNotifications);
2236
- }
1601
+ if (!graph.has(inverseIdentifier, inverseKey)) return;
1602
+ const relationship = graph.get(inverseIdentifier, inverseKey);
1603
+ if (!isBelongsTo(relationship) || !relationship.localState || resourceKey === relationship.localState) removeDematerializedInverse(graph, relationship, resourceKey, silenceNotifications);
2237
1604
  }
2238
1605
  function clearRelationship(relationship) {
2239
- if (isBelongsTo(relationship)) {
2240
- relationship.localState = null;
2241
- relationship.remoteState = null;
2242
- relationship.state.hasReceivedData = false;
2243
- relationship.state.isEmpty = true;
2244
- } else {
2245
- relationship.remoteMembers.clear();
2246
- relationship.remoteState = [];
2247
- relationship.additions = null;
2248
- relationship.removals = null;
2249
- relationship.localState = null;
2250
- }
1606
+ if (isBelongsTo(relationship)) {
1607
+ relationship.localState = null;
1608
+ relationship.remoteState = null;
1609
+ relationship.state.hasReceivedData = false;
1610
+ relationship.state.isEmpty = true;
1611
+ } else {
1612
+ relationship.remoteMembers.clear();
1613
+ relationship.remoteState = [];
1614
+ relationship.additions = null;
1615
+ relationship.removals = null;
1616
+ relationship.localState = null;
1617
+ }
2251
1618
  }
2252
1619
  function removeDematerializedInverse(graph, relationship, inverseIdentifier, silenceNotifications) {
2253
- if (isBelongsTo(relationship)) {
2254
- const localInverse = relationship.localState;
2255
- if (!relationship.definition.isAsync || localInverse && checkIfNew(graph._realStore, localInverse)) {
2256
- // unloading inverse of a sync relationship is treated as a client-side
2257
- // delete, so actually remove the models don't merely invalidate the cp
2258
- // cache.
2259
- // if the record being unloaded only exists on the client, we similarly
2260
- // treat it as a client side delete
2261
- if (relationship.localState === localInverse && localInverse !== null) {
2262
- relationship.localState = null;
2263
- }
2264
- if (relationship.remoteState === localInverse && localInverse !== null) {
2265
- relationship.remoteState = null;
2266
- relationship.state.hasReceivedData = true;
2267
- relationship.state.isEmpty = true;
2268
- if (relationship.localState && !checkIfNew(graph._realStore, relationship.localState)) {
2269
- relationship.localState = null;
2270
- }
2271
- }
2272
- } else {
2273
- relationship.state.hasDematerializedInverse = true;
2274
- }
2275
- if (!silenceNotifications) {
2276
- notifyChange(graph, relationship);
2277
- }
2278
- } else {
2279
- if (!relationship.definition.isAsync || inverseIdentifier && checkIfNew(graph._realStore, inverseIdentifier)) {
2280
- // unloading inverse of a sync relationship is treated as a client-side
2281
- // delete, so actually remove the models don't merely invalidate the cp
2282
- // cache.
2283
- // if the record being unloaded only exists on the client, we similarly
2284
- // treat it as a client side delete
2285
- /*#__NOINLINE__*/
2286
- removeIdentifierCompletelyFromRelationship(graph, relationship, inverseIdentifier);
2287
- } else {
2288
- relationship.state.hasDematerializedInverse = true;
2289
- }
2290
- if (!silenceNotifications) {
2291
- notifyChange(graph, relationship);
2292
- }
2293
- }
1620
+ if (isBelongsTo(relationship)) {
1621
+ const localInverse = relationship.localState;
1622
+ if (!relationship.definition.isAsync || localInverse && checkIfNew(graph._realStore, localInverse)) {
1623
+ if (relationship.localState === localInverse && localInverse !== null) relationship.localState = null;
1624
+ if (relationship.remoteState === localInverse && localInverse !== null) {
1625
+ relationship.remoteState = null;
1626
+ relationship.state.hasReceivedData = true;
1627
+ relationship.state.isEmpty = true;
1628
+ if (relationship.localState && !checkIfNew(graph._realStore, relationship.localState)) relationship.localState = null;
1629
+ }
1630
+ } else relationship.state.hasDematerializedInverse = true;
1631
+ if (!silenceNotifications) notifyChange(graph, relationship);
1632
+ } else {
1633
+ if (!relationship.definition.isAsync || inverseIdentifier && checkIfNew(graph._realStore, inverseIdentifier)) removeIdentifierCompletelyFromRelationship(graph, relationship, inverseIdentifier);
1634
+ else relationship.state.hasDematerializedInverse = true;
1635
+ if (!silenceNotifications) notifyChange(graph, relationship);
1636
+ }
2294
1637
  }
2295
1638
  function removeCompletelyFromInverse(graph, relationship) {
2296
- const {
2297
- identifier
2298
- } = relationship;
2299
- const {
2300
- inverseKey
2301
- } = relationship.definition;
2302
- forAllRelatedIdentifiers(relationship, inverseIdentifier => {
2303
- if (graph.has(inverseIdentifier, inverseKey)) {
2304
- removeIdentifierCompletelyFromRelationship(graph, graph.get(inverseIdentifier, inverseKey), identifier);
2305
- }
2306
- });
2307
- if (isBelongsTo(relationship)) {
2308
- if (!relationship.definition.isAsync) {
2309
- clearRelationship(relationship);
2310
- }
2311
- relationship.localState = null;
2312
- } else if (isHasMany(relationship)) {
2313
- if (!relationship.definition.isAsync) {
2314
- clearRelationship(relationship);
2315
- notifyChange(graph, relationship);
2316
- }
2317
- } else {
2318
- relationship.remoteMembers.clear();
2319
- relationship.localMembers.clear();
2320
- }
1639
+ const { identifier } = relationship;
1640
+ const { inverseKey } = relationship.definition;
1641
+ forAllRelatedIdentifiers(relationship, (inverseIdentifier) => {
1642
+ if (graph.has(inverseIdentifier, inverseKey)) removeIdentifierCompletelyFromRelationship(graph, graph.get(inverseIdentifier, inverseKey), identifier);
1643
+ });
1644
+ if (isBelongsTo(relationship)) {
1645
+ if (!relationship.definition.isAsync) clearRelationship(relationship);
1646
+ relationship.localState = null;
1647
+ } else if (isHasMany(relationship)) {
1648
+ if (!relationship.definition.isAsync) {
1649
+ clearRelationship(relationship);
1650
+ notifyChange(graph, relationship);
1651
+ }
1652
+ } else {
1653
+ relationship.remoteMembers.clear();
1654
+ relationship.localMembers.clear();
1655
+ }
2321
1656
  }
2322
1657
  function addPending(cache, definition, op) {
2323
- const cacheForKind = cache[definition.kind] = cache[definition.kind] || new Map();
2324
- let cacheForType = cacheForKind.get(definition.inverseType);
2325
- if (!cacheForType) {
2326
- cacheForType = new Map();
2327
- cacheForKind.set(definition.inverseType, cacheForType);
2328
- }
2329
- let cacheForField = cacheForType.get(op.field);
2330
- if (!cacheForField) {
2331
- cacheForField = [];
2332
- cacheForType.set(op.field, cacheForField);
2333
- }
2334
- cacheForField.push(op);
1658
+ const cacheForKind = cache[definition.kind] = cache[definition.kind] || /* @__PURE__ */ new Map();
1659
+ let cacheForType = cacheForKind.get(definition.inverseType);
1660
+ if (!cacheForType) {
1661
+ cacheForType = /* @__PURE__ */ new Map();
1662
+ cacheForKind.set(definition.inverseType, cacheForType);
1663
+ }
1664
+ let cacheForField = cacheForType.get(op.field);
1665
+ if (!cacheForField) {
1666
+ cacheForField = [];
1667
+ cacheForType.set(op.field, cacheForField);
1668
+ }
1669
+ cacheForField.push(op);
2335
1670
  }
2336
1671
  function isReordered(relationship) {
2337
- // if we are dirty we are never re-ordered because accessing
2338
- // the state would flush away any reordering.
2339
- if (relationship.isDirty) {
2340
- return false;
2341
- }
2342
- const {
2343
- remoteState,
2344
- localState,
2345
- additions,
2346
- removals
2347
- } = relationship;
2348
- if (localState === null) {
2349
- // the relationship has never been accessed, so it hasn't been reordered either
2350
- return false;
2351
- }
2352
- for (let i = 0, j = 0; i < remoteState.length; i++) {
2353
- const member = remoteState[i];
2354
- const localMember = localState[j];
2355
- if (member !== localMember) {
2356
- if (removals && removals.has(member)) {
2357
- // dont increment j because we want to skip this
2358
- continue;
2359
- }
2360
- if (additions && additions.has(localMember)) {
2361
- // increment j to skip this localMember
2362
- // decrement i to repeat this remoteMember
2363
- j++;
2364
- i--;
2365
- continue;
2366
- }
2367
- return true;
2368
- }
2369
-
2370
- // if we made it here, increment j
2371
- j++;
2372
- }
2373
- return false;
2374
- }
2375
-
1672
+ if (relationship.isDirty) return false;
1673
+ const { remoteState, localState, additions, removals } = relationship;
1674
+ if (localState === null) return false;
1675
+ for (let i = 0, j = 0; i < remoteState.length; i++) {
1676
+ const member = remoteState[i];
1677
+ const localMember = localState[j];
1678
+ if (member !== localMember) {
1679
+ if (removals && removals.has(member)) continue;
1680
+ if (additions && additions.has(localMember)) {
1681
+ j++;
1682
+ i--;
1683
+ continue;
1684
+ }
1685
+ return true;
1686
+ }
1687
+ j++;
1688
+ }
1689
+ return false;
1690
+ }
1691
+
1692
+ //#endregion
1693
+ //#region src/graph/-private.ts
2376
1694
  /**
2377
1695
  Provides a performance tuned normalized graph for intelligently managing relationships between resources based on identity
2378
1696
 
@@ -2380,26 +1698,31 @@ While this Graph is abstract, it currently is a private implementation required
2380
1698
 
2381
1699
  We intend to make this Graph public API after some additional iteration during the 5.x timeframe, until then all APIs should be considered experimental and unstable, not fit for direct application or 3rd party library usage.
2382
1700
 
2383
- @module
1701
+ @module
2384
1702
  */
2385
-
2386
1703
  function isStore(maybeStore) {
2387
- return maybeStore._instanceCache !== undefined;
1704
+ return maybeStore._instanceCache !== void 0;
2388
1705
  }
2389
1706
  function getWrapper(store) {
2390
- return isStore(store) ? store._instanceCache._storeWrapper : store;
1707
+ return isStore(store) ? store._instanceCache._storeWrapper : store;
2391
1708
  }
1709
+ /** Returns the {@link Graph} associated with the given store or capabilities manager, if one has been created. */
2392
1710
  function peekGraph(store) {
2393
- return Graphs.get(getWrapper(store));
1711
+ return Graphs.get(getWrapper(store));
2394
1712
  }
1713
+ /** The type of the {@link peekGraph} function. */
1714
+ /** Returns the {@link Graph} for the given store, creating (and caching) one first if it does not yet exist. */
2395
1715
  function graphFor(store) {
2396
- const wrapper = getWrapper(store);
2397
- let graph = Graphs.get(wrapper);
2398
- if (!graph) {
2399
- graph = new Graph(wrapper);
2400
- Graphs.set(wrapper, graph);
2401
- getStore(wrapper)._graph = graph;
2402
- }
2403
- return graph;
2404
- }
2405
- export { graphFor, isBelongsTo, peekGraph };
1716
+ const wrapper = getWrapper(store);
1717
+ let graph = Graphs.get(wrapper);
1718
+ if (!graph) {
1719
+ graph = new Graph(wrapper);
1720
+ Graphs.set(wrapper, graph);
1721
+ getStore(wrapper)._graph = graph;
1722
+ }
1723
+ return graph;
1724
+ }
1725
+
1726
+ //#endregion
1727
+ export { graphFor, isBelongsTo, peekGraph };
1728
+ //# sourceMappingURL=-private.js.map