@visulima/crud 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +46 -16
  3. package/dist/chunk-SH6A4KBC.mjs +28 -0
  4. package/dist/{chunk-UBXIGP5H.mjs.map → chunk-SH6A4KBC.mjs.map} +1 -1
  5. package/dist/chunk-ZY3WOLEP.js +28 -0
  6. package/dist/chunk-ZY3WOLEP.js.map +1 -0
  7. package/dist/index.d.ts +9 -15
  8. package/dist/index.js +57 -37
  9. package/dist/index.js.map +1 -1
  10. package/dist/index.mjs +54 -34
  11. package/dist/index.mjs.map +1 -1
  12. package/dist/next/index.js +10 -281
  13. package/dist/next/index.js.map +1 -1
  14. package/dist/next/index.mjs +9 -280
  15. package/dist/next/index.mjs.map +1 -1
  16. package/next/package.json +18 -0
  17. package/package.json +16 -14
  18. package/dist/chunk-FJWRITBO.js +0 -52
  19. package/dist/chunk-FJWRITBO.js.map +0 -1
  20. package/dist/chunk-UBXIGP5H.mjs +0 -52
  21. package/src/adapter/prisma/index.ts +0 -241
  22. package/src/adapter/prisma/types.d.ts +0 -46
  23. package/src/adapter/prisma/utils/models-to-route-names.ts +0 -12
  24. package/src/adapter/prisma/utils/parse-cursor.ts +0 -26
  25. package/src/adapter/prisma/utils/parse-order-by.ts +0 -21
  26. package/src/adapter/prisma/utils/parse-recursive.ts +0 -26
  27. package/src/adapter/prisma/utils/parse-where.ts +0 -197
  28. package/src/base-crud-handler.ts +0 -181
  29. package/src/handler/create.ts +0 -21
  30. package/src/handler/delete.ts +0 -27
  31. package/src/handler/list.ts +0 -62
  32. package/src/handler/read.ts +0 -27
  33. package/src/handler/update.ts +0 -29
  34. package/src/index.ts +0 -27
  35. package/src/next/api/edge/index.ts +0 -23
  36. package/src/next/api/node/index.ts +0 -27
  37. package/src/next/index.ts +0 -2
  38. package/src/query-parser.ts +0 -94
  39. package/src/swagger/adapter/prisma/index.ts +0 -95
  40. package/src/swagger/json-schema-parser.ts +0 -456
  41. package/src/swagger/parameters.ts +0 -83
  42. package/src/swagger/types.d.ts +0 -53
  43. package/src/swagger/utils/format-example-ref.ts +0 -4
  44. package/src/swagger/utils/format-schema-ref.ts +0 -4
  45. package/src/swagger/utils/get-models-accessible-routes.ts +0 -23
  46. package/src/swagger/utils/get-swagger-paths.ts +0 -244
  47. package/src/swagger/utils/get-swagger-tags.ts +0 -13
  48. package/src/types.d.ts +0 -124
  49. package/src/utils/format-resource-id.ts +0 -3
  50. package/src/utils/get-accessible-routes.ts +0 -18
  51. package/src/utils/get-resource-name-from-url.ts +0 -23
  52. package/src/utils/get-route-type.ts +0 -99
  53. package/src/utils/is-primitive.ts +0 -5
  54. package/src/utils/validate-adapter-methods.ts +0 -15
