@arrai-innovations/reactive-helpers 1.2.3 → 2.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/.lintstagedrc CHANGED
@@ -7,5 +7,8 @@
7
7
  ],
8
8
  "**/*.{js,cjs,mjs,ts,jsx,tsx,less,scss,css,vue,markdown,json,md,yml,yaml,html}": [
9
9
  "npx --no-install prettier --write"
10
+ ],
11
+ ".circleci/config.yml": [
12
+ "circleci config validate"
10
13
  ]
11
14
  }
package/README.md CHANGED
@@ -68,17 +68,19 @@ setListInstanceCrud({
68
68
  });
69
69
 
70
70
  // then use in your component
71
+ import { reactive } from "vue";
71
72
  import { useListInstance } from "@arrai-innovations/reactive-helpers";
73
+ const listArgs = reactive({
74
+ has_organization: true,
75
+ });
72
76
  const contacts = useListInstance({
73
77
  crudArgs: {
74
78
  stream: "contacts",
75
79
  },
76
- defaultRetrieveArgs: {
80
+ retrieveArgs: {
77
81
  fields: ["id", "has_name", "lexical_name", "organization", "phone"],
78
82
  },
79
- defaultListArgs: {
80
- has_organization: true,
81
- },
83
+ listArgs,
82
84
  });
83
85
 
84
86
  await contacts.list();
@@ -90,11 +92,14 @@ console.log(contacts.error);
90
92
  // null
91
93
  console.log(contacts.objects);
92
94
  // { contacts keyed by 'id' }
93
- contacts.defaultRetrieveArgs.fields.push("message_count");
95
+ // change list or retrieve args directly
96
+ contacts.state.retrieveArgs.fields.push("message_count");
94
97
  await contacts.list();
95
98
  console.log(contacts.objects);
96
99
  // { contacts keyed by 'id' with message_count }
97
- await contacts.list({ listArgs: {} });
100
+ // change list or retrieve args indirectly
101
+ listArgs.has_organization = false;
102
+ await contacts.list();
98
103
  console.log(contacts.objects);
99
104
  // { contacts keyed by 'id' with organizationless contacts }
100
105
  ```
@@ -126,10 +131,10 @@ const contacts = useListInstance({
126
131
  crudArgs: {
127
132
  stream: "contacts",
128
133
  },
129
- defaultRetrieveArgs: {
134
+ retrieveArgs: {
130
135
  fields: ["id", "has_name", "lexical_name", "organization", "phone"],
131
136
  },
132
- defaultListArgs: {
137
+ listArgs: {
133
138
  has_organization: true,
134
139
  },
135
140
  });
@@ -144,15 +149,15 @@ const contactsSubscription = useListSubscription({
144
149
  });
145
150
 
146
151
  // only get new or updated contacts, not existing.
147
- contactsSubscription.subscribe({ list: false });
152
+ contactsSubscription.subscribe();
148
153
  // or, subscribe and get the existing list.
149
154
  contactsSubscription.subscribe();
150
155
  // stop getting updates.
151
156
  contactsSubscription.unsubscribe();
152
157
  // re-retreive the list of existing contacts including another field.
153
- contacts.defaultRetrieveArgs.fields.push("message_count");
158
+ contacts.retrieveArgs.fields.push("message_count");
154
159
  // re-retreive the list of all existing contacts.
155
- delete contacts.defaultListArgs.has_organization;
160
+ delete contacts.listArgs.has_organization;
156
161
  ```
157
162
 
158
163
  #### Related
@@ -169,7 +174,7 @@ import { nextTick } from "vue";
169
174
  import { useListInstance, useListRelated } from "@arrai-innovations/reactive-helpers";
170
175
  const organizations = useListInstance({});
171
176
  const contacts = useListInstance({
172
- defaultRetrieveArgs: {
177
+ retrieveArgs: {
173
178
  fields: ["id", "lexical_name", "organization"],
174
179
  },
175
180
  });
@@ -236,7 +241,7 @@ import { nextTick } from "vue";
236
241
  // use in your component
237
242
  import { useListInstance, useListSort } from "@arrai-innovations/reactive-helpers";
238
243
  const contacts = useListInstance({
239
- defaultRetrieveArgs: {
244
+ retrieveArgs: {
240
245
  fields: ["id", "has_name", "lexical_name", "organization"],
241
246
  },
242
247
  });
@@ -269,7 +274,7 @@ import { nextTick } from "vue";
269
274
  // use in your component
270
275
  import { useListInstance, useListFilter } from "@arrai-innovations/reactive-helpers";
271
276
  const contacts = useListInstance({
272
- defaultRetrieveArgs: {
277
+ retrieveArgs: {
273
278
  fields: ["id", "has_name", "lexical_name", "organization"],
274
279
  },
275
280
  });
@@ -313,10 +318,10 @@ const contacts = useListInstance({
313
318
  crudArgs: {
314
319
  stream: "contacts",
315
320
  },
316
- defaultRetrieveArgs: {
321
+ retrieveArgs: {
317
322
  fields: ["id", "has_name", "lexical_name", "organization", "phone"],
318
323
  },
319
- defaultListArgs: {
324
+ listArgs: {
320
325
  has_organization: true,
321
326
  },
322
327
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arrai-innovations/reactive-helpers",
3
- "version": "1.2.3",
3
+ "version": "2.0.0",
4
4
  "description": "VueJS 3 utility composition functions to help manipulate objects and lists.",
5
5
  "main": "index.js",
6
6
  "directories": {
@@ -0,0 +1,23 @@
1
+ export class Resolvable {
2
+ constructor() {
3
+ this.promise = new Promise((resolve, reject) => {
4
+ this.resolve = resolve;
5
+ this.reject = reject;
6
+ });
7
+ }
8
+ }
9
+
10
+ export class CancellableResolvable {
11
+ constructor() {
12
+ const newResolvable = new Resolvable();
13
+ const cancelResolvable = new Resolvable();
14
+ newResolvable.promise.cancel = jest
15
+ .fn()
16
+ .mockImplementationOnce(async () => {
17
+ return cancelResolvable.promise;
18
+ })
19
+ .mockRejectedValue(new Error("cancel already called"));
20
+ Object.assign(this, newResolvable);
21
+ this.cancel = cancelResolvable;
22
+ }
23
+ }
@@ -0,0 +1,50 @@
1
+ import { Resolvable } from "./crudPromise";
2
+
3
+ export async function poll(condition, interval = 100, timeout = 1000) {
4
+ let intervalId,
5
+ timeoutId,
6
+ resolvable = new Resolvable();
7
+
8
+ const calledStack = new Error().stack.split("\n").slice(2).join("\n");
9
+
10
+ function stop() {
11
+ if (intervalId) {
12
+ clearInterval(intervalId);
13
+ intervalId = null;
14
+ }
15
+ if (timeoutId) {
16
+ clearTimeout(timeoutId);
17
+ timeoutId = null;
18
+ }
19
+ }
20
+
21
+ function doInterval() {
22
+ if (condition()) {
23
+ stop();
24
+ if (resolvable) {
25
+ resolvable.resolve();
26
+ resolvable = null;
27
+ }
28
+ }
29
+ }
30
+
31
+ function doTimeout() {
32
+ stop();
33
+ let conditionValue = condition();
34
+ if (conditionValue) {
35
+ if (resolvable) {
36
+ resolvable.resolve();
37
+ resolvable = null;
38
+ }
39
+ } else if (resolvable) {
40
+ let timedOutError = new Error(`poll timeout: condition was never true (it was last ${conditionValue})`);
41
+ timedOutError.stack = timedOutError.stack.split("\n").slice(0, 1).join("\n") + "\n" + calledStack;
42
+ resolvable.reject(timedOutError);
43
+ resolvable = null;
44
+ }
45
+ }
46
+ intervalId = setInterval(doInterval, interval);
47
+ timeoutId = setTimeout(doTimeout, timeout);
48
+
49
+ return resolvable.promise;
50
+ }
@@ -1,5 +1,5 @@
1
1
  import { expectErrorToBeNull } from "../expectHelpers";
2
- import { isReactive, nextTick } from "vue";
2
+ import { isReactive, nextTick, reactive } from "vue";
3
3
  import { keyBy } from "lodash";
4
4
  import flushPromises from "flush-promises";
5
5
  import { inspect } from "util";
@@ -68,7 +68,16 @@ describe("use/listInstance.spec.js", function () {
68
68
  const crudListResolvedObjects = keyBy([...crudListResolvedPage1, ...crudListResolvedPage2], "id");
69
69
  describe("list", function () {
70
70
  it("success", async function () {
71
- const listInstance = useListInstance({});
71
+ const listArgs = reactive({
72
+ user: 1,
73
+ });
74
+ const retrieveArgs = reactive({
75
+ fields,
76
+ });
77
+ const listInstance = useListInstance({
78
+ listArgs,
79
+ retrieveArgs,
80
+ });
72
81
  let crudListResolve;
73
82
  const crudListPromise = new Promise((resolve) => {
74
83
  crudListResolve = resolve;
@@ -84,10 +93,7 @@ describe("use/listInstance.spec.js", function () {
84
93
  expect(listInstance.state.loading).toBeUndefined();
85
94
  expect({ ...listInstance.state.objects }).toEqual({});
86
95
 
87
- const liListResolve = listInstance.list({
88
- listArgs: { user: 1 },
89
- retrieveArgs: { fields: fields },
90
- });
96
+ const liListResolve = listInstance.list();
91
97
 
92
98
  expectErrorToBeNull(listInstance.state.error);
93
99
  expect(listInstance.state.errored).toBe(false);
@@ -128,23 +134,24 @@ describe("use/listInstance.spec.js", function () {
128
134
  expect(globalList).toHaveBeenCalledTimes(1);
129
135
  });
130
136
  it("already loading", async function () {
131
- const listInstance = useListInstance({});
137
+ const listArgs = reactive({
138
+ user: 1,
139
+ });
140
+ const retrieveArgs = reactive({
141
+ fields,
142
+ });
143
+ const listInstance = useListInstance({
144
+ listArgs,
145
+ retrieveArgs,
146
+ });
132
147
  expectErrorToBeNull(listInstance.state.error);
133
148
  expect(listInstance.state.errored).toBe(false);
134
149
  expect(listInstance.state.loading).toBeUndefined();
135
150
  expect({ ...listInstance.state.objects }).toEqual({});
136
151
  globalList.mockImplementation(() => new Promise(() => {}));
137
152
 
138
- listInstance.list({
139
- listArgs: { user: 1 },
140
- retrieveArgs: { fields: fields },
141
- });
142
- await expect(
143
- listInstance.list({
144
- listArgs: { user: 1 },
145
- retrieveArgs: { fields: fields },
146
- })
147
- ).rejects.toThrow(ListError);
153
+ listInstance.list();
154
+ await expect(listInstance.list()).rejects.toThrow(ListError);
148
155
 
149
156
  expect(globalList).toHaveBeenCalledWith({
150
157
  crudArgs: { stream: "test_stream" },
@@ -159,7 +166,16 @@ describe("use/listInstance.spec.js", function () {
159
166
  expect({ ...listInstance.state.objects }).toEqual({});
160
167
  });
161
168
  it("errored", async function () {
162
- const listInstance = useListInstance({});
169
+ const listArgs = reactive({
170
+ user: 1,
171
+ });
172
+ const retrieveArgs = reactive({
173
+ fields,
174
+ });
175
+ const listInstance = useListInstance({
176
+ listArgs,
177
+ retrieveArgs,
178
+ });
163
179
  let crudListReject;
164
180
  const crudListPromise = new Promise((resolve, reject) => {
165
181
  crudListReject = reject;
@@ -175,10 +191,7 @@ describe("use/listInstance.spec.js", function () {
175
191
  expect(listInstance.state.loading).toBeUndefined();
176
192
  expect({ ...listInstance.state.objects }).toEqual({});
177
193
 
178
- const liListResolve = listInstance.list({
179
- listArgs: { user: 1 },
180
- retrieveArgs: { fields: fields },
181
- });
194
+ const liListResolve = listInstance.list();
182
195
 
183
196
  expectErrorToBeNull(listInstance.state.error);
184
197
  expect(listInstance.state.errored).toBe(false);
@@ -205,68 +218,16 @@ describe("use/listInstance.spec.js", function () {
205
218
  });
206
219
  expect(globalList).toHaveBeenCalledTimes(1);
207
220
  });
208
- it("success (default args)", async function () {
209
- const listInstance = useListInstance({
210
- defaultListArgs: { user: 1 },
211
- defaultRetrieveArgs: { fields: fields },
212
- });
213
- let crudListResolve;
214
- const crudListPromise = new Promise((resolve) => {
215
- crudListResolve = resolve;
216
- });
217
- let passedPageCallback;
218
- globalList.mockImplementation(({ pageCallback }) => {
219
- passedPageCallback = pageCallback;
220
- return crudListPromise;
221
+ it("success (custom stream)", async function () {
222
+ const listArgs = reactive({
223
+ user: 1,
221
224
  });
222
-
223
- expectErrorToBeNull(listInstance.state.error);
224
- expect(listInstance.state.errored).toBe(false);
225
- expect(listInstance.state.loading).toBeUndefined();
226
- expect({ ...listInstance.state.objects }).toEqual({});
227
-
228
- const liListResolve = listInstance.list();
229
-
230
- expectErrorToBeNull(listInstance.state.error);
231
- expect(listInstance.state.errored).toBe(false);
232
- expect(listInstance.state.loading).toBe(true);
233
- expect({ ...listInstance.state.object }).toEqual({});
234
-
235
- await nextTick();
236
-
237
- passedPageCallback(crudListResolvedPage1);
238
-
239
- expectErrorToBeNull(listInstance.state.error);
240
- expect(listInstance.state.errored).toBe(false);
241
- expect(listInstance.state.loading).toBe(true);
242
- expect({ ...listInstance.state.objects }).toEqual(crudListResolvedObjectsMid);
243
-
244
- passedPageCallback(crudListResolvedPage2);
245
-
246
- expectErrorToBeNull(listInstance.state.error);
247
- expect(listInstance.state.errored).toBe(false);
248
- expect(listInstance.state.loading).toBe(true);
249
- expect({ ...listInstance.state.objects }).toEqual(crudListResolvedObjects);
250
-
251
- crudListResolve();
252
- await flushPromises();
253
-
254
- await expect(liListResolve).resolves.toBe(true);
255
-
256
- expectErrorToBeNull(listInstance.state.error);
257
- expect(listInstance.state.errored).toBe(false);
258
- expect(listInstance.state.loading).toBe(false);
259
- expect({ ...listInstance.state.objects }).toEqual(crudListResolvedObjects);
260
- expect(globalList).toHaveBeenCalledWith({
261
- crudArgs: { stream: "test_stream" },
262
- listArgs: { user: 1 },
263
- retrieveArgs: { fields: fields },
264
- pageCallback: passedPageCallback,
225
+ const retrieveArgs = reactive({
226
+ fields,
265
227
  });
266
- expect(globalList).toHaveBeenCalledTimes(1);
267
- });
268
- it("success (custom stream)", async function () {
269
228
  const listInstance = useListInstance({
229
+ listArgs,
230
+ retrieveArgs,
270
231
  crudArgs: { stream: "custom_stream" },
271
232
  });
272
233
  let crudListResolve;
@@ -284,10 +245,7 @@ describe("use/listInstance.spec.js", function () {
284
245
  expect(listInstance.state.loading).toBeUndefined();
285
246
  expect({ ...listInstance.state.objects }).toEqual({});
286
247
 
287
- const liListResolve = listInstance.list({
288
- listArgs: { user: 1 },
289
- retrieveArgs: { fields: fields },
290
- });
248
+ const liListResolve = listInstance.list();
291
249
 
292
250
  expectErrorToBeNull(listInstance.state.error);
293
251
  expect(listInstance.state.errored).toBe(false);
@@ -390,8 +348,8 @@ describe("use/listInstance.spec.js", function () {
390
348
  });
391
349
  it("succeeds", async function () {
392
350
  const listInstance = useListInstance({
393
- defaultListArgs: { user: 1 },
394
- defaultRetrieveArgs: { fields: fields },
351
+ listArgs: { user: 1 },
352
+ retrieveArgs: { fields: fields },
395
353
  });
396
354
  let crudListResolve;
397
355
  const crudListPromise = new Promise((resolve) => {
@@ -445,8 +403,8 @@ describe("use/listInstance.spec.js", function () {
445
403
  name: "yiuo",
446
404
  };
447
405
  const listInstance = useListInstance({
448
- defaultListArgs: { user: 1 },
449
- defaultRetrieveArgs: { fields: fields },
406
+ listArgs: { user: 1 },
407
+ retrieveArgs: { fields: fields },
450
408
  });
451
409
  let crudListResolve;
452
410
  const crudListPromise = new Promise((resolve) => {
@@ -45,7 +45,7 @@ describe("use/useListSort", () => {
45
45
  { key: "lexical_name", desc: false, localeCompare: true },
46
46
  ];
47
47
  listInstance = useListInstance({
48
- defaultRetrieveArgs: {
48
+ retrieveArgs: {
49
49
  fields: ["id", "lexical_name", "organization", "relatedObjects"],
50
50
  },
51
51
  });