@aiao/rxdb-query-builder 0.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1 -0
  3. package/dist/index.d.ts +30 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +1224 -0
  6. package/dist/models/config.interface.d.ts +76 -0
  7. package/dist/models/config.interface.d.ts.map +1 -0
  8. package/dist/models/index.d.ts +8 -0
  9. package/dist/models/index.d.ts.map +1 -0
  10. package/dist/models/operator.interface.d.ts +42 -0
  11. package/dist/models/operator.interface.d.ts.map +1 -0
  12. package/dist/models/query-builder-state.d.ts +155 -0
  13. package/dist/models/query-builder-state.d.ts.map +1 -0
  14. package/dist/models/validation.interface.d.ts +88 -0
  15. package/dist/models/validation.interface.d.ts.map +1 -0
  16. package/dist/services/index.d.ts +9 -0
  17. package/dist/services/index.d.ts.map +1 -0
  18. package/dist/services/operator-registry.service.d.ts +132 -0
  19. package/dist/services/operator-registry.service.d.ts.map +1 -0
  20. package/dist/services/query-builder.service.d.ts +147 -0
  21. package/dist/services/query-builder.service.d.ts.map +1 -0
  22. package/dist/services/query-converter.service.d.ts +74 -0
  23. package/dist/services/query-converter.service.d.ts.map +1 -0
  24. package/dist/services/schema-parser.service.d.ts +83 -0
  25. package/dist/services/schema-parser.service.d.ts.map +1 -0
  26. package/dist/services/validation.service.d.ts +67 -0
  27. package/dist/services/validation.service.d.ts.map +1 -0
  28. package/dist/utils/field-tree.d.ts +119 -0
  29. package/dist/utils/field-tree.d.ts.map +1 -0
  30. package/dist/utils/id.d.ts +9 -0
  31. package/dist/utils/id.d.ts.map +1 -0
  32. package/dist/utils/index.d.ts +6 -0
  33. package/dist/utils/index.d.ts.map +1 -0
  34. package/dist/utils/metadata-field-extractor.d.ts +150 -0
  35. package/dist/utils/metadata-field-extractor.d.ts.map +1 -0
  36. package/dist/utils/schema-factory.d.ts +60 -0
  37. package/dist/utils/schema-factory.d.ts.map +1 -0
  38. package/package.json +35 -0
