@livequery/client 1.0.53 → 1.0.80
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
CHANGED
|
@@ -28,7 +28,9 @@ export declare class CollectionObservable<T extends LivequeryBaseEntity = Livequ
|
|
|
28
28
|
private ref;
|
|
29
29
|
private collection_options;
|
|
30
30
|
readonly $changes: Subject<UpdatedData<T>>;
|
|
31
|
-
|
|
31
|
+
value: CollectionStream<T>;
|
|
32
|
+
$: Subject<CollectionStream<T>>;
|
|
33
|
+
constructor(ref: string | false | null | '' | undefined, collection_options: CollectionOption<T>);
|
|
32
34
|
set_realtime(realtime: boolean): void;
|
|
33
35
|
private sync;
|
|
34
36
|
private fetch_data;
|
|
@@ -43,6 +45,6 @@ export declare class CollectionObservable<T extends LivequeryBaseEntity = Livequ
|
|
|
43
45
|
}>;
|
|
44
46
|
update({ id: update_payload_id, ...payload }: Partial<T>): Promise<any>;
|
|
45
47
|
remove(remove_document_id?: string): Promise<void>;
|
|
46
|
-
trigger<T>(name: string, payload?: object, trigger_document_id?: string): Promise<T>;
|
|
48
|
+
trigger<T>(name: string, payload?: object, trigger_document_id?: string): Promise<T | undefined>;
|
|
47
49
|
}
|
|
48
50
|
export {};
|
package/build/Collection.js
CHANGED
|
@@ -1,30 +1,35 @@
|
|
|
1
1
|
import { Subject, Observable, merge } from 'rxjs';
|
|
2
|
-
import { get_sort_function } from './helpers/get_sort_function.js';
|
|
3
2
|
import { bufferTime, filter, map } from 'rxjs/operators';
|
|
4
3
|
export class CollectionObservable extends Observable {
|
|
5
4
|
ref;
|
|
6
5
|
collection_options;
|
|
7
6
|
$changes = new Subject();
|
|
8
|
-
|
|
9
|
-
#subscriptions = new Set();
|
|
10
|
-
#state;
|
|
7
|
+
#queries = new Set();
|
|
11
8
|
#next_cursor = {};
|
|
12
9
|
#IdMap = new Map();
|
|
13
10
|
#refs = [];
|
|
11
|
+
value = {
|
|
12
|
+
has_more: false,
|
|
13
|
+
items: [],
|
|
14
|
+
options: {},
|
|
15
|
+
loading: false
|
|
16
|
+
};
|
|
17
|
+
$ = new Subject();
|
|
14
18
|
constructor(ref, collection_options) {
|
|
15
19
|
super(o => {
|
|
16
|
-
|
|
17
|
-
const subscription = this.#$state.subscribe(o);
|
|
20
|
+
const subscription = this.$.subscribe(o);
|
|
18
21
|
const auto_reload_interval = collection_options.reload_interval && setInterval(() => this.reload(), collection_options.reload_interval);
|
|
19
22
|
return () => {
|
|
20
|
-
this.#subscriptions.forEach(s => s.unsubscribe());
|
|
21
23
|
subscription.unsubscribe();
|
|
24
|
+
this.#queries.forEach(s => s.unsubscribe());
|
|
22
25
|
clearInterval(auto_reload_interval);
|
|
23
26
|
};
|
|
24
27
|
});
|
|
25
28
|
this.ref = ref;
|
|
26
29
|
this.collection_options = collection_options;
|
|
27
|
-
if (
|
|
30
|
+
if (collection_options.filters)
|
|
31
|
+
this.value.options = collection_options.filters;
|
|
32
|
+
if (ref && (ref.startsWith('/') || ref.endsWith('/')))
|
|
28
33
|
throw 'INVAILD_REF_FORMAT';
|
|
29
34
|
this.#refs = this.#ref_parser(ref);
|
|
30
35
|
}
|
|
@@ -50,13 +55,13 @@ export class CollectionObservable extends Observable {
|
|
|
50
55
|
for (const { data, error, ref } of stream) {
|
|
51
56
|
// Error & paging
|
|
52
57
|
if (error) {
|
|
53
|
-
this
|
|
58
|
+
this.value.error = error;
|
|
54
59
|
actions.update = true;
|
|
55
60
|
}
|
|
56
61
|
if (data?.paging?.n == 0) {
|
|
57
62
|
this.#next_cursor[ref] = data?.paging?.next_cursor;
|
|
58
|
-
this
|
|
59
|
-
this
|
|
63
|
+
this.value.has_more = Object.values(this.#next_cursor).some(v => v && v != '#');
|
|
64
|
+
this.value.loading = false;
|
|
60
65
|
actions.update = true;
|
|
61
66
|
}
|
|
62
67
|
// Sync
|
|
@@ -73,40 +78,34 @@ export class CollectionObservable extends Observable {
|
|
|
73
78
|
|| (
|
|
74
79
|
// Is realtime update that match filters
|
|
75
80
|
(realtime || from_local) && Object
|
|
76
|
-
.keys(this
|
|
81
|
+
.keys(this.value.options || {})
|
|
77
82
|
.filter(key => !key.includes('_'))
|
|
78
83
|
.every(key => {
|
|
79
84
|
try {
|
|
80
85
|
const [field, expression] = key.split(':');
|
|
81
86
|
const a = payload[field];
|
|
82
|
-
const b = this
|
|
87
|
+
const b = this.value.options?.[field];
|
|
83
88
|
if (!expression)
|
|
84
89
|
return a == b;
|
|
85
90
|
if (expression == 'ne')
|
|
86
91
|
return a != b;
|
|
87
92
|
if (expression == 'lt')
|
|
88
|
-
return a < b;
|
|
93
|
+
return typeof a == 'number' && typeof b == 'number' && a < b;
|
|
89
94
|
if (expression == 'lte')
|
|
90
|
-
return a <= b;
|
|
95
|
+
return typeof a == 'number' && typeof b == 'number' && a <= b;
|
|
91
96
|
if (expression == 'gt')
|
|
92
|
-
return a > b;
|
|
97
|
+
return typeof a == 'number' && typeof b == 'number' && a > b;
|
|
93
98
|
if (expression == 'gte')
|
|
94
|
-
return a >= b;
|
|
95
|
-
if (expression == 'in
|
|
96
|
-
return a?.includes(b);
|
|
97
|
-
if (expression == 'contains')
|
|
98
|
-
return a?.some(e => b?.includes(e));
|
|
99
|
-
if (expression == 'not-contains')
|
|
100
|
-
return a?.every(e => !b?.includes(e));
|
|
99
|
+
return typeof a == 'number' && typeof b == 'number' && a >= b;
|
|
100
|
+
if (expression == 'in' || expression == 'like')
|
|
101
|
+
return Array.isArray(a) && a?.includes(b);
|
|
101
102
|
if (expression == 'between')
|
|
102
103
|
return (b[0] <= a && a <= b[1]);
|
|
103
|
-
if (expression == 'like')
|
|
104
|
-
return a.includes(b);
|
|
105
104
|
}
|
|
106
105
|
catch (e) { }
|
|
107
106
|
return false;
|
|
108
107
|
}))) {
|
|
109
|
-
this
|
|
108
|
+
this.value.items.push({
|
|
110
109
|
...payload,
|
|
111
110
|
__adding: false,
|
|
112
111
|
__updating: false,
|
|
@@ -126,8 +125,8 @@ export class CollectionObservable extends Observable {
|
|
|
126
125
|
if (Object.keys(payload).some(key => ['created_at', this.collection_options?.filters?._order_by].includes(key))) {
|
|
127
126
|
actions.reindex = true;
|
|
128
127
|
}
|
|
129
|
-
this
|
|
130
|
-
...this
|
|
128
|
+
this.value.items[index] = {
|
|
129
|
+
...this.value.items[index],
|
|
131
130
|
__adding: false,
|
|
132
131
|
__updating: false,
|
|
133
132
|
__removing: false,
|
|
@@ -137,7 +136,7 @@ export class CollectionObservable extends Observable {
|
|
|
137
136
|
if (type == 'removed') {
|
|
138
137
|
actions.reindex = true;
|
|
139
138
|
actions.update = true;
|
|
140
|
-
this
|
|
139
|
+
this.value.items.splice(index, 1);
|
|
141
140
|
for (const [document_id, i] of this.#IdMap) {
|
|
142
141
|
i == index && this.#IdMap.delete(document_id);
|
|
143
142
|
i > index && this.#IdMap.set(document_id, i - 1);
|
|
@@ -147,33 +146,44 @@ export class CollectionObservable extends Observable {
|
|
|
147
146
|
}
|
|
148
147
|
}
|
|
149
148
|
if (actions.reindex) {
|
|
150
|
-
|
|
149
|
+
const _sort = this.collection_options?.filters?._sort || 'desc';
|
|
150
|
+
const _order_by = this.collection_options?.filters?._order_by || 'created_at';
|
|
151
|
+
this.value.items = this.value.items.sort((a, b) => {
|
|
152
|
+
const ka = a[_order_by];
|
|
153
|
+
const kb = b[_order_by];
|
|
154
|
+
if (typeof ka == 'string' && typeof kb == 'string')
|
|
155
|
+
return ka.localeCompare(ka) * (_sort == 'desc' ? -1 : 1);
|
|
156
|
+
if ((typeof ka == 'number' || typeof ka == 'number')
|
|
157
|
+
&& (typeof kb == 'number' || typeof kb == 'number'))
|
|
158
|
+
return (ka - kb) * (_sort == 'desc' ? -1 : 1);
|
|
159
|
+
return 1;
|
|
160
|
+
});
|
|
151
161
|
this.#IdMap.clear();
|
|
152
|
-
this
|
|
162
|
+
this.value.items.map((item, index) => this.#IdMap.set(item.id, index));
|
|
153
163
|
}
|
|
154
|
-
actions.update && this
|
|
164
|
+
actions.update && this.$.next(this.value);
|
|
155
165
|
}
|
|
156
166
|
fetch_data(options = {}, flush = false) {
|
|
157
167
|
if (this.#refs.length == 0)
|
|
158
168
|
return;
|
|
159
169
|
if (flush) {
|
|
160
170
|
this.#next_cursor = {};
|
|
161
|
-
this.#
|
|
162
|
-
this.#
|
|
171
|
+
this.#queries.forEach(s => s.unsubscribe());
|
|
172
|
+
this.#queries.clear();
|
|
163
173
|
this.#IdMap.clear();
|
|
164
174
|
}
|
|
165
175
|
const has_more_data_refs = this.#refs.filter(ref => this.#next_cursor[ref] === undefined || (this.#next_cursor[ref] && this.#next_cursor[ref] != '#'));
|
|
166
176
|
// Load more but no more data || loading
|
|
167
|
-
if (!flush && (has_more_data_refs.length == 0 || this
|
|
177
|
+
if (!flush && (has_more_data_refs.length == 0 || this.value.loading))
|
|
168
178
|
return;
|
|
169
|
-
this
|
|
170
|
-
...this
|
|
171
|
-
items: flush ? [] : this
|
|
172
|
-
error:
|
|
179
|
+
this.value = {
|
|
180
|
+
...this.value,
|
|
181
|
+
items: flush ? [] : this.value.items,
|
|
182
|
+
error: undefined,
|
|
173
183
|
loading: true,
|
|
174
184
|
options
|
|
175
185
|
};
|
|
176
|
-
this
|
|
186
|
+
this.$.next(this.value);
|
|
177
187
|
const queries = has_more_data_refs.map(ref => (this
|
|
178
188
|
.collection_options
|
|
179
189
|
.transporter
|
|
@@ -181,36 +191,41 @@ export class CollectionObservable extends Observable {
|
|
|
181
191
|
const reload = () => queries.map(q => q.reload());
|
|
182
192
|
const $ = merge(...queries.map((q, index) => q.pipe(map(data => ({ ...data, ref: has_more_data_refs[index] }))))).pipe(bufferTime(500), filter(list => list.length > 0), map(data => this.sync(data)));
|
|
183
193
|
const subscription = Object.assign($.subscribe(), { reload });
|
|
184
|
-
this.#
|
|
194
|
+
this.#queries.add(subscription);
|
|
185
195
|
}
|
|
186
196
|
reload() {
|
|
187
|
-
this.#
|
|
197
|
+
this.#queries.forEach(s => s.reload());
|
|
188
198
|
}
|
|
189
199
|
reset() {
|
|
190
200
|
this.fetch_data({}, true);
|
|
191
201
|
}
|
|
192
202
|
fetch_more() {
|
|
193
|
-
this.fetch_data(this
|
|
203
|
+
this.fetch_data(this.value?.options);
|
|
194
204
|
}
|
|
195
205
|
filter(filters) {
|
|
196
206
|
this.fetch_data(filters, true);
|
|
197
207
|
}
|
|
198
208
|
#find_ref_by_id(id) {
|
|
199
|
-
if (!id)
|
|
209
|
+
if (!id || !this.ref)
|
|
200
210
|
return { ref: this.ref, collection_ref: this.ref };
|
|
201
|
-
const
|
|
211
|
+
const index = this.#IdMap.get(id);
|
|
212
|
+
if (index == undefined)
|
|
213
|
+
return {};
|
|
214
|
+
const origin_ref = this.value.items[index].__ref;
|
|
202
215
|
if (!origin_ref)
|
|
203
216
|
throw 'COLLECTION_REF_NOT_FOUND';
|
|
204
217
|
const refs = origin_ref.split('/');
|
|
205
218
|
const collection_ref = refs.slice(0, refs.length - (refs.length % 2 == 1 ? 0 : 1)).join('/');
|
|
206
219
|
const ref = `${collection_ref}/${id}`;
|
|
207
|
-
return { ref, id, collection_ref };
|
|
220
|
+
return { ref, id, collection_ref, index };
|
|
208
221
|
}
|
|
209
222
|
async add(payload) {
|
|
210
223
|
return await this.collection_options.transporter.add(`${this.ref}`, payload);
|
|
211
224
|
}
|
|
212
225
|
async update({ id: update_payload_id, ...payload }) {
|
|
213
226
|
const { id, ref } = this.#find_ref_by_id(update_payload_id);
|
|
227
|
+
if (!ref)
|
|
228
|
+
return;
|
|
214
229
|
// Trigger local update
|
|
215
230
|
this.sync([{
|
|
216
231
|
ref,
|
|
@@ -241,6 +256,8 @@ export class CollectionObservable extends Observable {
|
|
|
241
256
|
}
|
|
242
257
|
async remove(remove_document_id) {
|
|
243
258
|
const { id, ref } = this.#find_ref_by_id(remove_document_id);
|
|
259
|
+
if (!ref)
|
|
260
|
+
return;
|
|
244
261
|
this.sync([{
|
|
245
262
|
ref,
|
|
246
263
|
data: {
|
|
@@ -271,6 +288,8 @@ export class CollectionObservable extends Observable {
|
|
|
271
288
|
}
|
|
272
289
|
async trigger(name, payload, trigger_document_id) {
|
|
273
290
|
const { ref } = this.#find_ref_by_id(trigger_document_id);
|
|
291
|
+
if (!ref)
|
|
292
|
+
return;
|
|
274
293
|
return await this.collection_options.transporter.trigger(ref, name, {}, payload);
|
|
275
294
|
}
|
|
276
295
|
}
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function get_sort_function(data: any, key: string, order?: 'asc' | 'desc'): (a: any, b: any) => number;
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
export function get_sort_function(data, key, order = 'desc') {
|
|
2
|
-
const type = typeof data?.[key];
|
|
3
|
-
if (type == 'bigint' || type == 'number') {
|
|
4
|
-
if (order == 'asc')
|
|
5
|
-
return (a, b) => a[key] - b[key] || ((a.created_at || 1) - (b.created_at || 0));
|
|
6
|
-
if (order == 'desc')
|
|
7
|
-
return (a, b) => b[key] - a[key] || ((a.created_at || 1) - (b.created_at || 0));
|
|
8
|
-
}
|
|
9
|
-
if (type == 'string') {
|
|
10
|
-
if (order == 'asc')
|
|
11
|
-
return (a, b) => a[key].localeCompare(b[key]) || ((a.created_at || 1) - (b.created_at || 0));
|
|
12
|
-
if (order == 'desc')
|
|
13
|
-
return (a, b) => b[key].localeCompare(a[key]) || ((a.created_at || 1) - (b.created_at || 0));
|
|
14
|
-
}
|
|
15
|
-
return () => 1;
|
|
16
|
-
}
|