@reldens/storage 0.78.0 → 0.80.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.
|
@@ -41,13 +41,15 @@ class ModelsGeneration extends BaseGenerator
|
|
|
41
41
|
.join('\n ');
|
|
42
42
|
let modelRelations = this.generateModelRelations(tableName, tableData, relationMetadata, driverKey);
|
|
43
43
|
let entityPropertiesDefinition = this.getEntityPropertiesDefinition(tableData.columns, driverKey);
|
|
44
|
+
let idColumn = this.generateIdColumn(tableData.columns, driverKey);
|
|
44
45
|
let replacements = {
|
|
45
46
|
modelClassName,
|
|
46
47
|
tableName: 'prisma' === driverKey ? tableName.toLowerCase() : tableName,
|
|
47
48
|
modelPropertiesList,
|
|
48
49
|
modelPropertiesConstructor,
|
|
49
50
|
modelRelations,
|
|
50
|
-
entityPropertiesDefinition
|
|
51
|
+
entityPropertiesDefinition,
|
|
52
|
+
idColumn
|
|
51
53
|
};
|
|
52
54
|
let modelContent = this.applyReplacements(modelTemplateContent, replacements);
|
|
53
55
|
let fileName = sc.kebabCase(tableName)+'-model.js';
|
|
@@ -67,6 +69,29 @@ class ModelsGeneration extends BaseGenerator
|
|
|
67
69
|
return true;
|
|
68
70
|
}
|
|
69
71
|
|
|
72
|
+
generateIdColumn(columns, driverKey)
|
|
73
|
+
{
|
|
74
|
+
if('objection-js' !== driverKey){
|
|
75
|
+
return '';
|
|
76
|
+
}
|
|
77
|
+
let primaryKeyColumn = this.detectPrimaryKeyColumn(columns);
|
|
78
|
+
if(!primaryKeyColumn || 'id' === primaryKeyColumn){
|
|
79
|
+
return '';
|
|
80
|
+
}
|
|
81
|
+
return '\n static get idColumn()\n {\n return \''+primaryKeyColumn+'\';\n }\n';
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
detectPrimaryKeyColumn(columns)
|
|
85
|
+
{
|
|
86
|
+
for(let columnName of Object.keys(columns)){
|
|
87
|
+
let column = columns[columnName];
|
|
88
|
+
if('PRI' === column.key){
|
|
89
|
+
return columnName;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
|
|
70
95
|
setAllTablesData(allTablesData)
|
|
71
96
|
{
|
|
72
97
|
this.allTablesData = allTablesData;
|
|
@@ -120,7 +120,7 @@ class PrismaDataServer extends BaseDataServer
|
|
|
120
120
|
return await this.prisma.$queryRawUnsafe(statement);
|
|
121
121
|
}
|
|
122
122
|
let result = await this.prisma.$executeRawUnsafe(statement);
|
|
123
|
-
Logger.debug('Raw result from Prisma: ' + result);
|
|
123
|
+
//Logger.debug('Raw result from Prisma: ' + result);
|
|
124
124
|
if(
|
|
125
125
|
trimmedStatement.startsWith('CREATE')
|
|
126
126
|
|| trimmedStatement.startsWith('ALTER')
|
|
@@ -129,6 +129,29 @@ class PrismaDriver extends BaseDriver
|
|
|
129
129
|
return Object.keys(this.relationMetadata || {});
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
+
normalizeRelationName(relationName)
|
|
133
|
+
{
|
|
134
|
+
if(sc.hasOwn(this.relationMetadata, relationName)){
|
|
135
|
+
return relationName;
|
|
136
|
+
}
|
|
137
|
+
if(relationName.startsWith('related_')){
|
|
138
|
+
let withoutPrefix = relationName.substring(8);
|
|
139
|
+
if(sc.hasOwn(this.relationMetadata, withoutPrefix)){
|
|
140
|
+
return withoutPrefix;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
let availableRelations = Object.keys(this.relationMetadata);
|
|
144
|
+
for(let availableRelation of availableRelations){
|
|
145
|
+
if(relationName.endsWith(availableRelation)){
|
|
146
|
+
return availableRelation;
|
|
147
|
+
}
|
|
148
|
+
if(availableRelation.endsWith(relationName.replace('related_', ''))){
|
|
149
|
+
return availableRelation;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return relationName;
|
|
153
|
+
}
|
|
154
|
+
|
|
132
155
|
isNumericFieldType(fieldType)
|
|
133
156
|
{
|
|
134
157
|
return ('Int' === fieldType || 'BigInt' === fieldType || 'Float' === fieldType || 'Decimal' === fieldType);
|
|
@@ -466,18 +489,18 @@ class PrismaDriver extends BaseDriver
|
|
|
466
489
|
return value;
|
|
467
490
|
}
|
|
468
491
|
|
|
469
|
-
transformRelationResults(result, includeConfig)
|
|
492
|
+
transformRelationResults(result, includeConfig, relationMapping)
|
|
470
493
|
{
|
|
471
494
|
if(!result || !includeConfig){
|
|
472
495
|
return result;
|
|
473
496
|
}
|
|
474
497
|
if(sc.isArray(result)){
|
|
475
|
-
return result.map(item => this.transformSingleResult(item, includeConfig));
|
|
498
|
+
return result.map(item => this.transformSingleResult(item, includeConfig, relationMapping));
|
|
476
499
|
}
|
|
477
|
-
return this.transformSingleResult(result, includeConfig);
|
|
500
|
+
return this.transformSingleResult(result, includeConfig, relationMapping);
|
|
478
501
|
}
|
|
479
502
|
|
|
480
|
-
transformSingleResult(item, includeConfig)
|
|
503
|
+
transformSingleResult(item, includeConfig, relationMapping)
|
|
481
504
|
{
|
|
482
505
|
if(!item || !sc.isObject(item)){
|
|
483
506
|
return item;
|
|
@@ -493,11 +516,15 @@ class PrismaDriver extends BaseDriver
|
|
|
493
516
|
}
|
|
494
517
|
let relationValue = transformed[relationName];
|
|
495
518
|
if('one' === relationMeta.type && sc.isArray(relationValue)){
|
|
496
|
-
|
|
497
|
-
continue;
|
|
519
|
+
relationValue = 0 < relationValue.length ? [...relationValue].shift() : null;
|
|
498
520
|
}
|
|
499
521
|
if('many' === relationMeta.type && !sc.isArray(relationValue)){
|
|
500
|
-
|
|
522
|
+
relationValue = relationValue ? [relationValue] : [];
|
|
523
|
+
}
|
|
524
|
+
let originalName = sc.get(relationMapping, relationName, relationName);
|
|
525
|
+
transformed[originalName] = relationValue;
|
|
526
|
+
if(originalName !== relationName){
|
|
527
|
+
delete transformed[relationName];
|
|
501
528
|
}
|
|
502
529
|
}
|
|
503
530
|
return transformed;
|
|
@@ -526,26 +553,33 @@ class PrismaDriver extends BaseDriver
|
|
|
526
553
|
this.ensureRequiredFields(preparedData);
|
|
527
554
|
let createData = {data: preparedData};
|
|
528
555
|
if(0 < relations.length){
|
|
529
|
-
let
|
|
530
|
-
createData.include =
|
|
556
|
+
let includeData = this.buildIncludeObjectWithMapping(relations);
|
|
557
|
+
createData.include = includeData.include;
|
|
531
558
|
for(let relation of relations){
|
|
532
|
-
|
|
559
|
+
let normalizedRelation = this.normalizeRelationName(relation);
|
|
560
|
+
if(!sc.hasOwn(params, relation) && !sc.hasOwn(params, normalizedRelation)){
|
|
533
561
|
continue;
|
|
534
562
|
}
|
|
535
|
-
let relationData = params
|
|
563
|
+
let relationData = sc.get(params, relation, sc.get(params, normalizedRelation, null));
|
|
536
564
|
if(sc.isArray(relationData)){
|
|
537
|
-
createData.data[
|
|
565
|
+
createData.data[normalizedRelation] = {
|
|
538
566
|
connect: relationData.map(item => ({id: this.castToIdType(item.id)}))
|
|
539
567
|
};
|
|
540
568
|
continue;
|
|
541
569
|
}
|
|
542
|
-
createData.data[
|
|
570
|
+
createData.data[normalizedRelation] = {
|
|
543
571
|
connect: {id: this.castToIdType(relationData.id)}
|
|
544
572
|
};
|
|
545
573
|
}
|
|
574
|
+
try {
|
|
575
|
+
return this.transformRelationResults(await this.model.create(createData), includeData.include, includeData.mapping);
|
|
576
|
+
} catch(error) {
|
|
577
|
+
Logger.error('Create with relations error: '+error.message);
|
|
578
|
+
return false;
|
|
579
|
+
}
|
|
546
580
|
}
|
|
547
581
|
try {
|
|
548
|
-
return
|
|
582
|
+
return await this.model.create(createData);
|
|
549
583
|
} catch(error) {
|
|
550
584
|
Logger.error('Create with relations error: '+error.message);
|
|
551
585
|
return false;
|
|
@@ -692,7 +726,7 @@ class PrismaDriver extends BaseDriver
|
|
|
692
726
|
where: processedFilters
|
|
693
727
|
};
|
|
694
728
|
if(0 < relations.length){
|
|
695
|
-
query.include = this.
|
|
729
|
+
query.include = this.buildIncludeObjectWithMapping(relations).include;
|
|
696
730
|
}
|
|
697
731
|
try {
|
|
698
732
|
return await this.model.count(query);
|
|
@@ -714,22 +748,13 @@ class PrismaDriver extends BaseDriver
|
|
|
714
748
|
|
|
715
749
|
async loadAllWithRelations(relations)
|
|
716
750
|
{
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
query.include = includeConfig;
|
|
725
|
-
}
|
|
726
|
-
try {
|
|
727
|
-
let results = await this.model.findMany(query);
|
|
728
|
-
return this.transformRelationResults(results, includeConfig);
|
|
729
|
-
} catch(error) {
|
|
730
|
-
Logger.error('Load all with relations error: '+error.message);
|
|
731
|
-
return [];
|
|
732
|
-
}
|
|
751
|
+
return this.executeQueryWithRelations(
|
|
752
|
+
(q) => this.model.findMany(q),
|
|
753
|
+
this.buildQueryOptions(),
|
|
754
|
+
relations,
|
|
755
|
+
'Load all with relations error: ',
|
|
756
|
+
[]
|
|
757
|
+
);
|
|
733
758
|
}
|
|
734
759
|
|
|
735
760
|
async load(filters)
|
|
@@ -747,24 +772,15 @@ class PrismaDriver extends BaseDriver
|
|
|
747
772
|
|
|
748
773
|
async loadWithRelations(filters, relations)
|
|
749
774
|
{
|
|
750
|
-
if(!sc.isArray(relations) || 0 === relations.length){
|
|
751
|
-
relations = this.getAllRelations();
|
|
752
|
-
}
|
|
753
|
-
let processedFilters = this.processFilters(filters);
|
|
754
775
|
let query = this.buildQueryOptions();
|
|
755
|
-
query.where =
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
return this.transformRelationResults(results, includeConfig);
|
|
764
|
-
} catch(error) {
|
|
765
|
-
Logger.error('Load with relations error: '+error.message);
|
|
766
|
-
return [];
|
|
767
|
-
}
|
|
776
|
+
query.where = this.processFilters(filters);
|
|
777
|
+
return this.executeQueryWithRelations(
|
|
778
|
+
(q) => this.model.findMany(q),
|
|
779
|
+
query,
|
|
780
|
+
relations,
|
|
781
|
+
'Load with relations error: ',
|
|
782
|
+
[]
|
|
783
|
+
);
|
|
768
784
|
}
|
|
769
785
|
|
|
770
786
|
async loadBy(field, fieldValue, operator = null)
|
|
@@ -782,24 +798,15 @@ class PrismaDriver extends BaseDriver
|
|
|
782
798
|
|
|
783
799
|
async loadByWithRelations(field, fieldValue, relations, operator = null)
|
|
784
800
|
{
|
|
785
|
-
if(!sc.isArray(relations) || 0 === relations.length){
|
|
786
|
-
relations = this.getAllRelations();
|
|
787
|
-
}
|
|
788
|
-
let filter = this.createSingleFilter(field, fieldValue, operator);
|
|
789
801
|
let query = this.buildQueryOptions();
|
|
790
|
-
query.where =
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
return this.transformRelationResults(results, includeConfig);
|
|
799
|
-
} catch(error) {
|
|
800
|
-
Logger.error('Load by with relations error: '+error.message);
|
|
801
|
-
return [];
|
|
802
|
-
}
|
|
802
|
+
query.where = this.createSingleFilter(field, fieldValue, operator);
|
|
803
|
+
return this.executeQueryWithRelations(
|
|
804
|
+
(q) => this.model.findMany(q),
|
|
805
|
+
query,
|
|
806
|
+
relations,
|
|
807
|
+
'Load by with relations error: ',
|
|
808
|
+
[]
|
|
809
|
+
);
|
|
803
810
|
}
|
|
804
811
|
|
|
805
812
|
async loadById(id)
|
|
@@ -817,25 +824,13 @@ class PrismaDriver extends BaseDriver
|
|
|
817
824
|
|
|
818
825
|
async loadByIdWithRelations(id, relations)
|
|
819
826
|
{
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
let includeConfig = {};
|
|
828
|
-
if(0 < relations.length){
|
|
829
|
-
includeConfig = this.buildIncludeObject(relations);
|
|
830
|
-
query.include = includeConfig;
|
|
831
|
-
}
|
|
832
|
-
try {
|
|
833
|
-
let result = await this.model.findUnique(query);
|
|
834
|
-
return this.transformRelationResults(result, includeConfig);
|
|
835
|
-
} catch(error) {
|
|
836
|
-
Logger.error('Load by ID with relations error: '+error.message);
|
|
837
|
-
return null;
|
|
838
|
-
}
|
|
827
|
+
return this.executeQueryWithRelations(
|
|
828
|
+
(q) => this.model.findUnique(q),
|
|
829
|
+
{where: {id: this.castToIdType(id)}},
|
|
830
|
+
relations,
|
|
831
|
+
'Load by ID with relations error: ',
|
|
832
|
+
null
|
|
833
|
+
);
|
|
839
834
|
}
|
|
840
835
|
|
|
841
836
|
async loadByIds(ids)
|
|
@@ -868,24 +863,15 @@ class PrismaDriver extends BaseDriver
|
|
|
868
863
|
|
|
869
864
|
async loadOneWithRelations(filters, relations)
|
|
870
865
|
{
|
|
871
|
-
if(!sc.isArray(relations) || 0 === relations.length){
|
|
872
|
-
relations = this.getAllRelations();
|
|
873
|
-
}
|
|
874
|
-
let processedFilters = this.processFilters(filters);
|
|
875
866
|
let query = this.buildQueryOptions(false);
|
|
876
|
-
query.where =
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
return this.transformRelationResults(result, includeConfig);
|
|
885
|
-
} catch(error) {
|
|
886
|
-
Logger.error('Load one with relations error: '+error.message);
|
|
887
|
-
return null;
|
|
888
|
-
}
|
|
867
|
+
query.where = this.processFilters(filters);
|
|
868
|
+
return this.executeQueryWithRelations(
|
|
869
|
+
(q) => this.model.findFirst(q),
|
|
870
|
+
query,
|
|
871
|
+
relations,
|
|
872
|
+
'Load one with relations error: ',
|
|
873
|
+
null
|
|
874
|
+
);
|
|
889
875
|
}
|
|
890
876
|
|
|
891
877
|
async loadOneBy(field, fieldValue, operator = null)
|
|
@@ -903,24 +889,15 @@ class PrismaDriver extends BaseDriver
|
|
|
903
889
|
|
|
904
890
|
async loadOneByWithRelations(field, fieldValue, relations, operator = null)
|
|
905
891
|
{
|
|
906
|
-
if(!sc.isArray(relations) || 0 === relations.length){
|
|
907
|
-
relations = this.getAllRelations();
|
|
908
|
-
}
|
|
909
|
-
let filter = this.createSingleFilter(field, fieldValue, operator);
|
|
910
892
|
let query = this.buildQueryOptions(false);
|
|
911
|
-
query.where =
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
return this.transformRelationResults(result, includeConfig);
|
|
920
|
-
} catch(error) {
|
|
921
|
-
Logger.error('Load one by with relations error: '+error.message);
|
|
922
|
-
return null;
|
|
923
|
-
}
|
|
893
|
+
query.where = this.createSingleFilter(field, fieldValue, operator);
|
|
894
|
+
return this.executeQueryWithRelations(
|
|
895
|
+
(q) => this.model.findFirst(q),
|
|
896
|
+
query,
|
|
897
|
+
relations,
|
|
898
|
+
'Load one by with relations error: ',
|
|
899
|
+
null
|
|
900
|
+
);
|
|
924
901
|
}
|
|
925
902
|
|
|
926
903
|
buildQueryOptions(useLimit = true)
|
|
@@ -999,13 +976,39 @@ class PrismaDriver extends BaseDriver
|
|
|
999
976
|
};
|
|
1000
977
|
}
|
|
1001
978
|
|
|
1002
|
-
|
|
979
|
+
async executeQueryWithRelations(modelMethod, query, relations, errorMessage, defaultReturn)
|
|
980
|
+
{
|
|
981
|
+
if(!sc.isArray(relations) || 0 === relations.length){
|
|
982
|
+
relations = this.getAllRelations();
|
|
983
|
+
}
|
|
984
|
+
let includeData = this.buildIncludeObjectWithMapping(relations);
|
|
985
|
+
if(0 < Object.keys(includeData.include).length){
|
|
986
|
+
query.include = includeData.include;
|
|
987
|
+
}
|
|
988
|
+
try {
|
|
989
|
+
return this.transformRelationResults(await modelMethod(query), includeData.include, includeData.mapping);
|
|
990
|
+
} catch(error) {
|
|
991
|
+
Logger.error(errorMessage+error.message);
|
|
992
|
+
return defaultReturn;
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
buildIncludeObjectWithMapping(relations)
|
|
1003
997
|
{
|
|
1004
998
|
let include = {};
|
|
999
|
+
let mapping = {};
|
|
1005
1000
|
for(let relation of relations){
|
|
1006
|
-
|
|
1001
|
+
let normalizedRelation = this.normalizeRelationName(relation);
|
|
1002
|
+
if(!sc.hasOwn(this.relationMetadata, normalizedRelation)){
|
|
1003
|
+
//Logger.debug('Relation "'+relation+'" (normalized: "'+normalizedRelation+'") not found in model '+this.tableName());
|
|
1004
|
+
continue;
|
|
1005
|
+
}
|
|
1006
|
+
include[normalizedRelation] = true;
|
|
1007
|
+
if(relation !== normalizedRelation){
|
|
1008
|
+
mapping[normalizedRelation] = relation;
|
|
1009
|
+
}
|
|
1007
1010
|
}
|
|
1008
|
-
return include;
|
|
1011
|
+
return {include, mapping};
|
|
1009
1012
|
}
|
|
1010
1013
|
|
|
1011
1014
|
}
|
|
@@ -1,182 +1,182 @@
|
|
|
1
|
-
/**
|
|
2
|
-
*
|
|
3
|
-
* Reldens - PrismaSchemaGenerator
|
|
4
|
-
*
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
const { execSync } = require('child_process');
|
|
8
|
-
const { FileHandler } = require('@reldens/server-utils');
|
|
9
|
-
const { Logger, sc } = require('@reldens/utils');
|
|
10
|
-
|
|
11
|
-
class PrismaSchemaGenerator
|
|
12
|
-
{
|
|
13
|
-
|
|
14
|
-
constructor(props)
|
|
15
|
-
{
|
|
16
|
-
this.config = sc.get(props, 'config', {});
|
|
17
|
-
this.client = sc.get(props, 'client', 'mysql');
|
|
18
|
-
this.debug = sc.get(props, 'debug', false);
|
|
19
|
-
this.dataProxy = sc.get(props, 'dataProxy', false);
|
|
20
|
-
this.checkInterval = sc.get(props, 'checkInterval', 1000);
|
|
21
|
-
this.maxWaitTime = sc.get(props, 'maxWaitTime', 30000);
|
|
22
|
-
this.prismaSchemaPath = sc.get(props, 'prismaSchemaPath', FileHandler.joinPaths(process.cwd(), 'prisma'));
|
|
23
|
-
this.schemaFilePath = FileHandler.joinPaths(this.prismaSchemaPath, 'schema.prisma');
|
|
24
|
-
this.clientOutputPath = sc.get(props, 'clientOutputPath', '');
|
|
25
|
-
this.generateBinaryTargets = sc.get(props, 'generateBinaryTargets', ['native', 'debian-openssl-1.1.x']);
|
|
26
|
-
this.dbParams = sc.get(props, 'dbParams', process.env.RELDENS_DB_PARAMS || '');
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
async generate()
|
|
30
|
-
{
|
|
31
|
-
FileHandler.createFolder(this.prismaSchemaPath);
|
|
32
|
-
this.generateSchemaFile();
|
|
33
|
-
Logger.info('Running prisma introspect "npx prisma db pull"...');
|
|
34
|
-
try {
|
|
35
|
-
execSync('npx prisma db pull', { stdio: 'inherit' });
|
|
36
|
-
} catch(error) {
|
|
37
|
-
Logger.critical('Failed to pull database schema: ' + error.message);
|
|
38
|
-
return false;
|
|
39
|
-
}
|
|
40
|
-
let generateCommand = 'npx prisma generate';
|
|
41
|
-
if(this.dataProxy){
|
|
42
|
-
generateCommand += ' --data-proxy';
|
|
43
|
-
}
|
|
44
|
-
Logger.info('Running prisma generate "'+generateCommand+'"...');
|
|
45
|
-
try {
|
|
46
|
-
execSync(generateCommand, { stdio: 'inherit' });
|
|
47
|
-
} catch(error) {
|
|
48
|
-
let errorString = error.toString();
|
|
49
|
-
if(errorString.includes('EPERM') && errorString.includes('query_engine-windows.dll.node')){
|
|
50
|
-
Logger.warning('Windows permission error detected with query engine file.');
|
|
51
|
-
Logger.warning('This is a known Prisma issue on Windows.');
|
|
52
|
-
Logger.warning('Please manually run: ' + generateCommand);
|
|
53
|
-
Logger.warning('You may need to close any processes using the Prisma client first.');
|
|
54
|
-
return false;
|
|
55
|
-
}
|
|
56
|
-
Logger.critical('Generate command failed: ' + error.message);
|
|
57
|
-
return false;
|
|
58
|
-
}
|
|
59
|
-
await this.waitForSchemaGeneration();
|
|
60
|
-
return true;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
async waitForSchemaGeneration()
|
|
64
|
-
{
|
|
65
|
-
let clientPath = this.clientOutputPath || 'node_modules/.prisma/client';
|
|
66
|
-
let generatedClientPath = this.resolveClientPath(clientPath);
|
|
67
|
-
let clientIndexPath = FileHandler.joinPaths(generatedClientPath, 'index.js');
|
|
68
|
-
let startTime = Date.now();
|
|
69
|
-
return new Promise((resolve) => {
|
|
70
|
-
let interval = setInterval(() => {
|
|
71
|
-
let awaitTime = Date.now() - startTime;
|
|
72
|
-
Logger.info('Awaiting on schema generation: ' + clientIndexPath, (awaitTime/1000).toFixed(0));
|
|
73
|
-
if(FileHandler.exists(clientIndexPath)){
|
|
74
|
-
clearInterval(interval);
|
|
75
|
-
resolve();
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
if(awaitTime > this.maxWaitTime){
|
|
79
|
-
clearInterval(interval);
|
|
80
|
-
Logger.warning('Schema generation wait timeout reached.');
|
|
81
|
-
resolve();
|
|
82
|
-
}
|
|
83
|
-
}, this.checkInterval);
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
resolveClientPath(clientPath)
|
|
88
|
-
{
|
|
89
|
-
if(clientPath.match(/^[a-zA-Z]:/) || clientPath.startsWith('/')){
|
|
90
|
-
return clientPath;
|
|
91
|
-
}
|
|
92
|
-
if(clientPath.startsWith('node_modules')){
|
|
93
|
-
return FileHandler.joinPaths(process.cwd(), clientPath);
|
|
94
|
-
}
|
|
95
|
-
return FileHandler.joinPaths(this.prismaSchemaPath, clientPath);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
generateSchemaFile()
|
|
99
|
-
{
|
|
100
|
-
let datasourceProvider = this.getDatasourceProvider();
|
|
101
|
-
let schemaContent = this.buildSchemaContent(
|
|
102
|
-
datasourceProvider,
|
|
103
|
-
this.buildConnectionString(datasourceProvider),
|
|
104
|
-
this.buildDirectConnectionString(datasourceProvider)
|
|
105
|
-
);
|
|
106
|
-
FileHandler.writeFile(this.schemaFilePath, schemaContent);
|
|
107
|
-
Logger.info('Generated Prisma schema file at: '+this.schemaFilePath);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
getDatasourceProvider()
|
|
111
|
-
{
|
|
112
|
-
if('postgresql' === this.client || 'postgres' === this.client){
|
|
113
|
-
return 'postgresql';
|
|
114
|
-
}
|
|
115
|
-
if('mongodb' === this.client){
|
|
116
|
-
return 'mongodb';
|
|
117
|
-
}
|
|
118
|
-
return 'mysql';
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
buildConnectionString(datasourceProvider)
|
|
122
|
-
{
|
|
123
|
-
if(this.dataProxy){
|
|
124
|
-
datasourceProvider = 'prisma';
|
|
125
|
-
}
|
|
126
|
-
return datasourceProvider + this.buildConnectionDataString();
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
buildDirectConnectionString(datasourceProvider)
|
|
130
|
-
{
|
|
131
|
-
if(!this.dataProxy){
|
|
132
|
-
return '';
|
|
133
|
-
}
|
|
134
|
-
return datasourceProvider + this.buildConnectionDataString();
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
buildConnectionDataString()
|
|
138
|
-
{
|
|
139
|
-
return '://' + this.config.user + ':' + this.config.password
|
|
140
|
-
+ '@' + this.config.host+':' + this.config.port
|
|
141
|
-
+ '/' + this.config.database
|
|
142
|
-
+ (this.dbParams ? '?' + this.dbParams : '');
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
buildSchemaContent(datasourceProvider, connectionString, directConnectionString)
|
|
146
|
-
{
|
|
147
|
-
return this.buildGeneratorBlock() + '\n\n'
|
|
148
|
-
+ this.buildDatasourceBlock(datasourceProvider, connectionString, directConnectionString) + '\n';
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
buildGeneratorBlock()
|
|
152
|
-
{
|
|
153
|
-
let generatorContent = 'generator client {\n';
|
|
154
|
-
generatorContent += ' provider = "prisma-client-js"\n';
|
|
155
|
-
if(this.clientOutputPath){
|
|
156
|
-
let normalizedPath = this.clientOutputPath.replace(/\\/g, '/');
|
|
157
|
-
generatorContent += ' output = "' + normalizedPath + '"\n';
|
|
158
|
-
}
|
|
159
|
-
if(0 < this.generateBinaryTargets.length){
|
|
160
|
-
generatorContent += ' binaryTargets = [' +
|
|
161
|
-
this.generateBinaryTargets.map(target => '"' + target + '"').join(', ')
|
|
162
|
-
+ ']\n';
|
|
163
|
-
}
|
|
164
|
-
generatorContent += '}';
|
|
165
|
-
return generatorContent;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
buildDatasourceBlock(datasourceProvider, connectionString, directConnectionString)
|
|
169
|
-
{
|
|
170
|
-
let datasourceContent = 'datasource db {\n';
|
|
171
|
-
datasourceContent += ' provider = "' + datasourceProvider + '"\n';
|
|
172
|
-
datasourceContent += ' url = "' + connectionString + '"\n';
|
|
173
|
-
if('' !== directConnectionString){
|
|
174
|
-
datasourceContent += ' directUrl = "' + directConnectionString + '"\n';
|
|
175
|
-
}
|
|
176
|
-
datasourceContent += '}';
|
|
177
|
-
return datasourceContent;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
module.exports.PrismaSchemaGenerator = PrismaSchemaGenerator;
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* Reldens - PrismaSchemaGenerator
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { execSync } = require('child_process');
|
|
8
|
+
const { FileHandler } = require('@reldens/server-utils');
|
|
9
|
+
const { Logger, sc } = require('@reldens/utils');
|
|
10
|
+
|
|
11
|
+
class PrismaSchemaGenerator
|
|
12
|
+
{
|
|
13
|
+
|
|
14
|
+
constructor(props)
|
|
15
|
+
{
|
|
16
|
+
this.config = sc.get(props, 'config', {});
|
|
17
|
+
this.client = sc.get(props, 'client', 'mysql');
|
|
18
|
+
this.debug = sc.get(props, 'debug', false);
|
|
19
|
+
this.dataProxy = sc.get(props, 'dataProxy', false);
|
|
20
|
+
this.checkInterval = sc.get(props, 'checkInterval', 1000);
|
|
21
|
+
this.maxWaitTime = sc.get(props, 'maxWaitTime', 30000);
|
|
22
|
+
this.prismaSchemaPath = sc.get(props, 'prismaSchemaPath', FileHandler.joinPaths(process.cwd(), 'prisma'));
|
|
23
|
+
this.schemaFilePath = FileHandler.joinPaths(this.prismaSchemaPath, 'schema.prisma');
|
|
24
|
+
this.clientOutputPath = sc.get(props, 'clientOutputPath', '');
|
|
25
|
+
this.generateBinaryTargets = sc.get(props, 'generateBinaryTargets', ['native', 'debian-openssl-1.1.x']);
|
|
26
|
+
this.dbParams = sc.get(props, 'dbParams', process.env.RELDENS_DB_PARAMS || '');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async generate()
|
|
30
|
+
{
|
|
31
|
+
FileHandler.createFolder(this.prismaSchemaPath);
|
|
32
|
+
this.generateSchemaFile();
|
|
33
|
+
Logger.info('Running prisma introspect "npx prisma db pull"...');
|
|
34
|
+
try {
|
|
35
|
+
execSync('npx prisma db pull', { stdio: 'inherit' });
|
|
36
|
+
} catch(error) {
|
|
37
|
+
Logger.critical('Failed to pull database schema: ' + error.message);
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
let generateCommand = 'npx prisma generate';
|
|
41
|
+
if(this.dataProxy){
|
|
42
|
+
generateCommand += ' --data-proxy';
|
|
43
|
+
}
|
|
44
|
+
Logger.info('Running prisma generate "'+generateCommand+'"...');
|
|
45
|
+
try {
|
|
46
|
+
execSync(generateCommand, { stdio: 'inherit' });
|
|
47
|
+
} catch(error) {
|
|
48
|
+
let errorString = error.toString();
|
|
49
|
+
if(errorString.includes('EPERM') && errorString.includes('query_engine-windows.dll.node')){
|
|
50
|
+
Logger.warning('Windows permission error detected with query engine file.');
|
|
51
|
+
Logger.warning('This is a known Prisma issue on Windows.');
|
|
52
|
+
Logger.warning('Please manually run: ' + generateCommand);
|
|
53
|
+
Logger.warning('You may need to close any processes using the Prisma client first.');
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
Logger.critical('Generate command failed: ' + error.message);
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
await this.waitForSchemaGeneration();
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async waitForSchemaGeneration()
|
|
64
|
+
{
|
|
65
|
+
let clientPath = this.clientOutputPath || 'node_modules/.prisma/client';
|
|
66
|
+
let generatedClientPath = this.resolveClientPath(clientPath);
|
|
67
|
+
let clientIndexPath = FileHandler.joinPaths(generatedClientPath, 'index.js');
|
|
68
|
+
let startTime = Date.now();
|
|
69
|
+
return new Promise((resolve) => {
|
|
70
|
+
let interval = setInterval(() => {
|
|
71
|
+
let awaitTime = Date.now() - startTime;
|
|
72
|
+
Logger.info('Awaiting on schema generation: ' + clientIndexPath, (awaitTime/1000).toFixed(0));
|
|
73
|
+
if(FileHandler.exists(clientIndexPath)){
|
|
74
|
+
clearInterval(interval);
|
|
75
|
+
resolve();
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
if(awaitTime > this.maxWaitTime){
|
|
79
|
+
clearInterval(interval);
|
|
80
|
+
Logger.warning('Schema generation wait timeout reached.');
|
|
81
|
+
resolve();
|
|
82
|
+
}
|
|
83
|
+
}, this.checkInterval);
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
resolveClientPath(clientPath)
|
|
88
|
+
{
|
|
89
|
+
if(clientPath.match(/^[a-zA-Z]:/) || clientPath.startsWith('/')){
|
|
90
|
+
return clientPath;
|
|
91
|
+
}
|
|
92
|
+
if(clientPath.startsWith('node_modules')){
|
|
93
|
+
return FileHandler.joinPaths(process.cwd(), clientPath);
|
|
94
|
+
}
|
|
95
|
+
return FileHandler.joinPaths(this.prismaSchemaPath, clientPath);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
generateSchemaFile()
|
|
99
|
+
{
|
|
100
|
+
let datasourceProvider = this.getDatasourceProvider();
|
|
101
|
+
let schemaContent = this.buildSchemaContent(
|
|
102
|
+
datasourceProvider,
|
|
103
|
+
this.buildConnectionString(datasourceProvider),
|
|
104
|
+
this.buildDirectConnectionString(datasourceProvider)
|
|
105
|
+
);
|
|
106
|
+
FileHandler.writeFile(this.schemaFilePath, schemaContent);
|
|
107
|
+
Logger.info('Generated Prisma schema file at: '+this.schemaFilePath);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
getDatasourceProvider()
|
|
111
|
+
{
|
|
112
|
+
if('postgresql' === this.client || 'postgres' === this.client){
|
|
113
|
+
return 'postgresql';
|
|
114
|
+
}
|
|
115
|
+
if('mongodb' === this.client){
|
|
116
|
+
return 'mongodb';
|
|
117
|
+
}
|
|
118
|
+
return 'mysql';
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
buildConnectionString(datasourceProvider)
|
|
122
|
+
{
|
|
123
|
+
if(this.dataProxy){
|
|
124
|
+
datasourceProvider = 'prisma';
|
|
125
|
+
}
|
|
126
|
+
return datasourceProvider + this.buildConnectionDataString();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
buildDirectConnectionString(datasourceProvider)
|
|
130
|
+
{
|
|
131
|
+
if(!this.dataProxy){
|
|
132
|
+
return '';
|
|
133
|
+
}
|
|
134
|
+
return datasourceProvider + this.buildConnectionDataString();
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
buildConnectionDataString()
|
|
138
|
+
{
|
|
139
|
+
return '://' + this.config.user + ':' + this.config.password
|
|
140
|
+
+ '@' + this.config.host+':' + this.config.port
|
|
141
|
+
+ '/' + this.config.database
|
|
142
|
+
+ (this.dbParams ? '?' + this.dbParams : '');
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
buildSchemaContent(datasourceProvider, connectionString, directConnectionString)
|
|
146
|
+
{
|
|
147
|
+
return this.buildGeneratorBlock() + '\n\n'
|
|
148
|
+
+ this.buildDatasourceBlock(datasourceProvider, connectionString, directConnectionString) + '\n';
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
buildGeneratorBlock()
|
|
152
|
+
{
|
|
153
|
+
let generatorContent = 'generator client {\n';
|
|
154
|
+
generatorContent += ' provider = "prisma-client-js"\n';
|
|
155
|
+
if(this.clientOutputPath){
|
|
156
|
+
let normalizedPath = this.clientOutputPath.replace(/\\/g, '/');
|
|
157
|
+
generatorContent += ' output = "' + normalizedPath + '"\n';
|
|
158
|
+
}
|
|
159
|
+
if(0 < this.generateBinaryTargets.length){
|
|
160
|
+
generatorContent += ' binaryTargets = [' +
|
|
161
|
+
this.generateBinaryTargets.map(target => '"' + target + '"').join(', ')
|
|
162
|
+
+ ']\n';
|
|
163
|
+
}
|
|
164
|
+
generatorContent += '}';
|
|
165
|
+
return generatorContent;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
buildDatasourceBlock(datasourceProvider, connectionString, directConnectionString)
|
|
169
|
+
{
|
|
170
|
+
let datasourceContent = 'datasource db {\n';
|
|
171
|
+
datasourceContent += ' provider = "' + datasourceProvider + '"\n';
|
|
172
|
+
datasourceContent += ' url = "' + connectionString + '"\n';
|
|
173
|
+
if('' !== directConnectionString){
|
|
174
|
+
datasourceContent += ' directUrl = "' + directConnectionString + '"\n';
|
|
175
|
+
}
|
|
176
|
+
datasourceContent += '}';
|
|
177
|
+
return datasourceContent;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
module.exports.PrismaSchemaGenerator = PrismaSchemaGenerator;
|
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.80.0",
|
|
5
5
|
"description": "Reldens - Storage",
|
|
6
6
|
"author": "Damian A. Pastorini",
|
|
7
7
|
"license": "MIT",
|
|
@@ -42,11 +42,11 @@
|
|
|
42
42
|
"url": "https://github.com/damian-pastorini/reldens-storage/issues"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@mikro-orm/core": "6.6.
|
|
46
|
-
"@mikro-orm/mongodb": "6.6.
|
|
47
|
-
"@mikro-orm/mysql": "6.6.
|
|
45
|
+
"@mikro-orm/core": "6.6.1",
|
|
46
|
+
"@mikro-orm/mongodb": "6.6.1",
|
|
47
|
+
"@mikro-orm/mysql": "6.6.1",
|
|
48
48
|
"@prisma/client": "6.19.0",
|
|
49
|
-
"@reldens/server-utils": "^0.
|
|
49
|
+
"@reldens/server-utils": "^0.41.0",
|
|
50
50
|
"@reldens/utils": "^0.54.0",
|
|
51
51
|
"knex": "3.1.0",
|
|
52
52
|
"mysql": "2.18.1",
|