@statezero/core 0.2.38 → 0.2.40

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 (294) hide show
  1. package/dist/actions/backend1/django_app/calculate-hash.d.ts +57 -0
  2. package/dist/actions/backend1/django_app/calculate-hash.js +80 -0
  3. package/dist/actions/backend1/django_app/calculate-hash.schema.json +148 -0
  4. package/dist/actions/backend1/django_app/get-current-username.d.ts +29 -0
  5. package/dist/actions/backend1/django_app/get-current-username.js +65 -0
  6. package/dist/actions/backend1/django_app/get-current-username.schema.json +47 -0
  7. package/dist/actions/backend1/django_app/get-server-status.d.ts +38 -0
  8. package/dist/actions/backend1/django_app/get-server-status.js +68 -0
  9. package/dist/actions/backend1/django_app/get-server-status.schema.json +93 -0
  10. package/dist/actions/backend1/django_app/get-user-info.d.ts +44 -0
  11. package/dist/actions/backend1/django_app/get-user-info.js +70 -0
  12. package/dist/actions/backend1/django_app/get-user-info.schema.json +127 -0
  13. package/dist/actions/backend1/django_app/index.d.ts +1 -0
  14. package/dist/actions/backend1/django_app/index.js +6 -0
  15. package/dist/actions/backend1/django_app/process-data.d.ts +51 -0
  16. package/dist/actions/backend1/django_app/process-data.js +78 -0
  17. package/dist/actions/backend1/django_app/process-data.schema.json +117 -0
  18. package/dist/actions/backend1/django_app/send-notification.d.ts +55 -0
  19. package/dist/actions/backend1/django_app/send-notification.js +81 -0
  20. package/dist/actions/backend1/django_app/send-notification.schema.json +175 -0
  21. package/dist/actions/backend1/index.d.ts +1 -0
  22. package/dist/actions/backend1/index.js +1 -0
  23. package/dist/actions/default/django_app/calculate-hash.d.ts +57 -0
  24. package/dist/actions/default/django_app/calculate-hash.js +80 -0
  25. package/dist/actions/default/django_app/calculate-hash.schema.json +148 -0
  26. package/dist/actions/default/django_app/get-current-username.d.ts +29 -0
  27. package/dist/actions/default/django_app/get-current-username.js +65 -0
  28. package/dist/actions/default/django_app/get-current-username.schema.json +47 -0
  29. package/dist/actions/default/django_app/get-server-status.d.ts +38 -0
  30. package/dist/actions/default/django_app/get-server-status.js +68 -0
  31. package/dist/actions/default/django_app/get-server-status.schema.json +93 -0
  32. package/dist/actions/default/django_app/get-user-info.d.ts +44 -0
  33. package/dist/actions/default/django_app/get-user-info.js +70 -0
  34. package/dist/actions/default/django_app/get-user-info.schema.json +127 -0
  35. package/dist/actions/default/django_app/index.d.ts +1 -0
  36. package/dist/actions/default/django_app/index.js +6 -0
  37. package/dist/actions/default/django_app/process-data.d.ts +51 -0
  38. package/dist/actions/default/django_app/process-data.js +78 -0
  39. package/dist/actions/default/django_app/process-data.schema.json +117 -0
  40. package/dist/actions/default/django_app/send-notification.d.ts +55 -0
  41. package/dist/actions/default/django_app/send-notification.js +81 -0
  42. package/dist/actions/default/django_app/send-notification.schema.json +175 -0
  43. package/dist/actions/default/index.d.ts +1 -0
  44. package/dist/actions/default/index.js +1 -0
  45. package/dist/actions/index.d.ts +1 -0
  46. package/dist/actions/index.js +5 -0
  47. package/dist/adaptors/react/composables.d.ts +1 -0
  48. package/dist/adaptors/react/composables.js +4 -0
  49. package/dist/adaptors/react/index.d.ts +1 -0
  50. package/dist/adaptors/react/index.js +1 -0
  51. package/dist/adaptors/vue/components/LayoutRenderer.js +46 -49
  52. package/dist/adaptors/vue/components/defaults/index.d.ts +7 -0
  53. package/dist/adaptors/vue/components/defaults/index.js +31 -0
  54. package/dist/adaptors/vue/components/index.d.ts +1 -0
  55. package/dist/adaptors/vue/components/index.js +7 -0
  56. package/dist/adaptors/vue/composables.d.ts +2 -0
  57. package/dist/adaptors/vue/composables.js +44 -0
  58. package/dist/adaptors/vue/index.d.ts +3 -0
  59. package/dist/adaptors/vue/index.js +4 -0
  60. package/dist/adaptors/vue/reactivity.d.ts +18 -0
  61. package/dist/adaptors/vue/reactivity.js +132 -0
  62. package/dist/cli/commands/sync.d.ts +6 -0
  63. package/dist/cli/commands/sync.js +30 -0
  64. package/dist/cli/commands/syncActions.d.ts +46 -0
  65. package/dist/cli/commands/syncActions.js +717 -0
  66. package/dist/cli/commands/syncModels.d.ts +132 -0
  67. package/dist/cli/commands/syncModels.js +1120 -0
  68. package/dist/cli/configFileLoader.d.ts +10 -0
  69. package/dist/cli/configFileLoader.js +85 -0
  70. package/dist/cli/index.d.ts +2 -0
  71. package/dist/cli/index.js +22 -0
  72. package/dist/config.d.ts +57 -0
  73. package/dist/config.js +273 -0
  74. package/dist/core/eventReceivers.d.ts +185 -0
  75. package/dist/core/eventReceivers.js +266 -0
  76. package/dist/core/utils.d.ts +8 -0
  77. package/dist/core/utils.js +62 -0
  78. package/dist/errorHandler.d.ts +21 -0
  79. package/dist/errorHandler.js +27 -0
  80. package/dist/filtering/localFiltering.d.ts +110 -0
  81. package/dist/filtering/localFiltering.js +1080 -0
  82. package/dist/flavours/django/dates.d.ts +34 -0
  83. package/dist/flavours/django/dates.js +113 -0
  84. package/dist/flavours/django/errors.d.ts +138 -0
  85. package/dist/flavours/django/errors.js +195 -0
  86. package/dist/flavours/django/f.d.ts +6 -0
  87. package/dist/flavours/django/f.js +91 -0
  88. package/dist/flavours/django/files.d.ts +62 -0
  89. package/dist/flavours/django/files.js +355 -0
  90. package/dist/flavours/django/makeApiCall.d.ts +36 -0
  91. package/dist/flavours/django/makeApiCall.js +169 -0
  92. package/dist/flavours/django/manager.d.ts +204 -0
  93. package/dist/flavours/django/manager.js +222 -0
  94. package/dist/flavours/django/model.d.ts +137 -0
  95. package/dist/flavours/django/model.js +366 -0
  96. package/dist/flavours/django/operationFactory.d.ts +73 -0
  97. package/dist/flavours/django/operationFactory.js +248 -0
  98. package/dist/flavours/django/q.d.ts +70 -0
  99. package/dist/flavours/django/q.js +43 -0
  100. package/dist/flavours/django/queryExecutor.d.ts +149 -0
  101. package/dist/flavours/django/queryExecutor.js +590 -0
  102. package/dist/flavours/django/querySet.d.ts +301 -0
  103. package/dist/flavours/django/querySet.js +736 -0
  104. package/dist/flavours/django/serializers.d.ts +39 -0
  105. package/dist/flavours/django/serializers.js +296 -0
  106. package/dist/flavours/django/tempPk.d.ts +31 -0
  107. package/dist/flavours/django/tempPk.js +92 -0
  108. package/dist/flavours/django/utils.d.ts +19 -0
  109. package/dist/flavours/django/utils.js +29 -0
  110. package/dist/index.d.ts +46 -0
  111. package/dist/index.js +48 -0
  112. package/dist/models/backend1/django_app/comprehensivemodel.d.ts +894 -0
  113. package/dist/models/backend1/django_app/comprehensivemodel.js +71 -0
  114. package/dist/models/backend1/django_app/comprehensivemodel.schema.json +870 -0
  115. package/dist/models/backend1/django_app/custompkmodel.d.ts +92 -0
  116. package/dist/models/backend1/django_app/custompkmodel.js +69 -0
  117. package/dist/models/backend1/django_app/custompkmodel.schema.json +71 -0
  118. package/dist/models/backend1/django_app/dailyrate.d.ts +230 -0
  119. package/dist/models/backend1/django_app/dailyrate.js +71 -0
  120. package/dist/models/backend1/django_app/dailyrate.schema.json +212 -0
  121. package/dist/models/backend1/django_app/deepmodellevel1.d.ts +140 -0
  122. package/dist/models/backend1/django_app/deepmodellevel1.js +72 -0
  123. package/dist/models/backend1/django_app/deepmodellevel1.schema.json +114 -0
  124. package/dist/models/backend1/django_app/deepmodellevel2.d.ts +118 -0
  125. package/dist/models/backend1/django_app/deepmodellevel2.js +71 -0
  126. package/dist/models/backend1/django_app/deepmodellevel2.schema.json +92 -0
  127. package/dist/models/backend1/django_app/deepmodellevel3.d.ts +92 -0
  128. package/dist/models/backend1/django_app/deepmodellevel3.js +69 -0
  129. package/dist/models/backend1/django_app/deepmodellevel3.schema.json +69 -0
  130. package/dist/models/backend1/django_app/dummymodel.d.ts +134 -0
  131. package/dist/models/backend1/django_app/dummymodel.js +71 -0
  132. package/dist/models/backend1/django_app/dummymodel.schema.json +109 -0
  133. package/dist/models/backend1/django_app/dummyrelatedmodel.d.ts +92 -0
  134. package/dist/models/backend1/django_app/dummyrelatedmodel.js +69 -0
  135. package/dist/models/backend1/django_app/dummyrelatedmodel.schema.json +69 -0
  136. package/dist/models/backend1/django_app/filetest.d.ts +140 -0
  137. package/dist/models/backend1/django_app/filetest.js +69 -0
  138. package/dist/models/backend1/django_app/filetest.schema.json +111 -0
  139. package/dist/models/backend1/django_app/index.d.ts +1 -0
  140. package/dist/models/backend1/django_app/index.js +21 -0
  141. package/dist/models/backend1/django_app/m2mdepthtestlevel1.d.ts +118 -0
  142. package/dist/models/backend1/django_app/m2mdepthtestlevel1.js +71 -0
  143. package/dist/models/backend1/django_app/m2mdepthtestlevel1.schema.json +94 -0
  144. package/dist/models/backend1/django_app/m2mdepthtestlevel2.d.ts +118 -0
  145. package/dist/models/backend1/django_app/m2mdepthtestlevel2.js +71 -0
  146. package/dist/models/backend1/django_app/m2mdepthtestlevel2.schema.json +94 -0
  147. package/dist/models/backend1/django_app/m2mdepthtestlevel3.d.ts +134 -0
  148. package/dist/models/backend1/django_app/m2mdepthtestlevel3.js +71 -0
  149. package/dist/models/backend1/django_app/m2mdepthtestlevel3.schema.json +112 -0
  150. package/dist/models/backend1/django_app/modelwithcustompkrelation.d.ts +118 -0
  151. package/dist/models/backend1/django_app/modelwithcustompkrelation.js +71 -0
  152. package/dist/models/backend1/django_app/modelwithcustompkrelation.schema.json +93 -0
  153. package/dist/models/backend1/django_app/modelwithrestrictedfields.d.ts +134 -0
  154. package/dist/models/backend1/django_app/modelwithrestrictedfields.js +71 -0
  155. package/dist/models/backend1/django_app/modelwithrestrictedfields.schema.json +111 -0
  156. package/dist/models/backend1/django_app/namefiltercustompkmodel.d.ts +92 -0
  157. package/dist/models/backend1/django_app/namefiltercustompkmodel.js +69 -0
  158. package/dist/models/backend1/django_app/namefiltercustompkmodel.schema.json +71 -0
  159. package/dist/models/backend1/django_app/order.d.ts +220 -0
  160. package/dist/models/backend1/django_app/order.js +71 -0
  161. package/dist/models/backend1/django_app/order.schema.json +203 -0
  162. package/dist/models/backend1/django_app/orderitem.d.ts +172 -0
  163. package/dist/models/backend1/django_app/orderitem.js +72 -0
  164. package/dist/models/backend1/django_app/orderitem.schema.json +149 -0
  165. package/dist/models/backend1/django_app/product.d.ts +254 -0
  166. package/dist/models/backend1/django_app/product.js +71 -0
  167. package/dist/models/backend1/django_app/product.schema.json +277 -0
  168. package/dist/models/backend1/django_app/productcategory.d.ts +92 -0
  169. package/dist/models/backend1/django_app/productcategory.js +69 -0
  170. package/dist/models/backend1/django_app/productcategory.schema.json +70 -0
  171. package/dist/models/backend1/django_app/rateplan.d.ts +92 -0
  172. package/dist/models/backend1/django_app/rateplan.js +69 -0
  173. package/dist/models/backend1/django_app/rateplan.schema.json +70 -0
  174. package/dist/models/backend1/django_app/restrictedfieldrelatedmodel.d.ts +108 -0
  175. package/dist/models/backend1/django_app/restrictedfieldrelatedmodel.js +69 -0
  176. package/dist/models/backend1/django_app/restrictedfieldrelatedmodel.schema.json +87 -0
  177. package/dist/models/backend1/fileobject.d.ts +4 -0
  178. package/dist/models/backend1/fileobject.js +9 -0
  179. package/dist/models/backend1/index.d.ts +2 -0
  180. package/dist/models/backend1/index.js +2 -0
  181. package/dist/models/default/django_app/comprehensivemodel.d.ts +894 -0
  182. package/dist/models/default/django_app/comprehensivemodel.js +71 -0
  183. package/dist/models/default/django_app/comprehensivemodel.schema.json +870 -0
  184. package/dist/models/default/django_app/custompkmodel.d.ts +92 -0
  185. package/dist/models/default/django_app/custompkmodel.js +69 -0
  186. package/dist/models/default/django_app/custompkmodel.schema.json +71 -0
  187. package/dist/models/default/django_app/dailyrate.d.ts +230 -0
  188. package/dist/models/default/django_app/dailyrate.js +71 -0
  189. package/dist/models/default/django_app/dailyrate.schema.json +212 -0
  190. package/dist/models/default/django_app/deepmodellevel1.d.ts +128 -0
  191. package/dist/models/default/django_app/deepmodellevel1.js +72 -0
  192. package/dist/models/default/django_app/deepmodellevel1.schema.json +102 -0
  193. package/dist/models/default/django_app/deepmodellevel2.d.ts +106 -0
  194. package/dist/models/default/django_app/deepmodellevel2.js +71 -0
  195. package/dist/models/default/django_app/deepmodellevel2.schema.json +80 -0
  196. package/dist/models/default/django_app/deepmodellevel3.d.ts +80 -0
  197. package/dist/models/default/django_app/deepmodellevel3.js +69 -0
  198. package/dist/models/default/django_app/deepmodellevel3.schema.json +57 -0
  199. package/dist/models/default/django_app/dummymodel.d.ts +122 -0
  200. package/dist/models/default/django_app/dummymodel.js +71 -0
  201. package/dist/models/default/django_app/dummymodel.schema.json +97 -0
  202. package/dist/models/default/django_app/dummyrelatedmodel.d.ts +80 -0
  203. package/dist/models/default/django_app/dummyrelatedmodel.js +69 -0
  204. package/dist/models/default/django_app/dummyrelatedmodel.schema.json +57 -0
  205. package/dist/models/default/django_app/filetest.d.ts +128 -0
  206. package/dist/models/default/django_app/filetest.js +69 -0
  207. package/dist/models/default/django_app/filetest.schema.json +99 -0
  208. package/dist/models/default/django_app/index.d.ts +1 -0
  209. package/dist/models/default/django_app/index.js +21 -0
  210. package/dist/models/default/django_app/m2mdepthtestlevel1.d.ts +118 -0
  211. package/dist/models/default/django_app/m2mdepthtestlevel1.js +71 -0
  212. package/dist/models/default/django_app/m2mdepthtestlevel1.schema.json +94 -0
  213. package/dist/models/default/django_app/m2mdepthtestlevel2.d.ts +118 -0
  214. package/dist/models/default/django_app/m2mdepthtestlevel2.js +71 -0
  215. package/dist/models/default/django_app/m2mdepthtestlevel2.schema.json +94 -0
  216. package/dist/models/default/django_app/m2mdepthtestlevel3.d.ts +134 -0
  217. package/dist/models/default/django_app/m2mdepthtestlevel3.js +71 -0
  218. package/dist/models/default/django_app/m2mdepthtestlevel3.schema.json +112 -0
  219. package/dist/models/default/django_app/modelwithcustompkrelation.d.ts +118 -0
  220. package/dist/models/default/django_app/modelwithcustompkrelation.js +71 -0
  221. package/dist/models/default/django_app/modelwithcustompkrelation.schema.json +93 -0
  222. package/dist/models/default/django_app/modelwithrestrictedfields.d.ts +134 -0
  223. package/dist/models/default/django_app/modelwithrestrictedfields.js +71 -0
  224. package/dist/models/default/django_app/modelwithrestrictedfields.schema.json +111 -0
  225. package/dist/models/default/django_app/namefiltercustompkmodel.d.ts +92 -0
  226. package/dist/models/default/django_app/namefiltercustompkmodel.js +69 -0
  227. package/dist/models/default/django_app/namefiltercustompkmodel.schema.json +71 -0
  228. package/dist/models/default/django_app/order.d.ts +220 -0
  229. package/dist/models/default/django_app/order.js +71 -0
  230. package/dist/models/default/django_app/order.schema.json +203 -0
  231. package/dist/models/default/django_app/orderitem.d.ts +172 -0
  232. package/dist/models/default/django_app/orderitem.js +72 -0
  233. package/dist/models/default/django_app/orderitem.schema.json +149 -0
  234. package/dist/models/default/django_app/product.d.ts +254 -0
  235. package/dist/models/default/django_app/product.js +71 -0
  236. package/dist/models/default/django_app/product.schema.json +277 -0
  237. package/dist/models/default/django_app/productcategory.d.ts +92 -0
  238. package/dist/models/default/django_app/productcategory.js +69 -0
  239. package/dist/models/default/django_app/productcategory.schema.json +70 -0
  240. package/dist/models/default/django_app/rateplan.d.ts +92 -0
  241. package/dist/models/default/django_app/rateplan.js +69 -0
  242. package/dist/models/default/django_app/rateplan.schema.json +70 -0
  243. package/dist/models/default/django_app/restrictedfieldrelatedmodel.d.ts +108 -0
  244. package/dist/models/default/django_app/restrictedfieldrelatedmodel.js +69 -0
  245. package/dist/models/default/django_app/restrictedfieldrelatedmodel.schema.json +87 -0
  246. package/dist/models/default/fileobject.d.ts +4 -0
  247. package/dist/models/default/fileobject.js +9 -0
  248. package/dist/models/default/index.d.ts +2 -0
  249. package/dist/models/default/index.js +2 -0
  250. package/dist/models/index.d.ts +1 -0
  251. package/dist/models/index.js +5 -0
  252. package/dist/react-entry.d.ts +2 -0
  253. package/dist/react-entry.js +2 -0
  254. package/dist/reactiveAdaptor.d.ts +24 -0
  255. package/dist/reactiveAdaptor.js +38 -0
  256. package/dist/reset.d.ts +15 -0
  257. package/dist/reset.js +97 -0
  258. package/dist/setup.d.ts +15 -0
  259. package/dist/setup.js +33 -0
  260. package/dist/syncEngine/cache/cache.d.ts +75 -0
  261. package/dist/syncEngine/cache/cache.js +355 -0
  262. package/dist/syncEngine/metrics/metricOptCalcs.d.ts +79 -0
  263. package/dist/syncEngine/metrics/metricOptCalcs.js +284 -0
  264. package/dist/syncEngine/registries/metricRegistry.d.ts +58 -0
  265. package/dist/syncEngine/registries/metricRegistry.js +171 -0
  266. package/dist/syncEngine/registries/modelStoreRegistry.d.ts +11 -0
  267. package/dist/syncEngine/registries/modelStoreRegistry.js +63 -0
  268. package/dist/syncEngine/registries/querysetStoreGraph.d.ts +41 -0
  269. package/dist/syncEngine/registries/querysetStoreGraph.js +174 -0
  270. package/dist/syncEngine/registries/querysetStoreRegistry.d.ts +72 -0
  271. package/dist/syncEngine/registries/querysetStoreRegistry.js +335 -0
  272. package/dist/syncEngine/stores/metricStore.d.ts +55 -0
  273. package/dist/syncEngine/stores/metricStore.js +222 -0
  274. package/dist/syncEngine/stores/modelStore.d.ts +53 -0
  275. package/dist/syncEngine/stores/modelStore.js +565 -0
  276. package/dist/syncEngine/stores/operation.d.ts +139 -0
  277. package/dist/syncEngine/stores/operation.js +291 -0
  278. package/dist/syncEngine/stores/operationEventHandlers.d.ts +8 -0
  279. package/dist/syncEngine/stores/operationEventHandlers.js +348 -0
  280. package/dist/syncEngine/stores/querysetStore.d.ts +60 -0
  281. package/dist/syncEngine/stores/querysetStore.js +294 -0
  282. package/dist/syncEngine/stores/reactivity.d.ts +3 -0
  283. package/dist/syncEngine/stores/reactivity.js +4 -0
  284. package/dist/syncEngine/stores/utils.d.ts +14 -0
  285. package/dist/syncEngine/stores/utils.js +32 -0
  286. package/dist/syncEngine/sync.d.ts +51 -0
  287. package/dist/syncEngine/sync.js +419 -0
  288. package/dist/testing.d.ts +63 -0
  289. package/dist/testing.js +175 -0
  290. package/dist/vue-entry.d.ts +15 -0
  291. package/dist/vue-entry.js +7 -0
  292. package/package.json +6 -7
  293. package/dist/adaptors/vue/components/layout.tailwind.css +0 -51
  294. /package/{dist → src}/adaptors/vue/components/layout.css +0 -0
