taon 21.0.53 → 21.0.54

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