@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,590 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import { configInstance } from '../../config.js';
|
|
3
|
+
import { parseStateZeroError, MultipleObjectsReturned, DoesNotExist } from './errors.js';
|
|
4
|
+
import { modelStoreRegistry } from '../../syncEngine/registries/modelStoreRegistry.js';
|
|
5
|
+
import { querysetStoreRegistry } from '../../syncEngine/registries/querysetStoreRegistry.js';
|
|
6
|
+
import { metricRegistry } from '../../syncEngine/registries/metricRegistry.js';
|
|
7
|
+
import { Status } from '../../syncEngine/stores/operation.js';
|
|
8
|
+
import { breakThenable, makeLiveThenable } from './utils.js';
|
|
9
|
+
import { setRealPk } from './tempPk.js';
|
|
10
|
+
import { isNil } from 'lodash-es';
|
|
11
|
+
import { Model } from './model.js';
|
|
12
|
+
import { v7 as uuid7 } from 'uuid';
|
|
13
|
+
import { makeApiCall, processIncludedEntities } from './makeApiCall.js';
|
|
14
|
+
import { OperationFactory } from './operationFactory.js';
|
|
15
|
+
const getModelClass = configInstance.getModelClass;
|
|
16
|
+
/**
|
|
17
|
+
* A custom data structure that behaves as an augmented array.
|
|
18
|
+
* It stores [instance, created] and also provides named properties for clarity.
|
|
19
|
+
*
|
|
20
|
+
* @class ResultTuple
|
|
21
|
+
* @extends {Array}
|
|
22
|
+
*/
|
|
23
|
+
export class ResultTuple extends Array {
|
|
24
|
+
/**
|
|
25
|
+
* Creates a new ResultTuple.
|
|
26
|
+
*
|
|
27
|
+
* @param {*} instance - The model instance.
|
|
28
|
+
* @param {boolean} created - Whether the instance was created.
|
|
29
|
+
*/
|
|
30
|
+
constructor(instance, created) {
|
|
31
|
+
// Create an array with length 2.
|
|
32
|
+
super(2);
|
|
33
|
+
// Set array indices directly instead of using push.
|
|
34
|
+
this[0] = instance;
|
|
35
|
+
this[1] = created;
|
|
36
|
+
// Set named properties.
|
|
37
|
+
this.instance = instance;
|
|
38
|
+
this.created = created;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Handles query execution against the backend, and parsing the response into the correct format.
|
|
43
|
+
*/
|
|
44
|
+
export class QueryExecutor {
|
|
45
|
+
/**
|
|
46
|
+
* Executes a get operation (get, first, last) with the QuerySet.
|
|
47
|
+
*
|
|
48
|
+
* @param {QuerySet} querySet - The QuerySet to execute.
|
|
49
|
+
* @param {string} operationType - The specific get operation type.
|
|
50
|
+
* @param {Object} args - Additional arguments for the operation.
|
|
51
|
+
* @returns {Promise<Object>} The model instance.
|
|
52
|
+
*/
|
|
53
|
+
static executeGet(querySet, operationType, args = {}) {
|
|
54
|
+
const ModelClass = querySet.ModelClass;
|
|
55
|
+
const store = querysetStoreRegistry.getStore(querySet);
|
|
56
|
+
const existing = store.render();
|
|
57
|
+
const tempPk = Array.isArray(existing) && existing.length === 1 ? existing[0] : null;
|
|
58
|
+
// always return a Model instance (pk might be null)
|
|
59
|
+
const live = ModelClass.fromPk(tempPk, querySet);
|
|
60
|
+
const promise = makeApiCall(querySet, operationType, args).then((resp) => {
|
|
61
|
+
const { data, included, model_name } = resp.data;
|
|
62
|
+
if (isNil(data) || (Array.isArray(data) && data.length === 0)) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
processIncludedEntities(modelStoreRegistry, included, ModelClass, querySet);
|
|
66
|
+
const realPk = Array.isArray(data) ? data[0] : data;
|
|
67
|
+
// swap in the real PK on the same instance, will trigger reactivity
|
|
68
|
+
live.pk = realPk;
|
|
69
|
+
breakThenable(live);
|
|
70
|
+
return live;
|
|
71
|
+
});
|
|
72
|
+
return makeLiveThenable(live, promise);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Execute a list-style API call for the given QuerySet, update the in‑memory store with the returned primary keys,
|
|
76
|
+
* process any included entities, and return a live‑thenable that keeps the local "live" collection in sync.
|
|
77
|
+
*
|
|
78
|
+
* @template T The model type of the QuerySet
|
|
79
|
+
* @param {QuerySet<T>} qs
|
|
80
|
+
* The QuerySet to execute.
|
|
81
|
+
* @param {string} [op="list"]
|
|
82
|
+
* The operation to perform. Defaults to `"list"`, but could be overridden for other list‑style endpoints.
|
|
83
|
+
* @param {Object} [args={}]
|
|
84
|
+
* Additional arguments to pass through to the underlying API call (e.g. filters, pagination).
|
|
85
|
+
* @returns {LiveThenable<import('./makeLiveThenable').Result<T[]>>}
|
|
86
|
+
* A live‑thenable wrapping an array of primary‑key values for the fetched models. The live part remains
|
|
87
|
+
* synchronized with the in‑memory store.
|
|
88
|
+
*/
|
|
89
|
+
static executeList(qs, op = "list", args = {}) {
|
|
90
|
+
const live = querysetStoreRegistry.getEntity(qs);
|
|
91
|
+
const promise = makeApiCall(qs, op, args).then((resp) => {
|
|
92
|
+
const { data, included } = resp.data;
|
|
93
|
+
processIncludedEntities(modelStoreRegistry, included, qs.ModelClass, qs);
|
|
94
|
+
const pks = Array.isArray(data) ? data : [];
|
|
95
|
+
querysetStoreRegistry.setEntity(qs, pks);
|
|
96
|
+
breakThenable(live);
|
|
97
|
+
return live;
|
|
98
|
+
});
|
|
99
|
+
return makeLiveThenable(live, promise);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Executes a get_or_create or update_or_create operation with the QuerySet.
|
|
103
|
+
*
|
|
104
|
+
* @param {QuerySet} querySet - The QuerySet to execute.
|
|
105
|
+
* @param {string} operationType - The specific operation type ('get_or_create' or 'update_or_create').
|
|
106
|
+
* @param {Object} args - Additional arguments for the operation.
|
|
107
|
+
* @returns {Promise<ResultTuple>} Tuple with instance and created flag.
|
|
108
|
+
*/
|
|
109
|
+
static executeOrCreate(querySet, operationType, args = {}) {
|
|
110
|
+
const ModelClass = querySet.ModelClass;
|
|
111
|
+
const primaryKeyField = ModelClass.primaryKeyField;
|
|
112
|
+
const apiCallArgs = {
|
|
113
|
+
lookup: args.lookup || {},
|
|
114
|
+
defaults: args.defaults || {},
|
|
115
|
+
};
|
|
116
|
+
// Use the factory to create the operation (which includes local filtering logic)
|
|
117
|
+
const operation = operationType === 'get_or_create'
|
|
118
|
+
? OperationFactory.createGetOrCreateOperation(querySet, apiCallArgs.lookup, apiCallArgs.defaults)
|
|
119
|
+
: OperationFactory.createUpdateOrCreateOperation(querySet, apiCallArgs.lookup, apiCallArgs.defaults);
|
|
120
|
+
// Determine if we're creating new based on the operation type
|
|
121
|
+
const isCreatingNew = operation.type === 'create';
|
|
122
|
+
// Create optimistic instance and result
|
|
123
|
+
const live = isCreatingNew
|
|
124
|
+
? ModelClass.fromPk(operation.instances[0][primaryKeyField], querySet)
|
|
125
|
+
: ModelClass.fromPk(operation.instances[0][primaryKeyField], querySet);
|
|
126
|
+
let liveResult = new ResultTuple(live, isCreatingNew);
|
|
127
|
+
// If optimistic-only, skip API call and immediately confirm
|
|
128
|
+
if (operation.localOnly) {
|
|
129
|
+
operation.updateStatus(Status.CONFIRMED, operation.instances);
|
|
130
|
+
return liveResult;
|
|
131
|
+
}
|
|
132
|
+
// Make API call with original operation type for backend
|
|
133
|
+
const promise = makeApiCall(querySet, operationType, apiCallArgs, operation.operationId)
|
|
134
|
+
.then((response) => {
|
|
135
|
+
const { data, included, model_name } = response.data;
|
|
136
|
+
const created = response.metadata.created;
|
|
137
|
+
// Process included entities
|
|
138
|
+
processIncludedEntities(modelStoreRegistry, included, ModelClass, querySet);
|
|
139
|
+
// Get the real PK
|
|
140
|
+
const pk = Array.isArray(data) ? data[0] : data;
|
|
141
|
+
// Update PK if we created a new instance
|
|
142
|
+
if (isCreatingNew) {
|
|
143
|
+
live.pk = pk;
|
|
144
|
+
}
|
|
145
|
+
// Confirm operation
|
|
146
|
+
const entityMap = included[model_name] || {};
|
|
147
|
+
const entityData = entityMap[pk];
|
|
148
|
+
if (entityData) {
|
|
149
|
+
operation.mutate({
|
|
150
|
+
instances: [entityData],
|
|
151
|
+
status: Status.CONFIRMED,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
// Update result with actual created flag
|
|
155
|
+
liveResult = new ResultTuple(live, created);
|
|
156
|
+
breakThenable(liveResult);
|
|
157
|
+
return liveResult;
|
|
158
|
+
})
|
|
159
|
+
.catch((error) => {
|
|
160
|
+
operation.updateStatus(Status.REJECTED);
|
|
161
|
+
throw error;
|
|
162
|
+
});
|
|
163
|
+
return makeLiveThenable(liveResult, promise);
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Executes an aggregation operation with the QuerySet.
|
|
167
|
+
*
|
|
168
|
+
* @param {QuerySet} querySet - The QuerySet to execute.
|
|
169
|
+
* @param {string} operationType - The specific aggregation operation type.
|
|
170
|
+
* @param {Object} args - Additional arguments for the operation.
|
|
171
|
+
* @returns {LiveMetric} The LiveMetric instance that updates optimistically.
|
|
172
|
+
*/
|
|
173
|
+
static executeAgg(querySet, operationType, args = {}) {
|
|
174
|
+
const ModelClass = querySet.ModelClass;
|
|
175
|
+
const field = operationType === 'count'
|
|
176
|
+
? (args.field || ModelClass.primaryKeyField)
|
|
177
|
+
: args.field;
|
|
178
|
+
// Only include defined properties
|
|
179
|
+
if (operationType !== 'exists' && operationType !== 'count' && field === undefined) {
|
|
180
|
+
throw new Error(`Field parameter is required for ${operationType} operation`);
|
|
181
|
+
}
|
|
182
|
+
// Get the live metric from the registry
|
|
183
|
+
const liveMetric = metricRegistry.getEntity(operationType, querySet, field);
|
|
184
|
+
// Create the API call args
|
|
185
|
+
const apiCallArgs = {};
|
|
186
|
+
if (operationType !== 'exists') {
|
|
187
|
+
apiCallArgs.field = field;
|
|
188
|
+
}
|
|
189
|
+
// Perform the async request
|
|
190
|
+
const promise = makeApiCall(querySet, operationType, apiCallArgs).then((response) => {
|
|
191
|
+
// The aggregation result should be directly in data
|
|
192
|
+
const value = response.data;
|
|
193
|
+
// Update the metric store with the ground truth value and current queryset
|
|
194
|
+
const dataSlice = querysetStoreRegistry.getEntity(querySet);
|
|
195
|
+
metricRegistry.setEntity(operationType, querySet, field, value, dataSlice);
|
|
196
|
+
breakThenable(liveMetric);
|
|
197
|
+
// Return the value for the promise resolution
|
|
198
|
+
return value;
|
|
199
|
+
});
|
|
200
|
+
// For consistency with other methods, make the liveMetric thenable
|
|
201
|
+
return makeLiveThenable(liveMetric, promise);
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Executes an exists operation with the QuerySet.
|
|
205
|
+
*
|
|
206
|
+
* @param {QuerySet} querySet - The QuerySet to execute.
|
|
207
|
+
* @param {string} operationType - The operation type (always 'exists' for this method).
|
|
208
|
+
* @param {Object} args - Additional arguments for the operation.
|
|
209
|
+
* @returns {Promise<boolean>} Whether records exist.
|
|
210
|
+
*/
|
|
211
|
+
static async executeExists(querySet, operationType = "exists", args = {}) {
|
|
212
|
+
// exists
|
|
213
|
+
const apiCallArgs = {};
|
|
214
|
+
const response = await makeApiCall(querySet, operationType, apiCallArgs);
|
|
215
|
+
return response.data || false;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Executes an update operation with the QuerySet.
|
|
219
|
+
*
|
|
220
|
+
* @param {QuerySet} querySet - The QuerySet to execute.
|
|
221
|
+
* @param {string} operationType - The operation type (always 'update' for this method).
|
|
222
|
+
* @param {Object} args - Additional arguments for the operation.
|
|
223
|
+
* @returns {Promise<Array>} Tuple with count and model counts map.
|
|
224
|
+
*/
|
|
225
|
+
static executeUpdate(querySet, operationType = "update", args = {}) {
|
|
226
|
+
const ModelClass = querySet.ModelClass;
|
|
227
|
+
const modelName = ModelClass.modelName;
|
|
228
|
+
const apiCallArgs = {
|
|
229
|
+
data: args.data || {},
|
|
230
|
+
};
|
|
231
|
+
const operation = OperationFactory.createUpdateOperation(querySet, apiCallArgs.data, querySet.build().filter);
|
|
232
|
+
const estimatedCount = operation.instances.length;
|
|
233
|
+
let liveResult = [estimatedCount, { [modelName]: estimatedCount }, operation.instances];
|
|
234
|
+
// If optimistic-only, skip API call and immediately confirm
|
|
235
|
+
if (operation.localOnly) {
|
|
236
|
+
operation.updateStatus(Status.CONFIRMED, operation.instances);
|
|
237
|
+
return liveResult;
|
|
238
|
+
}
|
|
239
|
+
const promise = makeApiCall(querySet, operationType, apiCallArgs, operation.operationId)
|
|
240
|
+
.then((response) => {
|
|
241
|
+
const { data, included } = response.data || {};
|
|
242
|
+
const fullData = included[modelName] || {};
|
|
243
|
+
const updatedObjects = Array.isArray(data)
|
|
244
|
+
? data.map((pk) => (fullData[`${pk}`]))
|
|
245
|
+
: [];
|
|
246
|
+
operation.updateStatus(Status.CONFIRMED, updatedObjects);
|
|
247
|
+
const updatedCount = response.metadata?.updated_count ?? 0;
|
|
248
|
+
liveResult = [updatedCount, { [modelName]: updatedCount }, updatedObjects];
|
|
249
|
+
breakThenable(liveResult);
|
|
250
|
+
return liveResult;
|
|
251
|
+
})
|
|
252
|
+
.catch((err) => {
|
|
253
|
+
operation.updateStatus(Status.REJECTED);
|
|
254
|
+
throw err;
|
|
255
|
+
});
|
|
256
|
+
return makeLiveThenable(liveResult, promise);
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Executes a delete operation with the QuerySet.
|
|
260
|
+
*
|
|
261
|
+
* @param {QuerySet} querySet - The QuerySet to execute.
|
|
262
|
+
* @param {string} operationType - The operation type (always 'delete' for this method).
|
|
263
|
+
* @param {Object} args - Additional arguments for the operation.
|
|
264
|
+
* @returns {Promise<Array>} Tuple with count and model counts map.
|
|
265
|
+
*/
|
|
266
|
+
static executeDelete(querySet, operationType = "delete", args = {}) {
|
|
267
|
+
const ModelClass = querySet.ModelClass;
|
|
268
|
+
const modelName = ModelClass.modelName;
|
|
269
|
+
// Use factory to create operation
|
|
270
|
+
const operation = OperationFactory.createDeleteOperation(querySet);
|
|
271
|
+
// live placeholder: assume we delete all existing pks
|
|
272
|
+
const estimatedCount = operation.instances.length;
|
|
273
|
+
let liveResult = [estimatedCount, { [modelName]: estimatedCount }, operation.instances];
|
|
274
|
+
// If optimistic-only, skip API call and immediately confirm
|
|
275
|
+
if (operation.localOnly) {
|
|
276
|
+
operation.updateStatus(Status.CONFIRMED, operation.instances);
|
|
277
|
+
return liveResult;
|
|
278
|
+
}
|
|
279
|
+
const promise = makeApiCall(querySet, operationType, {}, operation.operationId)
|
|
280
|
+
.then((response) => {
|
|
281
|
+
const deletedCount = response.metadata.deleted_count;
|
|
282
|
+
const deletedInstances = response.metadata.rows_deleted;
|
|
283
|
+
operation.updateStatus(Status.CONFIRMED, deletedInstances);
|
|
284
|
+
liveResult = [deletedCount, { [modelName]: deletedCount }, deletedInstances || []];
|
|
285
|
+
breakThenable(liveResult);
|
|
286
|
+
return liveResult;
|
|
287
|
+
})
|
|
288
|
+
.catch((err) => {
|
|
289
|
+
operation.updateStatus(Status.REJECTED);
|
|
290
|
+
throw err;
|
|
291
|
+
});
|
|
292
|
+
return makeLiveThenable(liveResult, promise);
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Executes a create operation with the QuerySet.
|
|
296
|
+
*
|
|
297
|
+
* @param {QuerySet} querySet - The QuerySet to execute.
|
|
298
|
+
* @param {string} operationType - The operation type (always 'create' for this method).
|
|
299
|
+
* @param {Object} args - Additional arguments for the operation.
|
|
300
|
+
* @returns {LiveThenable<Object>} The live Model instance which resolves to the created model.
|
|
301
|
+
*/
|
|
302
|
+
static executeCreate(querySet, operationType = "create", args = {}) {
|
|
303
|
+
const ModelClass = querySet.ModelClass;
|
|
304
|
+
const operationId = `${uuid7()}`;
|
|
305
|
+
const apiCallArgs = {
|
|
306
|
+
data: args.data || {},
|
|
307
|
+
};
|
|
308
|
+
// set the data so the operationId matches
|
|
309
|
+
if (isNil(args.data)) {
|
|
310
|
+
console.warn(`executeCreate was called with null data`);
|
|
311
|
+
args.data = {};
|
|
312
|
+
}
|
|
313
|
+
// Use factory to create operation
|
|
314
|
+
const operation = OperationFactory.createCreateOperation(querySet, apiCallArgs.data, operationId);
|
|
315
|
+
const tempPk = operation.instances[0][ModelClass.primaryKeyField];
|
|
316
|
+
// 1) placeholder instance
|
|
317
|
+
const live = ModelClass.fromPk(tempPk, querySet);
|
|
318
|
+
// If optimistic-only, skip API call and immediately confirm
|
|
319
|
+
if (operation.localOnly) {
|
|
320
|
+
operation.updateStatus(Status.CONFIRMED, operation.instances);
|
|
321
|
+
return live;
|
|
322
|
+
}
|
|
323
|
+
// 2) kick off the async call
|
|
324
|
+
const promise = makeApiCall(querySet, operationType, apiCallArgs, operationId, async (response) => {
|
|
325
|
+
const { data } = response.data;
|
|
326
|
+
const pk = Array.isArray(data) ? data[0] : data;
|
|
327
|
+
setRealPk(operationId, pk);
|
|
328
|
+
})
|
|
329
|
+
.then((response) => {
|
|
330
|
+
const { data, included, model_name } = response.data;
|
|
331
|
+
// Process included entities
|
|
332
|
+
processIncludedEntities(modelStoreRegistry, included, ModelClass, querySet);
|
|
333
|
+
// Get the real PK
|
|
334
|
+
const pk = Array.isArray(data) ? data[0] : data;
|
|
335
|
+
live.pk = pk;
|
|
336
|
+
// Two‑line lookup
|
|
337
|
+
const entityMap = included[model_name] || {};
|
|
338
|
+
const entityData = entityMap[pk];
|
|
339
|
+
if (!entityData) {
|
|
340
|
+
throw new Error(`Entity data not found for ${model_name} with pk ${pk}`);
|
|
341
|
+
}
|
|
342
|
+
// Confirm operation with full entity data
|
|
343
|
+
operation.mutate({
|
|
344
|
+
instances: [entityData],
|
|
345
|
+
status: Status.CONFIRMED,
|
|
346
|
+
});
|
|
347
|
+
// Freeze the live instance
|
|
348
|
+
breakThenable(live);
|
|
349
|
+
return live;
|
|
350
|
+
})
|
|
351
|
+
.catch((error) => {
|
|
352
|
+
operation.updateStatus(Status.REJECTED);
|
|
353
|
+
throw error;
|
|
354
|
+
});
|
|
355
|
+
// 3) return the live‑thenable
|
|
356
|
+
return makeLiveThenable(live, promise);
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* Executes a bulk_create operation with the QuerySet.
|
|
360
|
+
*
|
|
361
|
+
* @param {QuerySet} querySet - The QuerySet to execute.
|
|
362
|
+
* @param {string} operationType - The operation type (always 'bulk_create' for this method).
|
|
363
|
+
* @param {Object} args - Additional arguments for the operation.
|
|
364
|
+
* @returns {LiveThenable<Array>} Array of live Model instances.
|
|
365
|
+
*/
|
|
366
|
+
static executeBulkCreate(querySet, operationType = "bulk_create", args = {}) {
|
|
367
|
+
const ModelClass = querySet.ModelClass;
|
|
368
|
+
const operationId = `${uuid7()}`;
|
|
369
|
+
const primaryKeyField = ModelClass.primaryKeyField;
|
|
370
|
+
const apiCallArgs = {
|
|
371
|
+
data: args.data || [],
|
|
372
|
+
};
|
|
373
|
+
if (isNil(args.data) || !Array.isArray(args.data)) {
|
|
374
|
+
console.warn(`executeBulkCreate was called with invalid data`);
|
|
375
|
+
return Promise.resolve([]);
|
|
376
|
+
}
|
|
377
|
+
// Use factory to create operation
|
|
378
|
+
const operation = OperationFactory.createBulkCreateOperation(querySet, apiCallArgs.data, operationId);
|
|
379
|
+
// Create placeholder instances for each item
|
|
380
|
+
const liveInstances = operation.instances.map(instance => {
|
|
381
|
+
const tempPk = instance[primaryKeyField];
|
|
382
|
+
return ModelClass.fromPk(tempPk, querySet);
|
|
383
|
+
});
|
|
384
|
+
// If optimistic-only, skip API call and immediately confirm
|
|
385
|
+
if (operation.localOnly) {
|
|
386
|
+
operation.updateStatus(Status.CONFIRMED, operation.instances);
|
|
387
|
+
return liveInstances;
|
|
388
|
+
}
|
|
389
|
+
// Kick off the async call
|
|
390
|
+
const promise = makeApiCall(querySet, operationType, apiCallArgs, operationId, async (response) => {
|
|
391
|
+
const { data } = response.data;
|
|
392
|
+
const pks = Array.isArray(data) ? data : [];
|
|
393
|
+
// Set real PKs for all instances
|
|
394
|
+
pks.forEach((pk, index) => {
|
|
395
|
+
const tempPkKey = `${operationId}_${index}`;
|
|
396
|
+
setRealPk(tempPkKey, pk);
|
|
397
|
+
});
|
|
398
|
+
})
|
|
399
|
+
.then((response) => {
|
|
400
|
+
const { data, included, model_name } = response.data;
|
|
401
|
+
// Process included entities
|
|
402
|
+
processIncludedEntities(modelStoreRegistry, included, ModelClass, querySet);
|
|
403
|
+
// Get the real PKs
|
|
404
|
+
const pks = Array.isArray(data) ? data : [];
|
|
405
|
+
// Update each live instance with its real PK
|
|
406
|
+
pks.forEach((pk, index) => {
|
|
407
|
+
if (liveInstances[index]) {
|
|
408
|
+
liveInstances[index].pk = pk;
|
|
409
|
+
}
|
|
410
|
+
});
|
|
411
|
+
// Get full entity data for all created instances
|
|
412
|
+
const entityMap = included[model_name] || {};
|
|
413
|
+
const confirmedInstances = pks.map(pk => entityMap[pk]).filter(Boolean);
|
|
414
|
+
// Confirm operation with full entity data
|
|
415
|
+
operation.mutate({
|
|
416
|
+
instances: confirmedInstances,
|
|
417
|
+
status: Status.CONFIRMED,
|
|
418
|
+
});
|
|
419
|
+
// Freeze all live instances
|
|
420
|
+
liveInstances.forEach(instance => breakThenable(instance));
|
|
421
|
+
// Also break the thenable on the array itself
|
|
422
|
+
breakThenable(liveInstances);
|
|
423
|
+
return liveInstances;
|
|
424
|
+
})
|
|
425
|
+
.catch((error) => {
|
|
426
|
+
operation.updateStatus(Status.REJECTED);
|
|
427
|
+
throw error;
|
|
428
|
+
});
|
|
429
|
+
// Return a live-thenable array
|
|
430
|
+
return makeLiveThenable(liveInstances, promise);
|
|
431
|
+
}
|
|
432
|
+
/**
|
|
433
|
+
* Executes an update_instance operation with the QuerySet.
|
|
434
|
+
*
|
|
435
|
+
* @param {QuerySet} querySet - The QuerySet to execute.
|
|
436
|
+
* @param {string} operationType - The operation type (always 'update_instance' for this method).
|
|
437
|
+
* @param {Object} args - Additional arguments for the operation.
|
|
438
|
+
* @returns {LiveThenable<Object>} The live Model instance which resolves to the updated model.
|
|
439
|
+
*/
|
|
440
|
+
static executeUpdateInstance(querySet, operationType = "update_instance", args = {}) {
|
|
441
|
+
const ModelClass = querySet.ModelClass;
|
|
442
|
+
const primaryKeyField = ModelClass.primaryKeyField;
|
|
443
|
+
const store = querysetStoreRegistry.getStore(querySet);
|
|
444
|
+
const querysetPks = store.render();
|
|
445
|
+
const data = args.data || {};
|
|
446
|
+
// Use factory to create operation
|
|
447
|
+
const operation = OperationFactory.createUpdateInstanceOperation(querySet, data);
|
|
448
|
+
// 1) placeholder instance
|
|
449
|
+
const initialPk = Array.isArray(querysetPks) ? querysetPks[0] : null;
|
|
450
|
+
const live = ModelClass.fromPk(initialPk, querySet);
|
|
451
|
+
// If optimistic-only, skip API call and immediately confirm
|
|
452
|
+
if (operation.localOnly) {
|
|
453
|
+
operation.updateStatus(Status.CONFIRMED, operation.instances);
|
|
454
|
+
return live;
|
|
455
|
+
}
|
|
456
|
+
// 2) async call
|
|
457
|
+
const promise = makeApiCall(querySet, operationType, { data }, operation.operationId)
|
|
458
|
+
.then((response) => {
|
|
459
|
+
const { data: raw, included, model_name } = response.data;
|
|
460
|
+
// Process included entities
|
|
461
|
+
processIncludedEntities(modelStoreRegistry, included, ModelClass, querySet);
|
|
462
|
+
// Swap in the real PK
|
|
463
|
+
const pk = Array.isArray(raw) ? raw[0] : raw;
|
|
464
|
+
live.pk = pk;
|
|
465
|
+
// Two‑line lookup
|
|
466
|
+
const entityMap = included[model_name] || {};
|
|
467
|
+
const entityData = entityMap[pk];
|
|
468
|
+
if (!entityData) {
|
|
469
|
+
throw new Error(`Entity data not found for ${model_name} with pk ${pk}`);
|
|
470
|
+
}
|
|
471
|
+
// Confirm operation with full entity data
|
|
472
|
+
operation.updateStatus(Status.CONFIRMED, [entityData]);
|
|
473
|
+
// Freeze the live instance
|
|
474
|
+
breakThenable(live);
|
|
475
|
+
return live;
|
|
476
|
+
})
|
|
477
|
+
.catch((error) => {
|
|
478
|
+
operation.updateStatus(Status.REJECTED);
|
|
479
|
+
throw error;
|
|
480
|
+
});
|
|
481
|
+
// 3) return the live‑thenable
|
|
482
|
+
return makeLiveThenable(live, promise);
|
|
483
|
+
}
|
|
484
|
+
/**
|
|
485
|
+
* Executes a delete_instance operation with the QuerySet.
|
|
486
|
+
*
|
|
487
|
+
* @param {QuerySet} querySet - The QuerySet to execute.
|
|
488
|
+
* @param {string} operationType - The operation type (always 'delete_instance' for this method).
|
|
489
|
+
* @param {Object} args - Additional arguments for the operation, including the primary key.
|
|
490
|
+
* @returns {LiveThenable<Array>} A live‑thenable resolving to [deletedCount, { modelName: deletedCount }].
|
|
491
|
+
*/
|
|
492
|
+
static executeDeleteInstance(querySet, operationType = "delete_instance", args = {}) {
|
|
493
|
+
const ModelClass = querySet.ModelClass;
|
|
494
|
+
const modelName = ModelClass.modelName;
|
|
495
|
+
const primaryKeyField = ModelClass.primaryKeyField;
|
|
496
|
+
// Validate that the primary key is provided
|
|
497
|
+
if (args[primaryKeyField] === undefined) {
|
|
498
|
+
throw new Error(`Primary key '${primaryKeyField}' must be provided in args for delete_instance operation`);
|
|
499
|
+
}
|
|
500
|
+
// Use factory to create operation
|
|
501
|
+
const operation = OperationFactory.createDeleteInstanceOperation(querySet, args);
|
|
502
|
+
// 1) placeholder result
|
|
503
|
+
let liveResult = [1, { [modelName]: 1 }, operation.instances];
|
|
504
|
+
// If optimistic-only, skip API call and immediately confirm
|
|
505
|
+
if (operation.localOnly) {
|
|
506
|
+
operation.updateStatus(Status.CONFIRMED, operation.instances);
|
|
507
|
+
return liveResult;
|
|
508
|
+
}
|
|
509
|
+
// 2) async call
|
|
510
|
+
const promise = makeApiCall(querySet, operationType, args, operation.operationId)
|
|
511
|
+
.then((response) => {
|
|
512
|
+
// response.data is the count for delete_instance
|
|
513
|
+
let deletedCount = 1;
|
|
514
|
+
if (typeof response.data === "number") {
|
|
515
|
+
deletedCount = response.data;
|
|
516
|
+
}
|
|
517
|
+
// Get deleted instances from metadata if available
|
|
518
|
+
const deletedInstances = response.metadata?.rows_deleted || [args];
|
|
519
|
+
// Confirm operation
|
|
520
|
+
operation.updateStatus(Status.CONFIRMED, [args]);
|
|
521
|
+
// Swap in real result and freeze
|
|
522
|
+
liveResult = [deletedCount, { [modelName]: deletedCount }, deletedInstances];
|
|
523
|
+
breakThenable(liveResult);
|
|
524
|
+
return liveResult;
|
|
525
|
+
})
|
|
526
|
+
.catch((err) => {
|
|
527
|
+
operation.updateStatus(Status.REJECTED);
|
|
528
|
+
throw err;
|
|
529
|
+
});
|
|
530
|
+
// 3) return live‑thenable
|
|
531
|
+
return makeLiveThenable(liveResult, promise);
|
|
532
|
+
}
|
|
533
|
+
/**
|
|
534
|
+
* Executes a query operation with the QuerySet.
|
|
535
|
+
*
|
|
536
|
+
* @param {QuerySet} querySet - The QuerySet to execute.
|
|
537
|
+
* @param {string} operationType - The operation type to perform.
|
|
538
|
+
* @param {Object} args - Additional arguments for the operation.
|
|
539
|
+
* @returns {Promise<any>} The operation result.
|
|
540
|
+
*/
|
|
541
|
+
static execute(querySet, operationType = "list", args = {}) {
|
|
542
|
+
if (querySet._remoteOnly) {
|
|
543
|
+
return this.executeRemote(querySet, operationType, args);
|
|
544
|
+
}
|
|
545
|
+
// execute the query and return the result
|
|
546
|
+
switch (operationType) {
|
|
547
|
+
case "get":
|
|
548
|
+
case "first":
|
|
549
|
+
case "last":
|
|
550
|
+
return this.executeGet(querySet, operationType, args);
|
|
551
|
+
case "update_instance":
|
|
552
|
+
return this.executeUpdateInstance(querySet, operationType, args);
|
|
553
|
+
case "delete_instance":
|
|
554
|
+
return this.executeDeleteInstance(querySet, operationType, args);
|
|
555
|
+
case "update":
|
|
556
|
+
return this.executeUpdate(querySet, operationType, args);
|
|
557
|
+
case "delete":
|
|
558
|
+
return this.executeDelete(querySet, operationType, args);
|
|
559
|
+
case "create":
|
|
560
|
+
return this.executeCreate(querySet, operationType, args);
|
|
561
|
+
case "bulk_create":
|
|
562
|
+
return this.executeBulkCreate(querySet, operationType, args);
|
|
563
|
+
case "get_or_create":
|
|
564
|
+
case "update_or_create":
|
|
565
|
+
return this.executeOrCreate(querySet, operationType, args);
|
|
566
|
+
case "min":
|
|
567
|
+
case "max":
|
|
568
|
+
case "avg":
|
|
569
|
+
case "sum":
|
|
570
|
+
case "count":
|
|
571
|
+
return this.executeAgg(querySet, operationType, args);
|
|
572
|
+
case "exists":
|
|
573
|
+
return this.executeExists(querySet, operationType, args);
|
|
574
|
+
case "list":
|
|
575
|
+
return this.executeList(querySet, operationType, args);
|
|
576
|
+
}
|
|
577
|
+
throw new Error(`Invalid operation type: ${operationType}`);
|
|
578
|
+
}
|
|
579
|
+
/**
|
|
580
|
+
* Executes a query operation remotely without updating local stores.
|
|
581
|
+
*
|
|
582
|
+
* @param {QuerySet} querySet - The QuerySet to execute.
|
|
583
|
+
* @param {string} operationType - The operation type to perform.
|
|
584
|
+
* @param {Object} args - Additional arguments for the operation.
|
|
585
|
+
* @returns {Promise<any>} The raw API response data.
|
|
586
|
+
*/
|
|
587
|
+
static executeRemote(querySet, operationType = "list", args = {}) {
|
|
588
|
+
return makeApiCall(querySet, operationType, args);
|
|
589
|
+
}
|
|
590
|
+
}
|