@reldens/storage 0.89.0 → 0.91.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 (28) hide show
  1. package/CLAUDE.md +11 -2
  2. package/index.js +4 -1
  3. package/lib/entity-templates/entities-translations.template +3 -0
  4. package/lib/generators/entities-generation.js +52 -7
  5. package/lib/generators/entities-translations-generation.js +40 -4
  6. package/lib/generators/models-generation.js +10 -9
  7. package/lib/objection-js/objection-js-data-server.js +27 -2
  8. package/lib/relation-key.js +9 -0
  9. package/package.json +2 -2
  10. package/tests/fixtures/{expected-entities-prisma → expected-entities}/entities/test-categories-entity.js +70 -70
  11. package/tests/fixtures/{expected-entities-prisma → expected-entities}/entities/test-products-entity.js +96 -95
  12. package/tests/fixtures/{expected-entities-mikro-orm → expected-entities}/entities/test-reviews-entity.js +85 -84
  13. package/tests/fixtures/{expected-entities-mikro-orm → expected-entities}/entities-config.js +4 -4
  14. package/tests/fixtures/expected-entities/entities-translations.js +53 -0
  15. package/tests/run-tests.js +2 -2
  16. package/tests/utils/test-helpers.js +2 -2
  17. package/tests/utils/test-runner.js +1 -1
  18. package/tests/fixtures/expected-entities-mikro-orm/entities/test-categories-entity.js +0 -70
  19. package/tests/fixtures/expected-entities-mikro-orm/entities/test-products-entity.js +0 -95
  20. package/tests/fixtures/expected-entities-mikro-orm/entities-translations.js +0 -13
  21. package/tests/fixtures/expected-entities-objection-js/entities/test-categories-entity.js +0 -70
  22. package/tests/fixtures/expected-entities-objection-js/entities/test-products-entity.js +0 -95
  23. package/tests/fixtures/expected-entities-objection-js/entities/test-reviews-entity.js +0 -84
  24. package/tests/fixtures/expected-entities-objection-js/entities-config.js +0 -17
  25. package/tests/fixtures/expected-entities-objection-js/entities-translations.js +0 -13
  26. package/tests/fixtures/expected-entities-prisma/entities/test-reviews-entity.js +0 -84
  27. package/tests/fixtures/expected-entities-prisma/entities-config.js +0 -17
  28. package/tests/fixtures/expected-entities-prisma/entities-translations.js +0 -13
package/CLAUDE.md CHANGED
@@ -191,7 +191,14 @@ npx reldens-storage-prisma --host=<host> --database=<db> --user=<user> --passwor
191
191
 
192
192
  **EntitiesTranslationsGeneration** (`lib/generators/entities-translations-generation.js`):
193
193
  - Generates `entities-translations.js` file
194
- - Creates i18n translation keys for entities
194
+ - Creates i18n translation keys for entities and fields
195
+ - Generates two types of translations:
196
+ - Table labels: Human-readable entity names
197
+ - Entity-specific field translations: Field labels per entity
198
+ - Methods:
199
+ - `getTranslationLabels()`: Generates table name translations
200
+ - `getFieldTranslations()`: Generates entity-specific field translations
201
+ - `formatFieldName()`: Converts field names to human-readable labels (e.g., `owner_id` → `Owner ID`)
195
202
 
196
203
  **BaseGenerator** (`lib/generators/base-generator.js`):
197
204
  - Base class for all generators
