@solidxai/core 0.1.11-beta.0 → 0.1.11-beta.11

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 (226) hide show
  1. package/.claude/settings.local.json +2 -1
  2. package/CLAUDE.md +26 -0
  3. package/dist/commands/migrate-removed-fields.command.d.ts +19 -0
  4. package/dist/commands/migrate-removed-fields.command.d.ts.map +1 -0
  5. package/dist/commands/migrate-removed-fields.command.js +77 -0
  6. package/dist/commands/migrate-removed-fields.command.js.map +1 -0
  7. package/dist/controllers/datasource-introspection.controller.d.ts +46 -1
  8. package/dist/controllers/datasource-introspection.controller.d.ts.map +1 -1
  9. package/dist/controllers/datasource-introspection.controller.js +38 -0
  10. package/dist/controllers/datasource-introspection.controller.js.map +1 -1
  11. package/dist/controllers/service.controller.d.ts +1 -0
  12. package/dist/controllers/service.controller.d.ts.map +1 -1
  13. package/dist/controllers/service.controller.js +2 -2
  14. package/dist/controllers/service.controller.js.map +1 -1
  15. package/dist/dtos/datasource-introspection-mapping.dto.d.ts +5 -0
  16. package/dist/dtos/datasource-introspection-mapping.dto.d.ts.map +1 -1
  17. package/dist/dtos/datasource-introspection-mapping.dto.js +24 -2
  18. package/dist/dtos/datasource-introspection-mapping.dto.js.map +1 -1
  19. package/dist/entities/{legacy-common-with-id.entity.d.ts → legacy-common-with-generated-id.entity.d.ts} +2 -2
  20. package/dist/entities/legacy-common-with-generated-id.entity.d.ts.map +1 -0
  21. package/dist/entities/{legacy-common-with-id.entity.js → legacy-common-with-generated-id.entity.js} +4 -4
  22. package/dist/entities/legacy-common-with-generated-id.entity.js.map +1 -0
  23. package/dist/entities/{legacy-common.entity.d.ts → legacy-common.entity-with-existing-id.entity.d.ts} +1 -1
  24. package/dist/entities/legacy-common.entity-with-existing-id.entity.d.ts.map +1 -0
  25. package/dist/entities/{legacy-common.entity.js → legacy-common.entity-with-existing-id.entity.js} +1 -1
  26. package/dist/entities/legacy-common.entity-with-existing-id.entity.js.map +1 -0
  27. package/dist/helpers/command.service.d.ts +2 -0
  28. package/dist/helpers/command.service.d.ts.map +1 -1
  29. package/dist/helpers/command.service.js +6 -2
  30. package/dist/helpers/command.service.js.map +1 -1
  31. package/dist/helpers/environment.helper.d.ts +1 -0
  32. package/dist/helpers/environment.helper.d.ts.map +1 -1
  33. package/dist/helpers/environment.helper.js +4 -0
  34. package/dist/helpers/environment.helper.js.map +1 -1
  35. package/dist/helpers/field-crud-managers/IntFieldCrudManager.d.ts.map +1 -1
  36. package/dist/helpers/field-crud-managers/IntFieldCrudManager.js +4 -1
  37. package/dist/helpers/field-crud-managers/IntFieldCrudManager.js.map +1 -1
  38. package/dist/helpers/model-metadata-helper.service.d.ts +2 -1
  39. package/dist/helpers/model-metadata-helper.service.d.ts.map +1 -1
  40. package/dist/helpers/model-metadata-helper.service.js +9 -5
  41. package/dist/helpers/model-metadata-helper.service.js.map +1 -1
  42. package/dist/helpers/nodemon-heartbeat.d.ts +5 -0
  43. package/dist/helpers/nodemon-heartbeat.d.ts.map +1 -0
  44. package/dist/helpers/nodemon-heartbeat.js +67 -0
  45. package/dist/helpers/nodemon-heartbeat.js.map +1 -0
  46. package/dist/helpers/solid-registry.d.ts +2 -1
  47. package/dist/helpers/solid-registry.d.ts.map +1 -1
  48. package/dist/helpers/solid-registry.js.map +1 -1
  49. package/dist/helpers/typeorm-db-helper.d.ts +1 -0
  50. package/dist/helpers/typeorm-db-helper.d.ts.map +1 -1
  51. package/dist/helpers/typeorm-db-helper.js +12 -0
  52. package/dist/helpers/typeorm-db-helper.js.map +1 -1
  53. package/dist/index.d.ts +3 -2
  54. package/dist/index.d.ts.map +1 -1
  55. package/dist/index.js +3 -2
  56. package/dist/index.js.map +1 -1
  57. package/dist/interfaces/datasource-introspection-provider.interface.d.ts +1 -0
  58. package/dist/interfaces/datasource-introspection-provider.interface.d.ts.map +1 -1
  59. package/dist/interfaces/datasource-introspection-provider.interface.js.map +1 -1
  60. package/dist/interfaces.d.ts +1 -0
  61. package/dist/interfaces.d.ts.map +1 -1
  62. package/dist/interfaces.js.map +1 -1
  63. package/dist/repository/scheduled-job.repository.d.ts +5 -2
  64. package/dist/repository/scheduled-job.repository.d.ts.map +1 -1
  65. package/dist/repository/scheduled-job.repository.js +66 -3
  66. package/dist/repository/scheduled-job.repository.js.map +1 -1
  67. package/dist/repository/security-rule.repository.d.ts +2 -2
  68. package/dist/repository/security-rule.repository.d.ts.map +1 -1
  69. package/dist/repository/security-rule.repository.js +6 -3
  70. package/dist/repository/security-rule.repository.js.map +1 -1
  71. package/dist/seeders/module-metadata-seeder.service.d.ts +43 -2
  72. package/dist/seeders/module-metadata-seeder.service.d.ts.map +1 -1
  73. package/dist/seeders/module-metadata-seeder.service.js +1173 -232
  74. package/dist/seeders/module-metadata-seeder.service.js.map +1 -1
  75. package/dist/seeders/seed-data/solid-core-metadata.json +128 -34
  76. package/dist/services/action-metadata.service.d.ts +7 -0
  77. package/dist/services/action-metadata.service.d.ts.map +1 -1
  78. package/dist/services/action-metadata.service.js +76 -3
  79. package/dist/services/action-metadata.service.js.map +1 -1
  80. package/dist/services/api-key.service.d.ts.map +1 -1
  81. package/dist/services/api-key.service.js.map +1 -1
  82. package/dist/services/authentication.service.d.ts +2 -0
  83. package/dist/services/authentication.service.d.ts.map +1 -1
  84. package/dist/services/authentication.service.js +32 -11
  85. package/dist/services/authentication.service.js.map +1 -1
  86. package/dist/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.d.ts.map +1 -1
  87. package/dist/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.js +7 -5
  88. package/dist/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.js.map +1 -1
  89. package/dist/services/computed-fields/entity/concat-entity-computed-field-provider.service.d.ts +4 -0
  90. package/dist/services/computed-fields/entity/concat-entity-computed-field-provider.service.d.ts.map +1 -1
  91. package/dist/services/computed-fields/entity/concat-entity-computed-field-provider.service.js +18 -1
  92. package/dist/services/computed-fields/entity/concat-entity-computed-field-provider.service.js.map +1 -1
  93. package/dist/services/crud-helper.service.d.ts.map +1 -1
  94. package/dist/services/crud-helper.service.js +25 -12
  95. package/dist/services/crud-helper.service.js.map +1 -1
  96. package/dist/services/crud.service.d.ts +1 -0
  97. package/dist/services/crud.service.d.ts.map +1 -1
  98. package/dist/services/crud.service.js +27 -0
  99. package/dist/services/crud.service.js.map +1 -1
  100. package/dist/services/datasource-introspection/mssql-datasource-introspection-provider.service.d.ts.map +1 -1
  101. package/dist/services/datasource-introspection/mssql-datasource-introspection-provider.service.js +12 -0
  102. package/dist/services/datasource-introspection/mssql-datasource-introspection-provider.service.js.map +1 -1
  103. package/dist/services/datasource-introspection/mysql-datasource-introspection-provider.service.d.ts.map +1 -1
  104. package/dist/services/datasource-introspection/mysql-datasource-introspection-provider.service.js +2 -0
  105. package/dist/services/datasource-introspection/mysql-datasource-introspection-provider.service.js.map +1 -1
  106. package/dist/services/datasource-introspection/postgres-datasource-introspection-provider.service.d.ts.map +1 -1
  107. package/dist/services/datasource-introspection/postgres-datasource-introspection-provider.service.js +28 -15
  108. package/dist/services/datasource-introspection/postgres-datasource-introspection-provider.service.js.map +1 -1
  109. package/dist/services/datasource-introspection.service.d.ts +62 -2
  110. package/dist/services/datasource-introspection.service.d.ts.map +1 -1
  111. package/dist/services/datasource-introspection.service.js +654 -186
  112. package/dist/services/datasource-introspection.service.js.map +1 -1
  113. package/dist/services/import-transaction.service.d.ts.map +1 -1
  114. package/dist/services/import-transaction.service.js +3 -0
  115. package/dist/services/import-transaction.service.js.map +1 -1
  116. package/dist/services/locale.service.d.ts +14 -0
  117. package/dist/services/locale.service.d.ts.map +1 -1
  118. package/dist/services/locale.service.js +83 -0
  119. package/dist/services/locale.service.js.map +1 -1
  120. package/dist/services/mediaStorageProviders/file-s3-storage-provider.js +10 -10
  121. package/dist/services/mediaStorageProviders/file-s3-storage-provider.js.map +1 -1
  122. package/dist/services/menu-item-metadata.service.d.ts.map +1 -1
  123. package/dist/services/menu-item-metadata.service.js +1 -0
  124. package/dist/services/menu-item-metadata.service.js.map +1 -1
  125. package/dist/services/model-metadata.service.d.ts +3 -0
  126. package/dist/services/model-metadata.service.d.ts.map +1 -1
  127. package/dist/services/model-metadata.service.js +78 -0
  128. package/dist/services/model-metadata.service.js.map +1 -1
  129. package/dist/services/module-metadata.service.d.ts.map +1 -1
  130. package/dist/services/module-metadata.service.js +28 -0
  131. package/dist/services/module-metadata.service.js.map +1 -1
  132. package/dist/services/removed-field-migration.service.d.ts +30 -0
  133. package/dist/services/removed-field-migration.service.d.ts.map +1 -0
  134. package/dist/services/removed-field-migration.service.js +319 -0
  135. package/dist/services/removed-field-migration.service.js.map +1 -0
  136. package/dist/services/role-metadata.service.d.ts +5 -0
  137. package/dist/services/role-metadata.service.d.ts.map +1 -1
  138. package/dist/services/role-metadata.service.js +95 -33
  139. package/dist/services/role-metadata.service.js.map +1 -1
  140. package/dist/services/settings/default-settings-provider.service.d.ts +244 -0
  141. package/dist/services/settings/default-settings-provider.service.d.ts.map +1 -1
  142. package/dist/services/settings/default-settings-provider.service.js +120 -0
  143. package/dist/services/settings/default-settings-provider.service.js.map +1 -1
  144. package/dist/services/solid-ts-morph.service.d.ts +6 -0
  145. package/dist/services/solid-ts-morph.service.d.ts.map +1 -1
  146. package/dist/services/solid-ts-morph.service.js +43 -0
  147. package/dist/services/solid-ts-morph.service.js.map +1 -1
  148. package/dist/services/view-metadata.service.d.ts +6 -0
  149. package/dist/services/view-metadata.service.d.ts.map +1 -1
  150. package/dist/services/view-metadata.service.js +70 -8
  151. package/dist/services/view-metadata.service.js.map +1 -1
  152. package/dist/solid-core.module.d.ts.map +1 -1
  153. package/dist/solid-core.module.js +4 -0
  154. package/dist/solid-core.module.js.map +1 -1
  155. package/dist/subscribers/audit.subscriber.d.ts +5 -1
  156. package/dist/subscribers/audit.subscriber.d.ts.map +1 -1
  157. package/dist/subscribers/audit.subscriber.js +76 -12
  158. package/dist/subscribers/audit.subscriber.js.map +1 -1
  159. package/dist/subscribers/computed-entity-field.subscriber.d.ts +9 -1
  160. package/dist/subscribers/computed-entity-field.subscriber.d.ts.map +1 -1
  161. package/dist/subscribers/computed-entity-field.subscriber.js +45 -11
  162. package/dist/subscribers/computed-entity-field.subscriber.js.map +1 -1
  163. package/dist/subscribers/created-by-updated-by.subscriber.d.ts.map +1 -1
  164. package/dist/subscribers/created-by-updated-by.subscriber.js.map +1 -1
  165. package/dist/subscribers/field-metadata.subscriber.d.ts.map +1 -1
  166. package/dist/subscribers/field-metadata.subscriber.js.map +1 -1
  167. package/dist/subscribers/scheduled-job.subscriber.d.ts.map +1 -1
  168. package/dist/subscribers/scheduled-job.subscriber.js +3 -2
  169. package/dist/subscribers/scheduled-job.subscriber.js.map +1 -1
  170. package/dist/subscribers/security-rule.subscriber.d.ts.map +1 -1
  171. package/dist/subscribers/security-rule.subscriber.js +5 -3
  172. package/dist/subscribers/security-rule.subscriber.js.map +1 -1
  173. package/package.json +1 -1
  174. package/src/commands/migrate-removed-fields.command.ts +81 -0
  175. package/src/controllers/datasource-introspection.controller.ts +27 -1
  176. package/src/controllers/service.controller.ts +3 -2
  177. package/src/dtos/datasource-introspection-mapping.dto.ts +15 -0
  178. package/src/entities/{legacy-common-with-id.entity.ts → legacy-common-with-generated-id.entity.ts} +1 -1
  179. package/src/helpers/command.service.ts +10 -2
  180. package/src/helpers/environment.helper.ts +11 -0
  181. package/src/helpers/field-crud-managers/IntFieldCrudManager.ts +4 -1
  182. package/src/helpers/model-metadata-helper.service.ts +8 -3
  183. package/src/helpers/nodemon-heartbeat.ts +59 -0
  184. package/src/helpers/solid-registry.ts +7 -1
  185. package/src/helpers/typeorm-db-helper.ts +15 -0
  186. package/src/index.ts +3 -2
  187. package/src/interfaces/datasource-introspection-provider.interface.ts +1 -0
  188. package/src/interfaces.ts +1 -0
  189. package/src/repository/scheduled-job.repository.ts +83 -4
  190. package/src/repository/security-rule.repository.ts +10 -4
  191. package/src/seeders/module-metadata-seeder.service.ts +1415 -264
  192. package/src/seeders/seed-data/solid-core-metadata.json +128 -34
  193. package/src/services/action-metadata.service.ts +87 -2
  194. package/src/services/api-key.service.ts +36 -36
  195. package/src/services/authentication.service.ts +46 -12
  196. package/src/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.ts +11 -5
  197. package/src/services/computed-fields/entity/concat-entity-computed-field-provider.service.ts +15 -1
  198. package/src/services/crud-helper.service.ts +25 -12
  199. package/src/services/crud.service.ts +36 -11
  200. package/src/services/datasource-introspection/mssql-datasource-introspection-provider.service.ts +12 -0
  201. package/src/services/datasource-introspection/mysql-datasource-introspection-provider.service.ts +2 -0
  202. package/src/services/datasource-introspection/postgres-datasource-introspection-provider.service.ts +28 -15
  203. package/src/services/datasource-introspection.service.ts +811 -161
  204. package/src/services/import-transaction.service.ts +5 -0
  205. package/src/services/locale.service.ts +111 -3
  206. package/src/services/mediaStorageProviders/file-s3-storage-provider.ts +2 -2
  207. package/src/services/menu-item-metadata.service.ts +2 -1
  208. package/src/services/model-metadata.service.ts +109 -1
  209. package/src/services/module-metadata.service.ts +36 -0
  210. package/src/services/removed-field-migration.service.ts +334 -0
  211. package/src/services/role-metadata.service.ts +112 -49
  212. package/src/services/settings/default-settings-provider.service.ts +120 -0
  213. package/src/services/solid-ts-morph.service.ts +61 -1
  214. package/src/services/view-metadata.service.ts +83 -9
  215. package/src/solid-core.module.ts +4 -0
  216. package/src/subscribers/audit.subscriber.ts +101 -18
  217. package/src/subscribers/computed-entity-field.subscriber.ts +81 -28
  218. package/src/subscribers/created-by-updated-by.subscriber.ts +3 -0
  219. package/src/subscribers/field-metadata.subscriber.ts +3 -0
  220. package/src/subscribers/scheduled-job.subscriber.ts +3 -2
  221. package/src/subscribers/security-rule.subscriber.ts +8 -3
  222. package/dist/entities/legacy-common-with-id.entity.d.ts.map +0 -1
  223. package/dist/entities/legacy-common-with-id.entity.js.map +0 -1
  224. package/dist/entities/legacy-common.entity.d.ts.map +0 -1
  225. package/dist/entities/legacy-common.entity.js.map +0 -1
  226. /package/src/entities/{legacy-common.entity.ts → legacy-common.entity-with-existing-id.entity.ts} +0 -0
