@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/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, onScopeDispose, reactive, toRef, unref, watch } from "vue";
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
- sortCriteriaWatches: {},
57
+ sortCriteriaEffectScopes: {},
43
58
  orderByDesc: [],
44
59
  });
45
60
  const es = effectScope();
46
61
 
47
62
  function removeSortCriteria(removedKey) {
48
- const stopWatches = state.sortCriteriaWatches[removedKey] || [];
49
- let stopWatch = stopWatches.pop();
50
- while (stopWatch) {
51
- stopWatch();
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 oldStopWatches = state.sortCriteriaWatches[key] || [];
60
- let stopWatch = oldStopWatches.pop();
61
- while (stopWatch) {
62
- stopWatch();
63
- stopWatch = oldStopWatches.pop();
72
+ const oldScope = state.sortCriteriaEffectScopes[key];
73
+ if (oldScope) {
74
+ oldScope.stop();
64
75
  }
65
- const stopWatches = [];
66
- if (!state.sortCriteria[key]) {
67
- state.sortCriteria[key] = [];
68
- }
69
- stopWatches.push(
76
+ const newScope = effectScope();
77
+ newScope.run(() => {
78
+ if (!state.sortCriteria[key]) {
79
+ state.sortCriteria[key] = [];
80
+ }
70
81
  watch(
71
- [object, state.orderByRules],
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
- const obo = unref(orderByObj);
76
- const getter = obo.keyFn ? obo.keyFn : partial(get, partial.placeholder, obo.key);
77
- newSearchCriteria.push(getter(object));
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.sortCriteriaWatches[key] = stopWatches;
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
- for (const addedKey of addedKeys) {
105
- const object = parentState.objects[addedKey];
106
- addSortCriteria(object, addedKey);
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
- assignReactiveObject(state.order, Object.keys(parentState.objects));
117
- assignReactiveObject(state.objectsInOrder, Object.values(parentState.objects));
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
- state.objects = toRef(parentState, "objects");
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(() => cloneDeep(state.orderByRules), sortCriteriaWatch, {
203
+ watch(toRef(state, "orderByRules"), sortCriteriaWatch, {
168
204
  deep: true,
169
205
  immediate: true,
170
206
  });
171
207
 
172
- // watching parentState.order triggers some out of order `computed`s, now that listInstance.order is a computed.
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 {
@@ -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 function setListSubscriptionCrud({ subscribe }) {
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
- export function useListSubscription({ listInstance, props, functions }) {
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 crudArgs.");
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 crudArgs, not both."
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
- if (!listInstance.state.crud.subscribe) {
61
- listInstance.state.crud.subscribe = defaultCrud.subscribe;
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
- return reactive({
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
  };
@@ -1,8 +1,21 @@
1
- import { keyDiff, loadingCombine } from "../utils/index.js";
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
- calculatedObjectObjects: {},
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
- state[copn] = toRef(state, "calculatedObjectObjects");
63
- for (let key of passThroughPropertyNames) {
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.calculatedObjectObjects[removedKey];
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.calculatedObjectObjects[addedKey] = computed(() =>
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.relatedRunning));
100
+ state.running = computed(() => loadingCombine(watchesRunning.state.running, parentState.running));
114
101
 
115
102
  onScopeDispose(() => {
116
103
  for (const key in calculatedObjectEffectScopes) {
@@ -1,6 +1,5 @@
1
- import { addOrUpdateReactiveObject, assignReactiveObject } from "../utils/index.js";
2
- import cloneDeep from "lodash-es/cloneDeep.js";
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 defaultCrud = {
14
- args: {},
15
- retrieve: undefined,
16
- create: undefined,
17
- update: undefined,
18
- patch: undefined,
19
- delete: undefined,
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 function setObjectInstanceCrud({ retrieve, create, update, patch, delete: deleteFn, args = {} }) {
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
- // prevent linking of all instances to the same default .args object
58
- Object.assign(state.crud, cloneDeep(defaultCrud));
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
  });
@@ -1,4 +1,7 @@
1
- import { keyDiff } from "../utils/index.js";
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
- relatedObjectObjects: {},
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
- state[ropn] = toRef(state, "relatedObjectObjects");
59
- for (let key of passThroughPropertyNames) {
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.relatedObjectObjects);
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.relatedObjectObjects)
60
+ Object.keys(state.relatedObject)
72
61
  ));
73
62
  }
74
63
 
75
64
  for (const removedRuleKey of removedRuleKeys) {
76
- delete state.relatedObjectObjects[removedRuleKey];
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.relatedObjectObjects[addedRuleKey] = computed(() => {
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) {