@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.
Files changed (78) hide show
  1. package/.claude/test-architecture.md +27 -17
  2. package/CLAUDE.md +67 -11
  3. package/README.md +204 -22
  4. package/bin/reldens-storage.js +43 -10
  5. package/index.js +53 -12
  6. package/lib/drizzle/drizzle-data-server.js +123 -0
  7. package/lib/drizzle/drizzle-driver.js +228 -0
  8. package/lib/drizzle/drizzle-models-generation.js +49 -0
  9. package/lib/drizzle/drizzle-modules-loader.js +32 -0
  10. package/lib/drizzle/drizzle-modules-validator.js +74 -0
  11. package/lib/entities-generator.js +36 -7
  12. package/lib/entity-templates/drizzle-model.template +28 -0
  13. package/lib/entity-templates/query-builder-model.template +17 -0
  14. package/lib/generators/base-generator.js +13 -0
  15. package/lib/generators/entities-generation.js +0 -13
  16. package/lib/generators/models-generation.js +179 -680
  17. package/lib/generators/relations-detection.js +171 -0
  18. package/lib/knex/knex-data-server.js +128 -0
  19. package/lib/knex/knex-driver.js +157 -0
  20. package/lib/knex/knex-modules-loader.js +28 -0
  21. package/lib/knex/knex-modules-validator.js +45 -0
  22. package/lib/kysely/kysely-data-server.js +128 -0
  23. package/lib/kysely/kysely-driver.js +176 -0
  24. package/lib/kysely/kysely-modules-loader.js +28 -0
  25. package/lib/kysely/kysely-modules-validator.js +53 -0
  26. package/lib/mikro-orm/mikro-orm-data-server.js +48 -29
  27. package/lib/mikro-orm/mikro-orm-driver.js +317 -108
  28. package/lib/mikro-orm/mikro-orm-models-generation.js +178 -0
  29. package/lib/mikro-orm/mikro-orm-modules-loader.js +50 -0
  30. package/lib/mikro-orm/mikro-orm-modules-validator.js +46 -0
  31. package/lib/mysql2-connection-config.js +38 -0
  32. package/lib/objection-js/objection-js-data-server.js +71 -125
  33. package/lib/objection-js/objection-js-driver.js +4 -1
  34. package/lib/objection-js/objection-js-models-generation.js +98 -0
  35. package/lib/objection-js/objection-modules-loader.js +28 -0
  36. package/lib/objection-js/objection-modules-validator.js +31 -0
  37. package/lib/package-resolver.js +45 -0
  38. package/lib/prisma/prisma-client-loader.js +11 -1
  39. package/lib/prisma/prisma-driver.js +16 -2
  40. package/lib/prisma/prisma-filter-processor.js +5 -6
  41. package/lib/prisma/prisma-models-generation.js +236 -0
  42. package/lib/prisma/prisma-schema-generator.js +5 -1
  43. package/lib/prisma/prisma-type-caster.js +14 -0
  44. package/lib/query-builder-driver.js +210 -0
  45. package/lib/query-builder-models-generation.js +80 -0
  46. package/lib/relations-loader.js +192 -0
  47. package/lib/type-mapper.js +38 -0
  48. package/package.json +8 -8
  49. package/tests/.env.test.example +6 -0
  50. package/tests/fixtures/categories-fixtures.js +8 -0
  51. package/tests/fixtures/expected-entities/entities/test-product-details-entity.js +10 -1
  52. package/tests/fixtures/expected-entities/entities-translations.js +2 -0
  53. package/tests/fixtures/expected-entities-mikro-orm/models/mikro-orm/test-categories-model.js +13 -8
  54. package/tests/fixtures/expected-entities-mikro-orm/models/mikro-orm/test-product-details-model.js +30 -10
  55. package/tests/fixtures/expected-entities-mikro-orm/models/mikro-orm/test-products-model.js +15 -14
  56. package/tests/fixtures/expected-entities-mikro-orm/models/mikro-orm/test-reviews-model.js +13 -12
  57. package/tests/fixtures/expected-entities-prisma/models/prisma/test-product-details-model.js +3 -1
  58. package/tests/fixtures/product-details-fixtures.js +4 -1
  59. package/tests/fixtures/reviews-fixtures.js +2 -1
  60. package/tests/fixtures/sql/test-schema.sql +11 -2
  61. package/tests/fixtures/table-columns-fixtures.js +97 -0
  62. package/tests/integration/test-cross-driver-equivalence.js +286 -0
  63. package/tests/integration/test-nested-filters.js +265 -408
  64. package/tests/integration/test-relations.js +135 -0
  65. package/tests/integration/test-reldens-sample-data.js +255 -0
  66. package/tests/integration/test-reldens-shape-relations.js +292 -0
  67. package/tests/run-tests.js +111 -65
  68. package/tests/unit/test-drivers.js +7 -1
  69. package/tests/unit/test-models-generation.js +28 -18
  70. package/tests/utils/column-value-assert.js +139 -0
  71. package/tests/utils/entity-projection.js +111 -0
  72. package/tests/utils/observed-value.js +41 -0
  73. package/tests/utils/projection-difference.js +151 -0
  74. package/tests/utils/relations-shape-support.js +104 -0
  75. package/tests/utils/reldens-schema-loader.js +274 -0
  76. package/tests/utils/test-helpers.js +143 -13
  77. package/tests/utils/test-runner.js +26 -5
  78. package/tests/utils/whole-result-assert.js +243 -0
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
 