@@ -50,19 +50,101 @@ const crypto_1 = require("crypto");
50
50
  const fs = __importStar(require("fs/promises"));
51
51
  const path = __importStar(require("path"));
52
52
  const lodash_1 = require("lodash");
53
+ const ts_morph_1 = require("ts-morph");
53
54
  const legacy_table_type_enum_1 = require("../enums/legacy-table-type.enum");
55
+ const string_helper_1 = require("../helpers/string.helper");
54
56
  const module_metadata_helper_service_1 = require("../helpers/module-metadata-helper.service");
55
57
  const model_metadata_helper_service_1 = require("../helpers/model-metadata-helper.service");
56
58
  const model_metadata_repository_1 = require("../repository/model-metadata.repository");
57
59
  const module_metadata_repository_1 = require("../repository/module-metadata.repository");
58
60
  const datasource_management_service_1 = require("./datasource-management.service");
61
+ const command_service_1 = require("../helpers/command.service");
59
62
  const field_metadata_service_1 = require("./field-metadata.service");
60
63
  const model_metadata_service_1 = require("./model-metadata.service");
64
+ const module_metadata_service_1 = require("./module-metadata.service");
61
65
  const mssql_datasource_introspection_provider_service_1 = require("./datasource-introspection/mssql-datasource-introspection-provider.service");
62
66
  const mysql_datasource_introspection_provider_service_1 = require("./datasource-introspection/mysql-datasource-introspection-provider.service");
63
67
  const postgres_datasource_introspection_provider_service_1 = require("./datasource-introspection/postgres-datasource-introspection-provider.service");