@@ -0,0 +1,348 @@
1
+ import { operationEvents, Status, Type, operationRegistry, OperationMembership } from './operation.js';
2
+ import { modelStoreRegistry } from '../registries/modelStoreRegistry.js';
3
+ import { querysetStoreRegistry } from '../registries/querysetStoreRegistry.js';
4
+ import { metricRegistry } from '../registries/metricRegistry.js';
5
+ import { getFingerprint } from './utils.js';
6
+ import { QuerySet } from '../../flavours/django/querySet.js';
7
+ import { isEqual, isNil } from 'lodash-es';
8
+ import hash from 'object-hash';
9
+ import { filter, applyOrderBy } from '../../filtering/localFiltering.js';
10
+ /**
11
+ * Evaluates and routes a CREATE operation to querysets, tracking membership state.
12
+ *
13
+ * For each queryset:
14
+ * - If offset > 0: mark as MAYBE (can't determine position based on slicing)
15
+ * - If item doesn't match filter: mark DEFINITELY_NO
16
+ * - If item matches filter AND (no limit OR count < limit): mark DEFINITELY_YES
17
+ * - If item matches filter AND count >= limit: mark MAYBE (ordering determines inclusion)
18
+ *
19
+ * @param {Operation} operation - The CREATE operation to route
20
+ * @param {Function} applyAction - Function to apply the operation to a store
21
+ */
22
+ function routeCreateOperation(operation, applyAction) {
23
+ const modelClass = operation.queryset.ModelClass;
24
+ const instances = operation.instances;
25
+ Array.from(querysetStoreRegistry._stores.entries()).forEach(([semanticKey, store]) => {
26
+ if (store.modelClass !== modelClass)
27
+ return;
28
+ const serializerOptions = store.queryset?._serializerOptions || {};
29
+ const { offset, limit } = serializerOptions;
30
+ // Offset > 0: can't determine position based on slicing
31
+ if (offset != null && offset > 0) {
32
+ operationRegistry.setQuerysetState(operation.operationId, semanticKey, OperationMembership.MAYBE);
33
+ return;
34
+ }
35
+ // Evaluate if instances match this queryset's filter
36
+ const ast = store.queryset.build();
37
+ const matchingInstances = filter(instances, ast, modelClass, true);
38
+ if (matchingInstances.length === 0) {
39
+ // No instances match - mark DEFINITELY_NO (no need to sync this queryset)
40
+ operationRegistry.setQuerysetState(operation.operationId, semanticKey, OperationMembership.DEFINITELY_NO);
41
+ return;
42
+ }
43
+ // Item matches filter - check limit
44
+ if (limit != null) {
45
+ const currentCount = store.groundTruthPks?.length || 0;
46
+ // At capacity: check if ordering could affect position
47
+ if (currentCount >= limit) {
48
+ // Check explicit ordering on queryset OR implicit ordering from Django Meta
49
+ const hasExplicitOrdering = store.queryset._orderBy && store.queryset._orderBy.length > 0;
50
+ const hasImplicitOrdering = (modelClass.schema?.default_ordering?.length || 0) > 0;
51
+ if (hasExplicitOrdering || hasImplicitOrdering) {
52
+ // Use local sorting to determine if new items would be in top N
53
+ const orderBy = hasExplicitOrdering
54
+ ? store.queryset._orderBy
55
+ : modelClass.schema.default_ordering;
56
+ // Get current items from model store
57
+ const modelStore = modelStoreRegistry.getStore(modelClass);
58
+ const renderedItems = modelStore.render(store.groundTruthPks, true, false) || [];
59
+ const currentItems = renderedItems.filter(Boolean);
60
+ // If some ground truth items couldn't be rendered, we can't trust local sort
61
+ if (currentItems.length < store.groundTruthPks.length) {
62
+ operationRegistry.setQuerysetState(operation.operationId, semanticKey, OperationMembership.MAYBE);
63
+ return;
64
+ }
65
+ const allItems = [...currentItems, ...matchingInstances];
66
+ // Sort and take top N
67
+ const sorted = applyOrderBy(allItems, orderBy, modelClass);
68
+ const topN = sorted.slice(0, limit);
69
+ const topNPks = new Set(topN.map(item => item[modelClass.primaryKeyField]));
70
+ // Check if any new items made it into the top N
71
+ const newItemPks = matchingInstances.map(item => item[modelClass.primaryKeyField]);
72
+ const anyInTopN = newItemPks.some(pk => topNPks.has(pk));
73
+ if (anyInTopN) {
74
+ applyAction(store);
75
+ operationRegistry.setQuerysetState(operation.operationId, semanticKey, OperationMembership.DEFINITELY_YES);
76
+ }
77
+ else {
78
+ operationRegistry.setQuerysetState(operation.operationId, semanticKey, OperationMembership.DEFINITELY_NO);
79
+ }
80
+ }
81
+ else {
82
+ // No ordering - new items go at end, won't be in first N
83
+ operationRegistry.setQuerysetState(operation.operationId, semanticKey, OperationMembership.DEFINITELY_NO);
84
+ }
85
+ return;
86
+ }
87
+ // Room for some or all items - continue to DEFINITELY_YES below
88
+ }
89
+ // Matches filter, has room or no limit - DEFINITELY_YES
90
+ applyAction(store);
91
+ operationRegistry.setQuerysetState(operation.operationId, semanticKey, OperationMembership.DEFINITELY_YES);
92
+ });
93
+ }
94
+ /**
95
+ * Evaluates and tracks membership state for UPDATE operations.
96
+ *
97
+ * For UPDATE, we check filter FIRST (optimization), then offset:
98
+ * - If item didn't match before AND doesn't match after: DEFINITELY_NO (regardless of offset)
99
+ * - If item matched before OR matches after AND offset > 0: MAYBE (can't determine position)
100
+ * - If item matched before OR matches after AND offset = 0: DEFINITELY_YES
101
+ *
102
+ * @param {Operation} operation - The UPDATE operation
103
+ */
104
+ function routeUpdateOperation(operation) {
105
+ const modelClass = operation.queryset.ModelClass;
106
+ const beforeInstances = operation.frozenInstances;
107
+ const afterInstances = operation.instances;
108
+ Array.from(querysetStoreRegistry._stores.entries()).forEach(([semanticKey, store]) => {
109
+ if (store.modelClass !== modelClass)
110
+ return;
111
+ // Check filter match FIRST (optimization: skip offset check if no match)
112
+ const ast = store.queryset.build();
113
+ const matchedBefore = filter(beforeInstances, ast, modelClass, false).length > 0;
114
+ const matchesAfter = filter(afterInstances, ast, modelClass, false).length > 0;
115
+ // If item never matched filter, definitely not affected (regardless of offset)
116
+ if (!matchedBefore && !matchesAfter) {
117
+ operationRegistry.setQuerysetState(operation.operationId, semanticKey, OperationMembership.DEFINITELY_NO);
118
+ return;
119
+ }
120
+ // Item matches filter - now check offset
121
+ const serializerOptions = store.queryset?._serializerOptions || {};
122
+ const { offset } = serializerOptions;
123
+ if (offset != null && offset > 0) {
124
+ // Can't determine position in paginated window
125
+ operationRegistry.setQuerysetState(operation.operationId, semanticKey, OperationMembership.MAYBE);
126
+ return;
127
+ }
128
+ // Item matched before OR matches after, no offset - definitely affected
129
+ operationRegistry.setQuerysetState(operation.operationId, semanticKey, OperationMembership.DEFINITELY_YES);
130
+ });
131
+ }
132
+ /**
133
+ * Evaluates and tracks membership state for DELETE operations.
134
+ *
135
+ * For DELETE, we check filter FIRST (optimization), then offset:
136
+ * - If item didn't match before: DEFINITELY_NO (regardless of offset)
137
+ * - If item matched before AND offset > 0: MAYBE (can't determine position)
138
+ * - If item matched before AND offset = 0: DEFINITELY_YES
139
+ *
140
+ * @param {Operation} operation - The DELETE operation
141
+ */
142
+ function routeDeleteOperation(operation) {
143
+ const modelClass = operation.queryset.ModelClass;
144
+ const beforeInstances = operation.frozenInstances;
145
+ Array.from(querysetStoreRegistry._stores.entries()).forEach(([semanticKey, store]) => {
146
+ if (store.modelClass !== modelClass)
147
+ return;
148
+ // Check filter match FIRST (optimization: skip offset check if no match)
149
+ const ast = store.queryset.build();
150
+ const matchedBefore = filter(beforeInstances, ast, modelClass, false).length > 0;
151
+ // If item never matched filter, definitely not affected (regardless of offset)
152
+ if (!matchedBefore) {
153
+ operationRegistry.setQuerysetState(operation.operationId, semanticKey, OperationMembership.DEFINITELY_NO);
154
+ return;
155
+ }
156
+ // Item matched filter - now check offset
157
+ const serializerOptions = store.queryset?._serializerOptions || {};
158
+ const { offset } = serializerOptions;
159
+ if (offset != null && offset > 0) {
160
+ // Can't determine position in paginated window
161
+ operationRegistry.setQuerysetState(operation.operationId, semanticKey, OperationMembership.MAYBE);
162
+ return;
163
+ }
164
+ // Item matched before, no offset - definitely affected
165
+ operationRegistry.setQuerysetState(operation.operationId, semanticKey, OperationMembership.DEFINITELY_YES);
166
+ });
167
+ }
168
+ /**
169
+ * Process an operation in the model store
170
+ *
171
+ * @param {Operation} operation - The operation to process
172
+ * @param {string} actionType - The action to perform ('add', 'update', 'confirm', 'reject')
173
+ */
174
+ function processModelStore(operation, actionType) {
175
+ const ModelClass = operation.queryset.ModelClass;
176
+ const modelStore = modelStoreRegistry.getStore(ModelClass);
177
+ if (!modelStore)
178
+ return;
179
+ switch (actionType) {
180
+ case 'add':
181
+ modelStore.addOperation(operation);
182
+ break;
183
+ case 'update':
184
+ modelStore.updateOperation(operation);
185
+ break;
186
+ case 'confirm':
187
+ modelStore.confirm(operation);
188
+ break;
189
+ case 'reject':
190
+ modelStore.reject(operation);
191
+ break;
192
+ }
193
+ }
194
+ /**
195
+ * Process an operation in the queryset stores based on operation type
196
+ * Uses different routing strategies based on the operation type
197
+ *
198
+ * @param {Operation} operation - The operation to process
199
+ * @param {string} actionType - The action to perform ('add', 'update', 'confirm', 'reject')
200
+ */
201
+ function processQuerysetStores(operation, actionType) {
202
+ const ModelClass = operation.queryset.ModelClass;
203
+ const queryset = operation.queryset;
204
+ // Apply the appropriate action to a single queryset store
205
+ const applyAction = (store) => {
206
+ switch (actionType) {
207
+ case 'add':
208
+ store.addOperation(operation);
209
+ break;
210
+ case 'update':
211
+ store.updateOperation(operation);
212
+ break;
213
+ case 'confirm':
214
+ store.confirm(operation);
215
+ break;
216
+ case 'reject':
217
+ store.reject(operation);
218
+ break;
219
+ }
220
+ };
221
+ let querysetStoreMap;
222
+ // Route to querysets based on operation type
223
+ // All operation types track membership state for sync optimization
224
+ // CREATE: adds operation to store + tracks membership
225
+ // UPDATE/DELETE: only tracks membership (model store + reactivity handles rendering)
226
+ switch (operation.type) {
227
+ case Type.CREATE:
228
+ case Type.BULK_CREATE:
229
+ case Type.GET_OR_CREATE:
230
+ case Type.UPDATE_OR_CREATE:
231
+ // For creates, evaluate each queryset and track membership state
232
+ // This allows us to skip syncing querysets that we know don't contain the item
233
+ routeCreateOperation(operation, applyAction);
234
+ return;
235
+ case Type.UPDATE:
236
+ case Type.UPDATE_INSTANCE:
237
+ // Track membership for sync optimization
238
+ // Check both before (frozenInstances) and after (instances) state
239
+ routeUpdateOperation(operation);
240
+ return;
241
+ case Type.DELETE:
242
+ case Type.DELETE_INSTANCE:
243
+ // Track membership for sync optimization
244
+ // Check before state only (item being deleted)
245
+ routeDeleteOperation(operation);
246
+ return;
247
+ case Type.CHECKPOINT:
248
+ // Model store handles the change, querysets re-render via local filtering
249
+ // No membership tracking needed for checkpoints
250
+ return;
251
+ default:
252
+ // For other operation types, route like creates
253
+ routeCreateOperation(operation, applyAction);
254
+ return;
255
+ }
256
+ }
257
+ /**
258
+ * Process an operation in the metric stores
259
+ *
260
+ * For metrics, we route operations UP the family tree - any metric on an ancestor
261
+ * queryset should receive the operation so it can check if it affects the metric.
262
+ *
263
+ * @param {Operation} operation - The operation to process
264
+ * @param {string} actionType - The action to perform ('add', 'update', 'confirm', 'reject')
265
+ */
266
+ function processMetricStores(operation, actionType) {
267
+ const queryset = operation.queryset;
268
+ const allMetricStores = new Set();
269
+ // Walk up the queryset family tree and collect all metrics
270
+ let current = queryset;
271
+ while (current) {
272
+ const stores = metricRegistry.getAllStoresForQueryset(current);
273
+ if (stores && stores.length > 0) {
274
+ stores.forEach(store => allMetricStores.add(store));
275
+ }
276
+ current = current.__parent;
277
+ }
278
+ if (allMetricStores.size === 0) {
279
+ return;
280
+ }
281
+ // Apply the action to each matching metric store
282
+ allMetricStores.forEach(store => {
283
+ switch (actionType) {
284
+ case 'add':
285
+ store.addOperation(operation);
286
+ break;
287
+ case 'update':
288
+ store.updateOperation(operation);
289
+ break;
290
+ case 'confirm':
291
+ store.confirm(operation);
292
+ break;
293
+ case 'reject':
294
+ store.reject(operation);
295
+ break;
296
+ }
297
+ });
298
+ }
299
+ /**
300
+ * Common processing logic for operations, handling validation and routing
301
+ * to the appropriate store processors
302
+ *
303
+ * @param {Operation} operation - The operation to process
304
+ * @param {string} actionType - The action to perform ('add', 'update', 'confirm', 'reject')
305
+ */
306
+ function processOperation(operation, actionType) {
307
+ if (!operation || !operation.queryset || !operation.queryset.ModelClass) {
308
+ console.warn(`Received invalid operation in processOperation (${actionType})`, operation);
309
+ return;
310
+ }
311
+ if (operation.doNotPropagate) {
312
+ return;
313
+ }
314
+ // Process model store first
315
+ processModelStore(operation, actionType);
316
+ // Then process queryset stores with improved routing
317
+ processQuerysetStores(operation, actionType);
318
+ // Finally process metric stores
319
+ processMetricStores(operation, actionType);
320
+ }
321
+ // Define handlers as named arrow functions at the top level
322
+ const handleOperationCreated = operation => processOperation(operation, 'add');
323
+ const handleOperationUpdated = operation => processOperation(operation, 'update');
324
+ const handleOperationMutated = operation => processOperation(operation, 'update');
325
+ const handleOperationConfirmed = operation => processOperation(operation, 'confirm');
326
+ const handleOperationRejected = operation => processOperation(operation, 'reject');
327
+ /**
328
+ * Initialize the operation event handler system by setting up event listeners
329
+ */
330
+ export function initEventHandler() {
331
+ operationEvents.on(Status.CREATED, handleOperationCreated);
332
+ operationEvents.on(Status.UPDATED, handleOperationUpdated);
333
+ operationEvents.on(Status.CONFIRMED, handleOperationConfirmed);
334
+ operationEvents.on(Status.REJECTED, handleOperationRejected);
335
+ operationEvents.on(Status.MUTATED, handleOperationMutated);
336
+ console.log('Operation event handler initialized');
337
+ }
338
+ /**
339
+ * Clean up by removing all event listeners
340
+ */
341
+ export function cleanupEventHandler() {
342
+ operationEvents.off(Status.CREATED, handleOperationCreated);
343
+ operationEvents.off(Status.UPDATED, handleOperationUpdated);
344
+ operationEvents.off(Status.CONFIRMED, handleOperationConfirmed);
345
+ operationEvents.off(Status.REJECTED, handleOperationRejected);
346
+ operationEvents.off(Status.MUTATED, handleOperationMutated);
347
+ console.log('Operation event handler cleaned up');
348
+ }
@@ -0,0 +1,60 @@
1
+ export class QuerysetStore {
2
+ constructor(modelClass: any, fetchFn: any, queryset: any, initialGroundTruthPks?: null, initialOperations?: null, options?: {});
3
+ modelClass: any;
4
+ fetchFn: any;
5
+ queryset: any;
6
+ operationsMap: Map<any, any>;
7
+ groundTruthPks: never[];
8
+ isSyncing: boolean;
9
+ lastSync: number | null;
10
+ isTemp: any;
11
+ pruneThreshold: any;
12
+ includedPks: Map<any, any>;
13
+ qsCache: Cache;
14
+ _lastRenderedPks: any[] | null;
15
+ renderCallbacks: Set<any>;
16
+ _modelStoreUnregister: any;
17
+ get cacheKey(): any;
18
+ onHydrated(hydratedData: any): void;
19
+ setCache(result: any): void;
20
+ clearCache(): void;
21
+ get operations(): any[];
22
+ get pkField(): any;
23
+ get groundTruthSet(): Set<never>;
24
+ _emitRenderEvent(): void;
25
+ addOperation(operation: any): Promise<void>;
26
+ updateOperation(operation: any): Promise<true | undefined>;
27
+ confirm(operation: any): Promise<void>;
28
+ reject(operation: any): Promise<void>;
29
+ setGroundTruth(groundTruthPks: any): Promise<void>;
30
+ setOperations(operations: any): Promise<void>;
31
+ getTrimmedOperations(): any[];
32
+ getInflightOperations(): any[];
33
+ prune(): void;
34
+ registerRenderCallback(callback: any): () => boolean;
35
+ /**
36
+ * Register this store with the model store for change notifications.
37
+ * Called when a temp store is promoted to permanent.
38
+ */
39
+ registerWithModelStore(): void;
40
+ /**
41
+ * Helper to validate PKs against the model store and apply local filtering/sorting.
42
+ * This is the core of the rendering logic.
43
+ * @private
44
+ */
45
+ private _getValidatedAndFilteredPks;
46
+ render(optimistic?: boolean, fromCache?: boolean): any[];
47
+ renderFromData(optimistic?: boolean): any[];
48
+ /**
49
+ * Render by getting all instances from the model store and filtering locally.
50
+ * Used when a queryset has no ground truth (temp stores, newly created stores, etc.)
51
+ */
52
+ renderFromModelStore(): any[];
53
+ applyOperation(operation: any, currentPks: any): any;
54
+ /**
55
+ * Sync this queryset with the database.
56
+ * Fetches from DB and sets ground truth.
57
+ */
58
+ sync(): Promise<void>;
59
+ }
60
+ import { Cache } from '../cache/cache.js';