@wordrhyme/auto-crud-server 1.0.2 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +56 -12
- package/dist/index.d.cts +13 -20
- package/dist/index.d.ts +19 -26
- package/dist/index.js +56 -12
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -564,9 +564,53 @@ function validateColumn(columnId, allowedColumns) {
|
|
|
564
564
|
if (!allowedColumns || allowedColumns.length === 0) return true;
|
|
565
565
|
return allowedColumns.includes(columnId);
|
|
566
566
|
}
|
|
567
|
+
/**
|
|
568
|
+
* 创建 CRUD Router
|
|
569
|
+
*
|
|
570
|
+
* 类型安全由各 procedure 的 .output() 保证,
|
|
571
|
+
* 返回类型不携带深层 Drizzle 泛型,避免 TypeScript OOM。
|
|
572
|
+
*
|
|
573
|
+
* @typeParam TTable - Drizzle 表类型
|
|
574
|
+
* @typeParam TContext - 上下文类型(包含 db)
|
|
575
|
+
* @typeParam TSelect - 查询返回类型
|
|
576
|
+
* @typeParam TInsert - 创建输入类型
|
|
577
|
+
* @typeParam TUpdate - 更新输入类型
|
|
578
|
+
*/
|
|
567
579
|
function createCrudRouter(config) {
|
|
568
580
|
const { table, idField = "id", filterableColumns, sortableColumns, maxBatchSize = 100, maxExportSize = 5e3, softDelete: softDeleteOption, middleware = {} } = config;
|
|
569
|
-
const { schema, updateSchema } = resolveSchemas(config);
|
|
581
|
+
const { selectSchema, schema, updateSchema } = resolveSchemas(config);
|
|
582
|
+
const entityOutputSchema = selectSchema;
|
|
583
|
+
const listOutputSchema = zod.z.object({
|
|
584
|
+
data: zod.z.array(selectSchema),
|
|
585
|
+
total: zod.z.number(),
|
|
586
|
+
page: zod.z.number(),
|
|
587
|
+
perPage: zod.z.number(),
|
|
588
|
+
pageCount: zod.z.number()
|
|
589
|
+
});
|
|
590
|
+
const deleteManyOutputSchema = zod.z.object({ deleted: zod.z.number() });
|
|
591
|
+
const updateManyOutputSchema = zod.z.object({ updated: zod.z.number() });
|
|
592
|
+
const upsertOutputSchema = zod.z.object({
|
|
593
|
+
data: selectSchema,
|
|
594
|
+
isNew: zod.z.boolean()
|
|
595
|
+
});
|
|
596
|
+
const exportOutputSchema = zod.z.object({
|
|
597
|
+
data: zod.z.array(selectSchema),
|
|
598
|
+
total: zod.z.number(),
|
|
599
|
+
hasMore: zod.z.boolean()
|
|
600
|
+
});
|
|
601
|
+
const createManyOutputSchema = zod.z.object({
|
|
602
|
+
created: zod.z.array(selectSchema),
|
|
603
|
+
count: zod.z.number()
|
|
604
|
+
});
|
|
605
|
+
const importOutputSchema = zod.z.object({
|
|
606
|
+
success: zod.z.number(),
|
|
607
|
+
updated: zod.z.number(),
|
|
608
|
+
skipped: zod.z.number(),
|
|
609
|
+
failed: zod.z.array(zod.z.object({
|
|
610
|
+
row: zod.z.number(),
|
|
611
|
+
errors: zod.z.array(zod.z.string())
|
|
612
|
+
}))
|
|
613
|
+
});
|
|
570
614
|
const resolved = resolveConfig(config);
|
|
571
615
|
const softDelete = resolveSoftDelete(softDeleteOption);
|
|
572
616
|
const m = middleware;
|
|
@@ -610,7 +654,7 @@ function createCrudRouter(config) {
|
|
|
610
654
|
});
|
|
611
655
|
};
|
|
612
656
|
const procedures = {
|
|
613
|
-
list: resolved.procedureFactory("list").input(listInputSchema).query(async ({ ctx, input }) => {
|
|
657
|
+
list: resolved.procedureFactory("list").input(listInputSchema).output(listOutputSchema).query(async ({ ctx, input }) => {
|
|
614
658
|
await withGuard(ctx, "list");
|
|
615
659
|
const doList = async (listInput$1) => {
|
|
616
660
|
const offset = (listInput$1.page - 1) * listInput$1.perPage;
|
|
@@ -649,7 +693,7 @@ function createCrudRouter(config) {
|
|
|
649
693
|
});
|
|
650
694
|
return doList(listInput);
|
|
651
695
|
}),
|
|
652
|
-
get: resolved.procedureFactory("get").input(zod.z.string()).query(async ({ ctx, input }) => {
|
|
696
|
+
get: resolved.procedureFactory("get").input(zod.z.string()).output(entityOutputSchema.nullable()).query(async ({ ctx, input }) => {
|
|
653
697
|
await withGuard(ctx, "get");
|
|
654
698
|
const doGet = async () => {
|
|
655
699
|
const where = buildWhere(ctx, "get", (0, drizzle_orm.eq)(getIdColumn(), input));
|
|
@@ -664,7 +708,7 @@ function createCrudRouter(config) {
|
|
|
664
708
|
});
|
|
665
709
|
return doGet();
|
|
666
710
|
}),
|
|
667
|
-
create: resolved.procedureFactory("create").input(schema).mutation(async ({ ctx, input }) => {
|
|
711
|
+
create: resolved.procedureFactory("create").input(schema).output(entityOutputSchema).mutation(async ({ ctx, input }) => {
|
|
668
712
|
await withGuard(ctx, "create");
|
|
669
713
|
const doCreate = async (inputData) => {
|
|
670
714
|
const injectData = resolved.getInject(ctx, "create");
|
|
@@ -685,7 +729,7 @@ function createCrudRouter(config) {
|
|
|
685
729
|
update: resolved.procedureFactory("update").input(zod.z.object({
|
|
686
730
|
id: zod.z.string(),
|
|
687
731
|
data: updateSchema
|
|
688
|
-
})).mutation(async ({ ctx, input }) => {
|
|
732
|
+
})).output(entityOutputSchema).mutation(async ({ ctx, input }) => {
|
|
689
733
|
await withGuard(ctx, "update");
|
|
690
734
|
const where = buildWhere(ctx, "update", (0, drizzle_orm.eq)(getIdColumn(), input.id));
|
|
691
735
|
const [existing] = await ctx.db.select().from(table).where(where);
|
|
@@ -712,7 +756,7 @@ function createCrudRouter(config) {
|
|
|
712
756
|
});
|
|
713
757
|
return doUpdate(input.data);
|
|
714
758
|
}),
|
|
715
|
-
delete: resolved.procedureFactory("delete").input(zod.z.string()).mutation(async ({ ctx, input }) => {
|
|
759
|
+
delete: resolved.procedureFactory("delete").input(zod.z.string()).output(entityOutputSchema).mutation(async ({ ctx, input }) => {
|
|
716
760
|
await withGuard(ctx, "delete");
|
|
717
761
|
const where = buildWhere(ctx, "delete", (0, drizzle_orm.eq)(getIdColumn(), input));
|
|
718
762
|
const [existing] = await ctx.db.select().from(table).where(where);
|
|
@@ -735,7 +779,7 @@ function createCrudRouter(config) {
|
|
|
735
779
|
});
|
|
736
780
|
return doDelete();
|
|
737
781
|
}),
|
|
738
|
-
deleteMany: resolved.procedureFactory("deleteMany").input(zod.z.array(zod.z.string()).max(maxBatchSize)).mutation(async ({ ctx, input }) => {
|
|
782
|
+
deleteMany: resolved.procedureFactory("deleteMany").input(zod.z.array(zod.z.string()).max(maxBatchSize)).output(deleteManyOutputSchema).mutation(async ({ ctx, input }) => {
|
|
739
783
|
await withGuard(ctx, "deleteMany");
|
|
740
784
|
const where = buildWhere(ctx, "deleteMany", (0, drizzle_orm.inArray)(getIdColumn(), input));
|
|
741
785
|
const doDeleteMany = async () => {
|
|
@@ -752,7 +796,7 @@ function createCrudRouter(config) {
|
|
|
752
796
|
updateMany: resolved.procedureFactory("updateMany").input(zod.z.object({
|
|
753
797
|
ids: zod.z.array(zod.z.string()).max(maxBatchSize),
|
|
754
798
|
data: updateSchema
|
|
755
|
-
})).mutation(async ({ ctx, input }) => {
|
|
799
|
+
})).output(updateManyOutputSchema).mutation(async ({ ctx, input }) => {
|
|
756
800
|
await withGuard(ctx, "updateMany");
|
|
757
801
|
const where = buildWhere(ctx, "updateMany", (0, drizzle_orm.inArray)(getIdColumn(), input.ids));
|
|
758
802
|
const doUpdateMany = async (updateData) => {
|
|
@@ -771,7 +815,7 @@ function createCrudRouter(config) {
|
|
|
771
815
|
});
|
|
772
816
|
return doUpdateMany(input.data);
|
|
773
817
|
}),
|
|
774
|
-
upsert: resolved.procedureFactory("upsert").input(schema).mutation(async ({ ctx, input }) => {
|
|
818
|
+
upsert: resolved.procedureFactory("upsert").input(schema).output(upsertOutputSchema).mutation(async ({ ctx, input }) => {
|
|
775
819
|
await withGuard(ctx, "upsert");
|
|
776
820
|
const doUpsert = async (inputData) => {
|
|
777
821
|
const inputId = inputData[idField];
|
|
@@ -808,7 +852,7 @@ function createCrudRouter(config) {
|
|
|
808
852
|
});
|
|
809
853
|
return doUpsert(input);
|
|
810
854
|
}),
|
|
811
|
-
export: resolved.procedureFactory("export").input(exportInputSchema).query(async ({ ctx, input }) => {
|
|
855
|
+
export: resolved.procedureFactory("export").input(exportInputSchema).output(exportOutputSchema).query(async ({ ctx, input }) => {
|
|
812
856
|
await withGuard(ctx, "export");
|
|
813
857
|
const doExport = async (exportInput$1) => {
|
|
814
858
|
const effectiveLimit = Math.min(Math.max(exportInput$1.limit ?? maxExportSize, 1), maxExportSize);
|
|
@@ -845,7 +889,7 @@ function createCrudRouter(config) {
|
|
|
845
889
|
});
|
|
846
890
|
return doExport(exportInput);
|
|
847
891
|
}),
|
|
848
|
-
createMany: resolved.procedureFactory("createMany").input(zod.z.array(schema).min(1).max(maxBatchSize)).mutation(async ({ ctx, input }) => {
|
|
892
|
+
createMany: resolved.procedureFactory("createMany").input(zod.z.array(schema).min(1).max(maxBatchSize)).output(createManyOutputSchema).mutation(async ({ ctx, input }) => {
|
|
849
893
|
await withGuard(ctx, "createMany");
|
|
850
894
|
const doCreateMany = async (items) => {
|
|
851
895
|
const injectData = resolved.getInject(ctx, "create");
|
|
@@ -866,7 +910,7 @@ function createCrudRouter(config) {
|
|
|
866
910
|
});
|
|
867
911
|
return doCreateMany(input);
|
|
868
912
|
}),
|
|
869
|
-
import: resolved.procedureFactory("import").input(importInputSchema).mutation(async ({ ctx, input }) => {
|
|
913
|
+
import: resolved.procedureFactory("import").input(importInputSchema).output(importOutputSchema).mutation(async ({ ctx, input }) => {
|
|
870
914
|
await withGuard(ctx, "import");
|
|
871
915
|
const doImport = async (importData$1) => {
|
|
872
916
|
const validRows = [];
|
package/dist/index.d.cts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { InferInsertModel, InferSelectModel, SQL } from "drizzle-orm";
|
|
3
1
|
import { PgTable } from "drizzle-orm/pg-core";
|
|
4
2
|
import * as _trpc_server2 from "@trpc/server";
|
|
5
3
|
import { PostgresJsDatabase } from "drizzle-orm/postgres-js";
|
|
4
|
+
import { SQL } from "drizzle-orm";
|
|
5
|
+
import { z } from "zod";
|
|
6
6
|
|
|
7
7
|
//#region src/trpc.d.ts
|
|
8
8
|
/**
|
|
@@ -518,7 +518,7 @@ interface CrudRouterConfig<TTable extends PgTable = PgTable, TContext = unknown,
|
|
|
518
518
|
*/
|
|
519
519
|
middleware?: CrudMiddleware<TContext, TSelect, TInsert, TUpdate>;
|
|
520
520
|
}
|
|
521
|
-
interface CrudProcedures
|
|
521
|
+
interface CrudProcedures {
|
|
522
522
|
list: AnyProcedure;
|
|
523
523
|
get: AnyProcedure;
|
|
524
524
|
create: AnyProcedure;
|
|
@@ -535,31 +535,24 @@ interface CrudProcedures<TSelect, TInsert, TUpdate> {
|
|
|
535
535
|
//#region src/routers/_factory.d.ts
|
|
536
536
|
/**
|
|
537
537
|
* createCrudRouter 返回类型
|
|
538
|
+
* 不携带泛型参数 — 类型安全由各 procedure 的 .output() 保证
|
|
538
539
|
*/
|
|
539
|
-
type CrudRouterReturn
|
|
540
|
-
procedures: CrudProcedures
|
|
540
|
+
type CrudRouterReturn = ReturnType<typeof router> & {
|
|
541
|
+
procedures: CrudProcedures;
|
|
541
542
|
};
|
|
542
543
|
/**
|
|
543
544
|
* 创建 CRUD Router
|
|
544
545
|
*
|
|
546
|
+
* 类型安全由各 procedure 的 .output() 保证,
|
|
547
|
+
* 返回类型不携带深层 Drizzle 泛型,避免 TypeScript OOM。
|
|
548
|
+
*
|
|
549
|
+
* @typeParam TTable - Drizzle 表类型
|
|
545
550
|
* @typeParam TContext - 上下文类型(包含 db)
|
|
546
551
|
* @typeParam TSelect - 查询返回类型
|
|
547
|
-
* @typeParam TInsert -
|
|
548
|
-
* @typeParam TUpdate -
|
|
552
|
+
* @typeParam TInsert - 创建输入类型
|
|
553
|
+
* @typeParam TUpdate - 更新输入类型
|
|
549
554
|
*/
|
|
550
|
-
declare function createCrudRouter<TTable extends PgTable, TContext, TSelect, TInsert, TUpdate>(config: CrudRouterConfig<TTable, TContext, TSelect, TInsert, TUpdate>
|
|
551
|
-
schema: z.ZodType<TInsert>;
|
|
552
|
-
updateSchema: z.ZodType<TUpdate>;
|
|
553
|
-
}): CrudRouterReturn<TSelect, TInsert, TUpdate>;
|
|
554
|
-
declare function createCrudRouter<TTable extends PgTable, TContext = unknown>(config: Omit<CrudRouterConfig<TTable, TContext>, "schema" | "updateSchema"> & {
|
|
555
|
-
schema?: undefined;
|
|
556
|
-
updateSchema?: undefined;
|
|
557
|
-
}): CrudRouterReturn<InferSelectModel<TTable>, InferInsertModel<TTable>, Partial<InferInsertModel<TTable>>>;
|
|
558
|
-
declare function createCrudRouter<TTable extends PgTable, TContext, TInsert>(config: Omit<CrudRouterConfig<TTable, TContext, unknown, TInsert, unknown>, "updateSchema"> & {
|
|
559
|
-
schema: z.ZodType<TInsert>;
|
|
560
|
-
updateSchema?: undefined;
|
|
561
|
-
}): CrudRouterReturn<unknown, TInsert, Partial<TInsert>>;
|
|
562
|
-
declare function createCrudRouter<TTable extends PgTable, TContext = unknown, TSelect = unknown, TInsert = unknown, TUpdate = unknown>(config: CrudRouterConfig<TTable, TContext, TSelect, TInsert, TUpdate>): CrudRouterReturn<TSelect, TInsert, TUpdate>;
|
|
555
|
+
declare function createCrudRouter<TTable extends PgTable = PgTable, TContext = unknown, TSelect = unknown, TInsert = unknown, TUpdate = unknown>(config: CrudRouterConfig<TTable, TContext, TSelect, TInsert, TUpdate>): CrudRouterReturn;
|
|
563
556
|
//#endregion
|
|
564
557
|
//#region src/lib/middleware-helpers.d.ts
|
|
565
558
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import {
|
|
3
|
-
import * as
|
|
2
|
+
import { SQL } from "drizzle-orm";
|
|
3
|
+
import * as _trpc_server0 from "@trpc/server";
|
|
4
4
|
import superjson from "superjson";
|
|
5
5
|
import { PgTable } from "drizzle-orm/pg-core";
|
|
6
6
|
import { PostgresJsDatabase } from "drizzle-orm/postgres-js";
|
|
@@ -13,13 +13,13 @@ import { PostgresJsDatabase } from "drizzle-orm/postgres-js";
|
|
|
13
13
|
interface Context {
|
|
14
14
|
db: PostgresJsDatabase<Record<string, never>>;
|
|
15
15
|
}
|
|
16
|
-
declare const router:
|
|
16
|
+
declare const router: _trpc_server0.TRPCRouterBuilder<{
|
|
17
17
|
ctx: Context;
|
|
18
18
|
meta: object;
|
|
19
|
-
errorShape:
|
|
19
|
+
errorShape: _trpc_server0.TRPCDefaultErrorShape;
|
|
20
20
|
transformer: true;
|
|
21
21
|
}>;
|
|
22
|
-
declare const publicProcedure:
|
|
22
|
+
declare const publicProcedure: _trpc_server0.TRPCProcedureBuilder<Context, object, object, _trpc_server0.TRPCUnsetMarker, _trpc_server0.TRPCUnsetMarker, _trpc_server0.TRPCUnsetMarker, _trpc_server0.TRPCUnsetMarker, false>;
|
|
23
23
|
//#endregion
|
|
24
24
|
//#region src/types/config.d.ts
|
|
25
25
|
type CrudOperation = "list" | "get" | "create" | "update" | "delete" | "deleteMany" | "updateMany" | "upsert" | "export" | "import" | "createMany";
|
|
@@ -519,7 +519,7 @@ interface CrudRouterConfig<TTable extends PgTable = PgTable, TContext = unknown,
|
|
|
519
519
|
*/
|
|
520
520
|
middleware?: CrudMiddleware<TContext, TSelect, TInsert, TUpdate>;
|
|
521
521
|
}
|
|
522
|
-
interface CrudProcedures
|
|
522
|
+
interface CrudProcedures {
|
|
523
523
|
list: AnyProcedure;
|
|
524
524
|
get: AnyProcedure;
|
|
525
525
|
create: AnyProcedure;
|
|
@@ -536,31 +536,24 @@ interface CrudProcedures<TSelect, TInsert, TUpdate> {
|
|
|
536
536
|
//#region src/routers/_factory.d.ts
|
|
537
537
|
/**
|
|
538
538
|
* createCrudRouter 返回类型
|
|
539
|
+
* 不携带泛型参数 — 类型安全由各 procedure 的 .output() 保证
|
|
539
540
|
*/
|
|
540
|
-
type CrudRouterReturn
|
|
541
|
-
procedures: CrudProcedures
|
|
541
|
+
type CrudRouterReturn = ReturnType<typeof router> & {
|
|
542
|
+
procedures: CrudProcedures;
|
|
542
543
|
};
|
|
543
544
|
/**
|
|
544
545
|
* 创建 CRUD Router
|
|
545
546
|
*
|
|
547
|
+
* 类型安全由各 procedure 的 .output() 保证,
|
|
548
|
+
* 返回类型不携带深层 Drizzle 泛型,避免 TypeScript OOM。
|
|
549
|
+
*
|
|
550
|
+
* @typeParam TTable - Drizzle 表类型
|
|
546
551
|
* @typeParam TContext - 上下文类型(包含 db)
|
|
547
552
|
* @typeParam TSelect - 查询返回类型
|
|
548
|
-
* @typeParam TInsert -
|
|
549
|
-
* @typeParam TUpdate -
|
|
553
|
+
* @typeParam TInsert - 创建输入类型
|
|
554
|
+
* @typeParam TUpdate - 更新输入类型
|
|
550
555
|
*/
|
|
551
|
-
declare function createCrudRouter<TTable extends PgTable, TContext, TSelect, TInsert, TUpdate>(config: CrudRouterConfig<TTable, TContext, TSelect, TInsert, TUpdate>
|
|
552
|
-
schema: z.ZodType<TInsert>;
|
|
553
|
-
updateSchema: z.ZodType<TUpdate>;
|
|
554
|
-
}): CrudRouterReturn<TSelect, TInsert, TUpdate>;
|
|
555
|
-
declare function createCrudRouter<TTable extends PgTable, TContext = unknown>(config: Omit<CrudRouterConfig<TTable, TContext>, "schema" | "updateSchema"> & {
|
|
556
|
-
schema?: undefined;
|
|
557
|
-
updateSchema?: undefined;
|
|
558
|
-
}): CrudRouterReturn<InferSelectModel<TTable>, InferInsertModel<TTable>, Partial<InferInsertModel<TTable>>>;
|
|
559
|
-
declare function createCrudRouter<TTable extends PgTable, TContext, TInsert>(config: Omit<CrudRouterConfig<TTable, TContext, unknown, TInsert, unknown>, "updateSchema"> & {
|
|
560
|
-
schema: z.ZodType<TInsert>;
|
|
561
|
-
updateSchema?: undefined;
|
|
562
|
-
}): CrudRouterReturn<unknown, TInsert, Partial<TInsert>>;
|
|
563
|
-
declare function createCrudRouter<TTable extends PgTable, TContext = unknown, TSelect = unknown, TInsert = unknown, TUpdate = unknown>(config: CrudRouterConfig<TTable, TContext, TSelect, TInsert, TUpdate>): CrudRouterReturn<TSelect, TInsert, TUpdate>;
|
|
556
|
+
declare function createCrudRouter<TTable extends PgTable = PgTable, TContext = unknown, TSelect = unknown, TInsert = unknown, TUpdate = unknown>(config: CrudRouterConfig<TTable, TContext, TSelect, TInsert, TUpdate>): CrudRouterReturn;
|
|
564
557
|
//#endregion
|
|
565
558
|
//#region src/lib/middleware-helpers.d.ts
|
|
566
559
|
/**
|
|
@@ -620,12 +613,12 @@ type AnyMiddlewareParams<TContext> = {
|
|
|
620
613
|
declare function composeMiddleware<TContext, TResult>(...middlewares: Array<(params: AnyMiddlewareParams<TContext>) => Promise<any>>): (params: AnyMiddlewareParams<TContext>) => Promise<TResult>;
|
|
621
614
|
//#endregion
|
|
622
615
|
//#region src/routers/index.d.ts
|
|
623
|
-
declare const appRouter:
|
|
616
|
+
declare const appRouter: _trpc_server0.TRPCBuiltRouter<{
|
|
624
617
|
ctx: Context;
|
|
625
618
|
meta: object;
|
|
626
|
-
errorShape:
|
|
619
|
+
errorShape: _trpc_server0.TRPCDefaultErrorShape;
|
|
627
620
|
transformer: true;
|
|
628
|
-
},
|
|
621
|
+
}, _trpc_server0.TRPCDecorateCreateRouterOptions<{}>>;
|
|
629
622
|
type AppRouter = typeof appRouter;
|
|
630
623
|
//#endregion
|
|
631
624
|
export { type AnyProcedure, type AppRouter, type CreateManyMiddlewareParams, type CreateMiddlewareParams, type CrudMiddleware, type CrudOperation, type CrudProcedures, type CrudRouterConfig, type DeleteManyMiddlewareParams, type DeleteMiddlewareParams, type ExportInput, type ExportMiddlewareParams, type ExportResult, type GetMiddlewareParams, type ImportFailedRow, type ImportInput, type ImportMiddlewareParams, type ImportResult, type ListInput, type ListMiddlewareParams, type ListResult, type ProcedureConfig, type ProcedureFactory, type ProcedureMap, type SoftDeleteConfig, type SoftDeleteOption, type UpdateManyMiddlewareParams, type UpdateMiddlewareParams, type UpsertMiddlewareParams, type WriteOperation, afterMiddleware, appRouter, beforeMiddleware, composeMiddleware, createCrudRouter, publicProcedure, router };
|
package/dist/index.js
CHANGED
|
@@ -535,9 +535,53 @@ function validateColumn(columnId, allowedColumns) {
|
|
|
535
535
|
if (!allowedColumns || allowedColumns.length === 0) return true;
|
|
536
536
|
return allowedColumns.includes(columnId);
|
|
537
537
|
}
|
|
538
|
+
/**
|
|
539
|
+
* 创建 CRUD Router
|
|
540
|
+
*
|
|
541
|
+
* 类型安全由各 procedure 的 .output() 保证,
|
|
542
|
+
* 返回类型不携带深层 Drizzle 泛型,避免 TypeScript OOM。
|
|
543
|
+
*
|
|
544
|
+
* @typeParam TTable - Drizzle 表类型
|
|
545
|
+
* @typeParam TContext - 上下文类型(包含 db)
|
|
546
|
+
* @typeParam TSelect - 查询返回类型
|
|
547
|
+
* @typeParam TInsert - 创建输入类型
|
|
548
|
+
* @typeParam TUpdate - 更新输入类型
|
|
549
|
+
*/
|
|
538
550
|
function createCrudRouter(config) {
|
|
539
551
|
const { table, idField = "id", filterableColumns, sortableColumns, maxBatchSize = 100, maxExportSize = 5e3, softDelete: softDeleteOption, middleware = {} } = config;
|
|
540
|
-
const { schema, updateSchema } = resolveSchemas(config);
|
|
552
|
+
const { selectSchema, schema, updateSchema } = resolveSchemas(config);
|
|
553
|
+
const entityOutputSchema = selectSchema;
|
|
554
|
+
const listOutputSchema = z.object({
|
|
555
|
+
data: z.array(selectSchema),
|
|
556
|
+
total: z.number(),
|
|
557
|
+
page: z.number(),
|
|
558
|
+
perPage: z.number(),
|
|
559
|
+
pageCount: z.number()
|
|
560
|
+
});
|
|
561
|
+
const deleteManyOutputSchema = z.object({ deleted: z.number() });
|
|
562
|
+
const updateManyOutputSchema = z.object({ updated: z.number() });
|
|
563
|
+
const upsertOutputSchema = z.object({
|
|
564
|
+
data: selectSchema,
|
|
565
|
+
isNew: z.boolean()
|
|
566
|
+
});
|
|
567
|
+
const exportOutputSchema = z.object({
|
|
568
|
+
data: z.array(selectSchema),
|
|
569
|
+
total: z.number(),
|
|
570
|
+
hasMore: z.boolean()
|
|
571
|
+
});
|
|
572
|
+
const createManyOutputSchema = z.object({
|
|
573
|
+
created: z.array(selectSchema),
|
|
574
|
+
count: z.number()
|
|
575
|
+
});
|
|
576
|
+
const importOutputSchema = z.object({
|
|
577
|
+
success: z.number(),
|
|
578
|
+
updated: z.number(),
|
|
579
|
+
skipped: z.number(),
|
|
580
|
+
failed: z.array(z.object({
|
|
581
|
+
row: z.number(),
|
|
582
|
+
errors: z.array(z.string())
|
|
583
|
+
}))
|
|
584
|
+
});
|
|
541
585
|
const resolved = resolveConfig(config);
|
|
542
586
|
const softDelete = resolveSoftDelete(softDeleteOption);
|
|
543
587
|
const m = middleware;
|
|
@@ -581,7 +625,7 @@ function createCrudRouter(config) {
|
|
|
581
625
|
});
|
|
582
626
|
};
|
|
583
627
|
const procedures = {
|
|
584
|
-
list: resolved.procedureFactory("list").input(listInputSchema).query(async ({ ctx, input }) => {
|
|
628
|
+
list: resolved.procedureFactory("list").input(listInputSchema).output(listOutputSchema).query(async ({ ctx, input }) => {
|
|
585
629
|
await withGuard(ctx, "list");
|
|
586
630
|
const doList = async (listInput$1) => {
|
|
587
631
|
const offset = (listInput$1.page - 1) * listInput$1.perPage;
|
|
@@ -620,7 +664,7 @@ function createCrudRouter(config) {
|
|
|
620
664
|
});
|
|
621
665
|
return doList(listInput);
|
|
622
666
|
}),
|
|
623
|
-
get: resolved.procedureFactory("get").input(z.string()).query(async ({ ctx, input }) => {
|
|
667
|
+
get: resolved.procedureFactory("get").input(z.string()).output(entityOutputSchema.nullable()).query(async ({ ctx, input }) => {
|
|
624
668
|
await withGuard(ctx, "get");
|
|
625
669
|
const doGet = async () => {
|
|
626
670
|
const where = buildWhere(ctx, "get", eq(getIdColumn(), input));
|
|
@@ -635,7 +679,7 @@ function createCrudRouter(config) {
|
|
|
635
679
|
});
|
|
636
680
|
return doGet();
|
|
637
681
|
}),
|
|
638
|
-
create: resolved.procedureFactory("create").input(schema).mutation(async ({ ctx, input }) => {
|
|
682
|
+
create: resolved.procedureFactory("create").input(schema).output(entityOutputSchema).mutation(async ({ ctx, input }) => {
|
|
639
683
|
await withGuard(ctx, "create");
|
|
640
684
|
const doCreate = async (inputData) => {
|
|
641
685
|
const injectData = resolved.getInject(ctx, "create");
|
|
@@ -656,7 +700,7 @@ function createCrudRouter(config) {
|
|
|
656
700
|
update: resolved.procedureFactory("update").input(z.object({
|
|
657
701
|
id: z.string(),
|
|
658
702
|
data: updateSchema
|
|
659
|
-
})).mutation(async ({ ctx, input }) => {
|
|
703
|
+
})).output(entityOutputSchema).mutation(async ({ ctx, input }) => {
|
|
660
704
|
await withGuard(ctx, "update");
|
|
661
705
|
const where = buildWhere(ctx, "update", eq(getIdColumn(), input.id));
|
|
662
706
|
const [existing] = await ctx.db.select().from(table).where(where);
|
|
@@ -683,7 +727,7 @@ function createCrudRouter(config) {
|
|
|
683
727
|
});
|
|
684
728
|
return doUpdate(input.data);
|
|
685
729
|
}),
|
|
686
|
-
delete: resolved.procedureFactory("delete").input(z.string()).mutation(async ({ ctx, input }) => {
|
|
730
|
+
delete: resolved.procedureFactory("delete").input(z.string()).output(entityOutputSchema).mutation(async ({ ctx, input }) => {
|
|
687
731
|
await withGuard(ctx, "delete");
|
|
688
732
|
const where = buildWhere(ctx, "delete", eq(getIdColumn(), input));
|
|
689
733
|
const [existing] = await ctx.db.select().from(table).where(where);
|
|
@@ -706,7 +750,7 @@ function createCrudRouter(config) {
|
|
|
706
750
|
});
|
|
707
751
|
return doDelete();
|
|
708
752
|
}),
|
|
709
|
-
deleteMany: resolved.procedureFactory("deleteMany").input(z.array(z.string()).max(maxBatchSize)).mutation(async ({ ctx, input }) => {
|
|
753
|
+
deleteMany: resolved.procedureFactory("deleteMany").input(z.array(z.string()).max(maxBatchSize)).output(deleteManyOutputSchema).mutation(async ({ ctx, input }) => {
|
|
710
754
|
await withGuard(ctx, "deleteMany");
|
|
711
755
|
const where = buildWhere(ctx, "deleteMany", inArray(getIdColumn(), input));
|
|
712
756
|
const doDeleteMany = async () => {
|
|
@@ -723,7 +767,7 @@ function createCrudRouter(config) {
|
|
|
723
767
|
updateMany: resolved.procedureFactory("updateMany").input(z.object({
|
|
724
768
|
ids: z.array(z.string()).max(maxBatchSize),
|
|
725
769
|
data: updateSchema
|
|
726
|
-
})).mutation(async ({ ctx, input }) => {
|
|
770
|
+
})).output(updateManyOutputSchema).mutation(async ({ ctx, input }) => {
|
|
727
771
|
await withGuard(ctx, "updateMany");
|
|
728
772
|
const where = buildWhere(ctx, "updateMany", inArray(getIdColumn(), input.ids));
|
|
729
773
|
const doUpdateMany = async (updateData) => {
|
|
@@ -742,7 +786,7 @@ function createCrudRouter(config) {
|
|
|
742
786
|
});
|
|
743
787
|
return doUpdateMany(input.data);
|
|
744
788
|
}),
|
|
745
|
-
upsert: resolved.procedureFactory("upsert").input(schema).mutation(async ({ ctx, input }) => {
|
|
789
|
+
upsert: resolved.procedureFactory("upsert").input(schema).output(upsertOutputSchema).mutation(async ({ ctx, input }) => {
|
|
746
790
|
await withGuard(ctx, "upsert");
|
|
747
791
|
const doUpsert = async (inputData) => {
|
|
748
792
|
const inputId = inputData[idField];
|
|
@@ -779,7 +823,7 @@ function createCrudRouter(config) {
|
|
|
779
823
|
});
|
|
780
824
|
return doUpsert(input);
|
|
781
825
|
}),
|
|
782
|
-
export: resolved.procedureFactory("export").input(exportInputSchema).query(async ({ ctx, input }) => {
|
|
826
|
+
export: resolved.procedureFactory("export").input(exportInputSchema).output(exportOutputSchema).query(async ({ ctx, input }) => {
|
|
783
827
|
await withGuard(ctx, "export");
|
|
784
828
|
const doExport = async (exportInput$1) => {
|
|
785
829
|
const effectiveLimit = Math.min(Math.max(exportInput$1.limit ?? maxExportSize, 1), maxExportSize);
|
|
@@ -816,7 +860,7 @@ function createCrudRouter(config) {
|
|
|
816
860
|
});
|
|
817
861
|
return doExport(exportInput);
|
|
818
862
|
}),
|
|
819
|
-
createMany: resolved.procedureFactory("createMany").input(z.array(schema).min(1).max(maxBatchSize)).mutation(async ({ ctx, input }) => {
|
|
863
|
+
createMany: resolved.procedureFactory("createMany").input(z.array(schema).min(1).max(maxBatchSize)).output(createManyOutputSchema).mutation(async ({ ctx, input }) => {
|
|
820
864
|
await withGuard(ctx, "createMany");
|
|
821
865
|
const doCreateMany = async (items) => {
|
|
822
866
|
const injectData = resolved.getInject(ctx, "create");
|
|
@@ -837,7 +881,7 @@ function createCrudRouter(config) {
|
|
|
837
881
|
});
|
|
838
882
|
return doCreateMany(input);
|
|
839
883
|
}),
|
|
840
|
-
import: resolved.procedureFactory("import").input(importInputSchema).mutation(async ({ ctx, input }) => {
|
|
884
|
+
import: resolved.procedureFactory("import").input(importInputSchema).output(importOutputSchema).mutation(async ({ ctx, input }) => {
|
|
841
885
|
await withGuard(ctx, "import");
|
|
842
886
|
const doImport = async (importData$1) => {
|
|
843
887
|
const validRows = [];
|
package/package.json
CHANGED