@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.
@@ -21,6 +21,7 @@ describe("use/listSubscription.spec.js", function () {
21
21
  crudSubscribeResolvable = [];
22
22
  crudListResolvable.push(new CancellableResolvable());
23
23
  crudSubscribeResolvable.push(new CancellableResolvable());
24
+ const listCrudModule = await import("../../../config/listCrud.js");
24
25
  const listInstanceModule = await import("../../../use/listInstance");
25
26
  crudList = vi
26
27
  .fn()
@@ -30,8 +31,9 @@ describe("use/listSubscription.spec.js", function () {
30
31
  crudListResolvable.push(newResolvable);
31
32
  return newResolvable.promise;
32
33
  });
33
- listInstanceModule.setListInstanceCrud({
34
+ listCrudModule.setListCrud({
34
35
  list: crudList,
36
+ subscribe: crudSubscribe,
35
37
  args: { stream: "test_stream" },
36
38
  });
37
39
  const listSubscriptionModule = await import("../../../use/listSubscription");
@@ -49,10 +51,6 @@ describe("use/listSubscription.spec.js", function () {
49
51
  passedSubscriptionEventCallback = subscriptionEventCallback;
50
52
  return newResolvable.promise;
51
53
  });
52
- listSubscriptionModule.setListSubscriptionCrud({
53
- subscribe: crudSubscribe,
54
- args: { stream: "test_stream" },
55
- });
56
54
 
57
55
  useListInstance = listInstanceModule.useListInstance;
58
56
  useListInstances = listInstanceModule.useListInstances;
package/use/list.js CHANGED
@@ -1,7 +1,9 @@
1
- import { useListCalculated } from "./listCalculated.js";
2
- import { useListInstance } from "./listInstance.js";
3
- import { useListRelated } from "./listRelated.js";
4
- import { useListSubscription } from "./listSubscription.js";
1
+ import { useListCalculated, listCalculatedFunctions } from "./listCalculated.js";
2
+ import { useListFilter, listFilterFunctions } from "./listFilter.js";
3
+ import { useListInstance, listInstanceFunctions } from "./listInstance.js";
4
+ import { useListRelated, listRelatedFunctions } from "./listRelated.js";
5
+ import { useListSort, listSortFunctions } from "./listSort.js";
6
+ import { useListSubscription, listSubscriptionFunctions } from "./listSubscription.js";
5
7
  import { usePagedListInstance } from "./paginatedListInstance.js";
6
8
  import { effectScope, reactive, shallowReactive, shallowReadonly, toRef } from "vue";
7
9
 
@@ -42,6 +44,7 @@ export const useList = ({ props, functions, paged = false, keepOldPages = false
42
44
  listInstance: managed.listInstance,
43
45
  });
44
46
  managed.listSubscription.state.intendToList = toRef(props, "intendToList");
47
+ managed.listSubscription.state.intendToSubscribe = toRef(props, "intendToSubscribe");
45
48
 
46
49
  managed.listRelated = useListRelated({
47
50
  parentState: managed.listSubscription.state,
@@ -52,6 +55,23 @@ export const useList = ({ props, functions, paged = false, keepOldPages = false
52
55
  parentState: managed.listRelated.state,
53
56
  calculatedObjectsRules: toRef(props, "calculatedObjectsRules"),
54
57
  });
58
+
59
+ managed.listFilter = useListFilter({
60
+ parentState: managed.listCalculated.state,
61
+ useTextSearch: toRef(props, "useTextSearch"),
62
+ textSearchRules: toRef(props, "textSearchRules"),
63
+ textSearchValue: toRef(props, "textSearchValue"),
64
+ allowedValues: toRef(props, "allowedValues"),
65
+ excludedValues: toRef(props, "excludedValues"),
66
+ allowedFilter: toRef(props, "allowedFilter"),
67
+ excludedFilter: toRef(props, "excludedFilter"),
68
+ });
69
+
70
+ managed.listSort = useListSort({
71
+ parentState: managed.listFilter.state,
72
+ orderByRules: toRef(props, "orderByRules"),
73
+ sortThrottleWait: functions.sortThrottleWait,
74
+ });
55
75
  });
56
76
 
57
77
  const clearError = (error) => {
@@ -59,18 +79,32 @@ export const useList = ({ props, functions, paged = false, keepOldPages = false
59
79
  managed.listInstance.clearError(error);
60
80
  };
61
81
 
62
- return reactive({
82
+ const returnObject = reactive({
63
83
  // we manage the keys on both of these, so hands off the root.
64
84
  managed: shallowReadonly(managed),
65
- state: managed.listCalculated.state,
66
- list: managed.listInstance.list,
67
- addListObject: managed.listInstance.addListObject,
68
- updateListObject: managed.listInstance.updateListObject,
69
- deleteListObject: managed.listInstance.deleteListObject,
70
- clearList: managed.listInstance.clearList,
71
- clearError,
72
- getFakeId: managed.listInstance.getFakeId,
73
- defaultPageCallback: managed.listInstance.defaultPageCallback,
85
+ state: managed.listSort.state,
74
86
  effectScope: es,
75
87
  });
88
+ const handledDuplicateFunctions = {
89
+ clearError,
90
+ };
91
+ for (const [source, fnNames] of [
92
+ [managed.listInstance, listInstanceFunctions],
93
+ [managed.listSubscription, listSubscriptionFunctions],
94
+ [managed.listRelated, listRelatedFunctions],
95
+ [managed.listCalculated, listCalculatedFunctions],
96
+ [managed.listFilter, listFilterFunctions],
97
+ [managed.listSort, listSortFunctions],
98
+ ]) {
99
+ for (const fnName of fnNames) {
100
+ if (handledDuplicateFunctions[fnName]) {
101
+ continue;
102
+ }
103
+ returnObject[fnName] = source[fnName];
104
+ }
105
+ }
106
+ for (const [fnName, fn] of Object.entries(handledDuplicateFunctions)) {
107
+ returnObject[fnName] = fn;
108
+ }
109
+ return returnObject;
76
110
  };
@@ -13,6 +13,8 @@ export const listCalculatedStateKeys = [
13
13
  "calculatedObjectsWatchRunning",
14
14
  ];
15
15
 
16
+ export const listCalculatedFunctions = [];
17
+
16
18
  export function useListCalculateds(instances, args) {
17
19
  for (const [key, value] of Object.entries(args)) {
18
20
  useListCalculated({
@@ -130,6 +132,7 @@ export function useListCalculated({ parentState, calculatedObjectsRules }) {
130
132
  ],
131
133
  });
132
134
 
135
+ state.calculatedRunning = toRef(watchesRunning.state, "running");
133
136
  state.running = computed(() => loadingCombine(watchesRunning.state.running, parentState.running));
134
137
 
135
138
  onScopeDispose(() => {
package/use/listFilter.js CHANGED
@@ -1,10 +1,30 @@
1
1
  import { keyDiff } from "../utils/keyDiff.js";
2
+ import { listCalculatedStateKeys } from "./listCalculated.js";
3
+ import { listInstanceStateKeys } from "./listInstance.js";
4
+ import { listRelatedStateKeys } from "./listRelated.js";
5
+ import { listSubscriptionStateKeys } from "./listSubscription.js";
2
6
  import { useSearch } from "./search.js";
3
7
  import get from "lodash-es/get.js";
4
8
  import identity from "lodash-es/identity.js";
5
9
  import isEmpty from "lodash-es/isEmpty.js";
6
10
  import { computed, effectScope, onScopeDispose, reactive, toRef, watch, watchEffect } from "vue";
7
11
 
12
+ export const listFilterStateKeys = [
13
+ "objectIndexes",
14
+ // override but not ours
15
+ // "objects",
16
+ "textSearchRules",
17
+ "textSearchValue",
18
+ "allowedValues",
19
+ "excludedValues",
20
+ "allowedFilter",
21
+ "excludedFilter",
22
+ "searched",
23
+ "searching",
24
+ ];
25
+
26
+ export const listFilterFunctions = [];
27
+
8
28
  export function useListFilters(listFilterArgs, parentInstances) {
9
29
  const filters = {};
10
30
  for (const [key, value] of Object.entries(listFilterArgs)) {
@@ -32,6 +52,8 @@ export function useListFilter({
32
52
  excludedValues,
33
53
  allowedFilter,
34
54
  excludedFilter,
55
+ searched: undefined,
56
+ searching: undefined,
35
57
  });
36
58
 
37
59
  const es = effectScope();
@@ -39,6 +61,21 @@ export function useListFilter({
39
61
  let textSearchIndex;
40
62
 
41
63
  es.run(() => {
64
+ for (const key of listInstanceStateKeys) {
65
+ if (key === "objects") {
66
+ continue;
67
+ }
68
+ state[key] = toRef(parentState, key);
69
+ }
70
+ for (const key of listSubscriptionStateKeys) {
71
+ state[key] = toRef(parentState, key);
72
+ }
73
+ for (const key of listRelatedStateKeys) {
74
+ state[key] = toRef(parentState, key);
75
+ }
76
+ for (const key of listCalculatedStateKeys) {
77
+ state[key] = toRef(parentState, key);
78
+ }
42
79
  if (useTextSearch) {
43
80
  textSearchIndex = useSearch();
44
81
  textSearchIndex.state.search = toRef(state, "textSearchValue");
@@ -46,9 +83,11 @@ export function useListFilter({
46
83
  state.searching = toRef(textSearchIndex.state, "searching");
47
84
  }
48
85
 
86
+ // todo: computed is not the solution here for deep reactions
49
87
  state.objectsInOrder = computed(() => parentState.order.map((id) => state.objects[id]).filter(identity));
50
88
  state.order = computed(() => state.objectsInOrder.map((object) => `${object.id}`));
51
89
 
90
+ // todo: this huge watchEffect is fairly gross, but also doesn't watch deep similarly to computed
52
91
  watchEffect(() => {
53
92
  const allowedValuesEmpty = !state.allowedValues || isEmpty(state.allowedValues);
54
93
  const excludedValuesEmpty = !state.excludedValues || isEmpty(state.excludedValues);
@@ -104,6 +143,7 @@ export function useListFilter({
104
143
  if (useTextSearch) {
105
144
  const stopIndexWatch = {};
106
145
 
146
+ // todo: this huge watchEffect is fairly gross, but also doesn't watch deep similarly to computed
107
147
  watchEffect(() => {
108
148
  const { removedKeys, addedKeys } = keyDiff(
109
149
  Object.keys(parentState.objects),
@@ -1,9 +1,8 @@
1
- import { addOrUpdateReactiveObject, assignReactiveObject } from "../utils/assignReactiveObject.js";
1
+ import { getListCrud } from "../config/listCrud.js";
2
+ import { assignReactiveObject } from "../utils/assignReactiveObject.js";
2
3
  import { getFakeId } from "../utils/getFakeId.js";
3
4
  import inspect from "browser-util-inspect";
4
- import cloneDeep from "lodash-es/cloneDeep.js";
5
- import isFunction from "lodash-es/isFunction.js";
6
- import { computed, effectScope, reactive, toRef, watchEffect } from "vue";
5
+ import { computed, effectScope, reactive, toRef } from "vue";
7
6
 
8
7
  export class ListError extends Error {
9
8
  constructor(message, code) {
@@ -13,11 +12,6 @@ export class ListError extends Error {
13
12
  }
14
13
  }
15
14
 
16
- const defaultCrud = {
17
- args: {},
18
- list: undefined,
19
- };
20
-
21
15
  export const listInstanceStateKeys = [
22
16
  "crud",
23
17
  "retrieveArgs",
@@ -34,11 +28,39 @@ export const listInstanceStateKeys = [
34
28
  "perPage",
35
29
  ];
36
30
 
37
- export function setListInstanceCrud({ list, args = {} } = {}) {
38
- defaultCrud.list = list;
39
- Object.assign(defaultCrud.args, args);
40
- }
31
+ export const listInstanceFunctions = [
32
+ "list",
33
+ "addListObject",
34
+ "updateListObject",
35
+ "deleteListObject",
36
+ "clearList",
37
+ "clearError",
38
+ "getFakeId",
39
+ "defaultPageCallback",
40
+ "pageCallback",
41
+ ];
41
42
 
43
+ /**
44
+ * The configuration options used to create a list instance.
45
+ * @typedef {object} ListInstanceOptions
46
+ * @property {object} props - props passed to the component
47
+ * @property {object} props.retrieveArgs - the arguments passed to the server
48
+ * @property {object} props.listArgs - the arguments passed to the server
49
+ * @property {object} props.crudArgs - implementation specific arguments
50
+ * @property {object} functions - optional. default implementation are used as set by `setListCrud`.
51
+ * @property {Function} functions.list - provide the implementation for the list function
52
+ * @property {Function} functions.subscribe - provide the implementation for the subscribe function
53
+ * @property {boolean} keepOldPages - if true, pages will not be cleared when defaultPageCallback is called. default is false.
54
+ */
55
+
56
+ /* eslint-disable jsdoc/check-types */
57
+ // types valid for jsdoc-to-markdown, which uses the strict jsdoc.app. Object shorthand syntax doesn't work.
58
+ /**
59
+ * A Vue composition function that creates multiple list instances, and returns them as an object.
60
+ * @param {Object.<string, ListInstanceOptions>} listInstanceArgs - each desired list instance options, keyed by an instance name.
61
+ * @returns {Object.<string, ListInstance>} - each list instance, keyed by the instance name.
62
+ */
63
+ /* eslint-enable jsdoc/check-types */
42
64
  export function useListInstances(listInstanceArgs) {
43
65
  const instances = {};
44
66
  for (const [key, value] of Object.entries(listInstanceArgs)) {
@@ -47,6 +69,48 @@ export function useListInstances(listInstanceArgs) {
47
69
  return instances;
48
70
  }
49
71
 
72
+ /**
73
+ * A reactive object that manages a list of objects, as returned by `useListInstance`.
74
+ * @typedef {object} ListInstanceState
75
+ * @property {object} crud - the crud functions
76
+ * @property {object} crud.args - the arguments passed to the crud functions
77
+ * @property {Function} crud.list - the list function
78
+ * @property {Function} crud.subscribe - the subscribe function
79
+ * @property {object} retrieveArgs - the arguments passed to the server
80
+ * @property {object} listArgs - the arguments passed to the server
81
+ * @property {Map} objects - the objects in the list
82
+ * @property {boolean} loading - true if the list is loading
83
+ * @property {boolean} errored - true if the list has errored
84
+ * @property {object} error - the error object
85
+ * @property {Array} objectsInOrder - the objects in the list in order
86
+ * @property {Array} order - the order of the objects in the list
87
+ * @property {number} totalRecords - the total number of records
88
+ * @property {number} totalPages - the total number of pages
89
+ * @property {number} perPage - the number of records per page
90
+ */
91
+
92
+ /**
93
+ * @typedef {object} ListInstance
94
+ * @property {Function} list - subscribe to updates from the implementation
95
+ * @property {Function} addListObject - add an object to the list
96
+ * @property {Function} updateListObject - update an object in the list
97
+ * @property {Function} deleteListObject - delete an object from the list
98
+ * @property {Function} clearList - clear the list
99
+ * @property {Function} clearError - clear the error
100
+ * @property {Function} getFakeId - get a fake id
101
+ * @property {Function} defaultPageCallback - the default page callback
102
+ * @property {Function} pageCallback - the page callback
103
+ * @property {ListInstanceState} state - the list instance state
104
+ * @property {object} effectScope - a Vue effect scope
105
+ */
106
+
107
+ /**
108
+ * `useListInstance` is a Vue composition function that manages a list of objects.
109
+ * It has the ability to retrieve the list from an implementation, or subscribe to updates from an implementation.
110
+ * It tracks the objects in the list, and their added order.
111
+ * @param {ListInstanceOptions} options - the options used to create the list instance
112
+ * @returns {ListInstance} - the list instance
113
+ */
50
114
  export function useListInstance({ props, functions = {}, keepOldPages = false }) {
51
115
  if (!props) {
52
116
  throw new ListError(`useListInstance requires props`);
@@ -98,20 +162,8 @@ export function useListInstance({ props, functions = {}, keepOldPages = false })
98
162
  error: null,
99
163
  });
100
164
  const es = effectScope();
101
- watchEffect(() => {
102
- // prevent linking of all instances to the same default .args object
103
- Object.assign(state.crud, cloneDeep(defaultCrud));
104
- if (props.crudArgs) {
105
- addOrUpdateReactiveObject(state.crud.args, props.crudArgs);
106
- }
107
- for (const [key, value] of Object.entries(functions)) {
108
- if (isFunction(value) && key in state.crud) {
109
- state.crud[key] = value;
110
- } else {
111
- throw ListError(`Invalid function "${key}" for useListInstance: invalid key or not a function.`);
112
- }
113
- }
114
- });
165
+
166
+ getListCrud(state.crud, { props, functions });
115
167
 
116
168
  const defaultPageCallback = (newObjects) => {
117
169
  // with keepOldPages, you are responsible for clearing the list as needed
@@ -173,6 +225,7 @@ export function useListInstance({ props, functions = {}, keepOldPages = false })
173
225
  .finally(() => {
174
226
  state.loading = false;
175
227
  returnPromiseResolve(resolveState);
228
+ promises.list = null;
176
229
  });
177
230
  return promises.list;
178
231
  }
@@ -1,4 +1,5 @@
1
- import { keyDiff, loadingCombine } from "../utils/index.js";
1
+ import { keyDiff } from "../utils/keyDiff.js";
2
+ import { loadingCombine } from "../utils/loadingCombine.js";
2
3
  import { listInstanceStateKeys } from "./listInstance.js";
3
4
  import { listSubscriptionStateKeys } from "./listSubscription.js";
4
5
  import { useWatchesRunning } from "./watchesRunning.js";
@@ -15,6 +16,8 @@ export const listRelatedStateKeys = [
15
16
  "relatedObjectsParentStateObjectsWatchRunning",
16
17
  ];
17
18
 
19
+ export const listRelatedFunctions = [];
20
+
18
21
  export function useListRelateds(instances, args) {
19
22
  for (const [key, value] of Object.entries(args)) {
20
23
  useListRelated({
@@ -130,6 +133,7 @@ export function useListRelated({ parentState, relatedObjectsRules }) {
130
133
  ],
131
134
  });
132
135
 
136
+ state.relatedRunning = toRef(watchesRunning.state, "running");
133
137
  state.running = computed(() => loadingCombine(watchesRunning.state.running, parentState.running));
134
138
 
135
139
  onScopeDispose(() => {
package/use/listSort.js CHANGED
@@ -1,4 +1,9 @@
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";
@@ -10,6 +15,17 @@ import throttle from "lodash-es/throttle.js";
10
15
  import zip from "lodash-es/zip.js";
11
16
  import { effectScope, onScopeDispose, reactive, toRef, unref, watch } from "vue";
12
17
 
18
+ export const listSortStateKeys = [
19
+ "orderByRules",
20
+ // "order",
21
+ // "objectsInOrder",
22
+ "sortCriteria",
23
+ "sortCriteriaWatches",
24
+ "orderByDesc",
25
+ ];
26
+
27
+ export const listSortFunctions = [];
28
+
13
29
  const collator = new Intl.Collator(undefined, { numeric: true });
14
30
 
15
31
  const defaultSortThrottleWait = Symbol("defaultSortThrottleWait");
@@ -161,7 +177,24 @@ export function useListSort({ parentState, orderByRules, sortThrottleWait = defa
161
177
  const throttledSortWatch = throttle(sortWatch, sortThrottleWait);
162
178
 
163
179
  es.run(() => {
164
- state.objects = toRef(parentState, "objects");
180
+ for (const key of listInstanceStateKeys) {
181
+ if (["order", "objectsInOrder"].includes(key)) {
182
+ continue;
183
+ }
184
+ state[key] = toRef(parentState, key);
185
+ }
186
+ for (const key of listSubscriptionStateKeys) {
187
+ state[key] = toRef(parentState, key);
188
+ }
189
+ for (const key of listRelatedStateKeys) {
190
+ state[key] = toRef(parentState, key);
191
+ }
192
+ for (const key of listCalculatedStateKeys) {
193
+ state[key] = toRef(parentState, key);
194
+ }
195
+ for (const key of listFilterStateKeys) {
196
+ state[key] = toRef(parentState, key);
197
+ }
165
198
  // we do not need two immediate watches to the same function.
166
199
  watch(() => Object.keys(parentState.objects), sortCriteriaWatch);
167
200
  watch(() => cloneDeep(state.orderByRules), sortCriteriaWatch, {
@@ -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
 
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
  };