@@ -1,456 +0,0 @@
1
- import { getJSONSchemaProperty, transformDMMF } from "@visulima/prisma-dmmf-transformer";
2
- import type { JSONSchema7 } from "json-schema";
3
- import type { OpenAPIV3 } from "openapi-types";
4
-
5
- import formatSchemaReference from "./utils/format-schema-ref";
6
-
7
- const getJSONSchemaScalar = (fieldType: string | object) => {
8
- switch (fieldType) {
9
- case "Int":
10
- case "BigInt": {
11
- return "integer";
12
- }
13
- case "DateTime":
14
- case "Bytes":
15
- case "String": {
16
- return "string";
17
- }
18
- case "Float":
19
- case "Decimal": {
20
- return "number";
21
- }
22
- case "Json": {
23
- return "object";
24
- }
25
- case "Boolean": {
26
- return "boolean";
27
- }
28
- case "Null": {
29
- return "null";
30
- }
31
- default: {
32
- return "";
33
- }
34
- }
35
- };
36
-
37
- const PAGINATION_SCHEMA_NAME = "PaginationData";
38
-
39
- const methodsNames = [
40
- { methodStart: "createOne", schemaNameStart: "Create" },
41
- { methodStart: "updateOne", schemaNameStart: "Update" },
42
- ];
43
-
44
- class PrismaJsonSchemaParser {
45
- schemaInputTypes: Map<string, any> = new Map<string, any>();
46
-
47
- constructor(private dmmf: any) {}
48
-
49
- public parseModels(): {
50
- [key: string]: JSONSchema7;
51
- } {
52
- const modelsDefinitions = transformDMMF(this.dmmf).definitions as {
53
- [key: string]: JSONSchema7;
54
- };
55
-
56
- Object.keys(modelsDefinitions || {})?.forEach((definition: string | number) => {
57
- // @TODO: added the correct type
58
- // @ts-ignore
59
- const { properties } = modelsDefinitions[definition];
60
-
61
- Object.keys(properties).forEach((property: string) => {
62
- if (Array.isArray(properties[property].type) && properties[property].type.includes("null")) {
63
- properties[property].type = properties[property].type.filter((type: string) => type !== "null");
64
-
65
- if (properties[property].type.length === 1) {
66
- // eslint-disable-next-line prefer-destructuring
67
- properties[property].type = properties[property].type[0];
68
- }
69
-
70
- properties[property].nullable = true;
71
- }
72
- });
73
- });
74
-
75
- return modelsDefinitions;
76
- }
77
-
78
- // eslint-disable-next-line radar/cognitive-complexity
79
- public parseInputTypes(models: string[]) {
80
- // eslint-disable-next-line radar/cognitive-complexity
81
- const definitions = models.reduce((accumulator: { [key: string]: any }, modelName) => {
82
- const methods = methodsNames.map((method) => {
83
- return {
84
- name: `${method.methodStart}${modelName}`,
85
- schemaName: `${method.schemaNameStart}${modelName}`,
86
- };
87
- });
88
-
89
- methods.forEach(({ name: method, schemaName }) => {
90
- // @ts-ignore
91
- const dataFields = this.dmmf.mutationType.fieldMap[method].args[0].inputTypes[0].type.fields;
92
- const requiredProperties: string[] = [];
93
- const properties = dataFields.reduce((propertiesAccumulator: any, field: any) => {
94
- if (field.inputTypes[0].kind === "scalar") {
95
- const schema = getJSONSchemaProperty(
96
- this.dmmf.datamodel,
97
- {},
98
- )({
99
- name: field.name,
100
- ...field.inputTypes[0],
101
- });
102
-
103
- // @TODO: added the correct type
104
- // @ts-ignore
105
- const { type: schemaType } = schema[1];
106
-
107
- if (schemaType && Array.isArray(schemaType)) {
108
- if (schemaType.includes("null")) {
109
- // eslint-disable-next-line no-param-reassign
110
- propertiesAccumulator[field.name] = {
111
- ...schemaType,
112
- type: schemaType.filter((type: string) => type !== "null"),
113
- nullable: true,
114
- };
115
- if (propertiesAccumulator[field.name].type.length === 1) {
116
- // eslint-disable-next-line no-param-reassign
117
- propertiesAccumulator[field.name] = {
118
- ...propertiesAccumulator[field.name],
119
- type: propertiesAccumulator[field.name].type[0],
120
- };
121
- }
122
- }
123
- } else {
124
- // eslint-disable-next-line no-param-reassign,prefer-destructuring
125
- propertiesAccumulator[field.name] = schema[1];
126
- }
127
- } else {
128
- const typeName = this.parseObjectInputType(field.inputTypes[0]);
129
-
130
- // eslint-disable-next-line no-param-reassign
131
- propertiesAccumulator[field.name] = {
132
- ...typeName,
133
- nullable: field.isNullable,
134
- };
135
- }
136
-
137
- if (field.isRequired) {
138
- requiredProperties.push(field.name);
139
- }
140
-
141
- return propertiesAccumulator;
142
- }, {});
143
-
144
- accumulator[schemaName] = {
145
- type: "object",
146
- xml: {
147
- name: schemaName,
148
- },
149
- properties,
150
- };
151
-
152
- if (requiredProperties.length > 0) {
153
- accumulator[schemaName].required = requiredProperties;
154
- }
155
- });
156
-
157
- return accumulator;
158
- }, {});
159
-
160
- this.schemaInputTypes.forEach((value, key) => {
161
- definitions[key] = {
162
- type: "object",
163
- xml: {
164
- name: key,
165
- },
166
- properties: value,
167
- };
168
- });
169
-
170
- return definitions;
171
- }
172
-
173
- // eslint-disable-next-line class-methods-use-this
174
- public formatInputTypeData(inputType: any) {
175
- if (inputType.kind === "object") {
176
- const reference = formatSchemaReference(inputType.type.name);
177
-
178
- if (inputType.isList) {
179
- return {
180
- type: "array",
181
- xml: {
182
- name: inputType.type.name,
183
- wrapped: true,
184
- },
185
- items: {
186
- $ref: reference,
187
- },
188
- };
189
- }
190
-
191
- return { $ref: reference };
192
- }
193
-
194
- const type = getJSONSchemaScalar(inputType.type);
195
-
196
- if (inputType.isList) {
197
- return {
198
- type: "array",
199
- xml: {
200
- name: inputType.type.name,
201
- wrapped: true,
202
- },
203
- items: {
204
- type,
205
- },
206
- };
207
- }
208
-
209
- return { type };
210
- }
211
-
212
- // eslint-disable-next-line radar/cognitive-complexity
213
- public parseObjectInputType(fieldType: any) {
214
- if (fieldType.kind === "object") {
215
- if (!this.schemaInputTypes.has(fieldType.type.name)) {
216
- this.schemaInputTypes.set(fieldType.type.name, {});
217
-
218
- fieldType.type.fields.forEach((field: any) => {
219
- let fieldData: Record<string, any> = {};
220
-
221
- if (field.inputTypes.length > 1) {
222
- let nullable = false;
223
-
224
- const anyOf = field.inputTypes
225
- .map((inputType: any) => {
226
- const inputTypeData = this.formatInputTypeData(inputType);
227
-
228
- if (inputTypeData.type === "null") {
229
- nullable = true;
230
-
231
- return;
232
- }
233
-
234
- // eslint-disable-next-line consistent-return
235
- return inputTypeData;
236
- })
237
- .filter(Boolean);
238
-
239
- if (anyOf.length === 1) {
240
- // eslint-disable-next-line prefer-destructuring
241
- fieldData = anyOf[0];
242
- } else {
243
- fieldData.anyOf = anyOf;
244
- }
245
-
246
- if (nullable) {
247
- fieldData.nullable = true;
248
- }
249
- } else {
250
- const inputType = field.inputTypes[0];
251
-
252
- fieldData = this.formatInputTypeData(inputType);
253
- }
254
-
255
- this.schemaInputTypes.set(fieldType.type.name, {
256
- ...this.schemaInputTypes.get(fieldType.type.name),
257
- [field.name]: fieldData,
258
- });
259
-
260
- field.inputTypes.forEach((inputType: any) => {
261
- if (inputType.kind === "object") {
262
- this.parseObjectInputType(inputType);
263
- }
264
- });
265
- });
266
- }
267
-
268
- return { $ref: formatSchemaReference(fieldType.type.name) };
269
- }
270
-
271
- return { type: getJSONSchemaScalar(fieldType.type) };
272
- }
273
-
274
- // eslint-disable-next-line class-methods-use-this
275
- public getPaginationDataSchema() {
276
- return {
277
- [PAGINATION_SCHEMA_NAME]: {
278
- type: "object",
279
- xml: {
280
- name: PAGINATION_SCHEMA_NAME,
281
- },
282
- properties: {
283
- total: {
284
- type: "integer",
285
- minimum: 0,
286
- description: "Holds the value for the total number of rows in the database",
287
- },
288
- perPage: {
289
- type: "integer",
290
- minimum: 0,
291
- description: "Returns the value for the limit passed to the paginate method",
292
- },
293
- page: {
294
- type: "integer",
295
- minimum: 1,
296
- description: "Current page number",
297
- },
298
- lastPage: {
299
- type: "integer",
300
- minimum: 0,
301
- description: "Returns the value for the last page by taking the total of rows into account",
302
- },
303
- firstPage: {
304
- type: "integer",
305
- minimum: 0,
306
- description: "Returns the number for the first page. It is always 1",
307
- },
308
- firstPageUrl: {
309
- type: "string",
310
- description: "The URL for the first page",
311
- },
312
- lastPageUrl: {
313
- type: "string",
314
- description: "The URL for the last page",
315
- },
316
- nextPageUrl: {
317
- type: "string",
318
- description: "The URL for the next page",
319
- },
320
- previousPageUrl: {
321
- type: "string",
322
- description: "The URL for the previous page",
323
- },
324
- },
325
- },
326
- };
327
- }
328
-
329
- public getExampleModelsSchemas(
330
- modelNames: string[],
331
- schemas: {
332
- [key: string]: OpenAPIV3.SchemaObject;
333
- },
334
- ) {
335
- const referenceToSchema = (reference: string) => {
336
- const name = reference.replace("#/components/schemas/", "");
337
- const model = schemas[name] as OpenAPIV3.SchemaObject;
338
-
339
- const values: { [key: string]: string | object[] } = {};
340
-
341
- Object.entries((model?.properties as OpenAPIV3.SchemaObject) || {}).forEach(([key, v]) => {
342
- const type = (v as OpenAPIV3.SchemaObject).type as string;
343
-
344
- if (type === "array") {
345
- // eslint-disable-next-line @typescript-eslint/no-use-before-define
346
- values[key] = [arrayItemsToSchema(v.items)];
347
- } else {
348
- values[key] = type;
349
- }
350
- });
351
-
352
- return values;
353
- };
354
-
355
- const objectPropertiesToSchema = (objectProperties: { [name: string]: OpenAPIV3.ReferenceObject | OpenAPIV3.SchemaObject }) => {
356
- const values: { [key: string]: string | object | object[] } = {};
357
-
358
- Object.entries(objectProperties).forEach(([key, value]) => {
359
- if (typeof (value as OpenAPIV3.ReferenceObject).$ref !== "undefined") {
360
- values[key] = referenceToSchema((value as OpenAPIV3.ReferenceObject).$ref);
361
- } else {
362
- values[key] = (value as OpenAPIV3.SchemaObject).type as string;
363
- }
364
- });
365
-
366
- return values;
367
- };
368
-
369
- const arrayItemsToSchema = (items: OpenAPIV3.ArraySchemaObject) => {
370
- const values: { [key: string]: object | object[] } = {};
371
-
372
- Object.entries(items).forEach(([key, value]) => {
373
- if (typeof value.items.$ref !== "undefined") {
374
- values[key] = [referenceToSchema(value.items.$ref)];
375
- } else if (value.type === "array") {
376
- values[key] = [arrayItemsToSchema(value.items)];
377
- } else if (value.type === "object") {
378
- values[key] = objectPropertiesToSchema(value.properties);
379
- } else {
380
- values[key] = value.type;
381
- }
382
- });
383
-
384
- return values;
385
- };
386
-
387
- return modelNames.reduce((accumulator, modelName) => {
388
- const value: { [key: string]: string | object | object[] } = {};
389
- const model = schemas[modelName] as OpenAPIV3.SchemaObject;
390
-
391
- Object.entries(model.properties as OpenAPIV3.SchemaObject).forEach(([key, v]) => {
392
- const type = (v as OpenAPIV3.SchemaObject).type as string;
393
-
394
- if (type === "array") {
395
- value[key] = [referenceToSchema(v.items.$ref)];
396
- } else if (type === "object") {
397
- value[key] = objectPropertiesToSchema(v.properties);
398
- } else {
399
- value[key] = type;
400
- }
401
- });
402
-
403
- const pagination = this.getPaginationDataSchema()[PAGINATION_SCHEMA_NAME];
404
- const meta: { [key: string]: string } = {};
405
-
406
- Object.entries(pagination.properties as OpenAPIV3.SchemaObject).forEach(([key, v]) => {
407
- meta[key] = (v as OpenAPIV3.SchemaObject).type as string;
408
- });
409
-
410
- return {
411
- ...accumulator,
412
- [`${modelName}`]: {
413
- value,
414
- },
415
- [`${modelName}Page`]: {
416
- value: {
417
- data: [value],
418
- meta,
419
- },
420
- },
421
- };
422
- }, {});
423
- }
424
-
425
- // eslint-disable-next-line class-methods-use-this
426
- public getPaginatedModelsSchemas(modelNames: string[]) {
427
- return modelNames.reduce((accumulator, modelName) => {
428
- return {
429
- ...accumulator,
430
- [`${modelName}Page`]: {
431
- type: "object",
432
- xml: {
433
- name: `${modelName}Page`,
434
- },
435
- properties: {
436
- data: {
437
- type: "array",
438
- xml: {
439
- name: "Data",
440
- wrapped: true,
441
- },
442
- items: {
443
- $ref: formatSchemaReference(modelName),
444
- },
445
- },
446
- meta: {
447
- $ref: formatSchemaReference(PAGINATION_SCHEMA_NAME),
448
- },
449
- },
450
- },
451
- };
452
- }, {});
453
- }
454
- }
455
-
456
- export default PrismaJsonSchemaParser;
@@ -1,83 +0,0 @@
1
- import { RouteType } from "../types.d";
2
- import type { SwaggerParameter } from "./types.d";
3
-
4
- const queryParameters: Record<string, SwaggerParameter> = {
5
- select: {
6
- name: "select",
7
- description: "Fields to select. For nested fields, chain them separated with a dot, eg: user.posts",
8
- schema: {
9
- type: "string",
10
- },
11
- },
12
- include: {
13
- name: "include",
14
- description: "Include relations, same as select",
15
- schema: {
16
- type: "string",
17
- },
18
- },
19
- where: {
20
- name: "where",
21
- description: 'Fields to filter. See <a href="https://next-crud.js.org/query-params#where">the docs</a>',
22
- schema: {
23
- type: "string",
24
- },
25
- },
26
- orderBy: {
27
- name: "orderBy",
28
- description: 'Field on which to order by a direction. See <a href="https://next-crud.js.org/query-params#orderBy">the docs</a>',
29
- schema: {
30
- type: "string",
31
- },
32
- },
33
- limit: {
34
- name: "limit",
35
- description: "Maximum number of elements to retrieve",
36
- schema: {
37
- type: "integer",
38
- minimum: 0,
39
- },
40
- },
41
- skip: {
42
- name: "skip",
43
- description: "Number of rows to skip",
44
- schema: {
45
- type: "integer",
46
- minimum: 0,
47
- },
48
- },
49
- distinct: {
50
- name: "distinct",
51
- description: "Fields to distinctively retrieve",
52
- schema: {
53
- type: "string",
54
- },
55
- },
56
- page: {
57
- name: "page",
58
- description: "Page number. Use only for pagination.",
59
- schema: {
60
- type: "integer",
61
- minimum: 1,
62
- },
63
- },
64
- };
65
-
66
- export const commonQueryParameters = [queryParameters.select, queryParameters.include];
67
- export const listQueryParameters = [
68
- ...commonQueryParameters,
69
- queryParameters.limit,
70
- queryParameters.skip,
71
- queryParameters.where,
72
- queryParameters.orderBy,
73
- queryParameters.page,
74
- queryParameters.distinct,
75
- ];
76
-
77
- export const getQueryParameters = (routeType: RouteType, additionalQueryParameters: SwaggerParameter[] = []) => {
78
- if (routeType === RouteType.READ_ALL) {
79
- return [...listQueryParameters, ...additionalQueryParameters];
80
- }
81
-
82
- return [...commonQueryParameters, ...additionalQueryParameters];
83
- };
@@ -1,53 +0,0 @@
1
- import { RouteType } from "../types.d";
2
-
3
- export type SwaggerType = {
4
- name: string;
5
- isArray?: boolean;
6
- description?: string;
7
- required?: boolean;
8
- };
9
-
10
- export type SwaggerOperation = {
11
- summary?: string;
12
- responses?: Record<number, any>;
13
- body?: SwaggerType;
14
- response: SwaggerType;
15
- };
16
-
17
- export type SwaggerTag = {
18
- name?: string;
19
- description?: string;
20
- externalDocs?: {
21
- description: string;
22
- url: string;
23
- };
24
- };
25
-
26
- export type SwaggerParameter = {
27
- name: string;
28
- description?: string;
29
- schema: {
30
- type: string;
31
- } & any;
32
- };
33
-
34
- export type ModelsConfig = {
35
- tag: SwaggerTag;
36
- type?: SwaggerType;
37
- routeTypes?: {
38
- [RouteType.READ_ALL]?: SwaggerOperation;
39
- [RouteType.READ_ONE]?: SwaggerOperation;
40
- [RouteType.CREATE]?: SwaggerOperation;
41
- [RouteType.UPDATE]?: SwaggerOperation;
42
- [RouteType.DELETE]?: SwaggerOperation;
43
- };
44
- additionalQueryParams?: SwaggerParameter[];
45
- };
46
-
47
- export type SwaggerModelsConfig<M extends string> = {
48
- [key in M]?: ModelsConfig;
49
- };
50
-
51
- export type Routes<M extends string> = {
52
- [key in M]?: RouteType[];
53
- };
@@ -1,4 +0,0 @@
1
- // eslint-disable-next-line unicorn/prevent-abbreviations
2
- const formatExampleReference = (schemaName: string) => `#/components/examples/${schemaName}`;
3
-
4
- export default formatExampleReference;
@@ -1,4 +0,0 @@
1
- // eslint-disable-next-line unicorn/prevent-abbreviations
2
- const formatSchemaReference = (schemaName: string) => `#/components/schemas/${schemaName}`;
3
-
4
- export default formatSchemaReference;
@@ -1,23 +0,0 @@
1
- import type { ModelOption, ModelsOptions } from "../../types.d";
2
- import getAccessibleRoutes from "../../utils/get-accessible-routes";
3
- import type { Routes } from "../types.d";
4
-
5
- const getModelsAccessibleRoutes = <M extends string>(
6
- modelNames: M[],
7
- models?: ModelsOptions<M>,
8
- defaultExposeStrategy: "all" | "none" = "all",
9
- ): Routes<M> => modelNames.reduce((accumulator, modelName) => {
10
- if (models?.[modelName]) {
11
- return {
12
- ...accumulator,
13
- [modelName]: getAccessibleRoutes((models[modelName] as ModelOption).only, (models[modelName] as ModelOption).exclude, defaultExposeStrategy),
14
- };
15
- }
16
-
17
- return {
18
- ...accumulator,
19
- [modelName]: getAccessibleRoutes(undefined, undefined, defaultExposeStrategy),
20
- };
21
- }, {});
22
-
23
- export default getModelsAccessibleRoutes;