@flusys/nestjs-entity-builder 9.1.0-rc.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.
Files changed (115) hide show
  1. package/README.md +103 -0
  2. package/config/entity-builder.constants.d.ts +6 -0
  3. package/config/event-actions.d.ts +8 -0
  4. package/config/index.d.ts +3 -0
  5. package/config/message-keys.d.ts +481 -0
  6. package/controllers/entity-definition.controller.d.ts +40 -0
  7. package/controllers/field-definition.controller.d.ts +22 -0
  8. package/controllers/flow-api-key.controller.d.ts +14 -0
  9. package/controllers/flow-definition.controller.d.ts +45 -0
  10. package/controllers/flow-execution.controller.d.ts +21 -0
  11. package/controllers/flow-runtime.controller.d.ts +16 -0
  12. package/controllers/index.d.ts +6 -0
  13. package/docs/entity-builder-swagger.config.d.ts +3 -0
  14. package/docs/index.d.ts +1 -0
  15. package/dtos/entity-definition.dto.d.ts +58 -0
  16. package/dtos/field-definition.dto.d.ts +42 -0
  17. package/dtos/flow.dto.d.ts +85 -0
  18. package/dtos/index.d.ts +3 -0
  19. package/dtos/schema-change.dto.d.ts +53 -0
  20. package/entities/entity-definition.entity.d.ts +15 -0
  21. package/entities/field-definition.entity.d.ts +23 -0
  22. package/entities/flow-api-key.entity.d.ts +10 -0
  23. package/entities/flow-definition.entity.d.ts +20 -0
  24. package/entities/flow-execution.entity.d.ts +18 -0
  25. package/entities/index.d.ts +14 -0
  26. package/entities/schema-change-log.entity.d.ts +15 -0
  27. package/enums/ddl-operation.enum.d.ts +13 -0
  28. package/enums/entity-status.enum.d.ts +5 -0
  29. package/enums/field-type.enum.d.ts +15 -0
  30. package/enums/index.d.ts +3 -0
  31. package/fesm/21.js +515 -0
  32. package/fesm/362.js +1074 -0
  33. package/fesm/489.js +1238 -0
  34. package/fesm/606.js +1655 -0
  35. package/fesm/719.js +3615 -0
  36. package/fesm/794.js +1050 -0
  37. package/fesm/996.js +6537 -0
  38. package/fesm/config/index.js +126 -0
  39. package/fesm/controllers/index.js +28 -0
  40. package/fesm/docs/index.js +82 -0
  41. package/fesm/dtos/index.js +327 -0
  42. package/fesm/entities/index.js +18 -0
  43. package/fesm/enums/index.js +97 -0
  44. package/fesm/guards/index.js +228 -0
  45. package/fesm/index.js +1125 -0
  46. package/fesm/interfaces/index.js +80 -0
  47. package/fesm/modules/index.js +642 -0
  48. package/fesm/rule-engine/index.js +21 -0
  49. package/fesm/runtime.js +85 -0
  50. package/fesm/services/index.js +495 -0
  51. package/flow-engine/flow-api-key.d.ts +10 -0
  52. package/flow-engine/flow-code-sandbox.d.ts +5 -0
  53. package/flow-engine/flow-engine.d.ts +22 -0
  54. package/flow-engine/flow-graph.validator.d.ts +19 -0
  55. package/flow-engine/flow-http.client.d.ts +15 -0
  56. package/flow-engine/flow-input.validator.d.ts +7 -0
  57. package/flow-engine/flow-node-handlers.d.ts +5 -0
  58. package/flow-engine/flow-rate-limiter.d.ts +8 -0
  59. package/flow-engine/flow-reference.d.ts +7 -0
  60. package/flow-engine/flow-run.types.d.ts +120 -0
  61. package/flow-engine/flow.errors.d.ts +27 -0
  62. package/flow-engine/flow.types.d.ts +217 -0
  63. package/flow-engine/index.d.ts +4 -0
  64. package/flow-engine/redact.d.ts +3 -0
  65. package/flow-engine/ssrf-guard.d.ts +6 -0
  66. package/guards/flow-access.guard.d.ts +11 -0
  67. package/guards/index.d.ts +1 -0
  68. package/index.d.ts +11 -0
  69. package/interfaces/entity-builder-module.interface.d.ts +28 -0
  70. package/interfaces/field-definition.interface.d.ts +33 -0
  71. package/interfaces/flow-definition.interface.d.ts +20 -0
  72. package/interfaces/generic-record.interface.d.ts +15 -0
  73. package/interfaces/index.d.ts +5 -0
  74. package/interfaces/reference-provider.interface.d.ts +8 -0
  75. package/interfaces/schema-dialect-adapter.interface.d.ts +15 -0
  76. package/modules/entity-builder.module.d.ts +10 -0
  77. package/modules/index.d.ts +1 -0
  78. package/package.json +93 -0
  79. package/rule-engine/index.d.ts +3 -0
  80. package/rule-engine/rule-engine.service.d.ts +39 -0
  81. package/rule-engine/rule-evaluation-context.interface.d.ts +28 -0
  82. package/rule-engine/rule-ip.d.ts +3 -0
  83. package/rule-engine/rule-permission.d.ts +10 -0
  84. package/rule-engine/rule-regex.d.ts +4 -0
  85. package/rule-engine/rule-values.d.ts +5 -0
  86. package/rule-engine/rule.interface.d.ts +79 -0
  87. package/services/database-error.mapper.d.ts +2 -0
  88. package/services/definition-cache.service.d.ts +8 -0
  89. package/services/entity-builder-config.service.d.ts +12 -0
  90. package/services/entity-builder-datasource.provider.d.ts +24 -0
  91. package/services/entity-definition.service.d.ts +17 -0
  92. package/services/entity-flow-scaffold.d.ts +26 -0
  93. package/services/entity-permission.service.d.ts +8 -0
  94. package/services/field-definition.service.d.ts +17 -0
  95. package/services/field-type-conversion.d.ts +15 -0
  96. package/services/field-value-validator.d.ts +17 -0
  97. package/services/flow-api-key.service.d.ts +31 -0
  98. package/services/flow-definition.service.d.ts +49 -0
  99. package/services/flow-execution.service.d.ts +37 -0
  100. package/services/flow-executor.service.d.ts +40 -0
  101. package/services/flow-reference.provider.d.ts +13 -0
  102. package/services/flow-runtime.service.d.ts +29 -0
  103. package/services/generic-entity-service.factory.d.ts +12 -0
  104. package/services/generic-entity.service.d.ts +67 -0
  105. package/services/identifier-rules.d.ts +9 -0
  106. package/services/index.d.ts +27 -0
  107. package/services/reference-rewrite.d.ts +7 -0
  108. package/services/reference-scanner.service.d.ts +10 -0
  109. package/services/schema-change-executor.service.d.ts +39 -0
  110. package/services/schema-change.types.d.ts +59 -0
  111. package/services/schema-columns.d.ts +26 -0
  112. package/services/schema-dialect-adapter.service.d.ts +13 -0
  113. package/services/schema-evolution.service.d.ts +67 -0
  114. package/services/schema-registry.service.d.ts +13 -0
  115. package/services/schema-sync.service.d.ts +28 -0
