arkos 2.0.0-next.18 → 2.0.0-next.19
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/cli.js +8 -1
- package/dist/esm/app.js +1 -1
- package/dist/esm/app.js.map +1 -1
- package/dist/esm/components/arkos-gateway/arkos-gateway.js +5 -4
- package/dist/esm/components/arkos-gateway/arkos-gateway.js.map +1 -1
- package/dist/esm/components/arkos-gateway/socket-extensions.js +7 -0
- package/dist/esm/components/arkos-gateway/socket-extensions.js.map +1 -1
- package/dist/esm/components/arkos-gateway/utils/memory-gateway-store.js +2 -4
- package/dist/esm/components/arkos-gateway/utils/memory-gateway-store.js.map +1 -1
- package/dist/esm/components/arkos-gateway/utils/multi-tier-arkos-gateway-store.js +1 -0
- package/dist/esm/components/arkos-gateway/utils/multi-tier-arkos-gateway-store.js.map +1 -1
- package/dist/esm/components/arkos-loadable-registry/index.js +1 -3
- package/dist/esm/components/arkos-loadable-registry/index.js.map +1 -1
- package/dist/esm/components/arkos-route-hook/reader.js.map +1 -1
- package/dist/esm/components/arkos-route-hook/types.js.map +1 -1
- package/dist/esm/exports/index.js +1 -1
- package/dist/esm/exports/index.js.map +1 -1
- package/dist/esm/exports/middlewares/index.js +1 -1
- package/dist/esm/exports/middlewares/index.js.map +1 -1
- package/dist/esm/modules/auth/auth.controller.js +213 -221
- package/dist/esm/modules/auth/auth.controller.js.map +1 -1
- package/dist/esm/modules/auth/auth.service.js +11 -58
- package/dist/esm/modules/auth/auth.service.js.map +1 -1
- package/dist/esm/modules/auth/utils/auth-prisma-json-schema-generator.js +1 -0
- package/dist/esm/modules/auth/utils/auth-prisma-json-schema-generator.js.map +1 -1
- package/dist/esm/modules/auth/utils/services/auth-action.service.js +10 -12
- package/dist/esm/modules/auth/utils/services/auth-action.service.js.map +1 -1
- package/dist/esm/modules/base/base.controller.js +179 -177
- package/dist/esm/modules/base/base.controller.js.map +1 -1
- package/dist/esm/modules/base/base.middlewares.js +6 -21
- package/dist/esm/modules/base/base.middlewares.js.map +1 -1
- package/dist/esm/modules/base/base.service.js +28 -25
- package/dist/esm/modules/base/base.service.js.map +1 -1
- package/dist/esm/modules/base/utils/error-prettifier.js +26 -30
- package/dist/esm/modules/base/utils/error-prettifier.js.map +1 -1
- package/dist/esm/modules/email/email.service.js +2 -2
- package/dist/esm/modules/email/email.service.js.map +1 -1
- package/dist/esm/modules/error-handler/utils/app-error.js +5 -1
- package/dist/esm/modules/error-handler/utils/app-error.js.map +1 -1
- package/dist/esm/modules/file-upload/file-upload.controller.js +203 -205
- package/dist/esm/modules/file-upload/file-upload.controller.js.map +1 -1
- package/dist/esm/modules/file-upload/file-upload.router.js +3 -3
- package/dist/esm/modules/file-upload/file-upload.router.js.map +1 -1
- package/dist/esm/modules/file-upload/file-upload.service.js +12 -7
- package/dist/esm/modules/file-upload/file-upload.service.js.map +1 -1
- package/dist/esm/modules/file-upload/utils/file-upload-json-schema-generator.js +1 -1
- package/dist/esm/modules/file-upload/utils/file-upload-json-schema-generator.js.map +1 -1
- package/dist/esm/modules/swagger/swagger.router.js.map +1 -1
- package/dist/esm/modules/swagger/utils/helpers/openapi-schema-converter.js +1 -0
- package/dist/esm/modules/swagger/utils/helpers/openapi-schema-converter.js.map +1 -1
- package/dist/esm/types/index.js.map +1 -1
- package/dist/esm/types/new-arkos-config.js.map +1 -1
- package/dist/esm/types/router-config.js.map +1 -1
- package/dist/esm/types/validation/validation-manager.js +21 -22
- package/dist/esm/types/validation/validation-manager.js.map +1 -1
- package/dist/esm/utils/arkos-router/index.js +1 -6
- package/dist/esm/utils/arkos-router/index.js.map +1 -1
- package/dist/esm/utils/arkos-router/route-config-registry.js +2 -3
- package/dist/esm/utils/arkos-router/route-config-registry.js.map +1 -1
- package/dist/esm/utils/arkos-router/types/index.js.map +1 -1
- package/dist/esm/utils/arkos-router/utils/helpers/index.js +86 -43
- package/dist/esm/utils/arkos-router/utils/helpers/index.js.map +1 -1
- package/dist/esm/utils/arkos-router/utils/helpers/upload-manager.js +12 -14
- package/dist/esm/utils/arkos-router/utils/helpers/upload-manager.js.map +1 -1
- package/dist/esm/utils/bundler.js +6 -6
- package/dist/esm/utils/bundler.js.map +1 -1
- package/dist/esm/utils/cli/dev.js +4 -17
- package/dist/esm/utils/cli/dev.js.map +1 -1
- package/dist/esm/utils/cli/prisma-generate.js +8 -37
- package/dist/esm/utils/cli/prisma-generate.js.map +1 -1
- package/dist/esm/utils/cli/utils/cli.helpers.js +1 -1
- package/dist/esm/utils/cli/utils/smart-fs-watcher.js +3 -0
- package/dist/esm/utils/cli/utils/smart-fs-watcher.js.map +1 -1
- package/dist/esm/utils/cli/utils/template-generator/templates/router-template.js +1 -1
- package/dist/esm/utils/cli/utils/template-generator/templates/router-template.js.map +1 -1
- package/dist/esm/utils/dynamic-loader.js +2 -1
- package/dist/esm/utils/dynamic-loader.js.map +1 -1
- package/dist/esm/utils/features/api.features.js +24 -20
- package/dist/esm/utils/features/api.features.js.map +1 -1
- package/dist/esm/utils/features/port-and-host-allocator.js +4 -3
- package/dist/esm/utils/features/port-and-host-allocator.js.map +1 -1
- package/dist/esm/utils/helpers/arkos-config.helpers.js.map +1 -1
- package/dist/esm/utils/helpers/query-parser.helpers.js +7 -22
- package/dist/esm/utils/helpers/query-parser.helpers.js.map +1 -1
- package/dist/esm/utils/initialize-app.js +1 -1
- package/dist/esm/utils/initialize-app.js.map +1 -1
- package/dist/esm/utils/prisma/prisma-json-schema-generator.js +1 -3
- package/dist/esm/utils/prisma/prisma-json-schema-generator.js.map +1 -1
- package/dist/esm/utils/prisma/prisma-schema-parser.js +14 -8
- package/dist/esm/utils/prisma/prisma-schema-parser.js.map +1 -1
- package/dist/esm/utils/validate-schema.js +23 -21
- package/dist/esm/utils/validate-schema.js.map +1 -1
- package/dist/types/app.d.ts +1 -1
- package/dist/types/components/arkos-route-hook/reader.d.ts +2 -5
- package/dist/types/components/arkos-route-hook/types.d.ts +4 -4
- package/dist/types/exports/index.d.ts +3 -4
- package/dist/types/exports/middlewares/index.d.ts +1 -1
- package/dist/types/modules/auth/auth.service.d.ts +1 -40
- package/dist/types/modules/base/base.middlewares.d.ts +1 -10
- package/dist/types/modules/swagger/swagger.router.d.ts +1 -2
- package/dist/types/types/index.d.ts +3 -3
- package/dist/types/types/new-arkos-config.d.ts +0 -14
- package/dist/types/types/router-config.d.ts +0 -111
- package/dist/types/utils/arkos-router/types/index.d.ts +3 -3
- package/dist/types/utils/arkos-router/utils/helpers/index.d.ts +2 -6
- package/dist/types/utils/dynamic-loader.d.ts +2 -2
- package/dist/types/utils/helpers/query-parser.helpers.d.ts +1 -1
- package/dist/types/utils/prisma/prisma-schema-parser.d.ts +1 -0
- package/package.json +41 -41
- package/dist/esm/components/arkos-loadable-translator/index.js +0 -138
- package/dist/esm/components/arkos-loadable-translator/index.js.map +0 -1
- package/dist/types/components/arkos-loadable-translator/index.d.ts +0 -53
|
@@ -8,190 +8,113 @@ import deepmerge from "../../utils/helpers/deepmerge.helper.js";
|
|
|
8
8
|
import loadableRegistry from "../../components/arkos-loadable-registry/index.js";
|
|
9
9
|
import { routeHookReader } from "../../components/arkos-route-hook/reader.js";
|
|
10
10
|
export class BaseController {
|
|
11
|
+
service;
|
|
12
|
+
modelName;
|
|
11
13
|
constructor(modelName) {
|
|
12
|
-
this.executeOperation = (config) => {
|
|
13
|
-
return catchAsync(async (req, res, next) => {
|
|
14
|
-
if (config.hooks?.beforeQuery)
|
|
15
|
-
await config.hooks.beforeQuery(req);
|
|
16
|
-
if (config.requiresQueryForBulk) {
|
|
17
|
-
if (Object.keys(req.query).every((key) => ["filterMode", "prismaQueryOptions"].includes(key))) {
|
|
18
|
-
return next(new AppError(`Filter criteria not provided for bulk ${config.operationType.replace(/Many$/, "")}.`, 400, "MissingRequestQueryParameters"));
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
if (config.preventORFilter && req.query.filterMode === "OR") {
|
|
22
|
-
throw new AppError(`req.query.filterMode === OR is not valid for ${config.operationType} operation`, 400);
|
|
23
|
-
}
|
|
24
|
-
if (config.preventORFilter)
|
|
25
|
-
req.query.filterMode = "AND";
|
|
26
|
-
let apiFeatures = new APIFeatures(req, this.modelName);
|
|
27
|
-
config.queryFeatures.forEach((feature) => {
|
|
28
|
-
switch (feature) {
|
|
29
|
-
case "filter":
|
|
30
|
-
apiFeatures = apiFeatures.filter();
|
|
31
|
-
break;
|
|
32
|
-
case "sort":
|
|
33
|
-
apiFeatures = apiFeatures.sort();
|
|
34
|
-
break;
|
|
35
|
-
case "limitFields":
|
|
36
|
-
apiFeatures = apiFeatures.limitFields();
|
|
37
|
-
break;
|
|
38
|
-
case "paginate":
|
|
39
|
-
apiFeatures = apiFeatures.paginate();
|
|
40
|
-
break;
|
|
41
|
-
}
|
|
42
|
-
});
|
|
43
|
-
const { where, ...queryOptions } = apiFeatures.filters;
|
|
44
|
-
if (config.hooks?.afterQuery)
|
|
45
|
-
await config.hooks.afterQuery({ where, queryOptions }, req);
|
|
46
|
-
let serviceArgs = this.buildServiceArgs(config, req, where, queryOptions);
|
|
47
|
-
if (config.hooks?.beforeService)
|
|
48
|
-
serviceArgs = await config.hooks.beforeService(serviceArgs, req);
|
|
49
|
-
const routeHook = this.getRouteHook();
|
|
50
|
-
const isRouteHookMethod = routeHook && routeHook._configs.service &&
|
|
51
|
-
routeHook._configs.service[config.serviceMethod]
|
|
52
|
-
? true
|
|
53
|
-
: false;
|
|
54
|
-
const serviceMethod = (isRouteHookMethod
|
|
55
|
-
? routeHook._configs.service[config.serviceMethod]
|
|
56
|
-
: this.service[config.serviceMethod]);
|
|
57
|
-
let result = await serviceMethod.apply(isRouteHookMethod ? routeHook._configs.service : this.service, serviceArgs);
|
|
58
|
-
if (config.hooks?.afterService)
|
|
59
|
-
result = await config.hooks.afterService(result, req);
|
|
60
|
-
let data = result;
|
|
61
|
-
let additionalData = null;
|
|
62
|
-
if (config.operationType === "findMany") {
|
|
63
|
-
const [records, total] = await Promise.all([
|
|
64
|
-
result,
|
|
65
|
-
this.service.count(where, {
|
|
66
|
-
user: req?.user,
|
|
67
|
-
accessToken: req?.accessToken,
|
|
68
|
-
}),
|
|
69
|
-
]);
|
|
70
|
-
const take = serviceArgs[1]?.take ?? null;
|
|
71
|
-
const skip = serviceArgs[1]?.skip ?? 0;
|
|
72
|
-
const limit = take ?? total;
|
|
73
|
-
const currentPage = limit > 0 ? Math.floor(skip / limit) + 1 : 1;
|
|
74
|
-
const totalPages = limit > 0 ? Math.ceil(total / limit) : 1;
|
|
75
|
-
data = records;
|
|
76
|
-
additionalData = {
|
|
77
|
-
total,
|
|
78
|
-
results: records.length,
|
|
79
|
-
page: currentPage,
|
|
80
|
-
pages: totalPages,
|
|
81
|
-
limit,
|
|
82
|
-
hasNextPage: currentPage < totalPages,
|
|
83
|
-
hasPrevPage: currentPage > 1,
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
const error = config.errorHandler
|
|
87
|
-
? config.errorHandler(data, req, this.modelName)
|
|
88
|
-
: this.defaultErrorHandler(data, req, config.operationType);
|
|
89
|
-
if (error)
|
|
90
|
-
return next(error);
|
|
91
|
-
let responseData = config.responseBuilder
|
|
92
|
-
? config.responseBuilder(data, additionalData)
|
|
93
|
-
: this.defaultResponseBuilder(data, additionalData, config.operationType);
|
|
94
|
-
if (config.hooks?.beforeResponse)
|
|
95
|
-
responseData = await config.hooks.beforeResponse(responseData, req);
|
|
96
|
-
if (routeHook &&
|
|
97
|
-
routeHookReader.getHooks(this.modelName, config.operationType)
|
|
98
|
-
?.after) {
|
|
99
|
-
this.setResponseData(req, res, responseData, config.successStatus);
|
|
100
|
-
next();
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
if (config.operationType === "deleteOne") {
|
|
104
|
-
res.status(config.successStatus).send();
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
res.status(config.successStatus).json(responseData);
|
|
108
|
-
});
|
|
109
|
-
};
|
|
110
|
-
this.createOne = this.executeOperation({
|
|
111
|
-
operationType: "createOne",
|
|
112
|
-
serviceMethod: "createOne",
|
|
113
|
-
successStatus: 201,
|
|
114
|
-
queryFeatures: ["limitFields"],
|
|
115
|
-
usesRequestBody: true,
|
|
116
|
-
});
|
|
117
|
-
this.createMany = this.executeOperation({
|
|
118
|
-
operationType: "createMany",
|
|
119
|
-
serviceMethod: "createMany",
|
|
120
|
-
successStatus: 201,
|
|
121
|
-
queryFeatures: ["limitFields"],
|
|
122
|
-
usesRequestBody: true,
|
|
123
|
-
hooks: {
|
|
124
|
-
async beforeQuery(req) {
|
|
125
|
-
if (!req.body || (Array.isArray(req.body) && req.body.length === 0))
|
|
126
|
-
throw new AppError("Expected request body array to contain at least on item but received none", 400, { body: req.body }, "MissingArrayRequestBody");
|
|
127
|
-
},
|
|
128
|
-
},
|
|
129
|
-
});
|
|
130
|
-
this.findMany = this.executeOperation({
|
|
131
|
-
operationType: "findMany",
|
|
132
|
-
serviceMethod: "findMany",
|
|
133
|
-
successStatus: 200,
|
|
134
|
-
queryFeatures: ["filter", "sort", "limitFields", "paginate"],
|
|
135
|
-
});
|
|
136
|
-
this.findOne = this.executeOperation({
|
|
137
|
-
operationType: "findOne",
|
|
138
|
-
serviceMethod: "findOne",
|
|
139
|
-
successStatus: 200,
|
|
140
|
-
queryFeatures: ["limitFields", "filter"],
|
|
141
|
-
usesRequestParams: true,
|
|
142
|
-
});
|
|
143
|
-
this.updateOne = this.executeOperation({
|
|
144
|
-
operationType: "updateOne",
|
|
145
|
-
serviceMethod: "updateOne",
|
|
146
|
-
successStatus: 200,
|
|
147
|
-
queryFeatures: ["limitFields", "filter"],
|
|
148
|
-
usesRequestParams: true,
|
|
149
|
-
usesRequestBody: true,
|
|
150
|
-
});
|
|
151
|
-
this.updateMany = this.executeOperation({
|
|
152
|
-
operationType: "updateMany",
|
|
153
|
-
serviceMethod: "updateMany",
|
|
154
|
-
successStatus: 200,
|
|
155
|
-
queryFeatures: ["filter", "limitFields"],
|
|
156
|
-
requiresQueryForBulk: true,
|
|
157
|
-
preventORFilter: true,
|
|
158
|
-
usesRequestBody: true,
|
|
159
|
-
});
|
|
160
|
-
this.batchUpdate = this.executeOperation({
|
|
161
|
-
operationType: "batchUpdate",
|
|
162
|
-
serviceMethod: "batchUpdate",
|
|
163
|
-
successStatus: 200,
|
|
164
|
-
queryFeatures: ["limitFields", "filter"],
|
|
165
|
-
usesRequestBody: true,
|
|
166
|
-
});
|
|
167
|
-
this.deleteOne = this.executeOperation({
|
|
168
|
-
operationType: "deleteOne",
|
|
169
|
-
serviceMethod: "deleteOne",
|
|
170
|
-
successStatus: 204,
|
|
171
|
-
queryFeatures: ["filter"],
|
|
172
|
-
usesRequestParams: true,
|
|
173
|
-
});
|
|
174
|
-
this.deleteMany = this.executeOperation({
|
|
175
|
-
operationType: "deleteMany",
|
|
176
|
-
serviceMethod: "deleteMany",
|
|
177
|
-
successStatus: 200,
|
|
178
|
-
queryFeatures: ["filter"],
|
|
179
|
-
requiresQueryForBulk: true,
|
|
180
|
-
preventORFilter: true,
|
|
181
|
-
});
|
|
182
|
-
this.batchDelete = this.executeOperation({
|
|
183
|
-
operationType: "batchDelete",
|
|
184
|
-
serviceMethod: "batchDelete",
|
|
185
|
-
successStatus: 200,
|
|
186
|
-
queryFeatures: ["filter"],
|
|
187
|
-
usesRequestBody: true,
|
|
188
|
-
});
|
|
189
14
|
this.modelName = kebabCase(modelName);
|
|
190
15
|
this.service = new ArkosPrismaService(modelName);
|
|
191
16
|
}
|
|
192
17
|
getRouteHook() {
|
|
193
18
|
return loadableRegistry.getItem("ArkosRouteHook", kebabCase(kebabCase(this.modelName)));
|
|
194
19
|
}
|
|
20
|
+
executeOperation = (config) => {
|
|
21
|
+
return catchAsync(async (req, res, next) => {
|
|
22
|
+
if (config.hooks?.beforeQuery)
|
|
23
|
+
await config.hooks.beforeQuery(req);
|
|
24
|
+
if (config.requiresQueryForBulk) {
|
|
25
|
+
if (Object.keys(req.query).every((key) => ["filterMode", "prismaQueryOptions"].includes(key))) {
|
|
26
|
+
return next(new AppError(`Filter criteria not provided for bulk ${config.operationType.replace(/Many$/, "")}.`, 400, "MissingRequestQueryParameters"));
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
if (config.preventORFilter && req.query.filterMode === "OR") {
|
|
30
|
+
throw new AppError(`req.query.filterMode === OR is not valid for ${config.operationType} operation`, 400);
|
|
31
|
+
}
|
|
32
|
+
if (config.preventORFilter)
|
|
33
|
+
req.query.filterMode = "AND";
|
|
34
|
+
let apiFeatures = new APIFeatures(req, this.modelName);
|
|
35
|
+
config.queryFeatures.forEach((feature) => {
|
|
36
|
+
switch (feature) {
|
|
37
|
+
case "filter":
|
|
38
|
+
apiFeatures = apiFeatures.filter();
|
|
39
|
+
break;
|
|
40
|
+
case "sort":
|
|
41
|
+
apiFeatures = apiFeatures.sort();
|
|
42
|
+
break;
|
|
43
|
+
case "limitFields":
|
|
44
|
+
apiFeatures = apiFeatures.limitFields();
|
|
45
|
+
break;
|
|
46
|
+
case "paginate":
|
|
47
|
+
apiFeatures = apiFeatures.paginate();
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
const { where, ...queryOptions } = apiFeatures.filters;
|
|
52
|
+
if (config.hooks?.afterQuery)
|
|
53
|
+
await config.hooks.afterQuery({ where, queryOptions }, req);
|
|
54
|
+
let serviceArgs = this.buildServiceArgs(config, req, where, queryOptions);
|
|
55
|
+
if (config.hooks?.beforeService)
|
|
56
|
+
serviceArgs = await config.hooks.beforeService(serviceArgs, req);
|
|
57
|
+
const routeHook = this.getRouteHook();
|
|
58
|
+
const isRouteHookMethod = routeHook && routeHook._configs.service &&
|
|
59
|
+
routeHook._configs.service[config.serviceMethod]
|
|
60
|
+
? true
|
|
61
|
+
: false;
|
|
62
|
+
const serviceMethod = (isRouteHookMethod
|
|
63
|
+
? routeHook._configs.service[config.serviceMethod]
|
|
64
|
+
: this.service[config.serviceMethod]);
|
|
65
|
+
let result = await serviceMethod.apply(isRouteHookMethod ? routeHook._configs.service : this.service, serviceArgs);
|
|
66
|
+
if (config.hooks?.afterService)
|
|
67
|
+
result = await config.hooks.afterService(result, req);
|
|
68
|
+
let data = result;
|
|
69
|
+
let additionalData = null;
|
|
70
|
+
if (config.operationType === "findMany") {
|
|
71
|
+
const [records, total] = await Promise.all([
|
|
72
|
+
result,
|
|
73
|
+
this.service.count(where, {
|
|
74
|
+
user: req?.user,
|
|
75
|
+
accessToken: req?.accessToken,
|
|
76
|
+
}),
|
|
77
|
+
]);
|
|
78
|
+
const take = serviceArgs[1]?.take ?? null;
|
|
79
|
+
const skip = serviceArgs[1]?.skip ?? 0;
|
|
80
|
+
const limit = take ?? total;
|
|
81
|
+
const currentPage = limit > 0 ? Math.floor(skip / limit) + 1 : 1;
|
|
82
|
+
const totalPages = limit > 0 ? Math.ceil(total / limit) : 1;
|
|
83
|
+
data = records;
|
|
84
|
+
additionalData = {
|
|
85
|
+
total,
|
|
86
|
+
results: records.length,
|
|
87
|
+
page: currentPage,
|
|
88
|
+
pages: totalPages,
|
|
89
|
+
limit,
|
|
90
|
+
hasNextPage: currentPage < totalPages,
|
|
91
|
+
hasPrevPage: currentPage > 1,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
const error = config.errorHandler
|
|
95
|
+
? config.errorHandler(data, req, this.modelName)
|
|
96
|
+
: this.defaultErrorHandler(data, req, config.operationType);
|
|
97
|
+
if (error)
|
|
98
|
+
return next(error);
|
|
99
|
+
let responseData = config.responseBuilder
|
|
100
|
+
? config.responseBuilder(data, additionalData)
|
|
101
|
+
: this.defaultResponseBuilder(data, additionalData, config.operationType);
|
|
102
|
+
if (config.hooks?.beforeResponse)
|
|
103
|
+
responseData = await config.hooks.beforeResponse(responseData, req);
|
|
104
|
+
if (routeHook &&
|
|
105
|
+
routeHookReader.getHooks(this.modelName, config.operationType)
|
|
106
|
+
?.after) {
|
|
107
|
+
this.setResponseData(req, res, responseData, config.successStatus);
|
|
108
|
+
next();
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
if (config.operationType === "deleteOne") {
|
|
112
|
+
res.status(config.successStatus).send();
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
res.status(config.successStatus).json(responseData);
|
|
116
|
+
});
|
|
117
|
+
};
|
|
195
118
|
setResponseData(req, res, data, status) {
|
|
196
119
|
res.originalData = data;
|
|
197
120
|
req.responseData = data;
|
|
@@ -282,5 +205,84 @@ export class BaseController {
|
|
|
282
205
|
return { results: data.length, data };
|
|
283
206
|
return { data };
|
|
284
207
|
}
|
|
208
|
+
createOne = this.executeOperation({
|
|
209
|
+
operationType: "createOne",
|
|
210
|
+
serviceMethod: "createOne",
|
|
211
|
+
successStatus: 201,
|
|
212
|
+
queryFeatures: ["limitFields"],
|
|
213
|
+
usesRequestBody: true,
|
|
214
|
+
});
|
|
215
|
+
createMany = this.executeOperation({
|
|
216
|
+
operationType: "createMany",
|
|
217
|
+
serviceMethod: "createMany",
|
|
218
|
+
successStatus: 201,
|
|
219
|
+
queryFeatures: ["limitFields"],
|
|
220
|
+
usesRequestBody: true,
|
|
221
|
+
hooks: {
|
|
222
|
+
async beforeQuery(req) {
|
|
223
|
+
if (!req.body || (Array.isArray(req.body) && req.body.length === 0))
|
|
224
|
+
throw new AppError("Expected request body array to contain at least on item but received none", 400, { body: req.body }, "MissingArrayRequestBody");
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
});
|
|
228
|
+
findMany = this.executeOperation({
|
|
229
|
+
operationType: "findMany",
|
|
230
|
+
serviceMethod: "findMany",
|
|
231
|
+
successStatus: 200,
|
|
232
|
+
queryFeatures: ["filter", "sort", "limitFields", "paginate"],
|
|
233
|
+
});
|
|
234
|
+
findOne = this.executeOperation({
|
|
235
|
+
operationType: "findOne",
|
|
236
|
+
serviceMethod: "findOne",
|
|
237
|
+
successStatus: 200,
|
|
238
|
+
queryFeatures: ["limitFields", "filter"],
|
|
239
|
+
usesRequestParams: true,
|
|
240
|
+
});
|
|
241
|
+
updateOne = this.executeOperation({
|
|
242
|
+
operationType: "updateOne",
|
|
243
|
+
serviceMethod: "updateOne",
|
|
244
|
+
successStatus: 200,
|
|
245
|
+
queryFeatures: ["limitFields", "filter"],
|
|
246
|
+
usesRequestParams: true,
|
|
247
|
+
usesRequestBody: true,
|
|
248
|
+
});
|
|
249
|
+
updateMany = this.executeOperation({
|
|
250
|
+
operationType: "updateMany",
|
|
251
|
+
serviceMethod: "updateMany",
|
|
252
|
+
successStatus: 200,
|
|
253
|
+
queryFeatures: ["filter", "limitFields"],
|
|
254
|
+
requiresQueryForBulk: true,
|
|
255
|
+
preventORFilter: true,
|
|
256
|
+
usesRequestBody: true,
|
|
257
|
+
});
|
|
258
|
+
batchUpdate = this.executeOperation({
|
|
259
|
+
operationType: "batchUpdate",
|
|
260
|
+
serviceMethod: "batchUpdate",
|
|
261
|
+
successStatus: 200,
|
|
262
|
+
queryFeatures: ["limitFields", "filter"],
|
|
263
|
+
usesRequestBody: true,
|
|
264
|
+
});
|
|
265
|
+
deleteOne = this.executeOperation({
|
|
266
|
+
operationType: "deleteOne",
|
|
267
|
+
serviceMethod: "deleteOne",
|
|
268
|
+
successStatus: 204,
|
|
269
|
+
queryFeatures: ["filter"],
|
|
270
|
+
usesRequestParams: true,
|
|
271
|
+
});
|
|
272
|
+
deleteMany = this.executeOperation({
|
|
273
|
+
operationType: "deleteMany",
|
|
274
|
+
serviceMethod: "deleteMany",
|
|
275
|
+
successStatus: 200,
|
|
276
|
+
queryFeatures: ["filter"],
|
|
277
|
+
requiresQueryForBulk: true,
|
|
278
|
+
preventORFilter: true,
|
|
279
|
+
});
|
|
280
|
+
batchDelete = this.executeOperation({
|
|
281
|
+
operationType: "batchDelete",
|
|
282
|
+
serviceMethod: "batchDelete",
|
|
283
|
+
successStatus: 200,
|
|
284
|
+
queryFeatures: ["filter"],
|
|
285
|
+
usesRequestBody: true,
|
|
286
|
+
});
|
|
285
287
|
}
|
|
286
288
|
//# sourceMappingURL=base.controller.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base.controller.js","sourceRoot":"","sources":["../../../../src/modules/base/base.controller.ts"],"names":[],"mappings":"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","sourcesContent":["import { ArkosRequest, ArkosResponse, ArkosNextFunction } from \"../../types\";\nimport catchAsync from \"../error-handler/utils/catch-async\";\nimport { ArkosPrismaService } from \"./base.service\";\nimport AppError from \"../error-handler/utils/app-error\";\nimport { kebabCase, pascalCase } from \"../../utils/helpers/change-case.helpers\";\nimport pluralize from \"pluralize\";\nimport { APIFeatures } from \"../../exports/utils\";\nimport deepmerge from \"../../utils/helpers/deepmerge.helper\";\nimport loadableRegistry from \"../../components/arkos-loadable-registry\";\nimport { routeHookReader } from \"../../components/arkos-route-hook/reader\";\nimport { PrismaModels } from \"../../generated\";\nimport { ArkosRouteHookInstance } from \"../../components/arkos-route-hook/types\";\n\nexport interface OperationHooks {\n beforeQuery?: (req: ArkosRequest) => void | Promise<void>;\n afterQuery?: (\n queryData: { where: any; queryOptions: any },\n req: ArkosRequest\n ) => void | Promise<void>;\n beforeService?: (args: any[], req: ArkosRequest) => any[] | Promise<any[]>;\n afterService?: (data: any, req: ArkosRequest) => any | Promise<any>;\n beforeResponse?: (responseData: any, req: ArkosRequest) => any | Promise<any>;\n}\n\ninterface OperationConfig {\n operationType:\n | keyof Omit<ArkosRouteHookInstance<any>, \"__type\" | \"moduleName\">\n | \"batchUpdate\"\n | \"batchDelete\";\n serviceMethod: string;\n successStatus: number;\n queryFeatures: (\"filter\" | \"sort\" | \"limitFields\" | \"paginate\")[];\n requiresQueryForBulk?: boolean;\n preventORFilter?: boolean;\n responseBuilder?: (data: any, additionalData?: any) => any;\n errorHandler?: (\n data: any,\n req: ArkosRequest,\n modelName: string\n ) => AppError | null;\n usesRequestParams?: boolean;\n usesRequestBody?: boolean;\n hooks?: OperationHooks;\n}\n\n/**\n * The `BaseController` class provides standardized RESTful API endpoints\n * for any Prisma model based on its name. It supports automatic integration\n * with Prisma services and dynamic middleware hooks for extending behaviors.\n *\n * This controller includes:\n * - `createOne` / `createMany`\n * - `findOne` / `findMany`\n * - `updateOne` / `updateMany`\n * - `deleteOne` / `deleteMany`\n *\n * It handles:\n * - Prisma query options\n * - APIFeatures: filtering, sorting, pagination, field limiting\n * - Middleware hooks: `afterCreateOne`, `afterUpdateMany`, etc.\n *\n * @class BaseController\n *\n * @param {string} modelName - The Prisma model name this controller handles.\n *\n * @see {@link https://www.arkosjs.com/docs/reference/base-controller}\n *--\n * **See about how Arkos handles routers**\n * @see {@link https://www.arkosjs.com/docs/core-concepts/routing/setup}\n */\nexport class BaseController<TModuleName extends keyof PrismaModels<any>> {\n /**\n * Service instance to handle business logic operations\n * @public\n */\n service: ArkosPrismaService<TModuleName>;\n\n /**\n * Name of the model this controller handles\n * @private\n */\n private modelName: string;\n\n /**\n * Creates a new BaseController instance\n * @param {string} modelName - The name of the model for which this controller will handle operations\n */\n constructor(modelName: TModuleName) {\n this.modelName = kebabCase(modelName);\n this.service = new ArkosPrismaService(modelName);\n }\n\n private getRouteHook() {\n return loadableRegistry.getItem(\n \"ArkosRouteHook\",\n kebabCase(kebabCase(this.modelName))\n ) as ArkosRouteHookInstance<TModuleName> | null;\n }\n\n private executeOperation = (config: OperationConfig) => {\n return catchAsync(\n async (\n req: ArkosRequest,\n res: ArkosResponse,\n next: ArkosNextFunction\n ) => {\n if (config.hooks?.beforeQuery) await config.hooks.beforeQuery(req);\n\n if (config.requiresQueryForBulk) {\n if (\n Object.keys(req.query).every((key) =>\n [\"filterMode\", \"prismaQueryOptions\"].includes(key)\n )\n ) {\n return next(\n new AppError(\n `Filter criteria not provided for bulk ${config.operationType.replace(/Many$/, \"\")}.`,\n 400,\n \"MissingRequestQueryParameters\"\n )\n );\n }\n }\n\n if (config.preventORFilter && req.query.filterMode === \"OR\") {\n throw new AppError(\n `req.query.filterMode === OR is not valid for ${config.operationType} operation`,\n 400\n );\n }\n\n if (config.preventORFilter) req.query.filterMode = \"AND\";\n\n let apiFeatures = new APIFeatures(req, this.modelName);\n\n config.queryFeatures.forEach((feature) => {\n switch (feature) {\n case \"filter\":\n apiFeatures = apiFeatures.filter();\n break;\n case \"sort\":\n apiFeatures = apiFeatures.sort();\n break;\n case \"limitFields\":\n apiFeatures = apiFeatures.limitFields();\n break;\n case \"paginate\":\n apiFeatures = apiFeatures.paginate();\n break;\n }\n });\n\n const { where, ...queryOptions } = apiFeatures.filters;\n\n if (config.hooks?.afterQuery)\n await config.hooks.afterQuery({ where, queryOptions }, req);\n\n let serviceArgs = this.buildServiceArgs(\n config,\n req,\n where,\n queryOptions\n );\n\n if (config.hooks?.beforeService)\n serviceArgs = await config.hooks.beforeService(serviceArgs, req);\n\n const routeHook = this.getRouteHook();\n\n const isRouteHookMethod =\n routeHook && routeHook._configs.service &&\n routeHook._configs.service[\n config.serviceMethod as keyof ArkosPrismaService<any>\n ]\n ? true\n : false;\n\n const serviceMethod = (\n isRouteHookMethod\n ? routeHook!._configs.service![\n config.serviceMethod as keyof ArkosPrismaService<any>\n ]\n : this.service[\n config.serviceMethod as keyof ArkosPrismaService<any>\n ]\n ) as Function;\n\n let result = await serviceMethod.apply(\n isRouteHookMethod ? routeHook!._configs.service : this.service,\n serviceArgs\n );\n\n if (config.hooks?.afterService)\n result = await config.hooks.afterService(result, req);\n\n let data = result;\n let additionalData: any = null;\n\n if (config.operationType === \"findMany\") {\n const [records, total] = await Promise.all([\n result,\n this.service.count(where, {\n user: req?.user!,\n accessToken: req?.accessToken,\n }),\n ]);\n\n const take = serviceArgs[1]?.take ?? null;\n const skip = serviceArgs[1]?.skip ?? 0;\n\n const limit = take ?? total;\n const currentPage = limit > 0 ? Math.floor(skip / limit) + 1 : 1;\n const totalPages = limit > 0 ? Math.ceil(total / limit) : 1;\n\n data = records;\n additionalData = {\n total,\n results: records.length,\n page: currentPage,\n pages: totalPages,\n limit,\n hasNextPage: currentPage < totalPages,\n hasPrevPage: currentPage > 1,\n };\n }\n\n const error = config.errorHandler\n ? config.errorHandler(data, req, this.modelName)\n : this.defaultErrorHandler(data, req, config.operationType);\n\n if (error) return next(error);\n\n let responseData = config.responseBuilder\n ? config.responseBuilder(data, additionalData)\n : this.defaultResponseBuilder(\n data,\n additionalData,\n config.operationType\n );\n\n if (config.hooks?.beforeResponse)\n responseData = await config.hooks.beforeResponse(responseData, req);\n\n if (\n routeHook &&\n routeHookReader.getHooks(this.modelName, config.operationType as any)\n ?.after\n ) {\n this.setResponseData(req, res, responseData, config.successStatus);\n next();\n return;\n }\n\n if (config.operationType === \"deleteOne\") {\n res.status(config.successStatus).send();\n return;\n }\n\n res.status(config.successStatus).json(responseData);\n }\n );\n };\n\n /**\n * Sets response data for both legacy (req.responseData) and modern (res.locals) support\n */\n private setResponseData(\n req: ArkosRequest,\n res: ArkosResponse,\n data: any,\n status: number\n ): void {\n (res as any).originalData = data;\n req.responseData = data;\n res.locals.data = data;\n (res as any).originalStatus = status;\n req.responseStatus = status;\n res.locals.status = status;\n\n // Special handling for deleteOne\n if (status === 204) {\n req.additionalData = data;\n res.locals.additionalData = data;\n (res as any).originalAdditionalData = data;\n }\n }\n\n /**\n * Builds service method arguments based on operation configuration\n */\n private buildServiceArgs(\n config: OperationConfig,\n req: ArkosRequest,\n where: any,\n queryOptions: any\n ): any[] {\n const context = { user: req?.user, accessToken: req?.accessToken };\n const mergedOptions = deepmerge(req.prismaQueryOptions || {}, queryOptions);\n\n switch (config.operationType) {\n case \"createOne\":\n case \"createMany\":\n return [req.body, mergedOptions, context];\n\n case \"findMany\":\n return [where, queryOptions, context];\n\n case \"findOne\":\n return [{ ...req.params, ...where }, mergedOptions, context];\n\n case \"updateOne\":\n return [{ ...req.params, ...where }, req.body, mergedOptions, context];\n\n case \"updateMany\":\n // Remove include for bulk operations\n delete queryOptions.include;\n return [where, req.body, queryOptions, context];\n\n case \"batchUpdate\":\n return [req.body, mergedOptions, context];\n\n case \"deleteOne\":\n return [{ ...req.params, ...where }, context];\n\n case \"deleteMany\":\n return [where, context];\n\n case \"batchDelete\":\n return [req.body, context];\n\n default:\n throw new Error(`Unknown operation type: ${config.operationType}`);\n }\n }\n\n /**\n * Default error handler for operations\n */\n private defaultErrorHandler(\n data: any,\n req: ArkosRequest,\n operationType: string\n ): AppError | null {\n if (!data || (Array.isArray(data) && data.length === 0)) {\n // Handle different error scenarios\n if (operationType.includes(\"create\") || operationType.includes(\"batch\")) {\n return new AppError(\n \"Failed to create the resources. Please check your input.\",\n 400,\n { body: req.body }\n );\n }\n\n if (\n operationType === \"findOne\" ||\n operationType === \"updateOne\" ||\n operationType === \"deleteOne\"\n ) {\n if (\n Object.keys(req.params).length === 1 &&\n \"id\" in req.params &&\n req.params.id !== \"me\"\n ) {\n return new AppError(\n `${pascalCase(String(this.modelName))} with ID ${req.params?.id} not found`,\n 404,\n {},\n \"NotFound\"\n );\n } else {\n return new AppError(\n `${pascalCase(String(this.modelName))} not found`,\n 404,\n {},\n \"NotFound\"\n );\n }\n }\n\n if (operationType === \"updateMany\" || operationType === \"deleteMany\") {\n const isUpdate = operationType === \"updateMany\";\n return new AppError(\n isUpdate\n ? `${pluralize(pascalCase(String(this.modelName)))} not found`\n : `No records found to delete`,\n 404,\n {},\n \"NotFound\"\n );\n }\n }\n\n // Special handling for operations that return count\n if (\n data &&\n typeof data === \"object\" &&\n \"count\" in data &&\n data.count === 0\n ) {\n return new AppError(\n operationType === \"updateMany\"\n ? `${pluralize(pascalCase(String(this.modelName)))} not found`\n : `No records found to delete`,\n 404,\n {},\n \"NotFound\"\n );\n }\n\n return null;\n }\n\n /**\n * Default response builder for operations\n */\n private defaultResponseBuilder(\n data: any,\n additionalData: any,\n operationType: string\n ): any {\n if (operationType === \"findMany\" && additionalData)\n return {\n ...additionalData,\n data,\n };\n\n if (\n operationType.includes(\"Many\") &&\n data &&\n typeof data === \"object\" &&\n \"count\" in data\n )\n return { results: data.count, data };\n\n if (operationType.includes(\"batch\") && Array.isArray(data))\n return { results: data.length, data };\n\n return { data };\n }\n\n /**\n * Creates a single resource\n */\n createOne = this.executeOperation({\n operationType: \"createOne\",\n serviceMethod: \"createOne\",\n successStatus: 201,\n queryFeatures: [\"limitFields\"],\n usesRequestBody: true,\n });\n\n /**\n * Creates multiple resources in a single operation\n */\n createMany = this.executeOperation({\n operationType: \"createMany\",\n serviceMethod: \"createMany\",\n successStatus: 201,\n queryFeatures: [\"limitFields\"],\n usesRequestBody: true,\n hooks: {\n async beforeQuery(req) {\n if (!req.body || (Array.isArray(req.body) && req.body.length === 0))\n throw new AppError(\n \"Expected request body array to contain at least on item but received none\",\n 400,\n { body: req.body },\n \"MissingArrayRequestBody\"\n );\n },\n },\n });\n\n /**\n * Retrieves multiple resources with filtering, sorting, pagination, and field selection\n */\n findMany = this.executeOperation({\n operationType: \"findMany\",\n serviceMethod: \"findMany\",\n successStatus: 200,\n queryFeatures: [\"filter\", \"sort\", \"limitFields\", \"paginate\"],\n });\n\n /**\n * Retrieves a single resource by its identifier\n */\n findOne = this.executeOperation({\n operationType: \"findOne\",\n serviceMethod: \"findOne\",\n successStatus: 200,\n queryFeatures: [\"limitFields\", \"filter\"],\n usesRequestParams: true,\n });\n\n /**\n * Updates a single resource by its identifier\n */\n updateOne = this.executeOperation({\n operationType: \"updateOne\",\n serviceMethod: \"updateOne\",\n successStatus: 200,\n queryFeatures: [\"limitFields\", \"filter\"],\n usesRequestParams: true,\n usesRequestBody: true,\n });\n\n /**\n * Updates multiple resources that match specified criteria\n */\n updateMany = this.executeOperation({\n operationType: \"updateMany\",\n serviceMethod: \"updateMany\",\n successStatus: 200,\n queryFeatures: [\"filter\", \"limitFields\"],\n requiresQueryForBulk: true,\n preventORFilter: true,\n usesRequestBody: true,\n });\n\n /**\n * Updates multiple resources with different data in a single transaction\n */\n batchUpdate = this.executeOperation({\n operationType: \"batchUpdate\",\n serviceMethod: \"batchUpdate\",\n successStatus: 200,\n queryFeatures: [\"limitFields\", \"filter\"],\n usesRequestBody: true,\n });\n\n /**\n * Deletes a single resource by its identifier\n */\n deleteOne = this.executeOperation({\n operationType: \"deleteOne\",\n serviceMethod: \"deleteOne\",\n successStatus: 204,\n queryFeatures: [\"filter\"],\n usesRequestParams: true,\n });\n\n /**\n * Deletes multiple resources that match specified criteria\n */\n deleteMany = this.executeOperation({\n operationType: \"deleteMany\",\n serviceMethod: \"deleteMany\",\n successStatus: 200,\n queryFeatures: [\"filter\"],\n requiresQueryForBulk: true,\n preventORFilter: true,\n });\n\n /**\n * Deletes multiple resources with different filters in a single transaction\n */\n batchDelete = this.executeOperation({\n operationType: \"batchDelete\",\n serviceMethod: \"batchDelete\",\n successStatus: 200,\n queryFeatures: [\"filter\"],\n usesRequestBody: true,\n });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"base.controller.js","sourceRoot":"","sources":["../../../../src/modules/base/base.controller.ts"],"names":[],"mappings":"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","sourcesContent":["import { ArkosRequest, ArkosResponse, ArkosNextFunction } from \"../../types\";\nimport catchAsync from \"../error-handler/utils/catch-async\";\nimport { ArkosPrismaService } from \"./base.service\";\nimport AppError from \"../error-handler/utils/app-error\";\nimport { kebabCase, pascalCase } from \"../../utils/helpers/change-case.helpers\";\nimport pluralize from \"pluralize\";\nimport { APIFeatures } from \"../../exports/utils\";\nimport deepmerge from \"../../utils/helpers/deepmerge.helper\";\nimport loadableRegistry from \"../../components/arkos-loadable-registry\";\nimport { routeHookReader } from \"../../components/arkos-route-hook/reader\";\nimport { PrismaModels } from \"../../generated\";\nimport { ArkosRouteHookInstance } from \"../../components/arkos-route-hook/types\";\n\nexport interface OperationHooks {\n beforeQuery?: (req: ArkosRequest) => void | Promise<void>;\n afterQuery?: (\n queryData: { where: any; queryOptions: any },\n req: ArkosRequest\n ) => void | Promise<void>;\n beforeService?: (args: any[], req: ArkosRequest) => any[] | Promise<any[]>;\n afterService?: (data: any, req: ArkosRequest) => any | Promise<any>;\n beforeResponse?: (responseData: any, req: ArkosRequest) => any | Promise<any>;\n}\n\ninterface OperationConfig {\n operationType:\n | keyof Omit<ArkosRouteHookInstance<any>, \"__type\" | \"moduleName\">\n | \"batchUpdate\"\n | \"batchDelete\";\n serviceMethod: string;\n successStatus: number;\n queryFeatures: (\"filter\" | \"sort\" | \"limitFields\" | \"paginate\")[];\n requiresQueryForBulk?: boolean;\n preventORFilter?: boolean;\n responseBuilder?: (data: any, additionalData?: any) => any;\n errorHandler?: (\n data: any,\n req: ArkosRequest,\n modelName: string\n ) => AppError | null;\n usesRequestParams?: boolean;\n usesRequestBody?: boolean;\n hooks?: OperationHooks;\n}\n\n/**\n * The `BaseController` class provides standardized RESTful API endpoints\n * for any Prisma model based on its name. It supports automatic integration\n * with Prisma services and dynamic middleware hooks for extending behaviors.\n *\n * This controller includes:\n * - `createOne` / `createMany`\n * - `findOne` / `findMany`\n * - `updateOne` / `updateMany`\n * - `deleteOne` / `deleteMany`\n *\n * It handles:\n * - Prisma query options\n * - APIFeatures: filtering, sorting, pagination, field limiting\n * - Middleware hooks: `afterCreateOne`, `afterUpdateMany`, etc.\n *\n * @class BaseController\n *\n * @param {string} modelName - The Prisma model name this controller handles.\n *\n * @see {@link https://www.arkosjs.com/docs/reference/base-controller}\n *--\n * **See about how Arkos handles routers**\n * @see {@link https://www.arkosjs.com/docs/core-concepts/routing/setup}\n */\nexport class BaseController<TModuleName extends keyof PrismaModels<any>> {\n /**\n * Service instance to handle business logic operations\n * @public\n */\n service: ArkosPrismaService<TModuleName>;\n\n /**\n * Name of the model this controller handles\n * @private\n */\n private modelName: string;\n\n /**\n * Creates a new BaseController instance\n * @param {string} modelName - The name of the model for which this controller will handle operations\n */\n constructor(modelName: TModuleName) {\n this.modelName = kebabCase(modelName);\n this.service = new ArkosPrismaService(modelName);\n }\n\n private getRouteHook() {\n return loadableRegistry.getItem(\n \"ArkosRouteHook\",\n kebabCase(kebabCase(this.modelName))\n ) as ArkosRouteHookInstance<TModuleName> | null;\n }\n\n private executeOperation = (config: OperationConfig) => {\n return catchAsync(\n async (\n req: ArkosRequest,\n res: ArkosResponse,\n next: ArkosNextFunction\n ) => {\n if (config.hooks?.beforeQuery) await config.hooks.beforeQuery(req);\n\n if (config.requiresQueryForBulk) {\n if (\n Object.keys(req.query).every((key) =>\n [\"filterMode\", \"prismaQueryOptions\"].includes(key)\n )\n ) {\n return next(\n new AppError(\n `Filter criteria not provided for bulk ${config.operationType.replace(/Many$/, \"\")}.`,\n 400,\n \"MissingRequestQueryParameters\"\n )\n );\n }\n }\n\n if (config.preventORFilter && req.query.filterMode === \"OR\") {\n throw new AppError(\n `req.query.filterMode === OR is not valid for ${config.operationType} operation`,\n 400\n );\n }\n\n if (config.preventORFilter) req.query.filterMode = \"AND\";\n\n let apiFeatures = new APIFeatures(req, this.modelName);\n\n config.queryFeatures.forEach((feature) => {\n switch (feature) {\n case \"filter\":\n apiFeatures = apiFeatures.filter();\n break;\n case \"sort\":\n apiFeatures = apiFeatures.sort();\n break;\n case \"limitFields\":\n apiFeatures = apiFeatures.limitFields();\n break;\n case \"paginate\":\n apiFeatures = apiFeatures.paginate();\n break;\n }\n });\n\n const { where, ...queryOptions } = apiFeatures.filters;\n\n if (config.hooks?.afterQuery)\n await config.hooks.afterQuery({ where, queryOptions }, req);\n\n let serviceArgs = this.buildServiceArgs(\n config,\n req,\n where,\n queryOptions\n );\n\n if (config.hooks?.beforeService)\n serviceArgs = await config.hooks.beforeService(serviceArgs, req);\n\n const routeHook = this.getRouteHook();\n\n const isRouteHookMethod =\n routeHook && routeHook._configs.service &&\n routeHook._configs.service[\n config.serviceMethod as keyof ArkosPrismaService<any>\n ]\n ? true\n : false;\n\n const serviceMethod = (\n isRouteHookMethod\n ? routeHook!._configs.service![\n config.serviceMethod as keyof ArkosPrismaService<any>\n ]\n : this.service[\n config.serviceMethod as keyof ArkosPrismaService<any>\n ]\n ) as Function;\n\n let result = await serviceMethod.apply(\n isRouteHookMethod ? routeHook!._configs.service : this.service,\n serviceArgs\n );\n\n if (config.hooks?.afterService)\n result = await config.hooks.afterService(result, req);\n\n let data = result;\n let additionalData: any = null;\n\n if (config.operationType === \"findMany\") {\n const [records, total] = await Promise.all([\n result,\n this.service.count(where, {\n user: req?.user!,\n accessToken: req?.accessToken,\n }),\n ]);\n\n const take = serviceArgs[1]?.take ?? null;\n const skip = serviceArgs[1]?.skip ?? 0;\n\n const limit = take ?? total;\n const currentPage = limit > 0 ? Math.floor(skip / limit) + 1 : 1;\n const totalPages = limit > 0 ? Math.ceil(total / limit) : 1;\n\n data = records;\n additionalData = {\n total,\n results: records.length,\n page: currentPage,\n pages: totalPages,\n limit,\n hasNextPage: currentPage < totalPages,\n hasPrevPage: currentPage > 1,\n };\n }\n\n const error = config.errorHandler\n ? config.errorHandler(data, req, this.modelName)\n : this.defaultErrorHandler(data, req, config.operationType);\n\n if (error) return next(error);\n\n let responseData = config.responseBuilder\n ? config.responseBuilder(data, additionalData)\n : this.defaultResponseBuilder(\n data,\n additionalData,\n config.operationType\n );\n\n if (config.hooks?.beforeResponse)\n responseData = await config.hooks.beforeResponse(responseData, req);\n\n if (\n routeHook &&\n routeHookReader.getHooks(this.modelName, config.operationType as any)\n ?.after\n ) {\n this.setResponseData(req, res, responseData, config.successStatus);\n next();\n return;\n }\n\n if (config.operationType === \"deleteOne\") {\n res.status(config.successStatus).send();\n return;\n }\n\n res.status(config.successStatus).json(responseData);\n }\n );\n };\n\n /**\n * Sets response data for both legacy (req.responseData) and modern (res.locals) support\n */\n private setResponseData(\n req: ArkosRequest,\n res: ArkosResponse,\n data: any,\n status: number\n ): void {\n (res as any).originalData = data;\n req.responseData = data;\n res.locals.data = data;\n (res as any).originalStatus = status;\n req.responseStatus = status;\n res.locals.status = status;\n\n // Special handling for deleteOne\n if (status === 204) {\n req.additionalData = data;\n res.locals.additionalData = data;\n (res as any).originalAdditionalData = data;\n }\n }\n\n /**\n * Builds service method arguments based on operation configuration\n */\n private buildServiceArgs(\n config: OperationConfig,\n req: ArkosRequest,\n where: any,\n queryOptions: any\n ): any[] {\n const context = { user: req?.user, accessToken: req?.accessToken };\n const mergedOptions = deepmerge(req.prismaQueryOptions || {}, queryOptions);\n\n switch (config.operationType) {\n case \"createOne\":\n case \"createMany\":\n return [req.body, mergedOptions, context];\n\n case \"findMany\":\n return [where, queryOptions, context];\n\n case \"findOne\":\n return [{ ...req.params, ...where }, mergedOptions, context];\n\n case \"updateOne\":\n return [{ ...req.params, ...where }, req.body, mergedOptions, context];\n\n case \"updateMany\":\n // Remove include for bulk operations\n delete queryOptions.include;\n return [where, req.body, queryOptions, context];\n\n case \"batchUpdate\":\n return [req.body, mergedOptions, context];\n\n case \"deleteOne\":\n return [{ ...req.params, ...where }, context];\n\n case \"deleteMany\":\n return [where, context];\n\n case \"batchDelete\":\n return [req.body, context];\n\n default:\n throw new Error(`Unknown operation type: ${config.operationType}`);\n }\n }\n\n /**\n * Default error handler for operations\n */\n private defaultErrorHandler(\n data: any,\n req: ArkosRequest,\n operationType: string\n ): AppError | null {\n if (!data || (Array.isArray(data) && data.length === 0)) {\n // Handle different error scenarios\n if (operationType.includes(\"create\") || operationType.includes(\"batch\")) {\n return new AppError(\n \"Failed to create the resources. Please check your input.\",\n 400,\n { body: req.body }\n );\n }\n\n if (\n operationType === \"findOne\" ||\n operationType === \"updateOne\" ||\n operationType === \"deleteOne\"\n ) {\n if (\n Object.keys(req.params).length === 1 &&\n \"id\" in req.params &&\n req.params.id !== \"me\"\n ) {\n return new AppError(\n `${pascalCase(String(this.modelName))} with ID ${req.params?.id} not found`,\n 404,\n {},\n \"NotFound\"\n );\n } else {\n return new AppError(\n `${pascalCase(String(this.modelName))} not found`,\n 404,\n {},\n \"NotFound\"\n );\n }\n }\n\n if (operationType === \"updateMany\" || operationType === \"deleteMany\") {\n const isUpdate = operationType === \"updateMany\";\n return new AppError(\n isUpdate\n ? `${pluralize(pascalCase(String(this.modelName)))} not found`\n : `No records found to delete`,\n 404,\n {},\n \"NotFound\"\n );\n }\n }\n\n // Special handling for operations that return count\n if (\n data &&\n typeof data === \"object\" &&\n \"count\" in data &&\n data.count === 0\n ) {\n return new AppError(\n operationType === \"updateMany\"\n ? `${pluralize(pascalCase(String(this.modelName)))} not found`\n : `No records found to delete`,\n 404,\n {},\n \"NotFound\"\n );\n }\n\n return null;\n }\n\n /**\n * Default response builder for operations\n */\n private defaultResponseBuilder(\n data: any,\n additionalData: any,\n operationType: string\n ): any {\n if (operationType === \"findMany\" && additionalData)\n return {\n ...additionalData,\n data,\n };\n\n if (\n operationType.includes(\"Many\") &&\n data &&\n typeof data === \"object\" &&\n \"count\" in data\n )\n return { results: data.count, data };\n\n if (operationType.includes(\"batch\") && Array.isArray(data))\n return { results: data.length, data };\n\n return { data };\n }\n\n /**\n * Creates a single resource\n */\n createOne = this.executeOperation({\n operationType: \"createOne\",\n serviceMethod: \"createOne\",\n successStatus: 201,\n queryFeatures: [\"limitFields\"],\n usesRequestBody: true,\n });\n\n /**\n * Creates multiple resources in a single operation\n */\n createMany = this.executeOperation({\n operationType: \"createMany\",\n serviceMethod: \"createMany\",\n successStatus: 201,\n queryFeatures: [\"limitFields\"],\n usesRequestBody: true,\n hooks: {\n async beforeQuery(req) {\n if (!req.body || (Array.isArray(req.body) && req.body.length === 0))\n throw new AppError(\n \"Expected request body array to contain at least on item but received none\",\n 400,\n { body: req.body },\n \"MissingArrayRequestBody\"\n );\n },\n },\n });\n\n /**\n * Retrieves multiple resources with filtering, sorting, pagination, and field selection\n */\n findMany = this.executeOperation({\n operationType: \"findMany\",\n serviceMethod: \"findMany\",\n successStatus: 200,\n queryFeatures: [\"filter\", \"sort\", \"limitFields\", \"paginate\"],\n });\n\n /**\n * Retrieves a single resource by its identifier\n */\n findOne = this.executeOperation({\n operationType: \"findOne\",\n serviceMethod: \"findOne\",\n successStatus: 200,\n queryFeatures: [\"limitFields\", \"filter\"],\n usesRequestParams: true,\n });\n\n /**\n * Updates a single resource by its identifier\n */\n updateOne = this.executeOperation({\n operationType: \"updateOne\",\n serviceMethod: \"updateOne\",\n successStatus: 200,\n queryFeatures: [\"limitFields\", \"filter\"],\n usesRequestParams: true,\n usesRequestBody: true,\n });\n\n /**\n * Updates multiple resources that match specified criteria\n */\n updateMany = this.executeOperation({\n operationType: \"updateMany\",\n serviceMethod: \"updateMany\",\n successStatus: 200,\n queryFeatures: [\"filter\", \"limitFields\"],\n requiresQueryForBulk: true,\n preventORFilter: true,\n usesRequestBody: true,\n });\n\n /**\n * Updates multiple resources with different data in a single transaction\n */\n batchUpdate = this.executeOperation({\n operationType: \"batchUpdate\",\n serviceMethod: \"batchUpdate\",\n successStatus: 200,\n queryFeatures: [\"limitFields\", \"filter\"],\n usesRequestBody: true,\n });\n\n /**\n * Deletes a single resource by its identifier\n */\n deleteOne = this.executeOperation({\n operationType: \"deleteOne\",\n serviceMethod: \"deleteOne\",\n successStatus: 204,\n queryFeatures: [\"filter\"],\n usesRequestParams: true,\n });\n\n /**\n * Deletes multiple resources that match specified criteria\n */\n deleteMany = this.executeOperation({\n operationType: \"deleteMany\",\n serviceMethod: \"deleteMany\",\n successStatus: 200,\n queryFeatures: [\"filter\"],\n requiresQueryForBulk: true,\n preventORFilter: true,\n });\n\n /**\n * Deletes multiple resources with different filters in a single transaction\n */\n batchDelete = this.executeOperation({\n operationType: \"batchDelete\",\n serviceMethod: \"batchDelete\",\n successStatus: 200,\n queryFeatures: [\"filter\"],\n usesRequestBody: true,\n });\n}\n"]}
|
|
@@ -1,17 +1,12 @@
|
|
|
1
1
|
import { getArkosConfig } from "../../server.js";
|
|
2
2
|
import deepmerge from "../../utils/helpers/deepmerge.helper.js";
|
|
3
3
|
import { AppError, BadRequestError, catchAsync, } from "../../exports/error-handler/index.js";
|
|
4
|
-
import validateDto from "../../utils/validate-dto.js";
|
|
5
|
-
import validateSchema from "../../utils/validate-schema.js";
|
|
6
4
|
import { resolvePrismaQueryOptions } from "./utils/helpers/base.middlewares.helpers.js";
|
|
7
5
|
import { capitalize } from "../../utils/helpers/text.helpers.js";
|
|
8
6
|
import errorPrettifier from "./utils/error-prettifier.js";
|
|
9
7
|
import { lenientDecode } from "../../utils/helpers/url-helpers.js";
|
|
10
8
|
import { pascalCase } from "../../exports/utils/index.js";
|
|
11
9
|
import validationManager from "../../types/validation/validation-manager.js";
|
|
12
|
-
export function callNext(_, _1, next) {
|
|
13
|
-
next();
|
|
14
|
-
}
|
|
15
10
|
function deepEqual(a, b) {
|
|
16
11
|
if (a === b)
|
|
17
12
|
return true;
|
|
@@ -131,21 +126,6 @@ export function handleRequestLogs(req, res, next) {
|
|
|
131
126
|
});
|
|
132
127
|
next();
|
|
133
128
|
}
|
|
134
|
-
export function handleRequestBodyValidationAndTransformation(schemaOrDtoClass, classValidatorValidationOptions) {
|
|
135
|
-
return catchAsync(async (req, _, next) => {
|
|
136
|
-
const validationConfigs = getArkosConfig()?.validation;
|
|
137
|
-
let body = req.body;
|
|
138
|
-
if (validationConfigs?.resolver === "class-validator" && schemaOrDtoClass)
|
|
139
|
-
req.body = await validateDto(schemaOrDtoClass, body, deepmerge({
|
|
140
|
-
whitelist: true,
|
|
141
|
-
forbidNonWhitelisted: true,
|
|
142
|
-
...classValidatorValidationOptions,
|
|
143
|
-
}, validationConfigs?.validationOptions || {}));
|
|
144
|
-
else if (validationConfigs?.resolver === "zod" && schemaOrDtoClass)
|
|
145
|
-
req.body = await validateSchema(schemaOrDtoClass, body);
|
|
146
|
-
next();
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
129
|
export function validateRequestInputs(routeConfig) {
|
|
150
130
|
const arkosConfig = getArkosConfig();
|
|
151
131
|
const validationConfig = arkosConfig.validation;
|
|
@@ -202,7 +182,12 @@ Read more about strict validation at https://www.arkosjs.com/docs/guides/validat
|
|
|
202
182
|
continue;
|
|
203
183
|
if (validator)
|
|
204
184
|
try {
|
|
205
|
-
req
|
|
185
|
+
Object.defineProperty(req, key, {
|
|
186
|
+
value: await validationFn(validator, req[key], arkosConfig.validation?.validationOptions),
|
|
187
|
+
writable: false,
|
|
188
|
+
configurable: true,
|
|
189
|
+
enumerable: true,
|
|
190
|
+
});
|
|
206
191
|
}
|
|
207
192
|
catch (err) {
|
|
208
193
|
const resolver = validationConfig?.resolver;
|