3
3
  /**
4
4
  *
@@ -8,6 +8,11 @@
8
8
 
9
9
  const { EntitiesGenerator } = require('../lib/entities-generator');
10
10
  const { PrismaClientLoader } = require('../lib/prisma/prisma-client-loader');
11
+ const { KyselyModulesLoader } = require('../lib/kysely/kysely-modules-loader');
12
+ const { DrizzleModulesLoader } = require('../lib/drizzle/drizzle-modules-loader');
13
+ const { MikroOrmModulesLoader } = require('../lib/mikro-orm/mikro-orm-modules-loader');
14
+ const { ObjectionModulesLoader } = require('../lib/objection-js/objection-modules-loader');
15
+ const { KnexModulesLoader } = require('../lib/knex/knex-modules-loader');
11
16
  const { FileHandler } = require('@reldens/server-utils');
12
17
  const { Logger, sc } = require('@reldens/utils');
13
18
 
@@ -65,7 +70,7 @@ class StorageEntitiesGenerator
65
70
  continue;
66
71
  }
67
72
  if('port' === key){
68
- this.config[key] = parseInt(value);
73
+ this.config[key] = Number(value);
69
74
  continue;
70
75
  }
71
76
  this.config[key] = value;
@@ -75,7 +80,7 @@ class StorageEntitiesGenerator
75
80
  getConnectionData()
76
81
  {
77
82
  let connectionData = {
78
- driver: sc.get(this.config, 'driver', 'objection-js'),
83
+ driver: sc.get(this.config, 'driver', 'knex'),
79
84
  client: sc.get(this.config, 'client', 'mysql2'),
80
85
  user: sc.get(this.config, 'user', ''),
81
86
  password: sc.get(this.config, 'password', ''),
@@ -89,6 +94,12 @@ class StorageEntitiesGenerator
89
94
  if('prisma' === connectionData.driver && !this.config.client){
90
95
  connectionData.client = 'mysql';
91
96
  }
97
+ if('kysely' === connectionData.driver && !this.config.client){
98
+ connectionData.client = 'mysql';
99
+ }
100
+ if('drizzle' === connectionData.driver && !this.config.client){
101
+ connectionData.client = 'mysql';
102
+ }
92
103
  return connectionData;
93
104
  }
94
105
 
@@ -110,7 +121,7 @@ class StorageEntitiesGenerator
110
121
  +' --pass=[db-password]'
111
122
  +' --host=[db-host]'
112
123
  +' --database=[db-name]'
113
- +' --driver=[driver-map-key]'
124
+ +' --driver=[knex|kysely|drizzle|objection-js|mikro-orm|prisma] (default: knex)'
114
125
  +' --client=[db-client]'
115
126
  +' --prismaClientPath=[path-to-prisma-client]'
116
127
  +' --prismaAdapter=[prisma-adapter-package-or-path]'
@@ -154,6 +165,32 @@ class StorageEntitiesGenerator
154
165
  return loadedModules;
155
166
  }
156
167
 
168
+ appendDriverModules(generatorProps, connectionData)
169
+ {
170
+ if('prisma' === connectionData.driver){
171
+ generatorProps.prismaModules = this.loadPrismaModules(connectionData);
172
+ return Boolean(generatorProps.prismaModules);
173
+ }
174
+ if('kysely' === connectionData.driver){
175
+ generatorProps.kyselyModules = KyselyModulesLoader.load(this.projectPath);
176
+ return Boolean(generatorProps.kyselyModules);
177
+ }
178
+ if('drizzle' === connectionData.driver){
179
+ generatorProps.drizzleModules = DrizzleModulesLoader.load(this.projectPath);
180
+ return Boolean(generatorProps.drizzleModules);
181
+ }
182
+ if('mikro-orm' === connectionData.driver){
183
+ generatorProps.mikroOrmModules = MikroOrmModulesLoader.load(this.projectPath, connectionData.client);
184
+ return Boolean(generatorProps.mikroOrmModules);
185
+ }
186
+ if('objection-js' === connectionData.driver){
187
+ generatorProps.objectionModules = ObjectionModulesLoader.load(this.projectPath);
188
+ return Boolean(generatorProps.objectionModules);
189
+ }
190
+ generatorProps.knexModules = KnexModulesLoader.load(this.projectPath);
191
+ return Boolean(generatorProps.knexModules);
192
+ }
193
+
157
194
  async run()
158
195
  {
159
196
  if(!this.validateCommand()){
@@ -168,12 +205,8 @@ class StorageEntitiesGenerator
168
205
  projectPath: this.projectPath,
169
206
  isOverride: this.isOverride
170
207
  };
171
- if('prisma' === connectionData.driver){
172
- let prismaModules = this.loadPrismaModules(connectionData);
173
- if(!prismaModules){
174
- return false;
175
- }
176
- generatorProps.prismaModules = prismaModules;
208
+ if(!this.appendDriverModules(generatorProps, connectionData)){
209
+ return false;
177
210
  }
178
211
  let generator = new EntitiesGenerator(generatorProps);
179
212
  let success = await generator.generate();
package/index.js CHANGED
@@ -8,10 +8,13 @@ const { BaseDataServer } = require('./lib/base-data-server');
8
8
  const { BaseDriver } = require('./lib/base-driver');
9
9
  const { ObjectionJsDriver } = require('./lib/objection-js/objection-js-driver');
10
10
  const { ObjectionJsDataServer } = require('./lib/objection-js/objection-js-data-server');
11
- const { Model } = require('objection');
11
+ const { ObjectionModulesValidator } = require('./lib/objection-js/objection-modules-validator');
12
+ const { ObjectionModulesLoader } = require('./lib/objection-js/objection-modules-loader');
12
13
  const { MikroOrmDriver } = require('./lib/mikro-orm/mikro-orm-driver');
13
14
  const { MikroOrmDataServer } = require('./lib/mikro-orm/mikro-orm-data-server');
14
- const MikroOrmCore = require('@mikro-orm/core');
15
+ const { MikroOrmModulesValidator } = require('./lib/mikro-orm/mikro-orm-modules-validator');
16
+ const { MikroOrmModulesLoader } = require('./lib/mikro-orm/mikro-orm-modules-loader');
17
+ const { PackageResolver } = require('./lib/package-resolver');
15
18
  const { EntitiesGenerator } = require('./lib/entities-generator');
16
19
  const { EntityProperties } = require('./lib/entity-properties');
17
20
  const { TypeMapper } = require('./lib/type-mapper');
@@ -21,41 +24,79 @@ const { PrismaDataServer } = require('./lib/prisma/prisma-data-server');
21
24
  const { PrismaSchemaGenerator } = require('./lib/prisma/prisma-schema-generator');
22
25
  const { PrismaClientLoader } = require('./lib/prisma/prisma-client-loader');
23
26
  const { PrismaModulesValidator } = require('./lib/prisma/prisma-modules-validator');
27
+ const { QueryBuilderDriver } = require('./lib/query-builder-driver');
28
+ const { RelationsLoader } = require('./lib/relations-loader');
29
+ const { Mysql2ConnectionConfig } = require('./lib/mysql2-connection-config');
30
+ const { KnexDriver } = require('./lib/knex/knex-driver');
31
+ const { KnexDataServer } = require('./lib/knex/knex-data-server');
32
+ const { KnexModulesValidator } = require('./lib/knex/knex-modules-validator');
33
+ const { KnexModulesLoader } = require('./lib/knex/knex-modules-loader');
34
+ const { KyselyDriver } = require('./lib/kysely/kysely-driver');
35
+ const { KyselyDataServer } = require('./lib/kysely/kysely-data-server');
36
+ const { KyselyModulesValidator } = require('./lib/kysely/kysely-modules-validator');
37
+ const { KyselyModulesLoader } = require('./lib/kysely/kysely-modules-loader');
38
+ const { DrizzleDriver } = require('./lib/drizzle/drizzle-driver');
39
+ const { DrizzleDataServer } = require('./lib/drizzle/drizzle-data-server');
40
+ const { DrizzleModulesValidator } = require('./lib/drizzle/drizzle-modules-validator');
41
+ const { DrizzleModulesLoader } = require('./lib/drizzle/drizzle-modules-loader');
24
42
  const { RELATION_PREFIX } = require('./lib/relation-key');
25
43
 
44
+ let objectionPackage = PackageResolver.optionalPackage('objection');
45
+ let mikroOrmCorePackage = PackageResolver.optionalPackage('@mikro-orm/core');
46
+
26
47
  module.exports = {
27
- // base:
28
48
  BaseDataServer,
29
49
  BaseDriver,
30
50
  DriversMap: {
31
51
  'objection-js': ObjectionJsDataServer,
32
52
  'mikro-orm': MikroOrmDataServer,
33
- 'prisma': PrismaDataServer
53
+ 'prisma': PrismaDataServer,
54
+ 'knex': KnexDataServer,
55
+ 'kysely': KyselyDataServer,
56
+ 'drizzle': DrizzleDataServer
34
57
  },
35
58
  DriversClassMap: {
36
59
  'ObjectionJsDataServer': 'objection-js',
37
60
  'MikroOrmDataServer': 'mikro-orm',
38
- 'PrismaDataServer': 'prisma'
61
+ 'PrismaDataServer': 'prisma',
62
+ 'KnexDataServer': 'knex',
63
+ 'KyselyDataServer': 'kysely',
64
+ 'DrizzleDataServer': 'drizzle'
39
65
  },
40
- // objection-js:
66
+ QueryBuilderDriver,
67
+ RelationsLoader,
68
+ Mysql2ConnectionConfig,
69
+ KnexDataServer,
70
+ KnexDriver,
71
+ KyselyDataServer,
72
+ KyselyDriver,
73
+ KyselyModulesValidator,
74
+ KyselyModulesLoader,
75
+ DrizzleDataServer,
76
+ DrizzleDriver,
77
+ DrizzleModulesValidator,
78
+ DrizzleModulesLoader,
41
79
  ObjectionJsDataServer,
42
80
  ObjectionJsDriver,
43
- ObjectionJsRawModel: Model,
44
- // mikro-orm:
45
- MikroOrmCore,
81
+ ObjectionModulesValidator,
82
+ ObjectionModulesLoader,
83
+ ObjectionJsRawModel: objectionPackage ? objectionPackage.Model : false,
84
+ MikroOrmCore: mikroOrmCorePackage,
46
85
  MikroOrmDataServer,
47
86
  MikroOrmDriver,
48
- // prisma:
87
+ MikroOrmModulesValidator,
88
+ MikroOrmModulesLoader,
89
+ PackageResolver,
90
+ KnexModulesValidator,
91
+ KnexModulesLoader,
49
92
  PrismaDataServer,
50
93
  PrismaDriver,
51
94
  PrismaSchemaGenerator,
52
95
  PrismaClientLoader,
53
96
  PrismaModulesValidator,
54
- // entities:
55
97
  EntitiesGenerator,
56
98
  EntityProperties,
57
99
  TypeMapper,
58
100
  MySQLTablesProvider,
59
- // relation key:
60
101
  RELATION_PREFIX
61
102
  };
@@ -0,0 +1,123 @@
1
+ /**
2
+ *
3
+ * Reldens - DrizzleDataServer
4
+ *
5
+ */
6
+
7
+ const { BaseDataServer } = require('../base-data-server');
8
+ const { DrizzleDriver } = require('./drizzle-driver');
9
+ const { DrizzleModulesValidator } = require('./drizzle-modules-validator');
10
+ const { MySQLTablesProvider } = require('../mysql-tables-provider');
11
+ const { Mysql2ConnectionConfig } = require('../mysql2-connection-config');
12
+ const { createPool } = require('mysql2/promise');
13
+ const { Logger, sc } = require('@reldens/utils');
14
+
15
+ class DrizzleDataServer extends BaseDataServer
16
+ {
17
+
18
+ constructor(props)
19
+ {
20
+ super(props);
21
+ this.drizzleModules = sc.get(props, 'drizzleModules', false);
22
+ this.db = sc.get(this.drizzleModules, 'db', false);
23
+ }
24
+
25
+ async connect()
26
+ {
27
+ if(this.initialized){
28
+ return this.initialized;
29
+ }
30
+ if(!DrizzleModulesValidator.validate(this.drizzleModules)){
31
+ return false;
32
+ }
33
+ try {
34
+ if(!this.db){
35
+ this.db = this.drizzleModules.drizzle({client: createPool(this.poolConfiguration())});
36
+ this.drizzleModules.db = this.db;
37
+ }
38
+ await this.db.execute(this.drizzleModules.orm.sql.raw('SELECT 1'));
39
+ this.initialized = Date.now();
40
+ } catch(error) {
41
+ Logger.critical('Connection failed, Drizzle error: '+error.message);
42
+ }
43
+ return this.initialized;
44
+ }
45
+
46
+ poolConfiguration()
47
+ {
48
+ let poolConfiguration = Mysql2ConnectionConfig.sanitize(this.config);
49
+ if(this.multipleStatements){
50
+ poolConfiguration.multipleStatements = true;
51
+ }
52
+ return poolConfiguration;
53
+ }
54
+
55
+ async disconnect()
56
+ {
57
+ if(!this.db){
58
+ return false;
59
+ }
60
+ await this.db.$client.end();
61
+ this.db = false;
62
+ this.initialized = false;
63
+ return true;
64
+ }
65
+
66
+ generateEntities()
67
+ {
68
+ if(!this.rawEntities){
69
+ Logger.warning('Empty raw entities array, none entities generated.');
70
+ return {};
71
+ }
72
+ this.entities = {};
73
+ for(let i of Object.keys(this.rawEntities)){
74
+ let rawEntity = this.rawEntities[i];
75
+ if(!sc.isString(sc.get(rawEntity, 'tableName', false))){
76
+ Logger.critical('Invalid raw entity "'+i+'".');
77
+ continue;
78
+ }
79
+ if(!sc.isObject(sc.get(rawEntity, 'table', false))){
80
+ Logger.critical('Missing Drizzle table on raw entity "'+i+'".');
81
+ continue;
82
+ }
83
+ this.entities[i] = new DrizzleDriver({
84
+ rawModel: rawEntity,
85
+ id: i,
86
+ name: i,
87
+ config: this.config,
88
+ server: this,
89
+ db: this.db,
90
+ orm: this.drizzleModules.orm
91
+ });
92
+ }
93
+ this.entityManager.setEntities(this.entities);
94
+ return this.entities;
95
+ }
96
+
97
+ name()
98
+ {
99
+ return this.name || 'Drizzle Data Server Driver';
100
+ }
101
+
102
+ async rawQuery(content)
103
+ {
104
+ return (await this.db.execute(this.drizzleModules.orm.sql.raw(content))).shift() || false;
105
+ }
106
+
107
+ async fetchEntitiesFromDatabase()
108
+ {
109
+ if(!this.initialized){
110
+ Logger.critical('Connection was not initialized, please use the connect method first.');
111
+ return false;
112
+ }
113
+ try {
114
+ return await MySQLTablesProvider.fetchTables(this);
115
+ } catch(error) {
116
+ Logger.critical('Drizzle Data Server tables fetch failed. '+error.message);
117
+ return false;
118
+ }
119
+ }
120
+
121
+ }
122
+
123
+ module.exports.DrizzleDataServer = DrizzleDataServer;
@@ -0,0 +1,228 @@
1
+ /**
2
+ *
3
+ * Reldens - DrizzleDriver
4
+ *
5
+ */
6
+
7
+ const { QueryBuilderDriver } = require('../query-builder-driver');
8
+ const { Logger, sc } = require('@reldens/utils');
9
+
10
+ class DrizzleDriver extends QueryBuilderDriver
11
+ {
12
+
13
+ constructor(props)
14
+ {
15
+ super(props);
16
+ this.db = sc.get(props, 'db', false);
17
+ this.orm = sc.get(props, 'orm', false);
18
+ this.table = sc.get(this.rawModel, 'table', false);
19
+ this.comparisonFunctions = {'=': 'eq', '!=': 'ne', '>': 'gt', '>=': 'gte', '<': 'lt', '<=': 'lte'};
20
+ }
21
+
22
+ column(field)
23
+ {
24
+ let column = sc.get(this.table, field, false);
25
+ if(!column){
26
+ Logger.error('Column "'+field+'" not defined on table "'+this.tableName()+'".');
27
+ }
28
+ return column;
29
+ }
30
+
31
+ prepareData(data)
32
+ {
33
+ let prepared = Object.assign({}, data);
34
+ for(let key of Object.keys(prepared)){
35
+ if(!sc.isString(prepared[key])){
36
+ continue;
37
+ }
38
+ if('json' !== sc.get(this.column(key), 'dataType', '')){
39
+ continue;
40
+ }
41
+ prepared[key] = sc.parseJson(prepared[key]);
42
+ }
43
+ return prepared;
44
+ }
45
+
46
+ async insertRow(data)
47
+ {
48
+ return Number(sc.get((await this.db.insert(this.table).values(this.prepareData(data))).shift(), 'insertId', 0));
49
+ }
50
+
51
+ selectRows(filters, options)
52
+ {
53
+ let query = 0 < options.select.length
54
+ ? this.db.select(this.selectedColumns(options.select))
55
+ : this.db.select();
56
+ query = this.appendCondition(query.from(this.table), filters);
57
+ if(0 < options.limit){
58
+ query = query.limit(options.limit);
59
+ }
60
+ if(0 < options.offset){
61
+ query = query.offset(options.offset);
62
+ }
63
+ if(options.sortBy && options.sortDirection){
64
+ query = query.orderBy(this.orderByExpression(options));
65
+ }
66
+ return query;
67
+ }
68
+
69
+ orderByExpression(options)
70
+ {
71
+ if('DESC' === options.sortDirection.toUpperCase()){
72
+ return this.orm.desc(this.column(options.sortBy));
73
+ }
74
+ return this.orm.asc(this.column(options.sortBy));
75
+ }
76
+
77
+ selectedColumns(select)
78
+ {
79
+ let columns = {};
80
+ for(let field of select){
81
+ columns[field] = this.column(field);
82
+ }
83
+ return columns;
84
+ }
85
+
86
+ appendCondition(query, filters)
87
+ {
88
+ let condition = this.filtersCondition(filters);
89
+ if(!condition){
90
+ return query;
91
+ }
92
+ return query.where(condition);
93
+ }
94
+
95
+ async update(filters, updatePatch)
96
+ {
97
+ let query = this.db.update(this.table).set(this.prepareData(updatePatch));
98
+ return Number(sc.get((await this.appendCondition(query, filters)).shift(), 'affectedRows', 0));
99
+ }
100
+
101
+ async delete(filters = {})
102
+ {
103
+ let deleteResult = await this.appendCondition(this.db.delete(this.table), filters);
104
+ return Number(sc.get(deleteResult.shift(), 'affectedRows', 0));
105
+ }
106
+
107
+ async count(filters = {})
108
+ {
109
+ let query = this.db.select({count: this.orm.count()}).from(this.table);
110
+ let rows = await this.appendCondition(query, filters);
111
+ let firstRow = rows.shift();
112
+ if(!firstRow){
113
+ return 0;
114
+ }
115
+ return Number(firstRow.count);
116
+ }
117
+
118
+ filtersCondition(filters = {})
119
+ {
120
+ let conditions = [];
121
+ for(let key of Object.keys(filters)){
122
+ conditions = this.appendFilterCondition(conditions, key, filters[key]);
123
+ }
124
+ if(0 === conditions.length){
125
+ return null;
126
+ }
127
+ return this.orm.and(...conditions);
128
+ }
129
+
130
+ appendFilterCondition(conditions, key, filter)
131
+ {
132
+ if(('AND' === key || 'OR' === key) && sc.isArray(filter)){
133
+ return this.appendGroupCondition(conditions, key, filter);
134
+ }
135
+ let operator = sc.get(filter, 'operator', '').toUpperCase();
136
+ if('OR' === operator){
137
+ return this.appendOrValueCondition(conditions, key, filter);
138
+ }
139
+ if(operator){
140
+ conditions.push(this.operatorCondition(key, operator, filter));
141
+ return conditions;
142
+ }
143
+ if(sc.hasOwn(this.relationsLoader.relationMappings, key) && sc.isObject(filter)){
144
+ let mapping = this.relationsLoader.relationMappings[key];
145
+ conditions.push(this.orm.inArray(this.column(mapping.from), this.relationSubQuery(mapping, filter)));
146
+ return conditions;
147
+ }
148
+ if(null === filter){
149
+ conditions.push(this.orm.isNull(this.column(key)));
150
+ return conditions;
151
+ }
152
+ conditions.push(this.orm.eq(this.column(key), filter));
153
+ return conditions;
154
+ }
155
+
156
+ appendGroupCondition(conditions, key, group)
157
+ {
158
+ let nested = [];
159
+ for(let condition of group){
160
+ let nestedCondition = this.filtersCondition(condition);
161
+ if(nestedCondition){
162
+ nested.push(nestedCondition);
163
+ }
164
+ }
165
+ if(0 === nested.length){
166
+ return conditions;
167
+ }
168
+ conditions.push('AND' === key ? this.orm.and(...nested) : this.orm.or(...nested));
169
+ return conditions;
170
+ }
171
+
172
+ appendOrValueCondition(conditions, key, filter)
173
+ {
174
+ let orCondition = this.orm.eq(this.column(key), filter.value);
175
+ if(0 === conditions.length){
176
+ return [orCondition];
177
+ }
178
+ return [this.orm.or(this.orm.and(...conditions), orCondition)];
179
+ }
180
+
181
+ operatorCondition(field, operator, filter)
182
+ {
183
+ let column = this.column(field);
184
+ if('IN' === operator){
185
+ return this.orm.inArray(column, filter.value);
186
+ }
187
+ if('NOT' === operator){
188
+ return this.orm.not(this.orm.eq(column, filter.value));
189
+ }
190
+ if('LIKE' === operator){
191
+ return this.likeCondition(column, field, filter.value);
192
+ }
193
+ let sqlOperator = sc.get(this.operatorsMap, operator, filter.operator);
194
+ let comparisonFunction = sc.get(this.comparisonFunctions, sqlOperator, false);
195
+ if(!comparisonFunction){
196
+ Logger.error('Unsupported operator "'+filter.operator+'" on Drizzle driver, "=" used instead.');
197
+ return this.orm.eq(column, filter.value);
198
+ }
199
+ return this.orm[comparisonFunction](column, filter.value);
200
+ }
201
+
202
+ likeCondition(column, field, value)
203
+ {
204
+ let likeValue = '%'+String(value).replace(/%/g, '')+'%';
205
+ if(this.isJsonField(field)){
206
+ let castExpression = 'CAST(`'+this.tableName()+'`.`'+field+'` AS CHAR)';
207
+ return this.orm.like(this.orm.sql.raw(castExpression), likeValue);
208
+ }
209
+ return this.orm.like(column, likeValue);
210
+ }
211
+
212
+ relationSubQuery(mapping, nestedFilters)
213
+ {
214
+ let relatedDriver = this.relationsLoader.relatedDriver(mapping);
215
+ if(!relatedDriver){
216
+ return [];
217
+ }
218
+ let subQuery = this.db.select({value: relatedDriver.column(mapping.to)}).from(relatedDriver.table);
219
+ let condition = relatedDriver.filtersCondition(nestedFilters);
220
+ if(!condition){
221
+ return subQuery;
222
+ }
223
+ return subQuery.where(condition);
224
+ }
225
+
226
+ }
227
+
228
+ module.exports.DrizzleDriver = DrizzleDriver;
@@ -0,0 +1,49 @@
1
+ /**
2
+ *
3
+ * Reldens - DrizzleModelsGeneration
4
+ *
5
+ */
6
+
7
+ const { QueryBuilderModelsGeneration } = require('../query-builder-models-generation');
8
+ const { TypeMapper } = require('../type-mapper');
9
+
10
+ class DrizzleModelsGeneration extends QueryBuilderModelsGeneration
11
+ {
12
+
13
+ generateEntityProperties(columns, tableName, tableData)
14
+ {
15
+ let columnLines = [];
16
+ for(let columnName of Object.keys(columns)){
17
+ columnLines.push(columnName+': '+this.columnBuilder(columns[columnName]));
18
+ }
19
+ return columnLines.join(',\n ');
20
+ }
21
+
22
+ columnBuilder(column)
23
+ {
24
+ let builderName = TypeMapper.mapDbTypeToDrizzleBuilder(column.type);
25
+ let builder = 'DrizzleMysqlCore.'+builderName+'('+this.builderArguments(builderName, column)+')';
26
+ if('PRI' === column.key){
27
+ return builder+'.primaryKey()';
28
+ }
29
+ return builder;
30
+ }
31
+
32
+ builderArguments(builderName, column)
33
+ {
34
+ let builderArguments = '\''+column.name+'\'';
35
+ if('mysqlEnum' === builderName){
36
+ return builderArguments+', [\''+this.parseEnumValues(column.columnType).join('\', \'')+'\']';
37
+ }
38
+ if('varchar' === builderName || 'char' === builderName || 'varbinary' === builderName){
39
+ return builderArguments+', {length: '+column.length+'}';
40
+ }
41
+ if('bigint' === builderName){
42
+ return builderArguments+', {mode: \'number\'}';
43
+ }
44
+ return builderArguments;
45
+ }
46
+
47
+ }
48
+
49
+ module.exports.DrizzleModelsGeneration = DrizzleModelsGeneration;
@@ -0,0 +1,32 @@
1
+ /**
2
+ *
3
+ * Reldens - Storage - DrizzleModulesLoader
4
+ *
5
+ */
6
+
7
+ const { DrizzleModulesValidator } = require('./drizzle-modules-validator');
8
+ const { PackageResolver } = require('../package-resolver');
9
+
10
+ class DrizzleModulesLoader
11
+ {
12
+
13
+ static load(projectPath)
14
+ {
15
+ let orm = PackageResolver.loadPackage('drizzle-orm', projectPath);
16
+ if(!orm){
17
+ return false;
18
+ }
19
+ let mysql2Driver = PackageResolver.loadPackage('drizzle-orm/mysql2', projectPath);
20
+ if(!mysql2Driver){
21
+ return false;
22
+ }
23
+ let drizzleModules = {drizzle: mysql2Driver.drizzle, orm};
24
+ if(!DrizzleModulesValidator.validate(drizzleModules)){
25
+ return false;
26
+ }
27
+ return drizzleModules;
28
+ }
29
+
30
+ }
31
+
32
+ module.exports.DrizzleModulesLoader = DrizzleModulesLoader;