@wordrhyme/auto-crud-server 0.4.0 → 0.6.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/README.md +124 -1
- package/dist/index.cjs +240 -95
- package/dist/index.d.cts +232 -72
- package/dist/index.d.ts +242 -82
- package/dist/index.js +231 -96
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { SQL } from "drizzle-orm";
|
|
3
|
-
import * as
|
|
3
|
+
import * as _trpc_server5 from "@trpc/server";
|
|
4
4
|
import superjson from "superjson";
|
|
5
5
|
import { PostgresJsDatabase } from "drizzle-orm/postgres-js";
|
|
6
6
|
import * as node_modules__trpc_server_dist_unstable_core_do_not_import_d_CjQPvBRI_mjs0 from "node_modules/@trpc/server/dist/unstable-core-do-not-import.d-CjQPvBRI.mjs";
|
|
@@ -14,13 +14,13 @@ import { PgTable } from "drizzle-orm/pg-core";
|
|
|
14
14
|
interface Context {
|
|
15
15
|
db: PostgresJsDatabase<Record<string, never>>;
|
|
16
16
|
}
|
|
17
|
-
declare const router:
|
|
17
|
+
declare const router: _trpc_server5.TRPCRouterBuilder<{
|
|
18
18
|
ctx: Context;
|
|
19
19
|
meta: object;
|
|
20
|
-
errorShape:
|
|
20
|
+
errorShape: _trpc_server5.TRPCDefaultErrorShape;
|
|
21
21
|
transformer: true;
|
|
22
22
|
}>;
|
|
23
|
-
declare const publicProcedure:
|
|
23
|
+
declare const publicProcedure: _trpc_server5.TRPCProcedureBuilder<Context, object, object, _trpc_server5.TRPCUnsetMarker, _trpc_server5.TRPCUnsetMarker, _trpc_server5.TRPCUnsetMarker, _trpc_server5.TRPCUnsetMarker, false>;
|
|
24
24
|
//#endregion
|
|
25
25
|
//#region src/types/config.d.ts
|
|
26
26
|
type CrudOperation = "list" | "get" | "create" | "update" | "delete" | "deleteMany" | "updateMany";
|
|
@@ -73,89 +73,107 @@ interface ListResult<TSelect> {
|
|
|
73
73
|
pageCount: number;
|
|
74
74
|
}
|
|
75
75
|
/**
|
|
76
|
-
*
|
|
76
|
+
* 操作包装器 - 类似 tRPC middleware 的 next 模式
|
|
77
|
+
*
|
|
78
|
+
* 功能:
|
|
79
|
+
* - 修改输入数据(传参给 next)
|
|
80
|
+
* - 修改返回值(处理 next 的结果)
|
|
81
|
+
* - 执行副作用(日志、通知、审计)
|
|
82
|
+
* - 条件拦截(不调用 next 直接返回/抛错)
|
|
83
|
+
* - 包装事务(try/catch 包裹 next)
|
|
77
84
|
*
|
|
78
85
|
* @example
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
* await sendNotification(created);
|
|
86
|
+
* // 修改输入 + 执行副作用
|
|
87
|
+
* middleware: {
|
|
88
|
+
* create: async ({ ctx, input, next }) => {
|
|
89
|
+
* const data = { ...input, slug: slugify(input.title) };
|
|
90
|
+
* const result = await next(data);
|
|
91
|
+
* await sendNotification(result);
|
|
92
|
+
* return result;
|
|
87
93
|
* },
|
|
88
94
|
* }
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* // 简单副作用 - 使用工具函数
|
|
98
|
+
* import { afterMiddleware } from "@wordrhyme/auto-crud-server";
|
|
99
|
+
*
|
|
100
|
+
* middleware: {
|
|
101
|
+
* create: afterMiddleware(async (ctx, result) => {
|
|
102
|
+
* await sendEmail(result);
|
|
103
|
+
* }),
|
|
104
|
+
* }
|
|
89
105
|
*/
|
|
90
|
-
interface
|
|
91
|
-
/**
|
|
92
|
-
* 列表查询前
|
|
93
|
-
* 可修改查询参数
|
|
94
|
-
*/
|
|
95
|
-
beforeList?: (ctx: TContext, input: ListInput) => ListInput | void | Promise<ListInput | void>;
|
|
96
|
-
/**
|
|
97
|
-
* 列表查询后
|
|
98
|
-
* 可修改返回结果
|
|
99
|
-
*/
|
|
100
|
-
afterList?: <TSelect>(ctx: TContext, result: ListResult<TSelect>) => ListResult<TSelect> | void | Promise<ListResult<TSelect> | void>;
|
|
101
|
-
/**
|
|
102
|
-
* 单条查询前
|
|
103
|
-
*/
|
|
104
|
-
beforeGet?: (ctx: TContext, id: string) => void | Promise<void>;
|
|
105
|
-
/**
|
|
106
|
-
* 单条查询后
|
|
107
|
-
* 可修改返回结果
|
|
108
|
-
*/
|
|
109
|
-
afterGet?: <TSelect>(ctx: TContext, result: TSelect | null) => TSelect | null | void | Promise<TSelect | null | void>;
|
|
110
|
-
/**
|
|
111
|
-
* 创建前
|
|
112
|
-
* 可修改输入数据,返回新数据或抛出错误阻止创建
|
|
113
|
-
*/
|
|
114
|
-
beforeCreate?: <TInsert>(ctx: TContext, data: TInsert) => TInsert | void | Promise<TInsert | void>;
|
|
106
|
+
interface CrudMiddleware<TContext = unknown> {
|
|
115
107
|
/**
|
|
116
|
-
*
|
|
117
|
-
* 用于副作用(日志、通知、同步等)
|
|
108
|
+
* 列表查询包装器
|
|
118
109
|
*/
|
|
119
|
-
|
|
110
|
+
list?: (params: {
|
|
111
|
+
ctx: TContext;
|
|
112
|
+
input: ListInput;
|
|
113
|
+
next: (input?: ListInput) => Promise<ListResult<unknown>>;
|
|
114
|
+
}) => Promise<ListResult<unknown>>;
|
|
120
115
|
/**
|
|
121
|
-
*
|
|
122
|
-
* 可修改输入数据,existing 为更新前的记录
|
|
116
|
+
* 单条查询包装器
|
|
123
117
|
*/
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
118
|
+
get?: (params: {
|
|
119
|
+
ctx: TContext;
|
|
120
|
+
id: string;
|
|
121
|
+
next: () => Promise<unknown | null>;
|
|
122
|
+
}) => Promise<unknown | null>;
|
|
129
123
|
/**
|
|
130
|
-
*
|
|
131
|
-
* existing 为删除前的记录,可抛出错误阻止删除
|
|
124
|
+
* 创建包装器
|
|
132
125
|
*/
|
|
133
|
-
|
|
126
|
+
create?: (params: {
|
|
127
|
+
ctx: TContext;
|
|
128
|
+
input: unknown;
|
|
129
|
+
next: (input?: unknown) => Promise<unknown>;
|
|
130
|
+
}) => Promise<unknown>;
|
|
134
131
|
/**
|
|
135
|
-
*
|
|
132
|
+
* 更新包装器
|
|
133
|
+
* existing: 更新前的记录
|
|
136
134
|
*/
|
|
137
|
-
|
|
135
|
+
update?: (params: {
|
|
136
|
+
ctx: TContext;
|
|
137
|
+
id: string;
|
|
138
|
+
data: unknown;
|
|
139
|
+
existing: unknown;
|
|
140
|
+
next: (data?: unknown) => Promise<unknown>;
|
|
141
|
+
}) => Promise<unknown>;
|
|
138
142
|
/**
|
|
139
|
-
*
|
|
143
|
+
* 删除包装器
|
|
144
|
+
* existing: 删除前的记录
|
|
140
145
|
*/
|
|
141
|
-
|
|
146
|
+
delete?: (params: {
|
|
147
|
+
ctx: TContext;
|
|
148
|
+
id: string;
|
|
149
|
+
existing: unknown;
|
|
150
|
+
next: () => Promise<unknown>;
|
|
151
|
+
}) => Promise<unknown>;
|
|
142
152
|
/**
|
|
143
|
-
*
|
|
153
|
+
* 批量删除包装器
|
|
144
154
|
*/
|
|
145
|
-
|
|
155
|
+
deleteMany?: (params: {
|
|
156
|
+
ctx: TContext;
|
|
157
|
+
ids: string[];
|
|
158
|
+
next: () => Promise<{
|
|
159
|
+
deleted: number;
|
|
160
|
+
}>;
|
|
161
|
+
}) => Promise<{
|
|
146
162
|
deleted: number;
|
|
147
|
-
}
|
|
148
|
-
/**
|
|
149
|
-
* 批量更新前
|
|
150
|
-
* 可修改输入数据
|
|
151
|
-
*/
|
|
152
|
-
beforeUpdateMany?: <TUpdate>(ctx: TContext, ids: string[], data: TUpdate) => TUpdate | void | Promise<TUpdate | void>;
|
|
163
|
+
}>;
|
|
153
164
|
/**
|
|
154
|
-
*
|
|
165
|
+
* 批量更新包装器
|
|
155
166
|
*/
|
|
156
|
-
|
|
167
|
+
updateMany?: (params: {
|
|
168
|
+
ctx: TContext;
|
|
169
|
+
ids: string[];
|
|
170
|
+
data: unknown;
|
|
171
|
+
next: (data?: unknown) => Promise<{
|
|
172
|
+
updated: number;
|
|
173
|
+
}>;
|
|
174
|
+
}) => Promise<{
|
|
157
175
|
updated: number;
|
|
158
|
-
}
|
|
176
|
+
}>;
|
|
159
177
|
}
|
|
160
178
|
interface CrudRouterConfigBase<TContext = unknown> {
|
|
161
179
|
/** Drizzle 表定义 */
|
|
@@ -193,20 +211,34 @@ interface CrudRouterConfigBase<TContext = unknown> {
|
|
|
193
211
|
*/
|
|
194
212
|
softDelete?: SoftDeleteOption;
|
|
195
213
|
/**
|
|
196
|
-
*
|
|
197
|
-
*
|
|
214
|
+
* 操作中间件
|
|
215
|
+
* 类似 tRPC middleware 的 next 模式,完全控制操作流程
|
|
198
216
|
*
|
|
199
217
|
* @example
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
*
|
|
203
|
-
*
|
|
204
|
-
*
|
|
205
|
-
* await sendNotification(
|
|
218
|
+
* // 完整控制
|
|
219
|
+
* middleware: {
|
|
220
|
+
* create: async ({ ctx, input, next }) => {
|
|
221
|
+
* const data = { ...input, slug: slugify(input.title) };
|
|
222
|
+
* const result = await next(data);
|
|
223
|
+
* await sendNotification(result);
|
|
224
|
+
* return result;
|
|
206
225
|
* },
|
|
207
226
|
* }
|
|
227
|
+
*
|
|
228
|
+
* @example
|
|
229
|
+
* // 使用工具函数简化
|
|
230
|
+
* import { afterMiddleware, beforeMiddleware } from "@wordrhyme/auto-crud-server";
|
|
231
|
+
*
|
|
232
|
+
* middleware: {
|
|
233
|
+
* create: afterMiddleware(async (ctx, result) => {
|
|
234
|
+
* await sendEmail(result);
|
|
235
|
+
* }),
|
|
236
|
+
* update: beforeMiddleware(async (ctx, data) => {
|
|
237
|
+
* return { ...data, updatedAt: new Date() };
|
|
238
|
+
* }),
|
|
239
|
+
* }
|
|
208
240
|
*/
|
|
209
|
-
|
|
241
|
+
middleware?: CrudMiddleware<TContext>;
|
|
210
242
|
}
|
|
211
243
|
interface DeclarativeConfig<TContext = unknown> extends CrudRouterConfigBase<TContext> {
|
|
212
244
|
mode?: "declarative";
|
|
@@ -297,9 +329,9 @@ type CrudRouterConfig<TContext = unknown> = DeclarativeConfig<TContext> | Factor
|
|
|
297
329
|
declare function createCrudRouter<TContext = unknown>(config: CrudRouterConfig<TContext>): node_modules__trpc_server_dist_unstable_core_do_not_import_d_CjQPvBRI_mjs0.Router<{
|
|
298
330
|
ctx: Context;
|
|
299
331
|
meta: object;
|
|
300
|
-
errorShape:
|
|
332
|
+
errorShape: _trpc_server5.TRPCDefaultErrorShape;
|
|
301
333
|
transformer: true;
|
|
302
|
-
},
|
|
334
|
+
}, _trpc_server5.TRPCDecorateCreateRouterOptions<{
|
|
303
335
|
list: any;
|
|
304
336
|
getById: any;
|
|
305
337
|
create: any;
|
|
@@ -307,7 +339,7 @@ declare function createCrudRouter<TContext = unknown>(config: CrudRouterConfig<T
|
|
|
307
339
|
delete: any;
|
|
308
340
|
deleteMany: any;
|
|
309
341
|
updateMany: any;
|
|
310
|
-
}>> &
|
|
342
|
+
}>> & _trpc_server5.TRPCDecorateCreateRouterOptions<{
|
|
311
343
|
list: any;
|
|
312
344
|
getById: any;
|
|
313
345
|
create: any;
|
|
@@ -327,13 +359,141 @@ declare function createCrudRouter<TContext = unknown>(config: CrudRouterConfig<T
|
|
|
327
359
|
};
|
|
328
360
|
};
|
|
329
361
|
//#endregion
|
|
362
|
+
//#region src/lib/middleware-helpers.d.ts
|
|
363
|
+
type NextFn<TInput, TResult> = (input?: TInput) => Promise<TResult>;
|
|
364
|
+
interface MiddlewareParams<TContext, TInput, TResult> {
|
|
365
|
+
ctx: TContext;
|
|
366
|
+
input?: TInput;
|
|
367
|
+
next: NextFn<TInput, TResult>;
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* 创建 after-only 的 middleware(最常见场景)
|
|
371
|
+
* 在操作完成后执行副作用,不修改返回值
|
|
372
|
+
*
|
|
373
|
+
* @example
|
|
374
|
+
* middleware: {
|
|
375
|
+
* create: afterMiddleware(async (ctx, result) => {
|
|
376
|
+
* await sendEmail(result);
|
|
377
|
+
* await logAudit(ctx.user, 'create', result);
|
|
378
|
+
* }),
|
|
379
|
+
* }
|
|
380
|
+
*/
|
|
381
|
+
declare function afterMiddleware<TContext, TResult>(fn: (ctx: TContext, result: TResult) => void | Promise<void>): ({
|
|
382
|
+
ctx,
|
|
383
|
+
next
|
|
384
|
+
}: {
|
|
385
|
+
ctx: TContext;
|
|
386
|
+
next: () => Promise<TResult>;
|
|
387
|
+
}) => Promise<TResult>;
|
|
388
|
+
/**
|
|
389
|
+
* 创建 after-only 的 middleware,可修改返回值
|
|
390
|
+
*
|
|
391
|
+
* @example
|
|
392
|
+
* middleware: {
|
|
393
|
+
* get: afterMiddlewareTransform(async (ctx, result) => {
|
|
394
|
+
* return { ...result, computed: calculateSomething(result) };
|
|
395
|
+
* }),
|
|
396
|
+
* }
|
|
397
|
+
*/
|
|
398
|
+
declare function afterMiddlewareTransform<TContext, TResult>(fn: (ctx: TContext, result: TResult) => TResult | Promise<TResult>): ({
|
|
399
|
+
ctx,
|
|
400
|
+
next
|
|
401
|
+
}: {
|
|
402
|
+
ctx: TContext;
|
|
403
|
+
next: () => Promise<TResult>;
|
|
404
|
+
}) => Promise<TResult>;
|
|
405
|
+
/**
|
|
406
|
+
* 创建 before-only 的 middleware
|
|
407
|
+
* 在操作执行前修改输入数据
|
|
408
|
+
*
|
|
409
|
+
* @example
|
|
410
|
+
* middleware: {
|
|
411
|
+
* create: beforeMiddleware(async (ctx, input) => {
|
|
412
|
+
* return { ...input, slug: slugify(input.title), createdBy: ctx.user.id };
|
|
413
|
+
* }),
|
|
414
|
+
* }
|
|
415
|
+
*/
|
|
416
|
+
declare function beforeMiddleware<TContext, TInput>(fn: (ctx: TContext, input: TInput) => TInput | Promise<TInput>): <TResult>({
|
|
417
|
+
ctx,
|
|
418
|
+
input,
|
|
419
|
+
next
|
|
420
|
+
}: MiddlewareParams<TContext, TInput, TResult>) => Promise<TResult>;
|
|
421
|
+
/**
|
|
422
|
+
* 组合多个 middleware 为一个
|
|
423
|
+
*
|
|
424
|
+
* @example
|
|
425
|
+
* middleware: {
|
|
426
|
+
* create: composeMiddleware(
|
|
427
|
+
* beforeMiddleware((ctx, input) => ({ ...input, slug: slugify(input.title) })),
|
|
428
|
+
* afterMiddleware((ctx, result) => sendEmail(result)),
|
|
429
|
+
* ),
|
|
430
|
+
* }
|
|
431
|
+
*/
|
|
432
|
+
declare function composeMiddleware<TContext, TInput, TResult>(...middlewares: Array<(params: MiddlewareParams<TContext, TInput, TResult>) => Promise<TResult>>): (params: MiddlewareParams<TContext, TInput, TResult>) => Promise<TResult>;
|
|
433
|
+
/**
|
|
434
|
+
* 创建 list 操作的 after middleware
|
|
435
|
+
*/
|
|
436
|
+
declare function afterList<TContext, TSelect>(fn: (ctx: TContext, result: ListResult<TSelect>) => void | Promise<void>): ({
|
|
437
|
+
ctx,
|
|
438
|
+
next
|
|
439
|
+
}: {
|
|
440
|
+
ctx: TContext;
|
|
441
|
+
next: () => Promise<ListResult<TSelect>>;
|
|
442
|
+
}) => Promise<ListResult<TSelect>>;
|
|
443
|
+
/**
|
|
444
|
+
* 创建 list 操作的 before middleware
|
|
445
|
+
*/
|
|
446
|
+
declare function beforeList<TContext>(fn: (ctx: TContext, input: ListInput) => ListInput | Promise<ListInput>): <TResult>({
|
|
447
|
+
ctx,
|
|
448
|
+
input,
|
|
449
|
+
next
|
|
450
|
+
}: MiddlewareParams<TContext, ListInput, TResult>) => Promise<TResult>;
|
|
451
|
+
/**
|
|
452
|
+
* 创建 create 操作的 after middleware
|
|
453
|
+
*/
|
|
454
|
+
declare function afterCreate<TContext, TSelect>(fn: (ctx: TContext, created: TSelect) => void | Promise<void>): ({
|
|
455
|
+
ctx,
|
|
456
|
+
next
|
|
457
|
+
}: {
|
|
458
|
+
ctx: TContext;
|
|
459
|
+
next: () => Promise<TSelect>;
|
|
460
|
+
}) => Promise<TSelect>;
|
|
461
|
+
/**
|
|
462
|
+
* 创建 create 操作的 before middleware
|
|
463
|
+
*/
|
|
464
|
+
declare function beforeCreate<TContext, TInsert>(fn: (ctx: TContext, input: TInsert) => TInsert | Promise<TInsert>): <TResult>({
|
|
465
|
+
ctx,
|
|
466
|
+
input,
|
|
467
|
+
next
|
|
468
|
+
}: MiddlewareParams<TContext, TInsert, TResult>) => Promise<TResult>;
|
|
469
|
+
/**
|
|
470
|
+
* 创建 update 操作的 after middleware
|
|
471
|
+
*/
|
|
472
|
+
declare function afterUpdate<TContext, TSelect>(fn: (ctx: TContext, updated: TSelect) => void | Promise<void>): ({
|
|
473
|
+
ctx,
|
|
474
|
+
next
|
|
475
|
+
}: {
|
|
476
|
+
ctx: TContext;
|
|
477
|
+
next: () => Promise<TSelect>;
|
|
478
|
+
}) => Promise<TSelect>;
|
|
479
|
+
/**
|
|
480
|
+
* 创建 delete 操作的 after middleware
|
|
481
|
+
*/
|
|
482
|
+
declare function afterDelete<TContext, TSelect>(fn: (ctx: TContext, deleted: TSelect) => void | Promise<void>): ({
|
|
483
|
+
ctx,
|
|
484
|
+
next
|
|
485
|
+
}: {
|
|
486
|
+
ctx: TContext;
|
|
487
|
+
next: () => Promise<TSelect>;
|
|
488
|
+
}) => Promise<TSelect>;
|
|
489
|
+
//#endregion
|
|
330
490
|
//#region src/routers/index.d.ts
|
|
331
|
-
declare const appRouter:
|
|
491
|
+
declare const appRouter: _trpc_server5.TRPCBuiltRouter<{
|
|
332
492
|
ctx: Context;
|
|
333
493
|
meta: object;
|
|
334
|
-
errorShape:
|
|
494
|
+
errorShape: _trpc_server5.TRPCDefaultErrorShape;
|
|
335
495
|
transformer: true;
|
|
336
|
-
},
|
|
496
|
+
}, _trpc_server5.TRPCDecorateCreateRouterOptions<{}>>;
|
|
337
497
|
type AppRouter = typeof appRouter;
|
|
338
498
|
//#endregion
|
|
339
|
-
export { type AnyProcedure, type AppRouter, type
|
|
499
|
+
export { type AnyProcedure, type AppRouter, type CrudMiddleware, type CrudOperation, type CrudRouterConfig, type DeclarativeConfig, type FactoryConfig, type ListInput, type ListResult, type ProceduresConfig, type SoftDeleteConfig, type SoftDeleteOption, type WriteOperation, afterCreate, afterDelete, afterList, afterMiddleware, afterMiddlewareTransform, afterUpdate, appRouter, beforeCreate, beforeList, beforeMiddleware, composeMiddleware, createCrudRouter, publicProcedure, router };
|