@reldens/storage 0.53.0 → 0.55.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.
@@ -9,7 +9,10 @@ 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 { TypeMapper } = require('./type-mapper');
12
+ const { EntitiesGeneration } = require('./generators/entities-generation');
13
+ const { ModelsGeneration } = require('./generators/models-generation');
14
+ const { EntitiesConfigGeneration } = require('./generators/entities-config-generation');
15
+ const { EntitiesTranslationsGeneration } = require('./generators/entities-translations-generation');
13
16
 
14
17
  class EntitiesGenerator
15
18
  {
@@ -49,352 +52,26 @@ class EntitiesGenerator
49
52
  this.existingEntities = {};
50
53
  this.existingEntityFields = {};
51
54
  this.existingModels = {};
52
- }
53
-
54
- async generateEntityFile(tableName, tableData)
55
- {
56
- let entityTemplatePath = this.templates['entity'];
57
- if(!FileHandler.exists(entityTemplatePath)){
58
- Logger.critical('Entity template file not found: '+entityTemplatePath);
59
- return false;
60
- }
61
- let entityTemplateContent = FileHandler.fetchFileContents(entityTemplatePath);
62
- if(!entityTemplateContent){
63
- Logger.critical('Failed to read entity template file: '+entityTemplatePath);
64
- return false;
65
- }
66
- let entityClassName = sc.capitalizedCamelCase(tableName)+'Entity';
67
- let titleProperty = this.determineTitleProperty(tableData.columns);
68
- for(let columnName of Object.keys(tableData.columns)){
69
- tableData.columns[columnName].tableName = tableName;
70
- }
71
- let propertiesConfig = this.generatePropertiesConfig(tableData.columns, titleProperty);
72
- let titlePropertyDeclaration = titleProperty ? '\n let titleProperty = \''+titleProperty+'\';' : '';
73
- let titlePropertyReturn = titleProperty ? '\n titleProperty,' : '';
74
- let fieldsToRemoveFromEdit = ['id'];
75
- if(tableData.columns['created_at']){
76
- fieldsToRemoveFromEdit.push('created_at');
77
- }
78
- if(tableData.columns['updated_at']){
79
- fieldsToRemoveFromEdit.push('updated_at');
80
- }
81
- let editPropertiesRemoval = this.getEditPropertiesRemoval(fieldsToRemoveFromEdit);
82
- let listPropertiesDeclaration = this.getListPropertiesDeclaration(tableData.columns);
83
- let showPropertiesDeclaration = this.getShowPropertiesDeclaration(tableData.columns);
84
- let needsSc = listPropertiesDeclaration.includes('sc.removeFromArray')
85
- || editPropertiesRemoval.includes('sc.removeFromArray')
86
- || showPropertiesDeclaration.includes('sc.removeFromArray');
87
- let scRequire = needsSc ? '\nconst { sc } = require(\'@reldens/utils\');' : '';
88
- let replacements = {
89
- entityClassName,
90
- propertiesConfig,
91
- titlePropertyDeclaration,
92
- titlePropertyReturn,
93
- showPropertiesDeclaration,
94
- editPropertiesRemoval,
95
- listPropertiesDeclaration,
96
- scRequire
97
- };
98
- let entityContent = this.applyReplacements(entityTemplateContent, replacements);
99
- let fileName = sc.kebabCase(tableName)+'-entity.js';
100
- let filePath = FileHandler.joinPaths(this.entitiesFolder, fileName);
101
- if(!FileHandler.writeFile(filePath, entityContent)){
102
- Logger.critical('Failed to write entity file: '+filePath);
103
- return false;
104
- }
105
- Logger.info('Generated entity file: '+fileName);
106
- this.generatedEntities[tableName] = {
107
- entityClassName,
108
- entityFileName: fileName,
109
- tableName,
110
- titleProperty
111
- };
112
- return true;
113
- }
114
-
115
- getFieldsToRemoveFromList(columns)
116
- {
117
- let fieldsToRemove = [];
118
- for(let columnName of Object.keys(columns)){
119
- let column = columns[columnName];
120
- let type = column.type.toLowerCase();
121
- if(['text', 'json', 'tinytext', 'mediumtext', 'longtext'].includes(type)){
122
- fieldsToRemove.push(columnName);
123
- }
124
- if('password' === columnName.toLowerCase()){
125
- fieldsToRemove.push(columnName);
126
- }
127
- }
128
- return fieldsToRemove;
129
- }
130
-
131
- getEditPropertiesRemoval(fieldsToRemove)
132
- {
133
- if(1 === fieldsToRemove.length){
134
- return 'let editProperties = [...propertiesKeys];\n editProperties.splice(editProperties.indexOf(\''+
135
- fieldsToRemove[0]
136
- +'\'), 1);';
137
- }
138
- return 'let editProperties = sc.removeFromArray([...propertiesKeys], [\''+fieldsToRemove.join('\', \'')+'\']);';
139
- }
140
-
141
- determineTitleProperty(columns)
142
- {
143
- if(columns['label']){
144
- return 'label';
145
- }
146
- if(columns['title']){
147
- return 'title';
148
- }
149
- if(columns['name']){
150
- return 'name';
151
- }
152
- if(columns['key']){
153
- return 'key';
154
- }
155
- return false;
156
- }
157
-
158
- generatePropertiesConfig(columns, titleProperty)
159
- {
160
- let propertiesConfig = [];
161
- for(let columnName of Object.keys(columns)){
162
- let column = columns[columnName];
163
- let propertyKey = titleProperty && titleProperty === columnName ? '[titleProperty]' : columnName;
164
- if('id' === columnName){
165
- propertiesConfig.push(columnName+': {}');
166
- continue;
167
- }
168
- let props = this.getPropertyAttributes(column);
169
- if(0 === props.length){
170
- propertiesConfig.push(propertyKey+': {}');
171
- continue;
172
- }
173
- propertiesConfig.push(
174
- propertyKey+': {\n '+props.join(',\n ')+ '\n }'
175
- );
176
- }
177
- return propertiesConfig.join(',\n ');
178
- }
179
-
180
- getPropertyAttributes(column)
181
- {
182
- let props = [];
183
- let type = column.type.toLowerCase();
184
- this.addTypeAttribute(props, column, type);
185
- this.addRequiredAttribute(props, column);
186
- return props;
187
- }
188
-
189
- addTypeAttribute(props, column, type)
190
- {
191
- if(column.referencedTable){
192
- props.push('type: \'reference\'');
193
- props.push('reference: \''+this.getReferenceTable(column)+'\'');
194
- return;
195
- }
196
- if('date' === type || 'datetime' === type || 'timestamp' === type){
197
- props.push('type: \'datetime\'');
198
- return;
199
- }
200
- if('text' === type || 'longtext' === type || 'mediumtext' === type || 'tinytext' === type || 'json' === type){
201
- props.push('type: \'textarea\'');
202
- return;
203
- }
204
- if('tinyint' === type){
205
- props.push('type: \'boolean\'');
206
- return;
207
- }
208
- if('enum' === type){
209
- this.addEnumValues(props, column);
210
- return;
211
- }
212
- if(type.includes('int')){
213
- props.push('type: \'number\'');
214
- return;
215
- }
216
- if('varchar' === type || 'char' === type){
217
- return;
218
- }
219
- let jsType = TypeMapper.mapDbTypeToJsType(type);
220
- if(jsType && 'string' !== jsType){
221
- props.push('type: \''+jsType+'\'');
222
- }
223
- }
224
-
225
- addEnumValues(props, column)
226
- {
227
- let enumValues = this.parseEnumValues(column.columnType);
228
- if(0 === enumValues.length){
229
- return;
230
- }
231
- let availableValues = [];
232
- for(let i = 0; i < enumValues.length; i++){
233
- availableValues.push('{value: '+(i+1)+', label: \''+enumValues[i]+'\'}');
234
- }
235
- props.push(
236
- 'availableValues: [\n '+
237
- availableValues.join(',\n ')+
238
- '\n ]'
239
- );
240
- }
241
-
242
- parseEnumValues(columnType)
243
- {
244
- if(!columnType){
245
- return [];
246
- }
247
- let match = columnType.match(/^enum\('(.+)'\)$/i);
248
- if(!match){
249
- return [];
250
- }
251
- let valuesString = match[1];
252
- return valuesString.split('\',\'');
253
- }
254
-
255
- addRequiredAttribute(props, column)
256
- {
257
- if(!column.nullable && !column.default){
258
- props.push('isRequired: true');
259
- }
260
- }
261
-
262
- getReferenceTable(column)
263
- {
264
- if(column.referencedTable){
265
- return column.referencedTable;
266
- }
267
- let refTableName = column.name.replace('_id', '');
268
- if(refTableName.includes('_')){
269
- let parts = refTableName.split('_');
270
- if(column.tableName && column.tableName === parts[0]){
271
- refTableName = parts.slice(1).join('_');
272
- }
273
- }
274
- return refTableName;
275
- }
276
-
277
- getShowPropertiesDeclaration(columns)
278
- {
279
- let passwordFields = this.getPasswordFields(columns);
280
- if(0 === passwordFields.length){
281
- return 'let showProperties = propertiesKeys;';
282
- }
283
- if(1 === passwordFields.length){
284
- return 'let showProperties = [...propertiesKeys];\n showProperties.splice(showProperties.indexOf(\''+
285
- passwordFields[0]+
286
- '\'), 1);';
287
- }
288
- return 'let showProperties = sc.removeFromArray([...propertiesKeys], [\''+passwordFields.join('\', \'')+'\']);';
289
- }
290
-
291
- getPasswordFields(columns)
292
- {
293
- let passwordFields = [];
294
- for(let columnName of Object.keys(columns)){
295
- if('password' === columnName.toLowerCase()){
296
- passwordFields.push(columnName);
297
- }
298
- }
299
- return passwordFields;
300
- }
301
-
302
- getListPropertiesDeclaration(columns)
303
- {
304
- let fieldsToRemove = this.getFieldsToRemoveFromList(columns);
305
- if(0 === fieldsToRemove.length){
306
- return 'let listProperties = propertiesKeys;';
307
- }
308
- if(1 === fieldsToRemove.length){
309
- return 'let listProperties = [...propertiesKeys];\n listProperties.splice(listProperties.indexOf(\''+
310
- fieldsToRemove[0]+
311
- '\'), 1);';
312
- }
313
- return 'let listProperties = sc.removeFromArray([...propertiesKeys], [\''+fieldsToRemove.join('\', \'')+'\']);';
314
- }
315
-
316
- async generateModelFile(tableName, tableData, driverKey)
317
- {
318
- let modelTemplatePath = this.templates[driverKey];
319
- if(!FileHandler.exists(modelTemplatePath)){
320
- Logger.critical('Model template file "'+modelTemplatePath+'" not found for driver "'+driverKey+'".');
321
- return false;
322
- }
323
- let modelTemplateContent = FileHandler.fetchFileContents(modelTemplatePath);
324
- if(!modelTemplateContent){
325
- Logger.critical('Failed to read model template file: '+modelTemplatePath);
326
- return false;
327
- }
328
- let modelClassName = sc.capitalizedCamelCase(tableName)+'Model';
329
- let modelPropertiesList = Object.keys(tableData.columns).join(', ');
330
- let modelPropertiesConstructor = Object.keys(tableData.columns)
331
- .map(columnName => 'this.'+columnName+' = '+columnName+';')
332
- .join('\n ');
333
- let modelRelations = '';
334
- let entityPropertiesDefinition = this.getEntityPropertiesDefinition(tableData.columns, driverKey);
335
- let replacements = {
336
- modelClassName,
337
- tableName: 'prisma' === driverKey ? tableName.toLowerCase() : tableName,
338
- modelPropertiesList,
339
- modelPropertiesConstructor,
340
- modelRelations,
341
- entityPropertiesDefinition
342
- };
343
- let modelContent = this.applyReplacements(modelTemplateContent, replacements);
344
- let fileName = sc.kebabCase(tableName)+'-model.js';
345
- let driverFolder = FileHandler.joinPaths(this.modelsFolder, driverKey);
346
- FileHandler.createFolder(driverFolder);
347
- let filePath = FileHandler.joinPaths(driverFolder, fileName);
348
- if(!FileHandler.writeFile(filePath, modelContent)){
349
- Logger.critical('Failed to write model file: '+fileName);
350
- return false;
351
- }
352
- Logger.info('Generated model file: '+fileName);
353
- this.generatedEntities[tableName].modelClassName = modelClassName;
354
- this.generatedEntities[tableName].modelFileName = fileName;
355
- this.generatedEntities[tableName].driverKey = driverKey;
356
- return true;
357
- }
358
-
359
- getEntityPropertiesDefinition(columns, driverKey)
360
- {
361
- if('mikro-orm' === driverKey){
362
- let entityProps = [];
363
- for(let columnName of Object.keys(columns)){
364
- let column = columns[columnName];
365
- let isPrimary = 'PRI' === column.key;
366
- let type = TypeMapper.mapDbTypeToJsType(column.type);
367
- let propDef = columnName+': { type: \''+type+'\'';
368
- if(isPrimary){
369
- propDef += ', primary: true';
370
- }
371
- if(column.nullable){
372
- propDef += ', nullable: true';
373
- }
374
- propDef += ' }';
375
- entityProps.push(propDef);
376
- }
377
- return entityProps.join(',\n ');
378
- }
379
- if('prisma' === driverKey){
380
- let prismaProps = [];
381
- for(let columnName of Object.keys(columns)){
382
- let column = columns[columnName];
383
- let prismaType = TypeMapper.mapDbTypeToPrismaType(column.type);
384
- let isPrimary = 'PRI' === column.key;
385
- let propDef = columnName+': {\n type: \''+prismaType+'\'';
386
- if(isPrimary){
387
- propDef += ',\n id: true';
388
- }
389
- if(column.nullable){
390
- propDef += ',\n optional: true';
391
- }
392
- propDef += '\n }';
393
- prismaProps.push(propDef);
55
+ this.entitiesGeneration = new EntitiesGeneration({
56
+ entitiesFolder: this.entitiesFolder,
57
+ templatePath: this.templates['entity']
58
+ });
59
+ this.modelsGeneration = new ModelsGeneration({
60
+ modelsFolder: this.modelsFolder,
61
+ templates: {
62
+ 'objection-js': this.templates['objection-js'],
63
+ 'mikro-orm': this.templates['mikro-orm'],
64
+ 'prisma': this.templates['prisma']
394
65
  }
395
- return prismaProps.join(',\n ');
396
- }
397
- return '';
66
+ });
67
+ this.entitiesConfigGeneration = new EntitiesConfigGeneration({
68
+ entitiesConfigPath: this.entitiesConfigPath,
69
+ templatePath: this.templates['entities-config']
70
+ });
71
+ this.entitiesTranslationsGeneration = new EntitiesTranslationsGeneration({
72
+ entitiesTranslationsPath: this.entitiesTranslationsPath,
73
+ templatePath: this.templates['entities-translations']
74
+ });
398
75
  }
399
76
 
400
77
  detectExistingEntities()
@@ -411,7 +88,6 @@ class EntitiesGenerator
411
88
  this.existingEntities[tableName] = {entityFileName: file, tableName};
412
89
  this.detectExistingEntityFields(tableName, file);
413
90
  }