68
+ const DATASOURCE_TYPE_FAMILY_ALIASES = {
69
+ boolean: ["bit", "bool", "boolean"],
70
+ bigint: ["bigint"],
71
+ int: ["int", "integer", "smallint", "tinyint"],
72
+ numeric: ["numeric"],
73
+ decimal: ["decimal", "money", "smallmoney"],
74
+ float: ["float", "double", "double precision", "real", "float4", "float8"],
75
+ date: ["date"],
76
+ time: ["time", "time without time zone", "time with time zone"],
77
+ datetime: ["datetime", "datetime2", "smalldatetime", "timestamp", "timestamp without time zone"],
78
+ datetimeWithTimezone: ["timestamptz", "timestamp with time zone"],
79
+ json: ["json", "simple-json", "simplejson"],
80
+ jsonb: ["jsonb"],
81
+ uuid: ["uniqueidentifier", "uuid"],
82
+ longText: ["text", "ntext", "longtext", "clob"],
83
+ mediumText: ["mediumtext"],
84
+ shortText: ["varchar", "char", "citext"],
85
+ unicodeShortText: ["nvarchar", "nchar"],
86
+ };
87
+ const ORM_TYPE_BY_DATASOURCE_FAMILY = {
88
+ mssql: {
89
+ boolean: "bit",
90
+ bigint: "bigint",
91
+ int: "int",
92
+ numeric: "numeric",
93
+ decimal: "decimal",
94
+ float: "decimal",
95
+ date: "date",
96
+ time: "time",
97
+ datetime: "datetime",
98
+ datetimeWithTimezone: "datetime",
99
+ json: "simple-json",
100
+ jsonb: "simple-json",
101
+ uuid: "uniqueidentifier",
102
+ longText: "text",
103
+ mediumText: "text",
104
+ shortText: "varchar",
105
+ unicodeShortText: "nvarchar",
106
+ },
107
+ mysql: {
108
+ boolean: "boolean",
109
+ bigint: "int",
110
+ int: "int",
111
+ numeric: "decimal",
112
+ decimal: "decimal",
113
+ float: "double",
114
+ date: "date",
115
+ time: "time",
116
+ datetime: "datetime",
117
+ datetimeWithTimezone: "datetime",
118
+ json: "json",
119
+ jsonb: "json",
120
+ uuid: "varchar",
121
+ longText: "longtext",
122
+ mediumText: "mediumtext",
123
+ shortText: "varchar",
124
+ unicodeShortText: "varchar",
125
+ },
126
+ postgres: {
127
+ boolean: "boolean",
128
+ bigint: "bigint",
129
+ int: "integer",
130
+ numeric: "decimal",
131
+ decimal: "decimal",
132
+ float: "decimal",
133
+ date: "date",
134
+ time: "time",
135
+ datetime: "timestamp",
136
+ datetimeWithTimezone: "timestamptz",
137
+ json: "json",
138
+ jsonb: "jsonb",
139
+ uuid: "uuid",
140
+ longText: "text",
141
+ mediumText: "text",
142
+ shortText: "varchar",
143
+ unicodeShortText: "varchar",
144
+ },
145
+ };
64
146
  let DatasourceIntrospectionService = class DatasourceIntrospectionService {
65
- constructor(moduleRef, datasourceManagementService, moduleMetadataRepository, modelMetadataRepository, moduleMetadataHelperService, modelMetadataHelperService, fieldMetadataService, modelMetadataService, mssqlProvider, mysqlProvider, postgresProvider) {
147
+ constructor(moduleRef, datasourceManagementService, moduleMetadataRepository, modelMetadataRepository, moduleMetadataHelperService, modelMetadataHelperService, fieldMetadataService, modelMetadataService, moduleMetadataService, commandService, mssqlProvider, mysqlProvider, postgresProvider) {
66
148
  this.moduleRef = moduleRef;
67
149
  this.datasourceManagementService = datasourceManagementService;
68
150
  this.moduleMetadataRepository = moduleMetadataRepository;
@@ -71,6 +153,8 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
71
153
  this.modelMetadataHelperService = modelMetadataHelperService;
72
154
  this.fieldMetadataService = fieldMetadataService;
73
155
  this.modelMetadataService = modelMetadataService;
156
+ this.moduleMetadataService = moduleMetadataService;
157
+ this.commandService = commandService;
74
158
  this.mssqlProvider = mssqlProvider;
75
159
  this.mysqlProvider = mysqlProvider;
76
160
  this.postgresProvider = postgresProvider;
@@ -189,24 +273,98 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
189
273
  const persistedModel = plan.operation === "update" && mappingDto.modelId
190
274
  ? await this.modelMetadataService.update(mappingDto.modelId, plan.modelPayload)
191
275
  : await this.modelMetadataService.create(plan.modelPayload);
276
+ const persistedModelId = mappingDto.modelId ?? persistedModel?.id ?? null;
277
+ return {
278
+ data: {
279
+ modelId: persistedModelId,
280
+ operation: plan.operation,
281
+ metadataJson: plan.metadataJson,
282
+ summary: plan.summary,
283
+ },
284
+ };
285
+ }
286
+ async createMigrationArtifacts(moduleId, mappingDto) {
287
+ const plan = await this.buildMappingPreview(moduleId, mappingDto);
288
+ const module = await this.loadModule(moduleId);
289
+ const datasource = this.requireDatasource(mappingDto.dataSource);
290
+ if (!mappingDto.modelId) {
291
+ throw new common_1.BadRequestException("Persist the model mapping first so the generated entity can be registered before creating migration artifacts.");
292
+ }
192
293
  if (plan.migration.willGenerate && plan.migration.content && plan.migration.filePath) {
193
294
  await fs.mkdir(path.dirname(plan.migration.filePath), { recursive: true });
194
295
  await fs.writeFile(plan.migration.filePath, plan.migration.content, "utf8");
195
296
  }
196
- const persistedModelId = mappingDto.modelId ?? persistedModel?.id ?? null;
297
+ const datasourceFile = await this.syncTypeormDatasourceFile(module.name, datasource, plan.modelPayload.singularName);
197
298
  return {
198
299
  data: {
199
- modelId: persistedModelId,
300
+ modelId: mappingDto.modelId,
200
301
  operation: plan.operation,
201
- metadataJson: plan.metadataJson,
202
302
  migration: {
203
303
  ...plan.migration,
204
304
  written: Boolean(plan.migration.willGenerate && plan.migration.filePath),
205
305
  },
306
+ datasourceFile,
206
307
  summary: plan.summary,
207
308
  },
208
309
  };
209
310
  }
311
+ async generateCode(moduleId) {
312
+ await this.loadModule(moduleId);
313
+ const output = await this.moduleMetadataService.generateCodeViaCtl(moduleId);
314
+ return {
315
+ data: {
316
+ moduleId,
317
+ output,
318
+ message: "Module code generation completed.",
319
+ },
320
+ };
321
+ }
322
+ async runMigration(moduleId, datasourceName) {
323
+ const module = await this.loadModule(moduleId);
324
+ const datasource = this.requireDatasource(datasourceName);
325
+ const cwd = path.join(process.cwd(), "..");
326
+ const outputs = [];
327
+ const migrationOutput = await this.commandService.executeCommandWithArgs({
328
+ command: "npx",
329
+ args: ["-y", "@solidxai/solidctl@latest", "migration", "-d", datasource.name, "run"],
330
+ cwd,
331
+ });
332
+ outputs.push([
333
+ `npx @solidxai/solidctl@latest migration -d ${datasource.name} run`,
334
+ migrationOutput,
335
+ ].filter(Boolean).join("\n"));
336
+ const buildOutput = await this.commandService.executeCommandWithArgs({
337
+ command: "npx",
338
+ args: ["-y", "@solidxai/solidctl@latest", "build"],
339
+ cwd,
340
+ });
341
+ outputs.push([
342
+ "npx @solidxai/solidctl@latest build",
343
+ buildOutput,
344
+ ].filter(Boolean).join("\n"));
345
+ const seedOutput = await this.commandService.executeCommandWithArgs({
346
+ command: "npx",
347
+ args: ["-y", "@solidxai/solidctl@latest", "seed", "--modules-to-seed", module.name],
348
+ cwd,
349
+ });
350
+ outputs.push([
351
+ `npx @solidxai/solidctl@latest seed --modules-to-seed ${module.name}`,
352
+ seedOutput,
353
+ ].filter(Boolean).join("\n"));
354
+ return {
355
+ data: {
356
+ moduleId,
357
+ datasource: datasource.name,
358
+ output: outputs.join("\n\n"),
359
+ command: [
360
+ `npx @solidxai/solidctl@latest migration -d ${datasource.name} run`,
361
+ "npx @solidxai/solidctl@latest build",
362
+ `npx @solidxai/solidctl@latest seed --modules-to-seed ${module.name}`,
363
+ ].join("\n"),
364
+ message: `Migration, build, and seed completed successfully for datasource "${datasource.name}".`,
365
+ },
366
+ };
367
+ }
210
368
  async buildMappingPreview(moduleId, mappingDto) {
211
369
  const module = await this.loadModule(moduleId);
212
370
  const datasource = this.requireDatasource(mappingDto.dataSource);
@@ -219,6 +377,8 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
219
377
  if (!tableRecord) {
220
378
  throw new common_1.NotFoundException(`Table "${mappingDto.tableName}" was not found on datasource "${datasource.name}".`);
221
379
  }
380
+ const tableColumns = inventory.columnsByKey.get(tableKey) ?? [];
381
+ this.validateTablePrimaryKeyForMapping(tableRecord, tableColumns, mappingDto);
222
382
  const existingModel = mappingDto.mapped && mappingDto.modelId
223
383
  ? await this.modelMetadataRepository.findOne({
224
384
  where: { id: mappingDto.modelId },
@@ -233,14 +393,14 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
233
393
  if (mappingDto.mapped && !existingModel) {
234
394
  throw new common_1.NotFoundException(`Mapped model "${mappingDto.modelId}" was not found.`);
235
395
  }
236
- const reviewedModel = this.normalizeReviewedMetadataModel(mappingDto.reviewedModel, mappingDto);
396
+ const reviewedModel = this.normalizeReviewedMetadataModel(mappingDto.reviewedModel, mappingDto, tableColumns);
237
397
  const modelPayload = reviewedModel
238
398
  ? this.buildModelPayloadFromReviewedModel(moduleId, mappingDto, existingModel, reviewedModel)
239
399
  : this.buildModelPayload(moduleId, mappingDto, existingModel);
240
400
  const metadataJson = reviewedModel
241
401
  ? await this.buildMetadataJsonPreviewFromReviewedModel(module.name, reviewedModel)
242
402
  : await this.buildMetadataJsonPreview(module.name, mappingDto, existingModel);
243
- const migration = await this.buildMigrationPreview(module.name, datasource, mappingDto, inventory.columnsByKey.get(tableKey) ?? []);
403
+ const migration = await this.buildMigrationPreview(module.name, datasource, mappingDto, tableColumns);
244
404
  const includedColumnNames = mappingDto.columns
245
405
  .filter((column) => !column.handledBySuperclass && column.include)
246
406
  .map((column) => column.columnName);
@@ -252,6 +412,13 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
252
412
  mappedModelId: mappingDto.modelId ?? null,
253
413
  metadataJson,
254
414
  migration,
415
+ datasourceFile: {
416
+ filePath: path.resolve(process.cwd(), "src", `typeorm-${datasource.name}-datasource.ts`),
417
+ created: false,
418
+ updated: false,
419
+ entityRegistered: false,
420
+ migrationGlobRegistered: false,
421
+ },
255
422
  summary: {
256
423
  includedColumnNames,
257
424
  removedColumnNames,
@@ -297,6 +464,7 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
297
464
  };
298
465
  }
299
466
  buildModelPayloadFromReviewedModel(moduleId, mappingDto, existingModel, reviewedModel) {
467
+ const resolvedUserKeyFieldName = this.resolveReviewedUserKeyFieldName(reviewedModel.fields, reviewedModel.userKeyFieldUserKey, mappingDto.userKeyField);
300
468
  const systemFieldPayloads = existingModel
301
469
  ? existingModel.fields
302
470
  .filter((field) => field.isSystem)
@@ -307,7 +475,7 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
307
475
  return {
308
476
  ...field,
309
477
  ...(matchedExistingField?.id ? { id: matchedExistingField.id } : {}),
310
- isUserKey: field.name === reviewedModel.userKeyFieldUserKey,
478
+ isUserKey: field.name === resolvedUserKeyFieldName,
311
479
  isSystem: field.isSystem ?? false,
312
480
  };
313
481
  });
@@ -335,6 +503,7 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
335
503
  async buildMetadataJsonPreview(moduleName, mappingDto, existingModel) {
336
504
  const filePath = await this.moduleMetadataHelperService.getModuleMetadataFilePath(moduleName);
337
505
  const previewFields = await this.buildMetadataPreviewFields(mappingDto, existingModel);
506
+ const resolvedUserKeyFieldName = this.resolveReviewedUserKeyFieldName(previewFields, mappingDto.userKeyField, mappingDto.userKeyField) ?? mappingDto.userKeyField;
338
507
  return {
339
508
  filePath,
340
509
  model: {
@@ -345,7 +514,7 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
345
514
  dataSource: mappingDto.dataSource,
346
515
  dataSourceType: mappingDto.dataSourceType,
347
516
  tableName: mappingDto.tableName,
348
- userKeyFieldUserKey: mappingDto.userKeyField,
517
+ userKeyFieldUserKey: resolvedUserKeyFieldName,
349
518
  isChild: false,
350
519
  legacyTableType: mappingDto.legacyTableType,
351
520
  parentModelUserKey: "",
@@ -394,10 +563,6 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
394
563
  }
395
564
  const serialized = Array.from(finalFields.values())
396
565
  .filter((field) => !field.isSystem)
397
- .map((field) => ({
398
- ...field,
399
- isUserKey: field.name === mappingDto.userKeyField,
400
- }))
401
566
  .sort((left, right) => {
402
567
  const leftOrder = typeof left.id === "number" ? left.id : Number.MAX_SAFE_INTEGER;
403
568
  const rightOrder = typeof right.id === "number" ? right.id : Number.MAX_SAFE_INTEGER;
@@ -410,6 +575,10 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
410
575
  for (const field of serialized) {
411
576
  previewFields.push(await this.fieldMetadataService.createFieldConfig(field));
412
577
  }
578
+ const resolvedUserKeyFieldName = this.resolveReviewedUserKeyFieldName(previewFields, mappingDto.userKeyField, mappingDto.userKeyField);
579
+ for (const field of previewFields) {
580
+ field.isUserKey = field.name === resolvedUserKeyFieldName;
581
+ }
413
582
  return previewFields;
414
583
  }
415
584
  async buildMigrationPreview(moduleName, datasource, mappingDto, tableColumns) {
@@ -455,7 +624,13 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
455
624
  }
456
625
  return rest;
457
626
  }
458
- normalizeReviewedMetadataModel(reviewedModel, mappingDto) {
627
+ sanitizeConfiguredFieldPayload(fieldConfig) {
628
+ if (!fieldConfig || typeof fieldConfig !== "object" || Array.isArray(fieldConfig)) {
629
+ return {};
630
+ }
631
+ return this.sanitizeExistingFieldPayload(fieldConfig);
632
+ }
633
+ normalizeReviewedMetadataModel(reviewedModel, mappingDto, tableColumns) {
459
634
  if (!reviewedModel) {
460
635
  return null;
461
636
  }
@@ -504,10 +679,14 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
504
679
  }
505
680
  fieldNames.add(loweredName);
506
681
  }
507
- const userKeyFieldUserKey = readString("userKeyFieldUserKey");
508
- if (!normalizedFields.some((field) => field.name === userKeyFieldUserKey && !field.isMarkedForRemoval)) {
682
+ const requestedUserKeyFieldUserKey = readString("userKeyFieldUserKey");
683
+ const resolvedUserKeyFieldName = this.resolveReviewedUserKeyFieldName(normalizedFields, requestedUserKeyFieldUserKey, mappingDto.userKeyField);
684
+ const inheritedGeneratedIdUserKey = this.isGeneratedIdInheritedUserKey(mappingDto.legacyTableType, requestedUserKeyFieldUserKey);
685
+ if (!resolvedUserKeyFieldName && !inheritedGeneratedIdUserKey) {
509
686
  throw new common_1.BadRequestException("Reviewed metadata JSON must keep the selected userKeyFieldUserKey in the fields array.");
510
687
  }
688
+ this.validateReviewedPrimaryKeyFields(normalizedFields, tableColumns);
689
+ const userKeyFieldUserKey = resolvedUserKeyFieldName ?? requestedUserKeyFieldUserKey;
511
690
  return {
512
691
  singularName: readString("singularName"),
513
692
  pluralName: readString("pluralName"),
@@ -526,10 +705,39 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
526
705
  internationalisation: readBoolean("internationalisation"),
527
706
  fields: normalizedFields.map((field) => ({
528
707
  ...field,
529
- isUserKey: field.name === userKeyFieldUserKey,
708
+ isUserKey: field.name === resolvedUserKeyFieldName,
530
709
  })),
531
710
  };
532
711
  }
712
+ resolveReviewedUserKeyFieldName(reviewedFields, requestedUserKeyFieldName, fallbackUserKeyFieldName) {
713
+ const activeFields = reviewedFields.filter((field) => !field.isMarkedForRemoval);
714
+ const normalizedRequested = `${requestedUserKeyFieldName ?? ""}`.trim().toLowerCase();
715
+ const normalizedFallback = `${fallbackUserKeyFieldName ?? ""}`.trim().toLowerCase();
716
+ const byExactRequested = activeFields.find((field) => field.name?.toLowerCase?.() === normalizedRequested);
717
+ if (byExactRequested) {
718
+ return byExactRequested.name;
719
+ }
720
+ const byExistingUserKeyFlag = activeFields.find((field) => field.isUserKey);
721
+ if (byExistingUserKeyFlag) {
722
+ return byExistingUserKeyFlag.name;
723
+ }
724
+ const byPrimaryKeyFallback = activeFields.find((field) => {
725
+ if (!field.isPrimaryKey) {
726
+ return false;
727
+ }
728
+ const normalizedName = `${field.name ?? ""}`.trim().toLowerCase();
729
+ return normalizedName === normalizedFallback || normalizedName === "id" || normalizedName === "legacyid";
730
+ });
731
+ if (byPrimaryKeyFallback) {
732
+ return byPrimaryKeyFallback.name;
733
+ }
734
+ const byFallbackFieldName = activeFields.find((field) => field.name?.toLowerCase?.() === normalizedFallback);
735
+ return byFallbackFieldName?.name ?? null;
736
+ }
737
+ isGeneratedIdInheritedUserKey(legacyTableType, requestedUserKeyFieldName) {
738
+ return legacyTableType === legacy_table_type_enum_1.LegacyTableType.GENERATED_ID
739
+ && `${requestedUserKeyFieldName ?? ""}`.trim().toLowerCase() === "id";
740
+ }
533
741
  normalizeReviewedField(field, index) {
534
742
  if (!field || typeof field !== "object" || Array.isArray(field)) {
535
743
  throw new common_1.BadRequestException(`Reviewed metadata JSON field at index ${index} is not a valid object.`);
@@ -577,32 +785,37 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
577
785
  }
578
786
  buildFieldPayload(column, mappingDto, existingField) {
579
787
  const preserved = existingField ? this.sanitizeExistingFieldPayload(existingField) : {};
788
+ const configured = this.sanitizeConfiguredFieldPayload(column.fieldConfig);
789
+ const merged = {
790
+ ...preserved,
791
+ ...configured,
792
+ };
580
793
  const maxLength = column.characterMaximumLength && ["shortText", "longText"].includes(column.solidFieldType)
581
794
  ? column.characterMaximumLength
582
- : preserved.max;
795
+ : merged.max;
583
796
  return {
584
- ...preserved,
797
+ ...merged,
585
798
  ...(column.fieldId ? { id: column.fieldId } : {}),
586
799
  name: column.fieldName,
587
- displayName: preserved.displayName ?? (0, lodash_1.startCase)(column.fieldName),
588
- description: preserved.description ?? "",
800
+ displayName: column.displayName?.trim() || merged.displayName || (0, lodash_1.startCase)(column.fieldName),
801
+ description: merged.description ?? "",
589
802
  type: column.solidFieldType,
590
803
  ormType: column.ormType,
591
- length: preserved.length ?? column.characterMaximumLength ?? undefined,
592
- defaultValue: preserved.defaultValue ?? column.defaultValue ?? undefined,
593
- required: preserved.required ?? (!column.nullable || column.isPrimaryKey),
594
- unique: preserved.unique ?? false,
595
- encrypt: preserved.encrypt ?? false,
596
- index: preserved.index ?? false,
804
+ length: merged.length ?? column.characterMaximumLength ?? undefined,
805
+ defaultValue: merged.defaultValue ?? column.defaultValue ?? undefined,
806
+ required: merged.required ?? (!column.nullable || column.isPrimaryKey),
807
+ unique: merged.unique ?? false,
808
+ encrypt: merged.encrypt ?? false,
809
+ index: merged.index ?? false,
597
810
  max: maxLength ?? undefined,
598
- min: preserved.min ?? undefined,
599
- private: preserved.private ?? false,
600
- isSystem: preserved.isSystem ?? false,
811
+ min: merged.min ?? undefined,
812
+ private: merged.private ?? false,
813
+ isSystem: merged.isSystem ?? false,
601
814
  isMarkedForRemoval: false,
602
815
  columnName: column.columnName,
603
816
  isUserKey: mappingDto.userKeyField === column.fieldName,
604
- enableAuditTracking: preserved.enableAuditTracking ?? mappingDto.enableAuditTracking,
605
- isMultiSelect: preserved.isMultiSelect ?? false,
817
+ enableAuditTracking: merged.enableAuditTracking ?? mappingDto.enableAuditTracking,
818
+ isMultiSelect: merged.isMultiSelect ?? false,
606
819
  isPrimaryKey: column.isPrimaryKey,
607
820
  };
608
821
  }
@@ -696,23 +909,19 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
696
909
  const generatedIdUniqueName = this.buildMigrationObjectName("UQ", tableNameLiteral, "ss_id");
697
910
  const upColumnStatements = missingSystemColumns.map((definition) => {
698
911
  const columnLiteral = this.renderTableColumnLiteral(definition);
699
- return [
700
- ` if (!(await queryRunner.hasColumn(tableName, ${JSON.stringify(definition.columnName)}))) {`,
701
- ` await queryRunner.addColumn(tableName, new TableColumn(${columnLiteral}));`,
702
- " }",
703
- ].join("\n");
912
+ return ` if (!(await queryRunner.hasColumn(tableName, ${JSON.stringify(definition.columnName)})))\n`
913
+ + ` await queryRunner.addColumn(tableName, new TableColumn(${columnLiteral}));`;
704
914
  }).join("\n\n");
705
915
  const postUpStatements = [];
706
916
  if (missingSystemColumns.some((definition) => definition.columnName === "ss_deleted_at")) {
707
917
  postUpStatements.push([
708
918
  " {",
709
919
  " const table = await queryRunner.getTable(tableName);",
710
- ` if (table && !table.indices.some((index) => index.name === ${JSON.stringify(deletedAtIndexName)})) {`,
711
- " await queryRunner.createIndex(tableName, new TableIndex({",
712
- ` name: ${JSON.stringify(deletedAtIndexName)},`,
713
- " columnNames: [\"ss_deleted_at\"],",
714
- " }));",
715
- " }",
920
+ ` if (table && !table.indices.some((index) => index.name === ${JSON.stringify(deletedAtIndexName)}))`,
921
+ ` await queryRunner.createIndex(tableName, new TableIndex(${this.renderTableIndexLiteral({
922
+ name: deletedAtIndexName,
923
+ columnNames: ["ss_deleted_at"],
924
+ })}));`,
716
925
  " }",
717
926
  ].join("\n"));
718
927
  }
@@ -720,13 +929,12 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
720
929
  postUpStatements.push([
721
930
  " {",
722
931
  " const table = await queryRunner.getTable(tableName);",
723
- ` if (table && !table.indices.some((index) => index.name === ${JSON.stringify(generatedIdUniqueName)})) {`,
724
- " await queryRunner.createIndex(tableName, new TableIndex({",
725
- ` name: ${JSON.stringify(generatedIdUniqueName)},`,
726
- " columnNames: [\"ss_id\"],",
727
- " isUnique: true,",
728
- " }));",
729
- " }",
932
+ ` if (table && !table.indices.some((index) => index.name === ${JSON.stringify(generatedIdUniqueName)}))`,
933
+ ` await queryRunner.createIndex(tableName, new TableIndex(${this.renderTableIndexLiteral({
934
+ name: generatedIdUniqueName,
935
+ columnNames: ["ss_id"],
936
+ isUnique: true,
937
+ })}));`,
730
938
  " }",
731
939
  ].join("\n"));
732
940
  }
@@ -736,9 +944,8 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
736
944
  " {",
737
945
  " const table = await queryRunner.getTable(tableName);",
738
946
  ` const index = table?.indices.find((entry) => entry.name === ${JSON.stringify(generatedIdUniqueName)});`,
739
- " if (index) {",
947
+ " if (index)",
740
948
  " await queryRunner.dropIndex(tableName, index);",
741
- " }",
742
949
  " }",
743
950
  ].join("\n"));
744
951
  }
@@ -747,20 +954,16 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
747
954
  " {",
748
955
  " const table = await queryRunner.getTable(tableName);",
749
956
  ` const index = table?.indices.find((entry) => entry.name === ${JSON.stringify(deletedAtIndexName)});`,
750
- " if (index) {",
957
+ " if (index)",
751
958
  " await queryRunner.dropIndex(tableName, index);",
752
- " }",
753
959
  " }",
754
960
  ].join("\n"));
