@currentjs/gen 0.3.2 → 0.5.1
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/CHANGELOG.md +18 -609
- package/README.md +623 -427
- package/dist/cli.js +2 -1
- package/dist/commands/commit.js +25 -42
- package/dist/commands/createApp.js +1 -0
- package/dist/commands/createModule.js +151 -45
- package/dist/commands/diff.js +27 -40
- package/dist/commands/generateAll.js +141 -291
- package/dist/commands/migrateCommit.js +6 -18
- package/dist/generators/controllerGenerator.d.ts +50 -19
- package/dist/generators/controllerGenerator.js +588 -331
- package/dist/generators/domainLayerGenerator.d.ts +21 -0
- package/dist/generators/domainLayerGenerator.js +286 -0
- package/dist/generators/dtoGenerator.d.ts +21 -0
- package/dist/generators/dtoGenerator.js +523 -0
- package/dist/generators/serviceGenerator.d.ts +22 -51
- package/dist/generators/serviceGenerator.js +345 -568
- package/dist/generators/storeGenerator.d.ts +39 -32
- package/dist/generators/storeGenerator.js +396 -236
- package/dist/generators/templateGenerator.d.ts +21 -21
- package/dist/generators/templateGenerator.js +393 -268
- package/dist/generators/templates/appTemplates.d.ts +3 -1
- package/dist/generators/templates/appTemplates.js +16 -11
- package/dist/generators/templates/data/appYamlTemplate +5 -2
- package/dist/generators/templates/data/cursorRulesTemplate +315 -221
- package/dist/generators/templates/data/frontendScriptTemplate +56 -15
- package/dist/generators/templates/data/mainViewTemplate +2 -1
- package/dist/generators/templates/data/systemTsTemplate +5 -0
- package/dist/generators/templates/index.d.ts +0 -3
- package/dist/generators/templates/index.js +0 -3
- package/dist/generators/templates/storeTemplates.d.ts +1 -5
- package/dist/generators/templates/storeTemplates.js +84 -224
- package/dist/generators/useCaseGenerator.d.ts +13 -0
- package/dist/generators/useCaseGenerator.js +191 -0
- package/dist/types/configTypes.d.ts +149 -0
- package/dist/types/configTypes.js +10 -0
- package/dist/utils/childEntityUtils.d.ts +18 -0
- package/dist/utils/childEntityUtils.js +78 -0
- package/dist/utils/commandUtils.d.ts +43 -0
- package/dist/utils/commandUtils.js +124 -0
- package/dist/utils/commitUtils.d.ts +4 -1
- package/dist/utils/constants.d.ts +10 -0
- package/dist/utils/constants.js +13 -1
- package/dist/utils/diResolver.d.ts +32 -0
- package/dist/utils/diResolver.js +204 -0
- package/dist/utils/typeUtils.d.ts +23 -0
- package/dist/utils/typeUtils.js +77 -0
- package/package.json +7 -3
- package/dist/generators/domainModelGenerator.d.ts +0 -41
- package/dist/generators/domainModelGenerator.js +0 -242
- package/dist/generators/templates/controllerTemplates.d.ts +0 -43
- package/dist/generators/templates/controllerTemplates.js +0 -82
- package/dist/generators/templates/serviceTemplates.d.ts +0 -16
- package/dist/generators/templates/serviceTemplates.js +0 -59
- package/dist/generators/templates/validationTemplates.d.ts +0 -25
- package/dist/generators/templates/validationTemplates.js +0 -66
- package/dist/generators/templates/viewTemplates.d.ts +0 -25
- package/dist/generators/templates/viewTemplates.js +0 -491
- package/dist/generators/validationGenerator.d.ts +0 -29
- package/dist/generators/validationGenerator.js +0 -250
|
@@ -374,7 +374,10 @@ window.AppConfig = {
|
|
|
374
374
|
*/
|
|
375
375
|
function navigateToPage(url, targetElement = null) {
|
|
376
376
|
const target = targetElement || document.querySelector('#main');
|
|
377
|
-
if (!target)
|
|
377
|
+
if (!target) {
|
|
378
|
+
window.location.href = url;
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
378
381
|
|
|
379
382
|
showLoading('#main');
|
|
380
383
|
|
|
@@ -388,18 +391,22 @@ window.AppConfig = {
|
|
|
388
391
|
if (!response.ok) {
|
|
389
392
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
390
393
|
}
|
|
394
|
+
const targetLayout = response.headers.get('X-Layout') || '';
|
|
395
|
+
const currentLayout = (document.querySelector('meta[name="app-layout"]') || {}).content || '';
|
|
396
|
+
if (targetLayout !== currentLayout) {
|
|
397
|
+
window.location.href = url;
|
|
398
|
+
return null;
|
|
399
|
+
}
|
|
391
400
|
return response.text();
|
|
392
401
|
})
|
|
393
402
|
.then(html => {
|
|
403
|
+
if (html === null) return;
|
|
394
404
|
target.innerHTML = html;
|
|
395
|
-
// Update browser history
|
|
396
405
|
window.history.pushState({}, '', url);
|
|
397
|
-
// No need to re-initialize - delegation handles new content automatically
|
|
398
406
|
})
|
|
399
407
|
.catch(error => {
|
|
400
408
|
console.error('Navigation failed:', error);
|
|
401
409
|
showToast('Failed to load page', 'error');
|
|
402
|
-
// Fallback to normal navigation
|
|
403
410
|
window.location.href = url;
|
|
404
411
|
})
|
|
405
412
|
.finally(() => {
|
|
@@ -414,7 +421,7 @@ window.AppConfig = {
|
|
|
414
421
|
* @returns {any} Converted value
|
|
415
422
|
*/
|
|
416
423
|
function convertFieldValue(value, fieldType) {
|
|
417
|
-
if (
|
|
424
|
+
if (value === undefined || value === null || value === '') {
|
|
418
425
|
return null;
|
|
419
426
|
}
|
|
420
427
|
|
|
@@ -422,6 +429,7 @@ window.AppConfig = {
|
|
|
422
429
|
case 'number':
|
|
423
430
|
case 'int':
|
|
424
431
|
case 'integer':
|
|
432
|
+
case 'id':
|
|
425
433
|
const intVal = parseInt(value, 10);
|
|
426
434
|
return isNaN(intVal) ? null : intVal;
|
|
427
435
|
|
|
@@ -432,10 +440,15 @@ window.AppConfig = {
|
|
|
432
440
|
|
|
433
441
|
case 'boolean':
|
|
434
442
|
case 'bool':
|
|
435
|
-
if (value === 'true') return true;
|
|
436
|
-
if (value === 'false') return false;
|
|
443
|
+
if (value === 'true' || value === 'on' || value === '1') return true;
|
|
444
|
+
if (value === 'false' || value === 'off' || value === '0') return false;
|
|
437
445
|
return Boolean(value);
|
|
446
|
+
|
|
447
|
+
case 'json':
|
|
448
|
+
try { return JSON.parse(value); } catch { return value; }
|
|
438
449
|
|
|
450
|
+
case 'datetime':
|
|
451
|
+
case 'date':
|
|
439
452
|
case 'enum':
|
|
440
453
|
case 'string':
|
|
441
454
|
case 'text':
|
|
@@ -474,6 +487,30 @@ window.AppConfig = {
|
|
|
474
487
|
jsonData[key] = convertedValue;
|
|
475
488
|
}
|
|
476
489
|
}
|
|
490
|
+
|
|
491
|
+
// Unchecked checkboxes are not included in FormData — default to false
|
|
492
|
+
for (const [fieldName, fieldType] of Object.entries(fieldTypes)) {
|
|
493
|
+
const ft = fieldType.toLowerCase();
|
|
494
|
+
if ((ft === 'boolean' || ft === 'bool') && !(fieldName in jsonData)) {
|
|
495
|
+
jsonData[fieldName] = false;
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
// Unflatten dot-notation keys (e.g., "amount.currency") into nested objects
|
|
500
|
+
const finalData = {};
|
|
501
|
+
for (const [key, value] of Object.entries(jsonData)) {
|
|
502
|
+
if (key.includes('.')) {
|
|
503
|
+
const parts = key.split('.');
|
|
504
|
+
let current = finalData;
|
|
505
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
506
|
+
if (!(parts[i] in current)) current[parts[i]] = {};
|
|
507
|
+
current = current[parts[i]];
|
|
508
|
+
}
|
|
509
|
+
current[parts[parts.length - 1]] = value;
|
|
510
|
+
} else {
|
|
511
|
+
finalData[key] = value;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
477
514
|
|
|
478
515
|
const url = form.getAttribute('data-action') || form.action;
|
|
479
516
|
const method = (form.getAttribute('data-method') || form.method || 'POST').toUpperCase();
|
|
@@ -486,16 +523,20 @@ window.AppConfig = {
|
|
|
486
523
|
'Content-Type': 'application/json',
|
|
487
524
|
'Accept': 'application/json'
|
|
488
525
|
}),
|
|
489
|
-
body: JSON.stringify(
|
|
526
|
+
body: JSON.stringify(finalData)
|
|
490
527
|
})
|
|
491
|
-
.then(response =>
|
|
492
|
-
|
|
493
|
-
|
|
528
|
+
.then(response =>
|
|
529
|
+
response.json()
|
|
530
|
+
.catch(() => ({}))
|
|
531
|
+
.then(body => ({ ok: response.ok, status: response.status, statusText: response.statusText, body }))
|
|
532
|
+
)
|
|
533
|
+
.then(({ ok, status, statusText, body }) => {
|
|
534
|
+
if (!ok) {
|
|
535
|
+
const message = body.message || body.error || `HTTP ${status}: ${statusText}`;
|
|
536
|
+
handleFormError({ message }, options);
|
|
537
|
+
return;
|
|
494
538
|
}
|
|
495
|
-
|
|
496
|
-
})
|
|
497
|
-
.then(data => {
|
|
498
|
-
handleFormSuccess(data, strategy, options);
|
|
539
|
+
handleFormSuccess(body, strategy, options);
|
|
499
540
|
})
|
|
500
541
|
.catch(error => {
|
|
501
542
|
console.error('Form submission failed:', error);
|
|
@@ -5,12 +5,13 @@
|
|
|
5
5
|
<meta charset="UTF-8">
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
7
|
<title>Your App</title>
|
|
8
|
+
<meta name="app-layout" content="main_view">
|
|
8
9
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
|
|
9
10
|
<script src="/app.js"></script>
|
|
10
11
|
</head>
|
|
11
12
|
<body>
|
|
12
13
|
<div class="container-fluid">
|
|
13
|
-
<div id="main">{{ content }}</div>
|
|
14
|
+
<div id="main">{{{ content }}}</div>
|
|
14
15
|
</div>
|
|
15
16
|
</body>
|
|
16
17
|
</html>
|
|
@@ -14,8 +14,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
__exportStar(require("./serviceTemplates"), exports);
|
|
18
|
-
__exportStar(require("./controllerTemplates"), exports);
|
|
19
17
|
__exportStar(require("./storeTemplates"), exports);
|
|
20
|
-
__exportStar(require("./validationTemplates"), exports);
|
|
21
18
|
__exportStar(require("./appTemplates"), exports);
|
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
export declare const storeTemplates: {
|
|
2
2
|
rowInterface: string;
|
|
3
3
|
storeClass: string;
|
|
4
|
-
conversionMethods: string;
|
|
5
|
-
};
|
|
6
|
-
export declare const fileTemplates: {
|
|
7
|
-
storeFile: string;
|
|
8
|
-
storeInterface: string;
|
|
9
4
|
};
|
|
5
|
+
export declare const storeFileTemplate = "import { Injectable } from '../../../../system';\nimport { {{ENTITY_IMPORT_ITEMS}} } from '../../domain/entities/{{ENTITY_NAME}}';\nimport type { ISqlProvider } from '@currentjs/provider-mysql';{{VALUE_OBJECT_IMPORTS}}{{AGGREGATE_REF_IMPORTS}}\n\n{{ROW_INTERFACE}}\n\n{{STORE_CLASS}}\n";
|
|
@@ -1,260 +1,120 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.storeFileTemplate = exports.storeTemplates = void 0;
|
|
4
4
|
exports.storeTemplates = {
|
|
5
5
|
rowInterface: `export interface {{ENTITY_NAME}}Row {
|
|
6
6
|
id: number;
|
|
7
7
|
{{ROW_FIELDS}}
|
|
8
|
-
created_at:
|
|
9
|
-
updated_at:
|
|
10
|
-
deleted_at?:
|
|
8
|
+
created_at: string;
|
|
9
|
+
updated_at: string;
|
|
10
|
+
deleted_at?: string;
|
|
11
11
|
}`,
|
|
12
|
-
storeClass:
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
storeClass: `/**
|
|
13
|
+
* Data access layer for {{ENTITY_NAME}}
|
|
14
|
+
*/
|
|
15
|
+
@Injectable()
|
|
16
|
+
export class {{ENTITY_NAME}}Store {
|
|
17
|
+
private tableName = '{{TABLE_NAME}}';
|
|
18
|
+
|
|
16
19
|
constructor(private db: ISqlProvider) {}
|
|
17
20
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const query = 'SELECT * FROM {{TABLE_NAME}} WHERE id = :id AND deleted_at IS NULL';
|
|
21
|
-
const result = await this.db.query(query, { id });
|
|
22
|
-
|
|
23
|
-
if (!result.success || result.data.length === 0) {
|
|
24
|
-
return null;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
return {{ENTITY_NAME}}Store.rowToModel(result.data[0] as {{ENTITY_NAME}}Row);
|
|
28
|
-
} catch (error) {
|
|
29
|
-
if (error instanceof MySQLConnectionError) {
|
|
30
|
-
throw new Error(\`Database connection error while fetching {{ENTITY_NAME}} with id \${id}: \${error.message}\`);
|
|
31
|
-
} else if (error instanceof MySQLQueryError) {
|
|
32
|
-
throw new Error(\`Query error while fetching {{ENTITY_NAME}} with id \${id}: \${error.message}\`);
|
|
33
|
-
}
|
|
34
|
-
throw error;
|
|
35
|
-
}
|
|
21
|
+
private toMySQLDatetime(date: Date): string {
|
|
22
|
+
return date.toISOString().slice(0, 19).replace('T', ' ');
|
|
36
23
|
}
|
|
37
24
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
if (!result.success) {
|
|
44
|
-
return [];
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
return result.data.map((row: {{ENTITY_NAME}}Row) => {{ENTITY_NAME}}Store.rowToModel(row));
|
|
25
|
+
private rowToModel(row: {{ENTITY_NAME}}Row): {{ENTITY_NAME}} {
|
|
26
|
+
return new {{ENTITY_NAME}}(
|
|
27
|
+
row.id,
|
|
28
|
+
{{ROW_TO_MODEL_MAPPING}}
|
|
29
|
+
);
|
|
48
30
|
}
|
|
49
31
|
|
|
50
|
-
|
|
51
|
-
const offset = (page - 1) * limit;
|
|
52
|
-
const query = \`SELECT * FROM {{TABLE_NAME}} WHERE user_id = :userId AND deleted_at IS NULL ORDER BY created_at DESC LIMIT \${limit} OFFSET \${offset}\`;
|
|
53
|
-
const result = await this.db.query(query, { userId });
|
|
54
|
-
|
|
55
|
-
if (!result.success) {
|
|
56
|
-
return [];
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
return result.data.map((row: {{ENTITY_NAME}}Row) => {{ENTITY_NAME}}Store.rowToModel(row));
|
|
60
|
-
}
|
|
32
|
+
{{LIST_METHODS}}
|
|
61
33
|
|
|
62
|
-
async
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
if (!{{ENTITY_NAME}}Store.FILTERABLE_FIELDS.includes(key)) {
|
|
68
|
-
throw new Error(\`Invalid filter field: \${key}\`);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const whereConditions = filterKeys.map(key => \`\${key} = :\${key}\`);
|
|
73
|
-
|
|
74
|
-
if (whereConditions.length === 0) {
|
|
75
|
-
throw new Error('At least one filter condition is required');
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const query = \`SELECT * FROM {{TABLE_NAME}} WHERE \${whereConditions.join(' AND ')} AND deleted_at IS NULL LIMIT 1\`;
|
|
79
|
-
const result = await this.db.query(query, filters);
|
|
80
|
-
|
|
81
|
-
if (!result.success || result.data.length === 0) {
|
|
82
|
-
return null;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return {{ENTITY_NAME}}Store.rowToModel(result.data[0] as {{ENTITY_NAME}}Row);
|
|
86
|
-
}
|
|
34
|
+
async getById(id: number): Promise<{{ENTITY_NAME}} | null> {
|
|
35
|
+
const result = await this.db.query(
|
|
36
|
+
\`SELECT {{FIELD_NAMES}} FROM \\\`\${this.tableName}\\\` WHERE id = :id AND deleted_at IS NULL\`,
|
|
37
|
+
{ id }
|
|
38
|
+
);
|
|
87
39
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
// Runtime validation against SQL injection
|
|
92
|
-
for (const key of filterKeys) {
|
|
93
|
-
if (!{{ENTITY_NAME}}Store.FILTERABLE_FIELDS.includes(key)) {
|
|
94
|
-
throw new Error(\`Invalid filter field: \${key}\`);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
const whereConditions = filterKeys.map(key => \`\${key} = :\${key}\`);
|
|
99
|
-
|
|
100
|
-
if (whereConditions.length === 0) {
|
|
101
|
-
return this.getAll();
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
const query = \`SELECT * FROM {{TABLE_NAME}} WHERE \${whereConditions.join(' AND ')} AND deleted_at IS NULL ORDER BY created_at DESC\`;
|
|
105
|
-
const result = await this.db.query(query, filters);
|
|
106
|
-
|
|
107
|
-
if (!result.success) {
|
|
108
|
-
return [];
|
|
40
|
+
if (result.success && result.data && result.data.length > 0) {
|
|
41
|
+
return this.rowToModel(result.data[0] as {{ENTITY_NAME}}Row);
|
|
109
42
|
}
|
|
110
|
-
|
|
111
|
-
return result.data.map((row: {{ENTITY_NAME}}Row) => {{ENTITY_NAME}}Store.rowToModel(row));
|
|
43
|
+
return null;
|
|
112
44
|
}
|
|
113
45
|
|
|
114
|
-
async insert(
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
const fields = Object.keys(row);
|
|
122
|
-
const placeholders = fields.map(field => \`:\${field}\`).join(', ');
|
|
123
|
-
|
|
124
|
-
const query = \`INSERT INTO {{TABLE_NAME}} (\${fields.join(', ')}) VALUES (\${placeholders})\`;
|
|
125
|
-
const result = await this.db.query(query, row);
|
|
126
|
-
|
|
127
|
-
if (!result.success || !result.insertId) {
|
|
128
|
-
throw new Error('Failed to insert {{ENTITY_NAME}}: Insert operation did not return a valid ID');
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
return this.getById(Number(result.insertId));
|
|
132
|
-
} catch (error) {
|
|
133
|
-
if (error instanceof MySQLQueryError) {
|
|
134
|
-
throw new Error(\`Failed to insert {{ENTITY_NAME}}: \${error.message}\`);
|
|
135
|
-
} else if (error instanceof MySQLConnectionError) {
|
|
136
|
-
throw new Error(\`Database connection error while inserting {{ENTITY_NAME}}: \${error.message}\`);
|
|
137
|
-
}
|
|
138
|
-
throw error;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
46
|
+
async insert(entity: {{ENTITY_NAME}}): Promise<{{ENTITY_NAME}}> {
|
|
47
|
+
const now = new Date();
|
|
48
|
+
const data: Partial<{{ENTITY_NAME}}Row> = {
|
|
49
|
+
{{INSERT_DATA_MAPPING}},
|
|
50
|
+
created_at: this.toMySQLDatetime(now),
|
|
51
|
+
updated_at: this.toMySQLDatetime(now)
|
|
52
|
+
};
|
|
141
53
|
|
|
142
|
-
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
for (const key of updateKeys) {
|
|
154
|
-
if (!{{ENTITY_NAME}}Store.UPDATABLE_FIELDS.includes(key)) {
|
|
155
|
-
throw new Error(\`Invalid update field: \${key}\`);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
const updateFields = updateKeys.map(key => \`\${key} = :\${key}\`);
|
|
160
|
-
|
|
161
|
-
if (updateFields.length === 0) {
|
|
162
|
-
return existing;
|
|
54
|
+
const fieldsList = Object.keys(data).map(f => \`\\\`\${f}\\\`\`).join(', ');
|
|
55
|
+
const placeholders = Object.keys(data).map(f => \`:\${f}\`).join(', ');
|
|
56
|
+
|
|
57
|
+
const result = await this.db.query(
|
|
58
|
+
\`INSERT INTO \\\`\${this.tableName}\\\` (\${fieldsList}) VALUES (\${placeholders})\`,
|
|
59
|
+
data
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
if (result.success && result.insertId) {
|
|
63
|
+
const newId = typeof result.insertId === 'string' ? parseInt(result.insertId, 10) : result.insertId;
|
|
64
|
+
return this.getById(newId) as Promise<{{ENTITY_NAME}}>;
|
|
163
65
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
const query = \`UPDATE {{TABLE_NAME}} SET \${updateFields.join(', ')}, updated_at = :updated_at WHERE id = :id\`;
|
|
168
|
-
await this.db.query(query, params);
|
|
169
|
-
|
|
170
|
-
return this.getById(id);
|
|
66
|
+
|
|
67
|
+
throw new Error('Failed to insert {{ENTITY_NAME}}');
|
|
171
68
|
}
|
|
172
69
|
|
|
173
|
-
async
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
70
|
+
async update(id: number, entity: {{ENTITY_NAME}}): Promise<{{ENTITY_NAME}}> {
|
|
71
|
+
const now = new Date();
|
|
72
|
+
const data: Partial<{{ENTITY_NAME}}Row> & { id: number } = {
|
|
73
|
+
{{UPDATE_DATA_MAPPING}},
|
|
74
|
+
updated_at: this.toMySQLDatetime(now),
|
|
75
|
+
id
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const updateFields = {{UPDATE_FIELDS_ARRAY}}.map(f => \`\\\`\${f}\\\` = :\${f}\`).join(', ');
|
|
79
|
+
|
|
80
|
+
const result = await this.db.query(
|
|
81
|
+
\`UPDATE \\\`\${this.tableName}\\\` SET \${updateFields}, updated_at = :updated_at WHERE id = :id\`,
|
|
82
|
+
data
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
if (result.success) {
|
|
86
|
+
return this.getById(id) as Promise<{{ENTITY_NAME}}>;
|
|
179
87
|
}
|
|
180
|
-
|
|
181
|
-
|
|
88
|
+
|
|
89
|
+
throw new Error('Failed to update {{ENTITY_NAME}}');
|
|
182
90
|
}
|
|
183
91
|
|
|
184
92
|
async softDelete(id: number): Promise<boolean> {
|
|
185
|
-
const
|
|
186
|
-
const result = await this.db.query(
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
93
|
+
const now = new Date();
|
|
94
|
+
const result = await this.db.query(
|
|
95
|
+
\`UPDATE \\\`\${this.tableName}\\\` SET deleted_at = :deleted_at WHERE id = :id\`,
|
|
96
|
+
{ deleted_at: this.toMySQLDatetime(now), id }
|
|
97
|
+
);
|
|
190
98
|
|
|
191
|
-
|
|
192
|
-
let query = 'SELECT COUNT(*) as count FROM {{TABLE_NAME}} WHERE deleted_at IS NULL';
|
|
193
|
-
let params: Record<string, any> = {};
|
|
194
|
-
|
|
195
|
-
if (filters && Object.keys(filters).length > 0) {
|
|
196
|
-
const whereConditions = Object.keys(filters).map(key => \`\${key} = :\${key}\`);
|
|
197
|
-
params = { ...filters };
|
|
198
|
-
query += \` AND \${whereConditions.join(' AND ')}\`;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
const result = await this.db.query(query, params);
|
|
202
|
-
|
|
203
|
-
if (!result.success || result.data.length === 0) {
|
|
204
|
-
return 0;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
return result.data[0].count;
|
|
99
|
+
return result.success;
|
|
208
100
|
}
|
|
209
101
|
|
|
210
|
-
{
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
row.id,
|
|
215
|
-
{{ROW_TO_MODEL_MAPPING}}
|
|
102
|
+
async hardDelete(id: number): Promise<boolean> {
|
|
103
|
+
const result = await this.db.query(
|
|
104
|
+
\`DELETE FROM \\\`\${this.tableName}\\\` WHERE id = :id\`,
|
|
105
|
+
{ id }
|
|
216
106
|
);
|
|
217
|
-
}
|
|
218
107
|
|
|
219
|
-
|
|
220
|
-
return {
|
|
221
|
-
id: model.id,
|
|
222
|
-
{{MODEL_TO_ROW_MAPPING}},
|
|
223
|
-
updated_at: new Date()
|
|
224
|
-
};
|
|
108
|
+
return result.success;
|
|
225
109
|
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
const result: Record<string, any> = {};
|
|
229
|
-
|
|
230
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
231
|
-
// Only include properties that are not functions and are in updatable fields
|
|
232
|
-
if (typeof value !== 'function' && {{ENTITY_NAME}}Store.UPDATABLE_FIELDS.includes(key)) {
|
|
233
|
-
result[key] = value;
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
return result;
|
|
238
|
-
}`
|
|
110
|
+
{{GET_BY_PARENT_ID_METHOD}}
|
|
111
|
+
{{GET_RESOURCE_OWNER_METHOD}}}`
|
|
239
112
|
};
|
|
240
|
-
exports.
|
|
241
|
-
|
|
242
|
-
import {
|
|
243
|
-
import { ProviderMysql, ISqlProvider, MySQLQueryError, MySQLConnectionError } from '@currentjs/provider-mysql';
|
|
113
|
+
exports.storeFileTemplate = `import { Injectable } from '../../../../system';
|
|
114
|
+
import { {{ENTITY_IMPORT_ITEMS}} } from '../../domain/entities/{{ENTITY_NAME}}';
|
|
115
|
+
import type { ISqlProvider } from '@currentjs/provider-mysql';{{VALUE_OBJECT_IMPORTS}}{{AGGREGATE_REF_IMPORTS}}
|
|
244
116
|
|
|
245
117
|
{{ROW_INTERFACE}}
|
|
246
118
|
|
|
247
|
-
{{STORE_CLASS}}
|
|
248
|
-
|
|
249
|
-
getById(id: number): Promise<TModel | null>;
|
|
250
|
-
getAll(page?: number, limit?: number): Promise<TModel[]>;
|
|
251
|
-
getAllByUserId(userId: number, page?: number, limit?: number): Promise<TModel[]>;
|
|
252
|
-
getBy(filters: Partial<TRow>): Promise<TModel | null>;
|
|
253
|
-
getAllBy(filters: Partial<TRow>): Promise<TModel[]>;
|
|
254
|
-
insert(model: Omit<TModel, 'id'>): Promise<TModel>;
|
|
255
|
-
update(id: number, updates: Partial<Omit<TModel, 'id' | 'createdAt'>>): Promise<TModel | null>;
|
|
256
|
-
upsert(model: Partial<TModel>): Promise<TModel>;
|
|
257
|
-
softDelete(id: number): Promise<boolean>;
|
|
258
|
-
count(filters?: Partial<TRow>): Promise<number>;
|
|
259
|
-
}`
|
|
260
|
-
};
|
|
119
|
+
{{STORE_CLASS}}
|
|
120
|
+
`;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ModuleConfig } from '../types/configTypes';
|
|
2
|
+
export declare class UseCaseGenerator {
|
|
3
|
+
private availableAggregates;
|
|
4
|
+
private generateUseCaseMethod;
|
|
5
|
+
private generateGetResourceOwnerMethod;
|
|
6
|
+
private generateUseCase;
|
|
7
|
+
generateFromConfig(config: ModuleConfig): Record<string, string>;
|
|
8
|
+
generateFromYamlFile(yamlFilePath: string): Record<string, string>;
|
|
9
|
+
generateAndSaveFiles(yamlFilePath: string, moduleDir: string, opts?: {
|
|
10
|
+
force?: boolean;
|
|
11
|
+
skipOnConflict?: boolean;
|
|
12
|
+
}): Promise<void>;
|
|
13
|
+
}
|