@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.
Files changed (123) hide show
  1. package/.bin/add-v.sh +9 -9
  2. package/.bin/emerge.sh +10 -10
  3. package/.eslintrc.json +53 -53
  4. package/README.md +404 -404
  5. package/dist/decorators/IdType.d.ts +8 -0
  6. package/dist/decorators/IdType.js +10 -0
  7. package/dist/decorators/InverseRelation.d.ts +2 -2
  8. package/dist/decorators/InverseRelation.js +5 -1
  9. package/dist/decorators/InverseTimeSeries.d.ts +0 -0
  10. package/dist/decorators/InverseTimeSeries.js +0 -0
  11. package/dist/decorators/RWSCollection.d.ts +7 -0
  12. package/dist/decorators/RWSCollection.js +6 -0
  13. package/dist/decorators/Relation.d.ts +8 -6
  14. package/dist/decorators/Relation.js +8 -1
  15. package/dist/decorators/TrackType.d.ts +2 -14
  16. package/dist/decorators/TrackType.js +7 -0
  17. package/dist/decorators/TypeFunctions.d.ts +44 -0
  18. package/dist/decorators/TypeFunctions.js +174 -0
  19. package/dist/decorators/index.d.ts +4 -2
  20. package/dist/decorators/index.js +3 -1
  21. package/dist/helper/DbHelper.d.ts +76 -5
  22. package/dist/helper/DbHelper.js +93 -154
  23. package/dist/helper/FieldsHelper.d.ts +0 -0
  24. package/dist/helper/FieldsHelper.js +0 -0
  25. package/dist/helper/db/index.d.ts +9 -0
  26. package/dist/helper/db/index.js +18 -0
  27. package/dist/helper/db/relation-manager.d.ts +45 -0
  28. package/dist/helper/db/relation-manager.js +105 -0
  29. package/dist/helper/db/schema-generator.d.ts +37 -0
  30. package/dist/helper/db/schema-generator.js +243 -0
  31. package/dist/helper/db/type-converter.d.ts +22 -0
  32. package/dist/helper/db/type-converter.js +106 -0
  33. package/dist/helper/db/utils.d.ts +24 -0
  34. package/dist/helper/db/utils.js +99 -0
  35. package/dist/index.d.ts +3 -3
  36. package/dist/index.js +2 -1
  37. package/dist/models/TimeSeriesModel.d.ts +7 -7
  38. package/dist/models/TimeSeriesModel.js +33 -33
  39. package/dist/models/_model.d.ts +2 -2
  40. package/dist/models/_model.js +0 -0
  41. package/dist/models/core/RWSModel.d.ts +4 -1
  42. package/dist/models/core/RWSModel.js +6 -4
  43. package/dist/models/core/TimeSeriesModel.d.ts +0 -0
  44. package/dist/models/core/TimeSeriesModel.js +0 -0
  45. package/dist/models/index.d.ts +2 -2
  46. package/dist/models/index.js +0 -0
  47. package/dist/models/interfaces/IDbOpts.d.ts +17 -0
  48. package/dist/models/interfaces/IDbOpts.js +2 -0
  49. package/dist/models/interfaces/IIdOpts.d.ts +0 -0
  50. package/dist/models/interfaces/IIdOpts.js +1 -0
  51. package/dist/models/interfaces/IIdTypeOpts.d.ts +3 -0
  52. package/dist/models/interfaces/IIdTypeOpts.js +2 -0
  53. package/dist/models/interfaces/IModel.d.ts +0 -0
  54. package/dist/models/interfaces/IModel.js +0 -0
  55. package/dist/models/interfaces/IRWSModelServices.d.ts +0 -0
  56. package/dist/models/interfaces/IRWSModelServices.js +0 -0
  57. package/dist/models/interfaces/ITrackerOpts.d.ts +12 -0
  58. package/dist/models/interfaces/ITrackerOpts.js +2 -0
  59. package/dist/models/interfaces/OpModelType.d.ts +3 -0
  60. package/dist/models/interfaces/OpModelType.js +0 -0
  61. package/dist/models/types/RelationTypes.d.ts +0 -0
  62. package/dist/models/types/RelationTypes.js +0 -0
  63. package/dist/models/utils/ModelUtils.d.ts +0 -0
  64. package/dist/models/utils/ModelUtils.js +0 -0
  65. package/dist/models/utils/PaginationUtils.d.ts +0 -0
  66. package/dist/models/utils/PaginationUtils.js +0 -0
  67. package/dist/models/utils/RelationUtils.d.ts +1 -1
  68. package/dist/models/utils/RelationUtils.js +2 -2
  69. package/dist/models/utils/TimeSeriesUtils.d.ts +0 -0
  70. package/dist/models/utils/TimeSeriesUtils.js +0 -0
  71. package/dist/services/DBService.d.ts +0 -0
  72. package/dist/services/DBService.js +0 -0
  73. package/dist/types/DbConfigHandler.d.ts +1 -1
  74. package/dist/types/DbConfigHandler.js +0 -0
  75. package/dist/types/FindParams.d.ts +0 -0
  76. package/dist/types/FindParams.js +0 -0
  77. package/dist/types/IRWSModel.d.ts +1 -1
  78. package/dist/types/IRWSModel.js +0 -0
  79. package/dist/types/ITimeSeries.d.ts +0 -0
  80. package/dist/types/ITimeSeries.js +0 -0
  81. package/exec/console.js +110 -110
  82. package/exec/db.rws.webpack.config.js +168 -168
  83. package/exec/src/cli.ts +73 -75
  84. package/exec/tsconfig.json +32 -32
  85. package/exec/webpackFilters.js +17 -17
  86. package/package.json +36 -36
  87. package/src/decorators/IdType.ts +17 -0
  88. package/src/decorators/InverseRelation.ts +41 -37
  89. package/src/decorators/InverseTimeSeries.ts +21 -21
  90. package/src/decorators/RWSCollection.ts +45 -27
  91. package/src/decorators/Relation.ts +61 -48
  92. package/src/decorators/TrackType.ts +65 -69
  93. package/src/decorators/index.ts +16 -8
  94. package/src/empty.js +0 -0
  95. package/src/helper/DbHelper.ts +133 -223
  96. package/src/helper/FieldsHelper.ts +34 -34
  97. package/src/helper/db/index.ts +10 -0
  98. package/src/helper/db/relation-manager.ts +119 -0
  99. package/src/helper/db/schema-generator.ts +302 -0
  100. package/src/helper/db/type-converter.ts +119 -0
  101. package/src/helper/db/utils.ts +120 -0
  102. package/src/index.ts +47 -38
  103. package/src/models/_model.ts +29 -29
  104. package/src/models/core/RWSModel.ts +523 -520
  105. package/src/models/core/TimeSeriesModel.ts +19 -19
  106. package/src/models/index.ts +20 -20
  107. package/src/models/interfaces/IDbOpts.ts +17 -0
  108. package/src/models/interfaces/IIdTypeOpts.ts +4 -0
  109. package/src/models/interfaces/IModel.ts +12 -12
  110. package/src/models/interfaces/IRWSModelServices.ts +7 -7
  111. package/src/models/interfaces/ITrackerOpts.ts +13 -0
  112. package/src/models/interfaces/OpModelType.ts +52 -49
  113. package/src/models/types/RelationTypes.ts +25 -25
  114. package/src/models/utils/ModelUtils.ts +65 -65
  115. package/src/models/utils/PaginationUtils.ts +42 -42
  116. package/src/models/utils/RelationUtils.ts +76 -76
  117. package/src/models/utils/TimeSeriesUtils.ts +38 -38
  118. package/src/services/DBService.ts +277 -277
  119. package/src/types/DbConfigHandler.ts +17 -17
  120. package/src/types/FindParams.ts +13 -13
  121. package/src/types/IRWSModel.ts +2 -2
  122. package/src/types/ITimeSeries.ts +5 -5
  123. package/tsconfig.json +22 -22