755
961
  }
756
962
  downStatements.push(...missingSystemColumns
757
963
  .slice()
758
964
  .reverse()
759
- .map((definition) => [
760
- ` if (await queryRunner.hasColumn(tableName, ${JSON.stringify(definition.columnName)})) {`,
761
- ` await queryRunner.dropColumn(tableName, ${JSON.stringify(definition.columnName)});`,
762
- " }",
763
- ].join("\n")));
965
+ .map((definition) => ` if (await queryRunner.hasColumn(tableName, ${JSON.stringify(definition.columnName)}))\n`
966
+ + ` await queryRunner.dropColumn(tableName, ${JSON.stringify(definition.columnName)});`));
764
967
  return [
765
968
  "import { MigrationInterface, QueryRunner, TableColumn, TableIndex } from \"typeorm\";",
766
969
  "",
@@ -783,27 +986,36 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
783
986
  }
784
987
  renderTableColumnLiteral(definition) {
785
988
  const properties = [
786
- `{\n name: ${JSON.stringify(definition.columnName)},`,
787
- ` type: ${JSON.stringify(definition.type)},`,
989
+ `name: ${JSON.stringify(definition.columnName)}`,
990
+ `type: ${JSON.stringify(definition.type)}`,
788
991
  ];
789
992
  if (definition.length) {
790
- properties.push(` length: ${JSON.stringify(definition.length)},`);
993
+ properties.push(`length: ${JSON.stringify(definition.length)}`);
791
994
  }
792
995
  if (typeof definition.isNullable === "boolean") {
793
- properties.push(` isNullable: ${definition.isNullable},`);
996
+ properties.push(`isNullable: ${definition.isNullable}`);
794
997
  }
795
998
  if (definition.defaultExpression) {
796
- properties.push(` default: ${JSON.stringify(definition.defaultExpression)},`);
999
+ properties.push(`default: ${JSON.stringify(definition.defaultExpression)}`);
797
1000
  }
798
1001
  if (definition.isGenerated) {
799
- properties.push(" isGenerated: true,");
800
- properties.push(" generationStrategy: \"increment\",");
1002
+ properties.push("isGenerated: true");
1003
+ properties.push("generationStrategy: \"increment\"");
801
1004
  }
802
1005
  if (definition.isUnique) {
803
- properties.push(" isUnique: true,");
1006
+ properties.push("isUnique: true");
804
1007
  }
805
- properties.push(" }");
806
- return properties.join("\n");
1008
+ return `{ ${properties.join(", ")}, }`;
1009
+ }
1010
+ renderTableIndexLiteral(definition) {
1011
+ const properties = [
1012
+ `name: ${JSON.stringify(definition.name)}`,
1013
+ `columnNames: ${JSON.stringify(definition.columnNames)}`,
1014
+ ];
1015
+ if (definition.isUnique) {
1016
+ properties.push("isUnique: true");
1017
+ }
1018
+ return `{ ${properties.join(", ")}, }`;
807
1019
  }
