@reldens/storage 0.117.0 → 0.119.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/.claude/test-architecture.md +27 -17
- package/CLAUDE.md +67 -11
- package/README.md +204 -22
- package/bin/reldens-storage.js +43 -10
- package/index.js +53 -12
- package/lib/drizzle/drizzle-data-server.js +123 -0
- package/lib/drizzle/drizzle-driver.js +228 -0
- package/lib/drizzle/drizzle-models-generation.js +49 -0
- package/lib/drizzle/drizzle-modules-loader.js +32 -0
- package/lib/drizzle/drizzle-modules-validator.js +74 -0
- package/lib/entities-generator.js +36 -7
- package/lib/entity-templates/drizzle-model.template +28 -0
- package/lib/entity-templates/query-builder-model.template +17 -0
- package/lib/generators/base-generator.js +13 -0
- package/lib/generators/entities-generation.js +0 -13
- package/lib/generators/models-generation.js +179 -680
- package/lib/generators/relations-detection.js +171 -0
- package/lib/knex/knex-data-server.js +128 -0
- package/lib/knex/knex-driver.js +157 -0
- package/lib/knex/knex-modules-loader.js +28 -0
- package/lib/knex/knex-modules-validator.js +45 -0
- package/lib/kysely/kysely-data-server.js +128 -0
- package/lib/kysely/kysely-driver.js +176 -0
- package/lib/kysely/kysely-modules-loader.js +28 -0
- package/lib/kysely/kysely-modules-validator.js +53 -0
- package/lib/mikro-orm/mikro-orm-data-server.js +48 -29
- package/lib/mikro-orm/mikro-orm-driver.js +317 -108
- package/lib/mikro-orm/mikro-orm-models-generation.js +178 -0
- package/lib/mikro-orm/mikro-orm-modules-loader.js +50 -0
- package/lib/mikro-orm/mikro-orm-modules-validator.js +46 -0
- package/lib/mysql2-connection-config.js +38 -0
- package/lib/objection-js/objection-js-data-server.js +71 -125
- package/lib/objection-js/objection-js-driver.js +4 -1
- package/lib/objection-js/objection-js-models-generation.js +98 -0
- package/lib/objection-js/objection-modules-loader.js +28 -0
- package/lib/objection-js/objection-modules-validator.js +31 -0
- package/lib/package-resolver.js +45 -0
- package/lib/prisma/prisma-client-loader.js +11 -1
- package/lib/prisma/prisma-driver.js +16 -2
- package/lib/prisma/prisma-filter-processor.js +5 -6
- package/lib/prisma/prisma-models-generation.js +236 -0
- package/lib/prisma/prisma-schema-generator.js +5 -1
- package/lib/prisma/prisma-type-caster.js +14 -0
- package/lib/query-builder-driver.js +210 -0
- package/lib/query-builder-models-generation.js +80 -0
- package/lib/relations-loader.js +192 -0
- package/lib/type-mapper.js +38 -0
- package/package.json +8 -8
- package/tests/.env.test.example +6 -0
- package/tests/fixtures/categories-fixtures.js +8 -0
- package/tests/fixtures/expected-entities/entities/test-product-details-entity.js +10 -1
- package/tests/fixtures/expected-entities/entities-translations.js +2 -0
- package/tests/fixtures/expected-entities-mikro-orm/models/mikro-orm/test-categories-model.js +13 -8
- package/tests/fixtures/expected-entities-mikro-orm/models/mikro-orm/test-product-details-model.js +30 -10
- package/tests/fixtures/expected-entities-mikro-orm/models/mikro-orm/test-products-model.js +15 -14
- package/tests/fixtures/expected-entities-mikro-orm/models/mikro-orm/test-reviews-model.js +13 -12
- package/tests/fixtures/expected-entities-prisma/models/prisma/test-product-details-model.js +3 -1
- package/tests/fixtures/product-details-fixtures.js +4 -1
- package/tests/fixtures/reviews-fixtures.js +2 -1
- package/tests/fixtures/sql/test-schema.sql +11 -2
- package/tests/fixtures/table-columns-fixtures.js +97 -0
- package/tests/integration/test-cross-driver-equivalence.js +286 -0
- package/tests/integration/test-nested-filters.js +265 -408
- package/tests/integration/test-relations.js +135 -0
- package/tests/integration/test-reldens-sample-data.js +255 -0
- package/tests/integration/test-reldens-shape-relations.js +292 -0
- package/tests/run-tests.js +111 -65
- package/tests/unit/test-drivers.js +7 -1
- package/tests/unit/test-models-generation.js +28 -18
- package/tests/utils/column-value-assert.js +139 -0
- package/tests/utils/entity-projection.js +111 -0
- package/tests/utils/observed-value.js +41 -0
- package/tests/utils/projection-difference.js +151 -0
- package/tests/utils/relations-shape-support.js +104 -0
- package/tests/utils/reldens-schema-loader.js +274 -0
- package/tests/utils/test-helpers.js +143 -13
- package/tests/utils/test-runner.js +26 -5
- package/tests/utils/whole-result-assert.js +243 -0
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* Reldens - MikroOrmModelsGeneration
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { sc } = require('@reldens/utils');
|
|
8
|
+
|
|
9
|
+
class MikroOrmModelsGeneration
|
|
10
|
+
{
|
|
11
|
+
|
|
12
|
+
constructor(relationsDetection)
|
|
13
|
+
{
|
|
14
|
+
this.relationsDetection = relationsDetection;
|
|
15
|
+
this.relationKindMap = {
|
|
16
|
+
'BelongsToOneRelation': 'm:1',
|
|
17
|
+
'HasOneRelation': '1:1',
|
|
18
|
+
'HasManyRelation': '1:m',
|
|
19
|
+
'ManyToManyRelation': 'm:n'
|
|
20
|
+
};
|
|
21
|
+
this.columnTypesMap = {
|
|
22
|
+
'bigint': 'number'
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
modelTableName(tableName)
|
|
27
|
+
{
|
|
28
|
+
return tableName;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
generateRelations(tableName, tableData, relationMetadata)
|
|
32
|
+
{
|
|
33
|
+
return '';
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
generateIdColumn(columns)
|
|
37
|
+
{
|
|
38
|
+
return '';
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
generateEntityProperties(columns, tableName, tableData)
|
|
42
|
+
{
|
|
43
|
+
if(!tableName || !tableData){
|
|
44
|
+
return this.columnsProperties(columns, {}).join(',\n ');
|
|
45
|
+
}
|
|
46
|
+
let relations = this.relationsDetection.detectForwardRelations(tableName, tableData);
|
|
47
|
+
let entityProps = this.columnsProperties(columns);
|
|
48
|
+
for(let relationKey of Object.keys(relations)){
|
|
49
|
+
entityProps.push(this.forwardRelationProperty(relationKey, relations[relationKey], columns));
|
|
50
|
+
}
|
|
51
|
+
let reverseRelations = this.relationsDetection.detectReverseRelations(tableName);
|
|
52
|
+
for(let relationKey of Object.keys(reverseRelations)){
|
|
53
|
+
entityProps.push(this.reverseRelationProperty(relationKey, reverseRelations[relationKey], tableName));
|
|
54
|
+
}
|
|
55
|
+
return entityProps.join(',\n ');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
columnsProperties(columns)
|
|
59
|
+
{
|
|
60
|
+
let entityProps = [];
|
|
61
|
+
for(let columnName of Object.keys(columns)){
|
|
62
|
+
entityProps.push(this.columnProperty(columnName, columns[columnName]));
|
|
63
|
+
}
|
|
64
|
+
return entityProps;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
columnProperty(columnName, column)
|
|
68
|
+
{
|
|
69
|
+
let propDef = columnName+': { type: \''+sc.get(this.columnTypesMap, column.type, column.type)+'\'';
|
|
70
|
+
if('PRI' === column.key){
|
|
71
|
+
propDef += ', primary: true';
|
|
72
|
+
}
|
|
73
|
+
if('UNI' === column.key){
|
|
74
|
+
propDef += ', unique: true';
|
|
75
|
+
}
|
|
76
|
+
if(column.nullable || this.hasDefaultValue(column)){
|
|
77
|
+
propDef += ', nullable: true';
|
|
78
|
+
}
|
|
79
|
+
return propDef+' }';
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
hasDefaultValue(column)
|
|
83
|
+
{
|
|
84
|
+
return null !== column.default && 'undefined' !== typeof column.default;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
forwardRelationProperty(relationKey, relation, columns)
|
|
88
|
+
{
|
|
89
|
+
let relatedModelClass = sc.capitalizedCamelCase(relation.referencedTable)+'Model';
|
|
90
|
+
let relatedModelFile = sc.kebabCase(relation.referencedTable)+'-model';
|
|
91
|
+
let propDef = relationKey+': {\n';
|
|
92
|
+
propDef += ' kind: \''+this.forwardRelationKind(columns[relation.fromColumn])+'\',\n';
|
|
93
|
+
propDef += ' entity: () => require(\'./'+relatedModelFile+'\').'+relatedModelClass;
|
|
94
|
+
if(relation.fromColumn){
|
|
95
|
+
propDef += ',\n joinColumns: [\''+relation.fromColumn+'\']';
|
|
96
|
+
}
|
|
97
|
+
if(this.isNonPrimaryReference(relation)){
|
|
98
|
+
propDef += ',\n referencedColumnNames: [\''+relation.toColumn+'\']';
|
|
99
|
+
propDef += ',\n targetKey: \''+relation.toColumn+'\'';
|
|
100
|
+
propDef += ',\n cascade: [],\n mapToPk: true';
|
|
101
|
+
}
|
|
102
|
+
if(this.isNullableColumn(columns[relation.fromColumn])){
|
|
103
|
+
propDef += ',\n nullable: true';
|
|
104
|
+
}
|
|
105
|
+
propDef += ',\n persist: false';
|
|
106
|
+
return propDef+'\n }';
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
isNonPrimaryReference(relation)
|
|
110
|
+
{
|
|
111
|
+
if(!relation.toColumn){
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
return 'id' !== relation.toColumn;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
isNullableColumn(column)
|
|
118
|
+
{
|
|
119
|
+
if(!column){
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
return Boolean(column.nullable);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
forwardRelationKind(column)
|
|
126
|
+
{
|
|
127
|
+
if('HasOneRelation' === this.relationsDetection.determineRelationType(column, false)){
|
|
128
|
+
return this.relationKindMap.HasOneRelation;
|
|
129
|
+
}
|
|
130
|
+
return this.relationKindMap.BelongsToOneRelation;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
reverseRelationProperty(relationKey, relation, tableName)
|
|
134
|
+
{
|
|
135
|
+
let relatedModelClass = sc.capitalizedCamelCase(relation.referencingTable)+'Model';
|
|
136
|
+
let relatedModelFile = sc.kebabCase(relation.referencingTable)+'-model';
|
|
137
|
+
let mappedBy = this.relationsDetection.findMappedByKey(tableName, relation.referencingTable, relation);
|
|
138
|
+
let propDef = relationKey+': {\n';
|
|
139
|
+
propDef += ' kind: \''+sc.get(this.relationKindMap, relation.relationType, '1:m')+'\',\n';
|
|
140
|
+
propDef += ' entity: () => require(\'./'+relatedModelFile+'\').'+relatedModelClass;
|
|
141
|
+
if(mappedBy){
|
|
142
|
+
propDef += ',\n mappedBy: \''+mappedBy+'\'';
|
|
143
|
+
}
|
|
144
|
+
return propDef+'\n }';
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
generateFkMappings(tableName, tableData)
|
|
148
|
+
{
|
|
149
|
+
if(!tableName || !tableData){
|
|
150
|
+
return '';
|
|
151
|
+
}
|
|
152
|
+
let fkMappings = {};
|
|
153
|
+
let referenceCounts = this.relationsDetection.countReferencesPerTable(tableData);
|
|
154
|
+
for(let columnName of Object.keys(tableData.columns)){
|
|
155
|
+
let column = tableData.columns[columnName];
|
|
156
|
+
if(!sc.hasOwn(column, 'referencedTable')){
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
fkMappings[columnName] = {
|
|
160
|
+
relationKey: this.relationsDetection.generateForwardRelationKey(
|
|
161
|
+
column.referencedTable,
|
|
162
|
+
columnName,
|
|
163
|
+
referenceCounts
|
|
164
|
+
),
|
|
165
|
+
entityName: sc.capitalizedCamelCase(column.referencedTable)+'Model',
|
|
166
|
+
referencedColumn: column.referencedColumn,
|
|
167
|
+
nullable: sc.get(column, 'nullable', false)
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
if(0 === Object.keys(fkMappings).length){
|
|
171
|
+
return '';
|
|
172
|
+
}
|
|
173
|
+
return JSON.stringify(fkMappings, null, 4);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
module.exports.MikroOrmModelsGeneration = MikroOrmModelsGeneration;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* Reldens - Storage - MikroOrmModulesLoader
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { MikroOrmModulesValidator } = require('./mikro-orm-modules-validator');
|
|
8
|
+
const { PackageResolver } = require('../package-resolver');
|
|
9
|
+
|
|
10
|
+
class MikroOrmModulesLoader
|
|
11
|
+
{
|
|
12
|
+
|
|
13
|
+
static load(projectPath, client)
|
|
14
|
+
{
|
|
15
|
+
let mikroOrmCore = PackageResolver.loadPackage('@mikro-orm/core', projectPath);
|
|
16
|
+
if(!mikroOrmCore){
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
let mikroOrmModules = {
|
|
20
|
+
MikroORM: mikroOrmCore.MikroORM,
|
|
21
|
+
EntityCaseNamingStrategy: mikroOrmCore.EntityCaseNamingStrategy,
|
|
22
|
+
Collection: mikroOrmCore.Collection,
|
|
23
|
+
EntitySchema: mikroOrmCore.EntitySchema
|
|
24
|
+
};
|
|
25
|
+
MikroOrmModulesLoader.appendClientDriver(mikroOrmModules, projectPath, client);
|
|
26
|
+
if(!MikroOrmModulesValidator.validate(mikroOrmModules, client)){
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
return mikroOrmModules;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
static appendClientDriver(mikroOrmModules, projectPath, client)
|
|
33
|
+
{
|
|
34
|
+
if('mongodb' === client){
|
|
35
|
+
let mongoPackage = PackageResolver.loadPackage('@mikro-orm/mongodb', projectPath);
|
|
36
|
+
if(mongoPackage){
|
|
37
|
+
mikroOrmModules.MongoDriver = mongoPackage.MongoDriver;
|
|
38
|
+
}
|
|
39
|
+
return mikroOrmModules;
|
|
40
|
+
}
|
|
41
|
+
let mysqlPackage = PackageResolver.loadPackage('@mikro-orm/mysql', projectPath);
|
|
42
|
+
if(mysqlPackage){
|
|
43
|
+
mikroOrmModules.MySqlDriver = mysqlPackage.MySqlDriver;
|
|
44
|
+
}
|
|
45
|
+
return mikroOrmModules;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
module.exports.MikroOrmModulesLoader = MikroOrmModulesLoader;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* Reldens - MikroOrmModulesValidator
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { Logger, sc } = require('@reldens/utils');
|
|
8
|
+
|
|
9
|
+
let requiredCoreClasses = ['MikroORM', 'EntityCaseNamingStrategy', 'Collection'];
|
|
10
|
+
|
|
11
|
+
class MikroOrmModulesValidator
|
|
12
|
+
{
|
|
13
|
+
|
|
14
|
+
static validate(mikroOrmModules, client)
|
|
15
|
+
{
|
|
16
|
+
if(!sc.isObject(mikroOrmModules)){
|
|
17
|
+
Logger.critical('Missing "mikroOrmModules" object.');
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
let missingClasses = requiredCoreClasses.filter(coreClass => !sc.isFunction(mikroOrmModules[coreClass]));
|
|
21
|
+
if(0 < missingClasses.length){
|
|
22
|
+
Logger.critical('Invalid "mikroOrmModules", missing: '+missingClasses.join(', '));
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
return MikroOrmModulesValidator.validateClientDriver(mikroOrmModules, client);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
static validateClientDriver(mikroOrmModules, client)
|
|
29
|
+
{
|
|
30
|
+
if('mongodb' === client){
|
|
31
|
+
if(!sc.isFunction(mikroOrmModules.MongoDriver)){
|
|
32
|
+
Logger.critical('Missing "mikroOrmModules.MongoDriver" for the "mongodb" client.');
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
if(!sc.isFunction(mikroOrmModules.MySqlDriver)){
|
|
38
|
+
Logger.critical('Missing "mikroOrmModules.MySqlDriver" for the "'+client+'" client.');
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
module.exports.MikroOrmModulesValidator = MikroOrmModulesValidator;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* Reldens - Mysql2ConnectionConfig
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { sc } = require('@reldens/utils');
|
|
8
|
+
|
|
9
|
+
let validMySQL2Options = [
|
|
10
|
+
'authPlugins', 'authSwitchHandler', 'bigNumberStrings', 'charset', 'charsetNumber', 'compress',
|
|
11
|
+
'connectAttributes', 'connectTimeout', 'database', 'dateStrings', 'debug', 'decimalNumbers',
|
|
12
|
+
'enableKeepAlive', 'flags', 'host', 'insecureAuth', 'infileStreamFactory', 'isServer',
|
|
13
|
+
'keepAliveInitialDelay', 'localAddress', 'maxPreparedStatements', 'multipleStatements',
|
|
14
|
+
'namedPlaceholders', 'nestTables', 'password', 'password1', 'password2', 'password3', 'passwordSha1',
|
|
15
|
+
'pool', 'port', 'queryFormat', 'rowsAsArray', 'socketPath', 'ssl', 'stream', 'stringifyObjects',
|
|
16
|
+
'supportBigNumbers', 'timezone', 'trace', 'typeCast', 'uri', 'user', 'disableEval', 'connectionLimit',
|
|
17
|
+
'maxIdle', 'idleTimeout', 'Promise', 'queueLimit', 'waitForConnections', 'jsonStrings', 'gracefulEnd'
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
class Mysql2ConnectionConfig
|
|
21
|
+
{
|
|
22
|
+
|
|
23
|
+
static sanitize(config)
|
|
24
|
+
{
|
|
25
|
+
let cleanConfig = {};
|
|
26
|
+
for(let prop of validMySQL2Options){
|
|
27
|
+
if(sc.hasOwn(config, prop)){
|
|
28
|
+
cleanConfig[prop] = config[prop];
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return cleanConfig;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
module.exports.validMySQL2Options = validMySQL2Options;
|
|
37
|
+
|
|
38
|
+
module.exports.Mysql2ConnectionConfig = Mysql2ConnectionConfig;
|
|
@@ -1,125 +1,71 @@
|
|
|
1
|
-
/**
|
|
2
|
-
*
|
|
3
|
-
* Reldens - ObjectionJsDataServer
|
|
4
|
-
*
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
const {
|
|
8
|
-
const { ObjectionJsDriver } = require('./objection-js-driver');
|
|
9
|
-
const {
|
|
10
|
-
const {
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
this.
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
return cleanConfig;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
async disconnect()
|
|
76
|
-
{
|
|
77
|
-
if(!this.knex){
|
|
78
|
-
return false;
|
|
79
|
-
}
|
|
80
|
-
await this.knex.destroy();
|
|
81
|
-
return true;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
generateEntities()
|
|
85
|
-
{
|
|
86
|
-
if(!this.rawEntities){
|
|
87
|
-
Logger.warning('Empty raw entities array, none entities generated.');
|
|
88
|
-
return {};
|
|
89
|
-
}
|
|
90
|
-
this.entities = {};
|
|
91
|
-
for(let i of Object.keys(this.rawEntities)){
|
|
92
|
-
let rawEntity = this.rawEntities[i];
|
|
93
|
-
if(!rawEntity?.knex){
|
|
94
|
-
Logger.critical('Invalid raw entity "'+i+'".');
|
|
95
|
-
continue;
|
|
96
|
-
}
|
|
97
|
-
this.entities[i] = new ObjectionJsDriver({rawModel: rawEntity, id: i, name: i, config: rawEntity.knex});
|
|
98
|
-
}
|
|
99
|
-
this.entityManager.setEntities(this.entities);
|
|
100
|
-
return this.entities;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
name()
|
|
104
|
-
{
|
|
105
|
-
return this.name || 'Objection JS Data Server Driver';
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
async rawQuery(content)
|
|
109
|
-
{
|
|
110
|
-
let result = await this.knex.raw(content);
|
|
111
|
-
return result[0] || false;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
async fetchEntitiesFromDatabase()
|
|
115
|
-
{
|
|
116
|
-
if(!this.initialized){
|
|
117
|
-
Logger.error('Connection was not initialized, please use the connect method first.');
|
|
118
|
-
return false;
|
|
119
|
-
}
|
|
120
|
-
return await MySQLTablesProvider.fetchTables(this);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
module.exports.ObjectionJsDataServer = ObjectionJsDataServer;
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* Reldens - ObjectionJsDataServer
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { KnexDataServer } = require('../knex/knex-data-server');
|
|
8
|
+
const { ObjectionJsDriver } = require('./objection-js-driver');
|
|
9
|
+
const { ObjectionModulesValidator } = require('./objection-modules-validator');
|
|
10
|
+
const { ObjectionModulesLoader } = require('./objection-modules-loader');
|
|
11
|
+
const { Logger, sc } = require('@reldens/utils');
|
|
12
|
+
|
|
13
|
+
class ObjectionJsDataServer extends KnexDataServer
|
|
14
|
+
{
|
|
15
|
+
|
|
16
|
+
constructor(props)
|
|
17
|
+
{
|
|
18
|
+
super(props);
|
|
19
|
+
this.objectionModules = sc.get(props, 'objectionModules', false);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async connect()
|
|
23
|
+
{
|
|
24
|
+
if(!this.objectionModules){
|
|
25
|
+
this.objectionModules = ObjectionModulesLoader.load(this.projectRoot);
|
|
26
|
+
}
|
|
27
|
+
if(!ObjectionModulesValidator.validate(this.objectionModules)){
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
if(!this.rawModel){
|
|
31
|
+
this.rawModel = this.objectionModules.Model;
|
|
32
|
+
}
|
|
33
|
+
let initialized = await super.connect();
|
|
34
|
+
if(this.knex){
|
|
35
|
+
await this.rawModel.knex(this.knex);
|
|
36
|
+
}
|
|
37
|
+
return initialized;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
connectionErrorMessage()
|
|
41
|
+
{
|
|
42
|
+
return 'Connection failed, Objection JS error.';
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
generateEntities()
|
|
46
|
+
{
|
|
47
|
+
if(!this.rawEntities){
|
|
48
|
+
Logger.warning('Empty raw entities array, none entities generated.');
|
|
49
|
+
return {};
|
|
50
|
+
}
|
|
51
|
+
this.entities = {};
|
|
52
|
+
for(let i of Object.keys(this.rawEntities)){
|
|
53
|
+
let rawEntity = this.rawEntities[i];
|
|
54
|
+
if(!rawEntity?.knex){
|
|
55
|
+
Logger.critical('Invalid raw entity "'+i+'".');
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
this.entities[i] = new ObjectionJsDriver({rawModel: rawEntity, id: i, name: i, config: rawEntity.knex});
|
|
59
|
+
}
|
|
60
|
+
this.entityManager.setEntities(this.entities);
|
|
61
|
+
return this.entities;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
name()
|
|
65
|
+
{
|
|
66
|
+
return this.name || 'Objection JS Data Server Driver';
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
module.exports.ObjectionJsDataServer = ObjectionJsDataServer;
|
|
@@ -37,7 +37,7 @@ class ObjectionJsDriver extends BaseDriver
|
|
|
37
37
|
|
|
38
38
|
create(params)
|
|
39
39
|
{
|
|
40
|
-
return this.queryBuilder().
|
|
40
|
+
return this.queryBuilder().insertAndFetch(params);
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
createWithRelations(params, relations)
|
|
@@ -359,6 +359,9 @@ class ObjectionJsDriver extends BaseDriver
|
|
|
359
359
|
|
|
360
360
|
appendRelationsToQuery(queryBuilder, relations, relationsModifiers, useJoin = false)
|
|
361
361
|
{
|
|
362
|
+
if(sc.isString(relations)){
|
|
363
|
+
relations = this.parseRelationsString(relations);
|
|
364
|
+
}
|
|
362
365
|
if(!sc.isArray(relations) || 0 === relations.length){
|
|
363
366
|
relations = Object.keys(this.rawModel.relationMappings || {});
|
|
364
367
|
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* Reldens - ObjectionJsModelsGeneration
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { sc } = require('@reldens/utils');
|
|
8
|
+
|
|
9
|
+
class ObjectionJsModelsGeneration
|
|
10
|
+
{
|
|
11
|
+
|
|
12
|
+
constructor(relationsDetection)
|
|
13
|
+
{
|
|
14
|
+
this.relationsDetection = relationsDetection;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
modelTableName(tableName)
|
|
18
|
+
{
|
|
19
|
+
return tableName;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
generateEntityProperties(columns, tableName, tableData)
|
|
23
|
+
{
|
|
24
|
+
return '';
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
generateFkMappings(tableName, tableData)
|
|
28
|
+
{
|
|
29
|
+
return '';
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
generateIdColumn(columns)
|
|
33
|
+
{
|
|
34
|
+
let primaryKeyColumn = this.relationsDetection.detectPrimaryKeyColumn(columns);
|
|
35
|
+
if(!primaryKeyColumn || 'id' === primaryKeyColumn){
|
|
36
|
+
return '';
|
|
37
|
+
}
|
|
38
|
+
return '\n static get idColumn()\n {\n return \''+primaryKeyColumn+'\';\n }\n';
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
generateRelations(tableName, tableData, relationMetadata)
|
|
42
|
+
{
|
|
43
|
+
let relations = this.relationsDetection.detectForwardRelations(tableName, tableData);
|
|
44
|
+
let reverseRelations = this.relationsDetection.detectReverseRelations(tableName);
|
|
45
|
+
let allRelations = Object.assign({}, relations, reverseRelations);
|
|
46
|
+
if(0 === Object.keys(allRelations).length){
|
|
47
|
+
return '';
|
|
48
|
+
}
|
|
49
|
+
let relationMappings = [];
|
|
50
|
+
let requiredModels = [];
|
|
51
|
+
for(let relationKey of Object.keys(allRelations)){
|
|
52
|
+
let relation = allRelations[relationKey];
|
|
53
|
+
let tableReference = sc.get(relation, 'referencedTable', relation.referencingTable);
|
|
54
|
+
let relatedModelClass = sc.capitalizedCamelCase(tableReference)+'Model';
|
|
55
|
+
if(!requiredModels.find(requiredModel => requiredModel.modelClass === relatedModelClass)){
|
|
56
|
+
requiredModels.push({
|
|
57
|
+
modelClass: relatedModelClass,
|
|
58
|
+
fileName: sc.kebabCase(tableReference)+'-model'
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
relationMappings.push(this.relationMappingDefinition(relationKey, relation, relatedModelClass));
|
|
62
|
+
}
|
|
63
|
+
return this.relationMappingsMethod(requiredModels, relationMappings);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
relationMappingDefinition(relationKey, relation, relatedModelClass)
|
|
67
|
+
{
|
|
68
|
+
let relationMapping = ' '+relationKey+': {\n';
|
|
69
|
+
relationMapping += ' relation: this.'+relation.relationType+',\n';
|
|
70
|
+
relationMapping += ' modelClass: '+relatedModelClass+',\n';
|
|
71
|
+
relationMapping += ' join: {\n';
|
|
72
|
+
relationMapping += ' from: this.tableName+\'.'+relation.fromColumn+'\',\n';
|
|
73
|
+
relationMapping += ' to: '+relatedModelClass+'.tableName+\'.'+relation.toColumn+'\'\n';
|
|
74
|
+
relationMapping += ' }\n';
|
|
75
|
+
relationMapping += ' }';
|
|
76
|
+
return relationMapping;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
relationMappingsMethod(requiredModels, relationMappings)
|
|
80
|
+
{
|
|
81
|
+
let requireStatements = [];
|
|
82
|
+
for(let modelInfo of requiredModels){
|
|
83
|
+
requireStatements.push(
|
|
84
|
+
' const { '+modelInfo.modelClass+' } = require(\'./'+modelInfo.fileName+'\');'
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
let relationMappingsMethod = '\n static get relationMappings()\n {\n';
|
|
88
|
+
relationMappingsMethod += requireStatements.join('\n')+'\n';
|
|
89
|
+
relationMappingsMethod += ' return {\n';
|
|
90
|
+
relationMappingsMethod += relationMappings.join(',\n');
|
|
91
|
+
relationMappingsMethod += '\n };\n';
|
|
92
|
+
relationMappingsMethod += ' }';
|
|
93
|
+
return relationMappingsMethod;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
module.exports.ObjectionJsModelsGeneration = ObjectionJsModelsGeneration;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* Reldens - Storage - ObjectionModulesLoader
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { ObjectionModulesValidator } = require('./objection-modules-validator');
|
|
8
|
+
const { PackageResolver } = require('../package-resolver');
|
|
9
|
+
|
|
10
|
+
class ObjectionModulesLoader
|
|
11
|
+
{
|
|
12
|
+
|
|
13
|
+
static load(projectPath)
|
|
14
|
+
{
|
|
15
|
+
let objection = PackageResolver.loadPackage('objection', projectPath);
|
|
16
|
+
if(!objection){
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
let objectionModules = {Model: objection.Model};
|
|
20
|
+
if(!ObjectionModulesValidator.validate(objectionModules)){
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
return objectionModules;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
module.exports.ObjectionModulesLoader = ObjectionModulesLoader;
|