@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.
- package/dist/actions/backend1/django_app/calculate-hash.d.ts +57 -0
- package/dist/actions/backend1/django_app/calculate-hash.js +80 -0
- package/dist/actions/backend1/django_app/calculate-hash.schema.json +148 -0
- package/dist/actions/backend1/django_app/get-current-username.d.ts +29 -0
- package/dist/actions/backend1/django_app/get-current-username.js +65 -0
- package/dist/actions/backend1/django_app/get-current-username.schema.json +47 -0
- package/dist/actions/backend1/django_app/get-server-status.d.ts +38 -0
- package/dist/actions/backend1/django_app/get-server-status.js +68 -0
- package/dist/actions/backend1/django_app/get-server-status.schema.json +93 -0
- package/dist/actions/backend1/django_app/get-user-info.d.ts +44 -0
- package/dist/actions/backend1/django_app/get-user-info.js +70 -0
- package/dist/actions/backend1/django_app/get-user-info.schema.json +127 -0
- package/dist/actions/backend1/django_app/index.d.ts +1 -0
- package/dist/actions/backend1/django_app/index.js +6 -0
- package/dist/actions/backend1/django_app/process-data.d.ts +51 -0
- package/dist/actions/backend1/django_app/process-data.js +78 -0
- package/dist/actions/backend1/django_app/process-data.schema.json +117 -0
- package/dist/actions/backend1/django_app/send-notification.d.ts +55 -0
- package/dist/actions/backend1/django_app/send-notification.js +81 -0
- package/dist/actions/backend1/django_app/send-notification.schema.json +175 -0
- package/dist/actions/backend1/index.d.ts +1 -0
- package/dist/actions/backend1/index.js +1 -0
- package/dist/actions/default/django_app/calculate-hash.d.ts +57 -0
- package/dist/actions/default/django_app/calculate-hash.js +80 -0
- package/dist/actions/default/django_app/calculate-hash.schema.json +148 -0
- package/dist/actions/default/django_app/get-current-username.d.ts +29 -0
- package/dist/actions/default/django_app/get-current-username.js +65 -0
- package/dist/actions/default/django_app/get-current-username.schema.json +47 -0
- package/dist/actions/default/django_app/get-server-status.d.ts +38 -0
- package/dist/actions/default/django_app/get-server-status.js +68 -0
- package/dist/actions/default/django_app/get-server-status.schema.json +93 -0
- package/dist/actions/default/django_app/get-user-info.d.ts +44 -0
- package/dist/actions/default/django_app/get-user-info.js +70 -0
- package/dist/actions/default/django_app/get-user-info.schema.json +127 -0
- package/dist/actions/default/django_app/index.d.ts +1 -0
- package/dist/actions/default/django_app/index.js +6 -0
- package/dist/actions/default/django_app/process-data.d.ts +51 -0
- package/dist/actions/default/django_app/process-data.js +78 -0
- package/dist/actions/default/django_app/process-data.schema.json +117 -0
- package/dist/actions/default/django_app/send-notification.d.ts +55 -0
- package/dist/actions/default/django_app/send-notification.js +81 -0
- package/dist/actions/default/django_app/send-notification.schema.json +175 -0
- package/dist/actions/default/index.d.ts +1 -0
- package/dist/actions/default/index.js +1 -0
- package/dist/actions/index.d.ts +1 -0
- package/dist/actions/index.js +5 -0
- package/dist/adaptors/react/composables.d.ts +1 -0
- package/dist/adaptors/react/composables.js +4 -0
- package/dist/adaptors/react/index.d.ts +1 -0
- package/dist/adaptors/react/index.js +1 -0
- package/dist/adaptors/vue/components/LayoutRenderer.js +46 -49
- package/dist/adaptors/vue/components/defaults/index.d.ts +7 -0
- package/dist/adaptors/vue/components/defaults/index.js +31 -0
- package/dist/adaptors/vue/components/index.d.ts +1 -0
- package/dist/adaptors/vue/components/index.js +7 -0
- package/dist/adaptors/vue/composables.d.ts +2 -0
- package/dist/adaptors/vue/composables.js +44 -0
- package/dist/adaptors/vue/index.d.ts +3 -0
- package/dist/adaptors/vue/index.js +4 -0
- package/dist/adaptors/vue/reactivity.d.ts +18 -0
- package/dist/adaptors/vue/reactivity.js +132 -0
- package/dist/cli/commands/sync.d.ts +6 -0
- package/dist/cli/commands/sync.js +30 -0
- package/dist/cli/commands/syncActions.d.ts +46 -0
- package/dist/cli/commands/syncActions.js +717 -0
- package/dist/cli/commands/syncModels.d.ts +132 -0
- package/dist/cli/commands/syncModels.js +1120 -0
- package/dist/cli/configFileLoader.d.ts +10 -0
- package/dist/cli/configFileLoader.js +85 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +22 -0
- package/dist/config.d.ts +57 -0
- package/dist/config.js +273 -0
- package/dist/core/eventReceivers.d.ts +185 -0
- package/dist/core/eventReceivers.js +266 -0
- package/dist/core/utils.d.ts +8 -0
- package/dist/core/utils.js +62 -0
- package/dist/errorHandler.d.ts +21 -0
- package/dist/errorHandler.js +27 -0
- package/dist/filtering/localFiltering.d.ts +110 -0
- package/dist/filtering/localFiltering.js +1080 -0
- package/dist/flavours/django/dates.d.ts +34 -0
- package/dist/flavours/django/dates.js +113 -0
- package/dist/flavours/django/errors.d.ts +138 -0
- package/dist/flavours/django/errors.js +195 -0
- package/dist/flavours/django/f.d.ts +6 -0
- package/dist/flavours/django/f.js +91 -0
- package/dist/flavours/django/files.d.ts +62 -0
- package/dist/flavours/django/files.js +355 -0
- package/dist/flavours/django/makeApiCall.d.ts +36 -0
- package/dist/flavours/django/makeApiCall.js +169 -0
- package/dist/flavours/django/manager.d.ts +204 -0
- package/dist/flavours/django/manager.js +222 -0
- package/dist/flavours/django/model.d.ts +137 -0
- package/dist/flavours/django/model.js +366 -0
- package/dist/flavours/django/operationFactory.d.ts +73 -0
- package/dist/flavours/django/operationFactory.js +248 -0
- package/dist/flavours/django/q.d.ts +70 -0
- package/dist/flavours/django/q.js +43 -0
- package/dist/flavours/django/queryExecutor.d.ts +149 -0
- package/dist/flavours/django/queryExecutor.js +590 -0
- package/dist/flavours/django/querySet.d.ts +301 -0
- package/dist/flavours/django/querySet.js +736 -0
- package/dist/flavours/django/serializers.d.ts +39 -0
- package/dist/flavours/django/serializers.js +296 -0
- package/dist/flavours/django/tempPk.d.ts +31 -0
- package/dist/flavours/django/tempPk.js +92 -0
- package/dist/flavours/django/utils.d.ts +19 -0
- package/dist/flavours/django/utils.js +29 -0
- package/dist/index.d.ts +46 -0
- package/dist/index.js +48 -0
- package/dist/models/backend1/django_app/comprehensivemodel.d.ts +894 -0
- package/dist/models/backend1/django_app/comprehensivemodel.js +71 -0
- package/dist/models/backend1/django_app/comprehensivemodel.schema.json +870 -0
- package/dist/models/backend1/django_app/custompkmodel.d.ts +92 -0
- package/dist/models/backend1/django_app/custompkmodel.js +69 -0
- package/dist/models/backend1/django_app/custompkmodel.schema.json +71 -0
- package/dist/models/backend1/django_app/dailyrate.d.ts +230 -0
- package/dist/models/backend1/django_app/dailyrate.js +71 -0
- package/dist/models/backend1/django_app/dailyrate.schema.json +212 -0
- package/dist/models/backend1/django_app/deepmodellevel1.d.ts +140 -0
- package/dist/models/backend1/django_app/deepmodellevel1.js +72 -0
- package/dist/models/backend1/django_app/deepmodellevel1.schema.json +114 -0
- package/dist/models/backend1/django_app/deepmodellevel2.d.ts +118 -0
- package/dist/models/backend1/django_app/deepmodellevel2.js +71 -0
- package/dist/models/backend1/django_app/deepmodellevel2.schema.json +92 -0
- package/dist/models/backend1/django_app/deepmodellevel3.d.ts +92 -0
- package/dist/models/backend1/django_app/deepmodellevel3.js +69 -0
- package/dist/models/backend1/django_app/deepmodellevel3.schema.json +69 -0
- package/dist/models/backend1/django_app/dummymodel.d.ts +134 -0
- package/dist/models/backend1/django_app/dummymodel.js +71 -0
- package/dist/models/backend1/django_app/dummymodel.schema.json +109 -0
- package/dist/models/backend1/django_app/dummyrelatedmodel.d.ts +92 -0
- package/dist/models/backend1/django_app/dummyrelatedmodel.js +69 -0
- package/dist/models/backend1/django_app/dummyrelatedmodel.schema.json +69 -0
- package/dist/models/backend1/django_app/filetest.d.ts +140 -0
- package/dist/models/backend1/django_app/filetest.js +69 -0
- package/dist/models/backend1/django_app/filetest.schema.json +111 -0
- package/dist/models/backend1/django_app/index.d.ts +1 -0
- package/dist/models/backend1/django_app/index.js +21 -0
- package/dist/models/backend1/django_app/m2mdepthtestlevel1.d.ts +118 -0
- package/dist/models/backend1/django_app/m2mdepthtestlevel1.js +71 -0
- package/dist/models/backend1/django_app/m2mdepthtestlevel1.schema.json +94 -0
- package/dist/models/backend1/django_app/m2mdepthtestlevel2.d.ts +118 -0
- package/dist/models/backend1/django_app/m2mdepthtestlevel2.js +71 -0
- package/dist/models/backend1/django_app/m2mdepthtestlevel2.schema.json +94 -0
- package/dist/models/backend1/django_app/m2mdepthtestlevel3.d.ts +134 -0
- package/dist/models/backend1/django_app/m2mdepthtestlevel3.js +71 -0
- package/dist/models/backend1/django_app/m2mdepthtestlevel3.schema.json +112 -0
- package/dist/models/backend1/django_app/modelwithcustompkrelation.d.ts +118 -0
- package/dist/models/backend1/django_app/modelwithcustompkrelation.js +71 -0
- package/dist/models/backend1/django_app/modelwithcustompkrelation.schema.json +93 -0
- package/dist/models/backend1/django_app/modelwithrestrictedfields.d.ts +134 -0
- package/dist/models/backend1/django_app/modelwithrestrictedfields.js +71 -0
- package/dist/models/backend1/django_app/modelwithrestrictedfields.schema.json +111 -0
- package/dist/models/backend1/django_app/namefiltercustompkmodel.d.ts +92 -0
- package/dist/models/backend1/django_app/namefiltercustompkmodel.js +69 -0
- package/dist/models/backend1/django_app/namefiltercustompkmodel.schema.json +71 -0
- package/dist/models/backend1/django_app/order.d.ts +220 -0
- package/dist/models/backend1/django_app/order.js +71 -0
- package/dist/models/backend1/django_app/order.schema.json +203 -0
- package/dist/models/backend1/django_app/orderitem.d.ts +172 -0
- package/dist/models/backend1/django_app/orderitem.js +72 -0
- package/dist/models/backend1/django_app/orderitem.schema.json +149 -0
- package/dist/models/backend1/django_app/product.d.ts +254 -0
- package/dist/models/backend1/django_app/product.js +71 -0
- package/dist/models/backend1/django_app/product.schema.json +277 -0
- package/dist/models/backend1/django_app/productcategory.d.ts +92 -0
- package/dist/models/backend1/django_app/productcategory.js +69 -0
- package/dist/models/backend1/django_app/productcategory.schema.json +70 -0
- package/dist/models/backend1/django_app/rateplan.d.ts +92 -0
- package/dist/models/backend1/django_app/rateplan.js +69 -0
- package/dist/models/backend1/django_app/rateplan.schema.json +70 -0
- package/dist/models/backend1/django_app/restrictedfieldrelatedmodel.d.ts +108 -0
- package/dist/models/backend1/django_app/restrictedfieldrelatedmodel.js +69 -0
- package/dist/models/backend1/django_app/restrictedfieldrelatedmodel.schema.json +87 -0
- package/dist/models/backend1/fileobject.d.ts +4 -0
- package/dist/models/backend1/fileobject.js +9 -0
- package/dist/models/backend1/index.d.ts +2 -0
- package/dist/models/backend1/index.js +2 -0
- package/dist/models/default/django_app/comprehensivemodel.d.ts +894 -0
- package/dist/models/default/django_app/comprehensivemodel.js +71 -0
- package/dist/models/default/django_app/comprehensivemodel.schema.json +870 -0
- package/dist/models/default/django_app/custompkmodel.d.ts +92 -0
- package/dist/models/default/django_app/custompkmodel.js +69 -0
- package/dist/models/default/django_app/custompkmodel.schema.json +71 -0
- package/dist/models/default/django_app/dailyrate.d.ts +230 -0
- package/dist/models/default/django_app/dailyrate.js +71 -0
- package/dist/models/default/django_app/dailyrate.schema.json +212 -0
- package/dist/models/default/django_app/deepmodellevel1.d.ts +128 -0
- package/dist/models/default/django_app/deepmodellevel1.js +72 -0
- package/dist/models/default/django_app/deepmodellevel1.schema.json +102 -0
- package/dist/models/default/django_app/deepmodellevel2.d.ts +106 -0
- package/dist/models/default/django_app/deepmodellevel2.js +71 -0
- package/dist/models/default/django_app/deepmodellevel2.schema.json +80 -0
- package/dist/models/default/django_app/deepmodellevel3.d.ts +80 -0
- package/dist/models/default/django_app/deepmodellevel3.js +69 -0
- package/dist/models/default/django_app/deepmodellevel3.schema.json +57 -0
- package/dist/models/default/django_app/dummymodel.d.ts +122 -0
- package/dist/models/default/django_app/dummymodel.js +71 -0
- package/dist/models/default/django_app/dummymodel.schema.json +97 -0
- package/dist/models/default/django_app/dummyrelatedmodel.d.ts +80 -0
- package/dist/models/default/django_app/dummyrelatedmodel.js +69 -0
- package/dist/models/default/django_app/dummyrelatedmodel.schema.json +57 -0
- package/dist/models/default/django_app/filetest.d.ts +128 -0
- package/dist/models/default/django_app/filetest.js +69 -0
- package/dist/models/default/django_app/filetest.schema.json +99 -0
- package/dist/models/default/django_app/index.d.ts +1 -0
- package/dist/models/default/django_app/index.js +21 -0
- package/dist/models/default/django_app/m2mdepthtestlevel1.d.ts +118 -0
- package/dist/models/default/django_app/m2mdepthtestlevel1.js +71 -0
- package/dist/models/default/django_app/m2mdepthtestlevel1.schema.json +94 -0
- package/dist/models/default/django_app/m2mdepthtestlevel2.d.ts +118 -0
- package/dist/models/default/django_app/m2mdepthtestlevel2.js +71 -0
- package/dist/models/default/django_app/m2mdepthtestlevel2.schema.json +94 -0
- package/dist/models/default/django_app/m2mdepthtestlevel3.d.ts +134 -0
- package/dist/models/default/django_app/m2mdepthtestlevel3.js +71 -0
- package/dist/models/default/django_app/m2mdepthtestlevel3.schema.json +112 -0
- package/dist/models/default/django_app/modelwithcustompkrelation.d.ts +118 -0
- package/dist/models/default/django_app/modelwithcustompkrelation.js +71 -0
- package/dist/models/default/django_app/modelwithcustompkrelation.schema.json +93 -0
- package/dist/models/default/django_app/modelwithrestrictedfields.d.ts +134 -0
- package/dist/models/default/django_app/modelwithrestrictedfields.js +71 -0
- package/dist/models/default/django_app/modelwithrestrictedfields.schema.json +111 -0
- package/dist/models/default/django_app/namefiltercustompkmodel.d.ts +92 -0
- package/dist/models/default/django_app/namefiltercustompkmodel.js +69 -0
- package/dist/models/default/django_app/namefiltercustompkmodel.schema.json +71 -0
- package/dist/models/default/django_app/order.d.ts +220 -0
- package/dist/models/default/django_app/order.js +71 -0
- package/dist/models/default/django_app/order.schema.json +203 -0
- package/dist/models/default/django_app/orderitem.d.ts +172 -0
- package/dist/models/default/django_app/orderitem.js +72 -0
- package/dist/models/default/django_app/orderitem.schema.json +149 -0
- package/dist/models/default/django_app/product.d.ts +254 -0
- package/dist/models/default/django_app/product.js +71 -0
- package/dist/models/default/django_app/product.schema.json +277 -0
- package/dist/models/default/django_app/productcategory.d.ts +92 -0
- package/dist/models/default/django_app/productcategory.js +69 -0
- package/dist/models/default/django_app/productcategory.schema.json +70 -0
- package/dist/models/default/django_app/rateplan.d.ts +92 -0
- package/dist/models/default/django_app/rateplan.js +69 -0
- package/dist/models/default/django_app/rateplan.schema.json +70 -0
- package/dist/models/default/django_app/restrictedfieldrelatedmodel.d.ts +108 -0
- package/dist/models/default/django_app/restrictedfieldrelatedmodel.js +69 -0
- package/dist/models/default/django_app/restrictedfieldrelatedmodel.schema.json +87 -0
- package/dist/models/default/fileobject.d.ts +4 -0
- package/dist/models/default/fileobject.js +9 -0
- package/dist/models/default/index.d.ts +2 -0
- package/dist/models/default/index.js +2 -0
- package/dist/models/index.d.ts +1 -0
- package/dist/models/index.js +5 -0
- package/dist/react-entry.d.ts +2 -0
- package/dist/react-entry.js +2 -0
- package/dist/reactiveAdaptor.d.ts +24 -0
- package/dist/reactiveAdaptor.js +38 -0
- package/dist/reset.d.ts +15 -0
- package/dist/reset.js +97 -0
- package/dist/setup.d.ts +15 -0
- package/dist/setup.js +33 -0
- package/dist/syncEngine/cache/cache.d.ts +75 -0
- package/dist/syncEngine/cache/cache.js +355 -0
- package/dist/syncEngine/metrics/metricOptCalcs.d.ts +79 -0
- package/dist/syncEngine/metrics/metricOptCalcs.js +284 -0
- package/dist/syncEngine/registries/metricRegistry.d.ts +58 -0
- package/dist/syncEngine/registries/metricRegistry.js +171 -0
- package/dist/syncEngine/registries/modelStoreRegistry.d.ts +11 -0
- package/dist/syncEngine/registries/modelStoreRegistry.js +63 -0
- package/dist/syncEngine/registries/querysetStoreGraph.d.ts +41 -0
- package/dist/syncEngine/registries/querysetStoreGraph.js +174 -0
- package/dist/syncEngine/registries/querysetStoreRegistry.d.ts +72 -0
- package/dist/syncEngine/registries/querysetStoreRegistry.js +335 -0
- package/dist/syncEngine/stores/metricStore.d.ts +55 -0
- package/dist/syncEngine/stores/metricStore.js +222 -0
- package/dist/syncEngine/stores/modelStore.d.ts +53 -0
- package/dist/syncEngine/stores/modelStore.js +565 -0
- package/dist/syncEngine/stores/operation.d.ts +139 -0
- package/dist/syncEngine/stores/operation.js +291 -0
- package/dist/syncEngine/stores/operationEventHandlers.d.ts +8 -0
- package/dist/syncEngine/stores/operationEventHandlers.js +348 -0
- package/dist/syncEngine/stores/querysetStore.d.ts +60 -0
- package/dist/syncEngine/stores/querysetStore.js +294 -0
- package/dist/syncEngine/stores/reactivity.d.ts +3 -0
- package/dist/syncEngine/stores/reactivity.js +4 -0
- package/dist/syncEngine/stores/utils.d.ts +14 -0
- package/dist/syncEngine/stores/utils.js +32 -0
- package/dist/syncEngine/sync.d.ts +51 -0
- package/dist/syncEngine/sync.js +419 -0
- package/dist/testing.d.ts +63 -0
- package/dist/testing.js +175 -0
- package/dist/vue-entry.d.ts +15 -0
- package/dist/vue-entry.js +7 -0
- package/package.json +6 -7
- package/dist/adaptors/vue/components/layout.tailwind.css +0 -51
- /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';
|