@visulima/crud 1.0.1 → 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/CHANGELOG.md +23 -0
- package/README.md +46 -16
- package/dist/chunk-SH6A4KBC.mjs +28 -0
- package/dist/{chunk-UBXIGP5H.mjs.map → chunk-SH6A4KBC.mjs.map} +1 -1
- package/dist/chunk-ZY3WOLEP.js +28 -0
- package/dist/chunk-ZY3WOLEP.js.map +1 -0
- package/dist/index.d.ts +9 -15
- package/dist/index.js +57 -37
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +54 -34
- package/dist/index.mjs.map +1 -1
- package/dist/next/index.js +10 -281
- package/dist/next/index.js.map +1 -1
- package/dist/next/index.mjs +9 -280
- package/dist/next/index.mjs.map +1 -1
- package/next/package.json +18 -0
- package/package.json +16 -14
- package/dist/chunk-FJWRITBO.js +0 -52
- package/dist/chunk-FJWRITBO.js.map +0 -1
- package/dist/chunk-UBXIGP5H.mjs +0 -52
- package/src/adapter/prisma/index.ts +0 -241
- package/src/adapter/prisma/types.d.ts +0 -46
- package/src/adapter/prisma/utils/models-to-route-names.ts +0 -12
- package/src/adapter/prisma/utils/parse-cursor.ts +0 -26
- package/src/adapter/prisma/utils/parse-order-by.ts +0 -21
- package/src/adapter/prisma/utils/parse-recursive.ts +0 -26
- package/src/adapter/prisma/utils/parse-where.ts +0 -197
- package/src/base-crud-handler.ts +0 -181
- package/src/handler/create.ts +0 -21
- package/src/handler/delete.ts +0 -27
- package/src/handler/list.ts +0 -62
- package/src/handler/read.ts +0 -27
- package/src/handler/update.ts +0 -29
- package/src/index.ts +0 -27
- package/src/next/api/edge/index.ts +0 -23
- package/src/next/api/node/index.ts +0 -27
- package/src/next/index.ts +0 -2
- package/src/query-parser.ts +0 -94
- package/src/swagger/adapter/prisma/index.ts +0 -95
- package/src/swagger/json-schema-parser.ts +0 -456
- package/src/swagger/parameters.ts +0 -83
- package/src/swagger/types.d.ts +0 -53
- package/src/swagger/utils/format-example-ref.ts +0 -4
- package/src/swagger/utils/format-schema-ref.ts +0 -4
- package/src/swagger/utils/get-models-accessible-routes.ts +0 -23
- package/src/swagger/utils/get-swagger-paths.ts +0 -244
- package/src/swagger/utils/get-swagger-tags.ts +0 -13
- package/src/types.d.ts +0 -124
- package/src/utils/format-resource-id.ts +0 -3
- package/src/utils/get-accessible-routes.ts +0 -18
- package/src/utils/get-resource-name-from-url.ts +0 -23
- package/src/utils/get-route-type.ts +0 -99
- package/src/utils/is-primitive.ts +0 -5
- package/src/utils/validate-adapter-methods.ts +0 -15
package/dist/chunk-FJWRITBO.js
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true});var __create = Object.create;
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
-
var __commonJS = (cb, mod) => function __require() {
|
|
8
|
-
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
19
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
20
|
-
mod
|
|
21
|
-
));
|
|
22
|
-
|
|
23
|
-
// src/types.d.ts
|
|
24
|
-
var RouteType = /* @__PURE__ */ ((RouteType2) => {
|
|
25
|
-
RouteType2["CREATE"] = "CREATE";
|
|
26
|
-
RouteType2["READ_ALL"] = "READ_ALL";
|
|
27
|
-
RouteType2["READ_ONE"] = "READ_ONE";
|
|
28
|
-
RouteType2["UPDATE"] = "UPDATE";
|
|
29
|
-
RouteType2["DELETE"] = "DELETE";
|
|
30
|
-
return RouteType2;
|
|
31
|
-
})(RouteType || {});
|
|
32
|
-
|
|
33
|
-
// src/utils/get-accessible-routes.ts
|
|
34
|
-
var getAccessibleRoutes = (only, exclude, defaultExposeStrategy = "all") => {
|
|
35
|
-
let accessibleRoutes = defaultExposeStrategy === "none" ? [] : ["READ_ALL" /* READ_ALL */, "READ_ONE" /* READ_ONE */, "UPDATE" /* UPDATE */, "DELETE" /* DELETE */, "CREATE" /* CREATE */];
|
|
36
|
-
if (Array.isArray(only)) {
|
|
37
|
-
accessibleRoutes = only;
|
|
38
|
-
}
|
|
39
|
-
if (exclude == null ? void 0 : exclude.length) {
|
|
40
|
-
accessibleRoutes = accessibleRoutes.filter((element) => !exclude.includes(element));
|
|
41
|
-
}
|
|
42
|
-
return accessibleRoutes;
|
|
43
|
-
};
|
|
44
|
-
var get_accessible_routes_default = getAccessibleRoutes;
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
exports.__commonJS = __commonJS; exports.__toESM = __toESM; exports.RouteType = RouteType; exports.get_accessible_routes_default = get_accessible_routes_default;
|
|
52
|
-
//# sourceMappingURL=chunk-FJWRITBO.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.d.ts","../src/utils/get-accessible-routes.ts"],"names":["RouteType"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAMO,IAAK,YAAL,kBAAKA,eAAL;AACH,EAAAA,WAAA,YAAS;AACT,EAAAA,WAAA,cAAW;AACX,EAAAA,WAAA,cAAW;AACX,EAAAA,WAAA,YAAS;AACT,EAAAA,WAAA,YAAS;AALD,SAAAA;AAAA,GAAA;;;ACJZ,IAAM,sBAAsB,CAAC,MAAoB,SAAuB,wBAAwC,UAAuB;AAEnI,MAAI,mBAAgC,0BAA0B,SAAS,CAAC,IAAI,0HAA6F;AAEzK,MAAI,MAAM,QAAQ,IAAI,GAAG;AACrB,uBAAmB;AAAA,EACvB;AAEA,MAAI,mCAAS,QAAQ;AACjB,uBAAmB,iBAAiB,OAAO,CAAC,YAAY,CAAC,QAAQ,SAAS,OAAO,CAAC;AAAA,EACtF;AAEA,SAAO;AACX;AAEA,IAAO,gCAAQ","sourcesContent":["import type { Handler as CreateHandler } from \"./handler/create\";\nimport type { Handler as DeleteHandler } from \"./handler/delete\";\nimport type { Handler as ListHandler } from \"./handler/list\";\nimport type { Handler as GetHandler } from \"./handler/read\";\nimport type { Handler as UpdateHandler } from \"./handler/update\";\n\nexport enum RouteType {\n CREATE = \"CREATE\",\n READ_ALL = \"READ_ALL\",\n READ_ONE = \"READ_ONE\",\n UPDATE = \"UPDATE\",\n DELETE = \"DELETE\",\n}\n\nexport type ModelOption = {\n name?: string\n only?: RouteType[]\n exclude?: RouteType[]\n formatResourceId?: (resourceId: string) => string | number\n};\n\nexport type ModelsOptions<M extends string = string> = {\n [key in M]?: ModelOption\n};\n\nexport type HandlerOptions<M extends string = string> = {\n formatResourceId?: (resourceId: string) => string | number;\n models?: ModelsOptions<M>;\n exposeStrategy?: \"all\" | \"none\";\n pagination?: PaginationConfig,\n handlers?: {\n create?: CreateHandler;\n delete?: DeleteHandler;\n get?: GetHandler;\n list?: ListHandler;\n update?: UpdateHandler;\n },\n};\n\nexport type PaginationConfig = {\n perPage: number\n};\n\nexport interface HandlerParameters<T, Q> {\n adapter: Adapter<T, Q>;\n query: Q;\n resourceName: string;\n}\n\nexport interface UniqueResourceHandlerParameters<T, Q> {\n adapter: Adapter<T, Q>;\n query: Q;\n resourceName: string;\n resourceId: string | number;\n}\n\nexport interface Adapter<T, Q, M extends string = string> {\n models?: M[];\n init?: () => Promise<void>;\n parseQuery(resourceName: M, query: ParsedQueryParameters): Q;\n getAll(resourceName: M, query: Q): Promise<T[]>;\n getOne(resourceName: M, resourceId: string | number, query: Q): Promise<T>;\n create(resourceName: M, data: any, query: Q): Promise<T>;\n update(resourceName: M, resourceId: string | number, data: any, query: Q): Promise<T>;\n delete(resourceName: M, resourceId: string | number, query: Q): Promise<T>;\n getPaginationData(resourceName: M, query: Q): Promise<PaginationData>;\n getModels(): M[];\n connect?: () => Promise<void>;\n disconnect?: () => Promise<void>;\n handleError?: (error: Error) => void;\n mapModelsToRouteNames?: () => Promise<{ [key in M]?: string }>;\n}\n\nexport type PaginationData = {\n total: number\n pageCount: number\n page: number\n};\n\nexport type RecursiveField = {\n [key: string]: boolean | TRecursiveField;\n};\n\nexport type WhereOperator = \"$eq\" | \"$neq\" | \"$in\" | \"$notin\" | \"$lt\" | \"$lte\" | \"$gt\" | \"$gte\" | \"$cont\" | \"$starts\" | \"$ends\" | \"$isnull\";\n\nexport type SearchCondition = string | boolean | number | Date | null;\n\nexport type WhereCondition = {\n [key in TWhereOperator]?: TSearchCondition;\n};\n\nexport type Condition = {\n [key: string]: TSearchCondition | TWhereCondition | TCondition;\n};\n\nexport type WhereField = Condition & {\n $and?: TCondition | TCondition[];\n $or?: TCondition | TCondition[];\n $not?: TCondition | TCondition[];\n};\n\nexport type OrderByOperator = \"$asc\" | \"$desc\";\n\nexport type OrderByField = {\n [key: string]: TOrderByOperator;\n};\n\nexport interface ParsedQueryParameters {\n select?: RecursiveField;\n include?: RecursiveField;\n where?: WhereField;\n orderBy?: OrderByField;\n limit?: number;\n skip?: number;\n distinct?: string;\n page?: number;\n originalQuery?: {\n [key: string]: any;\n };\n}\n\nexport interface ExecuteHandler<Request, Response> {\n (request: Request, response: Response): Promise<void>;\n}\n","import { RouteType } from \"../types.d\";\n\nconst getAccessibleRoutes = (only?: RouteType[], exclude?: RouteType[], defaultExposeStrategy: \"all\" | \"none\" = \"all\"): RouteType[] => {\n // eslint-disable-next-line max-len\n let accessibleRoutes: RouteType[] = defaultExposeStrategy === \"none\" ? [] : [RouteType.READ_ALL, RouteType.READ_ONE, RouteType.UPDATE, RouteType.DELETE, RouteType.CREATE];\n\n if (Array.isArray(only)) {\n accessibleRoutes = only;\n }\n\n if (exclude?.length) {\n accessibleRoutes = accessibleRoutes.filter((element) => !exclude.includes(element));\n }\n\n return accessibleRoutes;\n};\n\nexport default getAccessibleRoutes;\n"]}
|
package/dist/chunk-UBXIGP5H.mjs
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
var __create = Object.create;
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
-
var __commonJS = (cb, mod) => function __require() {
|
|
8
|
-
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
19
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
20
|
-
mod
|
|
21
|
-
));
|
|
22
|
-
|
|
23
|
-
// src/types.d.ts
|
|
24
|
-
var RouteType = /* @__PURE__ */ ((RouteType2) => {
|
|
25
|
-
RouteType2["CREATE"] = "CREATE";
|
|
26
|
-
RouteType2["READ_ALL"] = "READ_ALL";
|
|
27
|
-
RouteType2["READ_ONE"] = "READ_ONE";
|
|
28
|
-
RouteType2["UPDATE"] = "UPDATE";
|
|
29
|
-
RouteType2["DELETE"] = "DELETE";
|
|
30
|
-
return RouteType2;
|
|
31
|
-
})(RouteType || {});
|
|
32
|
-
|
|
33
|
-
// src/utils/get-accessible-routes.ts
|
|
34
|
-
var getAccessibleRoutes = (only, exclude, defaultExposeStrategy = "all") => {
|
|
35
|
-
let accessibleRoutes = defaultExposeStrategy === "none" ? [] : ["READ_ALL" /* READ_ALL */, "READ_ONE" /* READ_ONE */, "UPDATE" /* UPDATE */, "DELETE" /* DELETE */, "CREATE" /* CREATE */];
|
|
36
|
-
if (Array.isArray(only)) {
|
|
37
|
-
accessibleRoutes = only;
|
|
38
|
-
}
|
|
39
|
-
if (exclude == null ? void 0 : exclude.length) {
|
|
40
|
-
accessibleRoutes = accessibleRoutes.filter((element) => !exclude.includes(element));
|
|
41
|
-
}
|
|
42
|
-
return accessibleRoutes;
|
|
43
|
-
};
|
|
44
|
-
var get_accessible_routes_default = getAccessibleRoutes;
|
|
45
|
-
|
|
46
|
-
export {
|
|
47
|
-
__commonJS,
|
|
48
|
-
__toESM,
|
|
49
|
-
RouteType,
|
|
50
|
-
get_accessible_routes_default
|
|
51
|
-
};
|
|
52
|
-
//# sourceMappingURL=chunk-UBXIGP5H.mjs.map
|
|
@@ -1,241 +0,0 @@
|
|
|
1
|
-
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
2
|
-
import {
|
|
3
|
-
// @ts-ignore
|
|
4
|
-
PrismaAction,
|
|
5
|
-
// @ts-ignore
|
|
6
|
-
PrismaClient,
|
|
7
|
-
} from "@prisma/client";
|
|
8
|
-
import createHttpError from "http-errors";
|
|
9
|
-
|
|
10
|
-
import type { Adapter, PaginationData, ParsedQueryParameters } from "../../types.d";
|
|
11
|
-
import type { PrismaParsedQueryParameters } from "./types.d";
|
|
12
|
-
import modelsToRouteNames from "./utils/models-to-route-names";
|
|
13
|
-
import parsePrismaCursor from "./utils/parse-cursor";
|
|
14
|
-
import parsePrismaOrderBy from "./utils/parse-order-by";
|
|
15
|
-
import parsePrismaRecursiveField from "./utils/parse-recursive";
|
|
16
|
-
import parsePrismaWhere from "./utils/parse-where";
|
|
17
|
-
|
|
18
|
-
interface AdapterCtorArguments<M extends string = string> {
|
|
19
|
-
primaryKey?: string;
|
|
20
|
-
manyRelations?: {
|
|
21
|
-
[key in M]?: string[];
|
|
22
|
-
};
|
|
23
|
-
prismaClient: PrismaClient;
|
|
24
|
-
models?: M[];
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export default class PrismaAdapter<T, M extends string> implements Adapter<T, PrismaParsedQueryParameters, M> {
|
|
28
|
-
private readonly primaryKey: string;
|
|
29
|
-
|
|
30
|
-
private readonly manyRelations: {
|
|
31
|
-
[key in M]?: string[];
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
private readonly prismaClient: PrismaClient;
|
|
35
|
-
|
|
36
|
-
models?: M[];
|
|
37
|
-
|
|
38
|
-
private readonly ctorModels?: M[];
|
|
39
|
-
|
|
40
|
-
private dmmf: any;
|
|
41
|
-
|
|
42
|
-
constructor({
|
|
43
|
-
primaryKey = "id", prismaClient, manyRelations = {}, models,
|
|
44
|
-
}: AdapterCtorArguments<M>) {
|
|
45
|
-
this.prismaClient = prismaClient;
|
|
46
|
-
this.primaryKey = primaryKey;
|
|
47
|
-
this.manyRelations = manyRelations;
|
|
48
|
-
this.ctorModels = models;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
private getPrismaClientModels = async () => {
|
|
52
|
-
// eslint-disable-next-line no-underscore-dangle
|
|
53
|
-
if (this.prismaClient._dmmf) {
|
|
54
|
-
// eslint-disable-next-line no-underscore-dangle
|
|
55
|
-
this.dmmf = this.prismaClient._dmmf;
|
|
56
|
-
|
|
57
|
-
return this.dmmf?.mappingsMap;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// eslint-disable-next-line no-underscore-dangle
|
|
61
|
-
if (this.prismaClient._getDmmf) {
|
|
62
|
-
// eslint-disable-next-line no-underscore-dangle
|
|
63
|
-
this.dmmf = await this.prismaClient._getDmmf();
|
|
64
|
-
|
|
65
|
-
return this.dmmf.mappingsMap;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
throw new Error("Couldn't get prisma client models");
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
async init() {
|
|
72
|
-
const models = this.ctorModels;
|
|
73
|
-
const prismaDmmfModels = await this.getPrismaClientModels();
|
|
74
|
-
|
|
75
|
-
if (typeof models !== "undefined") {
|
|
76
|
-
models.forEach((model) => {
|
|
77
|
-
if (!Object.keys(prismaDmmfModels).includes(model)) {
|
|
78
|
-
throw new Error(`Model name ${model} is invalid.`);
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// @ts-ignore
|
|
84
|
-
this.models = models ?? (Object.keys(prismaDmmfModels) as M[]); // Retrieve model names from dmmf for prisma v2
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
async getPaginationData(resourceName: M, query: PrismaParsedQueryParameters): Promise<PaginationData> {
|
|
88
|
-
// @ts-ignore
|
|
89
|
-
const total: number = await this.getPrismaDelegate(resourceName).count({
|
|
90
|
-
where: query.where,
|
|
91
|
-
distinct: query.distinct,
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
return {
|
|
95
|
-
total,
|
|
96
|
-
pageCount: Math.ceil(total / (query.take as number)),
|
|
97
|
-
page: Math.ceil((query.skip as number) / (query.take as number)) + 1,
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// eslint-disable-next-line class-methods-use-this
|
|
102
|
-
handleError(error: any) {
|
|
103
|
-
// eslint-disable-next-line no-console
|
|
104
|
-
console.error(error);
|
|
105
|
-
|
|
106
|
-
if (error instanceof Error && error.stack) {
|
|
107
|
-
// eslint-disable-next-line no-console
|
|
108
|
-
console.error(error.stack);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
throw error.constructor.name === "PrismaClientKnownRequestError" || error.constructor.name === "PrismaClientValidationError"
|
|
112
|
-
? createHttpError(400, "invalid request, check your server logs for more info")
|
|
113
|
-
: createHttpError(500, "an unknown error occured, check your server logs for more info");
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
parseQuery(resourceName: M, query: ParsedQueryParameters) {
|
|
117
|
-
const parsed: PrismaParsedQueryParameters = {};
|
|
118
|
-
|
|
119
|
-
if (query.select) {
|
|
120
|
-
parsed.select = parsePrismaRecursiveField(query.select, "select");
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
if (query.include) {
|
|
124
|
-
parsed.include = parsePrismaRecursiveField(query.include, "include");
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
if (query.originalQuery?.where) {
|
|
128
|
-
parsed.where = parsePrismaWhere(JSON.parse(query.originalQuery.where), this.manyRelations[resourceName] ?? []);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
if (query.orderBy) {
|
|
132
|
-
parsed.orderBy = parsePrismaOrderBy(query.orderBy);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
if (typeof query.limit !== "undefined") {
|
|
136
|
-
parsed.take = query.limit;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
if (typeof query.skip !== "undefined") {
|
|
140
|
-
parsed.skip = query.skip;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
if (query.originalQuery?.cursor) {
|
|
144
|
-
parsed.cursor = parsePrismaCursor(JSON.parse(query.originalQuery.cursor));
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
if (query.distinct) {
|
|
148
|
-
parsed.distinct = query.distinct;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
return parsed;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
async getAll(resourceName: M, query: PrismaParsedQueryParameters): Promise<T[]> {
|
|
155
|
-
// @ts-ignore
|
|
156
|
-
return (await this.getPrismaDelegate(resourceName).findMany({
|
|
157
|
-
select: query.select,
|
|
158
|
-
include: query.include,
|
|
159
|
-
where: query.where,
|
|
160
|
-
orderBy: query.orderBy,
|
|
161
|
-
cursor: query.cursor,
|
|
162
|
-
take: query.take,
|
|
163
|
-
skip: query.skip,
|
|
164
|
-
distinct: query.distinct,
|
|
165
|
-
})) as T[];
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
async getOne(resourceName: M, resourceId: string | number, query: PrismaParsedQueryParameters): Promise<T> {
|
|
169
|
-
const delegate = this.getPrismaDelegate(resourceName);
|
|
170
|
-
/**
|
|
171
|
-
* On prisma v2.12, findOne has been deprecated in favor of findUnique
|
|
172
|
-
* We use findUnique in priority only if it's available
|
|
173
|
-
*/
|
|
174
|
-
const findFunction = delegate.findUnique || delegate.findOne;
|
|
175
|
-
|
|
176
|
-
// @ts-ignore
|
|
177
|
-
return findFunction({
|
|
178
|
-
where: {
|
|
179
|
-
[this.primaryKey]: resourceId,
|
|
180
|
-
},
|
|
181
|
-
select: query.select,
|
|
182
|
-
include: query.include,
|
|
183
|
-
});
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
async create(resourceName: M, data: any, query: PrismaParsedQueryParameters): Promise<T> {
|
|
187
|
-
// @ts-ignore
|
|
188
|
-
return this.getPrismaDelegate(resourceName).create({
|
|
189
|
-
data,
|
|
190
|
-
select: query.select,
|
|
191
|
-
include: query.include,
|
|
192
|
-
});
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
async update(resourceName: M, resourceId: string | number, data: any, query: PrismaParsedQueryParameters): Promise<T> {
|
|
196
|
-
// @ts-ignore
|
|
197
|
-
return this.getPrismaDelegate(resourceName).update({
|
|
198
|
-
where: {
|
|
199
|
-
[this.primaryKey]: resourceId,
|
|
200
|
-
},
|
|
201
|
-
data,
|
|
202
|
-
select: query.select,
|
|
203
|
-
include: query.include,
|
|
204
|
-
});
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
async delete(resourceName: M, resourceId: string | number, query: PrismaParsedQueryParameters): Promise<T> {
|
|
208
|
-
// @ts-ignore
|
|
209
|
-
return this.getPrismaDelegate(resourceName).delete({
|
|
210
|
-
where: {
|
|
211
|
-
[this.primaryKey]: resourceId,
|
|
212
|
-
},
|
|
213
|
-
select: query.select,
|
|
214
|
-
include: query.include,
|
|
215
|
-
});
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
connect() {
|
|
219
|
-
return this.prismaClient.$connect();
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
disconnect() {
|
|
223
|
-
return this.prismaClient.$disconnect();
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
get client() {
|
|
227
|
-
return this.prismaClient;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
getModels() {
|
|
231
|
-
return this.models || [];
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
private getPrismaDelegate(resourceName: M): Record<PrismaAction, (...arguments_: any[]) => Promise<T>> {
|
|
235
|
-
return this.prismaClient[`${resourceName.charAt(0).toLowerCase()}${resourceName.slice(1)}`];
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
public async mapModelsToRouteNames() {
|
|
239
|
-
return modelsToRouteNames(await this.getPrismaClientModels(), this.getModels());
|
|
240
|
-
}
|
|
241
|
-
}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import type { Condition, SearchCondition } from "../../types.d";
|
|
2
|
-
|
|
3
|
-
export type PrismaRecursiveField = "select" | "include";
|
|
4
|
-
|
|
5
|
-
export type PrismaRecursive<T extends PrismaRecursiveField> = Record<string, boolean | { [key in T]: PrismaRecursive<T> }>;
|
|
6
|
-
|
|
7
|
-
export type PrismaWhereOperator = "equals" | "not" | "in" | "notIn" | "lt" | "lte" | "gt" | "gte" | "contains" | "startsWith" | "endsWith";
|
|
8
|
-
|
|
9
|
-
export type PrismaOrderByOperator = "asc" | "desc";
|
|
10
|
-
|
|
11
|
-
export type PrismaFieldFilterOperator = {
|
|
12
|
-
[key in PrismaWhereOperator]?: SearchCondition;
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
export type PrismaFieldFilter = {
|
|
16
|
-
[key: string]: SearchCondition | PrismaFieldFilterOperator | PrismaRelationFilter | Condition | undefined;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export type PrismaWhereField = PrismaFieldFilter & {
|
|
20
|
-
AND?: PrismaFieldFilter;
|
|
21
|
-
OR?: PrismaFieldFilter;
|
|
22
|
-
NOT?: PrismaFieldFilter;
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
export type PrismaRelationFilter = {
|
|
26
|
-
some: SearchCondition | PrismaFieldFilter;
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
export type PrismaOrderBy = {
|
|
30
|
-
[key: string]: PrismaOrderByOperator;
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
export type PrismaCursor = {
|
|
34
|
-
[key: string]: string | number | boolean;
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
export interface PrismaParsedQueryParameters {
|
|
38
|
-
select?: PrismaRecursive<"select">;
|
|
39
|
-
include?: PrismaRecursive<"include">;
|
|
40
|
-
where?: PrismaWhereField;
|
|
41
|
-
orderBy?: PrismaOrderBy;
|
|
42
|
-
take?: number;
|
|
43
|
-
skip?: number;
|
|
44
|
-
cursor?: PrismaCursor;
|
|
45
|
-
distinct?: string;
|
|
46
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
const modelsToRouteNames = <M extends string = string>(mappingsMap: { [key: string]: object }, models: M[]) => {
|
|
2
|
-
const routesMap: { [key in M]?: string } = {};
|
|
3
|
-
|
|
4
|
-
models?.forEach((model) => {
|
|
5
|
-
// @ts-ignore
|
|
6
|
-
routesMap[model] = mappingsMap[model].plural;
|
|
7
|
-
});
|
|
8
|
-
|
|
9
|
-
return routesMap;
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
export default modelsToRouteNames;
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import isPrimitive from "../../../utils/is-primitive";
|
|
2
|
-
import type { PrismaCursor } from "../types.d";
|
|
3
|
-
|
|
4
|
-
const parsePrismaCursor = (
|
|
5
|
-
cursor: Record<string, string | number | boolean>,
|
|
6
|
-
): PrismaCursor => {
|
|
7
|
-
const parsed: PrismaCursor = {};
|
|
8
|
-
|
|
9
|
-
Object.keys(cursor).forEach((key) => {
|
|
10
|
-
const value = cursor[key];
|
|
11
|
-
|
|
12
|
-
if (isPrimitive(value)) {
|
|
13
|
-
parsed[key as keyof typeof cursor] = value as string | number | boolean;
|
|
14
|
-
}
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
if (Object.keys(parsed).length !== 1) {
|
|
18
|
-
throw new Error(
|
|
19
|
-
"cursor needs to be an object with exactly 1 property with a primitive value",
|
|
20
|
-
);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
return parsed;
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
export default parsePrismaCursor;
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { OrderByField, OrderByOperator } from "../../../types.d";
|
|
2
|
-
import type { PrismaOrderBy, PrismaOrderByOperator } from "../types.d";
|
|
3
|
-
|
|
4
|
-
const operatorsAssociation: Record<OrderByOperator, PrismaOrderByOperator> = {
|
|
5
|
-
$asc: "asc",
|
|
6
|
-
$desc: "desc",
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
const parsePrismaOrderBy = (orderBy: OrderByField): PrismaOrderBy => {
|
|
10
|
-
const parsed: PrismaOrderBy = {};
|
|
11
|
-
|
|
12
|
-
Object.keys(orderBy).forEach((key) => {
|
|
13
|
-
const value = orderBy[key];
|
|
14
|
-
|
|
15
|
-
parsed[key] = operatorsAssociation[value as OrderByOperator];
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
return parsed;
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
export default parsePrismaOrderBy;
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import type { RecursiveField } from "../../../types.d";
|
|
2
|
-
import type { PrismaRecursive, PrismaRecursiveField } from "../types.d";
|
|
3
|
-
|
|
4
|
-
const parsePrismaRecursiveField = <T extends PrismaRecursiveField>(
|
|
5
|
-
select: RecursiveField,
|
|
6
|
-
fieldName: T,
|
|
7
|
-
): PrismaRecursive<T> => {
|
|
8
|
-
const parsed: PrismaRecursive<T> = {};
|
|
9
|
-
|
|
10
|
-
Object.keys(select).forEach((field) => {
|
|
11
|
-
if (select[field] !== true) {
|
|
12
|
-
parsed[field] = {
|
|
13
|
-
[fieldName]: parsePrismaRecursiveField(
|
|
14
|
-
select[field] as RecursiveField,
|
|
15
|
-
fieldName,
|
|
16
|
-
),
|
|
17
|
-
} as Record<T, PrismaRecursive<T>>;
|
|
18
|
-
} else {
|
|
19
|
-
parsed[field] = true;
|
|
20
|
-
}
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
return parsed;
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
export default parsePrismaRecursiveField;
|
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
Condition, SearchCondition, WhereCondition, WhereField, WhereOperator,
|
|
3
|
-
} from "../../../types.d";
|
|
4
|
-
import isPrimitive from "../../../utils/is-primitive";
|
|
5
|
-
import type {
|
|
6
|
-
PrismaFieldFilter, PrismaRelationFilter, PrismaWhereField, PrismaWhereOperator,
|
|
7
|
-
} from "../types.d";
|
|
8
|
-
|
|
9
|
-
const isObject = (a: any) => a instanceof Object;
|
|
10
|
-
|
|
11
|
-
const operatorsAssociation: {
|
|
12
|
-
[key in WhereOperator]?: PrismaWhereOperator;
|
|
13
|
-
} = {
|
|
14
|
-
$eq: "equals",
|
|
15
|
-
$neq: "not",
|
|
16
|
-
$cont: "contains",
|
|
17
|
-
$ends: "endsWith",
|
|
18
|
-
$gt: "gt",
|
|
19
|
-
$gte: "gte",
|
|
20
|
-
$in: "in",
|
|
21
|
-
$lt: "lt",
|
|
22
|
-
$lte: "lte",
|
|
23
|
-
$notin: "notIn",
|
|
24
|
-
$starts: "startsWith",
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
const isDateString = (value: string) => /^\d{4}-[01]\d-[0-3]\d(?:T[0-2](?:\d:[0-5]){2}\d(?:\.\d+)?(?:Z|[+-][0-2]\d(?::?[0-5]\d)?)?)?$/g.test(value);
|
|
28
|
-
|
|
29
|
-
const getSearchValue = (originalValue: any): SearchCondition => {
|
|
30
|
-
if (isDateString(originalValue)) {
|
|
31
|
-
return new Date(originalValue);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
if (typeof originalValue === "string" && originalValue === "$isnull") {
|
|
35
|
-
return null;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return originalValue;
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
const isRelation = (key: string, manyRelations: string[]): boolean => {
|
|
42
|
-
// Get the key containing . and remove the property name
|
|
43
|
-
const splitKey = key.split(".");
|
|
44
|
-
splitKey.splice(-1, 1);
|
|
45
|
-
|
|
46
|
-
return manyRelations.includes(splitKey.join("."));
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
const parseSimpleField = (value: Condition): undefined | { [key: string]: Condition } => {
|
|
50
|
-
const operator = Object.keys(value)[0];
|
|
51
|
-
const prismaOperator: undefined | PrismaWhereOperator = operatorsAssociation[operator as keyof typeof operatorsAssociation];
|
|
52
|
-
|
|
53
|
-
if (prismaOperator) {
|
|
54
|
-
return {
|
|
55
|
-
[prismaOperator]: value[operator as string],
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
return undefined;
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
const parseRelation = (
|
|
63
|
-
value: string | number | boolean | Date | Condition | WhereCondition,
|
|
64
|
-
key: string,
|
|
65
|
-
parsed: PrismaWhereField,
|
|
66
|
-
manyRelations: string[],
|
|
67
|
-
) => {
|
|
68
|
-
// Reverse the keys so that we can format our object by nesting
|
|
69
|
-
const fields = key.split(".").reverse();
|
|
70
|
-
|
|
71
|
-
let formatFields: { [key: string]: any } = {};
|
|
72
|
-
|
|
73
|
-
fields.forEach((field, index) => {
|
|
74
|
-
// If we iterate over the property name, which is index 0, we parse it like a normal field
|
|
75
|
-
if (index === 0) {
|
|
76
|
-
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
77
|
-
basicParse(value, field, formatFields, manyRelations);
|
|
78
|
-
// Else we format the relation filter in the prisma way
|
|
79
|
-
} else {
|
|
80
|
-
formatFields = {
|
|
81
|
-
[field]: {
|
|
82
|
-
some: formatFields,
|
|
83
|
-
},
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
// Retrieve the main relation field
|
|
89
|
-
const initialFieldKey = fields.reverse()[0] as string;
|
|
90
|
-
// Retrieve the old parsed version
|
|
91
|
-
const oldParsed = parsed[initialFieldKey] as PrismaRelationFilter;
|
|
92
|
-
|
|
93
|
-
// Format correctly in the prisma way
|
|
94
|
-
// eslint-disable-next-line no-param-reassign
|
|
95
|
-
parsed[initialFieldKey] = {
|
|
96
|
-
some: {
|
|
97
|
-
...(oldParsed?.some as object),
|
|
98
|
-
...(formatFields[initialFieldKey as string]?.some as object),
|
|
99
|
-
},
|
|
100
|
-
};
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
const parseObjectCombination = (object: Condition, manyRelations: string[]): PrismaFieldFilter => {
|
|
104
|
-
const parsed: PrismaFieldFilter = {};
|
|
105
|
-
|
|
106
|
-
Object.keys(object).forEach((key) => {
|
|
107
|
-
const value = object[key];
|
|
108
|
-
|
|
109
|
-
if (isRelation(key, manyRelations)) {
|
|
110
|
-
parseRelation(value, key, parsed, manyRelations);
|
|
111
|
-
} else if (isPrimitive(value)) {
|
|
112
|
-
parsed[key] = value as SearchCondition;
|
|
113
|
-
} else if (isObject(value)) {
|
|
114
|
-
const fieldResult = parseSimpleField(value as Condition);
|
|
115
|
-
|
|
116
|
-
if (fieldResult) {
|
|
117
|
-
parsed[key] = fieldResult;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
return parsed;
|
|
123
|
-
};
|
|
124
|
-
|
|
125
|
-
const basicParse = (value: string | number | boolean | Condition | Date | WhereCondition, key: string, parsed: PrismaWhereField, manyRelations: string[]) => {
|
|
126
|
-
if (isPrimitive(value)) {
|
|
127
|
-
// eslint-disable-next-line no-param-reassign
|
|
128
|
-
parsed[key] = getSearchValue(value);
|
|
129
|
-
} else {
|
|
130
|
-
switch (key) {
|
|
131
|
-
case "$or": {
|
|
132
|
-
if (isObject(value)) {
|
|
133
|
-
// eslint-disable-next-line no-param-reassign
|
|
134
|
-
parsed.OR = parseObjectCombination(value as Condition, manyRelations);
|
|
135
|
-
}
|
|
136
|
-
break;
|
|
137
|
-
}
|
|
138
|
-
case "$and": {
|
|
139
|
-
if (isObject(value)) {
|
|
140
|
-
// eslint-disable-next-line no-param-reassign
|
|
141
|
-
parsed.AND = parseObjectCombination(value as Condition, manyRelations);
|
|
142
|
-
}
|
|
143
|
-
break;
|
|
144
|
-
}
|
|
145
|
-
case "$not": {
|
|
146
|
-
if (isObject(value)) {
|
|
147
|
-
// eslint-disable-next-line no-param-reassign
|
|
148
|
-
parsed.NOT = parseObjectCombination(value as Condition, manyRelations);
|
|
149
|
-
}
|
|
150
|
-
break;
|
|
151
|
-
}
|
|
152
|
-
default: {
|
|
153
|
-
// eslint-disable-next-line no-param-reassign
|
|
154
|
-
parsed[key] = parseSimpleField(value as Condition);
|
|
155
|
-
break;
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
const parsePrismaWhere = (where: WhereField, manyRelations: string[]): PrismaWhereField => {
|
|
162
|
-
const parsed: PrismaWhereField = {};
|
|
163
|
-
|
|
164
|
-
Object.keys(where).forEach((key) => {
|
|
165
|
-
const value = where[key];
|
|
166
|
-
/**
|
|
167
|
-
* If the key without property name is a relation
|
|
168
|
-
*
|
|
169
|
-
* We want the following example input:
|
|
170
|
-
*
|
|
171
|
-
* posts.author.id: 1
|
|
172
|
-
*
|
|
173
|
-
* to output
|
|
174
|
-
*
|
|
175
|
-
* {
|
|
176
|
-
* posts: {
|
|
177
|
-
* some: {
|
|
178
|
-
* author: {
|
|
179
|
-
* some: {
|
|
180
|
-
* id: 1
|
|
181
|
-
* }
|
|
182
|
-
* }
|
|
183
|
-
* }
|
|
184
|
-
* }
|
|
185
|
-
* }
|
|
186
|
-
*/
|
|
187
|
-
if (isRelation(key, manyRelations)) {
|
|
188
|
-
parseRelation(value, key, parsed, manyRelations);
|
|
189
|
-
} else {
|
|
190
|
-
basicParse(value, key, parsed, manyRelations);
|
|
191
|
-
}
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
return parsed;
|
|
195
|
-
};
|
|
196
|
-
|
|
197
|
-
export default parsePrismaWhere;
|