@reldens/storage 0.48.0 → 0.50.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 +219 -55
- package/package.json +5 -5
|
@@ -44,7 +44,9 @@ class EntitiesGenerator
|
|
|
44
44
|
};
|
|
45
45
|
this.server = sc.get(props, 'server', false);
|
|
46
46
|
this.connectionData = sc.get(props, 'connectionData', false);
|
|
47
|
+
this.isOverride = sc.get(props, 'isOverride', false);
|
|
47
48
|
this.generatedEntities = {};
|
|
49
|
+
this.existingEntities = {};
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
async generateEntityFile(tableName, tableData)
|
|
@@ -98,7 +100,7 @@ class EntitiesGenerator
|
|
|
98
100
|
Logger.critical('Failed to write entity file: '+filePath);
|
|
99
101
|
return false;
|
|
100
102
|
}
|
|
101
|
-
Logger.info('Generated entity file: '+
|
|
103
|
+
Logger.info('Generated entity file: '+fileName);
|
|
102
104
|
this.generatedEntities[tableName] = {
|
|
103
105
|
entityClassName,
|
|
104
106
|
entityFileName: fileName,
|
|
@@ -295,16 +297,6 @@ class EntitiesGenerator
|
|
|
295
297
|
return passwordFields;
|
|
296
298
|
}
|
|
297
299
|
|
|
298
|
-
getEditPropertiesRemoval(fieldsToRemove)
|
|
299
|
-
{
|
|
300
|
-
if(1 === fieldsToRemove.length){
|
|
301
|
-
return 'let editProperties = [...propertiesKeys];\n editProperties.splice(editProperties.indexOf(\''+
|
|
302
|
-
fieldsToRemove[0]
|
|
303
|
-
+'\'), 1);';
|
|
304
|
-
}
|
|
305
|
-
return 'let editProperties = sc.removeFromArray([...propertiesKeys], [\''+fieldsToRemove.join('\', \'')+'\']);';
|
|
306
|
-
}
|
|
307
|
-
|
|
308
300
|
getListPropertiesDeclaration(columns)
|
|
309
301
|
{
|
|
310
302
|
let fieldsToRemove = this.getFieldsToRemoveFromList(columns);
|
|
@@ -355,10 +347,10 @@ class EntitiesGenerator
|
|
|
355
347
|
}
|
|
356
348
|
let filePath = FileHandler.joinPaths(driverFolder, fileName);
|
|
357
349
|
if(!FileHandler.writeFile(filePath, modelContent)){
|
|
358
|
-
Logger.critical('Failed to write model file: '+
|
|
350
|
+
Logger.critical('Failed to write model file: '+fileName);
|
|
359
351
|
return false;
|
|
360
352
|
}
|
|
361
|
-
Logger.info('Generated model file: '+
|
|
353
|
+
Logger.info('Generated model file: '+fileName);
|
|
362
354
|
this.generatedEntities[tableName].modelClassName = modelClassName;
|
|
363
355
|
this.generatedEntities[tableName].modelFileName = fileName;
|
|
364
356
|
this.generatedEntities[tableName].driverKey = driverKey;
|
|
@@ -406,57 +398,170 @@ class EntitiesGenerator
|
|
|
406
398
|
return '';
|
|
407
399
|
}
|
|
408
400
|
|
|
401
|
+
detectExistingEntities()
|
|
402
|
+
{
|
|
403
|
+
if(!FileHandler.exists(this.entitiesFolder)){
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
let entityFiles = FileHandler.getFilesInFolder(this.entitiesFolder, ['.js']);
|
|
407
|
+
for(let file of entityFiles){
|
|
408
|
+
if(!file.endsWith('-entity.js')){
|
|
409
|
+
continue;
|
|
410
|
+
}
|
|
411
|
+
let tableName = file.replace('-entity.js', '').replace(/-/g, '_');
|
|
412
|
+
this.existingEntities[tableName] = {entityFileName: file, tableName};
|
|
413
|
+
}
|
|
414
|
+
Logger.info('Detected '+Object.keys(this.existingEntities).length+' existing entities.');
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
filterTablesToGenerate(tables)
|
|
418
|
+
{
|
|
419
|
+
if(this.isOverride){
|
|
420
|
+
return tables;
|
|
421
|
+
}
|
|
422
|
+
let filteredTables = {};
|
|
423
|
+
let newTablesCount = 0;
|
|
424
|
+
for(let tableName of Object.keys(tables)){
|
|
425
|
+
if(!this.existingEntities[tableName]){
|
|
426
|
+
filteredTables[tableName] = tables[tableName];
|
|
427
|
+
newTablesCount++;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
if(0 === newTablesCount){
|
|
431
|
+
Logger.info('No new tables found. All entities are up to date.');
|
|
432
|
+
}
|
|
433
|
+
if(0 < newTablesCount){
|
|
434
|
+
Logger.info('Found '+newTablesCount+' new tables to generate entities for.');
|
|
435
|
+
}
|
|
436
|
+
return filteredTables;
|
|
437
|
+
}
|
|
438
|
+
|
|
409
439
|
generateEntitiesConfigFile()
|
|
410
440
|
{
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
Logger.critical('Entities config template file not found: '+configTemplatePath);
|
|
414
|
-
return false;
|
|
441
|
+
if(this.isOverride){
|
|
442
|
+
return this.regenerateEntitiesConfigFile();
|
|
415
443
|
}
|
|
416
|
-
|
|
444
|
+
return this.appendToEntitiesConfigFile();
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
regenerateEntitiesConfigFile()
|
|
448
|
+
{
|
|
449
|
+
let configTemplateContent = FileHandler.fetchFileContents(this.templates['entities-config']);
|
|
417
450
|
if(!configTemplateContent) {
|
|
418
|
-
Logger.critical('Failed to read entities config template file: '+
|
|
451
|
+
Logger.critical('Failed to read entities config template file: '+this.templates['entities-config']);
|
|
419
452
|
return false;
|
|
420
453
|
}
|
|
421
|
-
let
|
|
422
|
-
let entitiesConfigExport = this.getEntitiesConfigExport();
|
|
454
|
+
let allEntities = Object.assign({}, this.existingEntities, this.generatedEntities);
|
|
423
455
|
let replacements = {
|
|
424
|
-
requireStatements,
|
|
425
|
-
entitiesConfigExport
|
|
456
|
+
requireStatements: this.getRequireStatements(allEntities),
|
|
457
|
+
entitiesConfigExport: this.getEntitiesConfigExport(allEntities)
|
|
426
458
|
};
|
|
427
|
-
|
|
428
|
-
|
|
459
|
+
if(!FileHandler.writeFile(
|
|
460
|
+
this.entitiesConfigPath,
|
|
461
|
+
this.applyReplacements(configTemplateContent, replacements)
|
|
462
|
+
)){
|
|
429
463
|
Logger.critical('Failed to write entities config file: '+this.entitiesConfigPath);
|
|
430
464
|
return false;
|
|
431
465
|
}
|
|
432
|
-
Logger.info('
|
|
466
|
+
Logger.info('Regenerated entities config file: '+this.entitiesConfigPath);
|
|
433
467
|
return true;
|
|
434
468
|
}
|
|
435
469
|
|
|
436
|
-
|
|
470
|
+
appendToEntitiesConfigFile()
|
|
437
471
|
{
|
|
438
|
-
|
|
472
|
+
if(0 === Object.keys(this.generatedEntities).length){
|
|
473
|
+
return true;
|
|
474
|
+
}
|
|
475
|
+
if(!FileHandler.exists(this.entitiesConfigPath)){
|
|
476
|
+
Logger.error('Entities config file does not exist, cannot append new entities.');
|
|
477
|
+
return false;
|
|
478
|
+
}
|
|
479
|
+
let existingContent = FileHandler.readFile(this.entitiesConfigPath);
|
|
480
|
+
if(!existingContent){
|
|
481
|
+
Logger.error('Could not read existing entities config file.');
|
|
482
|
+
return false;
|
|
483
|
+
}
|
|
484
|
+
let newRequires = [];
|
|
485
|
+
let newConfigs = [];
|
|
439
486
|
for(let tableName of Object.keys(this.generatedEntities)){
|
|
440
487
|
let entity = this.generatedEntities[tableName];
|
|
441
|
-
let
|
|
488
|
+
let entityClassName = sc.get(entity, 'entityClassName', sc.capitalizedCamelCase(tableName)+'Entity');
|
|
489
|
+
let entityFileName = sc.get(entity, 'entityFileName', sc.kebabCase(tableName)+'-entity').replace('.js', '');
|
|
490
|
+
let requireStatement = 'const { '+ entityClassName+' } = require(\'./entities/'+entityFileName+'\');';
|
|
491
|
+
let configEntry = sc.camelCase(tableName)+': '+entityClassName+'.propertiesConfig()';
|
|
492
|
+
if(!existingContent.includes(requireStatement)){
|
|
493
|
+
newRequires.push(requireStatement);
|
|
494
|
+
}
|
|
495
|
+
if(!existingContent.includes(sc.camelCase(tableName)+':')){
|
|
496
|
+
newConfigs.push(configEntry);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
if(0 === newRequires.length && 0 === newConfigs.length){
|
|
500
|
+
return true;
|
|
501
|
+
}
|
|
502
|
+
let firstRequirePosition = existingContent.indexOf('const {');
|
|
503
|
+
let entitiesConfigEnd = existingContent.indexOf('};\n\nmodule.exports');
|
|
504
|
+
if(-1 === firstRequirePosition || -1 === entitiesConfigEnd){
|
|
505
|
+
Logger.error('Could not find insertion points in config file.');
|
|
506
|
+
return false;
|
|
507
|
+
}
|
|
508
|
+
let beforeFirstRequire = existingContent.substring(0, firstRequirePosition);
|
|
509
|
+
let afterFirstRequire = existingContent.substring(firstRequirePosition, entitiesConfigEnd);
|
|
510
|
+
let updatedContent = beforeFirstRequire;
|
|
511
|
+
if(0 < newRequires.length){
|
|
512
|
+
updatedContent += newRequires.join('\n') + '\n';
|
|
513
|
+
}
|
|
514
|
+
updatedContent += afterFirstRequire;
|
|
515
|
+
if(0 < newConfigs.length){
|
|
516
|
+
if(!afterFirstRequire.trim().endsWith(',')){
|
|
517
|
+
updatedContent = updatedContent.trimEnd() + ',';
|
|
518
|
+
}
|
|
519
|
+
updatedContent += '\n ' + newConfigs.join(',\n ') + '\n';
|
|
520
|
+
}
|
|
521
|
+
updatedContent += existingContent.substring(entitiesConfigEnd);
|
|
522
|
+
if(!FileHandler.writeFile(this.entitiesConfigPath, updatedContent)){
|
|
523
|
+
Logger.error('Failed to append to entities config file: '+this.entitiesConfigPath);
|
|
524
|
+
return false;
|
|
525
|
+
}
|
|
526
|
+
return true;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
getRequireStatements(allEntities)
|
|
530
|
+
{
|
|
531
|
+
let requireStatements = [];
|
|
532
|
+
for(let tableName of Object.keys(allEntities)){
|
|
533
|
+
let entity = allEntities[tableName];
|
|
534
|
+
let entityClassName = sc.get(entity, 'entityClassName', sc.capitalizedCamelCase(tableName)+'Entity');
|
|
535
|
+
let entityFileName = sc.get(entity, 'entityFileName', sc.kebabCase(tableName)+'-entity').replace('.js', '');
|
|
442
536
|
requireStatements.push(
|
|
443
|
-
'const { '+
|
|
537
|
+
'const { '+ entityClassName+' } = require(\'./entities/'+entityFileName+'\');'
|
|
444
538
|
);
|
|
445
539
|
}
|
|
446
540
|
return requireStatements.join('\n');
|
|
447
541
|
}
|
|
448
542
|
|
|
449
|
-
getEntitiesConfigExport()
|
|
543
|
+
getEntitiesConfigExport(allEntities)
|
|
450
544
|
{
|
|
451
545
|
let entitiesConfigExport = [];
|
|
452
|
-
for(let tableName of Object.keys(
|
|
453
|
-
|
|
454
|
-
|
|
546
|
+
for(let tableName of Object.keys(allEntities)){
|
|
547
|
+
entitiesConfigExport.push(
|
|
548
|
+
sc.camelCase(tableName)+': '
|
|
549
|
+
+sc.get(allEntities[tableName], 'entityClassName', sc.capitalizedCamelCase(tableName)+'Entity')
|
|
550
|
+
+'.propertiesConfig()'
|
|
551
|
+
);
|
|
455
552
|
}
|
|
456
553
|
return entitiesConfigExport.join(',\n ');
|
|
457
554
|
}
|
|
458
555
|
|
|
459
556
|
generateEntitiesTranslationsFile()
|
|
557
|
+
{
|
|
558
|
+
if(this.isOverride){
|
|
559
|
+
return this.regenerateEntitiesTranslationsFile();
|
|
560
|
+
}
|
|
561
|
+
return this.appendToEntitiesTranslationsFile();
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
regenerateEntitiesTranslationsFile()
|
|
460
565
|
{
|
|
461
566
|
let translationsTemplatePath = this.templates['entities-translations'];
|
|
462
567
|
if(!FileHandler.exists(translationsTemplatePath)){
|
|
@@ -468,22 +573,72 @@ class EntitiesGenerator
|
|
|
468
573
|
Logger.critical('Failed to read entities translations template file: '+translationsTemplatePath);
|
|
469
574
|
return false;
|
|
470
575
|
}
|
|
471
|
-
let
|
|
472
|
-
|
|
576
|
+
let translationsContent = translationsTemplateContent.replace(
|
|
577
|
+
/{{labels}}/g,
|
|
578
|
+
this.getTranslationLabels(Object.assign({}, this.existingEntities, this.generatedEntities))
|
|
579
|
+
);
|
|
473
580
|
if(!FileHandler.writeFile(this.entitiesTranslationsPath, translationsContent)){
|
|
474
581
|
Logger.critical('Failed to write entities translations file: '+this.entitiesTranslationsPath);
|
|
475
582
|
return false;
|
|
476
583
|
}
|
|
477
|
-
Logger.info('
|
|
584
|
+
Logger.info('Regenerated entities translations file: '+this.entitiesTranslationsPath);
|
|
478
585
|
return true;
|
|
479
586
|
}
|
|
480
587
|
|
|
481
|
-
|
|
588
|
+
appendToEntitiesTranslationsFile()
|
|
482
589
|
{
|
|
483
|
-
|
|
590
|
+
if(0 === Object.keys(this.generatedEntities).length){
|
|
591
|
+
return true;
|
|
592
|
+
}
|
|
593
|
+
if(!FileHandler.exists(this.entitiesTranslationsPath)){
|
|
594
|
+
Logger.error('Entities translations file does not exist, cannot append new entities.');
|
|
595
|
+
return false;
|
|
596
|
+
}
|
|
597
|
+
let existingContent = FileHandler.readFile(this.entitiesTranslationsPath);
|
|
598
|
+
if(!existingContent){
|
|
599
|
+
Logger.error('Could not read existing translations file.');
|
|
600
|
+
return false;
|
|
601
|
+
}
|
|
602
|
+
let newTranslations = [];
|
|
484
603
|
for(let tableName of Object.keys(this.generatedEntities)){
|
|
485
|
-
|
|
486
|
-
|
|
604
|
+
if(!existingContent.includes('\''+tableName+'\':')){
|
|
605
|
+
newTranslations.push(
|
|
606
|
+
'\''+tableName+'\': \''
|
|
607
|
+
+tableName.split('_').map(word => word.charAt(0).toUpperCase()+word.slice(1)).join(' ')+'\''
|
|
608
|
+
);
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
if(0 === newTranslations.length){
|
|
612
|
+
return true;
|
|
613
|
+
}
|
|
614
|
+
let labelsEnd = existingContent.indexOf('\n }\n');
|
|
615
|
+
if(-1 === existingContent.indexOf('labels: {') || -1 === labelsEnd){
|
|
616
|
+
Logger.error('Could not find labels object boundaries in existing translations file.');
|
|
617
|
+
return false;
|
|
618
|
+
}
|
|
619
|
+
let beforeLabelsEnd = existingContent.substring(0, labelsEnd);
|
|
620
|
+
if(!beforeLabelsEnd.trim().endsWith(',')){
|
|
621
|
+
beforeLabelsEnd = beforeLabelsEnd.trimEnd() + ',';
|
|
622
|
+
}
|
|
623
|
+
if(!FileHandler.writeFile(
|
|
624
|
+
this.entitiesTranslationsPath,
|
|
625
|
+
beforeLabelsEnd + '\n ' + newTranslations.join(',\n ') + existingContent.substring(labelsEnd)
|
|
626
|
+
)){
|
|
627
|
+
Logger.error('Failed to append to entities translations file: '+this.entitiesTranslationsPath);
|
|
628
|
+
return false;
|
|
629
|
+
}
|
|
630
|
+
return true;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
getTranslationLabels(allEntities)
|
|
634
|
+
{
|
|
635
|
+
let labels = [];
|
|
636
|
+
for(let tableName of Object.keys(allEntities)){
|
|
637
|
+
labels.push(
|
|
638
|
+
'\''+tableName+'\': \''
|
|
639
|
+
+tableName.split('_').map(word => word.charAt(0).toUpperCase()+word.slice(1)).join(' ')
|
|
640
|
+
+'\''
|
|
641
|
+
);
|
|
487
642
|
}
|
|
488
643
|
return labels.join(',\n ');
|
|
489
644
|
}
|
|
@@ -500,9 +655,10 @@ class EntitiesGenerator
|
|
|
500
655
|
Logger.critical('Failed to read registered models template file: '+registeredTemplatePath);
|
|
501
656
|
return false;
|
|
502
657
|
}
|
|
658
|
+
let allEntities = Object.assign({}, this.existingEntities, this.generatedEntities);
|
|
503
659
|
let replacements = {
|
|
504
|
-
registeredModels: this.getRegisteredModels(driverKey),
|
|
505
|
-
registeredEntitiesObject: this.getRegisteredEntitiesObject(driverKey)
|
|
660
|
+
registeredModels: this.getRegisteredModels(allEntities, driverKey),
|
|
661
|
+
registeredEntitiesObject: this.getRegisteredEntitiesObject(allEntities, driverKey)
|
|
506
662
|
};
|
|
507
663
|
let registeredContent = this.applyReplacements(registeredTemplateContent, replacements);
|
|
508
664
|
let driverFolder = FileHandler.joinPaths(this.modelsFolder, driverKey);
|
|
@@ -515,30 +671,33 @@ class EntitiesGenerator
|
|
|
515
671
|
return true;
|
|
516
672
|
}
|
|
517
673
|
|
|
518
|
-
getRegisteredModels(driverKey)
|
|
674
|
+
getRegisteredModels(allEntities, driverKey)
|
|
519
675
|
{
|
|
520
676
|
let registeredModels = [];
|
|
521
|
-
for(let tableName of Object.keys(
|
|
522
|
-
let entity =
|
|
523
|
-
if(driverKey !== entity.driverKey){
|
|
677
|
+
for(let tableName of Object.keys(allEntities)){
|
|
678
|
+
let entity = allEntities[tableName];
|
|
679
|
+
if(entity.driverKey && driverKey !== entity.driverKey){
|
|
524
680
|
continue;
|
|
525
681
|
}
|
|
682
|
+
let modelClassName = entity.modelClassName || sc.capitalizedCamelCase(tableName)+'Model';
|
|
683
|
+
let modelFileName = entity.modelFileName || sc.kebabCase(tableName)+'-model.js';
|
|
526
684
|
registeredModels.push(
|
|
527
|
-
'const { '+
|
|
685
|
+
'const { '+modelClassName+' } = require(\'./'+modelFileName.replace('.js', '')+'\');'
|
|
528
686
|
);
|
|
529
687
|
}
|
|
530
688
|
return registeredModels.join('\n');
|
|
531
689
|
}
|
|
532
690
|
|
|
533
|
-
getRegisteredEntitiesObject(driverKey)
|
|
691
|
+
getRegisteredEntitiesObject(allEntities, driverKey)
|
|
534
692
|
{
|
|
535
693
|
let registeredEntitiesObject = [];
|
|
536
|
-
for(let tableName of Object.keys(
|
|
537
|
-
let entity =
|
|
538
|
-
if(driverKey !== entity.driverKey){
|
|
694
|
+
for(let tableName of Object.keys(allEntities)){
|
|
695
|
+
let entity = allEntities[tableName];
|
|
696
|
+
if(entity.driverKey && driverKey !== entity.driverKey){
|
|
539
697
|
continue;
|
|
540
698
|
}
|
|
541
|
-
|
|
699
|
+
let modelClassName = entity.modelClassName || sc.capitalizedCamelCase(tableName)+'Model';
|
|
700
|
+
registeredEntitiesObject.push(sc.camelCase(tableName)+': '+modelClassName);
|
|
542
701
|
}
|
|
543
702
|
return registeredEntitiesObject.join(',\n ');
|
|
544
703
|
}
|
|
@@ -571,6 +730,11 @@ class EntitiesGenerator
|
|
|
571
730
|
if(!this.ensureFoldersExist()){
|
|
572
731
|
return false;
|
|
573
732
|
}
|
|
733
|
+
this.detectExistingEntities();
|
|
734
|
+
let tablesToGenerate = this.filterTablesToGenerate(tables);
|
|
735
|
+
if(0 === Object.keys(tablesToGenerate).length && !this.isOverride){
|
|
736
|
+
return true;
|
|
737
|
+
}
|
|
574
738
|
let driverKey = sc.get(
|
|
575
739
|
this.connectionData,
|
|
576
740
|
'driver',
|
|
@@ -580,8 +744,8 @@ class EntitiesGenerator
|
|
|
580
744
|
Logger.critical('Failed to fetch driver key.');
|
|
581
745
|
return false;
|
|
582
746
|
}
|
|
583
|
-
for(let tableName of Object.keys(
|
|
584
|
-
let tableData =
|
|
747
|
+
for(let tableName of Object.keys(tablesToGenerate)){
|
|
748
|
+
let tableData = tablesToGenerate[tableName];
|
|
585
749
|
await this.generateEntityFile(tableName, tableData);
|
|
586
750
|
await this.generateModelFile(tableName, tableData, driverKey);
|
|
587
751
|
}
|
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.50.0",
|
|
5
5
|
"description": "Reldens - Storage",
|
|
6
6
|
"author": "Damian A. Pastorini",
|
|
7
7
|
"license": "MIT",
|
|
@@ -42,12 +42,12 @@
|
|
|
42
42
|
"url": "https://github.com/damian-pastorini/reldens-storage/issues"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@mikro-orm/core": "^6.4.
|
|
46
|
-
"@mikro-orm/mongodb": "^6.4.
|
|
47
|
-
"@mikro-orm/mysql": "^6.4.
|
|
45
|
+
"@mikro-orm/core": "^6.4.16",
|
|
46
|
+
"@mikro-orm/mongodb": "^6.4.16",
|
|
47
|
+
"@mikro-orm/mysql": "^6.4.16",
|
|
48
48
|
"@prisma/client": "^6.8.2",
|
|
49
49
|
"@reldens/server-utils": "^0.18.0",
|
|
50
|
-
"@reldens/utils": "^0.
|
|
50
|
+
"@reldens/utils": "^0.50.0",
|
|
51
51
|
"knex": "^3.1.0",
|
|
52
52
|
"mysql": "^2.18.1",
|
|
53
53
|
"mysql2": "^3.14.1",
|