@arrai-innovations/reactive-helpers 22.0.0 → 22.1.0
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/README.md +3 -3
- package/config/commonCrud.js +3 -4
- package/config/listCrud.js +13 -11
- package/config/objectCrud.js +36 -24
- package/package.json +11 -1
- package/types/config/listCrud.d.ts +6 -8
- package/types/config/objectCrud.d.ts +33 -22
- package/types/tests/benchmarks/fixtures.d.ts +60 -0
- package/types/tests/benchmarks/listLayers.bench.d.ts +1 -0
- package/types/tests/benchmarks/listPush.bench.d.ts +1 -0
- package/types/tests/benchmarks/listStream.bench.d.ts +1 -0
- package/types/tests/unit/use/lifecycleCleanup.spec.d.ts +1 -0
- package/types/tests/unit/use/listPerformance.spec.d.ts +1 -0
- package/types/tests/unit/utils/cancellablePromise.spec.d.ts +1 -0
- package/types/use/cancellableIntent.d.ts +9 -2
- package/types/use/combineClasses.d.ts +1 -1
- package/types/use/listCalculated.d.ts +21 -20
- package/types/use/listInstance.d.ts +6 -1
- package/types/use/listRelated.d.ts +15 -15
- package/types/use/listSort.d.ts +6 -1
- package/types/use/listSubscription.d.ts +6 -2
- package/types/use/objectCalculated.d.ts +18 -14
- package/types/use/objectInstance.d.ts +4 -2
- package/types/use/objectRelated.d.ts +11 -9
- package/types/use/objectSubscription.d.ts +6 -5
- package/types/utils/cancellableFetch.d.ts +2 -3
- package/types/utils/cancellablePromise.d.ts +39 -5
- package/types/utils/getFakePk.d.ts +2 -2
- package/use/cancellableIntent.js +9 -2
- package/use/combineClasses.js +1 -1
- package/use/listCalculated.js +22 -17
- package/use/listFilter.js +4 -3
- package/use/listInstance.js +76 -16
- package/use/listRelated.js +9 -9
- package/use/listSearch.js +1 -1
- package/use/listSort.js +68 -23
- package/use/listSubscription.js +10 -1
- package/use/object.js +7 -8
- package/use/objectCalculated.js +13 -11
- package/use/objectInstance.js +9 -3
- package/use/objectRelated.js +6 -5
- package/use/objectSubscription.js +7 -5
- package/use/proxyLoadingError.js +3 -0
- package/utils/cancellableFetch.js +3 -3
- package/utils/cancellablePromise.js +21 -4
- package/utils/getFakePk.js +2 -2
package/use/objectCalculated.js
CHANGED
|
@@ -16,15 +16,17 @@ import { computed, effectScope, nextTick, onScopeDispose, reactive, ref, toRef,
|
|
|
16
16
|
/**
|
|
17
17
|
* @typedef {{
|
|
18
18
|
* [ruleKey: string]: (object: any, relatedObject: any) => any
|
|
19
|
-
* }} ObjectCalculatedRules -
|
|
19
|
+
* }} ObjectCalculatedRules - Rules for calculating values from the managed object, keyed by rule name. Each rule is used
|
|
20
|
+
* as a computed body and receives exactly two arguments: the managed object and its related objects (the latter only
|
|
21
|
+
* populated when a useObjectRelated sits upstream).
|
|
20
22
|
*/
|
|
21
23
|
|
|
22
24
|
/**
|
|
23
25
|
* @typedef {object} ObjectCalculatedRawState - The raw state for object calculated.
|
|
24
26
|
* @property {ObjectCalculatedRules} calculatedObjectRules - The calculated object rules.
|
|
25
27
|
* @property {{
|
|
26
|
-
* [ruleKey: string]:
|
|
27
|
-
* }} calculatedObject - The calculated
|
|
28
|
+
* [ruleKey: string]: any
|
|
29
|
+
* }} calculatedObject - The calculated values, by rule name. Each entry is backed by a computed, but it is read through a reactive proxy that unwraps it, so reads yield the calculated value and never carry a `.value`.
|
|
28
30
|
* @property {boolean} calculatedObjectWatchRunning - Whether the calculated object watch is running.
|
|
29
31
|
* @property {boolean} parentStateObjectWatchRunning - Whether the parent state object watch is running.
|
|
30
32
|
* @property {boolean} calculatedRunning - Whether the calculated is running.
|
|
@@ -125,7 +127,7 @@ export function useObjectCalculateds(objectCalculatedArgs) {
|
|
|
125
127
|
* ```vue
|
|
126
128
|
* <script setup>
|
|
127
129
|
* import { useObjectCalculated, useObjectSubscription } from "@arrai-innovations/reactive-helpers";
|
|
128
|
-
* import {
|
|
130
|
+
* import { reactive } from "vue";
|
|
129
131
|
*
|
|
130
132
|
* const objectSubscriptionProps = reactive({
|
|
131
133
|
* // whatever object subscription props you need to work with your crud implementation
|
|
@@ -134,21 +136,21 @@ export function useObjectCalculateds(objectCalculatedArgs) {
|
|
|
134
136
|
* pk: '1',
|
|
135
137
|
* pkKey: 'id',
|
|
136
138
|
* intendToRetrieve: true,
|
|
137
|
-
* };
|
|
138
|
-
* const objectSubscription = useObjectSubscription(objectSubscriptionProps);
|
|
139
|
+
* });
|
|
140
|
+
* const objectSubscription = useObjectSubscription({ props: objectSubscriptionProps });
|
|
139
141
|
* const objectCalculatedProps = reactive({
|
|
140
142
|
* parentState: objectSubscription.state,
|
|
141
143
|
* calculatedObjectRules: {
|
|
142
|
-
* someRule: (object, relatedObject
|
|
143
|
-
* // some complex calculation
|
|
144
|
-
* //
|
|
145
|
-
* // including yourself, so try not to create circular dependencies
|
|
144
|
+
* someRule: (object, relatedObject) => {
|
|
145
|
+
* // some complex calculation. relatedObject holds the managed object's related objects, and is
|
|
146
|
+
* // only populated when a useObjectRelated sits between the object and this composable.
|
|
146
147
|
* // this is used as a computed body.
|
|
147
148
|
* return object.someProperty + object.someOtherProperty;
|
|
148
149
|
* },
|
|
149
|
-
* ...
|
|
150
|
+
* // ...further rules
|
|
150
151
|
* },
|
|
151
152
|
* });
|
|
153
|
+
* const objectCalculated = useObjectCalculated(objectCalculatedProps);
|
|
152
154
|
* </script>
|
|
153
155
|
* <template>
|
|
154
156
|
* <div>
|
package/use/objectInstance.js
CHANGED
|
@@ -2,7 +2,7 @@ import { defaultObjectCrud, getObjectCrud } from "../config/objectCrud.js";
|
|
|
2
2
|
import { assignReactiveObject } from "../utils/assignReactiveObject.js";
|
|
3
3
|
import { useLoadingError } from "./loadingError.js";
|
|
4
4
|
import { reactive, readonly, ref } from "vue";
|
|
5
|
-
import {
|
|
5
|
+
import { wrapMaybeCancellable } from "../utils/cancellablePromise.js";
|
|
6
6
|
import { pkRefIfReactive, refIfReactive } from "../utils/refIfReactive.js";
|
|
7
7
|
|
|
8
8
|
/**
|
|
@@ -56,7 +56,8 @@ import { pkRefIfReactive, refIfReactive } from "../utils/refIfReactive.js";
|
|
|
56
56
|
* @property {import('vue').Ref<string|undefined>} pkKey - The pk key of the object.
|
|
57
57
|
* @property {import('vue').Ref<{[key:string]: any}>} params - The arguments to be passed to the retrieve function.
|
|
58
58
|
* @property {import('vue').Reactive<CrudObject>} object - The object.
|
|
59
|
-
* @property {boolean} deleted - Whether the object
|
|
59
|
+
* @property {boolean} deleted - Whether the object was deleted by the delete action or a subscription delete
|
|
60
|
+
* event. Cleared when a later create, retrieve, update, or patch repopulates the object, and by `clear()`.
|
|
60
61
|
*/
|
|
61
62
|
|
|
62
63
|
/**
|
|
@@ -280,6 +281,7 @@ export function useObjectInstance({ props, handlers = {} }) {
|
|
|
280
281
|
createPromise
|
|
281
282
|
.then((/** @type {ExistingCrudObject} */ object) => {
|
|
282
283
|
assignReactiveObject(state.object, object);
|
|
284
|
+
state.deleted = false;
|
|
283
285
|
return true;
|
|
284
286
|
})
|
|
285
287
|
.catch((/** @type {Error} */ error) => {
|
|
@@ -329,13 +331,14 @@ export function useObjectInstance({ props, handlers = {} }) {
|
|
|
329
331
|
} catch (error) {
|
|
330
332
|
loadingError.setError(error);
|
|
331
333
|
loadingError.clearLoading();
|
|
332
|
-
return
|
|
334
|
+
return Promise.resolve(false);
|
|
333
335
|
}
|
|
334
336
|
|
|
335
337
|
promises.retrieve = wrapMaybeCancellable(
|
|
336
338
|
retrievePromise
|
|
337
339
|
.then((/** @type {ExistingCrudObject} */ object) => {
|
|
338
340
|
assignReactiveObject(state.object, object);
|
|
341
|
+
state.deleted = false;
|
|
339
342
|
return true;
|
|
340
343
|
})
|
|
341
344
|
.catch((/** @type {Error} */ error) => {
|
|
@@ -382,6 +385,7 @@ export function useObjectInstance({ props, handlers = {} }) {
|
|
|
382
385
|
updatePromise
|
|
383
386
|
.then((/** @type {ExistingCrudObject} */ object) => {
|
|
384
387
|
assignReactiveObject(state.object, object);
|
|
388
|
+
state.deleted = false;
|
|
385
389
|
return true;
|
|
386
390
|
})
|
|
387
391
|
.catch((/** @type {Error} */ error) => {
|
|
@@ -469,6 +473,7 @@ export function useObjectInstance({ props, handlers = {} }) {
|
|
|
469
473
|
patchPromise
|
|
470
474
|
.then((/** @type {ExistingCrudObject} */ object) => {
|
|
471
475
|
assignReactiveObject(state.object, object);
|
|
476
|
+
state.deleted = false;
|
|
472
477
|
return true;
|
|
473
478
|
})
|
|
474
479
|
.catch((/** @type {Error} */ error) => {
|
|
@@ -533,6 +538,7 @@ export function useObjectInstance({ props, handlers = {} }) {
|
|
|
533
538
|
clear: () => {
|
|
534
539
|
loadingError.clearError();
|
|
535
540
|
assignReactiveObject(state.object, {});
|
|
541
|
+
state.deleted = false;
|
|
536
542
|
},
|
|
537
543
|
};
|
|
538
544
|
return instance;
|
package/use/objectRelated.js
CHANGED
|
@@ -21,9 +21,10 @@ import { computed, effectScope, nextTick, reactive, ref, toRef, unref, watch } f
|
|
|
21
21
|
// todo: pkKey is misnamed, it should be fkKey... this will be a major breaking change.
|
|
22
22
|
/**
|
|
23
23
|
* @typedef {object} ObjectRelatedRule - The rule for defining relationships for the managed object to other collections of objects.
|
|
24
|
-
* @property {string} pkKey - The key in the managed object that corresponds to the key in the related object.
|
|
24
|
+
* @property {string} [pkKey] - The key in the managed object that corresponds to the key in the related object.
|
|
25
|
+
* Defaults to the rule's own key when omitted.
|
|
25
26
|
* @property {import('./listInstance.js').ObjectsByPk} objects - The related objects, indexed by the key in the related object.
|
|
26
|
-
* @property {string[]} order - The order of the related objects, if the related objects are an array.
|
|
27
|
+
* @property {string[]} [order] - The order of the related objects, if the related objects are an array.
|
|
27
28
|
*/
|
|
28
29
|
|
|
29
30
|
/**
|
|
@@ -38,8 +39,8 @@ import { computed, effectScope, nextTick, reactive, ref, toRef, unref, watch } f
|
|
|
38
39
|
* @typedef {object} ObjectRelatedRawState - The raw reactive state of the object related composable, holding its rules, computed relations, and running flags.
|
|
39
40
|
* @property {ObjectRelatedRawRules} relatedObjectRules - The rules for defining relationships for the managed object to other collections of objects.
|
|
40
41
|
* @property {{
|
|
41
|
-
* [rule: string]:
|
|
42
|
-
* }} relatedObject - The related objects,
|
|
42
|
+
* [rule: string]: any,
|
|
43
|
+
* }} relatedObject - The related objects, by rule name. Each entry is backed by a computed, but it is read through a reactive proxy that unwraps it, so reads yield the related object (or array of related objects) and never carry a `.value`.
|
|
43
44
|
* @property {boolean} relatedObjectWatchRunning - Whether the related object watch is running.
|
|
44
45
|
* @property {boolean} parentStateObjectWatchRunning - Whether the parent state object watch is running.
|
|
45
46
|
* @property {boolean} relatedRunning - Whether the related objects are loading.
|
|
@@ -178,7 +179,7 @@ export function useObjectRelateds(objectRelatedArgs) {
|
|
|
178
179
|
* order: ['3','1','2'],
|
|
179
180
|
* },
|
|
180
181
|
* secondOrder: {
|
|
181
|
-
* pkKey: '
|
|
182
|
+
* pkKey: 'relatedItem.firstOrder.secondOrderId',
|
|
182
183
|
* objects: someOtherObjectsSource.objects,
|
|
183
184
|
* },
|
|
184
185
|
* },
|
|
@@ -123,7 +123,7 @@ export function useObjectSubscriptions(subscriptionArgs) {
|
|
|
123
123
|
* ```
|
|
124
124
|
* <script setup>
|
|
125
125
|
* import { useObjectSubscription } from "@arrai-innovations/reactive-helpers";
|
|
126
|
-
* import { reactive,
|
|
126
|
+
* import { reactive, toRef } from "vue";
|
|
127
127
|
*
|
|
128
128
|
* const pkKey = "id";
|
|
129
129
|
* const props = defineProps({
|
|
@@ -142,11 +142,12 @@ export function useObjectSubscriptions(subscriptionArgs) {
|
|
|
142
142
|
* params: {
|
|
143
143
|
* fields: ['foo', 'bar'],
|
|
144
144
|
* },
|
|
145
|
-
* intendToRetrieve:
|
|
146
|
-
* intendToSubscribe:
|
|
145
|
+
* intendToRetrieve: true,
|
|
146
|
+
* intendToSubscribe: true,
|
|
147
|
+
* });
|
|
148
|
+
* const objectSubscription = useObjectSubscription({
|
|
149
|
+
* props: objectSubscriptionProps,
|
|
147
150
|
* });
|
|
148
|
-
* objectSubscriptionProps.intendToRetrieve = objectSubscriptionProps.intendToSubscribe = computed(()=> !!props.pk);
|
|
149
|
-
* const objectSubscription = useObjectSubscription(objectSubscriptionProps);
|
|
150
151
|
* </script>
|
|
151
152
|
* <template>
|
|
152
153
|
* <div v-if="objectSubscription.state.loading">Loading...</div>
|
|
@@ -230,6 +231,7 @@ export function useObjectSubscription({ objectInstance, props, handlers }) {
|
|
|
230
231
|
assignReactiveObject(objectInstance.state.object, {});
|
|
231
232
|
} else {
|
|
232
233
|
assignReactiveObject(objectInstance.state.object, data);
|
|
234
|
+
state.deleted = false;
|
|
233
235
|
}
|
|
234
236
|
};
|
|
235
237
|
const parentState = objectInstance.state;
|
package/use/proxyLoadingError.js
CHANGED
|
@@ -44,5 +44,8 @@ export function asWatchableLoadingError(source) {
|
|
|
44
44
|
return {
|
|
45
45
|
...asWatchableLoading(unwrappedRefs),
|
|
46
46
|
...asWatchableError(unwrappedRefs),
|
|
47
|
+
// Preserve clearError: for a separate-state source it lives on the source
|
|
48
|
+
// itself, not on state, so extracting state above would otherwise drop it.
|
|
49
|
+
clearError: unwrappedSource.clearError,
|
|
47
50
|
};
|
|
48
51
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { makeCancellable } from "./cancellablePromise.js";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* A wrapper around fetch that adds cancellation via AbortController and returns a CancellablePromise.
|
|
@@ -7,7 +7,7 @@ import { CancellablePromise } from "./cancellablePromise.js";
|
|
|
7
7
|
* @param {RequestInfo} input - The URL or Request object to fetch.
|
|
8
8
|
* @param {RequestInit} init - The options for the fetch request.
|
|
9
9
|
* @param {(response: Response) => Promise<T>} transform - A function to transform the response.
|
|
10
|
-
* @returns {CancellablePromise<T>} A cancellable promise that resolves to the transformed response.
|
|
10
|
+
* @returns {import("./cancellablePromise.js").CancellablePromise<T>} A cancellable promise that resolves to the transformed response.
|
|
11
11
|
*/
|
|
12
12
|
export function cancellableFetch(input, init, transform) {
|
|
13
13
|
const controller = new AbortController();
|
|
@@ -35,7 +35,7 @@ export function cancellableFetch(input, init, transform) {
|
|
|
35
35
|
cleanupExternalSignal();
|
|
36
36
|
});
|
|
37
37
|
|
|
38
|
-
return
|
|
38
|
+
return makeCancellable(basePromise, async (/** @type {any} */ reason) => {
|
|
39
39
|
controller.abort(reason);
|
|
40
40
|
await basePromise.catch(() => {});
|
|
41
41
|
});
|
|
@@ -13,22 +13,37 @@
|
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
|
-
*
|
|
16
|
+
* Adds a cancel method to a promise.
|
|
17
17
|
*
|
|
18
18
|
* @template T
|
|
19
|
-
* @param {Promise<T>} promise - The promise to
|
|
19
|
+
* @param {Promise<T>} promise - The promise to make cancellable.
|
|
20
20
|
* @param {(reason?: any) => (Promise<void>|void)} cancel - The function to cancel the promise.
|
|
21
21
|
* @returns {CancellablePromise<T>} The cancellable promise.
|
|
22
22
|
*/
|
|
23
|
-
export
|
|
23
|
+
export function makeCancellable(promise, cancel) {
|
|
24
24
|
const cancellablePromise = /** @type {CancellablePromise<T>} */ (promise);
|
|
25
25
|
cancellablePromise.cancel = cancel;
|
|
26
26
|
return cancellablePromise;
|
|
27
|
-
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Adds a cancel method to a promise.
|
|
31
|
+
*
|
|
32
|
+
* @deprecated Use {@link makeCancellable} instead.
|
|
33
|
+
* @template T
|
|
34
|
+
* @param {Promise<T>} promise - The promise to make cancellable.
|
|
35
|
+
* @param {(reason?: any) => (Promise<void>|void)} cancel - The function to cancel the promise.
|
|
36
|
+
* @returns {CancellablePromise<T>} The cancellable promise.
|
|
37
|
+
*/
|
|
38
|
+
export function CancellablePromise(promise, cancel) {
|
|
39
|
+
return makeCancellable(promise, cancel);
|
|
40
|
+
}
|
|
28
41
|
|
|
29
42
|
/**
|
|
30
43
|
* Creates a rejected 'cancellable' promise.
|
|
31
44
|
*
|
|
45
|
+
* @deprecated Use `Promise.reject` directly; a plain rejected promise already
|
|
46
|
+
* satisfies {@link MaybeCancellablePromise}.
|
|
32
47
|
* @param {any} reason - The reason for the rejection.
|
|
33
48
|
* @returns {MaybeCancellablePromise<never>} A rejected 'cancellable' promise.
|
|
34
49
|
*/
|
|
@@ -39,6 +54,8 @@ CancellablePromise.reject = (reason) => {
|
|
|
39
54
|
/**
|
|
40
55
|
* Creates a resolved 'cancellable' promise.
|
|
41
56
|
*
|
|
57
|
+
* @deprecated Use `Promise.resolve` directly; a plain resolved promise already
|
|
58
|
+
* satisfies {@link MaybeCancellablePromise}.
|
|
42
59
|
* @template T
|
|
43
60
|
* @param {T} value - The value to resolve the promise with.
|
|
44
61
|
* @returns {MaybeCancellablePromise<T>} A resolved 'cancellable' promise.
|
package/utils/getFakePk.js
CHANGED
|
@@ -3,8 +3,8 @@ import isMap from "lodash-es/isMap.js";
|
|
|
3
3
|
import isSet from "lodash-es/isSet.js";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* Get a
|
|
7
|
-
*
|
|
6
|
+
* Get a random safe integer at or below zero and return it as a string. A candidate is redrawn when its numeric value
|
|
7
|
+
* exists in an array field, Set, or Map, or when its string property key exists in an object.
|
|
8
8
|
*
|
|
9
9
|
* @param {Array|Set|Map|object} arraySetMapOrObject - The array, set, map, or object to check for the fake pk.
|
|
10
10
|
* An array is assumed to be an array of objects.
|