@statezero/core 0.2.36 → 0.2.38

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 (301) hide show
  1. package/dist/adaptors/vue/components/LayoutRenderer.js +166 -0
  2. package/dist/adaptors/vue/components/defaults/AlertElement.js +31 -0
  3. package/dist/adaptors/vue/components/defaults/DisplayElement.js +44 -0
  4. package/dist/adaptors/vue/components/defaults/DividerElement.js +10 -0
  5. package/dist/adaptors/vue/components/defaults/ErrorBlock.js +24 -0
  6. package/dist/adaptors/vue/components/defaults/GroupElement.js +41 -0
  7. package/dist/adaptors/vue/components/defaults/LabelElement.js +21 -0
  8. package/dist/adaptors/vue/components/defaults/TabsElement.js +38 -0
  9. package/package.json +7 -6
  10. package/dist/actions/backend1/django_app/calculate-hash.d.ts +0 -57
  11. package/dist/actions/backend1/django_app/calculate-hash.js +0 -80
  12. package/dist/actions/backend1/django_app/calculate-hash.schema.json +0 -148
  13. package/dist/actions/backend1/django_app/get-current-username.d.ts +0 -29
  14. package/dist/actions/backend1/django_app/get-current-username.js +0 -65
  15. package/dist/actions/backend1/django_app/get-current-username.schema.json +0 -47
  16. package/dist/actions/backend1/django_app/get-server-status.d.ts +0 -38
  17. package/dist/actions/backend1/django_app/get-server-status.js +0 -68
  18. package/dist/actions/backend1/django_app/get-server-status.schema.json +0 -93
  19. package/dist/actions/backend1/django_app/get-user-info.d.ts +0 -44
  20. package/dist/actions/backend1/django_app/get-user-info.js +0 -70
  21. package/dist/actions/backend1/django_app/get-user-info.schema.json +0 -127
  22. package/dist/actions/backend1/django_app/index.d.ts +0 -1
  23. package/dist/actions/backend1/django_app/index.js +0 -6
  24. package/dist/actions/backend1/django_app/process-data.d.ts +0 -51
  25. package/dist/actions/backend1/django_app/process-data.js +0 -78
  26. package/dist/actions/backend1/django_app/process-data.schema.json +0 -117
  27. package/dist/actions/backend1/django_app/send-notification.d.ts +0 -55
  28. package/dist/actions/backend1/django_app/send-notification.js +0 -81
  29. package/dist/actions/backend1/django_app/send-notification.schema.json +0 -175
  30. package/dist/actions/backend1/index.d.ts +0 -1
  31. package/dist/actions/backend1/index.js +0 -1
  32. package/dist/actions/default/django_app/calculate-hash.d.ts +0 -57
  33. package/dist/actions/default/django_app/calculate-hash.js +0 -80
  34. package/dist/actions/default/django_app/calculate-hash.schema.json +0 -148
  35. package/dist/actions/default/django_app/get-current-username.d.ts +0 -29
  36. package/dist/actions/default/django_app/get-current-username.js +0 -65
  37. package/dist/actions/default/django_app/get-current-username.schema.json +0 -47
  38. package/dist/actions/default/django_app/get-server-status.d.ts +0 -38
  39. package/dist/actions/default/django_app/get-server-status.js +0 -68
  40. package/dist/actions/default/django_app/get-server-status.schema.json +0 -93
  41. package/dist/actions/default/django_app/get-user-info.d.ts +0 -44
  42. package/dist/actions/default/django_app/get-user-info.js +0 -70
  43. package/dist/actions/default/django_app/get-user-info.schema.json +0 -127
  44. package/dist/actions/default/django_app/index.d.ts +0 -1
  45. package/dist/actions/default/django_app/index.js +0 -6
  46. package/dist/actions/default/django_app/process-data.d.ts +0 -51
  47. package/dist/actions/default/django_app/process-data.js +0 -78
  48. package/dist/actions/default/django_app/process-data.schema.json +0 -117
  49. package/dist/actions/default/django_app/send-notification.d.ts +0 -55
  50. package/dist/actions/default/django_app/send-notification.js +0 -81
  51. package/dist/actions/default/django_app/send-notification.schema.json +0 -175
  52. package/dist/actions/default/index.d.ts +0 -1
  53. package/dist/actions/default/index.js +0 -1
  54. package/dist/actions/index.d.ts +0 -1
  55. package/dist/actions/index.js +0 -5
  56. package/dist/adaptors/react/composables.d.ts +0 -1
  57. package/dist/adaptors/react/composables.js +0 -4
  58. package/dist/adaptors/react/index.d.ts +0 -1
  59. package/dist/adaptors/react/index.js +0 -1
  60. package/dist/adaptors/vue/components/defaults/index.d.ts +0 -7
  61. package/dist/adaptors/vue/components/defaults/index.js +0 -31
  62. package/dist/adaptors/vue/components/index.d.ts +0 -1
  63. package/dist/adaptors/vue/components/index.js +0 -7
  64. package/dist/adaptors/vue/composables.d.ts +0 -2
  65. package/dist/adaptors/vue/composables.js +0 -44
  66. package/dist/adaptors/vue/index.d.ts +0 -3
  67. package/dist/adaptors/vue/index.js +0 -4
  68. package/dist/adaptors/vue/reactivity.d.ts +0 -18
  69. package/dist/adaptors/vue/reactivity.js +0 -132
  70. package/dist/cli/commands/sync.d.ts +0 -6
  71. package/dist/cli/commands/sync.js +0 -30
  72. package/dist/cli/commands/syncActions.d.ts +0 -46
  73. package/dist/cli/commands/syncActions.js +0 -717
  74. package/dist/cli/commands/syncModels.d.ts +0 -132
  75. package/dist/cli/commands/syncModels.js +0 -1120
  76. package/dist/cli/configFileLoader.d.ts +0 -10
  77. package/dist/cli/configFileLoader.js +0 -85
  78. package/dist/cli/index.d.ts +0 -2
  79. package/dist/cli/index.js +0 -22
  80. package/dist/config.d.ts +0 -57
  81. package/dist/config.js +0 -273
  82. package/dist/core/eventReceivers.d.ts +0 -185
  83. package/dist/core/eventReceivers.js +0 -266
  84. package/dist/core/utils.d.ts +0 -8
  85. package/dist/core/utils.js +0 -62
  86. package/dist/errorHandler.d.ts +0 -21
  87. package/dist/errorHandler.js +0 -27
  88. package/dist/filtering/localFiltering.d.ts +0 -110
  89. package/dist/filtering/localFiltering.js +0 -1080
  90. package/dist/flavours/django/dates.d.ts +0 -34
  91. package/dist/flavours/django/dates.js +0 -113
  92. package/dist/flavours/django/errors.d.ts +0 -138
  93. package/dist/flavours/django/errors.js +0 -195
  94. package/dist/flavours/django/f.d.ts +0 -6
  95. package/dist/flavours/django/f.js +0 -91
  96. package/dist/flavours/django/files.d.ts +0 -62
  97. package/dist/flavours/django/files.js +0 -355
  98. package/dist/flavours/django/makeApiCall.d.ts +0 -36
  99. package/dist/flavours/django/makeApiCall.js +0 -169
  100. package/dist/flavours/django/manager.d.ts +0 -204
  101. package/dist/flavours/django/manager.js +0 -222
  102. package/dist/flavours/django/model.d.ts +0 -137
  103. package/dist/flavours/django/model.js +0 -366
  104. package/dist/flavours/django/operationFactory.d.ts +0 -73
  105. package/dist/flavours/django/operationFactory.js +0 -248
  106. package/dist/flavours/django/q.d.ts +0 -70
  107. package/dist/flavours/django/q.js +0 -43
  108. package/dist/flavours/django/queryExecutor.d.ts +0 -149
  109. package/dist/flavours/django/queryExecutor.js +0 -590
  110. package/dist/flavours/django/querySet.d.ts +0 -301
  111. package/dist/flavours/django/querySet.js +0 -736
  112. package/dist/flavours/django/serializers.d.ts +0 -39
  113. package/dist/flavours/django/serializers.js +0 -296
  114. package/dist/flavours/django/tempPk.d.ts +0 -31
  115. package/dist/flavours/django/tempPk.js +0 -92
  116. package/dist/flavours/django/utils.d.ts +0 -19
  117. package/dist/flavours/django/utils.js +0 -29
  118. package/dist/index.d.ts +0 -46
  119. package/dist/index.js +0 -48
  120. package/dist/models/backend1/django_app/comprehensivemodel.d.ts +0 -894
  121. package/dist/models/backend1/django_app/comprehensivemodel.js +0 -71
  122. package/dist/models/backend1/django_app/comprehensivemodel.schema.json +0 -870
  123. package/dist/models/backend1/django_app/custompkmodel.d.ts +0 -92
  124. package/dist/models/backend1/django_app/custompkmodel.js +0 -69
  125. package/dist/models/backend1/django_app/custompkmodel.schema.json +0 -71
  126. package/dist/models/backend1/django_app/dailyrate.d.ts +0 -230
  127. package/dist/models/backend1/django_app/dailyrate.js +0 -71
  128. package/dist/models/backend1/django_app/dailyrate.schema.json +0 -212
  129. package/dist/models/backend1/django_app/deepmodellevel1.d.ts +0 -140
  130. package/dist/models/backend1/django_app/deepmodellevel1.js +0 -72
  131. package/dist/models/backend1/django_app/deepmodellevel1.schema.json +0 -114
  132. package/dist/models/backend1/django_app/deepmodellevel2.d.ts +0 -118
  133. package/dist/models/backend1/django_app/deepmodellevel2.js +0 -71
  134. package/dist/models/backend1/django_app/deepmodellevel2.schema.json +0 -92
  135. package/dist/models/backend1/django_app/deepmodellevel3.d.ts +0 -92
  136. package/dist/models/backend1/django_app/deepmodellevel3.js +0 -69
  137. package/dist/models/backend1/django_app/deepmodellevel3.schema.json +0 -69
  138. package/dist/models/backend1/django_app/dummymodel.d.ts +0 -134
  139. package/dist/models/backend1/django_app/dummymodel.js +0 -71
  140. package/dist/models/backend1/django_app/dummymodel.schema.json +0 -109
  141. package/dist/models/backend1/django_app/dummyrelatedmodel.d.ts +0 -92
  142. package/dist/models/backend1/django_app/dummyrelatedmodel.js +0 -69
  143. package/dist/models/backend1/django_app/dummyrelatedmodel.schema.json +0 -69
  144. package/dist/models/backend1/django_app/filetest.d.ts +0 -140
  145. package/dist/models/backend1/django_app/filetest.js +0 -69
  146. package/dist/models/backend1/django_app/filetest.schema.json +0 -111
  147. package/dist/models/backend1/django_app/index.d.ts +0 -1
  148. package/dist/models/backend1/django_app/index.js +0 -21
  149. package/dist/models/backend1/django_app/m2mdepthtestlevel1.d.ts +0 -118
  150. package/dist/models/backend1/django_app/m2mdepthtestlevel1.js +0 -71
  151. package/dist/models/backend1/django_app/m2mdepthtestlevel1.schema.json +0 -94
  152. package/dist/models/backend1/django_app/m2mdepthtestlevel2.d.ts +0 -118
  153. package/dist/models/backend1/django_app/m2mdepthtestlevel2.js +0 -71
  154. package/dist/models/backend1/django_app/m2mdepthtestlevel2.schema.json +0 -94
  155. package/dist/models/backend1/django_app/m2mdepthtestlevel3.d.ts +0 -134
  156. package/dist/models/backend1/django_app/m2mdepthtestlevel3.js +0 -71
  157. package/dist/models/backend1/django_app/m2mdepthtestlevel3.schema.json +0 -112
  158. package/dist/models/backend1/django_app/modelwithcustompkrelation.d.ts +0 -118
  159. package/dist/models/backend1/django_app/modelwithcustompkrelation.js +0 -71
  160. package/dist/models/backend1/django_app/modelwithcustompkrelation.schema.json +0 -93
  161. package/dist/models/backend1/django_app/modelwithrestrictedfields.d.ts +0 -134
  162. package/dist/models/backend1/django_app/modelwithrestrictedfields.js +0 -71
  163. package/dist/models/backend1/django_app/modelwithrestrictedfields.schema.json +0 -111
  164. package/dist/models/backend1/django_app/namefiltercustompkmodel.d.ts +0 -92
  165. package/dist/models/backend1/django_app/namefiltercustompkmodel.js +0 -69
  166. package/dist/models/backend1/django_app/namefiltercustompkmodel.schema.json +0 -71
  167. package/dist/models/backend1/django_app/order.d.ts +0 -220
  168. package/dist/models/backend1/django_app/order.js +0 -71
  169. package/dist/models/backend1/django_app/order.schema.json +0 -203
  170. package/dist/models/backend1/django_app/orderitem.d.ts +0 -172
  171. package/dist/models/backend1/django_app/orderitem.js +0 -72
  172. package/dist/models/backend1/django_app/orderitem.schema.json +0 -149
  173. package/dist/models/backend1/django_app/product.d.ts +0 -254
  174. package/dist/models/backend1/django_app/product.js +0 -71
  175. package/dist/models/backend1/django_app/product.schema.json +0 -277
  176. package/dist/models/backend1/django_app/productcategory.d.ts +0 -92
  177. package/dist/models/backend1/django_app/productcategory.js +0 -69
  178. package/dist/models/backend1/django_app/productcategory.schema.json +0 -70
  179. package/dist/models/backend1/django_app/rateplan.d.ts +0 -92
  180. package/dist/models/backend1/django_app/rateplan.js +0 -69
  181. package/dist/models/backend1/django_app/rateplan.schema.json +0 -70
  182. package/dist/models/backend1/django_app/restrictedfieldrelatedmodel.d.ts +0 -108
  183. package/dist/models/backend1/django_app/restrictedfieldrelatedmodel.js +0 -69
  184. package/dist/models/backend1/django_app/restrictedfieldrelatedmodel.schema.json +0 -87
  185. package/dist/models/backend1/fileobject.d.ts +0 -4
  186. package/dist/models/backend1/fileobject.js +0 -9
  187. package/dist/models/backend1/index.d.ts +0 -2
  188. package/dist/models/backend1/index.js +0 -2
  189. package/dist/models/default/django_app/comprehensivemodel.d.ts +0 -894
  190. package/dist/models/default/django_app/comprehensivemodel.js +0 -71
  191. package/dist/models/default/django_app/comprehensivemodel.schema.json +0 -870
  192. package/dist/models/default/django_app/custompkmodel.d.ts +0 -92
  193. package/dist/models/default/django_app/custompkmodel.js +0 -69
  194. package/dist/models/default/django_app/custompkmodel.schema.json +0 -71
  195. package/dist/models/default/django_app/dailyrate.d.ts +0 -230
  196. package/dist/models/default/django_app/dailyrate.js +0 -71
  197. package/dist/models/default/django_app/dailyrate.schema.json +0 -212
  198. package/dist/models/default/django_app/deepmodellevel1.d.ts +0 -128
  199. package/dist/models/default/django_app/deepmodellevel1.js +0 -72
  200. package/dist/models/default/django_app/deepmodellevel1.schema.json +0 -102
  201. package/dist/models/default/django_app/deepmodellevel2.d.ts +0 -106
  202. package/dist/models/default/django_app/deepmodellevel2.js +0 -71
  203. package/dist/models/default/django_app/deepmodellevel2.schema.json +0 -80
  204. package/dist/models/default/django_app/deepmodellevel3.d.ts +0 -80
  205. package/dist/models/default/django_app/deepmodellevel3.js +0 -69
  206. package/dist/models/default/django_app/deepmodellevel3.schema.json +0 -57
  207. package/dist/models/default/django_app/dummymodel.d.ts +0 -122
  208. package/dist/models/default/django_app/dummymodel.js +0 -71
  209. package/dist/models/default/django_app/dummymodel.schema.json +0 -97
  210. package/dist/models/default/django_app/dummyrelatedmodel.d.ts +0 -80
  211. package/dist/models/default/django_app/dummyrelatedmodel.js +0 -69
  212. package/dist/models/default/django_app/dummyrelatedmodel.schema.json +0 -57
  213. package/dist/models/default/django_app/filetest.d.ts +0 -128
  214. package/dist/models/default/django_app/filetest.js +0 -69
  215. package/dist/models/default/django_app/filetest.schema.json +0 -99
  216. package/dist/models/default/django_app/index.d.ts +0 -1
  217. package/dist/models/default/django_app/index.js +0 -21
  218. package/dist/models/default/django_app/m2mdepthtestlevel1.d.ts +0 -118
  219. package/dist/models/default/django_app/m2mdepthtestlevel1.js +0 -71
  220. package/dist/models/default/django_app/m2mdepthtestlevel1.schema.json +0 -94
  221. package/dist/models/default/django_app/m2mdepthtestlevel2.d.ts +0 -118
  222. package/dist/models/default/django_app/m2mdepthtestlevel2.js +0 -71
  223. package/dist/models/default/django_app/m2mdepthtestlevel2.schema.json +0 -94
  224. package/dist/models/default/django_app/m2mdepthtestlevel3.d.ts +0 -134
  225. package/dist/models/default/django_app/m2mdepthtestlevel3.js +0 -71
  226. package/dist/models/default/django_app/m2mdepthtestlevel3.schema.json +0 -112
  227. package/dist/models/default/django_app/modelwithcustompkrelation.d.ts +0 -118
  228. package/dist/models/default/django_app/modelwithcustompkrelation.js +0 -71
  229. package/dist/models/default/django_app/modelwithcustompkrelation.schema.json +0 -93
  230. package/dist/models/default/django_app/modelwithrestrictedfields.d.ts +0 -134
  231. package/dist/models/default/django_app/modelwithrestrictedfields.js +0 -71
  232. package/dist/models/default/django_app/modelwithrestrictedfields.schema.json +0 -111
  233. package/dist/models/default/django_app/namefiltercustompkmodel.d.ts +0 -92
  234. package/dist/models/default/django_app/namefiltercustompkmodel.js +0 -69
  235. package/dist/models/default/django_app/namefiltercustompkmodel.schema.json +0 -71
  236. package/dist/models/default/django_app/order.d.ts +0 -220
  237. package/dist/models/default/django_app/order.js +0 -71
  238. package/dist/models/default/django_app/order.schema.json +0 -203
  239. package/dist/models/default/django_app/orderitem.d.ts +0 -172
  240. package/dist/models/default/django_app/orderitem.js +0 -72
  241. package/dist/models/default/django_app/orderitem.schema.json +0 -149
  242. package/dist/models/default/django_app/product.d.ts +0 -254
  243. package/dist/models/default/django_app/product.js +0 -71
  244. package/dist/models/default/django_app/product.schema.json +0 -277
  245. package/dist/models/default/django_app/productcategory.d.ts +0 -92
  246. package/dist/models/default/django_app/productcategory.js +0 -69
  247. package/dist/models/default/django_app/productcategory.schema.json +0 -70
  248. package/dist/models/default/django_app/rateplan.d.ts +0 -92
  249. package/dist/models/default/django_app/rateplan.js +0 -69
  250. package/dist/models/default/django_app/rateplan.schema.json +0 -70
  251. package/dist/models/default/django_app/restrictedfieldrelatedmodel.d.ts +0 -108
  252. package/dist/models/default/django_app/restrictedfieldrelatedmodel.js +0 -69
  253. package/dist/models/default/django_app/restrictedfieldrelatedmodel.schema.json +0 -87
  254. package/dist/models/default/fileobject.d.ts +0 -4
  255. package/dist/models/default/fileobject.js +0 -9
  256. package/dist/models/default/index.d.ts +0 -2
  257. package/dist/models/default/index.js +0 -2
  258. package/dist/models/index.d.ts +0 -1
  259. package/dist/models/index.js +0 -5
  260. package/dist/react-entry.d.ts +0 -2
  261. package/dist/react-entry.js +0 -2
  262. package/dist/reactiveAdaptor.d.ts +0 -24
  263. package/dist/reactiveAdaptor.js +0 -38
  264. package/dist/reset.d.ts +0 -15
  265. package/dist/reset.js +0 -97
  266. package/dist/setup.d.ts +0 -15
  267. package/dist/setup.js +0 -33
  268. package/dist/syncEngine/cache/cache.d.ts +0 -75
  269. package/dist/syncEngine/cache/cache.js +0 -355
  270. package/dist/syncEngine/metrics/metricOptCalcs.d.ts +0 -79
  271. package/dist/syncEngine/metrics/metricOptCalcs.js +0 -284
  272. package/dist/syncEngine/registries/metricRegistry.d.ts +0 -58
  273. package/dist/syncEngine/registries/metricRegistry.js +0 -171
  274. package/dist/syncEngine/registries/modelStoreRegistry.d.ts +0 -11
  275. package/dist/syncEngine/registries/modelStoreRegistry.js +0 -63
  276. package/dist/syncEngine/registries/querysetStoreGraph.d.ts +0 -41
  277. package/dist/syncEngine/registries/querysetStoreGraph.js +0 -174
  278. package/dist/syncEngine/registries/querysetStoreRegistry.d.ts +0 -72
  279. package/dist/syncEngine/registries/querysetStoreRegistry.js +0 -335
  280. package/dist/syncEngine/stores/metricStore.d.ts +0 -55
  281. package/dist/syncEngine/stores/metricStore.js +0 -222
  282. package/dist/syncEngine/stores/modelStore.d.ts +0 -53
  283. package/dist/syncEngine/stores/modelStore.js +0 -565
  284. package/dist/syncEngine/stores/operation.d.ts +0 -139
  285. package/dist/syncEngine/stores/operation.js +0 -291
  286. package/dist/syncEngine/stores/operationEventHandlers.d.ts +0 -8
  287. package/dist/syncEngine/stores/operationEventHandlers.js +0 -322
  288. package/dist/syncEngine/stores/querysetStore.d.ts +0 -60
  289. package/dist/syncEngine/stores/querysetStore.js +0 -294
  290. package/dist/syncEngine/stores/reactivity.d.ts +0 -3
  291. package/dist/syncEngine/stores/reactivity.js +0 -4
  292. package/dist/syncEngine/stores/utils.d.ts +0 -14
  293. package/dist/syncEngine/stores/utils.js +0 -32
  294. package/dist/syncEngine/sync.d.ts +0 -46
  295. package/dist/syncEngine/sync.js +0 -389
  296. package/dist/testing.d.ts +0 -63
  297. package/dist/testing.js +0 -175
  298. package/dist/vue-entry.d.ts +0 -15
  299. package/dist/vue-entry.js +0 -7
  300. /package/{src → dist}/adaptors/vue/components/layout.css +0 -0
  301. /package/{src → dist}/adaptors/vue/components/layout.tailwind.css +0 -0