@@ -255,7 +262,9 @@ All generated files are created in the **generated-entities/** directory:
255
262
 
256
263
  **Configuration Files:**
257
264
  - entities-config.js (entity relation configuration)
258
- - entities-translations.js (translation keys)
265
+ - entities-translations.js (translation keys with two sections):
266
+ - `labels`: Table name translations (e.g., `'skills_class_path': 'Class Paths'`)
267
+ - `fields`: Entity-specific field translations (e.g., `'skills_class_path': {'id': 'ID', 'key': 'Key'}`)
259
268
 
260
269
  ## Relation Keys Pattern
261
270
 
package/index.js CHANGED
@@ -20,6 +20,7 @@ const { PrismaDriver } = require('./lib/prisma/prisma-driver');
20
20
  const { PrismaDataServer } = require('./lib/prisma/prisma-data-server');
21
21
  const { PrismaSchemaGenerator } = require('./lib/prisma/prisma-schema-generator');
22
22
  const { PrismaClientLoader } = require('./lib/prisma/prisma-client-loader');
23
+ const { RELATION_PREFIX } = require('./lib/relation-key');
23
24
 
24
25
  module.exports = {
25
26
  // base:
@@ -52,5 +53,7 @@ module.exports = {
52
53
  EntitiesGenerator,
53
54
  EntityProperties,
54
55
  TypeMapper,
55
- MySQLTablesProvider
56
+ MySQLTablesProvider,
57
+ // relation key:
58
+ RELATION_PREFIX
56
59
  };
@@ -7,5 +7,8 @@
7
7
  module.exports.entitiesTranslations = {
8
8
  labels: {
9
9
  {{labels}}
10
+ },
11
+ fields: {
12
+ {{fields}}
10
13
  }
11
14
  };
@@ -8,6 +8,7 @@ const { FileHandler } = require('@reldens/server-utils');
8
8
  const { Logger, sc } = require('@reldens/utils');
9
9
  const { TypeMapper } = require('../type-mapper');
10
10
  const { BaseGenerator } = require('./base-generator');
11
+ const { RELATION_PREFIX } = require('../relation-key');
11
12
 
12
13
  class EntitiesGeneration extends BaseGenerator
13
14
  {
@@ -18,6 +19,7 @@ class EntitiesGeneration extends BaseGenerator
18
19
  this.entitiesFolder = sc.get(props, 'entitiesFolder', '');
19
20
  this.templatePath = sc.get(props, 'templatePath', '');
20
21
  this.generatedEntities = {};
22
+ this.removeIdFromMultipleRelations = sc.get(props, 'removeIdFromMultipleRelations', true);
21
23
  }
22
24
 
23
25
  async generateEntityFile(tableName, tableData)
@@ -75,15 +77,26 @@ class EntitiesGeneration extends BaseGenerator
75
77
  return false;
76
78
  }
77
79
  Logger.info('Generated entity file: '+fileName);
80
+ let properties = this.buildPropertiesObject(tableData.columns);
78
81
  this.generatedEntities[tableName] = {
79
82
  entityClassName,
80
83
  entityFileName: fileName,
81
84
  tableName,
82
- titleProperty
85
+ titleProperty,
86
+ properties
83
87
  };
84
88
  return true;
85
89
  }
86
90
 
91
+ buildPropertiesObject(columns)
92
+ {
93
+ let properties = {};
94
+ for(let columnName of Object.keys(columns)){
95
+ properties[columnName] = true;
96
+ }
97
+ return properties;
98
+ }
99
+
87
100
  detectPrimaryKeyColumn(columns)
88
101
  {
89
102
  for(let columnName of Object.keys(columns)){
@@ -141,20 +154,49 @@ class EntitiesGeneration extends BaseGenerator
141
154
  return false;
142
155
  }
143
156
 
157
+ countReferencesPerTable(columns)
158
+ {
159
+ let counts = {};
160
+ for(let columnName of Object.keys(columns)){
161
+ let column = columns[columnName];
162
+ if(!sc.hasOwn(column, 'referencedTable')){
163
+ continue;
164
+ }
165
+ if(!counts[column.referencedTable]){
166
+ counts[column.referencedTable] = 0;
167
+ }
168
+ counts[column.referencedTable]++;
169
+ }
170
+ return counts;
171
+ }
172
+
173
+ generateForwardRelationKey(referencedTable, columnName, referenceCounts)
174
+ {
175
+ if(1 === referenceCounts[referencedTable]){
176
+ return RELATION_PREFIX+referencedTable;
177
+ }
178
+ let columnSuffix = columnName;
179
+ if(this.removeIdFromMultipleRelations){
180
+ columnSuffix = columnName.replace(/_id$/i, '');
181
+ }
182
+ return RELATION_PREFIX+referencedTable+'_'+columnSuffix;
183
+ }
184
+
144
185
  generatePropertiesConfig(columns, titleProperty, primaryKeyColumn)
145
186
  {
187
+ let referenceCounts = this.countReferencesPerTable(columns);
146
188
  let propertiesConfig = [];
147
189
  for(let columnName of Object.keys(columns)){
148
190
  let column = columns[columnName];
149
191
  let propertyKey = titleProperty && titleProperty === columnName ? '[titleProperty]' : columnName;
150
192
  let isPrimaryKey = primaryKeyColumn && primaryKeyColumn === columnName;
151
193
  if(isPrimaryKey){
152
- let props = this.getPropertyAttributes(column);
194
+ let props = this.getPropertyAttributes(column, columnName, referenceCounts);
153
195
  props.unshift('isId: true');
154
196
  propertiesConfig.push(propertyKey+': {\n '+props.join(',\n ')+ '\n }');
155
197
  continue;
156
198
  }
157
- let props = this.getPropertyAttributes(column);
199
+ let props = this.getPropertyAttributes(column, columnName, referenceCounts);
158
200
  if(0 === props.length){
159
201
  let dbType = column.type.toLowerCase();
160
202
  propertiesConfig.push(propertyKey+': {\n dbType: \''+dbType+'\'\n }');
@@ -167,21 +209,24 @@ class EntitiesGeneration extends BaseGenerator
167
209
  return propertiesConfig.join(',\n ');
168
210
  }
169
211
 
170
- getPropertyAttributes(column)
212
+ getPropertyAttributes(column, columnName, referenceCounts)
171
213
  {
172
214
  let props = [];
173
215
  let type = column.type.toLowerCase();
174
- this.addTypeAttribute(props, column, type);
216
+ this.addTypeAttribute(props, column, type, columnName, referenceCounts);
175
217
  this.addRequiredAttribute(props, column);
176
218
  props.push('dbType: \''+type+'\'');
177
219
  return props;
178
220
  }
179
221
 
180
- addTypeAttribute(props, column, type)
222
+ addTypeAttribute(props, column, type, columnName, referenceCounts)
181
223
  {
182
224
  if(column.referencedTable){
183
225
  props.push('type: \'reference\'');
184
- props.push('reference: \''+this.getReferenceTable(column)+'\'');
226
+ let referenceTable = this.getReferenceTable(column);
227
+ props.push('reference: \''+referenceTable+'\'');
228
+ let alias = this.generateForwardRelationKey(referenceTable, columnName, referenceCounts);
229
+ props.push('alias: \''+alias+'\'');
185
230
  return;
186
231
  }
187
232
  if('date' === type || 'datetime' === type || 'timestamp' === type){
@@ -37,10 +37,10 @@ class EntitiesTranslationsGeneration extends BaseGenerator
37
37
  Logger.critical('Failed to read entities translations template file: '+this.templatePath);
38
38
  return false;
39
39
  }
40
- let translationsContent = translationsTemplateContent.replace(
41
- /{{labels}}/g,
42
- this.getTranslationLabels(Object.assign({}, existingEntities, generatedEntities))
43
- );
40
+ let allEntities = Object.assign({}, existingEntities, generatedEntities);
41
+ let translationsContent = translationsTemplateContent
42
+ .replace(/{{labels}}/g, this.getTranslationLabels(allEntities))
43
+ .replace(/{{fields}}/g, this.getFieldTranslations(allEntities));
44
44
  if(!FileHandler.writeFile(this.entitiesTranslationsPath, translationsContent)){
45
45
  Logger.critical('Failed to write entities translations file: '+this.entitiesTranslationsPath);
46
46
  return false;
@@ -130,6 +130,42 @@ class EntitiesTranslationsGeneration extends BaseGenerator
130
130
  return labels.join(',\n ');
131
131
  }
132
132
 
133
+ getFieldTranslations(allEntities)
134
+ {
135
+ let fieldsTranslations = [];
136
+ for(let tableName of Object.keys(allEntities)){
137
+ let entity = allEntities[tableName];
138
+ if(!sc.hasOwn(entity, 'properties')){
139
+ continue;
140
+ }
141
+ let entityFields = [];
142
+ for(let fieldName of Object.keys(entity.properties)){
143
+ let formattedName = this.formatFieldName(fieldName);
144
+ entityFields.push('\''+fieldName+'\': \''+formattedName+'\'');
145
+ }
146
+ if(0 === entityFields.length){
147
+ continue;
148
+ }
149
+ fieldsTranslations.push(
150
+ '\''+tableName+'\': {\n '+entityFields.join(',\n ')+'\n }'
151
+ );
152
+ }
153
+ return fieldsTranslations.join(',\n ');
154
+ }
155
+
156
+ formatFieldName(fieldName)
157
+ {
158
+ let formatted = fieldName
159
+ .split('_')
160
+ .map(word => word.charAt(0).toUpperCase()+word.slice(1))
161
+ .join(' ');
162
+ formatted = formatted.replace(/\sId(\s|$)/g, ' ID$1');
163
+ formatted = formatted.replace(/\sAt(\s|$)/g, ' At$1');
164
+ formatted = formatted.replace(/\sKey(\s|$)/g, ' Key$1');
165
+ formatted = formatted.replace(/^Id(\s|$)/g, 'ID$1');
166
+ return formatted;
167
+ }
168
+
133
169
  }
134
170
 
135
171
  module.exports.EntitiesTranslationsGeneration = EntitiesTranslationsGeneration;
@@ -8,6 +8,7 @@ const { FileHandler } = require('@reldens/server-utils');
8
8
  const { Logger, sc } = require('@reldens/utils');
9
9
  const { TypeMapper } = require('../type-mapper');
10
10
  const { BaseGenerator } = require('./base-generator');
11
+ const { RELATION_PREFIX } = require('../relation-key');
11
12
 
12
13
  class ModelsGeneration extends BaseGenerator
13
14
  {
@@ -249,13 +250,13 @@ class ModelsGeneration extends BaseGenerator
249
250
  generatePrismaReverseRelationKey(relatedTable, prismaName, tableName, referenceCount)
250
251
  {
251
252
  if(1 === referenceCount){
252
- return 'related_'+relatedTable;
253
+ return RELATION_PREFIX+relatedTable;
253
254
  }
254
255
  let columnHint = this.extractColumnHintFromPrismaName(prismaName, relatedTable, tableName);
255
256
  if(columnHint){
256
- return 'related_'+relatedTable+'_'+columnHint;
257
+ return RELATION_PREFIX+relatedTable+'_'+columnHint;
257
258
  }
258
- return 'related_'+relatedTable;
259
+ return RELATION_PREFIX+relatedTable;
259
260
  }
260
261
 
261
262
  extractColumnHintFromPrismaName(prismaName, relatedTable, tableName)
@@ -420,25 +421,25 @@ class ModelsGeneration extends BaseGenerator
420
421
  generateForwardRelationKey(referencedTable, columnName, referenceCounts)
421
422
  {
422
423
  if(1 === referenceCounts[referencedTable]){
423
- return 'related_'+referencedTable;
424
+ return RELATION_PREFIX+referencedTable;
424
425
  }
425
426
  let columnSuffix = columnName;
426
427
  if(this.removeIdFromMultipleRelations){
427
428
  columnSuffix = columnName.replace(/_id$/i, '');
428
429
  }
429
- return 'related_'+referencedTable+'_'+columnSuffix;
430
+ return RELATION_PREFIX+referencedTable+'_'+columnSuffix;
430
431
  }
431
432
 
432
433
  generateReverseRelationKey(referencingTable, columnName, referenceCount)
433
434
  {
434
435
  if(1 === referenceCount){
435
- return 'related_'+referencingTable;
436
+ return RELATION_PREFIX+referencingTable;
436
437
  }
437
438
  let columnSuffix = columnName;
438
439
  if(this.removeIdFromMultipleRelations){
439
440
  columnSuffix = columnName.replace(/_id$/i, '');
440
441
  }
441
- return 'related_'+referencingTable+'_'+columnSuffix;
442
+ return RELATION_PREFIX+referencingTable+'_'+columnSuffix;
442
443
  }
443
444
 
444
445
  determineForwardRelationType(tableName, columnName, column)
@@ -578,7 +579,7 @@ class ModelsGeneration extends BaseGenerator
578
579
  findMappedByKey(currentTable, referencingTable, reverseRelation)
579
580
  {
580
581
  if(!this.allTablesData[referencingTable]){
581
- return 'related_'+currentTable;
582
+ return RELATION_PREFIX+currentTable;
582
583
  }
583
584
  let referencingTableData = this.allTablesData[referencingTable];
584
585
  let forwardRelations = this.detectObjectionJsRelations(referencingTable, referencingTableData);
@@ -588,7 +589,7 @@ class ModelsGeneration extends BaseGenerator
588
589
  return forwardKey;
589
590
  }
590
591
  }
591
- return 'related_'+currentTable;
592
+ return RELATION_PREFIX+currentTable;
592
593
  }
593
594
 
594
595
  generateFkMappings(tableName, tableData, driverKey)
@@ -9,7 +9,7 @@ const { ObjectionJsDriver } = require('./objection-js-driver');
9
9
  const { MySQLTablesProvider } = require('../mysql-tables-provider');
10
10
  const { Model } = require('objection');
11
11
  const Knex = require('knex');
12
- const { Logger } = require('@reldens/utils');
12
+ const { Logger, sc } = require('@reldens/utils');
13
13
 
14
14
  class ObjectionJsDataServer extends BaseDataServer
15
15
  {
@@ -21,6 +21,16 @@ class ObjectionJsDataServer extends BaseDataServer
21
21
  if(!this.rawModel){
22
22
  this.rawModel = Model;
23
23
  }
24
+ this.validMySQL2Options = [
25
+ 'authPlugins', 'authSwitchHandler', 'bigNumberStrings', 'charset', 'charsetNumber', 'compress',
26
+ 'connectAttributes', 'connectTimeout', 'database', 'dateStrings', 'debug', 'decimalNumbers',
27
+ 'enableKeepAlive', 'flags', 'host', 'insecureAuth', 'infileStreamFactory', 'isServer',
28
+ 'keepAliveInitialDelay', 'localAddress', 'maxPreparedStatements', 'multipleStatements',
29
+ 'namedPlaceholders', 'nestTables', 'password', 'password1', 'password2', 'password3', 'passwordSha1',
30
+ 'pool', 'port', 'queryFormat', 'rowsAsArray', 'socketPath', 'ssl', 'stream', 'stringifyObjects',
31
+ 'supportBigNumbers', 'timezone', 'trace', 'typeCast', 'uri', 'user', 'disableEval', 'connectionLimit',
32
+ 'maxIdle', 'idleTimeout', 'Promise', 'queueLimit', 'waitForConnections', 'jsonStrings', 'gracefulEnd'
33
+ ];
24
34
  }
25
35
 
26
36
  async connect()
@@ -28,9 +38,10 @@ class ObjectionJsDataServer extends BaseDataServer
28
38
  if(this.initialized){
29
39
  return this.initialized;
30
40
  }
41
+ let connectionConfig = this.sanitizeConnectionConfig(this.config);
31
42
  this.knex = await Knex({
32
43
  client: this.client,
33
- connection: this.config,
44
+ connection: connectionConfig,
34
45
  pool: this.poolConfig,
35
46
  debug: this.debug,
36
47
  multipleStatements: this.multipleStatements
@@ -47,6 +58,20 @@ class ObjectionJsDataServer extends BaseDataServer
47
58
  return this.initialized;
48
59
  }
49
60
 
61
+ sanitizeConnectionConfig(config)
62
+ {
63
+ if('mysql2' !== this.client){
64
+ return config;
65
+ }
66
+ let cleanConfig = {};
67
+ for(let prop of this.validMySQL2Options){
68
+ if(sc.hasOwn(config, prop)){
69
+ cleanConfig[prop] = config[prop];
70
+ }
71
+ }
72
+ return cleanConfig;
73
+ }
74
+
50
75
  async disconnect()
51
76
  {
52
77
  if(!this.knex){
@@ -0,0 +1,9 @@
1
+ /**
2
+ *
3
+ * Reldens - Relation Key
4
+ *
5
+ */
6
+
7
+ module.exports = {
8
+ RELATION_PREFIX: process.env.RELDENS_RELATION_PREFIX || 'related_'
9
+ };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@reldens/storage",
3
3
  "scope": "@reldens",