414
- this.detectExistingModels();
415
91
  Logger.info('Detected '+Object.keys(this.existingEntities).length+' existing entities.');
416
92
  }
417
93
 
@@ -438,6 +114,7 @@ class EntitiesGenerator
438
114
  };
439
115
  }
440
116
  }
117
+ Logger.info('Detected '+Object.keys(this.existingModels).length+' existing models.');
441
118
  }
442
119
 
443
120
  detectExistingEntityFields(tableName, fileName)
@@ -552,11 +229,7 @@ class EntitiesGenerator
552
229
 
553
230
  entityExistsInConfig(tableName)
554
231
  {
555
- if(!FileHandler.exists(this.entitiesConfigPath)){
556
- return false;
557
- }
558
- let configContent = FileHandler.readFile(this.entitiesConfigPath);
559
- return configContent && configContent.includes(sc.camelCase(tableName)+':');
232
+ return this.entitiesConfigGeneration.entityExistsInConfig(tableName, FileHandler.readFile(this.entitiesConfigPath));
560
233
  }
561
234
 
562
235
  modelExistsInRegistered(tableName, driverKey)
@@ -569,337 +242,6 @@ class EntitiesGenerator
569
242
  return registeredContent && registeredContent.includes(sc.camelCase(tableName)+':');
