@dcupl/common 1.11.10 → 2.0.0-beta.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/dist/esm/attribute-dependency-graph.d.ts +119 -0
- package/dist/esm/cache.controller.d.ts +56 -1
- package/dist/esm/changeDetection.d.ts +1 -1
- package/dist/esm/date-utils.d.ts +50 -0
- package/dist/esm/deep-query.service.d.ts +133 -0
- package/dist/esm/dependency-graph.d.ts +102 -3
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.js +3096 -19
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/indices.controller.d.ts +92 -0
- package/dist/esm/logger/index.d.ts +2 -0
- package/dist/esm/logger/logger.d.ts +101 -0
- package/dist/esm/pivot.d.ts +2 -1
- package/dist/esm/query-builder.d.ts +435 -2
- package/dist/esm/queryData.d.ts +9 -4
- package/dist/esm/types/dcupl.types.d.ts +80 -0
- package/dist/esm/types/internal.types.d.ts +1 -1
- package/dist/esm/types/list.types.d.ts +10 -0
- package/dist/esm/types/model.types.d.ts +49 -12
- package/dist/esm/types/query.types.d.ts +500 -2
- package/dist/node/index.cjs +5 -0
- package/dist/node/index.cjs.map +1 -0
- package/package.json +7 -8
- package/dist/browser/common.umd.js +0 -2
- package/dist/browser/common.umd.js.map +0 -1
- package/dist/esm/analytics.controller.js +0 -105
- package/dist/esm/analytics.controller.js.map +0 -1
- package/dist/esm/cache.controller.js +0 -40
- package/dist/esm/cache.controller.js.map +0 -1
- package/dist/esm/changeDetection.js +0 -179
- package/dist/esm/changeDetection.js.map +0 -1
- package/dist/esm/computeSuggestions.js +0 -38
- package/dist/esm/computeSuggestions.js.map +0 -1
- package/dist/esm/dependency-graph.js +0 -136
- package/dist/esm/dependency-graph.js.map +0 -1
- package/dist/esm/getAggregation.js +0 -170
- package/dist/esm/getAggregation.js.map +0 -1
- package/dist/esm/getFacets.js +0 -67
- package/dist/esm/getFacets.js.map +0 -1
- package/dist/esm/helper.js +0 -102
- package/dist/esm/helper.js.map +0 -1
- package/dist/esm/indices.controller.js +0 -97
- package/dist/esm/indices.controller.js.map +0 -1
- package/dist/esm/object-hash.js +0 -33
- package/dist/esm/object-hash.js.map +0 -1
- package/dist/esm/performance.js +0 -33
- package/dist/esm/performance.js.map +0 -1
- package/dist/esm/pivot.js +0 -132
- package/dist/esm/pivot.js.map +0 -1
- package/dist/esm/property-parser.js +0 -57
- package/dist/esm/property-parser.js.map +0 -1
- package/dist/esm/query-builder.js +0 -233
- package/dist/esm/query-builder.js.map +0 -1
- package/dist/esm/query.helper.js +0 -172
- package/dist/esm/query.helper.js.map +0 -1
- package/dist/esm/queryData.js +0 -360
- package/dist/esm/queryData.js.map +0 -1
- package/dist/esm/script.controller.js +0 -54
- package/dist/esm/script.controller.js.map +0 -1
- package/dist/esm/template-parser.js +0 -22
- package/dist/esm/template-parser.js.map +0 -1
- package/dist/esm/types/aggregation.types.js +0 -2
- package/dist/esm/types/aggregation.types.js.map +0 -1
- package/dist/esm/types/app-loader.types.js +0 -2
- package/dist/esm/types/app-loader.types.js.map +0 -1
- package/dist/esm/types/data.types.js +0 -2
- package/dist/esm/types/data.types.js.map +0 -1
- package/dist/esm/types/dcupl.types.js +0 -2
- package/dist/esm/types/dcupl.types.js.map +0 -1
- package/dist/esm/types/facets.types.js +0 -2
- package/dist/esm/types/facets.types.js.map +0 -1
- package/dist/esm/types/filter.types.js +0 -2
- package/dist/esm/types/filter.types.js.map +0 -1
- package/dist/esm/types/group-by.types.js +0 -2
- package/dist/esm/types/group-by.types.js.map +0 -1
- package/dist/esm/types/index.js +0 -17
- package/dist/esm/types/index.js.map +0 -1
- package/dist/esm/types/internal.types.js +0 -2
- package/dist/esm/types/internal.types.js.map +0 -1
- package/dist/esm/types/list.types.js +0 -2
- package/dist/esm/types/list.types.js.map +0 -1
- package/dist/esm/types/model.types.js +0 -16
- package/dist/esm/types/model.types.js.map +0 -1
- package/dist/esm/types/projection.types.js +0 -2
- package/dist/esm/types/projection.types.js.map +0 -1
- package/dist/esm/types/quality.types.js +0 -2
- package/dist/esm/types/quality.types.js.map +0 -1
- package/dist/esm/types/query.types.js +0 -12
- package/dist/esm/types/query.types.js.map +0 -1
- package/dist/esm/types/section.types.js +0 -2
- package/dist/esm/types/section.types.js.map +0 -1
- package/dist/esm/types/suggestion.types.js +0 -2
- package/dist/esm/types/suggestion.types.js.map +0 -1
- package/dist/esm/types/testing.types.js +0 -2
- package/dist/esm/types/testing.types.js.map +0 -1
- package/dist/node/index.cjs.js +0 -1
- package/dist/tsconfig.tsbuildinfo +0 -1
package/dist/esm/index.js
CHANGED
|
@@ -1,19 +1,3096 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
1
|
+
import { cloneDeep as y, get as v, every as B, findIndex as C, size as W, isEqual as E, differenceBy as q, startsWith as L, endsWith as H, isEqualWith as b, isMatch as U, find as V } from "lodash-es";
|
|
2
|
+
function I(o) {
|
|
3
|
+
const e = K(o);
|
|
4
|
+
return J(e);
|
|
5
|
+
}
|
|
6
|
+
function K(o) {
|
|
7
|
+
if (typeof o != "object" || o === null)
|
|
8
|
+
return String(o);
|
|
9
|
+
if (Array.isArray(o))
|
|
10
|
+
return "[" + o.map(K).join(",") + "]";
|
|
11
|
+
const e = Object.keys(o).sort();
|
|
12
|
+
let t = "{";
|
|
13
|
+
for (let r = 0; r < e.length; r++) {
|
|
14
|
+
const s = e[r];
|
|
15
|
+
t += s + ":" + K(o[s]), r < e.length - 1 && (t += ",");
|
|
16
|
+
}
|
|
17
|
+
return t += "}", t;
|
|
18
|
+
}
|
|
19
|
+
function J(o) {
|
|
20
|
+
let e = 0;
|
|
21
|
+
for (let t = 0; t < o.length; t++) {
|
|
22
|
+
const r = o.charCodeAt(t);
|
|
23
|
+
e = (e << 5) - e + r, e |= 0;
|
|
24
|
+
}
|
|
25
|
+
return e.toString(16);
|
|
26
|
+
}
|
|
27
|
+
const x = {
|
|
28
|
+
now: () => typeof performance < "u" && performance.now ? performance.now() : (/* @__PURE__ */ new Date()).getTime(),
|
|
29
|
+
mark: (o) => {
|
|
30
|
+
typeof performance < "u" && performance.mark && performance.mark(o);
|
|
31
|
+
},
|
|
32
|
+
measure: (o, e, t) => {
|
|
33
|
+
typeof performance < "u" && performance.measure && performance.measure(o, e, t);
|
|
34
|
+
},
|
|
35
|
+
getEntriesByName(o) {
|
|
36
|
+
if (typeof performance < "u" && performance.getEntriesByName)
|
|
37
|
+
return performance.getEntriesByName(o);
|
|
38
|
+
},
|
|
39
|
+
getEntriesByType(o) {
|
|
40
|
+
if (typeof performance < "u" && performance.getEntriesByType)
|
|
41
|
+
return performance.getEntriesByType(o);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
class De {
|
|
45
|
+
data;
|
|
46
|
+
enabled = !1;
|
|
47
|
+
constructor() {
|
|
48
|
+
}
|
|
49
|
+
init(e) {
|
|
50
|
+
this.data = /* @__PURE__ */ new Map(), this.enabled = e;
|
|
51
|
+
}
|
|
52
|
+
set(e) {
|
|
53
|
+
if (!this.enabled) return e.value;
|
|
54
|
+
const t = this.getKey(e.value.name, e.context);
|
|
55
|
+
return this.data.set(t, e.value), this.data.get(t);
|
|
56
|
+
}
|
|
57
|
+
mark(e) {
|
|
58
|
+
if (!this.enabled) return;
|
|
59
|
+
const t = this.getKey(e.name, e.context), r = {
|
|
60
|
+
name: e.name,
|
|
61
|
+
type: "mark",
|
|
62
|
+
value: x.now(),
|
|
63
|
+
createdAt: Date.now()
|
|
64
|
+
};
|
|
65
|
+
return this.data.set(t, r), r;
|
|
66
|
+
}
|
|
67
|
+
measure(e) {
|
|
68
|
+
if (!this.enabled) return;
|
|
69
|
+
const t = this.getKey(e.name, e.context), r = this.data.get(this.getKey(e.start, e.context)), s = this.data.get(this.getKey(e.end, e.context));
|
|
70
|
+
if (!r || !s)
|
|
71
|
+
return;
|
|
72
|
+
const i = s.value - r.value, n = Math.round(i * 100) / 100, a = this.data.get(t);
|
|
73
|
+
if (a && e.sum) {
|
|
74
|
+
const c = a.value + n, f = {
|
|
75
|
+
...a,
|
|
76
|
+
value: c
|
|
77
|
+
};
|
|
78
|
+
return this.data.set(t, f), f;
|
|
79
|
+
}
|
|
80
|
+
const u = {
|
|
81
|
+
name: e.name,
|
|
82
|
+
type: "measure",
|
|
83
|
+
value: n,
|
|
84
|
+
createdAt: Date.now()
|
|
85
|
+
};
|
|
86
|
+
return e.detail && (u.detail = e.detail), this.data.set(t, u), u;
|
|
87
|
+
}
|
|
88
|
+
update(e) {
|
|
89
|
+
if (!this.enabled) return e.value;
|
|
90
|
+
const t = this.getKey(e.value.name, e.context), r = this.data.get(t);
|
|
91
|
+
if (r) {
|
|
92
|
+
const s = { ...r, ...e.value };
|
|
93
|
+
this.data.set(t, s);
|
|
94
|
+
} else
|
|
95
|
+
this.data.set(t, e.value);
|
|
96
|
+
return this.data.get(t);
|
|
97
|
+
}
|
|
98
|
+
getResourceInfosFromPerformanceAPI() {
|
|
99
|
+
return typeof performance > "u" ? [] : x.getEntriesByType("resource");
|
|
100
|
+
}
|
|
101
|
+
get(e) {
|
|
102
|
+
const t = this.getKey(e.name, e.context);
|
|
103
|
+
return this.data.get(t);
|
|
104
|
+
}
|
|
105
|
+
getByType(e) {
|
|
106
|
+
return Array.from(this.data.values()).filter((t) => t.type === e);
|
|
107
|
+
}
|
|
108
|
+
getByName(e) {
|
|
109
|
+
return Array.from(this.data.values()).filter((t) => t.name === e);
|
|
110
|
+
}
|
|
111
|
+
clear() {
|
|
112
|
+
this.data.clear();
|
|
113
|
+
}
|
|
114
|
+
getKey(e, t) {
|
|
115
|
+
if (!t)
|
|
116
|
+
return e;
|
|
117
|
+
const r = I(t);
|
|
118
|
+
return e + "_" + r;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
let Z = class T {
|
|
122
|
+
nodes;
|
|
123
|
+
edges;
|
|
124
|
+
nodeKinds = /* @__PURE__ */ new Map();
|
|
125
|
+
nodeMeta = /* @__PURE__ */ new Map();
|
|
126
|
+
edgePolicy;
|
|
127
|
+
constructor() {
|
|
128
|
+
this.nodes = /* @__PURE__ */ new Set(), this.edges = /* @__PURE__ */ new Map();
|
|
129
|
+
}
|
|
130
|
+
addNode(e, t) {
|
|
131
|
+
this.nodes.has(e) || (this.nodes.add(e), this.edges.set(e, /* @__PURE__ */ new Set())), t?.kind !== void 0 && this.nodeKinds.set(e, t.kind), t?.meta !== void 0 && this.nodeMeta.set(e, t.meta);
|
|
132
|
+
}
|
|
133
|
+
addDependency(e, t) {
|
|
134
|
+
if (!this.nodes.has(e) || !this.nodes.has(t))
|
|
135
|
+
throw new Error("Both nodes must exist before adding a dependency.");
|
|
136
|
+
if (this.edgePolicy && !this.edgePolicy(
|
|
137
|
+
{ name: e, kind: this.nodeKinds.get(e) },
|
|
138
|
+
{ name: t, kind: this.nodeKinds.get(t) }
|
|
139
|
+
))
|
|
140
|
+
throw new Error(`Edge policy rejected dependency from "${e}" to "${t}".`);
|
|
141
|
+
this.edges.get(e).add(t);
|
|
142
|
+
}
|
|
143
|
+
/** Configure an optional policy to validate edges before they are added */
|
|
144
|
+
setEdgePolicy(e) {
|
|
145
|
+
this.edgePolicy = e;
|
|
146
|
+
}
|
|
147
|
+
/** Assign or change a node's kind */
|
|
148
|
+
setNodeKind(e, t) {
|
|
149
|
+
if (!this.nodes.has(e)) throw new Error("Node does not exist.");
|
|
150
|
+
t === void 0 ? this.nodeKinds.delete(e) : this.nodeKinds.set(e, t);
|
|
151
|
+
}
|
|
152
|
+
/** Get a node's kind */
|
|
153
|
+
getNodeKind(e) {
|
|
154
|
+
return this.nodeKinds.get(e);
|
|
155
|
+
}
|
|
156
|
+
/** Set arbitrary metadata for a node */
|
|
157
|
+
setNodeMeta(e, t) {
|
|
158
|
+
if (!this.nodes.has(e)) throw new Error("Node does not exist.");
|
|
159
|
+
this.nodeMeta.set(e, t);
|
|
160
|
+
}
|
|
161
|
+
/** Get metadata for a node */
|
|
162
|
+
getNodeMeta(e) {
|
|
163
|
+
return this.nodeMeta.get(e);
|
|
164
|
+
}
|
|
165
|
+
removeNode(e) {
|
|
166
|
+
if (!this.nodes.has(e))
|
|
167
|
+
throw new Error("Node does not exist.");
|
|
168
|
+
this.nodes.delete(e), this.edges.delete(e);
|
|
169
|
+
for (let t of this.edges.values())
|
|
170
|
+
t.delete(e);
|
|
171
|
+
}
|
|
172
|
+
removeDependency(e, t) {
|
|
173
|
+
if (!this.edges.has(e))
|
|
174
|
+
throw new Error("From node does not exist.");
|
|
175
|
+
this.edges.get(e).delete(t);
|
|
176
|
+
}
|
|
177
|
+
hasNode(e) {
|
|
178
|
+
return this.nodes.has(e);
|
|
179
|
+
}
|
|
180
|
+
hasDependency(e, t) {
|
|
181
|
+
return this.edges.has(e) ? this.edges.get(e).has(t) : !1;
|
|
182
|
+
}
|
|
183
|
+
getDependencies(e) {
|
|
184
|
+
if (!this.edges.has(e))
|
|
185
|
+
throw new Error("Node does not exist.");
|
|
186
|
+
return Array.from(this.edges.get(e));
|
|
187
|
+
}
|
|
188
|
+
getDependents(e) {
|
|
189
|
+
const t = [];
|
|
190
|
+
for (let [r, s] of this.edges)
|
|
191
|
+
s.has(e) && t.push(r);
|
|
192
|
+
return t;
|
|
193
|
+
}
|
|
194
|
+
isCyclic() {
|
|
195
|
+
const e = /* @__PURE__ */ new Set(), t = /* @__PURE__ */ new Set(), r = (s) => {
|
|
196
|
+
if (e.has(s))
|
|
197
|
+
return !1;
|
|
198
|
+
if (t.has(s))
|
|
199
|
+
return !0;
|
|
200
|
+
t.add(s);
|
|
201
|
+
const i = this.edges.get(s);
|
|
202
|
+
if (i) {
|
|
203
|
+
for (let n of i)
|
|
204
|
+
if (r(n))
|
|
205
|
+
return !0;
|
|
206
|
+
}
|
|
207
|
+
return t.delete(s), e.add(s), !1;
|
|
208
|
+
};
|
|
209
|
+
for (let s of this.nodes)
|
|
210
|
+
if (r(s))
|
|
211
|
+
return !0;
|
|
212
|
+
return !1;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Validates that the graph has no cycles.
|
|
216
|
+
* Returns an object with hasCycle boolean and the cycle path if found.
|
|
217
|
+
* @returns {hasCycle: boolean, path?: string[]} - hasCycle is true if a cycle exists, path contains the cycle nodes
|
|
218
|
+
*/
|
|
219
|
+
validateNoCycles() {
|
|
220
|
+
const e = /* @__PURE__ */ new Set(), t = /* @__PURE__ */ new Set(), r = [], s = (i) => {
|
|
221
|
+
if (e.has(i))
|
|
222
|
+
return null;
|
|
223
|
+
if (t.has(i)) {
|
|
224
|
+
const a = r.indexOf(i);
|
|
225
|
+
return r.slice(a).concat([i]);
|
|
226
|
+
}
|
|
227
|
+
t.add(i), r.push(i);
|
|
228
|
+
const n = this.edges.get(i);
|
|
229
|
+
if (n)
|
|
230
|
+
for (let a of n) {
|
|
231
|
+
const u = s(a);
|
|
232
|
+
if (u)
|
|
233
|
+
return u;
|
|
234
|
+
}
|
|
235
|
+
return r.pop(), t.delete(i), e.add(i), null;
|
|
236
|
+
};
|
|
237
|
+
for (let i of this.nodes) {
|
|
238
|
+
const n = s(i);
|
|
239
|
+
if (n)
|
|
240
|
+
return { hasCycle: !0, path: n };
|
|
241
|
+
}
|
|
242
|
+
return { hasCycle: !1 };
|
|
243
|
+
}
|
|
244
|
+
order(e) {
|
|
245
|
+
const t = /* @__PURE__ */ new Set(), r = /* @__PURE__ */ new Set(), s = [], i = e?.allowCycles ?? !1, n = (a) => {
|
|
246
|
+
if (t.has(a))
|
|
247
|
+
return;
|
|
248
|
+
if (r.has(a)) {
|
|
249
|
+
if (i)
|
|
250
|
+
return;
|
|
251
|
+
throw new Error("Graph has a cycle.");
|
|
252
|
+
}
|
|
253
|
+
r.add(a);
|
|
254
|
+
const u = this.edges.get(a);
|
|
255
|
+
if (u)
|
|
256
|
+
for (let c of u)
|
|
257
|
+
n(c);
|
|
258
|
+
r.delete(a), t.add(a), s.push(a);
|
|
259
|
+
};
|
|
260
|
+
for (let a of this.nodes)
|
|
261
|
+
t.has(a) || n(a);
|
|
262
|
+
return s;
|
|
263
|
+
}
|
|
264
|
+
clear() {
|
|
265
|
+
this.nodes.clear(), this.edges.clear();
|
|
266
|
+
}
|
|
267
|
+
getNodes() {
|
|
268
|
+
return Array.from(this.nodes);
|
|
269
|
+
}
|
|
270
|
+
getAllEdges() {
|
|
271
|
+
const e = [];
|
|
272
|
+
for (let [t, r] of this.edges)
|
|
273
|
+
for (let s of r)
|
|
274
|
+
e.push([t, s]);
|
|
275
|
+
return e;
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Returns all nodes that have no dependants (i.e., no other node depends on them).
|
|
279
|
+
* In graph terms, nodes with zero incoming edges.
|
|
280
|
+
*/
|
|
281
|
+
getNodesWithNoDependants() {
|
|
282
|
+
if (this.nodes.size === 0)
|
|
283
|
+
return [];
|
|
284
|
+
const e = /* @__PURE__ */ new Set();
|
|
285
|
+
for (const r of this.edges.values())
|
|
286
|
+
for (const s of r)
|
|
287
|
+
e.add(s);
|
|
288
|
+
const t = [];
|
|
289
|
+
for (const r of this.nodes)
|
|
290
|
+
e.has(r) || t.push(r);
|
|
291
|
+
return t;
|
|
292
|
+
}
|
|
293
|
+
/** Return nodes filtered by kind */
|
|
294
|
+
getNodesByKind(e) {
|
|
295
|
+
const t = [];
|
|
296
|
+
for (const r of this.nodes)
|
|
297
|
+
this.nodeKinds.get(r) === e && t.push(r);
|
|
298
|
+
return t;
|
|
299
|
+
}
|
|
300
|
+
/** Roots by kind (zero incoming) */
|
|
301
|
+
getRootsByKind(e) {
|
|
302
|
+
const t = new Set(this.getNodesWithNoDependants()), r = Array.from(t);
|
|
303
|
+
return e ? r.filter((s) => this.nodeKinds.get(s) === e) : r;
|
|
304
|
+
}
|
|
305
|
+
/** Leaves by kind (zero outgoing) */
|
|
306
|
+
getLeavesByKind(e) {
|
|
307
|
+
const t = [];
|
|
308
|
+
for (const r of this.nodes) {
|
|
309
|
+
const s = this.edges.get(r);
|
|
310
|
+
(!s || s.size === 0) && (!e || this.nodeKinds.get(r) === e) && t.push(r);
|
|
311
|
+
}
|
|
312
|
+
return t;
|
|
313
|
+
}
|
|
314
|
+
/** Filter dependencies of a node by kind */
|
|
315
|
+
getDependenciesOfKind(e, t) {
|
|
316
|
+
return this.getDependencies(e).filter((s) => this.nodeKinds.get(s) === t);
|
|
317
|
+
}
|
|
318
|
+
/** Filter dependents of a node by kind */
|
|
319
|
+
getDependentsOfKind(e, t) {
|
|
320
|
+
return this.getDependents(e).filter((s) => this.nodeKinds.get(s) === t);
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Create execution batches (topological levels). Throws if the graph has a cycle.
|
|
324
|
+
* If filterKinds is provided, batches contain only nodes of these kinds, but readiness
|
|
325
|
+
* is evaluated against the complete graph.
|
|
326
|
+
*/
|
|
327
|
+
plan(e) {
|
|
328
|
+
const t = /* @__PURE__ */ new Map();
|
|
329
|
+
for (const n of this.nodes) t.set(n, 0);
|
|
330
|
+
for (const n of this.edges.values())
|
|
331
|
+
for (const a of n) t.set(a, (t.get(a) || 0) + 1);
|
|
332
|
+
const r = [];
|
|
333
|
+
let s = Array.from(this.nodes).filter((n) => (t.get(n) || 0) === 0);
|
|
334
|
+
const i = /* @__PURE__ */ new Set();
|
|
335
|
+
for (; s.length > 0; ) {
|
|
336
|
+
const n = s.slice();
|
|
337
|
+
r.push(n), s = [];
|
|
338
|
+
for (const a of n) {
|
|
339
|
+
if (i.has(a)) continue;
|
|
340
|
+
i.add(a);
|
|
341
|
+
const u = this.edges.get(a);
|
|
342
|
+
if (u)
|
|
343
|
+
for (const c of u)
|
|
344
|
+
t.set(c, (t.get(c) || 0) - 1), (t.get(c) || 0) === 0 && s.push(c);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
if (i.size !== this.nodes.size)
|
|
348
|
+
throw new Error("Graph has a cycle.");
|
|
349
|
+
if (e?.filterKinds && e.filterKinds.length > 0) {
|
|
350
|
+
const n = new Set(e.filterKinds);
|
|
351
|
+
return {
|
|
352
|
+
batches: r.map((a) => a.filter((u) => n.has(this.nodeKinds.get(u))))
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
return { batches: r };
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Impact analysis: return nodes impacted by a set of changed nodes.
|
|
359
|
+
* direction:
|
|
360
|
+
* - 'downstream': nodes that depend (directly/indirectly) on changed
|
|
361
|
+
* - 'upstream': nodes that changed depends on
|
|
362
|
+
* - 'both': union of upstream and downstream
|
|
363
|
+
*/
|
|
364
|
+
getImpactedNodes(e, t = "downstream", r) {
|
|
365
|
+
const s = new Set(e), i = (c) => !r || r.length === 0 || r.includes(this.nodeKinds.get(c) ?? void 0), n = () => {
|
|
366
|
+
const c = /* @__PURE__ */ new Set(), f = Array.from(s);
|
|
367
|
+
for (; f.length; ) {
|
|
368
|
+
const d = f.shift();
|
|
369
|
+
for (const [l, h] of this.edges)
|
|
370
|
+
h.has(d) && !c.has(l) && (c.add(l), f.push(l));
|
|
371
|
+
}
|
|
372
|
+
return c;
|
|
373
|
+
}, a = () => {
|
|
374
|
+
const c = /* @__PURE__ */ new Set(), f = Array.from(s);
|
|
375
|
+
for (; f.length; ) {
|
|
376
|
+
const d = f.shift(), l = this.edges.get(d);
|
|
377
|
+
if (l)
|
|
378
|
+
for (const h of l)
|
|
379
|
+
c.has(h) || (c.add(h), f.push(h));
|
|
380
|
+
}
|
|
381
|
+
return c;
|
|
382
|
+
};
|
|
383
|
+
let u;
|
|
384
|
+
return t === "both" ? u = /* @__PURE__ */ new Set([...n(), ...a()]) : t === "upstream" ? u = a() : u = n(), Array.from(u).filter(i);
|
|
385
|
+
}
|
|
386
|
+
toJSON() {
|
|
387
|
+
const e = Array.from(this.nodes).map((r) => ({
|
|
388
|
+
name: r,
|
|
389
|
+
kind: this.nodeKinds.get(r),
|
|
390
|
+
meta: this.nodeMeta.get(r)
|
|
391
|
+
})), t = this.getAllEdges().map(([r, s]) => ({ from: r, to: s }));
|
|
392
|
+
return { nodes: e, edges: t };
|
|
393
|
+
}
|
|
394
|
+
static fromJSON(e) {
|
|
395
|
+
const t = new T();
|
|
396
|
+
for (const r of e.nodes)
|
|
397
|
+
t.addNode(r.name, { kind: r.kind, meta: r.meta });
|
|
398
|
+
for (const r of e.edges)
|
|
399
|
+
t.addDependency(r.from, r.to);
|
|
400
|
+
return t;
|
|
401
|
+
}
|
|
402
|
+
diff(e) {
|
|
403
|
+
const t = new Set(this.getNodes()), r = new Set(e.getNodes()), s = Array.from(r).filter((d) => !t.has(d)), i = Array.from(t).filter((d) => !r.has(d)), n = new Set(this.getAllEdges().map((d) => d.join("→"))), a = new Set(e.getAllEdges().map((d) => d.join("→"))), u = Array.from(a).filter((d) => !n.has(d)).map((d) => d.split("→")), c = Array.from(n).filter((d) => !a.has(d)).map((d) => d.split("→")), f = [];
|
|
404
|
+
for (const d of /* @__PURE__ */ new Set([...t, ...r])) {
|
|
405
|
+
const l = this.nodeKinds.get(d), h = e.nodeKinds.get(d);
|
|
406
|
+
l !== h && f.push({ name: d, from: l, to: h });
|
|
407
|
+
}
|
|
408
|
+
return { addedNodes: s, removedNodes: i, addedEdges: u, removedEdges: c, kindChanges: f };
|
|
409
|
+
}
|
|
410
|
+
};
|
|
411
|
+
class Ke {
|
|
412
|
+
graph;
|
|
413
|
+
nodeIndex;
|
|
414
|
+
constructor() {
|
|
415
|
+
this.graph = new Z(), this.nodeIndex = /* @__PURE__ */ new Map();
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* Creates a unique ID for an attribute node
|
|
419
|
+
*/
|
|
420
|
+
getNodeId(e, t) {
|
|
421
|
+
return `${e}.${t}`;
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Parses a node ID back into components
|
|
425
|
+
*/
|
|
426
|
+
parseNodeId(e) {
|
|
427
|
+
const t = e.split(".");
|
|
428
|
+
return {
|
|
429
|
+
modelKey: t[0],
|
|
430
|
+
attributeKey: t.slice(1).join(".")
|
|
431
|
+
// Handle attribute keys with dots
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* Adds an attribute node to the graph
|
|
436
|
+
*/
|
|
437
|
+
addAttribute(e) {
|
|
438
|
+
const t = this.getNodeId(e.modelKey, e.attributeKey);
|
|
439
|
+
this.nodeIndex.has(t) || (this.graph.addNode(t, { meta: e }), this.nodeIndex.set(t, e));
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* Adds a dependency between two attributes
|
|
443
|
+
* @param from - The dependent attribute (e.g., ModelA.derivedPrice)
|
|
444
|
+
* @param to - The source attribute it depends on (e.g., ModelB.baseCost)
|
|
445
|
+
*/
|
|
446
|
+
addAttributeDependency(e, t) {
|
|
447
|
+
this.addAttribute(e), this.addAttribute(t);
|
|
448
|
+
const r = this.getNodeId(e.modelKey, e.attributeKey), s = this.getNodeId(t.modelKey, t.attributeKey);
|
|
449
|
+
this.graph.hasDependency(r, s) || this.graph.addDependency(r, s);
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* Gets all attributes impacted by changes to the given attributes
|
|
453
|
+
* @param changed - Array of changed attribute nodes
|
|
454
|
+
* @returns Array of all impacted attribute nodes (including the changed ones)
|
|
455
|
+
*/
|
|
456
|
+
getImpactedAttributes(e) {
|
|
457
|
+
const t = e.map((a) => this.getNodeId(a.modelKey, a.attributeKey)), s = this.graph.getImpactedNodes(t, "downstream").map((a) => this.nodeIndex.get(a)).filter((a) => a !== void 0), i = [...e, ...s], n = /* @__PURE__ */ new Set();
|
|
458
|
+
return i.filter((a) => {
|
|
459
|
+
const u = this.getNodeId(a.modelKey, a.attributeKey);
|
|
460
|
+
return n.has(u) ? !1 : (n.add(u), !0);
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
/**
|
|
464
|
+
* Generates a processing plan for the given attributes
|
|
465
|
+
* Groups attributes by model and processing step for efficient batch processing
|
|
466
|
+
*
|
|
467
|
+
* @param attributes - Array of attributes to process
|
|
468
|
+
* @returns Map<modelKey, Map<processingStep, Set<attributeKeys>>>
|
|
469
|
+
*/
|
|
470
|
+
getProcessingOrder(e) {
|
|
471
|
+
const t = /* @__PURE__ */ new Map(), r = [...e].sort((s, i) => s.processingStep - i.processingStep);
|
|
472
|
+
for (const s of r) {
|
|
473
|
+
const { modelKey: i, attributeKey: n, processingStep: a } = s;
|
|
474
|
+
t.has(i) || t.set(i, /* @__PURE__ */ new Map());
|
|
475
|
+
const u = t.get(i);
|
|
476
|
+
u.has(a) || u.set(a, /* @__PURE__ */ new Set()), u.get(a).add(n);
|
|
477
|
+
}
|
|
478
|
+
return t;
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* Gets all attributes for a specific model
|
|
482
|
+
*/
|
|
483
|
+
getAttributesForModel(e) {
|
|
484
|
+
const t = [];
|
|
485
|
+
for (const r of this.nodeIndex.values())
|
|
486
|
+
r.modelKey === e && t.push(r);
|
|
487
|
+
return t;
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* Gets dependencies for a specific attribute
|
|
491
|
+
*/
|
|
492
|
+
getDependencies(e) {
|
|
493
|
+
const t = this.getNodeId(e.modelKey, e.attributeKey);
|
|
494
|
+
return this.graph.hasNode(t) ? this.graph.getDependencies(t).map((s) => this.nodeIndex.get(s)).filter((s) => s !== void 0) : [];
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* Gets dependents for a specific attribute (attributes that depend on this one)
|
|
498
|
+
*/
|
|
499
|
+
getDependents(e) {
|
|
500
|
+
const t = this.getNodeId(e.modelKey, e.attributeKey);
|
|
501
|
+
return this.graph.hasNode(t) ? this.graph.getDependents(t).map((s) => this.nodeIndex.get(s)).filter((s) => s !== void 0) : [];
|
|
502
|
+
}
|
|
503
|
+
/**
|
|
504
|
+
* Checks if an attribute has any dependencies
|
|
505
|
+
*/
|
|
506
|
+
hasDependencies(e) {
|
|
507
|
+
const t = this.getNodeId(e.modelKey, e.attributeKey);
|
|
508
|
+
return this.graph.hasNode(t) ? this.graph.getDependencies(t).length > 0 : !1;
|
|
509
|
+
}
|
|
510
|
+
/**
|
|
511
|
+
* Checks if a node exists in the graph
|
|
512
|
+
*/
|
|
513
|
+
hasNode(e) {
|
|
514
|
+
return this.nodeIndex.has(e);
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* Gets all attribute nodes in the graph
|
|
518
|
+
*/
|
|
519
|
+
getAllAttributes() {
|
|
520
|
+
return Array.from(this.nodeIndex.values());
|
|
521
|
+
}
|
|
522
|
+
/**
|
|
523
|
+
* Gets the maximum dependency depth in the graph
|
|
524
|
+
* Useful for determining if full update might be more efficient
|
|
525
|
+
*/
|
|
526
|
+
getMaxDepth() {
|
|
527
|
+
let e = 0;
|
|
528
|
+
const t = (r, s = /* @__PURE__ */ new Set()) => {
|
|
529
|
+
if (s.has(r)) return 0;
|
|
530
|
+
s.add(r);
|
|
531
|
+
const i = this.graph.getDependencies(r);
|
|
532
|
+
if (i.length === 0) return 1;
|
|
533
|
+
let n = 0;
|
|
534
|
+
for (const a of i) {
|
|
535
|
+
const u = t(a, new Set(s));
|
|
536
|
+
n = Math.max(n, u);
|
|
537
|
+
}
|
|
538
|
+
return n + 1;
|
|
539
|
+
};
|
|
540
|
+
for (const r of this.graph.getNodes()) {
|
|
541
|
+
const s = t(r);
|
|
542
|
+
e = Math.max(e, s);
|
|
543
|
+
}
|
|
544
|
+
return e;
|
|
545
|
+
}
|
|
546
|
+
/**
|
|
547
|
+
* Validates that all expected attributes are present in the graph.
|
|
548
|
+
* This helps catch silent failures during graph building where attributes
|
|
549
|
+
* with expressions or derivations might not be properly added.
|
|
550
|
+
*
|
|
551
|
+
* @param expectedAttributes - Map of modelKey to array of attribute keys that should exist
|
|
552
|
+
* @returns Object with validation result and any missing attributes
|
|
553
|
+
*/
|
|
554
|
+
validateCompleteness(e) {
|
|
555
|
+
const t = [];
|
|
556
|
+
for (const [r, s] of e)
|
|
557
|
+
for (const i of s) {
|
|
558
|
+
const n = this.getNodeId(r, i);
|
|
559
|
+
this.hasNode(n) || t.push({ modelKey: r, attributeKey: i });
|
|
560
|
+
}
|
|
561
|
+
return {
|
|
562
|
+
isComplete: t.length === 0,
|
|
563
|
+
missing: t
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
567
|
+
* Clears the entire graph
|
|
568
|
+
*/
|
|
569
|
+
clear() {
|
|
570
|
+
this.graph.clear(), this.nodeIndex.clear();
|
|
571
|
+
}
|
|
572
|
+
/**
|
|
573
|
+
* Gets statistics about the graph
|
|
574
|
+
*/
|
|
575
|
+
getStats() {
|
|
576
|
+
const e = /* @__PURE__ */ new Map(), t = /* @__PURE__ */ new Map();
|
|
577
|
+
for (const r of this.nodeIndex.values())
|
|
578
|
+
e.set(r.modelKey, (e.get(r.modelKey) || 0) + 1), t.set(r.processingStep, (t.get(r.processingStep) || 0) + 1);
|
|
579
|
+
return {
|
|
580
|
+
totalAttributes: this.nodeIndex.size,
|
|
581
|
+
totalDependencies: this.graph.getAllEdges().length,
|
|
582
|
+
maxDepth: this.getMaxDepth(),
|
|
583
|
+
attributesByModel: e,
|
|
584
|
+
attributesByStep: t
|
|
585
|
+
};
|
|
586
|
+
}
|
|
587
|
+
/**
|
|
588
|
+
* Exports the graph to JSON for debugging
|
|
589
|
+
*/
|
|
590
|
+
toJSON() {
|
|
591
|
+
return {
|
|
592
|
+
nodes: Array.from(this.nodeIndex.values()),
|
|
593
|
+
edges: this.graph.getAllEdges().map(([e, t]) => {
|
|
594
|
+
const r = this.parseNodeId(e), s = this.parseNodeId(t);
|
|
595
|
+
return {
|
|
596
|
+
from: r,
|
|
597
|
+
to: s
|
|
598
|
+
};
|
|
599
|
+
})
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
const O = {
|
|
604
|
+
silent: 0,
|
|
605
|
+
error: 1,
|
|
606
|
+
warn: 2,
|
|
607
|
+
info: 3,
|
|
608
|
+
debug: 4
|
|
609
|
+
};
|
|
610
|
+
class p {
|
|
611
|
+
config;
|
|
612
|
+
static globalConfig = {};
|
|
613
|
+
constructor(e = {}) {
|
|
614
|
+
this.config = {
|
|
615
|
+
level: e.level ?? p.globalConfig.level ?? this.getDefaultLevel(),
|
|
616
|
+
format: e.format ?? p.globalConfig.format ?? this.getDefaultFormat(),
|
|
617
|
+
prefix: e.prefix,
|
|
618
|
+
onLog: e.onLog ?? p.globalConfig.onLog,
|
|
619
|
+
onTrackError: e.onTrackError ?? p.globalConfig.onTrackError
|
|
620
|
+
};
|
|
621
|
+
}
|
|
622
|
+
/**
|
|
623
|
+
* Set global logger configuration (affects all logger instances)
|
|
624
|
+
*/
|
|
625
|
+
static setGlobalConfig(e) {
|
|
626
|
+
p.globalConfig = { ...p.globalConfig, ...e };
|
|
627
|
+
}
|
|
628
|
+
/**
|
|
629
|
+
* Get the global logger configuration
|
|
630
|
+
*/
|
|
631
|
+
static getGlobalConfig() {
|
|
632
|
+
return { ...p.globalConfig };
|
|
633
|
+
}
|
|
634
|
+
/**
|
|
635
|
+
* Configure module-specific log levels
|
|
636
|
+
* @example
|
|
637
|
+
* logger.setModuleLevel('ModelParser', 'debug');
|
|
638
|
+
* logger.setModuleLevel('Catalog', 'warn');
|
|
639
|
+
*/
|
|
640
|
+
static setModuleLevel(e, t) {
|
|
641
|
+
p.globalConfig.onLog || (p.globalConfig.onLog = void 0), p._moduleOverrides || (p._moduleOverrides = /* @__PURE__ */ new Map()), p._moduleOverrides.set(e, t);
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* Get module-specific log level
|
|
645
|
+
*/
|
|
646
|
+
static getModuleLevel(e) {
|
|
647
|
+
if (!(!e || !p._moduleOverrides))
|
|
648
|
+
return p._moduleOverrides.get(e);
|
|
649
|
+
}
|
|
650
|
+
getDefaultLevel() {
|
|
651
|
+
return "info";
|
|
652
|
+
}
|
|
653
|
+
getDefaultFormat() {
|
|
654
|
+
return "pretty";
|
|
655
|
+
}
|
|
656
|
+
getEffectiveLevel() {
|
|
657
|
+
if (this.config.prefix) {
|
|
658
|
+
const e = p.getModuleLevel(this.config.prefix);
|
|
659
|
+
if (e)
|
|
660
|
+
return e;
|
|
661
|
+
}
|
|
662
|
+
return this.config.level;
|
|
663
|
+
}
|
|
664
|
+
shouldLog(e) {
|
|
665
|
+
const t = this.getEffectiveLevel();
|
|
666
|
+
return O[e] <= O[t];
|
|
667
|
+
}
|
|
668
|
+
formatMessage(e) {
|
|
669
|
+
if (this.config.format === "json") {
|
|
670
|
+
const n = {
|
|
671
|
+
timestamp: new Date(e.timestamp).toISOString(),
|
|
672
|
+
level: e.level,
|
|
673
|
+
message: e.message
|
|
674
|
+
};
|
|
675
|
+
return e.prefix && (n.module = e.prefix), e.context && (n.context = e.context), e.error && (n.error = {
|
|
676
|
+
name: e.error.name,
|
|
677
|
+
message: e.error.message,
|
|
678
|
+
stack: e.error.stack
|
|
679
|
+
}), JSON.stringify(n);
|
|
680
|
+
}
|
|
681
|
+
const t = new Date(e.timestamp).toISOString().substring(11, 23), r = e.prefix ? `[${e.prefix}]` : "", s = this.getLevelIcon(e.level), i = e.context ? ` ${JSON.stringify(e.context)}` : "";
|
|
682
|
+
return `${t} ${s} ${r} ${e.message}${i}`.trim();
|
|
683
|
+
}
|
|
684
|
+
getLevelIcon(e) {
|
|
685
|
+
switch (e) {
|
|
686
|
+
case "error":
|
|
687
|
+
return "✖";
|
|
688
|
+
case "warn":
|
|
689
|
+
return "⚠";
|
|
690
|
+
case "info":
|
|
691
|
+
return "ℹ";
|
|
692
|
+
case "debug":
|
|
693
|
+
return "⚙";
|
|
694
|
+
default:
|
|
695
|
+
return " ";
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
log(e, t, r, s) {
|
|
699
|
+
if (!this.shouldLog(e))
|
|
700
|
+
return;
|
|
701
|
+
const i = {
|
|
702
|
+
level: e,
|
|
703
|
+
message: t,
|
|
704
|
+
timestamp: Date.now(),
|
|
705
|
+
prefix: this.config.prefix,
|
|
706
|
+
context: r,
|
|
707
|
+
error: s
|
|
708
|
+
};
|
|
709
|
+
if (this.config.onLog) {
|
|
710
|
+
this.config.onLog(i);
|
|
711
|
+
return;
|
|
712
|
+
}
|
|
713
|
+
const n = this.formatMessage(i);
|
|
714
|
+
if (typeof console < "u")
|
|
715
|
+
switch (e) {
|
|
716
|
+
case "error":
|
|
717
|
+
s ? console.error(n, s) : console.error(n);
|
|
718
|
+
break;
|
|
719
|
+
case "warn":
|
|
720
|
+
console.warn(n);
|
|
721
|
+
break;
|
|
722
|
+
case "debug":
|
|
723
|
+
console.debug ? console.debug(n) : console.log(n);
|
|
724
|
+
break;
|
|
725
|
+
default:
|
|
726
|
+
console.log(n);
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
/**
|
|
730
|
+
* Log an error message
|
|
731
|
+
*/
|
|
732
|
+
error(e, t, r) {
|
|
733
|
+
const s = t instanceof Error ? t : void 0, i = t instanceof Error ? r : t;
|
|
734
|
+
this.log("error", e, i, s);
|
|
735
|
+
}
|
|
736
|
+
/**
|
|
737
|
+
* Log and track an error (integrates with QualityController)
|
|
738
|
+
* @param message Error message
|
|
739
|
+
* @param error Error object
|
|
740
|
+
* @param options Additional context and error classification
|
|
741
|
+
*/
|
|
742
|
+
trackError(e, t, r) {
|
|
743
|
+
if (this.error(e, t, r?.context), this.config.onTrackError) {
|
|
744
|
+
const s = {
|
|
745
|
+
level: "error",
|
|
746
|
+
message: e,
|
|
747
|
+
timestamp: Date.now(),
|
|
748
|
+
prefix: this.config.prefix,
|
|
749
|
+
context: r?.context,
|
|
750
|
+
error: t,
|
|
751
|
+
errorType: r?.errorType,
|
|
752
|
+
errorGroup: r?.errorGroup
|
|
753
|
+
};
|
|
754
|
+
this.config.onTrackError(s);
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
/**
|
|
758
|
+
* Log a warning message
|
|
759
|
+
*/
|
|
760
|
+
warn(e, t) {
|
|
761
|
+
this.log("warn", e, t);
|
|
762
|
+
}
|
|
763
|
+
/**
|
|
764
|
+
* Log an info message
|
|
765
|
+
*/
|
|
766
|
+
info(e, t) {
|
|
767
|
+
this.log("info", e, t);
|
|
768
|
+
}
|
|
769
|
+
/**
|
|
770
|
+
* Log a debug message
|
|
771
|
+
*/
|
|
772
|
+
debug(e, t) {
|
|
773
|
+
this.log("debug", e, t);
|
|
774
|
+
}
|
|
775
|
+
/**
|
|
776
|
+
* Create a child logger with additional context or configuration
|
|
777
|
+
* Child loggers inherit parent config but can override specific settings
|
|
778
|
+
*
|
|
779
|
+
* @example
|
|
780
|
+
* const modelLogger = logger.child({ prefix: 'ModelParser' });
|
|
781
|
+
* modelLogger.info('Processing data'); // [ModelParser] Processing data
|
|
782
|
+
*
|
|
783
|
+
* @example
|
|
784
|
+
* const debugLogger = logger.child({ prefix: 'Catalog', level: 'debug' });
|
|
785
|
+
*/
|
|
786
|
+
child(e) {
|
|
787
|
+
const t = {
|
|
788
|
+
...this.config,
|
|
789
|
+
...e,
|
|
790
|
+
// Handle prefix concatenation for nested children
|
|
791
|
+
prefix: e.prefix ? this.config.prefix ? `${this.config.prefix}:${e.prefix}` : e.prefix : this.config.prefix
|
|
792
|
+
};
|
|
793
|
+
return new p(t);
|
|
794
|
+
}
|
|
795
|
+
/**
|
|
796
|
+
* Update this logger's configuration
|
|
797
|
+
*/
|
|
798
|
+
configure(e) {
|
|
799
|
+
Object.assign(this.config, e);
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
const Y = new p();
|
|
803
|
+
class Se {
|
|
804
|
+
constructor(e) {
|
|
805
|
+
this.enabled = e, this.cache = /* @__PURE__ */ new Map(), this.cacheDependencies = /* @__PURE__ */ new Map();
|
|
806
|
+
}
|
|
807
|
+
cache;
|
|
808
|
+
// Track which models and attributes each cache entry depends on
|
|
809
|
+
cacheDependencies;
|
|
810
|
+
// Track cache hits and misses for statistics
|
|
811
|
+
hitCount = 0;
|
|
812
|
+
missCount = 0;
|
|
813
|
+
log = Y.child({ prefix: "CacheController" });
|
|
814
|
+
get(e, t) {
|
|
815
|
+
if (!this.enabled) return;
|
|
816
|
+
const r = this.getCacheName(e, t);
|
|
817
|
+
return this.cache.has(r) ? this.hitCount++ : this.missCount++, this.cache.get(r);
|
|
818
|
+
}
|
|
819
|
+
set(e, t, r, s) {
|
|
820
|
+
if (!this.enabled) return;
|
|
821
|
+
const i = this.getCacheName(e, t);
|
|
822
|
+
this.cache.set(i, r), s ? this.cacheDependencies.set(i, s) : this.log.debug(
|
|
823
|
+
`Cache entry '${e}' stored without dependencies. This prevents granular invalidation and may cause stale data.`
|
|
824
|
+
);
|
|
825
|
+
}
|
|
826
|
+
has(e, t) {
|
|
827
|
+
return this.cache.has(this.getCacheName(e, t));
|
|
828
|
+
}
|
|
829
|
+
clear() {
|
|
830
|
+
this.cache.clear(), this.cacheDependencies.clear(), this.hitCount = 0, this.missCount = 0;
|
|
831
|
+
}
|
|
832
|
+
/**
|
|
833
|
+
* Invalidates cache entries that depend on the specified models and attributes
|
|
834
|
+
* @param changedModels - Map of modelKey → Set of changed attributeKeys
|
|
835
|
+
*/
|
|
836
|
+
invalidateByDependencies(e) {
|
|
837
|
+
if (!this.enabled) return;
|
|
838
|
+
const t = [];
|
|
839
|
+
for (const [r, s] of this.cacheDependencies) {
|
|
840
|
+
let i = !1;
|
|
841
|
+
for (const [n, a] of e) {
|
|
842
|
+
if (s.models.has(n))
|
|
843
|
+
if (s.modelAttributes.has(n)) {
|
|
844
|
+
const u = s.modelAttributes.get(n);
|
|
845
|
+
for (const c of a)
|
|
846
|
+
if (u.has(c)) {
|
|
847
|
+
i = !0;
|
|
848
|
+
break;
|
|
849
|
+
}
|
|
850
|
+
} else
|
|
851
|
+
i = !0;
|
|
852
|
+
if (i) break;
|
|
853
|
+
}
|
|
854
|
+
i && t.push(r);
|
|
855
|
+
}
|
|
856
|
+
for (const r of t)
|
|
857
|
+
this.cache.delete(r), this.cacheDependencies.delete(r);
|
|
858
|
+
}
|
|
859
|
+
/**
|
|
860
|
+
* Invalidates all cache entries for specific models
|
|
861
|
+
* @param modelKeys - Array of model keys to invalidate
|
|
862
|
+
*/
|
|
863
|
+
invalidateByModels(e) {
|
|
864
|
+
if (!this.enabled) return;
|
|
865
|
+
const t = new Set(e), r = [];
|
|
866
|
+
for (const [s, i] of this.cacheDependencies)
|
|
867
|
+
for (const n of t)
|
|
868
|
+
if (i.models.has(n)) {
|
|
869
|
+
r.push(s);
|
|
870
|
+
break;
|
|
871
|
+
}
|
|
872
|
+
for (const s of r)
|
|
873
|
+
this.cache.delete(s), this.cacheDependencies.delete(s);
|
|
874
|
+
}
|
|
875
|
+
/**
|
|
876
|
+
* Invalidates cache entries by key prefix (e.g., 'query', 'facets')
|
|
877
|
+
* @param keyPrefix - The key prefix to match
|
|
878
|
+
*/
|
|
879
|
+
invalidateByKeyPrefix(e) {
|
|
880
|
+
if (!this.enabled) return;
|
|
881
|
+
const t = [];
|
|
882
|
+
for (const r of this.cache.keys())
|
|
883
|
+
r.startsWith(e + "_") && t.push(r);
|
|
884
|
+
for (const r of t)
|
|
885
|
+
this.cache.delete(r), this.cacheDependencies.delete(r);
|
|
886
|
+
}
|
|
887
|
+
/**
|
|
888
|
+
* Invalidates all cache entries for a specific model
|
|
889
|
+
* @param modelKey - The model key to invalidate
|
|
890
|
+
*/
|
|
891
|
+
invalidateForModel(e) {
|
|
892
|
+
this.invalidateByModels([e]);
|
|
893
|
+
}
|
|
894
|
+
/**
|
|
895
|
+
* Invalidates cache entries that depend on a specific attribute of a model
|
|
896
|
+
* @param modelKey - The model key
|
|
897
|
+
* @param attributeKey - The attribute key to invalidate
|
|
898
|
+
*/
|
|
899
|
+
invalidateForAttribute(e, t) {
|
|
900
|
+
if (!this.enabled) return;
|
|
901
|
+
const r = /* @__PURE__ */ new Map();
|
|
902
|
+
r.set(e, /* @__PURE__ */ new Set([t])), this.invalidateByDependencies(r);
|
|
903
|
+
}
|
|
904
|
+
/**
|
|
905
|
+
* Invalidates cache entries matching a custom predicate
|
|
906
|
+
* @param predicate - Function that returns true for cache keys to invalidate
|
|
907
|
+
*/
|
|
908
|
+
invalidateMatching(e) {
|
|
909
|
+
if (!this.enabled) return;
|
|
910
|
+
const t = [];
|
|
911
|
+
for (const r of this.cache.keys())
|
|
912
|
+
e(r) && t.push(r);
|
|
913
|
+
for (const r of t)
|
|
914
|
+
this.cache.delete(r), this.cacheDependencies.delete(r);
|
|
915
|
+
}
|
|
916
|
+
generateContext(e) {
|
|
917
|
+
try {
|
|
918
|
+
return y(e);
|
|
919
|
+
} catch (t) {
|
|
920
|
+
return this.log.error("Error in cache generateContext", t), e;
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
getCacheName(e, t) {
|
|
924
|
+
const r = I(t);
|
|
925
|
+
return e + "_" + r;
|
|
926
|
+
}
|
|
927
|
+
/**
|
|
928
|
+
* Gets cache statistics including hit rate
|
|
929
|
+
*/
|
|
930
|
+
getStats() {
|
|
931
|
+
const e = this.hitCount + this.missCount, t = e > 0 ? this.hitCount / e : 0;
|
|
932
|
+
return {
|
|
933
|
+
size: this.cache.size,
|
|
934
|
+
hitRate: t,
|
|
935
|
+
totalEntries: this.cache.size,
|
|
936
|
+
entriesWithDependencies: this.cacheDependencies.size,
|
|
937
|
+
hits: this.hitCount,
|
|
938
|
+
misses: this.missCount
|
|
939
|
+
};
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
const Ie = (o, e = "") => `${o}#${e}`, Qe = (o) => `${o.gt}_${o.gte}_${o.lt}_${o.lte}_${o.eq}_${o.ne}`, Me = (o) => `${o.gt}_${o.gte}_${o.lt}_${o.lte}_${o.eq}_${o.ne}`, Ne = (o, e) => {
|
|
943
|
+
const t = typeof e == "function" ? e : (r) => r[e];
|
|
944
|
+
return [
|
|
945
|
+
...o.reduce((r, s) => {
|
|
946
|
+
const i = s == null ? s : t(s);
|
|
947
|
+
return r.has(i) || r.set(i, s), r;
|
|
948
|
+
}, /* @__PURE__ */ new Map()).values()
|
|
949
|
+
];
|
|
950
|
+
}, ke = (o, e) => o.reduce(function(t, r) {
|
|
951
|
+
const s = typeof e == "function" ? e(r) : r[e];
|
|
952
|
+
return Object.prototype.hasOwnProperty.call(t, s) || (t[s] = []), t[s].push(r), t;
|
|
953
|
+
}, {});
|
|
954
|
+
function X(o = 10) {
|
|
955
|
+
let e = "";
|
|
956
|
+
const t = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
957
|
+
for (let r = 0; r < o; r++) e += t.charAt(Math.floor(Math.random() * t.length));
|
|
958
|
+
return e;
|
|
959
|
+
}
|
|
960
|
+
const Ce = (o) => o.replace(/\/+$/, ""), ee = (o) => typeof o != "string" ? "" : o.replace(/[[\]{}()*+?.,\\^$|#]/g, "\\$&"), Ee = (o) => typeof o != "string" ? "" : o.replace(/\\([[\]{}()*+?.,\\^$|#])/g, "$1"), qe = (o, e) => {
|
|
961
|
+
try {
|
|
962
|
+
return te(o, e) >= 0;
|
|
963
|
+
} catch {
|
|
964
|
+
return !1;
|
|
965
|
+
}
|
|
966
|
+
}, te = (o, e) => {
|
|
967
|
+
if (!$(o) || !$(e))
|
|
968
|
+
throw new Error(`Invalid version format: v1="${o}", v2="${e}". Expected format: "x.y.z"`);
|
|
969
|
+
const t = o.split(".").map(Number), r = e.split(".").map(Number);
|
|
970
|
+
for (let s = 0; s < 3; s++) {
|
|
971
|
+
const i = t[s] || 0, n = r[s] || 0;
|
|
972
|
+
if (i > n) return 1;
|
|
973
|
+
if (i < n) return -1;
|
|
974
|
+
}
|
|
975
|
+
return 0;
|
|
976
|
+
}, $ = (o) => /^\d+(\.\d+){0,2}$/.test(o);
|
|
977
|
+
class Oe {
|
|
978
|
+
key;
|
|
979
|
+
parentCd;
|
|
980
|
+
dcuplInitOptions;
|
|
981
|
+
analyticsController;
|
|
982
|
+
off;
|
|
983
|
+
updateListener = /* @__PURE__ */ new Set();
|
|
984
|
+
// only the "root" counter will be increased and used in the events
|
|
985
|
+
counter = 0;
|
|
986
|
+
constructor() {
|
|
987
|
+
}
|
|
988
|
+
_init(e) {
|
|
989
|
+
this.key = e.cdRefKey, this.analyticsController = e.analyticsController, this.parentCd = e.parentCd, this.dcuplInitOptions = e.dcuplInitOptions, this.parentCd && (this.off = this.parentCd.on((t) => {
|
|
990
|
+
t.action === "update" && t.originCdRefKey === this.parentCd?.key && (t.connectMessage = !1, this.trigger(t));
|
|
991
|
+
}));
|
|
992
|
+
}
|
|
993
|
+
getCounter() {
|
|
994
|
+
return this.parentCd ? this.parentCd.getCounter() : this.counter;
|
|
995
|
+
}
|
|
996
|
+
increaseCounter() {
|
|
997
|
+
this.parentCd ? this.parentCd.increaseCounter() : this.counter++;
|
|
998
|
+
}
|
|
999
|
+
destroy() {
|
|
1000
|
+
this.off && this.off();
|
|
1001
|
+
}
|
|
1002
|
+
trigger(e) {
|
|
1003
|
+
e.originCdRefKey || (e.originCdRefKey = this.key), e.key || (this.increaseCounter(), e.key = this.getCounter()), e.end || (e.end = x.now(), e.duration = e.start - e.end), this.updateListener.forEach((t) => {
|
|
1004
|
+
t(e);
|
|
1005
|
+
});
|
|
1006
|
+
}
|
|
1007
|
+
on(e) {
|
|
1008
|
+
return this.updateListener.add(e), () => {
|
|
1009
|
+
this.updateListener.delete(e);
|
|
1010
|
+
};
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
const j = (o, e) => e ? typeof structuredClone < "u" ? structuredClone(o) : y(o) : o, F = (o, e, t, r, s, i) => {
|
|
1014
|
+
try {
|
|
1015
|
+
const n = !!e.dcuplInitOptions.performance?.clone?.enabled && !!t.cloneResult, a = j(i, n);
|
|
1016
|
+
if (t.scope === "list" && (t.listKey = o.cdRef?.key || o.key, t.modelKey = o.model?.key || o.modelKey), t.type === "list_created" && t.args[0].listKey.startsWith("__global_list__") || t.listKey?.startsWith("__global_list__"))
|
|
1017
|
+
return a;
|
|
1018
|
+
const u = x.now(), c = u - r, f = Math.round(c * 1e3) / 1e3;
|
|
1019
|
+
t.duration = f, t.start = r, t.end = u;
|
|
1020
|
+
const d = {
|
|
1021
|
+
duration: t.duration
|
|
1022
|
+
};
|
|
1023
|
+
return t.modelKey && (d.model = t.modelKey), t.connectMessageResult && (t.result = a), t.args && (d.args = t.args), e?.trigger(t), e.analyticsController.mark({
|
|
1024
|
+
name: `${t.type}:end`,
|
|
1025
|
+
context: s
|
|
1026
|
+
}), e.analyticsController.measure({
|
|
1027
|
+
name: t.type,
|
|
1028
|
+
start: `${t.type}:start`,
|
|
1029
|
+
end: `${t.type}:end`,
|
|
1030
|
+
context: s,
|
|
1031
|
+
detail: d
|
|
1032
|
+
}), a;
|
|
1033
|
+
} catch {
|
|
1034
|
+
return i;
|
|
1035
|
+
}
|
|
1036
|
+
}, $e = (o) => (t, r, s) => {
|
|
1037
|
+
const i = s.value;
|
|
1038
|
+
return s.value = function(...n) {
|
|
1039
|
+
const a = x.now(), u = this.cdRef, c = j(o, !0);
|
|
1040
|
+
c.key || (u.increaseCounter(), c.key = u.getCounter());
|
|
1041
|
+
const f = X();
|
|
1042
|
+
u.analyticsController.mark({
|
|
1043
|
+
name: `${c.type}:start`,
|
|
1044
|
+
context: f
|
|
1045
|
+
});
|
|
1046
|
+
const d = this.model?.key;
|
|
1047
|
+
!c.originCdRefKey && u.key && (c.originCdRefKey = u.key), d && (c.modelKey = d);
|
|
1048
|
+
const l = i.apply(this, n);
|
|
1049
|
+
return c.method = r, c.args = n, l && typeof l == "object" && "then" in l ? l.then((h) => F(this, u, c, a, f, h)) : F(this, u, c, a, f, l);
|
|
1050
|
+
}, s;
|
|
1051
|
+
};
|
|
1052
|
+
function Fe(o, e, t, r) {
|
|
1053
|
+
t.max || (t.max = 20);
|
|
1054
|
+
const s = [], i = t.transform ? r.transformValue(t.value, t.transform) : t.value;
|
|
1055
|
+
for (const [n, a] of e.entries()) {
|
|
1056
|
+
const u = Array.from(a).some((f) => o.has(f)), c = t.transform ? r.transformValue(n, t.transform) : n;
|
|
1057
|
+
if (!(t.excludeUndefineds && typeof n > "u") && !(t.excludeNulls && n === null)) {
|
|
1058
|
+
if (u && (i === "" || i === "//")) {
|
|
1059
|
+
const f = {
|
|
1060
|
+
value: n,
|
|
1061
|
+
keys: t.calculateResultKeys ? Array.from(a) : []
|
|
1062
|
+
};
|
|
1063
|
+
s.push(f);
|
|
1064
|
+
} else if (u && typeof i == "string" && i.startsWith("/") && i.endsWith("/")) {
|
|
1065
|
+
if (r.queryFind(c, i, "some")) {
|
|
1066
|
+
const f = {
|
|
1067
|
+
value: n,
|
|
1068
|
+
keys: t.calculateResultKeys ? Array.from(a) : []
|
|
1069
|
+
};
|
|
1070
|
+
s.push(f);
|
|
1071
|
+
}
|
|
1072
|
+
} else if (u && typeof i == "string") {
|
|
1073
|
+
const f = String(c ?? ""), d = i;
|
|
1074
|
+
if (f.toLowerCase().startsWith(d.toLowerCase())) {
|
|
1075
|
+
const l = {
|
|
1076
|
+
value: n,
|
|
1077
|
+
keys: t.calculateResultKeys ? Array.from(a) : []
|
|
1078
|
+
};
|
|
1079
|
+
s.push(l);
|
|
1080
|
+
}
|
|
1081
|
+
} else if (u && r.queryFind(c, i, "some")) {
|
|
1082
|
+
const f = {
|
|
1083
|
+
value: n,
|
|
1084
|
+
keys: t.calculateResultKeys ? Array.from(a) : []
|
|
1085
|
+
};
|
|
1086
|
+
s.push(f);
|
|
1087
|
+
}
|
|
1088
|
+
if (s.length === t.max)
|
|
1089
|
+
break;
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
return s;
|
|
1093
|
+
}
|
|
1094
|
+
function re(o) {
|
|
1095
|
+
return o instanceof Date;
|
|
1096
|
+
}
|
|
1097
|
+
function se(o) {
|
|
1098
|
+
return o instanceof Date && !isNaN(o.getTime());
|
|
1099
|
+
}
|
|
1100
|
+
const ne = {
|
|
1101
|
+
yyyy: { type: "year", pattern: "yyyy", regex: "(\\d{4})" },
|
|
1102
|
+
yy: { type: "year", pattern: "yy", regex: "(\\d{2})" },
|
|
1103
|
+
MM: { type: "month", pattern: "MM", regex: "(\\d{2})" },
|
|
1104
|
+
M: { type: "month", pattern: "M", regex: "(\\d{1,2})" },
|
|
1105
|
+
dd: { type: "day", pattern: "dd", regex: "(\\d{2})" },
|
|
1106
|
+
d: { type: "day", pattern: "d", regex: "(\\d{1,2})" },
|
|
1107
|
+
HH: { type: "hour", pattern: "HH", regex: "(\\d{2})" },
|
|
1108
|
+
H: { type: "hour", pattern: "H", regex: "(\\d{1,2})" },
|
|
1109
|
+
mm: { type: "minute", pattern: "mm", regex: "(\\d{2})" },
|
|
1110
|
+
m: { type: "minute", pattern: "m", regex: "(\\d{1,2})" },
|
|
1111
|
+
ss: { type: "second", pattern: "ss", regex: "(\\d{2})" },
|
|
1112
|
+
s: { type: "second", pattern: "s", regex: "(\\d{1,2})" },
|
|
1113
|
+
SSS: { type: "millisecond", pattern: "SSS", regex: "(\\d{3})" }
|
|
1114
|
+
};
|
|
1115
|
+
function ie(o) {
|
|
1116
|
+
let e = "^";
|
|
1117
|
+
const t = [];
|
|
1118
|
+
let r = o;
|
|
1119
|
+
const s = Object.entries(ne).sort((i, n) => n[0].length - i[0].length);
|
|
1120
|
+
for (; r.length > 0; ) {
|
|
1121
|
+
let i = !1;
|
|
1122
|
+
for (const [n, a] of s)
|
|
1123
|
+
if (r.startsWith(n)) {
|
|
1124
|
+
e += a.regex, t.push({ type: a.type, pattern: n }), r = r.slice(n.length), i = !0;
|
|
1125
|
+
break;
|
|
1126
|
+
}
|
|
1127
|
+
if (!i) {
|
|
1128
|
+
const n = r[0];
|
|
1129
|
+
if (!n)
|
|
1130
|
+
break;
|
|
1131
|
+
e += n.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), r = r.slice(1);
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
return e += "$", { regex: new RegExp(e), tokenOrder: t };
|
|
1135
|
+
}
|
|
1136
|
+
function oe(o, e) {
|
|
1137
|
+
const t = {
|
|
1138
|
+
year: 1970,
|
|
1139
|
+
month: 1,
|
|
1140
|
+
day: 1,
|
|
1141
|
+
hour: 0,
|
|
1142
|
+
minute: 0,
|
|
1143
|
+
second: 0,
|
|
1144
|
+
millisecond: 0
|
|
1145
|
+
};
|
|
1146
|
+
for (let r = 0; r < e.length; r++) {
|
|
1147
|
+
const s = o[r + 1];
|
|
1148
|
+
if (!s)
|
|
1149
|
+
continue;
|
|
1150
|
+
const i = parseInt(s, 10), n = e[r];
|
|
1151
|
+
n && (n.type === "year" && n.pattern === "yy" ? t.year = 2e3 + i : t[n.type] = i);
|
|
1152
|
+
}
|
|
1153
|
+
return t;
|
|
1154
|
+
}
|
|
1155
|
+
function ae(o) {
|
|
1156
|
+
if (o.month < 1 || o.month > 12)
|
|
1157
|
+
return /* @__PURE__ */ new Date(NaN);
|
|
1158
|
+
if (o.day < 1 || o.day > 31)
|
|
1159
|
+
return /* @__PURE__ */ new Date(NaN);
|
|
1160
|
+
if (o.hour < 0 || o.hour > 23)
|
|
1161
|
+
return /* @__PURE__ */ new Date(NaN);
|
|
1162
|
+
if (o.minute < 0 || o.minute > 59)
|
|
1163
|
+
return /* @__PURE__ */ new Date(NaN);
|
|
1164
|
+
if (o.second < 0 || o.second > 59)
|
|
1165
|
+
return /* @__PURE__ */ new Date(NaN);
|
|
1166
|
+
if (o.millisecond < 0 || o.millisecond > 999)
|
|
1167
|
+
return /* @__PURE__ */ new Date(NaN);
|
|
1168
|
+
const e = new Date(
|
|
1169
|
+
o.year,
|
|
1170
|
+
o.month - 1,
|
|
1171
|
+
o.day,
|
|
1172
|
+
o.hour,
|
|
1173
|
+
o.minute,
|
|
1174
|
+
o.second,
|
|
1175
|
+
o.millisecond
|
|
1176
|
+
);
|
|
1177
|
+
return se(e) ? e.getFullYear() !== o.year || e.getMonth() !== o.month - 1 || e.getDate() !== o.day ? /* @__PURE__ */ new Date(NaN) : e : /* @__PURE__ */ new Date(NaN);
|
|
1178
|
+
}
|
|
1179
|
+
function Ge(o, e, t) {
|
|
1180
|
+
if (o = o.trim(), e === "t") {
|
|
1181
|
+
const a = Number(o);
|
|
1182
|
+
return isNaN(a) ? /* @__PURE__ */ new Date(NaN) : new Date(a * 1e3);
|
|
1183
|
+
}
|
|
1184
|
+
if (e === "T") {
|
|
1185
|
+
const a = Number(o);
|
|
1186
|
+
return isNaN(a) ? /* @__PURE__ */ new Date(NaN) : new Date(a);
|
|
1187
|
+
}
|
|
1188
|
+
const { regex: r, tokenOrder: s } = ie(e), i = o.match(r);
|
|
1189
|
+
if (!i)
|
|
1190
|
+
return /* @__PURE__ */ new Date(NaN);
|
|
1191
|
+
const n = oe(i, s);
|
|
1192
|
+
return ae(n);
|
|
1193
|
+
}
|
|
1194
|
+
class ue {
|
|
1195
|
+
cache;
|
|
1196
|
+
maxSize;
|
|
1197
|
+
accessOrder;
|
|
1198
|
+
constructor(e) {
|
|
1199
|
+
this.cache = /* @__PURE__ */ new Map(), this.maxSize = e, this.accessOrder = [];
|
|
1200
|
+
}
|
|
1201
|
+
get(e) {
|
|
1202
|
+
const t = this.cache.get(e);
|
|
1203
|
+
return t !== void 0 && this.updateAccessOrder(e), t;
|
|
1204
|
+
}
|
|
1205
|
+
set(e, t) {
|
|
1206
|
+
if (this.cache.has(e))
|
|
1207
|
+
this.cache.set(e, t), this.updateAccessOrder(e);
|
|
1208
|
+
else {
|
|
1209
|
+
if (this.cache.size >= this.maxSize) {
|
|
1210
|
+
const r = this.accessOrder.shift();
|
|
1211
|
+
r !== void 0 && this.cache.delete(r);
|
|
1212
|
+
}
|
|
1213
|
+
this.cache.set(e, t), this.accessOrder.push(e);
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
has(e) {
|
|
1217
|
+
return this.cache.has(e);
|
|
1218
|
+
}
|
|
1219
|
+
clear() {
|
|
1220
|
+
this.cache.clear(), this.accessOrder = [];
|
|
1221
|
+
}
|
|
1222
|
+
get size() {
|
|
1223
|
+
return this.cache.size;
|
|
1224
|
+
}
|
|
1225
|
+
updateAccessOrder(e) {
|
|
1226
|
+
const t = this.accessOrder.indexOf(e);
|
|
1227
|
+
t > -1 && this.accessOrder.splice(t, 1), this.accessOrder.push(e);
|
|
1228
|
+
}
|
|
1229
|
+
// For testing/debugging
|
|
1230
|
+
getStats() {
|
|
1231
|
+
return {
|
|
1232
|
+
size: this.cache.size,
|
|
1233
|
+
maxSize: this.maxSize
|
|
1234
|
+
};
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
class ce {
|
|
1238
|
+
graph;
|
|
1239
|
+
constructor() {
|
|
1240
|
+
this.graph = /* @__PURE__ */ new Map();
|
|
1241
|
+
}
|
|
1242
|
+
addDependency(e, t) {
|
|
1243
|
+
this.graph.has(e) || this.graph.set(e, /* @__PURE__ */ new Set()), this.graph.get(e).add(t);
|
|
1244
|
+
}
|
|
1245
|
+
hasCycle(e) {
|
|
1246
|
+
if (e.length === 0) return !1;
|
|
1247
|
+
const t = /* @__PURE__ */ new Set(), r = /* @__PURE__ */ new Set(), s = (i) => {
|
|
1248
|
+
t.add(i), r.add(i);
|
|
1249
|
+
const n = this.graph.get(i);
|
|
1250
|
+
if (n) {
|
|
1251
|
+
for (const a of n)
|
|
1252
|
+
if (t.has(a)) {
|
|
1253
|
+
if (r.has(a))
|
|
1254
|
+
return !0;
|
|
1255
|
+
} else if (s(a))
|
|
1256
|
+
return !0;
|
|
1257
|
+
}
|
|
1258
|
+
return r.delete(i), !1;
|
|
1259
|
+
};
|
|
1260
|
+
for (let i = 0; i < e.length - 1; i++) {
|
|
1261
|
+
const n = e[i], a = e[i + 1];
|
|
1262
|
+
n && a && this.addDependency(n, a);
|
|
1263
|
+
}
|
|
1264
|
+
for (const i of e)
|
|
1265
|
+
if (!t.has(i) && s(i))
|
|
1266
|
+
return !0;
|
|
1267
|
+
return !1;
|
|
1268
|
+
}
|
|
1269
|
+
clear() {
|
|
1270
|
+
this.graph.clear();
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
class fe {
|
|
1274
|
+
parseCache;
|
|
1275
|
+
circularRefDetector;
|
|
1276
|
+
cacheHits = 0;
|
|
1277
|
+
cacheMisses = 0;
|
|
1278
|
+
constructor(e = 1e3) {
|
|
1279
|
+
this.parseCache = new ue(e), this.circularRefDetector = new ce();
|
|
1280
|
+
}
|
|
1281
|
+
/**
|
|
1282
|
+
* Parse an attribute string into its components
|
|
1283
|
+
*
|
|
1284
|
+
* Supports:
|
|
1285
|
+
* - Dot notation: `customer.name`
|
|
1286
|
+
* - Bracket notation: `items[0].price`, `items[*].price`
|
|
1287
|
+
* - Multi-level: `order.customer.address.city`
|
|
1288
|
+
*
|
|
1289
|
+
* @param attribute - The attribute path to parse
|
|
1290
|
+
* @returns QueryAttributeEntry with isDeepQuery, reference, referenceAttribute
|
|
1291
|
+
*
|
|
1292
|
+
* @example
|
|
1293
|
+
* ```typescript
|
|
1294
|
+
* const service = new DeepQueryService();
|
|
1295
|
+
* const entry = service.parse('customer.name');
|
|
1296
|
+
* // Returns: { attribute: 'customer.name', isDeepQuery: true, reference: 'customer', referenceAttribute: 'name' }
|
|
1297
|
+
* ```
|
|
1298
|
+
*/
|
|
1299
|
+
parse(e) {
|
|
1300
|
+
if (this.parseCache.has(e))
|
|
1301
|
+
return this.cacheHits++, this.parseCache.get(e);
|
|
1302
|
+
this.cacheMisses++;
|
|
1303
|
+
let t, r;
|
|
1304
|
+
const s = e.includes("."), i = e.includes("["), n = s || i;
|
|
1305
|
+
if (n)
|
|
1306
|
+
if (r = e.split(/[.[]/)[0], i) {
|
|
1307
|
+
const u = e.indexOf("]");
|
|
1308
|
+
if (u > -1) {
|
|
1309
|
+
const c = e.indexOf(".", u + 1);
|
|
1310
|
+
c > -1 ? t = e.substring(c + 1) : t = void 0;
|
|
1311
|
+
} else s && (t = e.substring(e.indexOf(".") + 1));
|
|
1312
|
+
} else s && (t = e.substring(e.indexOf(".") + 1));
|
|
1313
|
+
const a = {
|
|
1314
|
+
attribute: e,
|
|
1315
|
+
isDeepQuery: n
|
|
1316
|
+
};
|
|
1317
|
+
return r && (a.reference = r), typeof t < "u" && t !== "" && (a.referenceAttribute = t), this.parseCache.set(e, a), a;
|
|
1318
|
+
}
|
|
1319
|
+
/**
|
|
1320
|
+
* Detect circular references in a path
|
|
1321
|
+
*
|
|
1322
|
+
* Checks for:
|
|
1323
|
+
* - Direct circular: A→B→A
|
|
1324
|
+
* - Indirect circular: A→B→C→A
|
|
1325
|
+
* - Self-referential: A→A
|
|
1326
|
+
*
|
|
1327
|
+
* @param path - Array of model/reference keys in the dependency chain
|
|
1328
|
+
* @returns true if circular reference detected
|
|
1329
|
+
*
|
|
1330
|
+
* @example
|
|
1331
|
+
* ```typescript
|
|
1332
|
+
* const service = new DeepQueryService();
|
|
1333
|
+
* const hasCircular = service.detectCircular(['Order', 'Customer', 'Order']);
|
|
1334
|
+
* // Returns: true
|
|
1335
|
+
* ```
|
|
1336
|
+
*/
|
|
1337
|
+
detectCircular(e) {
|
|
1338
|
+
return e.length === 0 ? !1 : new Set(e).size !== e.length ? !0 : this.circularRefDetector.hasCycle(e);
|
|
1339
|
+
}
|
|
1340
|
+
/**
|
|
1341
|
+
* Validate attribute path syntax
|
|
1342
|
+
*
|
|
1343
|
+
* Checks for:
|
|
1344
|
+
* - Empty strings
|
|
1345
|
+
* - Malformed bracket notation
|
|
1346
|
+
* - Invalid characters
|
|
1347
|
+
* - Excessive nesting depth
|
|
1348
|
+
*
|
|
1349
|
+
* @param attribute - The attribute path to validate
|
|
1350
|
+
* @param maxDepth - Maximum allowed nesting depth (default: 10)
|
|
1351
|
+
* @returns ValidationResult with errors if invalid
|
|
1352
|
+
*
|
|
1353
|
+
* @example
|
|
1354
|
+
* ```typescript
|
|
1355
|
+
* const service = new DeepQueryService();
|
|
1356
|
+
* const result = service.validatePath('customer.name');
|
|
1357
|
+
* // Returns: { valid: true }
|
|
1358
|
+
*
|
|
1359
|
+
* const badResult = service.validatePath('customer.[invalid]');
|
|
1360
|
+
* // Returns: { valid: false, errors: ['Invalid bracket notation: customer.[invalid]'] }
|
|
1361
|
+
* ```
|
|
1362
|
+
*/
|
|
1363
|
+
validatePath(e, t = 10) {
|
|
1364
|
+
const r = [];
|
|
1365
|
+
if (!e || e.trim().length === 0)
|
|
1366
|
+
return r.push("Attribute path cannot be empty"), { valid: !1, errors: r };
|
|
1367
|
+
(e.startsWith(".") || e.endsWith(".")) && r.push(`Invalid path: Leading or trailing dots are not allowed: ${e}`), e.includes("..") && r.push(`Invalid path: Consecutive dots are not allowed: ${e}`);
|
|
1368
|
+
const s = (e.match(/\[/g) || []).length, i = (e.match(/]/g) || []).length;
|
|
1369
|
+
s !== i && r.push(`Invalid bracket notation: Mismatched brackets in ${e}`), e.includes("[]") && r.push(`Invalid bracket notation: Empty brackets not allowed: ${e}`);
|
|
1370
|
+
const n = /\[([^\]]+)\]/g;
|
|
1371
|
+
let a;
|
|
1372
|
+
for (; (a = n.exec(e)) !== null; ) {
|
|
1373
|
+
const f = a[1];
|
|
1374
|
+
f && f !== "*" && !/^\d+$/.test(f) && r.push(`Invalid bracket content: Must be a number or '*', got '${f}' in ${e}`);
|
|
1375
|
+
}
|
|
1376
|
+
const u = (e.match(/\./g) || []).length + 1;
|
|
1377
|
+
u > t && r.push(`Path too deep: Maximum depth is ${t}, got ${u} in ${e}`);
|
|
1378
|
+
const c = e.match(/[^a-zA-Z0-9._[\]*-]/g);
|
|
1379
|
+
return c && r.push(`Invalid characters in path: ${c.join(", ")} in ${e}`), {
|
|
1380
|
+
valid: r.length === 0,
|
|
1381
|
+
errors: r.length > 0 ? r : void 0
|
|
1382
|
+
};
|
|
1383
|
+
}
|
|
1384
|
+
/**
|
|
1385
|
+
* Clear the parse cache
|
|
1386
|
+
* Should be called when models are updated or removed
|
|
1387
|
+
*/
|
|
1388
|
+
clearCache() {
|
|
1389
|
+
this.parseCache.clear(), this.cacheHits = 0, this.cacheMisses = 0;
|
|
1390
|
+
}
|
|
1391
|
+
/**
|
|
1392
|
+
* Clear the circular reference detector
|
|
1393
|
+
*/
|
|
1394
|
+
clearCircularDetector() {
|
|
1395
|
+
this.circularRefDetector.clear();
|
|
1396
|
+
}
|
|
1397
|
+
/**
|
|
1398
|
+
* Get cache statistics for monitoring and debugging
|
|
1399
|
+
*
|
|
1400
|
+
* @returns Object containing cache size, hit rate, and other metrics
|
|
1401
|
+
*/
|
|
1402
|
+
getCacheStats() {
|
|
1403
|
+
const e = this.parseCache.getStats(), t = this.cacheHits + this.cacheMisses, r = t > 0 ? this.cacheHits / t : 0;
|
|
1404
|
+
return {
|
|
1405
|
+
...e,
|
|
1406
|
+
hits: this.cacheHits,
|
|
1407
|
+
misses: this.cacheMisses,
|
|
1408
|
+
hitRate: r
|
|
1409
|
+
};
|
|
1410
|
+
}
|
|
1411
|
+
/**
|
|
1412
|
+
* Extract path segments from an attribute string
|
|
1413
|
+
* Useful for analyzing deep query structure
|
|
1414
|
+
*
|
|
1415
|
+
* @param attribute - The attribute path
|
|
1416
|
+
* @returns Array of path segments
|
|
1417
|
+
*
|
|
1418
|
+
* @example
|
|
1419
|
+
* ```typescript
|
|
1420
|
+
* const service = new DeepQueryService();
|
|
1421
|
+
* const segments = service.getPathSegments('order.customer.name');
|
|
1422
|
+
* // Returns: ['order', 'customer', 'name']
|
|
1423
|
+
* ```
|
|
1424
|
+
*/
|
|
1425
|
+
getPathSegments(e) {
|
|
1426
|
+
return e.replace(/\[[^\]]+\]/g, "").split(".").filter((r) => r.length > 0);
|
|
1427
|
+
}
|
|
1428
|
+
/**
|
|
1429
|
+
* Get the depth of a deep query path
|
|
1430
|
+
*
|
|
1431
|
+
* @param attribute - The attribute path
|
|
1432
|
+
* @returns Depth of the path (1 for shallow, 2+ for deep)
|
|
1433
|
+
*/
|
|
1434
|
+
getPathDepth(e) {
|
|
1435
|
+
return this.getPathSegments(e).length;
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1438
|
+
const g = new fe();
|
|
1439
|
+
function D(o) {
|
|
1440
|
+
let e = 0;
|
|
1441
|
+
for (let t of o) {
|
|
1442
|
+
const r = t.toString().split(".")[1];
|
|
1443
|
+
r && (e = Math.max(e, r.length));
|
|
1444
|
+
}
|
|
1445
|
+
return Math.pow(10, e);
|
|
1446
|
+
}
|
|
1447
|
+
function G(o, e, t) {
|
|
1448
|
+
return (o * t + e * t) / t;
|
|
1449
|
+
}
|
|
1450
|
+
function de(o, e, t) {
|
|
1451
|
+
return o * t / (e * t);
|
|
1452
|
+
}
|
|
1453
|
+
const Q = (o, e, t, r) => {
|
|
1454
|
+
if (!r)
|
|
1455
|
+
throw new Error("Attribute not found");
|
|
1456
|
+
const s = {
|
|
1457
|
+
attribute: r,
|
|
1458
|
+
types: o.types
|
|
1459
|
+
};
|
|
1460
|
+
let i;
|
|
1461
|
+
(s.types.includes("sum") || s.types.includes("avg") || s.types.includes("count")) && (i = pe(r, e));
|
|
1462
|
+
let n;
|
|
1463
|
+
return (s.types.includes("min") || s.types.includes("max")) && (n = le(r, e)), o.types.forEach((a) => {
|
|
1464
|
+
a === "sum" ? s.sum = i?.sum : a === "avg" ? s.avg = i?.average : a === "count" ? s.count = i?.count : a === "min" ? s.min = n && n[0] : a === "max" ? s.max = n && n[1] : a === "distinct" ? s.distinct = ge(o, e, t) : a === "group" && (s.group = he(o, e));
|
|
1465
|
+
}), s;
|
|
1466
|
+
}, le = (o, e) => {
|
|
1467
|
+
let t, r;
|
|
1468
|
+
const i = g.parse(o).isDeepQuery;
|
|
1469
|
+
for (const n of e.values())
|
|
1470
|
+
if (n) {
|
|
1471
|
+
const a = i ? v(n, o) : n[o];
|
|
1472
|
+
(t === void 0 || a < t) && (t = a), (r === void 0 || a > r) && (r = a);
|
|
1473
|
+
}
|
|
1474
|
+
if (!(t === void 0 || r === void 0))
|
|
1475
|
+
return [t, r];
|
|
1476
|
+
}, he = (o, e) => {
|
|
1477
|
+
const t = [];
|
|
1478
|
+
o.groupOptions?.groups?.forEach((n) => {
|
|
1479
|
+
t.push({
|
|
1480
|
+
option: n,
|
|
1481
|
+
count: 0,
|
|
1482
|
+
keys: []
|
|
1483
|
+
});
|
|
1484
|
+
});
|
|
1485
|
+
const r = {
|
|
1486
|
+
option: { value: ["$dcupl_not_found"] },
|
|
1487
|
+
count: 0,
|
|
1488
|
+
keys: []
|
|
1489
|
+
}, i = g.parse(o.attribute).isDeepQuery;
|
|
1490
|
+
for (const n of e.values()) {
|
|
1491
|
+
const a = i ? v(n, o.attribute) : n[o.attribute];
|
|
1492
|
+
for (const u of t)
|
|
1493
|
+
typeof u.option.value < "u" && u.option.value.includes(a) || typeof u.option.from < "u" && u.option.from < a && typeof u.option.to < "u" && u.option.to > a ? (u.count++, u.keys.push(n.key)) : o?.groupOptions?.calculateNotFound && (r.count++, r.keys.push(n.key));
|
|
1494
|
+
}
|
|
1495
|
+
return o?.groupOptions?.calculateNotFound && t.push(r), t;
|
|
1496
|
+
}, pe = (o, e) => {
|
|
1497
|
+
let t = 0, r = 0;
|
|
1498
|
+
const i = g.parse(o).isDeepQuery;
|
|
1499
|
+
for (const u of e.values()) {
|
|
1500
|
+
if (!u) continue;
|
|
1501
|
+
const c = i ? v(u, o) : u[o];
|
|
1502
|
+
if (Array.isArray(c))
|
|
1503
|
+
for (const f of c)
|
|
1504
|
+
typeof f == "number" && (t = G(t, f, D([t, f])), r++);
|
|
1505
|
+
else typeof c == "number" && (t = G(t, c, D([t, c])), r++);
|
|
1506
|
+
}
|
|
1507
|
+
return r === 0 || r === 0 ? void 0 : {
|
|
1508
|
+
average: de(t, r, D([t, r])),
|
|
1509
|
+
count: e.size,
|
|
1510
|
+
sum: t
|
|
1511
|
+
};
|
|
1512
|
+
}, ge = (o, e, t) => {
|
|
1513
|
+
const r = [];
|
|
1514
|
+
for (const [s, i] of t)
|
|
1515
|
+
if (!(o.excludeUndefineds && typeof s > "u") && Array.from(i).find((n) => e.has(n))) {
|
|
1516
|
+
const n = {
|
|
1517
|
+
value: s,
|
|
1518
|
+
count: i.size
|
|
1519
|
+
};
|
|
1520
|
+
if (o.distinctOptions?.skipKeys || (n.keys = Array.from(i)), r.push(n), o.distinctOptions?.limit && r.length >= o.distinctOptions.limit)
|
|
1521
|
+
break;
|
|
1522
|
+
}
|
|
1523
|
+
return r;
|
|
1524
|
+
};
|
|
1525
|
+
class w extends Error {
|
|
1526
|
+
query;
|
|
1527
|
+
constructor(e, t) {
|
|
1528
|
+
const r = `Query Error: ${e} in ${JSON.stringify(t, null, 2)}`;
|
|
1529
|
+
super(r), this.query = t, this.name = "DcuplQueryError";
|
|
1530
|
+
}
|
|
1531
|
+
}
|
|
1532
|
+
class P {
|
|
1533
|
+
_defaultQueryOptions = {
|
|
1534
|
+
modelKey: "",
|
|
1535
|
+
groupKey: "root",
|
|
1536
|
+
groupType: "and",
|
|
1537
|
+
queries: []
|
|
1538
|
+
};
|
|
1539
|
+
_initOptions;
|
|
1540
|
+
currentQuery = y(this._defaultQueryOptions);
|
|
1541
|
+
deepQueryService;
|
|
1542
|
+
constructor(e) {
|
|
1543
|
+
this.deepQueryService = e || g;
|
|
1544
|
+
}
|
|
1545
|
+
/**
|
|
1546
|
+
* Initialize the query builder.
|
|
1547
|
+
* Accepts either minimal options with just modelKey, or a complete query object.
|
|
1548
|
+
*
|
|
1549
|
+
* @param options - Minimal { modelKey } or full DcuplGlobalQueryOptions
|
|
1550
|
+
*
|
|
1551
|
+
* @example
|
|
1552
|
+
* // Minimal initialization
|
|
1553
|
+
* builder.init({ modelKey: 'Product' });
|
|
1554
|
+
*
|
|
1555
|
+
* @example
|
|
1556
|
+
* // Full query initialization
|
|
1557
|
+
* builder.init({
|
|
1558
|
+
* modelKey: 'Product',
|
|
1559
|
+
* groupType: 'and',
|
|
1560
|
+
* queries: [
|
|
1561
|
+
* { operator: 'eq', attribute: 'status', value: 'active' },
|
|
1562
|
+
* { operator: 'gte', attribute: 'price', value: 100 }
|
|
1563
|
+
* ],
|
|
1564
|
+
* count: 10,
|
|
1565
|
+
* sort: { price: 'asc' }
|
|
1566
|
+
* });
|
|
1567
|
+
*/
|
|
1568
|
+
init(e) {
|
|
1569
|
+
this._initOptions = y(e), this.currentQuery = y(this._defaultQueryOptions), this.currentQuery.modelKey = e.modelKey, "queries" in e && Array.isArray(e.queries) && (e.groupType && (this.currentQuery.groupType = e.groupType), e.queries && (this.currentQuery.queries = y(e.queries)), e.count !== void 0 && (this.currentQuery.count = e.count), e.start !== void 0 && (this.currentQuery.start = e.start), e.sort && (this.currentQuery.sort = e.sort), e.projection && (this.currentQuery.projection = e.projection));
|
|
1570
|
+
}
|
|
1571
|
+
reset() {
|
|
1572
|
+
return this.init(this._initOptions), this.getQuery();
|
|
1573
|
+
}
|
|
1574
|
+
isQuery(e) {
|
|
1575
|
+
return "attribute" in e;
|
|
1576
|
+
}
|
|
1577
|
+
isQueryGroup(e) {
|
|
1578
|
+
return "groupKey" in e;
|
|
1579
|
+
}
|
|
1580
|
+
isRootQueryGroup(e) {
|
|
1581
|
+
return this.isQueryGroup(e) && e.groupKey === "root";
|
|
1582
|
+
}
|
|
1583
|
+
getQueryGroup(e) {
|
|
1584
|
+
return this.currentQuery.queries.find((t) => this.isQueryGroup(t) && t.groupKey === e);
|
|
1585
|
+
}
|
|
1586
|
+
getQuery() {
|
|
1587
|
+
return y(this.currentQuery);
|
|
1588
|
+
}
|
|
1589
|
+
hasQueryGroup(e) {
|
|
1590
|
+
return this.currentQuery.queries.some((t) => this.isQueryGroup(t) && t.groupKey === e);
|
|
1591
|
+
}
|
|
1592
|
+
has(e) {
|
|
1593
|
+
if (e.groupKey && e.queryKey) {
|
|
1594
|
+
const t = this.getQueryGroup(e.groupKey);
|
|
1595
|
+
if (t)
|
|
1596
|
+
return t.queries.some((r) => this.isQuery(r) && r.queryKey === e.queryKey);
|
|
1597
|
+
} else if (e.groupKey)
|
|
1598
|
+
return this.hasQueryGroup(e.groupKey);
|
|
1599
|
+
return !1;
|
|
1600
|
+
}
|
|
1601
|
+
validate(e) {
|
|
1602
|
+
const t = e.queries.map((s) => this.validateQuery(s));
|
|
1603
|
+
return { valid: B(t, (s) => s.valid), errors: t.map((s) => s.errors).flat() };
|
|
1604
|
+
}
|
|
1605
|
+
applyOptions(e, t = "update") {
|
|
1606
|
+
return t === "set" ? (this.currentQuery.count = e.count, this.currentQuery.start = e.start, this.currentQuery.sort = e.sort, this.currentQuery.projection = e.projection) : (typeof e?.sort < "u" && (this.currentQuery.sort = e.sort), typeof e?.count < "u" && (this.currentQuery.count = e.count), typeof e?.start < "u" && (this.currentQuery.start = e?.start), typeof e?.projection < "u" && (this.currentQuery.projection = e?.projection)), this.getQuery();
|
|
1607
|
+
}
|
|
1608
|
+
/**
|
|
1609
|
+
* Apply query conditions, groups, or complete queries.
|
|
1610
|
+
* This method has implicit behavior based on input type.
|
|
1611
|
+
*
|
|
1612
|
+
* @deprecated Use explicit methods instead for clearer intent:
|
|
1613
|
+
* - {@link addCondition} - Add single condition
|
|
1614
|
+
* - {@link addConditions} - Add multiple conditions
|
|
1615
|
+
* - {@link addGroup} - Add query group
|
|
1616
|
+
* - {@link setCondition} - Replace condition
|
|
1617
|
+
* - {@link setConditions} - Replace conditions
|
|
1618
|
+
* - {@link setGroup} - Replace query group
|
|
1619
|
+
* - {@link mergeQuery} - Merge complete query
|
|
1620
|
+
* - {@link replaceQuery} - Replace complete query
|
|
1621
|
+
*
|
|
1622
|
+
* @param queryToApply - Query, condition, or array to apply
|
|
1623
|
+
* @param options - Mode: 'add' (default) or 'set' (replace)
|
|
1624
|
+
* @param relevantQuery - Target query (defaults to current)
|
|
1625
|
+
* @returns Updated query
|
|
1626
|
+
*/
|
|
1627
|
+
applyQuery(e, t, r) {
|
|
1628
|
+
if (r || (r = this.currentQuery), Array.isArray(e))
|
|
1629
|
+
for (const s of e)
|
|
1630
|
+
this.applyQuery(s, t, r);
|
|
1631
|
+
else if (this.isRootQueryGroup(e))
|
|
1632
|
+
e.groupType && (r.groupType = e.groupType), t?.mode === "set" ? r.queries = e.queries : r.queries = [...r.queries, ...e.queries], this.applyOptions(e, "set");
|
|
1633
|
+
else if (this.isQuery(e)) {
|
|
1634
|
+
const s = r.queries.findIndex(
|
|
1635
|
+
(i) => this.isQueryGroup(i) && i.groupKey === e.attribute
|
|
1636
|
+
);
|
|
1637
|
+
if (s > -1) {
|
|
1638
|
+
const i = r.queries[s];
|
|
1639
|
+
t?.mode === "set" ? i.queries = [e] : i.queries.push(e);
|
|
1640
|
+
} else
|
|
1641
|
+
r.queries.push({
|
|
1642
|
+
groupKey: e.attribute,
|
|
1643
|
+
groupType: "or",
|
|
1644
|
+
queries: [e]
|
|
1645
|
+
});
|
|
1646
|
+
} else if (this.isQueryGroup(e)) {
|
|
1647
|
+
const s = r.queries.findIndex(
|
|
1648
|
+
(i) => this.isQueryGroup(i) && i.groupKey === e.groupKey
|
|
1649
|
+
);
|
|
1650
|
+
if (s > -1) {
|
|
1651
|
+
const i = r.queries[s];
|
|
1652
|
+
e.groupType && (i.groupType = e.groupType), t?.mode === "set" ? r.queries[s] = e : i.queries = [...i.queries, ...e.queries];
|
|
1653
|
+
} else
|
|
1654
|
+
r.queries.push({
|
|
1655
|
+
groupKey: e.groupKey,
|
|
1656
|
+
groupType: e.groupType || "or",
|
|
1657
|
+
queries: e.queries
|
|
1658
|
+
// options: queryToApply.options,
|
|
1659
|
+
});
|
|
1660
|
+
}
|
|
1661
|
+
return r;
|
|
1662
|
+
}
|
|
1663
|
+
/**
|
|
1664
|
+
* Remove all query conditions.
|
|
1665
|
+
*
|
|
1666
|
+
* @deprecated Use {@link clearConditions} for clearer intent.
|
|
1667
|
+
* @returns Query with no conditions
|
|
1668
|
+
*/
|
|
1669
|
+
removeAllQueries() {
|
|
1670
|
+
return this.currentQuery.queries = [], this.getQuery();
|
|
1671
|
+
}
|
|
1672
|
+
/**
|
|
1673
|
+
* Remove a specific query or query group.
|
|
1674
|
+
*
|
|
1675
|
+
* @param queryToRemove - Query or group to remove (partial match)
|
|
1676
|
+
* @param relevantQuery - Target query (defaults to current)
|
|
1677
|
+
* @returns Updated query
|
|
1678
|
+
*/
|
|
1679
|
+
removeQuery(e, t) {
|
|
1680
|
+
if (t || (t = this.currentQuery), this.isQuery(e)) {
|
|
1681
|
+
const r = t.queries.findIndex(
|
|
1682
|
+
(s) => this.isQueryGroup(s) && s.groupKey === e.attribute
|
|
1683
|
+
);
|
|
1684
|
+
if (r > -1) {
|
|
1685
|
+
const s = t.queries[r], i = C(s.queries, e);
|
|
1686
|
+
i > -1 && s.queries.splice(i, 1), s.queries.length === 0 && t.queries.splice(r, 1);
|
|
1687
|
+
}
|
|
1688
|
+
} else if (this.isQueryGroup(e)) {
|
|
1689
|
+
const r = t.queries.findIndex(
|
|
1690
|
+
(s) => this.isQueryGroup(s) && s.groupKey === e.groupKey
|
|
1691
|
+
);
|
|
1692
|
+
if (r > -1)
|
|
1693
|
+
if (!e.queries)
|
|
1694
|
+
t.queries.splice(r, 1);
|
|
1695
|
+
else {
|
|
1696
|
+
const s = t.queries[r];
|
|
1697
|
+
for (const i of e.queries) {
|
|
1698
|
+
const n = C(s.queries, i);
|
|
1699
|
+
n > -1 && s.queries.splice(n, 1);
|
|
1700
|
+
}
|
|
1701
|
+
s.queries.length === 0 && t.queries.splice(r, 1);
|
|
1702
|
+
}
|
|
1703
|
+
}
|
|
1704
|
+
return t;
|
|
1705
|
+
}
|
|
1706
|
+
validateQuery(e) {
|
|
1707
|
+
const t = [];
|
|
1708
|
+
if (this.isQuery(e))
|
|
1709
|
+
return e.attribute || t.push(new w("Missing attribute", e)), e.operator || t.push(new w("Missing operator", e)), typeof e.value > "u" && t.push(new w("Missing value", e)), e.operator === "find" && Array.isArray(e.value) && t.push(new w("find operator cannot have array value", e)), t.length > 0 ? { valid: !1, errors: t } : { valid: !0 };
|
|
1710
|
+
if (this.isQueryGroup(e)) {
|
|
1711
|
+
const i = e.queries.map((n) => this.validateQuery(n)).filter((n) => !n.valid).map((n) => n.errors).flat();
|
|
1712
|
+
return i.length > 0 ? { valid: !1, errors: i } : { valid: !0 };
|
|
1713
|
+
}
|
|
1714
|
+
return t.push(new w("Invalid query definition", e)), { valid: !1, errors: t };
|
|
1715
|
+
}
|
|
1716
|
+
/**
|
|
1717
|
+
* Get all attribute names used in the query.
|
|
1718
|
+
*
|
|
1719
|
+
* @deprecated Use {@link getAttributeNames} for clearer naming.
|
|
1720
|
+
* @param query - Optional query to analyze
|
|
1721
|
+
* @returns Array of attribute names
|
|
1722
|
+
*/
|
|
1723
|
+
getQueryAttributes(e) {
|
|
1724
|
+
const t = [], r = /* @__PURE__ */ new Set(), s = (i) => {
|
|
1725
|
+
for (const n of i)
|
|
1726
|
+
this.isQuery(n) ? n.attribute && !r.has(n.attribute) && (t.push(n.attribute), r.add(n.attribute)) : this.isQueryGroup(n) && s(n.queries);
|
|
1727
|
+
};
|
|
1728
|
+
return s(e?.queries || this.currentQuery.queries), t;
|
|
1729
|
+
}
|
|
1730
|
+
/**
|
|
1731
|
+
* Extract detailed attribute information from query.
|
|
1732
|
+
*
|
|
1733
|
+
* @deprecated Use {@link getAttributeDetails} for clearer naming.
|
|
1734
|
+
* @param query - Query to analyze
|
|
1735
|
+
* @returns Array of QueryAttributeEntry objects
|
|
1736
|
+
*/
|
|
1737
|
+
extractQueryAttributes(e) {
|
|
1738
|
+
const t = [], r = /* @__PURE__ */ new Set(), s = (i) => {
|
|
1739
|
+
for (const n of i)
|
|
1740
|
+
if (this.isQuery(n)) {
|
|
1741
|
+
if (n.attribute && !r.has(n.attribute)) {
|
|
1742
|
+
const a = this.getQueryAttributeForString(n.attribute);
|
|
1743
|
+
t.push(a), r.add(n.attribute);
|
|
1744
|
+
}
|
|
1745
|
+
} else this.isQueryGroup(n) && s(n.queries);
|
|
1746
|
+
};
|
|
1747
|
+
return s(e?.queries || this.currentQuery.queries), t;
|
|
1748
|
+
}
|
|
1749
|
+
/**
|
|
1750
|
+
* Parse an attribute string into its components using the DeepQueryService
|
|
1751
|
+
* This method now delegates to the centralized DeepQueryService for consistent
|
|
1752
|
+
* parsing, caching, and validation across the codebase.
|
|
1753
|
+
*
|
|
1754
|
+
* @param attribute - The attribute path to parse (e.g., 'customer.name', 'items[0].price')
|
|
1755
|
+
* @returns QueryAttributeEntry with isDeepQuery, reference, referenceAttribute
|
|
1756
|
+
*/
|
|
1757
|
+
getQueryAttributeForString(e) {
|
|
1758
|
+
return this.deepQueryService.parse(e);
|
|
1759
|
+
}
|
|
1760
|
+
/**
|
|
1761
|
+
* Get the DeepQueryService instance used by this query builder
|
|
1762
|
+
* Useful for accessing cache statistics and other service methods
|
|
1763
|
+
*
|
|
1764
|
+
* @returns The DeepQueryService instance
|
|
1765
|
+
*/
|
|
1766
|
+
getDeepQueryService() {
|
|
1767
|
+
return this.deepQueryService;
|
|
1768
|
+
}
|
|
1769
|
+
getProjectionForAttributes(e) {
|
|
1770
|
+
const t = {};
|
|
1771
|
+
return e.forEach((r) => {
|
|
1772
|
+
t[r] = !0;
|
|
1773
|
+
}), t;
|
|
1774
|
+
}
|
|
1775
|
+
getProjectionForAttributeEntries(e) {
|
|
1776
|
+
const t = {
|
|
1777
|
+
$: !0
|
|
1778
|
+
};
|
|
1779
|
+
return e.forEach((r) => {
|
|
1780
|
+
if (r.isDeepQuery) {
|
|
1781
|
+
if (r.reference)
|
|
1782
|
+
if (r.referenceAttribute && r.referenceAttribute.length > 0) {
|
|
1783
|
+
t[r.reference] || (t[r.reference] = { $: !0 });
|
|
1784
|
+
const s = this.deepQueryService.parse(r.referenceAttribute);
|
|
1785
|
+
if (s.isDeepQuery && r.reference) {
|
|
1786
|
+
const i = this.getProjectionForAttributeEntries([s]);
|
|
1787
|
+
Object.keys(i).forEach((n) => {
|
|
1788
|
+
n !== "$" && r.reference && (t[r.reference][n] = i[n]);
|
|
1789
|
+
});
|
|
1790
|
+
} else r.reference && (t[r.reference][r.referenceAttribute] = !0);
|
|
1791
|
+
} else
|
|
1792
|
+
t[r.reference] = !0;
|
|
1793
|
+
} else
|
|
1794
|
+
t[r.attribute] = !0;
|
|
1795
|
+
}), t;
|
|
1796
|
+
}
|
|
1797
|
+
// ============================================================================
|
|
1798
|
+
// Semantic Method Aliases - Clearer naming for improved developer experience
|
|
1799
|
+
// ============================================================================
|
|
1800
|
+
/**
|
|
1801
|
+
* Get all attribute names used in the query.
|
|
1802
|
+
* Returns a simple array of unique attribute names.
|
|
1803
|
+
*
|
|
1804
|
+
* Clearer alternative to {@link getQueryAttributes}.
|
|
1805
|
+
*
|
|
1806
|
+
* @param query - Optional query to analyze. If not provided, uses current query.
|
|
1807
|
+
* @returns Array of attribute names used in the query
|
|
1808
|
+
*
|
|
1809
|
+
* @example
|
|
1810
|
+
* ```typescript
|
|
1811
|
+
* builder.addCondition({ operator: 'eq', attribute: 'status', value: 'active' });
|
|
1812
|
+
* builder.addCondition({ operator: 'gte', attribute: 'price', value: 100 });
|
|
1813
|
+
* const attrs = builder.getAttributeNames(); // ['status', 'price']
|
|
1814
|
+
* ```
|
|
1815
|
+
*/
|
|
1816
|
+
getAttributeNames(e) {
|
|
1817
|
+
return this.getQueryAttributes(e);
|
|
1818
|
+
}
|
|
1819
|
+
/**
|
|
1820
|
+
* Get detailed information about attributes used in the query.
|
|
1821
|
+
* Returns entries with deep query information (reference, referenceAttribute).
|
|
1822
|
+
*
|
|
1823
|
+
* Clearer alternative to {@link extractQueryAttributes}.
|
|
1824
|
+
*
|
|
1825
|
+
* @param query - Query to analyze. Defaults to current query if not provided.
|
|
1826
|
+
* @returns Array of QueryAttributeEntry objects with details about each attribute
|
|
1827
|
+
*
|
|
1828
|
+
* @example
|
|
1829
|
+
* ```typescript
|
|
1830
|
+
* builder.addCondition({ operator: 'eq', attribute: 'customer.name', value: 'John' });
|
|
1831
|
+
* const details = builder.getAttributeDetails();
|
|
1832
|
+
* // [{ attribute: 'customer.name', isDeepQuery: true, reference: 'customer', referenceAttribute: 'name' }]
|
|
1833
|
+
* ```
|
|
1834
|
+
*/
|
|
1835
|
+
getAttributeDetails(e) {
|
|
1836
|
+
return this.extractQueryAttributes(e || this.currentQuery);
|
|
1837
|
+
}
|
|
1838
|
+
/**
|
|
1839
|
+
* Get attribute names from the current query state.
|
|
1840
|
+
* Convenience method that operates on the current query.
|
|
1841
|
+
*
|
|
1842
|
+
* @returns Array of attribute names in current query
|
|
1843
|
+
*
|
|
1844
|
+
* @example
|
|
1845
|
+
* ```typescript
|
|
1846
|
+
* const attrs = builder.getCurrentAttributeNames();
|
|
1847
|
+
* ```
|
|
1848
|
+
*/
|
|
1849
|
+
getCurrentAttributeNames() {
|
|
1850
|
+
return this.getAttributeNames(this.currentQuery);
|
|
1851
|
+
}
|
|
1852
|
+
/**
|
|
1853
|
+
* Get detailed attribute information from the current query state.
|
|
1854
|
+
* Convenience method that operates on the current query.
|
|
1855
|
+
*
|
|
1856
|
+
* @returns Array of QueryAttributeEntry objects from current query
|
|
1857
|
+
*
|
|
1858
|
+
* @example
|
|
1859
|
+
* ```typescript
|
|
1860
|
+
* const details = builder.getCurrentAttributeDetails();
|
|
1861
|
+
* ```
|
|
1862
|
+
*/
|
|
1863
|
+
getCurrentAttributeDetails() {
|
|
1864
|
+
return this.getAttributeDetails(this.currentQuery);
|
|
1865
|
+
}
|
|
1866
|
+
// ============================================================================
|
|
1867
|
+
// Explicit Query Application Methods - Intention-revealing alternatives to applyQuery
|
|
1868
|
+
// ============================================================================
|
|
1869
|
+
/**
|
|
1870
|
+
* Add query condition(s) to the current query.
|
|
1871
|
+
* Accepts single condition or array of conditions.
|
|
1872
|
+
* Each condition is added to its respective attribute group.
|
|
1873
|
+
*
|
|
1874
|
+
* Clearer alternative to `applyQuery(condition, { mode: 'add' })`.
|
|
1875
|
+
*
|
|
1876
|
+
* @param condition - Single query condition or array of conditions to add
|
|
1877
|
+
* @returns Updated query
|
|
1878
|
+
*
|
|
1879
|
+
* @example
|
|
1880
|
+
* ```typescript
|
|
1881
|
+
* // Add single condition
|
|
1882
|
+
* builder.addCondition({ operator: 'eq', attribute: 'status', value: 'active' });
|
|
1883
|
+
*
|
|
1884
|
+
* // Add multiple conditions
|
|
1885
|
+
* builder.addCondition([
|
|
1886
|
+
* { operator: 'eq', attribute: 'status', value: 'active' },
|
|
1887
|
+
* { operator: 'gte', attribute: 'price', value: 100 }
|
|
1888
|
+
* ]);
|
|
1889
|
+
* ```
|
|
1890
|
+
*/
|
|
1891
|
+
addCondition(e) {
|
|
1892
|
+
return this.applyQuery(e, { mode: "add" });
|
|
1893
|
+
}
|
|
1894
|
+
/**
|
|
1895
|
+
* Add a query group to the current query.
|
|
1896
|
+
* If a group with the same groupKey exists, extends it; otherwise creates new group.
|
|
1897
|
+
*
|
|
1898
|
+
* @param group - Query group to add
|
|
1899
|
+
* @returns Updated query
|
|
1900
|
+
*
|
|
1901
|
+
* @example
|
|
1902
|
+
* ```typescript
|
|
1903
|
+
* builder.addGroup({
|
|
1904
|
+
* groupKey: 'priceRange',
|
|
1905
|
+
* groupType: 'and',
|
|
1906
|
+
* queries: [
|
|
1907
|
+
* { operator: 'gte', attribute: 'price', value: 50 },
|
|
1908
|
+
* { operator: 'lte', attribute: 'price', value: 100 }
|
|
1909
|
+
* ]
|
|
1910
|
+
* });
|
|
1911
|
+
* ```
|
|
1912
|
+
*/
|
|
1913
|
+
addGroup(e) {
|
|
1914
|
+
return this.applyQuery(e, { mode: "add" });
|
|
1915
|
+
}
|
|
1916
|
+
/**
|
|
1917
|
+
* Replace query with new condition(s).
|
|
1918
|
+
* Accepts single condition or array of conditions.
|
|
1919
|
+
* Each condition replaces all existing conditions for its attribute.
|
|
1920
|
+
*
|
|
1921
|
+
* Clearer alternative to `applyQuery(condition, { mode: 'set' })`.
|
|
1922
|
+
*
|
|
1923
|
+
* @param condition - Single query condition or array of conditions to set
|
|
1924
|
+
* @returns Updated query
|
|
1925
|
+
*
|
|
1926
|
+
* @example
|
|
1927
|
+
* ```typescript
|
|
1928
|
+
* // Replace with single condition
|
|
1929
|
+
* builder.setCondition({ operator: 'eq', attribute: 'status', value: 'active' });
|
|
1930
|
+
*
|
|
1931
|
+
* // Replace with multiple conditions
|
|
1932
|
+
* builder.setCondition([
|
|
1933
|
+
* { operator: 'eq', attribute: 'status', value: 'active' },
|
|
1934
|
+
* { operator: 'gte', attribute: 'price', value: 100 }
|
|
1935
|
+
* ]);
|
|
1936
|
+
* ```
|
|
1937
|
+
*/
|
|
1938
|
+
setCondition(e) {
|
|
1939
|
+
return this.applyQuery(e, { mode: "set" });
|
|
1940
|
+
}
|
|
1941
|
+
/**
|
|
1942
|
+
* Replace a query group with new definition.
|
|
1943
|
+
* If group exists, replaces it; otherwise creates new group.
|
|
1944
|
+
*
|
|
1945
|
+
* @param group - Query group to set
|
|
1946
|
+
* @returns Updated query
|
|
1947
|
+
*
|
|
1948
|
+
* @example
|
|
1949
|
+
* ```typescript
|
|
1950
|
+
* builder.setGroup({
|
|
1951
|
+
* groupKey: 'priceRange',
|
|
1952
|
+
* groupType: 'and',
|
|
1953
|
+
* queries: [
|
|
1954
|
+
* { operator: 'gte', attribute: 'price', value: 100 },
|
|
1955
|
+
* { operator: 'lte', attribute: 'price', value: 200 }
|
|
1956
|
+
* ]
|
|
1957
|
+
* });
|
|
1958
|
+
* ```
|
|
1959
|
+
*/
|
|
1960
|
+
setGroup(e) {
|
|
1961
|
+
return this.applyQuery(e, { mode: "set" });
|
|
1962
|
+
}
|
|
1963
|
+
/**
|
|
1964
|
+
* Merge a complete query into the current query.
|
|
1965
|
+
* Adds all conditions and groups from the provided query.
|
|
1966
|
+
*
|
|
1967
|
+
* @param query - Complete query to merge
|
|
1968
|
+
* @returns Updated query
|
|
1969
|
+
*
|
|
1970
|
+
* @example
|
|
1971
|
+
* ```typescript
|
|
1972
|
+
* builder.mergeQuery({
|
|
1973
|
+
* modelKey: 'Product',
|
|
1974
|
+
* groupType: 'and',
|
|
1975
|
+
* queries: [
|
|
1976
|
+
* { operator: 'eq', attribute: 'status', value: 'active' },
|
|
1977
|
+
* { operator: 'gte', attribute: 'price', value: 100 }
|
|
1978
|
+
* ]
|
|
1979
|
+
* });
|
|
1980
|
+
* ```
|
|
1981
|
+
*/
|
|
1982
|
+
mergeQuery(e) {
|
|
1983
|
+
if (e.queries && Array.isArray(e.queries))
|
|
1984
|
+
for (const t of e.queries)
|
|
1985
|
+
this.applyQuery(t, { mode: "add" });
|
|
1986
|
+
return this.currentQuery;
|
|
1987
|
+
}
|
|
1988
|
+
/**
|
|
1989
|
+
* Replace the entire current query with a new query.
|
|
1990
|
+
* Completely replaces all conditions, groups, and options.
|
|
1991
|
+
*
|
|
1992
|
+
* @param query - Complete query to replace with
|
|
1993
|
+
* @returns Updated query
|
|
1994
|
+
*
|
|
1995
|
+
* @example
|
|
1996
|
+
* ```typescript
|
|
1997
|
+
* builder.replaceQuery({
|
|
1998
|
+
* modelKey: 'Product',
|
|
1999
|
+
* groupType: 'or',
|
|
2000
|
+
* queries: [
|
|
2001
|
+
* { operator: 'eq', attribute: 'featured', value: true },
|
|
2002
|
+
* { operator: 'gte', attribute: 'rating', value: 4.5 }
|
|
2003
|
+
* ]
|
|
2004
|
+
* });
|
|
2005
|
+
* ```
|
|
2006
|
+
*/
|
|
2007
|
+
replaceQuery(e) {
|
|
2008
|
+
return this.currentQuery.queries = [], e.groupType && (this.currentQuery.groupType = e.groupType), e.queries && Array.isArray(e.queries) && (this.currentQuery.queries = e.queries), this.currentQuery;
|
|
2009
|
+
}
|
|
2010
|
+
// ============================================================================
|
|
2011
|
+
// State Management Clarity Methods
|
|
2012
|
+
// ============================================================================
|
|
2013
|
+
/**
|
|
2014
|
+
* Clear all query conditions and reset to initial state.
|
|
2015
|
+
* Alias for {@link reset} with clearer intent.
|
|
2016
|
+
*
|
|
2017
|
+
* @returns Empty query
|
|
2018
|
+
*
|
|
2019
|
+
* @example
|
|
2020
|
+
* ```typescript
|
|
2021
|
+
* builder.addCondition({ operator: 'eq', attribute: 'status', value: 'active' });
|
|
2022
|
+
* builder.clear(); // Removes all conditions
|
|
2023
|
+
* ```
|
|
2024
|
+
*/
|
|
2025
|
+
clear() {
|
|
2026
|
+
return this.reset();
|
|
2027
|
+
}
|
|
2028
|
+
/**
|
|
2029
|
+
* Remove all query conditions but keep query structure.
|
|
2030
|
+
* Alias for {@link removeAllQueries} with clearer intent.
|
|
2031
|
+
*
|
|
2032
|
+
* @returns Query with no conditions
|
|
2033
|
+
*
|
|
2034
|
+
* @example
|
|
2035
|
+
* ```typescript
|
|
2036
|
+
* builder.clearConditions(); // Remove all conditions but keep modelKey, etc.
|
|
2037
|
+
* ```
|
|
2038
|
+
*/
|
|
2039
|
+
clearConditions() {
|
|
2040
|
+
return this.removeAllQueries();
|
|
2041
|
+
}
|
|
2042
|
+
/**
|
|
2043
|
+
* Get an immutable copy of the current query state.
|
|
2044
|
+
* Alias for {@link getQuery} with clearer intent.
|
|
2045
|
+
*
|
|
2046
|
+
* @returns Deep clone of current query
|
|
2047
|
+
*
|
|
2048
|
+
* @example
|
|
2049
|
+
* ```typescript
|
|
2050
|
+
* const snapshot = builder.getCurrentQuery();
|
|
2051
|
+
* ```
|
|
2052
|
+
*/
|
|
2053
|
+
getCurrentQuery() {
|
|
2054
|
+
return this.getQuery();
|
|
2055
|
+
}
|
|
2056
|
+
/**
|
|
2057
|
+
* Check if the query has any conditions.
|
|
2058
|
+
*
|
|
2059
|
+
* @returns true if query has no conditions, false otherwise
|
|
2060
|
+
*
|
|
2061
|
+
* @example
|
|
2062
|
+
* ```typescript
|
|
2063
|
+
* if (builder.isEmpty()) {
|
|
2064
|
+
* console.log('No filters applied');
|
|
2065
|
+
* }
|
|
2066
|
+
* ```
|
|
2067
|
+
*/
|
|
2068
|
+
isEmpty() {
|
|
2069
|
+
return this.currentQuery.queries.length === 0;
|
|
2070
|
+
}
|
|
2071
|
+
/**
|
|
2072
|
+
* Check if a specific condition exists in the query.
|
|
2073
|
+
*
|
|
2074
|
+
* @param condition - Condition to check for (partial match)
|
|
2075
|
+
* @returns true if condition exists
|
|
2076
|
+
*
|
|
2077
|
+
* @example
|
|
2078
|
+
* ```typescript
|
|
2079
|
+
* const hasStatus = builder.hasCondition({ attribute: 'status', value: 'active' });
|
|
2080
|
+
* ```
|
|
2081
|
+
*/
|
|
2082
|
+
hasCondition(e) {
|
|
2083
|
+
const t = (r) => {
|
|
2084
|
+
for (const s of r)
|
|
2085
|
+
if (this.isQuery(s)) {
|
|
2086
|
+
let i = !0;
|
|
2087
|
+
for (const n in e)
|
|
2088
|
+
if (s[n] !== e[n]) {
|
|
2089
|
+
i = !1;
|
|
2090
|
+
break;
|
|
2091
|
+
}
|
|
2092
|
+
if (i) return !0;
|
|
2093
|
+
} else if (this.isQueryGroup(s) && t(s.queries))
|
|
2094
|
+
return !0;
|
|
2095
|
+
return !1;
|
|
2096
|
+
};
|
|
2097
|
+
return t(this.currentQuery.queries);
|
|
2098
|
+
}
|
|
2099
|
+
/**
|
|
2100
|
+
* Check if a query group with the given key exists.
|
|
2101
|
+
* Alias for {@link hasQueryGroup} with consistent naming.
|
|
2102
|
+
*
|
|
2103
|
+
* @param groupKey - Group key to check
|
|
2104
|
+
* @returns true if group exists
|
|
2105
|
+
*
|
|
2106
|
+
* @example
|
|
2107
|
+
* ```typescript
|
|
2108
|
+
* if (builder.hasGroup('priceRange')) {
|
|
2109
|
+
* console.log('Price range filter is active');
|
|
2110
|
+
* }
|
|
2111
|
+
* ```
|
|
2112
|
+
*/
|
|
2113
|
+
hasGroup(e) {
|
|
2114
|
+
return this.hasQueryGroup(e);
|
|
2115
|
+
}
|
|
2116
|
+
// ============================================================================
|
|
2117
|
+
// Query Inspection Methods
|
|
2118
|
+
// ============================================================================
|
|
2119
|
+
/**
|
|
2120
|
+
* Get all unique attribute names used in the query.
|
|
2121
|
+
* Convenience alias for {@link getAttributeNames}.
|
|
2122
|
+
*
|
|
2123
|
+
* @returns Array of attribute names
|
|
2124
|
+
*
|
|
2125
|
+
* @example
|
|
2126
|
+
* ```typescript
|
|
2127
|
+
* const attrs = builder.getUsedAttributes(); // ['status', 'price', 'customer.name']
|
|
2128
|
+
* ```
|
|
2129
|
+
*/
|
|
2130
|
+
getUsedAttributes() {
|
|
2131
|
+
return this.getAttributeNames();
|
|
2132
|
+
}
|
|
2133
|
+
/**
|
|
2134
|
+
* Get only deep query attributes (e.g., 'customer.name', 'items[0].price').
|
|
2135
|
+
* Filters out simple attributes and returns only those with references.
|
|
2136
|
+
*
|
|
2137
|
+
* @returns Array of deep query attribute details
|
|
2138
|
+
*
|
|
2139
|
+
* @example
|
|
2140
|
+
* ```typescript
|
|
2141
|
+
* const deepAttrs = builder.getDeepQueryAttributes();
|
|
2142
|
+
* // [{ attribute: 'customer.name', isDeepQuery: true, reference: 'customer', referenceAttribute: 'name' }]
|
|
2143
|
+
* ```
|
|
2144
|
+
*/
|
|
2145
|
+
getDeepQueryAttributes() {
|
|
2146
|
+
return this.getAttributeDetails().filter((t) => t.isDeepQuery);
|
|
2147
|
+
}
|
|
2148
|
+
/**
|
|
2149
|
+
* Get all query groups in the current query.
|
|
2150
|
+
*
|
|
2151
|
+
* @returns Array of query groups
|
|
2152
|
+
*
|
|
2153
|
+
* @example
|
|
2154
|
+
* ```typescript
|
|
2155
|
+
* const groups = builder.getGroups();
|
|
2156
|
+
* // [{ groupKey: 'priceRange', groupType: 'and', queries: [...] }]
|
|
2157
|
+
* ```
|
|
2158
|
+
*/
|
|
2159
|
+
getGroups() {
|
|
2160
|
+
return this.currentQuery.queries.filter((e) => this.isQueryGroup(e));
|
|
2161
|
+
}
|
|
2162
|
+
/**
|
|
2163
|
+
* Get top-level conditions (queries not inside groups).
|
|
2164
|
+
*
|
|
2165
|
+
* @returns Array of top-level query conditions
|
|
2166
|
+
*
|
|
2167
|
+
* @example
|
|
2168
|
+
* ```typescript
|
|
2169
|
+
* const topLevel = builder.getTopLevelConditions();
|
|
2170
|
+
* ```
|
|
2171
|
+
*/
|
|
2172
|
+
getTopLevelConditions() {
|
|
2173
|
+
return this.currentQuery.queries.filter((e) => this.isQuery(e));
|
|
2174
|
+
}
|
|
2175
|
+
/**
|
|
2176
|
+
* Get a specific query group by its key.
|
|
2177
|
+
* Alias for {@link getQueryGroup} with consistent naming.
|
|
2178
|
+
*
|
|
2179
|
+
* @param groupKey - Key of the group to retrieve
|
|
2180
|
+
* @returns Query group or undefined if not found
|
|
2181
|
+
*
|
|
2182
|
+
* @example
|
|
2183
|
+
* ```typescript
|
|
2184
|
+
* const group = builder.getGroup('priceRange');
|
|
2185
|
+
* if (group) {
|
|
2186
|
+
* console.log('Price range:', group.queries);
|
|
2187
|
+
* }
|
|
2188
|
+
* ```
|
|
2189
|
+
*/
|
|
2190
|
+
getGroup(e) {
|
|
2191
|
+
return this.getQueryGroup(e);
|
|
2192
|
+
}
|
|
2193
|
+
/**
|
|
2194
|
+
* Count total number of conditions in the query (including nested).
|
|
2195
|
+
*
|
|
2196
|
+
* @returns Total count of query conditions
|
|
2197
|
+
*
|
|
2198
|
+
* @example
|
|
2199
|
+
* ```typescript
|
|
2200
|
+
* const count = builder.getConditionCount(); // 5
|
|
2201
|
+
* ```
|
|
2202
|
+
*/
|
|
2203
|
+
getConditionCount() {
|
|
2204
|
+
const e = (t) => {
|
|
2205
|
+
let r = 0;
|
|
2206
|
+
for (const s of t)
|
|
2207
|
+
this.isQuery(s) ? r++ : this.isQueryGroup(s) && (r += e(s.queries));
|
|
2208
|
+
return r;
|
|
2209
|
+
};
|
|
2210
|
+
return e(this.currentQuery.queries);
|
|
2211
|
+
}
|
|
2212
|
+
}
|
|
2213
|
+
const S = new P();
|
|
2214
|
+
function Be(o, e, t, r, s, i, n) {
|
|
2215
|
+
const a = [], u = S.removeQuery({ groupKey: s }, y(r)), c = n.queryData(o, u, !1, i), f = e ? [...e.keys()] : [], d = new Set(f), l = i.get(s);
|
|
2216
|
+
if (!t.excludeUnresolved)
|
|
2217
|
+
for (const h of l.keys())
|
|
2218
|
+
d.add(h);
|
|
2219
|
+
t.excludeUndefineds ? d.delete(void 0) : d.add(void 0);
|
|
2220
|
+
for (const h of d.values()) {
|
|
2221
|
+
const A = /* @__PURE__ */ new Map(), _ = l.get(h) || /* @__PURE__ */ new Set();
|
|
2222
|
+
for (const N of _) {
|
|
2223
|
+
const k = c.get(N);
|
|
2224
|
+
if (k && (A.set(N, k), !t?.calculateFacets))
|
|
2225
|
+
break;
|
|
2226
|
+
}
|
|
2227
|
+
const M = {
|
|
2228
|
+
key: String(h),
|
|
2229
|
+
value: h,
|
|
2230
|
+
selected: ye(s, h, r),
|
|
2231
|
+
enabled: A.size > 0,
|
|
2232
|
+
size: A.size,
|
|
2233
|
+
entry: e.get(h),
|
|
2234
|
+
resultKeys: Array.from(A.keys())
|
|
2235
|
+
};
|
|
2236
|
+
if (!(t?.excludeZeros && M.size === 0)) {
|
|
2237
|
+
if (t?.count && a.length === t?.count)
|
|
2238
|
+
return a;
|
|
2239
|
+
a.push(M);
|
|
2240
|
+
}
|
|
2241
|
+
}
|
|
2242
|
+
return a;
|
|
2243
|
+
}
|
|
2244
|
+
const ye = (o, e, t) => {
|
|
2245
|
+
const r = t.queries.findIndex((s) => S.isQueryGroup(s) && s.groupKey === o);
|
|
2246
|
+
return r > -1 ? !!t.queries[r].queries.find((i) => {
|
|
2247
|
+
if (S.isQuery(i)) {
|
|
2248
|
+
const n = i.value?.key || i.value;
|
|
2249
|
+
return i.attribute === o && n === e;
|
|
2250
|
+
}
|
|
2251
|
+
return !1;
|
|
2252
|
+
}) : !1;
|
|
2253
|
+
};
|
|
2254
|
+
class me {
|
|
2255
|
+
indexMap = /* @__PURE__ */ new Map();
|
|
2256
|
+
// Possible performance gain*
|
|
2257
|
+
dataMap = /* @__PURE__ */ new Map();
|
|
2258
|
+
indexMetadata = /* @__PURE__ */ new Map();
|
|
2259
|
+
constructor() {
|
|
2260
|
+
}
|
|
2261
|
+
reset(e) {
|
|
2262
|
+
e ? (this.indexMap.delete(e), this.dataMap.delete(e), this.indexMetadata.delete(e)) : (this.indexMap.clear(), this.dataMap.clear(), this.indexMetadata.clear());
|
|
2263
|
+
}
|
|
2264
|
+
fillDataMap(e, t) {
|
|
2265
|
+
let r = this.dataMap.get(e);
|
|
2266
|
+
r || (r = /* @__PURE__ */ new Map(), this.dataMap.set(e, r));
|
|
2267
|
+
for (const s of t) {
|
|
2268
|
+
let i;
|
|
2269
|
+
if (typeof s == "object" && s && s.key)
|
|
2270
|
+
i = s.key;
|
|
2271
|
+
else if (Array.isArray(s)) {
|
|
2272
|
+
for (const a of s)
|
|
2273
|
+
this.fillDataMap(e, [a]);
|
|
2274
|
+
return;
|
|
2275
|
+
} else s instanceof Date ? i = s.toISOString() : i = s;
|
|
2276
|
+
let n = r.get(i);
|
|
2277
|
+
n || (n = { key: i }, this.dataMap.get(e)?.set(i, n));
|
|
2278
|
+
}
|
|
2279
|
+
}
|
|
2280
|
+
fillInverseIndex(e, t, r) {
|
|
2281
|
+
if (!e || !t || !r || !Array.isArray(r))
|
|
2282
|
+
return;
|
|
2283
|
+
const s = this.indexMap.get(e) || /* @__PURE__ */ new Map();
|
|
2284
|
+
for (const i of r) {
|
|
2285
|
+
let n;
|
|
2286
|
+
if (typeof i == "object" && i && i.key)
|
|
2287
|
+
n = i.key;
|
|
2288
|
+
else if (Array.isArray(i)) {
|
|
2289
|
+
for (const u of i)
|
|
2290
|
+
this.fillInverseIndex(e, t, [u]);
|
|
2291
|
+
return;
|
|
2292
|
+
} else i instanceof Date ? n = i.toISOString() : n = i;
|
|
2293
|
+
let a = s.get(n);
|
|
2294
|
+
a || (a = /* @__PURE__ */ new Set(), s.set(n, a)), a.add(t);
|
|
2295
|
+
}
|
|
2296
|
+
this.indexMap.set(e, s);
|
|
2297
|
+
}
|
|
2298
|
+
getIndex(e, t) {
|
|
2299
|
+
const r = this.getIndexName(e, t);
|
|
2300
|
+
return this.indexMap.get(r);
|
|
2301
|
+
}
|
|
2302
|
+
getData(e, t) {
|
|
2303
|
+
const r = this.getIndexName(e, t);
|
|
2304
|
+
return this.dataMap.get(r);
|
|
2305
|
+
}
|
|
2306
|
+
getOrCreateIndex(e, t, r) {
|
|
2307
|
+
const s = this.getIndexName(e, r);
|
|
2308
|
+
let i = this.getIndex(s);
|
|
2309
|
+
const n = this.indexMetadata.get(s);
|
|
2310
|
+
if (n)
|
|
2311
|
+
n.lastAccessedAt = Date.now();
|
|
2312
|
+
else if (!i) {
|
|
2313
|
+
const u = g.parse(e).isDeepQuery ?? !1;
|
|
2314
|
+
this.indexMetadata.set(s, {
|
|
2315
|
+
createdAt: Date.now(),
|
|
2316
|
+
lastAccessedAt: Date.now(),
|
|
2317
|
+
context: r,
|
|
2318
|
+
type: u ? "deep" : "shallow"
|
|
2319
|
+
});
|
|
2320
|
+
}
|
|
2321
|
+
if (!i) {
|
|
2322
|
+
this.reset(s), this.indexMap.set(s, /* @__PURE__ */ new Map());
|
|
2323
|
+
const u = g.parse(e).isDeepQuery;
|
|
2324
|
+
for (const c of t.values()) {
|
|
2325
|
+
const f = u ? v(c, e) : c[e];
|
|
2326
|
+
this.fillInverseIndex(s, c.key, [f]), this.fillDataMap(s, [f]);
|
|
2327
|
+
}
|
|
2328
|
+
i = this.getIndex(s) || /* @__PURE__ */ new Map();
|
|
2329
|
+
}
|
|
2330
|
+
return i;
|
|
2331
|
+
}
|
|
2332
|
+
getIndexName(e, t) {
|
|
2333
|
+
return t ? e + "_" + I(t) : e;
|
|
2334
|
+
}
|
|
2335
|
+
// ========== PARTIAL UPDATE METHODS ==========
|
|
2336
|
+
/**
|
|
2337
|
+
* Removes a specific item from an inverse index
|
|
2338
|
+
* @param attributeKey - The attribute key
|
|
2339
|
+
* @param itemKey - The item key to remove
|
|
2340
|
+
* @param oldValues - The old attribute values to remove from the index
|
|
2341
|
+
*/
|
|
2342
|
+
removeFromInverseIndex(e, t, r) {
|
|
2343
|
+
const s = this.indexMap.get(e);
|
|
2344
|
+
if (s)
|
|
2345
|
+
for (const i of r) {
|
|
2346
|
+
let n;
|
|
2347
|
+
if (typeof i == "object" && i && i.key)
|
|
2348
|
+
n = i.key;
|
|
2349
|
+
else if (Array.isArray(i)) {
|
|
2350
|
+
for (const u of i)
|
|
2351
|
+
this.removeFromInverseIndex(e, t, [u]);
|
|
2352
|
+
return;
|
|
2353
|
+
} else i instanceof Date ? n = i.toISOString() : n = i;
|
|
2354
|
+
const a = s.get(n);
|
|
2355
|
+
a && (a.delete(t), a.size === 0 && s.delete(n));
|
|
2356
|
+
}
|
|
2357
|
+
}
|
|
2358
|
+
/**
|
|
2359
|
+
* Updates inverse index for a specific item by removing old values and adding new ones
|
|
2360
|
+
* @param attributeKey - The attribute key
|
|
2361
|
+
* @param itemKey - The item key being updated
|
|
2362
|
+
* @param oldValues - The old attribute values to remove
|
|
2363
|
+
* @param newValues - The new attribute values to add
|
|
2364
|
+
*/
|
|
2365
|
+
updateInverseIndex(e, t, r, s) {
|
|
2366
|
+
this.removeFromInverseIndex(e, t, r), this.fillInverseIndex(e, t, s);
|
|
2367
|
+
}
|
|
2368
|
+
/**
|
|
2369
|
+
* Removes a specific item from the data map
|
|
2370
|
+
* @param attributeKey - The attribute key
|
|
2371
|
+
* @param values - The values to remove
|
|
2372
|
+
*/
|
|
2373
|
+
removeFromDataMap(e, t) {
|
|
2374
|
+
const r = this.dataMap.get(e);
|
|
2375
|
+
if (r)
|
|
2376
|
+
for (const s of t) {
|
|
2377
|
+
let i;
|
|
2378
|
+
if (typeof s == "object" && s && s.key)
|
|
2379
|
+
i = s.key;
|
|
2380
|
+
else if (Array.isArray(s)) {
|
|
2381
|
+
for (const n of s)
|
|
2382
|
+
this.removeFromDataMap(e, [n]);
|
|
2383
|
+
return;
|
|
2384
|
+
} else s instanceof Date ? i = s.toISOString() : i = s;
|
|
2385
|
+
r.delete(i);
|
|
2386
|
+
}
|
|
2387
|
+
}
|
|
2388
|
+
/**
|
|
2389
|
+
* Updates data map for a specific item by removing old values and adding new ones
|
|
2390
|
+
* @param attributeKey - The attribute key
|
|
2391
|
+
* @param oldValues - The old values to remove
|
|
2392
|
+
* @param newValues - The new values to add
|
|
2393
|
+
*/
|
|
2394
|
+
updateDataMap(e, t, r) {
|
|
2395
|
+
this.removeFromDataMap(e, t), this.fillDataMap(e, r);
|
|
2396
|
+
}
|
|
2397
|
+
/**
|
|
2398
|
+
* Completely removes an item from all indices
|
|
2399
|
+
* Used when an item is deleted
|
|
2400
|
+
* @param itemKey - The item key to remove
|
|
2401
|
+
*/
|
|
2402
|
+
removeItemFromAllIndices(e) {
|
|
2403
|
+
for (const t of this.indexMap.values())
|
|
2404
|
+
for (const [r, s] of t)
|
|
2405
|
+
s.delete(e) && s.size === 0 && t.delete(r);
|
|
2406
|
+
for (const t of this.dataMap.values())
|
|
2407
|
+
t.has(e) && t.delete(e);
|
|
2408
|
+
}
|
|
2409
|
+
/**
|
|
2410
|
+
* Resets indices for specific attributes only
|
|
2411
|
+
* Useful for partial updates when only certain attributes changed
|
|
2412
|
+
* @param attributeKeys - Array of attribute keys to reset
|
|
2413
|
+
*/
|
|
2414
|
+
resetAttributes(e) {
|
|
2415
|
+
for (const t of e)
|
|
2416
|
+
this.reset(t);
|
|
2417
|
+
}
|
|
2418
|
+
/**
|
|
2419
|
+
* Checks if an index key represents a deep query (contains dots in the attribute path)
|
|
2420
|
+
* Uses deep query service for accurate detection
|
|
2421
|
+
* @param indexKey - The index key to check
|
|
2422
|
+
* @returns true if the index is for a deep query attribute
|
|
2423
|
+
*/
|
|
2424
|
+
isDeepQueryIndex(e) {
|
|
2425
|
+
const t = e.includes("_") ? e.split("_")[0] : e;
|
|
2426
|
+
try {
|
|
2427
|
+
return g.parse(t).isDeepQuery ?? !1;
|
|
2428
|
+
} catch {
|
|
2429
|
+
return !1;
|
|
2430
|
+
}
|
|
2431
|
+
}
|
|
2432
|
+
/**
|
|
2433
|
+
* Gets all deep query index keys currently in the index map
|
|
2434
|
+
* @returns Array of index keys that represent deep queries
|
|
2435
|
+
*/
|
|
2436
|
+
getDeepIndexKeys() {
|
|
2437
|
+
const e = [];
|
|
2438
|
+
for (const t of this.indexMap.keys())
|
|
2439
|
+
this.isDeepQueryIndex(t) && e.push(t);
|
|
2440
|
+
return e;
|
|
2441
|
+
}
|
|
2442
|
+
/**
|
|
2443
|
+
* Resets all deep query indices (e.g., "customer.country", "order.customer.address.city")
|
|
2444
|
+
* This is critical for data updates as deep query indices need to be rebuilt
|
|
2445
|
+
* when underlying data changes.
|
|
2446
|
+
*
|
|
2447
|
+
* Shallow indices (direct attributes) are preserved as they're updated incrementally.
|
|
2448
|
+
*/
|
|
2449
|
+
resetAllDeepIndices() {
|
|
2450
|
+
const e = this.getDeepIndexKeys();
|
|
2451
|
+
for (const t of e)
|
|
2452
|
+
this.indexMap.delete(t), this.dataMap.delete(t);
|
|
2453
|
+
}
|
|
2454
|
+
/**
|
|
2455
|
+
* Gets count of indices by type for monitoring and debugging
|
|
2456
|
+
* @returns Object with counts of shallow and deep indices
|
|
2457
|
+
*/
|
|
2458
|
+
getIndexCount() {
|
|
2459
|
+
let e = 0, t = 0;
|
|
2460
|
+
for (const r of this.indexMap.keys())
|
|
2461
|
+
this.isDeepQueryIndex(r) ? t++ : e++;
|
|
2462
|
+
return {
|
|
2463
|
+
shallow: e,
|
|
2464
|
+
deep: t,
|
|
2465
|
+
total: e + t
|
|
2466
|
+
};
|
|
2467
|
+
}
|
|
2468
|
+
/**
|
|
2469
|
+
* Removes stale indices that haven't been accessed recently
|
|
2470
|
+
* This helps prevent memory buildup from indices with varying contexts
|
|
2471
|
+
* @param maxAge - Maximum age in milliseconds (default: 5 minutes)
|
|
2472
|
+
* @returns Number of indices cleaned up
|
|
2473
|
+
*/
|
|
2474
|
+
cleanupStaleIndices(e = 300 * 1e3) {
|
|
2475
|
+
const t = Date.now();
|
|
2476
|
+
let r = 0;
|
|
2477
|
+
for (const [s, i] of this.indexMetadata)
|
|
2478
|
+
t - i.lastAccessedAt > e && (this.reset(s), r++);
|
|
2479
|
+
return r;
|
|
2480
|
+
}
|
|
2481
|
+
/**
|
|
2482
|
+
* Gets comprehensive statistics about indices for monitoring
|
|
2483
|
+
* @returns IndexStats object with counts and age information
|
|
2484
|
+
*/
|
|
2485
|
+
getStats() {
|
|
2486
|
+
const e = this.getIndexCount(), t = Date.now();
|
|
2487
|
+
let r = 0, s = 0;
|
|
2488
|
+
for (const n of this.indexMetadata.values()) {
|
|
2489
|
+
const a = t - n.createdAt;
|
|
2490
|
+
r += a, a > s && (s = a);
|
|
2491
|
+
}
|
|
2492
|
+
const i = this.indexMetadata.size > 0 ? r / this.indexMetadata.size : 0;
|
|
2493
|
+
return {
|
|
2494
|
+
shallow: e.shallow,
|
|
2495
|
+
deep: e.deep,
|
|
2496
|
+
total: e.total,
|
|
2497
|
+
oldestAge: s,
|
|
2498
|
+
avgAge: i
|
|
2499
|
+
};
|
|
2500
|
+
}
|
|
2501
|
+
}
|
|
2502
|
+
const m = "__";
|
|
2503
|
+
function R(o, e, t = { key: "root" }, r = "root", s = new me(), i) {
|
|
2504
|
+
const n = i || o;
|
|
2505
|
+
for (const a of e.columns)
|
|
2506
|
+
a.attribute && (g.parse(a.attribute), s.getOrCreateIndex(a.attribute, n));
|
|
2507
|
+
for (const a of e.rows)
|
|
2508
|
+
a.attribute && (g.parse(a.attribute), s.getOrCreateIndex(a.attribute, n));
|
|
2509
|
+
for (const a of e.values)
|
|
2510
|
+
a.attribute && (g.parse(a.attribute), s.getOrCreateIndex(a.attribute, n));
|
|
2511
|
+
if (e.rows && e.rows.length > 0) {
|
|
2512
|
+
t.rows = t.rows || [];
|
|
2513
|
+
const a = ve(o, e.rows[0], e, s, r, i);
|
|
2514
|
+
t.rows.push(a);
|
|
2515
|
+
}
|
|
2516
|
+
if (e.columns && e.columns.length > 0) {
|
|
2517
|
+
t.columns = t.columns || [];
|
|
2518
|
+
const a = z(o, e.columns[0], e, s, r, i);
|
|
2519
|
+
t.columns.push(a);
|
|
2520
|
+
}
|
|
2521
|
+
if (t.key === "root")
|
|
2522
|
+
for (const a of e.values) {
|
|
2523
|
+
if (t.values = t.values || [], r === "root" && e.options?.calculateTotals === !1)
|
|
2524
|
+
continue;
|
|
2525
|
+
const u = Q(a, o, s.getIndex(a.attribute), a.attribute);
|
|
2526
|
+
t.values.push(u);
|
|
2527
|
+
}
|
|
2528
|
+
return t;
|
|
2529
|
+
}
|
|
2530
|
+
function ve(o, e, t, r, s = "", i) {
|
|
2531
|
+
const n = { key: e.attribute }, a = r.getIndex(e.attribute);
|
|
2532
|
+
if (!a)
|
|
2533
|
+
return n;
|
|
2534
|
+
for (const [u, c] of a.entries()) {
|
|
2535
|
+
const f = {
|
|
2536
|
+
key: u,
|
|
2537
|
+
value: u
|
|
2538
|
+
}, d = /* @__PURE__ */ new Map();
|
|
2539
|
+
for (const l of c)
|
|
2540
|
+
o.has(l) && d.set(l, o.get(l));
|
|
2541
|
+
if (d.size) {
|
|
2542
|
+
for (const l of t.values) {
|
|
2543
|
+
if (f.values = f.values || [], s === "root" && e?.calculateTotals === !1)
|
|
2544
|
+
continue;
|
|
2545
|
+
const h = Q(l, d, r.getIndex(l.attribute), l.attribute);
|
|
2546
|
+
f.values.push(h);
|
|
2547
|
+
}
|
|
2548
|
+
if (n.rows = n.rows || [], n.rows.push(f), t.rows.length > 1) {
|
|
2549
|
+
const l = { ...t, rows: t.rows.slice(1) };
|
|
2550
|
+
R(
|
|
2551
|
+
d,
|
|
2552
|
+
l,
|
|
2553
|
+
f,
|
|
2554
|
+
s + m + e.attribute + m + u,
|
|
2555
|
+
r,
|
|
2556
|
+
i
|
|
2557
|
+
);
|
|
2558
|
+
} else if (t.columns)
|
|
2559
|
+
for (const l of t.columns) {
|
|
2560
|
+
f.columns = f.columns || [];
|
|
2561
|
+
const h = z(
|
|
2562
|
+
d,
|
|
2563
|
+
l,
|
|
2564
|
+
t,
|
|
2565
|
+
r,
|
|
2566
|
+
s + m + e.attribute + m + u,
|
|
2567
|
+
i
|
|
2568
|
+
);
|
|
2569
|
+
f.columns.push(h);
|
|
2570
|
+
}
|
|
2571
|
+
}
|
|
2572
|
+
}
|
|
2573
|
+
return n;
|
|
2574
|
+
}
|
|
2575
|
+
function z(o, e, t, r, s = "", i) {
|
|
2576
|
+
const n = { key: e.attribute }, a = r.getIndex(e.attribute);
|
|
2577
|
+
if (!a)
|
|
2578
|
+
return n;
|
|
2579
|
+
for (const [u, c] of a.entries()) {
|
|
2580
|
+
const f = {
|
|
2581
|
+
key: u,
|
|
2582
|
+
value: u
|
|
2583
|
+
}, d = /* @__PURE__ */ new Map();
|
|
2584
|
+
for (const l of c)
|
|
2585
|
+
o.has(l) && d.set(l, o.get(l));
|
|
2586
|
+
if (d.size) {
|
|
2587
|
+
for (const l of t.values) {
|
|
2588
|
+
if (f.values = f.values || [], s === "root" && e?.calculateTotals === !1)
|
|
2589
|
+
continue;
|
|
2590
|
+
const h = Q(l, d, r.getIndex(l.attribute), l.attribute);
|
|
2591
|
+
f.values.push(h);
|
|
2592
|
+
}
|
|
2593
|
+
if (n.columns = n.columns || [], n.columns.push(f), t.columns.length > 1) {
|
|
2594
|
+
const l = { ...t, columns: t.columns.slice(1) };
|
|
2595
|
+
R(
|
|
2596
|
+
d,
|
|
2597
|
+
l,
|
|
2598
|
+
f,
|
|
2599
|
+
s + m + e.attribute + m + u,
|
|
2600
|
+
r,
|
|
2601
|
+
i
|
|
2602
|
+
);
|
|
2603
|
+
}
|
|
2604
|
+
}
|
|
2605
|
+
}
|
|
2606
|
+
return n;
|
|
2607
|
+
}
|
|
2608
|
+
const Te = (o, e) => {
|
|
2609
|
+
const t = [];
|
|
2610
|
+
for (const r of o) {
|
|
2611
|
+
for (const [s, i] of Object.entries(r)) {
|
|
2612
|
+
const n = t.find((u) => u.key === s), a = Ae(i);
|
|
2613
|
+
if (n)
|
|
2614
|
+
n.type !== a && (n.type = "any");
|
|
2615
|
+
else {
|
|
2616
|
+
const u = {
|
|
2617
|
+
key: s,
|
|
2618
|
+
type: a
|
|
2619
|
+
};
|
|
2620
|
+
t.push(u);
|
|
2621
|
+
}
|
|
2622
|
+
}
|
|
2623
|
+
if (!e)
|
|
2624
|
+
break;
|
|
2625
|
+
}
|
|
2626
|
+
return t;
|
|
2627
|
+
}, we = (o) => Number(o) === o && o % 1 === 0, xe = (o) => Number(o) === o && o % 1 !== 0, Ae = (o) => {
|
|
2628
|
+
switch (typeof o) {
|
|
2629
|
+
case "string":
|
|
2630
|
+
return "string";
|
|
2631
|
+
case "number":
|
|
2632
|
+
return we(o) ? "int" : xe(o) ? "float" : "any";
|
|
2633
|
+
case "boolean":
|
|
2634
|
+
return "boolean";
|
|
2635
|
+
case "object":
|
|
2636
|
+
return re(o) ? "date" : "json";
|
|
2637
|
+
default:
|
|
2638
|
+
return "any";
|
|
2639
|
+
}
|
|
2640
|
+
}, je = (o, e) => {
|
|
2641
|
+
const t = ee(o.text || ""), r = e?.attributeKey || o.filterKey;
|
|
2642
|
+
let s;
|
|
2643
|
+
const i = e?.comparisonType || "containsIgnoreCase";
|
|
2644
|
+
return i === "containsIgnoreCase" ? s = {
|
|
2645
|
+
groupKey: o.filterKey,
|
|
2646
|
+
queries: [
|
|
2647
|
+
{
|
|
2648
|
+
queryKey: o.text,
|
|
2649
|
+
attribute: r,
|
|
2650
|
+
value: `/${t}/`,
|
|
2651
|
+
operator: "find",
|
|
2652
|
+
options: {
|
|
2653
|
+
transform: ["lowercase"]
|
|
2654
|
+
}
|
|
2655
|
+
}
|
|
2656
|
+
]
|
|
2657
|
+
} : i === "containsIgnoreCaseAndWhitespace" ? s = {
|
|
2658
|
+
groupKey: o.filterKey,
|
|
2659
|
+
queries: [
|
|
2660
|
+
{
|
|
2661
|
+
queryKey: o.text,
|
|
2662
|
+
attribute: r,
|
|
2663
|
+
value: `/${t}/`,
|
|
2664
|
+
operator: "find",
|
|
2665
|
+
options: {
|
|
2666
|
+
transform: ["removeWhitespace", "lowercase"]
|
|
2667
|
+
}
|
|
2668
|
+
}
|
|
2669
|
+
]
|
|
2670
|
+
} : i === "contains" ? s = {
|
|
2671
|
+
groupKey: o.filterKey,
|
|
2672
|
+
queries: [
|
|
2673
|
+
{
|
|
2674
|
+
queryKey: o.text,
|
|
2675
|
+
attribute: r,
|
|
2676
|
+
value: `/${t}/`,
|
|
2677
|
+
operator: "find"
|
|
2678
|
+
}
|
|
2679
|
+
]
|
|
2680
|
+
} : i === "equal" ? s = {
|
|
2681
|
+
groupKey: o.filterKey,
|
|
2682
|
+
queries: [
|
|
2683
|
+
{
|
|
2684
|
+
queryKey: o.text,
|
|
2685
|
+
attribute: r,
|
|
2686
|
+
value: o.text,
|
|
2687
|
+
operator: "eq"
|
|
2688
|
+
}
|
|
2689
|
+
]
|
|
2690
|
+
} : i === "equalIgnoreCase" && (s = {
|
|
2691
|
+
groupKey: o.filterKey,
|
|
2692
|
+
queries: [
|
|
2693
|
+
{
|
|
2694
|
+
queryKey: o.text,
|
|
2695
|
+
attribute: r,
|
|
2696
|
+
value: o.text,
|
|
2697
|
+
operator: "eq",
|
|
2698
|
+
options: {
|
|
2699
|
+
transform: ["lowercase"]
|
|
2700
|
+
}
|
|
2701
|
+
}
|
|
2702
|
+
]
|
|
2703
|
+
}), s;
|
|
2704
|
+
}, Pe = (o, e) => {
|
|
2705
|
+
const t = e?.attributeKey || o.filterKey;
|
|
2706
|
+
return {
|
|
2707
|
+
groupKey: o.filterKey,
|
|
2708
|
+
queries: [
|
|
2709
|
+
{
|
|
2710
|
+
queryKey: o.value,
|
|
2711
|
+
attribute: t,
|
|
2712
|
+
value: o.value,
|
|
2713
|
+
operator: "eq"
|
|
2714
|
+
}
|
|
2715
|
+
]
|
|
2716
|
+
};
|
|
2717
|
+
}, Re = (o, e) => {
|
|
2718
|
+
const t = e?.attributeKey || o.filterKey, r = {
|
|
2719
|
+
groupKey: o.filterKey,
|
|
2720
|
+
queries: []
|
|
2721
|
+
};
|
|
2722
|
+
return typeof o.eq < "u" && (r.groupType = "or", Array.isArray(o.eq) ? o.eq.forEach((s) => {
|
|
2723
|
+
r.queries.push({ attribute: t, value: s, operator: "eq" });
|
|
2724
|
+
}) : r.queries.push({ attribute: t, value: o.eq, operator: "eq" })), typeof o.ne < "u" && (r.groupType = "and", Array.isArray(o.ne) ? o.ne.forEach((s) => {
|
|
2725
|
+
r.queries.push({ attribute: t, value: s, operator: "eq", options: { invert: !0 } });
|
|
2726
|
+
}) : r.queries.push({
|
|
2727
|
+
attribute: t,
|
|
2728
|
+
value: o.ne,
|
|
2729
|
+
operator: "eq",
|
|
2730
|
+
options: { invert: !0 }
|
|
2731
|
+
})), typeof o.gt < "u" && (r.groupType = "and", r.queries.push({ attribute: t, value: o.gt, operator: "gt" })), typeof o.lt < "u" && (r.groupType = "and", r.queries.push({ attribute: t, value: o.lt, operator: "lt" })), typeof o.gte < "u" && (r.groupType = "and", r.queries.push({ attribute: t, value: o.gte, operator: "gte" })), typeof o.lte < "u" && (r.groupType = "and", r.queries.push({ attribute: t, value: o.lte, operator: "lte" })), r;
|
|
2732
|
+
}, ze = (o, e) => {
|
|
2733
|
+
const t = e?.attributeKey || o.filterKey, r = {
|
|
2734
|
+
groupKey: o.filterKey,
|
|
2735
|
+
queries: []
|
|
2736
|
+
};
|
|
2737
|
+
return o.itemKeys.forEach((s) => {
|
|
2738
|
+
r.queries.push({
|
|
2739
|
+
queryKey: s,
|
|
2740
|
+
attribute: t,
|
|
2741
|
+
value: { key: s },
|
|
2742
|
+
operator: "eq"
|
|
2743
|
+
});
|
|
2744
|
+
}), r;
|
|
2745
|
+
}, _e = (o) => !(typeof o.modelKey != "string" || !Array.isArray(o.queries));
|
|
2746
|
+
class We {
|
|
2747
|
+
constructor(e, t, r) {
|
|
2748
|
+
this.scriptController = e, this.globalItemService = t, this.modelParser = r;
|
|
2749
|
+
}
|
|
2750
|
+
registeredCustomOperator = /* @__PURE__ */ new Map();
|
|
2751
|
+
queryBuilder = new P();
|
|
2752
|
+
registerCustomOperator(e, t) {
|
|
2753
|
+
this.registeredCustomOperator.set(e, t);
|
|
2754
|
+
}
|
|
2755
|
+
transformValue(e, t) {
|
|
2756
|
+
if (Array.isArray(e))
|
|
2757
|
+
return e.map((r) => this.transformValue(r, t));
|
|
2758
|
+
if (typeof e != "string")
|
|
2759
|
+
return e;
|
|
2760
|
+
for (const r of t)
|
|
2761
|
+
r === "lowercase" ? e = e.toLowerCase() : r === "trim" ? e = e.trim() : r === "removeWhitespace" && (e = e.replace(/\s/g, ""));
|
|
2762
|
+
return e;
|
|
2763
|
+
}
|
|
2764
|
+
evaluateQuery(e, t) {
|
|
2765
|
+
let r, s = e.value;
|
|
2766
|
+
const i = e.options?.arrayValueHandling || "some";
|
|
2767
|
+
if (Array.isArray(e.options?.transform) && e.options.transform.length > 0 && (s = this.transformValue(s, e.options.transform)), e.attribute.includes(".") || e.attribute.includes("[") ? r = v(t, e.attribute) : r = t[e.attribute], Array.isArray(e.options?.transform) && e.options.transform.length > 0 && (r = this.transformValue(r, e.options.transform)), (typeof r > "u" || r === null) && !["typeof", "isTruthy", "eq"].includes(e.operator))
|
|
2768
|
+
return !1;
|
|
2769
|
+
switch (e.operator) {
|
|
2770
|
+
case "eq":
|
|
2771
|
+
return e.options?.invert ? !E(r, s) : E(r, s);
|
|
2772
|
+
case "find":
|
|
2773
|
+
return e.options?.invert ? !this.queryFind(r, s, i) : this.queryFind(r, s, i);
|
|
2774
|
+
case "lt":
|
|
2775
|
+
return Array.isArray(r) ? i === "some" ? r.some((n) => n < s) : r.every((n) => n < s) : r < s;
|
|
2776
|
+
case "gt":
|
|
2777
|
+
return Array.isArray(r) ? i === "some" ? r.some((n) => n > s) : r.every((n) => n > s) : r > s;
|
|
2778
|
+
case "lte":
|
|
2779
|
+
return Array.isArray(r) ? i === "some" ? r.some((n) => n <= s) : r.every((n) => n <= s) : r <= s;
|
|
2780
|
+
case "gte":
|
|
2781
|
+
return Array.isArray(r) ? i === "some" ? r.some((n) => n >= s) : r.every((n) => n >= s) : r >= s;
|
|
2782
|
+
case "typeof":
|
|
2783
|
+
return e.options?.invert ? typeof r !== s : Array.isArray(r) ? i === "some" ? r.some((n) => typeof n === s) : r.every((n) => typeof n === s) : typeof r === s;
|
|
2784
|
+
case "isTruthy":
|
|
2785
|
+
return s === !0 ? Array.isArray(r) ? i === "some" ? r.some((n) => typeof !!n) : r.every((n) => typeof !!n) : !!r : !r;
|
|
2786
|
+
case "size":
|
|
2787
|
+
return typeof r == "string" ? r.length === s : W(r) === s;
|
|
2788
|
+
default:
|
|
2789
|
+
if (this.scriptController.hasScript(e.operator))
|
|
2790
|
+
return this.scriptController.executeScript(e.operator, "operator", { query: e, item: t });
|
|
2791
|
+
if (this.registeredCustomOperator.has(e.operator)) {
|
|
2792
|
+
const n = this.registeredCustomOperator.get(e.operator);
|
|
2793
|
+
if (typeof n == "function")
|
|
2794
|
+
return n(e, t);
|
|
2795
|
+
}
|
|
2796
|
+
}
|
|
2797
|
+
return !1;
|
|
2798
|
+
}
|
|
2799
|
+
evaluateEqOperator(e, t, r, s) {
|
|
2800
|
+
const i = /* @__PURE__ */ new Map(), n = s.get(t.attribute);
|
|
2801
|
+
if (n) {
|
|
2802
|
+
let a;
|
|
2803
|
+
if (typeof t.value == "string" ? a = t.value : t.value?.key && Object.keys(t.value).length === 1 && (a = t.value.key), typeof a < "u") {
|
|
2804
|
+
const u = n.get(a);
|
|
2805
|
+
if (u)
|
|
2806
|
+
if (u.forEach((c) => {
|
|
2807
|
+
r.has(c) && i.set(c, r.get(c));
|
|
2808
|
+
}), t.options?.invert) {
|
|
2809
|
+
const c = q(Array.from(r.values()), Array.from(i.values()), "key"), f = /* @__PURE__ */ new Map();
|
|
2810
|
+
return c.forEach((d) => {
|
|
2811
|
+
f.set(d.key, d);
|
|
2812
|
+
}), f;
|
|
2813
|
+
} else
|
|
2814
|
+
return i;
|
|
2815
|
+
}
|
|
2816
|
+
}
|
|
2817
|
+
for (let [a, u] of r) {
|
|
2818
|
+
const c = this.queryBuilder.extractQueryAttributes({ queries: [t] });
|
|
2819
|
+
if (c.some((f) => f.isDeepQuery)) {
|
|
2820
|
+
const f = this.queryBuilder.getProjectionForAttributeEntries(
|
|
2821
|
+
c.filter((d) => d.isDeepQuery)
|
|
2822
|
+
);
|
|
2823
|
+
u = this.globalItemService.getProjectedData(
|
|
2824
|
+
f,
|
|
2825
|
+
this.modelParser.models.get(e.modelKey),
|
|
2826
|
+
u
|
|
2827
|
+
);
|
|
2828
|
+
}
|
|
2829
|
+
this.evaluateQuery(t, u) && i.set(a, u);
|
|
2830
|
+
}
|
|
2831
|
+
return i;
|
|
2832
|
+
}
|
|
2833
|
+
equalRegexFn(e, t) {
|
|
2834
|
+
if (typeof t == "string" && L(t, "/") && H(t, "/"))
|
|
2835
|
+
try {
|
|
2836
|
+
return new RegExp(t.slice(1, -1)).test(e);
|
|
2837
|
+
} catch {
|
|
2838
|
+
return !1;
|
|
2839
|
+
}
|
|
2840
|
+
else return Array.isArray(e) ? !!e.find((r) => b(r, t, this.equalRegexFn)) : typeof t == "object" ? U(e, t) : e === t;
|
|
2841
|
+
}
|
|
2842
|
+
queryFind(e, t, r) {
|
|
2843
|
+
return Array.isArray(e) ? typeof t == "string" || typeof t == "number" || typeof t == "boolean" ? r === "some" ? e.some((s) => b(s, t, this.equalRegexFn)) : e.every((s) => b(s, t, this.equalRegexFn)) : !!V(e, t) : b(e, t, this.equalRegexFn);
|
|
2844
|
+
}
|
|
2845
|
+
validateQuery(e) {
|
|
2846
|
+
if (this.queryBuilder.isQuery(e)) {
|
|
2847
|
+
if (!e.attribute || !e.operator)
|
|
2848
|
+
throw new Error("invalid query - missing attribute or operator");
|
|
2849
|
+
if (e.operator === "find" && Array.isArray(e.value))
|
|
2850
|
+
throw new Error("invalid query - find operator cannot have array value");
|
|
2851
|
+
return !0;
|
|
2852
|
+
} else {
|
|
2853
|
+
if (this.queryBuilder.isQueryGroup(e))
|
|
2854
|
+
return B(e.queries, (t) => this.validateQuery(t));
|
|
2855
|
+
throw new Error("invalid query - missing query or attribute");
|
|
2856
|
+
}
|
|
2857
|
+
}
|
|
2858
|
+
getEvaluatedQueryDataset(e, t, r, s) {
|
|
2859
|
+
const i = /* @__PURE__ */ new Map();
|
|
2860
|
+
if (t.attribute.includes("[*]"))
|
|
2861
|
+
for (let n of r.values()) {
|
|
2862
|
+
const a = this.queryBuilder.extractQueryAttributes({ queries: [t] });
|
|
2863
|
+
if (a.some((c) => c.isDeepQuery)) {
|
|
2864
|
+
const c = this.queryBuilder.getProjectionForAttributeEntries(
|
|
2865
|
+
a.filter((f) => f.isDeepQuery)
|
|
2866
|
+
);
|
|
2867
|
+
n = this.globalItemService.getProjectedData(
|
|
2868
|
+
c,
|
|
2869
|
+
this.modelParser.models.get(e.modelKey),
|
|
2870
|
+
n
|
|
2871
|
+
);
|
|
2872
|
+
}
|
|
2873
|
+
const u = this.handleArrayStarQuery(t, n);
|
|
2874
|
+
for (const c of u.queries)
|
|
2875
|
+
this.evaluateQuery(c, n) && i.set(n.key, n);
|
|
2876
|
+
}
|
|
2877
|
+
else {
|
|
2878
|
+
if (t.operator === "eq")
|
|
2879
|
+
return this.evaluateEqOperator(e, t, r, s);
|
|
2880
|
+
for (let [n, a] of r) {
|
|
2881
|
+
const u = this.queryBuilder.extractQueryAttributes({ queries: [t] });
|
|
2882
|
+
if (u.some((c) => c.isDeepQuery)) {
|
|
2883
|
+
const c = this.queryBuilder.getProjectionForAttributeEntries(
|
|
2884
|
+
u.filter((f) => f.isDeepQuery)
|
|
2885
|
+
);
|
|
2886
|
+
a = this.globalItemService.getProjectedData(
|
|
2887
|
+
c,
|
|
2888
|
+
this.modelParser.models.get(e.modelKey),
|
|
2889
|
+
a
|
|
2890
|
+
);
|
|
2891
|
+
}
|
|
2892
|
+
this.evaluateQuery(t, a) && i.set(n, a);
|
|
2893
|
+
}
|
|
2894
|
+
}
|
|
2895
|
+
return i;
|
|
2896
|
+
}
|
|
2897
|
+
handleArrayStarQuery(e, t) {
|
|
2898
|
+
const r = e.attribute.indexOf("[*]"), s = {
|
|
2899
|
+
groupKey: e.queryKey || e.attribute + "[*]",
|
|
2900
|
+
groupType: "or",
|
|
2901
|
+
queries: []
|
|
2902
|
+
};
|
|
2903
|
+
if (r !== -1) {
|
|
2904
|
+
const i = e.attribute.substring(0, r), n = t[i];
|
|
2905
|
+
if (Array.isArray(n))
|
|
2906
|
+
for (let a = 0; a < n.length; a++) {
|
|
2907
|
+
const u = e.attribute.replace("[*]", `[${a}]`);
|
|
2908
|
+
s.queries.push({
|
|
2909
|
+
attribute: u,
|
|
2910
|
+
operator: e.operator,
|
|
2911
|
+
value: e.value
|
|
2912
|
+
});
|
|
2913
|
+
}
|
|
2914
|
+
}
|
|
2915
|
+
return s;
|
|
2916
|
+
}
|
|
2917
|
+
evaluateQueryGroup(e, t, r, s, i) {
|
|
2918
|
+
let n = /* @__PURE__ */ new Map(), a = r;
|
|
2919
|
+
if (!t.queries || t.queries?.length === 0)
|
|
2920
|
+
return a;
|
|
2921
|
+
for (const u of t.queries) {
|
|
2922
|
+
let c = /* @__PURE__ */ new Map();
|
|
2923
|
+
if (this.queryBuilder.isQuery(u) ? c = this.getEvaluatedQueryDataset(e, u, a, i) : c = this.evaluateQueryGroup(e, u, a, s, i), n.size === 0 && (n = c), t.groupType === "or")
|
|
2924
|
+
c.forEach((f) => {
|
|
2925
|
+
n.set(f.key, f);
|
|
2926
|
+
});
|
|
2927
|
+
else {
|
|
2928
|
+
const f = q(Array.from(n.values()), Array.from(c.values()), "key");
|
|
2929
|
+
for (const d of f)
|
|
2930
|
+
n.delete(d.key);
|
|
2931
|
+
}
|
|
2932
|
+
t.groupType === "and" ? a = n : a = r;
|
|
2933
|
+
}
|
|
2934
|
+
return n;
|
|
2935
|
+
}
|
|
2936
|
+
queryData(e, t, r, s) {
|
|
2937
|
+
const i = new Map(e);
|
|
2938
|
+
return t.queries.length === 0 ? e : (t.groupKey || (t.groupKey = "root"), t.groupType || (t.groupType = "and"), t.queries || (t.queries = []), this.validateQuery(t), this.evaluateQueryGroup(t, t, i, r, s));
|
|
2939
|
+
}
|
|
2940
|
+
// public getRelevantQueryData(data: any, options: DcuplGlobalQueryOptions<any>, model: DcuplModel<ListItem>) {
|
|
2941
|
+
// // detect if any of the query attributes are a deep query.
|
|
2942
|
+
// // a deep query is a query that references another models property.
|
|
2943
|
+
// // if so we need to make a getItems call with the projected data.
|
|
2944
|
+
// const attributes = this.queryBuilder.getQueryAttributes(options);
|
|
2945
|
+
// const deepQueries = attributes.filter((attr) => {
|
|
2946
|
+
// return attr.includes('.') || attr.includes('[');
|
|
2947
|
+
// });
|
|
2948
|
+
// if (deepQueries.length > 0) {
|
|
2949
|
+
// const projection: Projection<any> = {
|
|
2950
|
+
// $: true,
|
|
2951
|
+
// };
|
|
2952
|
+
// for (const deepQuery of deepQueries) {
|
|
2953
|
+
// // split the deep query into modelKey and attribute
|
|
2954
|
+
// // e.g. modelA.someAttribute or modelB[0].someAttribute or modelB[*].someAttribute
|
|
2955
|
+
// // the result should the modelKey: modelA and attribute: someAttribute
|
|
2956
|
+
// // const [modelKey, attribute] = deepQuery.split(new RegExp(/\.|\[|\]/)).filter(Boolean);
|
|
2957
|
+
// const parts = deepQuery.split(new RegExp(/\.|\[|\]/)).filter(Boolean);
|
|
2958
|
+
// const modelKey = parts[0];
|
|
2959
|
+
// if (modelKey) {
|
|
2960
|
+
// (projection as any)[modelKey] = {
|
|
2961
|
+
// $: true,
|
|
2962
|
+
// };
|
|
2963
|
+
// }
|
|
2964
|
+
// }
|
|
2965
|
+
// const relevantData = this.globalItemService.getItemsAsMap(data, model, {
|
|
2966
|
+
// projection,
|
|
2967
|
+
// } as DcuplItemsOptions<ListItem>);
|
|
2968
|
+
// return relevantData;
|
|
2969
|
+
// } else {
|
|
2970
|
+
// return data;
|
|
2971
|
+
// }
|
|
2972
|
+
// }
|
|
2973
|
+
}
|
|
2974
|
+
class Le {
|
|
2975
|
+
scripts = /* @__PURE__ */ new Map();
|
|
2976
|
+
scriptFunctions = /* @__PURE__ */ new Map();
|
|
2977
|
+
constructor() {
|
|
2978
|
+
}
|
|
2979
|
+
keys() {
|
|
2980
|
+
return Array.from(this.scripts.keys());
|
|
2981
|
+
}
|
|
2982
|
+
setScript(e, t) {
|
|
2983
|
+
this.scripts.set(e, t);
|
|
2984
|
+
}
|
|
2985
|
+
removeScript(e) {
|
|
2986
|
+
this.scripts.delete(e);
|
|
2987
|
+
}
|
|
2988
|
+
getScript(e) {
|
|
2989
|
+
return this.scripts.get(e);
|
|
2990
|
+
}
|
|
2991
|
+
hasScript(e) {
|
|
2992
|
+
return this.scripts.has(e);
|
|
2993
|
+
}
|
|
2994
|
+
getScriptAsFn(e, t) {
|
|
2995
|
+
if (this.scriptFunctions.has(e))
|
|
2996
|
+
return this.scriptFunctions.get(e);
|
|
2997
|
+
const r = this.getScript(e);
|
|
2998
|
+
if (!r)
|
|
2999
|
+
throw new Error(`Script ${e} not found`);
|
|
3000
|
+
const s = this.getWrapperScript(r), i = new Function("script_type", ...t, s);
|
|
3001
|
+
return this.scriptFunctions.set(e, i), i;
|
|
3002
|
+
}
|
|
3003
|
+
getWrapperScript(e) {
|
|
3004
|
+
return `
|
|
3005
|
+
"use strict";
|
|
3006
|
+
${e}
|
|
3007
|
+
`;
|
|
3008
|
+
}
|
|
3009
|
+
executeScript(e, t, r) {
|
|
3010
|
+
if (!this.getScript(e))
|
|
3011
|
+
throw new Error(`Script ${e} not found`);
|
|
3012
|
+
r.context || (r.context = r.options || {});
|
|
3013
|
+
const i = Object.keys(r), n = Object.values(r);
|
|
3014
|
+
return this.getScriptAsFn(e, i)(t, ...n);
|
|
3015
|
+
}
|
|
3016
|
+
}
|
|
3017
|
+
const He = (o, e) => o ? (e || (e = {}), o.replace(/\$\{(.*?)\}/g, (t, r) => v(e, r.trim(), ""))) : "", Ue = (o) => {
|
|
3018
|
+
const e = /* @__PURE__ */ new Set();
|
|
3019
|
+
return o.replace(/\$\{(.*?)\}/g, (r, s) => (e.add(s.trim()), "")), { variables: Array.from(e).map((r) => ({ name: r })) };
|
|
3020
|
+
}, Ve = [
|
|
3021
|
+
"any",
|
|
3022
|
+
"Array<date>",
|
|
3023
|
+
"Array<float>",
|
|
3024
|
+
"Array<int>",
|
|
3025
|
+
"Array<string>",
|
|
3026
|
+
"boolean",
|
|
3027
|
+
"date",
|
|
3028
|
+
"float",
|
|
3029
|
+
"int",
|
|
3030
|
+
"json",
|
|
3031
|
+
"string"
|
|
3032
|
+
], Je = ["int", "float", "Array<int>", "Array<float>"], Ze = ["date", "Array<date>"], Ye = [
|
|
3033
|
+
"eq",
|
|
3034
|
+
"find",
|
|
3035
|
+
"gt",
|
|
3036
|
+
"gte",
|
|
3037
|
+
"lt",
|
|
3038
|
+
"lte",
|
|
3039
|
+
"typeof",
|
|
3040
|
+
"isTruthy",
|
|
3041
|
+
"size"
|
|
3042
|
+
];
|
|
3043
|
+
export {
|
|
3044
|
+
De as AnalyticsController,
|
|
3045
|
+
Ke as AttributeDependencyGraph,
|
|
3046
|
+
Se as CacheController,
|
|
3047
|
+
Oe as ChangeDetector,
|
|
3048
|
+
Ze as DatePropertyTypes,
|
|
3049
|
+
P as DcuplQueryBuilder,
|
|
3050
|
+
Ye as DcuplQueryOperatorsAsArray,
|
|
3051
|
+
fe as DeepQueryService,
|
|
3052
|
+
Z as DependencyGraph,
|
|
3053
|
+
me as IndicesController,
|
|
3054
|
+
p as Logger,
|
|
3055
|
+
Je as NumberPropertyTypes,
|
|
3056
|
+
Ve as PropertyTypesAsArray,
|
|
3057
|
+
We as QueryManager,
|
|
3058
|
+
Le as ScriptController,
|
|
3059
|
+
j as clone,
|
|
3060
|
+
te as compareVersions,
|
|
3061
|
+
Fe as computeSuggestions,
|
|
3062
|
+
g as deepQueryService,
|
|
3063
|
+
ee as escapeRegExp,
|
|
3064
|
+
He as evaluateTemplate,
|
|
3065
|
+
Pe as generateBooleanQuery,
|
|
3066
|
+
X as generateKey,
|
|
3067
|
+
Re as generateNumberAndDateQuery,
|
|
3068
|
+
ze as generateReferenceQuery,
|
|
3069
|
+
je as generateTextQuery,
|
|
3070
|
+
Q as getAggregation,
|
|
3071
|
+
Me as getDateConstraintUid,
|
|
3072
|
+
Ae as getDcuplPropertyTypeForNativeType,
|
|
3073
|
+
ge as getDistinct,
|
|
3074
|
+
Be as getFacets,
|
|
3075
|
+
Ie as getFilterEntryId,
|
|
3076
|
+
Qe as getNumberConstraintUid,
|
|
3077
|
+
Te as getPropertiesForData,
|
|
3078
|
+
ke as groupBy,
|
|
3079
|
+
qe as hasMinimumVersion,
|
|
3080
|
+
re as isDateInstance,
|
|
3081
|
+
xe as isFloat,
|
|
3082
|
+
we as isInt,
|
|
3083
|
+
se as isValidDate,
|
|
3084
|
+
_e as isValidQueryStatement,
|
|
3085
|
+
$ as isValidVersion,
|
|
3086
|
+
Y as logger,
|
|
3087
|
+
Ge as parseDate,
|
|
3088
|
+
Ue as parseTemplate,
|
|
3089
|
+
x as perf,
|
|
3090
|
+
R as pivot,
|
|
3091
|
+
Ce as removeTrailingSlash,
|
|
3092
|
+
$e as trigger,
|
|
3093
|
+
Ee as unescapeRegExp,
|
|
3094
|
+
Ne as uniqBy
|
|
3095
|
+
};
|
|
3096
|
+
//# sourceMappingURL=index.js.map
|