@visulima/crud 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/LICENSE.md +21 -0
  3. package/README.md +101 -0
  4. package/dist/chunk-FJWRITBO.js +52 -0
  5. package/dist/chunk-FJWRITBO.js.map +1 -0
  6. package/dist/chunk-UBXIGP5H.mjs +52 -0
  7. package/dist/chunk-UBXIGP5H.mjs.map +1 -0
  8. package/dist/index.d.ts +155 -0
  9. package/dist/index.js +1101 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/index.mjs +1101 -0
  12. package/dist/index.mjs.map +1 -0
  13. package/dist/next/index.d.ts +8 -0
  14. package/dist/next/index.js +729 -0
  15. package/dist/next/index.js.map +1 -0
  16. package/dist/next/index.mjs +729 -0
  17. package/dist/next/index.mjs.map +1 -0
  18. package/dist/types.d-6817d247.d.ts +155 -0
  19. package/package.json +136 -0
  20. package/src/adapter/prisma/index.ts +241 -0
  21. package/src/adapter/prisma/types.d.ts +46 -0
  22. package/src/adapter/prisma/utils/models-to-route-names.ts +12 -0
  23. package/src/adapter/prisma/utils/parse-cursor.ts +26 -0
  24. package/src/adapter/prisma/utils/parse-order-by.ts +21 -0
  25. package/src/adapter/prisma/utils/parse-recursive.ts +26 -0
  26. package/src/adapter/prisma/utils/parse-where.ts +197 -0
  27. package/src/base-crud-handler.ts +181 -0
  28. package/src/handler/create.ts +21 -0
  29. package/src/handler/delete.ts +27 -0
  30. package/src/handler/list.ts +62 -0
  31. package/src/handler/read.ts +27 -0
  32. package/src/handler/update.ts +29 -0
  33. package/src/index.ts +27 -0
  34. package/src/next/api/edge/index.ts +23 -0
  35. package/src/next/api/node/index.ts +27 -0
  36. package/src/next/index.ts +2 -0
  37. package/src/query-parser.ts +94 -0
  38. package/src/swagger/adapter/prisma/index.ts +95 -0
  39. package/src/swagger/json-schema-parser.ts +456 -0
  40. package/src/swagger/parameters.ts +83 -0
  41. package/src/swagger/types.d.ts +53 -0
  42. package/src/swagger/utils/format-example-ref.ts +4 -0
  43. package/src/swagger/utils/format-schema-ref.ts +4 -0
  44. package/src/swagger/utils/get-models-accessible-routes.ts +23 -0
  45. package/src/swagger/utils/get-swagger-paths.ts +244 -0
  46. package/src/swagger/utils/get-swagger-tags.ts +13 -0
  47. package/src/types.d.ts +124 -0
  48. package/src/utils/format-resource-id.ts +3 -0
  49. package/src/utils/get-accessible-routes.ts +18 -0
  50. package/src/utils/get-resource-name-from-url.ts +23 -0
  51. package/src/utils/get-route-type.ts +99 -0
  52. package/src/utils/is-primitive.ts +5 -0
  53. package/src/utils/validate-adapter-methods.ts +15 -0