package/fesm/719.js ADDED
@@ -0,0 +1,3615 @@
1
+ export const __rspack_esm_id = 719;
2
+ export const __rspack_esm_ids = [719];
3
+ export const __webpack_modules__ = {
4
+ 2492(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
5
+ const FLOW_REFERENCE_PROVIDER = 'FLOW_REFERENCE_PROVIDER';
6
+
7
+ __webpack_require__.d(__webpack_exports__, {
8
+ }, {
9
+ $: FLOW_REFERENCE_PROVIDER
10
+ });
11
+
12
+
13
+ },
14
+ 2931(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
15
+ /* import */ var _flusys_nestjs_shared_classes__rspack_import_0 = __webpack_require__(6937);
16
+ /* import */ var _flusys_nestjs_shared_modules__rspack_import_1 = __webpack_require__(1236);
17
+ /* import */ var _nestjs_common__rspack_import_2 = __webpack_require__(6157);
18
+ /* import */ var _config_event_actions_js__rspack_import_3 = __webpack_require__(982);
19
+ function _ts_decorate(decorators, target, key, desc) {
20
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
21
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
22
+ r = Reflect.decorate(decorators, target, key, desc);
23
+ } else {
24
+ for(var i = decorators.length - 1; i >= 0; i--){
25
+ if (d = decorators[i]) {
26
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
27
+ }
28
+ }
29
+ }
30
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
31
+ }
32
+ function _ts_metadata(metadataKey, metadataValue) {
33
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
34
+ return Reflect.metadata(metadataKey, metadataValue);
35
+ }
36
+ }
37
+ function _ts_param(paramIndex, decorator) {
38
+ return function(target, key) {
39
+ decorator(target, key, paramIndex);
40
+ };
41
+ }
42
+
43
+
44
+
45
+
46
+ /** Every cached definition list/get. Schema changes write these rows inside a transaction, past the cached services. */ const CACHED_DEFINITIONS = [
47
+ _config_event_actions_js__rspack_import_3/* .ENTITY_BUILDER_EVENT_ENTITIES.ENTITY_DEFINITION */.P.ENTITY_DEFINITION,
48
+ _config_event_actions_js__rspack_import_3/* .ENTITY_BUILDER_EVENT_ENTITIES.FIELD_DEFINITION */.P.FIELD_DEFINITION,
49
+ _config_event_actions_js__rspack_import_3/* .ENTITY_BUILDER_EVENT_ENTITIES.FLOW_DEFINITION */.P.FLOW_DEFINITION
50
+ ];
51
+ class DefinitionCacheService {
52
+ cacheManager;
53
+ utilsService;
54
+ constructor(cacheManager, utilsService){
55
+ this.cacheManager = cacheManager;
56
+ this.utilsService = utilsService;
57
+ }
58
+ /** `tenantId` is the tenant whose definitions changed (see `cacheTenantId`); caches are keyed per tenant. */ async clearAll(tenantId) {
59
+ await Promise.all(CACHED_DEFINITIONS.map((name)=>this.utilsService.clearCache(name, this.cacheManager, undefined, tenantId)));
60
+ }
61
+ }
62
+ DefinitionCacheService = _ts_decorate([
63
+ (0,_nestjs_common__rspack_import_2.Injectable)(),
64
+ _ts_param(0, (0,_nestjs_common__rspack_import_2.Inject)('CACHE_INSTANCE')),
65
+ _ts_param(1, (0,_nestjs_common__rspack_import_2.Inject)(_flusys_nestjs_shared_modules__rspack_import_1.UtilsService)),
66
+ _ts_metadata("design:type", Function),
67
+ _ts_metadata("design:paramtypes", [
68
+ typeof _flusys_nestjs_shared_classes__rspack_import_0.HybridCache === "undefined" ? Object : _flusys_nestjs_shared_classes__rspack_import_0.HybridCache,
69
+ typeof _flusys_nestjs_shared_modules__rspack_import_1.UtilsService === "undefined" ? Object : _flusys_nestjs_shared_modules__rspack_import_1.UtilsService
70
+ ])
71
+ ], DefinitionCacheService);
72
+
73
+ __webpack_require__.d(__webpack_exports__, {
74
+ V: () => (DefinitionCacheService)
75
+ });
76
+
77
+
78
+ },
79
+ 1296(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
80
+ /* import */ var _flusys_nestjs_shared_classes__rspack_import_0 = __webpack_require__(6937);
81
+ /* import */ var _flusys_nestjs_shared_modules__rspack_import_1 = __webpack_require__(1236);
82
+ /* import */ var _nestjs_common__rspack_import_2 = __webpack_require__(6157);
83
+ /* import */ var _config_event_actions_js__rspack_import_5 = __webpack_require__(982);
84
+ /* import */ var _entities_entity_definition_entity_js__rspack_import_3 = __webpack_require__(3189);
85
+ /* import */ var _entity_builder_datasource_provider_js__rspack_import_4 = __webpack_require__(424);
86
+ function _ts_decorate(decorators, target, key, desc) {
87
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
88
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
89
+ r = Reflect.decorate(decorators, target, key, desc);
90
+ } else {
91
+ for(var i = decorators.length - 1; i >= 0; i--){
92
+ if (d = decorators[i]) {
93
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
94
+ }
95
+ }
96
+ }
97
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
98
+ }
99
+ function _ts_metadata(metadataKey, metadataValue) {
100
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
101
+ return Reflect.metadata(metadataKey, metadataValue);
102
+ }
103
+ }
104
+ function _ts_param(paramIndex, decorator) {
105
+ return function(target, key) {
106
+ decorator(target, key, paramIndex);
107
+ };
108
+ }
109
+
110
+
111
+
112
+
113
+
114
+
115
+ class EntityDefinitionService extends _flusys_nestjs_shared_classes__rspack_import_0.ApiService {
116
+ cacheManager;
117
+ utilsService;
118
+ constructor(cacheManager, utilsService, dataSourceProvider){
119
+ super(_config_event_actions_js__rspack_import_5/* .ENTITY_BUILDER_EVENT_ENTITIES.ENTITY_DEFINITION */.P.ENTITY_DEFINITION, cacheManager, utilsService, EntityDefinitionService.name, true, _config_event_actions_js__rspack_import_5/* .ENTITY_BUILDER_EVENT_MODULE */.S, dataSourceProvider, _entities_entity_definition_entity_js__rspack_import_3/* .EntityDefinition */.f), this.cacheManager = cacheManager, this.utilsService = utilsService;
120
+ }
121
+ // Schema changes send the loaded `updatedAt` back as `expectedUpdatedAt`; Identity hides it by default.
122
+ async getSelectQuery(query, user, select) {
123
+ const result = await super.getSelectQuery(query, user, select);
124
+ result.query.addSelect(`${this.entityName}.updatedAt`);
125
+ return result;
126
+ }
127
+ }
128
+ EntityDefinitionService = _ts_decorate([
129
+ (0,_nestjs_common__rspack_import_2.Injectable)({
130
+ scope: _nestjs_common__rspack_import_2.Scope.REQUEST
131
+ }),
132
+ _ts_param(0, (0,_nestjs_common__rspack_import_2.Inject)('CACHE_INSTANCE')),
133
+ _ts_param(1, (0,_nestjs_common__rspack_import_2.Inject)(_flusys_nestjs_shared_modules__rspack_import_1.UtilsService)),
134
+ _ts_param(2, (0,_nestjs_common__rspack_import_2.Inject)(_entity_builder_datasource_provider_js__rspack_import_4/* .EntityBuilderDataSourceProvider */.D)),
135
+ _ts_metadata("design:type", Function),
136
+ _ts_metadata("design:paramtypes", [
137
+ typeof _flusys_nestjs_shared_classes__rspack_import_0.HybridCache === "undefined" ? Object : _flusys_nestjs_shared_classes__rspack_import_0.HybridCache,
138
+ typeof _flusys_nestjs_shared_modules__rspack_import_1.UtilsService === "undefined" ? Object : _flusys_nestjs_shared_modules__rspack_import_1.UtilsService,
139
+ typeof _entity_builder_datasource_provider_js__rspack_import_4/* .EntityBuilderDataSourceProvider */.D === "undefined" ? Object : _entity_builder_datasource_provider_js__rspack_import_4/* .EntityBuilderDataSourceProvider */.D
140
+ ])
141
+ ], EntityDefinitionService);
142
+
143
+ __webpack_require__.d(__webpack_exports__, {
144
+ o: () => (EntityDefinitionService)
145
+ });
146
+
147
+
148
+ },
149
+ 8271(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
150
+ /* import */ var _config_message_keys_js__rspack_import_2 = __webpack_require__(5732);
151
+ /* import */ var _enums_field_type_enum_js__rspack_import_1 = __webpack_require__(9614);
152
+ /* import */ var _flow_engine_flow_types_js__rspack_import_0 = __webpack_require__(6256);
153
+
154
+
155
+
156
+ const SLUG_SUFFIX = {
157
+ insert: 'insert',
158
+ insertMany: 'insert-many',
159
+ getById: 'get-by-id',
160
+ getByIds: 'get-by-ids',
161
+ getAll: 'get-all',
162
+ getByFilter: 'get-by-filter',
163
+ update: 'update',
164
+ updateMany: 'update-many',
165
+ bulkUpsert: 'bulk-upsert',
166
+ delete: 'delete'
167
+ };
168
+ const DEFAULT_FLOW_NAME = {
169
+ insert: 'Insert',
170
+ insertMany: 'Insert many',
171
+ getById: 'Get by id',
172
+ getByIds: 'Get by ids',
173
+ getAll: 'Get all',
174
+ getByFilter: 'Get by filter',
175
+ update: 'Update',
176
+ updateMany: 'Update many',
177
+ bulkUpsert: 'Bulk upsert',
178
+ delete: 'Delete'
179
+ };
180
+ const DEFAULT_INPUT_LABEL = {
181
+ id: 'Id',
182
+ ids: 'Ids',
183
+ search: 'Search'
184
+ };
185
+ const DEFAULT_NO_MATCH_MESSAGE = 'No record matches the filter.';
186
+ const MAX_FLOW_NAME_LENGTH = 255;
187
+ /** A supplied text when it has content, the English default otherwise. */ const textOr = (value, fallback)=>value?.trim() || fallback;
188
+ const INPUT_TYPE = {
189
+ [_enums_field_type_enum_js__rspack_import_1/* .FieldType.TEXT */.P.TEXT]: 'string',
190
+ [_enums_field_type_enum_js__rspack_import_1/* .FieldType.LONG_TEXT */.P.LONG_TEXT]: 'text',
191
+ [_enums_field_type_enum_js__rspack_import_1/* .FieldType.INTEGER */.P.INTEGER]: 'integer',
192
+ [_enums_field_type_enum_js__rspack_import_1/* .FieldType.DECIMAL */.P.DECIMAL]: 'number',
193
+ [_enums_field_type_enum_js__rspack_import_1/* .FieldType.BOOLEAN */.P.BOOLEAN]: 'boolean',
194
+ [_enums_field_type_enum_js__rspack_import_1/* .FieldType.DATE */.P.DATE]: 'date',
195
+ [_enums_field_type_enum_js__rspack_import_1/* .FieldType.DATETIME */.P.DATETIME]: 'datetime',
196
+ [_enums_field_type_enum_js__rspack_import_1/* .FieldType.EMAIL */.P.EMAIL]: 'email',
197
+ [_enums_field_type_enum_js__rspack_import_1/* .FieldType.SINGLE_SELECT */.P.SINGLE_SELECT]: 'choice',
198
+ [_enums_field_type_enum_js__rspack_import_1/* .FieldType.MULTI_SELECT */.P.MULTI_SELECT]: 'array',
199
+ [_enums_field_type_enum_js__rspack_import_1/* .FieldType.RELATION */.P.RELATION]: 'uuid',
200
+ [_enums_field_type_enum_js__rspack_import_1/* .FieldType.JSON */.P.JSON]: 'object',
201
+ [_enums_field_type_enum_js__rspack_import_1/* .FieldType.FILE */.P.FILE]: 'string'
202
+ };
203
+ const MAX_SLUG_LENGTH = 63;
204
+ const LIST_LIMIT = 50;
205
+ /** A bulk flow runs up to three steps per item (bulkUpsert: check, write, keep), well inside FLOW_LIMITS.MAX_STEPS_PER_RUN. */ const BULK_MAX_ITEMS = 200;
206
+ const COLUMN = {
207
+ x: 40,
208
+ gap: 300
209
+ };
210
+ const ROW = {
211
+ y: 60,
212
+ gap: 160
213
+ };
214
+ const ref = (path)=>({
215
+ type: 'field_ref',
216
+ ref: path
217
+ });
218
+ const lit = (value)=>({
219
+ type: 'literal',
220
+ value
221
+ });
222
+ /** `customer_ticket` + getAll -> `customer-ticket-get-all`, shortened so it always fits the slug length. */ function entityFlowSlug(entityCode, endpoint) {
223
+ const suffix = SLUG_SUFFIX[endpoint];
224
+ const base = entityCode.replace(/_/g, '-').slice(0, MAX_SLUG_LENGTH - suffix.length - 1).replace(/-+$/, '');
225
+ return `${base}-${suffix}`;
226
+ }
227
+ function optionValues(options) {
228
+ return (options ?? []).map((o)=>o && typeof o === 'object' && 'value' in o ? String(o.value) : String(o));
229
+ }
230
+ function fieldInput(field, required) {
231
+ const options = optionValues(field.selectOptions);
232
+ const type = INPUT_TYPE[field.fieldType] === 'choice' && !options.length ? 'string' : INPUT_TYPE[field.fieldType];
233
+ return {
234
+ name: field.code,
235
+ label: field.label || field.code,
236
+ type,
237
+ ...required ? {
238
+ required: true
239
+ } : {},
240
+ ...type === 'choice' ? {
241
+ options
242
+ } : {}
243
+ };
244
+ }
245
+ const isRequiredOnInsert = (field)=>field.nullable === false && (field.defaultValue === null || field.defaultValue === undefined);
246
+ const fieldMap = (fields, scope)=>Object.fromEntries(fields.map((f)=>[
247
+ f.code,
248
+ ref(`${scope}.${f.code}`)
249
+ ]));
250
+ const optionalFieldInputs = (fields)=>fields.map((f)=>fieldInput(f, false));
251
+ /** Fields an equality filter can match - a list or JSON value cannot be compared as one value. */ const filterableFields = (entity)=>entity.fields.filter((f)=>f.fieldType !== _enums_field_type_enum_js__rspack_import_1/* .FieldType.MULTI_SELECT */.P.MULTI_SELECT && f.fieldType !== _enums_field_type_enum_js__rspack_import_1/* .FieldType.JSON */.P.JSON);
252
+ const idInput = (t)=>({
253
+ name: 'id',
254
+ label: t.inputLabels.id,
255
+ type: 'uuid',
256
+ required: true
257
+ });
258
+ const idsInput = (t)=>({
259
+ name: 'ids',
260
+ label: t.inputLabels.ids,
261
+ type: 'array',
262
+ itemType: 'uuid',
263
+ required: true
264
+ });
265
+ const respond = (id, column, statusCode, body, row)=>({
266
+ id,
267
+ type: 'respond',
268
+ column,
269
+ row,
270
+ config: 'type' in body ? {
271
+ statusCode,
272
+ bodyExpression: body
273
+ } : {
274
+ statusCode,
275
+ body
276
+ }
277
+ });
278
+ /** The body is the list itself (`itemSchema` checks each item): foreach `input` -> `body` (per item) ... done -> respond with the collected results. */ function bulkGraph(itemSchema, body, bodyEdges, collect, statusCode) {
279
+ return {
280
+ bodyType: 'list',
281
+ inputSchema: itemSchema,
282
+ steps: [
283
+ {
284
+ id: 'each',
285
+ type: 'foreach',
286
+ column: 1,
287
+ config: {
288
+ items: ref('input'),
289
+ maxItems: BULK_MAX_ITEMS,
290
+ collect
291
+ }
292
+ },
293
+ ...body,
294
+ respond('respond', 2, statusCode, ref('context.each.results'))
295
+ ],
296
+ edges: [
297
+ [
298
+ 'each',
299
+ 'each',
300
+ body[0].id
301
+ ],
302
+ ...bodyEdges,
303
+ [
304
+ 'each',
305
+ 'done',
306
+ 'respond'
307
+ ]
308
+ ],
309
+ isTransactional: true
310
+ };
311
+ }
312
+ function endpointGraph(entity, endpoint, texts) {
313
+ const entityCode = entity.code;
314
+ const single = (inputSchema, step, statusCode = 200)=>({
315
+ inputSchema,
316
+ steps: [
317
+ {
318
+ ...step,
319
+ column: 1
320
+ },
321
+ respond('respond', 2, statusCode, ref(`context.${step.id}`))
322
+ ],
323
+ edges: [
324
+ [
325
+ step.id,
326
+ 'out',
327
+ 'respond'
328
+ ]
329
+ ]
330
+ });
331
+ const filterFields = filterableFields(entity);
332
+ const insertInputs = entity.fields.map((f)=>fieldInput(f, isRequiredOnInsert(f)));
333
+ switch(endpoint){
334
+ case 'insert':
335
+ return single(insertInputs, {
336
+ id: 'record',
337
+ type: 'entity_insert',
338
+ config: {
339
+ entityCode,
340
+ fields: fieldMap(entity.fields, 'input')
341
+ }
342
+ }, 201);
343
+ case 'insertMany':
344
+ return bulkGraph(insertInputs, [
345
+ {
346
+ id: 'record',
347
+ type: 'entity_insert',
348
+ column: 1,
349
+ row: 1,
350
+ config: {
351
+ entityCode,
352
+ fields: fieldMap(entity.fields, 'loop.item')
353
+ }
354
+ }
355
+ ], [], ref('context.record'), 201);
356
+ case 'getById':
357
+ return single([
358
+ idInput(texts)
359
+ ], {
360
+ id: 'record',
361
+ type: 'entity_get',
362
+ config: {
363
+ entityCode,
364
+ id: ref('input.id')
365
+ }
366
+ });
367
+ case 'getByIds':
368
+ return single([
369
+ idsInput(texts)
370
+ ], {
371
+ id: 'records',
372
+ type: 'entity_query',
373
+ config: {
374
+ entityCode,
375
+ filter: {
376
+ id: {
377
+ op: 'in',
378
+ value: ref('input.ids')
379
+ }
380
+ },
381
+ limit: _flow_engine_flow_types_js__rspack_import_0/* .FLOW_LIMITS.MAX_QUERY_LIMIT */.Or.MAX_QUERY_LIMIT
382
+ }
383
+ });
384
+ case 'getAll':
385
+ return single([
386
+ {
387
+ name: 'search',
388
+ label: texts.inputLabels.search,
389
+ type: 'string'
390
+ },
391
+ ...optionalFieldInputs(filterFields)
392
+ ], {
393
+ id: 'records',
394
+ type: 'entity_query',
395
+ config: {
396
+ entityCode,
397
+ search: ref('input.search'),
398
+ filter: fieldMap(filterFields, 'input'),
399
+ limit: LIST_LIMIT
400
+ }
401
+ });
402
+ case 'getByFilter':
403
+ return {
404
+ inputSchema: [
405
+ {
406
+ ...idInput(texts),
407
+ required: false
408
+ },
409
+ ...optionalFieldInputs(filterFields)
410
+ ],
411
+ steps: [
412
+ {
413
+ id: 'records',
414
+ type: 'entity_query',
415
+ column: 1,
416
+ config: {
417
+ entityCode,
418
+ filter: {
419
+ id: ref('input.id'),
420
+ ...fieldMap(filterFields, 'input')
421
+ },
422
+ limit: 1
423
+ }
424
+ },
425
+ {
426
+ id: 'found',
427
+ type: 'condition',
428
+ column: 2,
429
+ config: {
430
+ rule: {
431
+ operator: 'AND',
432
+ conditions: [
433
+ {
434
+ field: 'context.records.items',
435
+ comparison: 'is_not_empty'
436
+ }
437
+ ]
438
+ }
439
+ }
440
+ },
441
+ respond('respond', 3, 200, ref('context.records.items.0')),
442
+ respond('not_found', 3, 404, {
443
+ success: lit(false),
444
+ message: lit(texts.noMatchMessage),
445
+ messageKey: lit(_config_message_keys_js__rspack_import_2/* .GENERIC_RECORD_MESSAGES.NO_MATCH */.j4.NO_MATCH)
446
+ }, 1)
447
+ ],
448
+ edges: [
449
+ [
450
+ 'records',
451
+ 'out',
452
+ 'found'
453
+ ],
454
+ [
455
+ 'found',
456
+ 'true',
457
+ 'respond'
458
+ ],
459
+ [
460
+ 'found',
461
+ 'false',
462
+ 'not_found'
463
+ ]
464
+ ]
465
+ };
466
+ case 'update':
467
+ return single([
468
+ idInput(texts),
469
+ ...optionalFieldInputs(entity.fields)
470
+ ], {
471
+ id: 'record',
472
+ type: 'entity_update',
473
+ config: {
474
+ entityCode,
475
+ id: ref('input.id'),
476
+ fields: fieldMap(entity.fields, 'input')
477
+ }
478
+ });
479
+ case 'updateMany':
480
+ return bulkGraph([
481
+ idInput(texts),
482
+ ...optionalFieldInputs(entity.fields)
483
+ ], [
484
+ {
485
+ id: 'record',
486
+ type: 'entity_update',
487
+ column: 1,
488
+ row: 1,
489
+ config: {
490
+ entityCode,
491
+ id: ref('loop.item.id'),
492
+ fields: fieldMap(entity.fields, 'loop.item')
493
+ }
494
+ }
495
+ ], [], ref('context.record'), 200);
496
+ case 'bulkUpsert':
497
+ return bulkGraph([
498
+ {
499
+ ...idInput(texts),
500
+ required: false
501
+ },
502
+ ...optionalFieldInputs(entity.fields)
503
+ ], [
504
+ {
505
+ id: 'has_id',
506
+ type: 'condition',
507
+ column: 1,
508
+ row: 1,
509
+ config: {
510
+ rule: {
511
+ operator: 'AND',
512
+ conditions: [
513
+ {
514
+ field: 'loop.item.id',
515
+ comparison: 'is_not_empty'
516
+ }
517
+ ]
518
+ }
519
+ }
520
+ },
521
+ {
522
+ id: 'updated',
523
+ type: 'entity_update',
524
+ column: 2,
525
+ row: 1,
526
+ config: {
527
+ entityCode,
528
+ id: ref('loop.item.id'),
529
+ fields: fieldMap(entity.fields, 'loop.item')
530
+ }
531
+ },
532
+ {
533
+ id: 'inserted',
534
+ type: 'entity_insert',
535
+ column: 2,
536
+ row: 2,
537
+ config: {
538
+ entityCode,
539
+ fields: fieldMap(entity.fields, 'loop.item')
540
+ }
541
+ },
542
+ {
543
+ id: 'keep_updated',
544
+ type: 'set',
545
+ column: 3,
546
+ row: 1,
547
+ config: {
548
+ values: {
549
+ saved: ref('context.updated')
550
+ }
551
+ }
552
+ },
553
+ {
554
+ id: 'keep_inserted',
555
+ type: 'set',
556
+ column: 3,
557
+ row: 2,
558
+ config: {
559
+ values: {
560
+ saved: ref('context.inserted')
561
+ }
562
+ }
563
+ }
564
+ ], [
565
+ [
566
+ 'has_id',
567
+ 'true',
568
+ 'updated'
569
+ ],
570
+ [
571
+ 'has_id',
572
+ 'false',
573
+ 'inserted'
574
+ ],
575
+ [
576
+ 'updated',
577
+ 'out',
578
+ 'keep_updated'
579
+ ],
580
+ [
581
+ 'inserted',
582
+ 'out',
583
+ 'keep_inserted'
584
+ ]
585
+ ], ref('vars.saved'), 200);
586
+ case 'delete':
587
+ return single([
588
+ idInput(texts)
589
+ ], {
590
+ id: 'record',
591
+ type: 'entity_delete',
592
+ config: {
593
+ entityCode,
594
+ id: ref('input.id')
595
+ }
596
+ });
597
+ }
598
+ }
599
+ /**
600
+ * A ready-made flow for one record endpoint of the generic API controller. It runs as the
601
+ * caller, so the entity permissions still decide who may use it, and it is an ordinary flow
602
+ * afterwards - the user can change or delete it like any other. The bulk endpoints take the list
603
+ * of records as the body and loop over it in one transaction, so a failing item rolls back the whole request.
604
+ */ function buildEntityFlow(entity, endpoint, texts = {}) {
605
+ const resolved = {
606
+ inputLabels: {
607
+ id: textOr(texts.inputLabels?.id, DEFAULT_INPUT_LABEL.id),
608
+ ids: textOr(texts.inputLabels?.ids, DEFAULT_INPUT_LABEL.ids),
609
+ search: textOr(texts.inputLabels?.search, DEFAULT_INPUT_LABEL.search)
610
+ },
611
+ noMatchMessage: textOr(texts.noMatchMessage, DEFAULT_NO_MATCH_MESSAGE)
612
+ };
613
+ const graph = endpointGraph(entity, endpoint, resolved);
614
+ const nodes = [
615
+ {
616
+ id: 'trigger',
617
+ type: 'trigger',
618
+ name: '',
619
+ position: {
620
+ x: COLUMN.x,
621
+ y: ROW.y
622
+ },
623
+ config: {}
624
+ },
625
+ ...graph.steps.map(({ column, row, ...step })=>({
626
+ ...step,
627
+ name: '',
628
+ position: {
629
+ x: COLUMN.x + column * COLUMN.gap,
630
+ y: ROW.y + (row ?? 0) * ROW.gap
631
+ }
632
+ }))
633
+ ];
634
+ const edges = [
635
+ [
636
+ 'trigger',
637
+ 'out',
638
+ graph.steps[0].id
639
+ ],
640
+ ...graph.edges
641
+ ].map(([from, port, to])=>({
642
+ id: `e_${from}_${port}_${to}`,
643
+ from,
644
+ port,
645
+ to
646
+ }));
647
+ return {
648
+ name: `${entity.label} - ${textOr(texts.names?.[endpoint], DEFAULT_FLOW_NAME[endpoint])}`.slice(0, MAX_FLOW_NAME_LENGTH),
649
+ slug: entityFlowSlug(entity.code, endpoint),
650
+ isActive: true,
651
+ authMode: 'jwt',
652
+ runAs: 'caller',
653
+ isTransactional: graph.isTransactional ?? false,
654
+ bodyType: graph.bodyType ?? 'object',
655
+ inputSchema: graph.inputSchema,
656
+ nodes,
657
+ edges
658
+ };
659
+ }
660
+
661
+ __webpack_require__.d(__webpack_exports__, {
662
+ C: () => (buildEntityFlow),
663
+ x: () => (entityFlowSlug)
664
+ });
665
+
666
+
667
+ },
668
+ 1462(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
669
+ /* import */ var _flusys_nestjs_shared__rspack_import_0 = __webpack_require__(3422);
670
+ /* import */ var _nestjs_common__rspack_import_1 = __webpack_require__(6157);
671
+ function _ts_decorate(decorators, target, key, desc) {
672
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
673
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
674
+ r = Reflect.decorate(decorators, target, key, desc);
675
+ } else {
676
+ for(var i = decorators.length - 1; i >= 0; i--){
677
+ if (d = decorators[i]) {
678
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
679
+ }
680
+ }
681
+ }
682
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
683
+ }
684
+ function _ts_metadata(metadataKey, metadataValue) {
685
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
686
+ return Reflect.metadata(metadataKey, metadataValue);
687
+ }
688
+ }
689
+ function _ts_param(paramIndex, decorator) {
690
+ return function(target, key) {
691
+ decorator(target, key, paramIndex);
692
+ };
693
+ }
694
+
695
+
696
+ const CRUD_ACTIONS = [
697
+ 'create',
698
+ 'read',
699
+ 'update',
700
+ 'delete'
701
+ ];
702
+ class EntityPermissionService {
703
+ actionRegistry;
704
+ constructor(actionRegistry){
705
+ this.actionRegistry = actionRegistry;
706
+ }
707
+ async provisionForEntity(definition) {
708
+ if (!this.actionRegistry) return;
709
+ const parentCode = (0,_flusys_nestjs_shared__rspack_import_0.dynamicEntityPermissionParent)(definition.code);
710
+ await this.actionRegistry.registerActions(CRUD_ACTIONS.map((op)=>({
711
+ code: (0,_flusys_nestjs_shared__rspack_import_0.dynamicEntityPermission)(definition.code, op),
712
+ name: `${definition.label} - ${op}`,
713
+ parentCode,
714
+ actionType: 'BACKEND'
715
+ })));
716
+ }
717
+ async deprovisionForEntity(definition) {
718
+ if (!this.actionRegistry) return;
719
+ await this.actionRegistry.removeActionsByCodes([
720
+ (0,_flusys_nestjs_shared__rspack_import_0.dynamicEntityPermissionParent)(definition.code),
721
+ ...CRUD_ACTIONS.map((op)=>(0,_flusys_nestjs_shared__rspack_import_0.dynamicEntityPermission)(definition.code, op))
722
+ ]);
723
+ }
724
+ }
725
+ EntityPermissionService = _ts_decorate([
726
+ (0,_nestjs_common__rspack_import_1.Injectable)(),
727
+ _ts_param(0, (0,_nestjs_common__rspack_import_1.Optional)()),
728
+ _ts_param(0, (0,_nestjs_common__rspack_import_1.Inject)(_flusys_nestjs_shared__rspack_import_0.PERMISSION_ACTION_REGISTRY)),
729
+ _ts_metadata("design:type", Function),
730
+ _ts_metadata("design:paramtypes", [
731
+ typeof IPermissionActionRegistry === "undefined" ? Object : IPermissionActionRegistry
732
+ ])
733
+ ], EntityPermissionService);
734
+
735
+ __webpack_require__.d(__webpack_exports__, {
736
+ u: () => (EntityPermissionService)
737
+ });
738
+
739
+
740
+ },
741
+ 9487(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
742
+ /* import */ var _flusys_nestjs_shared_classes__rspack_import_0 = __webpack_require__(6937);
743
+ /* import */ var _flusys_nestjs_shared_modules__rspack_import_1 = __webpack_require__(1236);
744
+ /* import */ var _nestjs_common__rspack_import_2 = __webpack_require__(6157);
745
+ /* import */ var _config_event_actions_js__rspack_import_5 = __webpack_require__(982);
746
+ /* import */ var _entities_field_definition_entity_js__rspack_import_3 = __webpack_require__(2206);
747
+ /* import */ var _entity_builder_datasource_provider_js__rspack_import_4 = __webpack_require__(424);
748
+ function _ts_decorate(decorators, target, key, desc) {
749
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
750
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
751
+ r = Reflect.decorate(decorators, target, key, desc);
752
+ } else {
753
+ for(var i = decorators.length - 1; i >= 0; i--){
754
+ if (d = decorators[i]) {
755
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
756
+ }
757
+ }
758
+ }
759
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
760
+ }
761
+ function _ts_metadata(metadataKey, metadataValue) {
762
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
763
+ return Reflect.metadata(metadataKey, metadataValue);
764
+ }
765
+ }
766
+ function _ts_param(paramIndex, decorator) {
767
+ return function(target, key) {
768
+ decorator(target, key, paramIndex);
769
+ };
770
+ }
771
+
772
+
773
+
774
+
775
+
776
+
777
+ class FieldDefinitionService extends _flusys_nestjs_shared_classes__rspack_import_0.ApiService {
778
+ cacheManager;
779
+ utilsService;
780
+ constructor(cacheManager, utilsService, dataSourceProvider){
781
+ super(_config_event_actions_js__rspack_import_5/* .ENTITY_BUILDER_EVENT_ENTITIES.FIELD_DEFINITION */.P.FIELD_DEFINITION, cacheManager, utilsService, FieldDefinitionService.name, true, _config_event_actions_js__rspack_import_5/* .ENTITY_BUILDER_EVENT_MODULE */.S, dataSourceProvider, _entities_field_definition_entity_js__rspack_import_3/* .FieldDefinition */.c), this.cacheManager = cacheManager, this.utilsService = utilsService;
782
+ }
783
+ // Schema changes send the loaded `updatedAt` back as `expectedUpdatedAt`; Identity hides it by default.
784
+ async getSelectQuery(query, user, select) {
785
+ const result = await super.getSelectQuery(query, user, select);
786
+ result.query.addSelect(`${this.entityName}.updatedAt`);
787
+ return result;
788
+ }
789
+ }
790
+ FieldDefinitionService = _ts_decorate([
791
+ (0,_nestjs_common__rspack_import_2.Injectable)({
792
+ scope: _nestjs_common__rspack_import_2.Scope.REQUEST
793
+ }),
794
+ _ts_param(0, (0,_nestjs_common__rspack_import_2.Inject)('CACHE_INSTANCE')),
795
+ _ts_param(1, (0,_nestjs_common__rspack_import_2.Inject)(_flusys_nestjs_shared_modules__rspack_import_1.UtilsService)),
796
+ _ts_param(2, (0,_nestjs_common__rspack_import_2.Inject)(_entity_builder_datasource_provider_js__rspack_import_4/* .EntityBuilderDataSourceProvider */.D)),
797
+ _ts_metadata("design:type", Function),
798
+ _ts_metadata("design:paramtypes", [
799
+ typeof _flusys_nestjs_shared_classes__rspack_import_0.HybridCache === "undefined" ? Object : _flusys_nestjs_shared_classes__rspack_import_0.HybridCache,
800
+ typeof _flusys_nestjs_shared_modules__rspack_import_1.UtilsService === "undefined" ? Object : _flusys_nestjs_shared_modules__rspack_import_1.UtilsService,
801
+ typeof _entity_builder_datasource_provider_js__rspack_import_4/* .EntityBuilderDataSourceProvider */.D === "undefined" ? Object : _entity_builder_datasource_provider_js__rspack_import_4/* .EntityBuilderDataSourceProvider */.D
802
+ ])
803
+ ], FieldDefinitionService);
804
+
805
+ __webpack_require__.d(__webpack_exports__, {
806
+ J: () => (FieldDefinitionService)
807
+ });
808
+
809
+
810
+ },
811
+ 4984(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
812
+ /* import */ var _flusys_nestjs_shared_utils__rspack_import_0 = __webpack_require__(9216);
813
+ /* import */ var _config_message_keys_js__rspack_import_2 = __webpack_require__(5732);
814
+ /* import */ var _enums_field_type_enum_js__rspack_import_1 = __webpack_require__(9614);
815
+
816
+
817
+
818
+ const TEXT_LIKE = new Set([
819
+ _enums_field_type_enum_js__rspack_import_1/* .FieldType.TEXT */.P.TEXT,
820
+ _enums_field_type_enum_js__rspack_import_1/* .FieldType.EMAIL */.P.EMAIL,
821
+ _enums_field_type_enum_js__rspack_import_1/* .FieldType.SINGLE_SELECT */.P.SINGLE_SELECT
822
+ ]);
823
+ const SCALAR_TO_TEXT = new Set([
824
+ _enums_field_type_enum_js__rspack_import_1/* .FieldType.INTEGER */.P.INTEGER,
825
+ _enums_field_type_enum_js__rspack_import_1/* .FieldType.DECIMAL */.P.DECIMAL,
826
+ _enums_field_type_enum_js__rspack_import_1/* .FieldType.BOOLEAN */.P.BOOLEAN,
827
+ _enums_field_type_enum_js__rspack_import_1/* .FieldType.DATE */.P.DATE,
828
+ _enums_field_type_enum_js__rspack_import_1/* .FieldType.DATETIME */.P.DATETIME
829
+ ]);
830
+ const EMAIL_PG = `'^[^[:space:]@]+@[^[:space:]@]+\\.[^[:space:]@]+$'`;
831
+ const regexFail = (column, driver, pattern)=>driver === 'postgres' ? `${column} !~ '${pattern}'` : `${column} NOT REGEXP '${pattern}'`;
832
+ const SELECT_KINDS = new Set([
833
+ _enums_field_type_enum_js__rspack_import_1/* .FieldType.SINGLE_SELECT */.P.SINGLE_SELECT,
834
+ _enums_field_type_enum_js__rspack_import_1/* .FieldType.MULTI_SELECT */.P.MULTI_SELECT
835
+ ]);
836
+ const unsupported = (from, to)=>({
837
+ supported: false,
838
+ prechecks: [],
839
+ reason: (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_2/* .SCHEMA_BLOCKER_MESSAGES.CONVERSION_UNSUPPORTED */.M3.CONVERSION_UNSUPPORTED, {
840
+ from,
841
+ to
842
+ })
843
+ });
844
+ function planTypeConversion(from, to, driver) {
845
+ if (from === to) return {
846
+ supported: true,
847
+ noDbChange: true,
848
+ prechecks: []
849
+ };
850
+ // MySQL has no USING clause: MODIFY casts implicitly, which rejects text as JSON or boolean and would keep a JSON array as its text.
851
+ const textLike = TEXT_LIKE.has(from) || from === _enums_field_type_enum_js__rspack_import_1/* .FieldType.LONG_TEXT */.P.LONG_TEXT;
852
+ if (driver === 'mysql' && (SELECT_KINDS.has(from) && SELECT_KINDS.has(to) || textLike && to === _enums_field_type_enum_js__rspack_import_1/* .FieldType.BOOLEAN */.P.BOOLEAN)) return unsupported(from, to);
853
+ // Same physical column (varchar(255)): only the meaning changes.
854
+ if (TEXT_LIKE.has(from) && TEXT_LIKE.has(to)) {
855
+ const checks = [];
856
+ if (to === _enums_field_type_enum_js__rspack_import_1/* .FieldType.EMAIL */.P.EMAIL) {
857
+ checks.push({
858
+ description: (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_2/* .SCHEMA_PRECHECK_MESSAGES.NOT_EMAIL */.NE.NOT_EMAIL),
859
+ badRowsWhere: (c, d)=>d === 'postgres' ? `${c} !~ ${EMAIL_PG}` : `${c} NOT REGEXP '^[^ @]+@[^ @]+\\\\.[^ @]+$'`
860
+ });
861
+ }
862
+ return {
863
+ supported: true,
864
+ noDbChange: true,
865
+ prechecks: checks
866
+ };
867
+ }
868
+ if (from === _enums_field_type_enum_js__rspack_import_1/* .FieldType.RELATION */.P.RELATION && to === _enums_field_type_enum_js__rspack_import_1/* .FieldType.FILE */.P.FILE || from === _enums_field_type_enum_js__rspack_import_1/* .FieldType.FILE */.P.FILE && to === _enums_field_type_enum_js__rspack_import_1/* .FieldType.RELATION */.P.RELATION) {
869
+ return {
870
+ supported: true,
871
+ noDbChange: true,
872
+ prechecks: []
873
+ };
874
+ }
875
+ // -> LONG_TEXT (text): widening from everything scalar/text-like
876
+ if (to === _enums_field_type_enum_js__rspack_import_1/* .FieldType.LONG_TEXT */.P.LONG_TEXT && (TEXT_LIKE.has(from) || SCALAR_TO_TEXT.has(from))) {
877
+ return {
878
+ supported: true,
879
+ using: (c)=>`${c}::text`,
880
+ prechecks: []
881
+ };
882
+ }
883
+ // LONG_TEXT -> varchar(255) kinds: narrowing, blocked if any value is too long
884
+ if (from === _enums_field_type_enum_js__rspack_import_1/* .FieldType.LONG_TEXT */.P.LONG_TEXT && TEXT_LIKE.has(to)) {
885
+ const checks = [
886
+ {
887
+ description: (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_2/* .SCHEMA_PRECHECK_MESSAGES.TOO_LONG */.NE.TOO_LONG),
888
+ badRowsWhere: (c, d)=>d === 'postgres' ? `char_length(${c}) > 255` : `CHAR_LENGTH(${c}) > 255`
889
+ }
890
+ ];
891
+ if (to === _enums_field_type_enum_js__rspack_import_1/* .FieldType.EMAIL */.P.EMAIL) {
892
+ checks.push({
893
+ description: (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_2/* .SCHEMA_PRECHECK_MESSAGES.NOT_EMAIL */.NE.NOT_EMAIL),
894
+ badRowsWhere: (c, d)=>d === 'postgres' ? `${c} !~ ${EMAIL_PG}` : `${c} NOT REGEXP '^[^ @]+@[^ @]+\\\\.[^ @]+$'`
895
+ });
896
+ }
897
+ return {
898
+ supported: true,
899
+ using: (c)=>`${c}::varchar(255)`,
900
+ prechecks: checks
901
+ };
902
+ }
903
+ // scalar -> text-like: always representable
904
+ if (SCALAR_TO_TEXT.has(from) && TEXT_LIKE.has(to)) {
905
+ const checks = [];
906
+ if (to === _enums_field_type_enum_js__rspack_import_1/* .FieldType.EMAIL */.P.EMAIL) {
907
+ checks.push({
908
+ description: (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_2/* .SCHEMA_PRECHECK_MESSAGES.NOT_EMAIL */.NE.NOT_EMAIL),
909
+ badRowsWhere: (c, d)=>d === 'postgres' ? `${c}::text !~ ${EMAIL_PG}` : `CAST(${c} AS CHAR) NOT REGEXP '^[^ @]+@[^ @]+\\\\.[^ @]+$'`
910
+ });
911
+ }
912
+ return {
913
+ supported: true,
914
+ using: (c)=>`${c}::text`,
915
+ prechecks: checks
916
+ };
917
+ }
918
+ // text-like / long text -> scalar: every existing value must parse
919
+ if (textLike) {
920
+ switch(to){
921
+ case _enums_field_type_enum_js__rspack_import_1/* .FieldType.INTEGER */.P.INTEGER:
922
+ return {
923
+ supported: true,
924
+ using: (c)=>`${c}::integer`,
925
+ prechecks: [
926
+ {
927
+ description: (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_2/* .SCHEMA_PRECHECK_MESSAGES.NOT_WHOLE_NUMBER */.NE.NOT_WHOLE_NUMBER),
928
+ badRowsWhere: (c, d)=>regexFail(c, d, '^-?[0-9]{1,10}$')
929
+ }
930
+ ]
931
+ };
932
+ case _enums_field_type_enum_js__rspack_import_1/* .FieldType.DECIMAL */.P.DECIMAL:
933
+ return {
934
+ supported: true,
935
+ using: (c)=>`${c}::numeric(18,4)`,
936
+ prechecks: [
937
+ {
938
+ description: (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_2/* .SCHEMA_PRECHECK_MESSAGES.NOT_NUMBER */.NE.NOT_NUMBER),
939
+ badRowsWhere: (c, d)=>regexFail(c, d, '^-?[0-9]{1,14}(\\.[0-9]+)?$')
940
+ }
941
+ ]
942
+ };
943
+ case _enums_field_type_enum_js__rspack_import_1/* .FieldType.BOOLEAN */.P.BOOLEAN:
944
+ return {
945
+ supported: true,
946
+ using: (c)=>`(lower(${c}))::boolean`,
947
+ prechecks: [
948
+ {
949
+ description: (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_2/* .SCHEMA_PRECHECK_MESSAGES.NOT_BOOLEAN_TEXT */.NE.NOT_BOOLEAN_TEXT),
950
+ badRowsWhere: (c)=>`lower(${c}) NOT IN ('true','false')`
951
+ }
952
+ ]
953
+ };
954
+ case _enums_field_type_enum_js__rspack_import_1/* .FieldType.DATE */.P.DATE:
955
+ return {
956
+ supported: true,
957
+ using: (c)=>`${c}::date`,
958
+ prechecks: [
959
+ {
960
+ description: (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_2/* .SCHEMA_PRECHECK_MESSAGES.NOT_DATE */.NE.NOT_DATE),
961
+ badRowsWhere: (c, d)=>regexFail(c, d, '^[0-9]{4}-[0-9]{2}-[0-9]{2}$')
962
+ }
963
+ ]
964
+ };
965
+ case _enums_field_type_enum_js__rspack_import_1/* .FieldType.DATETIME */.P.DATETIME:
966
+ return {
967
+ supported: true,
968
+ using: (c)=>`${c}::timestamptz`,
969
+ prechecks: [
970
+ {
971
+ description: (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_2/* .SCHEMA_PRECHECK_MESSAGES.NOT_DATETIME */.NE.NOT_DATETIME),
972
+ badRowsWhere: (c, d)=>regexFail(c, d, d === 'postgres' ? '^[0-9]{4}-[0-9]{2}-[0-9]{2}([T ][0-9:.]+)?(Z|[+-][0-9:]+)?$' : '^[0-9]{4}-[0-9]{2}-[0-9]{2}([T ][0-9]{2}:[0-9]{2}(:[0-9]{2}(\\.[0-9]+)?)?)?$')
973
+ }
974
+ ]
975
+ };
976
+ default:
977
+ break;
978
+ }
979
+ }
980
+ // numeric conversions
981
+ if (from === _enums_field_type_enum_js__rspack_import_1/* .FieldType.INTEGER */.P.INTEGER && to === _enums_field_type_enum_js__rspack_import_1/* .FieldType.DECIMAL */.P.DECIMAL) return {
982
+ supported: true,
983
+ using: (c)=>`${c}::numeric(18,4)`,
984
+ prechecks: []
985
+ };
986
+ if (from === _enums_field_type_enum_js__rspack_import_1/* .FieldType.DECIMAL */.P.DECIMAL && to === _enums_field_type_enum_js__rspack_import_1/* .FieldType.INTEGER */.P.INTEGER) {
987
+ return {
988
+ supported: true,
989
+ using: (c)=>`round(${c})::integer`,
990
+ lossy: (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_2/* .SCHEMA_WARNING_MESSAGES.LOSSY_ROUNDING */.Uu.LOSSY_ROUNDING),
991
+ prechecks: [
992
+ {
993
+ description: (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_2/* .SCHEMA_PRECHECK_MESSAGES.OUT_OF_INTEGER_RANGE */.NE.OUT_OF_INTEGER_RANGE),
994
+ badRowsWhere: (c)=>`abs(${c}) > 2147483647`
995
+ }
996
+ ]
997
+ };
998
+ }
999
+ if ((from === _enums_field_type_enum_js__rspack_import_1/* .FieldType.INTEGER */.P.INTEGER || from === _enums_field_type_enum_js__rspack_import_1/* .FieldType.DECIMAL */.P.DECIMAL) && to === _enums_field_type_enum_js__rspack_import_1/* .FieldType.BOOLEAN */.P.BOOLEAN) {
1000
+ return {
1001
+ supported: true,
1002
+ using: (c)=>`(${c} <> 0)`,
1003
+ prechecks: [
1004
+ {
1005
+ description: (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_2/* .SCHEMA_PRECHECK_MESSAGES.NOT_ZERO_OR_ONE */.NE.NOT_ZERO_OR_ONE),
1006
+ badRowsWhere: (c)=>`${c} NOT IN (0,1)`
1007
+ }
1008
+ ]
1009
+ };
1010
+ }
1011
+ if (from === _enums_field_type_enum_js__rspack_import_1/* .FieldType.BOOLEAN */.P.BOOLEAN && (to === _enums_field_type_enum_js__rspack_import_1/* .FieldType.INTEGER */.P.INTEGER || to === _enums_field_type_enum_js__rspack_import_1/* .FieldType.DECIMAL */.P.DECIMAL)) {
1012
+ return {
1013
+ supported: true,
1014
+ using: (c)=>to === _enums_field_type_enum_js__rspack_import_1/* .FieldType.INTEGER */.P.INTEGER ? `${c}::integer` : `${c}::integer::numeric(18,4)`,
1015
+ prechecks: []
1016
+ };
1017
+ }
1018
+ // dates
1019
+ if (from === _enums_field_type_enum_js__rspack_import_1/* .FieldType.DATE */.P.DATE && to === _enums_field_type_enum_js__rspack_import_1/* .FieldType.DATETIME */.P.DATETIME) return {
1020
+ supported: true,
1021
+ using: (c)=>`${c}::timestamptz`,
1022
+ prechecks: []
1023
+ };
1024
+ if (from === _enums_field_type_enum_js__rspack_import_1/* .FieldType.DATETIME */.P.DATETIME && to === _enums_field_type_enum_js__rspack_import_1/* .FieldType.DATE */.P.DATE) {
1025
+ return {
1026
+ supported: true,
1027
+ using: (c)=>`${c}::date`,
1028
+ lossy: (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_2/* .SCHEMA_WARNING_MESSAGES.LOSSY_TIME_DROPPED */.Uu.LOSSY_TIME_DROPPED),
1029
+ prechecks: []
1030
+ };
1031
+ }
1032
+ // select <-> multi select
1033
+ if (from === _enums_field_type_enum_js__rspack_import_1/* .FieldType.SINGLE_SELECT */.P.SINGLE_SELECT && to === _enums_field_type_enum_js__rspack_import_1/* .FieldType.MULTI_SELECT */.P.MULTI_SELECT) {
1034
+ return {
1035
+ supported: true,
1036
+ using: (c)=>`CASE WHEN ${c} IS NULL THEN NULL ELSE jsonb_build_array(${c}) END`,
1037
+ prechecks: []
1038
+ };
1039
+ }
1040
+ if (from === _enums_field_type_enum_js__rspack_import_1/* .FieldType.MULTI_SELECT */.P.MULTI_SELECT && to === _enums_field_type_enum_js__rspack_import_1/* .FieldType.SINGLE_SELECT */.P.SINGLE_SELECT) {
1041
+ return {
1042
+ supported: true,
1043
+ using: (c)=>`${c}->>0`,
1044
+ prechecks: [
1045
+ {
1046
+ description: (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_2/* .SCHEMA_PRECHECK_MESSAGES.MULTIPLE_SELECTED */.NE.MULTIPLE_SELECTED),
1047
+ badRowsWhere: (c)=>`jsonb_array_length(${c}) > 1`
1048
+ }
1049
+ ]
1050
+ };
1051
+ }
1052
+ return unsupported(from, to);
1053
+ }
1054
+
1055
+ __webpack_require__.d(__webpack_exports__, {
1056
+ I: () => (planTypeConversion)
1057
+ });
1058
+
1059
+
1060
+ },
1061
+ 413(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
1062
+ /* import */ var _nestjs_common__rspack_import_0 = __webpack_require__(6157);
1063
+ /* import */ var _config_message_keys_js__rspack_import_3 = __webpack_require__(5732);
1064
+ /* import */ var _config_entity_builder_constants_js__rspack_import_2 = __webpack_require__(6576);
1065
+ /* import */ var _config_event_actions_js__rspack_import_4 = __webpack_require__(982);
1066
+ /* import */ var _schema_columns_js__rspack_import_1 = __webpack_require__(5313);
1067
+
1068
+
1069
+
1070
+
1071
+
1072
+ /**
1073
+ * SQL reserved words relevant to table/column identifiers (ANSI/Postgres/MySQL keywords most
1074
+ * likely to collide with a user-chosen code). Not exhaustive - the `eb_` table prefix, the
1075
+ * identifier pattern and the live "table exists" check are defense in depth.
1076
+ */ const RESERVED_WORDS = new Set([
1077
+ 'select',
1078
+ 'insert',
1079
+ 'update',
1080
+ 'delete',
1081
+ 'from',
1082
+ 'where',
1083
+ 'table',
1084
+ 'index',
1085
+ 'key',
1086
+ 'primary',
1087
+ 'foreign',
1088
+ 'references',
1089
+ 'default',
1090
+ 'null',
1091
+ 'true',
1092
+ 'false',
1093
+ 'user',
1094
+ 'role',
1095
+ 'grant',
1096
+ 'revoke',
1097
+ 'database',
1098
+ 'schema',
1099
+ 'view',
1100
+ 'trigger',
1101
+ 'function',
1102
+ 'procedure',
1103
+ 'constraint',
1104
+ 'unique',
1105
+ 'check',
1106
+ 'and',
1107
+ 'or',
1108
+ 'not',
1109
+ 'in',
1110
+ 'exists',
1111
+ 'between',
1112
+ 'like',
1113
+ 'is',
1114
+ 'as',
1115
+ 'on',
1116
+ 'into',
1117
+ 'values',
1118
+ 'set',
1119
+ 'alter',
1120
+ 'drop',
1121
+ 'create',
1122
+ 'cascade',
1123
+ 'limit',
1124
+ 'offset',
1125
+ 'union',
1126
+ 'all',
1127
+ 'distinct',
1128
+ 'having',
1129
+ 'case',
1130
+ 'when',
1131
+ 'then',
1132
+ 'else',
1133
+ 'end',
1134
+ 'order',
1135
+ 'group',
1136
+ 'by',
1137
+ 'join',
1138
+ 'left',
1139
+ 'right',
1140
+ 'inner',
1141
+ 'outer',
1142
+ 'id'
1143
+ ]);
1144
+ /** Throws a 400 with a specific reason if `code` cannot safely be a table/column identifier. */ function assertValidIdentifier(code, kind) {
1145
+ if (!_config_entity_builder_constants_js__rspack_import_2/* .ENTITY_CODE_PATTERN.test */.vs.test(code) || code.length > (/* inlined export .ENTITY_CODE_MAX_LENGTH */63)) {
1146
+ throw new _nestjs_common__rspack_import_0.BadRequestException({
1147
+ message: `'${code}' is not a valid ${kind} code. Use lowercase letters, digits and underscores, starting with a letter (3-60 characters).`,
1148
+ messageKey: _config_message_keys_js__rspack_import_3/* .SCHEMA_MESSAGES.INVALID_CODE_PATTERN */.Hu.INVALID_CODE_PATTERN,
1149
+ messageVariables: {
1150
+ code,
1151
+ kind
1152
+ }
1153
+ });
1154
+ }
1155
+ // An entity's events are published as entity-builder.<code>.*, so it cannot share a name with
1156
+ // the module's own definition events.
1157
+ const reservedForKind = kind === 'entity' && Object.values(_config_event_actions_js__rspack_import_4/* .ENTITY_BUILDER_EVENT_ENTITIES */.P).includes(code);
1158
+ if (RESERVED_WORDS.has(code.toLowerCase()) || reservedForKind) {
1159
+ throw new _nestjs_common__rspack_import_0.BadRequestException({
1160
+ message: `'${code}' is a reserved word and cannot be used as a ${kind} code.`,
1161
+ messageKey: _config_message_keys_js__rspack_import_3/* .SCHEMA_MESSAGES.RESERVED_WORD */.Hu.RESERVED_WORD,
1162
+ messageVariables: {
1163
+ code,
1164
+ kind
1165
+ }
1166
+ });
1167
+ }
1168
+ if (kind === 'field' && _schema_columns_js__rspack_import_1/* .SYSTEM_COLUMN_NAMES.includes */.mq.includes(code)) {
1169
+ throw new _nestjs_common__rspack_import_0.BadRequestException({
1170
+ message: `'${code}' is a system column and cannot be used as a field code.`,
1171
+ messageKey: _config_message_keys_js__rspack_import_3/* .SCHEMA_MESSAGES.SYSTEM_COLUMN_CODE */.Hu.SYSTEM_COLUMN_CODE,
1172
+ messageVariables: {
1173
+ code
1174
+ }
1175
+ });
1176
+ }
1177
+ }
1178
+ /** Throws a 400 when a long text / JSON / multi select field is made unique or indexed. */ function assertIndexableField(field) {
1179
+ if ((field.unique === true || field.isIndexed === true) && !(0,_schema_columns_js__rspack_import_1/* .isIndexableFieldType */.d4)(field.fieldType)) {
1180
+ throw new _nestjs_common__rspack_import_0.BadRequestException({
1181
+ message: `'${field.code}' is a ${field.fieldType} field, which cannot be unique or indexed.`,
1182
+ messageKey: _config_message_keys_js__rspack_import_3/* .SCHEMA_MESSAGES.NOT_INDEXABLE */.Hu.NOT_INDEXABLE,
1183
+ messageVariables: {
1184
+ field: field.code,
1185
+ fieldType: field.fieldType
1186
+ }
1187
+ });
1188
+ }
1189
+ }
1190
+
1191
+ __webpack_require__.d(__webpack_exports__, {
1192
+ fY: () => (assertIndexableField),
1193
+ kV: () => (assertValidIdentifier)
1194
+ }, {
1195
+ xJ: RESERVED_WORDS
1196
+ });
1197
+
1198
+
1199
+ },
1200
+ 921(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
1201
+ /* import */ var _nestjs_common__rspack_import_0 = __webpack_require__(6157);
1202
+ /* import */ var _interfaces_reference_provider_interface_js__rspack_import_1 = __webpack_require__(2492);
1203
+ function _ts_decorate(decorators, target, key, desc) {
1204
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1205
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
1206
+ r = Reflect.decorate(decorators, target, key, desc);
1207
+ } else {
1208
+ for(var i = decorators.length - 1; i >= 0; i--){
1209
+ if (d = decorators[i]) {
1210
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1211
+ }
1212
+ }
1213
+ }
1214
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
1215
+ }
1216
+ function _ts_metadata(metadataKey, metadataValue) {
1217
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
1218
+ return Reflect.metadata(metadataKey, metadataValue);
1219
+ }
1220
+ }
1221
+ function _ts_param(paramIndex, decorator) {
1222
+ return function(target, key) {
1223
+ decorator(target, key, paramIndex);
1224
+ };
1225
+ }
1226
+
1227
+
1228
+ class ReferenceScannerService {
1229
+ flowReferences;
1230
+ constructor(flowReferences){
1231
+ this.flowReferences = flowReferences;
1232
+ }
1233
+ async forEntity(entityCode) {
1234
+ return this.flowReferences ? this.flowReferences.findEntityReferences(entityCode) : [];
1235
+ }
1236
+ async forField(entityCode, fieldCode) {
1237
+ return this.flowReferences ? this.flowReferences.findFieldReferences(entityCode, fieldCode) : [];
1238
+ }
1239
+ /**
1240
+ * Rewrites every reference after a field rename. Pass the schema change's own `manager` so
1241
+ * the rewrite is part of the same transaction. Returns how many definitions changed.
1242
+ */ async rewriteFieldCode(entityCode, from, to, manager) {
1243
+ return this.flowReferences ? this.flowReferences.rewriteFieldReferences(entityCode, from, to, manager) : 0;
1244
+ }
1245
+ }
1246
+ ReferenceScannerService = _ts_decorate([
1247
+ (0,_nestjs_common__rspack_import_0.Injectable)({
1248
+ scope: _nestjs_common__rspack_import_0.Scope.REQUEST
1249
+ }),
1250
+ _ts_param(0, (0,_nestjs_common__rspack_import_0.Optional)()),
1251
+ _ts_param(0, (0,_nestjs_common__rspack_import_0.Inject)(_interfaces_reference_provider_interface_js__rspack_import_1/* .FLOW_REFERENCE_PROVIDER */.$)),
1252
+ _ts_metadata("design:type", Function),
1253
+ _ts_metadata("design:paramtypes", [
1254
+ typeof IEntityReferenceProvider === "undefined" ? Object : IEntityReferenceProvider
1255
+ ])
1256
+ ], ReferenceScannerService);
1257
+
1258
+ __webpack_require__.d(__webpack_exports__, {
1259
+ t: () => (ReferenceScannerService)
1260
+ });
1261
+
1262
+
1263
+ },
1264
+ 6605(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
1265
+ /* import */ var _flusys_nestjs_shared_utils__rspack_import_0 = __webpack_require__(9216);
1266
+ /* import */ var _nestjs_common__rspack_import_1 = __webpack_require__(6157);
1267
+ /* import */ var typeorm__rspack_import_2 = __webpack_require__(7158);
1268
+ /* import */ var _config_message_keys_js__rspack_import_11 = __webpack_require__(5732);
1269
+ /* import */ var _flow_engine_flow_errors_js__rspack_import_3 = __webpack_require__(8542);
1270
+ /* import */ var _entities_entity_definition_entity_js__rspack_import_4 = __webpack_require__(3189);
1271
+ /* import */ var _entities_schema_change_log_entity_js__rspack_import_5 = __webpack_require__(875);
1272
+ /* import */ var _enums_ddl_operation_enum_js__rspack_import_12 = __webpack_require__(9949);
1273
+ /* import */ var _database_error_mapper_js__rspack_import_6 = __webpack_require__(8323);
1274
+ /* import */ var _definition_cache_service_js__rspack_import_7 = __webpack_require__(2931);
1275
+ /* import */ var _entity_builder_datasource_provider_js__rspack_import_8 = __webpack_require__(424);
1276
+ /* import */ var _schema_dialect_adapter_service_js__rspack_import_9 = __webpack_require__(7259);
1277
+ /* import */ var _schema_registry_service_js__rspack_import_10 = __webpack_require__(2134);
1278
+ function _ts_decorate(decorators, target, key, desc) {
1279
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1280
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
1281
+ r = Reflect.decorate(decorators, target, key, desc);
1282
+ } else {
1283
+ for(var i = decorators.length - 1; i >= 0; i--){
1284
+ if (d = decorators[i]) {
1285
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1286
+ }
1287
+ }
1288
+ }
1289
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
1290
+ }
1291
+ function _ts_metadata(metadataKey, metadataValue) {
1292
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
1293
+ return Reflect.metadata(metadataKey, metadataValue);
1294
+ }
1295
+ }
1296
+ function _ts_param(paramIndex, decorator) {
1297
+ return function(target, key) {
1298
+ decorator(target, key, paramIndex);
1299
+ };
1300
+ }
1301
+
1302
+
1303
+
1304
+
1305
+
1306
+
1307
+
1308
+
1309
+
1310
+
1311
+
1312
+
1313
+
1314
+ /** Codes of the entities `ids` point at: locked with a change, so none of them can be dropped meanwhile. */ async function relationTargetCodes(provider, ids) {
1315
+ const unique = [
1316
+ ...new Set(ids.filter((id)=>!!id))
1317
+ ];
1318
+ if (!unique.length) return [];
1319
+ const targets = await (await provider.getRepository(_entities_entity_definition_entity_js__rspack_import_4/* .EntityDefinition */.f)).find({
1320
+ select: {
1321
+ id: true,
1322
+ code: true
1323
+ },
1324
+ where: {
1325
+ id: (0,typeorm__rspack_import_2.In)(unique)
1326
+ }
1327
+ });
1328
+ return targets.map((t)=>t.code);
1329
+ }
1330
+ const hasMessage = (list, message)=>list.some((m)=>JSON.stringify(m) === JSON.stringify(message));
1331
+ const isReadOrSession = (sql)=>/^\s*(SELECT|SET|SHOW|BEGIN|COMMIT|ROLLBACK|START)/i.test(sql);
1332
+ const formatSql = (sql, params)=>params?.length ? `${sql.trim()} -- params: ${JSON.stringify(params)}` : sql.trim();
1333
+ const format = (statement)=>formatSql(statement.query, statement.parameters);
1334
+ class SchemaChangeExecutor {
1335
+ dataSourceProvider;
1336
+ dialectAdapter;
1337
+ schemaRegistry;
1338
+ definitionCache;
1339
+ logger = new _nestjs_common__rspack_import_1.Logger(SchemaChangeExecutor.name);
1340
+ constructor(dataSourceProvider, dialectAdapter, schemaRegistry, definitionCache){
1341
+ this.dataSourceProvider = dataSourceProvider;
1342
+ this.dialectAdapter = dialectAdapter;
1343
+ this.schemaRegistry = schemaRegistry;
1344
+ this.definitionCache = definitionCache;
1345
+ }
1346
+ async simulate(target, run, impact = []) {
1347
+ const driver = await this.dataSourceProvider.getDriver();
1348
+ // A dedicated connection: memory mode also mutates TypeORM's cached table metadata, which
1349
+ // must never leak into the connection that later applies the change for real.
1350
+ const qr = await this.dataSourceProvider.getQueryRunner();
1351
+ await qr.connect();
1352
+ qr.enableSqlMemory();
1353
+ const state = this.newState(target, impact);
1354
+ try {
1355
+ const ctx = this.buildContext(qr, driver, true, state);
1356
+ await run(ctx);
1357
+ if (driver === 'mysql' && state.steps.some((s)=>s.sql.length > 0)) ctx.warn((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_11/* .SCHEMA_WARNING_MESSAGES.MYSQL_NO_ROLLBACK */.Uu.MYSQL_NO_ROLLBACK));
1358
+ return this.toPlan(target, state);
1359
+ } finally{
1360
+ qr.disableSqlMemory();
1361
+ await qr.release();
1362
+ }
1363
+ }
1364
+ async apply(target, run, options = {}) {
1365
+ const plan = await this.simulate(target, run, options.impact ?? []);
1366
+ if (plan.blockers.length > 0) {
1367
+ throw new _nestjs_common__rspack_import_1.ConflictException({
1368
+ message: 'This change cannot be applied.',
1369
+ messageKey: _config_message_keys_js__rspack_import_11/* .SCHEMA_MESSAGES.BLOCKED */.Hu.BLOCKED,
1370
+ blockers: plan.blockers,
1371
+ plan
1372
+ });
1373
+ }
1374
+ if (plan.destructive && !options.confirm) {
1375
+ throw new _nestjs_common__rspack_import_1.BadRequestException({
1376
+ message: 'This change loses data or information. Review the plan and resend with confirm: true.',
1377
+ messageKey: _config_message_keys_js__rspack_import_11/* .SCHEMA_MESSAGES.CONFIRMATION_REQUIRED */.Hu.CONFIRMATION_REQUIRED,
1378
+ plan
1379
+ });
1380
+ }
1381
+ const driver = await this.dataSourceProvider.getDriver();
1382
+ // Sorted, so two changes that lock the same entities always take them in the same order.
1383
+ const lockKeys = [
1384
+ ...new Set([
1385
+ target.entityCode,
1386
+ ...target.lockCodes ?? []
1387
+ ])
1388
+ ].toSorted().map((code)=>`eb_entity:${code}`);
1389
+ const heldLocks = [];
1390
+ const qr = await this.dataSourceProvider.getQueryRunner();
1391
+ await qr.connect();
1392
+ await qr.startTransaction();
1393
+ const state = this.newState(target, options.impact ?? []);
1394
+ let committed = false;
1395
+ try {
1396
+ for (const key of lockKeys){
1397
+ await this.dialectAdapter.acquireEntityLock(qr, key, driver);
1398
+ heldLocks.push(key);
1399
+ }
1400
+ const ctx = this.buildContext(qr, driver, false, state);
1401
+ const outcome = await run(ctx);
1402
+ if (state.blockers.length > 0) {
1403
+ // The data changed between the dry-run and the lock - re-checked under the lock.
1404
+ throw new _nestjs_common__rspack_import_1.ConflictException({
1405
+ message: 'This change can no longer be applied.',
1406
+ messageKey: _config_message_keys_js__rspack_import_11/* .SCHEMA_MESSAGES.NO_LONGER_APPLICABLE */.Hu.NO_LONGER_APPLICABLE,
1407
+ blockers: state.blockers
1408
+ });
1409
+ }
1410
+ if (target.entityDefinitionId && outcome.bumpVersion !== false) {
1411
+ const repo = qr.manager.getRepository(_entities_entity_definition_entity_js__rspack_import_4/* .EntityDefinition */.f);
1412
+ const current = await repo.findOne({
1413
+ where: {
1414
+ id: target.entityDefinitionId
1415
+ }
1416
+ });
1417
+ if (current) await repo.update(current.id, {
1418
+ schemaVersion: current.schemaVersion + 1
1419
+ });
1420
+ }
1421
+ await qr.manager.save(_entities_schema_change_log_entity_js__rspack_import_5/* .SchemaChangeLog */.W, qr.manager.getRepository(_entities_schema_change_log_entity_js__rspack_import_5/* .SchemaChangeLog */.W).create({
1422
+ entityDefinitionId: outcome.entityDefinitionId ?? target.entityDefinitionId,
1423
+ entityCode: target.entityCode,
1424
+ operation: outcome.operation,
1425
+ tableName: target.tableName,
1426
+ fieldDefinitionId: outcome.fieldDefinitionId ?? null,
1427
+ diff: outcome.diff,
1428
+ generatedSql: state.steps.flatMap((s)=>s.sql),
1429
+ downSql: state.downSql,
1430
+ status: 'SUCCESS',
1431
+ errorMessage: null,
1432
+ performedById: target.user?.id ?? null
1433
+ }));
1434
+ await qr.commitTransaction();
1435
+ committed = true;
1436
+ const entityId = outcome.entityDefinitionId ?? target.entityDefinitionId;
1437
+ if (entityId) this.schemaRegistry.invalidate(entityId);
1438
+ await this.definitionCache.clearAll((0,_flusys_nestjs_shared_utils__rspack_import_0.cacheTenantId)(this.dataSourceProvider));
1439
+ try {
1440
+ await outcome.afterCommit?.();
1441
+ } catch (postCommitError) {
1442
+ // The change is already committed - reporting a failure now would be a lie.
1443
+ this.logger.error(`Post-commit step failed after '${target.action}' on '${target.entityCode}': ${postCommitError.message}`);
1444
+ state.warnings.push((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_11/* .SCHEMA_WARNING_MESSAGES.FOLLOW_UP_FAILED */.Uu.FOLLOW_UP_FAILED, {
1445
+ detail: (0,_flow_engine_flow_errors_js__rspack_import_3/* .errorRef */.O$)(postCommitError)
1446
+ }));
1447
+ }
1448
+ return {
1449
+ plan: this.toPlan(target, state),
1450
+ outcome
1451
+ };
1452
+ } catch (error) {
1453
+ if (!committed) await qr.rollbackTransaction().catch(()=>undefined);
1454
+ const undo = !committed && driver === 'mysql' && state.undo.length > 0 ? await this.compensate(qr, target, state) : null;
1455
+ await this.logFailure(target, error, state.steps, undo);
1456
+ throw this.withUndo((0,_database_error_mapper_js__rspack_import_6/* .mapSchemaError */.i)(error), undo);
1457
+ } finally{
1458
+ for (const key of heldLocks)await this.dialectAdapter.releaseEntityLock(qr, key, driver).catch(()=>undefined);
1459
+ await qr.release();
1460
+ }
1461
+ }
1462
+ /**
1463
+ * MySQL only: runs the reverse of every DDL statement that had run, newest first, still under
1464
+ * the entity lock. Stops at the first undo statement that fails - running later ones against an
1465
+ * unknown state could make it worse - and reports the rest as pending.
1466
+ */ async compensate(qr, target, state) {
1467
+ const statements = state.undo.toReversed().flat();
1468
+ const pending = [];
1469
+ for (const statement of statements){
1470
+ if (pending.length) {
1471
+ pending.push(statement);
1472
+ continue;
1473
+ }
1474
+ try {
1475
+ await qr.query(statement.query, statement.parameters);
1476
+ } catch (undoError) {
1477
+ this.logger.error(`Could not undo '${format(statement)}' after the failed '${target.action}' on '${target.entityCode}': ${undoError.message}`);
1478
+ pending.push(statement);
1479
+ }
1480
+ }
1481
+ const report = {
1482
+ reverted: pending.length === 0,
1483
+ pendingSql: pending.map(format),
1484
+ dataNotReverted: state.dataSteps > 0
1485
+ };
1486
+ const ran = statements.length - pending.length;
1487
+ const summary = `'${target.action}' on '${target.entityCode}' failed on MySQL after ${statements.length} DDL statement(s) had committed; ${ran} undone`;
1488
+ if (report.reverted) this.logger.warn(`${summary}.${report.dataNotReverted ? ' Backfilled values were not undone.' : ''}`);
1489
+ else this.logger.error(`${summary}, ${pending.length} still pending - the table and its metadata may disagree until they are run or the entity is repaired.`);
1490
+ return report;
1491
+ }
1492
+ withUndo(mapped, undo) {
1493
+ if (!undo) return mapped;
1494
+ const status = mapped instanceof _nestjs_common__rspack_import_1.HttpException ? mapped.getStatus() : 500;
1495
+ const original = mapped instanceof _nestjs_common__rspack_import_1.HttpException ? mapped.getResponse() : null;
1496
+ const body = typeof original === 'object' && original !== null ? original : {};
1497
+ if (undo.reverted && mapped instanceof _nestjs_common__rspack_import_1.HttpException) {
1498
+ return new _nestjs_common__rspack_import_1.HttpException({
1499
+ ...body,
1500
+ undo
1501
+ }, status);
1502
+ }
1503
+ if (undo.reverted) {
1504
+ return new _nestjs_common__rspack_import_1.InternalServerErrorException({
1505
+ message: 'The schema change failed and was rolled back',
1506
+ messageKey: _config_message_keys_js__rspack_import_11/* .SCHEMA_MESSAGES.FAILED */.Hu.FAILED,
1507
+ undo
1508
+ });
1509
+ }
1510
+ return new _nestjs_common__rspack_import_1.HttpException({
1511
+ message: 'The schema change failed and could not be fully undone.',
1512
+ messageKey: _config_message_keys_js__rspack_import_11/* .SCHEMA_MESSAGES.FAILED_NOT_REVERTED */.Hu.FAILED_NOT_REVERTED,
1513
+ cause: {
1514
+ messageKey: body.messageKey,
1515
+ details: body.details
1516
+ },
1517
+ undo
1518
+ }, status);
1519
+ }
1520
+ /** Written on its own connection - the failed transaction's own writes were rolled back. */ async logFailure(target, error, steps = [], undo = null) {
1521
+ try {
1522
+ const repo = await this.dataSourceProvider.getRepository(_entities_schema_change_log_entity_js__rspack_import_5/* .SchemaChangeLog */.W);
1523
+ const response = error instanceof _nestjs_common__rspack_import_1.HttpException ? error.getResponse() : null;
1524
+ const messageKey = typeof response === 'object' && response !== null ? response.messageKey : undefined;
1525
+ const message = typeof messageKey === 'string' ? messageKey : error instanceof Error ? error.message : String(error);
1526
+ const undoNote = undo ? ` [MySQL: ${undo.reverted ? 'statements that had run were undone' : `${undo.pendingSql.length} undo statement(s) still pending`}]` : '';
1527
+ await repo.save(repo.create({
1528
+ entityDefinitionId: target.entityDefinitionId,
1529
+ entityCode: target.entityCode,
1530
+ operation: this.operationFor(target.action),
1531
+ tableName: target.tableName,
1532
+ fieldDefinitionId: null,
1533
+ diff: undo ? {
1534
+ action: target.action,
1535
+ undo
1536
+ } : {
1537
+ action: target.action
1538
+ },
1539
+ generatedSql: steps.flatMap((s)=>s.sql),
1540
+ downSql: undo?.pendingSql.length ? undo.pendingSql : null,
1541
+ status: 'FAILED',
1542
+ errorMessage: `${message}${undoNote}`.slice(0, 2000),
1543
+ performedById: target.user?.id ?? null
1544
+ }));
1545
+ } catch (logError) {
1546
+ this.logger.error(`Could not record failed schema change: ${logError.message}`);
1547
+ }
1548
+ }
1549
+ operationFor(action) {
1550
+ const map = {
1551
+ create_entity: _enums_ddl_operation_enum_js__rspack_import_12/* .DdlOperation.CREATE_TABLE */.i.CREATE_TABLE,
1552
+ add_field: _enums_ddl_operation_enum_js__rspack_import_12/* .DdlOperation.ADD_COLUMN */.i.ADD_COLUMN,
1553
+ update_field: _enums_ddl_operation_enum_js__rspack_import_12/* .DdlOperation.ALTER_FIELD */.i.ALTER_FIELD,
1554
+ restore_field: _enums_ddl_operation_enum_js__rspack_import_12/* .DdlOperation.RESTORE_FIELD */.i.RESTORE_FIELD,
1555
+ deprecate_field: _enums_ddl_operation_enum_js__rspack_import_12/* .DdlOperation.MARK_DEPRECATED */.i.MARK_DEPRECATED,
1556
+ purge_field: _enums_ddl_operation_enum_js__rspack_import_12/* .DdlOperation.DROP_COLUMN */.i.DROP_COLUMN,
1557
+ update_entity: _enums_ddl_operation_enum_js__rspack_import_12/* .DdlOperation.ALTER_ENTITY */.i.ALTER_ENTITY,
1558
+ drop_entity: _enums_ddl_operation_enum_js__rspack_import_12/* .DdlOperation.DROP_TABLE */.i.DROP_TABLE,
1559
+ repair: _enums_ddl_operation_enum_js__rspack_import_12/* .DdlOperation.REPAIR */.i.REPAIR
1560
+ };
1561
+ return map[action] ?? _enums_ddl_operation_enum_js__rspack_import_12/* .DdlOperation.ALTER_ENTITY */.i.ALTER_ENTITY;
1562
+ }
1563
+ // ── internals ─────────────────────────────────────────────────────────────────────
1564
+ newState(target, impact) {
1565
+ return {
1566
+ target,
1567
+ impact,
1568
+ steps: [],
1569
+ downSql: [],
1570
+ /** Per DDL step that ran for real, its reverse statements in the order to run them. */ undo: [],
1571
+ dataSteps: 0,
1572
+ warnings: [],
1573
+ blockers: [],
1574
+ affectedRows: null,
1575
+ destructive: false
1576
+ };
1577
+ }
1578
+ toPlan(target, state) {
1579
+ return {
1580
+ action: target.action,
1581
+ entityCode: target.entityCode,
1582
+ tableName: target.tableName,
1583
+ steps: state.steps,
1584
+ downSql: state.downSql,
1585
+ warnings: state.warnings,
1586
+ blockers: state.blockers,
1587
+ impact: state.impact,
1588
+ affectedRows: state.affectedRows,
1589
+ destructive: state.destructive,
1590
+ metadataOnly: !state.steps.some((s)=>s.sql.length > 0)
1591
+ };
1592
+ }
1593
+ buildContext(qr, driver, simulate, state) {
1594
+ const escape = (name)=>qr.connection.driver.escape(name);
1595
+ const recordUndo = (reverse)=>{
1596
+ if (!reverse.length) return;
1597
+ state.undo.push(reverse);
1598
+ state.downSql.unshift(...reverse.map(format));
1599
+ };
1600
+ return {
1601
+ qr,
1602
+ driver,
1603
+ get blocked () {
1604
+ return state.blockers.length > 0;
1605
+ },
1606
+ q: escape,
1607
+ ddl: async (description, fn)=>{
1608
+ // TypeORM records every schema statement and its reverse in the SQL memory in both modes;
1609
+ // only memory mode skips running them.
1610
+ qr.clearSqlMemory();
1611
+ if (simulate) {
1612
+ await fn();
1613
+ const memory = qr.getMemorySql();
1614
+ state.steps.push({
1615
+ description,
1616
+ sql: memory.upQueries.map(format)
1617
+ });
1618
+ state.downSql.unshift(...memory.downQueries.map(format).toReversed());
1619
+ qr.clearSqlMemory();
1620
+ return;
1621
+ }
1622
+ const captured = [];
1623
+ const original = qr.query.bind(qr);
1624
+ let failed = false;
1625
+ qr.query = (sql, params, ...rest)=>{
1626
+ if (!isReadOrSession(sql)) captured.push(formatSql(sql, params));
1627
+ return original(sql, params, ...rest);
1628
+ };
1629
+ try {
1630
+ await fn();
1631
+ } catch (error) {
1632
+ failed = true;
1633
+ throw error;
1634
+ } finally{
1635
+ qr.query = original;
1636
+ const down = qr.getMemorySql().downQueries.map((q)=>({
1637
+ query: q.query,
1638
+ parameters: q.parameters
1639
+ }));
1640
+ qr.clearSqlMemory();
1641
+ // TypeORM pairs each statement with its reverse; on failure the last captured one is the one that failed.
1642
+ const ran = failed ? Math.max(captured.length - 1, 0) : down.length;
1643
+ state.steps.push({
1644
+ description,
1645
+ sql: captured
1646
+ });
1647
+ recordUndo(down.slice(0, ran).toReversed());
1648
+ }
1649
+ },
1650
+ rawDdl: async (description, sql, downSql = [])=>{
1651
+ if (simulate) {
1652
+ state.steps.push({
1653
+ description,
1654
+ sql
1655
+ });
1656
+ state.downSql.unshift(...downSql.toReversed());
1657
+ return;
1658
+ }
1659
+ let ran = 0;
1660
+ try {
1661
+ for (const statement of sql){
1662
+ await qr.query(statement);
1663
+ ran += 1;
1664
+ }
1665
+ } finally{
1666
+ state.steps.push({
1667
+ description,
1668
+ sql: sql.slice(0, ran + (ran < sql.length ? 1 : 0))
1669
+ });
1670
+ recordUndo(downSql.slice(0, ran).toReversed().map((query)=>({
1671
+ query
1672
+ })));
1673
+ }
1674
+ },
1675
+ data: async (description, sqlPreview, fn)=>{
1676
+ if (!simulate) {
1677
+ await fn();
1678
+ state.dataSteps += 1;
1679
+ }
1680
+ state.steps.push({
1681
+ description,
1682
+ sql: [
1683
+ sqlPreview
1684
+ ]
1685
+ });
1686
+ },
1687
+ metadata: async (fn)=>{
1688
+ if (!simulate) await fn();
1689
+ },
1690
+ warn: (message)=>{
1691
+ if (!hasMessage(state.warnings, message)) state.warnings.push(message);
1692
+ },
1693
+ block: (message)=>{
1694
+ if (!hasMessage(state.blockers, message)) state.blockers.push(message);
1695
+ },
1696
+ setAffectedRows: (count)=>{
1697
+ state.affectedRows = count;
1698
+ },
1699
+ markDestructive: ()=>{
1700
+ state.destructive = true;
1701
+ }
1702
+ };
1703
+ }
1704
+ }
1705
+ SchemaChangeExecutor = _ts_decorate([
1706
+ (0,_nestjs_common__rspack_import_1.Injectable)({
1707
+ scope: _nestjs_common__rspack_import_1.Scope.REQUEST
1708
+ }),
1709
+ _ts_param(0, (0,_nestjs_common__rspack_import_1.Inject)(_entity_builder_datasource_provider_js__rspack_import_8/* .EntityBuilderDataSourceProvider */.D)),
1710
+ _ts_param(1, (0,_nestjs_common__rspack_import_1.Inject)(_schema_dialect_adapter_service_js__rspack_import_9/* .SchemaDialectAdapterService */.I)),
1711
+ _ts_param(2, (0,_nestjs_common__rspack_import_1.Inject)(_schema_registry_service_js__rspack_import_10/* .SchemaRegistryService */.C)),
1712
+ _ts_param(3, (0,_nestjs_common__rspack_import_1.Inject)(_definition_cache_service_js__rspack_import_7/* .DefinitionCacheService */.V)),
1713
+ _ts_metadata("design:type", Function),
1714
+ _ts_metadata("design:paramtypes", [
1715
+ typeof _entity_builder_datasource_provider_js__rspack_import_8/* .EntityBuilderDataSourceProvider */.D === "undefined" ? Object : _entity_builder_datasource_provider_js__rspack_import_8/* .EntityBuilderDataSourceProvider */.D,
1716
+ typeof _schema_dialect_adapter_service_js__rspack_import_9/* .SchemaDialectAdapterService */.I === "undefined" ? Object : _schema_dialect_adapter_service_js__rspack_import_9/* .SchemaDialectAdapterService */.I,
1717
+ typeof _schema_registry_service_js__rspack_import_10/* .SchemaRegistryService */.C === "undefined" ? Object : _schema_registry_service_js__rspack_import_10/* .SchemaRegistryService */.C,
1718
+ typeof _definition_cache_service_js__rspack_import_7/* .DefinitionCacheService */.V === "undefined" ? Object : _definition_cache_service_js__rspack_import_7/* .DefinitionCacheService */.V
1719
+ ])
1720
+ ], SchemaChangeExecutor);
1721
+
1722
+ __webpack_require__.d(__webpack_exports__, {
1723
+ T: () => (SchemaChangeExecutor),
1724
+ e: () => (relationTargetCodes)
1725
+ });
1726
+
1727
+
1728
+ },
1729
+ 7827(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
1730
+ /** `"Name", "Other"` - the impacted flow names; the translated message supplies the word "flows". */ const describeImpact = (impact)=>impact.map((i)=>`"${i.name}"`).join(', ');
1731
+
1732
+ __webpack_require__.d(__webpack_exports__, {
1733
+ }, {
1734
+ a: describeImpact
1735
+ });
1736
+
1737
+
1738
+ },
1739
+ 3606(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
1740
+ /* import */ var _flusys_nestjs_shared_classes__rspack_import_0 = __webpack_require__(6937);
1741
+ /* import */ var _flusys_nestjs_shared_utils__rspack_import_1 = __webpack_require__(9216);
1742
+ /* import */ var _nestjs_common__rspack_import_2 = __webpack_require__(6157);
1743
+ /* import */ var class_transformer__rspack_import_3 = __webpack_require__(5812);
1744
+ /* import */ var class_validator__rspack_import_4 = __webpack_require__(5421);
1745
+ /* import */ var typeorm__rspack_import_5 = __webpack_require__(7158);
1746
+ /* import */ var _config_message_keys_js__rspack_import_19 = __webpack_require__(5732);
1747
+ /* import */ var _dtos_schema_change_dto_js__rspack_import_6 = __webpack_require__(4945);
1748
+ /* import */ var _entities_entity_definition_entity_js__rspack_import_7 = __webpack_require__(3189);
1749
+ /* import */ var _entities_field_definition_entity_js__rspack_import_8 = __webpack_require__(2206);
1750
+ /* import */ var _entities_schema_change_log_entity_js__rspack_import_9 = __webpack_require__(875);
1751
+ /* import */ var _enums_ddl_operation_enum_js__rspack_import_21 = __webpack_require__(9949);
1752
+ /* import */ var _enums_entity_status_enum_js__rspack_import_23 = __webpack_require__(1313);
1753
+ /* import */ var _enums_field_type_enum_js__rspack_import_20 = __webpack_require__(9614);
1754
+ /* import */ var _entity_builder_datasource_provider_js__rspack_import_10 = __webpack_require__(424);
1755
+ /* import */ var _entity_permission_service_js__rspack_import_11 = __webpack_require__(1462);
1756
+ /* import */ var _field_value_validator_js__rspack_import_12 = __webpack_require__(3525);
1757
+ /* import */ var _field_type_conversion_js__rspack_import_13 = __webpack_require__(4984);
1758
+ /* import */ var _identifier_rules_js__rspack_import_14 = __webpack_require__(413);
1759
+ /* import */ var _reference_scanner_service_js__rspack_import_15 = __webpack_require__(921);
1760
+ /* import */ var _schema_change_executor_service_js__rspack_import_16 = __webpack_require__(6605);
1761
+ /* import */ var _schema_change_types_js__rspack_import_22 = __webpack_require__(7827);
1762
+ /* import */ var _schema_columns_js__rspack_import_17 = __webpack_require__(5313);
1763
+ /* import */ var _schema_dialect_adapter_service_js__rspack_import_18 = __webpack_require__(7259);
1764
+ function _ts_decorate(decorators, target, key, desc) {
1765
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1766
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
1767
+ r = Reflect.decorate(decorators, target, key, desc);
1768
+ } else {
1769
+ for(var i = decorators.length - 1; i >= 0; i--){
1770
+ if (d = decorators[i]) {
1771
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1772
+ }
1773
+ }
1774
+ }
1775
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
1776
+ }
1777
+ function _ts_metadata(metadataKey, metadataValue) {
1778
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
1779
+ return Reflect.metadata(metadataKey, metadataValue);
1780
+ }
1781
+ }
1782
+ function _ts_param(paramIndex, decorator) {
1783
+ return function(target, key) {
1784
+ decorator(target, key, paramIndex);
1785
+ };
1786
+ }
1787
+
1788
+
1789
+
1790
+
1791
+
1792
+
1793
+
1794
+
1795
+
1796
+
1797
+
1798
+
1799
+
1800
+
1801
+
1802
+
1803
+
1804
+
1805
+
1806
+
1807
+
1808
+
1809
+
1810
+
1811
+ const entityNotFound = (id)=>new _nestjs_common__rspack_import_2.NotFoundException({
1812
+ message: `Entity definition '${id}' not found.`,
1813
+ messageKey: _config_message_keys_js__rspack_import_19/* .ENTITY_DEFINITION_MESSAGES.NOT_FOUND */.pL.NOT_FOUND,
1814
+ messageVariables: {
1815
+ id
1816
+ }
1817
+ });
1818
+ const fieldNotFound = (id)=>new _nestjs_common__rspack_import_2.NotFoundException({
1819
+ message: `Field definition '${id}' not found.`,
1820
+ messageKey: _config_message_keys_js__rspack_import_19/* .FIELD_DEFINITION_MESSAGES.NOT_FOUND */.oc.NOT_FOUND,
1821
+ messageVariables: {
1822
+ id
1823
+ }
1824
+ });
1825
+ const DESTRUCTIVE_ACTIONS = [
1826
+ _dtos_schema_change_dto_js__rspack_import_6/* .SchemaChangeAction.DROP_ENTITY */.M3.DROP_ENTITY,
1827
+ _dtos_schema_change_dto_js__rspack_import_6/* .SchemaChangeAction.PURGE_FIELD */.M3.PURGE_FIELD
1828
+ ];
1829
+ const isDestructiveSchemaAction = (action)=>DESTRUCTIVE_ACTIONS.includes(action);
1830
+ const fieldLike = (field)=>({
1831
+ code: field.code,
1832
+ label: field.label ?? field.code,
1833
+ fieldType: field.fieldType,
1834
+ nullable: true,
1835
+ defaultValue: null,
1836
+ selectOptions: field.selectOptions ?? null,
1837
+ validationRules: field.validationRules ?? null
1838
+ });
1839
+ class SchemaEvolutionService {
1840
+ dataSourceProvider;
1841
+ adapter;
1842
+ executor;
1843
+ references;
1844
+ permissions;
1845
+ constructor(dataSourceProvider, adapter, executor, references, permissions){
1846
+ this.dataSourceProvider = dataSourceProvider;
1847
+ this.adapter = adapter;
1848
+ this.executor = executor;
1849
+ this.references = references;
1850
+ this.permissions = permissions;
1851
+ }
1852
+ // ── public API ──────────────────────────────────────────────────────────────────────
1853
+ async plan(request, user) {
1854
+ const prepared = await this.prepare(request, user);
1855
+ return this.executor.simulate(prepared.target, prepared.run, prepared.impact);
1856
+ }
1857
+ async apply(request, user) {
1858
+ const prepared = await this.prepare(request, user);
1859
+ const { plan, outcome } = await this.executor.apply(prepared.target, prepared.run, {
1860
+ confirm: request.confirm === true,
1861
+ impact: prepared.impact
1862
+ });
1863
+ return {
1864
+ ...plan,
1865
+ result: outcome.diff
1866
+ };
1867
+ }
1868
+ /** Compares the metadata with the real table and reports every difference. */ async inspect(entityDefinitionId) {
1869
+ const { definition, fields } = await this.loadEntity(entityDefinitionId);
1870
+ const driver = await this.dataSourceProvider.getDriver();
1871
+ const qr = await this.dataSourceProvider.getQueryRunner();
1872
+ await qr.connect();
1873
+ try {
1874
+ const table = await qr.getTable(definition.tableName);
1875
+ const findings = this.diff(definition, fields, table ?? undefined, driver);
1876
+ let rowCount = null;
1877
+ if (table) {
1878
+ const rows = await qr.query(`SELECT COUNT(*) AS c FROM ${qr.connection.driver.escape(definition.tableName)}`);
1879
+ rowCount = Number(rows[0]?.c ?? 0);
1880
+ }
1881
+ return {
1882
+ entityCode: definition.code,
1883
+ tableName: definition.tableName,
1884
+ healthy: findings.every((f)=>f.severity !== 'error'),
1885
+ rowCount,
1886
+ findings
1887
+ };
1888
+ } finally{
1889
+ await qr.release();
1890
+ }
1891
+ }
1892
+ /** Newest first. Includes failed attempts, with the SQL that was about to run. */ async history(entityDefinitionId, limit = 50) {
1893
+ const repo = await this.dataSourceProvider.getRepository(_entities_schema_change_log_entity_js__rspack_import_9/* .SchemaChangeLog */.W);
1894
+ return repo.find({
1895
+ select: {
1896
+ id: true,
1897
+ operation: true,
1898
+ status: true,
1899
+ tableName: true,
1900
+ generatedSql: true,
1901
+ downSql: true,
1902
+ errorMessage: true,
1903
+ diff: true,
1904
+ createdAt: true,
1905
+ performedById: true
1906
+ },
1907
+ where: {
1908
+ entityDefinitionId
1909
+ },
1910
+ order: {
1911
+ createdAt: 'DESC'
1912
+ },
1913
+ take: Math.min(Math.max(limit, 1), 200)
1914
+ });
1915
+ }
1916
+ // ── loading ─────────────────────────────────────────────────────────────────────────
1917
+ async loadEntity(entityDefinitionId) {
1918
+ if (!entityDefinitionId) {
1919
+ throw new _nestjs_common__rspack_import_2.BadRequestException({
1920
+ message: 'entityDefinitionId is required for this action.',
1921
+ messageKey: _config_message_keys_js__rspack_import_19/* .ENTITY_DEFINITION_MESSAGES.ID_REQUIRED */.pL.ID_REQUIRED
1922
+ });
1923
+ }
1924
+ return this.definitions((entity)=>this.dataSourceProvider.getRepository(entity), entityDefinitionId);
1925
+ }
1926
+ async loadField(fieldDefinitionId) {
1927
+ if (!fieldDefinitionId) {
1928
+ throw new _nestjs_common__rspack_import_2.BadRequestException({
1929
+ message: 'fieldDefinitionId is required for this action.',
1930
+ messageKey: _config_message_keys_js__rspack_import_19/* .FIELD_DEFINITION_MESSAGES.ID_REQUIRED */.oc.ID_REQUIRED
1931
+ });
1932
+ }
1933
+ const field = await (await this.dataSourceProvider.getRepository(_entities_field_definition_entity_js__rspack_import_8/* .FieldDefinition */.c)).findOne({
1934
+ where: {
1935
+ id: fieldDefinitionId
1936
+ }
1937
+ });
1938
+ if (!field) throw fieldNotFound(fieldDefinitionId);
1939
+ return {
1940
+ ...await this.loadEntity(field.entityDefinitionId),
1941
+ field
1942
+ };
1943
+ }
1944
+ async definitions(repositoryOf, entityDefinitionId, fieldDefinitionId) {
1945
+ const definition = await (await repositoryOf(_entities_entity_definition_entity_js__rspack_import_7/* .EntityDefinition */.f)).findOne({
1946
+ where: {
1947
+ id: entityDefinitionId
1948
+ }
1949
+ });
1950
+ if (!definition) throw entityNotFound(entityDefinitionId);
1951
+ const fields = await (await repositoryOf(_entities_field_definition_entity_js__rspack_import_8/* .FieldDefinition */.c)).find({
1952
+ where: {
1953
+ entityDefinitionId
1954
+ },
1955
+ order: {
1956
+ order: 'ASC'
1957
+ }
1958
+ });
1959
+ const field = fieldDefinitionId ? fields.find((f)=>f.id === fieldDefinitionId) : undefined;
1960
+ if (fieldDefinitionId && !field) throw fieldNotFound(fieldDefinitionId);
1961
+ return {
1962
+ definition,
1963
+ fields,
1964
+ field
1965
+ };
1966
+ }
1967
+ rejectUnknownKeys(changes, allowed, what) {
1968
+ const unknown = Object.keys(changes).filter((k)=>!allowed.includes(k));
1969
+ if (unknown.length) {
1970
+ throw new _nestjs_common__rspack_import_2.BadRequestException({
1971
+ message: `Cannot change ${what} property: ${unknown.join(', ')}. Allowed: ${allowed.join(', ')}.`,
1972
+ messageKey: _config_message_keys_js__rspack_import_19/* .SCHEMA_MESSAGES.UNKNOWN_CHANGE_PROPERTY */.Hu.UNKNOWN_CHANGE_PROPERTY,
1973
+ messageVariables: {
1974
+ what,
1975
+ properties: unknown.join(', '),
1976
+ allowed: allowed.join(', ')
1977
+ }
1978
+ });
1979
+ }
1980
+ }
1981
+ validateChanges(dto, changes) {
1982
+ const errors = (0,class_validator__rspack_import_4.validateSync)((0,class_transformer__rspack_import_3.plainToInstance)(dto, changes), {
1983
+ forbidUnknownValues: false
1984
+ });
1985
+ if (!errors.length) return;
1986
+ const properties = errors.map((e)=>e.property);
1987
+ throw new _nestjs_common__rspack_import_2.BadRequestException({
1988
+ message: `Invalid value for ${properties.map((p)=>`'${p}'`).join(', ')}.`,
1989
+ messageKey: _config_message_keys_js__rspack_import_19/* .SCHEMA_MESSAGES.INVALID_CHANGE_VALUE */.Hu.INVALID_CHANGE_VALUE,
1990
+ messageVariables: {
1991
+ property: properties.join(', ')
1992
+ },
1993
+ errors: properties.map((property)=>({
1994
+ field: property,
1995
+ messageKey: _config_message_keys_js__rspack_import_19/* .SCHEMA_MESSAGES.INVALID_CHANGE_VALUE */.Hu.INVALID_CHANGE_VALUE,
1996
+ messageVariables: {
1997
+ property
1998
+ }
1999
+ }))
2000
+ });
2001
+ }
2002
+ async current(ctx, request, entityDefinitionId, fieldDefinitionId) {
2003
+ const found = await this.definitions((entity)=>ctx.qr.manager.getRepository(entity), entityDefinitionId, fieldDefinitionId);
2004
+ if (request.expectedUpdatedAt) {
2005
+ await this.assertNotStale(ctx, fieldDefinitionId ? _entities_field_definition_entity_js__rspack_import_8/* .FieldDefinition */.c : _entities_entity_definition_entity_js__rspack_import_7/* .EntityDefinition */.f, fieldDefinitionId ?? entityDefinitionId, request.expectedUpdatedAt);
2006
+ }
2007
+ return found;
2008
+ }
2009
+ async assertNotStale(ctx, entity, id, expected) {
2010
+ const row = await ctx.qr.manager.getRepository(entity).findOne({
2011
+ select: {
2012
+ id: true,
2013
+ updatedAt: true
2014
+ },
2015
+ where: {
2016
+ id
2017
+ }
2018
+ });
2019
+ const updatedAt = row?.updatedAt ? new Date(row.updatedAt) : null;
2020
+ if (updatedAt && updatedAt.getTime() !== new Date(expected).getTime()) {
2021
+ throw new _nestjs_common__rspack_import_2.ConflictException({
2022
+ message: 'Someone else changed this definition since you opened it. Reload it and make your change again.',
2023
+ messageKey: _config_message_keys_js__rspack_import_19/* .SCHEMA_MESSAGES.STALE_DEFINITION */.Hu.STALE_DEFINITION,
2024
+ messageVariables: {
2025
+ updatedAt: updatedAt.toISOString()
2026
+ }
2027
+ });
2028
+ }
2029
+ }
2030
+ /** The field was renamed (or deprecated) by a change that committed after this request was checked. */ changedUnderneath(ctx, before, now) {
2031
+ if (now.code === before.code && !!now.deprecatedAt === !!before.deprecatedAt) return false;
2032
+ ctx.block((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_BLOCKER_MESSAGES.DEFINITION_CHANGED */.M3.DEFINITION_CHANGED));
2033
+ return true;
2034
+ }
2035
+ // ── dispatch ────────────────────────────────────────────────────────────────────────
2036
+ async prepare(request, user) {
2037
+ switch(request.action){
2038
+ case _dtos_schema_change_dto_js__rspack_import_6/* .SchemaChangeAction.ADD_FIELD */.M3.ADD_FIELD:
2039
+ return this.prepareAddField(request, user);
2040
+ case _dtos_schema_change_dto_js__rspack_import_6/* .SchemaChangeAction.UPDATE_FIELD */.M3.UPDATE_FIELD:
2041
+ return this.prepareUpdateField(request, user);
2042
+ case _dtos_schema_change_dto_js__rspack_import_6/* .SchemaChangeAction.DEPRECATE_FIELD */.M3.DEPRECATE_FIELD:
2043
+ return this.prepareDeprecateField(request, user);
2044
+ case _dtos_schema_change_dto_js__rspack_import_6/* .SchemaChangeAction.RESTORE_FIELD */.M3.RESTORE_FIELD:
2045
+ return this.prepareRestoreField(request, user);
2046
+ case _dtos_schema_change_dto_js__rspack_import_6/* .SchemaChangeAction.PURGE_FIELD */.M3.PURGE_FIELD:
2047
+ return this.preparePurgeField(request, user);
2048
+ case _dtos_schema_change_dto_js__rspack_import_6/* .SchemaChangeAction.UPDATE_ENTITY */.M3.UPDATE_ENTITY:
2049
+ return this.prepareUpdateEntity(request, user);
2050
+ case _dtos_schema_change_dto_js__rspack_import_6/* .SchemaChangeAction.DROP_ENTITY */.M3.DROP_ENTITY:
2051
+ return this.prepareDropEntity(request, user);
2052
+ case _dtos_schema_change_dto_js__rspack_import_6/* .SchemaChangeAction.REPAIR */.M3.REPAIR:
2053
+ return this.prepareRepair(request, user);
2054
+ }
2055
+ }
2056
+ target(action, definition, user, lockCodes = []) {
2057
+ return {
2058
+ action,
2059
+ entityDefinitionId: definition.id,
2060
+ entityCode: definition.code,
2061
+ tableName: definition.tableName,
2062
+ user,
2063
+ lockCodes
2064
+ };
2065
+ }
2066
+ // ── small SQL helpers (identifiers come from validated metadata and are escaped) ────
2067
+ // No placeholder rewriting here: prechecks embed regexes containing '?', which buildQuery would corrupt.
2068
+ async scalar(ctx, sql, params) {
2069
+ const rows = await ctx.qr.query(sql, params);
2070
+ return Number(Object.values(rows[0] ?? {
2071
+ c: 0
2072
+ })[0]);
2073
+ }
2074
+ /** A count that only feeds a warning: a failure reads as 0 and, thanks to the savepoint, leaves the change's transaction usable. */ advisoryScalar(ctx, sql, params) {
2075
+ return (0,_flusys_nestjs_shared_utils__rspack_import_1.withSavepoint)(ctx.qr, ()=>this.scalar(ctx, sql, params)).catch(()=>0);
2076
+ }
2077
+ paramValue(fieldType, value) {
2078
+ return fieldType === _enums_field_type_enum_js__rspack_import_20/* .FieldType.JSON */.P.JSON || fieldType === _enums_field_type_enum_js__rspack_import_20/* .FieldType.MULTI_SELECT */.P.MULTI_SELECT ? JSON.stringify(value) : value;
2079
+ }
2080
+ notNullSql(ctx, table, column, fieldType, notNull) {
2081
+ if (ctx.driver === 'postgres') {
2082
+ return `ALTER TABLE ${ctx.q(table)} ALTER COLUMN ${ctx.q(column)} ${notNull ? 'SET' : 'DROP'} NOT NULL`;
2083
+ }
2084
+ return `ALTER TABLE ${ctx.q(table)} MODIFY ${ctx.q(column)} ${(0,_schema_columns_js__rspack_import_17/* .sqlTypeFor */.cg)(fieldType, ctx.driver, this.adapter)} ${notNull ? 'NOT NULL' : 'NULL'}`;
2085
+ }
2086
+ /** Makes a column NOT NULL (or nullable again), with the reverse statement for the plan. */ setRequired(ctx, table, column, fieldType, required, step = required ? _config_message_keys_js__rspack_import_19/* .SCHEMA_STEP_MESSAGES.MAKE_REQUIRED */.EQ.MAKE_REQUIRED : _config_message_keys_js__rspack_import_19/* .SCHEMA_STEP_MESSAGES.MAKE_OPTIONAL */.EQ.MAKE_OPTIONAL) {
2087
+ return ctx.rawDdl((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(step, {
2088
+ column
2089
+ }), [
2090
+ this.notNullSql(ctx, table, column, fieldType, required)
2091
+ ], [
2092
+ this.notNullSql(ctx, table, column, fieldType, !required)
2093
+ ]);
2094
+ }
2095
+ checkValue(field, value) {
2096
+ const { errors } = (0,_field_value_validator_js__rspack_import_12/* .validateRecord */.e)([
2097
+ fieldLike(field)
2098
+ ], {
2099
+ [field.code]: value
2100
+ }, 'insert');
2101
+ return errors[0] ? (0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(errors[0].messageKey, errors[0].messageVariables) : null;
2102
+ }
2103
+ async requireTable(ctx, tableName) {
2104
+ const table = await ctx.qr.getTable(tableName);
2105
+ if (!table) {
2106
+ ctx.block((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_BLOCKER_MESSAGES.TABLE_MISSING */.M3.TABLE_MISSING, {
2107
+ table: tableName
2108
+ }));
2109
+ }
2110
+ return table ?? undefined;
2111
+ }
2112
+ /** How many values a unique constraint on `code` would clash on. */ countDuplicates(ctx, table, code) {
2113
+ const key = ctx.q(code);
2114
+ return this.scalar(ctx, `SELECT COUNT(*) AS c FROM (SELECT ${key} FROM ${ctx.q(table)} WHERE ${key} IS NOT NULL GROUP BY ${key} HAVING COUNT(*) > 1) d`);
2115
+ }
2116
+ async dropUniques(ctx, table, code) {
2117
+ const drop = (columnNames)=>(0,_schema_columns_js__rspack_import_17/* .sameColumns */.G7)(columnNames, [
2118
+ code
2119
+ ]);
2120
+ for (const uq of table.uniques.filter((u)=>drop(u.columnNames)))await ctx.qr.dropUniqueConstraint(table, uq);
2121
+ for (const idx of table.indices.filter((i)=>i.isUnique && drop(i.columnNames)))await ctx.qr.dropIndex(table, idx);
2122
+ }
2123
+ hasUnique(table, code) {
2124
+ if (table.uniques.some((u)=>(0,_schema_columns_js__rspack_import_17/* .sameColumns */.G7)(u.columnNames, [
2125
+ code
2126
+ ]))) return true;
2127
+ if (table.indices.some((i)=>i.isUnique && (0,_schema_columns_js__rspack_import_17/* .sameColumns */.G7)(i.columnNames, [
2128
+ code
2129
+ ]))) return true;
2130
+ return !!table.findColumnByName(code)?.isUnique;
2131
+ }
2132
+ indexOn(table, column, unique) {
2133
+ return table.indices.filter((i)=>i.columnNames.length === 1 && i.columnNames[0] === column && i.isUnique === unique);
2134
+ }
2135
+ // ── add_field ───────────────────────────────────────────────────────────────────────
2136
+ async prepareAddField(request, user) {
2137
+ const { definition: loaded } = await this.loadEntity(request.entityDefinitionId);
2138
+ const spec = request.field;
2139
+ if (!spec) {
2140
+ throw new _nestjs_common__rspack_import_2.BadRequestException({
2141
+ message: "add_field needs a 'field' definition.",
2142
+ messageKey: _config_message_keys_js__rspack_import_19/* .FIELD_DEFINITION_MESSAGES.DEFINITION_REQUIRED */.oc.DEFINITION_REQUIRED
2143
+ });
2144
+ }
2145
+ (0,_identifier_rules_js__rspack_import_14/* .assertValidIdentifier */.kV)(spec.code, 'field');
2146
+ (0,_identifier_rules_js__rspack_import_14/* .assertIndexableField */.fY)(spec);
2147
+ const lockCodes = await (0,_schema_change_executor_service_js__rspack_import_16/* .relationTargetCodes */.e)(this.dataSourceProvider, [
2148
+ spec.relationTargetEntityId
2149
+ ]);
2150
+ const run = async (ctx)=>{
2151
+ const { definition, fields } = await this.current(ctx, request, loaded.id);
2152
+ const existing = fields.find((f)=>f.code === spec.code);
2153
+ if (existing) {
2154
+ ctx.block((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(existing.deprecatedAt ? _config_message_keys_js__rspack_import_19/* .SCHEMA_BLOCKER_MESSAGES.FIELD_EXISTS_DEPRECATED */.M3.FIELD_EXISTS_DEPRECATED : _config_message_keys_js__rspack_import_19/* .SCHEMA_BLOCKER_MESSAGES.FIELD_EXISTS */.M3.FIELD_EXISTS, {
2155
+ code: spec.code
2156
+ }));
2157
+ }
2158
+ const nullable = spec.nullable ?? true;
2159
+ const unique = spec.unique ?? false;
2160
+ const dbType = this.adapter.mapFieldType(spec.fieldType, ctx.driver);
2161
+ if (spec.relationTargetEntityId) {
2162
+ const target = await ctx.qr.manager.getRepository(_entities_entity_definition_entity_js__rspack_import_7/* .EntityDefinition */.f).findOne({
2163
+ where: {
2164
+ id: spec.relationTargetEntityId
2165
+ }
2166
+ });
2167
+ if (!target) ctx.block((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_BLOCKER_MESSAGES.RELATION_TARGET_MISSING */.M3.RELATION_TARGET_MISSING));
2168
+ }
2169
+ if ((spec.fieldType === _enums_field_type_enum_js__rspack_import_20/* .FieldType.SINGLE_SELECT */.P.SINGLE_SELECT || spec.fieldType === _enums_field_type_enum_js__rspack_import_20/* .FieldType.MULTI_SELECT */.P.MULTI_SELECT) && !spec.selectOptions?.length) {
2170
+ ctx.warn((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_WARNING_MESSAGES.NO_SELECT_OPTIONS_YET */.Uu.NO_SELECT_OPTIONS_YET));
2171
+ }
2172
+ if (spec.defaultValue !== undefined && spec.defaultValue !== null) {
2173
+ const problem = this.checkValue({
2174
+ ...spec,
2175
+ code: spec.code,
2176
+ fieldType: spec.fieldType
2177
+ }, spec.defaultValue);
2178
+ if (problem) ctx.block((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_BLOCKER_MESSAGES.DEFAULT_INVALID */.M3.DEFAULT_INVALID, {
2179
+ problem
2180
+ }));
2181
+ }
2182
+ const table = await this.requireTable(ctx, definition.tableName);
2183
+ const rows = table ? await this.scalar(ctx, `SELECT COUNT(*) AS c FROM ${ctx.q(definition.tableName)}`) : 0;
2184
+ const backfill = request.backfillValue ?? spec.defaultValue ?? null;
2185
+ if (!nullable && rows > 0) {
2186
+ if (backfill === null) {
2187
+ ctx.block((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_BLOCKER_MESSAGES.REQUIRED_NEEDS_VALUE */.M3.REQUIRED_NEEDS_VALUE, {
2188
+ count: rows
2189
+ }));
2190
+ } else {
2191
+ const problem = this.checkValue({
2192
+ ...spec,
2193
+ code: spec.code,
2194
+ fieldType: spec.fieldType
2195
+ }, backfill);
2196
+ if (problem) ctx.block((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_BLOCKER_MESSAGES.BACKFILL_INVALID */.M3.BACKFILL_INVALID, {
2197
+ problem
2198
+ }));
2199
+ }
2200
+ }
2201
+ // Every existing row gets the same backfill value, so two rows or more would clash.
2202
+ if (unique && backfill !== null && rows > 1) {
2203
+ ctx.block((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_BLOCKER_MESSAGES.UNIQUE_BACKFILL_CONFLICT */.M3.UNIQUE_BACKFILL_CONFLICT));
2204
+ }
2205
+ if (ctx.blocked || !table) {
2206
+ return {
2207
+ operation: _enums_ddl_operation_enum_js__rspack_import_21/* .DdlOperation.ADD_COLUMN */.i.ADD_COLUMN,
2208
+ diff: {}
2209
+ };
2210
+ }
2211
+ const column = (0,_schema_columns_js__rspack_import_17/* .buildFieldColumn */.fu)({
2212
+ code: spec.code,
2213
+ fieldType: spec.fieldType,
2214
+ dbType,
2215
+ nullable,
2216
+ unique
2217
+ }, ctx.driver, this.adapter, {
2218
+ enforceNotNull: false,
2219
+ withUnique: false
2220
+ });
2221
+ await ctx.ddl((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_STEP_MESSAGES.ADD_COLUMN */.EQ.ADD_COLUMN, {
2222
+ column: spec.code
2223
+ }), async ()=>{
2224
+ await ctx.qr.addColumn(table, column);
2225
+ });
2226
+ if (!nullable && rows > 0) {
2227
+ await ctx.data((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_STEP_MESSAGES.BACKFILL_EXISTING */.EQ.BACKFILL_EXISTING, {
2228
+ count: rows
2229
+ }), `UPDATE ${ctx.q(definition.tableName)} SET ${ctx.q(spec.code)} = ${this.adapter.sqlLiteral(this.paramValue(spec.fieldType, backfill), ctx.driver)}`, async ()=>{
2230
+ await ctx.qr.query((0,_flusys_nestjs_shared_classes__rspack_import_0.buildQuery)(`UPDATE ${ctx.q(definition.tableName)} SET ${ctx.q(spec.code)} = ?`, ctx.driver), [
2231
+ this.paramValue(spec.fieldType, backfill)
2232
+ ]);
2233
+ });
2234
+ }
2235
+ if (!nullable) {
2236
+ await this.setRequired(ctx, definition.tableName, spec.code, spec.fieldType, true);
2237
+ }
2238
+ if (unique) {
2239
+ await ctx.ddl((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_STEP_MESSAGES.ADD_UNIQUE */.EQ.ADD_UNIQUE, {
2240
+ column: spec.code
2241
+ }), async ()=>{
2242
+ await (0,_schema_columns_js__rspack_import_17/* .addUnique */.$6)(ctx.qr, table, spec.code, ctx.driver, this.adapter);
2243
+ });
2244
+ }
2245
+ if (spec.isIndexed && !unique) {
2246
+ await ctx.ddl((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_STEP_MESSAGES.ADD_INDEX */.EQ.ADD_INDEX, {
2247
+ column: spec.code
2248
+ }), async ()=>{
2249
+ await ctx.qr.createIndex(table, (0,_schema_columns_js__rspack_import_17/* .plainIndex */.v7)(definition.tableName, spec.code, ctx.driver, this.adapter));
2250
+ });
2251
+ }
2252
+ let fieldId = null;
2253
+ await ctx.metadata(async ()=>{
2254
+ const repo = ctx.qr.manager.getRepository(_entities_field_definition_entity_js__rspack_import_8/* .FieldDefinition */.c);
2255
+ const saved = await repo.save(repo.create({
2256
+ entityDefinitionId: definition.id,
2257
+ code: spec.code,
2258
+ label: spec.label,
2259
+ fieldType: spec.fieldType,
2260
+ dbType,
2261
+ nullable,
2262
+ unique,
2263
+ isIndexed: spec.isIndexed ?? false,
2264
+ defaultValue: spec.defaultValue ?? null,
2265
+ validationRules: spec.validationRules ?? null,
2266
+ selectOptions: spec.selectOptions ?? null,
2267
+ relationTargetEntityId: spec.relationTargetEntityId ?? null,
2268
+ order: spec.order ?? Math.max(-1, ...fields.map((f)=>f.order)) + 1,
2269
+ uiConfig: spec.uiConfig ?? null,
2270
+ isSearchable: spec.isSearchable ?? false,
2271
+ isSystemField: false,
2272
+ deprecatedAt: null
2273
+ }));
2274
+ fieldId = saved.id;
2275
+ });
2276
+ return {
2277
+ operation: _enums_ddl_operation_enum_js__rspack_import_21/* .DdlOperation.ADD_COLUMN */.i.ADD_COLUMN,
2278
+ fieldDefinitionId: fieldId,
2279
+ diff: {
2280
+ field: {
2281
+ code: spec.code,
2282
+ fieldType: spec.fieldType,
2283
+ nullable,
2284
+ unique
2285
+ },
2286
+ backfilledRows: !nullable ? rows : 0
2287
+ }
2288
+ };
2289
+ };
2290
+ return {
2291
+ target: this.target('add_field', loaded, user, lockCodes),
2292
+ run,
2293
+ impact: []
2294
+ };
2295
+ }
2296
+ // ── update_field ────────────────────────────────────────────────────────────────────
2297
+ async prepareUpdateField(request, user) {
2298
+ const { field: loadedField, definition: loaded } = await this.loadField(request.fieldDefinitionId);
2299
+ const changes = request.changes ?? {};
2300
+ this.rejectUnknownKeys(changes, _dtos_schema_change_dto_js__rspack_import_6/* .FIELD_CHANGE_KEYS */.bD, 'field');
2301
+ this.validateChanges(_dtos_schema_change_dto_js__rspack_import_6/* .FieldChangesDto */.Pr, changes);
2302
+ if (loadedField.deprecatedAt) {
2303
+ throw new _nestjs_common__rspack_import_2.BadRequestException({
2304
+ message: 'A deprecated field cannot be changed. Restore it first.',
2305
+ messageKey: _config_message_keys_js__rspack_import_19/* .FIELD_DEFINITION_MESSAGES.DEPRECATED_LOCKED */.oc.DEPRECATED_LOCKED
2306
+ });
2307
+ }
2308
+ const newCode = typeof changes.code === 'string' && changes.code !== loadedField.code ? changes.code : null;
2309
+ if (newCode) (0,_identifier_rules_js__rspack_import_14/* .assertValidIdentifier */.kV)(newCode, 'field');
2310
+ const structuralKeys = (field)=>[
2311
+ 'fieldType',
2312
+ 'nullable',
2313
+ 'unique',
2314
+ 'isIndexed'
2315
+ ].filter((k)=>k in changes && changes[k] !== field[k]);
2316
+ const requested = structuralKeys(loadedField);
2317
+ if (newCode && requested.length) {
2318
+ throw new _nestjs_common__rspack_import_2.BadRequestException({
2319
+ message: `Rename '${loadedField.code}' in its own change - it cannot be combined with: ${requested.join(', ')}.`,
2320
+ messageKey: _config_message_keys_js__rspack_import_19/* .FIELD_DEFINITION_MESSAGES.RENAME_ALONE */.oc.RENAME_ALONE,
2321
+ messageVariables: {
2322
+ field: loadedField.code,
2323
+ changes: requested.join(', ')
2324
+ }
2325
+ });
2326
+ }
2327
+ if ([
2328
+ 'fieldType',
2329
+ 'unique',
2330
+ 'isIndexed'
2331
+ ].some((k)=>k in changes)) {
2332
+ (0,_identifier_rules_js__rspack_import_14/* .assertIndexableField */.fY)({
2333
+ ...loadedField,
2334
+ ...changes,
2335
+ code: loadedField.code
2336
+ });
2337
+ }
2338
+ const targetType = changes.fieldType ?? loadedField.fieldType;
2339
+ const newTargetId = typeof changes.relationTargetEntityId === 'string' ? changes.relationTargetEntityId : null;
2340
+ if (newTargetId && targetType !== _enums_field_type_enum_js__rspack_import_20/* .FieldType.RELATION */.P.RELATION) {
2341
+ throw new _nestjs_common__rspack_import_2.BadRequestException({
2342
+ message: 'relationTargetEntityId can only be set on a RELATION field.',
2343
+ messageKey: _config_message_keys_js__rspack_import_19/* .SCHEMA_MESSAGES.INVALID_CHANGE_VALUE */.Hu.INVALID_CHANGE_VALUE,
2344
+ messageVariables: {
2345
+ property: 'relationTargetEntityId'
2346
+ }
2347
+ });
2348
+ }
2349
+ const lockCodes = await (0,_schema_change_executor_service_js__rspack_import_16/* .relationTargetCodes */.e)(this.dataSourceProvider, [
2350
+ newTargetId
2351
+ ]);
2352
+ const impact = newCode || changes.fieldType !== undefined ? await this.references.forField(loaded.code, loadedField.code) : [];
2353
+ const run = async (ctx)=>{
2354
+ const { definition, fields, field } = await this.current(ctx, request, loaded.id, loadedField.id);
2355
+ if (this.changedUnderneath(ctx, loadedField, field)) {
2356
+ return {
2357
+ operation: _enums_ddl_operation_enum_js__rspack_import_21/* .DdlOperation.ALTER_FIELD */.i.ALTER_FIELD,
2358
+ fieldDefinitionId: field.id,
2359
+ diff: {}
2360
+ };
2361
+ }
2362
+ const structural = structuralKeys(field);
2363
+ const merged = {
2364
+ ...field,
2365
+ ...changes
2366
+ };
2367
+ const patch = {};
2368
+ const table = structural.length || newCode ? await this.requireTable(ctx, definition.tableName) : undefined;
2369
+ const column = table?.findColumnByName(field.code);
2370
+ if ((structural.length || newCode) && table && !column) {
2371
+ ctx.block((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_BLOCKER_MESSAGES.COLUMN_MISSING */.M3.COLUMN_MISSING, {
2372
+ column: field.code
2373
+ }));
2374
+ }
2375
+ // ── plain metadata ──
2376
+ for (const key of [
2377
+ 'label',
2378
+ 'order',
2379
+ 'uiConfig',
2380
+ 'isSearchable'
2381
+ ]){
2382
+ if (key in changes) patch[key] = changes[key];
2383
+ }
2384
+ if ('selectOptions' in changes) {
2385
+ patch.selectOptions = changes.selectOptions;
2386
+ if (merged.fieldType === _enums_field_type_enum_js__rspack_import_20/* .FieldType.SINGLE_SELECT */.P.SINGLE_SELECT && Array.isArray(changes.selectOptions) && changes.selectOptions.length && !ctx.blocked) {
2387
+ const values = changes.selectOptions.map((o)=>String(o.value));
2388
+ const stray = await this.advisoryScalar(ctx, (0,_flusys_nestjs_shared_classes__rspack_import_0.buildQuery)(`SELECT COUNT(*) AS c FROM ${ctx.q(definition.tableName)} WHERE ${ctx.q(field.code)} IS NOT NULL AND ${ctx.q(field.code)} NOT IN (${values.map(()=>'?').join(', ')})`, ctx.driver), values);
2389
+ if (stray > 0) ctx.warn((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_WARNING_MESSAGES.STRAY_VALUES */.Uu.STRAY_VALUES, {
2390
+ count: stray
2391
+ }));
2392
+ }
2393
+ }
2394
+ if ('validationRules' in changes) {
2395
+ patch.validationRules = changes.validationRules;
2396
+ const rules = changes.validationRules ?? {};
2397
+ const isNumber = merged.fieldType === _enums_field_type_enum_js__rspack_import_20/* .FieldType.INTEGER */.P.INTEGER || merged.fieldType === _enums_field_type_enum_js__rspack_import_20/* .FieldType.DECIMAL */.P.DECIMAL;
2398
+ const violating = [];
2399
+ if (isNumber && typeof rules.min === 'number') violating.push(`${ctx.q(field.code)} < ${Number(rules.min)}`);
2400
+ if (isNumber && typeof rules.max === 'number') violating.push(`${ctx.q(field.code)} > ${Number(rules.max)}`);
2401
+ if (!isNumber && typeof rules.minLength === 'number') violating.push(`CHAR_LENGTH(${ctx.q(field.code)}) < ${Number(rules.minLength)}`);
2402
+ if (!isNumber && typeof rules.maxLength === 'number') violating.push(`CHAR_LENGTH(${ctx.q(field.code)}) > ${Number(rules.maxLength)}`);
2403
+ if (violating.length && [
2404
+ _enums_field_type_enum_js__rspack_import_20/* .FieldType.INTEGER */.P.INTEGER,
2405
+ _enums_field_type_enum_js__rspack_import_20/* .FieldType.DECIMAL */.P.DECIMAL,
2406
+ _enums_field_type_enum_js__rspack_import_20/* .FieldType.TEXT */.P.TEXT,
2407
+ _enums_field_type_enum_js__rspack_import_20/* .FieldType.LONG_TEXT */.P.LONG_TEXT,
2408
+ _enums_field_type_enum_js__rspack_import_20/* .FieldType.EMAIL */.P.EMAIL
2409
+ ].includes(merged.fieldType)) {
2410
+ const bad = await this.advisoryScalar(ctx, `SELECT COUNT(*) AS c FROM ${ctx.q(definition.tableName)} WHERE ${ctx.q(field.code)} IS NOT NULL AND (${violating.join(' OR ')})`);
2411
+ if (bad > 0) ctx.warn((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_WARNING_MESSAGES.RULES_VIOLATED */.Uu.RULES_VIOLATED, {
2412
+ count: bad
2413
+ }));
2414
+ }
2415
+ }
2416
+ // ── relation target ──
2417
+ if (merged.fieldType === _enums_field_type_enum_js__rspack_import_20/* .FieldType.RELATION */.P.RELATION) {
2418
+ const targetId = 'relationTargetEntityId' in changes ? changes.relationTargetEntityId : field.relationTargetEntityId;
2419
+ const becomesRelation = field.fieldType !== _enums_field_type_enum_js__rspack_import_20/* .FieldType.RELATION */.P.RELATION;
2420
+ if (!targetId && (becomesRelation || 'relationTargetEntityId' in changes)) {
2421
+ ctx.block((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_BLOCKER_MESSAGES.RELATION_TARGET_REQUIRED */.M3.RELATION_TARGET_REQUIRED, {
2422
+ field: field.code
2423
+ }));
2424
+ } else if (targetId && (becomesRelation || targetId !== field.relationTargetEntityId)) {
2425
+ const target = await ctx.qr.manager.getRepository(_entities_entity_definition_entity_js__rspack_import_7/* .EntityDefinition */.f).findOne({
2426
+ where: {
2427
+ id: targetId
2428
+ }
2429
+ });
2430
+ if (!target) ctx.block((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_BLOCKER_MESSAGES.RELATION_TARGET_MISSING */.M3.RELATION_TARGET_MISSING));
2431
+ else if (target.id !== field.relationTargetEntityId) patch.relationTargetEntityId = target.id;
2432
+ }
2433
+ } else if (field.relationTargetEntityId && changes.fieldType !== undefined) {
2434
+ patch.relationTargetEntityId = null;
2435
+ }
2436
+ if ('defaultValue' in changes) {
2437
+ if (changes.defaultValue !== null && changes.defaultValue !== undefined) {
2438
+ const problem = this.checkValue(merged, changes.defaultValue);
2439
+ if (problem) ctx.block((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_BLOCKER_MESSAGES.DEFAULT_INVALID */.M3.DEFAULT_INVALID, {
2440
+ problem
2441
+ }));
2442
+ }
2443
+ patch.defaultValue = changes.defaultValue ?? null;
2444
+ }
2445
+ // ── type change ──
2446
+ const typeChanged = changes.fieldType !== undefined && changes.fieldType !== field.fieldType;
2447
+ if (typeChanged && table && column) {
2448
+ const conversion = (0,_field_type_conversion_js__rspack_import_13/* .planTypeConversion */.I)(field.fieldType, merged.fieldType, ctx.driver);
2449
+ if (!conversion.supported) {
2450
+ ctx.block(conversion.reason);
2451
+ } else {
2452
+ const nonNull = await this.scalar(ctx, `SELECT COUNT(*) AS c FROM ${ctx.q(definition.tableName)} WHERE ${ctx.q(field.code)} IS NOT NULL`);
2453
+ ctx.setAffectedRows(nonNull);
2454
+ for (const check of conversion.prechecks){
2455
+ const where = check.badRowsWhere(ctx.q(field.code), ctx.driver);
2456
+ const bad = await this.scalar(ctx, `SELECT COUNT(*) AS c FROM ${ctx.q(definition.tableName)} WHERE ${ctx.q(field.code)} IS NOT NULL AND (${where})`);
2457
+ if (bad > 0) {
2458
+ ctx.block((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_BLOCKER_MESSAGES.CONVERSION_BAD_ROWS */.M3.CONVERSION_BAD_ROWS, {
2459
+ count: bad,
2460
+ check: check.description,
2461
+ from: field.fieldType,
2462
+ to: merged.fieldType
2463
+ }));
2464
+ }
2465
+ }
2466
+ if (conversion.lossy) {
2467
+ ctx.warn(conversion.lossy);
2468
+ ctx.markDestructive();
2469
+ }
2470
+ const newDefaultProblem = merged.defaultValue !== null && merged.defaultValue !== undefined ? this.checkValue(merged, merged.defaultValue) : null;
2471
+ if (newDefaultProblem) ctx.block((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_BLOCKER_MESSAGES.CURRENT_DEFAULT_INVALID */.M3.CURRENT_DEFAULT_INVALID, {
2472
+ type: merged.fieldType,
2473
+ problem: newDefaultProblem
2474
+ }));
2475
+ if ((merged.fieldType === _enums_field_type_enum_js__rspack_import_20/* .FieldType.SINGLE_SELECT */.P.SINGLE_SELECT || merged.fieldType === _enums_field_type_enum_js__rspack_import_20/* .FieldType.MULTI_SELECT */.P.MULTI_SELECT) && !merged.selectOptions?.length) {
2476
+ ctx.warn((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_WARNING_MESSAGES.NO_SELECT_OPTIONS_CONVERT */.Uu.NO_SELECT_OPTIONS_CONVERT));
2477
+ }
2478
+ if (!ctx.blocked) {
2479
+ const newDbType = this.adapter.mapFieldType(merged.fieldType, ctx.driver);
2480
+ if (!conversion.noDbChange) {
2481
+ const from = (0,_schema_columns_js__rspack_import_17/* .sqlTypeFor */.cg)(field.fieldType, ctx.driver, this.adapter);
2482
+ const to = (0,_schema_columns_js__rspack_import_17/* .sqlTypeFor */.cg)(merged.fieldType, ctx.driver, this.adapter);
2483
+ const t = ctx.q(definition.tableName);
2484
+ const c = ctx.q(field.code);
2485
+ const nullSql = column.isNullable ? 'NULL' : 'NOT NULL';
2486
+ const up = ctx.driver === 'postgres' ? `ALTER TABLE ${t} ALTER COLUMN ${c} TYPE ${to} USING ${conversion.using ? conversion.using(c) : `${c}::${to}`}` : `ALTER TABLE ${t} MODIFY ${c} ${to} ${nullSql}`;
2487
+ const down = ctx.driver === 'postgres' ? `ALTER TABLE ${t} ALTER COLUMN ${c} TYPE ${from} USING ${c}::${from}` : `ALTER TABLE ${t} MODIFY ${c} ${from} ${nullSql}`;
2488
+ await ctx.rawDdl((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_STEP_MESSAGES.CONVERT_TYPE */.EQ.CONVERT_TYPE, {
2489
+ column: field.code,
2490
+ from: field.fieldType,
2491
+ to: merged.fieldType
2492
+ }), [
2493
+ up
2494
+ ], [
2495
+ down
2496
+ ]);
2497
+ }
2498
+ patch.fieldType = merged.fieldType;
2499
+ patch.dbType = newDbType;
2500
+ }
2501
+ }
2502
+ }
2503
+ // ── nullable ──
2504
+ if (changes.nullable !== undefined && changes.nullable !== field.nullable && table && column && !ctx.blocked) {
2505
+ if (changes.nullable === false) {
2506
+ const nulls = await this.scalar(ctx, `SELECT COUNT(*) AS c FROM ${ctx.q(definition.tableName)} WHERE ${ctx.q(field.code)} IS NULL`);
2507
+ const value = request.backfillValue ?? merged.defaultValue ?? null;
2508
+ if (nulls > 0 && value === null) {
2509
+ ctx.block((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_BLOCKER_MESSAGES.NULLS_NEED_VALUE */.M3.NULLS_NEED_VALUE, {
2510
+ count: nulls,
2511
+ field: field.code
2512
+ }));
2513
+ } else if (nulls > 0) {
2514
+ const problem = this.checkValue(merged, value);
2515
+ if (problem) ctx.block((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_BLOCKER_MESSAGES.BACKFILL_INVALID */.M3.BACKFILL_INVALID, {
2516
+ problem
2517
+ }));
2518
+ else {
2519
+ ctx.warn((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_WARNING_MESSAGES.BACKFILL_WILL_SET */.Uu.BACKFILL_WILL_SET, {
2520
+ count: nulls,
2521
+ value: JSON.stringify(value)
2522
+ }));
2523
+ await ctx.data((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_STEP_MESSAGES.BACKFILL_RECORDS */.EQ.BACKFILL_RECORDS, {
2524
+ count: nulls
2525
+ }), `UPDATE ${ctx.q(definition.tableName)} SET ${ctx.q(field.code)} = ${this.adapter.sqlLiteral(this.paramValue(merged.fieldType, value), ctx.driver)} WHERE ${ctx.q(field.code)} IS NULL`, async ()=>{
2526
+ await ctx.qr.query((0,_flusys_nestjs_shared_classes__rspack_import_0.buildQuery)(`UPDATE ${ctx.q(definition.tableName)} SET ${ctx.q(field.code)} = ? WHERE ${ctx.q(field.code)} IS NULL`, ctx.driver), [
2527
+ this.paramValue(merged.fieldType, value)
2528
+ ]);
2529
+ });
2530
+ }
2531
+ }
2532
+ if (!ctx.blocked && column.isNullable) {
2533
+ await this.setRequired(ctx, definition.tableName, field.code, merged.fieldType, true);
2534
+ }
2535
+ } else if (!column.isNullable) {
2536
+ await this.setRequired(ctx, definition.tableName, field.code, merged.fieldType, false);
2537
+ }
2538
+ if (!ctx.blocked) patch.nullable = changes.nullable;
2539
+ }
2540
+ // ── unique ──
2541
+ if (changes.unique !== undefined && changes.unique !== field.unique && table && column && !ctx.blocked) {
2542
+ if (changes.unique === true) {
2543
+ const dups = await this.countDuplicates(ctx, definition.tableName, field.code);
2544
+ if (dups > 0) {
2545
+ ctx.block((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_BLOCKER_MESSAGES.DUPLICATE_VALUES */.M3.DUPLICATE_VALUES, {
2546
+ count: dups,
2547
+ field: field.code
2548
+ }));
2549
+ } else {
2550
+ await ctx.ddl((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_STEP_MESSAGES.ADD_UNIQUE */.EQ.ADD_UNIQUE, {
2551
+ column: field.code
2552
+ }), async ()=>{
2553
+ await (0,_schema_columns_js__rspack_import_17/* .addUnique */.$6)(ctx.qr, table, field.code, ctx.driver, this.adapter);
2554
+ });
2555
+ }
2556
+ } else {
2557
+ await ctx.ddl((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_STEP_MESSAGES.REMOVE_UNIQUE */.EQ.REMOVE_UNIQUE, {
2558
+ column: field.code
2559
+ }), async ()=>this.dropUniques(ctx, table, field.code));
2560
+ }
2561
+ if (!ctx.blocked) patch.unique = changes.unique;
2562
+ }
2563
+ // ── index ──
2564
+ if (changes.isIndexed !== undefined && changes.isIndexed !== field.isIndexed && table && column && !ctx.blocked) {
2565
+ if (changes.isIndexed) {
2566
+ await ctx.ddl((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_STEP_MESSAGES.ADD_INDEX */.EQ.ADD_INDEX, {
2567
+ column: field.code
2568
+ }), async ()=>{
2569
+ await ctx.qr.createIndex(table, (0,_schema_columns_js__rspack_import_17/* .plainIndex */.v7)(definition.tableName, field.code, ctx.driver, this.adapter));
2570
+ });
2571
+ } else {
2572
+ await ctx.ddl((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_STEP_MESSAGES.REMOVE_INDEX */.EQ.REMOVE_INDEX, {
2573
+ column: field.code
2574
+ }), async ()=>{
2575
+ for (const idx of this.indexOn(table, field.code, false))await ctx.qr.dropIndex(table, idx);
2576
+ });
2577
+ }
2578
+ patch.isIndexed = changes.isIndexed;
2579
+ }
2580
+ // ── rename ──
2581
+ if (newCode && table && column) {
2582
+ const taken = fields.find((f)=>f.code === newCode);
2583
+ if (taken) ctx.block((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(taken.deprecatedAt ? _config_message_keys_js__rspack_import_19/* .SCHEMA_BLOCKER_MESSAGES.FIELD_CODE_TAKEN_DEPRECATED */.M3.FIELD_CODE_TAKEN_DEPRECATED : _config_message_keys_js__rspack_import_19/* .SCHEMA_BLOCKER_MESSAGES.FIELD_CODE_TAKEN */.M3.FIELD_CODE_TAKEN, {
2584
+ code: newCode
2585
+ }));
2586
+ if (impact.length && request.rewriteReferences === false) {
2587
+ ctx.block((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_BLOCKER_MESSAGES.RENAME_IN_USE */.M3.RENAME_IN_USE, {
2588
+ field: field.code,
2589
+ references: (0,_schema_change_types_js__rspack_import_22/* .describeImpact */.a)(impact)
2590
+ }));
2591
+ } else if (impact.length) {
2592
+ ctx.warn((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_WARNING_MESSAGES.REFERENCES_REWRITTEN */.Uu.REFERENCES_REWRITTEN, {
2593
+ count: impact.length,
2594
+ code: newCode
2595
+ }));
2596
+ }
2597
+ if (!ctx.blocked) {
2598
+ await ctx.ddl((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_STEP_MESSAGES.RENAME_COLUMN */.EQ.RENAME_COLUMN, {
2599
+ from: field.code,
2600
+ to: newCode
2601
+ }), async ()=>{
2602
+ await ctx.qr.renameColumn(table, field.code, newCode);
2603
+ });
2604
+ // TypeORM moves the index/unique onto the renamed column but keeps its name, which is
2605
+ // derived from the old code - recreate them so a new field with the old code can have its own.
2606
+ if (field.isIndexed && !field.unique) {
2607
+ await ctx.ddl((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_STEP_MESSAGES.RENAME_INDEX */.EQ.RENAME_INDEX, {
2608
+ column: field.code
2609
+ }), async ()=>{
2610
+ for (const idx of this.indexOn(table, newCode, false))await ctx.qr.dropIndex(table, idx);
2611
+ await ctx.qr.createIndex(table, (0,_schema_columns_js__rspack_import_17/* .plainIndex */.v7)(definition.tableName, newCode, ctx.driver, this.adapter));
2612
+ });
2613
+ }
2614
+ if (field.unique) {
2615
+ await ctx.ddl((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_STEP_MESSAGES.RENAME_INDEX */.EQ.RENAME_INDEX, {
2616
+ column: field.code
2617
+ }), async ()=>{
2618
+ await this.dropUniques(ctx, table, newCode);
2619
+ await (0,_schema_columns_js__rspack_import_17/* .addUnique */.$6)(ctx.qr, table, newCode, ctx.driver, this.adapter);
2620
+ });
2621
+ }
2622
+ patch.code = newCode;
2623
+ }
2624
+ }
2625
+ if (ctx.blocked) return {
2626
+ operation: _enums_ddl_operation_enum_js__rspack_import_21/* .DdlOperation.ALTER_FIELD */.i.ALTER_FIELD,
2627
+ fieldDefinitionId: field.id,
2628
+ diff: {}
2629
+ };
2630
+ await ctx.metadata(async ()=>{
2631
+ if (Object.keys(patch).length) await ctx.qr.manager.getRepository(_entities_field_definition_entity_js__rspack_import_8/* .FieldDefinition */.c).update(field.id, patch);
2632
+ if (newCode && request.rewriteReferences !== false) {
2633
+ await this.references.rewriteFieldCode(definition.code, field.code, newCode, ctx.qr.manager);
2634
+ }
2635
+ });
2636
+ const metadataOnly = !structural.length && !newCode;
2637
+ return {
2638
+ operation: newCode ? _enums_ddl_operation_enum_js__rspack_import_21/* .DdlOperation.RENAME_FIELD */.i.RENAME_FIELD : _enums_ddl_operation_enum_js__rspack_import_21/* .DdlOperation.ALTER_FIELD */.i.ALTER_FIELD,
2639
+ fieldDefinitionId: field.id,
2640
+ diff: {
2641
+ field: field.code,
2642
+ changed: Object.keys(patch),
2643
+ before: Object.fromEntries(Object.keys(patch).map((k)=>[
2644
+ k,
2645
+ field[k]
2646
+ ])),
2647
+ after: patch
2648
+ },
2649
+ bumpVersion: !metadataOnly || Object.keys(patch).some((k)=>[
2650
+ 'selectOptions',
2651
+ 'validationRules',
2652
+ 'defaultValue',
2653
+ 'label',
2654
+ 'relationTargetEntityId'
2655
+ ].includes(k))
2656
+ };
2657
+ };
2658
+ return {
2659
+ target: this.target('update_field', loaded, user, lockCodes),
2660
+ run,
2661
+ impact
2662
+ };
2663
+ }
2664
+ // ── deprecate / restore / purge ─────────────────────────────────────────────────────
2665
+ async prepareDeprecateField(request, user) {
2666
+ const { field: loadedField, definition: loaded } = await this.loadField(request.fieldDefinitionId);
2667
+ const impact = await this.references.forField(loaded.code, loadedField.code);
2668
+ const run = async (ctx)=>{
2669
+ const { definition, field } = await this.current(ctx, request, loaded.id, loadedField.id);
2670
+ if (field.code !== loadedField.code) ctx.block((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_BLOCKER_MESSAGES.DEFINITION_CHANGED */.M3.DEFINITION_CHANGED));
2671
+ if (field.deprecatedAt) ctx.block((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_BLOCKER_MESSAGES.ALREADY_DEPRECATED */.M3.ALREADY_DEPRECATED, {
2672
+ field: field.code
2673
+ }));
2674
+ if (impact.length) ctx.warn((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_WARNING_MESSAGES.STILL_REFERENCED */.Uu.STILL_REFERENCED, {
2675
+ references: (0,_schema_change_types_js__rspack_import_22/* .describeImpact */.a)(impact)
2676
+ }));
2677
+ const table = await this.requireTable(ctx, definition.tableName);
2678
+ const column = table?.findColumnByName(field.code);
2679
+ if (ctx.blocked) return {
2680
+ operation: _enums_ddl_operation_enum_js__rspack_import_21/* .DdlOperation.MARK_DEPRECATED */.i.MARK_DEPRECATED,
2681
+ fieldDefinitionId: field.id,
2682
+ diff: {}
2683
+ };
2684
+ // A hidden NOT NULL column would make every new record fail (nobody supplies it any more).
2685
+ if (column && !column.isNullable) {
2686
+ await this.setRequired(ctx, definition.tableName, field.code, field.fieldType, false, _config_message_keys_js__rspack_import_19/* .SCHEMA_STEP_MESSAGES.RELAX_DEPRECATED */.EQ.RELAX_DEPRECATED);
2687
+ }
2688
+ await ctx.metadata(async ()=>{
2689
+ await ctx.qr.manager.getRepository(_entities_field_definition_entity_js__rspack_import_8/* .FieldDefinition */.c).update(field.id, {
2690
+ deprecatedAt: new Date(),
2691
+ nullable: true
2692
+ });
2693
+ });
2694
+ return {
2695
+ operation: _enums_ddl_operation_enum_js__rspack_import_21/* .DdlOperation.MARK_DEPRECATED */.i.MARK_DEPRECATED,
2696
+ fieldDefinitionId: field.id,
2697
+ diff: {
2698
+ field: field.code
2699
+ }
2700
+ };
2701
+ };
2702
+ return {
2703
+ target: this.target('deprecate_field', loaded, user),
2704
+ run,
2705
+ impact
2706
+ };
2707
+ }
2708
+ async prepareRestoreField(request, user) {
2709
+ const { field: loadedField, definition: loaded } = await this.loadField(request.fieldDefinitionId);
2710
+ const run = async (ctx)=>{
2711
+ const { definition, field } = await this.current(ctx, request, loaded.id, loadedField.id);
2712
+ if (!field.deprecatedAt) ctx.block((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_BLOCKER_MESSAGES.NOT_DEPRECATED */.M3.NOT_DEPRECATED, {
2713
+ field: field.code
2714
+ }));
2715
+ const table = await this.requireTable(ctx, definition.tableName);
2716
+ if (table && !table.findColumnByName(field.code)) ctx.block((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_BLOCKER_MESSAGES.COLUMN_GONE */.M3.COLUMN_GONE, {
2717
+ column: field.code
2718
+ }));
2719
+ if (ctx.blocked) return {
2720
+ operation: _enums_ddl_operation_enum_js__rspack_import_21/* .DdlOperation.RESTORE_FIELD */.i.RESTORE_FIELD,
2721
+ fieldDefinitionId: field.id,
2722
+ diff: {}
2723
+ };
2724
+ await ctx.metadata(async ()=>{
2725
+ await ctx.qr.manager.getRepository(_entities_field_definition_entity_js__rspack_import_8/* .FieldDefinition */.c).update(field.id, {
2726
+ deprecatedAt: null
2727
+ });
2728
+ });
2729
+ ctx.warn((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_WARNING_MESSAGES.FIELD_OPTIONAL_AGAIN */.Uu.FIELD_OPTIONAL_AGAIN));
2730
+ return {
2731
+ operation: _enums_ddl_operation_enum_js__rspack_import_21/* .DdlOperation.RESTORE_FIELD */.i.RESTORE_FIELD,
2732
+ fieldDefinitionId: field.id,
2733
+ diff: {
2734
+ field: field.code
2735
+ }
2736
+ };
2737
+ };
2738
+ return {
2739
+ target: this.target('restore_field', loaded, user),
2740
+ run,
2741
+ impact: []
2742
+ };
2743
+ }
2744
+ async preparePurgeField(request, user) {
2745
+ const { field: loadedField, definition: loaded } = await this.loadField(request.fieldDefinitionId);
2746
+ const impact = await this.references.forField(loaded.code, loadedField.code);
2747
+ const run = async (ctx)=>{
2748
+ const { definition, field } = await this.current(ctx, request, loaded.id, loadedField.id);
2749
+ if (this.changedUnderneath(ctx, loadedField, field)) return {
2750
+ operation: _enums_ddl_operation_enum_js__rspack_import_21/* .DdlOperation.DROP_COLUMN */.i.DROP_COLUMN,
2751
+ fieldDefinitionId: field.id,
2752
+ diff: {}
2753
+ };
2754
+ if (!field.deprecatedAt) ctx.block((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_BLOCKER_MESSAGES.PURGE_REQUIRES_DEPRECATED */.M3.PURGE_REQUIRES_DEPRECATED));
2755
+ if (request.confirmCode !== field.code) ctx.block((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_BLOCKER_MESSAGES.PURGE_CONFIRM_CODE */.M3.PURGE_CONFIRM_CODE, {
2756
+ code: field.code
2757
+ }));
2758
+ if (impact.length) ctx.block((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_BLOCKER_MESSAGES.PURGE_IN_USE */.M3.PURGE_IN_USE, {
2759
+ field: field.code,
2760
+ references: (0,_schema_change_types_js__rspack_import_22/* .describeImpact */.a)(impact)
2761
+ }));
2762
+ const table = await this.requireTable(ctx, definition.tableName);
2763
+ const column = table?.findColumnByName(field.code);
2764
+ if (ctx.blocked) return {
2765
+ operation: _enums_ddl_operation_enum_js__rspack_import_21/* .DdlOperation.DROP_COLUMN */.i.DROP_COLUMN,
2766
+ fieldDefinitionId: field.id,
2767
+ diff: {}
2768
+ };
2769
+ if (table && column) {
2770
+ const values = await this.scalar(ctx, `SELECT COUNT(*) AS c FROM ${ctx.q(definition.tableName)} WHERE ${ctx.q(field.code)} IS NOT NULL`);
2771
+ ctx.setAffectedRows(values);
2772
+ ctx.warn((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_WARNING_MESSAGES.VALUES_DELETED */.Uu.VALUES_DELETED, {
2773
+ count: values
2774
+ }));
2775
+ await ctx.ddl((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_STEP_MESSAGES.DROP_COLUMN */.EQ.DROP_COLUMN, {
2776
+ column: field.code
2777
+ }), async ()=>{
2778
+ await ctx.qr.dropColumn(table, column);
2779
+ });
2780
+ } else {
2781
+ ctx.warn((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_WARNING_MESSAGES.COLUMN_ALREADY_MISSING */.Uu.COLUMN_ALREADY_MISSING));
2782
+ }
2783
+ ctx.markDestructive();
2784
+ await ctx.metadata(async ()=>{
2785
+ await ctx.qr.manager.getRepository(_entities_field_definition_entity_js__rspack_import_8/* .FieldDefinition */.c).delete(field.id);
2786
+ });
2787
+ return {
2788
+ operation: _enums_ddl_operation_enum_js__rspack_import_21/* .DdlOperation.DROP_COLUMN */.i.DROP_COLUMN,
2789
+ fieldDefinitionId: null,
2790
+ diff: {
2791
+ field: field.code,
2792
+ fieldType: field.fieldType
2793
+ }
2794
+ };
2795
+ };
2796
+ return {
2797
+ target: this.target('purge_field', loaded, user),
2798
+ run,
2799
+ impact
2800
+ };
2801
+ }
2802
+ // ── entity level ────────────────────────────────────────────────────────────────────
2803
+ async prepareUpdateEntity(request, user) {
2804
+ const { definition: loaded } = await this.loadEntity(request.entityDefinitionId);
2805
+ const changes = request.changes ?? {};
2806
+ this.rejectUnknownKeys(changes, _dtos_schema_change_dto_js__rspack_import_6/* .ENTITY_CHANGE_KEYS */.Oi, 'entity');
2807
+ if (changes.status !== undefined && ![
2808
+ _enums_entity_status_enum_js__rspack_import_23/* .EntityStatus.ACTIVE */.c.ACTIVE,
2809
+ _enums_entity_status_enum_js__rspack_import_23/* .EntityStatus.DEPRECATED */.c.DEPRECATED
2810
+ ].includes(changes.status)) {
2811
+ throw new _nestjs_common__rspack_import_2.BadRequestException({
2812
+ message: "status must be 'ACTIVE' or 'DEPRECATED'.",
2813
+ messageKey: _config_message_keys_js__rspack_import_19/* .ENTITY_DEFINITION_MESSAGES.INVALID_STATUS */.pL.INVALID_STATUS
2814
+ });
2815
+ }
2816
+ this.validateChanges(_dtos_schema_change_dto_js__rspack_import_6/* .EntityChangesDto */.OW, changes);
2817
+ const impact = changes.status === _enums_entity_status_enum_js__rspack_import_23/* .EntityStatus.DEPRECATED */.c.DEPRECATED ? await this.references.forEntity(loaded.code) : [];
2818
+ const run = async (ctx)=>{
2819
+ const { definition } = await this.current(ctx, request, loaded.id);
2820
+ const patch = {};
2821
+ for (const key of [
2822
+ 'label',
2823
+ 'description',
2824
+ 'uiConfig',
2825
+ 'status'
2826
+ ]){
2827
+ if (key in changes) patch[key] = changes[key];
2828
+ }
2829
+ const wantsSoft = changes.isSoftDeleteEnabled;
2830
+ const wantsAudit = changes.isAuditEnabled;
2831
+ const touchesColumns = wantsSoft === true && !definition.isSoftDeleteEnabled || wantsAudit === true && !definition.isAuditEnabled;
2832
+ const table = touchesColumns ? await this.requireTable(ctx, definition.tableName) : undefined;
2833
+ if (ctx.blocked) return {
2834
+ operation: _enums_ddl_operation_enum_js__rspack_import_21/* .DdlOperation.ALTER_ENTITY */.i.ALTER_ENTITY,
2835
+ diff: {}
2836
+ };
2837
+ if (wantsSoft !== undefined && wantsSoft !== definition.isSoftDeleteEnabled) {
2838
+ if (wantsSoft && table) {
2839
+ if (!table.findColumnByName('deleted_at')) {
2840
+ await ctx.ddl((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_STEP_MESSAGES.ADD_DELETED_AT */.EQ.ADD_DELETED_AT), async ()=>{
2841
+ await ctx.qr.addColumn(table, (0,_schema_columns_js__rspack_import_17/* .softDeleteColumn */.OG)());
2842
+ });
2843
+ }
2844
+ } else if (!wantsSoft) {
2845
+ ctx.warn((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_WARNING_MESSAGES.SOFT_DELETE_OFF */.Uu.SOFT_DELETE_OFF));
2846
+ ctx.markDestructive();
2847
+ }
2848
+ patch.isSoftDeleteEnabled = wantsSoft;
2849
+ }
2850
+ if (wantsAudit !== undefined && wantsAudit !== definition.isAuditEnabled) {
2851
+ if (wantsAudit && table) {
2852
+ const missing = (0,_schema_columns_js__rspack_import_17/* .auditColumns */.HK)(ctx.driver).filter((c)=>!table.findColumnByName(c.name));
2853
+ if (missing.length) {
2854
+ await ctx.ddl((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_STEP_MESSAGES.ADD_AUDIT_COLUMNS */.EQ.ADD_AUDIT_COLUMNS), async ()=>{
2855
+ for (const c of missing)await ctx.qr.addColumn(table, c);
2856
+ });
2857
+ }
2858
+ } else if (!wantsAudit) {
2859
+ ctx.warn((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_WARNING_MESSAGES.AUDIT_OFF */.Uu.AUDIT_OFF));
2860
+ }
2861
+ patch.isAuditEnabled = wantsAudit;
2862
+ }
2863
+ if (changes.status === _enums_entity_status_enum_js__rspack_import_23/* .EntityStatus.DEPRECATED */.c.DEPRECATED && impact.length) {
2864
+ ctx.warn((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_WARNING_MESSAGES.ENTITY_REFERENCED */.Uu.ENTITY_REFERENCED, {
2865
+ count: impact.length
2866
+ }));
2867
+ }
2868
+ await ctx.metadata(async ()=>{
2869
+ if (Object.keys(patch).length) await ctx.qr.manager.getRepository(_entities_entity_definition_entity_js__rspack_import_7/* .EntityDefinition */.f).update(definition.id, patch);
2870
+ });
2871
+ return {
2872
+ operation: _enums_ddl_operation_enum_js__rspack_import_21/* .DdlOperation.ALTER_ENTITY */.i.ALTER_ENTITY,
2873
+ diff: {
2874
+ changed: Object.keys(patch),
2875
+ after: patch
2876
+ }
2877
+ };
2878
+ };
2879
+ return {
2880
+ target: this.target('update_entity', loaded, user),
2881
+ run,
2882
+ impact
2883
+ };
2884
+ }
2885
+ /** `"orders.customer_id", ...` - relation fields of other entities that point at this one. */ async relationsInto(ctx, definition) {
2886
+ const pointing = (await ctx.qr.manager.getRepository(_entities_field_definition_entity_js__rspack_import_8/* .FieldDefinition */.c).find({
2887
+ where: {
2888
+ relationTargetEntityId: definition.id
2889
+ }
2890
+ })).filter((f)=>f.entityDefinitionId !== definition.id);
2891
+ if (!pointing.length) return null;
2892
+ const owners = await ctx.qr.manager.getRepository(_entities_entity_definition_entity_js__rspack_import_7/* .EntityDefinition */.f).find({
2893
+ where: {
2894
+ id: (0,typeorm__rspack_import_5.In)([
2895
+ ...new Set(pointing.map((f)=>f.entityDefinitionId))
2896
+ ])
2897
+ }
2898
+ });
2899
+ const codeOf = new Map(owners.map((o)=>[
2900
+ o.id,
2901
+ o.code
2902
+ ]));
2903
+ return pointing.map((f)=>`"${codeOf.get(f.entityDefinitionId) ?? f.entityDefinitionId}.${f.code}"`).join(', ');
2904
+ }
2905
+ async prepareDropEntity(request, user) {
2906
+ const { definition: loaded } = await this.loadEntity(request.entityDefinitionId);
2907
+ const impact = await this.references.forEntity(loaded.code);
2908
+ const run = async (ctx)=>{
2909
+ const { definition } = await this.current(ctx, request, loaded.id);
2910
+ if (request.confirmCode !== definition.code) ctx.block((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_BLOCKER_MESSAGES.DROP_CONFIRM_CODE */.M3.DROP_CONFIRM_CODE, {
2911
+ code: definition.code
2912
+ }));
2913
+ if (impact.length) ctx.block((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_BLOCKER_MESSAGES.DROP_IN_USE */.M3.DROP_IN_USE, {
2914
+ references: (0,_schema_change_types_js__rspack_import_22/* .describeImpact */.a)(impact)
2915
+ }));
2916
+ const relations = await this.relationsInto(ctx, definition);
2917
+ if (relations) ctx.block((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_BLOCKER_MESSAGES.DROP_RELATION_IN_USE */.M3.DROP_RELATION_IN_USE, {
2918
+ fields: relations
2919
+ }));
2920
+ const table = await ctx.qr.getTable(definition.tableName);
2921
+ if (ctx.blocked) return {
2922
+ operation: _enums_ddl_operation_enum_js__rspack_import_21/* .DdlOperation.DROP_TABLE */.i.DROP_TABLE,
2923
+ diff: {}
2924
+ };
2925
+ if (table) {
2926
+ const rows = await this.scalar(ctx, `SELECT COUNT(*) AS c FROM ${ctx.q(definition.tableName)}`);
2927
+ ctx.setAffectedRows(rows);
2928
+ ctx.warn((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_WARNING_MESSAGES.RECORDS_DELETED */.Uu.RECORDS_DELETED, {
2929
+ count: rows
2930
+ }));
2931
+ await ctx.ddl((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_STEP_MESSAGES.DROP_TABLE */.EQ.DROP_TABLE, {
2932
+ table: definition.tableName
2933
+ }), async ()=>{
2934
+ await ctx.qr.dropTable(table);
2935
+ });
2936
+ } else {
2937
+ ctx.warn((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_WARNING_MESSAGES.TABLE_ALREADY_MISSING */.Uu.TABLE_ALREADY_MISSING));
2938
+ }
2939
+ ctx.markDestructive();
2940
+ await ctx.metadata(async ()=>{
2941
+ await ctx.qr.manager.getRepository(_entities_field_definition_entity_js__rspack_import_8/* .FieldDefinition */.c).delete({
2942
+ entityDefinitionId: definition.id
2943
+ });
2944
+ await ctx.qr.manager.getRepository(_entities_entity_definition_entity_js__rspack_import_7/* .EntityDefinition */.f).delete(definition.id);
2945
+ });
2946
+ return {
2947
+ operation: _enums_ddl_operation_enum_js__rspack_import_21/* .DdlOperation.DROP_TABLE */.i.DROP_TABLE,
2948
+ diff: {
2949
+ entity: definition.code
2950
+ },
2951
+ bumpVersion: false,
2952
+ afterCommit: async ()=>this.permissions.deprovisionForEntity(definition)
2953
+ };
2954
+ };
2955
+ return {
2956
+ target: this.target('drop_entity', loaded, user),
2957
+ run,
2958
+ impact
2959
+ };
2960
+ }
2961
+ // ── inspection and repair ───────────────────────────────────────────────────────────
2962
+ diff(definition, fields, table, driver) {
2963
+ const findings = [];
2964
+ if (!table) {
2965
+ findings.push({
2966
+ kind: 'missing_table',
2967
+ severity: 'error',
2968
+ ...(0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_FINDING_MESSAGES.MISSING_TABLE */.Vu.MISSING_TABLE, {
2969
+ table: definition.tableName
2970
+ }),
2971
+ repairable: true
2972
+ });
2973
+ return findings;
2974
+ }
2975
+ const known = new Set([
2976
+ 'id',
2977
+ 'created_at',
2978
+ 'updated_at'
2979
+ ]);
2980
+ if (definition.isSoftDeleteEnabled) known.add('deleted_at');
2981
+ if (definition.isAuditEnabled) (0,_schema_columns_js__rspack_import_17/* .auditColumns */.HK)(driver).forEach((c)=>known.add(c.name));
2982
+ for (const name of known){
2983
+ if (!table.findColumnByName(name)) {
2984
+ findings.push({
2985
+ kind: 'missing_column',
2986
+ severity: 'error',
2987
+ field: name,
2988
+ ...(0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_FINDING_MESSAGES.SYSTEM_COLUMN_MISSING */.Vu.SYSTEM_COLUMN_MISSING, {
2989
+ column: name
2990
+ }),
2991
+ repairable: name !== 'id'
2992
+ });
2993
+ }
2994
+ }
2995
+ for (const field of fields){
2996
+ known.add(field.code);
2997
+ const column = table.findColumnByName(field.code);
2998
+ if (!column) {
2999
+ findings.push({
3000
+ kind: 'missing_column',
3001
+ severity: field.deprecatedAt ? 'warning' : 'error',
3002
+ field: field.code,
3003
+ ...(0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_FINDING_MESSAGES.COLUMN_MISSING */.Vu.COLUMN_MISSING, {
3004
+ column: field.code
3005
+ }),
3006
+ repairable: true
3007
+ });
3008
+ continue;
3009
+ }
3010
+ const expected = (0,_schema_columns_js__rspack_import_17/* .typeFamily */.jp)(this.adapter.mapFieldType(field.fieldType, driver));
3011
+ const actual = (0,_schema_columns_js__rspack_import_17/* .typeFamily */.jp)(column.type);
3012
+ const uuidAsChar = expected === 'uuid' && actual === 'varchar';
3013
+ if (expected !== actual && !uuidAsChar) {
3014
+ findings.push({
3015
+ kind: 'type_mismatch',
3016
+ severity: 'error',
3017
+ field: field.code,
3018
+ ...(0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_FINDING_MESSAGES.TYPE_MISMATCH */.Vu.TYPE_MISMATCH, {
3019
+ column: field.code,
3020
+ actual: column.type,
3021
+ fieldType: field.fieldType,
3022
+ expected
3023
+ }),
3024
+ repairable: false
3025
+ });
3026
+ }
3027
+ if (!field.deprecatedAt && !field.nullable && column.isNullable) {
3028
+ findings.push({
3029
+ kind: 'nullability_mismatch',
3030
+ severity: 'warning',
3031
+ field: field.code,
3032
+ ...(0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_FINDING_MESSAGES.REQUIRED_BUT_NULLABLE */.Vu.REQUIRED_BUT_NULLABLE, {
3033
+ column: field.code
3034
+ }),
3035
+ repairable: true
3036
+ });
3037
+ }
3038
+ if (field.nullable && !column.isNullable) {
3039
+ findings.push({
3040
+ kind: 'nullability_mismatch',
3041
+ severity: 'warning',
3042
+ field: field.code,
3043
+ ...(0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_FINDING_MESSAGES.OPTIONAL_BUT_NOT_NULL */.Vu.OPTIONAL_BUT_NOT_NULL, {
3044
+ column: field.code
3045
+ }),
3046
+ repairable: true
3047
+ });
3048
+ }
3049
+ if (field.isIndexed && !field.unique && this.indexOn(table, field.code, false).length === 0) {
3050
+ findings.push({
3051
+ kind: 'missing_index',
3052
+ severity: 'warning',
3053
+ field: field.code,
3054
+ ...(0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_FINDING_MESSAGES.INDEX_MISSING */.Vu.INDEX_MISSING, {
3055
+ column: field.code
3056
+ }),
3057
+ repairable: true
3058
+ });
3059
+ }
3060
+ if (field.unique && !this.hasUnique(table, field.code)) {
3061
+ findings.push({
3062
+ kind: 'missing_unique',
3063
+ severity: 'warning',
3064
+ field: field.code,
3065
+ ...(0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_FINDING_MESSAGES.UNIQUE_MISSING */.Vu.UNIQUE_MISSING, {
3066
+ column: field.code
3067
+ }),
3068
+ repairable: true
3069
+ });
3070
+ }
3071
+ if (field.dbType && field.dbType !== this.adapter.mapFieldType(field.fieldType, driver)) {
3072
+ findings.push({
3073
+ kind: 'stale_metadata',
3074
+ severity: 'warning',
3075
+ field: field.code,
3076
+ ...(0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_FINDING_MESSAGES.STALE_METADATA */.Vu.STALE_METADATA, {
3077
+ dbType: field.dbType,
3078
+ driver,
3079
+ fieldType: field.fieldType
3080
+ }),
3081
+ repairable: false
3082
+ });
3083
+ }
3084
+ }
3085
+ for (const column of table.columns){
3086
+ if (!known.has(column.name)) {
3087
+ findings.push({
3088
+ kind: 'extra_column',
3089
+ severity: 'warning',
3090
+ field: column.name,
3091
+ ...(0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_FINDING_MESSAGES.EXTRA_COLUMN */.Vu.EXTRA_COLUMN, {
3092
+ column: column.name
3093
+ }),
3094
+ repairable: false
3095
+ });
3096
+ }
3097
+ }
3098
+ return findings;
3099
+ }
3100
+ async prepareRepair(request, user) {
3101
+ const { definition: loaded } = await this.loadEntity(request.entityDefinitionId);
3102
+ const run = async (ctx)=>{
3103
+ const { definition, fields } = await this.current(ctx, request, loaded.id);
3104
+ const table = await ctx.qr.getTable(definition.tableName);
3105
+ const findings = this.diff(definition, fields, table ?? undefined, ctx.driver);
3106
+ // Only what a statement actually ran for - a finding that is skipped or only warned about is not "fixed".
3107
+ const fixed = [];
3108
+ if (!table) {
3109
+ const columns = [
3110
+ ...(0,_schema_columns_js__rspack_import_17/* .buildSystemColumns */.Rm)(definition, ctx.driver),
3111
+ ...fields.map((f)=>(0,_schema_columns_js__rspack_import_17/* .buildFieldColumn */.fu)(f, ctx.driver, this.adapter, {
3112
+ enforceNotNull: false,
3113
+ withUnique: false
3114
+ }))
3115
+ ];
3116
+ const uniques = fields.filter((f)=>f.unique).map((f)=>(0,_schema_columns_js__rspack_import_17/* .tableUnique */.uy)(definition.tableName, f.code, ctx.driver, this.adapter));
3117
+ const recreated = new typeorm__rspack_import_5.Table({
3118
+ name: definition.tableName,
3119
+ columns,
3120
+ uniques
3121
+ });
3122
+ await ctx.ddl((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_STEP_MESSAGES.RECREATE_TABLE */.EQ.RECREATE_TABLE, {
3123
+ table: definition.tableName
3124
+ }), async ()=>{
3125
+ await ctx.qr.createTable(recreated, false);
3126
+ });
3127
+ fixed.push('missing_table');
3128
+ for (const indexed of fields.filter((f)=>f.isIndexed && !f.unique)){
3129
+ await ctx.ddl((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_STEP_MESSAGES.RECREATE_INDEX */.EQ.RECREATE_INDEX, {
3130
+ column: indexed.code
3131
+ }), async ()=>{
3132
+ await ctx.qr.createIndex(recreated, (0,_schema_columns_js__rspack_import_17/* .plainIndex */.v7)(definition.tableName, indexed.code, ctx.driver, this.adapter));
3133
+ });
3134
+ fixed.push(`missing_index:${indexed.code}`);
3135
+ }
3136
+ ctx.warn((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_WARNING_MESSAGES.TABLE_RECREATED_EMPTY */.Uu.TABLE_RECREATED_EMPTY));
3137
+ ctx.markDestructive();
3138
+ return {
3139
+ operation: _enums_ddl_operation_enum_js__rspack_import_21/* .DdlOperation.REPAIR */.i.REPAIR,
3140
+ diff: {
3141
+ fixed,
3142
+ manual: 0
3143
+ }
3144
+ };
3145
+ }
3146
+ for (const finding of findings){
3147
+ if (!finding.repairable || !finding.field) continue;
3148
+ const field = fields.find((f)=>f.code === finding.field);
3149
+ switch(finding.kind){
3150
+ case 'missing_column':
3151
+ {
3152
+ if (!field) {
3153
+ const sys = [
3154
+ (0,_schema_columns_js__rspack_import_17/* .softDeleteColumn */.OG)(),
3155
+ ...(0,_schema_columns_js__rspack_import_17/* .auditColumns */.HK)(ctx.driver)
3156
+ ].find((c)=>c.name === finding.field);
3157
+ if (!sys) break;
3158
+ await ctx.ddl((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_STEP_MESSAGES.ADD_SYSTEM_COLUMN */.EQ.ADD_SYSTEM_COLUMN, {
3159
+ column: sys.name
3160
+ }), async ()=>ctx.qr.addColumn(table, sys));
3161
+ } else {
3162
+ await ctx.ddl((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_STEP_MESSAGES.ADD_MISSING_COLUMN */.EQ.ADD_MISSING_COLUMN, {
3163
+ column: field.code
3164
+ }), async ()=>{
3165
+ await ctx.qr.addColumn(table, (0,_schema_columns_js__rspack_import_17/* .buildFieldColumn */.fu)(field, ctx.driver, this.adapter, {
3166
+ enforceNotNull: false,
3167
+ withUnique: false
3168
+ }));
3169
+ });
3170
+ // Re-added columns start empty, so a required field stays nullable until its records have values.
3171
+ const rows = !field.nullable && !field.deprecatedAt ? await this.scalar(ctx, `SELECT COUNT(*) AS c FROM ${ctx.q(definition.tableName)}`) : 0;
3172
+ if (rows > 0) ctx.warn((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_WARNING_MESSAGES.REQUIRED_HAS_NULLS */.Uu.REQUIRED_HAS_NULLS, {
3173
+ field: field.code,
3174
+ count: rows
3175
+ }));
3176
+ }
3177
+ fixed.push(`missing_column:${finding.field}`);
3178
+ break;
3179
+ }
3180
+ case 'missing_index':
3181
+ await ctx.ddl((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_STEP_MESSAGES.RECREATE_INDEX */.EQ.RECREATE_INDEX, {
3182
+ column: finding.field
3183
+ }), async ()=>{
3184
+ await ctx.qr.createIndex(table, (0,_schema_columns_js__rspack_import_17/* .plainIndex */.v7)(definition.tableName, finding.field, ctx.driver, this.adapter));
3185
+ });
3186
+ fixed.push(`missing_index:${finding.field}`);
3187
+ break;
3188
+ case 'missing_unique':
3189
+ {
3190
+ const code = finding.field;
3191
+ const dups = await this.countDuplicates(ctx, definition.tableName, code);
3192
+ if (dups > 0) ctx.warn((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_WARNING_MESSAGES.UNIQUE_NOT_RECREATED */.Uu.UNIQUE_NOT_RECREATED, {
3193
+ field: code,
3194
+ count: dups
3195
+ }));
3196
+ else {
3197
+ await ctx.ddl((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_STEP_MESSAGES.RECREATE_UNIQUE */.EQ.RECREATE_UNIQUE, {
3198
+ column: code
3199
+ }), async ()=>{
3200
+ await (0,_schema_columns_js__rspack_import_17/* .addUnique */.$6)(ctx.qr, table, code, ctx.driver, this.adapter);
3201
+ });
3202
+ fixed.push(`missing_unique:${finding.field}`);
3203
+ }
3204
+ break;
3205
+ }
3206
+ case 'nullability_mismatch':
3207
+ {
3208
+ const column = field && table.findColumnByName(field.code);
3209
+ if (!field || !column) break;
3210
+ if (!field.nullable && column.isNullable) {
3211
+ const nulls = await this.scalar(ctx, `SELECT COUNT(*) AS c FROM ${ctx.q(definition.tableName)} WHERE ${ctx.q(field.code)} IS NULL`);
3212
+ if (nulls > 0) ctx.warn((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_WARNING_MESSAGES.REQUIRED_HAS_NULLS */.Uu.REQUIRED_HAS_NULLS, {
3213
+ field: field.code,
3214
+ count: nulls
3215
+ }));
3216
+ else {
3217
+ await this.setRequired(ctx, definition.tableName, field.code, field.fieldType, true);
3218
+ fixed.push(`nullability:${field.code}`);
3219
+ }
3220
+ } else if (field.nullable && !column.isNullable) {
3221
+ await this.setRequired(ctx, definition.tableName, field.code, field.fieldType, false);
3222
+ fixed.push(`nullability:${field.code}`);
3223
+ }
3224
+ break;
3225
+ }
3226
+ default:
3227
+ break;
3228
+ }
3229
+ }
3230
+ const manual = findings.filter((f)=>!f.repairable);
3231
+ for (const f of manual)ctx.warn((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_WARNING_MESSAGES.NEEDS_MANUAL_ATTENTION */.Uu.NEEDS_MANUAL_ATTENTION, {
3232
+ finding: (0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(f.messageKey, f.messageVariables)
3233
+ }));
3234
+ if (fixed.length === 0 && manual.length === 0) ctx.warn((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_WARNING_MESSAGES.NOTHING_TO_REPAIR */.Uu.NOTHING_TO_REPAIR));
3235
+ return {
3236
+ operation: _enums_ddl_operation_enum_js__rspack_import_21/* .DdlOperation.REPAIR */.i.REPAIR,
3237
+ diff: {
3238
+ fixed,
3239
+ manual: manual.length
3240
+ },
3241
+ bumpVersion: fixed.length > 0
3242
+ };
3243
+ };
3244
+ return {
3245
+ target: this.target('repair', loaded, user),
3246
+ run,
3247
+ impact: []
3248
+ };
3249
+ }
3250
+ }
3251
+ SchemaEvolutionService = _ts_decorate([
3252
+ (0,_nestjs_common__rspack_import_2.Injectable)({
3253
+ scope: _nestjs_common__rspack_import_2.Scope.REQUEST
3254
+ }),
3255
+ _ts_param(0, (0,_nestjs_common__rspack_import_2.Inject)(_entity_builder_datasource_provider_js__rspack_import_10/* .EntityBuilderDataSourceProvider */.D)),
3256
+ _ts_param(1, (0,_nestjs_common__rspack_import_2.Inject)(_schema_dialect_adapter_service_js__rspack_import_18/* .SchemaDialectAdapterService */.I)),
3257
+ _ts_param(2, (0,_nestjs_common__rspack_import_2.Inject)(_schema_change_executor_service_js__rspack_import_16/* .SchemaChangeExecutor */.T)),
3258
+ _ts_param(3, (0,_nestjs_common__rspack_import_2.Inject)(_reference_scanner_service_js__rspack_import_15/* .ReferenceScannerService */.t)),
3259
+ _ts_param(4, (0,_nestjs_common__rspack_import_2.Inject)(_entity_permission_service_js__rspack_import_11/* .EntityPermissionService */.u)),
3260
+ _ts_metadata("design:type", Function),
3261
+ _ts_metadata("design:paramtypes", [
3262
+ typeof _entity_builder_datasource_provider_js__rspack_import_10/* .EntityBuilderDataSourceProvider */.D === "undefined" ? Object : _entity_builder_datasource_provider_js__rspack_import_10/* .EntityBuilderDataSourceProvider */.D,
3263
+ typeof _schema_dialect_adapter_service_js__rspack_import_18/* .SchemaDialectAdapterService */.I === "undefined" ? Object : _schema_dialect_adapter_service_js__rspack_import_18/* .SchemaDialectAdapterService */.I,
3264
+ typeof _schema_change_executor_service_js__rspack_import_16/* .SchemaChangeExecutor */.T === "undefined" ? Object : _schema_change_executor_service_js__rspack_import_16/* .SchemaChangeExecutor */.T,
3265
+ typeof _reference_scanner_service_js__rspack_import_15/* .ReferenceScannerService */.t === "undefined" ? Object : _reference_scanner_service_js__rspack_import_15/* .ReferenceScannerService */.t,
3266
+ typeof _entity_permission_service_js__rspack_import_11/* .EntityPermissionService */.u === "undefined" ? Object : _entity_permission_service_js__rspack_import_11/* .EntityPermissionService */.u
3267
+ ])
3268
+ ], SchemaEvolutionService);
3269
+
3270
+ __webpack_require__.d(__webpack_exports__, {
3271
+ _: () => (SchemaEvolutionService)
3272
+ }, {
3273
+ C: isDestructiveSchemaAction
3274
+ });
3275
+
3276
+
3277
+ },
3278
+ 3474(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
3279
+ /* import */ var _flusys_nestjs_shared_classes__rspack_import_0 = __webpack_require__(6937);
3280
+ /* import */ var _flusys_nestjs_shared_utils__rspack_import_1 = __webpack_require__(9216);
3281
+ /* import */ var _nestjs_common__rspack_import_2 = __webpack_require__(6157);
3282
+ /* import */ var typeorm__rspack_import_3 = __webpack_require__(7158);
3283
+ /* import */ var _config_message_keys_js__rspack_import_16 = __webpack_require__(5732);
3284
+ /* import */ var _entities_entity_definition_entity_js__rspack_import_4 = __webpack_require__(3189);
3285
+ /* import */ var _entities_field_definition_entity_js__rspack_import_5 = __webpack_require__(2206);
3286
+ /* import */ var _entities_flow_definition_entity_js__rspack_import_6 = __webpack_require__(3770);
3287
+ /* import */ var _enums_ddl_operation_enum_js__rspack_import_18 = __webpack_require__(9949);
3288
+ /* import */ var _enums_entity_status_enum_js__rspack_import_19 = __webpack_require__(1313);
3289
+ /* import */ var _flow_engine_flow_errors_js__rspack_import_7 = __webpack_require__(8542);
3290
+ /* import */ var _entity_builder_datasource_provider_js__rspack_import_8 = __webpack_require__(424);
3291
+ /* import */ var _entity_flow_scaffold_js__rspack_import_9 = __webpack_require__(8271);
3292
+ /* import */ var _entity_permission_service_js__rspack_import_10 = __webpack_require__(1462);
3293
+ /* import */ var _flow_definition_service_js__rspack_import_11 = __webpack_require__(5229);
3294
+ /* import */ var _identifier_rules_js__rspack_import_12 = __webpack_require__(413);
3295
+ /* import */ var _schema_change_executor_service_js__rspack_import_13 = __webpack_require__(6605);
3296
+ /* import */ var _schema_columns_js__rspack_import_14 = __webpack_require__(5313);
3297
+ /* import */ var _schema_dialect_adapter_service_js__rspack_import_15 = __webpack_require__(7259);
3298
+ function _ts_decorate(decorators, target, key, desc) {
3299
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3300
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
3301
+ r = Reflect.decorate(decorators, target, key, desc);
3302
+ } else {
3303
+ for(var i = decorators.length - 1; i >= 0; i--){
3304
+ if (d = decorators[i]) {
3305
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
3306
+ }
3307
+ }
3308
+ }
3309
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
3310
+ }
3311
+ function _ts_metadata(metadataKey, metadataValue) {
3312
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
3313
+ return Reflect.metadata(metadataKey, metadataValue);
3314
+ }
3315
+ }
3316
+ function _ts_param(paramIndex, decorator) {
3317
+ return function(target, key) {
3318
+ decorator(target, key, paramIndex);
3319
+ };
3320
+ }
3321
+
3322
+
3323
+
3324
+
3325
+
3326
+
3327
+
3328
+
3329
+
3330
+
3331
+
3332
+
3333
+
3334
+
3335
+
3336
+
3337
+
3338
+
3339
+
3340
+
3341
+ class SchemaSyncService {
3342
+ dataSourceProvider;
3343
+ dialectAdapter;
3344
+ executor;
3345
+ entityPermissionService;
3346
+ flowDefinitionService;
3347
+ logger = new _nestjs_common__rspack_import_2.Logger(SchemaSyncService.name);
3348
+ constructor(dataSourceProvider, dialectAdapter, executor, entityPermissionService, flowDefinitionService){
3349
+ this.dataSourceProvider = dataSourceProvider;
3350
+ this.dialectAdapter = dialectAdapter;
3351
+ this.executor = executor;
3352
+ this.entityPermissionService = entityPermissionService;
3353
+ this.flowDefinitionService = flowDefinitionService;
3354
+ }
3355
+ validateCreateRequest(dto) {
3356
+ (0,_identifier_rules_js__rspack_import_12/* .assertValidIdentifier */.kV)(dto.code, 'entity');
3357
+ const fields = dto.fields ?? [];
3358
+ for (const field of fields){
3359
+ (0,_identifier_rules_js__rspack_import_12/* .assertValidIdentifier */.kV)(field.code, 'field');
3360
+ (0,_identifier_rules_js__rspack_import_12/* .assertIndexableField */.fY)(field);
3361
+ }
3362
+ const duplicate = fields.map((f)=>f.code).find((code, index, all)=>all.indexOf(code) !== index);
3363
+ if (duplicate) {
3364
+ throw new _nestjs_common__rspack_import_2.BadRequestException({
3365
+ message: `Field code '${duplicate}' is defined more than once.`,
3366
+ messageKey: _config_message_keys_js__rspack_import_16/* .SCHEMA_MESSAGES.DUPLICATE_FIELD_CODE */.Hu.DUPLICATE_FIELD_CODE,
3367
+ messageVariables: {
3368
+ code: duplicate
3369
+ }
3370
+ });
3371
+ }
3372
+ }
3373
+ async createTarget(dto, user) {
3374
+ const lockCodes = await (0,_schema_change_executor_service_js__rspack_import_13/* .relationTargetCodes */.e)(this.dataSourceProvider, (dto.fields ?? []).map((f)=>f.relationTargetEntityId));
3375
+ return {
3376
+ action: 'create_entity',
3377
+ entityDefinitionId: null,
3378
+ entityCode: dto.code,
3379
+ tableName: `${(/* inlined export .ENTITY_TABLE_PREFIX */"eb_")}${dto.code}`,
3380
+ user,
3381
+ lockCodes
3382
+ };
3383
+ }
3384
+ createRun(dto, user, created) {
3385
+ const tableName = `${(/* inlined export .ENTITY_TABLE_PREFIX */"eb_")}${dto.code}`;
3386
+ const fieldSpecs = dto.fields ?? [];
3387
+ const flowEndpoints = dto.flowEndpoints ?? [];
3388
+ const isSoftDeleteEnabled = dto.isSoftDeleteEnabled ?? true;
3389
+ const isAuditEnabled = dto.isAuditEnabled ?? true;
3390
+ return async (ctx)=>{
3391
+ const schemaExpr = ctx.driver === 'postgres' ? 'current_schema()' : 'DATABASE()';
3392
+ const taken = await ctx.qr.query((0,_flusys_nestjs_shared_classes__rspack_import_0.buildQuery)(`SELECT table_name FROM information_schema.tables WHERE table_schema = ${schemaExpr} AND table_name = ?`, ctx.driver), [
3393
+ tableName
3394
+ ]);
3395
+ if (taken.length) ctx.block((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_16/* .SCHEMA_BLOCKER_MESSAGES.TABLE_EXISTS */.M3.TABLE_EXISTS, {
3396
+ table: tableName
3397
+ }));
3398
+ const definitions = ctx.qr.manager.getRepository(_entities_entity_definition_entity_js__rspack_import_4/* .EntityDefinition */.f);
3399
+ const known = await definitions.findOne({
3400
+ where: {
3401
+ code: dto.code
3402
+ }
3403
+ });
3404
+ if (known) ctx.block((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_16/* .SCHEMA_BLOCKER_MESSAGES.ENTITY_CODE_EXISTS */.M3.ENTITY_CODE_EXISTS, {
3405
+ code: dto.code
3406
+ }));
3407
+ for (const spec of fieldSpecs){
3408
+ if (spec.relationTargetEntityId) {
3409
+ const target = await definitions.findOne({
3410
+ where: {
3411
+ id: spec.relationTargetEntityId
3412
+ }
3413
+ });
3414
+ if (!target) ctx.block((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_16/* .SCHEMA_BLOCKER_MESSAGES.RELATION_FIELD_TARGET_MISSING */.M3.RELATION_FIELD_TARGET_MISSING, {
3415
+ field: spec.code
3416
+ }));
3417
+ }
3418
+ }
3419
+ if (flowEndpoints.length) {
3420
+ const slugs = flowEndpoints.map((endpoint)=>(0,_entity_flow_scaffold_js__rspack_import_9/* .entityFlowSlug */.x)(dto.code, endpoint));
3421
+ const clashes = await ctx.qr.manager.getRepository(_entities_flow_definition_entity_js__rspack_import_6/* .FlowDefinition */.G).find({
3422
+ select: {
3423
+ slug: true
3424
+ },
3425
+ where: {
3426
+ slug: (0,typeorm__rspack_import_3.In)(slugs)
3427
+ },
3428
+ withDeleted: true
3429
+ });
3430
+ for (const clash of clashes)ctx.block((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_16/* .SCHEMA_BLOCKER_MESSAGES.FLOW_SLUG_TAKEN */.M3.FLOW_SLUG_TAKEN, {
3431
+ slug: clash.slug
3432
+ }));
3433
+ }
3434
+ if (ctx.blocked) return {
3435
+ operation: _enums_ddl_operation_enum_js__rspack_import_18/* .DdlOperation.CREATE_TABLE */.i.CREATE_TABLE,
3436
+ diff: {}
3437
+ };
3438
+ const columns = fieldSpecs.map((spec)=>(0,_schema_columns_js__rspack_import_14/* .buildFieldColumn */.fu)({
3439
+ code: spec.code,
3440
+ fieldType: spec.fieldType,
3441
+ dbType: '',
3442
+ nullable: spec.nullable ?? true,
3443
+ unique: spec.unique ?? false
3444
+ }, ctx.driver, this.dialectAdapter, {
3445
+ enforceNotNull: true,
3446
+ withUnique: true
3447
+ }));
3448
+ const table = new typeorm__rspack_import_3.Table({
3449
+ name: tableName,
3450
+ columns: [
3451
+ ...(0,_schema_columns_js__rspack_import_14/* .buildSystemColumns */.Rm)({
3452
+ isSoftDeleteEnabled,
3453
+ isAuditEnabled
3454
+ }, ctx.driver),
3455
+ ...columns
3456
+ ]
3457
+ });
3458
+ await ctx.ddl((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_16/* .SCHEMA_STEP_MESSAGES.CREATE_TABLE */.EQ.CREATE_TABLE, {
3459
+ table: tableName
3460
+ }), async ()=>{
3461
+ await ctx.qr.createTable(table, false);
3462
+ });
3463
+ for (const spec of fieldSpecs.filter((f)=>f.isIndexed && !f.unique)){
3464
+ await ctx.ddl((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_16/* .SCHEMA_STEP_MESSAGES.ADD_INDEX */.EQ.ADD_INDEX, {
3465
+ column: spec.code
3466
+ }), async ()=>{
3467
+ await ctx.qr.createIndex(table, (0,_schema_columns_js__rspack_import_14/* .plainIndex */.v7)(tableName, spec.code, ctx.driver, this.dialectAdapter));
3468
+ });
3469
+ }
3470
+ await ctx.metadata(async ()=>{
3471
+ const definitionRepo = ctx.qr.manager.getRepository(_entities_entity_definition_entity_js__rspack_import_4/* .EntityDefinition */.f);
3472
+ const definition = await definitionRepo.save(definitionRepo.create({
3473
+ code: dto.code,
3474
+ label: dto.label,
3475
+ description: dto.description ?? null,
3476
+ tableName,
3477
+ status: _enums_entity_status_enum_js__rspack_import_19/* .EntityStatus.ACTIVE */.c.ACTIVE,
3478
+ schemaVersion: 1,
3479
+ isSoftDeleteEnabled,
3480
+ isAuditEnabled,
3481
+ uiConfig: dto.uiConfig ?? null
3482
+ }));
3483
+ const fieldRepo = ctx.qr.manager.getRepository(_entities_field_definition_entity_js__rspack_import_5/* .FieldDefinition */.c);
3484
+ if (fieldSpecs.length) {
3485
+ await fieldRepo.save(fieldSpecs.map((spec, index)=>fieldRepo.create({
3486
+ entityDefinitionId: definition.id,
3487
+ code: spec.code,
3488
+ label: spec.label,
3489
+ fieldType: spec.fieldType,
3490
+ dbType: this.dialectAdapter.mapFieldType(spec.fieldType, ctx.driver),
3491
+ nullable: spec.nullable ?? true,
3492
+ unique: spec.unique ?? false,
3493
+ isIndexed: spec.isIndexed ?? false,
3494
+ defaultValue: spec.defaultValue ?? null,
3495
+ validationRules: spec.validationRules ?? null,
3496
+ selectOptions: spec.selectOptions ?? null,
3497
+ relationTargetEntityId: spec.relationTargetEntityId ?? null,
3498
+ order: spec.order ?? index,
3499
+ uiConfig: spec.uiConfig ?? null,
3500
+ isSearchable: spec.isSearchable ?? false,
3501
+ isSystemField: false,
3502
+ deprecatedAt: null
3503
+ })));
3504
+ }
3505
+ created.definition = definition;
3506
+ });
3507
+ return {
3508
+ operation: _enums_ddl_operation_enum_js__rspack_import_18/* .DdlOperation.CREATE_TABLE */.i.CREATE_TABLE,
3509
+ entityDefinitionId: created.definition?.id ?? null,
3510
+ diff: {
3511
+ fields: fieldSpecs.map((f)=>({
3512
+ code: f.code,
3513
+ fieldType: f.fieldType
3514
+ }))
3515
+ },
3516
+ bumpVersion: false,
3517
+ afterCommit: async ()=>{
3518
+ if (!created.definition) return;
3519
+ try {
3520
+ await this.entityPermissionService.provisionForEntity(created.definition);
3521
+ } finally{
3522
+ created.warnings.push(...await this.createEndpointFlows(dto, flowEndpoints, user));
3523
+ }
3524
+ }
3525
+ };
3526
+ };
3527
+ }
3528
+ /**
3529
+ * One ready-made flow per requested endpoint, saved through FlowDefinitionService so it is
3530
+ * validated like any other flow. Each is saved on its own: one that fails does not stop the
3531
+ * rest, and is reported as a warning since the entity is already committed.
3532
+ */ async createEndpointFlows(dto, endpoints, user) {
3533
+ const entity = {
3534
+ code: dto.code,
3535
+ label: dto.label,
3536
+ fields: dto.fields ?? []
3537
+ };
3538
+ const warnings = [];
3539
+ for (const endpoint of endpoints){
3540
+ const flow = (0,_entity_flow_scaffold_js__rspack_import_9/* .buildEntityFlow */.C)(entity, endpoint, dto.flowTexts);
3541
+ try {
3542
+ await this.flowDefinitionService.insert(flow, user);
3543
+ } catch (error) {
3544
+ this.logger.error(`Endpoint flow '${flow.slug}' of entity '${dto.code}' could not be created: ${error.message}`);
3545
+ warnings.push((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_16/* .SCHEMA_WARNING_MESSAGES.ENDPOINT_FLOW_FAILED */.Uu.ENDPOINT_FLOW_FAILED, {
3546
+ slug: flow.slug,
3547
+ detail: (0,_flow_engine_flow_errors_js__rspack_import_7/* .errorRef */.O$)(error)
3548
+ }));
3549
+ }
3550
+ }
3551
+ return warnings;
3552
+ }
3553
+ /** Preview of `createEntity`: the CREATE TABLE / CREATE INDEX statements, nothing is created. */ async planCreateEntity(dto, user) {
3554
+ this.validateCreateRequest(dto);
3555
+ return this.executor.simulate(await this.createTarget(dto, user), this.createRun(dto, user, {
3556
+ warnings: []
3557
+ }));
3558
+ }
3559
+ async createEntity(dto, user) {
3560
+ this.validateCreateRequest(dto);
3561
+ if (dto.flowEndpoints?.length) await this.flowDefinitionService.assertMayCreate(user);
3562
+ const created = {
3563
+ warnings: []
3564
+ };
3565
+ let planWarnings;
3566
+ try {
3567
+ ({ plan: { warnings: planWarnings } } = await this.executor.apply(await this.createTarget(dto, user), this.createRun(dto, user, created)));
3568
+ } catch (error) {
3569
+ if (error instanceof _nestjs_common__rspack_import_2.ConflictException && error.getResponse().blockers?.some((b)=>b.messageKey === _config_message_keys_js__rspack_import_16/* .SCHEMA_BLOCKER_MESSAGES.ENTITY_CODE_EXISTS */.M3.ENTITY_CODE_EXISTS || b.messageKey === _config_message_keys_js__rspack_import_16/* .SCHEMA_BLOCKER_MESSAGES.TABLE_EXISTS */.M3.TABLE_EXISTS)) {
3570
+ throw new _nestjs_common__rspack_import_2.ConflictException({
3571
+ message: `An entity with the code '${dto.code}' already exists.`,
3572
+ messageKey: _config_message_keys_js__rspack_import_16/* .ENTITY_DEFINITION_MESSAGES.CODE_ALREADY_EXISTS */.pL.CODE_ALREADY_EXISTS,
3573
+ messageVariables: {
3574
+ code: dto.code
3575
+ }
3576
+ });
3577
+ }
3578
+ throw error;
3579
+ }
3580
+ return {
3581
+ definition: created.definition,
3582
+ warnings: [
3583
+ ...planWarnings,
3584
+ ...created.warnings
3585
+ ]
3586
+ };
3587
+ }
3588
+ }
3589
+ SchemaSyncService = _ts_decorate([
3590
+ (0,_nestjs_common__rspack_import_2.Injectable)({
3591
+ scope: _nestjs_common__rspack_import_2.Scope.REQUEST
3592
+ }),
3593
+ _ts_param(0, (0,_nestjs_common__rspack_import_2.Inject)(_entity_builder_datasource_provider_js__rspack_import_8/* .EntityBuilderDataSourceProvider */.D)),
3594
+ _ts_param(1, (0,_nestjs_common__rspack_import_2.Inject)(_schema_dialect_adapter_service_js__rspack_import_15/* .SchemaDialectAdapterService */.I)),
3595
+ _ts_param(2, (0,_nestjs_common__rspack_import_2.Inject)(_schema_change_executor_service_js__rspack_import_13/* .SchemaChangeExecutor */.T)),
3596
+ _ts_param(3, (0,_nestjs_common__rspack_import_2.Inject)(_entity_permission_service_js__rspack_import_10/* .EntityPermissionService */.u)),
3597
+ _ts_param(4, (0,_nestjs_common__rspack_import_2.Inject)(_flow_definition_service_js__rspack_import_11/* .FlowDefinitionService */.Tk)),
3598
+ _ts_metadata("design:type", Function),
3599
+ _ts_metadata("design:paramtypes", [
3600
+ typeof _entity_builder_datasource_provider_js__rspack_import_8/* .EntityBuilderDataSourceProvider */.D === "undefined" ? Object : _entity_builder_datasource_provider_js__rspack_import_8/* .EntityBuilderDataSourceProvider */.D,
3601
+ typeof _schema_dialect_adapter_service_js__rspack_import_15/* .SchemaDialectAdapterService */.I === "undefined" ? Object : _schema_dialect_adapter_service_js__rspack_import_15/* .SchemaDialectAdapterService */.I,
3602
+ typeof _schema_change_executor_service_js__rspack_import_13/* .SchemaChangeExecutor */.T === "undefined" ? Object : _schema_change_executor_service_js__rspack_import_13/* .SchemaChangeExecutor */.T,
3603
+ typeof _entity_permission_service_js__rspack_import_10/* .EntityPermissionService */.u === "undefined" ? Object : _entity_permission_service_js__rspack_import_10/* .EntityPermissionService */.u,
3604
+ typeof _flow_definition_service_js__rspack_import_11/* .FlowDefinitionService */.Tk === "undefined" ? Object : _flow_definition_service_js__rspack_import_11/* .FlowDefinitionService */.Tk
3605
+ ])
3606
+ ], SchemaSyncService);
3607
+
3608
+ __webpack_require__.d(__webpack_exports__, {
3609
+ W: () => (SchemaSyncService)
3610
+ });
3611
+
3612
+
3613
+ },
3614
+
3615
+ };