@ngutil/data 0.0.17 → 0.0.19

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.
Files changed (41) hide show
  1. package/esm2022/provider/local.mjs +1 -1
  2. package/esm2022/provider/provider.mjs +1 -1
  3. package/esm2022/query/common.mjs +33 -0
  4. package/esm2022/query/executor.mjs +1 -1
  5. package/esm2022/query/filter.mjs +82 -109
  6. package/esm2022/query/grouper.mjs +19 -1
  7. package/esm2022/query/index.mjs +4 -3
  8. package/esm2022/query/query-property.mjs +56 -0
  9. package/esm2022/query/query.mjs +19 -2
  10. package/esm2022/query/slimer.mjs +18 -1
  11. package/esm2022/query/sorter.mjs +70 -36
  12. package/esm2022/source/proxy.directive.mjs +21 -24
  13. package/esm2022/source/source.mjs +24 -25
  14. package/fesm2022/ngutil-data.mjs +323 -304
  15. package/fesm2022/ngutil-data.mjs.map +1 -1
  16. package/package.json +10 -10
  17. package/provider/local.d.ts +5 -5
  18. package/provider/provider.d.ts +4 -4
  19. package/query/common.d.ts +2 -0
  20. package/query/executor.d.ts +2 -2
  21. package/query/filter.d.ts +32 -0
  22. package/query/grouper.d.ts +11 -0
  23. package/query/index.d.ts +3 -3
  24. package/query/query-property.d.ts +21 -0
  25. package/query/query.d.ts +16 -5
  26. package/query/slimer.d.ts +12 -2
  27. package/query/sorter.d.ts +16 -3
  28. package/source/proxy.directive.d.ts +6 -6
  29. package/source/source.d.ts +7 -14
  30. package/esm2022/source/properties/abstract.mjs +0 -33
  31. package/esm2022/source/properties/filter.mjs +0 -16
  32. package/esm2022/source/properties/grouper.mjs +0 -16
  33. package/esm2022/source/properties/index.mjs +0 -5
  34. package/esm2022/source/properties/slimer.mjs +0 -16
  35. package/esm2022/source/properties/sorter.mjs +0 -43
  36. package/source/properties/abstract.d.ts +0 -17
  37. package/source/properties/filter.d.ts +0 -11
  38. package/source/properties/grouper.d.ts +0 -11
  39. package/source/properties/index.d.ts +0 -4
  40. package/source/properties/slimer.d.ts +0 -11
  41. package/source/properties/sorter.d.ts +0 -20
@@ -1,7 +1,7 @@
1
- import { flattenDepth, intersection, flattenDeep, isEqual } from 'lodash';
1
+ import { flattenDepth, isEqual, intersection, flattenDeep } from 'lodash';
2
2
  import * as i1 from '@ngutil/common';
3
- import { isPlainObject, deepClone, toSorted, deepFreeze } from '@ngutil/common';
4
- import { BehaviorSubject, map, combineLatest, take, of, shareReplay, ReplaySubject, switchMap, distinctUntilChanged, tap, debounceTime, finalize, Subject, Observable, takeUntil, share, Subscription, throwError } from 'rxjs';
3
+ import { deepClone, deepFreeze, isPlainObject, toSorted } from '@ngutil/common';
4
+ import { BehaviorSubject, Observable, combineLatest, map, shareReplay, take, of, ReplaySubject, switchMap, distinctUntilChanged, tap, debounceTime, finalize, Subject, takeUntil, share, Subscription, throwError } from 'rxjs';
5
5
  import { DataSource as DataSource$1 } from '@angular/cdk/collections';
6
6
  import * as i0 from '@angular/core';
7
7
  import { Directive, Optional, Input } from '@angular/core';
@@ -24,6 +24,91 @@ function makeGetter(part, parent) {
24
24
  }
25
25
  }
26
26
 