@@ -0,0 +1,302 @@
1
+ import { rwsShell } from '@rws-framework/console';
2
+ import chalk from 'chalk';
3
+ import fs from 'fs';
4
+ import path from 'path';
5
+
6
+ import { IDbConfigHandler } from '../../types/DbConfigHandler';
7
+ import { OpModelType, RWSModel } from '../../models/_model';
8
+ import { DBService } from '../../services/DBService';
9
+ import { IRelationOpts } from '../../decorators/Relation';
10
+ import { InverseRelationOpts } from '../../decorators/InverseRelation';
11
+
12
+ import { DbUtils } from './utils';
13
+ import { TypeConverter } from './type-converter';
14
+ import { RelationManager } from './relation-manager';
15
+ import { ITrackerMetaOpts } from '../../decorators/TrackType';
16
+ import { IDbOpts } from '../../models/interfaces/IDbOpts';
17
+
18
+ const log = console.log;
19
+
20
+ /**
21
+ * Handles Prisma schema generation
22
+ */
23
+ export class SchemaGenerator {
24
+ static dbUrlVarName: string = 'PRISMA_DB_URL';
25
+
26
+ /**
27
+ * Generate the base schema for Prisma
28
+ * @param dbType The database type
29
+ * @param dbUrl The database URL
30
+ * @returns The base schema
31
+ */
32
+ static generateBaseSchema(dbType: string, dbUrl: string): string {
33
+ process.env = { ...process.env, [this.dbUrlVarName]: dbUrl };
34
+
35
+ return `generator client {
36
+ provider = "prisma-client-js"
37
+ }
38
+
39
+ datasource db {
40
+ provider = "${dbType}"
41
+ url = env("${this.dbUrlVarName}")
42
+ }`;
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
+ let section = '';
56
+ const modelMetadatas: Record<string, { annotationType: string, metadata: any }> = await RWSModel.getModelAnnotations(model);
57
+ const dbType = configService.get('db_type') || 'mongodb';
58
+ const modelName: string = (model as any)._collection;
59
+
60
+ section += `model ${modelName} {\n`;
61
+
62
+ if(
63
+ !model._NO_ID
64
+ ){
65
+ section += `\t${DbUtils.generateId(dbType, modelMetadatas, false)}\n`;
66
+ }
67
+
68
+ for (const key in modelMetadatas) {
69
+ const modelMetadata = modelMetadatas[key].metadata;
70
+ let requiredString = modelMetadata.required ? '' : '?';
71
+ const annotationType: string = modelMetadatas[key].annotationType;
72
+
73
+ let indexedId = false;
74
+
75
+ if(model._NO_ID){
76
+ indexedId = true;
77
+ requiredString = '';
78
+ }
79
+
80
+
81
+ if (key === 'id' && !indexedId) {
82
+ continue;
83
+ }
84
+
85
+ if (annotationType === 'Relation') {
86
+ const relationMeta = modelMetadata as IRelationOpts;
87
+
88
+ const relatedModel = relationMeta.relatedTo as OpModelType<any>;
89
+ const isMany = relationMeta.many;
90
+ const cascadeOpts = [];
91
+
92
+ if (relationMeta.cascade?.onDelete) {
93
+ cascadeOpts.push(`onDelete: ${relationMeta.cascade.onDelete}`);
94
+ }
95
+
96
+ if (relationMeta.cascade?.onUpdate) {
97
+ cascadeOpts.push(`onUpdate: ${relationMeta.cascade.onUpdate}`);
98
+ }
99
+
100
+ const relatedModelName = relatedModel._collection;
101
+ const relationKey = [modelName, relatedModelName].join('_');
102
+
103
+ const relationIndex = RelationManager.getRelationCounter(relationKey);
104
+ const relationName = RelationManager.getShortenedRelationName(modelName, relatedModelName, relationIndex);
105
+ const mapName = relationName;
106
+
107
+ const relatedModelMetadatas: Record<string, { annotationType: string, metadata: ITrackerMetaOpts }> = await RWSModel.getModelAnnotations(relatedModel);
108
+ const relationFieldName = modelMetadata.relationField ? modelMetadata.relationField : key.toLowerCase() + '_' + modelMetadata.relationField.toLowerCase();
109
+
110
+ const relatedToField = modelMetadata.relatedToField || 'id';
111
+ const bindingFieldExists = !!modelMetadatas[relationFieldName];
112
+
113
+ if (isMany) {
114
+ // Add an inverse field to the related model if it doesn't exist
115
+ section += `\t${key} ${relatedModel._collection}[] @relation("${relationName}", fields: [${relationFieldName}], references: [${relatedToField}], map: "${mapName}", ${cascadeOpts.join(', ')})\n`;
116
+ } else {
117
+ section += `\t${key} ${relatedModel._collection}${requiredString} @relation("${relationName}", fields: [${relationFieldName}], references: [${relatedToField}], map: "${mapName}", ${cascadeOpts.join(', ')})\n`;
118
+ if(!bindingFieldExists){
119
+ const relatedFieldMeta = relatedModelMetadatas[relatedToField];
120
+
121
+ if(!relatedFieldMeta.metadata.required){
122
+ requiredString = '';
123
+ }
124
+
125
+ let relatedFieldType = TypeConverter.toConfigCase(relatedFieldMeta.metadata, dbType, true);
126
+
127
+ if(relatedToField === 'id' && dbType !== 'mongodb'){
128
+ relatedFieldType = 'Int';
129
+ }
130
+
131
+ // Add relation field with appropriate type based on database
132
+ if (dbType === 'mongodb') {
133
+ section += `\t${relationFieldName} String${requiredString} @db.ObjectId\n`;
134
+ } else if (dbType === 'mysql') {
135
+ // For MySQL, determine the type based on the related model's ID type
136
+ section += `\t${relationFieldName} ${relatedFieldType}${requiredString}\n`;
137
+ } else if (dbType === 'postgresql' || dbType === 'postgres') {
138
+ if (relatedFieldType === 'String') {
139
+ section += `\t${relationFieldName} ${relatedFieldType}${requiredString} @db.Uuid\n`;
140
+ } else {
141
+ section += `\t${relationFieldName} ${relatedFieldType}${requiredString}\n`;
142
+ }
143
+ } else {
144
+ section += `\t${relationFieldName} String${requiredString}\n`;
145
+ }
146
+ }
147
+ }
148
+
149
+ RelationManager.completeRelation(relationKey, relationIndex);
150
+ } else if (annotationType === 'InverseRelation') {
151
+ const relationMeta = modelMetadata as InverseRelationOpts;
152
+
153
+ // Check if we need a custom relation name (if there are multiple relations to the same model)
154
+ const relatedModelName = relationMeta.inversionModel._collection;
155
+
156
+ // Generate a very short relation name using a counter
157
+ // Use a consistent key for both sides of the relation to ensure the same name is used
158
+ const relationKey = [relatedModelName, modelName].join('_');
159
+ const relationIndex = RelationManager.getRelationCounter(relationKey, true);
160
+
161
+ const relationName = RelationManager.getShortenedRelationName(relatedModelName, modelName, relationIndex);
162
+ const mapName = relationName;
163
+
164
+ section += `\t${key} ${relationMeta.inversionModel._collection}[] @relation("${relationName}", map: "${mapName}")\n`;
165
+
166
+ RelationManager.completeRelation(relationKey, relationIndex, true);
167
+ } else if (annotationType === 'InverseTimeSeries') {
168
+ if (dbType === 'mongodb') {
169
+ section += `\t${key} String[] @db.ObjectId\n`;
170
+ } else if (dbType === 'mysql') {
171
+ // For MySQL, we need a different approach for arrays
172
+ section += `\t${key} Json\n`;
173
+ } else if (dbType === 'postgresql' || dbType === 'postgres') {
174
+ // PostgreSQL supports arrays natively
175
+ section += `\t${key} String[]\n`;
176
+ } else {
177
+ section += `\t${key} String[]\n`;
178
+ }
179
+ } else if (annotationType === 'TrackType') {
180
+ const trackMeta = modelMetadata as ITrackerMetaOpts;
181
+ const tags: string[] = trackMeta.tags.map((item: string) => '@' + item);
182
+
183
+ if(trackMeta.unique){
184
+ const fieldDetail: string | null = typeof trackMeta.unique === 'string' ? trackMeta.unique : null;
185
+ tags.push(`@unique(${fieldDetail ? `map: "${fieldDetail}"` : ''})`);
186
+ }
187
+
188
+ if (trackMeta.isArray || trackMeta.type.name === 'Array') {
189
+ requiredString = '';
190
+ }
191
+
192
+ // Process any database-specific options from the metadata
193
+ const dbSpecificTags = TypeConverter.processTypeOptions(trackMeta as { tags: string[], dbOptions: IDbOpts['dbOptions'] }, dbType);
194
+ tags.push(...dbSpecificTags);
195
+
196
+ section += `\t${key} ${TypeConverter.toConfigCase(trackMeta, dbType, key === 'id')}${requiredString} ${tags.join(' ')}\n`;
197
+ }
198
+ }
199
+
200
+ for(const superTag of model._SUPER_TAGS){
201
+
202
+ const mapStr = superTag.map ? `, map: "${superTag.map}"` : '';
203
+
204
+ section += `\t@@${superTag.tagType}([${superTag.fields.join(', ')}]${mapStr})\n`;
205
+ }
206
+
207
+ section += '}\n';
208
+ return section;
209
+ }
210
+
211
+ /**
212
+ * Install Prisma with the generated schema
213
+ * @param configService The configuration service
214
+ * @param dbService The database service
215
+ * @param leaveFile Whether to leave the schema file after generation
216
+ */
217
+ static async installPrisma(configService: IDbConfigHandler, dbService: DBService, leaveFile = false): Promise<void> {
218
+ const dbUrl = configService.get('db_url');
219
+ const dbType = configService.get('db_type') || 'mongodb';
220
+
221
+ let template: string = this.generateBaseSchema(dbType, dbUrl);
222
+
223
+ const dbModels: OpModelType<unknown>[] | null = configService.get('db_models');
224
+
225
+ if (dbModels) {
226
+ for (const model of dbModels) {
227
+ const modelName = (model as any)._collection;
228
+ const modelMetadatas: Record<string, { annotationType: string, metadata: any }> = await RWSModel.getModelAnnotations(model);
229
+
230
+ for (const key in modelMetadatas) {
231
+ const annotationType: string = modelMetadatas[key].annotationType;
232
+
233
+ if (annotationType === 'Relation') {
234
+ const relationMeta = modelMetadatas[key].metadata as IRelationOpts;
235
+
236
+ const relatedModel = relationMeta.relatedTo as OpModelType<any>;
237
+ const relatedModelName = relatedModel._collection;
238
+
239
+ const relationKey = [modelName, relatedModelName].join('_');
240
+
241
+ // Add this relation to the map
242
+ RelationManager.markRelation(relationKey);
243
+ }
244
+
245
+ if(annotationType === 'InverseRelation'){
246
+ const relationMeta = modelMetadatas[key].metadata as InverseRelationOpts;
247
+ const relatedModel = relationMeta.inversionModel as OpModelType<any>;
248
+
249
+ const relatedModelName = relatedModel._collection;
250
+
251
+ const relationKey = [relatedModelName, modelName].join('_');
252
+ RelationManager.markRelation(relationKey, true);
253
+ }
254
+ }
255
+ }
256
+
257
+ // Now generate the model sections with all relations
258
+ for (const model of dbModels) {
259
+ const modelSection = await SchemaGenerator.generateModelSections(model, configService);
260
+
261
+ template += '\n\n' + modelSection;
262
+
263
+ log(chalk.green('[RWS]'), chalk.blue('Building DB Model'), model.name);
264
+ }
265
+
266
+ const [schemaDir, schemaPath] = DbUtils.getSchemaDir();
267
+
268
+ if (!fs.existsSync(schemaDir)) {
269
+ fs.mkdirSync(schemaDir);
270
+ }
271
+
272
+ if (fs.existsSync(schemaPath)) {
273
+ fs.unlinkSync(schemaPath);
274
+ }
275
+
276
+ fs.writeFileSync(schemaPath, template);
277
+
278
+ await rwsShell.runCommand(`${DbUtils.detectInstaller()} prisma generate --schema=${schemaPath}`, process.cwd());
279
+
280
+ leaveFile = false;
281
+ log(chalk.green('[RWS Init]') + ' prisma schema generated from ', schemaPath);
282
+
283
+ if (!leaveFile) {
284
+ // fs.unlinkSync(schemaPath);
285
+ }
286
+ }
287
+ }
288
+
289
+ /**
290
+ * Push database models to the database
291
+ * @param configService The configuration service
292
+ * @param dbService The database service
293
+ * @param leaveFile Whether to leave the schema file after generation
294
+ */
295
+ static async pushDBModels(configService: IDbConfigHandler, dbService: DBService, leaveFile = false): Promise<void> {
296
+ process.env = { ...process.env, [this.dbUrlVarName]: configService.get('db_url') };
297
+
298
+ const [_, schemaPath] = DbUtils.getSchemaDir();
299
+
300
+ await rwsShell.runCommand(`${DbUtils.detectInstaller()} prisma db push --schema=${schemaPath}`, process.cwd());
301
+ }
302
+ }
@@ -0,0 +1,119 @@
1
+ import { IDbOpts } from '../../models/interfaces/IDbOpts';
2
+ import { ITrackerMetaOpts } from '../../models/_model';
3
+ import { IIdMetaOpts } from 'src/decorators/IdType';
4
+
5
+ /**
6
+ * Handles type conversion for database schema generation
7
+ */
8
+ export class TypeConverter {
9
+ /**
10
+ * Convert a JavaScript type to a Prisma schema type
11
+ */
12
+ static toConfigCase(modelType: ITrackerMetaOpts | IIdMetaOpts, dbType: string = 'mongodb', isId: boolean = false): string {
13
+ const type = modelType.type;
14
+ let input = type.name;
15
+
16
+
17
+ // Handle basic types
18
+ if (input == 'Number') {
19
+ input = 'Int';
20
+ }
21
+
22
+ if (input == 'Object') {
23
+ input = 'Json';
24
+ }
25
+
26
+ if (input == 'Date') {
27
+ input = 'DateTime';
28
+ }
29
+
30
+ if (input == 'Boolean') {
31
+ // Ensure Boolean is properly handled for all database types
32
+ input = 'Boolean';
33
+ }
34
+
35
+ if (input == 'Array') {
36
+ // Handle arrays differently based on database type
37
+ if (dbType === 'mysql') {
38
+ // MySQL doesn't support native arrays, use Json instead
39
+ input = 'Json';
40
+ } else {
41
+ input = 'Json[]';
42
+ }
43
+ }
44
+
45
+ const firstChar = input.charAt(0).toUpperCase();
46
+ const restOfString = input.slice(1);
47
+ let resultField = firstChar + restOfString;
48
+
49
+ if(isId){
50
+ return dbType === 'mongodb' ? 'String' : 'Int';
51
+ }
52
+
53
+ const trackerModelType = modelType as ITrackerMetaOpts;
54
+
55
+ if (trackerModelType.isArray) {
56
+ // Handle arrays differently based on database type
57
+ if (dbType === 'mysql') {
58
+ // For MySQL, we don't append [] as it doesn't support native arrays
59
+ // Instead, we'll store arrays as JSON
60
+ resultField = 'Json';
61
+ } else if (dbType === 'postgresql' || dbType === 'postgres') {
62
+ // PostgreSQL supports arrays natively
63
+ resultField += '[]';
64
+ } else {
65
+ resultField += '[]';
66
+ }
67
+ }
68
+
69
+ return resultField;
70
+ }
71
+
72
+ /**
73
+ * Process type functions metadata to extract database-specific options
74
+ * @param metadata The metadata from a type function
75
+ * @param dbType The database type
76
+ * @returns Array of tags to apply to the field
77
+ */
78
+ static processTypeOptions(metadata: { tags: string[], dbOptions: IDbOpts['dbOptions'] }, dbType: string): string[] {
79
+ const tags: string[] = [...(metadata.tags || [])];
80
+
81
+ // Extract any database-specific options from the metadata
82
+ // and convert them to appropriate Prisma schema tags
83
+ if (metadata.dbOptions) {
84
+ // Handle MySQL-specific options
85
+ if (dbType === 'mysql' && metadata.dbOptions.mysql) {
86
+ if (metadata.dbOptions.mysql.useText) {
87
+ tags.push('@db.Text');
88
+ } else if (metadata.dbOptions.mysql.maxLength) {
89
+ tags.push(`@db.VarChar(${metadata.dbOptions.mysql.maxLength})`);
90
+ }
91
+
92
+ if (metadata.dbOptions.mysql.useUuid && metadata.tags?.includes('id')) {
93
+ tags.push('default(uuid())');
94
+ }
95
+ }
96
+
97
+ // Handle PostgreSQL-specific options
98
+ if ((dbType === 'postgresql' || dbType === 'postgres') && metadata.dbOptions.postgres) {
99
+ if (metadata.dbOptions.postgres.useText) {
100
+ tags.push('@db.Text');
101
+ }
102
+
103
+ if (metadata.dbOptions.postgres.useUuid && metadata.tags?.includes('id')) {
104
+ tags.push('@default(uuid())');
105
+ tags.push('@db.Uuid');
106
+ }
107
+ }
108
+
109
+ // Handle MongoDB-specific options
110
+ if (dbType === 'mongodb' && metadata.dbOptions.mongodb) {
111
+ if (metadata.dbOptions.mongodb.customType) {
112
+ tags.push(`@db.${metadata.dbOptions.mongodb.customType}`);
113
+ }
114
+ }
115
+ }
116
+
117
+ return tags;
118
+ }
119
+ }
@@ -0,0 +1,120 @@
1
+ import { rwsPath } from '@rws-framework/console';
2
+ import path from 'path';
3
+ import fs from 'fs';
4
+ import { IDbConfigParams } from '../../types/DbConfigHandler';
5
+ import { IIdMetaOpts, IIdTypeOpts } from '../../decorators/IdType';
6
+ import { TypeConverter } from './type-converter';
7
+ import { IDbOpts } from '../../models/interfaces/IDbOpts';
8
+
9
+ const workspaceRoot = rwsPath.findRootWorkspacePath();
10
+ const moduleDir = path.resolve(workspaceRoot, 'node_modules', '@rws-framework', 'db');
11
+
12
+ /**
13
+ * Utility functions for database operations
14
+ */
15
+ export class DbUtils {
16
+ /**
17
+ * Get the directory and path for the Prisma schema file
18
+ */
19
+ static getSchemaDir(): [string, string] {
20
+ const schemaDir = path.join(moduleDir, 'prisma');
21
+ const schemaPath = path.join(schemaDir, 'schema.prisma');
22
+
23
+ return [schemaDir, schemaPath];
24
+ }
25
+
26
+ /**
27
+ * Detect the package installer (yarn or npx)
28
+ */
29
+ static detectInstaller(): string {
30
+ if (fs.existsSync(path.join(workspaceRoot, 'yarn.lock'))) {
31
+ return 'yarn';
32
+ }
33
+
34
+ return 'npx';
35
+ }
36
+
37
+ /**
38
+ * Generate an ID field based on the database type
39
+ */
40
+ static generateId(
41
+ dbType: IDbConfigParams['db_type'],
42
+ modelMeta: Record<string, { annotationType: string, metadata: IIdMetaOpts }>,
43
+ debug = false
44
+ ): string {
45
+ let useUuid = false;
46
+ let field = 'id';
47
+ const tags: string[] = [];
48
+
49
+ for (const key in modelMeta) {
50
+ const modelMetadata: IIdMetaOpts = modelMeta[key].metadata;
51
+ const annotationType: string = modelMeta[key].annotationType;
52
+
53
+ if(key !== 'id'){
54
+ if(annotationType == 'IdType'){
55
+ const dbSpecificTags = TypeConverter.processTypeOptions({ tags: [], dbOptions: modelMetadata.dbOptions }, dbType);
56
+ tags.push(...dbSpecificTags);
57
+ if(debug){
58
+ console.log({modelMetadata: modelMetadata.dbOptions});
59
+ }
60
+
61
+ field = key;
62
+
63
+ if(modelMetadata.dbOptions?.mysql?.useUuid){
64
+ useUuid = true;
65
+ }
66
+
67
+ if(modelMetadata.dbOptions?.postgres?.useUuid){
68
+ useUuid = true;
69
+ }
70
+
71
+ if(modelMetadata.type.name === 'String'){
72
+ useUuid = true;
73
+ }
74
+ }
75
+ }
76
+ }
77
+
78
+ let idString: string;
79
+
80
+ switch (dbType) {
81
+ case 'mongodb':
82
+ idString = `${field} String @id @default(auto()) @map("_id") @db.ObjectId`;
83
+ break;
84
+
85
+ case 'mysql':
86
+ idString = useUuid
87
+ ? `${field} String @id @default(uuid())`
88
+ : `${field} Int @id @default(autoincrement())`;
89
+ break;
90
+
91
+ case 'postgresql':
92
+ case 'postgres':
93
+ idString = useUuid
94
+ ? `${field} String @id @default(uuid())`
95
+ : `${field} Int @id @default(autoincrement())`;
96
+ break;
97
+
98
+ case 'sqlite':
99
+ idString = `${field} Int @id @default(autoincrement())`;
100
+ break;
101
+ }
102
+
103
+ if(tags.length){
104
+ idString += ' '+tags.join(' ');
105
+ }
106
+
107
+ if(!idString){
108
+ throw new Error(`DB type "${dbType}" is not supported!`);
109
+ }
110
+
111
+ if(debug){
112
+ console.log({idString, useUuid});
113
+ }
114
+
115
+ return idString;
116
+ }
117
+ }
118
+
119
+ export const workspaceRootPath = workspaceRoot;
120
+ export const moduleDirPath = moduleDir;
package/src/index.ts CHANGED
@@ -1,38 +1,47 @@
1
- import { DBService } from "./services/DBService";
2
- import { RWSModel, OpModelType } from "./models/_model";
3
- // import TimeSeriesModel from './models/core/TimeSeriesModel';
4
- import { InverseRelation, Relation, TrackType, InverseTimeSeries, IMetaOpts } from './decorators';
5
-
6
- import { DbHelper } from './helper/DbHelper';
7
- import { FieldsHelper } from './helper/FieldsHelper';
8
-
9
- import type { FindByType } from './types/FindParams';
10
- import type { ITimeSeries } from './types/ITimeSeries';
11
- import type { IDbConfigHandler, IDbConfigParams } from './types/DbConfigHandler';
12
- import type { IRWSModel } from './types/IRWSModel';
13
- import { RWSCollection, IRWSCollectionMeta, IRWSCollectionOpts } from "./decorators/RWSCollection";
14
-
15
- export type {
16
- IRWSCollectionMeta, IRWSCollectionOpts,
17
- IRWSModel,
18
- IMetaOpts,
19
- OpModelType,
20
- IDbConfigHandler,
21
- IDbConfigParams,
22
- ITimeSeries,
23
- }
24
-
25
- export {
26
- RWSModel,
27
- RWSCollection,
28
-
29
- DBService,
30
-
31
- FindByType,
32
- // TimeSeriesModel,
33
-
34
- InverseRelation, Relation, TrackType, InverseTimeSeries,
35
-
36
- DbHelper,
37
- FieldsHelper
38
- };
1
+ import { DBService } from "./services/DBService";
2
+ import { RWSModel, OpModelType } from "./models/_model";
3
+ // import TimeSeriesModel from './models/core/TimeSeriesModel';
4
+ import {
5
+ InverseRelation,
6
+ Relation,
7
+ TrackType,
8
+ IdType,
9
+ InverseTimeSeries,
10
+ ITrackerMetaOpts,
11
+ ITrackerOpts
12
+ } from './decorators';
13
+
14
+ import { DbHelper } from './helper/DbHelper';
15
+ import { FieldsHelper } from './helper/FieldsHelper';
16
+
17
+ import type { FindByType } from './types/FindParams';
18
+ import type { ITimeSeries } from './types/ITimeSeries';
19
+ import type { IDbConfigHandler, IDbConfigParams } from './types/DbConfigHandler';
20
+ import type { IRWSModel } from './types/IRWSModel';
21
+ import { RWSCollection, IRWSCollectionMeta, IRWSCollectionOpts } from "./decorators/RWSCollection";
22
+
23
+ export type {
24
+ IRWSCollectionMeta, IRWSCollectionOpts,
25
+ IRWSModel,
26
+ ITrackerMetaOpts,
27
+ ITrackerOpts,
28
+ OpModelType,
29
+ IDbConfigHandler,
30
+ IDbConfigParams,
31
+ ITimeSeries,
32
+ }
33
+
34
+ export {
35
+ RWSModel,
36
+ RWSCollection,
37
+
38
+ DBService,
39
+
40
+ FindByType,
41
+ // TimeSeriesModel,
42
+
43
+ InverseRelation, Relation, TrackType, InverseTimeSeries, IdType,
44
+
45
+ DbHelper,
46
+ FieldsHelper
47
+ };
@@ -1,30 +1,30 @@
1
- /**
2
- * @deprecated This file is deprecated. Import from 'models' directory instead.
3
- */
4
-
5
- import {
6
- IModel,
7
- IRWSModelServices,
8
- OpModelType,
9
- RelationBindType,
10
- RelOneMetaType,
11
- RelManyMetaType,
12
- RWSModel,
13
- TrackType,
14
- IMetaOpts
15
- } from './index';
16
-
17
- export {
18
- RWSModel,
19
- TrackType
20
- };
21
-
22
- export type {
23
- IModel,
24
- IRWSModelServices,
25
- OpModelType,
26
- RelationBindType,
27
- RelOneMetaType,
28
- RelManyMetaType,
29
- IMetaOpts
1
+ /**
2
+ * @deprecated This file is deprecated. Import from 'models' directory instead.
3
+ */
4
+
5
+ import {
6
+ IModel,
7
+ IRWSModelServices,
8
+ OpModelType,
9
+ RelationBindType,
10
+ RelOneMetaType,
11
+ RelManyMetaType,
12
+ RWSModel,
13
+ TrackType,
14
+ ITrackerMetaOpts
15
+ } from './index';
16
+
17
+ export {
18
+ RWSModel,
19
+ TrackType
20
+ };
21
+
22
+ export type {
23
+ IModel,
24
+ IRWSModelServices,
25
+ OpModelType,
26
+ RelationBindType,
27
+ RelOneMetaType,
28
+ RelManyMetaType,
29
+ ITrackerMetaOpts
30
30
  };