@rws-framework/db 3.1.0 → 3.2.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.
- package/dist/decorators/Relation.js +2 -1
- package/dist/helper/db/schema-generator.js +25 -9
- package/dist/helper/db/type-converter.js +27 -6
- package/dist/models/interfaces/IDbOpts.d.ts +3 -0
- package/dist/models/utils/HydrateUtils.js +0 -1
- package/exec/console.js +0 -2
- package/package.json +1 -1
- package/src/decorators/Relation.ts +4 -2
- package/src/helper/db/schema-generator.ts +35 -11
- package/src/helper/db/type-converter.ts +31 -4
- package/src/models/interfaces/IDbOpts.ts +3 -0
- package/src/models/utils/HydrateUtils.ts +0 -2
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
require("reflect-metadata");
|
|
4
|
-
const
|
|
4
|
+
const _DEFAULT_CASCADE = { onDelete: 'SetNull', onUpdate: 'Cascade' };
|
|
5
|
+
const _DEFAULTS = { required: false, many: false, embed: false, cascade: null };
|
|
5
6
|
function Relation(theModel, relationOptions = _DEFAULTS) {
|
|
6
7
|
return function (target, key) {
|
|
7
8
|
// Store the promise in metadata immediately
|
|
@@ -11,7 +11,6 @@ const _model_1 = require("../../models/_model");
|
|
|
11
11
|
const utils_1 = require("./utils");
|
|
12
12
|
const type_converter_1 = require("./type-converter");
|
|
13
13
|
const relation_manager_1 = require("./relation-manager");
|
|
14
|
-
const log = console.log;
|
|
15
14
|
/**
|
|
16
15
|
* Handles Prisma schema generation
|
|
17
16
|
*/
|
|
@@ -84,12 +83,13 @@ datasource db {
|
|
|
84
83
|
if (modelMetadata.required === false) {
|
|
85
84
|
requiredString = '?';
|
|
86
85
|
}
|
|
86
|
+
const cascadeStr = cascadeOpts.length ? `, ${cascadeOpts.join(', ')}` : '';
|
|
87
87
|
if (isMany) {
|
|
88
88
|
// Add an inverse field to the related model if it doesn't exist
|
|
89
|
-
section += `\t${key} ${relatedModel._collection}[] @relation("${relationName}", fields: [${relationFieldName}], references: [${relatedToField}], map: "${mapName}"
|
|
89
|
+
section += `\t${key} ${relatedModel._collection}[] @relation("${relationName}", fields: [${relationFieldName}], references: [${relatedToField}], map: "${mapName}"${cascadeStr})\n`;
|
|
90
90
|
}
|
|
91
91
|
else {
|
|
92
|
-
section += `\t${key} ${relatedModel._collection}${requiredString} @relation("${relationName}", fields: [${relationFieldName}], references: [${relatedToField}], map: "${mapName}"
|
|
92
|
+
section += `\t${key} ${relatedModel._collection}${requiredString} @relation("${relationName}", fields: [${relationFieldName}], references: [${relatedToField}], map: "${mapName}"${cascadeStr})\n`;
|
|
93
93
|
if (!bindingFieldExists) {
|
|
94
94
|
const relatedFieldMeta = relatedModelMetadatas[relatedToField];
|
|
95
95
|
if (!relatedFieldMeta.metadata.required) {
|
|
@@ -173,15 +173,31 @@ datasource db {
|
|
|
173
173
|
// Process any database-specific options from the metadata
|
|
174
174
|
const dbSpecificTags = type_converter_1.TypeConverter.processTypeOptions(trackMeta, dbType);
|
|
175
175
|
tags.push(...dbSpecificTags);
|
|
176
|
-
if (modelName === 'category_translation' && key === 'meta_keywords') {
|
|
177
|
-
console.log({ requiredString, trackMeta });
|
|
178
|
-
}
|
|
179
176
|
section += `\t${key} ${type_converter_1.TypeConverter.toConfigCase(trackMeta, dbType, key === 'id')}${requiredString} ${tags.join(' ')}\n`;
|
|
180
177
|
}
|
|
181
178
|
}
|
|
179
|
+
if (model._SUPER_TAGS.length) {
|
|
180
|
+
section += '\n';
|
|
181
|
+
}
|
|
182
182
|
for (const superTag of model._SUPER_TAGS) {
|
|
183
183
|
const mapStr = superTag.map ? `, map: "${superTag.map}"` : '';
|
|
184
|
-
|
|
184
|
+
const superFields = [];
|
|
185
|
+
for (const superField of superTag.fields) {
|
|
186
|
+
const fieldMetadata = modelMetadatas[superField]['metadata'];
|
|
187
|
+
let pushed = false;
|
|
188
|
+
if (fieldMetadata.dbOptions && fieldMetadata.dbOptions.mysql && fieldMetadata.dbOptions.mysql.useType) {
|
|
189
|
+
switch (fieldMetadata.dbOptions.mysql.useType) {
|
|
190
|
+
case 'db.LongText':
|
|
191
|
+
superFields.push(`${superField}(length: 255)`);
|
|
192
|
+
pushed = true;
|
|
193
|
+
break;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
if (!pushed) {
|
|
197
|
+
superFields.push(superField);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
section += `\t@@${superTag.tagType}([${superFields.join(', ')}]${mapStr})\n`;
|
|
185
201
|
}
|
|
186
202
|
section += '}\n';
|
|
187
203
|
return section;
|
|
@@ -224,7 +240,7 @@ datasource db {
|
|
|
224
240
|
for (const model of dbModels) {
|
|
225
241
|
const modelSection = await SchemaGenerator.generateModelSections(model, configService);
|
|
226
242
|
template += '\n\n' + modelSection;
|
|
227
|
-
log(chalk_1.default.green('[RWS]'), chalk_1.default.blue('Building DB Model'), model.name);
|
|
243
|
+
console.log(chalk_1.default.green('[RWS]'), chalk_1.default.blue('Building DB Model'), model.name);
|
|
228
244
|
}
|
|
229
245
|
const [schemaDir, schemaPath] = utils_1.DbUtils.getSchemaDir();
|
|
230
246
|
if (!fs_1.default.existsSync(schemaDir)) {
|
|
@@ -236,7 +252,7 @@ datasource db {
|
|
|
236
252
|
fs_1.default.writeFileSync(schemaPath, template);
|
|
237
253
|
await console_1.rwsShell.runCommand(`${utils_1.DbUtils.detectInstaller()} prisma generate --schema=${schemaPath}`, process.cwd());
|
|
238
254
|
leaveFile = false;
|
|
239
|
-
log(chalk_1.default.green('[RWS Init]') + ' prisma schema generated from ', schemaPath);
|
|
255
|
+
console.log(chalk_1.default.green('[RWS Init]') + ' prisma schema generated from ', schemaPath);
|
|
240
256
|
if (!leaveFile) {
|
|
241
257
|
// fs.unlinkSync(schemaPath);
|
|
242
258
|
}
|
|
@@ -13,7 +13,22 @@ class TypeConverter {
|
|
|
13
13
|
let input = type.name;
|
|
14
14
|
// Handle basic types
|
|
15
15
|
if (input == 'Number') {
|
|
16
|
-
|
|
16
|
+
let numberOverride = false;
|
|
17
|
+
if (modelType.dbOptions && modelType.dbOptions.mysql) {
|
|
18
|
+
if (modelType.dbOptions.mysql.useType) {
|
|
19
|
+
if (['db.Float'].includes(modelType.dbOptions.mysql.useType)) {
|
|
20
|
+
input = 'Float';
|
|
21
|
+
numberOverride = true;
|
|
22
|
+
}
|
|
23
|
+
if (['db.Decimal'].includes(modelType.dbOptions.mysql.useType)) {
|
|
24
|
+
input = 'Decimal';
|
|
25
|
+
numberOverride = true;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
if (!numberOverride) {
|
|
30
|
+
input = 'Int';
|
|
31
|
+
}
|
|
17
32
|
}
|
|
18
33
|
if (input == 'Object') {
|
|
19
34
|
input = 'Json';
|
|
@@ -66,20 +81,26 @@ class TypeConverter {
|
|
|
66
81
|
* @returns Array of tags to apply to the field
|
|
67
82
|
*/
|
|
68
83
|
static processTypeOptions(metadata, dbType) {
|
|
69
|
-
var _a, _b;
|
|
84
|
+
var _a, _b, _c, _d;
|
|
70
85
|
const tags = [...(metadata.tags || [])];
|
|
71
86
|
// Extract any database-specific options from the metadata
|
|
72
87
|
// and convert them to appropriate Prisma schema tags
|
|
73
88
|
if (metadata.dbOptions) {
|
|
74
89
|
// Handle MySQL-specific options
|
|
75
90
|
if (dbType === 'mysql' && metadata.dbOptions.mysql) {
|
|
91
|
+
let tag = null;
|
|
92
|
+
if (metadata.dbOptions.mysql.useType && !metadata.dbOptions.mysql.useText) {
|
|
93
|
+
const tagName = metadata.dbOptions.mysql.useType === 'VarChar' ? 'db.' + metadata.dbOptions.mysql.useType : metadata.dbOptions.mysql.useType;
|
|
94
|
+
let tagParams = tagName === 'db.VarChar' && metadata.dbOptions.mysql.maxLength ? metadata.dbOptions.mysql.maxLength : (((_b = (_a = metadata.dbOptions.mysql) === null || _a === void 0 ? void 0 : _a.params) === null || _b === void 0 ? void 0 : _b.join(', ')) || '');
|
|
95
|
+
tag = `@${tagName}(${tagParams})`;
|
|
96
|
+
}
|
|
76
97
|
if (metadata.dbOptions.mysql.useText) {
|
|
77
98
|
tags.push('@db.Text');
|
|
78
99
|
}
|
|
79
|
-
|
|
80
|
-
tags.push(
|
|
100
|
+
if (tag) {
|
|
101
|
+
tags.push(tag);
|
|
81
102
|
}
|
|
82
|
-
if (metadata.dbOptions.mysql.useUuid && ((
|
|
103
|
+
if (metadata.dbOptions.mysql.useUuid && ((_c = metadata.tags) === null || _c === void 0 ? void 0 : _c.includes('id'))) {
|
|
83
104
|
tags.push('default(uuid())');
|
|
84
105
|
}
|
|
85
106
|
}
|
|
@@ -88,7 +109,7 @@ class TypeConverter {
|
|
|
88
109
|
if (metadata.dbOptions.postgres.useText) {
|
|
89
110
|
tags.push('@db.Text');
|
|
90
111
|
}
|
|
91
|
-
if (metadata.dbOptions.postgres.useUuid && ((
|
|
112
|
+
if (metadata.dbOptions.postgres.useUuid && ((_d = metadata.tags) === null || _d === void 0 ? void 0 : _d.includes('id'))) {
|
|
92
113
|
tags.push('@default(uuid())');
|
|
93
114
|
tags.push('@db.Uuid');
|
|
94
115
|
}
|
|
@@ -5,13 +5,16 @@ export interface IDbOpts {
|
|
|
5
5
|
useText?: boolean;
|
|
6
6
|
maxLength?: number;
|
|
7
7
|
useUuid?: boolean;
|
|
8
|
+
params?: string[];
|
|
8
9
|
};
|
|
9
10
|
postgres?: {
|
|
10
11
|
useText?: boolean;
|
|
11
12
|
useUuid?: boolean;
|
|
13
|
+
params?: string[];
|
|
12
14
|
};
|
|
13
15
|
mongodb?: {
|
|
14
16
|
customType?: string;
|
|
17
|
+
params?: string[];
|
|
15
18
|
};
|
|
16
19
|
};
|
|
17
20
|
}
|
|
@@ -41,7 +41,6 @@ class HydrateUtils {
|
|
|
41
41
|
continue;
|
|
42
42
|
}
|
|
43
43
|
const relMeta = relManyData[key];
|
|
44
|
-
// console.log({relMeta});
|
|
45
44
|
const relationEnabled = !RelationUtils_1.RelationUtils.checkRelDisabled(model, relMeta.key);
|
|
46
45
|
if (relationEnabled) {
|
|
47
46
|
model[relMeta.key] = await relMeta.inversionModel.findBy({
|
package/exec/console.js
CHANGED
|
@@ -15,8 +15,6 @@ const getCachedPath = (key) => path.resolve(rwsCliConfigDir, key);
|
|
|
15
15
|
|
|
16
16
|
const currentCwd = path.resolve(__dirname);
|
|
17
17
|
|
|
18
|
-
console.log({params})
|
|
19
|
-
|
|
20
18
|
|
|
21
19
|
const commandString = `npx webpack --config db.rws.webpack.config.js --output-path ./build ${process.cwd()} ${params[2]}`;
|
|
22
20
|
function needsCacheWarming(){
|
package/package.json
CHANGED
|
@@ -20,13 +20,15 @@ export interface IRelationOpts {
|
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
const
|
|
23
|
+
const _DEFAULT_CASCADE = { onDelete: 'SetNull', onUpdate: 'Cascade' };
|
|
24
|
+
|
|
25
|
+
const _DEFAULTS: Partial<IRelationOpts> = { required: false, many: false, embed: false, cascade: null};
|
|
24
26
|
|
|
25
27
|
function Relation(theModel: () => OpModelType<RWSModel<any>>, relationOptions: Partial<IRelationOpts> = _DEFAULTS) {
|
|
26
28
|
return function(target: any, key: string) {
|
|
27
29
|
// Store the promise in metadata immediately
|
|
28
30
|
|
|
29
|
-
const metadataPromise = Promise.resolve().then(() => {
|
|
31
|
+
const metadataPromise = Promise.resolve().then(() => {
|
|
30
32
|
const relatedTo = theModel();
|
|
31
33
|
|
|
32
34
|
const metaOpts: IRelationOpts = {
|
|
@@ -15,7 +15,6 @@ import { RelationManager } from './relation-manager';
|
|
|
15
15
|
import { ITrackerMetaOpts } from '../../decorators/TrackType';
|
|
16
16
|
import { IDbOpts } from '../../models/interfaces/IDbOpts';
|
|
17
17
|
|
|
18
|
-
const log = console.log;
|
|
19
18
|
|
|
20
19
|
/**
|
|
21
20
|
* Handles Prisma schema generation
|
|
@@ -114,11 +113,13 @@ datasource db {
|
|
|
114
113
|
requiredString = '?';
|
|
115
114
|
}
|
|
116
115
|
|
|
116
|
+
const cascadeStr = cascadeOpts.length ? `, ${cascadeOpts.join(', ')}` : '' ;
|
|
117
|
+
|
|
117
118
|
if (isMany) {
|
|
118
119
|
// Add an inverse field to the related model if it doesn't exist
|
|
119
|
-
section += `\t${key} ${relatedModel._collection}[] @relation("${relationName}", fields: [${relationFieldName}], references: [${relatedToField}], map: "${mapName}"
|
|
120
|
+
section += `\t${key} ${relatedModel._collection}[] @relation("${relationName}", fields: [${relationFieldName}], references: [${relatedToField}], map: "${mapName}"${cascadeStr})\n`;
|
|
120
121
|
} else {
|
|
121
|
-
section += `\t${key} ${relatedModel._collection}${requiredString} @relation("${relationName}", fields: [${relationFieldName}], references: [${relatedToField}], map: "${mapName}"
|
|
122
|
+
section += `\t${key} ${relatedModel._collection}${requiredString} @relation("${relationName}", fields: [${relationFieldName}], references: [${relatedToField}], map: "${mapName}"${cascadeStr})\n`;
|
|
122
123
|
if(!bindingFieldExists){
|
|
123
124
|
const relatedFieldMeta = relatedModelMetadatas[relatedToField];
|
|
124
125
|
|
|
@@ -204,24 +205,47 @@ datasource db {
|
|
|
204
205
|
if(model._SUPER_TAGS.some(tag => tag.tagType === 'id' && tag.fields.includes(key))){
|
|
205
206
|
requiredString = '';
|
|
206
207
|
}
|
|
207
|
-
|
|
208
|
+
|
|
208
209
|
// Process any database-specific options from the metadata
|
|
209
210
|
const dbSpecificTags = TypeConverter.processTypeOptions(trackMeta as { tags: string[], dbOptions: IDbOpts['dbOptions'] }, dbType);
|
|
210
211
|
tags.push(...dbSpecificTags);
|
|
211
|
-
|
|
212
|
-
if(modelName === 'category_translation' && key === 'meta_keywords'){
|
|
213
|
-
console.log({requiredString, trackMeta});
|
|
214
|
-
}
|
|
212
|
+
|
|
215
213
|
|
|
216
214
|
section += `\t${key} ${TypeConverter.toConfigCase(trackMeta, dbType, key === 'id')}${requiredString} ${tags.join(' ')}\n`;
|
|
217
215
|
}
|
|
218
216
|
}
|
|
219
217
|
|
|
218
|
+
if(model._SUPER_TAGS.length){
|
|
219
|
+
section += '\n';
|
|
220
|
+
}
|
|
221
|
+
|
|
220
222
|
for(const superTag of model._SUPER_TAGS){
|
|
221
223
|
|
|
222
224
|
const mapStr = superTag.map ? `, map: "${superTag.map}"` : '';
|
|
223
225
|
|
|
224
|
-
|
|
226
|
+
const superFields = [];
|
|
227
|
+
|
|
228
|
+
for(const superField of superTag.fields){
|
|
229
|
+
const fieldMetadata = modelMetadatas[superField]['metadata'];
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
let pushed = false;
|
|
233
|
+
|
|
234
|
+
if(fieldMetadata.dbOptions && fieldMetadata.dbOptions.mysql && fieldMetadata.dbOptions.mysql.useType){
|
|
235
|
+
switch(fieldMetadata.dbOptions.mysql.useType){
|
|
236
|
+
case 'db.LongText':
|
|
237
|
+
superFields.push(`${superField}(length: 255)`);
|
|
238
|
+
pushed = true;
|
|
239
|
+
break;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if(!pushed){
|
|
244
|
+
superFields.push(superField);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
section += `\t@@${superTag.tagType}([${superFields.join(', ')}]${mapStr})\n`;
|
|
225
249
|
}
|
|
226
250
|
|
|
227
251
|
section += '}\n';
|
|
@@ -280,7 +304,7 @@ datasource db {
|
|
|
280
304
|
|
|
281
305
|
template += '\n\n' + modelSection;
|
|
282
306
|
|
|
283
|
-
log(chalk.green('[RWS]'), chalk.blue('Building DB Model'), model.name);
|
|
307
|
+
console.log(chalk.green('[RWS]'), chalk.blue('Building DB Model'), model.name);
|
|
284
308
|
}
|
|
285
309
|
|
|
286
310
|
const [schemaDir, schemaPath] = DbUtils.getSchemaDir();
|
|
@@ -298,7 +322,7 @@ datasource db {
|
|
|
298
322
|
await rwsShell.runCommand(`${DbUtils.detectInstaller()} prisma generate --schema=${schemaPath}`, process.cwd());
|
|
299
323
|
|
|
300
324
|
leaveFile = false;
|
|
301
|
-
log(chalk.green('[RWS Init]') + ' prisma schema generated from ', schemaPath);
|
|
325
|
+
console.log(chalk.green('[RWS Init]') + ' prisma schema generated from ', schemaPath);
|
|
302
326
|
|
|
303
327
|
if (!leaveFile) {
|
|
304
328
|
// fs.unlinkSync(schemaPath);
|
|
@@ -16,7 +16,24 @@ export class TypeConverter {
|
|
|
16
16
|
|
|
17
17
|
// Handle basic types
|
|
18
18
|
if (input == 'Number') {
|
|
19
|
-
|
|
19
|
+
let numberOverride = false;
|
|
20
|
+
if(modelType.dbOptions && modelType.dbOptions.mysql){
|
|
21
|
+
if(modelType.dbOptions.mysql.useType){
|
|
22
|
+
if(['db.Float'].includes(modelType.dbOptions.mysql.useType)){
|
|
23
|
+
input = 'Float';
|
|
24
|
+
numberOverride = true;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if(['db.Decimal'].includes(modelType.dbOptions.mysql.useType)){
|
|
28
|
+
input = 'Decimal';
|
|
29
|
+
numberOverride = true;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if(!numberOverride){
|
|
35
|
+
input = 'Int';
|
|
36
|
+
}
|
|
20
37
|
}
|
|
21
38
|
|
|
22
39
|
if (input == 'Object') {
|
|
@@ -64,7 +81,7 @@ export class TypeConverter {
|
|
|
64
81
|
} else {
|
|
65
82
|
resultField += '[]';
|
|
66
83
|
}
|
|
67
|
-
}
|
|
84
|
+
}
|
|
68
85
|
|
|
69
86
|
return resultField;
|
|
70
87
|
}
|
|
@@ -83,10 +100,20 @@ export class TypeConverter {
|
|
|
83
100
|
if (metadata.dbOptions) {
|
|
84
101
|
// Handle MySQL-specific options
|
|
85
102
|
if (dbType === 'mysql' && metadata.dbOptions.mysql) {
|
|
103
|
+
let tag = null;
|
|
104
|
+
|
|
105
|
+
if (metadata.dbOptions.mysql.useType && !metadata.dbOptions.mysql.useText) {
|
|
106
|
+
const tagName = metadata.dbOptions.mysql.useType === 'VarChar' ? 'db.' + metadata.dbOptions.mysql.useType : metadata.dbOptions.mysql.useType;
|
|
107
|
+
let tagParams = tagName === 'db.VarChar' && metadata.dbOptions.mysql.maxLength ? metadata.dbOptions.mysql.maxLength : (metadata.dbOptions.mysql?.params?.join(', ') || '');
|
|
108
|
+
tag = `@${tagName}(${tagParams})`;
|
|
109
|
+
}
|
|
110
|
+
|
|
86
111
|
if (metadata.dbOptions.mysql.useText) {
|
|
87
112
|
tags.push('@db.Text');
|
|
88
|
-
}
|
|
89
|
-
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if(tag){
|
|
116
|
+
tags.push(tag);
|
|
90
117
|
}
|
|
91
118
|
|
|
92
119
|
if (metadata.dbOptions.mysql.useUuid && metadata.tags?.includes('id')) {
|
|
@@ -5,13 +5,16 @@ export interface IDbOpts {
|
|
|
5
5
|
useText?: boolean;
|
|
6
6
|
maxLength?: number;
|
|
7
7
|
useUuid?: boolean;
|
|
8
|
+
params?: string[]
|
|
8
9
|
};
|
|
9
10
|
postgres?: {
|
|
10
11
|
useText?: boolean;
|
|
11
12
|
useUuid?: boolean;
|
|
13
|
+
params?: string[]
|
|
12
14
|
};
|
|
13
15
|
mongodb?: {
|
|
14
16
|
customType?: string;
|
|
17
|
+
params?: string[]
|
|
15
18
|
};
|
|
16
19
|
}
|
|
17
20
|
}
|