package/dist/index.js ADDED
@@ -0,0 +1,1224 @@
1
+ import { v4 as V } from "uuid";
2
+ import { BehaviorSubject as L, map as M, distinctUntilChanged as w } from "rxjs";
3
+ import { RelationKind as B, PropertyType as g } from "@aiao/rxdb";
4
+ function b(n) {
5
+ return "combinator" in n && "rules" in n;
6
+ }
7
+ function S(n) {
8
+ return "field" in n && "operator" in n;
9
+ }
10
+ const k = [
11
+ // 相等操作符
12
+ {
13
+ key: "=",
14
+ label: "等于",
15
+ valueType: "single",
16
+ applicableTypes: ["string", "number", "boolean", "date"]
17
+ },
18
+ {
19
+ key: "!=",
20
+ label: "不等于",
21
+ valueType: "single",
22
+ applicableTypes: ["string", "number", "boolean", "date"]
23
+ },
24
+ // 比较操作符
25
+ {
26
+ key: "<",
27
+ label: "小于",
28
+ valueType: "single",
29
+ applicableTypes: ["number", "date", "string"]
30
+ },
31
+ {
32
+ key: ">",
33
+ label: "大于",
34
+ valueType: "single",
35
+ applicableTypes: ["number", "date", "string"]
36
+ },
37
+ {
38
+ key: "<=",
39
+ label: "小于等于",
40
+ valueType: "single",
41
+ applicableTypes: ["number", "date", "string"]
42
+ },
43
+ {
44
+ key: ">=",
45
+ label: "大于等于",
46
+ valueType: "single",
47
+ applicableTypes: ["number", "date", "string"]
48
+ },
49
+ // 字符串操作符
50
+ {
51
+ key: "contains",
52
+ label: "包含",
53
+ valueType: "single",
54
+ applicableTypes: ["string", "array"]
55
+ },
56
+ {
57
+ key: "notContains",
58
+ label: "不包含",
59
+ valueType: "single",
60
+ applicableTypes: ["string", "array"]
61
+ },
62
+ {
63
+ key: "startsWith",
64
+ label: "开头是",
65
+ valueType: "single",
66
+ applicableTypes: ["string"]
67
+ },
68
+ {
69
+ key: "notStartsWith",
70
+ label: "开头不是",
71
+ valueType: "single",
72
+ applicableTypes: ["string"]
73
+ },
74
+ {
75
+ key: "endsWith",
76
+ label: "结尾是",
77
+ valueType: "single",
78
+ applicableTypes: ["string"]
79
+ },
80
+ {
81
+ key: "notEndsWith",
82
+ label: "结尾不是",
83
+ valueType: "single",
84
+ applicableTypes: ["string"]
85
+ },
86
+ // 空值操作符(仅在 nullable 字段时通过 getForField() 动态添加)
87
+ {
88
+ key: "null",
89
+ label: "为空",
90
+ valueType: "none",
91
+ applicableTypes: []
92
+ },
93
+ {
94
+ key: "notNull",
95
+ label: "不为空",
96
+ valueType: "none",
97
+ applicableTypes: []
98
+ },
99
+ // 集合操作符
100
+ {
101
+ key: "in",
102
+ label: "在列表中",
103
+ valueType: "array",
104
+ applicableTypes: ["string", "number"]
105
+ },
106
+ {
107
+ key: "notIn",
108
+ label: "不在列表中",
109
+ valueType: "array",
110
+ applicableTypes: ["string", "number"]
111
+ },
112
+ // 范围操作符
113
+ {
114
+ key: "between",
115
+ label: "在范围内",
116
+ valueType: "range",
117
+ applicableTypes: ["number", "date"]
118
+ },
119
+ {
120
+ key: "notBetween",
121
+ label: "不在范围内",
122
+ valueType: "range",
123
+ applicableTypes: ["number", "date"]
124
+ },
125
+ // 关系操作符
126
+ {
127
+ key: "exists",
128
+ label: "存在",
129
+ valueType: "subquery",
130
+ applicableTypes: ["relation"]
131
+ },
132
+ {
133
+ key: "notExists",
134
+ label: "不存在",
135
+ valueType: "subquery",
136
+ applicableTypes: ["relation"]
137
+ }
138
+ ];
139
+ function ce(n, e = k) {
140
+ return e.filter((r) => r.applicableTypes.includes(n));
141
+ }
142
+ const K = [
143
+ {
144
+ name: "stringType",
145
+ appliesTo: ["string"],
146
+ message: "值必须是字符串类型",
147
+ validate: (n) => n.value === void 0 || n.value === null || Array.isArray(n.value) ? !0 : typeof n.value == "string"
148
+ },
149
+ {
150
+ name: "numberType",
151
+ appliesTo: ["number"],
152
+ message: "值必须是数字类型",
153
+ validate: (n) => n.value === void 0 || n.value === null || Array.isArray(n.value) ? !0 : typeof n.value == "number" && !isNaN(n.value)
154
+ },
155
+ {
156
+ name: "booleanType",
157
+ appliesTo: ["boolean"],
158
+ message: "值必须是布尔类型",
159
+ validate: (n) => n.value === void 0 || n.value === null || Array.isArray(n.value) ? !0 : typeof n.value == "boolean"
160
+ },
161
+ {
162
+ name: "dateType",
163
+ appliesTo: ["date"],
164
+ message: "值必须是有效日期",
165
+ validate: (n) => {
166
+ if (n.value === void 0 || n.value === null || Array.isArray(n.value))
167
+ return !0;
168
+ if (n.value instanceof Date)
169
+ return !isNaN(n.value.getTime());
170
+ if (typeof n.value == "string") {
171
+ const e = new Date(n.value);
172
+ return !isNaN(e.getTime());
173
+ }
174
+ return !1;
175
+ }
176
+ }
177
+ ], U = {
178
+ uuid: "string",
179
+ string: "string",
180
+ number: "number",
181
+ integer: "number",
182
+ boolean: "boolean",
183
+ date: "date",
184
+ stringArray: "array",
185
+ numberArray: "array",
186
+ keyValue: "object",
187
+ json: "object"
188
+ };
189
+ function W(n, e) {
190
+ return e?.displayName ? e.displayName : n.replace(/([A-Z])/g, " $1").replace(/^./, (r) => r.toUpperCase()).trim();
191
+ }
192
+ class P {
193
+ options;
194
+ constructor(e = {}) {
195
+ this.options = {
196
+ includeForeignKeys: e.includeForeignKeys ?? !1,
197
+ includeComputedProperties: e.includeComputedProperties ?? !1,
198
+ includeRelations: e.includeRelations ?? !1,
199
+ entityMetadataMap: e.entityMetadataMap,
200
+ fieldFilter: e.fieldFilter ?? (() => !0),
201
+ displayNameGenerator: e.displayNameGenerator ?? W
202
+ };
203
+ }
204
+ /**
205
+ * 从 EntityMetadata 解析字段元数据
206
+ *
207
+ * @param metadata - RxDB 实体元数据
208
+ * @returns 字段元数据数组
209
+ *
210
+ * @example
211
+ * ```typescript
212
+ * const parser = new SchemaParser();
213
+ * const fields = parser.parse(userMetadata);
214
+ * // [{ name: 'id', displayName: 'ID', type: 'string' }, ...]
215
+ * ```
216
+ */
217
+ parse(e) {
218
+ const r = [];
219
+ for (const t of e.properties) {
220
+ if (!this.options.includeForeignKeys && e.isForeignKey(t.name))
221
+ continue;
222
+ const s = this.parseProperty(t);
223
+ s && this.options.fieldFilter(s) && r.push(s);
224
+ }
225
+ if (this.options.includeComputedProperties)
226
+ for (const t of e.computedProperties) {
227
+ const s = this.parseProperty(t);
228
+ s && this.options.fieldFilter(s) && r.push(s);
229
+ }
230
+ if (this.options.includeRelations && e.relations)
231
+ for (const t of e.relations) {
232
+ const s = this.parseRelation(t);
233
+ s && this.options.fieldFilter(s) && r.push(s);
234
+ }
235
+ return r;
236
+ }
237
+ /**
238
+ * 从多个 EntityMetadata 批量解析
239
+ *
240
+ * @param metadataMap - 实体名称到元数据的映射
241
+ * @returns 实体名称到字段数组的映射
242
+ */
243
+ parseMany(e) {
244
+ const r = /* @__PURE__ */ new Map();
245
+ for (const [t, s] of e)
246
+ r.set(t, this.parse(s));
247
+ return r;
248
+ }
249
+ /**
250
+ * 解析单个属性
251
+ */
252
+ parseProperty(e) {
253
+ const r = this.mapPropertyType(e.type);
254
+ if (!r)
255
+ return null;
256
+ const t = {
257
+ name: e.name,
258
+ displayName: this.options.displayNameGenerator(e.name, e),
259
+ type: r
260
+ };
261
+ return e.nullable !== void 0 && (t.required = !e.nullable), e.description && (t.description = e.description), e.enum && Array.isArray(e.enum) && (t.enum = e.enum), e.pattern && (t.pattern = e.pattern), t;
262
+ }
263
+ /**
264
+ * 将 RxDB PropertyType 映射到 QueryBuilder 类型
265
+ */
266
+ mapPropertyType(e) {
267
+ const r = typeof e == "string" ? e : String(e);
268
+ return U[r] ?? null;
269
+ }
270
+ /**
271
+ * 解析关系字段
272
+ */
273
+ parseRelation(e) {
274
+ const r = {
275
+ name: e.name,
276
+ displayName: this.options.displayNameGenerator(e.name, e),
277
+ type: "relation",
278
+ isRelation: !0,
279
+ relationTarget: e.mappedEntity,
280
+ relationKind: e.kind
281
+ };
282
+ if (this.options.entityMetadataMap) {
283
+ const t = e.mappedEntity, s = this.options.entityMetadataMap.get(t);
284
+ if (s) {
285
+ const a = new P({
286
+ ...this.options,
287
+ includeRelations: !1
288
+ // 防止无限递归
289
+ });
290
+ r.relationFields = a.parse(s);
291
+ }
292
+ }
293
+ return r;
294
+ }
295
+ }
296
+ function j(n) {
297
+ return new P(n);
298
+ }
299
+ function A() {
300
+ return V();
301
+ }
302
+ class Y {
303
+ idGenerator;
304
+ constructor(e = {}) {
305
+ this.idGenerator = e.idGenerator ?? A;
306
+ }
307
+ /**
308
+ * 将 QueryBuilder 状态转换为 RxDB Query
309
+ *
310
+ * @param state - QueryBuilder 状态
311
+ * @returns RxDB RuleGroup 查询对象
312
+ *
313
+ * @example
314
+ * ```typescript
315
+ * const converter = new QueryConverter<User>();
316
+ * const query = converter.toRxDBQuery(queryBuilderState);
317
+ * // { combinator: 'and', rules: [...] }
318
+ * ```
319
+ */
320
+ toRxDBQuery(e) {
321
+ return this.convertGroupToRxDB(e.rootGroup);
322
+ }
323
+ /**
324
+ * 将 RxDB Query 转换为 QueryBuilder 状态
325
+ *
326
+ * @param query - RxDB RuleGroup 查询对象
327
+ * @returns QueryBuilder 状态
328
+ *
329
+ * @example
330
+ * ```typescript
331
+ * const converter = new QueryConverter<User>();
332
+ * const state = converter.fromRxDBQuery(rxdbQuery);
333
+ * ```
334
+ */
335
+ fromRxDBQuery(e) {
336
+ return {
337
+ rootGroup: this.convertGroupFromRxDB(e)
338
+ };
339
+ }
340
+ /**
341
+ * 转换单个规则组到 RxDB 格式
342
+ */
343
+ convertGroupToRxDB(e) {
344
+ const r = [];
345
+ for (const t of e.rules)
346
+ b(t) ? r.push(this.convertGroupToRxDB(t)) : S(t) && r.push(this.convertRuleToRxDB(t));
347
+ return {
348
+ combinator: e.combinator,
349
+ rules: r
350
+ };
351
+ }
352
+ /**
353
+ * 转换单条规则到 RxDB 格式
354
+ * 移除 QueryBuilder 特有的 id 字段
355
+ */
356
+ convertRuleToRxDB(e) {
357
+ const { id: r, ...t } = e;
358
+ return t;
359
+ }
360
+ /**
361
+ * 从 RxDB 格式转换规则组
362
+ */
363
+ convertGroupFromRxDB(e) {
364
+ const r = [];
365
+ for (const t of e.rules)
366
+ this.isRxDBRuleGroup(t) ? r.push(this.convertGroupFromRxDB(t)) : r.push(this.convertRuleFromRxDB(t));
367
+ return {
368
+ id: this.idGenerator(),
369
+ combinator: e.combinator,
370
+ rules: r
371
+ };
372
+ }
373
+ /**
374
+ * 从 RxDB 格式转换单条规则
375
+ * 添加 QueryBuilder 需要的 id 字段
376
+ */
377
+ convertRuleFromRxDB(e) {
378
+ return {
379
+ id: this.idGenerator(),
380
+ ...e
381
+ };
382
+ }
383
+ /**
384
+ * 判断是否为 RxDB RuleGroup
385
+ */
386
+ isRxDBRuleGroup(e) {
387
+ return typeof e == "object" && e !== null && "combinator" in e && "rules" in e && Array.isArray(e.rules);
388
+ }
389
+ }
390
+ function X(n) {
391
+ return new Y(n);
392
+ }
393
+ class q {
394
+ operators;
395
+ /**
396
+ * 获取操作符数量
397
+ */
398
+ get size() {
399
+ return this.operators.size;
400
+ }
401
+ constructor(e = {}) {
402
+ if (this.operators = /* @__PURE__ */ new Map(), e.useDefaultOperators !== !1)
403
+ for (const r of k)
404
+ this.operators.set(r.key, r);
405
+ if (e.operators)
406
+ for (const r of e.operators)
407
+ this.operators.set(r.key, r);
408
+ }
409
+ /**
410
+ * 注册新操作符
411
+ *
412
+ * @param operator - 操作符定义
413
+ *
414
+ * @example
415
+ * ```typescript
416
+ * registry.register({
417
+ * key: 'contains',
418
+ * label: '包含',
419
+ * applicableTypes: ['string'],
420
+ * valueType: 'single'
421
+ * });
422
+ * ```
423
+ */
424
+ register(e) {
425
+ this.operators.set(e.key, e);
426
+ }
427
+ /**
428
+ * 批量注册操作符
429
+ *
430
+ * @param operators - 操作符定义数组
431
+ */
432
+ registerMany(e) {
433
+ for (const r of e)
434
+ this.register(r);
435
+ }
436
+ /**
437
+ * 移除操作符
438
+ *
439
+ * @param key - 操作符键值
440
+ * @returns 是否成功移除
441
+ */
442
+ unregister(e) {
443
+ return this.operators.delete(e);
444
+ }
445
+ /**
446
+ * 获取操作符定义
447
+ *
448
+ * @param key - 操作符键值
449
+ * @returns 操作符定义或 undefined
450
+ */
451
+ get(e) {
452
+ return this.operators.get(e);
453
+ }
454
+ /**
455
+ * 获取所有操作符
456
+ *
457
+ * @returns 所有操作符定义数组
458
+ */
459
+ getAll() {
460
+ return Array.from(this.operators.values());
461
+ }
462
+ /**
463
+ * 根据字段类型获取适用的操作符
464
+ *
465
+ * @param fieldType - 字段类型
466
+ * @returns 适用的操作符数组
467
+ *
468
+ * @example
469
+ * ```typescript
470
+ * const stringOperators = registry.getForType('string');
471
+ * // [{ key: '=', ... }, { key: 'contains', ... }, ...]
472
+ * ```
473
+ */
474
+ getForType(e) {
475
+ return Array.from(this.operators.values()).filter((r) => r.applicableTypes.includes(e));
476
+ }
477
+ /**
478
+ * 根据字段元数据获取适用的操作符
479
+ *
480
+ * @param field - 字段元数据
481
+ * @returns 适用的操作符数组
482
+ */
483
+ getForField(e) {
484
+ const r = this.getForType(e.type);
485
+ if (e.nullable) {
486
+ const t = r.some((o) => o.key === "null"), s = r.some((o) => o.key === "notNull"), a = this.operators.get("null"), l = this.operators.get("notNull"), i = [...r];
487
+ return !t && a && i.push(a), !s && l && i.push(l), i;
488
+ }
489
+ return r;
490
+ }
491
+ /**
492
+ * 检查操作符是否支持指定类型
493
+ *
494
+ * @param operatorKey - 操作符键值
495
+ * @param fieldType - 字段类型
496
+ * @returns 是否支持
497
+ */
498
+ isOperatorSupportedForType(e, r) {
499
+ const t = this.operators.get(e);
500
+ return t ? t.applicableTypes.includes(r) : !1;
501
+ }
502
+ /**
503
+ * 检查操作符是否支持指定字段
504
+ *
505
+ * @param operatorKey - 操作符键值
506
+ * @param field - 字段元数据
507
+ * @returns 是否支持
508
+ */
509
+ isOperatorSupportedForField(e, r) {
510
+ const t = this.operators.get(e);
511
+ return t ? (e === "null" || e === "notNull") && r.nullable ? !0 : t.applicableTypes.includes(r.type) : !1;
512
+ }
513
+ /**
514
+ * 获取操作符的值类型
515
+ *
516
+ * @param operatorKey - 操作符键值
517
+ * @returns 值类型
518
+ */
519
+ getValueType(e) {
520
+ return this.operators.get(e)?.valueType;
521
+ }
522
+ /**
523
+ * 清空所有操作符
524
+ */
525
+ clear() {
526
+ this.operators.clear();
527
+ }
528
+ /**
529
+ * 重置为默认操作符
530
+ */
531
+ reset() {
532
+ this.clear();
533
+ for (const e of k)
534
+ this.operators.set(e.key, e);
535
+ }
536
+ }
537
+ function J(n) {
538
+ return new q(n);
539
+ }
540
+ let $ = null;
541
+ function z() {
542
+ return $ || ($ = new q()), $;
543
+ }
544
+ function Z(n) {
545
+ return typeof n == "object" && n !== null && "where" in n;
546
+ }
547
+ function O(n) {
548
+ if ("value" in n)
549
+ return n.value;
550
+ }
551
+ class H {
552
+ rules;
553
+ operatorRegistry;
554
+ constructor(e = {}) {
555
+ if (this.rules = /* @__PURE__ */ new Map(), this.operatorRegistry = e.operatorRegistry ?? z(), e.useBuiltinRules !== !1)
556
+ for (const r of K)
557
+ this.rules.set(r.name, r);
558
+ if (e.customRules)
559
+ for (const r of e.customRules)
560
+ this.rules.set(r.name, r);
561
+ }
562
+ /**
563
+ * 校验单条规则
564
+ */
565
+ validateRule(e, r) {
566
+ const t = [], s = O(e), a = {
567
+ fieldType: r.type,
568
+ operator: e.operator,
569
+ value: s
570
+ };
571
+ this.operatorRegistry.isOperatorSupportedForField(e.operator, r) || t.push({
572
+ field: e.field,
573
+ rule: "operatorTypeMatch",
574
+ message: `操作符 "${e.operator}" 不支持字段 "${r.name}"`
575
+ });
576
+ const l = this.operatorRegistry.getValueType(e.operator);
577
+ if (l === "subquery") {
578
+ if (Z(e) && e.where !== void 0 && e.where !== null) {
579
+ const i = e.where;
580
+ if (typeof i == "object" && "combinator" in i && "rules" in i)
581
+ if (!i.rules || i.rules.length === 0)
582
+ t.push({
583
+ field: e.field,
584
+ rule: "valueType",
585
+ message: "EXISTS 子查询条件不能为空"
586
+ });
587
+ else {
588
+ const o = this.validateSubqueryRules(i);
589
+ o.length > 0 && t.push(
590
+ ...o.map((f) => ({
591
+ ...f,
592
+ field: `${e.field}.${f.field}`
593
+ // 添加父字段前缀
594
+ }))
595
+ );
596
+ }
597
+ else
598
+ t.push({
599
+ field: e.field,
600
+ rule: "valueType",
601
+ message: "EXISTS 子查询格式无效"
602
+ });
603
+ }
604
+ } else {
605
+ const i = this.validateValueType(s, l, e.field, r.displayName);
606
+ i && t.push(i);
607
+ }
608
+ for (const i of this.rules.values()) {
609
+ if (i.appliesTo && !i.appliesTo.includes(r.type))
610
+ continue;
611
+ i.validate(a) || t.push({
612
+ field: e.field,
613
+ rule: i.name,
614
+ message: i.message
615
+ });
616
+ }
617
+ return {
618
+ valid: t.length === 0,
619
+ errors: t.length > 0 ? t : void 0
620
+ };
621
+ }
622
+ /**
623
+ * 校验整个规则组
624
+ */
625
+ validateGroup(e, r) {
626
+ const t = [];
627
+ for (const s of e.rules)
628
+ if (b(s)) {
629
+ const a = this.validateGroup(s, r);
630
+ !a.valid && a.errors && t.push(...a.errors);
631
+ } else if (S(s)) {
632
+ const a = r.get(s.field);
633
+ if (!a) {
634
+ t.push({
635
+ field: s.field,
636
+ rule: "fieldExists",
637
+ message: `字段 "${s.field}" 不存在`
638
+ });
639
+ continue;
640
+ }
641
+ const l = this.validateRule(s, a);
642
+ !l.valid && l.errors && t.push(...l.errors);
643
+ }
644
+ return {
645
+ valid: t.length === 0,
646
+ errors: t.length > 0 ? t : void 0
647
+ };
648
+ }
649
+ /**
650
+ * 注册自定义校验规则
651
+ */
652
+ registerRule(e) {
653
+ this.rules.set(e.name, e);
654
+ }
655
+ /**
656
+ * 移除校验规则
657
+ */
658
+ unregisterRule(e) {
659
+ return this.rules.delete(e);
660
+ }
661
+ /**
662
+ * 获取所有校验规则
663
+ */
664
+ getRules() {
665
+ return Array.from(this.rules.values());
666
+ }
667
+ /**
668
+ * 校验值类型
669
+ */
670
+ validateValueType(e, r, t, s) {
671
+ return r === "none" || r === "subquery" ? null : r === "array" ? !Array.isArray(e) || e.length === 0 ? {
672
+ field: t,
673
+ rule: "valueType",
674
+ message: `${s || t}需要提供一个或多个值`
675
+ } : null : r === "range" ? !Array.isArray(e) || e.length !== 2 ? {
676
+ field: t,
677
+ rule: "valueType",
678
+ message: `${s || t}需要提供两个值(范围)`
679
+ } : null : e == null || e === "" ? {
680
+ field: t,
681
+ rule: "valueType",
682
+ message: `${s || t}需要提供一个值`
683
+ } : null;
684
+ }
685
+ /**
686
+ * 验证子查询规则的基本有效性(不依赖字段元数据)
687
+ *
688
+ * @description
689
+ * 子查询可能引用关系实体的字段,我们无法获取其 FieldMetadata。
690
+ * 因此只验证规则的基本结构和值类型,不验证字段是否存在或操作符是否匹配。
691
+ */
692
+ validateSubqueryRules(e) {
693
+ const r = [];
694
+ for (const t of e.rules)
695
+ if (b(t)) {
696
+ const s = this.validateSubqueryRules(t);
697
+ r.push(...s);
698
+ } else if (S(t)) {
699
+ const s = O(t), a = this.operatorRegistry.getValueType(t.operator), l = this.validateValueType(s, a, t.field);
700
+ if (l && r.push(l), a === "subquery") {
701
+ const i = t;
702
+ if ("where" in i && i.where) {
703
+ const o = i.where;
704
+ if (typeof o == "object" && "combinator" in o && "rules" in o)
705
+ if (!o.rules || o.rules.length === 0)
706
+ r.push({
707
+ field: t.field,
708
+ rule: "valueType",
709
+ message: "EXISTS 子查询条件不能为空"
710
+ });
711
+ else {
712
+ const f = this.validateSubqueryRules(o);
713
+ r.push(...f);
714
+ }
715
+ else
716
+ r.push({
717
+ field: t.field,
718
+ rule: "valueType",
719
+ message: "EXISTS 子查询格式无效"
720
+ });
721
+ }
722
+ }
723
+ }
724
+ return r;
725
+ }
726
+ }
727
+ function ee(n) {
728
+ return new H(n);
729
+ }
730
+ const te = 5, _ = "and";
731
+ function I() {
732
+ return {
733
+ id: A(),
734
+ combinator: _,
735
+ rules: []
736
+ };
737
+ }
738
+ class re {
739
+ stateSubject;
740
+ fieldsMap;
741
+ config;
742
+ operatorRegistry;
743
+ validationService;
744
+ queryConverter;
745
+ /**
746
+ * 状态变更的 Observable 流
747
+ */
748
+ state$;
749
+ /**
750
+ * 根规则组的 Observable
751
+ */
752
+ rootGroup$;
753
+ /**
754
+ * 校验结果的 Observable
755
+ */
756
+ validation$;
757
+ /**
758
+ * RxDB Query 格式的 Observable
759
+ */
760
+ query$;
761
+ constructor(e = {}) {
762
+ if (this.operatorRegistry = e.operatorRegistry ?? J(), this.validationService = e.validationService ?? ee({
763
+ operatorRegistry: this.operatorRegistry
764
+ }), this.queryConverter = e.queryConverter ?? X(), this.fieldsMap = /* @__PURE__ */ new Map(), e.fields)
765
+ for (const t of e.fields)
766
+ this.fieldsMap.set(t.name, t);
767
+ this.config = e.config ?? {};
768
+ let r;
769
+ e.initialState ? r = e.initialState : e.initialQuery ? r = this.queryConverter.fromRxDBQuery(e.initialQuery) : e.config?.initialQuery ? r = { rootGroup: e.config.initialQuery } : r = { rootGroup: I() }, this.stateSubject = new L(r), this.state$ = this.stateSubject.asObservable(), this.rootGroup$ = this.state$.pipe(
770
+ M((t) => t.rootGroup),
771
+ w()
772
+ ), this.validation$ = this.state$.pipe(
773
+ M((t) => this.validationService.validateGroup(t.rootGroup, this.fieldsMap)),
774
+ w((t, s) => t.valid === s.valid && JSON.stringify(t.errors) === JSON.stringify(s.errors))
775
+ ), this.query$ = this.state$.pipe(
776
+ M((t) => this.queryConverter.toRxDBQuery(t)),
777
+ w((t, s) => JSON.stringify(t) === JSON.stringify(s))
778
+ );
779
+ }
780
+ /**
781
+ * 获取当前状态快照
782
+ */
783
+ getState() {
784
+ return this.stateSubject.getValue();
785
+ }
786
+ /**
787
+ * 获取当前配置
788
+ */
789
+ getConfig() {
790
+ return this.config;
791
+ }
792
+ /**
793
+ * 获取最大嵌套层级
794
+ */
795
+ getMaxNestingLevel() {
796
+ return this.config.maxNestingLevel ?? te;
797
+ }
798
+ /**
799
+ * 获取字段列表
800
+ */
801
+ getFields() {
802
+ return Array.from(this.fieldsMap.values());
803
+ }
804
+ /**
805
+ * 设置字段列表
806
+ */
807
+ setFields(e) {
808
+ this.fieldsMap.clear();
809
+ for (const r of e)
810
+ this.fieldsMap.set(r.name, r);
811
+ }
812
+ /**
813
+ * 获取操作符注册表
814
+ */
815
+ getOperatorRegistry() {
816
+ return this.operatorRegistry;
817
+ }
818
+ // ==================== 规则操作 ====================
819
+ /**
820
+ * 添加规则
821
+ */
822
+ addRule(e = null, r) {
823
+ const t = {
824
+ id: A(),
825
+ field: r?.field ?? "",
826
+ operator: r?.operator ?? "=",
827
+ value: "value" in (r ?? {}) ? r.value : ""
828
+ }, s = this.getState(), a = this.addItemToGroup(s.rootGroup, e ?? s.rootGroup.id, t);
829
+ return this.stateSubject.next({ rootGroup: a }), t.id;
830
+ }
831
+ /**
832
+ * 添加规则组
833
+ */
834
+ addGroup(e = null, r = _) {
835
+ const t = this.getState(), s = e ?? t.rootGroup.id, a = this.getGroupDepth(t.rootGroup, s), l = this.getMaxNestingLevel();
836
+ if (a >= l)
837
+ throw new Error(`已达到最大嵌套深度 ${l}`);
838
+ const i = {
839
+ id: A(),
840
+ combinator: r,
841
+ rules: []
842
+ }, o = this.addItemToGroup(t.rootGroup, s, i);
843
+ return this.stateSubject.next({ rootGroup: o }), i.id;
844
+ }
845
+ /**
846
+ * 更新规则
847
+ */
848
+ updateRule(e, r) {
849
+ const t = this.getState(), s = this.updateItemInGroup(t.rootGroup, e, r);
850
+ this.stateSubject.next({ rootGroup: s });
851
+ }
852
+ /**
853
+ * 更新组的组合器
854
+ */
855
+ updateGroupCombinator(e, r) {
856
+ const t = this.getState(), s = this.updateItemInGroup(t.rootGroup, e, { combinator: r });
857
+ this.stateSubject.next({ rootGroup: s });
858
+ }
859
+ /**
860
+ * 删除规则或组
861
+ */
862
+ remove(e) {
863
+ const r = this.getState();
864
+ if (e === r.rootGroup.id)
865
+ throw new Error("不能删除根组");
866
+ const t = this.removeItemFromGroup(r.rootGroup, e);
867
+ this.stateSubject.next({ rootGroup: t });
868
+ }
869
+ /**
870
+ * 清空所有规则
871
+ */
872
+ clear() {
873
+ this.stateSubject.next({ rootGroup: I() });
874
+ }
875
+ /**
876
+ * 销毁服务
877
+ */
878
+ destroy() {
879
+ this.stateSubject.complete();
880
+ }
881
+ // ==================== 转换方法 ====================
882
+ /**
883
+ * 获取 RxDB Query 格式
884
+ */
885
+ toRxDBQuery() {
886
+ return this.queryConverter.toRxDBQuery(this.getState());
887
+ }
888
+ /**
889
+ * 从 RxDB Query 加载
890
+ */
891
+ fromRxDBQuery(e) {
892
+ const r = this.queryConverter.fromRxDBQuery(e);
893
+ this.stateSubject.next(r);
894
+ }
895
+ // ==================== 校验方法 ====================
896
+ /**
897
+ * 执行校验并返回结果
898
+ */
899
+ validate() {
900
+ return this.validationService.validateGroup(this.getState().rootGroup, this.fieldsMap);
901
+ }
902
+ /**
903
+ * 检查当前状态是否有效
904
+ */
905
+ isValid() {
906
+ return this.validate().valid;
907
+ }
908
+ // ==================== 私有辅助方法 ====================
909
+ addItemToGroup(e, r, t) {
910
+ return e.id === r ? {
911
+ ...e,
912
+ rules: [...e.rules, t]
913
+ } : {
914
+ ...e,
915
+ rules: e.rules.map((s) => b(s) ? this.addItemToGroup(s, r, t) : s)
916
+ };
917
+ }
918
+ updateItemInGroup(e, r, t) {
919
+ return e.id === r ? { ...e, ...t } : {
920
+ ...e,
921
+ rules: e.rules.map((s) => b(s) ? s.id === r ? { ...s, ...t } : this.updateItemInGroup(s, r, t) : S(s) && s.id === r ? { ...s, ...t } : s)
922
+ };
923
+ }
924
+ removeItemFromGroup(e, r) {
925
+ return {
926
+ ...e,
927
+ rules: e.rules.filter((t) => b(t) || S(t) ? t.id !== r : !0).map((t) => b(t) ? this.removeItemFromGroup(t, r) : t)
928
+ };
929
+ }
930
+ getGroupDepth(e, r, t = 1) {
931
+ if (e.id === r)
932
+ return t;
933
+ for (const s of e.rules)
934
+ if (b(s)) {
935
+ const a = this.getGroupDepth(s, r, t + 1);
936
+ if (a > 0)
937
+ return a;
938
+ }
939
+ return 0;
940
+ }
941
+ }
942
+ function fe(n) {
943
+ return new re(n);
944
+ }
945
+ const x = "__exists__";
946
+ function ye(n) {
947
+ const e = /* @__PURE__ */ new Set(), r = n.filter((i) => e.has(i.name) ? !1 : (e.add(i.name), !0)), t = [], s = /* @__PURE__ */ new Map(), a = [...r].sort((i, o) => {
948
+ const f = (i.name.match(/\./g) || []).length, y = (o.name.match(/\./g) || []).length;
949
+ return f - y;
950
+ }), l = /* @__PURE__ */ new Map();
951
+ for (const i of r)
952
+ if (i.displayName) {
953
+ const o = i.name.split("."), f = i.displayName.split(".");
954
+ let y = "";
955
+ for (let u = 0; u < o.length - 1; u++)
956
+ y = y ? `${y}.${o[u]}` : o[u], f[u] && !l.has(y) && l.set(y, f[u]);
957
+ }
958
+ for (const i of a) {
959
+ const o = i.name.split("."), f = o[o.length - 1], y = i.type === "relation" || !!i.isRelation, u = (i.displayName ?? f).split("."), c = u[u.length - 1] || f, p = {
960
+ label: f,
961
+ value: i.name,
962
+ displayName: c,
963
+ type: i.type,
964
+ isRelation: y,
965
+ description: i.description,
966
+ required: i.required,
967
+ enum: i.enum,
968
+ // 关系字段复制 relationFields 用于子查询
969
+ ...i.relationFields && { relationFields: i.relationFields }
970
+ };
971
+ if (s.set(i.name, p), o.length === 1)
972
+ t.push(p);
973
+ else {
974
+ const m = o.slice(0, -1).join("."), v = s.get(m);
975
+ if (v)
976
+ v.children = v.children ?? [], v.children.push(p);
977
+ else {
978
+ let d = "", N = t;
979
+ for (let T = 0; T < o.length - 1; T++) {
980
+ const R = o[T];
981
+ d = d ? `${d}.${R}` : R;
982
+ let h = s.get(d);
983
+ if (!h) {
984
+ const F = l.get(d) ?? R;
985
+ h = {
986
+ label: R,
987
+ value: d,
988
+ displayName: F,
989
+ type: "relation",
990
+ isRelation: !0,
991
+ children: []
992
+ }, s.set(d, h), N.push(h);
993
+ }
994
+ h.children = h.children ?? [], N = h.children;
995
+ }
996
+ N.push(p);
997
+ }
998
+ }
999
+ }
1000
+ return C(t, r), t;
1001
+ }
1002
+ function C(n, e) {
1003
+ const r = new Map(e.map((t) => [t.name, t]));
1004
+ for (const t of n) {
1005
+ if (t.isRelation && t.children && t.children.length > 0 && !t.children.some((a) => a.label === x)) {
1006
+ const l = r.get(t.value)?.relationFields;
1007
+ t.children.unshift({
1008
+ label: x,
1009
+ value: t.value,
1010
+ // 使用父节点的值,这样选择它就等于选择关系字段本身
1011
+ displayName: "(存在性检查)",
1012
+ type: "relation",
1013
+ isRelation: !0,
1014
+ description: `检查 ${t.displayName} 是否存在`,
1015
+ relationFields: l
1016
+ // 复制 relationFields,确保 EXISTS 查询可以访问关联实体字段
1017
+ });
1018
+ }
1019
+ t.children && C(t.children, e);
1020
+ }
1021
+ }
1022
+ function se(n, e) {
1023
+ for (const r of n) {
1024
+ if (r.value === e)
1025
+ return r;
1026
+ if (r.children) {
1027
+ const t = se(r.children, e);
1028
+ if (t) return t;
1029
+ }
1030
+ }
1031
+ }
1032
+ function de(n) {
1033
+ const e = /* @__PURE__ */ new Map(), r = (t) => {
1034
+ for (const s of t)
1035
+ e.set(s.value, s), s.children && r(s.children);
1036
+ };
1037
+ return r(n), e;
1038
+ }
1039
+ function he(n = 10) {
1040
+ return Array(n).fill("children");
1041
+ }
1042
+ function me(n, e) {
1043
+ const r = e.split("."), t = [];
1044
+ let s = n;
1045
+ for (let a = 0; a < r.length; a++) {
1046
+ const l = r.slice(0, a + 1).join("."), i = s.find((o) => o.value === l);
1047
+ i ? (t.push(i.displayName || i.label), s = i.children ?? []) : t.push(r[a]);
1048
+ }
1049
+ return t.join(".");
1050
+ }
1051
+ const ne = 4, Q = ["id", "createdAt", "updatedAt", "createdBy", "updatedBy"];
1052
+ function G(n) {
1053
+ switch (n) {
1054
+ case g.uuid:
1055
+ return "string";
1056
+ case g.string:
1057
+ return "string";
1058
+ case g.number:
1059
+ case g.integer:
1060
+ return "number";
1061
+ case g.boolean:
1062
+ return "boolean";
1063
+ case g.date:
1064
+ return "date";
1065
+ case g.stringArray:
1066
+ case g.numberArray:
1067
+ return "array";
1068
+ case g.json:
1069
+ case g.keyValue:
1070
+ return "object";
1071
+ default:
1072
+ return "string";
1073
+ }
1074
+ }
1075
+ function ie(n) {
1076
+ return n.kind === B.ONE_TO_MANY || n.kind === B.MANY_TO_MANY ? "mappedProperty" in n && n.mappedProperty ? [n.mappedProperty] : [] : [];
1077
+ }
1078
+ function ae(n, e, r = {}, t, s = [], a = "", l = /* @__PURE__ */ new Set(), i = 0) {
1079
+ const o = [], f = r.relationQueryDeep ?? ne, y = r.systemFields ?? Q;
1080
+ if (t = t ?? n, l.has(n.name))
1081
+ return o;
1082
+ if (!a)
1083
+ for (const u of y) {
1084
+ const c = n.properties.find((p) => p.name === u);
1085
+ c && o.push({
1086
+ name: u,
1087
+ displayName: c.displayName ?? u,
1088
+ type: G(c.type),
1089
+ nullable: c.nullable ?? !1
1090
+ });
1091
+ }
1092
+ for (const [u, c] of n.propertyMap) {
1093
+ const p = a ? `${a}.${u}` : u;
1094
+ o.push({
1095
+ name: p,
1096
+ displayName: c.displayName ?? u,
1097
+ type: G(c.type),
1098
+ nullable: c.nullable ?? !1
1099
+ });
1100
+ }
1101
+ for (const u of n.foreignKeyNames) {
1102
+ const c = a ? `${a}.${u}` : u;
1103
+ if (!o.some((p) => p.name === c)) {
1104
+ const p = u.slice(0, -2), m = n.foreignKeyRelationMap.get(p), v = m?.displayName ?? p, d = m && "nullable" in m ? m.nullable ?? !1 : !1;
1105
+ o.push({
1106
+ name: c,
1107
+ displayName: `${v}ID`,
1108
+ type: "string",
1109
+ nullable: d
1110
+ });
1111
+ }
1112
+ }
1113
+ if (i < f)
1114
+ for (const [u, c] of n.relationMap) {
1115
+ if (s.includes(u)) continue;
1116
+ const p = e.get(c.mappedEntity);
1117
+ if (!p || i > 0 && p.metadata === t || l.has(p.metadata.name)) continue;
1118
+ const m = a ? `${a}.${u}` : u, v = c.displayName || u, d = oe(p.metadata, r);
1119
+ o.push({
1120
+ name: m,
1121
+ displayName: `${v} (${c.kind})`,
1122
+ type: "relation",
1123
+ isRelation: !0,
1124
+ relationTarget: c.mappedEntity,
1125
+ relationFields: d
1126
+ });
1127
+ const N = ie(c), T = new Set(l);
1128
+ T.add(n.name);
1129
+ const R = ae(
1130
+ p.metadata,
1131
+ e,
1132
+ r,
1133
+ t,
1134
+ N,
1135
+ m,
1136
+ T,
1137
+ i + 1
1138
+ );
1139
+ for (const h of y) {
1140
+ const F = `${m}.${h}`, D = p.metadata.properties.find((E) => E.name === h);
1141
+ D && !o.some((E) => E.name === F) && o.push({
1142
+ name: F,
1143
+ displayName: `${v}.${D.displayName ?? h}`,
1144
+ type: G(D.type),
1145
+ nullable: D.nullable ?? !1
1146
+ });
1147
+ }
1148
+ o.push(...R);
1149
+ }
1150
+ return o;
1151
+ }
1152
+ function oe(n, e = {}) {
1153
+ const r = [], t = e.systemFields ?? Q;
1154
+ for (const s of t) {
1155
+ const a = n.properties.find((l) => l.name === s);
1156
+ a && r.push({
1157
+ name: s,
1158
+ displayName: a.displayName ?? s,
1159
+ type: G(a.type),
1160
+ nullable: a.nullable ?? !1
1161
+ });
1162
+ }
1163
+ for (const [s, a] of n.propertyMap)
1164
+ r.push({
1165
+ name: s,
1166
+ displayName: a.displayName ?? s,
1167
+ type: G(a.type),
1168
+ nullable: a.nullable ?? !1
1169
+ });
1170
+ for (const s of n.foreignKeyNames)
1171
+ if (!r.some((a) => a.name === s)) {
1172
+ const a = s.slice(0, -2), l = n.foreignKeyRelationMap.get(a), i = l?.displayName ?? a, o = l && "nullable" in l ? l.nullable ?? !1 : !1;
1173
+ r.push({
1174
+ name: s,
1175
+ displayName: `${i}ID`,
1176
+ type: "string",
1177
+ nullable: o
1178
+ });
1179
+ }
1180
+ return r;
1181
+ }
1182
+ function ge(n) {
1183
+ return n.sort((e, r) => {
1184
+ const t = (e.name.match(/\./g) || []).length, s = (r.name.match(/\./g) || []).length;
1185
+ return t !== s ? t - s : e.name.localeCompare(r.name);
1186
+ });
1187
+ }
1188
+ function ve(n, e) {
1189
+ return j(e).parse(n);
1190
+ }
1191
+ function be(n, e) {
1192
+ return j(e).parseMany(n);
1193
+ }
1194
+ export {
1195
+ K as BUILTIN_VALIDATION_RULES,
1196
+ k as DEFAULT_OPERATORS,
1197
+ q as OperatorRegistry,
1198
+ re as QueryBuilderService,
1199
+ Y as QueryConverter,
1200
+ P as SchemaParser,
1201
+ H as ValidationService,
1202
+ ye as buildFieldTree,
1203
+ de as createFieldNodeMap,
1204
+ J as createOperatorRegistry,
1205
+ fe as createQueryBuilderService,
1206
+ X as createQueryConverter,
1207
+ be as createSchemaFromEntities,
1208
+ ve as createSchemaFromEntity,
1209
+ j as createSchemaParser,
1210
+ ee as createValidationService,
1211
+ ae as extractFieldsFromMetadata,
1212
+ oe as extractRelationTargetFields,
1213
+ se as findNodeByValue,
1214
+ A as generateId,
1215
+ z as getDefaultOperatorRegistry,
1216
+ me as getDisplayNamePath,
1217
+ ce as getOperatorsForType,
1218
+ he as getOptionGroupChildren,
1219
+ ie as getRelationIgnoreKeys,
1220
+ S as isRule,
1221
+ b as isRuleGroup,
1222
+ G as mapPropertyType,
1223
+ ge as organizeFields
1224
+ };