@reldens/storage 0.104.0 → 0.106.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/lib/entities-generator.js +6 -120
- package/lib/generators/entities-generation.js +8 -0
- package/lib/prisma/prisma-metadata-loader.js +7 -14
- package/lib/prisma/prisma-relations-metadata-extractor.js +137 -0
- package/package.json +5 -5
- package/tests/fixtures/expected-entities/entities/test-categories-entity.js +1 -0
- package/tests/fixtures/expected-entities/entities/test-products-entity.js +1 -0
- package/tests/run-tests.js +6 -0
- package/tests/unit/test-entities-generation.js +152 -0
|
@@ -9,6 +9,7 @@ const { Logger, sc } = require('@reldens/utils');
|
|
|
9
9
|
const { ObjectionJsDataServer } = require('./objection-js/objection-js-data-server');
|
|
10
10
|
const { MikroOrmDataServer } = require('./mikro-orm/mikro-orm-data-server');
|
|
11
11
|
const { PrismaDataServer } = require('./prisma/prisma-data-server');
|
|
12
|
+
const { PrismaRelationsMetadataExtractor } = require('./prisma/prisma-relations-metadata-extractor');
|
|
12
13
|
const { EntitiesGeneration } = require('./generators/entities-generation');
|
|
13
14
|
const { ModelsGeneration } = require('./generators/models-generation');
|
|
14
15
|
const { EntitiesConfigGeneration } = require('./generators/entities-config-generation');
|
|
@@ -165,125 +166,6 @@ class EntitiesGenerator
|
|
|
165
166
|
return false;
|
|
166
167
|
}
|
|
167
168
|
|
|
168
|
-
extractPrismaRelationsMetadata()
|
|
169
|
-
{
|
|
170
|
-
if(!this.prismaClient){
|
|
171
|
-
Logger.warning('Missing PrismaClient.');
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
if(!this.server || !(this.server instanceof PrismaDataServer)){
|
|
175
|
-
Logger.warning('Server is not a PrismaDataServer instance.');
|
|
176
|
-
return;
|
|
177
|
-
}
|
|
178
|
-
try {
|
|
179
|
-
let dmmf = this.prismaClient._runtimeDataModel || this.prismaClient._dmmf?.datamodel;
|
|
180
|
-
if(!dmmf || !dmmf.models){
|
|
181
|
-
Logger.warning('Could not extract Prisma DMMF data for relations metadata.');
|
|
182
|
-
return;
|
|
183
|
-
}
|
|
184
|
-
if(sc.isArray(dmmf.models)){
|
|
185
|
-
this.processArrayModels(dmmf.models);
|
|
186
|
-
return;
|
|
187
|
-
}
|
|
188
|
-
this.processObjectModels(dmmf.models);
|
|
189
|
-
} catch(error) {
|
|
190
|
-
Logger.warning('Failed to extract Prisma relations metadata: ' + error.message);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
processArrayModels(models)
|
|
195
|
-
{
|
|
196
|
-
for(let model of models){
|
|
197
|
-
if(!model){
|
|
198
|
-
Logger.error('Missing model.');
|
|
199
|
-
continue;
|
|
200
|
-
}
|
|
201
|
-
if(!model.name){
|
|
202
|
-
Logger.error('Missing model name.', model);
|
|
203
|
-
continue;
|
|
204
|
-
}
|
|
205
|
-
if(!sc.isArray(model.fields)){
|
|
206
|
-
Logger.error('Model fields not an array.', model);
|
|
207
|
-
continue;
|
|
208
|
-
}
|
|
209
|
-
this.processModelForRelations(model.name, model, models);
|
|
210
|
-
}
|
|
211
|
-
Logger.info('Extracted relations metadata for '+Object.keys(this.prismaRelationsMetadata).length+' models.');
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
processObjectModels(models)
|
|
215
|
-
{
|
|
216
|
-
for(let modelName of Object.keys(models)){
|
|
217
|
-
let model = models[modelName];
|
|
218
|
-
if(!model){
|
|
219
|
-
Logger.error('Missing model.');
|
|
220
|
-
continue;
|
|
221
|
-
}
|
|
222
|
-
if(!sc.isArray(model.fields)){
|
|
223
|
-
Logger.error('Model fields not an array.', model);
|
|
224
|
-
continue;
|
|
225
|
-
}
|
|
226
|
-
this.processModelForRelations(modelName, model, models);
|
|
227
|
-
}
|
|
228
|
-
Logger.info('Extracted relations metadata for '+Object.keys(this.prismaRelationsMetadata).length+' models.');
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
processModelForRelations(modelName, model, allModels)
|
|
232
|
-
{
|
|
233
|
-
let tableName = modelName.toLowerCase();
|
|
234
|
-
this.prismaRelationsMetadata[tableName] = {};
|
|
235
|
-
for(let field of model.fields){
|
|
236
|
-
if('object' !== field.kind){
|
|
237
|
-
continue;
|
|
238
|
-
}
|
|
239
|
-
let relationType = 'many';
|
|
240
|
-
if(!field.isList){
|
|
241
|
-
relationType = this.inferRelationType(field, model, allModels, modelName);
|
|
242
|
-
}
|
|
243
|
-
this.prismaRelationsMetadata[tableName][field.name] = {
|
|
244
|
-
type: relationType,
|
|
245
|
-
model: field.type,
|
|
246
|
-
isList: field.isList,
|
|
247
|
-
isOptional: field.isOptional,
|
|
248
|
-
relationName: field.relationName
|
|
249
|
-
};
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
inferRelationType(field, model, allModels, modelName)
|
|
254
|
-
{
|
|
255
|
-
if(field.isList){
|
|
256
|
-
return 'many';
|
|
257
|
-
}
|
|
258
|
-
let relatedModel = this.findRelatedModel(allModels, field.type);
|
|
259
|
-
if(!relatedModel){
|
|
260
|
-
return 'one';
|
|
261
|
-
}
|
|
262
|
-
let backReference = relatedModel.fields.find(f =>
|
|
263
|
-
'object' === f.kind &&
|
|
264
|
-
f.type === modelName &&
|
|
265
|
-
f.relationName === field.relationName
|
|
266
|
-
);
|
|
267
|
-
if(!backReference){
|
|
268
|
-
return 'one';
|
|
269
|
-
}
|
|
270
|
-
if(field.relationFromFields && 0 < field.relationFromFields.length){
|
|
271
|
-
return 'one';
|
|
272
|
-
}
|
|
273
|
-
if(backReference.relationFromFields && 0 < backReference.relationFromFields.length){
|
|
274
|
-
return 'one';
|
|
275
|
-
}
|
|
276
|
-
return 'one';
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
findRelatedModel(allModels, fieldType)
|
|
280
|
-
{
|
|
281
|
-
if(sc.isArray(allModels)){
|
|
282
|
-
return allModels.find(m => m.name === fieldType);
|
|
283
|
-
}
|
|
284
|
-
return allModels[fieldType];
|
|
285
|
-
}
|
|
286
|
-
|
|
287
169
|
filterTablesToGenerate(tables, driverKey)
|
|
288
170
|
{
|
|
289
171
|
let filteredTables = {};
|
|
@@ -386,7 +268,11 @@ class EntitiesGenerator
|
|
|
386
268
|
this.prismaClient = this.server.prisma;
|
|
387
269
|
}
|
|
388
270
|
//Logger.debug('Extract Prisma relations metadata.');
|
|
389
|
-
this.
|
|
271
|
+
this.prismaRelationsMetadata = new PrismaRelationsMetadataExtractor({
|
|
272
|
+
prismaClient: this.prismaClient,
|
|
273
|
+
projectRoot: this.server ? this.server.projectRoot : false,
|
|
274
|
+
projectPath: this.projectPath
|
|
275
|
+
}).extract();
|
|
390
276
|
}
|
|
391
277
|
let tables = await this.server.fetchEntitiesFromDatabase();
|
|
392
278
|
if(!tables){
|
|
@@ -215,6 +215,7 @@ class EntitiesGeneration extends BaseGenerator
|
|
|
215
215
|
let type = column.type.toLowerCase();
|
|
216
216
|
this.addTypeAttribute(props, column, type, columnName, referenceCounts);
|
|
217
217
|
this.addRequiredAttribute(props, column);
|
|
218
|
+
this.addUniqueAttribute(props, column);
|
|
218
219
|
props.push('dbType: \''+type+'\'');
|
|
219
220
|
return props;
|
|
220
221
|
}
|
|
@@ -295,6 +296,13 @@ class EntitiesGeneration extends BaseGenerator
|
|
|
295
296
|
}
|
|
296
297
|
}
|
|
297
298
|
|
|
299
|
+
addUniqueAttribute(props, column)
|
|
300
|
+
{
|
|
301
|
+
if('UNI' === column.key){
|
|
302
|
+
props.push('isUnique: true');
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
298
306
|
getReferenceTable(column)
|
|
299
307
|
{
|
|
300
308
|
if(column.referencedTable){
|
|
@@ -17,21 +17,10 @@ class PrismaMetadataLoader
|
|
|
17
17
|
|
|
18
18
|
getDmmf()
|
|
19
19
|
{
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
return this.prisma._dmmf.datamodel;
|
|
23
|
-
}
|
|
24
|
-
if(this.prisma._getDmmf && sc.isFunction(this.prisma._getDmmf)){
|
|
25
|
-
return this.prisma._getDmmf().datamodel;
|
|
26
|
-
}
|
|
27
|
-
if(this.prisma._runtimeDataModel){
|
|
28
|
-
return this.prisma._runtimeDataModel;
|
|
29
|
-
}
|
|
30
|
-
return null;
|
|
31
|
-
} catch(error) {
|
|
32
|
-
Logger.warning('Failed to access DMMF: '+error.message);
|
|
33
|
-
return null;
|
|
20
|
+
if(this.prisma && this.prisma._runtimeDataModel){
|
|
21
|
+
return this.prisma._runtimeDataModel;
|
|
34
22
|
}
|
|
23
|
+
return null;
|
|
35
24
|
}
|
|
36
25
|
|
|
37
26
|
loadModelMetadata(tableName)
|
|
@@ -50,6 +39,7 @@ class PrismaMetadataLoader
|
|
|
50
39
|
let metadata = {
|
|
51
40
|
requiredFields: [],
|
|
52
41
|
optionalFields: [],
|
|
42
|
+
uniqueFields: [],
|
|
53
43
|
fieldTypes: {},
|
|
54
44
|
fieldDefaults: {},
|
|
55
45
|
idFieldType: 'String',
|
|
@@ -92,6 +82,9 @@ class PrismaMetadataLoader
|
|
|
92
82
|
if(field.isOptional || field.hasDefaultValue){
|
|
93
83
|
metadata.optionalFields.push(field.name);
|
|
94
84
|
}
|
|
85
|
+
if(field.isUnique){
|
|
86
|
+
metadata.uniqueFields.push(field.name);
|
|
87
|
+
}
|
|
95
88
|
if(field.kind === 'scalar' && field.isList === false){
|
|
96
89
|
let isNumericType = this.isNumericFieldType(field.type);
|
|
97
90
|
let isReferenceField = field.relationFromFields && 0 < field.relationFromFields.length;
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* Reldens - PrismaRelationsMetadataExtractor
|
|
4
|
+
*
|
|
5
|
+
* Builds the per-model relation metadata ({type: 'many'|'one', model, isList, isOptional, relationName})
|
|
6
|
+
* consumed by ModelsGeneration to emit each Prisma model's relationTypes. The DMMF access is reused from
|
|
7
|
+
* PrismaMetadataLoader.getDmmf(). Cardinality (list vs single) is read from schema.prisma's list markers
|
|
8
|
+
* ("[]") because Prisma 7's pruned _runtimeDataModel no longer exposes field.isList.
|
|
9
|
+
*
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const { PrismaMetadataLoader } = require('./prisma-metadata-loader');
|
|
13
|
+
const { FileHandler } = require('@reldens/server-utils');
|
|
14
|
+
const { Logger, sc } = require('@reldens/utils');
|
|
15
|
+
|
|
16
|
+
class PrismaRelationsMetadataExtractor
|
|
17
|
+
{
|
|
18
|
+
|
|
19
|
+
constructor(props)
|
|
20
|
+
{
|
|
21
|
+
this.prismaClient = sc.get(props, 'prismaClient', false);
|
|
22
|
+
this.projectRoot = sc.get(props, 'projectRoot', false);
|
|
23
|
+
this.projectPath = sc.get(props, 'projectPath', false);
|
|
24
|
+
this.metadataLoader = new PrismaMetadataLoader({prisma: this.prismaClient});
|
|
25
|
+
this.relationsMetadata = {};
|
|
26
|
+
this.schemaListRelations = {};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
extract()
|
|
30
|
+
{
|
|
31
|
+
if(!this.prismaClient){
|
|
32
|
+
Logger.warning('Missing PrismaClient for relations metadata extraction.');
|
|
33
|
+
return this.relationsMetadata;
|
|
34
|
+
}
|
|
35
|
+
let dmmf = this.metadataLoader.getDmmf();
|
|
36
|
+
if(!dmmf || !dmmf.models){
|
|
37
|
+
Logger.warning('Could not access Prisma DMMF for relations metadata.');
|
|
38
|
+
return this.relationsMetadata;
|
|
39
|
+
}
|
|
40
|
+
this.schemaListRelations = this.resolveSchemaListRelations();
|
|
41
|
+
this.processModels(dmmf.models);
|
|
42
|
+
Logger.info('Extracted relations metadata for '+Object.keys(this.relationsMetadata).length+' models.');
|
|
43
|
+
return this.relationsMetadata;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
processModels(models)
|
|
47
|
+
{
|
|
48
|
+
if(sc.isArray(models)){
|
|
49
|
+
for(let model of models){
|
|
50
|
+
this.processModel(sc.get(model, 'name', ''), model);
|
|
51
|
+
}
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
for(let modelName of Object.keys(models)){
|
|
55
|
+
this.processModel(modelName, models[modelName]);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
processModel(modelName, model)
|
|
60
|
+
{
|
|
61
|
+
if('' === modelName || !sc.isArray(sc.get(model, 'fields', false))){
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
let tableName = modelName.toLowerCase();
|
|
65
|
+
this.relationsMetadata[tableName] = {};
|
|
66
|
+
for(let field of model.fields){
|
|
67
|
+
if('object' !== field.kind){
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
let isListRelation = true === sc.get(sc.get(this.schemaListRelations, tableName, {}), field.name, false);
|
|
71
|
+
this.relationsMetadata[tableName][field.name] = {
|
|
72
|
+
type: isListRelation ? 'many' : 'one',
|
|
73
|
+
model: field.type,
|
|
74
|
+
isList: isListRelation,
|
|
75
|
+
isOptional: field.isOptional,
|
|
76
|
+
relationName: field.relationName
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
resolveSchemaPath()
|
|
82
|
+
{
|
|
83
|
+
let candidatePaths = [];
|
|
84
|
+
if(this.projectRoot){
|
|
85
|
+
candidatePaths.push(FileHandler.joinPaths(this.projectRoot, 'prisma', 'schema.prisma'));
|
|
86
|
+
}
|
|
87
|
+
candidatePaths.push(FileHandler.joinPaths(process.cwd(), 'prisma', 'schema.prisma'));
|
|
88
|
+
if(this.projectPath){
|
|
89
|
+
candidatePaths.push(FileHandler.joinPaths(this.projectPath, 'prisma', 'schema.prisma'));
|
|
90
|
+
}
|
|
91
|
+
for(let candidatePath of candidatePaths){
|
|
92
|
+
if(FileHandler.exists(candidatePath)){
|
|
93
|
+
return candidatePath;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
resolveSchemaListRelations()
|
|
100
|
+
{
|
|
101
|
+
let listRelations = {};
|
|
102
|
+
let schemaPath = this.resolveSchemaPath();
|
|
103
|
+
if(!schemaPath){
|
|
104
|
+
Logger.warning('Prisma schema.prisma not found; relation cardinality may fall back to one.');
|
|
105
|
+
return listRelations;
|
|
106
|
+
}
|
|
107
|
+
let schemaContent = FileHandler.readFile(schemaPath);
|
|
108
|
+
if(!schemaContent){
|
|
109
|
+
return listRelations;
|
|
110
|
+
}
|
|
111
|
+
let currentModel = '';
|
|
112
|
+
for(let schemaLine of schemaContent.toString().split('\n')){
|
|
113
|
+
let line = schemaLine.trim();
|
|
114
|
+
let modelMatch = line.match(/^model\s+(\w+)\s*\{/);
|
|
115
|
+
if(modelMatch){
|
|
116
|
+
currentModel = modelMatch[1].toLowerCase();
|
|
117
|
+
listRelations[currentModel] = {};
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
if('' === currentModel){
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
if('}' === line){
|
|
124
|
+
currentModel = '';
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
let listFieldMatch = line.match(/^(\w+)\s+\w+\[\]/);
|
|
128
|
+
if(listFieldMatch){
|
|
129
|
+
listRelations[currentModel][listFieldMatch[1]] = true;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return listRelations;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
module.exports.PrismaRelationsMetadataExtractor = PrismaRelationsMetadataExtractor;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reldens/storage",
|
|
3
3
|
"scope": "@reldens",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.106.0",
|
|
5
5
|
"description": "Reldens - Storage",
|
|
6
6
|
"author": "Damian A. Pastorini",
|
|
7
7
|
"license": "MIT",
|
|
@@ -51,16 +51,16 @@
|
|
|
51
51
|
"test:driver": "node tests/run-tests.js --driver="
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"@mikro-orm/core": "7.1.
|
|
55
|
-
"@mikro-orm/mongodb": "7.1.
|
|
56
|
-
"@mikro-orm/mysql": "7.1.
|
|
54
|
+
"@mikro-orm/core": "7.1.6",
|
|
55
|
+
"@mikro-orm/mongodb": "7.1.6",
|
|
56
|
+
"@mikro-orm/mysql": "7.1.6",
|
|
57
57
|
"@prisma/adapter-mariadb": "7.8.0",
|
|
58
58
|
"@prisma/client": "7.8.0",
|
|
59
59
|
"@reldens/server-utils": "^0.53.0",
|
|
60
60
|
"@reldens/utils": "^0.57.0",
|
|
61
61
|
"knex": "3.3.0",
|
|
62
62
|
"mysql": "2.18.1",
|
|
63
|
-
"mysql2": "3.
|
|
63
|
+
"mysql2": "3.23.0",
|
|
64
64
|
"objection": "3.1.5",
|
|
65
65
|
"prisma": "7.8.0"
|
|
66
66
|
}
|
package/tests/run-tests.js
CHANGED
|
@@ -15,6 +15,7 @@ const RawQueriesTest = require('./integration/test-raw-queries');
|
|
|
15
15
|
const EntityManagerTest = require('./unit/test-entity-manager');
|
|
16
16
|
const TypeMapperTest = require('./unit/test-type-mapper');
|
|
17
17
|
const DriversUnitTest = require('./unit/test-drivers');
|
|
18
|
+
const EntitiesGenerationTest = require('./unit/test-entities-generation');
|
|
18
19
|
|
|
19
20
|
if(!process.env.RELDENS_TEST_DB_HOST){
|
|
20
21
|
let envPath = FileHandler.joinPaths(__dirname, '.env.test');
|
|
@@ -187,6 +188,11 @@ class RunTests
|
|
|
187
188
|
this.allCounts.total += driversUnitResult.total;
|
|
188
189
|
this.allCounts.passed += driversUnitResult.passed;
|
|
189
190
|
this.allCounts.failed += driversUnitResult.failed;
|
|
191
|
+
let entitiesGenerationTest = new EntitiesGenerationTest();
|
|
192
|
+
let entitiesGenerationResult = await entitiesGenerationTest.run();
|
|
193
|
+
this.allCounts.total += entitiesGenerationResult.total;
|
|
194
|
+
this.allCounts.passed += entitiesGenerationResult.passed;
|
|
195
|
+
this.allCounts.failed += entitiesGenerationResult.failed;
|
|
190
196
|
}
|
|
191
197
|
|
|
192
198
|
async runPreFlightChecks(config)
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* Reldens - EntitiesGeneration Test
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { TestRunner, assert } = require('../utils/test-runner');
|
|
8
|
+
const { EntitiesGeneration } = require('../../lib/generators/entities-generation');
|
|
9
|
+
|
|
10
|
+
class EntitiesGenerationTest
|
|
11
|
+
{
|
|
12
|
+
|
|
13
|
+
constructor()
|
|
14
|
+
{
|
|
15
|
+
this.runner = new TestRunner();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
createColumn(props)
|
|
19
|
+
{
|
|
20
|
+
return Object.assign(
|
|
21
|
+
{
|
|
22
|
+
name: 'test_column',
|
|
23
|
+
type: 'varchar',
|
|
24
|
+
columnType: 'varchar(100)',
|
|
25
|
+
length: '100',
|
|
26
|
+
nullable: true,
|
|
27
|
+
key: '',
|
|
28
|
+
extra: '',
|
|
29
|
+
default: null
|
|
30
|
+
},
|
|
31
|
+
props
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async run()
|
|
36
|
+
{
|
|
37
|
+
this.runner.suite('EntitiesGeneration');
|
|
38
|
+
await this.testAddUniqueAttribute();
|
|
39
|
+
await this.testGetPropertyAttributesUnique();
|
|
40
|
+
await this.testGeneratePropertiesConfigUnique();
|
|
41
|
+
return this.runner.getResults();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async testAddUniqueAttribute()
|
|
45
|
+
{
|
|
46
|
+
this.runner.group('addUniqueAttribute');
|
|
47
|
+
let generation = new EntitiesGeneration({});
|
|
48
|
+
await this.runner.test('should push isUnique for a UNI column', async () => {
|
|
49
|
+
let props = [];
|
|
50
|
+
generation.addUniqueAttribute(props, this.createColumn({key: 'UNI'}));
|
|
51
|
+
assert.deepStrictEqual(props, ['isUnique: true']);
|
|
52
|
+
});
|
|
53
|
+
await this.runner.test('should not push isUnique for a non indexed column', async () => {
|
|
54
|
+
let props = [];
|
|
55
|
+
generation.addUniqueAttribute(props, this.createColumn({key: ''}));
|
|
56
|
+
assert.deepStrictEqual(props, []);
|
|
57
|
+
});
|
|
58
|
+
await this.runner.test('should not push isUnique for a MUL column', async () => {
|
|
59
|
+
let props = [];
|
|
60
|
+
generation.addUniqueAttribute(props, this.createColumn({key: 'MUL'}));
|
|
61
|
+
assert.deepStrictEqual(props, []);
|
|
62
|
+
});
|
|
63
|
+
await this.runner.test('should not push isUnique for a PRI column', async () => {
|
|
64
|
+
let props = [];
|
|
65
|
+
generation.addUniqueAttribute(props, this.createColumn({key: 'PRI'}));
|
|
66
|
+
assert.deepStrictEqual(props, []);
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async testGetPropertyAttributesUnique()
|
|
71
|
+
{
|
|
72
|
+
this.runner.group('getPropertyAttributes - isUnique');
|
|
73
|
+
let generation = new EntitiesGeneration({});
|
|
74
|
+
await this.runner.test('should include isUnique for a UNI column', async () => {
|
|
75
|
+
let column = this.createColumn({name: 'slug', key: 'UNI'});
|
|
76
|
+
let props = generation.getPropertyAttributes(column, 'slug', {});
|
|
77
|
+
assert.ok(props.includes('isUnique: true'));
|
|
78
|
+
});
|
|
79
|
+
await this.runner.test('should not include isUnique for a non unique column', async () => {
|
|
80
|
+
let column = this.createColumn({name: 'tags', key: ''});
|
|
81
|
+
let props = generation.getPropertyAttributes(column, 'tags', {});
|
|
82
|
+
assert.deepStrictEqual(props, ['dbType: \'varchar\'']);
|
|
83
|
+
});
|
|
84
|
+
await this.runner.test('should include both isRequired and isUnique for a required unique column', async () => {
|
|
85
|
+
let column = this.createColumn({name: 'sku', key: 'UNI', nullable: false});
|
|
86
|
+
let props = generation.getPropertyAttributes(column, 'sku', {});
|
|
87
|
+
assert.deepStrictEqual(props, ['isRequired: true', 'isUnique: true', 'dbType: \'varchar\'']);
|
|
88
|
+
});
|
|
89
|
+
await this.runner.test('should include isUnique only for a nullable unique column', async () => {
|
|
90
|
+
let column = this.createColumn({name: 'sku', key: 'UNI', nullable: true});
|
|
91
|
+
let props = generation.getPropertyAttributes(column, 'sku', {});
|
|
92
|
+
assert.deepStrictEqual(props, ['isUnique: true', 'dbType: \'varchar\'']);
|
|
93
|
+
});
|
|
94
|
+
await this.runner.test('should not include isUnique for a composite unique member column', async () => {
|
|
95
|
+
let column = this.createColumn({name: 'owner_id', type: 'int', key: 'MUL', nullable: false});
|
|
96
|
+
let props = generation.getPropertyAttributes(column, 'owner_id', {});
|
|
97
|
+
assert.deepStrictEqual(props, ['type: \'number\'', 'isRequired: true', 'dbType: \'int\'']);
|
|
98
|
+
});
|
|
99
|
+
await this.runner.test('should not include isUnique for the primary key column', async () => {
|
|
100
|
+
let column = this.createColumn({name: 'id', type: 'int', key: 'PRI', nullable: false, extra: 'auto_increment'});
|
|
101
|
+
let props = generation.getPropertyAttributes(column, 'id', {});
|
|
102
|
+
assert.deepStrictEqual(props, ['type: \'number\'', 'isRequired: true', 'dbType: \'int\'']);
|
|
103
|
+
});
|
|
104
|
+
await this.runner.test('should include isUnique for a unique reference column', async () => {
|
|
105
|
+
let column = this.createColumn({
|
|
106
|
+
name: 'profile_id',
|
|
107
|
+
type: 'int',
|
|
108
|
+
key: 'UNI',
|
|
109
|
+
nullable: false,
|
|
110
|
+
referencedTable: 'profiles',
|
|
111
|
+
referencedColumn: 'id'
|
|
112
|
+
});
|
|
113
|
+
let props = generation.getPropertyAttributes(column, 'profile_id', {profiles: 1});
|
|
114
|
+
assert.deepStrictEqual(props, [
|
|
115
|
+
'type: \'reference\'',
|
|
116
|
+
'reference: \'profiles\'',
|
|
117
|
+
'alias: \'related_profiles\'',
|
|
118
|
+
'isRequired: true',
|
|
119
|
+
'isUnique: true',
|
|
120
|
+
'dbType: \'int\''
|
|
121
|
+
]);
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
async testGeneratePropertiesConfigUnique()
|
|
126
|
+
{
|
|
127
|
+
this.runner.group('generatePropertiesConfig - isUnique');
|
|
128
|
+
let generation = new EntitiesGeneration({});
|
|
129
|
+
await this.runner.test('should render isUnique in the generated properties config', async () => {
|
|
130
|
+
let columns = {
|
|
131
|
+
id: this.createColumn({name: 'id', type: 'int', key: 'PRI', nullable: false}),
|
|
132
|
+
slug: this.createColumn({name: 'slug', key: 'UNI', nullable: false}),
|
|
133
|
+
tags: this.createColumn({name: 'tags', key: ''})
|
|
134
|
+
};
|
|
135
|
+
let propertiesConfig = generation.generatePropertiesConfig(columns, false, 'id');
|
|
136
|
+
assert.ok(propertiesConfig.includes('slug: {'));
|
|
137
|
+
assert.ok(propertiesConfig.includes('isUnique: true'));
|
|
138
|
+
assert.strictEqual(propertiesConfig.split('isUnique: true').length - 1, 1);
|
|
139
|
+
});
|
|
140
|
+
await this.runner.test('should not render isUnique when no unique columns exist', async () => {
|
|
141
|
+
let columns = {
|
|
142
|
+
id: this.createColumn({name: 'id', type: 'int', key: 'PRI', nullable: false}),
|
|
143
|
+
tags: this.createColumn({name: 'tags', key: ''})
|
|
144
|
+
};
|
|
145
|
+
let propertiesConfig = generation.generatePropertiesConfig(columns, false, 'id');
|
|
146
|
+
assert.ok(!propertiesConfig.includes('isUnique'));
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
module.exports = EntitiesGenerationTest;
|