@arrai-innovations/reactive-helpers 3.2.0 → 3.3.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arrai-innovations/reactive-helpers",
3
- "version": "3.2.0",
3
+ "version": "3.3.0",
4
4
  "description": "VueJS 3 utility composition functions to help manipulate objects and lists.",
5
5
  "main": "index.js",
6
6
  "directories": {
package/use/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from "./cancellableIntent.js";
2
+ export * from "./list.js";
2
3
  export * from "./listCalculated.js";
3
4
  export * from "./listFilter.js";
4
5
  export * from "./listInstance.js";
package/use/list.js ADDED
@@ -0,0 +1,103 @@
1
+ import { effectScope, shallowReactive, shallowReadonly, toRef, watch } from "vue";
2
+ import { useListCalculated } from "./listCalculated";
3
+ import { useListInstance } from "./listInstance";
4
+ import { useListRelated } from "./listRelated";
5
+ import { useListSubscription } from "./listSubscription";
6
+
7
+ // the big brother of useObject, managing a chain of useList* instances.
8
+ export const useList = ({ props, functions }) => {
9
+ const managed = shallowReactive({
10
+ listInstance: null,
11
+ listSubscription: null,
12
+ listRelated: null,
13
+ listCalculated: null,
14
+ });
15
+ const es = effectScope();
16
+
17
+ managed.listInstance = useListInstance({
18
+ crudArgs: toRef(props, "crudArgs"),
19
+ functions,
20
+ retrieveArgs: toRef(props, "retrieveArgs"),
21
+ listArgs: toRef(props, "listArgs"),
22
+ });
23
+
24
+ const intentPropsWatch = () => {
25
+ es.run(() => {
26
+ let nextState = managed.listInstance?.state;
27
+ // true or false, having a key is intent to use
28
+ const hasIntendToList = "intendToList" in props;
29
+ if (hasIntendToList && !managed.listSubscription) {
30
+ managed.listSubscription = useListSubscription({
31
+ listInstance: managed.listInstance,
32
+ });
33
+ managed.listSubscription.state.intendToList = toRef(props, "intendToList");
34
+ } else if (!hasIntendToList && managed.listSubscription) {
35
+ managed.listSubscription.effectScope.stop();
36
+ managed.listSubscription = null;
37
+ }
38
+ const hasRelatedObjectRules = "relatedObjectsRules" in props;
39
+ if (hasRelatedObjectRules && !managed.listRelated) {
40
+ nextState = managed.listSubscription?.state || nextState;
41
+ managed.listRelated = useListRelated({
42
+ parentState: nextState,
43
+ relatedObjectsRules: toRef(props, "relatedObjectsRules"),
44
+ });
45
+ } else if (!hasRelatedObjectRules && managed.listRelated) {
46
+ managed.listRelated.effectScope.stop();
47
+ managed.listRelated = null;
48
+ }
49
+ const hasCalculatedObjectRules = "calculatedObjectsRules" in props;
50
+ if (hasCalculatedObjectRules && !managed.listCalculated) {
51
+ nextState = managed.listRelated?.state || nextState;
52
+ managed.listCalculated = useListCalculated({
53
+ parentState: nextState,
54
+ calculatedObjectsRules: toRef(props, "calculatedObjectsRules"),
55
+ });
56
+ } else if (!hasCalculatedObjectRules && managed.listCalculated) {
57
+ managed.listCalculated.effectScope.stop();
58
+ managed.listCalculated = null;
59
+ }
60
+ });
61
+ };
62
+
63
+ let exposedState;
64
+
65
+ es.run(() => {
66
+ watch(
67
+ [
68
+ //
69
+ toRef(props, "intendToList"),
70
+ toRef(props, "relatedObjectsRules"),
71
+ toRef(props, "calculatedObjectsRules"),
72
+ ],
73
+ intentPropsWatch,
74
+ { immediate: true }
75
+ );
76
+ const getState = () =>
77
+ managed.listCalculated?.state ||
78
+ managed.listRelated?.state ||
79
+ managed.listSubscription?.state ||
80
+ managed.listInstance?.state;
81
+ // used as proxy to have the properties and not be settable, so we only have to override get
82
+ const proxyBase = shallowReadonly({
83
+ loading: null,
84
+ error: null,
85
+ errored: null,
86
+ objects: null,
87
+ order: null,
88
+ objectsInOrder: null,
89
+ running: null,
90
+ });
91
+ exposedState = new Proxy(proxyBase, {
92
+ get: (target, prop) => {
93
+ return Reflect.get(getState(), prop);
94
+ },
95
+ });
96
+ });
97
+
98
+ return {
99
+ managed: shallowReadonly(managed),
100
+ state: exposedState,
101
+ effectScope: es,
102
+ };
103
+ };
@@ -1,5 +1,6 @@
1
1
  import inspect from "browser-util-inspect";
2
2
  import { cloneDeep } from "lodash";
3
+ import { isFunction } from "lodash";
3
4
  import { computed, effectScope, reactive } from "vue";
4
5
  import { addOrUpdateReactiveObject, assignReactiveObject } from "../utils/assignReactiveObject";
5
6
  import { getFakeId } from "../utils/getFakeId";
@@ -30,7 +31,7 @@ export function useListInstances(listInstanceArgs) {
30
31
  return instances;
31
32
  }
32
33
 
33
- export function useListInstance({ crudArgs, listArgs = {}, retrieveArgs = {} }) {
34
+ export function useListInstance({ crudArgs, listArgs = {}, retrieveArgs = {}, functions = {} }) {
34
35
  // ### touching the _objectsMap or _objectsProxy directly will not trigger reactivity ###
35
36
  const _objectsMap = new Map();
36
37
  // ### touching the _objectsMap or _objectsProxy directly will not trigger reactivity ###
@@ -82,6 +83,13 @@ export function useListInstance({ crudArgs, listArgs = {}, retrieveArgs = {} })
82
83
  if (crudArgs) {
83
84
  addOrUpdateReactiveObject(state.crud.args, crudArgs);
84
85
  }
86
+ for (const [key, value] of Object.entries(functions)) {
87
+ if (isFunction(value) && key in state.crud) {
88
+ state.crud[key] = value;
89
+ } else {
90
+ throw ListError(`Invalid function "${key}" for useListInstance: invalid key or not a function.`);
91
+ }
92
+ }
85
93
 
86
94
  const defaultPageCallback = (newObjects) => {
87
95
  newObjects.forEach((newObject) => {
package/use/object.js CHANGED
@@ -5,7 +5,7 @@ import { useObjectRelated } from "./objectRelated";
5
5
  import { useObjectSubscription } from "./objectSubscription";
6
6
 
7
7
  // Manages a chain of useObject functions, based on existence of keys in props: intendToRetrieve, relatedObjectRules, calculatedObjectRules
8
- export const useObject = ({ props }) => {
8
+ export const useObject = ({ props, functions }) => {
9
9
  const managed = shallowReactive({
10
10
  objectInstance: null,
11
11
  objectSubscription: null,
@@ -18,6 +18,7 @@ export const useObject = ({ props }) => {
18
18
  crudArgs: toRef(props, "crudArgs"),
19
19
  id: toRef(props, "id"),
20
20
  retrieveArgs: toRef(props, "retrieveArgs"),
21
+ functions,
21
22
  });
22
23
 
23
24
  const intentPropsWatch = () => {
@@ -86,8 +87,8 @@ export const useObject = ({ props }) => {
86
87
  });
87
88
  exposedState = new Proxy(proxyBase, {
88
89
  // get values from the current state
89
- get(target, key) {
90
- return Reflect.get(getState(), key);
90
+ get(target, prop) {
91
+ return Reflect.get(getState(), prop);
91
92
  },
92
93
  });
93
94
  });
@@ -1,4 +1,4 @@
1
- import { cloneDeep } from "lodash";
1
+ import { cloneDeep, isFunction } from "lodash";
2
2
  import { effectScope, reactive } from "vue";
3
3
  import { addOrUpdateReactiveObject, assignReactiveObject } from "../utils/assignReactiveObject";
4
4
 
@@ -35,7 +35,7 @@ export function useObjectInstances(instanceArgs) {
35
35
  return instances;
36
36
  }
37
37
 
38
- export function useObjectInstance({ crudArgs, id, retrieveArgs }) {
38
+ export function useObjectInstance({ crudArgs, id, retrieveArgs, functions = {} }) {
39
39
  const state = reactive({
40
40
  crud: {
41
41
  args: {},
@@ -58,6 +58,13 @@ export function useObjectInstance({ crudArgs, id, retrieveArgs }) {
58
58
  if (crudArgs) {
59
59
  addOrUpdateReactiveObject(state.crud.args, crudArgs);
60
60
  }
61
+ for (const [key, value] of Object.entries(functions)) {
62
+ if (isFunction(value) && key in state.crud) {
63
+ state[key] = value;
64
+ } else {
65
+ throw ObjectError(`Invalid function "${key}" for useObjectInstance: invalid key or not a function.`);
66
+ }
67
+ }
61
68
 
62
69
  // due to retrieve being called by `useCancelleableIntent`, if called manually then by the watch,
63
70
  // it will run into the loading check. Instead, return the current retrieve promise if it exists.