bradb 3.1.1 → 3.1.2
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/src/builder.d.ts +3 -0
- package/dist/src/builder.js +22 -6
- package/dist/src/commands.js +5 -1
- package/dist/src/controller.d.ts +16 -39
- package/dist/src/controller.js +36 -96
- package/dist/src/errors.js +16 -3
- package/dist/src/filters.d.ts +3 -0
- package/dist/src/filters.js +3 -2
- package/dist/src/generators.d.ts +1 -0
- package/dist/src/generators.js +52 -20
- package/dist/src/service.d.ts +10 -4
- package/dist/src/service.js +36 -7
- package/dist/src/types.d.ts +7 -26
- package/package.json +1 -1
package/dist/src/builder.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { PgTable } from 'drizzle-orm/pg-core';
|
|
1
2
|
import { BradConfig } from './config';
|
|
2
3
|
export declare const nodeTypes: readonly ["validator", "controller", "service", "schema", "router", "filter", "db"];
|
|
3
4
|
export type NodeType = typeof nodeTypes[number];
|
|
@@ -8,6 +9,8 @@ type Node = {
|
|
|
8
9
|
adj: Node[];
|
|
9
10
|
exports: string[];
|
|
10
11
|
};
|
|
12
|
+
type GeneratorFunc = (name: string, table: PgTable, imports: string[]) => string;
|
|
13
|
+
export declare const generators: Record<NodeType, GeneratorFunc | null>;
|
|
11
14
|
type Export = Record<string, any>;
|
|
12
15
|
export declare const valid: Record<string, boolean>;
|
|
13
16
|
export declare let mods: Export;
|
package/dist/src/builder.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.mods = exports.valid = exports.nodeTypes = void 0;
|
|
6
|
+
exports.mods = exports.valid = exports.generators = exports.nodeTypes = void 0;
|
|
7
7
|
exports.buildGraph = buildGraph;
|
|
8
8
|
exports.addNodeTo = addNodeTo;
|
|
9
9
|
exports.build = build;
|
|
@@ -24,6 +24,12 @@ const dependOn = {
|
|
|
24
24
|
schema: [],
|
|
25
25
|
db: []
|
|
26
26
|
};
|
|
27
|
+
/* CRUD Operations
|
|
28
|
+
* # READ
|
|
29
|
+
* router.getAll -> controller.getAll -> service.getAll -> schema
|
|
30
|
+
* controller.count -> service.count -> schema
|
|
31
|
+
* controller
|
|
32
|
+
*/
|
|
27
33
|
// Default and base exports for each node type
|
|
28
34
|
const requiredExports = {
|
|
29
35
|
validator: (name) => [`${name}Validator`],
|
|
@@ -34,7 +40,7 @@ const requiredExports = {
|
|
|
34
40
|
filter: (name) => [`${name}FilterMap`],
|
|
35
41
|
db: (name) => ["db"]
|
|
36
42
|
};
|
|
37
|
-
|
|
43
|
+
exports.generators = {
|
|
38
44
|
router: generators_1.generateRouter,
|
|
39
45
|
controller: generators_1.generateController,
|
|
40
46
|
validator: generators_1.generateValidator,
|
|
@@ -63,7 +69,7 @@ function buildGraph(cfg, name, type) {
|
|
|
63
69
|
checked[id(n)] = true;
|
|
64
70
|
try {
|
|
65
71
|
// If config is set to override = true we not check the modules and re-write anywise
|
|
66
|
-
if (cfg.override) {
|
|
72
|
+
if (cfg.override && dependOn[type].length > 0) {
|
|
67
73
|
exports.valid[id(n)] = false;
|
|
68
74
|
}
|
|
69
75
|
else {
|
|
@@ -73,8 +79,6 @@ function buildGraph(cfg, name, type) {
|
|
|
73
79
|
}
|
|
74
80
|
}
|
|
75
81
|
catch (err) {
|
|
76
|
-
console.error(err.message);
|
|
77
|
-
console.log(cfg.override);
|
|
78
82
|
// it's not necessary to set it to false
|
|
79
83
|
exports.valid[id(n)] = false;
|
|
80
84
|
}
|
|
@@ -109,7 +113,7 @@ function build(root) {
|
|
|
109
113
|
build(dep);
|
|
110
114
|
}
|
|
111
115
|
if (!exports.valid[id(root)]) {
|
|
112
|
-
const gen = generators[root.type];
|
|
116
|
+
const gen = exports.generators[root.type];
|
|
113
117
|
if (!gen) {
|
|
114
118
|
throw Error(`Missing generator for ${root.type}`);
|
|
115
119
|
}
|
|
@@ -144,6 +148,10 @@ function checkNode(root) {
|
|
|
144
148
|
console.log(`Checking ${root.name}.${root.type}...`);
|
|
145
149
|
// throw the require error
|
|
146
150
|
const module = require(root.path);
|
|
151
|
+
// const code = fs.readFileSync(root.path).toString();
|
|
152
|
+
//
|
|
153
|
+
// const a = addCrudOp(`${root.name}${requiredExports[root.type]}`, code, "getAll");
|
|
154
|
+
// console.log(a);
|
|
147
155
|
for (const exp of root.exports) {
|
|
148
156
|
if (!module[exp]) {
|
|
149
157
|
throw new Error(`[Missing export]: Cannot import ${exp} from ${root.path}`);
|
|
@@ -151,6 +159,14 @@ function checkNode(root) {
|
|
|
151
159
|
}
|
|
152
160
|
return module;
|
|
153
161
|
}
|
|
162
|
+
function addCrudOp(name, code, op) {
|
|
163
|
+
const regex = new RegExp(`(export\s+const\s+${name}\s*=\s*\{)([\s\S]*?)\};`);
|
|
164
|
+
const match = code.match(regex);
|
|
165
|
+
if (!match) {
|
|
166
|
+
return code;
|
|
167
|
+
}
|
|
168
|
+
return match.toString();
|
|
169
|
+
}
|
|
154
170
|
function buildImportLine(from, to, maxColumns = 80) {
|
|
155
171
|
const relativePath = buildRelativeImport(from.path, to.path);
|
|
156
172
|
let sep = ' ';
|
package/dist/src/commands.js
CHANGED
|
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
4
4
|
const commander_1 = require("commander");
|
|
5
5
|
const builder_1 = require("./builder");
|
|
6
6
|
const config_1 = require("./config");
|
|
7
|
+
const generators_1 = require("./generators");
|
|
7
8
|
const program = new commander_1.Command();
|
|
8
9
|
program.name("brad").description("BRAD - Generator");
|
|
9
10
|
program
|
|
@@ -13,16 +14,19 @@ program
|
|
|
13
14
|
.choices(builder_1.nodeTypes)
|
|
14
15
|
.default("router"))
|
|
15
16
|
.option('-o, --override', 'Generator will override the current code', false)
|
|
17
|
+
.option('--cb, --controller-with-builder', 'Generate controller using builder', false)
|
|
16
18
|
.description("generate entity recursively")
|
|
17
19
|
.action(async (name, type, options) => {
|
|
18
20
|
const cfg = (0, config_1.loadConfig)();
|
|
19
21
|
cfg.override = options.override || false;
|
|
22
|
+
if (options.controllerWithBuilder) {
|
|
23
|
+
builder_1.generators["controller"] = generators_1.generateControllerBuilder;
|
|
24
|
+
}
|
|
20
25
|
require('ts-node/register');
|
|
21
26
|
const root = (0, builder_1.buildGraph)(cfg, name, type);
|
|
22
27
|
// Aca tendríamos que ir desde (name, type) hasta la raiz (name, "router")
|
|
23
28
|
// y desde ahi, ver si tenemos dependencias de otra entidad
|
|
24
29
|
console.log(JSON.stringify(root, null, 4));
|
|
25
|
-
console.log(builder_1.valid);
|
|
26
30
|
(0, builder_1.build)(root);
|
|
27
31
|
});
|
|
28
32
|
program
|
package/dist/src/controller.d.ts
CHANGED
|
@@ -1,43 +1,20 @@
|
|
|
1
|
-
import { PgTable } from "drizzle-orm/pg-core";
|
|
2
1
|
import { Request, Response } from "express";
|
|
3
2
|
import { z, ZodObject } from "zod";
|
|
4
3
|
import { Filter } from "./types";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
},
|
|
9
|
-
export
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
export declare function
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
export declare function
|
|
20
|
-
|
|
21
|
-
}): (req: Request, res: Response) => Promise<Response<any, Record<string, any>>>;
|
|
4
|
+
export declare const paginationSchema: z.ZodObject<{
|
|
5
|
+
page: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
6
|
+
pageSize: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
7
|
+
}, z.core.$strip>;
|
|
8
|
+
export type Pagination = {
|
|
9
|
+
page: number;
|
|
10
|
+
pageSize: number;
|
|
11
|
+
total?: number;
|
|
12
|
+
count?: number;
|
|
13
|
+
};
|
|
14
|
+
export declare function newPagination(data: unknown): Pagination;
|
|
15
|
+
export declare function findOneBuilder<PK extends ZodObject, Item>(findOne: (pk: z.output<PK>) => Promise<Item>, pkSchema: PK, hook?: (item: Item) => Promise<object>): (req: Request, res: Response) => Promise<Response<any, Record<string, any>> | undefined>;
|
|
16
|
+
export declare function findAllBuilder<FSchema extends ZodObject, Item>(findAll: (filters?: Filter<FSchema>, p?: Pagination) => Promise<Item[]>, filter: FSchema, hook?: (items: Item[], total: number) => Promise<object[]>): (req: Request, res: Response) => Promise<Response<any, Record<string, any>>>;
|
|
17
|
+
export declare function createBuilder<CSchema extends ZodObject, Item>(create: (data: z.core.output<CSchema>) => Promise<Item>, schema: CSchema, hook?: (req: Request, res: Response, data: z.core.output<CSchema>, item: Item) => Promise<object>): (req: Request, res: Response) => Promise<Response<any, Record<string, any>>>;
|
|
18
|
+
export declare function updateBuilder<PKSchema extends ZodObject, USchema extends ZodObject, Item>(update: (pks: z.core.output<PKSchema>, data: z.core.output<USchema>) => Promise<Item>, pkSchema: PKSchema, schema: USchema): (req: Request, res: Response) => Promise<Response<any, Record<string, any>>>;
|
|
19
|
+
export declare function deleteBuilder<PKSchema extends ZodObject>(remove: (id: z.core.output<PKSchema>) => Promise<void>, pkSchema: PKSchema): (req: Request, res: Response) => Promise<Response<any, Record<string, any>>>;
|
|
22
20
|
export declare function validate<T extends ZodObject>(schema: T, fn: (req: Request, res: Response, data: z.output<T>) => Promise<Response>): (req: Request, res: Response) => Promise<Response<any, Record<string, any>>>;
|
|
23
|
-
interface CRUDService<FSchema extends ZodObject> {
|
|
24
|
-
findOne: (id: any) => Promise<any>;
|
|
25
|
-
findAll: (filters?: Filter<FSchema>, page?: number, pageSize?: number) => Promise<any[]>;
|
|
26
|
-
count: (filters: Filter<FSchema>) => Promise<number>;
|
|
27
|
-
create: (data: any) => Promise<any>;
|
|
28
|
-
update: (id: any, data: Partial<any>) => Promise<any>;
|
|
29
|
-
delete: (id: any) => Promise<any>;
|
|
30
|
-
}
|
|
31
|
-
export declare class BaseController<T extends PgTable, FSchema extends z.ZodObject> {
|
|
32
|
-
protected service: CRUDService<FSchema>;
|
|
33
|
-
private filterSchema;
|
|
34
|
-
private createSchema;
|
|
35
|
-
private updateSchema;
|
|
36
|
-
constructor(service: CRUDService<FSchema>, base: z.ZodObject, filter: FSchema, createSchema?: z.ZodSchema<InferInsertModel<T>>, updateSchema?: Partial<InferInsertModel<T>>);
|
|
37
|
-
getAll: (req: Request, res: Response) => Promise<void>;
|
|
38
|
-
getById: (req: Request, res: Response) => Promise<void>;
|
|
39
|
-
create: (req: Request, res: Response) => Promise<void>;
|
|
40
|
-
update: (req: Request, res: Response) => Promise<void>;
|
|
41
|
-
delete: (req: Request, res: Response) => Promise<void>;
|
|
42
|
-
}
|
|
43
|
-
export {};
|
package/dist/src/controller.js
CHANGED
|
@@ -1,15 +1,26 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.paginationSchema = void 0;
|
|
4
|
+
exports.newPagination = newPagination;
|
|
4
5
|
exports.findOneBuilder = findOneBuilder;
|
|
5
6
|
exports.findAllBuilder = findAllBuilder;
|
|
6
7
|
exports.createBuilder = createBuilder;
|
|
7
8
|
exports.updateBuilder = updateBuilder;
|
|
8
9
|
exports.deleteBuilder = deleteBuilder;
|
|
9
10
|
exports.validate = validate;
|
|
10
|
-
|
|
11
|
+
const zod_1 = require("zod");
|
|
12
|
+
exports.paginationSchema = zod_1.z.object({
|
|
13
|
+
page: zod_1.z.coerce.number().default(1),
|
|
14
|
+
pageSize: zod_1.z.coerce.number().default(10)
|
|
15
|
+
});
|
|
16
|
+
function newPagination(data) {
|
|
17
|
+
const p = exports.paginationSchema.parse(data);
|
|
18
|
+
return p;
|
|
19
|
+
}
|
|
20
|
+
function findOneBuilder(findOne, pkSchema, hook) {
|
|
11
21
|
return async (req, res) => {
|
|
12
|
-
const
|
|
22
|
+
const pk = pkSchema.parse(req.params);
|
|
23
|
+
const item = await findOne(pk);
|
|
13
24
|
if (hook !== undefined) {
|
|
14
25
|
const i = await hook(item);
|
|
15
26
|
return res.status(200).json(i);
|
|
@@ -17,44 +28,33 @@ function findOneBuilder(service, hook) {
|
|
|
17
28
|
res.status(200).json(item);
|
|
18
29
|
};
|
|
19
30
|
}
|
|
20
|
-
function findAllBuilder(
|
|
31
|
+
function findAllBuilder(findAll, filter, hook) {
|
|
21
32
|
return async (req, res) => {
|
|
22
33
|
const filters = filter.parse({
|
|
23
34
|
...req.params,
|
|
24
35
|
...req.query
|
|
25
36
|
});
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
pagination = getPagination(req);
|
|
29
|
-
itemsProm = service.findAll(filters, pagination.page, pagination.pageSize);
|
|
30
|
-
}
|
|
31
|
-
else {
|
|
32
|
-
itemsProm = service.findAll(filters);
|
|
33
|
-
}
|
|
34
|
-
const totalProm = service.count(filters);
|
|
35
|
-
const [items, total] = await Promise.all([itemsProm, totalProm]);
|
|
37
|
+
const pagination = newPagination(req.query);
|
|
38
|
+
const items = await findAll(filters, pagination);
|
|
36
39
|
let resItems = items;
|
|
37
40
|
if (hook != undefined) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
pagination
|
|
43
|
-
|
|
44
|
-
total
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
else {
|
|
48
|
-
return res.status(200).json({
|
|
49
|
-
items: resItems,
|
|
50
|
-
total
|
|
51
|
-
});
|
|
41
|
+
if (!pagination.total) {
|
|
42
|
+
resItems = await hook(items, items.length);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
resItems = await hook(items, pagination.total);
|
|
46
|
+
}
|
|
52
47
|
}
|
|
48
|
+
return res.status(200).json({
|
|
49
|
+
pagination,
|
|
50
|
+
items: resItems,
|
|
51
|
+
total: pagination.total
|
|
52
|
+
});
|
|
53
53
|
};
|
|
54
54
|
}
|
|
55
|
-
function createBuilder(
|
|
55
|
+
function createBuilder(create, schema, hook) {
|
|
56
56
|
return validate(schema, async (req, res, data) => {
|
|
57
|
-
const item = await
|
|
57
|
+
const item = await create(data);
|
|
58
58
|
if (hook) {
|
|
59
59
|
const i = await hook(req, res, data, item);
|
|
60
60
|
return res.status(201).json(i);
|
|
@@ -62,15 +62,17 @@ function createBuilder(service, schema, hook) {
|
|
|
62
62
|
return res.status(201).json(item);
|
|
63
63
|
});
|
|
64
64
|
}
|
|
65
|
-
function updateBuilder(
|
|
65
|
+
function updateBuilder(update, pkSchema, schema) {
|
|
66
66
|
return validate(schema, async (req, res, data) => {
|
|
67
|
-
const
|
|
67
|
+
const pk = pkSchema.parse(req.params);
|
|
68
|
+
const item = await update(pk, data);
|
|
68
69
|
return res.status(200).json(item);
|
|
69
70
|
});
|
|
70
71
|
}
|
|
71
|
-
function deleteBuilder(
|
|
72
|
+
function deleteBuilder(remove, pkSchema) {
|
|
72
73
|
return async (req, res) => {
|
|
73
|
-
|
|
74
|
+
const pk = pkSchema.parse(req.params);
|
|
75
|
+
await remove(pk);
|
|
74
76
|
return res.status(204).send();
|
|
75
77
|
};
|
|
76
78
|
}
|
|
@@ -80,65 +82,3 @@ function validate(schema, fn) {
|
|
|
80
82
|
return fn(req, res, validated);
|
|
81
83
|
};
|
|
82
84
|
}
|
|
83
|
-
function getPagination(req) {
|
|
84
|
-
return {
|
|
85
|
-
page: req.query.page ? parseInt(req.query.page) : 1,
|
|
86
|
-
pageSize: req.query.pageSize
|
|
87
|
-
? parseInt(req.query.pageSize)
|
|
88
|
-
: 10
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
class BaseController {
|
|
92
|
-
constructor(service, base, filter, createSchema, updateSchema) {
|
|
93
|
-
this.getAll = async (req, res) => {
|
|
94
|
-
const filters = getFilters(req, this.filterSchema);
|
|
95
|
-
const pagination = getPagination(req);
|
|
96
|
-
const [items, total] = await Promise.all([
|
|
97
|
-
this.service.findAll(filters, pagination.page, pagination.pageSize),
|
|
98
|
-
this.service.count(filters)
|
|
99
|
-
]);
|
|
100
|
-
res.status(200).json({
|
|
101
|
-
pagination,
|
|
102
|
-
items,
|
|
103
|
-
total
|
|
104
|
-
});
|
|
105
|
-
};
|
|
106
|
-
this.getById = async (req, res) => {
|
|
107
|
-
const item = await this.service.findOne(req.params.id);
|
|
108
|
-
res.status(200).json(item);
|
|
109
|
-
};
|
|
110
|
-
this.create = async (req, res) => {
|
|
111
|
-
const data = this.createSchema.parse(req.body);
|
|
112
|
-
const item = await this.service.create(data);
|
|
113
|
-
res.status(201).json(item);
|
|
114
|
-
};
|
|
115
|
-
this.update = async (req, res) => {
|
|
116
|
-
const data = this.updateSchema.parse(req.body);
|
|
117
|
-
const item = await this.service.update(req.params.id, data);
|
|
118
|
-
res.status(200).json(item);
|
|
119
|
-
};
|
|
120
|
-
this.delete = async (req, res) => {
|
|
121
|
-
await this.service.delete(req.params.id);
|
|
122
|
-
res.status(204).send();
|
|
123
|
-
};
|
|
124
|
-
this.service = service;
|
|
125
|
-
// @ts-expect-error infer schema
|
|
126
|
-
this.createSchema = createSchema || base.omit({
|
|
127
|
-
id: true,
|
|
128
|
-
deletedAt: true
|
|
129
|
-
});
|
|
130
|
-
// @ts-expect-error infer schema
|
|
131
|
-
this.updateSchema = updateSchema || base.partial();
|
|
132
|
-
this.filterSchema = filter;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
exports.BaseController = BaseController;
|
|
136
|
-
/*
|
|
137
|
-
* Extract the filters from the Request
|
|
138
|
-
*/
|
|
139
|
-
function getFilters(req, filter) {
|
|
140
|
-
return filter.parse({
|
|
141
|
-
...req.params,
|
|
142
|
-
...req.query
|
|
143
|
-
});
|
|
144
|
-
}
|
package/dist/src/errors.js
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.errorHandler = exports.Unauthorized = exports.Forbidden = exports.BadRequest = exports.Duplicated = exports.NotFound = exports.ServiceError = void 0;
|
|
4
4
|
exports.handleSqlError = handleSqlError;
|
|
5
|
-
const drizzle_orm_1 = require("drizzle-orm");
|
|
6
5
|
const zod_1 = require("zod");
|
|
7
6
|
class ServiceError extends Error {
|
|
8
7
|
constructor(statusCode, message) {
|
|
@@ -45,10 +44,16 @@ class Unauthorized extends ServiceError {
|
|
|
45
44
|
exports.Unauthorized = Unauthorized;
|
|
46
45
|
const errorHandler = (err, req, res, next) => {
|
|
47
46
|
if (err instanceof ServiceError) {
|
|
48
|
-
return res.status(err.statusCode).json({
|
|
47
|
+
return res.status(err.statusCode).json({
|
|
48
|
+
success: false,
|
|
49
|
+
code: err.statusCode,
|
|
50
|
+
message: err.message
|
|
51
|
+
});
|
|
49
52
|
}
|
|
50
53
|
if (err instanceof zod_1.ZodError) {
|
|
51
54
|
return res.status(400).json({
|
|
55
|
+
success: false,
|
|
56
|
+
code: 400,
|
|
52
57
|
message: "Validation failed",
|
|
53
58
|
errors: err.issues
|
|
54
59
|
});
|
|
@@ -61,7 +66,7 @@ exports.errorHandler = errorHandler;
|
|
|
61
66
|
// infiera bien los tipos
|
|
62
67
|
function handleSqlError(e) {
|
|
63
68
|
let err = e;
|
|
64
|
-
if (e
|
|
69
|
+
if (instanceOf(e) && e.cause) {
|
|
65
70
|
const cause = e.cause;
|
|
66
71
|
if (/duplicate key/i.test(cause.message)) {
|
|
67
72
|
if (isPgErrorWithDetail(cause)) {
|
|
@@ -82,6 +87,14 @@ function handleSqlError(e) {
|
|
|
82
87
|
}
|
|
83
88
|
throw err;
|
|
84
89
|
}
|
|
90
|
+
// Safer version of instanceof that works on vitest too
|
|
91
|
+
function instanceOf(err) {
|
|
92
|
+
return typeof err === 'object' &&
|
|
93
|
+
err !== null &&
|
|
94
|
+
'constructor' in err &&
|
|
95
|
+
'name' in err.constructor &&
|
|
96
|
+
err.constructor.name === "DrizzleQueryError";
|
|
97
|
+
}
|
|
85
98
|
function isPgErrorWithDetail(err) {
|
|
86
99
|
return (typeof err === "object" &&
|
|
87
100
|
err !== null &&
|
package/dist/src/filters.d.ts
CHANGED
|
@@ -5,5 +5,8 @@ import { AnyPgTable, PgColumn } from "drizzle-orm/pg-core";
|
|
|
5
5
|
export declare const createFilterSchema: import("drizzle-zod").CreateInsertSchema<{
|
|
6
6
|
number: true;
|
|
7
7
|
}>;
|
|
8
|
+
export declare const createPkSchema: import("drizzle-zod").CreateSelectSchema<{
|
|
9
|
+
number: true;
|
|
10
|
+
}>;
|
|
8
11
|
export declare function buildFilters<FSchema extends ZodObject>(map: FilterMap<FSchema>, filters?: Filter<FSchema>): SQL<unknown> | undefined;
|
|
9
12
|
export declare function buildPKFilters<T extends AnyPgTable>(pks: PgColumn[], values: PrimaryKeyData<T>): SQL<unknown> | undefined;
|
package/dist/src/filters.js
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createFilterSchema = void 0;
|
|
3
|
+
exports.createPkSchema = exports.createFilterSchema = void 0;
|
|
4
4
|
exports.buildFilters = buildFilters;
|
|
5
5
|
exports.buildPKFilters = buildPKFilters;
|
|
6
6
|
const drizzle_orm_1 = require("drizzle-orm");
|
|
7
7
|
const drizzle_zod_1 = require("drizzle-zod");
|
|
8
|
-
const { createInsertSchema } = (0, drizzle_zod_1.createSchemaFactory)({
|
|
8
|
+
const { createInsertSchema, createSelectSchema } = (0, drizzle_zod_1.createSchemaFactory)({
|
|
9
9
|
coerce: {
|
|
10
10
|
number: true,
|
|
11
11
|
},
|
|
12
12
|
});
|
|
13
13
|
exports.createFilterSchema = createInsertSchema;
|
|
14
|
+
exports.createPkSchema = createSelectSchema;
|
|
14
15
|
function buildFilters(map, filters) {
|
|
15
16
|
const conditions = [];
|
|
16
17
|
if (!filters)
|
package/dist/src/generators.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { PgTable } from "drizzle-orm/pg-core";
|
|
|
2
2
|
export declare function generateRouter(name: string, table: PgTable, imports: string[]): string;
|
|
3
3
|
export declare function generateValidator(name: string, table: PgTable, imports: string[]): string;
|
|
4
4
|
export declare function generateController(name: string, table: PgTable, imports: string[]): string;
|
|
5
|
+
export declare function generateControllerBuilder(name: string, table: PgTable, imports: string[]): string;
|
|
5
6
|
export declare function generateService(name: string, table: PgTable, imports: string[]): string;
|
|
6
7
|
export declare function generateFilter(name: string, table: PgTable, imports: string[]): string;
|
|
7
8
|
export declare function getRelationName(fkName: string): string;
|
package/dist/src/generators.js
CHANGED
|
@@ -3,14 +3,21 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.generateRouter = generateRouter;
|
|
4
4
|
exports.generateValidator = generateValidator;
|
|
5
5
|
exports.generateController = generateController;
|
|
6
|
+
exports.generateControllerBuilder = generateControllerBuilder;
|
|
6
7
|
exports.generateService = generateService;
|
|
7
8
|
exports.generateFilter = generateFilter;
|
|
8
9
|
exports.getRelationName = getRelationName;
|
|
9
|
-
const pg_core_1 = require("drizzle-orm/pg-core");
|
|
10
10
|
const pg_1 = require("./pg");
|
|
11
|
+
const drizzle_orm_1 = require("drizzle-orm");
|
|
11
12
|
function generateRouter(name, table, imports) {
|
|
12
13
|
const pkColumns = (0, pg_1.getPKs)(table);
|
|
13
|
-
|
|
14
|
+
let route = '';
|
|
15
|
+
if (pkColumns.length == 1) {
|
|
16
|
+
route = `:${pkColumns[0].name}`;
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
route = pkColumns.map(pk => `${getRelationName(pk.name)}/:${pk.name}`).join("/");
|
|
20
|
+
}
|
|
14
21
|
return `import { Router } from "express";
|
|
15
22
|
${imports.join('\n')};
|
|
16
23
|
export const ${name}Router = Router();
|
|
@@ -22,19 +29,19 @@ ${name}Router.get("/", ${name}Controller.getAll);
|
|
|
22
29
|
${name}Router.post("/", ${name}Controller.create);
|
|
23
30
|
|
|
24
31
|
// Get one
|
|
25
|
-
${name}Router.get("
|
|
32
|
+
${name}Router.get("/${route}", ${name}Controller.getOne);
|
|
26
33
|
|
|
27
34
|
// Update
|
|
28
|
-
${name}Router.put("
|
|
35
|
+
${name}Router.put("/${route}", ${name}Controller.update);
|
|
29
36
|
|
|
30
37
|
// Delete
|
|
31
|
-
${name}Router.delete("
|
|
38
|
+
${name}Router.delete("/${route}", ${name}Controller.remove);`;
|
|
32
39
|
}
|
|
33
40
|
function generateValidator(name, table, imports) {
|
|
34
41
|
const pkColumns = (0, pg_1.getPKs)(table);
|
|
35
42
|
const zodPkPicker = buildZodPkPicker(pkColumns);
|
|
36
43
|
return `import { createInsertSchema, createSelectSchema } from "drizzle-zod";
|
|
37
|
-
import { createFilterSchema } from "bradb";
|
|
44
|
+
import { createFilterSchema, createPkSchema } from "bradb";
|
|
38
45
|
import { z } from "zod";
|
|
39
46
|
${imports.join('\n')};
|
|
40
47
|
|
|
@@ -42,7 +49,7 @@ const select = createSelectSchema(${name}Table);
|
|
|
42
49
|
const insert = createInsertSchema(${name}Table);
|
|
43
50
|
const update = insert.partial();
|
|
44
51
|
const filter = createFilterSchema(${name}Table).partial();
|
|
45
|
-
const pk =
|
|
52
|
+
const pk = createPkSchema(${name}Table).pick({
|
|
46
53
|
${zodPkPicker}
|
|
47
54
|
});
|
|
48
55
|
|
|
@@ -62,16 +69,18 @@ export const ${name}Validator = {
|
|
|
62
69
|
}
|
|
63
70
|
function generateController(name, table, imports) {
|
|
64
71
|
return `import { Request, Response } from "express";
|
|
72
|
+
import { newPagination } from "bradb";
|
|
65
73
|
${imports.join('\n')};
|
|
66
74
|
|
|
67
75
|
async function getAll(req: Request, res: Response) {
|
|
76
|
+
const pagination = newPagination(req.query);
|
|
68
77
|
const filters = ${name}Validator.filter.parse(req.query);
|
|
69
|
-
const items = await ${name}Service.findAll(filters);
|
|
70
|
-
const total = await ${name}Service.count(filters);
|
|
78
|
+
const items = await ${name}Service.findAll(filters, pagination);
|
|
71
79
|
|
|
72
80
|
res.json({
|
|
81
|
+
pagination,
|
|
73
82
|
items,
|
|
74
|
-
total
|
|
83
|
+
total: pagination.total // this is going to be removed
|
|
75
84
|
});
|
|
76
85
|
}
|
|
77
86
|
|
|
@@ -108,29 +117,52 @@ export const ${name}Controller = {
|
|
|
108
117
|
remove
|
|
109
118
|
};`;
|
|
110
119
|
}
|
|
120
|
+
function generateControllerBuilder(name, table, imports) {
|
|
121
|
+
return `import {
|
|
122
|
+
findAllBuilder,
|
|
123
|
+
findOneBuilder,
|
|
124
|
+
updateBuilder,
|
|
125
|
+
deleteBuilder,
|
|
126
|
+
createBuilder
|
|
127
|
+
} from "bradb";
|
|
128
|
+
${imports.join('\n')};
|
|
129
|
+
|
|
130
|
+
export const ${name}Controller = {
|
|
131
|
+
getAll: findAllBuilder(${name}Service.findAll, ${name}Validator.filter),
|
|
132
|
+
getOne: findOneBuilder(${name}Service.findOne, ${name}Validator.pk),
|
|
133
|
+
create: createBuilder(${name}Service.create, ${name}Validator.insert),
|
|
134
|
+
update: updateBuilder(${name}Service.update, ${name}Validator.pk, ${name}Validator.update),
|
|
135
|
+
remove: deleteBuilder(${name}Service.delete, ${name}Validator.pk)
|
|
136
|
+
};`;
|
|
137
|
+
}
|
|
111
138
|
function generateService(name, table, imports) {
|
|
139
|
+
const selection = `db
|
|
140
|
+
.select()
|
|
141
|
+
.from(${name}Table)
|
|
142
|
+
.$dynamic()`;
|
|
112
143
|
return `import { ServiceBuilder } from "bradb";
|
|
113
144
|
${imports.join('\n')};
|
|
114
145
|
|
|
115
146
|
const builder = new ServiceBuilder(db, ${name}Table, ${name}FilterMap);
|
|
116
147
|
|
|
117
|
-
const selection = db
|
|
118
|
-
.select()
|
|
119
|
-
.from(${name}Table)
|
|
120
|
-
.$dynamic();
|
|
121
|
-
|
|
122
148
|
export const ${name}Service = {
|
|
123
149
|
create: builder.create(),
|
|
124
150
|
update: builder.update(),
|
|
125
|
-
count: builder.count(),
|
|
126
151
|
delete: builder.delete(),
|
|
127
|
-
findAll: builder.findAll(
|
|
128
|
-
|
|
152
|
+
findAll: builder.findAll(
|
|
153
|
+
${selection}
|
|
154
|
+
),
|
|
155
|
+
findOne: builder.findOne(
|
|
156
|
+
${selection}
|
|
157
|
+
)
|
|
129
158
|
};`;
|
|
130
159
|
}
|
|
131
160
|
function generateFilter(name, table, imports) {
|
|
132
|
-
const { columns } =
|
|
133
|
-
const
|
|
161
|
+
// const { columns } = getTableConfig(table);
|
|
162
|
+
const columns = (0, drizzle_orm_1.getTableColumns)(table);
|
|
163
|
+
const filters = Object.entries(columns).map(([colName, _]) => {
|
|
164
|
+
return `${colName}: (val) => eq(${name}Table.${colName}, val)`;
|
|
165
|
+
}).join(',\n\t');
|
|
134
166
|
return `import { FilterMap } from "bradb";
|
|
135
167
|
import { eq } from "drizzle-orm";
|
|
136
168
|
${imports.join('\n')};
|
package/dist/src/service.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { Filter, FilterMap, PrimaryKeyData } from "./types";
|
|
2
|
-
import { AnyPgTable, PgColumn, PgSelect, PgTransaction } from "drizzle-orm/pg-core";
|
|
2
|
+
import { AnyPgColumn, AnyPgTable, PgColumn, PgSelect, PgTransaction, SelectedFields } from "drizzle-orm/pg-core";
|
|
3
3
|
import { NodePgDatabase } from "drizzle-orm/node-postgres";
|
|
4
4
|
import { InferInsertModel, SQL } from "drizzle-orm";
|
|
5
5
|
import { ZodObject } from "zod";
|
|
6
|
+
import { Pagination } from "./controller";
|
|
6
7
|
export declare class ServiceBuilder<T extends AnyPgTable, TSchema extends Record<string, unknown>, FSchema extends ZodObject, PKType extends object = PrimaryKeyData<T>> {
|
|
7
8
|
private readonly db;
|
|
8
9
|
private readonly table;
|
|
@@ -13,12 +14,17 @@ export declare class ServiceBuilder<T extends AnyPgTable, TSchema extends Record
|
|
|
13
14
|
readonly findOneConditions: (pkFilter: PKType) => SQL | undefined;
|
|
14
15
|
readonly tableName: string;
|
|
15
16
|
constructor(db: NodePgDatabase<TSchema>, table: T, map: FilterMap<FSchema>);
|
|
16
|
-
findOne<S extends PgSelect>(select: S): (pkValues: PKType) => Promise<
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
findOne<S extends PgSelect>(select: S): (pkValues: PKType) => Promise<S["_"]["result"][0]>;
|
|
18
|
+
TEST<F extends SelectedFields>(fields: F, cb: (qb: PgSelect) => PgSelect): (pkValues: PKType) => Promise<RowFromFields<F>>;
|
|
19
|
+
findAll<S extends PgSelect>(select: S, paginated?: boolean): (filters?: Filter<FSchema>, p?: Pagination) => Promise<S["_"]["result"][0][]>;
|
|
20
|
+
count<S extends PgSelect>(select?: S): (filters?: Filter<FSchema>) => Promise<number>;
|
|
19
21
|
create<S extends any>(hook?: (data: S extends Object ? S : InferInsertModel<T>, tx?: PgTransaction<any, TSchema, any>) => Promise<InferInsertModel<T>>): (data: S extends Object ? S : InferInsertModel<T>, tx?: PgTransaction<any, TSchema, any>) => Promise<{ [Key in keyof T["_"]["columns"] & string as Key]: T["_"]["columns"][Key]["_"]["notNull"] extends true ? T["_"]["columns"][Key]["_"]["data"] : T["_"]["columns"][Key]["_"]["data"] | null; } extends infer T_1 ? { [K in keyof T_1]: T_1[K]; } : never>;
|
|
20
22
|
update<S extends any>(pre?: (data: S extends Object ? S : Partial<InferInsertModel<T>>, tx?: PgTransaction<any, TSchema, any>) => Promise<InferInsertModel<T>>): (pks: PKType, data: S extends Object ? S : Partial<InferInsertModel<T>>, tx?: PgTransaction<any, TSchema, any>) => Promise<{ [Key in keyof T["_"]["columns"] & string as Key]: T["_"]["columns"][Key]["_"]["notNull"] extends true ? T["_"]["columns"][Key]["_"]["data"] : T["_"]["columns"][Key]["_"]["data"] | null; } extends infer T_1 ? { [K in keyof T_1]: T_1[K]; } : never>;
|
|
21
23
|
delete(): (pks: PKType, tx?: PgTransaction<any, TSchema, any>) => Promise<void>;
|
|
22
24
|
softDelete(): (pks: PKType, tx?: PgTransaction<any, TSchema, any>) => Promise<void>;
|
|
23
25
|
hardDelete(): (pks: PKType, tx?: PgTransaction<any, TSchema, any>) => Promise<void>;
|
|
24
26
|
}
|
|
27
|
+
type RowFromFields<T extends SelectedFields> = {
|
|
28
|
+
[K in keyof T]: T[K] extends AnyPgColumn ? T[K]['_']['data'] : never;
|
|
29
|
+
};
|
|
30
|
+
export {};
|
package/dist/src/service.js
CHANGED
|
@@ -31,23 +31,52 @@ class ServiceBuilder {
|
|
|
31
31
|
return result[0];
|
|
32
32
|
};
|
|
33
33
|
}
|
|
34
|
+
TEST(fields, cb) {
|
|
35
|
+
return async (pkValues) => {
|
|
36
|
+
const pre = this.db.select(fields).from(this.table).$dynamic();
|
|
37
|
+
const result = await cb(pre).where(this.findOneConditions(pkValues));
|
|
38
|
+
if (result.length == 0)
|
|
39
|
+
throw notFoundWithId(this.tableName, pkValues);
|
|
40
|
+
return result[0];
|
|
41
|
+
};
|
|
42
|
+
}
|
|
34
43
|
findAll(select, paginated = true) {
|
|
35
44
|
const base = (f) => select.where(this.findAllConditions(f));
|
|
36
45
|
if (paginated) {
|
|
37
|
-
return async (filters,
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
46
|
+
return async (filters, p) => {
|
|
47
|
+
if (!p)
|
|
48
|
+
p = {
|
|
49
|
+
page: 1,
|
|
50
|
+
pageSize: 10
|
|
51
|
+
};
|
|
52
|
+
const countQuery = this.db
|
|
53
|
+
.select({ count: (0, drizzle_orm_1.count)() })
|
|
54
|
+
.from(this.table)
|
|
55
|
+
.where(this.findAllConditions(filters));
|
|
56
|
+
const offset = (p.page - 1) * p.pageSize;
|
|
57
|
+
const items = await base(filters).limit(p.pageSize).offset(offset);
|
|
58
|
+
const [res] = await countQuery;
|
|
59
|
+
p.total = res.count;
|
|
60
|
+
p.count = items.length;
|
|
61
|
+
return items;
|
|
42
62
|
};
|
|
43
63
|
}
|
|
44
64
|
else {
|
|
45
65
|
return async (filters) => {
|
|
46
|
-
|
|
66
|
+
const items = await base(filters);
|
|
67
|
+
return items;
|
|
47
68
|
};
|
|
48
69
|
}
|
|
49
70
|
}
|
|
50
|
-
count() {
|
|
71
|
+
count(select) {
|
|
72
|
+
if (select) {
|
|
73
|
+
return async (filters) => {
|
|
74
|
+
const base = select.where(this.findAllConditions(filters));
|
|
75
|
+
const subquery = base.as('countsubquery');
|
|
76
|
+
const [result] = await this.db.select({ count: (0, drizzle_orm_1.count)() }).from(subquery);
|
|
77
|
+
return result.count;
|
|
78
|
+
};
|
|
79
|
+
}
|
|
51
80
|
return async (filters) => {
|
|
52
81
|
const [result] = await this.db
|
|
53
82
|
.select({ count: (0, drizzle_orm_1.count)() })
|
package/dist/src/types.d.ts
CHANGED
|
@@ -1,22 +1,12 @@
|
|
|
1
1
|
import { SQL } from "drizzle-orm";
|
|
2
|
-
import { AnyPgTable,
|
|
2
|
+
import { AnyPgTable, PgTable, PgTransaction } from "drizzle-orm/pg-core";
|
|
3
3
|
import z, { ZodObject } from "zod";
|
|
4
|
-
export
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
export
|
|
9
|
-
|
|
10
|
-
}
|
|
11
|
-
export interface CreateService<TTable extends PgTable, TSchema extends Record<string, unknown>> {
|
|
12
|
-
create: (data: TTable["$inferInsert"], tx?: PgTransaction<any, TSchema, any>) => Promise<TTable["$inferSelect"]>;
|
|
13
|
-
}
|
|
14
|
-
export interface UpdateService<TTable extends PgTable, TSchema extends Record<string, unknown>> {
|
|
15
|
-
update: (id: PrimaryKeyType<TTable>, data: Partial<TTable["$inferInsert"]>, tx?: PgTransaction<any, TSchema, any>) => Promise<TTable["$inferSelect"]>;
|
|
16
|
-
}
|
|
17
|
-
export interface DeleteService<TTable extends PgTable, TSchema extends Record<string, unknown>> {
|
|
18
|
-
delete: (id: PrimaryKeyType<TTable>, tx?: PgTransaction<any, TSchema, any>) => Promise<void>;
|
|
19
|
-
}
|
|
4
|
+
export type FindOneFunc<T extends PgTable> = (pks: PrimaryKeyData<T>) => Promise<object>;
|
|
5
|
+
export type FindAllFunc<F extends ZodObject> = (filters?: F, page?: number, pageSize?: number) => Promise<object>;
|
|
6
|
+
export type CountFunc<F extends ZodObject> = (filters?: F) => Promise<object>;
|
|
7
|
+
export type CreateFunc<T extends PgTable> = (data: T["$inferInsert"], tx?: PgTransaction<any, any, any>) => Promise<T["$inferSelect"]>;
|
|
8
|
+
export type UpdateFunc<T extends PgTable> = (pks: PrimaryKeyData<T>, data: Partial<T["$inferInsert"]>, tx?: PgTransaction<any, any, any>) => Promise<T["$inferSelect"]>;
|
|
9
|
+
export type DeleteFunc<T extends PgTable> = (pks: PrimaryKeyData<T>) => Promise<void>;
|
|
20
10
|
export type PrimaryKeyData<TTable extends AnyPgTable> = {
|
|
21
11
|
[K in keyof TTable["_"]["columns"] as TTable["_"]["columns"][K] extends {
|
|
22
12
|
_: {
|
|
@@ -24,15 +14,6 @@ export type PrimaryKeyData<TTable extends AnyPgTable> = {
|
|
|
24
14
|
};
|
|
25
15
|
} ? K : never]: TTable["_"]["columns"][K]["_"]["data"];
|
|
26
16
|
};
|
|
27
|
-
export interface PaginationParams {
|
|
28
|
-
page: number;
|
|
29
|
-
pageSize: number;
|
|
30
|
-
}
|
|
31
|
-
export type Table = AnyPgTable & {
|
|
32
|
-
deletedAt: PgColumn;
|
|
33
|
-
id: any;
|
|
34
|
-
};
|
|
35
|
-
export type PrimaryKeyType<T extends AnyPgTable> = T["_"]["columns"]["id"]["_"]["data"];
|
|
36
17
|
export type FilterMap<Schema extends z.ZodObject, Out = z.infer<Schema>> = {
|
|
37
18
|
[K in keyof Out]: (value: NonNullable<Out[K]>) => SQL;
|
|
38
19
|
};
|