taon 21.0.53 → 21.0.55

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 (115) hide show
  1. package/bin/taon +5 -5
  2. package/bin/taon-debug +5 -5
  3. package/bin/taon-debug-brk +4 -4
  4. package/browser/package.json +1 -1
  5. package/browser-prod/package.json +1 -1
  6. package/icon-menu-taon.svg +15 -15
  7. package/lib/build-info._auto-generated_.d.ts +1 -1
  8. package/lib/build-info._auto-generated_.js +1 -1
  9. package/lib/package.json +1 -1
  10. package/lib/ui/index.js +2 -2
  11. package/lib/ui/taon-admin-mode-configuration/index.js +2 -2
  12. package/lib-prod/base-classes/base-abstract-entity.js +17 -31
  13. package/lib-prod/base-classes/base-angular-service.js +83 -55
  14. package/lib-prod/base-classes/base-class.js +33 -35
  15. package/lib-prod/base-classes/base-context.js +17 -19
  16. package/lib-prod/base-classes/base-controller.js +146 -154
  17. package/lib-prod/base-classes/base-crud-controller.js +250 -221
  18. package/lib-prod/base-classes/base-custom-repository.js +7 -18
  19. package/lib-prod/base-classes/base-electron-service.js +49 -0
  20. package/lib-prod/base-classes/base-entity.js +20 -30
  21. package/lib-prod/base-classes/base-file-upload.middleware.js +72 -75
  22. package/lib-prod/base-classes/base-injector.js +176 -194
  23. package/lib-prod/base-classes/base-middleware.js +8 -5
  24. package/lib-prod/base-classes/base-migration.js +19 -22
  25. package/lib-prod/base-classes/base-provider.js +7 -5
  26. package/lib-prod/base-classes/base-repository.js +601 -573
  27. package/lib-prod/base-classes/base-subscriber-for-entity.js +143 -152
  28. package/lib-prod/base-classes/base.js +18 -0
  29. package/lib-prod/build-info._auto-generated_.js +26 -14
  30. package/lib-prod/config/controller-config.js +24 -24
  31. package/lib-prod/config/controller-options.js +2 -5
  32. package/lib-prod/config/method-config.js +6 -8
  33. package/lib-prod/config/param-config.js +2 -8
  34. package/lib-prod/constants.js +29 -25
  35. package/lib-prod/context-db-migrations.js +328 -324
  36. package/lib-prod/create-context.js +211 -146
  37. package/lib-prod/decorators/classes/controller-decorator.js +16 -20
  38. package/lib-prod/decorators/classes/entity-decorator.js +26 -47
  39. package/lib-prod/decorators/classes/middleware-decorator.js +14 -24
  40. package/lib-prod/decorators/classes/migration-decorator.js +13 -22
  41. package/lib-prod/decorators/classes/provider-decorator.js +13 -23
  42. package/lib-prod/decorators/classes/repository-decorator.js +13 -22
  43. package/lib-prod/decorators/classes/subscriber-decorator.js +13 -23
  44. package/lib-prod/decorators/decorator-abstract-opt.js +1 -4
  45. package/lib-prod/decorators/http/http-decorators.js +20 -5
  46. package/lib-prod/decorators/http/http-methods-decorators.js +91 -133
  47. package/lib-prod/decorators/http/http-params-decorators.js +36 -62
  48. package/lib-prod/dependency-injection/di-container.js +28 -29
  49. package/lib-prod/endpoint-context-storage.js +27 -32
  50. package/lib-prod/endpoint-context.js +2294 -1930
  51. package/lib-prod/entity-process.js +209 -198
  52. package/lib-prod/env/env.angular-node-app.js +66 -130
  53. package/lib-prod/env/env.docs-webapp.js +66 -130
  54. package/lib-prod/env/env.electron-app.js +66 -130
  55. package/lib-prod/env/env.mobile-app.js +66 -130
  56. package/lib-prod/env/env.npm-lib-and-cli-tool.js +66 -130
  57. package/lib-prod/env/env.vscode-plugin.js +66 -130
  58. package/lib-prod/env/index.js +6 -6
  59. package/lib-prod/express-types.js +1 -0
  60. package/lib-prod/formly/formly.models.js +1 -0
  61. package/lib-prod/formly/fromly.js +196 -175
  62. package/lib-prod/formly/type-from-entity.js +45 -52
  63. package/lib-prod/get-response-value.js +21 -18
  64. package/lib-prod/global-state/taon-global-state/index.js +6 -5
  65. package/lib-prod/global-state/taon-global-state/taon-global-state.abstract.context.js +18 -19
  66. package/lib-prod/global-state/taon-global-state/taon-global-state.constants.js +6 -9
  67. package/lib-prod/global-state/taon-global-state/taon-global-state.controller.js +40 -46
  68. package/lib-prod/global-state/taon-global-state/taon-global-state.entity.js +33 -46
  69. package/lib-prod/global-state/taon-global-state/taon-global-state.middleware.js +10 -20
  70. package/lib-prod/global-state/taon-global-state/taon-global-state.models.js +43 -33
  71. package/lib-prod/global-state/taon-global-state/taon-global-state.provider.js +10 -20
  72. package/lib-prod/global-state/taon-global-state/taon-global-state.repository.js +43 -44
  73. package/lib-prod/global-state/taon-global-state/taon-global-state.subscriber.js +20 -27
  74. package/lib-prod/global-state/taon-global-state/taon-global-state.utils.js +10 -10
  75. package/lib-prod/global-state/taon-transaction-registry/index.js +11 -10
  76. package/lib-prod/global-state/taon-transaction-registry/taon-transaction-registry.abstract.context.js +20 -21
  77. package/lib-prod/global-state/taon-transaction-registry/taon-transaction-registry.constants.js +4 -7
  78. package/lib-prod/global-state/taon-transaction-registry/taon-transaction-registry.controller.js +34 -39
  79. package/lib-prod/global-state/taon-transaction-registry/taon-transaction-registry.entity.js +34 -54
  80. package/lib-prod/global-state/taon-transaction-registry/taon-transaction-registry.middleware.js +10 -20
  81. package/lib-prod/global-state/taon-transaction-registry/taon-transaction-registry.models.js +7 -10
  82. package/lib-prod/global-state/taon-transaction-registry/taon-transaction-registry.provider.js +10 -20
  83. package/lib-prod/global-state/taon-transaction-registry/taon-transaction-registry.repository.js +29 -34
  84. package/lib-prod/global-state/taon-transaction-registry/taon-transaction-registry.subscriber.js +20 -27
  85. package/lib-prod/global-state/taon-transaction-registry/taon-transaction-registry.utils.js +4 -5
  86. package/lib-prod/helpers/class-helpers.js +210 -177
  87. package/lib-prod/helpers/clone-obj.js +16 -20
  88. package/lib-prod/helpers/taon-helpers.js +132 -114
  89. package/lib-prod/index._auto-generated_.js +5 -0
  90. package/lib-prod/index.js +248 -227
  91. package/lib-prod/inject.js +88 -33
  92. package/lib-prod/migrations/index.js +2 -1
  93. package/lib-prod/migrations/migrations_index._auto-generated_.js +3 -0
  94. package/lib-prod/models.js +72 -103
  95. package/lib-prod/orm/columns.js +58 -118
  96. package/lib-prod/orm/index.js +56 -1
  97. package/lib-prod/package.json +1 -1
  98. package/lib-prod/realtime/realtime-client.js +188 -186
  99. package/lib-prod/realtime/realtime-core.js +77 -78
  100. package/lib-prod/realtime/realtime-server.js +225 -240
  101. package/lib-prod/realtime/realtime-strategy/index.js +4 -4
  102. package/lib-prod/realtime/realtime-strategy/realtime-strategy-ipc.js +273 -219
  103. package/lib-prod/realtime/realtime-strategy/realtime-strategy-mock.js +267 -240
  104. package/lib-prod/realtime/realtime-strategy/realtime-strategy-socket-io.js +26 -20
  105. package/lib-prod/realtime/realtime-strategy/realtime-strategy.js +10 -13
  106. package/lib-prod/realtime/realtime-subs-manager.js +82 -90
  107. package/lib-prod/realtime/realtime.models.js +2 -0
  108. package/lib-prod/symbols.js +104 -105
  109. package/lib-prod/ui/index.js +1 -5
  110. package/lib-prod/ui/taon-admin-mode-configuration/index.js +1 -5
  111. package/lib-prod/validators.js +43 -37
  112. package/lib-prod.split-namespaces.json +32 -86
  113. package/package.json +1 -1
  114. package/websql/package.json +1 -1
  115. package/websql-prod/package.json +1 -1
