@zucker-framework/crud 1.0.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.
@@ -0,0 +1,1334 @@
1
+ import { Term, DatabaseAdapter, GenericEntity, TreeSortSupportEntity, TreePathStrategy, TransactionAwareDatabaseAdapter, ModelOperations, ValidationSchema } from '@zucker-framework/core';
2
+ export { DATABASE_ADAPTER } from '@zucker-framework/core';
3
+ import { Logger, Type, DynamicModule, InjectionToken, OptionalFactoryDependency } from '@nestjs/common';
4
+ import { TopicEventBus, EntityEventType, EntityEventPhase, EntityEvent } from '@zucker-framework/event';
5
+ import { ICache } from '@zucker-framework/cache';
6
+
7
+ type FilterOperatorType = 'eq' | 'neq' | 'like' | 'notLike' | 'contains' | 'startsWith' | 'endsWith' | 'gt' | 'gte' | 'lt' | 'lte' | 'in' | 'notIn' | 'isNull' | 'isNotNull' | 'between' | 'has' | 'hasSome' | 'empty' | 'notEmpty';
8
+ interface IFilterOperator {
9
+ readonly operatorType: FilterOperatorType;
10
+ apply(field: string, value: unknown): Record<string, unknown> | null;
11
+ }
12
+ declare const FILTER_OPERATORS = "FILTER_OPERATORS";
13
+ declare class EqualsOperator implements IFilterOperator {
14
+ readonly operatorType: "eq";
15
+ apply(field: string, value: unknown): Record<string, unknown>;
16
+ }
17
+ declare class NotEqualsOperator implements IFilterOperator {
18
+ readonly operatorType: "neq";
19
+ apply(field: string, value: unknown): Record<string, unknown>;
20
+ }
21
+ declare class LikeOperator implements IFilterOperator {
22
+ readonly operatorType: "like";
23
+ apply(field: string, value: unknown): Record<string, unknown>;
24
+ }
25
+ declare class ContainsOperator implements IFilterOperator {
26
+ readonly operatorType: "contains";
27
+ apply(field: string, value: unknown): Record<string, unknown>;
28
+ }
29
+ declare class GtOperator implements IFilterOperator {
30
+ readonly operatorType: "gt";
31
+ apply(field: string, value: unknown): Record<string, unknown>;
32
+ }
33
+ declare class GteOperator implements IFilterOperator {
34
+ readonly operatorType: "gte";
35
+ apply(field: string, value: unknown): Record<string, unknown>;
36
+ }
37
+ declare class LtOperator implements IFilterOperator {
38
+ readonly operatorType: "lt";
39
+ apply(field: string, value: unknown): Record<string, unknown>;
40
+ }
41
+ declare class LteOperator implements IFilterOperator {
42
+ readonly operatorType: "lte";
43
+ apply(field: string, value: unknown): Record<string, unknown>;
44
+ }
45
+ declare class InOperator implements IFilterOperator {
46
+ readonly operatorType: "in";
47
+ apply(field: string, value: unknown): Record<string, unknown>;
48
+ }
49
+ declare class NotInOperator implements IFilterOperator {
50
+ readonly operatorType: "notIn";
51
+ apply(field: string, value: unknown): Record<string, unknown>;
52
+ }
53
+ declare class IsNullOperator implements IFilterOperator {
54
+ readonly operatorType: "isNull";
55
+ apply(field: string, value: unknown): Record<string, unknown>;
56
+ }
57
+ declare class BetweenOperator implements IFilterOperator {
58
+ readonly operatorType: "between";
59
+ apply(field: string, value: unknown): Record<string, unknown> | null;
60
+ }
61
+ declare class HasOperator implements IFilterOperator {
62
+ readonly operatorType: "has";
63
+ apply(field: string, value: unknown): Record<string, unknown>;
64
+ }
65
+ declare class HasSomeOperator implements IFilterOperator {
66
+ readonly operatorType: "hasSome";
67
+ apply(field: string, value: unknown): Record<string, unknown>;
68
+ }
69
+ declare class NotLikeOperator implements IFilterOperator {
70
+ readonly operatorType: "notLike";
71
+ apply(field: string, value: unknown): Record<string, unknown>;
72
+ }
73
+ declare class StartsWithOperator implements IFilterOperator {
74
+ readonly operatorType: "startsWith";
75
+ apply(field: string, value: unknown): Record<string, unknown>;
76
+ }
77
+ declare class EndsWithOperator implements IFilterOperator {
78
+ readonly operatorType: "endsWith";
79
+ apply(field: string, value: unknown): Record<string, unknown>;
80
+ }
81
+ declare class IsNotNullOperator implements IFilterOperator {
82
+ readonly operatorType: "isNotNull";
83
+ apply(field: string, _value: unknown): Record<string, unknown>;
84
+ }
85
+ declare class EmptyOperator implements IFilterOperator {
86
+ readonly operatorType: "empty";
87
+ apply(field: string, _value: unknown): Record<string, unknown>;
88
+ }
89
+ declare class NotEmptyOperator implements IFilterOperator {
90
+ readonly operatorType: "notEmpty";
91
+ apply(field: string, _value: unknown): Record<string, unknown>;
92
+ }
93
+ declare const ALL_OPERATORS: (typeof EqualsOperator | typeof NotEqualsOperator | typeof LikeOperator | typeof ContainsOperator | typeof GtOperator | typeof GteOperator | typeof LtOperator | typeof LteOperator | typeof InOperator | typeof NotInOperator | typeof IsNullOperator | typeof BetweenOperator | typeof HasOperator | typeof HasSomeOperator | typeof NotLikeOperator | typeof StartsWithOperator | typeof EndsWithOperator | typeof IsNotNullOperator | typeof EmptyOperator | typeof NotEmptyOperator)[];
94
+ declare class FilterOperatorFactory {
95
+ private readonly operators;
96
+ private readonly logger;
97
+ private readonly operatorMap;
98
+ constructor(operators: IFilterOperator[]);
99
+ /** Normalize hyphen-style aliases (e.g. 'is-null' → 'isNull') to camelCase keys */
100
+ private normalizeType;
101
+ getOperator(operatorType: string): IFilterOperator | null;
102
+ applyFilter(field: string, operatorType: string, value: unknown): Record<string, unknown> | null;
103
+ getSupportedOperators(): FilterOperatorType[];
104
+ isOperatorSupported(operatorType: string): boolean;
105
+ }
106
+
107
+ /**
108
+ * 将 WHERE 表达式解析为 Term[]
109
+ * 支持: =, !=, >, <, >=, <=, like, not-like, in, not-in, is-null, is-not-null
110
+ * 支持: and, or 连接
111
+ * 支持: 字符串值用单引号包裹
112
+ *
113
+ * 例: "name = '张三' and age > 16"
114
+ */
115
+ declare function parseExpression(expression: string): Term[];
116
+ /**
117
+ * 将 {"field$operator": value} 格式解析为 Term[]
118
+ * 如 {"name$like": "张"} -> [{column: "name", termType: "like", value: "张"}]
119
+ * 没有 $ 的 key 默认 eq 操作符
120
+ * $or$ 前缀表示 or 连接
121
+ * $nest / $orNest 前缀表示嵌套条件
122
+ */
123
+ declare function parseFilterMap(filterMap: Record<string, unknown>): Term[];
124
+
125
+ /**
126
+ * 完整的 SQL-like 表达式解析器
127
+ * 支持运算符:=, !=, >, >=, <, <=, like, in, not in, between, is null, is not null
128
+ * 支持 AND/OR 组合和括号嵌套
129
+ *
130
+ * 示例: "name = '张三' and (age > 16 or status in ('active', 'pending'))"
131
+ */
132
+ declare class TermExpressionParser {
133
+ private tokens;
134
+ private pos;
135
+ /**
136
+ * 解析排序表达式
137
+ * 例: "age asc,score desc"
138
+ * @returns 排序数组 [{name: 'age', order: 'asc'}, {name: 'score', order: 'desc'}]
139
+ */
140
+ static parseOrder(expression: string): Array<{
141
+ name: string;
142
+ order: 'asc' | 'desc';
143
+ }>;
144
+ /**
145
+ * 解析 Map 为 Term[]
146
+ *
147
+ * 格式:
148
+ * - {"name$like": "张三"} -> column=name, termType=like, value=张三
149
+ * - {"$or$status$in": [1,2,3]} -> or 连接, column=status, termType=in
150
+ * - {"$nest": {"age$gt": 10}} -> 嵌套条件
151
+ * - {"$orNest": {"age$gt": 10}} -> or 嵌套条件
152
+ */
153
+ static parseMap(map: Record<string, unknown>): Term[];
154
+ /**
155
+ * 解析 SQL-like 表达式为 Term[]
156
+ */
157
+ parse(expression: string): Term[];
158
+ /** 解析 OR 层级 */
159
+ private parseOrExpression;
160
+ /** 解析 AND 层级 */
161
+ private parseAndExpression;
162
+ /** 解析基本表达式:括号分组或单个条件 */
163
+ private parsePrimary;
164
+ /** 解析单个条件表达式 */
165
+ private parseCondition;
166
+ /** 解析括号包裹的值列表: ('a', 'b', 'c') */
167
+ private parseValueList;
168
+ /** 解析单个标量值 */
169
+ private parseScalarValue;
170
+ private matchKeyword;
171
+ private expectKeyword;
172
+ private match;
173
+ private expect;
174
+ private expectToken;
175
+ private expectValue;
176
+ private peek;
177
+ private nextToken;
178
+ private error;
179
+ private convertOperator;
180
+ private tokenize;
181
+ private isIdentStart;
182
+ private isIdentPart;
183
+ }
184
+
185
+ /**
186
+ * Pagination utilities for dynamic query results.
187
+ */
188
+
189
+ /**
190
+ * Paginated query result containing data and pagination metadata.
191
+ * @template T - The type of each data item
192
+ */
193
+ interface PaginatedResult<T> {
194
+ /** The data items for the current page */
195
+ data: T[];
196
+ /** Total number of matching records */
197
+ total: number;
198
+ /** Current page number (1-based) */
199
+ page: number;
200
+ /** Number of items per page */
201
+ pageSize: number;
202
+ /** Total number of pages */
203
+ totalPages: number;
204
+ /**
205
+ * 0-based page index, equal to page - 1.
206
+ */
207
+ pageIndex: number;
208
+ }
209
+ /**
210
+ * SaveResult
211
+ * Represents the outcome of a batch save (upsert) operation.
212
+ */
213
+ interface SaveResult {
214
+ /** Number of newly created records */
215
+ created: number;
216
+ /** Number of updated records */
217
+ updated: number;
218
+ /** Total number of affected records (created + updated) */
219
+ total: number;
220
+ }
221
+ /**
222
+ * Create an empty PaginatedResult.
223
+ */
224
+ declare function emptyPagerResult<T>(): PaginatedResult<T>;
225
+ /**
226
+ * Merge two SaveResults.
227
+ */
228
+ declare function mergeSaveResult(a: SaveResult, b: SaveResult): SaveResult;
229
+ /**
230
+ * Adjust pagination parameters based on total count.
231
+ * If the current page exceeds total pages, automatically adjusts to the last page.
232
+ * @param queryParam - The original query parameters
233
+ * @param totalCount - The total number of matching records
234
+ * @returns Adjusted query parameters with corrected page number
235
+ */
236
+ declare function rePaging(queryParam: DynamicQueryParam, totalCount: number): DynamicQueryParam;
237
+ /**
238
+ * Create a query parameter with pagination disabled.
239
+ * @param queryParam - Optional base query parameters
240
+ * @returns Query parameters with page and pageSize set to undefined
241
+ */
242
+ declare function noPaging(queryParam?: DynamicQueryParam): DynamicQueryParam;
243
+ /**
244
+ * Check whether the query parameters have pagination enabled.
245
+ * @param queryParam - The query parameters to check
246
+ * @returns True if both page and pageSize are defined
247
+ */
248
+ declare function isPaged(queryParam: DynamicQueryParam): boolean;
249
+ /**
250
+ * Build a PaginatedResult from raw data and pagination metadata.
251
+ * @param data - The data items for the current page
252
+ * @param total - Total number of matching records
253
+ * @param page - Current page number (1-based)
254
+ * @param pageSize - Number of items per page
255
+ * @returns A complete PaginatedResult
256
+ */
257
+ declare function toPaginatedResult<T>(data: T[], total: number, page: number, pageSize: number): PaginatedResult<T>;
258
+ /**
259
+ * Calculate the total number of pages.
260
+ * @param total - Total number of records
261
+ * @param pageSize - Number of items per page
262
+ * @returns The total number of pages
263
+ */
264
+ declare function calculateTotalPages(total: number, pageSize: number): number;
265
+
266
+ /**
267
+ * Dynamic query parameter — describes filter, sort, pagination, and field selection
268
+ * for dynamic queries.
269
+ *
270
+ * @example
271
+ * ```ts
272
+ * const query: DynamicQueryParam = {
273
+ * filters: '{"name$like":"Alice"}',
274
+ * orderBy: 'createdAt desc',
275
+ * page: 1,
276
+ * pageSize: 20,
277
+ * };
278
+ * ```
279
+ */
280
+ interface DynamicQueryParam {
281
+ /** JSON-encoded filter map (e.g., '{"name$like":"value"}') */
282
+ filters?: string;
283
+ /** Raw where clause string */
284
+ where?: string;
285
+ /** Structured filter object */
286
+ filter?: Record<string, unknown>;
287
+ /** Sort expression (e.g., 'createdAt desc,name asc') */
288
+ orderBy?: string;
289
+ /** Page number (1-based) */
290
+ page?: number;
291
+ /** Page index (0-based), 与 page 二选一,pageIndex 优先级高于 page */
292
+ pageIndex?: number;
293
+ /** Number of items per page */
294
+ pageSize?: number;
295
+ /** Pre-computed total count (skips COUNT query when provided) */
296
+ total?: number;
297
+ /** Fields to include in the result */
298
+ includes?: string[];
299
+ /** Fields to exclude from the result */
300
+ excludes?: string[];
301
+ /** Whether to run COUNT and SELECT queries in parallel */
302
+ parallelPager?: boolean;
303
+ /** Structured Term conditions */
304
+ terms?: Term[];
305
+ }
306
+ /**
307
+ * Service for parsing dynamic query parameters into Prisma-compatible query arguments.
308
+ * Handles filter maps, sort expressions, pagination, and field selection.
309
+ */
310
+ declare class DynamicQueryParamService {
311
+ private readonly operatorFactory;
312
+ private readonly logger;
313
+ constructor(operatorFactory: FilterOperatorFactory);
314
+ /**
315
+ * 解析查询条件(filter map 格式: {"name$like": "张三"})
316
+ *
317
+ * 支持:
318
+ * - 普通字段:{ "name$like": "张三" } → AND 条件
319
+ * - OR 前缀:{ "$or$role": "admin" } → OR 条件(与同级其他条件 OR)
320
+ * - 嵌套 AND 组:{ "$nest": { ... } } → 递归解析,AND 到外层
321
+ * - 嵌套 OR 组:{ "$orNest": { ... } } → 递归解析,OR 到外层
322
+ */
323
+ parseFilters(filters?: Record<string, unknown>): Record<string, unknown>;
324
+ /**
325
+ * 解析排序
326
+ * @param orderBy 排序字符串,格式:'field1 desc,field2 asc'
327
+ * @param defaultField 默认排序字段
328
+ */
329
+ parseOrderBy(orderBy?: string, defaultField?: string): Record<string, string>[];
330
+ /**
331
+ * 解析分页参数
332
+ */
333
+ parsePagination(page?: number, pageSize?: number): {
334
+ skip: number;
335
+ take: number;
336
+ };
337
+ /**
338
+ * 解析字段选择
339
+ */
340
+ parseSelect(includes?: string[], excludes?: string[]): Record<string, boolean> | undefined;
341
+ /**
342
+ * 将 DataAccess Term[] 转换为 Prisma WHERE 条件
343
+ *
344
+ * Term 是 Zucker 统一的过滤条件格式(column + termType + value),
345
+ * 由 DataAccessHandler 生成,需注入到查询中以实现行级数据权限。
346
+ *
347
+ * @param terms DataAccess 产生的过滤条件
348
+ * @returns Prisma 兼容的 WHERE 条件对象
349
+ */
350
+ termsToWhere(terms: Term[]): Record<string, unknown>;
351
+ }
352
+ /**
353
+ * Service for executing dynamic queries with automatic filter parsing,
354
+ * sorting, pagination, and field selection. Supports parallel paging
355
+ * and total count reuse for optimized queries.
356
+ */
357
+ declare class DynamicQueryService {
358
+ private readonly db;
359
+ private readonly dynamicQueryParam;
360
+ private readonly logger;
361
+ constructor(db: DatabaseAdapter, dynamicQueryParam: DynamicQueryParamService);
362
+ /**
363
+ * 通用分页查询
364
+ * @param model 模型名称
365
+ * @param queryParam 查询参数
366
+ * @param defaultOrderField 默认排序字段
367
+ * @param dataAccessTerms DataAccess 产生的过滤条件(由 DataPermissionGuard 注入)
368
+ * @param denyFields DataAccess 产生的禁止字段列表
369
+ * @returns 分页查询结果
370
+ */
371
+ findMany<T = unknown>(model: string, queryParam: DynamicQueryParam, defaultOrderField?: string, dataAccessTerms?: Term[], denyFields?: string[]): Promise<PaginatedResult<T>>;
372
+ /**
373
+ * 查询单条记录
374
+ */
375
+ findOne(model: string, id: string, includes?: string[], excludes?: string[]): Promise<unknown>;
376
+ }
377
+
378
+ /**
379
+ * DynamicQueryParam 的增强封装类
380
+ * - 静态工厂方法: of(), newQuery()
381
+ * - 链式操作: noPaging(), doNotSort(), clone(), rePaging(total)
382
+ * - 嵌套查询转换: toNestQuery()
383
+ * - DSL 构建: and(), or()
384
+ *
385
+ * 内部以 terms 为唯一权威表示,where/filter/filters 只是输入或序列化形式。
386
+ */
387
+ declare class QueryParamEntity implements DynamicQueryParam {
388
+ private _filters?;
389
+ private _where?;
390
+ private _filter?;
391
+ orderBy?: string;
392
+ page?: number;
393
+ pageSize?: number;
394
+ total?: number;
395
+ includes?: string[];
396
+ excludes?: string[];
397
+ parallelPager?: boolean;
398
+ private _terms;
399
+ private _termsInitialized;
400
+ private _noPaging;
401
+ private _noSort;
402
+ constructor(param?: DynamicQueryParam);
403
+ get filters(): string | undefined;
404
+ set filters(value: string | undefined);
405
+ get where(): string | undefined;
406
+ set where(value: string | undefined);
407
+ get filter(): Record<string, unknown> | undefined;
408
+ set filter(value: Record<string, unknown> | undefined);
409
+ get terms(): Term[] | undefined;
410
+ set terms(value: Term[] | undefined);
411
+ /**
412
+ * 创建一个空的查询参数实体
413
+ */
414
+ static of(): QueryParamEntity;
415
+ /**
416
+ * 基于已有参数创建查询参数实体
417
+ */
418
+ static of(param: DynamicQueryParam): QueryParamEntity;
419
+ /**
420
+ * 创建带单个 eq 条件的查询参数
421
+ */
422
+ static of(field: string, value: unknown): QueryParamEntity;
423
+ /**
424
+ * 创建新的链式查询构建器
425
+ */
426
+ static newQuery(): QueryParamEntity;
427
+ /**
428
+ * 添加 AND 条件
429
+ * @param column 字段名
430
+ * @param termType 操作符 (eq, like, gt, in, etc.)
431
+ * @param value 值
432
+ */
433
+ and(column: string, termType: string, value: unknown): this;
434
+ /**
435
+ * 添加 OR 条件
436
+ */
437
+ or(column: string, termType: string, value: unknown): this;
438
+ /**
439
+ * 将已有条件包装到嵌套条件里,并返回自身用于继续添加外层条件。
440
+ */
441
+ toNestQuery(): this;
442
+ /** 禁用分页,查询全部数据 */
443
+ noPaging(): this;
444
+ /** 禁用排序 */
445
+ doNotSort(): this;
446
+ /** 深拷贝当前查询参数 */
447
+ clone(): QueryParamEntity;
448
+ /**
449
+ * 根据总数重新计算分页
450
+ * 根据总数重新分页:
451
+ * - 缓存 total 到实例,后续分页查询跳过 count
452
+ * - 如果当前页超过总页数,自动跳转到最后一页
453
+ */
454
+ rePaging(total: number): this;
455
+ /** 设置分页参数 */
456
+ withPage(page: number, pageSize?: number): this;
457
+ /** 设置排序 */
458
+ withOrderBy(orderBy: string): this;
459
+ /** 添加过滤条件 */
460
+ withFilter(key: string, value: unknown): this;
461
+ /** 设置 includes(要查询的列) */
462
+ withIncludes(...fields: string[]): this;
463
+ /** 设置 excludes(不查询的列) */
464
+ withExcludes(...fields: string[]): this;
465
+ /** 是否禁用分页 */
466
+ get isPagingDisabled(): boolean;
467
+ /** 是否禁用排序 */
468
+ get isSortDisabled(): boolean;
469
+ /**
470
+ * 获取 0 基索引的页码(用于 PagerResult)
471
+ */
472
+ getThinkPageIndex(): number;
473
+ getTerms(): Term[];
474
+ private ensureTermsInitialized;
475
+ /** 将 _terms 同步到 filter map 格式 */
476
+ private syncFilterFromTerms;
477
+ private serializeTermsToFilterMap;
478
+ private cloneTerm;
479
+ private cloneValue;
480
+ }
481
+
482
+ /**
483
+ * 链式查询构建器接口
484
+ */
485
+ interface IQueryBuilder<T extends GenericEntity> {
486
+ where<K extends string & keyof T>(field: K, op: string, value: unknown): IQueryBuilder<T>;
487
+ whereEq<K extends string & keyof T>(field: K, value: T[K]): IQueryBuilder<T>;
488
+ in<K extends string & keyof T>(field: K, values: unknown[]): IQueryBuilder<T>;
489
+ notIn<K extends string & keyof T>(field: K, values: unknown[]): IQueryBuilder<T>;
490
+ like<K extends string & keyof T>(field: K, value: string): IQueryBuilder<T>;
491
+ notLike<K extends string & keyof T>(field: K, value: string): IQueryBuilder<T>;
492
+ startsWith<K extends string & keyof T>(field: K, value: string): IQueryBuilder<T>;
493
+ endsWith<K extends string & keyof T>(field: K, value: string): IQueryBuilder<T>;
494
+ isNull<K extends string & keyof T>(field: K): IQueryBuilder<T>;
495
+ isNotNull<K extends string & keyof T>(field: K): IQueryBuilder<T>;
496
+ between<K extends string & keyof T>(field: K, low: unknown, high: unknown): IQueryBuilder<T>;
497
+ and(fn: (q: IQueryBuilder<T>) => IQueryBuilder<T>): IQueryBuilder<T>;
498
+ or(fn: (q: IQueryBuilder<T>) => IQueryBuilder<T>): IQueryBuilder<T>;
499
+ orderBy<K extends string & keyof T>(field: K, direction?: 'asc' | 'desc'): IQueryBuilder<T>;
500
+ select(...fields: Array<string & keyof T>): IQueryBuilder<T>;
501
+ distinct(...fields: Array<string & keyof T>): IQueryBuilder<T>;
502
+ groupBy(...fields: Array<string & keyof T>): IQueryBuilder<T>;
503
+ having(field: string, op: string, value: unknown): IQueryBuilder<T>;
504
+ exists(relation: string, fn?: (q: IQueryBuilder<any>) => IQueryBuilder<any>): IQueryBuilder<T>;
505
+ notExists(relation: string, fn?: (q: IQueryBuilder<any>) => IQueryBuilder<any>): IQueryBuilder<T>;
506
+ limit(n: number): IQueryBuilder<T>;
507
+ offset(n: number): IQueryBuilder<T>;
508
+ include(relation: string): IQueryBuilder<T>;
509
+ join(model: string): IJoinClause<T>;
510
+ fetch(): Promise<T[]>;
511
+ fetchOne(): Promise<T | null>;
512
+ count(): Promise<number>;
513
+ aggregate(args: AggregateQueryArgs): Promise<any>;
514
+ fetchGroupBy(args: GroupByQueryArgs): Promise<any[]>;
515
+ }
516
+ /** 聚合查询参数 */
517
+ interface AggregateQueryArgs {
518
+ _count?: Record<string, boolean> | boolean;
519
+ _sum?: Record<string, boolean>;
520
+ _avg?: Record<string, boolean>;
521
+ _min?: Record<string, boolean>;
522
+ _max?: Record<string, boolean>;
523
+ }
524
+ /** groupBy 查询参数 */
525
+ interface GroupByQueryArgs {
526
+ by: string[];
527
+ _count?: Record<string, boolean> | boolean;
528
+ _sum?: Record<string, boolean>;
529
+ _avg?: Record<string, boolean>;
530
+ _min?: Record<string, boolean>;
531
+ _max?: Record<string, boolean>;
532
+ }
533
+ /** JOIN 子句接口 */
534
+ interface IJoinClause<T extends GenericEntity> {
535
+ on(localField: string, foreignField: string): IQueryBuilder<T>;
536
+ }
537
+ /**
538
+ * 链式查询构建器实现
539
+ * 通过 DatabaseAdapter 执行查询,将链式 API 转换为 Prisma 兼容的查询参数
540
+ */
541
+ declare class QueryBuilder<T extends GenericEntity> implements IQueryBuilder<T> {
542
+ private readonly db;
543
+ private readonly modelName;
544
+ private _conditions;
545
+ private _orderBy;
546
+ private _selectFields;
547
+ private _distinctFields;
548
+ private _groupByFields;
549
+ private _havingConditions;
550
+ private _existsConditions;
551
+ private _limit?;
552
+ private _offset?;
553
+ private _includes;
554
+ private _joins;
555
+ constructor(db: DatabaseAdapter, modelName: string);
556
+ where<K extends string & keyof T>(field: K, op: string, value: unknown): this;
557
+ whereEq<K extends string & keyof T>(field: K, value: T[K]): this;
558
+ in<K extends string & keyof T>(field: K, values: unknown[]): this;
559
+ notIn<K extends string & keyof T>(field: K, values: unknown[]): this;
560
+ like<K extends string & keyof T>(field: K, value: string): this;
561
+ notLike<K extends string & keyof T>(field: K, value: string): this;
562
+ startsWith<K extends string & keyof T>(field: K, value: string): this;
563
+ endsWith<K extends string & keyof T>(field: K, value: string): this;
564
+ isNull<K extends string & keyof T>(field: K): this;
565
+ isNotNull<K extends string & keyof T>(field: K): this;
566
+ between<K extends string & keyof T>(field: K, low: unknown, high: unknown): this;
567
+ and(fn: (q: IQueryBuilder<T>) => IQueryBuilder<T>): this;
568
+ or(fn: (q: IQueryBuilder<T>) => IQueryBuilder<T>): this;
569
+ orderBy<K extends string & keyof T>(field: K, direction?: 'asc' | 'desc'): this;
570
+ select(...fields: Array<string & keyof T>): this;
571
+ distinct(...fields: Array<string & keyof T>): this;
572
+ groupBy(...fields: Array<string & keyof T>): this;
573
+ having(field: string, op: string, value: unknown): this;
574
+ exists(relation: string, fn?: (q: IQueryBuilder<any>) => IQueryBuilder<any>): this;
575
+ notExists(relation: string, fn?: (q: IQueryBuilder<any>) => IQueryBuilder<any>): this;
576
+ limit(n: number): this;
577
+ offset(n: number): this;
578
+ include(relation: string): this;
579
+ join(model: string): IJoinClause<T>;
580
+ /** leftJoin 便捷方法 */
581
+ leftJoin(model: string): IJoinClause<T>;
582
+ /** innerJoin 便捷方法 */
583
+ innerJoin(model: string): IJoinClause<T>;
584
+ /** 执行查询,返回结果列表 */
585
+ fetch(): Promise<T[]>;
586
+ /** 执行查询,返回单条结果 */
587
+ fetchOne(): Promise<T | null>;
588
+ /** 执行计数查询 */
589
+ count(): Promise<number>;
590
+ /** 执行聚合查询 */
591
+ aggregate(args: AggregateQueryArgs): Promise<any>;
592
+ /** 执行 groupBy 查询 */
593
+ fetchGroupBy(args: GroupByQueryArgs): Promise<any[]>;
594
+ /** 构建完整的查询参数 */
595
+ private buildQueryArgs;
596
+ /** 将条件组转换为 Prisma where 对象 */
597
+ private buildWhere;
598
+ /** Allowed Prisma operators — prevents arbitrary operator injection */
599
+ private static readonly ALLOWED_OPS;
600
+ /** 将单个条件转换为 Prisma 条件 */
601
+ private buildCondition;
602
+ /** 构建含 exists 子查询的 WHERE 条件 */
603
+ private buildWhereWithExists;
604
+ /** 构建 HAVING 条件(用于 groupBy) */
605
+ private buildHaving;
606
+ /** 构建 include 对象(将 JOIN 和 include 合并) */
607
+ private buildInclude;
608
+ }
609
+
610
+ /**
611
+ * Abstract base service providing standard CRUD operations with entity event support.
612
+ *
613
+ * Subclasses should provide the model name and optionally customize the default order field.
614
+ *
615
+ * @template T - The entity type, must extend GenericEntity
616
+ */
617
+ declare abstract class BaseService<T extends GenericEntity> {
618
+ protected readonly db: DatabaseAdapter;
619
+ protected readonly dynamicQuery: DynamicQueryService;
620
+ protected readonly eventBus?: TopicEventBus | undefined;
621
+ protected readonly logger: Logger;
622
+ protected readonly modelName: string;
623
+ protected readonly defaultOrderField: string;
624
+ constructor(db: DatabaseAdapter, dynamicQuery: DynamicQueryService, modelName: string, eventBus?: TopicEventBus | undefined, options?: {
625
+ defaultOrderField?: string;
626
+ });
627
+ /**
628
+ * 创建记录
629
+ * @param data 实体数据
630
+ * @returns 创建后的完整实体
631
+ */
632
+ create(data: Partial<T>): Promise<T>;
633
+ /**
634
+ * 根据 ID 更新记录
635
+ * @param id 记录 ID
636
+ * @param data 要更新的字段
637
+ * @returns 更新后的完整实体
638
+ * @throws NotFoundException 记录不存在时
639
+ */
640
+ update(id: string, data: Partial<T>): Promise<T>;
641
+ /**
642
+ * 保存或更新单条记录 — 有 ID 则 update,无 ID 则 create
643
+ * 发送保存操作的实体生命周期事件
644
+ * @param data 实体数据
645
+ * @returns 保存后的完整实体
646
+ */
647
+ saveOrUpdate(data: Partial<T>): Promise<T>;
648
+ /**
649
+ * 根据 ID 删除记录
650
+ * @param id 记录 ID
651
+ * @returns 被删除的实体
652
+ * @throws NotFoundException 记录不存在时
653
+ */
654
+ delete(id: string): Promise<T>;
655
+ /**
656
+ * 根据 ID 查询单条记录
657
+ * @param id 记录 ID
658
+ * @returns 查询到的实体
659
+ * @throws NotFoundException 记录不存在时
660
+ */
661
+ findOne(id: string): Promise<T>;
662
+ /**
663
+ * 动态条件查询(带分页)
664
+ * @param query 动态查询参数
665
+ * @returns 分页查询结果
666
+ */
667
+ findAll(query: DynamicQueryParam): Promise<PaginatedResult<T>>;
668
+ /**
669
+ * 根据 ID 查询,返回 null 而不抛异常
670
+ * 记录不存在时返回空值
671
+ * @param id 记录 ID
672
+ * @returns 实体或 null(不存在时返回 null)
673
+ */
674
+ findByIdOptional(id: string): Promise<T | null>;
675
+ /**
676
+ * 根据 ID 列表批量查询
677
+ */
678
+ findByIds(ids: string[]): Promise<T[]>;
679
+ /**
680
+ * 查询总数
681
+ */
682
+ count(where?: Record<string, unknown>): Promise<number>;
683
+ /**
684
+ * 根据动态查询参数查询总数
685
+ */
686
+ countByQuery(query: DynamicQueryParam): Promise<number>;
687
+ /**
688
+ * 判断数据是否存在
689
+ */
690
+ exists(query: DynamicQueryParam): Promise<boolean>;
691
+ /**
692
+ * 分页查询
693
+ * - 如果 param.total 已设置(前端传入),跳过 count 查询
694
+ * - count 为 0 时直接返回空结果
695
+ * - 自动调用 rePaging 修正越界页码
696
+ */
697
+ queryPager(param: DynamicQueryParam): Promise<PaginatedResult<T>>;
698
+ /**
699
+ * 批量保存(upsert 语义)
700
+ * 有 ID 则 update,无 ID 则 create
701
+ * 发出 SAVE 类型事件(EntityBeforeSaveEvent / EntitySavedEvent)
702
+ * @returns SaveResult { created: number, updated: number, total: number }
703
+ */
704
+ save(entities: Partial<T>[]): Promise<{
705
+ created: number;
706
+ updated: number;
707
+ total: number;
708
+ }>;
709
+ /**
710
+ * 批量创建记录(不触发事件)
711
+ * @param data 实体数据数组
712
+ * @returns 创建数量
713
+ */
714
+ createMany(data: Partial<T>[]): Promise<{
715
+ count: number;
716
+ }>;
717
+ /**
718
+ * 按条件批量更新记录
719
+ * @param where 过滤条件
720
+ * @param data 要更新的字段
721
+ * @returns 更新数量
722
+ */
723
+ updateMany(where: Record<string, unknown>, data: Partial<T>): Promise<{
724
+ count: number;
725
+ }>;
726
+ /**
727
+ * 按条件批量删除记录
728
+ * @param where 过滤条件
729
+ * @returns 删除数量
730
+ */
731
+ deleteMany(where: Record<string, unknown>): Promise<{
732
+ count: number;
733
+ }>;
734
+ /**
735
+ * 软删除(设置 deletedAt 字段)
736
+ * @param id 记录 ID
737
+ * @returns 更新后的实体
738
+ */
739
+ softDelete(id: string): Promise<T>;
740
+ /**
741
+ * 恢复软删除的记录(清除 deletedAt 字段)
742
+ * @param id 记录 ID
743
+ * @returns 恢复后的实体
744
+ */
745
+ restore(id: string): Promise<T>;
746
+ /** 创建链式查询构建器 */
747
+ createQuery(): IQueryBuilder<T>;
748
+ /**
749
+ * 乐观锁批量更新
750
+ * 使用 updatedAt 作为版本号,只有 updatedAt 匹配时才执行更新
751
+ * @param items 待更新的记录数组,每条记录必须包含 id 和 updatedAt
752
+ * @returns { count: 成功更新数, failed: 冲突记录数组 }
753
+ */
754
+ updateManyWithOptimisticLock(items: Array<Partial<T> & {
755
+ id: string;
756
+ updatedAt: Date;
757
+ }>): Promise<{
758
+ count: number;
759
+ failed: T[];
760
+ }>;
761
+ /**
762
+ * 批量创建(带事件)
763
+ */
764
+ createBatch(items: Partial<T>[], options?: {
765
+ skipEvents?: boolean;
766
+ }): Promise<T[]>;
767
+ /**
768
+ * 批量更新(带事件)
769
+ */
770
+ updateBatch(items: (Partial<T> & {
771
+ id: string;
772
+ })[], options?: {
773
+ skipEvents?: boolean;
774
+ }): Promise<T[]>;
775
+ /**
776
+ * 批量删除(带事件)
777
+ */
778
+ deleteBatch(ids: string[], options?: {
779
+ skipEvents?: boolean;
780
+ }): Promise<number>;
781
+ /**
782
+ * 执行事务
783
+ * @param fn 事务回调函数
784
+ * @returns 事务执行结果
785
+ */
786
+ transaction<R>(fn: (db: DatabaseAdapter) => Promise<R>): Promise<R>;
787
+ protected emitEvent(type: EntityEventType, phase: EntityEventPhase, entity: unknown): Promise<EntityEvent>;
788
+ /**
789
+ * 发出 BEFORE 阶段事件并检查是否被取消
790
+ * 如果事件被取消,抛出 OperationCancelledException
791
+ */
792
+ protected emitEventWithCancelCheck(type: EntityEventType, entity: unknown): Promise<void>;
793
+ }
794
+
795
+ declare class BaseControllerHost<T extends GenericEntity> {
796
+ protected readonly service: BaseService<T>;
797
+ create(..._args: unknown[]): Promise<T>;
798
+ findOne(..._args: unknown[]): Promise<T>;
799
+ findAll(..._args: unknown[]): Promise<unknown>;
800
+ saveOrUpdate(..._args: unknown[]): Promise<T>;
801
+ update(..._args: unknown[]): Promise<T>;
802
+ delete(..._args: unknown[]): Promise<T>;
803
+ save(..._args: unknown[]): Promise<{
804
+ created: number;
805
+ updated: number;
806
+ total: number;
807
+ }>;
808
+ createMany(..._args: unknown[]): Promise<{
809
+ count: number;
810
+ }>;
811
+ updateMany(..._args: unknown[]): Promise<{
812
+ count: number;
813
+ }>;
814
+ deleteMany(..._args: unknown[]): Promise<{
815
+ count: number;
816
+ }>;
817
+ queryNoPaging(..._args: unknown[]): Promise<T[]>;
818
+ queryNoPagingPost(..._args: unknown[]): Promise<T[]>;
819
+ queryPager(..._args: unknown[]): Promise<unknown>;
820
+ queryPagerPost(..._args: unknown[]): Promise<unknown>;
821
+ count(..._args: unknown[]): Promise<{
822
+ total: number;
823
+ }>;
824
+ countPost(..._args: unknown[]): Promise<{
825
+ total: number;
826
+ }>;
827
+ exists(..._args: unknown[]): Promise<{
828
+ exists: boolean;
829
+ }>;
830
+ existsPost(..._args: unknown[]): Promise<{
831
+ exists: boolean;
832
+ }>;
833
+ }
834
+ declare function BaseController<T extends GenericEntity>(EntityClass: Type<T>): Type<BaseControllerHost<T>>;
835
+
836
+ interface CacheEnabledServiceOptions {
837
+ /** 缓存 TTL(毫秒) */
838
+ ttlMs?: number;
839
+ /** 默认排序字段 */
840
+ defaultOrderField?: string;
841
+ }
842
+ /**
843
+ * 带缓存的 CRUD 服务
844
+ * - findOne/findById 自动读缓存、写缓存(带 TTL)
845
+ * - update/delete 自动失效缓存,发布缓存清除事件
846
+ */
847
+ declare abstract class CacheEnabledService<T extends GenericEntity> extends BaseService<T> {
848
+ protected readonly cache: ICache;
849
+ protected readonly cacheLogger: Logger;
850
+ protected readonly ttlMs: number;
851
+ constructor(db: DatabaseAdapter, dynamicQuery: DynamicQueryService, modelName: string, cache: ICache, eventBus?: TopicEventBus, options?: CacheEnabledServiceOptions);
852
+ /**
853
+ * 获取缓存名称
854
+ */
855
+ getCacheName(): string;
856
+ /** 生成缓存键 */
857
+ protected getCacheKey(id: string): string;
858
+ /** 全量缓存键 */
859
+ protected getAllCacheKey(): string;
860
+ /**
861
+ * 获取全量数据(优先走缓存)
862
+ * 适用于数据量较小的配置表、字典表等
863
+ */
864
+ getCacheAll(): Promise<T[]>;
865
+ /**
866
+ * 创建后失效全量缓存
867
+ */
868
+ create(data: Partial<T>): Promise<T>;
869
+ /**
870
+ * 批量保存后失效缓存
871
+ */
872
+ save(entities: Partial<T>[]): Promise<{
873
+ created: number;
874
+ updated: number;
875
+ total: number;
876
+ }>;
877
+ /** 读取时优先走缓存 */
878
+ findOne(id: string): Promise<T>;
879
+ /** 更新后失效缓存 */
880
+ update(id: string, data: Partial<T>): Promise<T>;
881
+ /** 删除后失效缓存 */
882
+ delete(id: string): Promise<T>;
883
+ /** 软删除后失效缓存 */
884
+ softDelete(id: string): Promise<T>;
885
+ /**
886
+ * 批量创建后失效全量缓存
887
+ */
888
+ createMany(data: Partial<T>[]): Promise<{
889
+ count: number;
890
+ }>;
891
+ /**
892
+ * 批量更新后失效全量缓存
893
+ */
894
+ updateMany(where: Record<string, unknown>, data: Partial<T>): Promise<{
895
+ count: number;
896
+ }>;
897
+ /**
898
+ * 批量删除后失效全量缓存
899
+ */
900
+ deleteMany(where: Record<string, unknown>): Promise<{
901
+ count: number;
902
+ }>;
903
+ /**
904
+ * 失效指定 ID 的缓存,并发布缓存清除事件
905
+ *
906
+ * 事务感知行为:
907
+ * - 有事务上下文时:注册 afterCommit 回调,commit 后才真正失效缓存
908
+ * 这样如果事务回滚,缓存不会被错误清除
909
+ * - 无事务上下文时:立即执行缓存失效
910
+ */
911
+ protected invalidateCache(id: string): Promise<void>;
912
+ /**
913
+ * 批量删除后失效缓存
914
+ */
915
+ deleteBatch(ids: string[], options?: {
916
+ skipEvents?: boolean;
917
+ }): Promise<number>;
918
+ /** 批量失效缓存 */
919
+ protected invalidateCacheMany(ids: string[]): Promise<void>;
920
+ }
921
+ /**
922
+ * @Cacheable() 方法装饰器
923
+ * 为任意方法添加缓存能力,使用方法的第一个参数作为缓存键的一部分
924
+ */
925
+ declare function Cacheable(options?: {
926
+ ttlMs?: number;
927
+ keyPrefix?: string;
928
+ }): MethodDecorator;
929
+
930
+ /** 支持软删除的实体接口 */
931
+ interface SoftDeletableEntity extends GenericEntity {
932
+ deletedAt?: Date | null;
933
+ }
934
+ /** 软删除查询选项 */
935
+ interface SoftDeleteQueryOptions {
936
+ includeDeleted?: boolean;
937
+ }
938
+ /**
939
+ * 软删除服务
940
+ * - 所有查询自动加 WHERE deletedAt IS NULL 条件
941
+ * - delete() 执行软删除而非物理删除
942
+ * - 通过 options.includeDeleted 参数临时包含已删除记录
943
+ * - restore(id) 恢复已删除记录
944
+ */
945
+ declare abstract class SoftDeleteService<T extends SoftDeletableEntity> extends BaseService<T> {
946
+ constructor(db: DatabaseAdapter, dynamicQuery: DynamicQueryService, modelName: string, eventBus?: TopicEventBus, options?: {
947
+ defaultOrderField?: string;
948
+ });
949
+ /** 查询单条记录(自动排除已删除) */
950
+ findOne(id: string, options?: SoftDeleteQueryOptions): Promise<T>;
951
+ /** 分页查询(自动排除已删除) */
952
+ findAll(query: DynamicQueryParam, options?: SoftDeleteQueryOptions): Promise<PaginatedResult<T>>;
953
+ /**
954
+ * 执行软删除(设置 deletedAt)
955
+ * BEFORE 阶段检查取消标志,支持监听器取消删除操作
956
+ */
957
+ delete(id: string): Promise<T>;
958
+ /** 批量软删除 */
959
+ deleteMany(where: Record<string, unknown>, options?: SoftDeleteQueryOptions): Promise<{
960
+ count: number;
961
+ }>;
962
+ /** 恢复已删除记录 */
963
+ restore(id: string): Promise<T>;
964
+ /**
965
+ * @deprecated Use `findAll(query, { includeDeleted: true })` or
966
+ * `findOne(id, { includeDeleted: true })` instead.
967
+ * This method uses Object.create(this) which causes shared mutable state bugs.
968
+ */
969
+ withDeleted(): this;
970
+ /**
971
+ * 物理删除(真正从数据库删除)
972
+ */
973
+ forceDelete(id: string): Promise<T>;
974
+ /** 在查询参数中注入软删除过滤条件 */
975
+ private injectSoftDeleteFilter;
976
+ }
977
+
978
+ /**
979
+ * Abstract service for tree-structured entities with automatic path/level management.
980
+ * Extends BaseService with tree-specific operations: findAsTree, moveNode, rebuildPath, etc.
981
+ *
982
+ * @template T - The entity type, must extend TreeSortSupportEntity
983
+ */
984
+ declare abstract class TreeService<T extends TreeSortSupportEntity> extends BaseService<T> {
985
+ protected readonly treeLogger: Logger;
986
+ protected readonly pathStrategy?: TreePathStrategy;
987
+ /**
988
+ * 获取批量操作的缓冲大小
989
+ */
990
+ getBufferSize(): number;
991
+ /**
992
+ * 设置子节点
993
+ */
994
+ setChildren(entity: T, children: T[]): void;
995
+ /**
996
+ * 获取子节点
997
+ */
998
+ getChildren(entity: T): T[];
999
+ /**
1000
+ * 查询所有数据并组装为树形结构
1001
+ */
1002
+ findAsTree(): Promise<T[]>;
1003
+ /**
1004
+ * 查询指定父节点下的所有子节点(直接子节点)
1005
+ */
1006
+ findChildren(parentId: string): Promise<T[]>;
1007
+ /**
1008
+ * 查询节点及其所有后代(利用 path 前缀匹配)
1009
+ */
1010
+ findWithChildren(id: string): Promise<T[]>;
1011
+ /**
1012
+ * 创建节点时自动计算 path、level 和 sortIndex
1013
+ */
1014
+ create(data: Partial<T>): Promise<T>;
1015
+ /**
1016
+ * 重建所有节点的 path 和 level 字段
1017
+ */
1018
+ rebuildPath(): Promise<void>;
1019
+ /**
1020
+ * 查询指定 ID 的实体及其所有后代节点
1021
+ * 使用 path 前缀匹配,并自动去重
1022
+ */
1023
+ queryIncludeChildren(ids: string[]): Promise<T[]>;
1024
+ /**
1025
+ * 根据查询参数查询数据,并包含所有匹配节点的子节点
1026
+ * 保留 includes/excludes 字段选择
1027
+ */
1028
+ queryIncludeChildrenByQuery(queryParam: DynamicQueryParam): Promise<T[]>;
1029
+ /**
1030
+ * 查询节点及所有后代(通过 path 前缀匹配)
1031
+ * @deprecated 使用 queryIncludeChildren() 代替
1032
+ */
1033
+ findByTreeChild(parentIds: string[]): Promise<T[]>;
1034
+ /**
1035
+ * 向上查找所有祖先节点
1036
+ */
1037
+ findParents(childId: string): Promise<T[]>;
1038
+ /**
1039
+ * 查找同级节点
1040
+ */
1041
+ findSiblings(nodeId: string): Promise<T[]>;
1042
+ /**
1043
+ * 查询指定 ID 节点的所有父/祖先节点(通过 path 反向匹配)
1044
+ */
1045
+ queryIncludeParent(ids: string[]): Promise<T[]>;
1046
+ /**
1047
+ * 删除节点及其所有后代(通过 path 前缀匹配级联删除)
1048
+ * 通过路径前缀匹配级联删除子节点
1049
+ */
1050
+ delete(id: string): Promise<T>;
1051
+ /**
1052
+ * 批量删除节点及其后代
1053
+ */
1054
+ deleteBatch(ids: string[], options?: {
1055
+ skipEvents?: boolean;
1056
+ }): Promise<number>;
1057
+ /**
1058
+ * 保存/更新时自动处理树属性
1059
+ * - 校验循环依赖
1060
+ * - 展开子节点
1061
+ * - 自动分配 path, level, sortIndex
1062
+ */
1063
+ save(entities: Partial<T>[]): Promise<SaveResult>;
1064
+ /**
1065
+ * 查询并返回树形结构(使用查询参数)
1066
+ */
1067
+ queryResultToTree(queryParam?: DynamicQueryParam): Promise<T[]>;
1068
+ /**
1069
+ * 查询符合条件的数据及其所有子节点,组装为树
1070
+ */
1071
+ queryIncludeChildrenTree(queryParam: DynamicQueryParam): Promise<T[]>;
1072
+ /**
1073
+ * 校验循环依赖
1074
+ * 防止将节点的父节点设置为自己的子节点
1075
+ */
1076
+ checkCyclicDependency(nodeId: string, newParentId: string | null): Promise<void>;
1077
+ /**
1078
+ * 判断节点是否为根节点
1079
+ */
1080
+ isRootNode(entity: T): boolean;
1081
+ /**
1082
+ * 移动节点到新的父节点下
1083
+ */
1084
+ moveNode(id: string, newParentId: string | null): Promise<T>;
1085
+ /**
1086
+ * 获取同级节点的下一个 sortIndex
1087
+ */
1088
+ protected getNextSortIndex(parentId: string | null): Promise<number>;
1089
+ /**
1090
+ * 展开树形输入数据为扁平列表
1091
+ * 递归遍历 children 字段,将嵌套树结构展平
1092
+ */
1093
+ private expandTreeToList;
1094
+ private buildTree;
1095
+ /**
1096
+ * 通过向上遍历祖先链计算 path 和 level,避免加载全表。
1097
+ */
1098
+ private computePathByAncestors;
1099
+ private computePath;
1100
+ }
1101
+
1102
+ declare class TreeControllerHost<T extends TreeSortSupportEntity> {
1103
+ protected readonly service: TreeService<T>;
1104
+ findAllTree(..._args: unknown[]): Promise<T[]>;
1105
+ findAllChildren(..._args: unknown[]): Promise<T[]>;
1106
+ findAllChildrenTree(..._args: unknown[]): Promise<T[]>;
1107
+ }
1108
+ /**
1109
+ * 树形结构控制器工厂
1110
+ * 提供树形查询和树节点 CRUD 路由
1111
+ *
1112
+ * 路由:
1113
+ * - GET /_query/tree 动态查询并返回树形结构
1114
+ * - POST /_query/tree POST方式动态查询并返回树形结构
1115
+ * - GET /_query/_children 动态查询并返回子节点数据(扁平)
1116
+ * - POST /_query/_children POST方式动态查询并返回子节点数据(扁平)
1117
+ * - GET /_query/_children/tree 动态查询并返回子节点树形结构
1118
+ * - POST /_query/_children/tree POST方式动态查询并返回子节点树形结构
1119
+ * - DELETE /{id} 删除节点及其所有子节点
1120
+ */
1121
+ declare function TreeController<T extends TreeSortSupportEntity>(EntityClass: Type<T>): Type<TreeControllerHost<T>>;
1122
+
1123
+ /** Minimal interface for a Prisma-like client */
1124
+ interface PrismaLikeClient extends Record<string, unknown> {
1125
+ $transaction<T>(fn: (tx: Record<string, unknown>) => Promise<T>): Promise<T>;
1126
+ }
1127
+ interface PrismaAdapterOptions {
1128
+ /** 项目级别的额外模型名别名(业务侧覆盖 framework 默认) */
1129
+ modelAliases?: Record<string, string>;
1130
+ }
1131
+ declare class PrismaAdapter extends TransactionAwareDatabaseAdapter {
1132
+ private readonly prisma;
1133
+ private readonly aliases;
1134
+ constructor(prisma: PrismaLikeClient, options?: PrismaAdapterOptions);
1135
+ model(name: string): ModelOperations;
1136
+ protected doTransaction<R>(fn: (adapter: DatabaseAdapter) => Promise<R>): Promise<R>;
1137
+ }
1138
+
1139
+ interface PrismaDatabaseAdapterModuleOptions {
1140
+ /** 项目侧 PrismaService class(构造时会被作为 inject token) */
1141
+ prismaService: Type<unknown>;
1142
+ /** 项目侧 PrismaModule(含 PrismaService)。
1143
+ * 通常需要传入,否则在 forRoot 模块作用域内拿不到 PrismaService。 */
1144
+ prismaModule?: Type<unknown> | DynamicModule;
1145
+ /**
1146
+ * 业务侧扩展模型名别名。会与框架默认别名 merge。
1147
+ * 例:{ aiModels: 'aIModel' }(Prisma client AIModel → aIModel)
1148
+ */
1149
+ modelAliases?: Record<string, string>;
1150
+ /** 是否注册为 @Global()。默认 true(@zucker-framework/ai 等需全局可见 DATABASE_ADAPTER) */
1151
+ global?: boolean;
1152
+ }
1153
+ /**
1154
+ * 现成的 Nest dynamic module:把 PrismaService 包装成 `DATABASE_ADAPTER`
1155
+ * provider,让 @zucker-framework/ai 的 AIConfigService、PromptManager 等开箱使用。
1156
+ *
1157
+ * 比 ZuckerCrudModule.forRootAsync 更轻量:不带 dynamic-query / 操作符 /
1158
+ * BaseService 等 CRUD 周边,仅注册 DATABASE_ADAPTER + PrismaAdapter 实例。
1159
+ *
1160
+ * 用法(项目 AppModule):
1161
+ * ```ts
1162
+ * import { PrismaModule, PrismaService } from '@/prisma';
1163
+ *
1164
+ * @Module({
1165
+ * imports: [
1166
+ * PrismaDatabaseAdapterModule.forRoot({
1167
+ * prismaService: PrismaService,
1168
+ * prismaModule: PrismaModule,
1169
+ * modelAliases: { aiModels: 'aIModel' },
1170
+ * }),
1171
+ * ZuckerAIModule.forRoot({ ... }),
1172
+ * ],
1173
+ * })
1174
+ * ```
1175
+ */
1176
+ declare class PrismaDatabaseAdapterModule {
1177
+ static forRoot(options: PrismaDatabaseAdapterModuleOptions): DynamicModule;
1178
+ }
1179
+
1180
+ /**
1181
+ * InMemoryAdapter — development / testing database adapter.
1182
+ *
1183
+ * Stores all data in a plain JS Map<model, Map<id, record>>.
1184
+ * Supports simple Prisma-style where-clauses (equality only) and
1185
+ * auto-generates string IDs when missing.
1186
+ *
1187
+ * NOT suitable for production — data is lost on restart.
1188
+ *
1189
+ * Usage:
1190
+ * ```typescript
1191
+ * ZuckerCrudModule.forRoot({ adapterClass: InMemoryAdapter })
1192
+ * ```
1193
+ */
1194
+ declare class InMemoryAdapter extends TransactionAwareDatabaseAdapter {
1195
+ /** Shared store across all model instances */
1196
+ private readonly store;
1197
+ private getStore;
1198
+ model(name: string): ModelOperations;
1199
+ protected doTransaction<T>(fn: (adapter: DatabaseAdapter) => Promise<T>): Promise<T>;
1200
+ }
1201
+
1202
+ interface CurrentUserProvider {
1203
+ getCurrentUserId(): string | undefined;
1204
+ getCurrentUserName(): string | undefined;
1205
+ }
1206
+ declare const CURRENT_USER_PROVIDER = "CURRENT_USER_PROVIDER";
1207
+ declare class CreatorEventListener {
1208
+ private readonly userProvider?;
1209
+ private readonly eventBus?;
1210
+ constructor(userProvider?: CurrentUserProvider | undefined, eventBus?: TopicEventBus | undefined);
1211
+ private registerListeners;
1212
+ private handleCreate;
1213
+ private handleUpdate;
1214
+ }
1215
+
1216
+ /**
1217
+ * 实体验证规则注册表
1218
+ * 使用方通过 registerSchema() 注册实体的验证规则
1219
+ */
1220
+ interface EntityValidationRegistry {
1221
+ /**
1222
+ * 获取指定实体类型的验证规则
1223
+ * @param entityType 实体模型名称
1224
+ * @param group 验证分组 ('create' | 'update')
1225
+ * @returns 验证规则,如果没有注册规则则返回 undefined
1226
+ */
1227
+ getSchema(entityType: string, group: string): ValidationSchema | undefined;
1228
+ }
1229
+ declare const ENTITY_VALIDATION_REGISTRY = "ENTITY_VALIDATION_REGISTRY";
1230
+ declare class ValidateEventListener {
1231
+ private readonly registry?;
1232
+ private readonly eventBus?;
1233
+ private readonly logger;
1234
+ constructor(registry?: EntityValidationRegistry | undefined, eventBus?: TopicEventBus | undefined);
1235
+ private registerListeners;
1236
+ private handleValidation;
1237
+ }
1238
+ /**
1239
+ * 简单的内存验证规则注册表实现
1240
+ */
1241
+ declare class SimpleEntityValidationRegistry implements EntityValidationRegistry {
1242
+ private readonly schemas;
1243
+ /**
1244
+ * 注册实体验证规则
1245
+ * @param entityType 实体模型名称
1246
+ * @param group 验证分组 ('create' | 'update')
1247
+ * @param schema 验证规则
1248
+ */
1249
+ registerSchema(entityType: string, group: string, schema: ValidationSchema): void;
1250
+ getSchema(entityType: string, group: string): ValidationSchema | undefined;
1251
+ }
1252
+
1253
+ /**
1254
+ * QueryAnalyzer — 查询分析优化
1255
+ */
1256
+
1257
+ interface OptimizedQuery {
1258
+ /** 优化后的查询参数 */
1259
+ query: DynamicQueryParam;
1260
+ /** 用于 count 的查询(去掉 orderBy 和 select) */
1261
+ countQuery: DynamicQueryParam;
1262
+ /** 检测到的潜在问题 */
1263
+ warnings: string[];
1264
+ }
1265
+ declare class QueryAnalyzer {
1266
+ /**
1267
+ * 分析查询参数并返回优化后的查询
1268
+ */
1269
+ static analyze(queryParam: DynamicQueryParam): OptimizedQuery;
1270
+ }
1271
+
1272
+ interface CrudModuleAsyncOptions {
1273
+ imports?: Array<Type | DynamicModule>;
1274
+ useFactory?: (...args: unknown[]) => DatabaseAdapter | Promise<DatabaseAdapter>;
1275
+ useClass?: Type<DatabaseAdapter>;
1276
+ useExisting?: InjectionToken;
1277
+ inject?: Array<InjectionToken | OptionalFactoryDependency>;
1278
+ }
1279
+ declare class ZuckerCrudModule {
1280
+ static forRoot(options: {
1281
+ adapterClass: Type<DatabaseAdapter>;
1282
+ }): DynamicModule;
1283
+ static forRootAsync(options: CrudModuleAsyncOptions): DynamicModule;
1284
+ private static createAdapterProvider;
1285
+ }
1286
+
1287
+ /**
1288
+ * CRUD 自动生成装饰器 — 对标 Claude Code Tool 统一注册模式
1289
+ *
1290
+ * 将重复的 CRUD Controller 代码抽象为声明式配置。
1291
+ * 生成标准端点: POST /_query, GET /:id, POST /, PUT /:id, DELETE /:id
1292
+ *
1293
+ * 注意: 这是元数据标记 + mixin 模式,需配合 CrudControllerFactory 使用。
1294
+ *
1295
+ * 用法:
1296
+ * ```ts
1297
+ * @Controller('admin/users')
1298
+ * class UsersController extends CrudControllerFactory(UserService, {
1299
+ * routes: {
1300
+ * query: { decorators: [Permissions('user:query')] },
1301
+ * create: { decorators: [Permissions('user:add')] },
1302
+ * },
1303
+ * }) {
1304
+ * // 自动拥有 query/findOne/create/update/delete 方法
1305
+ * // 只需手写非标准端点
1306
+ * }
1307
+ * ```
1308
+ */
1309
+ declare const CRUD_METADATA: unique symbol;
1310
+ interface CrudRouteConfig {
1311
+ /** 额外的装饰器(如权限控制) */
1312
+ decorators?: MethodDecorator[];
1313
+ /** 是否启用此路由(默认 true) */
1314
+ enabled?: boolean;
1315
+ }
1316
+ interface CrudOptions {
1317
+ routes?: {
1318
+ query?: CrudRouteConfig;
1319
+ findOne?: CrudRouteConfig;
1320
+ create?: CrudRouteConfig;
1321
+ update?: CrudRouteConfig;
1322
+ delete?: CrudRouteConfig;
1323
+ };
1324
+ /** 软删除模式(delete 时调用 softDelete 而非 delete) */
1325
+ softDelete?: boolean;
1326
+ }
1327
+ /**
1328
+ * CRUD Controller 工厂
1329
+ *
1330
+ * 生成一个带标准 CRUD 方法的基类,子类可以覆写或扩展。
1331
+ */
1332
+ declare function CrudControllerFactory<T>(serviceToken: new (...args: unknown[]) => T, options?: CrudOptions): new (...args: unknown[]) => object;
1333
+
1334
+ export { ALL_OPERATORS, type AggregateQueryArgs, BaseController, BaseControllerHost, BaseService, BetweenOperator, CRUD_METADATA, CURRENT_USER_PROVIDER, CacheEnabledService, type CacheEnabledServiceOptions, Cacheable, ContainsOperator, CreatorEventListener, CrudControllerFactory, type CrudModuleAsyncOptions, type CrudOptions, type CrudRouteConfig, type CurrentUserProvider, type DynamicQueryParam, DynamicQueryParamService, DynamicQueryService, ENTITY_VALIDATION_REGISTRY, EmptyOperator, EndsWithOperator, type EntityValidationRegistry, EqualsOperator, FILTER_OPERATORS, FilterOperatorFactory, type FilterOperatorType, type GroupByQueryArgs, GtOperator, GteOperator, HasOperator, HasSomeOperator, type IFilterOperator, type IJoinClause, type IQueryBuilder, InMemoryAdapter, InOperator, IsNotNullOperator, IsNullOperator, LikeOperator, LtOperator, LteOperator, NotEmptyOperator, NotEqualsOperator, NotInOperator, NotLikeOperator, type OptimizedQuery, type PaginatedResult, PrismaAdapter, type PrismaAdapterOptions, PrismaDatabaseAdapterModule, type PrismaDatabaseAdapterModuleOptions, QueryAnalyzer, QueryBuilder, QueryParamEntity as QueryParam, QueryParamEntity, type SaveResult, SimpleEntityValidationRegistry, type SoftDeletableEntity, type SoftDeleteQueryOptions, SoftDeleteService, StartsWithOperator, TermExpressionParser, TreeController, TreeControllerHost, TreeService, ValidateEventListener, ZuckerCrudModule, calculateTotalPages, emptyPagerResult, isPaged, mergeSaveResult, noPaging, parseExpression, parseFilterMap, rePaging, toPaginatedResult };