4
- "version": "0.89.0",
4
+ "version": "0.91.0",
5
5
  "description": "Reldens - Storage",
6
6
  "author": "Damian A. Pastorini",
7
7
  "license": "MIT",
@@ -59,7 +59,7 @@
59
59
  "@reldens/utils": "^0.54.0",
60
60
  "knex": "3.1.0",
61
61
  "mysql": "2.18.1",
62
- "mysql2": "3.16.2",
62
+ "mysql2": "3.16.3",
63
63
  "objection": "3.1.5",
64
64
  "prisma": "6.19.2"
65
65
  }
@@ -1,70 +1,70 @@
1
- /**
2
- *
3
- * Reldens - TestCategoriesEntity
4
- *
5
- */
6
-
7
- const { EntityProperties } = require('../../index');
8
- const { sc } = require('@reldens/utils');
9
-
10
- class TestCategoriesEntity extends EntityProperties
11
- {
12
-
13
- static propertiesConfig(extraProps)
14
- {
15
- let titleProperty = 'name';
16
- let properties = {
17
- id: {
18
- isId: true,
19
- type: 'number',
20
- isRequired: true,
21
- dbType: 'int'
22
- },
23
- [titleProperty]: {
24
- isRequired: true,
25
- dbType: 'varchar'
26
- },
27
- slug: {
28
- isRequired: true,
29
- dbType: 'varchar'
30
- },
31
- description: {
32
- type: 'textarea',
33
- dbType: 'text'
34
- },
35
- is_active: {
36
- type: 'boolean',
37
- dbType: 'tinyint'
38
- },
39
- display_order: {
40
- type: 'number',
41
- dbType: 'int'
42
- },
43
- created_at: {
44
- type: 'datetime',
45
- dbType: 'timestamp'
46
- },
47
- updated_at: {
48
- type: 'datetime',
49
- dbType: 'timestamp'
50
- }
51
- };
52
- let propertiesKeys = Object.keys(properties);
53
- let showProperties = propertiesKeys;
54
- let editProperties = sc.removeFromArray([...propertiesKeys], ['id', 'created_at', 'updated_at']);
55
- let listProperties = [...propertiesKeys];
56
- listProperties.splice(listProperties.indexOf('description'), 1);
57
- return {
58
- showProperties,
59
- editProperties,
60
- listProperties,
61
- filterProperties: listProperties,
62
- properties,
63
- titleProperty,
64
- ...extraProps
65
- };
66
- }
67
-
68
- }
69
-
70
- module.exports.TestCategoriesEntity = TestCategoriesEntity;
1
+ /**
2
+ *
3
+ * Reldens - TestCategoriesEntity
4
+ *
5
+ */
6
+
7
+ const { EntityProperties } = require('../../index');
8
+ const { sc } = require('@reldens/utils');
9
+
10
+ class TestCategoriesEntity extends EntityProperties
11
+ {
12
+
13
+ static propertiesConfig(extraProps)
14
+ {
15
+ let titleProperty = 'name';
16
+ let properties = {
17
+ id: {
18
+ isId: true,
19
+ type: 'number',
20
+ isRequired: true,
21
+ dbType: 'int'
22
+ },
23
+ [titleProperty]: {
24
+ isRequired: true,
25
+ dbType: 'varchar'
26
+ },
27
+ slug: {
28
+ isRequired: true,
29
+ dbType: 'varchar'
30
+ },
31
+ description: {
32
+ type: 'textarea',
33
+ dbType: 'text'
34
+ },
35
+ is_active: {
36
+ type: 'boolean',
37
+ dbType: 'tinyint'
38
+ },
39
+ display_order: {
40
+ type: 'number',
41
+ dbType: 'int'
42
+ },
43
+ created_at: {
44
+ type: 'datetime',
45
+ dbType: 'timestamp'
46
+ },
47
+ updated_at: {
48
+ type: 'datetime',
49
+ dbType: 'timestamp'
50
+ }
51
+ };
52
+ let propertiesKeys = Object.keys(properties);
53
+ let showProperties = propertiesKeys;
54
+ let editProperties = sc.removeFromArray([...propertiesKeys], ['id', 'created_at', 'updated_at']);
55
+ let listProperties = [...propertiesKeys];
56
+ listProperties.splice(listProperties.indexOf('description'), 1);
57
+ return {
58
+ showProperties,
59
+ editProperties,
60
+ listProperties,
61
+ filterProperties: listProperties,
62
+ properties,
63
+ titleProperty,
64
+ ...extraProps
65
+ };
66
+ }
67
+
68
+ }
69
+
70
+ module.exports.TestCategoriesEntity = TestCategoriesEntity;