808
1020
  buildMigrationObjectName(prefix, tableName, columnName) {
809
1021
  const hash = (0, crypto_1.createHash)("md5").update(`${tableName}:${columnName}:${prefix}`).digest("hex").slice(0, 24);
@@ -832,12 +1044,14 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
832
1044
  async buildTableInventory(datasource) {
833
1045
  const provider = this.getProvider(datasource.type);
834
1046
  const runtimeDataSource = this.resolveDataSourceByName(datasource.name);
835
- const [tables, columns, models] = await Promise.all([
1047
+ const [rawTables, rawColumns, models] = await Promise.all([
836
1048
  provider.listTables(runtimeDataSource),
837
1049
  provider.listColumns(runtimeDataSource),
838
1050
  this.modelMetadataRepository.find({ relations: { module: true } }),
839
1051
  ]);
840
- const modelMap = this.buildModelMap(models);
1052
+ const tables = rawTables.filter((table) => !this.isSolidxInternalTableName(table.tableName));
1053
+ const columns = rawColumns.filter((column) => !this.isSolidxInternalTableName(column.tableName));
1054
+ const modelLookup = this.buildModelLookup(models);
841
1055
  const columnsByKey = this.groupColumnsByTable(columns);
842
1056
  const tableKeys = new Set();
843
1057
  for (const table of tables) {
@@ -857,8 +1071,10 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
857
1071
  }
858
1072
  const suggestedLegacyTableType = this.detectLegacyTableType(datasource.type, tableColumns);
859
1073
  const suggestedIdColumn = this.getSuggestedIdColumn(datasource.type, tableColumns, suggestedLegacyTableType);
860
- const mappedModel = modelMap.get(this.toModelMapKey(datasource.name, tableName)) ?? null;
1074
+ const mappedModel = this.resolveMappedModel(modelLookup, datasource.name, tableName);
861
1075
  const physicalColumns = tableColumns.filter((column) => !this.isHandledBySuperclass(column.columnName, suggestedLegacyTableType));
1076
+ const primaryKeyColumns = tableColumns.filter((column) => column.isPrimaryKey);
1077
+ const hasPrimaryKey = primaryKeyColumns.length > 0;
862
1078
  return {
863
1079
  schema,
864
1080
  tableName,
@@ -875,6 +1091,12 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
875
1091
  suggestedUserKeyField: this.buildUserKeyCandidates(tableColumns)[0]?.name ?? "id",
876
1092
  columnCount: tableColumns.length,
877
1093
  physicalColumnCount: physicalColumns.length,
1094
+ hasPrimaryKey,
1095
+ primaryKeyColumnCount: primaryKeyColumns.length,
1096
+ primaryKeyColumnNames: primaryKeyColumns.map((column) => column.columnName),
1097
+ mappingBlockedReason: hasPrimaryKey
1098
+ ? null
1099
+ : this.buildMissingPrimaryKeyMessage(tableName),
878
1100
  };
879
1101
  })
880
1102
  .filter((record) => Boolean(record))
@@ -892,16 +1114,37 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
892
1114
  columnsByKey,
893
1115
  };
894
1116
  }
