@arrai-innovations/reactive-helpers 9.0.2 → 10.0.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/.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 +169 -14
- package/index.js +1 -0
- package/package.json +1 -1
- 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/listSubscription.spec.js +3 -5
- package/use/list.js +48 -14
- package/use/listCalculated.js +3 -0
- package/use/listFilter.js +40 -0
- package/use/listInstance.js +80 -27
- package/use/listRelated.js +5 -1
- package/use/listSort.js +34 -1
- package/use/listSubscription.js +56 -14
- 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
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { addOrUpdateReactiveObject } from "../utils/assignReactiveObject.js";
|
|
2
|
+
import cloneDeep from "lodash-es/cloneDeep.js";
|
|
3
|
+
import isFunction from "lodash-es/isFunction.js";
|
|
4
|
+
import { isReactive, toRef } from "vue";
|
|
5
|
+
|
|
6
|
+
const defaultCrud = {
|
|
7
|
+
args: {},
|
|
8
|
+
list: undefined,
|
|
9
|
+
subscribe: undefined,
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const setListCrud = ({ list, subscribe, args = {}, ...rest }) => {
|
|
13
|
+
defaultCrud.list = list;
|
|
14
|
+
defaultCrud.subscribe = subscribe;
|
|
15
|
+
// defensive cloning
|
|
16
|
+
Object.assign(defaultCrud.args, cloneDeep(args));
|
|
17
|
+
if (Object.keys(rest).length) {
|
|
18
|
+
throw new Error(`Unknown key(s) passed to setListCrud: ${Object.keys(rest).join(", ")}`);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const getListCrud = (reactiveCrud, { props, functions } = {}) => {
|
|
23
|
+
// don't mutate the default crud
|
|
24
|
+
Object.assign(reactiveCrud, cloneDeep(defaultCrud));
|
|
25
|
+
if (props?.crudArgs) {
|
|
26
|
+
addOrUpdateReactiveObject(reactiveCrud.args, props.crudArgs);
|
|
27
|
+
}
|
|
28
|
+
if (functions) {
|
|
29
|
+
for (const [key, value] of Object.entries(functions)) {
|
|
30
|
+
if (isFunction(value) && key in reactiveCrud) {
|
|
31
|
+
reactiveCrud[key] = isReactive(functions) ? toRef(functions, key) : value;
|
|
32
|
+
} else {
|
|
33
|
+
throw Error(`Invalid function "${key}" for getListCrud: invalid key or not a function.`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { addOrUpdateReactiveObject } from "../utils/assignReactiveObject.js";
|
|
2
|
+
import cloneDeep from "lodash-es/cloneDeep.js";
|
|
3
|
+
import isFunction from "lodash-es/isFunction.js";
|
|
4
|
+
import { isReactive, toRef } from "vue";
|
|
5
|
+
|
|
6
|
+
const defaultCrud = {
|
|
7
|
+
args: {},
|
|
8
|
+
retrieve: undefined,
|
|
9
|
+
create: undefined,
|
|
10
|
+
update: undefined,
|
|
11
|
+
patch: undefined,
|
|
12
|
+
delete: undefined,
|
|
13
|
+
subscribe: undefined,
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const setObjectCrud = ({ retrieve, create, update, patch, delete: deleteFn, subscribe, args = {}, ...rest }) => {
|
|
17
|
+
defaultCrud.retrieve = retrieve;
|
|
18
|
+
defaultCrud.create = create;
|
|
19
|
+
defaultCrud.update = update;
|
|
20
|
+
defaultCrud.patch = patch;
|
|
21
|
+
defaultCrud.delete = deleteFn;
|
|
22
|
+
defaultCrud.subscribe = subscribe;
|
|
23
|
+
// defensive cloning
|
|
24
|
+
Object.assign(defaultCrud.args, cloneDeep(args));
|
|
25
|
+
if (Object.keys(rest).length) {
|
|
26
|
+
throw new Error(`Unknown key(s) passed to setObjectCrud: ${Object.keys(rest).join(", ")}`);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const getObjectCrud = (reactiveCrud, { props, functions } = {}) => {
|
|
31
|
+
// don't mutate the default crud
|
|
32
|
+
Object.assign(reactiveCrud, cloneDeep(defaultCrud));
|
|
33
|
+
if (props?.crudArgs) {
|
|
34
|
+
addOrUpdateReactiveObject(reactiveCrud.args, props.crudArgs);
|
|
35
|
+
}
|
|
36
|
+
if (functions) {
|
|
37
|
+
for (const [key, value] of Object.entries(functions)) {
|
|
38
|
+
if (isFunction(value) && key in reactiveCrud) {
|
|
39
|
+
reactiveCrud[key] = isReactive(functions) ? toRef(functions, key) : value;
|
|
40
|
+
} else {
|
|
41
|
+
throw Error(`Invalid function "${key}" for getObjectCrud: invalid key or not a function.`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
};
|
package/docs.md
CHANGED
|
@@ -23,23 +23,31 @@
|
|
|
23
23
|
|
|
24
24
|
## Functions
|
|
25
25
|
|
|
26
|
-
| Name
|
|
27
|
-
|
|
|
28
|
-
| [useCombineClasses(classes)]
|
|
26
|
+
| Name | Description |
|
|
27
|
+
| ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
28
|
+
| [useCombineClasses(classes)] |
|
|
29
|
+
| [useListInstance(options)] | `useListInstance` is a Vue composition function that manages a list of objects. It has the ability to retrieve the list from an implementation, or subscribe to updates from an implementation. It tracks the objects in the list, and their added order. |
|
|
30
|
+
| [useListSubscription(options)] | `useListSubscription` creates a reactive object that manages a list of objects, as returned by `useListInstance`, causing the list to be re-fetched as needed and listening for updates to the list. |
|
|
29
31
|
|
|
30
32
|
## Typedefs
|
|
31
33
|
|
|
32
|
-
| Name
|
|
33
|
-
|
|
|
34
|
-
| [CSSValue]
|
|
35
|
-
| [CSSObject]
|
|
36
|
-
| [CSSClasses]
|
|
37
|
-
| [CSSStringOrObject]
|
|
38
|
-
| [
|
|
39
|
-
| [
|
|
40
|
-
| [
|
|
41
|
-
| [
|
|
42
|
-
| [
|
|
34
|
+
| Name | Description |
|
|
35
|
+
| ------------------------- | ------------------------------------------------------------------------------------------------------ |
|
|
36
|
+
| [CSSValue] | A string representing a CSS class or a space-separated list of CSS classes. |
|
|
37
|
+
| [CSSObject] | A CSS object where keys are CSS classes and values are booleans indicating whether to apply the class. |
|
|
38
|
+
| [CSSClasses] | A mixed array containing multiple ways of specifying CSS classes. |
|
|
39
|
+
| [CSSStringOrObject] | The amalgamated classes as returned by `objectifyClasses` & `combineClasses`. |
|
|
40
|
+
| [ListInstanceOptions] | The configuration options used to create a list instance. |
|
|
41
|
+
| [ListInstanceState] | A reactive object that manages a list of objects, as returned by `useListInstance`. |
|
|
42
|
+
| [ListInstance] |
|
|
43
|
+
| [ListSubscriptionOptions] | The configuration options used to create a list subscription. |
|
|
44
|
+
| [ListSubscriptionState] | A reactive object that manages a list of objects, as returned by `useListInstance`. |
|
|
45
|
+
| [ListSubscription] |
|
|
46
|
+
| [CSSValue] | A string representing a CSS class or a space-separated list of CSS classes. |
|
|
47
|
+
| [CSSObject] | A CSS object where keys are CSS classes and values are booleans indicating whether to apply the class. |
|
|
48
|
+
| [CSSClasses] | A mixed array containing multiple ways of specifying CSS classes. |
|
|
49
|
+
| [CSSClassesWithRefs] | A mixed array containing multiple ways of specifying CSS classes. |
|
|
50
|
+
| [CSSStringOrObject] | A CSS object or a space-separated list of CSS classes. |
|
|
43
51
|
|
|
44
52
|
## utils/assignReactiveObject
|
|
45
53
|
|
|
@@ -427,6 +435,31 @@ Remove empty objects and undefined values from arrays in a mixed object array tr
|
|
|
427
435
|
| ------- | -------------- | -------------------------------------------------------------------------------------------- |
|
|
428
436
|
| classes | [`CSSClasses`] | A mixed array containing multiple ways of specifying CSS classes. Non-ref values are cloned. |
|
|
429
437
|
|
|
438
|
+
## useListInstance(options)
|
|
439
|
+
|
|
440
|
+
`useListInstance` is a Vue composition function that manages a list of objects.
|
|
441
|
+
It has the ability to retrieve the list from an implementation, or subscribe to updates from an implementation.
|
|
442
|
+
It tracks the objects in the list, and their added order.
|
|
443
|
+
|
|
444
|
+
**Kind**: global function
|
|
445
|
+
**Returns**: [`ListInstance`] - - the list instance
|
|
446
|
+
|
|
447
|
+
| Param | Type | Description |
|
|
448
|
+
| ------- | ----------------------- | -------------------------------------------- |
|
|
449
|
+
| options | [`ListInstanceOptions`] | the options used to create the list instance |
|
|
450
|
+
|
|
451
|
+
## useListSubscription(options)
|
|
452
|
+
|
|
453
|
+
`useListSubscription` creates a reactive object that manages a list of objects, as returned by `useListInstance`,
|
|
454
|
+
causing the list to be re-fetched as needed and listening for updates to the list.
|
|
455
|
+
|
|
456
|
+
**Kind**: global function
|
|
457
|
+
**Returns**: ListSubscription
|
|
458
|
+
|
|
459
|
+
| Param | Type |
|
|
460
|
+
| ------- | --------------------------- |
|
|
461
|
+
| options | [`ListSubscriptionOptions`] |
|
|
462
|
+
|
|
430
463
|
## CSSValue
|
|
431
464
|
|
|
432
465
|
A string representing a CSS class or a space-separated list of CSS classes.
|
|
@@ -451,6 +484,115 @@ The amalgamated classes as returned by `objectifyClasses` & `combineClasses`.
|
|
|
451
484
|
|
|
452
485
|
**Kind**: global typedef
|
|
453
486
|
|
|
487
|
+
## ListInstanceOptions
|
|
488
|
+
|
|
489
|
+
The configuration options used to create a list instance.
|
|
490
|
+
|
|
491
|
+
**Kind**: global typedef
|
|
492
|
+
**Properties**
|
|
493
|
+
|
|
494
|
+
| Name | Type | Description |
|
|
495
|
+
| ------------------- | ---------- | ---------------------------------------------------------------------------------------- |
|
|
496
|
+
| props | `object` | props passed to the component |
|
|
497
|
+
| props.retrieveArgs | `object` | the arguments passed to the server |
|
|
498
|
+
| props.listArgs | `object` | the arguments passed to the server |
|
|
499
|
+
| props.crudArgs | `object` | implementation specific arguments |
|
|
500
|
+
| functions | `object` | optional. default implementation are used as set by `setListCrud`. |
|
|
501
|
+
| functions.list | `function` | provide the implementation for the list function |
|
|
502
|
+
| functions.subscribe | `function` | provide the implementation for the subscribe function |
|
|
503
|
+
| keepOldPages | `boolean` | if true, pages will not be cleared when defaultPageCallback is called. default is false. |
|
|
504
|
+
|
|
505
|
+
## ListInstanceState
|
|
506
|
+
|
|
507
|
+
A reactive object that manages a list of objects, as returned by `useListInstance`.
|
|
508
|
+
|
|
509
|
+
**Kind**: global typedef
|
|
510
|
+
**Properties**
|
|
511
|
+
|
|
512
|
+
| Name | Type | Description |
|
|
513
|
+
| -------------- | ---------- | ------------------------------------------ |
|
|
514
|
+
| crud | `object` | the crud functions |
|
|
515
|
+
| crud.args | `object` | the arguments passed to the crud functions |
|
|
516
|
+
| crud.list | `function` | the list function |
|
|
517
|
+
| crud.subscribe | `function` | the subscribe function |
|
|
518
|
+
| retrieveArgs | `object` | the arguments passed to the server |
|
|
519
|
+
| listArgs | `object` | the arguments passed to the server |
|
|
520
|
+
| objects | `Map` | the objects in the list |
|
|
521
|
+
| loading | `boolean` | true if the list is loading |
|
|
522
|
+
| errored | `boolean` | true if the list has errored |
|
|
523
|
+
| error | `object` | the error object |
|
|
524
|
+
| objectsInOrder | `Array` | the objects in the list in order |
|
|
525
|
+
| order | `Array` | the order of the objects in the list |
|
|
526
|
+
| totalRecords | `number` | the total number of records |
|
|
527
|
+
| totalPages | `number` | the total number of pages |
|
|
528
|
+
| perPage | `number` | the number of records per page |
|
|
529
|
+
|
|
530
|
+
## ListInstance
|
|
531
|
+
|
|
532
|
+
**Kind**: global typedef
|
|
533
|
+
**Properties**
|
|
534
|
+
|
|
535
|
+
| Name | Type | Description |
|
|
536
|
+
| ------------------- | --------------------- | -------------------------------------------- |
|
|
537
|
+
| list | `function` | subscribe to updates from the implementation |
|
|
538
|
+
| addListObject | `function` | add an object to the list |
|
|
539
|
+
| updateListObject | `function` | update an object in the list |
|
|
540
|
+
| deleteListObject | `function` | delete an object from the list |
|
|
541
|
+
| clearList | `function` | clear the list |
|
|
542
|
+
| clearError | `function` | clear the error |
|
|
543
|
+
| getFakeId | `function` | get a fake id |
|
|
544
|
+
| defaultPageCallback | `function` | the default page callback |
|
|
545
|
+
| pageCallback | `function` | the page callback |
|
|
546
|
+
| state | [`ListInstanceState`] | the list instance state |
|
|
547
|
+
| effectScope | `object` | a Vue effect scope |
|
|
548
|
+
|
|
549
|
+
## ListSubscriptionOptions
|
|
550
|
+
|
|
551
|
+
The configuration options used to create a list subscription.
|
|
552
|
+
|
|
553
|
+
**Kind**: global typedef
|
|
554
|
+
**Properties**
|
|
555
|
+
|
|
556
|
+
| Name | Type | Description |
|
|
557
|
+
| ------------ | ---------------- | ---------------------------------------------------------------------------------------- |
|
|
558
|
+
| props | `object` | passed on to a created list instance if one is not provided |
|
|
559
|
+
| functions | `object` | passed on to a created list instance if one is not provided |
|
|
560
|
+
| listInstance | [`ListInstance`] | a list instance to use instead of creating one |
|
|
561
|
+
| keepOldPages | `boolean` | if true, pages will not be cleared when defaultPageCallback is called. default is false. |
|
|
562
|
+
|
|
563
|
+
## ListSubscriptionState
|
|
564
|
+
|
|
565
|
+
A reactive object that manages a list of objects, as returned by `useListInstance`.
|
|
566
|
+
|
|
567
|
+
**Kind**: global typedef
|
|
568
|
+
**Extends**: [`ListInstanceState`]
|
|
569
|
+
**Properties**
|
|
570
|
+
|
|
571
|
+
| Name | Type | Description |
|
|
572
|
+
| ------------------- | --------- | ----------------------------------------------------------------- |
|
|
573
|
+
| subscriptionLoading | `boolean` | true if the subscription is loading |
|
|
574
|
+
| subscriptionErrored | `boolean` | true if the subscription errored |
|
|
575
|
+
| subscriptionError | `Error` | the error that caused the subscription to error |
|
|
576
|
+
| intendToList | `boolean` | true if the list should be fetched, or refetched when args change |
|
|
577
|
+
| intendToSubscribe | `boolean` | true if the list should subscribe for updates |
|
|
578
|
+
| subscribed | `boolean` | true if the subscription is active |
|
|
579
|
+
|
|
580
|
+
## ListSubscription
|
|
581
|
+
|
|
582
|
+
**Kind**: global typedef
|
|
583
|
+
**Properties**
|
|
584
|
+
|
|
585
|
+
| Name | Type | Description |
|
|
586
|
+
| ------------------ | ------------------------- | -------------------------------------------------------------------------------------- |
|
|
587
|
+
| state | [`ListSubscriptionState`] | the reactive state of the list subscription |
|
|
588
|
+
| listInstance | [`ListInstance`] | the list instance used by the subscription |
|
|
589
|
+
| listIntent | `object` | the useCancelleableIntent object managing if the list should be (re)fetched |
|
|
590
|
+
| subscriptionIntent | `object` | the useCancelleableIntent object managing if the subscription should be (un)subscribed |
|
|
591
|
+
| subscribe | `function` | subscribe to the list |
|
|
592
|
+
| unsubscribe | `function` | unsubscribe from the list |
|
|
593
|
+
| clearError | `function` | clear the subscription error |
|
|
594
|
+
| effectScope | `object` | a Vue effect scope |
|
|
595
|
+
|
|
454
596
|
## CSSValue
|
|
455
597
|
|
|
456
598
|
A string representing a CSS class or a space-separated list of CSS classes.
|
|
@@ -500,6 +642,12 @@ A CSS object or a space-separated list of CSS classes.
|
|
|
500
642
|
[cssobject]: #cssobject
|
|
501
643
|
[cssclasses]: #cssclasses
|
|
502
644
|
[cssstringorobject]: #cssstringorobject
|
|
645
|
+
[listinstanceoptions]: #listinstanceoptions
|
|
646
|
+
[listinstancestate]: #listinstancestate
|
|
647
|
+
[listinstance]: #listinstance
|
|
648
|
+
[listsubscriptionoptions]: #listsubscriptionoptions
|
|
649
|
+
[listsubscriptionstate]: #listsubscriptionstate
|
|
650
|
+
[listsubscription]: #listsubscription
|
|
503
651
|
[cssclasseswithrefs]: #cssclasseswithrefs
|
|
504
652
|
[~validtargetorsource]: #utilsassignreactiveobjectvalidtargetorsource
|
|
505
653
|
[`utils/assignreactiveobject`]: #utilsassignreactiveobject
|
|
@@ -515,7 +663,14 @@ A CSS object or a space-separated list of CSS classes.
|
|
|
515
663
|
[`cssclasses`]: #cssclasses
|
|
516
664
|
[`cssstringorobject`]: #cssstringorobject
|
|
517
665
|
[`cssclasseswithrefs`]: #cssclasseswithrefs
|
|
666
|
+
[`listinstance`]: #listinstance
|
|
667
|
+
[`listinstanceoptions`]: #listinstanceoptions
|
|
668
|
+
[`listsubscriptionoptions`]: #listsubscriptionoptions
|
|
669
|
+
[`listinstancestate`]: #listinstancestate
|
|
670
|
+
[`listsubscriptionstate`]: #listsubscriptionstate
|
|
518
671
|
[usecombineclasses(classes)]: #usecombineclassesclasses
|
|
672
|
+
[uselistinstance(options)]: #uselistinstanceoptions
|
|
673
|
+
[uselistsubscription(options)]: #uselistsubscriptionoptions
|
|
519
674
|
[~addreactiveobject(target, source, \[exclude\], \[addedkeys\])]: #utilsassignreactiveobjectaddreactiveobjecttarget-source-exclude-addedkeys
|
|
520
675
|
[~updatereactiveobject(target, source, \[exclude\], \[samekeys\])]: #utilsassignreactiveobjectupdatereactiveobjecttarget-source-exclude-samekeys
|
|
521
676
|
[~addorupdatereactiveobject(target, source, \[exclude\], \[addedkeys\], \[samekeys\])]: #utilsassignreactiveobjectaddorupdatereactiveobjecttarget-source-exclude-addedkeys-samekeys
|
package/index.js
CHANGED
package/package.json
CHANGED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as config from "../../../config/index.js";
|
|
2
|
+
import fs from "fs/promises";
|
|
3
|
+
|
|
4
|
+
describe("config/index.js", function () {
|
|
5
|
+
it("should export everything exported by individual files", async function () {
|
|
6
|
+
const files = await fs.readdir("./config");
|
|
7
|
+
const modules = files.filter((file) => file.endsWith(".js") && file !== "index.js");
|
|
8
|
+
const exportedKeys = [];
|
|
9
|
+
for (const module of modules) {
|
|
10
|
+
const moduleExports = await import(`../../../config/${module}`);
|
|
11
|
+
exportedKeys.push(...Object.keys(moduleExports).filter((key) => key !== "default"));
|
|
12
|
+
}
|
|
13
|
+
const useKeys = Object.keys(config);
|
|
14
|
+
useKeys.sort();
|
|
15
|
+
exportedKeys.sort();
|
|
16
|
+
expect(useKeys).toEqual(exportedKeys);
|
|
17
|
+
});
|
|
18
|
+
});
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import cloneDeep from "lodash-es/cloneDeep.js";
|
|
2
|
+
import { reactive } from "vue";
|
|
3
|
+
|
|
4
|
+
describe("config/listCrud.js", () => {
|
|
5
|
+
describe("get & set", () => {
|
|
6
|
+
let setListCrud, getListCrud;
|
|
7
|
+
beforeAll(async () => {
|
|
8
|
+
const listCrudModule = await import("../../../config/listCrud.js");
|
|
9
|
+
setListCrud = listCrudModule.setListCrud;
|
|
10
|
+
getListCrud = listCrudModule.getListCrud;
|
|
11
|
+
});
|
|
12
|
+
it("should not die getting crud before setting", () => {
|
|
13
|
+
const reactiveCrud = reactive({});
|
|
14
|
+
expect(() => getListCrud(reactiveCrud)).not.toThrow();
|
|
15
|
+
});
|
|
16
|
+
it("should set and get the default crud, avoiding mutation", () => {
|
|
17
|
+
const crud = {
|
|
18
|
+
list: () => 1,
|
|
19
|
+
subscribe: () => 2,
|
|
20
|
+
args: {
|
|
21
|
+
test: "test",
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
expect(() => setListCrud(crud)).not.toThrow();
|
|
25
|
+
|
|
26
|
+
const retrievedCrud = reactive({});
|
|
27
|
+
expect(() => getListCrud(retrievedCrud)).not.toThrow();
|
|
28
|
+
expect(new Set(Object.keys(retrievedCrud))).toEqual(new Set(["list", "subscribe", "args"]));
|
|
29
|
+
expect(retrievedCrud.args).not.toBe(crud.args);
|
|
30
|
+
expect(retrievedCrud.args).toEqual(crud.args);
|
|
31
|
+
expect(retrievedCrud.list).toBe(crud.list);
|
|
32
|
+
expect(retrievedCrud.subscribe).toBe(crud.subscribe);
|
|
33
|
+
|
|
34
|
+
const originalCrud = cloneDeep(crud);
|
|
35
|
+
crud.args.test = "test2";
|
|
36
|
+
crud.list = () => 3;
|
|
37
|
+
crud.subscribe = () => 4;
|
|
38
|
+
expect(retrievedCrud.args.test).toBe(originalCrud.args.test);
|
|
39
|
+
expect(retrievedCrud.list).toBe(originalCrud.list);
|
|
40
|
+
expect(retrievedCrud.subscribe).toBe(originalCrud.subscribe);
|
|
41
|
+
});
|
|
42
|
+
it("should die if an unknown function is passed", () => {
|
|
43
|
+
expect(() =>
|
|
44
|
+
setListCrud({ list: () => 1, subscribe: () => 2, args: { test: "test" }, unknown: () => 3 })
|
|
45
|
+
).toThrow("Unknown key(s) passed to setListCrud: unknown");
|
|
46
|
+
});
|
|
47
|
+
it("should customize via getListCrud", () => {
|
|
48
|
+
const defaultCrud = {
|
|
49
|
+
list: () => 1,
|
|
50
|
+
subscribe: () => 2,
|
|
51
|
+
args: {
|
|
52
|
+
test: "test",
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
const customCrudArgs = {
|
|
56
|
+
props: reactive({
|
|
57
|
+
crudArgs: {
|
|
58
|
+
test: "test2",
|
|
59
|
+
},
|
|
60
|
+
}),
|
|
61
|
+
functions: {
|
|
62
|
+
list: () => 3,
|
|
63
|
+
subscribe: () => 4,
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
const expectedCustomCrud = {
|
|
67
|
+
list: customCrudArgs.functions.list,
|
|
68
|
+
subscribe: customCrudArgs.functions.subscribe,
|
|
69
|
+
args: customCrudArgs.props.crudArgs,
|
|
70
|
+
};
|
|
71
|
+
expect(() => setListCrud(defaultCrud)).not.toThrow();
|
|
72
|
+
const defaultRetrievedCrud = reactive({});
|
|
73
|
+
getListCrud(defaultRetrievedCrud);
|
|
74
|
+
expect(defaultRetrievedCrud).toEqual(defaultCrud);
|
|
75
|
+
expect(defaultRetrievedCrud).not.toEqual(expectedCustomCrud);
|
|
76
|
+
const customRetrievedCrud = reactive({});
|
|
77
|
+
getListCrud(customRetrievedCrud, customCrudArgs);
|
|
78
|
+
expect(customRetrievedCrud).toEqual(expectedCustomCrud);
|
|
79
|
+
expect(customRetrievedCrud).not.toEqual(defaultCrud);
|
|
80
|
+
expect(defaultRetrievedCrud).toEqual(defaultCrud);
|
|
81
|
+
expect(defaultRetrievedCrud).not.toEqual(expectedCustomCrud);
|
|
82
|
+
});
|
|
83
|
+
it("should throw if passed functions object that has values that are not functions", () => {
|
|
84
|
+
const retrievedCrud = reactive({});
|
|
85
|
+
expect(() =>
|
|
86
|
+
getListCrud(retrievedCrud, {
|
|
87
|
+
functions: {
|
|
88
|
+
list: () => 1,
|
|
89
|
+
subscribe: true,
|
|
90
|
+
},
|
|
91
|
+
})
|
|
92
|
+
).toThrow('Invalid function "subscribe" for getListCrud: invalid key or not a function.');
|
|
93
|
+
});
|
|
94
|
+
it("should throw if passed unexpected functions", () => {
|
|
95
|
+
const retrievedCrud = reactive({});
|
|
96
|
+
expect(() =>
|
|
97
|
+
getListCrud(retrievedCrud, {
|
|
98
|
+
functions: {
|
|
99
|
+
list: () => 1,
|
|
100
|
+
subscribe: () => 2,
|
|
101
|
+
unknown: () => 3,
|
|
102
|
+
},
|
|
103
|
+
})
|
|
104
|
+
).toThrow('Invalid function "unknown" for getListCrud: invalid key or not a function.');
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
});
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import cloneDeep from "lodash-es/cloneDeep.js";
|
|
2
|
+
import { reactive } from "vue";
|
|
3
|
+
|
|
4
|
+
describe("config/objectCrud.js", () => {
|
|
5
|
+
describe("get & set", () => {
|
|
6
|
+
let setObjectCrud, getObjectCrud;
|
|
7
|
+
beforeAll(async () => {
|
|
8
|
+
const objectCrudModule = await import("../../../config/objectCrud.js");
|
|
9
|
+
setObjectCrud = objectCrudModule.setObjectCrud;
|
|
10
|
+
getObjectCrud = objectCrudModule.getObjectCrud;
|
|
11
|
+
});
|
|
12
|
+
it("should not die getting crud before setting", () => {
|
|
13
|
+
const reactiveCrud = reactive({});
|
|
14
|
+
expect(() => getObjectCrud(reactiveCrud)).not.toThrow();
|
|
15
|
+
});
|
|
16
|
+
it("should set and get the default crud, avoiding mutation", () => {
|
|
17
|
+
const crud = {
|
|
18
|
+
retrieve: () => 1,
|
|
19
|
+
create: () => 2,
|
|
20
|
+
update: () => 3,
|
|
21
|
+
patch: () => 4,
|
|
22
|
+
delete: () => 5,
|
|
23
|
+
subscribe: () => 6,
|
|
24
|
+
args: {
|
|
25
|
+
test: "test",
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
expect(() => setObjectCrud(crud)).not.toThrow();
|
|
29
|
+
|
|
30
|
+
const retrievedCrud = reactive({});
|
|
31
|
+
expect(() => getObjectCrud(retrievedCrud)).not.toThrow();
|
|
32
|
+
expect(new Set(Object.keys(retrievedCrud))).toEqual(
|
|
33
|
+
new Set(["retrieve", "create", "update", "patch", "delete", "subscribe", "args"])
|
|
34
|
+
);
|
|
35
|
+
expect(retrievedCrud.args).not.toBe(crud.args);
|
|
36
|
+
expect(retrievedCrud.args).toEqual(crud.args);
|
|
37
|
+
expect(retrievedCrud.retrieve).toBe(crud.retrieve);
|
|
38
|
+
expect(retrievedCrud.create).toBe(crud.create);
|
|
39
|
+
expect(retrievedCrud.update).toBe(crud.update);
|
|
40
|
+
expect(retrievedCrud.patch).toBe(crud.patch);
|
|
41
|
+
expect(retrievedCrud.delete).toBe(crud.delete);
|
|
42
|
+
expect(retrievedCrud.subscribe).toBe(crud.subscribe);
|
|
43
|
+
|
|
44
|
+
const originalCrud = cloneDeep(crud);
|
|
45
|
+
crud.args.test = "test2";
|
|
46
|
+
crud.retrieve = () => 7;
|
|
47
|
+
crud.create = () => 8;
|
|
48
|
+
crud.update = () => 9;
|
|
49
|
+
crud.patch = () => 10;
|
|
50
|
+
crud.delete = () => 11;
|
|
51
|
+
crud.subscribe = () => 12;
|
|
52
|
+
expect(retrievedCrud.args.test).toBe(originalCrud.args.test);
|
|
53
|
+
expect(retrievedCrud.retrieve).toBe(originalCrud.retrieve);
|
|
54
|
+
expect(retrievedCrud.create).toBe(originalCrud.create);
|
|
55
|
+
expect(retrievedCrud.update).toBe(originalCrud.update);
|
|
56
|
+
expect(retrievedCrud.patch).toBe(originalCrud.patch);
|
|
57
|
+
expect(retrievedCrud.delete).toBe(originalCrud.delete);
|
|
58
|
+
expect(retrievedCrud.subscribe).toBe(originalCrud.subscribe);
|
|
59
|
+
});
|
|
60
|
+
it("should customize via getObjectCrud", () => {
|
|
61
|
+
const defaultCrud = {
|
|
62
|
+
retrieve: () => 1,
|
|
63
|
+
create: () => 2,
|
|
64
|
+
update: () => 3,
|
|
65
|
+
patch: () => 4,
|
|
66
|
+
delete: () => 5,
|
|
67
|
+
subscribe: () => 6,
|
|
68
|
+
args: {
|
|
69
|
+
test: "test",
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
const customCrudArgs = {
|
|
73
|
+
props: reactive({
|
|
74
|
+
crudArgs: {
|
|
75
|
+
test: "test2",
|
|
76
|
+
},
|
|
77
|
+
}),
|
|
78
|
+
functions: {
|
|
79
|
+
retrieve: () => 7,
|
|
80
|
+
create: () => 8,
|
|
81
|
+
update: () => 9,
|
|
82
|
+
patch: () => 10,
|
|
83
|
+
delete: () => 11,
|
|
84
|
+
subscribe: () => 12,
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
const expectedCustomCrud = {
|
|
88
|
+
retrieve: customCrudArgs.functions.retrieve,
|
|
89
|
+
create: customCrudArgs.functions.create,
|
|
90
|
+
update: customCrudArgs.functions.update,
|
|
91
|
+
patch: customCrudArgs.functions.patch,
|
|
92
|
+
delete: customCrudArgs.functions.delete,
|
|
93
|
+
subscribe: customCrudArgs.functions.subscribe,
|
|
94
|
+
args: customCrudArgs.props.crudArgs,
|
|
95
|
+
};
|
|
96
|
+
expect(() => setObjectCrud(defaultCrud)).not.toThrow();
|
|
97
|
+
const defaultRetrievedCrud = reactive({});
|
|
98
|
+
getObjectCrud(defaultRetrievedCrud);
|
|
99
|
+
expect(defaultRetrievedCrud).toEqual(defaultCrud);
|
|
100
|
+
expect(defaultRetrievedCrud).not.toEqual(expectedCustomCrud);
|
|
101
|
+
const customRetrievedCrud = reactive({});
|
|
102
|
+
getObjectCrud(customRetrievedCrud, customCrudArgs);
|
|
103
|
+
expect(customRetrievedCrud).toEqual(expectedCustomCrud);
|
|
104
|
+
expect(customRetrievedCrud).not.toEqual(defaultCrud);
|
|
105
|
+
expect(defaultRetrievedCrud).toEqual(defaultCrud);
|
|
106
|
+
expect(defaultRetrievedCrud).not.toEqual(expectedCustomCrud);
|
|
107
|
+
});
|
|
108
|
+
it("should die if an unknown function is passed", () => {
|
|
109
|
+
expect(() =>
|
|
110
|
+
setObjectCrud({
|
|
111
|
+
retrieve: () => 1,
|
|
112
|
+
create: () => 2,
|
|
113
|
+
update: () => 3,
|
|
114
|
+
patch: () => 4,
|
|
115
|
+
delete: () => 5,
|
|
116
|
+
subscribe: () => 6,
|
|
117
|
+
args: { test: "test" },
|
|
118
|
+
unknown: () => 7,
|
|
119
|
+
})
|
|
120
|
+
).toThrow("Unknown key(s) passed to setObjectCrud: unknown");
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it("should throw if passed functions object that has values that are not functions", () => {
|
|
124
|
+
const retrievedCrud = reactive({});
|
|
125
|
+
expect(() =>
|
|
126
|
+
getObjectCrud(retrievedCrud, {
|
|
127
|
+
functions: {
|
|
128
|
+
retrieve: () => 1,
|
|
129
|
+
create: () => 2,
|
|
130
|
+
update: 3,
|
|
131
|
+
patch: () => 4,
|
|
132
|
+
delete: () => 5,
|
|
133
|
+
subscribe: () => 6,
|
|
134
|
+
},
|
|
135
|
+
})
|
|
136
|
+
).toThrow('Invalid function "update" for getObjectCrud: invalid key or not a function.');
|
|
137
|
+
});
|
|
138
|
+
it("should throw if passed unexpected functions", () => {
|
|
139
|
+
const retrievedCrud = reactive({});
|
|
140
|
+
expect(() =>
|
|
141
|
+
getObjectCrud(retrievedCrud, {
|
|
142
|
+
functions: {
|
|
143
|
+
retrieve: () => 1,
|
|
144
|
+
create: () => 2,
|
|
145
|
+
update: () => 3,
|
|
146
|
+
patch: () => 4,
|
|
147
|
+
delete: () => 5,
|
|
148
|
+
subscribe: () => 6,
|
|
149
|
+
unknown: () => 7,
|
|
150
|
+
},
|
|
151
|
+
})
|
|
152
|
+
).toThrow('Invalid function "unknown" for getObjectCrud: invalid key or not a function.');
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useCancellableIntent } from "../../../use/
|
|
1
|
+
import { useCancellableIntent } from "../../../use/cancellableIntent.js";
|
|
2
2
|
import { CancellableResolvable } from "../crudPromise.js";
|
|
3
3
|
import flushPromises from "flush-promises";
|
|
4
4
|
import { nextTick, reactive, ref } from "vue";
|
|
@@ -9,12 +9,13 @@ afterAll(() => {
|
|
|
9
9
|
});
|
|
10
10
|
|
|
11
11
|
const fields = ["id", "__str__", "name"];
|
|
12
|
-
describe
|
|
12
|
+
describe("use/listInstance.spec.js", function () {
|
|
13
13
|
let useListInstance, ListError, useListInstances, globalList;
|
|
14
14
|
beforeEach(async () => {
|
|
15
|
+
const listCrud = await import("../../../config/listCrud.js");
|
|
15
16
|
const imported = await import("../../../use/listInstance");
|
|
16
17
|
globalList = vi.fn();
|
|
17
|
-
|
|
18
|
+
listCrud.setListCrud({
|
|
18
19
|
list: globalList,
|
|
19
20
|
args: { stream: "test_stream" },
|
|
20
21
|
});
|
|
@@ -143,8 +144,8 @@ describe.skip("use/listInstance.spec.js", function () {
|
|
|
143
144
|
expect({ ...listInstance.state.objects }).toEqual({});
|
|
144
145
|
globalList.mockImplementation(() => new Promise(() => {}));
|
|
145
146
|
|
|
146
|
-
listInstance.list();
|
|
147
|
-
|
|
147
|
+
const firstPromise = listInstance.list();
|
|
148
|
+
expect(listInstance.list()).toBe(firstPromise);
|
|
148
149
|
|
|
149
150
|
expect(globalList).toHaveBeenCalledWith({
|
|
150
151
|
crudArgs: { stream: "test_stream" },
|