570
243
  }
571
244
 
572
- generateEntitiesConfigFile()
573
- {
574
- if(this.isOverride){
575
- return this.regenerateEntitiesConfigFile();
576
- }
577
- return this.appendToEntitiesConfigFile();
578
- }
579
-
580
- regenerateEntitiesConfigFile()
581
- {
582
- let configTemplateContent = FileHandler.fetchFileContents(this.templates['entities-config']);
583
- if(!configTemplateContent){
584
- Logger.critical('Failed to read entities config template file: '+this.templates['entities-config']);
585
- return false;
586
- }
587
- let allEntities = Object.assign({}, this.existingEntities, this.generatedEntities);
588
- let replacements = {
589
- requireStatements: this.getRequireStatements(allEntities),
590
- entitiesConfigExport: this.getEntitiesConfigExport(allEntities)
591
- };
592
- if(!FileHandler.writeFile(
593
- this.entitiesConfigPath,
594
- this.applyReplacements(configTemplateContent, replacements)
595
- )){
596
- Logger.critical('Failed to write entities config file: '+this.entitiesConfigPath);
597
- return false;
598
- }
599
- Logger.info('Regenerated entities config file: '+this.entitiesConfigPath);
600
- return true;
601
- }
602
-
603
- appendToEntitiesConfigFile()
604
- {
605
- if(0 === Object.keys(this.generatedEntities).length){
606
- return true;
607
- }
608
- if(!FileHandler.exists(this.entitiesConfigPath)){
609
- Logger.error('Entities config file does not exist, cannot append new entities.');
610
- return false;
611
- }
612
- let existingContent = FileHandler.readFile(this.entitiesConfigPath);
613
- if(!existingContent){
614
- Logger.error('Could not read existing entities config file.');
615
- return false;
616
- }
617
- let newRequires = [];
618
- let newConfigs = [];
619
- for(let tableName of Object.keys(this.generatedEntities)){
620
- let entity = this.generatedEntities[tableName];
621
- let entityClassName = sc.get(entity, 'entityClassName', sc.capitalizedCamelCase(tableName)+'Entity');
622
- let entityFileName = sc.get(entity, 'entityFileName', sc.kebabCase(tableName)+'-entity').replace('.js', '');
623
- let requireStatement = 'const { '+ entityClassName+' } = require(\'./entities/'+entityFileName+'\');';
624
- let configEntry = sc.camelCase(tableName)+': '+entityClassName+'.propertiesConfig()';
625
- if(!existingContent.includes(requireStatement)){
626
- newRequires.push(requireStatement);
627
- }
628
- if(!this.entityExistsInConfig(tableName)){
629
- newConfigs.push(configEntry);
630
- }
631
- }
632
- if(0 === newRequires.length && 0 === newConfigs.length){
633
- return true;
634
- }
635
- let normalizedContent = existingContent.replace(/\s+/g, ' ');
636
- let entitiesConfigPattern = /let\s+entitiesConfig\s*=\s*\{/;
637
- let entitiesConfigMatch = normalizedContent.match(entitiesConfigPattern);
638
- if(!entitiesConfigMatch){
639
- Logger.error('Could not find entitiesConfig variable in config file.');
640
- return false;
641
- }
642
- let entitiesConfigStart = existingContent.indexOf(entitiesConfigMatch[0]);
643
- let searchStart = entitiesConfigStart + entitiesConfigMatch[0].length;
644
- let braceCount = 1;
645
- let entitiesConfigEnd = -1;
646
- for(let i = searchStart; i < existingContent.length; i++){
647
- if('{' === existingContent[i]){
648
- braceCount++;
649
- }
650
- if('}' === existingContent[i]){
651
- braceCount--;
652
- if(0 === braceCount){
653
- entitiesConfigEnd = i;
654
- break;
655
- }
656
- }
657
- }
658
- if(-1 === entitiesConfigEnd){
659
- Logger.error('Could not find end of entitiesConfig object.');
660
- return false;
661
- }
662
- let firstRequirePosition = existingContent.indexOf('const {');
663
- if(-1 === firstRequirePosition){
664
- Logger.error('Could not find require statements in config file.');
665
- return false;
666
- }
667
- let beforeFirstRequire = existingContent.substring(0, firstRequirePosition);
668
- let afterFirstRequire = existingContent.substring(firstRequirePosition, entitiesConfigEnd);
669
- let afterConfig = existingContent.substring(entitiesConfigEnd);
670
- let updatedContent = beforeFirstRequire;
671
- if(0 < newRequires.length){
672
- updatedContent += newRequires.join('\n') + '\n';
673
- }
674
- updatedContent += afterFirstRequire;
675
- if(0 < newConfigs.length){
676
- let trimmedContent = afterFirstRequire.trimEnd();
677
- if(!trimmedContent.endsWith(',')){
678
- updatedContent = updatedContent.trimEnd() + ',';
679
- }
680
- updatedContent += '\n ' + newConfigs.join(',\n ');
681
- }
682
- updatedContent += afterConfig;
683
- if(!FileHandler.writeFile(this.entitiesConfigPath, updatedContent)){
684
- Logger.error('Failed to append to entities config file: '+this.entitiesConfigPath);
685
- return false;
686
- }
687
- Logger.info('Updated entities config file with '+newConfigs.length+' new entities.');
688
- return true;
689
- }
690
-
691
- getRequireStatements(allEntities)
692
- {
693
- let requireStatements = [];
694
- for(let tableName of Object.keys(allEntities)){
695
- let entity = allEntities[tableName];
696
- let entityClassName = sc.get(entity, 'entityClassName', sc.capitalizedCamelCase(tableName)+'Entity');
697
- let entityFileName = sc.get(entity, 'entityFileName', sc.kebabCase(tableName)+'-entity').replace('.js', '');
698
- requireStatements.push(
699
- 'const { '+ entityClassName+' } = require(\'./entities/'+entityFileName+'\');'
700
- );
701
- }
702
- return requireStatements.join('\n');
703
- }
704
-
705
- getEntitiesConfigExport(allEntities)
706
- {
707
- let entitiesConfigExport = [];
708
- for(let tableName of Object.keys(allEntities)){
709
- entitiesConfigExport.push(
710
- sc.camelCase(tableName)+': '
711
- +sc.get(allEntities[tableName], 'entityClassName', sc.capitalizedCamelCase(tableName)+'Entity')
712
- +'.propertiesConfig()'
713
- );
714
- }
715
- return entitiesConfigExport.join(',\n ');
716
- }
717
-
718
- generateEntitiesTranslationsFile()
719
- {
720
- if(this.isOverride){
721
- return this.regenerateEntitiesTranslationsFile();
722
- }
723
- return this.appendToEntitiesTranslationsFile();
724
- }
725
-
726
- regenerateEntitiesTranslationsFile()
727
- {
728
- let translationsTemplatePath = this.templates['entities-translations'];
729
- if(!FileHandler.exists(translationsTemplatePath)){
730
- Logger.critical('Entities translations template file not found: '+translationsTemplatePath);
731
- return false;
732
- }
733
- let translationsTemplateContent = FileHandler.fetchFileContents(translationsTemplatePath);
734
- if(!translationsTemplateContent){
735
- Logger.critical('Failed to read entities translations template file: '+translationsTemplatePath);
736
- return false;
737
- }
738
- let translationsContent = translationsTemplateContent.replace(
739
- /{{labels}}/g,
740
- this.getTranslationLabels(Object.assign({}, this.existingEntities, this.generatedEntities))
741
- );
742
- if(!FileHandler.writeFile(this.entitiesTranslationsPath, translationsContent)){
743
- Logger.critical('Failed to write entities translations file: '+this.entitiesTranslationsPath);
744
- return false;
745
- }
746
- Logger.info('Regenerated entities translations file: '+this.entitiesTranslationsPath);
747
- return true;
748
- }
749
-
750
- appendToEntitiesTranslationsFile()
751
- {
752
- if(0 === Object.keys(this.generatedEntities).length){
753
- return true;
754
- }
755
- if(!FileHandler.exists(this.entitiesTranslationsPath)){
756
- Logger.error('Entities translations file does not exist, cannot append new entities.');
757
- return false;
758
- }
759
- let existingContent = FileHandler.readFile(this.entitiesTranslationsPath);
760
- if(!existingContent){
761
- Logger.error('Could not read existing translations file.');
762
- return false;
763
- }
764
- let newTranslations = [];
765
- for(let tableName of Object.keys(this.generatedEntities)){
766
- if(!existingContent.includes('\''+tableName+'\':')){
767
- newTranslations.push(
768
- '\''+tableName+'\': \''
769
- +tableName.split('_').map(word => word.charAt(0).toUpperCase()+word.slice(1)).join(' ')+'\''
770
- );
771
- }
772
- }
773
- if(0 === newTranslations.length){
774
- return true;
775
- }
776
- let normalizedContent = existingContent.replace(/\s+/g, ' ');
777
- let labelsPattern = /labels\s*:\s*\{/;
778
- let labelsMatch = normalizedContent.match(labelsPattern);
779
- if(!labelsMatch){
780
- Logger.error('Could not find labels object in translations file.');
781
- return false;
782
- }
783
- let labelsStart = existingContent.indexOf(labelsMatch[0]);
784
- let searchStart = labelsStart + labelsMatch[0].length;
785
- let braceCount = 1;
786
- let labelsEnd = -1;
787
- for(let i = searchStart; i < existingContent.length; i++){
788
- if('{' === existingContent[i]){
789
- braceCount++;
790
- }
791
- if('}' === existingContent[i]){
792
- braceCount--;
793
- if(0 === braceCount){
794
- labelsEnd = i;
795
- break;
796
- }
797
- }
798
- }
799
- if(-1 === labelsEnd){
800
- Logger.error('Could not find end of labels object.');
801
- return false;
802
- }
803
- let beforeLabelsEnd = existingContent.substring(0, labelsEnd);
804
- let contentBeforeEnd = beforeLabelsEnd.trimEnd();
805
- let lastChar = contentBeforeEnd[contentBeforeEnd.length - 1];
806
- if('{' !== lastChar && ',' !== lastChar){
807
- beforeLabelsEnd = contentBeforeEnd + ',';
808
- }
809
- let updatedContent = beforeLabelsEnd + '\n ' + newTranslations.join(',\n ') + existingContent.substring(labelsEnd);
810
- if(!FileHandler.writeFile(this.entitiesTranslationsPath, updatedContent)){
811
- Logger.error('Failed to append to entities translations file: '+this.entitiesTranslationsPath);
812
- return false;
813
- }
814
- Logger.info('Updated translations file with '+newTranslations.length+' new labels.');
815
- return true;
816
- }
817
-
818
- getTranslationLabels(allEntities)
819
- {
820
- let labels = [];
821
- for(let tableName of Object.keys(allEntities)){
822
- labels.push(
823
- '\''+tableName+'\': \''
824
- +tableName.split('_').map(word => word.charAt(0).toUpperCase()+word.slice(1)).join(' ')
825
- +'\''
826
- );
827
- }
828
- return labels.join(',\n ');
829
- }
830
-
831
- generateRegisteredModelsFile(driverKey)
832
- {
833
- let registeredTemplatePath = this.templates['registered-models'];
834
- if(!FileHandler.exists(registeredTemplatePath)){
835
- Logger.critical('Registered models template file not found: '+registeredTemplatePath);
836
- return false;
837
- }
838
- let registeredTemplateContent = FileHandler.fetchFileContents(registeredTemplatePath);
839
- if(!registeredTemplateContent){
840
- Logger.critical('Failed to read registered models template file: '+registeredTemplatePath);
841
- return false;
842
- }
843
- let allEntities = Object.assign({}, this.existingEntities, this.generatedEntities);
844
- let replacements = {
845
- registeredModels: this.getRegisteredModels(allEntities, driverKey),
846
- registeredEntitiesObject: this.getRegisteredEntitiesObject(allEntities, driverKey)
847
- };
848
- let registeredContent = this.applyReplacements(registeredTemplateContent, replacements);
849
- let driverFolder = FileHandler.joinPaths(this.modelsFolder, driverKey);
850
- let filePath = FileHandler.joinPaths(driverFolder, 'registered-models-'+driverKey+'.js');
851
- if(!FileHandler.writeFile(filePath, registeredContent)){
852
- Logger.critical('Failed to write registered models file: '+filePath);
853
- return false;
854
- }
855
- Logger.info('Generated registered models file: '+filePath);
856
- return true;
857
- }
858
-
859
- getRegisteredModels(allEntities, driverKey)
860
- {
861
- let registeredModels = [];
862
- for(let tableName of Object.keys(allEntities)){
863
- let entity = allEntities[tableName];
864
- if(entity.driverKey && driverKey !== entity.driverKey){
865
- if(!this.existingModels[tableName] || !this.existingModels[tableName][driverKey]){
866
- continue;
867
- }
868
- }
869
- let modelClassName = entity.modelClassName || sc.capitalizedCamelCase(tableName)+'Model';
870
- let modelFileName = entity.modelFileName || sc.kebabCase(tableName)+'-model.js';
871
- registeredModels.push(
872
- 'const { '+modelClassName+' } = require(\'./'+modelFileName.replace('.js', '')+'\');'
873
- );
874
- }
875
- return registeredModels.join('\n');
876
- }
877
-
878
- getRegisteredEntitiesObject(allEntities, driverKey)
879
- {
880
- let registeredEntitiesObject = [];
881
- for(let tableName of Object.keys(allEntities)){
882
- let entity = allEntities[tableName];
883
- if(entity.driverKey && driverKey !== entity.driverKey){
884
- if(!this.existingModels[tableName] || !this.existingModels[tableName][driverKey]){
885
- continue;
886
- }
887
- }
888
- let modelClassName = entity.modelClassName || sc.capitalizedCamelCase(tableName)+'Model';
889
- registeredEntitiesObject.push(sc.camelCase(tableName)+': '+modelClassName);
890
- }
891
- return registeredEntitiesObject.join(',\n ');
892
- }
893
-
894
- applyReplacements(content, replacements)
895
- {
896
- let result = content;
897
- for(let placeholder of Object.keys(replacements)){
898
- result = result.replace(new RegExp('{{'+placeholder+'}}','g'), replacements[placeholder]);
899
- }
900
- return result;
901
- }
902
-
903
245
  async generate()
904
246
  {
905
247
  if(!this.server){
@@ -920,6 +262,7 @@ class EntitiesGenerator
920
262
  return false;
921
263
  }
922
264
  this.detectExistingEntities();
265
+ this.detectExistingModels();
923
266
  let driverKey = sc.get(
924
267
  this.connectionData,
925
268
  'driver',
@@ -935,12 +278,41 @@ class EntitiesGenerator
935
278
  }
936
279
  for(let tableName of Object.keys(tablesToGenerate)){
937
280
  let tableData = tablesToGenerate[tableName];
938
- await this.generateEntityFile(tableName, tableData);
939
- await this.generateModelFile(tableName, tableData, driverKey);
281
+ let entityGenerated = await this.entitiesGeneration.generateEntityFile(tableName, tableData);
282
+ if(!entityGenerated){
283
+ continue;
284
+ }
285
+ let entityInfo = this.entitiesGeneration.generatedEntities[tableName];
286
+ let modelGenerated = await this.modelsGeneration.generateModelFile(
287
+ tableName,
288
+ tableData,
289
+ driverKey,
290
+ entityInfo
291
+ );
292
+ if(modelGenerated){
293
+ let modelInfo = this.modelsGeneration.generatedModels[tableName];
294
+ this.generatedEntities[tableName] = Object.assign({}, entityInfo, modelInfo);
295
+ continue;
296
+ }
297
+ this.generatedEntities[tableName] = entityInfo;
940
298
  }
941
- this.generateEntitiesConfigFile();
942
- this.generateEntitiesTranslationsFile();
943
- this.generateRegisteredModelsFile(driverKey);
299
+ let allEntities = Object.assign({}, this.existingEntities, this.generatedEntities);
300
+ this.entitiesConfigGeneration.generateEntitiesConfigFile(
301
+ this.generatedEntities,
302
+ this.existingEntities,
303
+ this.isOverride
304
+ );
305
+ this.entitiesTranslationsGeneration.generateEntitiesTranslationsFile(
306
+ this.generatedEntities,
307
+ this.existingEntities,
308
+ this.isOverride
309
+ );
310
+ this.modelsGeneration.generateRegisteredModelsFile(
311
+ allEntities,
312
+ this.existingModels,
313
+ driverKey,
314
+ this.templates['registered-models']
315
+ );
944
316
  return true;
945
317
  }
946
318