895
- buildModelMap(models) {
896
- const map = new Map();
1117
+ buildModelLookup(models) {
1118
+ const byDatasourceAndTable = new Map();
1119
+ const byTableName = new Map();
897
1120
  for (const model of models) {
898
1121
  if (!model.tableName) {
899
1122
  continue;
900
1123
  }
901
- map.set(this.toModelMapKey(model.dataSource, model.tableName), model);
902
- map.set(this.toModelMapKey("*", model.tableName), model);
1124
+ byDatasourceAndTable.set(this.toModelMapKey(model.dataSource, model.tableName), model);
1125
+ const normalizedTableName = model.tableName.trim().toLowerCase();
1126
+ const bucket = byTableName.get(normalizedTableName);
1127
+ if (bucket) {
1128
+ bucket.push(model);
1129
+ continue;
1130
+ }
1131
+ byTableName.set(normalizedTableName, [model]);
1132
+ }
1133
+ return {
1134
+ byDatasourceAndTable,
1135
+ byTableName,
1136
+ };
1137
+ }
1138
+ resolveMappedModel(lookup, datasourceName, tableName) {
1139
+ const exactMatch = lookup.byDatasourceAndTable.get(this.toModelMapKey(datasourceName, tableName));
1140
+ if (exactMatch) {
1141
+ return exactMatch;
903
1142
  }
904
- return map;
1143
+ const fallbackMatches = lookup.byTableName.get(tableName.trim().toLowerCase()) ?? [];
1144
+ if (fallbackMatches.length === 1) {
1145
+ return fallbackMatches[0];
1146
+ }
1147
+ return fallbackMatches[0] ?? null;
905
1148
  }
906
1149
  groupColumnsByTable(columns) {
907
1150
  const grouped = new Map();
@@ -916,6 +1159,9 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
916
1159
  }
917
1160
  return grouped;
918
1161
  }
1162
+ isSolidxInternalTableName(tableName) {
1163
+ return typeof tableName === "string" && tableName.toLowerCase().startsWith("ss_");
1164
+ }
919
1165
  detectLegacyTableType(datasourceType, columns) {
920
1166
  const normalizedDatasourceType = datasourceType.toLowerCase();
921
1167
  const hasExistingGeneratedId = columns.some((column) => column.isAutoGenerated);
@@ -983,12 +1229,16 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
983
1229
  }
984
1230
  toDetailColumnRecord(column, legacyTableType, datasourceType) {
985
1231
  const superclassFieldName = this.getSuperclassFieldName(column.columnName, legacyTableType);
1232
+ const normalizedColumnName = column.columnName.toLowerCase();
986
1233
  const fieldName = legacyTableType === legacy_table_type_enum_1.LegacyTableType.EXISTING_ID && column.isAutoGenerated
987
1234
  ? "id"
988
- : this.toFieldName(column.columnName);
1235
+ : legacyTableType === legacy_table_type_enum_1.LegacyTableType.GENERATED_ID && normalizedColumnName === "id"
1236
+ ? "legacyId"
1237
+ : this.toFieldName(column.columnName);
989
1238
  return {
990
1239
  columnName: column.columnName,
991
1240
  fieldName,
1241
+ displayName: (0, lodash_1.startCase)(fieldName),
992
1242
  dataType: column.dataType,
993
1243
  solidFieldType: this.toSolidFieldType(column),
994
1244
  ormType: this.toOrmFieldType(column, datasourceType),
@@ -999,10 +1249,49 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
999
1249
  numericScale: column.numericScale,
1000
1250
  ordinalPosition: column.ordinalPosition,
1001
1251
  isAutoGenerated: column.isAutoGenerated,
1252
+ isPrimaryKey: column.isPrimaryKey,
1002
1253
  handledBySuperclass: Boolean(superclassFieldName),
1003
1254
  superclassFieldName,
1004
1255
  };
1005
1256
  }
1257
+ validateTablePrimaryKeyForMapping(tableRecord, tableColumns, mappingDto) {
1258
+ const detectedPrimaryKeyColumns = tableColumns.filter((column) => column.isPrimaryKey);
1259
+ if (!detectedPrimaryKeyColumns.length) {
1260
+ throw new common_1.BadRequestException(tableRecord.mappingBlockedReason ?? this.buildMissingPrimaryKeyMessage(tableRecord.tableName));
1261
+ }
1262
+ const requestColumnsByName = new Map(mappingDto.columns.map((column) => [column.columnName.trim().toLowerCase(), column]));
1263
+ for (const primaryKeyColumn of detectedPrimaryKeyColumns) {
1264
+ const matchingRequestColumn = requestColumnsByName.get(primaryKeyColumn.columnName.trim().toLowerCase());
1265
+ if (!matchingRequestColumn) {
1266
+ throw new common_1.BadRequestException(`Primary key column "${primaryKeyColumn.columnName}" must remain present in the mapping request for table "${tableRecord.tableName}".`);
1267
+ }
1268
+ if (!matchingRequestColumn.include) {
1269
+ throw new common_1.BadRequestException(`Primary key column "${primaryKeyColumn.columnName}" cannot be excluded from the mapping for table "${tableRecord.tableName}".`);
1270
+ }
1271
+ if (!matchingRequestColumn.isPrimaryKey) {
1272
+ throw new common_1.BadRequestException(`Primary key column "${primaryKeyColumn.columnName}" must stay marked as isPrimaryKey for table "${tableRecord.tableName}".`);
1273
+ }
1274
+ }
1275
+ }
1276
+ validateReviewedPrimaryKeyFields(reviewedFields, tableColumns) {
1277
+ const detectedPrimaryKeyColumns = tableColumns.filter((column) => column.isPrimaryKey);
1278
+ if (!detectedPrimaryKeyColumns.length) {
1279
+ return;
1280
+ }
1281
+ const activeReviewedFields = reviewedFields.filter((field) => !field.isMarkedForRemoval);
1282
+ for (const primaryKeyColumn of detectedPrimaryKeyColumns) {
1283
+ const matchingReviewedField = activeReviewedFields.find((field) => `${field.columnName ?? ""}`.trim().toLowerCase() === primaryKeyColumn.columnName.trim().toLowerCase());
1284
+ if (!matchingReviewedField) {
1285
+ throw new common_1.BadRequestException(`Reviewed metadata JSON must keep datasource primary key column "${primaryKeyColumn.columnName}" in the fields array.`);
1286
+ }
1287
+ if (!matchingReviewedField.isPrimaryKey) {
1288
+ throw new common_1.BadRequestException(`Reviewed metadata JSON must keep datasource primary key column "${primaryKeyColumn.columnName}" marked with isPrimaryKey: true.`);
1289
+ }
1290
+ }
1291
+ }
1292
+ buildMissingPrimaryKeyMessage(tableName) {
1293
+ return `Table "${tableName}" cannot be mapped because the datasource table does not define any primary key. Add a real primary key to the table before continuing with SolidX mapping.`;
1294
+ }
1006
1295
  getSuperclassFieldName(columnName, legacyTableType) {
1007
1296
  return this.getLegacySuperclassFieldName(columnName, legacyTableType);
1008
1297
  }
@@ -1033,127 +1322,70 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
1033
1322
  }
1034
1323
  return "LegacyCommonEntityWithExistingId";
1035
1324
  }
