@arrai-innovations/reactive-helpers 9.0.3 → 10.0.1
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/.idea/inspectionProfiles/Project_Default.xml +1 -0
- package/README.md +405 -65
- package/config/index.js +2 -0
- package/config/listCrud.js +37 -0
- package/config/objectCrud.js +45 -0
- package/docs.md +186 -24
- package/index.js +1 -0
- package/package.json +2 -2
- package/tests/unit/config/index.spec.js +18 -0
- package/tests/unit/config/listCrud.spec.js +107 -0
- package/tests/unit/config/objectCrud.spec.js +155 -0
- package/tests/unit/use/cancellableIntent.spec.js +1 -1
- package/tests/unit/use/listInstance.spec.js +5 -4
- package/tests/unit/use/listSort.spec.js +1 -1
- package/tests/unit/use/listSubscription.spec.js +3 -5
- package/tests/unit/utils/flattenPaths.spec.js +8 -0
- package/tests/unit/utils/keyDiff.spec.js +44 -1
- package/use/list.js +49 -15
- package/use/listCalculated.js +3 -0
- package/use/listFilter.js +40 -0
- package/use/listInstance.js +79 -27
- package/use/listRelated.js +41 -9
- package/use/listSort.js +71 -41
- package/use/listSubscription.js +57 -15
- package/use/object.js +26 -5
- package/use/objectCalculated.js +26 -39
- package/use/objectInstance.js +19 -35
- package/use/objectRelated.js +24 -34
- package/use/objectSubscription.js +25 -28
- package/utils/flattenPaths.js +11 -3
- package/utils/keyDiff.js +11 -4
package/use/listSort.js
CHANGED
|
@@ -1,14 +1,29 @@
|
|
|
1
1
|
import { assignReactiveObject, keyDiff } from "../utils/index.js";
|
|
2
|
+
import { listCalculatedStateKeys } from "./listCalculated.js";
|
|
3
|
+
import { listFilterStateKeys } from "./listFilter.js";
|
|
4
|
+
import { listInstanceStateKeys } from "./listInstance.js";
|
|
5
|
+
import { listRelatedStateKeys } from "./listRelated.js";
|
|
6
|
+
import { listSubscriptionStateKeys } from "./listSubscription.js";
|
|
2
7
|
import cloneDeep from "lodash-es/cloneDeep.js";
|
|
3
8
|
import get from "lodash-es/get.js";
|
|
4
9
|
import identity from "lodash-es/identity.js";
|
|
5
10
|
import isEmpty from "lodash-es/isEmpty.js";
|
|
6
11
|
import isNull from "lodash-es/isNull.js";
|
|
7
12
|
import isUndefined from "lodash-es/isUndefined.js";
|
|
8
|
-
import partial from "lodash-es/partial.js";
|
|
9
13
|
import throttle from "lodash-es/throttle.js";
|
|
10
14
|
import zip from "lodash-es/zip.js";
|
|
11
|
-
import { effectScope,
|
|
15
|
+
import { effectScope, reactive, toRef, unref, watch } from "vue";
|
|
16
|
+
|
|
17
|
+
export const listSortStateKeys = [
|
|
18
|
+
"orderByRules",
|
|
19
|
+
// "order",
|
|
20
|
+
// "objectsInOrder",
|
|
21
|
+
"sortCriteria",
|
|
22
|
+
"sortCriteriaEffectScopes",
|
|
23
|
+
"orderByDesc",
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
export const listSortFunctions = [];
|
|
12
27
|
|
|
13
28
|
const collator = new Intl.Collator(undefined, { numeric: true });
|
|
14
29
|
|
|
@@ -39,42 +54,43 @@ export function useListSort({ parentState, orderByRules, sortThrottleWait = defa
|
|
|
39
54
|
order: [],
|
|
40
55
|
objectsInOrder: [],
|
|
41
56
|
sortCriteria: {},
|
|
42
|
-
|
|
57
|
+
sortCriteriaEffectScopes: {},
|
|
43
58
|
orderByDesc: [],
|
|
44
59
|
});
|
|
45
60
|
const es = effectScope();
|
|
46
61
|
|
|
47
62
|
function removeSortCriteria(removedKey) {
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
stopWatch = stopWatches.pop();
|
|
63
|
+
const oldScope = state.sortCriteriaEffectScopes[removedKey];
|
|
64
|
+
if (oldScope) {
|
|
65
|
+
oldScope.stop();
|
|
66
|
+
delete state.sortCriteriaEffectScopes[removedKey];
|
|
53
67
|
}
|
|
54
|
-
delete state.sortCriteriaWatches[removedKey];
|
|
55
68
|
delete state.sortCriteria[removedKey];
|
|
56
69
|
}
|
|
57
70
|
|
|
58
71
|
function addSortCriteria(object, key) {
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
stopWatch();
|
|
63
|
-
stopWatch = oldStopWatches.pop();
|
|
72
|
+
const oldScope = state.sortCriteriaEffectScopes[key];
|
|
73
|
+
if (oldScope) {
|
|
74
|
+
oldScope.stop();
|
|
64
75
|
}
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
state.sortCriteria[key]
|
|
68
|
-
|
|
69
|
-
|
|
76
|
+
const newScope = effectScope();
|
|
77
|
+
newScope.run(() => {
|
|
78
|
+
if (!state.sortCriteria[key]) {
|
|
79
|
+
state.sortCriteria[key] = [];
|
|
80
|
+
}
|
|
70
81
|
watch(
|
|
71
|
-
[object, state
|
|
82
|
+
[object, toRef(state, "orderByRules")],
|
|
72
83
|
() => {
|
|
84
|
+
const obj = unref(object);
|
|
73
85
|
const newSearchCriteria = [];
|
|
74
86
|
for (const orderByObj of state.orderByRules.filter(identity)) {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
87
|
+
let newItem;
|
|
88
|
+
if (orderByObj.keyFn) {
|
|
89
|
+
newItem = orderByObj.keyFn(obj, state);
|
|
90
|
+
} else {
|
|
91
|
+
newItem = get(obj, orderByObj.key);
|
|
92
|
+
}
|
|
93
|
+
newSearchCriteria.push(newItem);
|
|
78
94
|
}
|
|
79
95
|
assignReactiveObject(state.sortCriteria[key], newSearchCriteria);
|
|
80
96
|
},
|
|
@@ -82,9 +98,9 @@ export function useListSort({ parentState, orderByRules, sortThrottleWait = defa
|
|
|
82
98
|
deep: true,
|
|
83
99
|
immediate: true,
|
|
84
100
|
}
|
|
85
|
-
)
|
|
86
|
-
);
|
|
87
|
-
state.
|
|
101
|
+
);
|
|
102
|
+
});
|
|
103
|
+
state.sortCriteriaEffectScopes[key] = newScope;
|
|
88
104
|
}
|
|
89
105
|
|
|
90
106
|
function sortCriteriaWatch() {
|
|
@@ -101,10 +117,12 @@ export function useListSort({ parentState, orderByRules, sortThrottleWait = defa
|
|
|
101
117
|
removeSortCriteria(removedKey);
|
|
102
118
|
}
|
|
103
119
|
|
|
104
|
-
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
120
|
+
es.run(() => {
|
|
121
|
+
for (const addedKey of addedKeys) {
|
|
122
|
+
const object = toRef(() => parentState.objects[addedKey]);
|
|
123
|
+
addSortCriteria(object, addedKey);
|
|
124
|
+
}
|
|
125
|
+
});
|
|
108
126
|
assignReactiveObject(
|
|
109
127
|
state.orderByDesc,
|
|
110
128
|
state.orderByRules.filter(identity).map((e) => e.desc || false)
|
|
@@ -113,8 +131,9 @@ export function useListSort({ parentState, orderByRules, sortThrottleWait = defa
|
|
|
113
131
|
|
|
114
132
|
function sortWatch() {
|
|
115
133
|
if (!state.orderByRules || !state.orderByRules.length) {
|
|
116
|
-
|
|
117
|
-
assignReactiveObject(state.
|
|
134
|
+
console.log("sortWatch no orderByRules");
|
|
135
|
+
assignReactiveObject(state.order, cloneDeep(parentState.order));
|
|
136
|
+
assignReactiveObject(state.objectsInOrder, cloneDeep(parentState.objectsInOrder));
|
|
118
137
|
return;
|
|
119
138
|
}
|
|
120
139
|
|
|
@@ -161,23 +180,34 @@ export function useListSort({ parentState, orderByRules, sortThrottleWait = defa
|
|
|
161
180
|
const throttledSortWatch = throttle(sortWatch, sortThrottleWait);
|
|
162
181
|
|
|
163
182
|
es.run(() => {
|
|
164
|
-
|
|
183
|
+
for (const key of listInstanceStateKeys) {
|
|
184
|
+
if (["order", "objectsInOrder"].includes(key)) {
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
state[key] = toRef(parentState, key);
|
|
188
|
+
}
|
|
189
|
+
for (const key of listSubscriptionStateKeys) {
|
|
190
|
+
state[key] = toRef(parentState, key);
|
|
191
|
+
}
|
|
192
|
+
for (const key of listRelatedStateKeys) {
|
|
193
|
+
state[key] = toRef(parentState, key);
|
|
194
|
+
}
|
|
195
|
+
for (const key of listCalculatedStateKeys) {
|
|
196
|
+
state[key] = toRef(parentState, key);
|
|
197
|
+
}
|
|
198
|
+
for (const key of listFilterStateKeys) {
|
|
199
|
+
state[key] = toRef(parentState, key);
|
|
200
|
+
}
|
|
165
201
|
// we do not need two immediate watches to the same function.
|
|
166
202
|
watch(() => Object.keys(parentState.objects), sortCriteriaWatch);
|
|
167
|
-
watch((
|
|
203
|
+
watch(toRef(state, "orderByRules"), sortCriteriaWatch, {
|
|
168
204
|
deep: true,
|
|
169
205
|
immediate: true,
|
|
170
206
|
});
|
|
171
207
|
|
|
172
|
-
|
|
173
|
-
watch([toRef(state, "orderByDesc"), () => state.sortCriteria], throttledSortWatch, {
|
|
208
|
+
watch([toRef(state, "orderByDesc"), toRef(state, "sortCriteria")], throttledSortWatch, {
|
|
174
209
|
deep: true,
|
|
175
210
|
});
|
|
176
|
-
onScopeDispose(() => {
|
|
177
|
-
Object.keys(state.sortCriteriaWatches).forEach((key) => {
|
|
178
|
-
removeSortCriteria(key);
|
|
179
|
-
});
|
|
180
|
-
});
|
|
181
211
|
});
|
|
182
212
|
|
|
183
213
|
return {
|
package/use/listSubscription.js
CHANGED
|
@@ -14,10 +14,6 @@ export class ListSubscriptionError extends Error {
|
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
const defaultCrud = {
|
|
18
|
-
subscribe: undefined,
|
|
19
|
-
};
|
|
20
|
-
|
|
21
17
|
export const listSubscriptionStateKeys = [
|
|
22
18
|
"subscriptionLoading",
|
|
23
19
|
"subscriptionErrored",
|
|
@@ -27,10 +23,25 @@ export const listSubscriptionStateKeys = [
|
|
|
27
23
|
"subscribed",
|
|
28
24
|
];
|
|
29
25
|
|
|
30
|
-
export
|
|
31
|
-
defaultCrud.subscribe = subscribe;
|
|
32
|
-
}
|
|
26
|
+
export const listSubscriptionFunctions = ["subscribe", "unsubscribe", "clearError"];
|
|
33
27
|
|
|
28
|
+
/**
|
|
29
|
+
* The configuration options used to create a list subscription.
|
|
30
|
+
* @typedef {object} ListSubscriptionOptions
|
|
31
|
+
* @property {object} props - passed on to a created list instance if one is not provided
|
|
32
|
+
* @property {object} functions - passed on to a created list instance if one is not provided
|
|
33
|
+
* @property {ListInstance} listInstance - a list instance to use instead of creating one
|
|
34
|
+
* @property {boolean} keepOldPages - if true, pages will not be cleared when defaultPageCallback is called. default is false.
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
/* eslint-disable jsdoc/check-types */
|
|
38
|
+
// types valid for jsdoc-to-markdown, which uses the strict jsdoc.app. Object shorthand syntax doesn't work.
|
|
39
|
+
/**
|
|
40
|
+
* A Vue composition function that creates multiple list instances, and returns them as an object.
|
|
41
|
+
* @param {Object.<string, ListInstanceOptions>} listInstanceArgs - each desired list instance options, keyed by an instance name.
|
|
42
|
+
* @returns {Object.<string, ListInstance>} - each list instance, keyed by the instance name.
|
|
43
|
+
*/
|
|
44
|
+
/* eslint-enable jsdoc/check-types */
|
|
34
45
|
export function useListSubscriptions(args, listInstances = {}) {
|
|
35
46
|
const subscriptions = {};
|
|
36
47
|
for (const [key, value] of Object.entries(args)) {
|
|
@@ -39,13 +50,43 @@ export function useListSubscriptions(args, listInstances = {}) {
|
|
|
39
50
|
return subscriptions;
|
|
40
51
|
}
|
|
41
52
|
|
|
42
|
-
|
|
53
|
+
/**
|
|
54
|
+
* A reactive object that manages a list of objects, as returned by `useListInstance`.
|
|
55
|
+
* @typedef {object} ListSubscriptionState
|
|
56
|
+
* @augments ListInstanceState
|
|
57
|
+
* @property {boolean} subscriptionLoading - true if the subscription is loading
|
|
58
|
+
* @property {boolean} subscriptionErrored - true if the subscription errored
|
|
59
|
+
* @property {Error} subscriptionError - the error that caused the subscription to error
|
|
60
|
+
* @property {boolean} intendToList - true if the list should be fetched, or refetched when args change
|
|
61
|
+
* @property {boolean} intendToSubscribe - true if the list should subscribe for updates
|
|
62
|
+
* @property {boolean} subscribed - true if the subscription is active
|
|
63
|
+
*/
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* @typedef {object} ListSubscription
|
|
67
|
+
* @property {ListSubscriptionState} state - the reactive state of the list subscription
|
|
68
|
+
* @property {ListInstance} listInstance - the list instance used by the subscription
|
|
69
|
+
* @property {object} listIntent - the useCancelleableIntent object managing if the list should be (re)fetched
|
|
70
|
+
* @property {object} subscriptionIntent - the useCancelleableIntent object managing if the subscription should be (un)subscribed
|
|
71
|
+
* @property {Function} subscribe - subscribe to the list
|
|
72
|
+
* @property {Function} unsubscribe - unsubscribe from the list
|
|
73
|
+
* @property {Function} clearError - clear the subscription error
|
|
74
|
+
* @property {object} effectScope - a Vue effect scope
|
|
75
|
+
*/
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* `useListSubscription` creates a reactive object that manages a list of objects, as returned by `useListInstance`,
|
|
79
|
+
* causing the list to be re-fetched as needed and listening for updates to the list.
|
|
80
|
+
* @param {ListSubscriptionOptions} options
|
|
81
|
+
* @returns ListSubscription
|
|
82
|
+
*/
|
|
83
|
+
export function useListSubscription({ listInstance, props, functions, keepOldPages = false }) {
|
|
43
84
|
if (!listInstance && !props) {
|
|
44
|
-
throw new ListSubscriptionError("useListSubscription should be passed listInstance or props and
|
|
85
|
+
throw new ListSubscriptionError("useListSubscription should be passed listInstance or props and functions.");
|
|
45
86
|
}
|
|
46
87
|
if (listInstance && props) {
|
|
47
88
|
throw new ListSubscriptionError(
|
|
48
|
-
"useListSubscription should be passed listInstance or props and
|
|
89
|
+
"useListSubscription should be passed listInstance or props and functions, not both."
|
|
49
90
|
);
|
|
50
91
|
}
|
|
51
92
|
if (!listInstance) {
|
|
@@ -55,10 +96,11 @@ export function useListSubscription({ listInstance, props, functions }) {
|
|
|
55
96
|
if (!("retrieveArgs" in props)) {
|
|
56
97
|
console.error("retrieveArgs not set, must be true for intendToList or intendToSubscribe to work.");
|
|
57
98
|
}
|
|
58
|
-
listInstance = useListInstance({ props, functions });
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
|
|
99
|
+
listInstance = useListInstance({ props, functions, keepOldPages });
|
|
100
|
+
} else {
|
|
101
|
+
if (functions) {
|
|
102
|
+
console.error("functions passed to useListSubscription, but listInstance was passed. functions ignored.");
|
|
103
|
+
}
|
|
62
104
|
}
|
|
63
105
|
const parentState = listInstance.state;
|
|
64
106
|
|
|
@@ -188,7 +230,7 @@ export function useListSubscription({ listInstance, props, functions }) {
|
|
|
188
230
|
state.subscriptionErrored = true;
|
|
189
231
|
state.subscriptionError = err;
|
|
190
232
|
});
|
|
191
|
-
catchPromise.cancel = subscribePromise.cancel;
|
|
233
|
+
catchPromise.cancel = subscribePromise.cancel.bind(subscribePromise);
|
|
192
234
|
return catchPromise;
|
|
193
235
|
},
|
|
194
236
|
watchArguments: reactive({
|
package/use/object.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { useObjectCalculated } from "./objectCalculated.js";
|
|
2
|
-
import { useObjectInstance } from "./objectInstance.js";
|
|
3
|
-
import { useObjectRelated } from "./objectRelated.js";
|
|
4
|
-
import { useObjectSubscription } from "./objectSubscription.js";
|
|
1
|
+
import { useObjectCalculated, objectCalculatedFunctions } from "./objectCalculated.js";
|
|
2
|
+
import { useObjectInstance, objectInstanceFunctions } from "./objectInstance.js";
|
|
3
|
+
import { useObjectRelated, objectRelatedFunctions } from "./objectRelated.js";
|
|
4
|
+
import { useObjectSubscription, objectSubscriptionFunctions } from "./objectSubscription.js";
|
|
5
5
|
import { effectScope, reactive, shallowReadonly, toRef } from "vue";
|
|
6
6
|
|
|
7
7
|
// Manages a chain of useObject* functions
|
|
@@ -49,7 +49,7 @@ export const useObject = ({ props, functions }) => {
|
|
|
49
49
|
// objectInstance.clear also does objectInstance.clearError
|
|
50
50
|
managed.objectInstance.clear();
|
|
51
51
|
};
|
|
52
|
-
|
|
52
|
+
const returnObject = reactive({
|
|
53
53
|
managed: shallowReadonly(managed),
|
|
54
54
|
state: managed.objectCalculated.state,
|
|
55
55
|
retrieve: managed.objectInstance.retrieve,
|
|
@@ -64,4 +64,25 @@ export const useObject = ({ props, functions }) => {
|
|
|
64
64
|
clear,
|
|
65
65
|
effectScope: es,
|
|
66
66
|
});
|
|
67
|
+
const handledDuplicateFunctions = {
|
|
68
|
+
clearError,
|
|
69
|
+
clear,
|
|
70
|
+
};
|
|
71
|
+
for (const [source, fnNames] of [
|
|
72
|
+
[managed.objectInstance, objectInstanceFunctions],
|
|
73
|
+
[managed.objectSubscription, objectSubscriptionFunctions],
|
|
74
|
+
[managed.objectRelated, objectRelatedFunctions],
|
|
75
|
+
[managed.objectCalculated, objectCalculatedFunctions],
|
|
76
|
+
]) {
|
|
77
|
+
for (const fnName of fnNames) {
|
|
78
|
+
if (handledDuplicateFunctions[fnName]) {
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
returnObject[fnName] = source[fnName];
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
for (const [fnName, fn] of Object.entries(handledDuplicateFunctions)) {
|
|
85
|
+
returnObject[fnName] = fn;
|
|
86
|
+
}
|
|
87
|
+
return returnObject;
|
|
67
88
|
};
|
package/use/objectCalculated.js
CHANGED
|
@@ -1,8 +1,21 @@
|
|
|
1
|
-
import { keyDiff
|
|
1
|
+
import { keyDiff } from "../utils/keyDiff.js";
|
|
2
|
+
import { loadingCombine } from "../utils/loadingCombine.js";
|
|
3
|
+
import { objectInstanceStateKeys } from "./objectInstance.js";
|
|
4
|
+
import { objectRelatedStateKeys } from "./objectRelated.js";
|
|
5
|
+
import { objectSubscriptionStateKeys } from "./objectSubscription.js";
|
|
2
6
|
import { useWatchesRunning } from "./watchesRunning.js";
|
|
3
7
|
import isEmpty from "lodash-es/isEmpty.js";
|
|
4
8
|
import { computed, effectScope, onScopeDispose, reactive, toRef, watch } from "vue";
|
|
5
9
|
|
|
10
|
+
export const objectCalculatedStateKeys = [
|
|
11
|
+
"calculatedObject",
|
|
12
|
+
"calculatedObjectRules",
|
|
13
|
+
"calculatedObjectWatchRunning",
|
|
14
|
+
"parentStateObjectWatchRunning",
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
export const objectCalculatedFunctions = [];
|
|
18
|
+
|
|
6
19
|
export function useObjectCalculateds(instances, args) {
|
|
7
20
|
for (const [key, value] of Object.entries(args)) {
|
|
8
21
|
useObjectCalculated({
|
|
@@ -13,54 +26,28 @@ export function useObjectCalculateds(instances, args) {
|
|
|
13
26
|
}
|
|
14
27
|
|
|
15
28
|
// the single object version of useListCalculated
|
|
16
|
-
export function useObjectCalculated({
|
|
17
|
-
parentState,
|
|
18
|
-
calculatedObjectRules,
|
|
19
|
-
calculatedObjectPropertyName = "calculatedObject", // NOT REACTIVE
|
|
20
|
-
passThroughPropertyNames = [
|
|
21
|
-
// instance
|
|
22
|
-
"crud",
|
|
23
|
-
"deleted",
|
|
24
|
-
"error",
|
|
25
|
-
"errored",
|
|
26
|
-
"id",
|
|
27
|
-
"loading",
|
|
28
|
-
"object",
|
|
29
|
-
"retrieveArgs",
|
|
30
|
-
// subscription
|
|
31
|
-
"intendToRetrieve",
|
|
32
|
-
"intendToSubscribe",
|
|
33
|
-
"subscribed",
|
|
34
|
-
"subscriptionError",
|
|
35
|
-
"subscriptionErrored",
|
|
36
|
-
"subscriptionLoading",
|
|
37
|
-
// related
|
|
38
|
-
"relatedObject",
|
|
39
|
-
"relatedObjectObjects",
|
|
40
|
-
"relatedObjectRules",
|
|
41
|
-
"relatedObjectWatchRunning",
|
|
42
|
-
"relatedRunning",
|
|
43
|
-
], // NOT REACTIVE
|
|
44
|
-
}) {
|
|
29
|
+
export function useObjectCalculated({ parentState, calculatedObjectRules }) {
|
|
45
30
|
const state = reactive({
|
|
46
31
|
calculatedObjectRules,
|
|
47
|
-
|
|
32
|
+
calculatedObject: {},
|
|
48
33
|
parentStateObjectWatchRunning: false,
|
|
49
34
|
calculatedObjectWatchRunning: false,
|
|
50
35
|
});
|
|
51
36
|
const calculatedObjectEffectScopes = {};
|
|
52
37
|
const calculatedObjectOriginalFunctions = {};
|
|
53
38
|
|
|
54
|
-
// don't change calculatedObjectPropertyName on us or it will break
|
|
55
|
-
const copn = calculatedObjectPropertyName + "";
|
|
56
|
-
|
|
57
39
|
let watchesRunning = null;
|
|
58
40
|
|
|
59
41
|
const es = effectScope();
|
|
60
42
|
|
|
61
43
|
es.run(() => {
|
|
62
|
-
|
|
63
|
-
|
|
44
|
+
for (const key of objectInstanceStateKeys) {
|
|
45
|
+
state[key] = toRef(parentState, key);
|
|
46
|
+
}
|
|
47
|
+
for (const key of objectSubscriptionStateKeys) {
|
|
48
|
+
state[key] = toRef(parentState, key);
|
|
49
|
+
}
|
|
50
|
+
for (const key of objectRelatedStateKeys) {
|
|
64
51
|
state[key] = toRef(parentState, key);
|
|
65
52
|
}
|
|
66
53
|
|
|
@@ -84,7 +71,7 @@ export function useObjectCalculated({
|
|
|
84
71
|
}
|
|
85
72
|
for (const removedKey of removedKeys) {
|
|
86
73
|
delete calculatedObjectOriginalFunctions[removedKey];
|
|
87
|
-
delete state.
|
|
74
|
+
delete state.calculatedObject[removedKey];
|
|
88
75
|
if (calculatedObjectEffectScopes[removedKey]) {
|
|
89
76
|
calculatedObjectEffectScopes[removedKey].stop();
|
|
90
77
|
delete calculatedObjectEffectScopes[removedKey];
|
|
@@ -94,7 +81,7 @@ export function useObjectCalculated({
|
|
|
94
81
|
calculatedObjectOriginalFunctions[addedKey] = state.calculatedObjectRules[addedKey];
|
|
95
82
|
calculatedObjectEffectScopes[addedKey] = effectScope();
|
|
96
83
|
calculatedObjectEffectScopes[addedKey].run(() => {
|
|
97
|
-
state.
|
|
84
|
+
state.calculatedObject[addedKey] = computed(() =>
|
|
98
85
|
calculatedObjectOriginalFunctions[addedKey](state.object)
|
|
99
86
|
);
|
|
100
87
|
});
|
|
@@ -110,7 +97,7 @@ export function useObjectCalculated({
|
|
|
110
97
|
});
|
|
111
98
|
|
|
112
99
|
state.calculatedRunning = toRef(watchesRunning.state, "running");
|
|
113
|
-
state.running = computed(() => loadingCombine(watchesRunning.state.running, parentState.
|
|
100
|
+
state.running = computed(() => loadingCombine(watchesRunning.state.running, parentState.running));
|
|
114
101
|
|
|
115
102
|
onScopeDispose(() => {
|
|
116
103
|
for (const key in calculatedObjectEffectScopes) {
|
package/use/objectInstance.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import isFunction from "lodash-es/isFunction.js";
|
|
1
|
+
import { getObjectCrud } from "../config/objectCrud.js";
|
|
2
|
+
import { assignReactiveObject } from "../utils/assignReactiveObject.js";
|
|
4
3
|
import { reactive, toRef } from "vue";
|
|
5
4
|
|
|
6
5
|
export class ObjectError extends Error {
|
|
@@ -10,23 +9,18 @@ export class ObjectError extends Error {
|
|
|
10
9
|
}
|
|
11
10
|
}
|
|
12
11
|
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
12
|
+
export const objectInstanceStateKeys = [
|
|
13
|
+
"crud",
|
|
14
|
+
"id",
|
|
15
|
+
"retrieveArgs",
|
|
16
|
+
"object",
|
|
17
|
+
"loading",
|
|
18
|
+
"errored",
|
|
19
|
+
"error",
|
|
20
|
+
"deleted",
|
|
21
|
+
];
|
|
21
22
|
|
|
22
|
-
export
|
|
23
|
-
defaultCrud.retrieve = retrieve;
|
|
24
|
-
defaultCrud.create = create;
|
|
25
|
-
defaultCrud.update = update;
|
|
26
|
-
defaultCrud.patch = patch;
|
|
27
|
-
defaultCrud.delete = deleteFn;
|
|
28
|
-
Object.assign(defaultCrud.args, args);
|
|
29
|
-
}
|
|
23
|
+
export const objectInstanceFunctions = ["create", "retrieve", "update", "delete", "patch", "clearError", "clear"];
|
|
30
24
|
|
|
31
25
|
export function useObjectInstances(instanceArgs) {
|
|
32
26
|
const instances = {};
|
|
@@ -40,11 +34,11 @@ export function useObjectInstance({ props, functions = {} }) {
|
|
|
40
34
|
const state = reactive({
|
|
41
35
|
crud: {
|
|
42
36
|
args: {},
|
|
43
|
-
retrieve: undefined,
|
|
44
37
|
create: undefined,
|
|
38
|
+
retrieve: undefined,
|
|
45
39
|
update: undefined,
|
|
46
|
-
patch: undefined,
|
|
47
40
|
delete: undefined,
|
|
41
|
+
patch: undefined,
|
|
48
42
|
},
|
|
49
43
|
object: {},
|
|
50
44
|
id: toRef(props, "id"),
|
|
@@ -54,18 +48,8 @@ export function useObjectInstance({ props, functions = {} }) {
|
|
|
54
48
|
error: null,
|
|
55
49
|
deleted: false,
|
|
56
50
|
});
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
if (props.crudArgs) {
|
|
60
|
-
addOrUpdateReactiveObject(state.crud.args, props.crudArgs);
|
|
61
|
-
}
|
|
62
|
-
for (const [key, value] of Object.entries(functions)) {
|
|
63
|
-
if (isFunction(value) && key in state.crud) {
|
|
64
|
-
state[key] = value;
|
|
65
|
-
} else {
|
|
66
|
-
throw ObjectError(`Invalid function "${key}" for useObjectInstance: invalid key or not a function.`);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
51
|
+
|
|
52
|
+
getObjectCrud(state.crud, { props, functions });
|
|
69
53
|
|
|
70
54
|
// due to retrieve being called by `useCancelleableIntent`, if called manually then by the watch,
|
|
71
55
|
// it will run into the loading check. Instead, return the current retrieve promise if it exists.
|
|
@@ -229,11 +213,11 @@ export function useObjectInstance({ props, functions = {} }) {
|
|
|
229
213
|
|
|
230
214
|
return reactive({
|
|
231
215
|
state,
|
|
232
|
-
retrieve,
|
|
233
216
|
create,
|
|
217
|
+
retrieve,
|
|
234
218
|
update,
|
|
235
|
-
patch,
|
|
236
219
|
delete: deleteFn,
|
|
220
|
+
patch,
|
|
237
221
|
clearError,
|
|
238
222
|
clear,
|
|
239
223
|
});
|
package/use/objectRelated.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { loadingCombine } from "../utils/index.js";
|
|
2
|
+
import { keyDiff } from "../utils/keyDiff.js";
|
|
3
|
+
import { objectInstanceStateKeys } from "./objectInstance.js";
|
|
4
|
+
import { objectSubscriptionStateKeys } from "./objectSubscription.js";
|
|
2
5
|
import { useWatchesRunning } from "./watchesRunning.js";
|
|
3
6
|
import get from "lodash-es/get.js";
|
|
4
7
|
import isArray from "lodash-es/isArray.js";
|
|
@@ -6,6 +9,15 @@ import isEmpty from "lodash-es/isEmpty.js";
|
|
|
6
9
|
import isUndefined from "lodash-es/isUndefined.js";
|
|
7
10
|
import { computed, effectScope, onScopeDispose, reactive, toRef, unref, watch } from "vue";
|
|
8
11
|
|
|
12
|
+
export const objectRelatedStateKeys = [
|
|
13
|
+
"relatedObject",
|
|
14
|
+
"relatedObjectRules",
|
|
15
|
+
"relatedObjectWatchRunning",
|
|
16
|
+
"parentStateObjectWatchRunning",
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
export const objectRelatedFunctions = [];
|
|
20
|
+
|
|
9
21
|
export function useObjectRelateds(instances, args) {
|
|
10
22
|
for (const [key, value] of Object.entries(args)) {
|
|
11
23
|
useObjectRelated({
|
|
@@ -16,47 +28,24 @@ export function useObjectRelateds(instances, args) {
|
|
|
16
28
|
}
|
|
17
29
|
|
|
18
30
|
// the single object version of useListRelated
|
|
19
|
-
export function useObjectRelated({
|
|
20
|
-
parentState,
|
|
21
|
-
relatedObjectRules,
|
|
22
|
-
relatedObjectPropertyName = "relatedObject", // NOT REACTIVE
|
|
23
|
-
passThroughPropertyNames = [
|
|
24
|
-
// instance
|
|
25
|
-
"crud",
|
|
26
|
-
"deleted",
|
|
27
|
-
"error",
|
|
28
|
-
"errored",
|
|
29
|
-
"id",
|
|
30
|
-
"loading",
|
|
31
|
-
"object",
|
|
32
|
-
"retrieveArgs",
|
|
33
|
-
// subscription
|
|
34
|
-
"intendToRetrieve",
|
|
35
|
-
"intendToSubscribe",
|
|
36
|
-
"subscribed",
|
|
37
|
-
"subscriptionError",
|
|
38
|
-
"subscriptionErrored",
|
|
39
|
-
"subscriptionLoading",
|
|
40
|
-
], // NOT REACTIVE
|
|
41
|
-
}) {
|
|
31
|
+
export function useObjectRelated({ parentState, relatedObjectRules }) {
|
|
42
32
|
const state = reactive({
|
|
43
33
|
relatedObjectRules,
|
|
44
|
-
|
|
34
|
+
relatedObject: {},
|
|
45
35
|
parentStateObjectWatchRunning: false,
|
|
46
36
|
relatedObjectWatchRunning: false,
|
|
47
37
|
});
|
|
48
38
|
const relatedObjectEffectScopes = {};
|
|
49
39
|
|
|
50
|
-
// don't change relatedObjectPropertyName on us or it will break
|
|
51
|
-
const ropn = relatedObjectPropertyName + "";
|
|
52
|
-
|
|
53
40
|
let watchesRunning = null;
|
|
54
41
|
|
|
55
42
|
const es = effectScope();
|
|
56
43
|
|
|
57
44
|
es.run(() => {
|
|
58
|
-
|
|
59
|
-
|
|
45
|
+
for (const key of objectInstanceStateKeys) {
|
|
46
|
+
state[key] = toRef(parentState, key);
|
|
47
|
+
}
|
|
48
|
+
for (const key of objectSubscriptionStateKeys) {
|
|
60
49
|
state[key] = toRef(parentState, key);
|
|
61
50
|
}
|
|
62
51
|
|
|
@@ -64,16 +53,16 @@ export function useObjectRelated({
|
|
|
64
53
|
let addedRuleKeys = [],
|
|
65
54
|
removedRuleKeys = [];
|
|
66
55
|
if (!state.relatedObjectRules) {
|
|
67
|
-
removedRuleKeys = Object.keys(state.
|
|
56
|
+
removedRuleKeys = Object.keys(state.relatedObject);
|
|
68
57
|
} else {
|
|
69
58
|
({ addedKeys: addedRuleKeys, removedKeys: removedRuleKeys } = keyDiff(
|
|
70
59
|
Object.keys(state.relatedObjectRules),
|
|
71
|
-
Object.keys(state.
|
|
60
|
+
Object.keys(state.relatedObject)
|
|
72
61
|
));
|
|
73
62
|
}
|
|
74
63
|
|
|
75
64
|
for (const removedRuleKey of removedRuleKeys) {
|
|
76
|
-
delete state.
|
|
65
|
+
delete state.relatedObject[removedRuleKey];
|
|
77
66
|
if (relatedObjectEffectScopes[removedRuleKey]) {
|
|
78
67
|
relatedObjectEffectScopes[removedRuleKey].stop();
|
|
79
68
|
delete relatedObjectEffectScopes[removedRuleKey];
|
|
@@ -82,7 +71,7 @@ export function useObjectRelated({
|
|
|
82
71
|
for (const addedRuleKey of addedRuleKeys) {
|
|
83
72
|
relatedObjectEffectScopes[addedRuleKey] = effectScope();
|
|
84
73
|
relatedObjectEffectScopes[addedRuleKey].run(() => {
|
|
85
|
-
state.
|
|
74
|
+
state.relatedObject[addedRuleKey] = computed(() => {
|
|
86
75
|
// deal with computed objects being passed.
|
|
87
76
|
const ruleObjects = unref(state.relatedObjectRules?.[addedRuleKey]?.objects);
|
|
88
77
|
const rulePkKey = state.relatedObjectRules?.[addedRuleKey]?.pkKey || addedRuleKey;
|
|
@@ -111,6 +100,7 @@ export function useObjectRelated({
|
|
|
111
100
|
});
|
|
112
101
|
|
|
113
102
|
state.relatedRunning = toRef(watchesRunning.state, "running");
|
|
103
|
+
state.running = computed(() => loadingCombine(watchesRunning.state.running, parentState.running));
|
|
114
104
|
|
|
115
105
|
onScopeDispose(() => {
|
|
116
106
|
for (const key in relatedObjectEffectScopes) {
|