@reldens/storage 0.117.0 → 0.118.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 +7 -7
- 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,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* Reldens - QueryBuilderModelsGeneration
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { BaseGenerator } = require('./generators/base-generator');
|
|
8
|
+
const { sc } = require('@reldens/utils');
|
|
9
|
+
|
|
10
|
+
class QueryBuilderModelsGeneration extends BaseGenerator
|
|
11
|
+
{
|
|
12
|
+
|
|
13
|
+
constructor(relationsDetection)
|
|
14
|
+
{
|
|
15
|
+
super();
|
|
16
|
+
this.relationsDetection = relationsDetection;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
modelTableName(tableName)
|
|
20
|
+
{
|
|
21
|
+
return tableName;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
generateEntityProperties(columns, tableName, tableData)
|
|
25
|
+
{
|
|
26
|
+
return '';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
generateFkMappings(tableName, tableData)
|
|
30
|
+
{
|
|
31
|
+
return '';
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
generateIdColumn(columns)
|
|
35
|
+
{
|
|
36
|
+
let primaryKeyColumn = this.relationsDetection.detectPrimaryKeyColumn(columns);
|
|
37
|
+
if(!primaryKeyColumn){
|
|
38
|
+
return '';
|
|
39
|
+
}
|
|
40
|
+
if('id' === primaryKeyColumn){
|
|
41
|
+
return '';
|
|
42
|
+
}
|
|
43
|
+
return '\n static get idColumn()\n {\n return \''+primaryKeyColumn+'\';\n }\n';
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
generateRelations(tableName, tableData, relationMetadata)
|
|
47
|
+
{
|
|
48
|
+
let allRelations = Object.assign(
|
|
49
|
+
{},
|
|
50
|
+
this.relationsDetection.detectForwardRelations(tableName, tableData),
|
|
51
|
+
this.relationsDetection.detectReverseRelations(tableName)
|
|
52
|
+
);
|
|
53
|
+
let relationKeys = Object.keys(allRelations);
|
|
54
|
+
if(0 === relationKeys.length){
|
|
55
|
+
return '';
|
|
56
|
+
}
|
|
57
|
+
let relationMappings = [];
|
|
58
|
+
for(let relationKey of relationKeys){
|
|
59
|
+
relationMappings.push(this.relationMappingDefinition(relationKey, allRelations[relationKey]));
|
|
60
|
+
}
|
|
61
|
+
return '\n static get relationMappings()\n {\n return {\n'
|
|
62
|
+
+relationMappings.join(',\n')
|
|
63
|
+
+'\n };\n }';
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
relationMappingDefinition(relationKey, relation)
|
|
67
|
+
{
|
|
68
|
+
let relatedTable = sc.get(relation, 'referencedTable', relation.referencingTable);
|
|
69
|
+
let relationMapping = ' '+relationKey+': {\n';
|
|
70
|
+
relationMapping += ' relation: \''+relation.relationType+'\',\n';
|
|
71
|
+
relationMapping += ' tableName: \''+relatedTable+'\',\n';
|
|
72
|
+
relationMapping += ' from: \''+relation.fromColumn+'\',\n';
|
|
73
|
+
relationMapping += ' to: \''+relation.toColumn+'\'\n';
|
|
74
|
+
relationMapping += ' }';
|
|
75
|
+
return relationMapping;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
module.exports.QueryBuilderModelsGeneration = QueryBuilderModelsGeneration;
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* Reldens - RelationsLoader
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { Logger, sc } = require('@reldens/utils');
|
|
8
|
+
|
|
9
|
+
class RelationsLoader
|
|
10
|
+
{
|
|
11
|
+
|
|
12
|
+
constructor(props)
|
|
13
|
+
{
|
|
14
|
+
this.driver = sc.get(props, 'driver', false);
|
|
15
|
+
this.server = sc.get(props, 'server', false);
|
|
16
|
+
this.relationMappings = sc.get(this.driver.rawModel, 'relationMappings', {});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
normalizeRelations(relations)
|
|
20
|
+
{
|
|
21
|
+
if(sc.isString(relations)){
|
|
22
|
+
relations = this.driver.parseRelationsString(relations);
|
|
23
|
+
}
|
|
24
|
+
if(!sc.isArray(relations)){
|
|
25
|
+
return Object.keys(this.relationMappings);
|
|
26
|
+
}
|
|
27
|
+
if(0 === relations.length){
|
|
28
|
+
return Object.keys(this.relationMappings);
|
|
29
|
+
}
|
|
30
|
+
return relations;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
relatedDriver(mapping)
|
|
34
|
+
{
|
|
35
|
+
if(!this.server){
|
|
36
|
+
Logger.error('Missing server on relations loader for table: '+mapping.tableName);
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
let entities = this.server.entityManager.entities;
|
|
40
|
+
for(let entityKey of Object.keys(entities)){
|
|
41
|
+
if(entities[entityKey].tableName() === mapping.tableName){
|
|
42
|
+
return entities[entityKey];
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
Logger.error('Related entity not found for table: '+mapping.tableName);
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async populate(result, relations)
|
|
50
|
+
{
|
|
51
|
+
if(!result){
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
54
|
+
let rows = sc.isArray(result) ? result : [result];
|
|
55
|
+
if(0 === rows.length){
|
|
56
|
+
return result;
|
|
57
|
+
}
|
|
58
|
+
for(let relationPath of this.normalizeRelations(relations)){
|
|
59
|
+
await this.populateRelation(rows, relationPath);
|
|
60
|
+
}
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async populateRelation(rows, relationPath)
|
|
65
|
+
{
|
|
66
|
+
let pathParts = relationPath.split('.');
|
|
67
|
+
let relationKey = pathParts.shift();
|
|
68
|
+
let mapping = sc.get(this.relationMappings, relationKey, false);
|
|
69
|
+
if(!mapping){
|
|
70
|
+
Logger.warning('Unknown relation "'+relationKey+'" on table "'+this.driver.tableName()+'".');
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
let relatedDriver = this.relatedDriver(mapping);
|
|
74
|
+
if(!relatedDriver){
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
let relatedRows = await this.fetchRelatedRows(rows, mapping, relatedDriver);
|
|
78
|
+
this.assignRelatedRows(rows, relatedRows, mapping, relationKey);
|
|
79
|
+
if(0 === pathParts.length){
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
if(0 === relatedRows.length){
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
await relatedDriver.relationsLoader.populate(relatedRows, [pathParts.join('.')]);
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async fetchRelatedRows(rows, mapping, relatedDriver)
|
|
90
|
+
{
|
|
91
|
+
let values = [...new Set(
|
|
92
|
+
rows.map(row => row[mapping.from]).filter(value => sc.isNumber(value) || sc.isString(value))
|
|
93
|
+
)];
|
|
94
|
+
if(0 === values.length){
|
|
95
|
+
return [];
|
|
96
|
+
}
|
|
97
|
+
return await relatedDriver.selectRows(
|
|
98
|
+
{[mapping.to]: {operator: 'IN', value: values}},
|
|
99
|
+
Object.assign(relatedDriver.selectOptions(false), {offset: 0})
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
assignRelatedRows(rows, relatedRows, mapping, relationKey)
|
|
104
|
+
{
|
|
105
|
+
let isMany = 'HasManyRelation' === mapping.relation;
|
|
106
|
+
for(let row of rows){
|
|
107
|
+
let matches = relatedRows.filter(relatedRow => relatedRow[mapping.to] === row[mapping.from]);
|
|
108
|
+
if(isMany){
|
|
109
|
+
row[relationKey] = matches;
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
row[relationKey] = matches.shift() || null;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
extractNestedRelations(params, relations)
|
|
117
|
+
{
|
|
118
|
+
let nested = {};
|
|
119
|
+
for(let relationKey of this.normalizeRelations(relations)){
|
|
120
|
+
if(!sc.hasOwn(this.relationMappings, relationKey)){
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
if(!sc.hasOwn(params, relationKey)){
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
nested[relationKey] = params[relationKey];
|
|
127
|
+
}
|
|
128
|
+
return nested;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
async createWithRelations(params, relations)
|
|
132
|
+
{
|
|
133
|
+
let nested = this.extractNestedRelations(params, relations);
|
|
134
|
+
let nestedKeys = Object.keys(nested);
|
|
135
|
+
if(0 === nestedKeys.length){
|
|
136
|
+
return await this.driver.create(params);
|
|
137
|
+
}
|
|
138
|
+
let data = sc.omitProps(params, nestedKeys);
|
|
139
|
+
await this.createParents(data, nested);
|
|
140
|
+
let created = await this.driver.create(data);
|
|
141
|
+
if(!created){
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
await this.createChildren(created, nested);
|
|
145
|
+
return await this.populate(created, nestedKeys);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
async createParents(data, nested)
|
|
149
|
+
{
|
|
150
|
+
for(let relationKey of Object.keys(nested)){
|
|
151
|
+
let mapping = sc.get(this.relationMappings, relationKey, false);
|
|
152
|
+
if('BelongsToOneRelation' !== mapping.relation){
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
let relatedDriver = this.relatedDriver(mapping);
|
|
156
|
+
if(!relatedDriver){
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
let parent = await relatedDriver.create(nested[relationKey]);
|
|
160
|
+
if(!parent){
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
data[mapping.from] = parent[mapping.to];
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
async createChildren(created, nested)
|
|
168
|
+
{
|
|
169
|
+
for(let relationKey of Object.keys(nested)){
|
|
170
|
+
let mapping = sc.get(this.relationMappings, relationKey, false);
|
|
171
|
+
if('BelongsToOneRelation' === mapping.relation){
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
let relatedDriver = this.relatedDriver(mapping);
|
|
175
|
+
if(!relatedDriver){
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
await this.createChildRows(created, nested[relationKey], mapping, relatedDriver);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
async createChildRows(created, children, mapping, relatedDriver)
|
|
183
|
+
{
|
|
184
|
+
let childRows = sc.isArray(children) ? children : [children];
|
|
185
|
+
for(let childRow of childRows){
|
|
186
|
+
await relatedDriver.create(Object.assign({}, childRow, {[mapping.to]: created[mapping.from]}));
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
module.exports.RelationsLoader = RelationsLoader;
|
package/lib/type-mapper.js
CHANGED
|
@@ -81,6 +81,44 @@ class TypeMapper
|
|
|
81
81
|
return typeMap[dbType.toLowerCase()] || 'String';
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
+
mapDbTypeToDrizzleBuilder(dbType)
|
|
85
|
+
{
|
|
86
|
+
let typeMap = {
|
|
87
|
+
'int': 'int',
|
|
88
|
+
'integer': 'int',
|
|
89
|
+
'tinyint': 'tinyint',
|
|
90
|
+
'smallint': 'smallint',
|
|
91
|
+
'mediumint': 'mediumint',
|
|
92
|
+
'bigint': 'bigint',
|
|
93
|
+
'decimal': 'decimal',
|
|
94
|
+
'float': 'float',
|
|
95
|
+
'double': 'double',
|
|
96
|
+
'varchar': 'varchar',
|
|
97
|
+
'char': 'char',
|
|
98
|
+
'text': 'text',
|
|
99
|
+
'tinytext': 'text',
|
|
100
|
+
'mediumtext': 'text',
|
|
101
|
+
'longtext': 'text',
|
|
102
|
+
'date': 'date',
|
|
103
|
+
'datetime': 'datetime',
|
|
104
|
+
'timestamp': 'timestamp',
|
|
105
|
+
'time': 'time',
|
|
106
|
+
'year': 'year',
|
|
107
|
+
'boolean': 'boolean',
|
|
108
|
+
'bool': 'boolean',
|
|
109
|
+
'bit': 'binary',
|
|
110
|
+
'json': 'json',
|
|
111
|
+
'enum': 'mysqlEnum',
|
|
112
|
+
'binary': 'binary',
|
|
113
|
+
'varbinary': 'varbinary',
|
|
114
|
+
'blob': 'binary',
|
|
115
|
+
'tinyblob': 'binary',
|
|
116
|
+
'mediumblob': 'binary',
|
|
117
|
+
'longblob': 'binary'
|
|
118
|
+
};
|
|
119
|
+
return typeMap[dbType.toLowerCase()] || 'text';
|
|
120
|
+
}
|
|
121
|
+
|
|
84
122
|
}
|
|
85
123
|
|
|
86
124
|
module.exports.TypeMapper = new TypeMapper();
|
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.118.0",
|
|
5
5
|
"description": "Reldens - Storage",
|
|
6
6
|
"author": "Damian A. Pastorini",
|
|
7
7
|
"license": "MIT",
|
|
@@ -27,6 +27,11 @@
|
|
|
27
27
|
"mikro-orm",
|
|
28
28
|
"prisma",
|
|
29
29
|
"prisma-orm",
|
|
30
|
+
"knex",
|
|
31
|
+
"kysely",
|
|
32
|
+
"drizzle",
|
|
33
|
+
"drizzle-orm",
|
|
34
|
+
"query-builder",
|
|
30
35
|
"driver",
|
|
31
36
|
"orm",
|
|
32
37
|
"database",
|
|
@@ -51,14 +56,9 @@
|
|
|
51
56
|
"test:driver": "node tests/run-tests.js --driver="
|
|
52
57
|
},
|
|
53
58
|
"dependencies": {
|
|
54
|
-
"@mikro-orm/core": "7.2.0",
|
|
55
|
-
"@mikro-orm/mongodb": "7.2.0",
|
|
56
|
-
"@mikro-orm/mysql": "7.2.0",
|
|
57
59
|
"@reldens/server-utils": "^0.57.0",
|
|
58
60
|
"@reldens/utils": "^0.58.0",
|
|
59
61
|
"knex": "3.3.0",
|
|
60
|
-
"
|
|
61
|
-
"mysql2": "3.24.4",
|
|
62
|
-
"objection": "3.1.5"
|
|
62
|
+
"mysql2": "3.24.4"
|
|
63
63
|
}
|
|
64
64
|
}
|
package/tests/.env.test.example
CHANGED
|
@@ -5,4 +5,10 @@ RELDENS_TEST_DB_PASSWORD=test_password
|
|
|
5
5
|
RELDENS_TEST_DB_NAME=reldens_storage_test
|
|
6
6
|
RELDENS_TEST_DB_CLIENT=mysql
|
|
7
7
|
RELDENS_DB_URL=mysql://test_user:test_password@localhost:3306/reldens_storage_test
|
|
8
|
+
RELDENS_TEST_OBJECTION_ENABLED=0
|
|
9
|
+
RELDENS_TEST_MIKRO_ORM_ENABLED=0
|
|
8
10
|
RELDENS_TEST_PRISMA_ENABLED=0
|
|
11
|
+
RELDENS_TEST_KYSELY_ENABLED=0
|
|
12
|
+
RELDENS_TEST_DRIZZLE_ENABLED=0
|
|
13
|
+
RELDENS_TEST_MIGRATIONS_PATH=
|
|
14
|
+
RELDENS_TEST_RELDENS_DB_NAME=reldens_storage_test_full
|
|
@@ -154,6 +154,14 @@ module.exports.CategoriesFixtures = {
|
|
|
154
154
|
display_order: 2,
|
|
155
155
|
slug: 'relations-test-2'
|
|
156
156
|
},
|
|
157
|
+
category_cross_driver_create: {
|
|
158
|
+
id: 1700,
|
|
159
|
+
name: 'Cross Driver Create',
|
|
160
|
+
description: 'Category created with the same explicit id by every driver',
|
|
161
|
+
is_active: 1,
|
|
162
|
+
display_order: 7,
|
|
163
|
+
slug: 'cross-driver-create'
|
|
164
|
+
},
|
|
157
165
|
category_create_nested: {
|
|
158
166
|
name: 'Nested Create Category',
|
|
159
167
|
description: 'Category for createWithRelations test',
|
|
@@ -35,6 +35,14 @@ class TestProductDetailsEntity extends EntityProperties
|
|
|
35
35
|
dimensions: {
|
|
36
36
|
dbType: 'varchar'
|
|
37
37
|
},
|
|
38
|
+
customData: {
|
|
39
|
+
type: 'textarea',
|
|
40
|
+
dbType: 'text'
|
|
41
|
+
},
|
|
42
|
+
useTimeOut: {
|
|
43
|
+
type: 'number',
|
|
44
|
+
dbType: 'int'
|
|
45
|
+
},
|
|
38
46
|
created_at: {
|
|
39
47
|
type: 'datetime',
|
|
40
48
|
dbType: 'timestamp'
|
|
@@ -47,7 +55,8 @@ class TestProductDetailsEntity extends EntityProperties
|
|
|
47
55
|
let propertiesKeys = Object.keys(properties);
|
|
48
56
|
let showProperties = propertiesKeys;
|
|
49
57
|
let editProperties = sc.removeFromArray([...propertiesKeys], ['id', 'created_at', 'updated_at']);
|
|
50
|
-
let listProperties = propertiesKeys;
|
|
58
|
+
let listProperties = [...propertiesKeys];
|
|
59
|
+
listProperties.splice(listProperties.indexOf('customData'), 1);
|
|
51
60
|
return {
|
|
52
61
|
showProperties,
|
|
53
62
|
editProperties,
|
package/tests/fixtures/expected-entities-mikro-orm/models/mikro-orm/test-categories-model.js
CHANGED
|
@@ -34,14 +34,19 @@ const schema = new EntitySchema({
|
|
|
34
34
|
class: TestCategoriesModel,
|
|
35
35
|
tableName: 'test_categories',
|
|
36
36
|
properties: {
|
|
37
|
-
id: { type: '
|
|
38
|
-
name: { type: '
|
|
39
|
-
slug: { type: '
|
|
40
|
-
description: { type: '
|
|
41
|
-
is_active: { type: '
|
|
42
|
-
display_order: { type: '
|
|
43
|
-
created_at: { type: '
|
|
44
|
-
updated_at: { type: '
|
|
37
|
+
id: { type: 'int', primary: true },
|
|
38
|
+
name: { type: 'varchar' },
|
|
39
|
+
slug: { type: 'varchar' },
|
|
40
|
+
description: { type: 'text', nullable: true },
|
|
41
|
+
is_active: { type: 'tinyint', nullable: true },
|
|
42
|
+
display_order: { type: 'int', nullable: true },
|
|
43
|
+
created_at: { type: 'timestamp', nullable: true },
|
|
44
|
+
updated_at: { type: 'timestamp', nullable: true },
|
|
45
|
+
related_test_product_details: {
|
|
46
|
+
kind: '1:m',
|
|
47
|
+
entity: () => require('./test-product-details-model').TestProductDetailsModel,
|
|
48
|
+
mappedBy: 'related_test_categories'
|
|
49
|
+
},
|
|
45
50
|
related_test_products: {
|
|
46
51
|
kind: '1:m',
|
|
47
52
|
entity: () => require('./test-products-model').TestProductsModel,
|
package/tests/fixtures/expected-entities-mikro-orm/models/mikro-orm/test-product-details-model.js
CHANGED
|
@@ -10,20 +10,23 @@ const { EntitySchema } = MikroOrmCore;
|
|
|
10
10
|
class TestProductDetailsModel
|
|
11
11
|
{
|
|
12
12
|
|
|
13
|
-
constructor(id, product_id, weight, dimensions, created_at, updated_at)
|
|
13
|
+
constructor(id, product_id, weight, dimensions, customData, useTimeOut, category_id, created_at, updated_at)
|
|
14
14
|
{
|
|
15
15
|
this.id = id;
|
|
16
16
|
this.product_id = product_id;
|
|
17
17
|
this.weight = weight;
|
|
18
18
|
this.dimensions = dimensions;
|
|
19
|
+
this.customData = customData;
|
|
20
|
+
this.useTimeOut = useTimeOut;
|
|
21
|
+
this.category_id = category_id;
|
|
19
22
|
this.created_at = created_at;
|
|
20
23
|
this.updated_at = updated_at;
|
|
21
24
|
}
|
|
22
25
|
|
|
23
26
|
static createByProps(props)
|
|
24
27
|
{
|
|
25
|
-
const {id, product_id, weight, dimensions, created_at, updated_at} = props;
|
|
26
|
-
return new this(id, product_id, weight, dimensions, created_at, updated_at);
|
|
28
|
+
const {id, product_id, weight, dimensions, customData, useTimeOut, category_id, created_at, updated_at} = props;
|
|
29
|
+
return new this(id, product_id, weight, dimensions, customData, useTimeOut, category_id, created_at, updated_at);
|
|
27
30
|
}
|
|
28
31
|
|
|
29
32
|
}
|
|
@@ -32,16 +35,27 @@ const schema = new EntitySchema({
|
|
|
32
35
|
class: TestProductDetailsModel,
|
|
33
36
|
tableName: 'test_product_details',
|
|
34
37
|
properties: {
|
|
35
|
-
id: { type: '
|
|
36
|
-
product_id: { type: '
|
|
37
|
-
weight: { type: '
|
|
38
|
-
dimensions: { type: '
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
id: { type: 'int', primary: true },
|
|
39
|
+
product_id: { type: 'int' },
|
|
40
|
+
weight: { type: 'decimal', nullable: true },
|
|
41
|
+
dimensions: { type: 'varchar', nullable: true },
|
|
42
|
+
customData: { type: 'text', nullable: true },
|
|
43
|
+
useTimeOut: { type: 'int', nullable: true },
|
|
44
|
+
category_id: { type: 'int', nullable: true },
|
|
45
|
+
created_at: { type: 'timestamp', nullable: true },
|
|
46
|
+
updated_at: { type: 'timestamp', nullable: true },
|
|
41
47
|
related_test_products: {
|
|
42
48
|
kind: '1:1',
|
|
43
49
|
entity: () => require('./test-products-model').TestProductsModel,
|
|
44
|
-
joinColumns: ['product_id']
|
|
50
|
+
joinColumns: ['product_id'],
|
|
51
|
+
persist: false
|
|
52
|
+
},
|
|
53
|
+
related_test_categories: {
|
|
54
|
+
kind: 'm:1',
|
|
55
|
+
entity: () => require('./test-categories-model').TestCategoriesModel,
|
|
56
|
+
joinColumns: ['category_id'],
|
|
57
|
+
nullable: true,
|
|
58
|
+
persist: false
|
|
45
59
|
}
|
|
46
60
|
},
|
|
47
61
|
});
|
|
@@ -51,6 +65,12 @@ schema._fkMappings = {
|
|
|
51
65
|
"entityName": "TestProductsModel",
|
|
52
66
|
"referencedColumn": "id",
|
|
53
67
|
"nullable": false
|
|
68
|
+
},
|
|
69
|
+
"category_id": {
|
|
70
|
+
"relationKey": "related_test_categories",
|
|
71
|
+
"entityName": "TestCategoriesModel",
|
|
72
|
+
"referencedColumn": "id",
|
|
73
|
+
"nullable": true
|
|
54
74
|
}
|
|
55
75
|
};
|
|
56
76
|
module.exports = {
|
|
@@ -39,23 +39,24 @@ const schema = new EntitySchema({
|
|
|
39
39
|
class: TestProductsModel,
|
|
40
40
|
tableName: 'test_products',
|
|
41
41
|
properties: {
|
|
42
|
-
id: { type: '
|
|
43
|
-
category_id: { type: '
|
|
44
|
-
name: { type: '
|
|
45
|
-
sku: { type: '
|
|
46
|
-
description: { type: '
|
|
47
|
-
price: { type: '
|
|
48
|
-
stock_quantity: { type: '
|
|
49
|
-
is_featured: { type: '
|
|
50
|
-
metadata: { type: '
|
|
51
|
-
tags: { type: '
|
|
52
|
-
status: { type: '
|
|
53
|
-
created_at: { type: '
|
|
54
|
-
updated_at: { type: '
|
|
42
|
+
id: { type: 'int', primary: true },
|
|
43
|
+
category_id: { type: 'int' },
|
|
44
|
+
name: { type: 'varchar' },
|
|
45
|
+
sku: { type: 'varchar' },
|
|
46
|
+
description: { type: 'text', nullable: true },
|
|
47
|
+
price: { type: 'decimal' },
|
|
48
|
+
stock_quantity: { type: 'int', nullable: true },
|
|
49
|
+
is_featured: { type: 'tinyint', nullable: true },
|
|
50
|
+
metadata: { type: 'json', nullable: true },
|
|
51
|
+
tags: { type: 'varchar', nullable: true },
|
|
52
|
+
status: { type: 'enum', nullable: true },
|
|
53
|
+
created_at: { type: 'timestamp', nullable: true },
|
|
54
|
+
updated_at: { type: 'timestamp', nullable: true },
|
|
55
55
|
related_test_categories: {
|
|
56
56
|
kind: 'm:1',
|
|
57
57
|
entity: () => require('./test-categories-model').TestCategoriesModel,
|
|
58
|
-
joinColumns: ['category_id']
|
|
58
|
+
joinColumns: ['category_id'],
|
|
59
|
+
persist: false
|
|
59
60
|
},
|
|
60
61
|
related_test_product_details: {
|
|
61
62
|
kind: '1:1',
|
|
@@ -37,21 +37,22 @@ const schema = new EntitySchema({
|
|
|
37
37
|
class: TestReviewsModel,
|
|
38
38
|
tableName: 'test_reviews',
|
|
39
39
|
properties: {
|
|
40
|
-
id: { type: '
|
|
41
|
-
product_id: { type: '
|
|
42
|
-
reviewer_name: { type: '
|
|
43
|
-
reviewer_email: { type: '
|
|
44
|
-
rating: { type: '
|
|
45
|
-
title: { type: '
|
|
46
|
-
comment: { type: '
|
|
47
|
-
is_verified: { type: '
|
|
48
|
-
helpful_count: { type: '
|
|
49
|
-
created_at: { type: '
|
|
50
|
-
updated_at: { type: '
|
|
40
|
+
id: { type: 'int', primary: true },
|
|
41
|
+
product_id: { type: 'int' },
|
|
42
|
+
reviewer_name: { type: 'varchar' },
|
|
43
|
+
reviewer_email: { type: 'varchar' },
|
|
44
|
+
rating: { type: 'tinyint' },
|
|
45
|
+
title: { type: 'varchar', nullable: true },
|
|
46
|
+
comment: { type: 'text', nullable: true },
|
|
47
|
+
is_verified: { type: 'tinyint', nullable: true },
|
|
48
|
+
helpful_count: { type: 'int', nullable: true },
|
|
49
|
+
created_at: { type: 'timestamp', nullable: true },
|
|
50
|
+
updated_at: { type: 'timestamp', nullable: true },
|
|
51
51
|
related_test_products: {
|
|
52
52
|
kind: 'm:1',
|
|
53
53
|
entity: () => require('./test-products-model').TestProductsModel,
|
|
54
|
-
joinColumns: ['product_id']
|
|
54
|
+
joinColumns: ['product_id'],
|
|
55
|
+
persist: false
|
|
55
56
|
}
|
|
56
57
|
},
|
|
57
58
|
});
|
|
@@ -7,12 +7,14 @@
|
|
|
7
7
|
class TestProductDetailsModel
|
|
8
8
|
{
|
|
9
9
|
|
|
10
|
-
constructor(id, product_id, weight, dimensions, created_at, updated_at)
|
|
10
|
+
constructor(id, product_id, weight, dimensions, customData, useTimeOut, created_at, updated_at)
|
|
11
11
|
{
|
|
12
12
|
this.id = id;
|
|
13
13
|
this.product_id = product_id;
|
|
14
14
|
this.weight = weight;
|
|
15
15
|
this.dimensions = dimensions;
|
|
16
|
+
this.customData = customData;
|
|
17
|
+
this.useTimeOut = useTimeOut;
|
|
16
18
|
this.created_at = created_at;
|
|
17
19
|
this.updated_at = updated_at;
|
|
18
20
|
}
|
|
@@ -10,7 +10,10 @@ module.exports.ProductDetailsFixtures = {
|
|
|
10
10
|
id: 4600,
|
|
11
11
|
product_id: 2600,
|
|
12
12
|
weight: 1.25,
|
|
13
|
-
dimensions: '10x20x30'
|
|
13
|
+
dimensions: '10x20x30',
|
|
14
|
+
customData: '{"origin":"fixture"}',
|
|
15
|
+
useTimeOut: 45,
|
|
16
|
+
total_views: 9007199254740991
|
|
14
17
|
},
|
|
15
18
|
product_details_create_nested: {
|
|
16
19
|
weight: 2.5,
|
|
@@ -45,11 +45,17 @@ CREATE TABLE `test_product_details` (
|
|
|
45
45
|
`product_id` INT UNSIGNED NOT NULL,
|
|
46
46
|
`weight` DECIMAL(10,2) NULL,
|
|
47
47
|
`dimensions` VARCHAR(100) NULL,
|
|
48
|
+
`customData` TEXT NULL,
|
|
49
|
+
`useTimeOut` INT NULL,
|
|
50
|
+
`total_views` BIGINT NULL,
|
|
51
|
+
`category_id` INT UNSIGNED NULL DEFAULT NULL,
|
|
48
52
|
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
49
53
|
`updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
50
54
|
PRIMARY KEY (`id`),
|
|
51
55
|
UNIQUE KEY `product_id` (`product_id`),
|
|
52
|
-
|
|
56
|
+
KEY `category_id` (`category_id`),
|
|
57
|
+
CONSTRAINT `fk_product_details_product` FOREIGN KEY (`product_id`) REFERENCES `test_products` (`id`) ON DELETE CASCADE,
|
|
58
|
+
CONSTRAINT `fk_product_details_category` FOREIGN KEY (`category_id`) REFERENCES `test_categories` (`id`) ON DELETE SET NULL
|
|
53
59
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
54
60
|
|
|
55
61
|
CREATE TABLE `test_reviews` (
|
|
@@ -62,11 +68,14 @@ CREATE TABLE `test_reviews` (
|
|
|
62
68
|
`comment` TEXT NULL,
|
|
63
69
|
`is_verified` TINYINT(1) NOT NULL DEFAULT 0,
|
|
64
70
|
`helpful_count` INT NOT NULL DEFAULT 0,
|
|
71
|
+
`category_slug` VARCHAR(100) NULL,
|
|
65
72
|
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
66
73
|
`updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
67
74
|
PRIMARY KEY (`id`),
|
|
68
75
|
KEY `product_id` (`product_id`),
|
|
69
76
|
KEY `rating` (`rating`),
|
|
70
77
|
KEY `is_verified` (`is_verified`),
|
|
71
|
-
|
|
78
|
+
KEY `category_slug` (`category_slug`),
|
|
79
|
+
CONSTRAINT `fk_reviews_product` FOREIGN KEY (`product_id`) REFERENCES `test_products` (`id`) ON DELETE CASCADE,
|
|
80
|
+
CONSTRAINT `fk_reviews_category_slug` FOREIGN KEY (`category_slug`) REFERENCES `test_categories` (`slug`) ON DELETE SET NULL
|
|
72
81
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|