@@ -1,339 +1,343 @@
1
- import { Helpers__NS__throwError, UtilsMigrations__NS__getTimestampFromClassName, UtilsMigrations__NS__isValidTimestamp } from "tnp-core/lib-prod";
2
- import { Models__NS__ClassType } from "./models";
3
- import { ClassHelpers__NS__getName } from "./helpers/class-helpers";
4
- import {
5
- Table,
6
- TableIndex
7
- } from "taon-typeorm/lib-prod";
8
- class ContextDbMigrations {
9
- //#endregion
10
- //#endregion
11
- //#region constructor
12
- constructor(ctx) {
13
- this.ctx = ctx;
14
- }
15
- //#region fields
16
- //#region fields / migration table name
17
- DEFAULT_MIGRATION_TABLE_NAME = "TAON_MIGRATION_META";
18
- //#endregion
19
- //#region fields / migration statuses
20
- MIGRATION_STATUS_COMPLETED = "completed";
21
- MIGRATION_STATUS_PENDING = "pending";
22
- //#endregion
23
- //#region fields / migration table schema
24
- table = new Table({
25
- name: this.DEFAULT_MIGRATION_TABLE_NAME,
26
- columns: [
27
- {
28
- name: "id",
29
- type: "integer",
30
- isPrimary: true,
31
- // Mark it as the primary key
32
- isGenerated: true,
33
- // Enable auto-generation
34
- generationStrategy: "increment"
35
- // Use auto-increment strategy
36
- },
37
- {
38
- name: "name",
39
- type: "varchar",
40
- length: "255",
41
- isUnique: true,
42
- // Ensure the name is unique
43
- isNullable: false
44
- // Ensure this field is required
45
- },
46
- {
47
- // context is a part of name
48
- name: "context",
49
- type: "varchar",
50
- length: "255",
51
- isNullable: false
52
- // Optional context for migrations (e.g., tenant or module name)
53
- },
54
- {
55
- name: "applied_at",
56
- type: "timestamp",
57
- default: "CURRENT_TIMESTAMP",
58
- // Automatically set the timestamp
59
- isNullable: true
60
- },
61
- {
62
- name: "status",
63
- type: "varchar",
64
- length: "50",
65
- default: `'${this.MIGRATION_STATUS_COMPLETED}'`,
66
- isNullable: false
67
- }
68
- // { // TODO not needed for now
69
- // name: 'checksum',
70
- // type: 'varchar',
71
- // length: '64',
72
- // isNullable: true, // Optional field to store a hash/checksum of migration file
73
- // },
74
- ]
75
- });
76
- //#endregion
77
- //#region methods & getters / make sure migration table exists
78
- async ensureMigrationTableExists() {
79
- if (this.ctx.isRemoteHost || !this.ctx.connection) {
80
- return;
1
+ //#region imports
2
+ import { Helpers__NS__throwError, UtilsMigrations__NS__getTimestampFromClassName, UtilsMigrations__NS__isValidTimestamp } from 'tnp-core/lib-prod';
3
+ import { Models__NS__ClassType } from './models';
4
+ import { ClassHelpers__NS__getName } from './helpers/class-helpers';
5
+ import { Table, TableIndex, } from 'taon-typeorm/lib-prod';
6
+ export class ContextDbMigrations {
7
+ //#endregion
8
+ //#endregion
9
+ //#region constructor
10
+ constructor(ctx) {
11
+ this.ctx = ctx;
12
+ //#region fields
13
+ //#region fields / migration table name
14
+ this.DEFAULT_MIGRATION_TABLE_NAME = 'TAON_MIGRATION_META';
15
+ //#endregion
16
+ //#region fields / migration statuses
17
+ this.MIGRATION_STATUS_COMPLETED = 'completed';
18
+ this.MIGRATION_STATUS_PENDING = 'pending';
19
+ //#endregion
20
+ //#region fields / migration table schema
21
+ this.table = new Table({
22
+ name: this.DEFAULT_MIGRATION_TABLE_NAME,
23
+ columns: [
24
+ {
25
+ name: 'id',
26
+ type: 'integer',
27
+ isPrimary: true, // Mark it as the primary key
28
+ isGenerated: true, // Enable auto-generation
29
+ generationStrategy: 'increment', // Use auto-increment strategy
30
+ },
31
+ {
32
+ name: 'name',
33
+ type: 'varchar',
34
+ length: '255',
35
+ isUnique: true, // Ensure the name is unique
36
+ isNullable: false, // Ensure this field is required
37
+ },
38
+ {
39
+ // context is a part of name
40
+ name: 'context',
41
+ type: 'varchar',
42
+ length: '255',
43
+ isNullable: false, // Optional context for migrations (e.g., tenant or module name)
44
+ },
45
+ {
46
+ name: 'applied_at',
47
+ type: 'timestamp',
48
+ default: 'CURRENT_TIMESTAMP', // Automatically set the timestamp
49
+ isNullable: true,
50
+ },
51
+ {
52
+ name: 'status',
53
+ type: 'varchar',
54
+ length: '50',
55
+ default: `'${this.MIGRATION_STATUS_COMPLETED}'`,
56
+ isNullable: false,
57
+ },
58
+ // { // TODO not needed for now
59
+ // name: 'checksum',
60
+ // type: 'varchar',
61
+ // length: '64',
62
+ // isNullable: true, // Optional field to store a hash/checksum of migration file
63
+ // },
64
+ ],
65
+ });
81
66
  }
82
- const queryRunner = this.ctx.connection.createQueryRunner();
83
- await queryRunner.connect();
84
- await queryRunner.startTransaction();
85
- const hasTable = await queryRunner.hasTable(
86
- this.DEFAULT_MIGRATION_TABLE_NAME
87
- );
88
- if (hasTable) {
89
- this.ctx.logMigrations && console.log(
90
- `Table ${this.DEFAULT_MIGRATION_TABLE_NAME} already exists.`
91
- );
92
- await queryRunner.commitTransaction();
93
- await queryRunner.release();
94
- return;
95
- }
96
- try {
97
- await queryRunner.createTable(this.table);
98
- await queryRunner.createIndex(
99
- this.DEFAULT_MIGRATION_TABLE_NAME,
100
- new TableIndex({
101
- name: "IDX_NAME",
102
- columnNames: ["name"]
103
- })
104
- );
105
- await queryRunner.commitTransaction();
106
- } catch (error) {
107
- this.ctx.logMigrations && console.error(
108
- `Transaction failed [ensureMigrationTableExists], rolling back:`,
109
- error
110
- );
111
- await queryRunner.rollbackTransaction();
112
- } finally {
113
- await queryRunner.release();
114
- }
115
- }
116
- //#endregion
117
- //#region methods & getters / revert migration to timestamp
118
- async logSelectALl(name, queryRunner) {
119
- console.log(
120
- name,
121
- (await queryRunner.query(
122
- `SELECT * FROM ${this.DEFAULT_MIGRATION_TABLE_NAME} WHERE context = $1`,
123
- [this.ctx.contextName]
124
- )).map((m) => m.name)
125
- );
126
- }
127
- async revertMigrationToTimestamp(timestamp) {
128
- if (this.ctx.isRemoteHost || !this.ctx.connection) {
129
- return;
130
- }
131
- if (!UtilsMigrations__NS__isValidTimestamp(timestamp)) {
132
- Helpers__NS__throwError(
133
- `Invalid timestamp provided for migration revert: ${timestamp}`
134
- );
135
- }
136
- const migrationsClassFns = this.ctx.getClassFunByArr(Models__NS__ClassType.MIGRATION).reverse();
137
- const migrationClassesInstancesToRevert = migrationsClassFns.map((classFn) => {
138
- const timestampFromClassName = Number(
139
- UtilsMigrations__NS__getTimestampFromClassName(
140
- ClassHelpers__NS__getName(classFn)
141
- )
142
- );
143
- if (timestampFromClassName <= timestamp) {
144
- return null;
145
- }
146
- return this.ctx.getInstanceBy(classFn);
147
- }).filter((f) => !!f).map((f) => f).filter((migrationInstance) => migrationInstance.isReadyToRun());
148
- const queryRunner = this.ctx.connection.createQueryRunner();
149
- await queryRunner.connect();
150
- try {
151
- await queryRunner.startTransaction();
152
- const appliedMigrationsForContext = await queryRunner.query(
153
- `SELECT name FROM ${this.DEFAULT_MIGRATION_TABLE_NAME}
154
- WHERE status = $1 AND context = $2`,
155
- [this.MIGRATION_STATUS_COMPLETED, this.ctx.contextName]
156
- );
157
- const appliedMigrationsForContextNames = appliedMigrationsForContext.map(
158
- (m) => m.name
159
- );
160
- for (const migrationClassInstance of migrationClassesInstancesToRevert) {
161
- const migrationName = ClassHelpers__NS__getName(migrationClassInstance);
162
- if (!appliedMigrationsForContextNames.includes(migrationName)) {
163
- this.ctx.logMigrations && console.warn(
164
- `Skipping migration not marked as applied: ${migrationName}`
165
- );
166
- continue;
67
+ //#endregion
68
+ //#region methods & getters / make sure migration table exists
69
+ async ensureMigrationTableExists() {
70
+ //#region @websqlFunc
71
+ if (this.ctx.isRemoteHost || !this.ctx.connection) {
72
+ return;
73
+ }
74
+ const queryRunner = this.ctx.connection.createQueryRunner();
75
+ await queryRunner.connect();
76
+ await queryRunner.startTransaction();
77
+ // Check if the table already exists
78
+ const hasTable = await queryRunner.hasTable(this.DEFAULT_MIGRATION_TABLE_NAME);
79
+ if (hasTable) {
80
+ this.ctx.logMigrations &&
81
+ console.log(`Table ${this.DEFAULT_MIGRATION_TABLE_NAME} already exists.`);
82
+ await queryRunner.commitTransaction();
83
+ await queryRunner.release();
84
+ return; // Exit early if the table exists
85
+ }
86
+ try {
87
+ await queryRunner.createTable(this.table);
88
+ await queryRunner.createIndex(this.DEFAULT_MIGRATION_TABLE_NAME, new TableIndex({
89
+ name: 'IDX_NAME',
90
+ columnNames: ['name'],
91
+ }));
92
+ await queryRunner.commitTransaction();
167
93
  }
168
- this.ctx.logMigrations && console.log(
169
- `Reverting migration: ${migrationName} , context: ${this.ctx.contextName}`
170
- );
171
- await migrationClassInstance.down(queryRunner);
172
- await queryRunner.query(
173
- `DELETE FROM ${this.DEFAULT_MIGRATION_TABLE_NAME} WHERE name = $1`,
174
- [migrationName]
175
- );
176
- }
177
- await queryRunner.commitTransaction();
178
- this.ctx.logMigrations && console.log(
179
- `Migrations successfully reverted to the specified timestamp ${timestamp} .`
180
- );
181
- } catch (error) {
182
- this.ctx.logMigrations && console.error("Transaction failed, rolling back:", error);
183
- await queryRunner.rollbackTransaction();
184
- } finally {
185
- await queryRunner.release();
94
+ catch (error) {
95
+ this.ctx.logMigrations &&
96
+ console.error(`Transaction failed [ensureMigrationTableExists]` + `, rolling back:`, error);
97
+ await queryRunner.rollbackTransaction();
98
+ }
99
+ finally {
100
+ await queryRunner.release();
101
+ }
102
+ //#endregion
186
103
  }
187
- }
188
- //#endregion
189
- //#region methods & getters / clear migration table
190
- async clearMigrationTable() {
191
- if (this.ctx.isRemoteHost || !this.ctx.connection) {
192
- return;
104
+ //#endregion
105
+ //#region methods & getters / revert migration to timestamp
106
+ async logSelectALl(name, queryRunner) {
107
+ console.log(name, (await queryRunner.query(`SELECT * FROM ${this.DEFAULT_MIGRATION_TABLE_NAME} WHERE context = $1`, [this.ctx.contextName])).map(m => m.name));
193
108
  }
194
- const queryRunner = this.ctx.connection.createQueryRunner();
195
- await queryRunner.connect();
196
- await queryRunner.startTransaction();
197
- try {
198
- await queryRunner.clearTable(this.DEFAULT_MIGRATION_TABLE_NAME);
199
- await queryRunner.commitTransaction();
200
- } catch (error) {
201
- this.ctx.logMigrations && console.error("Transaction failed, rolling back:", error);
202
- await queryRunner.rollbackTransaction();
203
- } finally {
204
- await queryRunner.release();
109
+ async revertMigrationToTimestamp(timestamp) {
110
+ //#region @websqlFunc
111
+ if (this.ctx.isRemoteHost || !this.ctx.connection) {
112
+ return;
113
+ }
114
+ if (!UtilsMigrations__NS__isValidTimestamp(timestamp)) {
115
+ Helpers__NS__throwError(`Invalid timestamp provided for migration revert: ${timestamp}`);
116
+ }
117
+ // Get all migration class functions and reverse the order
118
+ const migrationsClassFns = this.ctx
119
+ .getClassFunByArr(Models__NS__ClassType.MIGRATION)
120
+ .reverse();
121
+ // Filter migrations that need to be reverted
122
+ const migrationClassesInstancesToRevert = migrationsClassFns
123
+ .map(classFn => {
124
+ const timestampFromClassName = Number(UtilsMigrations__NS__getTimestampFromClassName(ClassHelpers__NS__getName(classFn)));
125
+ if (timestampFromClassName <= timestamp) {
126
+ // this.ctx.logMigrations &&
127
+ // console.log(
128
+ // `Stopping migration filter at: ${ClassHelpers__NS__getName(classFn)} ` +
129
+ // `with timestamp ${timestampFromClassName}`,
130
+ // );
131
+ return null;
132
+ }
133
+ return this.ctx.getInstanceBy(classFn);
134
+ })
135
+ .filter(f => !!f)
136
+ .map(f => f)
137
+ .filter(migrationInstance => migrationInstance.isReadyToRun());
138
+ const queryRunner = this.ctx.connection.createQueryRunner();
139
+ await queryRunner.connect();
140
+ try {
141
+ await queryRunner.startTransaction();
142
+ // Fetch applied migrations from the database
143
+ const appliedMigrationsForContext = await queryRunner.query(`SELECT name FROM ${this.DEFAULT_MIGRATION_TABLE_NAME}
144
+ WHERE status = $1 AND context = $2`, [this.MIGRATION_STATUS_COMPLETED, this.ctx.contextName]);
145
+ const appliedMigrationsForContextNames = appliedMigrationsForContext.map(m => m.name);
146
+ // console.log({ appliedMigrationsForContextNames });
147
+ for (const migrationClassInstance of migrationClassesInstancesToRevert) {
148
+ const migrationName = ClassHelpers__NS__getName(migrationClassInstance);
149
+ if (!appliedMigrationsForContextNames.includes(migrationName)) {
150
+ this.ctx.logMigrations &&
151
+ console.warn(`Skipping migration not marked as applied: ${migrationName}`);
152
+ continue;
153
+ }
154
+ this.ctx.logMigrations &&
155
+ console.log(`Reverting migration: ${migrationName} , context: ${this.ctx.contextName}`);
156
+ await migrationClassInstance.down(queryRunner);
157
+ // Remove the reverted migration from the tracking table
158
+ await queryRunner.query(`DELETE FROM ${this.DEFAULT_MIGRATION_TABLE_NAME} WHERE name = $1`, [migrationName]);
159
+ }
160
+ await queryRunner.commitTransaction();
161
+ this.ctx.logMigrations &&
162
+ console.log(`Migrations successfully reverted ` +
163
+ `to the specified timestamp ${timestamp} .`);
164
+ }
165
+ catch (error) {
166
+ this.ctx.logMigrations &&
167
+ console.error('Transaction failed, rolling back:', error);
168
+ await queryRunner.rollbackTransaction();
169
+ }
170
+ finally {
171
+ await queryRunner.release();
172
+ }
173
+ //#endregion
205
174
  }
206
- }
207
- //#endregion
208
- //#region methods & getters / mark all migrations as applied
209
- async markAllMigrationsAsApplied() {
210
- if (this.ctx.isRemoteHost || !this.ctx.connection) {
211
- return;
175
+ //#endregion
176
+ //#region methods & getters / clear migration table
177
+ async clearMigrationTable() {
178
+ //#region @websqlFunc
179
+ if (this.ctx.isRemoteHost || !this.ctx.connection) {
180
+ return;
181
+ }
182
+ const queryRunner = this.ctx.connection.createQueryRunner();
183
+ await queryRunner.connect();
184
+ await queryRunner.startTransaction();
185
+ try {
186
+ await queryRunner.clearTable(this.DEFAULT_MIGRATION_TABLE_NAME);
187
+ await queryRunner.commitTransaction();
188
+ }
189
+ catch (error) {
190
+ this.ctx.logMigrations &&
191
+ console.error('Transaction failed, rolling back:', error);
192
+ await queryRunner.rollbackTransaction();
193
+ }
194
+ finally {
195
+ await queryRunner.release();
196
+ }
197
+ //#endregion
212
198
  }
213
- const migrationsClassFns = this.ctx.getClassFunByArr(
214
- Models__NS__ClassType.MIGRATION
215
- );
216
- const migrationClassesInstances = migrationsClassFns.map((classFn) => this.ctx.getInstanceBy(classFn)).map((f) => f).filter((migrationInstance) => migrationInstance.isReadyToRun());
217
- const queryRunner = this.ctx.connection.createQueryRunner();
218
- await queryRunner.connect();
219
- try {
220
- await queryRunner.startTransaction();
221
- const allMigrationsInDb = await queryRunner.query(
222
- `SELECT name FROM ${this.DEFAULT_MIGRATION_TABLE_NAME}`
223
- );
224
- const allMigrationInDBNames = allMigrationsInDb.map((m) => m.name);
225
- for (const instance of migrationClassesInstances) {
226
- const migrationName = ClassHelpers__NS__getName(instance);
227
- if (allMigrationInDBNames.includes(migrationName)) {
228
- this.ctx.logMigrations && console.log(`Skipping already applied migration: ${migrationName}`);
229
- continue;
199
+ //#endregion
200
+ //#region methods & getters / mark all migrations as applied
201
+ async markAllMigrationsAsApplied() {
202
+ //#region @websqlFunc
203
+ if (this.ctx.isRemoteHost || !this.ctx.connection) {
204
+ return;
230
205
  }
231
- this.ctx.logMigrations && console.log(`Marking migration as applied: ${migrationName}`);
232
- await queryRunner.query(
233
- `INSERT INTO ${this.DEFAULT_MIGRATION_TABLE_NAME} (name, status, context, applied_at) VALUES ($1, $2, $3, CURRENT_TIMESTAMP)`,
234
- [
235
- migrationName,
236
- this.MIGRATION_STATUS_COMPLETED,
237
- instance.ctx.contextName
238
- ]
239
- );
240
- }
241
- await queryRunner.query(
242
- `UPDATE ${this.DEFAULT_MIGRATION_TABLE_NAME}
206
+ const migrationsClassFns = this.ctx.getClassFunByArr(Models__NS__ClassType.MIGRATION);
207
+ const migrationClassesInstances = migrationsClassFns
208
+ .map(classFn => this.ctx.getInstanceBy(classFn))
209
+ .map(f => f)
210
+ .filter(migrationInstance => migrationInstance.isReadyToRun());
211
+ const queryRunner = this.ctx.connection.createQueryRunner();
212
+ await queryRunner.connect();
213
+ try {
214
+ await queryRunner.startTransaction();
215
+ // Fetch already applied migrations from the database
216
+ const allMigrationsInDb = await queryRunner.query(`SELECT name FROM ${this.DEFAULT_MIGRATION_TABLE_NAME}`);
217
+ const allMigrationInDBNames = allMigrationsInDb.map(m => m.name);
218
+ for (const instance of migrationClassesInstances) {
219
+ const migrationName = ClassHelpers__NS__getName(instance);
220
+ if (allMigrationInDBNames.includes(migrationName)) {
221
+ this.ctx.logMigrations &&
222
+ console.log(`Skipping already applied migration: ${migrationName}`);
223
+ continue;
224
+ }
225
+ this.ctx.logMigrations &&
226
+ console.log(`Marking migration as applied: ${migrationName}`);
227
+ // Insert migration as 'complete' without running
228
+ await queryRunner.query(`INSERT INTO ${this.DEFAULT_MIGRATION_TABLE_NAME} (name, status, context, applied_at) ` +
229
+ `VALUES ($1, $2, $3, CURRENT_TIMESTAMP)`, [
230
+ migrationName,
231
+ this.MIGRATION_STATUS_COMPLETED,
232
+ instance.ctx.contextName,
233
+ ]);
234
+ }
235
+ // update all pending migrations to completed
236
+ await queryRunner.query(`UPDATE ${this.DEFAULT_MIGRATION_TABLE_NAME}
243
237
  SET status = $1, applied_at = CURRENT_TIMESTAMP
244
- WHERE status = $2`,
245
- [this.MIGRATION_STATUS_COMPLETED, this.MIGRATION_STATUS_PENDING]
246
- );
247
- await queryRunner.commitTransaction();
248
- this.ctx.logMigrations && console.log("All migrations marked as applied.");
249
- } catch (error) {
250
- this.ctx.logMigrations && console.error(
251
- "Failed to mark all migrations as applied, rolling back:",
252
- error
253
- );
254
- await queryRunner.rollbackTransaction();
255
- } finally {
256
- await queryRunner.release();
257
- }
258
- }
259
- //#endregion
260
- //#region methods & getters / run all migrations
261
- async runAllNotCompletedMigrations() {
262
- if (this.ctx.isRemoteHost || !this.ctx.connection) {
263
- return;
238
+ WHERE status = $2`, [this.MIGRATION_STATUS_COMPLETED, this.MIGRATION_STATUS_PENDING]);
239
+ await queryRunner.commitTransaction();
240
+ this.ctx.logMigrations &&
241
+ console.log('All migrations marked as applied.');
242
+ }
243
+ catch (error) {
244
+ this.ctx.logMigrations &&
245
+ console.error('Failed to mark all migrations as applied, rolling back:', error);
246
+ await queryRunner.rollbackTransaction();
247
+ }
248
+ finally {
249
+ await queryRunner.release();
250
+ }
251
+ //#endregion
264
252
  }
265
- const migrationsClassFns = this.ctx.getClassFunByArr(
266
- Models__NS__ClassType.MIGRATION
267
- );
268
- const migrationClassesInstances = migrationsClassFns.map((classFn) => this.ctx.getInstanceBy(classFn)).map((f) => f).filter((migrationInstance) => migrationInstance.isReadyToRun());
269
- const queryRunner = this.ctx.connection.createQueryRunner();
270
- await queryRunner.connect();
271
- try {
272
- await queryRunner.startTransaction();
273
- const appliedMigrationsForContext = await queryRunner.query(
274
- `SELECT name, status FROM ${this.DEFAULT_MIGRATION_TABLE_NAME} WHERE context = $1`,
275
- [this.ctx.contextName]
276
- );
277
- const pendingMigrationsForContext = appliedMigrationsForContext.filter(
278
- (m) => m.status === this.MIGRATION_STATUS_PENDING
279
- );
280
- for (const pendingContextMigration of pendingMigrationsForContext) {
281
- const migrationInstance = migrationClassesInstances.find(
282
- (instance) => ClassHelpers__NS__getName(instance) === pendingContextMigration.name
283
- );
284
- if (!migrationInstance) {
285
- this.ctx.logMigrations && console.warn(
286
- `Pending migration ${pendingContextMigration.name} not found in loaded migrations.`
287
- );
288
- continue;
253
+ //#endregion
254
+ //#region methods & getters / run all migrations
255
+ async runAllNotCompletedMigrations() {
256
+ //#region @websqlFunc
257
+ if (this.ctx.isRemoteHost || !this.ctx.connection) {
258
+ return;
289
259
  }
290
- this.ctx.logMigrations && console.log(
291
- `Completing pending migration: ${pendingContextMigration.name}`
292
- );
293
- await migrationInstance.up(queryRunner);
294
- await queryRunner.query(
295
- `UPDATE ${this.DEFAULT_MIGRATION_TABLE_NAME}
260
+ const migrationsClassFns = this.ctx.getClassFunByArr(Models__NS__ClassType.MIGRATION);
261
+ // console.log({
262
+ // migrationClassesALl: migrationsClassFns.map(f => ClassHelpers__NS__getName(f)),
263
+ // });
264
+ const migrationClassesInstances = migrationsClassFns
265
+ .map(classFn => this.ctx.getInstanceBy(classFn))
266
+ .map(f => f)
267
+ .filter(migrationInstance => migrationInstance.isReadyToRun());
268
+ // console.log({
269
+ // migrationClassesInstances: migrationsClassFns.map(f =>
270
+ // ClassHelpers__NS__getName(f),
271
+ // ),
272
+ // });
273
+ const queryRunner = this.ctx.connection.createQueryRunner();
274
+ await queryRunner.connect();
275
+ try {
276
+ await queryRunner.startTransaction();
277
+ // Check if the migrations table exists
278
+ // TODO: Implement check for migrations table existence here
279
+ // Fetch applied migrations from the database
280
+ const appliedMigrationsForContext = await queryRunner.query(`SELECT name, status FROM ${this.DEFAULT_MIGRATION_TABLE_NAME} ` +
281
+ `WHERE context = $1`, [this.ctx.contextName]);
282
+ //#region check and update pending migrations
283
+ const pendingMigrationsForContext = appliedMigrationsForContext.filter(m => m.status === this.MIGRATION_STATUS_PENDING);
284
+ // Run pending migrations first
285
+ for (const pendingContextMigration of pendingMigrationsForContext) {
286
+ const migrationInstance = migrationClassesInstances.find(instance => ClassHelpers__NS__getName(instance) === pendingContextMigration.name);
287
+ if (!migrationInstance) {
288
+ this.ctx.logMigrations &&
289
+ console.warn(`Pending migration ${pendingContextMigration.name} not found in loaded migrations.`);
290
+ continue;
291
+ }
292
+ this.ctx.logMigrations &&
293
+ console.log(`Completing pending migration: ${pendingContextMigration.name}`);
294
+ await migrationInstance.up(queryRunner);
295
+ // Update migration status to 'complete'
296
+ await queryRunner.query(`UPDATE ${this.DEFAULT_MIGRATION_TABLE_NAME}
296
297
  SET status = $1, applied_at = CURRENT_TIMESTAMP
297
- WHERE name = $2`,
298
- [this.MIGRATION_STATUS_COMPLETED, pendingContextMigration.name]
299
- );
300
- }
301
- for (const instance of migrationClassesInstances) {
302
- const migrationName = ClassHelpers__NS__getName(instance);
303
- if (appliedMigrationsForContext.some((m) => m.name === migrationName)) {
304
- this.ctx.logMigrations && console.log(`Skipping already applied migration: ${migrationName}`);
305
- continue;
298
+ WHERE name = $2`, [this.MIGRATION_STATUS_COMPLETED, pendingContextMigration.name]);
299
+ }
300
+ //#endregion
301
+ //#region run new migrations
302
+ for (const instance of migrationClassesInstances) {
303
+ const migrationName = ClassHelpers__NS__getName(instance);
304
+ if (appliedMigrationsForContext.some(m => m.name === migrationName)) {
305
+ this.ctx.logMigrations &&
306
+ console.log(`Skipping already applied migration: ${migrationName}`);
307
+ continue;
308
+ }
309
+ this.ctx.logMigrations &&
310
+ console.log(`Applying new migration: ${migrationName}`);
311
+ // Insert migration as 'pending' before execution
312
+ await queryRunner.query(`INSERT INTO ${this.DEFAULT_MIGRATION_TABLE_NAME} (name, status, context, applied_at) ` +
313
+ `VALUES ($1, $2, $3, NULL)`, [migrationName, this.MIGRATION_STATUS_PENDING, this.ctx.contextName]);
314
+ try {
315
+ // Apply migration
316
+ await instance.up(queryRunner);
317
+ // Update migration to 'complete' after successful execution
318
+ await queryRunner.query(`UPDATE ${this.DEFAULT_MIGRATION_TABLE_NAME} ` +
319
+ `SET status = '${this.MIGRATION_STATUS_COMPLETED}', applied_at = CURRENT_TIMESTAMP ` +
320
+ `WHERE name = $1`, [migrationName]);
321
+ }
322
+ catch (error) {
323
+ this.ctx.logMigrations &&
324
+ console.error(`Failed to apply migration: ${migrationName}`, error);
325
+ // Rollback pending migration entry
326
+ await queryRunner.query(`DELETE FROM ${this.DEFAULT_MIGRATION_TABLE_NAME} WHERE name = $1`, [migrationName]);
327
+ throw error; // Rethrow to ensure the transaction is rolled back
328
+ }
329
+ }
330
+ //#endregion
331
+ await queryRunner.commitTransaction();
306
332
  }
307
- this.ctx.logMigrations && console.log(`Applying new migration: ${migrationName}`);
308
- await queryRunner.query(
309
- `INSERT INTO ${this.DEFAULT_MIGRATION_TABLE_NAME} (name, status, context, applied_at) VALUES ($1, $2, $3, NULL)`,
310
- [migrationName, this.MIGRATION_STATUS_PENDING, this.ctx.contextName]
311
- );
312
- try {
313
- await instance.up(queryRunner);
314
- await queryRunner.query(
315
- `UPDATE ${this.DEFAULT_MIGRATION_TABLE_NAME} SET status = '${this.MIGRATION_STATUS_COMPLETED}', applied_at = CURRENT_TIMESTAMP WHERE name = $1`,
316
- [migrationName]
317
- );
318
- } catch (error) {
319
- this.ctx.logMigrations && console.error(`Failed to apply migration: ${migrationName}`, error);
320
- await queryRunner.query(
321
- `DELETE FROM ${this.DEFAULT_MIGRATION_TABLE_NAME} WHERE name = $1`,
322
- [migrationName]
323
- );
324
- throw error;
333
+ catch (error) {
334
+ this.ctx.logMigrations &&
335
+ console.error('Transaction failed, rolling back:', error);
336
+ await queryRunner.rollbackTransaction();
337
+ }
338
+ finally {
339
+ await queryRunner.release();
325
340
  }
326
- }
327
- await queryRunner.commitTransaction();
328
- } catch (error) {
329
- this.ctx.logMigrations && console.error("Transaction failed, rolling back:", error);
330
- await queryRunner.rollbackTransaction();
331
- } finally {
332
- await queryRunner.release();
341
+ //#endregion
333
342
  }
334
- }
335
- //#endregion
336
343
  }
337
- export {
338
- ContextDbMigrations
339
- };