1036
- toSolidFieldType(column) {
1037
- const normalized = column.dataType.toLowerCase();
1038
- const charLength = column.characterMaximumLength ?? null;
1039
- if (["bit", "bool", "boolean"].includes(normalized)) {
1040
- return "boolean";
1041
- }
1042
- if (["bigint"].includes(normalized)) {
1043
- return "bigint";
1044
- }
1045
- if (["int", "integer", "smallint", "tinyint"].includes(normalized)) {
1046
- return "int";
1047
- }
1048
- if (["numeric", "decimal", "float", "double", "real", "money", "smallmoney"].includes(normalized)) {
1049
- return "decimal";
1050
- }
1051
- if (["date"].includes(normalized)) {
1052
- return "date";
1053
- }
1054
- if (["time"].includes(normalized)) {
1055
- return "time";
1056
- }
1057
- if (["datetime", "datetime2", "timestamp", "timestamptz", "smalldatetime"].includes(normalized) || normalized.includes("date")) {
1058
- return "datetime";
1325
+ getDatasourceTypeFamily(dataType) {
1326
+ const normalized = dataType.toLowerCase();
1327
+ for (const [family, aliases] of Object.entries(DATASOURCE_TYPE_FAMILY_ALIASES)) {
1328
+ if (aliases.includes(normalized)) {
1329
+ return family;
1330
+ }
1059
1331
  }
1060
- if (["json", "jsonb", "simple-json", "simplejson"].includes(normalized) || normalized.includes("json")) {
1332
+ if (normalized.includes("json")) {
1061
1333
  return "json";
1062
1334
  }
1063
- if (["uniqueidentifier", "uuid"].includes(normalized)) {
1064
- return "uuid";
1065
- }
1066
- if (["text", "ntext", "mediumtext", "longtext", "clob"].includes(normalized)) {
1067
- return "longText";
1068
- }
1069
- if (["varchar", "nvarchar", "char", "nchar", "citext"].includes(normalized)) {
1070
- if (charLength !== null && charLength > 255) {
1071
- return "longText";
1072
- }
1073
- return "shortText";
1335
+ if (normalized.includes("date")) {
1336
+ return "datetime";
1074
1337
  }
1075
- return "shortText";
1338
+ return null;
1076
1339
  }
1077
- toOrmFieldType(column, datasourceType) {
1078
- const normalized = column.dataType.toLowerCase();
1079
- const normalizedDatasourceType = datasourceType.toLowerCase();
1080
- if (normalizedDatasourceType === "mssql") {
1081
- if (["bit", "bool", "boolean"].includes(normalized))
1082
- return "bit";
1083
- if (["bigint"].includes(normalized))
1340
+ toSolidFieldType(column) {
1341
+ const family = this.getDatasourceTypeFamily(column.dataType);
1342
+ const charLength = column.characterMaximumLength ?? null;
1343
+ switch (family) {
1344
+ case "boolean":
1345
+ return "boolean";
1346
+ case "bigint":
1084
1347
  return "bigint";
1085
- if (["int", "integer", "smallint", "tinyint"].includes(normalized))
1086
- return "int";
1087
- if (["numeric"].includes(normalized))
1088
- return "numeric";
1089
- if (["decimal", "float", "double", "real", "money", "smallmoney"].includes(normalized))
1090
- return "decimal";
1091
- if (["date"].includes(normalized))
1092
- return "date";
1093
- if (["time"].includes(normalized))
1094
- return "time";
1095
- if (["datetime2"].includes(normalized))
1096
- return "datetime2";
1097
- if (["datetime", "smalldatetime", "timestamp"].includes(normalized) || normalized.includes("date"))
1098
- return "datetime";
1099
- if (["json", "jsonb", "simple-json", "simplejson"].includes(normalized) || normalized.includes("json"))
1100
- return "simple-json";
1101
- if (["uniqueidentifier", "uuid"].includes(normalized))
1102
- return "uniqueidentifier";
1103
- if (["text", "ntext", "mediumtext", "longtext", "clob"].includes(normalized))
1104
- return "text";
1105
- if (["nvarchar", "nchar"].includes(normalized))
1106
- return "nvarchar";
1107
- return "varchar";
1108
- }
1109
- if (normalizedDatasourceType === "mysql") {
1110
- if (["bigint"].includes(normalized))
1348
+ case "int":
1111
1349
  return "int";
1112
- if (["int", "integer", "smallint", "tinyint"].includes(normalized))
1113
- return "int";
1114
- if (["decimal", "numeric"].includes(normalized))
1350
+ case "numeric":
1351
+ case "decimal":
1352
+ case "float":
1115
1353
  return "decimal";
1116
- if (["float", "double", "real", "money", "smallmoney"].includes(normalized))
1117
- return "double";
1118
- if (["bit", "bool", "boolean"].includes(normalized))
1119
- return "boolean";
1120
- if (["date"].includes(normalized))
1354
+ case "date":
1121
1355
  return "date";
1122
- if (["time"].includes(normalized))
1356
+ case "time":
1123
1357
  return "time";
1124
- if (["datetime", "timestamp", "smalldatetime"].includes(normalized) || normalized.includes("date"))
1358
+ case "datetime":
1359
+ case "datetimeWithTimezone":
1125
1360
  return "datetime";
1126
- if (["json", "jsonb", "simple-json", "simplejson"].includes(normalized) || normalized.includes("json"))
1361
+ case "json":
1362
+ case "jsonb":
1127
1363
  return "json";
1128
- if (["mediumtext"].includes(normalized))
1129
- return "mediumtext";
1130
- if (["longtext", "text", "ntext", "clob"].includes(normalized))
1131
- return "longtext";
1132
- return "varchar";
1133
- }
1134
- if (["bigint"].includes(normalized))
1135
- return "bigint";
1136
- if (["int", "integer", "smallint", "tinyint"].includes(normalized))
1137
- return "integer";
1138
- if (["decimal", "numeric", "float", "double", "real", "money", "smallmoney"].includes(normalized))
1139
- return "decimal";
1140
- if (["bit", "bool", "boolean"].includes(normalized))
1141
- return "boolean";
1142
- if (["date"].includes(normalized))
1143
- return "date";
1144
- if (["time"].includes(normalized))
1145
- return "time";
1146
- if (["timestamptz"].includes(normalized))
1147
- return "timestamptz";
1148
- if (["datetime", "datetime2", "timestamp", "smalldatetime"].includes(normalized) || normalized.includes("date"))
1149
- return "timestamp";
1150
- if (["jsonb"].includes(normalized))
1151
- return "jsonb";
1152
- if (["json", "simple-json", "simplejson"].includes(normalized) || normalized.includes("json"))
1153
- return "json";
1154
- if (["text", "ntext", "mediumtext", "longtext", "clob"].includes(normalized))
1155
- return "text";
1156
- return "varchar";
1364
+ case "uuid":
1365
+ return "uuid";
1366
+ case "mediumText":
1367
+ case "longText":
1368
+ return "longText";
1369
+ case "shortText":
1370
+ case "unicodeShortText":
1371
+ if (charLength !== null && charLength > 255) {
1372
+ return "longText";
1373
+ }
1374
+ return "shortText";
1375
+ default:
1376
+ return "shortText";
1377
+ }
1378
+ }
1379
+ toOrmFieldType(column, datasourceType) {
1380
+ const family = this.getDatasourceTypeFamily(column.dataType);
1381
+ const normalizedDatasourceType = datasourceType.toLowerCase();
1382
+ const ormType = family
1383
+ ? ORM_TYPE_BY_DATASOURCE_FAMILY[normalizedDatasourceType]?.[family]
1384
+ : undefined;
1385
+ if (ormType) {
1386
+ return ormType;
1387
+ }
1388
+ return normalizedDatasourceType === "postgres" ? "varchar" : "varchar";
1157
1389
  }
1158
1390
  toFieldName(columnName) {
1159
1391
  return (0, lodash_1.camelCase)(columnName.replace(/^ss_/, ""));
@@ -1190,6 +1422,240 @@ let DatasourceIntrospectionService = class DatasourceIntrospectionService {
1190
1422
  toModelMapKey(datasourceName, tableName) {
1191
1423
  return `${datasourceName.toLowerCase()}::${tableName.toLowerCase()}`;
1192
1424
  }
1425
+ async syncTypeormDatasourceFile(moduleName, datasource, singularName) {
1426
+ const datasourceFilePath = path.resolve(process.cwd(), "src", `typeorm-${datasource.name}-datasource.ts`);
1427
+ const entityClassName = (0, string_helper_1.classify)(singularName);
1428
+ const entityImportPath = `./${moduleName}/entities/${(0, lodash_1.kebabCase)(singularName)}.entity`;
1429
+ const migrationGlob = `join(__dirname, './${moduleName}/migrations/${datasource.name}/*.{ts,js}')`;
1430
+ const existingContent = await fs.readFile(datasourceFilePath, "utf8").catch(() => null);
1431
+ if (!existingContent) {
1432
+ const rendered = this.renderTypeormDatasourceTemplate({
1433
+ datasource,
1434
+ entityClassName,
1435
+ entityImportPath,
1436
+ migrationGlob,
1437
+ });
1438
+ await fs.writeFile(datasourceFilePath, rendered, "utf8");
1439
+ return {
1440
+ filePath: datasourceFilePath,
1441
+ created: true,
1442
+ updated: false,
1443
+ entityRegistered: true,
1444
+ migrationGlobRegistered: true,
1445
+ };
1446
+ }
1447
+ const project = new ts_morph_1.Project({
1448
+ skipAddingFilesFromTsConfig: true,
1449
+ manipulationSettings: {
1450
+ quoteKind: ts_morph_1.QuoteKind.Single,
1451
+ indentationText: ts_morph_1.IndentationText.FourSpaces,
1452
+ insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: true,
1453
+ },
1454
+ });
1455
+ const sourceFile = project.createSourceFile(datasourceFilePath, existingContent, { overwrite: true });
1456
+ const entityImportDeclaration = sourceFile.getImportDeclarations().find((declaration) => declaration.getModuleSpecifierValue() === entityImportPath);
1457
+ if (entityImportDeclaration) {
1458
+ const alreadyImported = entityImportDeclaration.getNamedImports().some((namedImport) => namedImport.getName() === entityClassName);
1459
+ if (!alreadyImported) {
1460
+ entityImportDeclaration.addNamedImport(entityClassName);
1461
+ }
1462
+ }
1463
+ else {
1464
+ sourceFile.addImportDeclaration({
1465
+ moduleSpecifier: entityImportPath,
1466
+ namedImports: [entityClassName],
1467
+ });
1468
+ }
1469
+ const entitiesArray = sourceFile
1470
+ .getVariableDeclarationOrThrow("entities")
1471
+ .getInitializerIfKindOrThrow(ts_morph_1.SyntaxKind.ArrayLiteralExpression);
1472
+ const entityAlreadyRegistered = this.arrayLiteralContainsValue(entitiesArray, entityClassName);
1473
+ if (!entityAlreadyRegistered) {
1474
+ entitiesArray.addElement(entityClassName);
1475
+ }
1476
+ const dataSourceOptions = this.getTypeormDatasourceOptions(sourceFile);
1477
+ const migrationsArray = this.getObjectPropertyArrayLiteral(dataSourceOptions, "migrations");
1478
+ const migrationAlreadyRegistered = this.arrayLiteralContainsValue(migrationsArray, migrationGlob);
1479
+ if (!migrationAlreadyRegistered) {
1480
+ migrationsArray.addElement(migrationGlob);
1481
+ }
1482
+ sourceFile.organizeImports();
1483
+ sourceFile.formatText();
1484
+ const nextContent = sourceFile.getFullText();
1485
+ const updated = nextContent !== existingContent;
1486
+ if (updated) {
1487
+ await fs.writeFile(datasourceFilePath, nextContent, "utf8");
1488
+ }
1489
+ return {
1490
+ filePath: datasourceFilePath,
1491
+ created: false,
1492
+ updated,
1493
+ entityRegistered: true,
1494
+ migrationGlobRegistered: true,
1495
+ };
1496
+ }
1497
+ renderTypeormDatasourceTemplate(input) {
1498
+ const { datasource, entityClassName, entityImportPath, migrationGlob } = input;
1499
+ const envPrefix = datasource.envPrefix?.toUpperCase?.() || "DEFAULT";
1500
+ const portFallback = datasource.type === "postgres" ? 5432 : datasource.type === "mysql" ? 3306 : 1433;
1501
+ const project = new ts_morph_1.Project({
1502
+ skipAddingFilesFromTsConfig: true,
1503
+ manipulationSettings: {
1504
+ quoteKind: ts_morph_1.QuoteKind.Single,
1505
+ indentationText: ts_morph_1.IndentationText.FourSpaces,
1506
+ insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: true,
1507
+ },
1508
+ });
1509
+ const sourceFile = project.createSourceFile("typeorm-template.ts", "", { overwrite: true });
1510
+ sourceFile.addImportDeclaration({ moduleSpecifier: "reflect-metadata" });
1511
+ sourceFile.addImportDeclaration({ moduleSpecifier: "path", namedImports: ["join"] });
1512
+ sourceFile.addImportDeclaration({
1513
+ moduleSpecifier: "dotenv",
1514
+ namedImports: [{ name: "config", alias: "dotenvConfig" }],
1515
+ });
1516
+ sourceFile.addStatements("dotenvConfig({ path: join(__dirname, '../.env') });");
1517
+ sourceFile.addStatements("");
1518
+ sourceFile.addImportDeclaration({ moduleSpecifier: "typeorm", namedImports: ["DataSource"] });
1519
+ sourceFile.addImportDeclaration({
1520
+ moduleSpecifier: "@solidxai/core",
1521
+ namespaceImport: "SolidCoreModuleExports",
1522
+ });
1523
+ sourceFile.addImportDeclaration({
1524
+ moduleSpecifier: "@solidxai/core",
1525
+ namedImports: ["getDynamicModuleNames", "parseBooleanEnv"],
1526
+ });
1527
+ sourceFile.addImportDeclaration({
1528
+ moduleSpecifier: "typeorm",
1529
+ namedImports: ["getMetadataArgsStorage"],
1530
+ });
1531
+ sourceFile.addImportDeclaration({
1532
+ moduleSpecifier: "typeorm-naming-strategies",
1533
+ namedImports: ["SnakeNamingStrategy"],
1534
+ });
1535
+ sourceFile.addImportDeclaration({
1536
+ moduleSpecifier: entityImportPath,
1537
+ namedImports: [entityClassName],
1538
+ });
1539
+ sourceFile.addFunction({
1540
+ name: "getEntitiesFromExports",
1541
+ parameters: [{ name: "exports", type: "Record<string, any>" }],
1542
+ statements: (writer) => {
1543
+ writer.writeLine("const metadataStorage = getMetadataArgsStorage();");
1544
+ writer.writeLine("return Object.values(exports).filter((item) =>");
1545
+ writer.indent(() => {
1546
+ writer.writeLine("metadataStorage.tables.some((table) => table.target === item),");
1547
+ });
1548
+ writer.write(");");
1549
+ },
1550
+ });
1551
+ sourceFile.addVariableStatement({
1552
+ declarationKind: ts_morph_1.VariableDeclarationKind.Const,
1553
+ declarations: [
1554
+ {
1555
+ name: "coreEntities",
1556
+ initializer: "getEntitiesFromExports(SolidCoreModuleExports)",
1557
+ },
1558
+ ],
1559
+ });
1560
+ sourceFile.addVariableStatement({
1561
+ declarationKind: ts_morph_1.VariableDeclarationKind.Const,
1562
+ declarations: [
1563
+ {
1564
+ name: "dynamicModules",
1565
+ initializer: "getDynamicModuleNames()",
1566
+ },
1567
+ ],
1568
+ });
1569
+ sourceFile.addVariableStatement({
1570
+ declarationKind: ts_morph_1.VariableDeclarationKind.Const,
1571
+ declarations: [
1572
+ {
1573
+ name: "entities",
1574
+ initializer: `[\n ...coreEntities,\n ${entityClassName},\n]`,
1575
+ },
1576
+ ],
1577
+ });
1578
+ sourceFile.addVariableStatement({
1579
+ declarationKind: ts_morph_1.VariableDeclarationKind.Const,
1580
+ declarations: [
1581
+ {
1582
+ name: "logging",
1583
+ initializer: `parseBooleanEnv('${envPrefix}_DATABASE_LOGGING')`,
1584
+ },
1585
+ ],
1586
+ });
1587
+ sourceFile.addStatements("// IMPORTANT: synchronize must be false when using migrations");
1588
+ sourceFile.addVariableStatement({
1589
+ declarationKind: ts_morph_1.VariableDeclarationKind.Const,
1590
+ isExported: true,
1591
+ declarations: [
1592
+ {
1593
+ name: "DefaultDataSource",
1594
+ initializer: (writer) => {
1595
+ writer.write("new DataSource(");
1596
+ writer.inlineBlock(() => {
1597
+ writer.writeLine(`type: '${datasource.type}',`);
1598
+ writer.blankLine();
1599
+ writer.writeLine(`host: process.env.${envPrefix}_DATABASE_HOST,`);
1600
+ writer.writeLine(`port: +(process.env.${envPrefix}_DATABASE_PORT || ${portFallback}),`);
1601
+ writer.writeLine(`username: process.env.${envPrefix}_DATABASE_USER,`);
1602
+ writer.writeLine(`password: process.env.${envPrefix}_DATABASE_PASSWORD,`);
1603
+ writer.writeLine(`database: process.env.${envPrefix}_DATABASE_NAME,`);
1604
+ writer.blankLine();
1605
+ writer.writeLine("entities,");
1606
+ writer.writeLine("migrations: [");
1607
+ writer.indent(() => {
1608
+ writer.writeLine(`${migrationGlob},`);
1609
+ });
1610
+ writer.writeLine("],");
1611
+ writer.writeLine("synchronize: false,");
1612
+ writer.writeLine("logging,");
1613
+ writer.writeLine("namingStrategy: new SnakeNamingStrategy(),");
1614
+ if (datasource.type === "mssql") {
1615
+ writer.writeLine("options: {");
1616
+ writer.indent(() => {
1617
+ writer.writeLine("encrypt: false,");
1618
+ writer.writeLine("trustServerCertificate: true,");
1619
+ });
1620
+ writer.writeLine("},");
1621
+ }
1622
+ });
1623
+ writer.write(")");
1624
+ },
1625
+ },
1626
+ ],
1627
+ });
1628
+ sourceFile.organizeImports();
1629
+ sourceFile.formatText();
1630
+ return sourceFile.getFullText();
1631
+ }
1632
+ arrayLiteralContainsValue(arrayLiteral, rawValue) {
1633
+ const normalizedTarget = rawValue.replace(/\s+/g, "");
1634
+ return arrayLiteral.getElements().some((element) => element.getText().replace(/\s+/g, "") === normalizedTarget);
1635
+ }
1636
+ getTypeormDatasourceOptions(sourceFile) {
1637
+ const defaultDataSourceDeclaration = sourceFile.getVariableDeclarationOrThrow("DefaultDataSource");
1638
+ const initializer = defaultDataSourceDeclaration.getInitializer();
1639
+ if (!initializer || !ts_morph_1.Node.isNewExpression(initializer)) {
1640
+ throw new common_1.BadRequestException("Unable to locate DefaultDataSource initializer in datasource file.");
1641
+ }
1642
+ const options = initializer.getArguments()[0];
1643
+ if (!options || !ts_morph_1.Node.isObjectLiteralExpression(options)) {
1644
+ throw new common_1.BadRequestException("Unable to locate DefaultDataSource options object in datasource file.");
1645
+ }
1646
+ return options;
1647
+ }
1648
+ getObjectPropertyArrayLiteral(objectLiteral, propertyName) {
1649
+ const property = objectLiteral.getProperty(propertyName);
1650
+ if (!property || !ts_morph_1.Node.isPropertyAssignment(property)) {
1651
+ throw new common_1.BadRequestException(`Unable to locate "${propertyName}" property in datasource file.`);
1652
+ }
1653
+ const initializer = property.getInitializer();
1654
+ if (!initializer || !ts_morph_1.Node.isArrayLiteralExpression(initializer)) {
1655
+ throw new common_1.BadRequestException(`Unable to locate "${propertyName}" array in datasource file.`);
1656
+ }
1657
+ return initializer;
1658
+ }
1193
1659
  buildSynchronizeBlockedMessage(datasource) {
1194
1660
  return `Datasource "${datasource.displayName}" has synchronize enabled. Set ${datasource.envPrefix}_DATABASE_SYNCHRONIZE=false before starting legacy table introspection.`;
1195
1661
  }
@@ -1271,6 +1737,8 @@ exports.DatasourceIntrospectionService = DatasourceIntrospectionService = __deco
1271
1737
  model_metadata_helper_service_1.ModelMetadataHelperService,
1272
1738
  field_metadata_service_1.FieldMetadataService,
1273
1739
  model_metadata_service_1.ModelMetadataService,
1740
+ module_metadata_service_1.ModuleMetadataService,
1741
+ command_service_1.CommandService,
1274
1742
  mssql_datasource_introspection_provider_service_1.MssqlDatasourceIntrospectionProviderService,
1275
1743
  mysql_datasource_introspection_provider_service_1.MysqlDatasourceIntrospectionProviderService,
1276
1744
  postgres_datasource_introspection_provider_service_1.PostgresDatasourceIntrospectionProviderService])