package/dist/index.js ADDED
@@ -0,0 +1,1101 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }
2
+
3
+
4
+ var _chunkFJWRITBOjs = require('./chunk-FJWRITBO.js');
5
+
6
+ // src/adapter/prisma/index.ts
7
+ var _httperrors = require('http-errors'); var _httperrors2 = _interopRequireDefault(_httperrors);
8
+
9
+ // src/adapter/prisma/utils/models-to-route-names.ts
10
+ var modelsToRouteNames = (mappingsMap, models) => {
11
+ const routesMap = {};
12
+ models == null ? void 0 : models.forEach((model) => {
13
+ routesMap[model] = mappingsMap[model].plural;
14
+ });
15
+ return routesMap;
16
+ };
17
+ var models_to_route_names_default = modelsToRouteNames;
18
+
19
+ // src/utils/is-primitive.ts
20
+ var primitiveTypes = /* @__PURE__ */ new Set(["string", "boolean", "number"]);
21
+ var isPrimitive = (value) => primitiveTypes.has(typeof value);
22
+ var is_primitive_default = isPrimitive;
23
+
24
+ // src/adapter/prisma/utils/parse-cursor.ts
25
+ var parsePrismaCursor = (cursor) => {
26
+ const parsed = {};
27
+ Object.keys(cursor).forEach((key) => {
28
+ const value = cursor[key];
29
+ if (is_primitive_default(value)) {
30
+ parsed[key] = value;
31
+ }
32
+ });
33
+ if (Object.keys(parsed).length !== 1) {
34
+ throw new Error(
35
+ "cursor needs to be an object with exactly 1 property with a primitive value"
36
+ );
37
+ }
38
+ return parsed;
39
+ };
40
+ var parse_cursor_default = parsePrismaCursor;
41
+
42
+ // src/adapter/prisma/utils/parse-order-by.ts
43
+ var operatorsAssociation = {
44
+ $asc: "asc",
45
+ $desc: "desc"
46
+ };
47
+ var parsePrismaOrderBy = (orderBy) => {
48
+ const parsed = {};
49
+ Object.keys(orderBy).forEach((key) => {
50
+ const value = orderBy[key];
51
+ parsed[key] = operatorsAssociation[value];
52
+ });
53
+ return parsed;
54
+ };
55
+ var parse_order_by_default = parsePrismaOrderBy;
56
+
57
+ // src/adapter/prisma/utils/parse-recursive.ts
58
+ var parsePrismaRecursiveField = (select, fieldName) => {
59
+ const parsed = {};
60
+ Object.keys(select).forEach((field) => {
61
+ if (select[field] !== true) {
62
+ parsed[field] = {
63
+ [fieldName]: parsePrismaRecursiveField(
64
+ select[field],
65
+ fieldName
66
+ )
67
+ };
68
+ } else {
69
+ parsed[field] = true;
70
+ }
71
+ });
72
+ return parsed;
73
+ };
74
+ var parse_recursive_default = parsePrismaRecursiveField;
75
+
76
+ // src/adapter/prisma/utils/parse-where.ts
77
+ var isObject = (a) => a instanceof Object;
78
+ var operatorsAssociation2 = {
79
+ $eq: "equals",
80
+ $neq: "not",
81
+ $cont: "contains",
82
+ $ends: "endsWith",
83
+ $gt: "gt",
84
+ $gte: "gte",
85
+ $in: "in",
86
+ $lt: "lt",
87
+ $lte: "lte",
88
+ $notin: "notIn",
89
+ $starts: "startsWith"
90
+ };
91
+ var isDateString = (value) => /^\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);
92
+ var getSearchValue = (originalValue) => {
93
+ if (isDateString(originalValue)) {
94
+ return new Date(originalValue);
95
+ }
96
+ if (typeof originalValue === "string" && originalValue === "$isnull") {
97
+ return null;
98
+ }
99
+ return originalValue;
100
+ };
101
+ var isRelation = (key, manyRelations) => {
102
+ const splitKey = key.split(".");
103
+ splitKey.splice(-1, 1);
104
+ return manyRelations.includes(splitKey.join("."));
105
+ };
106
+ var parseSimpleField = (value) => {
107
+ const operator = Object.keys(value)[0];
108
+ const prismaOperator = operatorsAssociation2[operator];
109
+ if (prismaOperator) {
110
+ return {
111
+ [prismaOperator]: value[operator]
112
+ };
113
+ }
114
+ return void 0;
115
+ };
116
+ var parseRelation = (value, key, parsed, manyRelations) => {
117
+ var _a;
118
+ const fields = key.split(".").reverse();
119
+ let formatFields = {};
120
+ fields.forEach((field, index) => {
121
+ if (index === 0) {
122
+ basicParse(value, field, formatFields, manyRelations);
123
+ } else {
124
+ formatFields = {
125
+ [field]: {
126
+ some: formatFields
127
+ }
128
+ };
129
+ }
130
+ });
131
+ const initialFieldKey = fields.reverse()[0];
132
+ const oldParsed = parsed[initialFieldKey];
133
+ parsed[initialFieldKey] = {
134
+ some: {
135
+ ...oldParsed == null ? void 0 : oldParsed.some,
136
+ ...(_a = formatFields[initialFieldKey]) == null ? void 0 : _a.some
137
+ }
138
+ };
139
+ };
140
+ var parseObjectCombination = (object, manyRelations) => {
141
+ const parsed = {};
142
+ Object.keys(object).forEach((key) => {
143
+ const value = object[key];
144
+ if (isRelation(key, manyRelations)) {
145
+ parseRelation(value, key, parsed, manyRelations);
146
+ } else if (is_primitive_default(value)) {
147
+ parsed[key] = value;
148
+ } else if (isObject(value)) {
149
+ const fieldResult = parseSimpleField(value);
150
+ if (fieldResult) {
151
+ parsed[key] = fieldResult;
152
+ }
153
+ }
154
+ });
155
+ return parsed;
156
+ };
157
+ var basicParse = (value, key, parsed, manyRelations) => {
158
+ if (is_primitive_default(value)) {
159
+ parsed[key] = getSearchValue(value);
160
+ } else {
161
+ switch (key) {
162
+ case "$or": {
163
+ if (isObject(value)) {
164
+ parsed.OR = parseObjectCombination(value, manyRelations);
165
+ }
166
+ break;
167
+ }
168
+ case "$and": {
169
+ if (isObject(value)) {
170
+ parsed.AND = parseObjectCombination(value, manyRelations);
171
+ }
172
+ break;
173
+ }
174
+ case "$not": {
175
+ if (isObject(value)) {
176
+ parsed.NOT = parseObjectCombination(value, manyRelations);
177
+ }
178
+ break;
179
+ }
180
+ default: {
181
+ parsed[key] = parseSimpleField(value);
182
+ break;
183
+ }
184
+ }
185
+ }
186
+ };
187
+ var parsePrismaWhere = (where, manyRelations) => {
188
+ const parsed = {};
189
+ Object.keys(where).forEach((key) => {
190
+ const value = where[key];
191
+ if (isRelation(key, manyRelations)) {
192
+ parseRelation(value, key, parsed, manyRelations);
193
+ } else {
194
+ basicParse(value, key, parsed, manyRelations);
195
+ }
196
+ });
197
+ return parsed;
198
+ };
199
+ var parse_where_default = parsePrismaWhere;
200
+
201
+ // src/adapter/prisma/index.ts
202
+ var PrismaAdapter = class {
203
+ constructor({
204
+ primaryKey = "id",
205
+ prismaClient,
206
+ manyRelations = {},
207
+ models
208
+ }) {
209
+ this.getPrismaClientModels = async () => {
210
+ var _a;
211
+ if (this.prismaClient._dmmf) {
212
+ this.dmmf = this.prismaClient._dmmf;
213
+ return (_a = this.dmmf) == null ? void 0 : _a.mappingsMap;
214
+ }
215
+ if (this.prismaClient._getDmmf) {
216
+ this.dmmf = await this.prismaClient._getDmmf();
217
+ return this.dmmf.mappingsMap;
218
+ }
219
+ throw new Error("Couldn't get prisma client models");
220
+ };
221
+ this.prismaClient = prismaClient;
222
+ this.primaryKey = primaryKey;
223
+ this.manyRelations = manyRelations;
224
+ this.ctorModels = models;
225
+ }
226
+ async init() {
227
+ const models = this.ctorModels;
228
+ const prismaDmmfModels = await this.getPrismaClientModels();
229
+ if (typeof models !== "undefined") {
230
+ models.forEach((model) => {
231
+ if (!Object.keys(prismaDmmfModels).includes(model)) {
232
+ throw new Error(`Model name ${model} is invalid.`);
233
+ }
234
+ });
235
+ }
236
+ this.models = _nullishCoalesce(models, () => ( Object.keys(prismaDmmfModels)));
237
+ }
238
+ async getPaginationData(resourceName, query) {
239
+ const total = await this.getPrismaDelegate(resourceName).count({
240
+ where: query.where,
241
+ distinct: query.distinct
242
+ });
243
+ return {
244
+ total,
245
+ pageCount: Math.ceil(total / query.take),
246
+ page: Math.ceil(query.skip / query.take) + 1
247
+ };
248
+ }
249
+ handleError(error) {
250
+ console.error(error);
251
+ if (error instanceof Error && error.stack) {
252
+ console.error(error.stack);
253
+ }
254
+ throw error.constructor.name === "PrismaClientKnownRequestError" || error.constructor.name === "PrismaClientValidationError" ? _httperrors2.default.call(void 0, 400, "invalid request, check your server logs for more info") : _httperrors2.default.call(void 0, 500, "an unknown error occured, check your server logs for more info");
255
+ }
256
+ parseQuery(resourceName, query) {
257
+ var _a, _b;
258
+ const parsed = {};
259
+ if (query.select) {
260
+ parsed.select = parse_recursive_default(query.select, "select");
261
+ }
262
+ if (query.include) {
263
+ parsed.include = parse_recursive_default(query.include, "include");
264
+ }
265
+ if ((_a = query.originalQuery) == null ? void 0 : _a.where) {
266
+ parsed.where = parse_where_default(JSON.parse(query.originalQuery.where), _nullishCoalesce(this.manyRelations[resourceName], () => ( [])));
267
+ }
268
+ if (query.orderBy) {
269
+ parsed.orderBy = parse_order_by_default(query.orderBy);
270
+ }
271
+ if (typeof query.limit !== "undefined") {
272
+ parsed.take = query.limit;
273
+ }
274
+ if (typeof query.skip !== "undefined") {
275
+ parsed.skip = query.skip;
276
+ }
277
+ if ((_b = query.originalQuery) == null ? void 0 : _b.cursor) {
278
+ parsed.cursor = parse_cursor_default(JSON.parse(query.originalQuery.cursor));
279
+ }
280
+ if (query.distinct) {
281
+ parsed.distinct = query.distinct;
282
+ }
283
+ return parsed;
284
+ }
285
+ async getAll(resourceName, query) {
286
+ return await this.getPrismaDelegate(resourceName).findMany({
287
+ select: query.select,
288
+ include: query.include,
289
+ where: query.where,
290
+ orderBy: query.orderBy,
291
+ cursor: query.cursor,
292
+ take: query.take,
293
+ skip: query.skip,
294
+ distinct: query.distinct
295
+ });
296
+ }
297
+ async getOne(resourceName, resourceId, query) {
298
+ const delegate = this.getPrismaDelegate(resourceName);
299
+ const findFunction = delegate.findUnique || delegate.findOne;
300
+ return findFunction({
301
+ where: {
302
+ [this.primaryKey]: resourceId
303
+ },
304
+ select: query.select,
305
+ include: query.include
306
+ });
307
+ }
308
+ async create(resourceName, data, query) {
309
+ return this.getPrismaDelegate(resourceName).create({
310
+ data,
311
+ select: query.select,
312
+ include: query.include
313
+ });
314
+ }
315
+ async update(resourceName, resourceId, data, query) {
316
+ return this.getPrismaDelegate(resourceName).update({
317
+ where: {
318
+ [this.primaryKey]: resourceId
319
+ },
320
+ data,
321
+ select: query.select,
322
+ include: query.include
323
+ });
324
+ }
325
+ async delete(resourceName, resourceId, query) {
326
+ return this.getPrismaDelegate(resourceName).delete({
327
+ where: {
328
+ [this.primaryKey]: resourceId
329
+ },
330
+ select: query.select,
331
+ include: query.include
332
+ });
333
+ }
334
+ connect() {
335
+ return this.prismaClient.$connect();
336
+ }
337
+ disconnect() {
338
+ return this.prismaClient.$disconnect();
339
+ }
340
+ get client() {
341
+ return this.prismaClient;
342
+ }
343
+ getModels() {
344
+ return this.models || [];
345
+ }
346
+ getPrismaDelegate(resourceName) {
347
+ return this.prismaClient[`${resourceName.charAt(0).toLowerCase()}${resourceName.slice(1)}`];
348
+ }
349
+ async mapModelsToRouteNames() {
350
+ return models_to_route_names_default(await this.getPrismaClientModels(), this.getModels());
351
+ }
352
+ };
353
+
354
+ // src/swagger/json-schema-parser.ts
355
+ var _prismadmmftransformer = require('@visulima/prisma-dmmf-transformer');
356
+
357
+ // src/swagger/utils/format-schema-ref.ts
358
+ var formatSchemaReference = (schemaName) => `#/components/schemas/${schemaName}`;
359
+ var format_schema_ref_default = formatSchemaReference;
360
+
361
+ // src/swagger/json-schema-parser.ts
362
+ var getJSONSchemaScalar = (fieldType) => {
363
+ switch (fieldType) {
364
+ case "Int":
365
+ case "BigInt": {
366
+ return "integer";
367
+ }
368
+ case "DateTime":
369
+ case "Bytes":
370
+ case "String": {
371
+ return "string";
372
+ }
373
+ case "Float":
374
+ case "Decimal": {
375
+ return "number";
376
+ }
377
+ case "Json": {
378
+ return "object";
379
+ }
380
+ case "Boolean": {
381
+ return "boolean";
382
+ }
383
+ case "Null": {
384
+ return "null";
385
+ }
386
+ default: {
387
+ return "";
388
+ }
389
+ }
390
+ };
391
+ var PAGINATION_SCHEMA_NAME = "PaginationData";
392
+ var methodsNames = [
393
+ { methodStart: "createOne", schemaNameStart: "Create" },
394
+ { methodStart: "updateOne", schemaNameStart: "Update" }
395
+ ];
396
+ var PrismaJsonSchemaParser = class {
397
+ constructor(dmmf) {
398
+ this.dmmf = dmmf;
399
+ this.schemaInputTypes = /* @__PURE__ */ new Map();
400
+ }
401
+ parseModels() {
402
+ var _a;
403
+ const modelsDefinitions = _prismadmmftransformer.transformDMMF.call(void 0, this.dmmf).definitions;
404
+ (_a = Object.keys(modelsDefinitions || {})) == null ? void 0 : _a.forEach((definition) => {
405
+ const { properties } = modelsDefinitions[definition];
406
+ Object.keys(properties).forEach((property) => {
407
+ if (Array.isArray(properties[property].type) && properties[property].type.includes("null")) {
408
+ properties[property].type = properties[property].type.filter((type) => type !== "null");
409
+ if (properties[property].type.length === 1) {
410
+ properties[property].type = properties[property].type[0];
411
+ }
412
+ properties[property].nullable = true;
413
+ }
414
+ });
415
+ });
416
+ return modelsDefinitions;
417
+ }
418
+ parseInputTypes(models) {
419
+ const definitions = models.reduce((accumulator, modelName) => {
420
+ const methods = methodsNames.map((method) => {
421
+ return {
422
+ name: `${method.methodStart}${modelName}`,
423
+ schemaName: `${method.schemaNameStart}${modelName}`
424
+ };
425
+ });
426
+ methods.forEach(({ name: method, schemaName }) => {
427
+ const dataFields = this.dmmf.mutationType.fieldMap[method].args[0].inputTypes[0].type.fields;
428
+ const requiredProperties = [];
429
+ const properties = dataFields.reduce((propertiesAccumulator, field) => {
430
+ if (field.inputTypes[0].kind === "scalar") {
431
+ const schema = _prismadmmftransformer.getJSONSchemaProperty.call(void 0,
432
+ this.dmmf.datamodel,
433
+ {}
434
+ )({
435
+ name: field.name,
436
+ ...field.inputTypes[0]
437
+ });
438
+ const { type: schemaType } = schema[1];
439
+ if (schemaType && Array.isArray(schemaType)) {
440
+ if (schemaType.includes("null")) {
441
+ propertiesAccumulator[field.name] = {
442
+ ...schemaType,
443
+ type: schemaType.filter((type) => type !== "null"),
444
+ nullable: true
445
+ };
446
+ if (propertiesAccumulator[field.name].type.length === 1) {
447
+ propertiesAccumulator[field.name] = {
448
+ ...propertiesAccumulator[field.name],
449
+ type: propertiesAccumulator[field.name].type[0]
450
+ };
451
+ }
452
+ }
453
+ } else {
454
+ propertiesAccumulator[field.name] = schema[1];
455
+ }
456
+ } else {
457
+ const typeName = this.parseObjectInputType(field.inputTypes[0]);
458
+ propertiesAccumulator[field.name] = {
459
+ ...typeName,
460
+ nullable: field.isNullable
461
+ };
462
+ }
463
+ if (field.isRequired) {
464
+ requiredProperties.push(field.name);
465
+ }
466
+ return propertiesAccumulator;
467
+ }, {});
468
+ accumulator[schemaName] = {
469
+ type: "object",
470
+ xml: {
471
+ name: schemaName
472
+ },
473
+ properties
474
+ };
475
+ if (requiredProperties.length > 0) {
476
+ accumulator[schemaName].required = requiredProperties;
477
+ }
478
+ });
479
+ return accumulator;
480
+ }, {});
481
+ this.schemaInputTypes.forEach((value, key) => {
482
+ definitions[key] = {
483
+ type: "object",
484
+ xml: {
485
+ name: key
486
+ },
487
+ properties: value
488
+ };
489
+ });
490
+ return definitions;
491
+ }
492
+ formatInputTypeData(inputType) {
493
+ if (inputType.kind === "object") {
494
+ const reference = format_schema_ref_default(inputType.type.name);
495
+ if (inputType.isList) {
496
+ return {
497
+ type: "array",
498
+ xml: {
499
+ name: inputType.type.name,
500
+ wrapped: true
501
+ },
502
+ items: {
503
+ $ref: reference
504
+ }
505
+ };
506
+ }
507
+ return { $ref: reference };
508
+ }
509
+ const type = getJSONSchemaScalar(inputType.type);
510
+ if (inputType.isList) {
511
+ return {
512
+ type: "array",
513
+ xml: {
514
+ name: inputType.type.name,
515
+ wrapped: true
516
+ },
517
+ items: {
518
+ type
519
+ }
520
+ };
521
+ }
522
+ return { type };
523
+ }
524
+ parseObjectInputType(fieldType) {
525
+ if (fieldType.kind === "object") {
526
+ if (!this.schemaInputTypes.has(fieldType.type.name)) {
527
+ this.schemaInputTypes.set(fieldType.type.name, {});
528
+ fieldType.type.fields.forEach((field) => {
529
+ let fieldData = {};
530
+ if (field.inputTypes.length > 1) {
531
+ let nullable = false;
532
+ const anyOf = field.inputTypes.map((inputType) => {
533
+ const inputTypeData = this.formatInputTypeData(inputType);
534
+ if (inputTypeData.type === "null") {
535
+ nullable = true;
536
+ return;
537
+ }
538
+ return inputTypeData;
539
+ }).filter(Boolean);
540
+ if (anyOf.length === 1) {
541
+ fieldData = anyOf[0];
542
+ } else {
543
+ fieldData.anyOf = anyOf;
544
+ }
545
+ if (nullable) {
546
+ fieldData.nullable = true;
547
+ }
548
+ } else {
549
+ const inputType = field.inputTypes[0];
550
+ fieldData = this.formatInputTypeData(inputType);
551
+ }
552
+ this.schemaInputTypes.set(fieldType.type.name, {
553
+ ...this.schemaInputTypes.get(fieldType.type.name),
554
+ [field.name]: fieldData
555
+ });
556
+ field.inputTypes.forEach((inputType) => {
557
+ if (inputType.kind === "object") {
558
+ this.parseObjectInputType(inputType);
559
+ }
560
+ });
561
+ });
562
+ }
563
+ return { $ref: format_schema_ref_default(fieldType.type.name) };
564
+ }
565
+ return { type: getJSONSchemaScalar(fieldType.type) };
566
+ }
567
+ getPaginationDataSchema() {
568
+ return {
569
+ [PAGINATION_SCHEMA_NAME]: {
570
+ type: "object",
571
+ xml: {
572
+ name: PAGINATION_SCHEMA_NAME
573
+ },
574
+ properties: {
575
+ total: {
576
+ type: "integer",
577
+ minimum: 0,
578
+ description: "Holds the value for the total number of rows in the database"
579
+ },
580
+ perPage: {
581
+ type: "integer",
582
+ minimum: 0,
583
+ description: "Returns the value for the limit passed to the paginate method"
584
+ },
585
+ page: {
586
+ type: "integer",
587
+ minimum: 1,
588
+ description: "Current page number"
589
+ },
590
+ lastPage: {
591
+ type: "integer",
592
+ minimum: 0,
593
+ description: "Returns the value for the last page by taking the total of rows into account"
594
+ },
595
+ firstPage: {
596
+ type: "integer",
597
+ minimum: 0,
598
+ description: "Returns the number for the first page. It is always 1"
599
+ },
600
+ firstPageUrl: {
601
+ type: "string",
602
+ description: "The URL for the first page"
603
+ },
604
+ lastPageUrl: {
605
+ type: "string",
606
+ description: "The URL for the last page"
607
+ },
608
+ nextPageUrl: {
609
+ type: "string",
610
+ description: "The URL for the next page"
611
+ },
612
+ previousPageUrl: {
613
+ type: "string",
614
+ description: "The URL for the previous page"
615
+ }
616
+ }
617
+ }
618
+ };
619
+ }
620
+ getExampleModelsSchemas(modelNames, schemas) {
621
+ const referenceToSchema = (reference) => {
622
+ const name = reference.replace("#/components/schemas/", "");
623
+ const model = schemas[name];
624
+ const values = {};
625
+ Object.entries((model == null ? void 0 : model.properties) || {}).forEach(([key, v]) => {
626
+ const type = v.type;
627
+ if (type === "array") {
628
+ values[key] = [arrayItemsToSchema(v.items)];
629
+ } else {
630
+ values[key] = type;
631
+ }
632
+ });
633
+ return values;
634
+ };
635
+ const objectPropertiesToSchema = (objectProperties) => {
636
+ const values = {};
637
+ Object.entries(objectProperties).forEach(([key, value]) => {
638
+ if (typeof value.$ref !== "undefined") {
639
+ values[key] = referenceToSchema(value.$ref);
640
+ } else {
641
+ values[key] = value.type;
642
+ }
643
+ });
644
+ return values;
645
+ };
646
+ const arrayItemsToSchema = (items) => {
647
+ const values = {};
648
+ Object.entries(items).forEach(([key, value]) => {
649
+ if (typeof value.items.$ref !== "undefined") {
650
+ values[key] = [referenceToSchema(value.items.$ref)];
651
+ } else if (value.type === "array") {
652
+ values[key] = [arrayItemsToSchema(value.items)];
653
+ } else if (value.type === "object") {
654
+ values[key] = objectPropertiesToSchema(value.properties);
655
+ } else {
656
+ values[key] = value.type;
657
+ }
658
+ });
659
+ return values;
660
+ };
661
+ return modelNames.reduce((accumulator, modelName) => {
662
+ const value = {};
663
+ const model = schemas[modelName];
664
+ Object.entries(model.properties).forEach(([key, v]) => {
665
+ const type = v.type;
666
+ if (type === "array") {
667
+ value[key] = [referenceToSchema(v.items.$ref)];
668
+ } else if (type === "object") {
669
+ value[key] = objectPropertiesToSchema(v.properties);
670
+ } else {
671
+ value[key] = type;
672
+ }
673
+ });
674
+ const pagination = this.getPaginationDataSchema()[PAGINATION_SCHEMA_NAME];
675
+ const meta = {};
676
+ Object.entries(pagination.properties).forEach(([key, v]) => {
677
+ meta[key] = v.type;
678
+ });
679
+ return {
680
+ ...accumulator,
681
+ [`${modelName}`]: {
682
+ value
683
+ },
684
+ [`${modelName}Page`]: {
685
+ value: {
686
+ data: [value],
687
+ meta
688
+ }
689
+ }
690
+ };
691
+ }, {});
692
+ }
693
+ getPaginatedModelsSchemas(modelNames) {
694
+ return modelNames.reduce((accumulator, modelName) => {
695
+ return {
696
+ ...accumulator,
697
+ [`${modelName}Page`]: {
698
+ type: "object",
699
+ xml: {
700
+ name: `${modelName}Page`
701
+ },
702
+ properties: {
703
+ data: {
704
+ type: "array",
705
+ xml: {
706
+ name: "Data",
707
+ wrapped: true
708
+ },
709
+ items: {
710
+ $ref: format_schema_ref_default(modelName)
711
+ }
712
+ },
713
+ meta: {
714
+ $ref: format_schema_ref_default(PAGINATION_SCHEMA_NAME)
715
+ }
716
+ }
717
+ }
718
+ };
719
+ }, {});
720
+ }
721
+ };
722
+ var json_schema_parser_default = PrismaJsonSchemaParser;
723
+
724
+ // src/swagger/utils/get-models-accessible-routes.ts
725
+ var getModelsAccessibleRoutes = (modelNames, models, defaultExposeStrategy = "all") => modelNames.reduce((accumulator, modelName) => {
726
+ if (models == null ? void 0 : models[modelName]) {
727
+ return {
728
+ ...accumulator,
729
+ [modelName]: _chunkFJWRITBOjs.get_accessible_routes_default.call(void 0, models[modelName].only, models[modelName].exclude, defaultExposeStrategy)
730
+ };
731
+ }
732
+ return {
733
+ ...accumulator,
734
+ [modelName]: _chunkFJWRITBOjs.get_accessible_routes_default.call(void 0, void 0, void 0, defaultExposeStrategy)
735
+ };
736
+ }, {});
737
+ var get_models_accessible_routes_default = getModelsAccessibleRoutes;
738
+
739
+ // src/swagger/parameters.ts
740
+ var queryParameters = {
741
+ select: {
742
+ name: "select",
743
+ description: "Fields to select. For nested fields, chain them separated with a dot, eg: user.posts",
744
+ schema: {
745
+ type: "string"
746
+ }
747
+ },
748
+ include: {
749
+ name: "include",
750
+ description: "Include relations, same as select",
751
+ schema: {
752
+ type: "string"
753
+ }
754
+ },
755
+ where: {
756
+ name: "where",
757
+ description: 'Fields to filter. See <a href="https://next-crud.js.org/query-params#where">the docs</a>',
758
+ schema: {
759
+ type: "string"
760
+ }
761
+ },
762
+ orderBy: {
763
+ name: "orderBy",
764
+ description: 'Field on which to order by a direction. See <a href="https://next-crud.js.org/query-params#orderBy">the docs</a>',
765
+ schema: {
766
+ type: "string"
767
+ }
768
+ },
769
+ limit: {
770
+ name: "limit",
771
+ description: "Maximum number of elements to retrieve",
772
+ schema: {
773
+ type: "integer",
774
+ minimum: 0
775
+ }
776
+ },
777
+ skip: {
778
+ name: "skip",
779
+ description: "Number of rows to skip",
780
+ schema: {
781
+ type: "integer",
782
+ minimum: 0
783
+ }
784
+ },
785
+ distinct: {
786
+ name: "distinct",
787
+ description: "Fields to distinctively retrieve",
788
+ schema: {
789
+ type: "string"
790
+ }
791
+ },
792
+ page: {
793
+ name: "page",
794
+ description: "Page number. Use only for pagination.",
795
+ schema: {
796
+ type: "integer",
797
+ minimum: 1
798
+ }
799
+ }
800
+ };
801
+ var commonQueryParameters = [queryParameters.select, queryParameters.include];
802
+ var listQueryParameters = [
803
+ ...commonQueryParameters,
804
+ queryParameters.limit,
805
+ queryParameters.skip,
806
+ queryParameters.where,
807
+ queryParameters.orderBy,
808
+ queryParameters.page,
809
+ queryParameters.distinct
810
+ ];
811
+ var getQueryParameters = (routeType, additionalQueryParameters = []) => {
812
+ if (routeType === "READ_ALL" /* READ_ALL */) {
813
+ return [...listQueryParameters, ...additionalQueryParameters];
814
+ }
815
+ return [...commonQueryParameters, ...additionalQueryParameters];
816
+ };
817
+
818
+ // src/swagger/utils/format-example-ref.ts
819
+ var formatExampleReference = (schemaName) => `#/components/examples/${schemaName}`;
820
+ var format_example_ref_default = formatExampleReference;
821
+
822
+ // src/swagger/utils/get-swagger-paths.ts
823
+ var generateContentForSchema = (schemaName, isArray) => {
824
+ if (isArray) {
825
+ return {
826
+ type: "array",
827
+ items: {
828
+ $ref: format_schema_ref_default(schemaName)
829
+ }
830
+ };
831
+ }
832
+ return {
833
+ $ref: format_schema_ref_default(schemaName)
834
+ };
835
+ };
836
+ var generateSwaggerResponse = (routeType, modelName) => {
837
+ if (routeType === "CREATE" /* CREATE */) {
838
+ return {
839
+ statusCode: 201,
840
+ content: {
841
+ description: `${modelName} created`,
842
+ content: {
843
+ "application/json": {
844
+ schema: generateContentForSchema(modelName)
845
+ }
846
+ }
847
+ }
848
+ };
849
+ }
850
+ if (routeType === "DELETE" /* DELETE */) {
851
+ return {
852
+ statusCode: 200,
853
+ content: {
854
+ description: `${modelName} item deleted`,
855
+ content: {
856
+ "application/json": {
857
+ schema: generateContentForSchema(modelName)
858
+ }
859
+ }
860
+ }
861
+ };
862
+ }
863
+ if (routeType === "READ_ALL" /* READ_ALL */) {
864
+ return {
865
+ statusCode: 200,
866
+ content: {
867
+ description: `${modelName} list retrieved`,
868
+ content: {
869
+ "application/json": {
870
+ schema: {
871
+ oneOf: [generateContentForSchema(modelName, true), generateContentForSchema(`${modelName}Page`, false)]
872
+ },
873
+ examples: {
874
+ Default: {
875
+ $ref: format_example_ref_default(`${modelName}`)
876
+ },
877
+ Pagination: {
878
+ $ref: format_example_ref_default(`${modelName}Page`)
879
+ }
880
+ }
881
+ }
882
+ }
883
+ }
884
+ };
885
+ }
886
+ if (routeType === "READ_ONE" /* READ_ONE */) {
887
+ return {
888
+ statusCode: 200,
889
+ content: {
890
+ description: `${modelName} item retrieved`,
891
+ content: {
892
+ "application/json": {
893
+ schema: generateContentForSchema(modelName)
894
+ }
895
+ }
896
+ }
897
+ };
898
+ }
899
+ if (routeType === "UPDATE" /* UPDATE */) {
900
+ return {
901
+ statusCode: 200,
902
+ content: {
903
+ description: `${modelName} item updated`,
904
+ content: {
905
+ "application/json": {
906
+ schema: generateContentForSchema(modelName)
907
+ }
908
+ }
909
+ }
910
+ };
911
+ }
912
+ return void 0;
913
+ };
914
+ var generateRequestBody = (schemaStartName, modelName) => {
915
+ return {
916
+ content: {
917
+ "application/json": {
918
+ schema: {
919
+ $ref: format_schema_ref_default(`${schemaStartName}${modelName}`)
920
+ }
921
+ }
922
+ }
923
+ };
924
+ };
925
+ var getRouteTypeMethod = (routeType) => {
926
+ switch (routeType) {
927
+ case "CREATE" /* CREATE */: {
928
+ return "post";
929
+ }
930
+ case "READ_ALL" /* READ_ALL */:
931
+ case "READ_ONE" /* READ_ONE */: {
932
+ return "get";
933
+ }
934
+ case "UPDATE" /* UPDATE */: {
935
+ return "put";
936
+ }
937
+ case "DELETE" /* DELETE */: {
938
+ return "delete";
939
+ }
940
+ default: {
941
+ throw new TypeError(`Method for route type ${routeType} was not found.`);
942
+ }
943
+ }
944
+ };
945
+ var generateSwaggerPathObject = ({
946
+ tag,
947
+ routeTypes,
948
+ modelName,
949
+ modelsConfig,
950
+ hasId
951
+ }) => {
952
+ const methods = {};
953
+ routeTypes.forEach((routeType) => {
954
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
955
+ if (routeTypes.includes(routeType)) {
956
+ const returnType = _nullishCoalesce(_nullishCoalesce(((_d = (_c = (_b = (_a = modelsConfig == null ? void 0 : modelsConfig[modelName]) == null ? void 0 : _a.routeTypes) == null ? void 0 : _b[routeType]) == null ? void 0 : _c.response) == null ? void 0 : _d.name), () => ( ((_f = (_e = modelsConfig == null ? void 0 : modelsConfig[modelName]) == null ? void 0 : _e.type) == null ? void 0 : _f.name))), () => ( modelName));
957
+ const method = getRouteTypeMethod(routeType);
958
+ const response = generateSwaggerResponse(routeType, returnType);
959
+ if (typeof response === "undefined") {
960
+ throw new TypeError(`Route type ${routeType}; response config was not found.`);
961
+ }
962
+ methods[method] = {
963
+ tags: [tag],
964
+ summary: (_i = (_h = (_g = modelsConfig == null ? void 0 : modelsConfig[modelName]) == null ? void 0 : _g.routeTypes) == null ? void 0 : _h[routeType]) == null ? void 0 : _i.summary,
965
+ parameters: getQueryParameters(routeType).map((queryParameter) => {
966
+ return { ...queryParameter, in: "query" };
967
+ }),
968
+ responses: {
969
+ [response.statusCode]: response.content,
970
+ ...(_l = (_k = (_j = modelsConfig == null ? void 0 : modelsConfig[modelName]) == null ? void 0 : _j.routeTypes) == null ? void 0 : _k[routeType]) == null ? void 0 : _l.responses
971
+ }
972
+ };
973
+ if (hasId) {
974
+ methods[method].parameters.push({
975
+ in: "path",
976
+ name: "id",
977
+ description: `ID of the ${modelName}`,
978
+ required: true,
979
+ schema: {
980
+ type: "string"
981
+ }
982
+ });
983
+ }
984
+ if (routeType === "UPDATE" /* UPDATE */ || routeType === "CREATE" /* CREATE */) {
985
+ if (routeType === "UPDATE" /* UPDATE */) {
986
+ methods[method].requestBody = generateRequestBody("Update", returnType);
987
+ } else if (routeType === "CREATE" /* CREATE */) {
988
+ methods[method].requestBody = generateRequestBody("Create", returnType);
989
+ }
990
+ }
991
+ }
992
+ });
993
+ return methods;
994
+ };
995
+ var getSwaggerPaths = ({
996
+ routes,
997
+ models,
998
+ modelsConfig,
999
+ routesMap
1000
+ }) => Object.keys(routes).reduce((accumulator, value) => {
1001
+ var _a, _b, _c;
1002
+ const routeTypes = routes[value];
1003
+ const resourceName = ((_a = models == null ? void 0 : models[value]) == null ? void 0 : _a.name) ? models[value].name : (routesMap == null ? void 0 : routesMap[value]) || value;
1004
+ const tag = ((_c = (_b = modelsConfig == null ? void 0 : modelsConfig[value]) == null ? void 0 : _b.tag) == null ? void 0 : _c.name) || value;
1005
+ if (routeTypes.includes("CREATE" /* CREATE */) || routeTypes.includes("READ_ALL" /* READ_ALL */)) {
1006
+ const path = `/${resourceName}`;
1007
+ const routeTypesToUse = ["READ_ALL" /* READ_ALL */, "CREATE" /* CREATE */].filter((routeType) => routeTypes.includes(routeType));
1008
+ accumulator[path] = generateSwaggerPathObject({
1009
+ tag,
1010
+ modelName: value,
1011
+ modelsConfig,
1012
+ routeTypes: routeTypesToUse
1013
+ });
1014
+ }
1015
+ if (routeTypes.includes("READ_ONE" /* READ_ONE */) || routeTypes.includes("UPDATE" /* UPDATE */) || routeTypes.includes("DELETE" /* DELETE */)) {
1016
+ const path = `/${resourceName}/{id}`;
1017
+ const routeTypesToUse = ["READ_ONE" /* READ_ONE */, "UPDATE" /* UPDATE */, "DELETE" /* DELETE */].filter((routeType) => routeTypes.includes(routeType));
1018
+ accumulator[path] = generateSwaggerPathObject({
1019
+ tag,
1020
+ modelName: value,
1021
+ modelsConfig,
1022
+ routeTypes: routeTypesToUse,
1023
+ hasId: true
1024
+ });
1025
+ }
1026
+ return accumulator;
1027
+ }, {});
1028
+ var get_swagger_paths_default = getSwaggerPaths;
1029
+
1030
+ // src/swagger/utils/get-swagger-tags.ts
1031
+ var getSwaggerTags = (modelNames, modelsConfig) => modelNames.map((modelName) => {
1032
+ var _a;
1033
+ if ((_a = modelsConfig == null ? void 0 : modelsConfig[modelName]) == null ? void 0 : _a.tag) {
1034
+ return modelsConfig[modelName].tag;
1035
+ }
1036
+ return {
1037
+ name: modelName
1038
+ };
1039
+ });
1040
+ var get_swagger_tags_default = getSwaggerTags;
1041
+
1042
+ // src/swagger/adapter/prisma/index.ts
1043
+ var modelsToOpenApi = async ({
1044
+ prismaClient,
1045
+ models: ctorModels,
1046
+ swagger = { models: {}, allowedMediaTypes: { "application/json": true } },
1047
+ crud = { models: {} },
1048
+ defaultExposeStrategy = "all"
1049
+ }) => {
1050
+ let dmmf;
1051
+ let prismaDmmfModels;
1052
+ if (prismaClient._dmmf) {
1053
+ dmmf = prismaClient._dmmf;
1054
+ prismaDmmfModels = dmmf == null ? void 0 : dmmf.mappingsMap;
1055
+ } else if (prismaClient._getDmmf) {
1056
+ dmmf = await prismaClient._getDmmf();
1057
+ prismaDmmfModels = dmmf.mappingsMap;
1058
+ }
1059
+ if (typeof dmmf === void 0) {
1060
+ throw new TypeError("Couldn't get prisma client models");
1061
+ }
1062
+ const parser = new json_schema_parser_default(dmmf);
1063
+ const definitions = parser.parseModels();
1064
+ const dModels = Object.keys(definitions);
1065
+ const schema = JSON.stringify({
1066
+ ...definitions,
1067
+ ...parser.parseInputTypes(dModels),
1068
+ ...parser.getPaginationDataSchema(),
1069
+ ...parser.getPaginatedModelsSchemas(dModels)
1070
+ });
1071
+ if (typeof ctorModels !== "undefined") {
1072
+ ctorModels.forEach((model) => {
1073
+ if (!Object.keys(prismaDmmfModels).includes(model)) {
1074
+ throw new Error(`Model name ${model} is invalid.`);
1075
+ }
1076
+ });
1077
+ }
1078
+ const models = _nullishCoalesce(ctorModels, () => ( Object.keys(prismaDmmfModels)));
1079
+ const swaggerRoutes = get_models_accessible_routes_default(models, crud.models || {}, defaultExposeStrategy);
1080
+ const swaggerTags = get_swagger_tags_default(models, (swagger == null ? void 0 : swagger.models) || {});
1081
+ const swaggerPaths = get_swagger_paths_default({
1082
+ routes: swaggerRoutes,
1083
+ modelsConfig: (swagger == null ? void 0 : swagger.models) || {},
1084
+ models: crud.models || {},
1085
+ routesMap: models_to_route_names_default(prismaDmmfModels, models)
1086
+ });
1087
+ const schemas = JSON.parse(schema.replace(/#\/definitions/g, "#/components/schemas"));
1088
+ return {
1089
+ schemas,
1090
+ examples: parser.getExampleModelsSchemas(dModels, schemas),
1091
+ tags: swaggerTags,
1092
+ paths: swaggerPaths
1093
+ };
1094
+ };
1095
+ var prisma_default = modelsToOpenApi;
1096
+
1097
+
1098
+
1099
+
1100
+ exports.PrismaAdapter = PrismaAdapter; exports.RouteType = _chunkFJWRITBOjs.RouteType; exports.modelsToOpenApi = prisma_default;
1101
+ //# sourceMappingURL=index.js.map