@arrai-innovations/reactive-helpers 2.7.0 → 2.8.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": "2.7.0",
3
+ "version": "2.8.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
@@ -4,6 +4,7 @@ export * from "./listInstance.js";
4
4
  export * from "./listRelated.js";
5
5
  export * from "./listSort.js";
6
6
  export * from "./listSubscription.js";
7
+ export * from "./object.js";
7
8
  export * from "./objectCalculated.js";
8
9
  export * from "./objectInstance.js";
9
10
  export * from "./objectRelated.js";
package/use/object.js ADDED
@@ -0,0 +1,99 @@
1
+ import { effectScope, shallowReactive, shallowReadonly, toRef, watch } from "vue";
2
+ import { useObjectCalculated } from "./objectCalculated";
3
+ import { useObjectInstance } from "./objectInstance";
4
+ import { useObjectRelated } from "./objectRelated";
5
+ import { useObjectSubscription } from "./objectSubscription";
6
+
7
+ // Manages a chain of useObject functions, based on existence of keys in props: intendToRetrieve, relatedObjectRules, calculatedObjectRules
8
+ export const useObject = ({ props }) => {
9
+ const managed = shallowReactive({
10
+ objectInstance: null,
11
+ objectSubscription: null,
12
+ objectRelated: null,
13
+ objectCalculated: null,
14
+ });
15
+ const es = effectScope();
16
+
17
+ managed.objectInstance = useObjectInstance({
18
+ crudArgs: toRef(props, "crudArgs"),
19
+ id: toRef(props, "id"),
20
+ retrieveArgs: toRef(props, "retrieveArgs"),
21
+ });
22
+
23
+ const intentPropsWatch = () => {
24
+ es.run(() => {
25
+ let nextState = managed.objectInstance?.state;
26
+ // true or false, having a key is intent to use
27
+ const hasIntendToRetrieve = "intendToRetrieve" in props;
28
+ if (hasIntendToRetrieve && !managed.objectSubscription) {
29
+ managed.objectSubscription = useObjectSubscription({
30
+ objectInstance: managed.objectInstance,
31
+ });
32
+ managed.objectSubscription.state.intendToRetrieve = toRef(props, "intendToRetrieve");
33
+ } else if (!hasIntendToRetrieve && managed.objectSubscription) {
34
+ managed.objectSubscription.effectScope.stop();
35
+ managed.objectSubscription = null;
36
+ }
37
+ const hasRelatedObjectRules = "relatedObjectRules" in props;
38
+ if (hasRelatedObjectRules && !managed.objectRelated) {
39
+ nextState = managed.objectSubscription?.state || nextState;
40
+ managed.objectRelated = useObjectRelated({
41
+ parentState: nextState,
42
+ relatedObjectRules: toRef(props, "relatedObjectRules"),
43
+ });
44
+ } else if (!hasRelatedObjectRules && managed.objectRelated) {
45
+ managed.objectRelated.effectScope.stop();
46
+ managed.objectRelated = null;
47
+ }
48
+ const hasCalculatedObjectRules = "calculatedObjectRules" in props;
49
+ if (hasCalculatedObjectRules && !managed.objectCalculated) {
50
+ nextState = managed.objectRelated?.state || nextState;
51
+ managed.objectCalculated = useObjectCalculated({
52
+ parentState: nextState,
53
+ calculatedObjectRules: toRef(props, "calculatedObjectRules"),
54
+ });
55
+ } else if (!hasCalculatedObjectRules && managed.objectCalculated) {
56
+ managed.objectCalculated.effectScope.stop();
57
+ managed.objectCalculated = null;
58
+ }
59
+ });
60
+ };
61
+
62
+ let exposedState;
63
+
64
+ es.run(() => {
65
+ watch(
66
+ [
67
+ toRef(props, "intendToRetrieve"),
68
+ toRef(props, "relatedObjectRules"),
69
+ toRef(props, "calculatedObjectRules"),
70
+ ],
71
+ intentPropsWatch,
72
+ { immediate: true }
73
+ );
74
+ const getState = () =>
75
+ managed.objectCalculated?.state ||
76
+ managed.objectRelated?.state ||
77
+ managed.objectSubscription?.state ||
78
+ managed.objectInstance.state;
79
+ // used as proxy to have the properties and not be settable, so we only have to override get
80
+ const proxyBase = shallowReadonly({
81
+ loading: null,
82
+ error: null,
83
+ errored: null,
84
+ object: null,
85
+ });
86
+ exposedState = new Proxy(proxyBase, {
87
+ // get values from the current state
88
+ get(target, key) {
89
+ return Reflect.get(getState(), key);
90
+ },
91
+ });
92
+ });
93
+
94
+ return {
95
+ managed: shallowReadonly(managed),
96
+ state: exposedState,
97
+ effectScope: es,
98
+ };
99
+ };
@@ -1,5 +1,5 @@
1
1
  import { cloneDeep } from "lodash";
