@rvoh/psychic 0.37.4 → 0.37.6
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/dist/cjs/src/generate/helpers/generateResourceControllerSpecContent.js +37 -21
- package/dist/cjs/src/generate/initializer/syncEnums.js +1 -1
- package/dist/cjs/src/openapi-renderer/endpoint.js +11 -143
- package/dist/cjs/src/openapi-renderer/helpers/dreamColumnToOpenapiType.js +128 -0
- package/dist/cjs/src/server/helpers/paramNamesForDreamClass.js +16 -0
- package/dist/cjs/src/server/params.js +6 -5
- package/dist/cjs/src/watcher/Watcher.js +10 -3
- package/dist/esm/src/generate/helpers/generateResourceControllerSpecContent.js +37 -21
- package/dist/esm/src/generate/initializer/syncEnums.js +1 -1
- package/dist/esm/src/openapi-renderer/endpoint.js +11 -143
- package/dist/esm/src/openapi-renderer/helpers/dreamColumnToOpenapiType.js +122 -0
- package/dist/esm/src/server/helpers/paramNamesForDreamClass.js +13 -0
- package/dist/esm/src/server/params.js +6 -5
- package/dist/esm/src/watcher/Watcher.js +10 -3
- package/dist/types/src/controller/index.d.ts +7 -5
- package/dist/types/src/openapi-renderer/endpoint.d.ts +150 -9
- package/dist/types/src/openapi-renderer/helpers/dreamColumnToOpenapiType.d.ts +2 -0
- package/dist/types/src/server/helpers/paramNamesForDreamClass.d.ts +9 -0
- package/dist/types/src/server/params.d.ts +19 -7
- package/package.json +1 -1
|
@@ -20,6 +20,7 @@ function generateResourceControllerSpecContent({ fullyQualifiedControllerName, r
|
|
|
20
20
|
const importStatements = [
|
|
21
21
|
importStatementForModel(fullyQualifiedControllerName, fullyQualifiedModelName),
|
|
22
22
|
importStatementForModel(fullyQualifiedControllerName, 'User'),
|
|
23
|
+
importStatementForType('openapi/validation.openapi', 'validationOpenapiPaths'),
|
|
23
24
|
importStatementForModelFactory(fullyQualifiedControllerName, fullyQualifiedModelName),
|
|
24
25
|
importStatementForModelFactory(fullyQualifiedControllerName, 'User'),
|
|
25
26
|
];
|
|
@@ -49,12 +50,13 @@ function generateResourceControllerSpecContent({ fullyQualifiedControllerName, r
|
|
|
49
50
|
}
|
|
50
51
|
}
|
|
51
52
|
return `\
|
|
52
|
-
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
53
53
|
import { UpdateableProperties } from '@rvoh/dream'
|
|
54
54
|
import { PsychicServer } from '@rvoh/psychic'
|
|
55
|
-
import {
|
|
55
|
+
import { OpenapiSpecRequest } from '@rvoh/psychic-spec-helpers'${(0, dream_1.uniq)(importStatements).join('')}
|
|
56
56
|
import addEndUserAuthHeader from '${specUnitUpdirs}helpers/authentication.js'
|
|
57
57
|
|
|
58
|
+
const request = new OpenapiSpecRequest<validationOpenapiPaths>()
|
|
59
|
+
|
|
58
60
|
describe('${fullyQualifiedControllerName}', () => {
|
|
59
61
|
let ${userVariableName}: ${owningModelClassName}${attachedModelVariableName ? `\n let ${attachedModelVariableName}: ${attachedModelClassName}` : ''}
|
|
60
62
|
|
|
@@ -64,7 +66,7 @@ describe('${fullyQualifiedControllerName}', () => {
|
|
|
64
66
|
})
|
|
65
67
|
|
|
66
68
|
describe('GET index', () => {
|
|
67
|
-
const subject = async (expectedStatus:
|
|
69
|
+
const subject = async <StatusCode extends 200 | 400>(expectedStatus: StatusCode) => {
|
|
68
70
|
return request.get('/${route}', expectedStatus, {
|
|
69
71
|
headers: await addEndUserAuthHeader(request, ${userVariableName}, {}),
|
|
70
72
|
})
|
|
@@ -74,9 +76,9 @@ describe('${fullyQualifiedControllerName}', () => {
|
|
|
74
76
|
const ${modelVariableName} = await create${modelClassName}({
|
|
75
77
|
${attachedModelVariableName || userVariableName}${originalStringKeyValues.length ? ',\n ' + originalStringKeyValues.join('\n ') : ''}
|
|
76
78
|
})
|
|
77
|
-
const
|
|
79
|
+
const { body } = await subject(200)
|
|
78
80
|
|
|
79
|
-
expect(
|
|
81
|
+
expect(body).toEqual([
|
|
80
82
|
expect.objectContaining({
|
|
81
83
|
id: ${modelVariableName}.id,
|
|
82
84
|
}),
|
|
@@ -86,16 +88,17 @@ describe('${fullyQualifiedControllerName}', () => {
|
|
|
86
88
|
context('${modelClassName}s created by another ${owningModelClassName}', () => {
|
|
87
89
|
it('are omitted', async () => {
|
|
88
90
|
await create${modelClassName}()
|
|
89
|
-
const
|
|
91
|
+
const { body } = await subject(200)
|
|
90
92
|
|
|
91
|
-
expect(
|
|
93
|
+
expect(body).toEqual([])
|
|
92
94
|
})
|
|
93
95
|
})
|
|
94
96
|
})
|
|
95
97
|
|
|
96
98
|
describe('GET show', () => {
|
|
97
|
-
const subject = async (${modelVariableName}: ${modelClassName}, expectedStatus:
|
|
98
|
-
return request.get(
|
|
99
|
+
const subject = async <StatusCode extends 200 | 400 | 404>(${modelVariableName}: ${modelClassName}, expectedStatus: StatusCode) => {
|
|
100
|
+
return request.get('/${route}/{id}', expectedStatus, {
|
|
101
|
+
id: ${modelVariableName}.id,
|
|
99
102
|
headers: await addEndUserAuthHeader(request, ${userVariableName}, {}),
|
|
100
103
|
})
|
|
101
104
|
}
|
|
@@ -104,9 +107,9 @@ describe('${fullyQualifiedControllerName}', () => {
|
|
|
104
107
|
const ${modelVariableName} = await create${modelClassName}({
|
|
105
108
|
${attachedModelVariableName || userVariableName}${originalStringKeyValues.length ? ',\n ' + originalStringKeyValues.join('\n ') : ''}
|
|
106
109
|
})
|
|
107
|
-
const
|
|
110
|
+
const { body } = await subject(${modelVariableName}, 200)
|
|
108
111
|
|
|
109
|
-
expect(
|
|
112
|
+
expect(body).toEqual(
|
|
110
113
|
expect.objectContaining({
|
|
111
114
|
id: ${modelVariableName}.id,${originalStringKeyValues.length ? '\n ' + originalStringKeyValues.join('\n ') : ''}
|
|
112
115
|
}),
|
|
@@ -122,7 +125,10 @@ describe('${fullyQualifiedControllerName}', () => {
|
|
|
122
125
|
})
|
|
123
126
|
|
|
124
127
|
describe('POST create', () => {
|
|
125
|
-
const subject = async
|
|
128
|
+
const subject = async <StatusCode extends 201 | 400>(
|
|
129
|
+
data: UpdateableProperties<${modelClassName}>,
|
|
130
|
+
expectedStatus: StatusCode
|
|
131
|
+
) => {
|
|
126
132
|
return request.post('/${route}', expectedStatus, {
|
|
127
133
|
data,
|
|
128
134
|
headers: await addEndUserAuthHeader(request, ${userVariableName}, {}),
|
|
@@ -130,12 +136,12 @@ describe('${fullyQualifiedControllerName}', () => {
|
|
|
130
136
|
}
|
|
131
137
|
|
|
132
138
|
it('creates a ${fullyQualifiedModelName} for this ${owningModelClassName}', async () => {
|
|
133
|
-
const
|
|
139
|
+
const { body } = await subject({
|
|
134
140
|
${originalStringKeyValues.length ? originalStringKeyValues.join('\n ') : ''}
|
|
135
|
-
})
|
|
141
|
+
}, 201)
|
|
136
142
|
const ${modelVariableName} = await ${modelClassName}.findOrFailBy({ ${userVariableName}Id: ${userVariableName}.id })
|
|
137
143
|
|
|
138
|
-
expect(
|
|
144
|
+
expect(body).toEqual(
|
|
139
145
|
expect.objectContaining({
|
|
140
146
|
id: ${modelVariableName}.id,${originalStringKeyValues.length ? '\n ' + originalStringKeyValues.join('\n ') : ''}
|
|
141
147
|
}),
|
|
@@ -144,8 +150,13 @@ describe('${fullyQualifiedControllerName}', () => {
|
|
|
144
150
|
})
|
|
145
151
|
|
|
146
152
|
describe('PATCH update', () => {
|
|
147
|
-
const subject = async
|
|
148
|
-
|
|
153
|
+
const subject = async <StatusCode extends 204 | 400 | 404>(
|
|
154
|
+
${modelVariableName}: ${modelClassName},
|
|
155
|
+
data: UpdateableProperties<${modelClassName}>,
|
|
156
|
+
expectedStatus: StatusCode
|
|
157
|
+
) => {
|
|
158
|
+
return request.patch('/${route}/{id}', expectedStatus, {
|
|
159
|
+
id: ${modelVariableName}.id,
|
|
149
160
|
data,
|
|
150
161
|
headers: await addEndUserAuthHeader(request, ${userVariableName}, {}),
|
|
151
162
|
})
|
|
@@ -157,7 +168,7 @@ describe('${fullyQualifiedControllerName}', () => {
|
|
|
157
168
|
})
|
|
158
169
|
await subject(${modelVariableName}, {
|
|
159
170
|
${updatedStringKeyValues.length ? updatedStringKeyValues.join('\n ') : ''}
|
|
160
|
-
})
|
|
171
|
+
}, 204)
|
|
161
172
|
|
|
162
173
|
await ${modelVariableName}.reload()
|
|
163
174
|
${updatedStringAttributeChecks.join('\n ')}
|
|
@@ -177,15 +188,16 @@ describe('${fullyQualifiedControllerName}', () => {
|
|
|
177
188
|
})
|
|
178
189
|
|
|
179
190
|
describe('DELETE destroy', () => {
|
|
180
|
-
const subject = async (${modelVariableName}: ${modelClassName}, expectedStatus:
|
|
181
|
-
return request.delete(
|
|
191
|
+
const subject = async <StatusCode extends 204 | 400 | 404>(${modelVariableName}: ${modelClassName}, expectedStatus: StatusCode) => {
|
|
192
|
+
return request.delete('/${route}/{id}', expectedStatus, {
|
|
193
|
+
id: ${modelVariableName}.id,
|
|
182
194
|
headers: await addEndUserAuthHeader(request, ${userVariableName}, {}),
|
|
183
195
|
})
|
|
184
196
|
}
|
|
185
197
|
|
|
186
198
|
it('deletes the ${fullyQualifiedModelName}', async () => {
|
|
187
199
|
const ${modelVariableName} = await create${modelClassName}({ ${attachedModelVariableName || userVariableName} })
|
|
188
|
-
await subject(${modelVariableName})
|
|
200
|
+
await subject(${modelVariableName}, 204)
|
|
189
201
|
|
|
190
202
|
expect(await ${modelClassName}.find(${modelVariableName}.id)).toBeNull()
|
|
191
203
|
})
|
|
@@ -205,6 +217,10 @@ describe('${fullyQualifiedControllerName}', () => {
|
|
|
205
217
|
function importStatementForModel(originModelName, destinationModelName = originModelName) {
|
|
206
218
|
return `\nimport ${(0, dream_1.globalClassNameFromFullyQualifiedModelName)(destinationModelName)} from '${(0, relativePsychicPath_js_1.default)('controllerSpecs', 'models', originModelName, destinationModelName)}'`;
|
|
207
219
|
}
|
|
220
|
+
function importStatementForType(typeFilePath, typeExportName) {
|
|
221
|
+
const importPath = (0, relativePsychicPath_js_1.default)('controllerSpecs', 'types', typeFilePath).toLowerCase();
|
|
222
|
+
return `\nimport { ${typeExportName} } from '${importPath}'`;
|
|
223
|
+
}
|
|
208
224
|
function importStatementForModelFactory(originModelName, destinationModelName = originModelName) {
|
|
209
225
|
return `\nimport create${(0, dream_1.globalClassNameFromFullyQualifiedModelName)(destinationModelName)} from '${(0, relativePsychicPath_js_1.default)('controllerSpecs', 'factories', originModelName, destinationModelName)}'`;
|
|
210
226
|
}
|
|
@@ -55,7 +55,7 @@ import { PsychicApp, PsychicBin } from "@rvoh/psychic"
|
|
|
55
55
|
import AppEnv from '../AppEnv.js'
|
|
56
56
|
|
|
57
57
|
export default function ${camelized}(psy: PsychicApp) {
|
|
58
|
-
psy.on('sync', async () => {
|
|
58
|
+
psy.on('cli:sync', async () => {
|
|
59
59
|
if (AppEnv.isDevelopmentOrTest) {
|
|
60
60
|
DreamCLI.logger.logStartProgress(\`[${camelized}] syncing enums to ${outfile}...\`)
|
|
61
61
|
await PsychicBin.syncClientEnums('${outfile}')
|
|
@@ -11,12 +11,13 @@ const NonSerializerDerivedInToSchemaObjects_js_1 = __importDefault(require("../e
|
|
|
11
11
|
const SerializerForEndpointNotAFunction_js_1 = __importDefault(require("../error/openapi/SerializerForEndpointNotAFunction.js"));
|
|
12
12
|
const body_segment_js_1 = __importDefault(require("./body-segment.js"));
|
|
13
13
|
const defaults_js_1 = require("./defaults.js");
|
|
14
|
+
const dreamColumnToOpenapiType_js_1 = __importDefault(require("./helpers/dreamColumnToOpenapiType.js"));
|
|
14
15
|
const openapiOpts_js_1 = __importDefault(require("./helpers/openapiOpts.js"));
|
|
15
16
|
const openapiRoute_js_1 = __importDefault(require("./helpers/openapiRoute.js"));
|
|
16
17
|
const pageParamOpenapiProperty_js_1 = __importDefault(require("./helpers/pageParamOpenapiProperty.js"));
|
|
17
|
-
const primitiveOpenapiStatementToOpenapi_js_1 = __importDefault(require("./helpers/primitiveOpenapiStatementToOpenapi.js"));
|
|
18
18
|
const safelyAttachPaginationParamsToBodySegment_js_1 = __importDefault(require("./helpers/safelyAttachPaginationParamsToBodySegment.js"));
|
|
19
19
|
const SerializerOpenapiRenderer_js_1 = __importDefault(require("./SerializerOpenapiRenderer.js"));
|
|
20
|
+
const paramNamesForDreamClass_js_1 = __importDefault(require("../server/helpers/paramNamesForDreamClass.js"));
|
|
20
21
|
class OpenapiEndpointRenderer {
|
|
21
22
|
dreamsOrSerializers;
|
|
22
23
|
controllerClass;
|
|
@@ -411,19 +412,14 @@ class OpenapiEndpointRenderer {
|
|
|
411
412
|
* the request body.
|
|
412
413
|
*/
|
|
413
414
|
generateRequestBodyForModel({ renderOpts, }) {
|
|
414
|
-
const forDreamClass = this.requestBody
|
|
415
|
+
const forDreamClass = this.requestBody
|
|
416
|
+
?.for;
|
|
415
417
|
const dreamClass = forDreamClass || this.getSingleDreamModelClass();
|
|
416
418
|
if (!dreamClass)
|
|
417
419
|
return this.defaultRequestBody();
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
paramSafeColumns = paramSafeColumns.filter(column => only.includes(column));
|
|
422
|
-
}
|
|
423
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
424
|
-
const schema = dreamClass.prototype.schema;
|
|
425
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
426
|
-
const columns = schema[dreamClass.prototype.table]?.columns;
|
|
420
|
+
const { only, including } = (this.requestBody || {});
|
|
421
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
422
|
+
const paramSafeColumns = (0, paramNamesForDreamClass_js_1.default)(dreamClass, { only, including });
|
|
427
423
|
const paramsShape = {
|
|
428
424
|
type: 'object',
|
|
429
425
|
properties: {},
|
|
@@ -433,138 +429,10 @@ class OpenapiEndpointRenderer {
|
|
|
433
429
|
paramsShape.required = required;
|
|
434
430
|
}
|
|
435
431
|
for (const columnName of paramSafeColumns) {
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
case 'boolean[]':
|
|
441
|
-
case 'date':
|
|
442
|
-
case 'date[]':
|
|
443
|
-
case 'integer':
|
|
444
|
-
case 'integer[]':
|
|
445
|
-
paramsShape.properties = {
|
|
446
|
-
...paramsShape.properties,
|
|
447
|
-
[columnName]: (0, primitiveOpenapiStatementToOpenapi_js_1.default)(columnMetadata.dbType, nullableColumn),
|
|
448
|
-
};
|
|
449
|
-
break;
|
|
450
|
-
case 'character varying':
|
|
451
|
-
case 'citext':
|
|
452
|
-
case 'text':
|
|
453
|
-
case 'uuid':
|
|
454
|
-
case 'bigint':
|
|
455
|
-
paramsShape.properties = {
|
|
456
|
-
...paramsShape.properties,
|
|
457
|
-
[columnName]: (0, primitiveOpenapiStatementToOpenapi_js_1.default)('string', nullableColumn),
|
|
458
|
-
};
|
|
459
|
-
break;
|
|
460
|
-
case 'character varying[]':
|
|
461
|
-
case 'citext[]':
|
|
462
|
-
case 'text[]':
|
|
463
|
-
case 'uuid[]':
|
|
464
|
-
case 'bigint[]':
|
|
465
|
-
paramsShape.properties = {
|
|
466
|
-
...paramsShape.properties,
|
|
467
|
-
[columnName]: (0, primitiveOpenapiStatementToOpenapi_js_1.default)('string[]', nullableColumn),
|
|
468
|
-
};
|
|
469
|
-
break;
|
|
470
|
-
case 'timestamp':
|
|
471
|
-
case 'timestamp with time zone':
|
|
472
|
-
case 'timestamp without time zone':
|
|
473
|
-
paramsShape.properties = {
|
|
474
|
-
...paramsShape.properties,
|
|
475
|
-
[columnName]: (0, primitiveOpenapiStatementToOpenapi_js_1.default)('date-time', nullableColumn),
|
|
476
|
-
};
|
|
477
|
-
break;
|
|
478
|
-
case 'timestamp[]':
|
|
479
|
-
case 'timestamp with time zone[]':
|
|
480
|
-
case 'timestamp without time zone[]':
|
|
481
|
-
paramsShape.properties = {
|
|
482
|
-
...paramsShape.properties,
|
|
483
|
-
[columnName]: (0, primitiveOpenapiStatementToOpenapi_js_1.default)('date-time[]', nullableColumn),
|
|
484
|
-
};
|
|
485
|
-
break;
|
|
486
|
-
case 'json':
|
|
487
|
-
case 'jsonb':
|
|
488
|
-
paramsShape.properties = {
|
|
489
|
-
...paramsShape.properties,
|
|
490
|
-
[columnName]: {
|
|
491
|
-
type: nullableColumn ? ['object', 'null'] : 'object',
|
|
492
|
-
},
|
|
493
|
-
};
|
|
494
|
-
break;
|
|
495
|
-
case 'json[]':
|
|
496
|
-
case 'jsonb[]':
|
|
497
|
-
paramsShape.properties = {
|
|
498
|
-
...paramsShape.properties,
|
|
499
|
-
[columnName]: {
|
|
500
|
-
type: nullableColumn ? ['array', 'null'] : 'array',
|
|
501
|
-
items: {
|
|
502
|
-
type: 'object',
|
|
503
|
-
},
|
|
504
|
-
},
|
|
505
|
-
};
|
|
506
|
-
break;
|
|
507
|
-
case 'numeric':
|
|
508
|
-
paramsShape.properties = {
|
|
509
|
-
...paramsShape.properties,
|
|
510
|
-
[columnName]: (0, primitiveOpenapiStatementToOpenapi_js_1.default)('number', nullableColumn),
|
|
511
|
-
};
|
|
512
|
-
break;
|
|
513
|
-
case 'numeric[]':
|
|
514
|
-
paramsShape.properties = {
|
|
515
|
-
...paramsShape.properties,
|
|
516
|
-
[columnName]: (0, primitiveOpenapiStatementToOpenapi_js_1.default)('number[]', nullableColumn),
|
|
517
|
-
};
|
|
518
|
-
break;
|
|
519
|
-
default:
|
|
520
|
-
if (dreamClass.isVirtualColumn(columnName)) {
|
|
521
|
-
const metadata = dreamClass['virtualAttributes'].find(statement => statement.property === columnName);
|
|
522
|
-
if (metadata?.type) {
|
|
523
|
-
paramsShape.properties = {
|
|
524
|
-
...paramsShape.properties,
|
|
525
|
-
[columnName]: new body_segment_js_1.default(metadata.type, {
|
|
526
|
-
renderOpts,
|
|
527
|
-
target: 'request',
|
|
528
|
-
}).render().openapi,
|
|
529
|
-
};
|
|
530
|
-
}
|
|
531
|
-
else {
|
|
532
|
-
paramsShape.properties = {
|
|
533
|
-
...paramsShape.properties,
|
|
534
|
-
[columnName]: {
|
|
535
|
-
anyOf: [
|
|
536
|
-
{ type: ['string', 'null'] },
|
|
537
|
-
{ type: ['number', 'null'] },
|
|
538
|
-
{ type: ['object', 'null'] },
|
|
539
|
-
],
|
|
540
|
-
},
|
|
541
|
-
};
|
|
542
|
-
}
|
|
543
|
-
}
|
|
544
|
-
else if (columnMetadata?.enumValues) {
|
|
545
|
-
if (columnMetadata.isArray) {
|
|
546
|
-
paramsShape.properties = {
|
|
547
|
-
...paramsShape.properties,
|
|
548
|
-
[columnName]: {
|
|
549
|
-
type: nullableColumn ? ['array', 'null'] : 'array',
|
|
550
|
-
items: {
|
|
551
|
-
type: 'string',
|
|
552
|
-
enum: [...columnMetadata.enumValues, ...(nullableColumn ? [null] : [])],
|
|
553
|
-
},
|
|
554
|
-
},
|
|
555
|
-
};
|
|
556
|
-
}
|
|
557
|
-
else {
|
|
558
|
-
paramsShape.properties = {
|
|
559
|
-
...paramsShape.properties,
|
|
560
|
-
[columnName]: {
|
|
561
|
-
type: nullableColumn ? ['string', 'null'] : 'string',
|
|
562
|
-
enum: [...columnMetadata.enumValues, ...(nullableColumn ? [null] : [])],
|
|
563
|
-
},
|
|
564
|
-
};
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
}
|
|
432
|
+
paramsShape.properties = {
|
|
433
|
+
...paramsShape.properties,
|
|
434
|
+
...(0, dreamColumnToOpenapiType_js_1.default)(dreamClass, columnName),
|
|
435
|
+
};
|
|
568
436
|
}
|
|
569
437
|
let processedSchema = new body_segment_js_1.default(paramsShape, {
|
|
570
438
|
renderOpts,
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.default = dreamColumnToOpenapiType;
|
|
7
|
+
const primitiveOpenapiStatementToOpenapi_js_1 = __importDefault(require("./primitiveOpenapiStatementToOpenapi.js"));
|
|
8
|
+
const body_segment_js_1 = __importDefault(require("../body-segment.js"));
|
|
9
|
+
function dreamColumnToOpenapiType(dreamClass, columnName) {
|
|
10
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
11
|
+
const schema = dreamClass.prototype.schema;
|
|
12
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
13
|
+
const columns = schema[dreamClass.prototype.table]?.columns;
|
|
14
|
+
const columnMetadata = columns[columnName];
|
|
15
|
+
const nullableColumn = columnMetadata?.allowNull;
|
|
16
|
+
switch (columnMetadata?.dbType) {
|
|
17
|
+
case 'boolean':
|
|
18
|
+
case 'boolean[]':
|
|
19
|
+
case 'date':
|
|
20
|
+
case 'date[]':
|
|
21
|
+
case 'integer':
|
|
22
|
+
case 'integer[]':
|
|
23
|
+
return {
|
|
24
|
+
[columnName]: (0, primitiveOpenapiStatementToOpenapi_js_1.default)(columnMetadata.dbType, nullableColumn),
|
|
25
|
+
};
|
|
26
|
+
case 'character varying':
|
|
27
|
+
case 'citext':
|
|
28
|
+
case 'text':
|
|
29
|
+
case 'uuid':
|
|
30
|
+
case 'bigint':
|
|
31
|
+
return {
|
|
32
|
+
[columnName]: (0, primitiveOpenapiStatementToOpenapi_js_1.default)('string', nullableColumn),
|
|
33
|
+
};
|
|
34
|
+
case 'character varying[]':
|
|
35
|
+
case 'citext[]':
|
|
36
|
+
case 'text[]':
|
|
37
|
+
case 'uuid[]':
|
|
38
|
+
case 'bigint[]':
|
|
39
|
+
return {
|
|
40
|
+
[columnName]: (0, primitiveOpenapiStatementToOpenapi_js_1.default)('string[]', nullableColumn),
|
|
41
|
+
};
|
|
42
|
+
case 'timestamp':
|
|
43
|
+
case 'timestamp with time zone':
|
|
44
|
+
case 'timestamp without time zone':
|
|
45
|
+
return {
|
|
46
|
+
[columnName]: (0, primitiveOpenapiStatementToOpenapi_js_1.default)('date-time', nullableColumn),
|
|
47
|
+
};
|
|
48
|
+
case 'timestamp[]':
|
|
49
|
+
case 'timestamp with time zone[]':
|
|
50
|
+
case 'timestamp without time zone[]':
|
|
51
|
+
return {
|
|
52
|
+
[columnName]: (0, primitiveOpenapiStatementToOpenapi_js_1.default)('date-time[]', nullableColumn),
|
|
53
|
+
};
|
|
54
|
+
case 'json':
|
|
55
|
+
case 'jsonb':
|
|
56
|
+
return {
|
|
57
|
+
[columnName]: {
|
|
58
|
+
type: nullableColumn ? ['object', 'null'] : 'object',
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
case 'json[]':
|
|
62
|
+
case 'jsonb[]':
|
|
63
|
+
return {
|
|
64
|
+
[columnName]: {
|
|
65
|
+
type: nullableColumn ? ['array', 'null'] : 'array',
|
|
66
|
+
items: {
|
|
67
|
+
type: 'object',
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
case 'numeric':
|
|
72
|
+
return {
|
|
73
|
+
[columnName]: (0, primitiveOpenapiStatementToOpenapi_js_1.default)('number', nullableColumn),
|
|
74
|
+
};
|
|
75
|
+
case 'numeric[]':
|
|
76
|
+
return {
|
|
77
|
+
[columnName]: (0, primitiveOpenapiStatementToOpenapi_js_1.default)('number[]', nullableColumn),
|
|
78
|
+
};
|
|
79
|
+
default:
|
|
80
|
+
if (dreamClass.isVirtualColumn(columnName)) {
|
|
81
|
+
const metadata = dreamClass['virtualAttributes'].find(statement => statement.property === columnName);
|
|
82
|
+
if (metadata?.type) {
|
|
83
|
+
return {
|
|
84
|
+
[columnName]: new body_segment_js_1.default(metadata.type, {
|
|
85
|
+
renderOpts: {
|
|
86
|
+
casing: 'camel',
|
|
87
|
+
suppressResponseEnums: false,
|
|
88
|
+
},
|
|
89
|
+
target: 'request',
|
|
90
|
+
}).render().openapi,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
return {
|
|
95
|
+
[columnName]: {
|
|
96
|
+
anyOf: [
|
|
97
|
+
{ type: ['string', 'null'] },
|
|
98
|
+
{ type: ['number', 'null'] },
|
|
99
|
+
{ type: ['object', 'null'] },
|
|
100
|
+
],
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
else if (columnMetadata?.enumValues) {
|
|
106
|
+
if (columnMetadata.isArray) {
|
|
107
|
+
return {
|
|
108
|
+
[columnName]: {
|
|
109
|
+
type: nullableColumn ? ['array', 'null'] : 'array',
|
|
110
|
+
items: {
|
|
111
|
+
type: 'string',
|
|
112
|
+
enum: [...columnMetadata.enumValues, ...(nullableColumn ? [null] : [])],
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
return {
|
|
119
|
+
[columnName]: {
|
|
120
|
+
type: nullableColumn ? ['string', 'null'] : 'string',
|
|
121
|
+
enum: [...columnMetadata.enumValues, ...(nullableColumn ? [null] : [])],
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return {};
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.default = paramNamesForDreamClass;
|
|
4
|
+
function paramNamesForDreamClass(dreamClass, { only, including } = {}) {
|
|
5
|
+
let paramSafeColumns = Array.isArray(only)
|
|
6
|
+
? dreamClass.paramSafeColumnsOrFallback().filter(column => only.includes(column))
|
|
7
|
+
: dreamClass.paramSafeColumnsOrFallback();
|
|
8
|
+
if (Array.isArray(including)) {
|
|
9
|
+
paramSafeColumns = [
|
|
10
|
+
...paramSafeColumns,
|
|
11
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any
|
|
12
|
+
...[...dreamClass.columns()].filter(columnName => including.includes(columnName)),
|
|
13
|
+
];
|
|
14
|
+
}
|
|
15
|
+
return paramSafeColumns;
|
|
16
|
+
}
|
|
@@ -10,6 +10,7 @@ const alternateParamName_js_1 = __importDefault(require("../helpers/alternatePar
|
|
|
10
10
|
const isArrayParamName_js_1 = __importDefault(require("../helpers/isArrayParamName.js"));
|
|
11
11
|
const isObject_js_1 = __importDefault(require("../helpers/isObject.js"));
|
|
12
12
|
const isUuid_js_1 = __importDefault(require("../helpers/isUuid.js"));
|
|
13
|
+
const paramNamesForDreamClass_js_1 = __importDefault(require("./helpers/paramNamesForDreamClass.js"));
|
|
13
14
|
class Params {
|
|
14
15
|
$params;
|
|
15
16
|
/**
|
|
@@ -27,13 +28,15 @@ class Params {
|
|
|
27
28
|
* ```
|
|
28
29
|
*/
|
|
29
30
|
static for(params, dreamClass, forOpts = {}) {
|
|
30
|
-
const { array = false
|
|
31
|
+
const { array = false } = forOpts;
|
|
31
32
|
if (!dreamClass?.isDream)
|
|
32
33
|
throw new Error(`Params.for must receive a dream class as it's second argument`);
|
|
33
34
|
if (array) {
|
|
34
35
|
if (!Array.isArray(params))
|
|
35
36
|
throw new Error(`Params.for was expecting a top-level array. got ${typeof params}`);
|
|
36
|
-
return params.map(param =>
|
|
37
|
+
return params.map(param =>
|
|
38
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
39
|
+
this.for(param, dreamClass, { ...forOpts, array: undefined }));
|
|
37
40
|
}
|
|
38
41
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
39
42
|
const schema = dreamClass.prototype.schema;
|
|
@@ -41,9 +44,7 @@ class Params {
|
|
|
41
44
|
const columns = schema[dreamClass.prototype.table]?.columns;
|
|
42
45
|
const returnObj = {};
|
|
43
46
|
const errors = {};
|
|
44
|
-
const paramSafeColumns =
|
|
45
|
-
? dreamClass.paramSafeColumnsOrFallback().filter(column => only.includes(column))
|
|
46
|
-
: dreamClass.paramSafeColumnsOrFallback();
|
|
47
|
+
const paramSafeColumns = (0, paramNamesForDreamClass_js_1.default)(dreamClass, forOpts);
|
|
47
48
|
for (const columnName of paramSafeColumns) {
|
|
48
49
|
if (params[columnName] === undefined)
|
|
49
50
|
continue;
|
|
@@ -47,13 +47,20 @@ class Watcher {
|
|
|
47
47
|
// the timeout and restarting it
|
|
48
48
|
clearTimeout(timer);
|
|
49
49
|
const seconds = TIMEOUT_INTERVAL / 1000;
|
|
50
|
-
dream_1.DreamCLI.logger.log(`${filename} changed
|
|
50
|
+
dream_1.DreamCLI.logger.log(`${filename} changed`);
|
|
51
|
+
dream_1.DreamCLI.logger.log(`next sync in ${seconds} seconds...`, { logPrefixColor: 'cyan' });
|
|
51
52
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
|
52
53
|
timer = setTimeout(async () => {
|
|
53
|
-
dream_1.DreamCLI.logger.log(`executing sync
|
|
54
|
+
dream_1.DreamCLI.logger.log(`executing sync...`, { logPrefixColor: 'cyan' });
|
|
54
55
|
const psy = index_js_1.default.getOrFail();
|
|
55
56
|
this.syncing = true;
|
|
56
|
-
|
|
57
|
+
try {
|
|
58
|
+
await dream_1.DreamCLI.spawn(psy.psyCmd('sync'));
|
|
59
|
+
}
|
|
60
|
+
catch (err) {
|
|
61
|
+
dream_1.DreamCLI.logger.log(`ERROR!`, { logPrefixColor: 'red' });
|
|
62
|
+
console.error(err);
|
|
63
|
+
}
|
|
57
64
|
// pause for an additional second, so that any file changes
|
|
58
65
|
// still being regestered from the end of the sync
|
|
59
66
|
// command don't accidentally trick it into running again,
|