27
+ function readonlyProp(o, n, v) {
28
+ Object.defineProperty(o, n, {
29
+ value: v,
30
+ configurable: false,
31
+ enumerable: true,
32
+ writable: false
33
+ });
34
+ }
35
+ const NORMALIZED = Symbol("NORMALIZED");
36
+ const IS_NORMALIZED = Symbol("IS_NORMALIZED");
37
+ function normalize(obj, normalizer) {
38
+ if (obj[IS_NORMALIZED]) {
39
+ return obj;
40
+ }
41
+ if (obj[NORMALIZED] == null) {
42
+ const normalized = normalizer(obj);
43
+ Object.defineProperty(obj, NORMALIZED, {
44
+ value: normalized,
45
+ configurable: false,
46
+ enumerable: false,
47
+ writable: false
48
+ });
49
+ Object.defineProperty(normalize, IS_NORMALIZED, {
50
+ value: true,
51
+ configurable: false,
52
+ enumerable: false,
53
+ writable: false
54
+ });
55
+ return normalized;
56
+ }
57
+ return obj[NORMALIZED];
58
+ }
59
+
60
+ class QueryProperty extends BehaviorSubject {
61
+ set(value) {
62
+ this.#nextClone(value != null ? this.norm(value) : undefined);
63
+ }
64
+ update(value) {
65
+ const norm = value != null ? this.norm(value) : undefined;
66
+ if (!isEqual(this.value, norm)) {
67
+ this.#next(this.merge(this.value, norm));
68
+ }
69
+ }
70
+ del() {
71
+ this.set(undefined);
72
+ }
73
+ #next(value) {
74
+ if (!isEqual(this.value, value)) {
75
+ if (value == null) {
76
+ this.next(undefined);
77
+ }
78
+ else {
79
+ this.next(value);
80
+ }
81
+ }
82
+ }
83
+ #nextClone(value) {
84
+ if (!isEqual(this.value, value)) {
85
+ if (value == null) {
86
+ this.next(undefined);
87
+ }
88
+ else {
89
+ this.next(deepClone(value));
90
+ }
91
+ }
92
+ }
93
+ }
94
+ class QueryPropertySet extends Observable {
95
+ #combined;
96
+ constructor(...names) {
97
+ super(dest => this.#combined.subscribe(dest));
98
+ const observables = [];
99
+ const props = {};
100
+ for (const name of names) {
101
+ const o = this.newProperty();
102
+ observables.push(o);
103
+ props[name] = o;
104
+ }
105
+ this.#combined = combineLatest(observables).pipe(map(values => deepFreeze(this.merge(...values))), shareReplay(1));
106
+ for (const [k, v] of Object.entries(props)) {
107
+ readonlyProp(this, k, v);
108
+ }
109
+ }
110
+ }
111
+
27
112
  const OPERATORS = [
28
113
  "==" /* FilterOp.Eq */,
29
114
  "===" /* FilterOp.EqStrict */,
@@ -70,107 +155,81 @@ function asOperators(value) {
70
155
  function filterBy(filters) {
71
156
  return _filterCompile(filters);
72
157
  }
73
- // TODO: Normalize filter
74
- // type _Filter = { path: string; op: FilterOp; value: any }
75
- // type _Or = { "|": Array<_Filter> }
76
- // type _And = { "&": Array<_Filter> }
77
- // export type NormalizedFilter = _Or | _And
78
- // /**
79
- // * @example
80
- // * ```ts
81
- // * normalizeFilter({id: 2, name: {"=*": "AnyName"}}) -> {id: {"==": 2}, name: {"=*": "AnyName"}}}
82
- // * normalizeFilter({id: {">": 0, "<": 10}}) -> {"&": [{id: {">": 0}}, {id: {"<": 10}}]}
83
- // * ```
84
- // */
85
- // export function normalizeFilter<T extends Model>(filters: Filters<T>): Filters<T> {
86
- // return _normalizeFilter(filters)
87
- // }
88
- // function _normalizeFilter(filters: any, path?: string): any {
89
- // const result = {} as any
90
- // for (const [path, v] of Object.entries(filters)) {
91
- // switch (path) {
92
- // case FilterOp.And:
93
- // if (!Array.isArray(v)) {
94
- // throw new Error("The '&' (AND) operator must have array type")
95
- // }
96
- // if (!result[FilterOp.And]) {
97
- // result[FilterOp.And] = []
98
- // }
99
- // result[FilterOp.And] = result[FilterOp.And].concat(v.map(f => _normalizeFilter(f)))
100
- // break
101
- // case FilterOp.Or:
102
- // if (!Array.isArray(v)) {
103
- // throw new Error("The '|' (OR) operator must have array type")
104
- // }
105
- // if (!result[FilterOp.Or]) {
106
- // result[FilterOp.Or] = []
107
- // }
108
- // result[FilterOp.Or] = result[FilterOp.Or].concat(v.map(f => _normalizeFilter(f)))
109
- // break
110
- // default:
111
- // for (const entry of asOperators(v)) {
112
- // switch (entry.op) {
113
- // case FilterOp.And:
114
- // if (!result[FilterOp.And]) {
115
- // result[FilterOp.And] = []
116
- // }
117
- // result[FilterOp.And] = result[FilterOp.And].concat(
118
- // entry.value.map((v: any) => _normalizeFilter(v, path))
119
- // )
120
- // break
121
- // case FilterOp.Or:
122
- // if (!result[FilterOp.Or]) {
123
- // result[FilterOp.Or] = []
124
- // }
125
- // result[FilterOp.Or] = result[FilterOp.Or].concat(
126
- // entry.value.map((v: any) => _normalizeFilter(v, path))
127
- // )
128
- // break
129
- // default:
130
- // if (!result[FilterOp.And]) {
131
- // result[FilterOp.And] = []
132
- // }
133
- // result[FilterOp.And].push({ path, ...entry })
134
- // }
135
- // }
136
- // }
137
- // }
138
- // return result
139
- // }
140
- function _filterCompile(filters) {
141
- let getter;
142
- const result = [];
143
- for (const [pth, value] of Object.entries(filters)) {
144
- switch (pth) {
158
+ /**
159
+ * @example
160
+ * ```ts
161
+ * filterNormalize({id: {">": 0, "<": 10}})
162
+ * {op: "&", value: [{path: "id", op: ">", value: 0}, {path: "id", op: "<", value: 10}]}
163
+ * ```
164
+ */
165
+ function filterNormalize(filters) {
166
+ return _normalizeFilter(filters);
167
+ }
168
+ function _normalizeFilter(filters, parent) {
169
+ const norm = flattenDeep(Object.entries(filters).map(([path, value]) => {
170
+ switch (path) {
145
171
  case "&" /* FilterOp.And */:
146
172
  if (!Array.isArray(value)) {
147
- throw new Error("Root '&' (AND) operator must have array type");
173
+ throw new Error(`Operator AND (${"&" /* FilterOp.And */}) must have array type`);
148
174
  }
149
- result.splice(result.length, 0, ...value.map((_filterCompile)));
150
- break;
175
+ return { op: "&" /* FilterOp.And */, value: value.map(v => _normalizeFilter(v, parent)) };
151
176
  case "|" /* FilterOp.Or */:
152
177
  if (!Array.isArray(value)) {
153
- throw new Error("Root '|' (OR) operator must have array type");
178
+ throw new Error(`Operator OR (${"|" /* FilterOp.Or */}) must have array type`);
154
179
  }
155
- result.push(or_(value.map((_filterCompile))));
156
- break;
180
+ return { op: "|" /* FilterOp.Or */, value: value.map(v => _normalizeFilter(v, parent)) };
181
+ // TODO: check all filter, and if not found filter key, taht object maybne not a filter
157
182
  default:
158
- getter = pathGetterCompile(pth);
159
183
  if (isPlainObject(value)) {
160
- result.push(and_(Object.entries(value).map(([op, opv]) => filterCompileOp(getter, op, opv))));
184
+ return _normalizeFilter(value, path);
185
+ }
186
+ if (parent != null) {
187
+ return { path: parent, op: path, value };
161
188
  }
162
189
  else {
163
- result.push(filterCompileOp(getter, "==" /* FilterOp.Eq */, value));
190
+ return { path, op: "===" /* FilterOp.EqStrict */, value };
164
191
  }
165
- break;
166
192
  }
193
+ }));
194
+ if (norm.length === 0) {
195
+ return norm;
196
+ }
197
+ else if (norm.length === 1) {
198
+ return norm[0];
199
+ }
200
+ else {
201
+ return { op: "&" /* FilterOp.And */, value: norm };
202
+ }
203
+ }
204
+ function _filterCompile(filters) {
205
+ const pathCache = {};
206
+ const getPath = (pth) => {
207
+ if (pathCache[pth] != null) {
208
+ return pathCache[pth];
209
+ }
210
+ return (pathCache[pth] = pathGetterCompile(pth));
211
+ };
212
+ const normalized = filterNormalize(filters);
213
+ return _filterCompileNorm(normalized, getPath);
214
+ }
215
+ function _filterCompileNorm(filter, getPath) {
216
+ switch (filter.op) {
217
+ case "&" /* FilterOp.And */:
218
+ return and_(filter.value.map(v => _filterCompileNorm(v, getPath)));
219
+ case "|" /* FilterOp.Or */:
220
+ return or_(filter.value.map(v => _filterCompileNorm(v, getPath)));
221
+ default:
222
+ return _filterComplileNormPath(getPath(filter.path), filter.op, filter.value, getPath);
167
223
  }
168
- return and_(result);
169
224
  }
170
- function filterCompileOp(getter, op, value) {
225
+ function _filterComplileNormPath(getter, op, value, getPath) {
171
226
  let lower;
172
227
  let regex;
173
228
  switch (op) {
229
+ case "&" /* FilterOp.And */:
230
+ return and_(value.map(v => _filterCompileNorm(v, getPath)));
231
+ case "|" /* FilterOp.Or */:
232
+ return or_(value.map(v => _filterCompileNorm(v, getPath)));
174
233
  case "==" /* FilterOp.Eq */:
175
234
  // eslint-disable-next-line eqeqeq
176
235
  return matcher(getter, v => v == value);
@@ -231,30 +290,6 @@ function filterCompileOp(getter, op, value) {
231
290
  case "~*" /* FilterOp.RegexpInsesitive */:
232
291
  regex = value instanceof RegExp ? value : new RegExp(value, "msvi");
233
292
  return matcher(getter, v => regex.test(v));
234
- case "&" /* FilterOp.And */:
235
- if (!Array.isArray(value)) {
236
- throw new Error("Root '&' (AND) operator must have array type");
237
- }
238
- return and_(flattenDeep(value.map(v => {
239
- if (isPlainObject(v)) {
240
- return Object.entries(v).map(([op, opv]) => filterCompileOp(getter, op, opv));
241
- }
242
- else {
243
- return filterCompileOp(getter, "==" /* FilterOp.Eq */, v);
244
- }
245
- })));
246
- case "|" /* FilterOp.Or */:
247
- if (!Array.isArray(value)) {
248
- throw new Error("Root '|' (OR) operator must have array type");
249
- }
250
- return or_(flattenDeep(value.map(v => {
251
- if (isPlainObject(v)) {
252
- return Object.entries(v).map(([op, opv]) => filterCompileOp(getter, op, opv));
253
- }
254
- else {
255
- return filterCompileOp(getter, "==" /* FilterOp.Eq */, v);
256
- }
257
- })));
258
293
  }
259
294
  throw new Error(`Unexpected operator: ${op}`);
260
295
  }
@@ -265,6 +300,9 @@ function and_(fns) {
265
300
  if (fns.length === 0) {
266
301
  return _ => true;
267
302
  }
303
+ if (fns.length === 1) {
304
+ return fns[0];
305
+ }
268
306
  return item => {
269
307
  for (const fn of fns) {
270
308
  if (!fn(item)) {
@@ -278,6 +316,9 @@ function or_(fns) {
278
316
  if (fns.length === 0) {
279
317
  return _ => true;
280
318
  }
319
+ if (fns.length === 1) {
320
+ return fns[0];
321
+ }
281
322
  return item => {
282
323
  for (const fn of fns) {
283
324
  if (fn(item)) {
@@ -308,6 +349,22 @@ function filterMerge(...filters) {
308
349
  }
309
350
  return result;
310
351
  }
352
+ class FilterProperty extends QueryProperty {
353
+ merge(a, b) {
354
+ return filterMerge(a, b);
355
+ }
356
+ norm(a) {
357
+ return filterNormalize(a);
358
+ }
359
+ }
360
+ class FilterPropertySet extends QueryPropertySet {
361
+ newProperty() {
362
+ return new FilterProperty(undefined);
363
+ }
364
+ merge(...args) {
365
+ return filterMerge(...args);
366
+ }
367
+ }
311
368
 
312
369
  function groupBy(grouper) {
313
370
  return grouperCompile(grouper);
@@ -318,6 +375,7 @@ function grouperCompile(grouper) {
318
375
  function grouperMerge(...groupers) {
319
376
  return undefined;
320
377
  }
378
+ function grouperNormalize(grouper) { }
321
379
  // import { Primitive } from "utility-types"
322
380
  // import { Eval, Flatten } from "@ngutil/common"
323
381
  // import { type Model } from "./query"
@@ -375,6 +433,22 @@ function grouperMerge(...groupers) {
375
433
  // ): Grouper<T, F> | undefined {
376
434
  // return undefined
377
435
  // }
436
+ class GrouperProperty extends QueryProperty {
437
+ norm(a) {
438
+ return grouperNormalize;
439
+ }
440
+ merge(a, b) {
441
+ return grouperMerge(a, b);
442
+ }
443
+ }
444
+ class GrouperPropertySet extends QueryPropertySet {
445
+ newProperty() {
446
+ return new GrouperProperty(undefined);
447
+ }
448
+ merge(...args) {
449
+ return grouperMerge(...args);
450
+ }
451
+ }
378
452
 
379
453
  /**
380
454
  * @example
@@ -398,22 +472,39 @@ function sortBy(sorters) {
398
472
  * ```
399
473
  */
400
474
  function sorterNormalize(sorters) {
401
- return flattenDeep(sorters.map((s) => Object.entries(s).map(([k, v]) => {
402
- if (typeof v === "string") {
403
- const isAsc = v.toLowerCase() === "asc";
404
- return { path: k, isAsc, emptyFirst: isAsc ? false : true };
405
- }
406
- else if (isPlainObject(v)) {
407
- return {
408
- path: k,
409
- isAsc: (v.dir || "asc").toLowerCase() === "asc",
410
- emptyFirst: v.emptyFirst == null ? true : !!v.emptyFirst
411
- };
412
- }
413
- else {
414
- throw new Error(`Invalid sorter: ${v}`);
475
+ return _sorterNormalize(sorters);
476
+ }
477
+ function _sorterNormalize(sorters) {
478
+ if (!Array.isArray(sorters)) {
479
+ sorters = [sorters];
480
+ }
481
+ return flattenDeep(sorters.map((s) => {
482
+ if (isPlainObject(s)) {
483
+ // entry is normalized
484
+ if (s["path"] != null && s["isAsc"] != null && s["emptyFirst"] != null) {
485
+ return s;
486
+ }
415
487
  }
416
- })));
488
+ return Object.entries(s).map(([k, v]) => {
489
+ if (v == null) {
490
+ return { path: k, remove: true };
491
+ }
492
+ else if (typeof v === "string") {
493
+ const isAsc = v.toLowerCase() === "asc";
494
+ return { path: k, isAsc, emptyFirst: isAsc ? false : true };
495
+ }
496
+ else if (isPlainObject(v)) {
497
+ return {
498
+ path: k,
499
+ isAsc: (v.dir || "asc").toLowerCase() === "asc",
500
+ emptyFirst: v.emptyFirst == null ? true : !!v.emptyFirst
501
+ };
502
+ }
503
+ else {
504
+ throw new Error(`Invalid sorter: ${v}`);
505
+ }
506
+ });
507
+ }));
417
508
  }
418
509
  function _sorterCompile(sorters) {
419
510
  if (sorters.length === 0) {
@@ -524,34 +615,49 @@ function sorterMerge(...sorters) {
524
615
  continue;
525
616
  }
526
617
  for (const sentry of sorter) {
527
- for (const [k, v] of Object.entries(sentry)) {
528
- const existing = result.find((value) => value[k] != null);
529
- if (existing) {
530
- if (v == null) {
531
- delete existing[k];
532
- if (Object.keys(existing).length === 0) {
533
- result.splice(result.indexOf(existing), 1);
534
- }
535
- }
536
- else {
537
- ;
538
- existing[k] = deepClone(v);
539
- }
618
+ const existingIndex = result.findIndex(value => value.path === sentry.path);
619
+ if (existingIndex > -1) {
620
+ if (sentry.remove) {
621
+ result.splice(existingIndex, 1);
540
622
  }
541
- else if (v != null) {
542
- result.push({ [k]: deepClone(v) });
623
+ else {
624
+ result[existingIndex] = deepClone(sentry);
543
625
  }
544
626
  }
627
+ else if (!sentry.remove) {
628
+ result.push(deepClone(sentry));
629
+ }
545
630
  }
546
631
  }
632
+ if (result?.length === 0) {
633
+ return undefined;
634
+ }
547
635
  return result;
548
636
  }
549
- function sorterFind(sorters, name) {
550
- const sorter = sorters.find(v => v[name] != null);
551
- if (sorter != null) {
552
- return sorter[name];
637
+ class SorterProperty extends QueryProperty {
638
+ norm(a) {
639
+ return sorterNormalize(a);
640
+ }
641
+ merge(a, b) {
642
+ return sorterMerge(a, b);
643
+ }
644
+ }
645
+ class SorterPropertySet extends QueryPropertySet {
646
+ of(name) {
647
+ return this.pipe(map(sorters => (sorters == null ? undefined : sorters.find(value => value.path === name))));
648
+ }
649
+ isAsc(name) {
650
+ return this.of(name).pipe(map(v => (v != null ? v.isAsc : undefined)));
651
+ }
652
+ isDesc(name) {
653
+ return this.of(name).pipe(map(v => (v != null ? !v.isAsc : undefined)));
654
+ }
655
+ newProperty() {
656
+ return new SorterProperty(undefined);
657
+ }
658
+ merge(...args) {
659
+ return sorterMerge(...args);
553
660
  }
554
- return undefined;
555
661
  }
556
662
 
557
663
  function slimBy(slimer) { }
@@ -560,6 +666,22 @@ function slimerCompile(slimer) {
560
666
  return item => item;
561
667
  }
562
668
  function slimerMerge(...slimers) { }
669
+ class SlimerProperty extends QueryProperty {
670
+ norm(a) {
671
+ return slimerNormalize(a);
672
+ }
673
+ merge(a, b) {
674
+ return slimerMerge(a, b);
675
+ }
676
+ }
677
+ class SlimerPropertySet extends QueryPropertySet {
678
+ newProperty() {
679
+ return new SlimerProperty(undefined);
680
+ }
681
+ merge(...args) {
682
+ return slimerMerge(...args);
683
+ }
684
+ }
563
685
 
564
686
  function sliceMerge(...slices) {
565
687
  let result = undefined;
@@ -621,6 +743,19 @@ function sliceEq(a, b) {
621
743
  // TODO: sliceConcat(...slices: Slice[]): Slice[]
622
744
  // TODO: sliceDiff(slice: Slice): Slice[]
623
745
 
746
+ function querySubject(...names) {
747
+ const filter = new FilterPropertySet(...names);
748
+ const sorter = new SorterPropertySet(...names);
749
+ const slimer = new SlimerPropertySet(...names);
750
+ const grouper = new GrouperPropertySet(...names);
751
+ const result = combineLatest({ filter, sorter, slimer, grouper }).pipe(shareReplay(1));
752
+ readonlyProp(result, "filter", filter);
753
+ readonlyProp(result, "sorter", sorter);
754
+ readonlyProp(result, "slimer", slimer);
755
+ readonlyProp(result, "grouper", grouper);
756
+ return result;
757
+ }
758
+
624
759
  const INPUT = Symbol("INPUT");
625
760
  function queryExecutor(query, previous) {
626
761
  const executors = {
@@ -896,150 +1031,35 @@ class MemoryStore extends CollectionStore {
896
1031
  }
897
1032
  }
898
1033
 
899
- class Property extends BehaviorSubject {
900
- // readonly #signal: Signal<DeepReadonly<T> | undefined> = toSignal(this, { requireSync: true })
901
- set(value, clone = true) {
902
- if (!isEqual(this.value, value)) {
903
- if (value != null) {
904
- this.next(deepFreeze(clone ? deepClone(value) : value));
905
- }
906
- else {
907
- this.next(undefined);
908
- }
909
- }
910
- }
911
- get() {
912
- return this.value;
913
- }
914
- del() {
915
- this.set(undefined);
916
- }
917
- }
918
- class PropertyCombined {
919
- }
920
- function mergedProperty(merger, ...props) {
921
- if (props.length > 1) {
922
- return combineLatest(props).pipe(map(values => deepFreeze(merger(...values))));
923
- }
924
- else {
925
- return props[0];
926
- }
927
- }
928
-
929
- class FilterProperty extends Property {
930
- update(other) {
931
- this.set(filterMerge(this.value, other), false);
932
- }
933
- }
934
- class FilterCombined extends PropertyCombined {
935
- constructor() {
936
- super(...arguments);
937
- this.normal = new FilterProperty(undefined);
938
- this.forced = new FilterProperty(undefined);
939
- this.merged$ = mergedProperty(filterMerge, this.normal, this.forced);
940
- }
941
- }
942
-
943
- class SorterProperty extends Property {
944
- update(other) {
945
- this.set(sorterMerge(this.value, other), false);
946
- }
947
- }
948
- class SorterCombined extends PropertyCombined {
949
- constructor() {
950
- super(...arguments);
951
- this.normal = new SorterProperty(undefined);
952
- this.forced = new SorterProperty(undefined);
953
- // TODO: normalized sorter
954
- this.merged$ = mergedProperty(sorterMerge, this.normal, this.forced);
955
- }
956
- of(name) {
957
- return this.merged$.pipe(map((sorters) => (sorters == null ? undefined : sorterFind(sorters, name))));
958
- }
959
- directionOf(name) {
960
- return this.of(name).pipe(map(value => {
961
- if (value == null) {
962
- return undefined;
963
- }
964
- else if (typeof value === "string") {
965
- return value;
966
- }
967
- else {
968
- return value.dir;
969
- }
970
- }));
971
- }
972
- isSet(name) {
973
- return this.directionOf(name).pipe(map(v => v != null));
974
- }
975
- isAsc(name) {
976
- return this.directionOf(name).pipe(map(v => v === "asc" /* SortDirection.Asc */));
977
- }
978
- isDesc(name) {
979
- return this.directionOf(name).pipe(map(v => v === "desc" /* SortDirection.Desc */));
980
- }
981
- }
982
-
983
- class SlimerProperty extends Property {
984
- update(other) {
985
- this.set(slimerMerge(this.value, other), false);
986
- }
987
- }
988
- class SlimerCombined extends PropertyCombined {
989
- constructor() {
990
- super(...arguments);
991
- this.normal = new SlimerProperty(undefined);
992
- this.forced = new SlimerProperty(undefined);
993
- this.merged$ = mergedProperty(slimerMerge, this.normal, this.forced);
994
- }
995
- }
996
-
997
- class GrouperProperty extends Property {
998
- update(other) {
999
- this.set(grouperMerge(this.value, other), false);
1000
- }
1001
- }
1002
- class GrouperCombined extends PropertyCombined {
1003
- constructor() {
1004
- super(...arguments);
1005
- this.normal = new GrouperProperty(undefined);
1006
- this.forced = new GrouperProperty(undefined);
1007
- this.merged$ = mergedProperty(grouperMerge, this.normal, this.forced);
1008
- }
1009
- }
1010
-
1011
1034
  const DEBOUNCE_TIME = 50;
1012
1035
  class DataSource extends DataSource$1 {
1013
- #queryBase;
1014
1036
  #slice;
1015
1037
  #reload;
1016
- constructor(provider, store) {
1038
+ #query;
1039
+ constructor(provider, store = new MemoryStore(), query$ = querySubject("normal", "forced")) {
1017
1040
  super();
1018
1041
  this.provider = provider;
1042
+ this.store = store;
1043
+ this.query$ = query$;
1019
1044
  this.busy$ = new BehaviorSubject(false);
1020
1045
  this.total$ = new BehaviorSubject(undefined);
1021
- this.filter = new FilterCombined();
1022
- this.sorter = new SorterCombined();
1023
- this.slimer = new SlimerCombined();
1024
- this.grouper = new GrouperCombined();
1025
- this.#queryBase = combineLatest({
1026
- filter: this.filter.merged$,
1027
- sorter: this.sorter.merged$,
1028
- slimer: this.slimer.merged$,
1029
- grouper: this.grouper.merged$
1030
- }).pipe(shareReplay(1));
1031
1046
  this.#slice = new ReplaySubject(1);
1032
1047
  this.slice$ = this.#slice.pipe(switchMap(slice => this.provider.clampSlice(slice)), distinctUntilChanged(isEqual), map(slice => deepFreeze(deepClone(slice))), shareReplay(1));
1033
1048
  this.#reload = new BehaviorSubject(undefined);
1034
- this.query$ = combineLatest({ base: this.#queryBase, reload: this.#reload }).pipe(tap(() => this.#setBusy(true)),
1049
+ this.#query = combineLatest({
1050
+ query: this.query$,
1051
+ reload: this.#reload
1052
+ }).pipe(tap(() => this.#setBusy(true)),
1035
1053
  // TODO: maybe silent reset or prevent items$ chenges
1036
1054
  // TODO: alternative solution use cacheId, and query item from store with this cacheId
1037
- switchMap(({ base }) => this.store.clear().pipe(map(() => base))), switchMap(queryBase => this.slice$.pipe(tap(() => this.#setBusy(true)), map(slice => {
1038
- return { ...queryBase, slice };
1055
+ switchMap(({ query }) => this.store.clear().pipe(map(() => query))), switchMap(query => this.slice$.pipe(tap(() => this.#setBusy(true)), map(slice => {
1056
+ return { ...query, slice };
1039
1057
  }))), shareReplay(1));
1040
- this.items$ = this.query$.pipe(tap(() => this.#setBusy(true)), debounceTime(DEBOUNCE_TIME), switchMap(query => this.store.hasSlice(query.slice).pipe(switchMap(hasSlice => {
1058
+ this.items$ = this.#query.pipe(tap(() => this.#setBusy(true)), debounceTime(DEBOUNCE_TIME),
1059
+ // tap(query => console.log(query)),
1060
+ switchMap(query => this.store.hasSlice(query.slice).pipe(take(1), switchMap(hasSlice => {
1041
1061
  if (hasSlice) {
1042
- return this.store.getSlice(query.slice);
1062
+ return this.store.getSlice(query.slice).pipe(take(1));
1043
1063
  }
1044
1064
  else {
1045
1065
  return this.provider.queryList(query).pipe(switchMap(result => {
@@ -1051,10 +1071,6 @@ class DataSource extends DataSource$1 {
1051
1071
  }
1052
1072
  }))), finalize(() => this.#setBusy(false)), shareReplay(1));
1053
1073
  this.#cvSubs = new Map();
1054
- if (store == null) {
1055
- store = new MemoryStore();
1056
- }
1057
- this.store = store;
1058
1074
  }
1059
1075
  setSlice(slice) {
1060
1076
  this.#slice.next(slice);
@@ -1067,19 +1083,25 @@ class DataSource extends DataSource$1 {
1067
1083
  this.#reload.next();
1068
1084
  }
1069
1085
  getItem(ref) {
1086
+ return this.watchItem(ref).pipe(take(1));
1087
+ }
1088
+ watchItem(ref) {
1070
1089
  const refn = this.provider.meta.normalizeRef(ref);
1071
1090
  return this.#storeFirst(query => this.store.get(refn), query => this.provider.queryItem(refn, query));
1072
1091
  }
1073
1092
  getItemPosition(ref) {
1093
+ return this.watchItemPosition(ref).pipe(take(1));
1094
+ }
1095
+ watchItemPosition(ref) {
1074
1096
  const refn = this.provider.meta.normalizeRef(ref);
1075
1097
  return this.#storeFirst(query => this.store.indexOf(refn).pipe(map(i => (i < 0 ? undefined : i))), query => this.provider.queryPosition(refn, query));
1076
1098
  }
1077
1099
  realodItem(ref, insertPosition) {
1078
1100
  const refn = this.provider.meta.normalizeRef(ref);
1079
- return this.query$.pipe(switchMap(query => this.provider.queryItem(refn, query)), switchMap(item => item != null ? this.store.updateOrInsert(refn, item, insertPosition).pipe(map(() => item)) : of(item)), take(1));
1101
+ return this.#query.pipe(take(1), switchMap(query => this.provider.queryItem(refn, query).pipe(take(1))), switchMap(item => item != null ? this.store.updateOrInsert(refn, item, insertPosition).pipe(map(() => item)) : of(item)));
1080
1102
  }
1081
1103
  #storeFirst(storeFn, selfFn) {
1082
- return this.query$.pipe(take(1), switchMap(query => storeFn(query).pipe(switchMap(result => (result == null ? selfFn(query) : of(result))))));
1104
+ return this.#query.pipe(take(1), switchMap(query => storeFn(query).pipe(switchMap(result => (result == null ? selfFn(query) : of(result))))));
1083
1105
  }
1084
1106
  #setBusy(busy) {
1085
1107
  if (this.provider.isAsync) {
@@ -1152,25 +1174,22 @@ class DataSourceProxy extends DataSource$1 {
1152
1174
  }))
1153
1175
  .subscribe(this.#value);
1154
1176
  }
1155
- get value() {
1156
- return this.#valueSig();
1157
- }
1158
1177
  #valueSub;
1159
1178
  #value;
1160
- #valueSig;
1161
- set filter(value) {
1179
+ set forcedFilterInput(value) {
1180
+ // this.query.filter.forced.update(value)
1162
1181
  this.#filter.next(value);
1163
1182
  }
1164
1183
  #filter;
1165
- set sorter(value) {
1184
+ set forcedSorterInput(value) {
1166
1185
  this.#sorter.next(value);
1167
1186
  }
1168
1187
  #sorter;
1169
- set grouper(value) {
1188
+ set forcedGrouperInput(value) {
1170
1189
  this.#grouper.next(value);
1171
1190
  }
1172
1191
  #grouper;
1173
- set slimer(value) {
1192
+ set forcedSlimerInput(value) {
1174
1193
  this.#slimer.next(value);
1175
1194
  }
1176
1195
  #slimer;
@@ -1179,7 +1198,7 @@ class DataSourceProxy extends DataSource$1 {
1179
1198
  super();
1180
1199
  this.#value = new ReplaySubject(1);
1181
1200
  this.value$ = this.#value.pipe(takeUntilDestroyed());
1182
- this.#valueSig = toSignal(this.value$);
1201
+ this.query$ = this.value$.pipe(map(value => value.query$), shareReplay(1));
1183
1202
  this.items$ = this.value$.pipe(switchMap(value => value.items$), share());
1184
1203
  this.busy$ = this.value$.pipe(switchMap(value => value.busy$), share());
1185
1204
  this.isBusy = toSignal(this.busy$, { rejectErrors: true, initialValue: false });
@@ -1192,17 +1211,17 @@ class DataSourceProxy extends DataSource$1 {
1192
1211
  if (busy != null) {
1193
1212
  this.#subs.add(busy.connect(this.busy$).subscribe());
1194
1213
  }
1195
- this.#subs.add(combineLatest({ src: this.value$, filter: this.#filter }).subscribe(({ src, filter }) => {
1196
- src.filter.forced.set(filter);
1214
+ this.#subs.add(combineLatest({ query: this.query$, filter: this.#filter }).subscribe(({ query, filter }) => {
1215
+ query.filter.forced.set(filter);
1197
1216
  }));
1198
- this.#subs.add(combineLatest({ src: this.value$, sorter: this.#sorter }).subscribe(({ src, sorter }) => {
1199
- src.sorter.forced.set(sorter);
1217
+ this.#subs.add(combineLatest({ query: this.query$, sorter: this.#sorter }).subscribe(({ query, sorter }) => {
1218
+ query.sorter.forced.set(sorter);
1200
1219
  }));
1201
- this.#subs.add(combineLatest({ src: this.value$, grouper: this.#grouper }).subscribe(({ src, grouper }) => {
1202
- src.grouper.forced.set(grouper);
1220
+ this.#subs.add(combineLatest({ query: this.query$, grouper: this.#grouper }).subscribe(({ query, grouper }) => {
1221
+ query.grouper.forced.set(grouper);
1203
1222
  }));
1204
- this.#subs.add(combineLatest({ src: this.value$, slimer: this.#slimer }).subscribe(({ src, slimer }) => {
1205
- src.slimer.forced.set(slimer);
1223
+ this.#subs.add(combineLatest({ query: this.query$, slimer: this.#slimer }).subscribe(({ query, slimer }) => {
1224
+ query.slimer.forced.set(slimer);
1206
1225
  }));
1207
1226
  }
1208
1227
  #cvSubs;
@@ -1222,7 +1241,7 @@ class DataSourceProxy extends DataSource$1 {
1222
1241
  this.#subs.unsubscribe();
1223
1242
  }
1224
1243
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.6", ngImport: i0, type: DataSourceProxy, deps: [{ token: i1.Busy, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); }
1225
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.6", type: DataSourceProxy, isStandalone: true, selector: "[nuDataSource]", inputs: { value: ["nuDataSource", "value"], filter: "filter", sorter: "sorter", grouper: "grouper", slimer: "slimer" }, exportAs: ["nuDataSource"], usesInheritance: true, ngImport: i0 }); }
1244
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.6", type: DataSourceProxy, isStandalone: true, selector: "[nuDataSource]", inputs: { value: ["nuDataSource", "value"], forcedFilterInput: "forcedFilterInput", forcedSorterInput: "forcedSorterInput", forcedGrouperInput: "forcedGrouperInput", forcedSlimerInput: "forcedSlimerInput" }, exportAs: ["nuDataSource"], usesInheritance: true, ngImport: i0 }); }
1226
1245
  }
1227
1246
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.6", ngImport: i0, type: DataSourceProxy, decorators: [{
1228
1247
  type: Directive,
@@ -1236,13 +1255,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.6", ngImpor
1236
1255
  }] }], propDecorators: { value: [{
1237
1256
  type: Input,
1238
1257
  args: [{ required: true, alias: "nuDataSource" }]
1239
- }], filter: [{
1258
+ }], forcedFilterInput: [{
1240
1259
  type: Input
1241
- }], sorter: [{
1260
+ }], forcedSorterInput: [{
1242
1261
  type: Input
1243
- }], grouper: [{
1262
+ }], forcedGrouperInput: [{
1244
1263
  type: Input
1245
- }], slimer: [{
1264
+ }], forcedSlimerInput: [{
1246
1265
  type: Input
1247
1266
  }] } });
1248
1267
  function coerceDataSource(value) {
@@ -1318,5 +1337,5 @@ class ObservableProvider extends LocalProvider {
1318
1337
  * Generated bundle index. Do not edit.
1319
1338
  */
1320
1339
 
1321
- export { ArrayProvider, CollectionStore, DataProvider, DataSource, DataSourceProxy, LocalProvider, MemoryStore, ModelMeta, ModelRefByIndex, ModelRefByKey, ModelRefNorm, ObservableProvider, UnknownMeta, filterBy, filterMerge, groupBy, grouperMerge, pathGetterCompile, queryExecutor, sliceApply, sliceClamp, sliceEq, sliceInsert, sliceMerge, sliceToPages, slimBy, slimerMerge, sortBy, sorterFind, sorterMerge };
1340
+ export { ArrayProvider, CollectionStore, DataProvider, DataSource, DataSourceProxy, LocalProvider, MemoryStore, ModelMeta, ModelRefByIndex, ModelRefByKey, ModelRefNorm, ObservableProvider, UnknownMeta, filterBy, filterMerge, filterNormalize, groupBy, grouperMerge, pathGetterCompile, queryExecutor, querySubject, sliceApply, sliceClamp, sliceEq, sliceInsert, sliceMerge, sliceToPages, slimBy, slimerMerge, sortBy, sorterMerge, sorterNormalize };
1322
1341
  //# sourceMappingURL=ngutil-data.mjs.map