@rws-framework/db 2.4.5 → 3.0.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/.bin/add-v.sh +9 -9
- package/.bin/emerge.sh +10 -10
- package/.eslintrc.json +53 -53
- package/README.md +404 -404
- package/dist/decorators/IdType.d.ts +8 -0
- package/dist/decorators/IdType.js +10 -0
- package/dist/decorators/InverseRelation.d.ts +2 -2
- package/dist/decorators/InverseRelation.js +5 -1
- package/dist/decorators/InverseTimeSeries.d.ts +0 -0
- package/dist/decorators/InverseTimeSeries.js +0 -0
- package/dist/decorators/RWSCollection.d.ts +7 -0
- package/dist/decorators/RWSCollection.js +6 -0
- package/dist/decorators/Relation.d.ts +8 -6
- package/dist/decorators/Relation.js +8 -1
- package/dist/decorators/TrackType.d.ts +2 -14
- package/dist/decorators/TrackType.js +7 -0
- package/dist/decorators/TypeFunctions.d.ts +44 -0
- package/dist/decorators/TypeFunctions.js +174 -0
- package/dist/decorators/index.d.ts +4 -2
- package/dist/decorators/index.js +3 -1
- package/dist/helper/DbHelper.d.ts +76 -5
- package/dist/helper/DbHelper.js +93 -154
- package/dist/helper/FieldsHelper.d.ts +0 -0
- package/dist/helper/FieldsHelper.js +0 -0
- package/dist/helper/db/index.d.ts +9 -0
- package/dist/helper/db/index.js +18 -0
- package/dist/helper/db/relation-manager.d.ts +45 -0
- package/dist/helper/db/relation-manager.js +105 -0
- package/dist/helper/db/schema-generator.d.ts +37 -0
- package/dist/helper/db/schema-generator.js +243 -0
- package/dist/helper/db/type-converter.d.ts +22 -0
- package/dist/helper/db/type-converter.js +106 -0
- package/dist/helper/db/utils.d.ts +24 -0
- package/dist/helper/db/utils.js +99 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -1
- package/dist/models/TimeSeriesModel.d.ts +7 -7
- package/dist/models/TimeSeriesModel.js +33 -33
- package/dist/models/_model.d.ts +2 -2
- package/dist/models/_model.js +0 -0
- package/dist/models/core/RWSModel.d.ts +4 -1
- package/dist/models/core/RWSModel.js +6 -4
- package/dist/models/core/TimeSeriesModel.d.ts +0 -0
- package/dist/models/core/TimeSeriesModel.js +0 -0
- package/dist/models/index.d.ts +2 -2
- package/dist/models/index.js +0 -0
- package/dist/models/interfaces/IDbOpts.d.ts +17 -0
- package/dist/models/interfaces/IDbOpts.js +2 -0
- package/dist/models/interfaces/IIdOpts.d.ts +0 -0
- package/dist/models/interfaces/IIdOpts.js +1 -0
- package/dist/models/interfaces/IIdTypeOpts.d.ts +3 -0
- package/dist/models/interfaces/IIdTypeOpts.js +2 -0
- package/dist/models/interfaces/IModel.d.ts +0 -0
- package/dist/models/interfaces/IModel.js +0 -0
- package/dist/models/interfaces/IRWSModelServices.d.ts +0 -0
- package/dist/models/interfaces/IRWSModelServices.js +0 -0
- package/dist/models/interfaces/ITrackerOpts.d.ts +12 -0
- package/dist/models/interfaces/ITrackerOpts.js +2 -0
- package/dist/models/interfaces/OpModelType.d.ts +3 -0
- package/dist/models/interfaces/OpModelType.js +0 -0
- package/dist/models/types/RelationTypes.d.ts +0 -0
- package/dist/models/types/RelationTypes.js +0 -0
- package/dist/models/utils/ModelUtils.d.ts +0 -0
- package/dist/models/utils/ModelUtils.js +0 -0
- package/dist/models/utils/PaginationUtils.d.ts +0 -0
- package/dist/models/utils/PaginationUtils.js +0 -0
- package/dist/models/utils/RelationUtils.d.ts +1 -1
- package/dist/models/utils/RelationUtils.js +2 -2
- package/dist/models/utils/TimeSeriesUtils.d.ts +0 -0
- package/dist/models/utils/TimeSeriesUtils.js +0 -0
- package/dist/services/DBService.d.ts +0 -0
- package/dist/services/DBService.js +0 -0
- package/dist/types/DbConfigHandler.d.ts +1 -1
- package/dist/types/DbConfigHandler.js +0 -0
- package/dist/types/FindParams.d.ts +0 -0
- package/dist/types/FindParams.js +0 -0
- package/dist/types/IRWSModel.d.ts +1 -1
- package/dist/types/IRWSModel.js +0 -0
- package/dist/types/ITimeSeries.d.ts +0 -0
- package/dist/types/ITimeSeries.js +0 -0
- package/exec/console.js +110 -110
- package/exec/db.rws.webpack.config.js +168 -168
- package/exec/src/cli.ts +73 -75
- package/exec/tsconfig.json +32 -32
- package/exec/webpackFilters.js +17 -17
- package/package.json +36 -36
- package/src/decorators/IdType.ts +17 -0
- package/src/decorators/InverseRelation.ts +41 -37
- package/src/decorators/InverseTimeSeries.ts +21 -21
- package/src/decorators/RWSCollection.ts +45 -27
- package/src/decorators/Relation.ts +61 -48
- package/src/decorators/TrackType.ts +65 -69
- package/src/decorators/index.ts +16 -8
- package/src/empty.js +0 -0
- package/src/helper/DbHelper.ts +133 -223
- package/src/helper/FieldsHelper.ts +34 -34
- package/src/helper/db/index.ts +10 -0
- package/src/helper/db/relation-manager.ts +119 -0
- package/src/helper/db/schema-generator.ts +302 -0
- package/src/helper/db/type-converter.ts +119 -0
- package/src/helper/db/utils.ts +120 -0
- package/src/index.ts +47 -38
- package/src/models/_model.ts +29 -29
- package/src/models/core/RWSModel.ts +523 -520
- package/src/models/core/TimeSeriesModel.ts +19 -19
- package/src/models/index.ts +20 -20
- package/src/models/interfaces/IDbOpts.ts +17 -0
- package/src/models/interfaces/IIdTypeOpts.ts +4 -0
- package/src/models/interfaces/IModel.ts +12 -12
- package/src/models/interfaces/IRWSModelServices.ts +7 -7
- package/src/models/interfaces/ITrackerOpts.ts +13 -0
- package/src/models/interfaces/OpModelType.ts +52 -49
- package/src/models/types/RelationTypes.ts +25 -25
- package/src/models/utils/ModelUtils.ts +65 -65
- package/src/models/utils/PaginationUtils.ts +42 -42
- package/src/models/utils/RelationUtils.ts +76 -76
- package/src/models/utils/TimeSeriesUtils.ts +38 -38
- package/src/services/DBService.ts +277 -277
- package/src/types/DbConfigHandler.ts +17 -17
- package/src/types/FindParams.ts +13 -13
- package/src/types/IRWSModel.ts +2 -2
- package/src/types/ITimeSeries.ts +5 -5
- package/tsconfig.json +22 -22
package/src/helper/DbHelper.ts
CHANGED
|
@@ -1,223 +1,133 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
section += `model ${modelName} {\n`;
|
|
136
|
-
section += `\t${this.generateId(configService.get('db_type'))}\n`;
|
|
137
|
-
|
|
138
|
-
for (const key in modelMetadatas) {
|
|
139
|
-
const modelMetadata = modelMetadatas[key].metadata;
|
|
140
|
-
let requiredString = modelMetadata.required ? '' : '?';
|
|
141
|
-
const annotationType: string = modelMetadatas[key].annotationType;
|
|
142
|
-
|
|
143
|
-
if(key === 'id'){
|
|
144
|
-
continue;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
if(annotationType === 'Relation'){
|
|
149
|
-
const relationMeta = modelMetadata as IRelationOpts
|
|
150
|
-
|
|
151
|
-
const relatedModel = relationMeta.relatedTo as OpModelType<any>;
|
|
152
|
-
const isMany = relationMeta.many;
|
|
153
|
-
const cascadeOpts = [];
|
|
154
|
-
|
|
155
|
-
if (relationMeta.cascade?.onDelete) {
|
|
156
|
-
cascadeOpts.push(`onDelete: ${relationMeta.cascade.onDelete}`);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
if (relationMeta.cascade?.onUpdate) {
|
|
160
|
-
cascadeOpts.push(`onUpdate: ${relationMeta.cascade.onUpdate}`);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
if (isMany) {
|
|
164
|
-
// Handle many-to-many or one-to-many relation
|
|
165
|
-
section += `\t${key} ${relatedModel._collection}[] @relation("${modelName}_${relatedModel._collection}")\n`;
|
|
166
|
-
} else {
|
|
167
|
-
// Handle one-to-one or many-to-one relation
|
|
168
|
-
section += `\t${key} ${relatedModel._collection}${requiredString} @relation("${modelName}_${relatedModel._collection}", fields: [${modelMetadata.relationField}], references: [${modelMetadata.relatedToField || 'id'}], ${cascadeOpts.join(', ')})\n`;
|
|
169
|
-
section += `\t${modelMetadata.relationField} String${requiredString} @db.ObjectId\n`;
|
|
170
|
-
}
|
|
171
|
-
} else if (annotationType === 'InverseRelation'){
|
|
172
|
-
const relationMeta = modelMetadata as InverseRelationOpts;
|
|
173
|
-
|
|
174
|
-
// Handle inverse relation (one-to-many or one-to-one)
|
|
175
|
-
section += `\t${key} ${relationMeta.inversionModel._collection}[] @relation("${ relationMeta.relationName ? relationMeta.relationName : `${relationMeta.inversionModel._collection}_${modelName}`}")\n`;
|
|
176
|
-
} else if (annotationType === 'InverseTimeSeries'){
|
|
177
|
-
section += `\t${key} String[] @db.ObjectId\n`;
|
|
178
|
-
} else if (annotationType === 'TrackType'){
|
|
179
|
-
const tags: string[] = modelMetadata.tags.map((item: string) => '@' + item);
|
|
180
|
-
|
|
181
|
-
if(modelMetadata.isArray || modelMetadata.type.name === 'Array'){
|
|
182
|
-
requiredString = '';
|
|
183
|
-
}
|
|
184
|
-
section += `\t${key} ${DbHelper.toConfigCase(modelMetadata)}${requiredString} ${tags.join(' ')}\n`;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
section += '}\n';
|
|
189
|
-
return section;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
static toConfigCase(modelType: IMetaOpts): string {
|
|
193
|
-
const type = modelType.type;
|
|
194
|
-
let input = type.name;
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
if(input == 'Number'){
|
|
198
|
-
input = 'Int';
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
if(input == 'Object'){
|
|
202
|
-
input = 'Json';
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
if(input == 'Date'){
|
|
206
|
-
input = 'DateTime';
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
if(input == 'Array'){
|
|
210
|
-
input = 'Json[]';
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
const firstChar = input.charAt(0).toUpperCase();
|
|
214
|
-
const restOfString = input.slice(1);
|
|
215
|
-
let resultField = firstChar + restOfString;
|
|
216
|
-
|
|
217
|
-
if(modelType.isArray){
|
|
218
|
-
resultField += '[]';
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
return resultField;
|
|
222
|
-
}
|
|
223
|
-
}
|
|
1
|
+
import { IDbConfigHandler, IDbConfigParams, IdGeneratorOptions } from '../types/DbConfigHandler';
|
|
2
|
+
import { OpModelType } from '../models/_model';
|
|
3
|
+
import { DBService } from '../services/DBService';
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
DbUtils,
|
|
7
|
+
TypeConverter,
|
|
8
|
+
RelationManager,
|
|
9
|
+
SchemaGenerator
|
|
10
|
+
} from './db';
|
|
11
|
+
import { IIdMetaOpts, IIdTypeOpts } from '../decorators/IdType';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Database helper class
|
|
15
|
+
*
|
|
16
|
+
* This class provides a facade for the database helper modules.
|
|
17
|
+
* It delegates to the specialized modules for specific functionality.
|
|
18
|
+
*/
|
|
19
|
+
export class DbHelper {
|
|
20
|
+
/**
|
|
21
|
+
* The environment variable name for the Prisma database URL
|
|
22
|
+
*/
|
|
23
|
+
static dbUrlVarName: string = SchemaGenerator.dbUrlVarName;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Install Prisma with the generated schema
|
|
27
|
+
* @param configService The configuration service
|
|
28
|
+
* @param dbService The database service
|
|
29
|
+
* @param leaveFile Whether to leave the schema file after generation
|
|
30
|
+
*/
|
|
31
|
+
static async installPrisma(configService: IDbConfigHandler, dbService: DBService, leaveFile = false): Promise<void> {
|
|
32
|
+
return SchemaGenerator.installPrisma(configService, dbService, leaveFile);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Push database models to the database
|
|
37
|
+
* @param configService The configuration service
|
|
38
|
+
* @param dbService The database service
|
|
39
|
+
* @param leaveFile Whether to leave the schema file after generation
|
|
40
|
+
*/
|
|
41
|
+
static async pushDBModels(configService: IDbConfigHandler, dbService: DBService, leaveFile = false): Promise<void> {
|
|
42
|
+
return SchemaGenerator.pushDBModels(configService, dbService, leaveFile);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Generate model sections for the schema
|
|
47
|
+
* @param model The model to generate a section for
|
|
48
|
+
* @param configService The configuration service
|
|
49
|
+
* @returns The model section
|
|
50
|
+
*/
|
|
51
|
+
static async generateModelSections(
|
|
52
|
+
model: OpModelType<any>,
|
|
53
|
+
configService: IDbConfigHandler
|
|
54
|
+
): Promise<string> {
|
|
55
|
+
return SchemaGenerator.generateModelSections(model, configService);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Generate the base schema for Prisma
|
|
60
|
+
* @param dbType The database type
|
|
61
|
+
* @param dbUrl The database URL
|
|
62
|
+
* @returns The base schema
|
|
63
|
+
*/
|
|
64
|
+
static generateBaseSchema(dbType: string, dbUrl: string): string {
|
|
65
|
+
return SchemaGenerator.generateBaseSchema(dbType, dbUrl);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Get the directory and path for the Prisma schema file
|
|
70
|
+
*/
|
|
71
|
+
static getSchemaDir(): [string, string] {
|
|
72
|
+
return DbUtils.getSchemaDir();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Detect the package installer (yarn or npx)
|
|
77
|
+
*/
|
|
78
|
+
static detectInstaller(): string {
|
|
79
|
+
return DbUtils.detectInstaller();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Generate an ID field based on the database type
|
|
84
|
+
*/
|
|
85
|
+
static generateId(
|
|
86
|
+
dbType: IDbConfigParams['db_type'],
|
|
87
|
+
modelMeta: Record<string, { annotationType: string, metadata: IIdMetaOpts }>
|
|
88
|
+
): string {
|
|
89
|
+
return DbUtils.generateId(dbType, modelMeta);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Convert a JavaScript type to a Prisma schema type
|
|
94
|
+
*/
|
|
95
|
+
static toConfigCase(modelType: any, dbType: string = 'mongodb'): string {
|
|
96
|
+
return TypeConverter.toConfigCase(modelType, dbType);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Process type functions metadata to extract database-specific options
|
|
101
|
+
*/
|
|
102
|
+
static processTypeOptions(metadata: any, dbType: string): string[] {
|
|
103
|
+
return TypeConverter.processTypeOptions(metadata, dbType);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Mark a relation between two models
|
|
108
|
+
*/
|
|
109
|
+
static markRelation(relationKey: string, inverse: boolean = false): void {
|
|
110
|
+
RelationManager.markRelation(relationKey, inverse);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Complete a relation between two models
|
|
115
|
+
*/
|
|
116
|
+
static completeRelation(relationKey: string, index: number, inverse: boolean = false): void {
|
|
117
|
+
RelationManager.completeRelation(relationKey, index, inverse);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Get a unique counter for a relation between two models
|
|
122
|
+
*/
|
|
123
|
+
static getRelationCounter(relationKey: string, inverse: boolean = false): number {
|
|
124
|
+
return RelationManager.getRelationCounter(relationKey, inverse);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Generate a shortened relation name to stay within database limits
|
|
129
|
+
*/
|
|
130
|
+
static getShortenedRelationName(modelName: string, relatedModelName: string, index: number): string {
|
|
131
|
+
return RelationManager.getShortenedRelationName(modelName, relatedModelName, index);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
@@ -1,35 +1,35 @@
|
|
|
1
|
-
export class FieldsHelper {
|
|
2
|
-
private constructor(){
|
|
3
|
-
throw new Error(`Class ${this.constructor.name} cannot be instanced.`)
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
static getAllClassFields(target: any): string[] {
|
|
7
|
-
// Get instance properties
|
|
8
|
-
const instanceFields = Object.getOwnPropertyNames(target.prototype);
|
|
9
|
-
|
|
10
|
-
// Get static properties
|
|
11
|
-
const staticFields = Object.getOwnPropertyNames(target);
|
|
12
|
-
|
|
13
|
-
// Get decorated properties using Reflect metadata if available
|
|
14
|
-
const decoratedFields = Reflect.getMetadataKeys(target.prototype) || [];
|
|
15
|
-
|
|
16
|
-
// Combine all fields and remove duplicates and methods
|
|
17
|
-
const allFields = new Set([
|
|
18
|
-
...instanceFields,
|
|
19
|
-
...staticFields,
|
|
20
|
-
...decoratedFields
|
|
21
|
-
]);
|
|
22
|
-
|
|
23
|
-
// Filter out constructor and methods
|
|
24
|
-
return Array.from(allFields).filter(field => {
|
|
25
|
-
// Remove constructor
|
|
26
|
-
if (field === 'constructor') return false;
|
|
27
|
-
|
|
28
|
-
// Remove methods
|
|
29
|
-
const descriptor = Object.getOwnPropertyDescriptor(target.prototype, field);
|
|
30
|
-
if (descriptor && typeof descriptor.value === 'function') return false;
|
|
31
|
-
|
|
32
|
-
return true;
|
|
33
|
-
});
|
|
34
|
-
};
|
|
1
|
+
export class FieldsHelper {
|
|
2
|
+
private constructor(){
|
|
3
|
+
throw new Error(`Class ${this.constructor.name} cannot be instanced.`)
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
static getAllClassFields(target: any): string[] {
|
|
7
|
+
// Get instance properties
|
|
8
|
+
const instanceFields = Object.getOwnPropertyNames(target.prototype);
|
|
9
|
+
|
|
10
|
+
// Get static properties
|
|
11
|
+
const staticFields = Object.getOwnPropertyNames(target);
|
|
12
|
+
|
|
13
|
+
// Get decorated properties using Reflect metadata if available
|
|
14
|
+
const decoratedFields = Reflect.getMetadataKeys(target.prototype) || [];
|
|
15
|
+
|
|
16
|
+
// Combine all fields and remove duplicates and methods
|
|
17
|
+
const allFields = new Set([
|
|
18
|
+
...instanceFields,
|
|
19
|
+
...staticFields,
|
|
20
|
+
...decoratedFields
|
|
21
|
+
]);
|
|
22
|
+
|
|
23
|
+
// Filter out constructor and methods
|
|
24
|
+
return Array.from(allFields).filter(field => {
|
|
25
|
+
// Remove constructor
|
|
26
|
+
if (field === 'constructor') return false;
|
|
27
|
+
|
|
28
|
+
// Remove methods
|
|
29
|
+
const descriptor = Object.getOwnPropertyDescriptor(target.prototype, field);
|
|
30
|
+
if (descriptor && typeof descriptor.value === 'function') return false;
|
|
31
|
+
|
|
32
|
+
return true;
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
35
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database helper modules
|
|
3
|
+
*
|
|
4
|
+
* This module exports all the database helper classes for use in the application.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export { DbUtils, workspaceRootPath, moduleDirPath } from './utils';
|
|
8
|
+
export { TypeConverter } from './type-converter';
|
|
9
|
+
export { RelationManager } from './relation-manager';
|
|
10
|
+
export { SchemaGenerator } from './schema-generator';
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Manages database relations for schema generation
|
|
3
|
+
*/
|
|
4
|
+
export class RelationManager {
|
|
5
|
+
private static allRelations = new Map<string, {base: boolean | null, inversion: boolean | null}[]>();
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Mark a relation between two models
|
|
9
|
+
* @param relationKey A unique key for the relation
|
|
10
|
+
* @param inverse Whether this is an inverse relation
|
|
11
|
+
*/
|
|
12
|
+
static markRelation(relationKey: string, inverse: boolean = false): void {
|
|
13
|
+
if (!this.allRelations.has(relationKey)) {
|
|
14
|
+
this.allRelations.set(relationKey, []);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const modelRelations = this.allRelations.get(relationKey);
|
|
18
|
+
|
|
19
|
+
let marked = false;
|
|
20
|
+
|
|
21
|
+
for(const relationInfo of modelRelations){
|
|
22
|
+
if((relationInfo.base !== null && !inverse) || (relationInfo.inversion !== null && inverse)){
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if(inverse){
|
|
27
|
+
relationInfo.inversion = false;
|
|
28
|
+
marked = true;
|
|
29
|
+
}else{
|
|
30
|
+
relationInfo.base = false;
|
|
31
|
+
marked = true;
|
|
32
|
+
}
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if(!marked){
|
|
37
|
+
modelRelations.push({base: inverse ? null : false, inversion: inverse ? false : null});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Complete a relation between two models
|
|
43
|
+
* @param relationKey A unique key for the relation
|
|
44
|
+
* @param index The index of the relation
|
|
45
|
+
* @param inverse Whether this is an inverse relation
|
|
46
|
+
*/
|
|
47
|
+
static completeRelation(relationKey: string, index: number, inverse: boolean = false): void {
|
|
48
|
+
const modelRelations = this.allRelations.get(relationKey);
|
|
49
|
+
|
|
50
|
+
if(inverse){
|
|
51
|
+
modelRelations[index].inversion = true;
|
|
52
|
+
}else{
|
|
53
|
+
modelRelations[index].base = true;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Get a unique counter for a relation between two models
|
|
59
|
+
* @param relationKey A unique key for the relation
|
|
60
|
+
* @param inverse Whether this is an inverse relation
|
|
61
|
+
* @returns A unique counter for this relation
|
|
62
|
+
*/
|
|
63
|
+
static getRelationCounter(relationKey: string, inverse: boolean = false): number {
|
|
64
|
+
let counter = 0;
|
|
65
|
+
|
|
66
|
+
for(const relationInfo of this.allRelations.get(relationKey)) {
|
|
67
|
+
if((relationInfo.base === true && !inverse) || (relationInfo.inversion === true && inverse)) {
|
|
68
|
+
counter++;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return counter;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Generate a shortened relation name to stay within database limits
|
|
77
|
+
* @param modelName The name of the model
|
|
78
|
+
* @param relatedModelName The name of the related model
|
|
79
|
+
* @param index The index of the relation
|
|
80
|
+
* @returns A shortened relation name
|
|
81
|
+
*/
|
|
82
|
+
static getShortenedRelationName(modelName: string, relatedModelName: string, index: number): string {
|
|
83
|
+
const fullRelationName = `${modelName}_${relatedModelName}_${index}`.toLowerCase();
|
|
84
|
+
|
|
85
|
+
if (fullRelationName.length <= 64) {
|
|
86
|
+
return fullRelationName;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const extraChars = 2 + String(index).length;
|
|
90
|
+
const availableChars = 64 - extraChars;
|
|
91
|
+
|
|
92
|
+
const modelNameLength = modelName.length;
|
|
93
|
+
const relatedModelNameLength = relatedModelName.length;
|
|
94
|
+
const totalLength = modelNameLength + relatedModelNameLength;
|
|
95
|
+
|
|
96
|
+
const modelNameMaxLength = Math.floor(availableChars * (modelNameLength / totalLength));
|
|
97
|
+
const relatedModelNameMaxLength = availableChars - modelNameMaxLength;
|
|
98
|
+
|
|
99
|
+
const shortenedModelName = modelName.substring(0, Math.max(3, modelNameMaxLength));
|
|
100
|
+
const shortenedRelatedModelName = relatedModelName.substring(0, Math.max(3, relatedModelNameMaxLength));
|
|
101
|
+
|
|
102
|
+
// Create the new relation name
|
|
103
|
+
return `${shortenedModelName}_${shortenedRelatedModelName}_${index}`.toLowerCase();
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Reset all relations (useful for testing)
|
|
108
|
+
*/
|
|
109
|
+
static resetRelations(): void {
|
|
110
|
+
this.allRelations.clear();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Get all relations (useful for debugging)
|
|
115
|
+
*/
|
|
116
|
+
static getAllRelations(): Map<string, {base: boolean | null, inversion: boolean | null}[]> {
|
|
117
|
+
return this.allRelations;
|
|
118
|
+
}
|
|
119
|
+
}
|