@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.
@@ -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: '+filePath);
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: '+filePath);
350
+ Logger.critical('Failed to write model file: '+fileName);
359
351
  return false;
360
352
  }
361
- Logger.info('Generated model file: '+filePath);
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
- let configTemplatePath = this.templates['entities-config'];
412
- if(!FileHandler.exists(configTemplatePath)){
413
- Logger.critical('Entities config template file not found: '+configTemplatePath);
414
- return false;
441
+ if(this.isOverride){
442
+ return this.regenerateEntitiesConfigFile();
415
443
  }
416
- let configTemplateContent = FileHandler.fetchFileContents(configTemplatePath);
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: '+configTemplatePath);
451
+ Logger.critical('Failed to read entities config template file: '+this.templates['entities-config']);
419
452
  return false;
420
453
  }
421
- let requireStatements = this.getRequireStatements();
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
- let configContent = this.applyReplacements(configTemplateContent, replacements);
428
- if (!FileHandler.writeFile(this.entitiesConfigPath, configContent)){
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('Generated entities config file: '+this.entitiesConfigPath);
466
+ Logger.info('Regenerated entities config file: '+this.entitiesConfigPath);
433
467
  return true;
434
468
  }
435
469
 
436
- getRequireStatements()
470
+ appendToEntitiesConfigFile()
437
471
  {
438
- let requireStatements = [];
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 nameWithoutExtension = entity.entityFileName.replace('.js', '');
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 { '+ entity.entityClassName+' } = require(\'./entities/'+nameWithoutExtension+'\');'
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(this.generatedEntities)){
453
- let entity = this.generatedEntities[tableName];
454
- entitiesConfigExport.push(sc.camelCase(tableName)+': '+entity.entityClassName+'.propertiesConfig()');
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 labels = this.getTranslationLabels();
472
- let translationsContent = translationsTemplateContent.replace(/{{labels}}/g, labels);
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('Generated entities translations file: '+this.entitiesTranslationsPath);
584
+ Logger.info('Regenerated entities translations file: '+this.entitiesTranslationsPath);
478
585
  return true;
479
586
  }
480
587
 
481
- getTranslationLabels()
588
+ appendToEntitiesTranslationsFile()
482
589
  {
483
- let labels = [];
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
- let humanReadable = tableName.split('_').map(word => word.charAt(0).toUpperCase()+word.slice(1)).join(' ');
486
- labels.push('\''+tableName+'\': \''+humanReadable+'\'');
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(this.generatedEntities)){
522
- let entity = this.generatedEntities[tableName];
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 { '+entity.modelClassName+' } = require(\'./'+entity.modelFileName.replace('.js', '')+'\');'
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(this.generatedEntities)){
537
- let entity = this.generatedEntities[tableName];
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
- registeredEntitiesObject.push(sc.camelCase(tableName)+': '+entity.modelClassName);
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(tables)){
584
- let tableData = tables[tableName];
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.48.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.15",
46
- "@mikro-orm/mongodb": "^6.4.15",
47
- "@mikro-orm/mysql": "^6.4.15",
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.49.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",