2
- import { effectScope, reactive } from "vue";
2
+ import { effectScope, reactive, unref } from "vue";
3
3
  import { assignReactiveObject } from "../utils/assignReactiveObject";
4
4
 
5
5
  export class ObjectError extends Error {
@@ -56,7 +56,9 @@ export function useObjectInstance({ crudArgs, id, retrieveArgs }) {
56
56
  // prevent linking of all instances to the same default .args object
57
57
  Object.assign(state.crud, cloneDeep(defaultCrud));
58
58
  if (crudArgs) {
59
- assignReactiveObject(state.crud.args, crudArgs);
59
+ // generally you won't have a ref to an object, but indirectly, you could have a ref to a reactive.
60
+ // either way, we want a reactive or plain object. computed isn't going to work for this.
61
+ assignReactiveObject(state.crud.args, unref(crudArgs));
60
62
  }
61
63
 
62
64
  // due to retrieve being called by `useCancelleableIntent`, if called manually then by the watch,
@@ -1,9 +1,9 @@
1
1
  import { cloneDeep } from "lodash";
2
2
  import { computed, effectScope, reactive, toRef } from "vue";
3
3
  import { assignReactiveObject } from "../utils/assignReactiveObject";
4
- import { useObjectInstance } from "./objectInstance";
5
4
  import { useCancellableIntent } from "../utils/cancellableIntent";
6
5
  import { loadingCombine } from "../utils/loadingCombine";
6
+ import { useObjectInstance } from "./objectInstance";
7
7
 
8
8
  export class ObjectSubscriptionError extends Error {
9
9
  constructor(message) {
@@ -30,7 +30,7 @@ export function useObjectSubscriptions(subscriptionArgs) {
30
30
  return subscriptions;
31
31
  }
32
32
 
33
- export function useObjectSubscription({ objectInstance, crudArgs, id, retrieveArgs = {} }) {
33
+ export function useObjectSubscription({ objectInstance, crudArgs, id, retrieveArgs }) {
34
34
  if (retrieveArgs && objectInstance) {
35
35
  throw new ObjectSubscriptionError(
36
36
  "Cannot use retrieveArgs and objectInstance together, set retrieveArgs on objectInstance instead"
@@ -44,7 +44,6 @@ export function useObjectSubscription({ objectInstance, crudArgs, id, retrieveAr
44
44
  args: {},
45
45
  subscribe: undefined,
46
46
  },
47
- id,
48
47
  subscriptionLoading: undefined,
49
48
  subscriptionErrored: false,
50
49
  subscriptionError: null,
@@ -95,7 +94,7 @@ export function useObjectSubscription({ objectInstance, crudArgs, id, retrieveAr
95
94
  let subscribePromise;
96
95
  subscribePromise = state.crud.subscribe({
97
96
  crudArgs: state.crud.args,
98
- id,
97
+ id: objectInstance.state.id,
99
98
  retrieveArgs: state.retrieveArgs,
100
99
  callback: (data, action) => {
101
100
  if (action === "delete") {
@@ -166,13 +165,22 @@ export function useObjectSubscription({ objectInstance, crudArgs, id, retrieveAr
166
165
 
167
166
  subscribeIntent = useCancellableIntent({
168
167
  awaitableWithCancel: subscribe,
169
- watchArguments: [toRef(state, "intendToSubscribe"), toRef(state, "id"), toRef(state, "retrieveArgs")],
168
+ watchArguments: [
169
+ toRef(state, "intendToSubscribe"),
170
+ toRef(objectInstance.state, "id"),
171
+ toRef(state, "retrieveArgs"),
172
+ ],
170
173
  clearActiveOnResolved: false,
171
174
  });
172
175
 
173
176
  retrieveIntent = useCancellableIntent({
174
177
  awaitableWithCancel: objectInstance.retrieve,
175
- watchArguments: [toRef(state, "intendToRetrieve"), toRef(state, "id"), toRef(state, "retrieveArgs")],
178
+ watchArguments: [
179
+ toRef(state, "intendToRetrieve"),
180
+ toRef(objectInstance.state, "id"),
181
+ toRef(state, "retrieveArgs"),
182
+ ],
183
+ nameForLog: "retrieveIntent",
176
184
  });
177
185
  });
178
186