@@ -1,366 +0,0 @@
1
- import { Manager } from "./manager.js";
2
- import { ValidationError } from "./errors.js";
3
- import { modelStoreRegistry } from "../../syncEngine/registries/modelStoreRegistry.js";
4
- import { isNil } from "lodash-es";
5
- import { QueryExecutor } from "./queryExecutor.js";
6
- import { wrapReactiveModel } from "../../reactiveAdaptor.js";
7
- import { DateParsingHelpers } from "./dates.js";
8
- import { FileObject } from './files.js';
9
- import { configInstance } from "../../config.js";
10
- import { ModelSerializer } from "./serializers.js";
11
- import { parseStateZeroError, MultipleObjectsReturned, DoesNotExist, } from "./errors.js";
12
- import axios from "axios";
13
- /**
14
- * A constructor for a Model.
15
- *
16
- * @typedef {Function} ModelConstructor
17
- * @param {any} data - Data to initialize the model.
18
- * @returns {Model}
19
- *
20
- * @property {Manager} objects - The model's manager.
21
- * @property {string} configKey - The configuration key.
22
- * @property {string} modelName - The model name.
23
- * @property {string} primaryKeyField - The primary key field (default 'id').
24
- */
25
- /**
26
- * Base Model class with integrated API implementation.
27
- *
28
- * @abstract
29
- */
30
- export class Model {
31
- constructor(data = {}) {
32
- this.serializer = new ModelSerializer(this.constructor);
33
- const serializedData = this.serializer.toInternal(data);
34
- this._data = serializedData;
35
- this._pk = serializedData[this.constructor.primaryKeyField] || undefined;
36
- this.__version = 0;
37
- return wrapReactiveModel(this);
38
- }
39
- /**
40
- * Remote-only manager that skips local store updates.
41
- */
42
- static get remote() {
43
- return this.objects.remote();
44
- }
45
- touch() {
46
- this.__version++;
47
- }
48
- /**
49
- * Returns the primary key of the model instance.
50
- *
51
- * @returns {number|undefined} The primary key.
52
- */
53
- get pk() {
54
- return this._pk;
55
- }
56
- /**
57
- * Sets the primary key of the model instance.
58
- *
59
- * @param {number|undefined} value - The new primary key value.
60
- */
61
- set pk(value) {
62
- this._pk = value;
63
- this.touch();
64
- }
65
- /**
66
- * Instantiate from pk using queryset scoped singletons
67
- */
68
- static fromPk(pk, querySet) {
69
- let qsId = querySet ? querySet.__uuid : "";
70
- let key = `${qsId}__${this.configKey}__${this.modelName}__${pk}`;
71
- if (!this.instanceCache.has(key)) {
72
- const instance = new this();
73
- instance.pk = pk;
74
- this.instanceCache.set(key, instance);
75
- }
76
- return this.instanceCache.get(key);
77
- }
78
- /**
79
- * Gets a field value from the internal data store
80
- *
81
- * @param {string} field - The field name
82
- * @returns {any} The field value
83
- */
84
- getField(field) {
85
- // Access the reactive __version property to establish dependency for vue integration
86
- const trackVersion = this.__version;
87
- const ModelClass = this.constructor;
88
- if (ModelClass.primaryKeyField === field)
89
- return this._pk;
90
- // check local overrides
91
- let value = this._data[field];
92
- // if its not been overridden, get it from the store
93
- if (value === undefined && !isNil(this._pk)) {
94
- let storedValue = modelStoreRegistry.getEntity(ModelClass, this._pk);
95
- if (storedValue)
96
- value = storedValue[field]; // if stops null -> undefined
97
- }
98
- // Use serializer to convert internal format to live format
99
- return this.serializer.toLiveField(field, value);
100
- }
101
- /**
102
- * Sets a field value in the internal data store
103
- *
104
- * @param {string} field - The field name
105
- * @param {any} value - The field value to set
106
- */
107
- setField(field, value) {
108
- const ModelClass = this.constructor;
109
- // Use serializer to convert live format to internal format
110
- const internalValue = this.serializer.toInternalField(field, value);
111
- if (ModelClass.primaryKeyField === field) {
112
- this._pk = internalValue;
113
- }
114
- else {
115
- this._data[field] = internalValue;
116
- }
117
- }
118
- /**
119
- * Validates that the provided data object only contains keys
120
- * defined in the model's allowed fields. Supports nested fields
121
- * using double underscore notation (e.g., author__name).
122
- *
123
- * @param {Object} data - The object to validate.
124
- * @throws {ValidationError} If an unknown key is found.
125
- */
126
- static validateFields(data) {
127
- if (isNil(data))
128
- return;
129
- const allowedFields = this.fields;
130
- for (const key of Object.keys(data)) {
131
- if (key === "repr" || key === "type")
132
- continue;
133
- // Handle nested fields by splitting on double underscore
134
- // and taking just the base field name
135
- const baseField = key.split("__")[0];
136
- if (!allowedFields.includes(baseField)) {
137
- let errorMsg = `Invalid field: ${baseField}. Allowed fields are: ${allowedFields.join(", ")}`;
138
- console.error(errorMsg);
139
- throw new ValidationError(errorMsg);
140
- }
141
- }
142
- }
143
- /**
144
- * Serializes the model instance.
145
- *
146
- * By default, it returns all enumerable own properties.
147
- * Subclasses should override this to return specific keys.
148
- *
149
- * @param {boolean} includeRepr - Whether to include the repr field (for caching). Default: false.
150
- * @returns {Object} The serialized model data.
151
- */
152
- serialize(includeRepr = false) {
153
- const ModelClass = this.constructor;
154
- const data = {};
155
- // Collect all field values (already in internal format)
156
- for (const field of ModelClass.fields) {
157
- if (field === ModelClass.primaryKeyField) {
158
- data[field] = this._pk;
159
- }
160
- else {
161
- let value = this._data[field];
162
- // Get from store if not in local data
163
- if (value === undefined && !isNil(this._pk)) {
164
- const storedData = modelStoreRegistry.getEntity(ModelClass, this._pk);
165
- if (storedData) {
166
- value = storedData[field];
167
- }
168
- }
169
- data[field] = value;
170
- }
171
- }
172
- // Include repr field if requested (for caching purposes)
173
- if (includeRepr && !isNil(this._pk)) {
174
- const storedData = modelStoreRegistry.getEntity(ModelClass, this._pk);
175
- if (storedData && storedData.repr) {
176
- data.repr = storedData.repr;
177
- }
178
- }
179
- // Data is already in internal format, so return as-is for API transmission
180
- return data;
181
- }
182
- /**
183
- * Saves the model instance by either creating a new record or updating an existing one.
184
- *
185
- * @returns {Promise<Model>} A promise that resolves to the updated model instance.
186
- */
187
- async save() {
188
- const ModelClass = this.constructor;
189
- const pkField = ModelClass.primaryKeyField;
190
- const querySet = !this.pk
191
- ? ModelClass.objects.newQuerySet()
192
- : ModelClass.objects.filter({ [pkField]: this.pk });
193
- const data = this.serialize();
194
- let instance;
195
- if (!this.pk) {
196
- // Create new instance
197
- instance = await QueryExecutor.execute(querySet, "create", { data });
198
- }
199
- else {
200
- // Update existing instance
201
- instance = await QueryExecutor.execute(querySet, "update_instance", {
202
- data,
203
- });
204
- }
205
- this._pk = instance.pk;
206
- this._data = {};
207
- return this;
208
- }
209
- /**
210
- * Deletes the instance from the database.
211
- *
212
- * Returns a tuple with the number of objects deleted and an object mapping
213
- * model names to the number of objects deleted, matching Django's behavior.
214
- *
215
- * @returns {Promise<[number, Object]>} A promise that resolves to the deletion result.
216
- * @throws {Error} If the instance has not been saved (no primary key).
217
- */
218
- async delete() {
219
- if (!this.pk) {
220
- throw new Error("Cannot delete unsaved instance");
221
- }
222
- const ModelClass = this.constructor;
223
- const pkField = ModelClass.primaryKeyField;
224
- const querySet = ModelClass.objects.filter({ [pkField]: this.pk });
225
- // Pass the instance data with primary key as the args
226
- const args = { [pkField]: this.pk };
227
- const result = await QueryExecutor.execute(querySet, "delete_instance", args);
228
- // result -> [deletedCount, { [modelName]: deletedCount }];
229
- return result;
230
- }
231
- /**
232
- * Refreshes the model instance with data from the database.
233
- *
234
- * @returns {Promise<void>} A promise that resolves when the instance has been refreshed.
235
- * @throws {Error} If the instance has not been saved (no primary key).
236
- */
237
- async refreshFromDb() {
238
- if (!this.pk) {
239
- throw new Error("Cannot refresh unsaved instance");
240
- }
241
- const ModelClass = this.constructor;
242
- const fresh = await ModelClass.objects.get({
243
- [ModelClass.primaryKeyField]: this.pk,
244
- });
245
- // clear the current data and fresh data will flow
246
- this._data = {};
247
- }
248
- /**
249
- * Validates the model instance using the same serialize behavior as save()
250
- * @param {string} validateType - 'create' or 'update' (defaults to auto-detect)
251
- * @param {boolean} partial - Whether to allow partial validation
252
- * @returns {Promise<boolean>} Promise that resolves to true if valid, throws error if invalid
253
- */
254
- async validate(validateType = null, partial = false) {
255
- const ModelClass = this.constructor;
256
- if (!validateType) {
257
- validateType = this.pk ? "update" : "create";
258
- }
259
- // Validate the validateType parameter
260
- if (!["update", "create"].includes(validateType)) {
261
- throw new Error(`Validation type must be 'update' or 'create', not '${validateType}'`);
262
- }
263
- // Use the same serialize logic as save()
264
- const data = this.serialize();
265
- // Delegate to static method
266
- return ModelClass.validate(data, validateType, partial);
267
- }
268
- /**
269
- * Static method to validate data without creating an instance
270
- * @param {Object} data - Data to validate
271
- * @param {string} validateType - 'create' or 'update'
272
- * @param {boolean} partial - Whether to allow partial validation
273
- * @returns {Promise<boolean>} Promise that resolves to true if valid, throws error if invalid
274
- */
275
- static async validate(data, validateType = "create", partial = false) {
276
- const ModelClass = this;
277
- // Validate the validateType parameter
278
- if (!["update", "create"].includes(validateType)) {
279
- throw new Error(`Validation type must be 'update' or 'create', not '${validateType}'`);
280
- }
281
- // Get backend config and check if it exists
282
- const config = configInstance.getConfig();
283
- const backend = config.backendConfigs[ModelClass.configKey];
284
- if (!backend) {
285
- throw new Error(`No backend configuration found for key: ${ModelClass.configKey}`);
286
- }
287
- // Build URL for validate endpoint
288
- const baseUrl = backend.API_URL.replace(/\/+$/, "");
289
- const url = `${baseUrl}/${ModelClass.modelName}/validate/`;
290
- // Prepare headers
291
- const headers = {
292
- "Content-Type": "application/json",
293
- ...(backend.getAuthHeaders ? backend.getAuthHeaders() : {}),
294
- };
295
- // Make direct API call to validate endpoint
296
- try {
297
- const response = await axios.post(url, {
298
- data: data,
299
- validate_type: validateType,
300
- partial: partial,
301
- }, { headers });
302
- // Backend returns {"valid": true} on success
303
- return response.data.valid === true;
304
- }
305
- catch (error) {
306
- if (error.response && error.response.data) {
307
- const parsedError = parseStateZeroError(error.response.data);
308
- if (Error.captureStackTrace) {
309
- Error.captureStackTrace(parsedError, ModelClass.validate);
310
- }
311
- throw parsedError;
312
- }
313
- throw new Error(`Validation failed: ${error.message}`);
314
- }
315
- }
316
- /**
317
- * Get field permissions for the current user (cached on the class)
318
- * @param {boolean} refresh - Force refresh the cached permissions
319
- * @returns {Promise<{visible_fields: string[], creatable_fields: string[], editable_fields: string[]}>}
320
- */
321
- static async getFieldPermissions(refresh = false) {
322
- const ModelClass = this;
323
- // Return cached permissions if available and not forcing refresh
324
- if (!refresh && ModelClass._fieldPermissionsCache) {
325
- return ModelClass._fieldPermissionsCache;
326
- }
327
- // Get backend config and check if it exists
328
- const config = configInstance.getConfig();
329
- const backend = config.backendConfigs[ModelClass.configKey];
330
- if (!backend) {
331
- throw new Error(`No backend configuration found for key: ${ModelClass.configKey}`);
332
- }
333
- // Build URL for field permissions endpoint
334
- const baseUrl = backend.API_URL.replace(/\/+$/, "");
335
- const url = `${baseUrl}/${ModelClass.modelName}/field-permissions/`;
336
- // Prepare headers
337
- const headers = {
338
- "Content-Type": "application/json",
339
- ...(backend.getAuthHeaders ? backend.getAuthHeaders() : {}),
340
- };
341
- // Make direct API call to field permissions endpoint
342
- try {
343
- const response = await axios.get(url, { headers });
344
- // Cache the permissions on the class
345
- ModelClass._fieldPermissionsCache = response.data;
346
- // Backend returns {visible_fields: [], creatable_fields: [], editable_fields: []}
347
- return response.data;
348
- }
349
- catch (error) {
350
- if (error.response && error.response.data) {
351
- const parsedError = parseStateZeroError(error.response.data);
352
- if (Error.captureStackTrace) {
353
- Error.captureStackTrace(parsedError, ModelClass.getFieldPermissions);
354
- }
355
- throw parsedError;
356
- }
357
- throw new Error(`Failed to get field permissions: ${error.message}`);
358
- }
359
- }
360
- }
361
- /**
362
- * Creates a new Model instance.
363
- *
364
- * @param {any} [data={}] - The data for initialization.
365
- */
366
- Model.instanceCache = new Map();
@@ -1,73 +0,0 @@
1
- /**
2
- * Factory for creating Operation instances with consistent behavior
3
- * across QueryExecutor and hotpath event handling
4
- */
5
- export class OperationFactory {
6
- /**
7
- * Create a CREATE operation
8
- * @param {QuerySet} queryset - The queryset context
9
- * @param {Object} data - The data for the new instance
10
- * @param {string} [operationId] - Optional operation ID (for hotpath events)
11
- * @returns {Operation} The created operation
12
- */
13
- static createCreateOperation(queryset: QuerySet, data?: Object, operationId?: string): Operation;
14
- /**
15
- * Create a BULK_CREATE operation
16
- * @param {QuerySet} queryset - The queryset context
17
- * @param {Array<Object>} dataList - Array of data objects for the new instances
18
- * @param {string} [operationId] - Optional operation ID (for hotpath events)
19
- * @returns {Operation} The created operation
20
- */
21
- static createBulkCreateOperation(queryset: QuerySet, dataList?: Array<Object>, operationId?: string): Operation;
22
- /**
23
- * Create an UPDATE operation with optimistic instance updates
24
- * @param {QuerySet} queryset - The queryset context
25
- * @param {Object} data - The update data
26
- * @param {Object} filter - Optional filter for the update
27
- * @param {string} [operationId] - Optional operation ID (for hotpath events)
28
- * @returns {Operation} The created operation
29
- */
30
- static createUpdateOperation(queryset: QuerySet, data?: Object, filter?: Object, operationId?: string): Operation;
31
- /**
32
- * Create a DELETE operation
33
- * @param {QuerySet} queryset - The queryset context
34
- * @param {string} [operationId] - Optional operation ID (for hotpath events)
35
- * @returns {Operation} The created operation
36
- */
37
- static createDeleteOperation(queryset: QuerySet, operationId?: string): Operation;
38
- /**
39
- * Create an UPDATE_INSTANCE operation
40
- * @param {QuerySet} queryset - The queryset context
41
- * @param {Object} data - The update data
42
- * @param {string} [operationId] - Optional operation ID (for hotpath events)
43
- * @returns {Operation} The created operation
44
- */
45
- static createUpdateInstanceOperation(queryset: QuerySet, data?: Object, operationId?: string): Operation;
46
- /**
47
- * Create a DELETE_INSTANCE operation
48
- * @param {QuerySet} queryset - The queryset context
49
- * @param {Object} instanceData - The instance to delete (object with PK)
50
- * @param {string} [operationId] - Optional operation ID (for hotpath events)
51
- * @returns {Operation} The created operation
52
- */
53
- static createDeleteInstanceOperation(queryset: QuerySet, instanceData: Object, operationId?: string): Operation;
54
- /**
55
- * Create a GET_OR_CREATE operation with local filtering logic
56
- * @param {QuerySet} queryset - The queryset context
57
- * @param {Object} lookup - The lookup criteria
58
- * @param {Object} defaults - The default values for creation
59
- * @param {string} [operationId] - Optional operation ID (for hotpath events)
60
- * @returns {Operation} The created operation
61
- */
62
- static createGetOrCreateOperation(queryset: QuerySet, lookup?: Object, defaults?: Object, operationId?: string): Operation;
63
- /**
64
- * Create an UPDATE_OR_CREATE operation with local filtering logic
65
- * @param {QuerySet} queryset - The queryset context
66
- * @param {Object} lookup - The lookup criteria
67
- * @param {Object} defaults - The default values for creation/update
68
- * @param {string} [operationId] - Optional operation ID (for hotpath events)
69
- * @returns {Operation} The created operation
70
- */
71
- static createUpdateOrCreateOperation(queryset: QuerySet, lookup?: Object, defaults?: Object, operationId?: string): Operation;
72
- }
73
- import { Operation } from '../../syncEngine/stores/operation.js';
@@ -1,248 +0,0 @@
1
- import { Operation, Type, Status } from '../../syncEngine/stores/operation.js';
2
- import { v7 as uuid7 } from 'uuid';
3
- import { createTempPk } from './tempPk.js';
4
- import { getRequiredFields, pickRequiredFields, processQuery } from '../../filtering/localFiltering.js';
5
- import { evaluateExpression } from './f.js';
6
- import { modelStoreRegistry } from '../../syncEngine/registries/modelStoreRegistry.js';
7
- import { querysetStoreRegistry } from '../../syncEngine/registries/querysetStoreRegistry.js';
8
- import { isNil } from 'lodash-es';
9
- /**
10
- * Factory for creating Operation instances with consistent behavior
11
- * across QueryExecutor and hotpath event handling
12
- */
13
- export class OperationFactory {
14
- /**
15
- * Create a CREATE operation
16
- * @param {QuerySet} queryset - The queryset context
17
- * @param {Object} data - The data for the new instance
18
- * @param {string} [operationId] - Optional operation ID (for hotpath events)
19
- * @returns {Operation} The created operation
20
- */
21
- static createCreateOperation(queryset, data = {}, operationId = null) {
22
- const ModelClass = queryset.ModelClass;
23
- const primaryKeyField = ModelClass.primaryKeyField;
24
- const opId = operationId || `${uuid7()}`;
25
- const tempPk = createTempPk(opId);
26
- return new Operation({
27
- operationId: opId,
28
- type: Type.CREATE,
29
- instances: [{ ...data, [primaryKeyField]: tempPk }],
30
- queryset: queryset,
31
- args: { data },
32
- localOnly: queryset._optimisticOnly || false,
33
- });
34
- }
35
- /**
36
- * Create a BULK_CREATE operation
37
- * @param {QuerySet} queryset - The queryset context
38
- * @param {Array<Object>} dataList - Array of data objects for the new instances
39
- * @param {string} [operationId] - Optional operation ID (for hotpath events)
40
- * @returns {Operation} The created operation
41
- */
42
- static createBulkCreateOperation(queryset, dataList = [], operationId = null) {
43
- const ModelClass = queryset.ModelClass;
44
- const primaryKeyField = ModelClass.primaryKeyField;
45
- const opId = operationId || `${uuid7()}`;
46
- // Create temp PKs for each instance
47
- const instances = dataList.map((data, index) => {
48
- const tempPk = createTempPk(`${opId}_${index}`);
49
- return { ...data, [primaryKeyField]: tempPk };
50
- });
51
- return new Operation({
52
- operationId: opId,
53
- type: Type.BULK_CREATE,
54
- instances: instances,
55
- queryset: queryset,
56
- args: { data: dataList },
57
- localOnly: queryset._optimisticOnly || false,
58
- });
59
- }
60
- /**
61
- * Create an UPDATE operation with optimistic instance updates
62
- * @param {QuerySet} queryset - The queryset context
63
- * @param {Object} data - The update data
64
- * @param {Object} filter - Optional filter for the update
65
- * @param {string} [operationId] - Optional operation ID (for hotpath events)
66
- * @returns {Operation} The created operation
67
- */
68
- static createUpdateOperation(queryset, data = {}, filter = null, operationId = null) {
69
- const ModelClass = queryset.ModelClass;
70
- const primaryKeyField = ModelClass.primaryKeyField;
71
- const store = querysetStoreRegistry.getStore(queryset);
72
- const querysetPks = store.render();
73
- const opId = operationId || `${uuid7()}`;
74
- // Create optimistic instances with F expression evaluation
75
- const optimisticInstances = querysetPks.map(pk => {
76
- const instance = modelStoreRegistry.getEntity(ModelClass, pk);
77
- const updatedInstance = { ...instance };
78
- updatedInstance[primaryKeyField] = pk;
79
- for (const [key, value] of Object.entries(data)) {
80
- if (value && typeof value === 'object' && value.__f_expr) {
81
- const evaluatedValue = evaluateExpression(value, instance);
82
- if (evaluatedValue !== null) {
83
- updatedInstance[key] = evaluatedValue;
84
- }
85
- else {
86
- updatedInstance[key] = instance[key];
87
- }
88
- }
89
- else {
90
- updatedInstance[key] = value;
91
- }
92
- }
93
- return updatedInstance;
94
- });
95
- return new Operation({
96
- operationId: opId,
97
- type: Type.UPDATE,
98
- instances: optimisticInstances,
99
- queryset: queryset,
100
- args: { filter, data },
101
- localOnly: queryset._optimisticOnly || false,
102
- });
103
- }
104
- /**
105
- * Create a DELETE operation
106
- * @param {QuerySet} queryset - The queryset context
107
- * @param {string} [operationId] - Optional operation ID (for hotpath events)
108
- * @returns {Operation} The created operation
109
- */
110
- static createDeleteOperation(queryset, operationId = null) {
111
- const ModelClass = queryset.ModelClass;
112
- const primaryKeyField = ModelClass.primaryKeyField;
113
- const store = querysetStoreRegistry.getStore(queryset);
114
- const querysetPks = store.render();
115
- const opId = operationId || `${uuid7()}`;
116
- const instances = querysetPks.map((pk) => ({ [primaryKeyField]: pk }));
117
- return new Operation({
118
- operationId: opId,
119
- type: Type.DELETE,
120
- instances: instances,
121
- queryset: queryset,
122
- args: {},
123
- localOnly: queryset._optimisticOnly || false,
124
- });
125
- }
126
- /**
127
- * Create an UPDATE_INSTANCE operation
128
- * @param {QuerySet} queryset - The queryset context
129
- * @param {Object} data - The update data
130
- * @param {string} [operationId] - Optional operation ID (for hotpath events)
131
- * @returns {Operation} The created operation
132
- */
133
- static createUpdateInstanceOperation(queryset, data = {}, operationId = null) {
134
- const ModelClass = queryset.ModelClass;
135
- const primaryKeyField = ModelClass.primaryKeyField;
136
- const store = querysetStoreRegistry.getStore(queryset);
137
- const querysetPks = store.render();
138
- const opId = operationId || `${uuid7()}`;
139
- const instances = querysetPks.map(pk => ({ ...data, [primaryKeyField]: pk }));
140
- return new Operation({
141
- operationId: opId,
142
- type: Type.UPDATE_INSTANCE,
143
- instances: instances,
144
- queryset: queryset,
145
- args: { data },
146
- localOnly: queryset._optimisticOnly || false,
147
- });
148
- }
149
- /**
150
- * Create a DELETE_INSTANCE operation
151
- * @param {QuerySet} queryset - The queryset context
152
- * @param {Object} instanceData - The instance to delete (object with PK)
153
- * @param {string} [operationId] - Optional operation ID (for hotpath events)
154
- * @returns {Operation} The created operation
155
- */
156
- static createDeleteInstanceOperation(queryset, instanceData, operationId = null) {
157
- const opId = operationId || `${uuid7()}`;
158
- return new Operation({
159
- operationId: opId,
160
- type: Type.DELETE_INSTANCE,
161
- instances: [instanceData],
162
- queryset: queryset,
163
- args: instanceData,
164
- localOnly: queryset._optimisticOnly || false,
165
- });
166
- }
167
- /**
168
- * Create a GET_OR_CREATE operation with local filtering logic
169
- * @param {QuerySet} queryset - The queryset context
170
- * @param {Object} lookup - The lookup criteria
171
- * @param {Object} defaults - The default values for creation
172
- * @param {string} [operationId] - Optional operation ID (for hotpath events)
173
- * @returns {Operation} The created operation
174
- */
175
- static createGetOrCreateOperation(queryset, lookup = {}, defaults = {}, operationId = null) {
176
- const ModelClass = queryset.ModelClass;
177
- const primaryKeyField = ModelClass.primaryKeyField;
178
- const opId = operationId || `${uuid7()}`;
179
- // Get all current instances from the store for local filtering
180
- const modelStore = modelStoreRegistry.getStore(ModelClass);
181
- const allInstances = modelStore.render();
182
- // Create a queryset filter for the lookup criteria
183
- const lookupFilter = { ...lookup };
184
- const lookupQuerySet = new queryset.constructor(ModelClass).filter(lookupFilter);
185
- const lookupQuery = lookupQuerySet.build();
186
- // Use local filtering to find matching instances
187
- const requiredPaths = getRequiredFields(lookupQuery, ModelClass);
188
- const prunedData = allInstances.map(inst => pickRequiredFields(requiredPaths, ModelClass.fromPk(inst[primaryKeyField], queryset)));
189
- const matchingPks = processQuery(prunedData, lookupQuery, ModelClass);
190
- // Find the corresponding instances
191
- const matchingInstances = allInstances.filter(inst => matchingPks.includes(inst[primaryKeyField]));
192
- const isCreatingNew = matchingInstances.length === 0;
193
- const effectiveType = isCreatingNew ? Type.CREATE : Type.UPDATE;
194
- // Create the instance data
195
- const instanceData = isCreatingNew
196
- ? { ...lookup, ...defaults, [primaryKeyField]: opId }
197
- : matchingInstances[0];
198
- return new Operation({
199
- operationId: opId,
200
- type: effectiveType,
201
- instances: [instanceData],
202
- queryset: queryset,
203
- args: { lookup, defaults },
204
- localOnly: queryset._optimisticOnly || false,
205
- });
206
- }
207
- /**
208
- * Create an UPDATE_OR_CREATE operation with local filtering logic
209
- * @param {QuerySet} queryset - The queryset context
210
- * @param {Object} lookup - The lookup criteria
211
- * @param {Object} defaults - The default values for creation/update
212
- * @param {string} [operationId] - Optional operation ID (for hotpath events)
213
- * @returns {Operation} The created operation
214
- */
215
- static createUpdateOrCreateOperation(queryset, lookup = {}, defaults = {}, operationId = null) {
216
- const ModelClass = queryset.ModelClass;
217
- const primaryKeyField = ModelClass.primaryKeyField;
218
- const opId = operationId || `${uuid7()}`;
219
- // Get all current instances from the store for local filtering
220
- const modelStore = modelStoreRegistry.getStore(ModelClass);
221
- const allInstances = modelStore.render();
222
- // Create a queryset filter for the lookup criteria
223
- const lookupFilter = { ...lookup };
224
- const lookupQuerySet = new queryset.constructor(ModelClass).filter(lookupFilter);
225
- const lookupQuery = lookupQuerySet.build();
226
- // Use local filtering to find matching instances
227
- const requiredPaths = getRequiredFields(lookupQuery, ModelClass);
228
- const prunedData = allInstances.map(inst => pickRequiredFields(requiredPaths, ModelClass.fromPk(inst[primaryKeyField], queryset)));
229
- const matchingPks = processQuery(prunedData, lookupQuery, ModelClass);
230
- // Find the corresponding instances
231
- const matchingInstances = allInstances.filter(inst => matchingPks.includes(inst[primaryKeyField]));
232
- const isCreatingNew = matchingInstances.length === 0;
233
- const isUpdating = !isCreatingNew;
234
- const effectiveType = isCreatingNew ? Type.CREATE : Type.UPDATE;
235
- // Create the instance data
236
- const instanceData = isCreatingNew
237
- ? { ...lookup, ...defaults, [primaryKeyField]: opId }
238
- : { ...matchingInstances[0], ...defaults };
239
- return new Operation({
240
- operationId: opId,
241
- type: effectiveType,
242
- instances: [instanceData],
243
- queryset: queryset,
244
- args: { lookup, defaults },
245
- localOnly: queryset._optimisticOnly || false,
246
- });
247
- }
248
- }