@rvoh/psychic 1.6.1 → 1.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,16 +9,16 @@ const FailedToLookupSerializerForEndpoint_js_1 = __importDefault(require("../err
9
9
  const NonSerializerDerivedInOpenapiEndpointRenderer_js_1 = __importDefault(require("../error/openapi/NonSerializerDerivedInOpenapiEndpointRenderer.js"));
10
10
  const NonSerializerDerivedInToSchemaObjects_js_1 = __importDefault(require("../error/openapi/NonSerializerDerivedInToSchemaObjects.js"));
11
11
  const SerializerForEndpointNotAFunction_js_1 = __importDefault(require("../error/openapi/SerializerForEndpointNotAFunction.js"));
12
+ const index_js_1 = __importDefault(require("../psychic-app/index.js"));
13
+ const paramNamesForDreamClass_js_1 = __importDefault(require("../server/helpers/paramNamesForDreamClass.js"));
12
14
  const body_segment_js_1 = __importDefault(require("./body-segment.js"));
13
15
  const defaults_js_1 = require("./defaults.js");
14
- const dreamColumnToOpenapiType_js_1 = __importDefault(require("./helpers/dreamColumnToOpenapiType.js"));
16
+ const dreamAttributeOpenapiShape_js_1 = require("./helpers/dreamAttributeOpenapiShape.js");
15
17
  const openapiOpts_js_1 = __importDefault(require("./helpers/openapiOpts.js"));
16
18
  const openapiRoute_js_1 = __importDefault(require("./helpers/openapiRoute.js"));
17
19
  const pageParamOpenapiProperty_js_1 = __importDefault(require("./helpers/pageParamOpenapiProperty.js"));
18
20
  const safelyAttachPaginationParamsToBodySegment_js_1 = __importDefault(require("./helpers/safelyAttachPaginationParamsToBodySegment.js"));
19
21
  const SerializerOpenapiRenderer_js_1 = __importDefault(require("./SerializerOpenapiRenderer.js"));
20
- const paramNamesForDreamClass_js_1 = __importDefault(require("../server/helpers/paramNamesForDreamClass.js"));
21
- const index_js_1 = __importDefault(require("../psychic-app/index.js"));
22
22
  class OpenapiEndpointRenderer {
23
23
  dreamsOrSerializers;
24
24
  controllerClass;
@@ -505,12 +505,12 @@ class OpenapiEndpointRenderer {
505
505
  if (required) {
506
506
  paramsShape.required = required;
507
507
  }
508
- for (const columnName of paramSafeColumns) {
509
- paramsShape.properties = {
510
- ...paramsShape.properties,
511
- ...(0, dreamColumnToOpenapiType_js_1.default)(dreamClass, columnName),
512
- };
513
- }
508
+ paramsShape.properties = paramSafeColumns.reduce((acc, columnName) => {
509
+ acc[columnName] = (0, dreamAttributeOpenapiShape_js_1.dreamColumnOpenapiShape)(dreamClass, columnName, undefined, {
510
+ allowGenericJson: true,
511
+ });
512
+ return acc;
513
+ }, paramsShape.properties);
514
514
  let processedSchema = new body_segment_js_1.default(paramsShape, {
515
515
  renderOpts,
516
516
  target: 'request',
@@ -5,8 +5,34 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.UseCustomOpenapiForJson = exports.UseCustomOpenapiForVirtualAttributes = void 0;
7
7
  exports.dreamColumnOpenapiShape = dreamColumnOpenapiShape;
8
+ const body_segment_js_1 = __importDefault(require("../body-segment.js"));
8
9
  const openapiShorthandToOpenapi_js_1 = __importDefault(require("./openapiShorthandToOpenapi.js"));
9
- function dreamColumnOpenapiShape(dreamClass, column, openapi = undefined, { suppressResponseEnums = false } = {}) {
10
+ function dreamColumnOpenapiShape(dreamClass, column, openapi = undefined, { suppressResponseEnums = false, allowGenericJson = false, } = {}) {
11
+ if (dreamClass.isVirtualColumn(column)) {
12
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any
13
+ const openapiObject = (0, openapiShorthandToOpenapi_js_1.default)((openapi ?? {}));
14
+ const metadata = dreamClass['virtualAttributes'].find(statement => statement.property === column);
15
+ if (metadata?.type) {
16
+ return {
17
+ ...new body_segment_js_1.default(metadata.type, {
18
+ renderOpts: {
19
+ casing: 'camel',
20
+ suppressResponseEnums: false,
21
+ },
22
+ target: 'request',
23
+ }).render().openapi,
24
+ ...openapiObject,
25
+ };
26
+ }
27
+ else if (openapi) {
28
+ return openapiObject;
29
+ }
30
+ else {
31
+ return {
32
+ anyOf: [{ type: ['string', 'null'] }, { type: ['number', 'null'] }, { type: ['object', 'null'] }],
33
+ };
34
+ }
35
+ }
10
36
  const dream = dreamClass.prototype;
11
37
  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment
12
38
  const dreamColumnInfo = dream.schema[dream.table]?.columns[column];
@@ -16,13 +42,15 @@ function dreamColumnOpenapiShape(dreamClass, column, openapi = undefined, { supp
16
42
  return (0, openapiShorthandToOpenapi_js_1.default)(openapi);
17
43
  throw new UseCustomOpenapiForVirtualAttributes(dreamClass, column);
18
44
  }
19
- switch (baseDbType(dreamColumnInfo)) {
20
- case 'json':
21
- case 'jsonb':
22
- // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any
23
- if (openapi)
24
- return (0, openapiShorthandToOpenapi_js_1.default)(openapi);
25
- throw new UseCustomOpenapiForJson(dreamClass, column);
45
+ if (!allowGenericJson) {
46
+ switch (baseDbType(dreamColumnInfo)) {
47
+ case 'json':
48
+ case 'jsonb':
49
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any
50
+ if (openapi)
51
+ return (0, openapiShorthandToOpenapi_js_1.default)(openapi);
52
+ throw new UseCustomOpenapiForJson(dreamClass, column);
53
+ }
26
54
  }
27
55
  // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any
28
56
  const openapiObject = (0, openapiShorthandToOpenapi_js_1.default)((openapi ?? {}));
@@ -35,10 +63,12 @@ function dreamColumnOpenapiShape(dreamClass, column, openapi = undefined, { supp
35
63
  };
36
64
  }
37
65
  else {
38
- const existingType = singleType.type;
66
+ const existingType = dreamColumnInfo.allowNull
67
+ ? [singleType.type, 'null']
68
+ : singleType.type;
39
69
  return {
40
70
  ...singleType,
41
- type: dreamColumnInfo.allowNull && !Array.isArray(existingType) ? [existingType, 'null'] : existingType,
71
+ type: existingType,
42
72
  ...openapiObject,
43
73
  };
44
74
  }
@@ -55,13 +85,18 @@ function singularAttributeOpenapiShape(dreamColumnInfo, suppressResponseEnums) {
55
85
  };
56
86
  }
57
87
  else {
58
- return { type: 'string', enum: dreamColumnInfo.enumValues };
88
+ return {
89
+ type: 'string',
90
+ enum: [
91
+ ...dreamColumnInfo.enumValues,
92
+ ...(dreamColumnInfo.allowNull && !dreamColumnInfo.isArray ? [null] : []),
93
+ ],
94
+ };
59
95
  }
60
96
  }
61
97
  switch (baseDbType(dreamColumnInfo)) {
62
98
  case 'boolean':
63
99
  return { type: 'boolean' };
64
- case 'bigint':
65
100
  case 'bigserial':
66
101
  case 'bytea':
67
102
  case 'char':
@@ -84,6 +119,8 @@ function singularAttributeOpenapiShape(dreamColumnInfo, suppressResponseEnums) {
84
119
  case 'smallint':
85
120
  case 'smallserial':
86
121
  return { type: 'integer' };
122
+ case 'bigint':
123
+ return { type: 'string', format: 'bigint' };
87
124
  case 'numeric':
88
125
  case 'decimal':
89
126
  return { type: 'number', format: 'decimal' };
@@ -99,6 +136,9 @@ function singularAttributeOpenapiShape(dreamColumnInfo, suppressResponseEnums) {
99
136
  return { type: 'string', format: 'date-time' };
100
137
  case 'date':
101
138
  return { type: 'string', format: 'date' };
139
+ case 'json':
140
+ case 'jsonb':
141
+ return { type: 'object' };
102
142
  default:
103
143
  throw new Error(`Unrecognized dbType used in serializer OpenAPI type declaration: ${dreamColumnInfo.dbType}`);
104
144
  }
@@ -65,7 +65,7 @@ function simpleOpenapiShorthandToOpenapi(shorthand, options) {
65
65
  case 'integer[]':
66
66
  return { type: 'array', items: { type: 'integer' } };
67
67
  case 'json':
68
- return { type: 'json' };
68
+ return { type: 'object' };
69
69
  default: {
70
70
  // protection so that if a new OpenapiShorthandPrimitiveBaseTypes is ever added, this will throw a type error at build time
71
71
  const _never = shorthand;
@@ -3,16 +3,16 @@ import OpenApiFailedToLookupSerializerForEndpoint from '../error/openapi/FailedT
3
3
  import NonSerializerDerivedInOpenapiEndpointRenderer from '../error/openapi/NonSerializerDerivedInOpenapiEndpointRenderer.js';
4
4
  import NonSerializerDerivedInToSchemaObjects from '../error/openapi/NonSerializerDerivedInToSchemaObjects.js';
5
5
  import OpenApiSerializerForEndpointNotAFunction from '../error/openapi/SerializerForEndpointNotAFunction.js';
6
+ import PsychicApp from '../psychic-app/index.js';
7
+ import paramNamesForDreamClass from '../server/helpers/paramNamesForDreamClass.js';
6
8
  import OpenapiSegmentExpander from './body-segment.js';
7
9
  import { DEFAULT_OPENAPI_RESPONSES } from './defaults.js';
8
- import dreamColumnToOpenapiType from './helpers/dreamColumnToOpenapiType.js';
10
+ import { dreamColumnOpenapiShape } from './helpers/dreamAttributeOpenapiShape.js';
9
11
  import openapiOpts from './helpers/openapiOpts.js';
10
12
  import openapiRoute from './helpers/openapiRoute.js';
11
13
  import openapiPageParamProperty from './helpers/pageParamOpenapiProperty.js';
12
14
  import safelyAttachPaginationParamToRequestBodySegment from './helpers/safelyAttachPaginationParamsToBodySegment.js';
13
15
  import SerializerOpenapiRenderer from './SerializerOpenapiRenderer.js';
14
- import paramNamesForDreamClass from '../server/helpers/paramNamesForDreamClass.js';
15
- import PsychicApp from '../psychic-app/index.js';
16
16
  export default class OpenapiEndpointRenderer {
17
17
  dreamsOrSerializers;
18
18
  controllerClass;
@@ -499,12 +499,12 @@ export default class OpenapiEndpointRenderer {
499
499
  if (required) {
500
500
  paramsShape.required = required;
501
501
  }
502
- for (const columnName of paramSafeColumns) {
503
- paramsShape.properties = {
504
- ...paramsShape.properties,
505
- ...dreamColumnToOpenapiType(dreamClass, columnName),
506
- };
507
- }
502
+ paramsShape.properties = paramSafeColumns.reduce((acc, columnName) => {
503
+ acc[columnName] = dreamColumnOpenapiShape(dreamClass, columnName, undefined, {
504
+ allowGenericJson: true,
505
+ });
506
+ return acc;
507
+ }, paramsShape.properties);
508
508
  let processedSchema = new OpenapiSegmentExpander(paramsShape, {
509
509
  renderOpts,
510
510
  target: 'request',
@@ -1,5 +1,31 @@
1
+ import OpenapiSegmentExpander from '../body-segment.js';
1
2
  import openapiShorthandToOpenapi from './openapiShorthandToOpenapi.js';
2
- export function dreamColumnOpenapiShape(dreamClass, column, openapi = undefined, { suppressResponseEnums = false } = {}) {
3
+ export function dreamColumnOpenapiShape(dreamClass, column, openapi = undefined, { suppressResponseEnums = false, allowGenericJson = false, } = {}) {
4
+ if (dreamClass.isVirtualColumn(column)) {
5
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any
6
+ const openapiObject = openapiShorthandToOpenapi((openapi ?? {}));
7
+ const metadata = dreamClass['virtualAttributes'].find(statement => statement.property === column);
8
+ if (metadata?.type) {
9
+ return {
10
+ ...new OpenapiSegmentExpander(metadata.type, {
11
+ renderOpts: {
12
+ casing: 'camel',
13
+ suppressResponseEnums: false,
14
+ },
15
+ target: 'request',
16
+ }).render().openapi,
17
+ ...openapiObject,
18
+ };
19
+ }
20
+ else if (openapi) {
21
+ return openapiObject;
22
+ }
23
+ else {
24
+ return {
25
+ anyOf: [{ type: ['string', 'null'] }, { type: ['number', 'null'] }, { type: ['object', 'null'] }],
26
+ };
27
+ }
28
+ }
3
29
  const dream = dreamClass.prototype;
4
30
  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment
5
31
  const dreamColumnInfo = dream.schema[dream.table]?.columns[column];
@@ -9,13 +35,15 @@ export function dreamColumnOpenapiShape(dreamClass, column, openapi = undefined,
9
35
  return openapiShorthandToOpenapi(openapi);
10
36
  throw new UseCustomOpenapiForVirtualAttributes(dreamClass, column);
11
37
  }
12
- switch (baseDbType(dreamColumnInfo)) {
13
- case 'json':
14
- case 'jsonb':
15
- // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any
16
- if (openapi)
17
- return openapiShorthandToOpenapi(openapi);
18
- throw new UseCustomOpenapiForJson(dreamClass, column);
38
+ if (!allowGenericJson) {
39
+ switch (baseDbType(dreamColumnInfo)) {
40
+ case 'json':
41
+ case 'jsonb':
42
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any
43
+ if (openapi)
44
+ return openapiShorthandToOpenapi(openapi);
45
+ throw new UseCustomOpenapiForJson(dreamClass, column);
46
+ }
19
47
  }
20
48
  // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any
21
49
  const openapiObject = openapiShorthandToOpenapi((openapi ?? {}));
@@ -28,10 +56,12 @@ export function dreamColumnOpenapiShape(dreamClass, column, openapi = undefined,
28
56
  };
29
57
  }
30
58
  else {
31
- const existingType = singleType.type;
59
+ const existingType = dreamColumnInfo.allowNull
60
+ ? [singleType.type, 'null']
61
+ : singleType.type;
32
62
  return {
33
63
  ...singleType,
34
- type: dreamColumnInfo.allowNull && !Array.isArray(existingType) ? [existingType, 'null'] : existingType,
64
+ type: existingType,
35
65
  ...openapiObject,
36
66
  };
37
67
  }
@@ -48,13 +78,18 @@ function singularAttributeOpenapiShape(dreamColumnInfo, suppressResponseEnums) {
48
78
  };
49
79
  }
50
80
  else {
51
- return { type: 'string', enum: dreamColumnInfo.enumValues };
81
+ return {
82
+ type: 'string',
83
+ enum: [
84
+ ...dreamColumnInfo.enumValues,
85
+ ...(dreamColumnInfo.allowNull && !dreamColumnInfo.isArray ? [null] : []),
86
+ ],
87
+ };
52
88
  }
53
89
  }
54
90
  switch (baseDbType(dreamColumnInfo)) {
55
91
  case 'boolean':
56
92
  return { type: 'boolean' };
57
- case 'bigint':
58
93
  case 'bigserial':
59
94
  case 'bytea':
60
95
  case 'char':
@@ -77,6 +112,8 @@ function singularAttributeOpenapiShape(dreamColumnInfo, suppressResponseEnums) {
77
112
  case 'smallint':
78
113
  case 'smallserial':
79
114
  return { type: 'integer' };
115
+ case 'bigint':
116
+ return { type: 'string', format: 'bigint' };
80
117
  case 'numeric':
81
118
  case 'decimal':
82
119
  return { type: 'number', format: 'decimal' };
@@ -92,6 +129,9 @@ function singularAttributeOpenapiShape(dreamColumnInfo, suppressResponseEnums) {
92
129
  return { type: 'string', format: 'date-time' };
93
130
  case 'date':
94
131
  return { type: 'string', format: 'date' };
132
+ case 'json':
133
+ case 'jsonb':
134
+ return { type: 'object' };
95
135
  default:
96
136
  throw new Error(`Unrecognized dbType used in serializer OpenAPI type declaration: ${dreamColumnInfo.dbType}`);
97
137
  }
@@ -58,7 +58,7 @@ function simpleOpenapiShorthandToOpenapi(shorthand, options) {
58
58
  case 'integer[]':
59
59
  return { type: 'array', items: { type: 'integer' } };
60
60
  case 'json':
61
- return { type: 'json' };
61
+ return { type: 'object' };
62
62
  default: {
63
63
  // protection so that if a new OpenapiShorthandPrimitiveBaseTypes is ever added, this will throw a type error at build time
64
64
  const _never = shorthand;
@@ -2,10 +2,10 @@ import { Dream, DreamAttributes, DreamOrViewModelClassSerializerKey, DreamParamS
2
2
  import PsychicController from '../controller/index.js';
3
3
  import { HttpStatusCode, HttpStatusCodeNumber } from '../error/http/status-codes.js';
4
4
  import { DreamOrViewModelClassSerializerArrayKeys } from '../helpers/typeHelpers.js';
5
+ import { ValidateOpenapiSchemaOptions } from '../helpers/validateOpenApiSchema.js';
5
6
  import { RouteConfig } from '../router/route-manager.js';
6
7
  import { HttpMethod } from '../router/types.js';
7
8
  import { OpenapiBodySegment, ReferencedSerializersAndOpenapiEndpointResponse, SerializerArray } from './body-segment.js';
8
- import { ValidateOpenapiSchemaOptions } from '../helpers/validateOpenApiSchema.js';
9
9
  export interface OpenapiRenderOpts {
10
10
  casing: SerializerCasing;
11
11
  suppressResponseEnums: boolean;