@livequery/client 2.0.22 → 2.0.24
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/build/Collection.d.ts +1 -0
- package/build/Collection.js +63 -71
- package/package.json +1 -1
package/build/Collection.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ export type SmartQueryItem<T> = T & {
|
|
|
15
15
|
__adding: boolean;
|
|
16
16
|
__trigger: <R extends {}>(name: string, payload?: any, query?: any) => Promise<Response<R>>;
|
|
17
17
|
__ref: string;
|
|
18
|
+
toJson: () => T;
|
|
18
19
|
};
|
|
19
20
|
export type CollectionStream<T extends LivequeryBaseEntity = LivequeryBaseEntity> = {
|
|
20
21
|
items: SmartQueryItem<T>[];
|
package/build/Collection.js
CHANGED
|
@@ -42,25 +42,23 @@ export class CollectionObservable extends BehaviorSubject {
|
|
|
42
42
|
set_realtime(realtime) {
|
|
43
43
|
this.collection_options.realtime = realtime;
|
|
44
44
|
}
|
|
45
|
-
#sync(stream,
|
|
45
|
+
#sync(stream, from, direction) {
|
|
46
|
+
if (from == 'realtime' && this.collection_options.realtime == false)
|
|
47
|
+
return;
|
|
46
48
|
const state = this.getValue();
|
|
47
|
-
const
|
|
48
|
-
const actions = { update: false, reindex: false };
|
|
49
|
+
const actions = { reindex: false };
|
|
49
50
|
for (const { data, error, code, message, } of stream) {
|
|
50
|
-
if (
|
|
51
|
+
if (from == 'request') {
|
|
51
52
|
state.loading = false;
|
|
52
|
-
actions.update = true;
|
|
53
53
|
}
|
|
54
54
|
// Error & paging
|
|
55
55
|
if (error) {
|
|
56
56
|
state.error = true;
|
|
57
57
|
state.code = code;
|
|
58
58
|
state.message = message;
|
|
59
|
-
actions.update = true;
|
|
60
59
|
}
|
|
61
60
|
if (data?.summary) {
|
|
62
61
|
state.summary = data.summary;
|
|
63
|
-
actions.update = true;
|
|
64
62
|
}
|
|
65
63
|
// Sync
|
|
66
64
|
for (const change of data?.changes || []) {
|
|
@@ -72,35 +70,32 @@ export class CollectionObservable extends BehaviorSubject {
|
|
|
72
70
|
if (index == -1 && type == 'added') {
|
|
73
71
|
if (
|
|
74
72
|
// Is first value from HTTP query
|
|
75
|
-
|
|
73
|
+
from == 'request'
|
|
76
74
|
|| (
|
|
77
75
|
// Is realtime update that match filters
|
|
78
|
-
|
|
76
|
+
from == 'realtime' && Object
|
|
79
77
|
.keys(state.options || {})
|
|
80
78
|
.filter(key => !key.includes('_'))
|
|
81
79
|
.every(key => {
|
|
80
|
+
const [field, expression] = key.split(':');
|
|
81
|
+
const a = payload[field];
|
|
82
|
+
const b = state.options?.[field];
|
|
83
|
+
const map = {
|
|
84
|
+
'default': () => a == b,
|
|
85
|
+
eq: () => a == b,
|
|
86
|
+
ne: () => a != b,
|
|
87
|
+
lt: () => typeof a == 'number' && typeof b == 'number' && a < b,
|
|
88
|
+
lte: () => typeof a == 'number' && typeof b == 'number' && a <= b,
|
|
89
|
+
gt: () => typeof a == 'number' && typeof b == 'number' && a > b,
|
|
90
|
+
gte: () => typeof a == 'number' && typeof b == 'number' && a >= b,
|
|
91
|
+
in: () => Array.isArray(a) && a?.includes(b),
|
|
92
|
+
like: () => typeof a == 'string' && a.includes(`${b}`),
|
|
93
|
+
between: () => typeof a == 'number' && Array.isArray(b) && typeof b[0] == 'number' && b[0] <= a && typeof b[1] == 'number' && a <= b[1]
|
|
94
|
+
};
|
|
82
95
|
try {
|
|
83
|
-
const [
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
if (!expression)
|
|
87
|
-
return a == b;
|
|
88
|
-
if (expression == 'ne')
|
|
89
|
-
return a != b;
|
|
90
|
-
if (expression == 'lt')
|
|
91
|
-
return typeof a == 'number' && typeof b == 'number' && a < b;
|
|
92
|
-
if (expression == 'lte')
|
|
93
|
-
return typeof a == 'number' && typeof b == 'number' && a <= b;
|
|
94
|
-
if (expression == 'gt')
|
|
95
|
-
return typeof a == 'number' && typeof b == 'number' && a > b;
|
|
96
|
-
if (expression == 'gte')
|
|
97
|
-
return typeof a == 'number' && typeof b == 'number' && a >= b;
|
|
98
|
-
if (expression == 'in' || expression == 'like')
|
|
99
|
-
return Array.isArray(a) && a?.includes(b);
|
|
100
|
-
if (expression == 'between') {
|
|
101
|
-
const [x, y] = b;
|
|
102
|
-
return x <= a && a <= y;
|
|
103
|
-
}
|
|
96
|
+
const fn = map[expression || 'default'];
|
|
97
|
+
if (fn)
|
|
98
|
+
return fn();
|
|
104
99
|
}
|
|
105
100
|
catch (e) { }
|
|
106
101
|
return false;
|
|
@@ -114,16 +109,15 @@ export class CollectionObservable extends BehaviorSubject {
|
|
|
114
109
|
__remove: () => this.remove(payload?.id),
|
|
115
110
|
__trigger: (name, input = undefined, query) => this.trigger(name, input, payload?.id, query),
|
|
116
111
|
__update: (input) => this.update({ ...input, id: payload?.id }),
|
|
117
|
-
__ref: change.ref
|
|
112
|
+
__ref: change.ref,
|
|
113
|
+
toJson: () => payload
|
|
118
114
|
};
|
|
119
115
|
direction == 'forward' ? state.items.push(item) : state.items.unshift(item);
|
|
120
116
|
actions.reindex = true;
|
|
121
|
-
actions.update = true;
|
|
122
117
|
}
|
|
123
118
|
}
|
|
124
|
-
if (index >= 0
|
|
119
|
+
if (index >= 0) {
|
|
125
120
|
if (type == 'added' || type == 'modified') {
|
|
126
|
-
actions.update = true;
|
|
127
121
|
const sort_key_value_updated = this.#sorters.some(({ key }) => {
|
|
128
122
|
const value = payload[key];
|
|
129
123
|
if (typeof value == 'string' || typeof value == 'number')
|
|
@@ -141,7 +135,6 @@ export class CollectionObservable extends BehaviorSubject {
|
|
|
141
135
|
};
|
|
142
136
|
}
|
|
143
137
|
if (type == 'removed') {
|
|
144
|
-
actions.update = true;
|
|
145
138
|
state.items.splice(index, 1);
|
|
146
139
|
for (const [document_id, i] of this.#IdMap) {
|
|
147
140
|
i == index && this.#IdMap.delete(document_id);
|
|
@@ -205,23 +198,30 @@ export class CollectionObservable extends BehaviorSubject {
|
|
|
205
198
|
}
|
|
206
199
|
};
|
|
207
200
|
}
|
|
208
|
-
|
|
201
|
+
this.next(state);
|
|
209
202
|
}
|
|
210
203
|
fetch_data(options = {}, loading, flush = false) {
|
|
204
|
+
if (flush) {
|
|
205
|
+
this.#pages.clear();
|
|
206
|
+
this.#queries.forEach(s => s.unsubscribe());
|
|
207
|
+
this.#queries.clear();
|
|
208
|
+
this.#IdMap.clear();
|
|
209
|
+
}
|
|
211
210
|
if (!this.ref)
|
|
212
211
|
return;
|
|
213
212
|
if (this.#refs.length == 0)
|
|
214
213
|
return;
|
|
215
|
-
if (this.getValue().loading)
|
|
214
|
+
if (this.getValue().loading && !flush)
|
|
216
215
|
return;
|
|
217
|
-
this.
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
return
|
|
216
|
+
const remain_data_refs = this.#refs.filter(ref => {
|
|
217
|
+
const paging = this.#pages.get(ref);
|
|
218
|
+
if (!paging)
|
|
219
|
+
return true;
|
|
220
|
+
return loading == 'forward' ? paging.has?.next : paging.has?.prev;
|
|
222
221
|
});
|
|
223
|
-
|
|
224
|
-
|
|
222
|
+
if (remain_data_refs.length == 0)
|
|
223
|
+
return;
|
|
224
|
+
this.next({
|
|
225
225
|
...this.getValue(),
|
|
226
226
|
items: flush ? [] : this.getValue().items,
|
|
227
227
|
loading,
|
|
@@ -229,23 +229,14 @@ export class CollectionObservable extends BehaviorSubject {
|
|
|
229
229
|
...this.getValue().options || {},
|
|
230
230
|
...options
|
|
231
231
|
}
|
|
232
|
-
};
|
|
233
|
-
if (flush) {
|
|
234
|
-
this.#pages.clear();
|
|
235
|
-
this.#queries.forEach(s => s.unsubscribe());
|
|
236
|
-
this.#queries.clear();
|
|
237
|
-
this.#IdMap.clear();
|
|
238
|
-
}
|
|
239
|
-
const remain_data_refs = this.#refs.filter(ref => {
|
|
240
|
-
const paging = this.#pages.get(ref);
|
|
241
|
-
if (!paging)
|
|
242
|
-
return true;
|
|
243
|
-
return loading == 'forward' ? paging.has?.next : paging.has?.prev;
|
|
244
232
|
});
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
233
|
+
this.collection_options.options = options;
|
|
234
|
+
this.#sorters = Object.keys(options).filter(k => k.endsWith(':sort')).map(k => {
|
|
235
|
+
const key = k.split(':sort')[0];
|
|
236
|
+
const order = options[k] == 1 ? 1 : -1;
|
|
237
|
+
return { key, order };
|
|
238
|
+
});
|
|
239
|
+
this.#sorters.every(a => a.key != 'id') && this.#sorters.push({ key: 'id', order: -1 });
|
|
249
240
|
const queries = remain_data_refs.map((ref, index) => {
|
|
250
241
|
const cursor = this.#pages.get(ref)?.cursor;
|
|
251
242
|
const opts = {
|
|
@@ -261,8 +252,8 @@ export class CollectionObservable extends BehaviorSubject {
|
|
|
261
252
|
ref
|
|
262
253
|
})), share());
|
|
263
254
|
});
|
|
264
|
-
const first_values = merge(...queries.map(q => q.pipe(filter(r => !!r.data?.paging || !!r.error), first()))).pipe(toArray(), tap(list => this.#sync(list,
|
|
265
|
-
const subscription = merge(...queries.map(q => q.pipe(skip(1)))).pipe(bufferTime(this.collection_options?.sync_delay || 500), filter(list => list.length > 0), map(data => this.#sync(data,
|
|
255
|
+
const first_values = merge(...queries.map(q => q.pipe(filter(r => !!r.data?.paging || !!r.error), first()))).pipe(toArray(), tap(list => this.#sync(list, 'request', loading))).subscribe();
|
|
256
|
+
const subscription = merge(...queries.map(q => q.pipe(skip(1)))).pipe(bufferTime(this.collection_options?.sync_delay || 500), filter(list => list.length > 0), map(data => this.#sync(data, 'realtime', loading)), finalize(() => first_values.unsubscribe())).subscribe();
|
|
266
257
|
this.#queries.add(subscription);
|
|
267
258
|
}
|
|
268
259
|
reset() {
|
|
@@ -281,17 +272,18 @@ export class CollectionObservable extends BehaviorSubject {
|
|
|
281
272
|
}
|
|
282
273
|
#find_ref_by_id(id) {
|
|
283
274
|
if (!id || !this.ref)
|
|
284
|
-
return { ref: this.ref, collection_ref: this.ref };
|
|
275
|
+
return { ref: this.ref, collection_ref: this.ref, doc: null };
|
|
285
276
|
const index = this.#IdMap.get(id);
|
|
286
277
|
if (index == undefined)
|
|
287
278
|
return {};
|
|
288
|
-
const
|
|
279
|
+
const doc = this.getValue().items[index];
|
|
280
|
+
const origin_ref = doc.__ref;
|
|
289
281
|
if (!origin_ref)
|
|
290
282
|
throw 'COLLECTION_REF_NOT_FOUND';
|
|
291
283
|
const refs = origin_ref.split('/');
|
|
292
284
|
const collection_ref = refs.slice(0, refs.length - (refs.length % 2 == 1 ? 0 : 1)).join('/');
|
|
293
285
|
const ref = `${collection_ref}/${id}`;
|
|
294
|
-
return { ref, id, collection_ref, index };
|
|
286
|
+
return { ref, id, collection_ref, index, doc };
|
|
295
287
|
}
|
|
296
288
|
async add(payload) {
|
|
297
289
|
const r = await this.collection_options.transporter.add(`${this.ref}`, payload);
|
|
@@ -301,7 +293,7 @@ export class CollectionObservable extends BehaviorSubject {
|
|
|
301
293
|
return r;
|
|
302
294
|
}
|
|
303
295
|
async update({ id: update_payload_id, ...payload }) {
|
|
304
|
-
const { id, ref } = this.#find_ref_by_id(update_payload_id);
|
|
296
|
+
const { id, ref, doc } = this.#find_ref_by_id(update_payload_id);
|
|
305
297
|
if (!ref)
|
|
306
298
|
return;
|
|
307
299
|
// Trigger local update
|
|
@@ -314,7 +306,7 @@ export class CollectionObservable extends BehaviorSubject {
|
|
|
314
306
|
type: 'modified'
|
|
315
307
|
}]
|
|
316
308
|
}
|
|
317
|
-
}],
|
|
309
|
+
}], 'local');
|
|
318
310
|
try {
|
|
319
311
|
return await this.collection_options.transporter.update(ref, payload);
|
|
320
312
|
}
|
|
@@ -323,12 +315,12 @@ export class CollectionObservable extends BehaviorSubject {
|
|
|
323
315
|
ref,
|
|
324
316
|
data: {
|
|
325
317
|
changes: [{
|
|
326
|
-
data: { id, __updating: false },
|
|
318
|
+
data: { ...doc || {}, id, __updating: false },
|
|
327
319
|
ref,
|
|
328
320
|
type: 'modified'
|
|
329
321
|
}]
|
|
330
322
|
}
|
|
331
|
-
}],
|
|
323
|
+
}], 'local');
|
|
332
324
|
throw e;
|
|
333
325
|
}
|
|
334
326
|
}
|
|
@@ -345,7 +337,7 @@ export class CollectionObservable extends BehaviorSubject {
|
|
|
345
337
|
type: 'modified'
|
|
346
338
|
}]
|
|
347
339
|
}
|
|
348
|
-
}],
|
|
340
|
+
}], 'local');
|
|
349
341
|
// Trigger
|
|
350
342
|
try {
|
|
351
343
|
return await this.collection_options.transporter.remove(ref);
|
|
@@ -360,7 +352,7 @@ export class CollectionObservable extends BehaviorSubject {
|
|
|
360
352
|
type: 'modified'
|
|
361
353
|
}]
|
|
362
354
|
}
|
|
363
|
-
}],
|
|
355
|
+
}], 'local');
|
|
364
356
|
throw e;
|
|
365
357
|
}
|
|
366
358
|
}
|