@memberjunction/codegen-lib 3.3.0 → 4.0.0

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 (92) hide show
  1. package/README.md +56 -1
  2. package/dist/Angular/angular-codegen.d.ts +1 -1
  3. package/dist/Angular/angular-codegen.d.ts.map +1 -1
  4. package/dist/Angular/angular-codegen.js +80 -136
  5. package/dist/Angular/angular-codegen.js.map +1 -1
  6. package/dist/Angular/entity-data-grid-related-entity-component.d.ts +1 -1
  7. package/dist/Angular/entity-data-grid-related-entity-component.js +6 -9
  8. package/dist/Angular/entity-data-grid-related-entity-component.js.map +1 -1
  9. package/dist/Angular/join-grid-related-entity-component.d.ts +1 -1
  10. package/dist/Angular/join-grid-related-entity-component.js +8 -36
  11. package/dist/Angular/join-grid-related-entity-component.js.map +1 -1
  12. package/dist/Angular/related-entity-components.js +13 -79
  13. package/dist/Angular/related-entity-components.js.map +1 -1
  14. package/dist/Angular/timeline-related-entity-component.d.ts +1 -1
  15. package/dist/Angular/timeline-related-entity-component.js +14 -38
  16. package/dist/Angular/timeline-related-entity-component.js.map +1 -1
  17. package/dist/Angular/user-view-grid-related-entity-component.d.ts +43 -0
  18. package/dist/Angular/user-view-grid-related-entity-component.d.ts.map +1 -0
  19. package/dist/Angular/user-view-grid-related-entity-component.js +85 -0
  20. package/dist/Angular/user-view-grid-related-entity-component.js.map +1 -0
  21. package/dist/Config/config.d.ts +79 -0
  22. package/dist/Config/config.d.ts.map +1 -1
  23. package/dist/Config/config.js +174 -172
  24. package/dist/Config/config.js.map +1 -1
  25. package/dist/Config/db-connection.d.ts +1 -1
  26. package/dist/Config/db-connection.d.ts.map +1 -1
  27. package/dist/Config/db-connection.js +6 -33
  28. package/dist/Config/db-connection.js.map +1 -1
  29. package/dist/Database/dbSchema.js +28 -35
  30. package/dist/Database/dbSchema.js.map +1 -1
  31. package/dist/Database/manage-metadata.d.ts +25 -9
  32. package/dist/Database/manage-metadata.d.ts.map +1 -1
  33. package/dist/Database/manage-metadata.js +438 -316
  34. package/dist/Database/manage-metadata.js.map +1 -1
  35. package/dist/Database/reorder-columns.d.ts +1 -1
  36. package/dist/Database/reorder-columns.d.ts.map +1 -1
  37. package/dist/Database/reorder-columns.js +1 -5
  38. package/dist/Database/reorder-columns.js.map +1 -1
  39. package/dist/Database/sql.d.ts +1 -1
  40. package/dist/Database/sql.d.ts.map +1 -1
  41. package/dist/Database/sql.js +67 -98
  42. package/dist/Database/sql.js.map +1 -1
  43. package/dist/Database/sql_codegen.d.ts +5 -2
  44. package/dist/Database/sql_codegen.d.ts.map +1 -1
  45. package/dist/Database/sql_codegen.js +344 -268
  46. package/dist/Database/sql_codegen.js.map +1 -1
  47. package/dist/Manifest/GenerateClassRegistrationsManifest.d.ts +110 -0
  48. package/dist/Manifest/GenerateClassRegistrationsManifest.d.ts.map +1 -0
  49. package/dist/Manifest/GenerateClassRegistrationsManifest.js +632 -0
  50. package/dist/Manifest/GenerateClassRegistrationsManifest.js.map +1 -0
  51. package/dist/Misc/action_subclasses_codegen.d.ts.map +1 -1
  52. package/dist/Misc/action_subclasses_codegen.js +15 -26
  53. package/dist/Misc/action_subclasses_codegen.js.map +1 -1
  54. package/dist/Misc/advanced_generation.d.ts +1 -1
  55. package/dist/Misc/advanced_generation.js +34 -40
  56. package/dist/Misc/advanced_generation.js.map +1 -1
  57. package/dist/Misc/createNewUser.d.ts +1 -1
  58. package/dist/Misc/createNewUser.js +22 -26
  59. package/dist/Misc/createNewUser.js.map +1 -1
  60. package/dist/Misc/entity_subclasses_codegen.d.ts +2 -2
  61. package/dist/Misc/entity_subclasses_codegen.d.ts.map +1 -1
  62. package/dist/Misc/entity_subclasses_codegen.js +33 -40
  63. package/dist/Misc/entity_subclasses_codegen.js.map +1 -1
  64. package/dist/Misc/graphql_server_codegen.js +36 -41
  65. package/dist/Misc/graphql_server_codegen.js.map +1 -1
  66. package/dist/Misc/runCommand.d.ts +1 -1
  67. package/dist/Misc/runCommand.js +13 -20
  68. package/dist/Misc/runCommand.js.map +1 -1
  69. package/dist/Misc/sql_logging.d.ts +7 -1
  70. package/dist/Misc/sql_logging.d.ts.map +1 -1
  71. package/dist/Misc/sql_logging.js +40 -53
  72. package/dist/Misc/sql_logging.js.map +1 -1
  73. package/dist/Misc/status_logging.js +45 -60
  74. package/dist/Misc/status_logging.js.map +1 -1
  75. package/dist/Misc/system_integrity.d.ts +1 -1
  76. package/dist/Misc/system_integrity.d.ts.map +1 -1
  77. package/dist/Misc/system_integrity.js +12 -16
  78. package/dist/Misc/system_integrity.js.map +1 -1
  79. package/dist/Misc/temp_batch_file.js +15 -22
  80. package/dist/Misc/temp_batch_file.js.map +1 -1
  81. package/dist/Misc/util.d.ts.map +1 -1
  82. package/dist/Misc/util.js +17 -28
  83. package/dist/Misc/util.js.map +1 -1
  84. package/dist/index.d.ts +21 -20
  85. package/dist/index.d.ts.map +1 -1
  86. package/dist/index.js +22 -40
  87. package/dist/index.js.map +1 -1
  88. package/dist/runCodeGen.d.ts +1 -0
  89. package/dist/runCodeGen.d.ts.map +1 -1
  90. package/dist/runCodeGen.js +151 -178
  91. package/dist/runCodeGen.js.map +1 -1
  92. package/package.json +24 -21
@@ -1,165 +1,170 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
25
- var __importDefault = (this && this.__importDefault) || function (mod) {
26
- return (mod && mod.__esModule) ? mod : { "default": mod };
27
- };
28
- Object.defineProperty(exports, "__esModule", { value: true });
29
- exports.ManageMetadataBase = exports.ValidatorResult = void 0;
30
- const sql = __importStar(require("mssql"));
31
- const config_1 = require("../Config/config");
32
- const core_1 = require("@memberjunction/core");
33
- const status_logging_1 = require("../Misc/status_logging");
34
- const sql_1 = require("./sql");
35
- const advanced_generation_1 = require("../Misc/advanced_generation");
36
- const global_1 = require("@memberjunction/global");
37
- const uuid_1 = require("uuid");
38
- const fs = __importStar(require("fs"));
39
- const path_1 = __importDefault(require("path"));
40
- const sql_logging_1 = require("../Misc/sql_logging");
41
- class ValidatorResult {
42
- entityName = "";
43
- fieldName;
44
- sourceCheckConstraint = "";
45
- functionText = "";
46
- functionName = "";
47
- functionDescription = "";
48
- /**
49
- * The ID value in the Generated Codes entity that was created for this validator.
50
- */
51
- generatedCodeId = "";
52
- /**
53
- * The ID for the AI Model that was used to generate the code
54
- */
55
- aiModelID = "";
56
- wasGenerated = true;
57
- success = false;
1
+ import sql from 'mssql';
2
+ import { configInfo, currentWorkingDirectory, getSettingValue, mj_core_schema, outputDir } from '../Config/config.js';
3
+ import { CodeNameFromString, EntityInfo, ExtractActualDefaultValue, LogError, LogStatus, Metadata, SeverityType } from "@memberjunction/core";
4
+ import { logError, logMessage, logStatus } from "../Misc/status_logging.js";
5
+ import { SQLUtilityBase } from "./sql.js";
6
+ import { AdvancedGeneration } from "../Misc/advanced_generation.js";
7
+ import { convertCamelCaseToHaveSpaces, generatePluralName, MJGlobal, stripTrailingChars } from "@memberjunction/global";
8
+ import { v4 as uuidv4 } from 'uuid';
9
+ import * as fs from 'fs';
10
+ import path from 'path';
11
+ import { SQLLogging } from "../Misc/sql_logging.js";
12
+ export class ValidatorResult {
13
+ constructor() {
14
+ this.entityName = "";
15
+ this.sourceCheckConstraint = "";
16
+ this.functionText = "";
17
+ this.functionName = "";
18
+ this.functionDescription = "";
19
+ /**
20
+ * The ID value in the Generated Codes entity that was created for this validator.
21
+ */
22
+ this.generatedCodeId = "";
23
+ /**
24
+ * The ID for the AI Model that was used to generate the code
25
+ */
26
+ this.aiModelID = "";
27
+ this.wasGenerated = true;
28
+ this.success = false;
29
+ }
58
30
  }
59
- exports.ValidatorResult = ValidatorResult;
60
31
  /**
61
32
  * Base class for managing metadata within the CodeGen system. This class can be sub-classed to extend/override base class functionality. Make sure to use the RegisterClass decorator from the @memberjunction/global package
62
33
  * to properly register your subclass with a priority of 1+ to ensure it gets instantiated.
63
34
  */
64
- class ManageMetadataBase {
65
- _sqlUtilityObject = global_1.MJGlobal.Instance.ClassFactory.CreateInstance(sql_1.SQLUtilityBase);
35
+ export class ManageMetadataBase {
36
+ constructor() {
37
+ this._sqlUtilityObject = MJGlobal.Instance.ClassFactory.CreateInstance(SQLUtilityBase);
38
+ }
66
39
  get SQLUtilityObject() {
67
40
  return this._sqlUtilityObject;
68
41
  }
69
- static _newEntityList = [];
42
+ static { this._newEntityList = []; }
70
43
  /**
71
44
  * Globally scoped list of entities that have been created during the metadata management process.
72
45
  */
73
46
  static get newEntityList() {
74
47
  return this._newEntityList;
75
48
  }
76
- static _modifiedEntityList = [];
49
+ static { this._modifiedEntityList = []; }
77
50
  /**
78
51
  * Globally scoped list of entities that have been modified during the metadata management process.
79
52
  */
80
53
  static get modifiedEntityList() {
81
54
  return this._modifiedEntityList;
82
55
  }
83
- static _generatedValidators = [];
56
+ static { this._generatedValidators = []; }
84
57
  /**
85
58
  * Globally scoped list of validators that have been generated during the metadata management process.
86
59
  */
87
60
  static get generatedValidators() {
88
61
  return this._generatedValidators;
89
62
  }
63
+ static { this._softPKFKConfigCache = null; }
64
+ static { this._softPKFKConfigPath = ''; }
65
+ /**
66
+ * Loads and caches the soft PK/FK configuration from the additionalSchemaInfo file.
67
+ * The file is only loaded once per session to avoid repeated I/O.
68
+ */
69
+ static getSoftPKFKConfig() {
70
+ // Return cached config if path hasn't changed
71
+ const configPath = configInfo.additionalSchemaInfo
72
+ ? path.join(currentWorkingDirectory, configInfo.additionalSchemaInfo)
73
+ : '';
74
+ if (this._softPKFKConfigCache !== null && this._softPKFKConfigPath === configPath) {
75
+ return this._softPKFKConfigCache;
76
+ }
77
+ // Cache miss or path changed - reload from disk
78
+ if (!configPath || !fs.existsSync(configPath)) {
79
+ this._softPKFKConfigCache = null;
80
+ this._softPKFKConfigPath = configPath;
81
+ return null;
82
+ }
83
+ try {
84
+ const configContent = fs.readFileSync(configPath, 'utf-8');
85
+ this._softPKFKConfigCache = JSON.parse(configContent);
86
+ this._softPKFKConfigPath = configPath;
87
+ return this._softPKFKConfigCache;
88
+ }
89
+ catch (e) {
90
+ this._softPKFKConfigCache = null;
91
+ this._softPKFKConfigPath = configPath;
92
+ return null;
93
+ }
94
+ }
90
95
  /**
91
96
  * Primary function to manage metadata within the CodeGen system. This function will call a series of sub-functions to manage the metadata.
92
97
  * @param pool - the ConnectionPool object to use for querying and updating the database
93
98
  * @returns
94
99
  */
95
100
  async manageMetadata(pool, currentUser) {
96
- const md = new core_1.Metadata();
97
- const excludeSchemas = config_1.configInfo.excludeSchemas ? config_1.configInfo.excludeSchemas : [];
101
+ const md = new Metadata();
102
+ const excludeSchemas = configInfo.excludeSchemas ? configInfo.excludeSchemas : [];
98
103
  let bSuccess = true;
99
104
  let start = new Date();
100
- (0, status_logging_1.logStatus)(' Creating new entities...');
105
+ logStatus(' Creating new entities...');
101
106
  if (!await this.createNewEntities(pool, currentUser)) {
102
- (0, status_logging_1.logError)(' Error creating new entities');
107
+ logError(' Error creating new entities');
103
108
  bSuccess = false;
104
109
  }
105
- (0, status_logging_1.logStatus)(` > Created new entities in ${(new Date().getTime() - start.getTime()) / 1000} seconds`);
110
+ logStatus(` > Created new entities in ${(new Date().getTime() - start.getTime()) / 1000} seconds`);
106
111
  start = new Date();
107
- (0, status_logging_1.logStatus)(' Updating existing entities...');
112
+ logStatus(' Updating existing entities...');
108
113
  if (!await this.updateExistingEntitiesFromSchema(pool, excludeSchemas)) {
109
- (0, status_logging_1.logError)(' Error updating existing entities');
114
+ logError(' Error updating existing entities');
110
115
  bSuccess = false;
111
116
  }
112
- (0, status_logging_1.logStatus)(` > Updated existing entities in ${(new Date().getTime() - start.getTime()) / 1000} seconds`);
117
+ logStatus(` > Updated existing entities in ${(new Date().getTime() - start.getTime()) / 1000} seconds`);
113
118
  start = new Date();
114
- (0, status_logging_1.logStatus)(' Scanning for tables that were deleted where entity metadata still exists...');
119
+ logStatus(' Scanning for tables that were deleted where entity metadata still exists...');
115
120
  if (!await this.checkAndRemoveMetadataForDeletedTables(pool, excludeSchemas)) {
116
- (0, status_logging_1.logError)(' Error removing metadata for tables that were removed');
121
+ logError(' Error removing metadata for tables that were removed');
117
122
  bSuccess = false;
118
123
  }
119
- (0, status_logging_1.logStatus)(` > Removed metadata for deleted tables in ${(new Date().getTime() - start.getTime()) / 1000} seconds`);
124
+ logStatus(` > Removed metadata for deleted tables in ${(new Date().getTime() - start.getTime()) / 1000} seconds`);
120
125
  start = new Date();
121
- (0, status_logging_1.logStatus)(' Recompiling base views...');
122
- const sqlUtility = global_1.MJGlobal.Instance.ClassFactory.CreateInstance(sql_1.SQLUtilityBase);
123
- const adminSchema = (0, config_1.getSettingValue)('mj_core_schema', '__mj');
124
- const schemasToExclude = (0, config_1.getSettingValue)('recompile_mj_views', true)
126
+ logStatus(' Recompiling base views...');
127
+ const sqlUtility = MJGlobal.Instance.ClassFactory.CreateInstance(SQLUtilityBase);
128
+ const adminSchema = getSettingValue('mj_core_schema', '__mj');
129
+ const schemasToExclude = getSettingValue('recompile_mj_views', true)
125
130
  ? excludeSchemas.filter((s) => s !== adminSchema)
126
131
  : excludeSchemas;
127
132
  if (!await sqlUtility.recompileAllBaseViews(pool, schemasToExclude, true, ManageMetadataBase._newEntityList /*exclude the newly created entities from the above step the first time we run as those views don't exist yet*/)) {
128
- (0, status_logging_1.logMessage)(' Warning: Non-Fatal error recompiling base views', core_1.SeverityType.Warning, false);
133
+ logMessage(' Warning: Non-Fatal error recompiling base views', SeverityType.Warning, false);
129
134
  // many times the former versions of base views will NOT succesfully recompile, so don't consider that scenario to be a
130
135
  // failure for this entire function
131
136
  }
132
- (0, status_logging_1.logStatus)(` > Recompiled base views in ${(new Date().getTime() - start.getTime()) / 1000} seconds`);
137
+ logStatus(` > Recompiled base views in ${(new Date().getTime() - start.getTime()) / 1000} seconds`);
133
138
  start = new Date();
134
- (0, status_logging_1.logStatus)(' Managing entity fields...');
139
+ logStatus(' Managing entity fields...');
135
140
  // note that we skip Advanced Generation here because we do it again later when the manageSQLScriptsAndExecution occurs in SQLCodeGen class
136
141
  if (!await this.manageEntityFields(pool, excludeSchemas, false, false, currentUser, true)) {
137
- (0, status_logging_1.logError)(' Error managing entity fields');
142
+ logError(' Error managing entity fields');
138
143
  bSuccess = false;
139
144
  }
140
- (0, status_logging_1.logStatus)(` > Managed entity fields in ${(new Date().getTime() - start.getTime()) / 1000} seconds`);
145
+ logStatus(` > Managed entity fields in ${(new Date().getTime() - start.getTime()) / 1000} seconds`);
141
146
  start = new Date();
142
- (0, status_logging_1.logStatus)(' Managing entity relationships...');
147
+ logStatus(' Managing entity relationships...');
143
148
  if (!await this.manageEntityRelationships(pool, excludeSchemas, md)) {
144
- (0, status_logging_1.logError)(' Error managing entity relationships');
149
+ logError(' Error managing entity relationships');
145
150
  bSuccess = false;
146
151
  }
147
- (0, status_logging_1.logStatus)(` > Managed entity relationships in ${(new Date().getTime() - start.getTime()) / 1000} seconds`);
152
+ logStatus(` > Managed entity relationships in ${(new Date().getTime() - start.getTime()) / 1000} seconds`);
148
153
  if (ManageMetadataBase.newEntityList.length > 0) {
149
154
  await this.generateNewEntityDescriptions(pool, md, currentUser); // don't pass excludeSchemas becuase by definition this is the NEW entities we created
150
155
  }
151
156
  const veResult = await this.manageVirtualEntities(pool);
152
157
  if (!veResult.success) {
153
- (0, status_logging_1.logError)(' Error managing virtual entities');
158
+ logError(' Error managing virtual entities');
154
159
  bSuccess = false;
155
160
  }
156
161
  start = new Date();
157
- (0, status_logging_1.logStatus)(' Syncing schema info from database...');
162
+ logStatus(' Syncing schema info from database...');
158
163
  if (!await this.updateSchemaInfoFromDatabase(pool, excludeSchemas)) {
159
- (0, status_logging_1.logError)(' Error syncing schema info');
164
+ logError(' Error syncing schema info');
160
165
  bSuccess = false;
161
166
  }
162
- (0, status_logging_1.logStatus)(` > Synced schema info in ${(new Date().getTime() - start.getTime()) / 1000} seconds`);
167
+ logStatus(` > Synced schema info in ${(new Date().getTime() - start.getTime()) / 1000} seconds`);
163
168
  return bSuccess;
164
169
  }
165
170
  async manageVirtualEntities(pool) {
@@ -167,7 +172,7 @@ class ManageMetadataBase {
167
172
  // virtual entities are records defined in the entity metadata and do NOT define a distinct base table
168
173
  // but they do specify a base view. We DO NOT generate a base view for a virtual entity, we simply use it to figure
169
174
  // out the fields that should be in the entity definition and add/update/delete the entity definition to match what's in the view when this runs
170
- const sql = `SELECT * FROM [${(0, config_1.mj_core_schema)()}].vwEntities WHERE VirtualEntity = 1`;
175
+ const sql = `SELECT * FROM [${mj_core_schema()}].vwEntities WHERE VirtualEntity = 1`;
171
176
  const virtualEntitiesResult = await pool.request().query(sql);
172
177
  const virtualEntities = virtualEntitiesResult.recordset;
173
178
  let anyUpdates = false;
@@ -177,7 +182,7 @@ class ManageMetadataBase {
177
182
  const { success, updatedEntity } = await this.manageSingleVirtualEntity(pool, ve);
178
183
  anyUpdates = anyUpdates || updatedEntity;
179
184
  if (!success) {
180
- (0, status_logging_1.logError)(` Error managing virtual entity ${ve.Name}`);
185
+ logError(` Error managing virtual entity ${ve.Name}`);
181
186
  bSuccess = false;
182
187
  }
183
188
  }
@@ -208,7 +213,7 @@ class ManageMetadataBase {
208
213
  if (veFields && veFields.length > 0) {
209
214
  // we have 1+ fields, now loop through them and process each one
210
215
  // first though, remove any fields that are no longer in the view
211
- const md = new core_1.Metadata();
216
+ const md = new Metadata();
212
217
  const entity = md.EntityByName(virtualEntity.Name);
213
218
  if (entity) {
214
219
  const removeList = [];
@@ -217,7 +222,7 @@ class ManageMetadataBase {
217
222
  removeList.push(f.ID);
218
223
  }
219
224
  if (removeList.length > 0) {
220
- const sqlRemove = `DELETE FROM [${(0, config_1.mj_core_schema)()}].EntityField WHERE ID IN (${removeList.map(removeId => `'${removeId}'`).join(',')})`;
225
+ const sqlRemove = `DELETE FROM [${mj_core_schema()}].EntityField WHERE ID IN (${removeList.map(removeId => `'${removeId}'`).join(',')})`;
221
226
  // this removes the fields that shouldn't be there anymore
222
227
  await this.LogSQLAndExecute(pool, sqlRemove, `SQL text to remove fields from entity ${virtualEntity.Name}`);
223
228
  bUpdated = true;
@@ -231,7 +236,7 @@ class ManageMetadataBase {
231
236
  const { success, updatedField } = await this.manageSingleVirtualEntityField(pool, virtualEntity, vef, i + 1, !hasPkey && i === 0);
232
237
  bUpdated = bUpdated || updatedField;
233
238
  if (!success) {
234
- (0, status_logging_1.logError)(`Error managing virtual entity field ${vef.FieldName} for virtual entity ${virtualEntity.Name}`);
239
+ logError(`Error managing virtual entity field ${vef.FieldName} for virtual entity ${virtualEntity.Name}`);
235
240
  bSuccess = false;
236
241
  }
237
242
  }
@@ -239,13 +244,13 @@ class ManageMetadataBase {
239
244
  }
240
245
  if (bUpdated) {
241
246
  // finally make sure we update the UpdatedAt field for the entity if we made changes to its fields
242
- const sqlUpdate = `UPDATE [${(0, config_1.mj_core_schema)()}].Entity SET [${core_1.EntityInfo.UpdatedAtFieldName}]=GETUTCDATE() WHERE ID='${virtualEntity.ID}'`;
247
+ const sqlUpdate = `UPDATE [${mj_core_schema()}].Entity SET [${EntityInfo.UpdatedAtFieldName}]=GETUTCDATE() WHERE ID='${virtualEntity.ID}'`;
243
248
  await this.LogSQLAndExecute(pool, sqlUpdate, `SQL text to update virtual entity updated date for ${virtualEntity.Name}`);
244
249
  }
245
250
  return { success: bSuccess, updatedEntity: bUpdated };
246
251
  }
247
252
  catch (e) {
248
- (0, status_logging_1.logError)(e);
253
+ logError(e);
249
254
  return { success: false, updatedEntity: bUpdated };
250
255
  }
251
256
  }
@@ -253,7 +258,7 @@ class ManageMetadataBase {
253
258
  // this protected checks to see if the field exists in the entity definition, and if not, adds it
254
259
  // if it exist it updates the entity field to match the view's data type and nullability attributes
255
260
  // first, get the entity definition
256
- const md = new core_1.Metadata();
261
+ const md = new Metadata();
257
262
  const entity = md.EntityByName(virtualEntity.Name);
258
263
  let newEntityFieldUUID = null;
259
264
  let didUpdate = false;
@@ -270,7 +275,7 @@ class ManageMetadataBase {
270
275
  field.Sequence !== fieldSequence) {
271
276
  // the field needs to be updated, so update it
272
277
  const sqlUpdate = `UPDATE
273
- [${(0, config_1.mj_core_schema)()}].EntityField
278
+ [${mj_core_schema()}].EntityField
274
279
  SET
275
280
  Sequence=${fieldSequence},
276
281
  Type='${veField.Type}',
@@ -288,7 +293,7 @@ class ManageMetadataBase {
288
293
  else {
289
294
  // this means that we do NOT have a match so the field does not exist in the entity definition, so we need to add it
290
295
  newEntityFieldUUID = this.createNewUUID();
291
- const sqlAdd = `INSERT INTO [${(0, config_1.mj_core_schema)()}].EntityField (
296
+ const sqlAdd = `INSERT INTO [${mj_core_schema()}].EntityField (
292
297
  ID, EntityID, Name, Type, AllowsNull,
293
298
  Length, Precision, Scale,
294
299
  Sequence, IsPrimaryKey, IsUnique )
@@ -338,16 +343,16 @@ class ManageMetadataBase {
338
343
  try {
339
344
  // STEP 1 - search for all foreign keys in the vwEntityFields view, we use the RelatedEntityID field to determine our FKs
340
345
  const sSQL = `SELECT *
341
- FROM ${(0, config_1.mj_core_schema)()}.vwEntityFields
346
+ FROM ${mj_core_schema()}.vwEntityFields
342
347
  WHERE
343
348
  RelatedEntityID IS NOT NULL AND
344
349
  IsVirtual = 0 AND
345
- EntityID NOT IN (SELECT ID FROM ${(0, config_1.mj_core_schema)()}.Entity WHERE SchemaName IN (${excludeSchemas.map(s => `'${s}'`).join(',')}))
350
+ EntityID NOT IN (SELECT ID FROM ${mj_core_schema()}.Entity WHERE SchemaName IN (${excludeSchemas.map(s => `'${s}'`).join(',')}))
346
351
  ORDER BY RelatedEntityID`;
347
352
  const entityFieldsResult = await pool.request().query(sSQL);
348
353
  const entityFields = entityFieldsResult.recordset;
349
354
  // Get the relationship counts for each entity
350
- const sSQLRelationshipCount = `SELECT EntityID, COUNT(*) AS Count FROM ${(0, config_1.mj_core_schema)()}.EntityRelationship GROUP BY EntityID`;
355
+ const sSQLRelationshipCount = `SELECT EntityID, COUNT(*) AS Count FROM ${mj_core_schema()}.EntityRelationship GROUP BY EntityID`;
351
356
  const relationshipCountsResult = await pool.request().query(sSQLRelationshipCount);
352
357
  const relationshipCounts = relationshipCountsResult.recordset;
353
358
  const relationshipCountMap = new Map();
@@ -355,7 +360,7 @@ class ManageMetadataBase {
355
360
  relationshipCountMap.set(rc.EntityID, rc.Count);
356
361
  }
357
362
  // get all relationships in one query for performance improvement
358
- const sSQLRelationship = `SELECT * FROM ${(0, config_1.mj_core_schema)()}.EntityRelationship`;
363
+ const sSQLRelationship = `SELECT * FROM ${mj_core_schema()}.EntityRelationship`;
359
364
  const allRelationshipsResult = await pool.request().query(sSQLRelationship);
360
365
  const allRelationships = allRelationshipsResult.recordset;
361
366
  // Function to process a batch of entity fields
@@ -374,11 +379,11 @@ class ManageMetadataBase {
374
379
  batchSQL += `
375
380
  IF NOT EXISTS (
376
381
  SELECT 1
377
- FROM [${(0, config_1.mj_core_schema)()}].EntityRelationship
382
+ FROM [${mj_core_schema()}].EntityRelationship
378
383
  WHERE ID = '${newEntityRelationshipUUID}'
379
384
  )
380
385
  BEGIN
381
- INSERT INTO ${(0, config_1.mj_core_schema)()}.EntityRelationship (ID, EntityID, RelatedEntityID, RelatedEntityJoinField, Type, BundleInAPI, DisplayInForm, DisplayName, Sequence)
386
+ INSERT INTO ${mj_core_schema()}.EntityRelationship (ID, EntityID, RelatedEntityID, RelatedEntityJoinField, Type, BundleInAPI, DisplayInForm, DisplayName, Sequence)
382
387
  VALUES ('${newEntityRelationshipUUID}', '${f.RelatedEntityID}', '${f.EntityID}', '${f.Name}', 'One To Many', 1, 1, '${e.Name}', ${sequence});
383
388
  END
384
389
  `;
@@ -398,7 +403,7 @@ class ManageMetadataBase {
398
403
  return true;
399
404
  }
400
405
  catch (e) {
401
- (0, status_logging_1.logError)(e);
406
+ logError(e);
402
407
  return false;
403
408
  }
404
409
  }
@@ -410,7 +415,7 @@ class ManageMetadataBase {
410
415
  */
411
416
  async checkAndRemoveMetadataForDeletedTables(pool, excludeSchemas) {
412
417
  try {
413
- const sql = `SELECT * FROM ${(0, config_1.mj_core_schema)()}.vwEntitiesWithMissingBaseTables WHERE VirtualEntity=0`;
418
+ const sql = `SELECT * FROM ${mj_core_schema()}.vwEntitiesWithMissingBaseTables WHERE VirtualEntity=0`;
414
419
  const entitiesResult = await pool.request().query(sql);
415
420
  const entities = entitiesResult.recordset;
416
421
  if (entities && entities.length > 0) {
@@ -421,7 +426,7 @@ class ManageMetadataBase {
421
426
  try {
422
427
  const sqlDelete = `__mj.spDeleteEntityWithCoreDependencies @EntityID='${e.ID}'`;
423
428
  await this.LogSQLAndExecute(pool, sqlDelete, `SQL text to remove entity ${e.Name}`);
424
- (0, status_logging_1.logStatus)(` > Removed metadata for table ${e.SchemaName}.${e.BaseTable}`);
429
+ logStatus(` > Removed metadata for table ${e.SchemaName}.${e.BaseTable}`);
425
430
  // next up we need to remove the spCreate, spDelete, spUpdate, BaseView, and FullTextSearchFunction, if provided.
426
431
  // We only remoe these artifcacts when they are generated which is info we have in the BaseViewGenerated, spCreateGenerated, etc. fields
427
432
  await this.checkDropSQLObject(pool, e.BaseViewGenerated, 'view', e.SchemaName, e.BaseView);
@@ -431,17 +436,17 @@ class ManageMetadataBase {
431
436
  await this.checkDropSQLObject(pool, e.FullTextSearchFunctionGenerated, 'function', e.SchemaName, e.FullTextSearchFunction);
432
437
  }
433
438
  catch (ex) {
434
- (0, status_logging_1.logError)(`Error removing metadata for entity ${ex.Name}, error: ${ex}`);
439
+ logError(`Error removing metadata for entity ${ex.Name}, error: ${ex}`);
435
440
  }
436
441
  }
437
442
  // if we get here we now need to refresh our metadata object
438
- const md = new core_1.Metadata();
443
+ const md = new Metadata();
439
444
  await md.Refresh();
440
445
  }
441
446
  return true;
442
447
  }
443
448
  catch (e) {
444
- (0, status_logging_1.logError)(e);
449
+ logError(e);
445
450
  return false;
446
451
  }
447
452
  }
@@ -455,23 +460,23 @@ class ManageMetadataBase {
455
460
  const sqlDelete = `IF OBJECT_ID('[${schemaName}].[${name}]', '${objectTypeCode}') IS NOT NULL\n DROP ${upperType} [${schemaName}].[${name}]`;
456
461
  await this.LogSQLAndExecute(pool, sqlDelete, `SQL text to remove ${type} ${schemaName}.${name}`);
457
462
  // next up, we need to clean up the cache of saved DB objects that may exist for this entity in the appropriate sub-directory.
458
- const sqlOutputDir = (0, config_1.outputDir)('SQL', true);
463
+ const sqlOutputDir = outputDir('SQL', true);
459
464
  if (sqlOutputDir) {
460
465
  // now do the same thing for the /schema directory within the provided directory
461
466
  const fType = type === 'procedure' ? 'sp' : type === 'view' ? 'view' : 'full_text_search_function';
462
- const filePath = path_1.default.join(sqlOutputDir, this.SQLUtilityObject.getDBObjectFileName(fType, schemaName, name, false, true));
463
- const filePathPermissions = path_1.default.join(sqlOutputDir, this.SQLUtilityObject.getDBObjectFileName(fType, schemaName, name, true, true));
467
+ const filePath = path.join(sqlOutputDir, this.SQLUtilityObject.getDBObjectFileName(fType, schemaName, name, false, true));
468
+ const filePathPermissions = path.join(sqlOutputDir, this.SQLUtilityObject.getDBObjectFileName(fType, schemaName, name, true, true));
464
469
  // if the files exist, delete them
465
470
  if (fs.existsSync(filePath))
466
471
  fs.unlinkSync(filePath);
467
472
  if (fs.existsSync(filePathPermissions))
468
473
  fs.unlinkSync(filePathPermissions);
469
474
  }
470
- (0, status_logging_1.logStatus)(` > Removed ${type} ${schemaName}.${name}`);
475
+ logStatus(` > Removed ${type} ${schemaName}.${name}`);
471
476
  }
472
477
  }
473
478
  catch (e) {
474
- (0, status_logging_1.logError)(` > Error removing ${type} ${schemaName}.${name}, error: ${e}`);
479
+ logError(` > Error removing ${type} ${schemaName}.${name}, error: ${e}`);
475
480
  }
476
481
  }
477
482
  /**
@@ -497,66 +502,72 @@ class ManageMetadataBase {
497
502
  if (!skipCreatedAtUpdatedAtDeletedAtFieldValidation) {
498
503
  if (!await this.ensureCreatedAtUpdatedAtFieldsExist(pool, excludeSchemas) ||
499
504
  !await this.ensureDeletedAtFieldsExist(pool, excludeSchemas)) {
500
- (0, status_logging_1.logError)(`Error ensuring ${core_1.EntityInfo.CreatedAtFieldName}, ${core_1.EntityInfo.UpdatedAtFieldName} and ${core_1.EntityInfo.DeletedAtFieldName} fields exist`);
505
+ logError(`Error ensuring ${EntityInfo.CreatedAtFieldName}, ${EntityInfo.UpdatedAtFieldName} and ${EntityInfo.DeletedAtFieldName} fields exist`);
501
506
  bSuccess = false;
502
507
  }
503
- (0, status_logging_1.logStatus)(` Ensured ${core_1.EntityInfo.CreatedAtFieldName}/${core_1.EntityInfo.UpdatedAtFieldName}/${core_1.EntityInfo.DeletedAtFieldName} fields exist in ${(new Date().getTime() - startTime.getTime()) / 1000} seconds`);
508
+ logStatus(` Ensured ${EntityInfo.CreatedAtFieldName}/${EntityInfo.UpdatedAtFieldName}/${EntityInfo.DeletedAtFieldName} fields exist in ${(new Date().getTime() - startTime.getTime()) / 1000} seconds`);
504
509
  }
505
510
  const step1StartTime = new Date();
506
511
  if (!await this.deleteUnneededEntityFields(pool, excludeSchemas)) {
507
- (0, status_logging_1.logError)('Error deleting unneeded entity fields');
512
+ logError('Error deleting unneeded entity fields');
508
513
  bSuccess = false;
509
514
  }
510
- (0, status_logging_1.logStatus)(` Deleted unneeded entity fields in ${(new Date().getTime() - step1StartTime.getTime()) / 1000} seconds`);
515
+ logStatus(` Deleted unneeded entity fields in ${(new Date().getTime() - step1StartTime.getTime()) / 1000} seconds`);
511
516
  // AN: 14-June-2025 - See note below about the new order of these steps, this must
512
517
  // happen before we update existing entity fields from schema.
513
518
  const step2StartTime = new Date();
514
519
  if (!await this.createNewEntityFieldsFromSchema(pool)) { // has its own internal filtering for exclude schema/table so don't pass in
515
- (0, status_logging_1.logError)('Error creating new entity fields from schema');
520
+ logError('Error creating new entity fields from schema');
516
521
  bSuccess = false;
517
522
  }
518
- (0, status_logging_1.logStatus)(` Created new entity fields from schema in ${(new Date().getTime() - step2StartTime.getTime()) / 1000} seconds`);
523
+ logStatus(` Created new entity fields from schema in ${(new Date().getTime() - step2StartTime.getTime()) / 1000} seconds`);
519
524
  // AN: 14-June-2025 - we are now running this AFTER we create new entity fields from schema
520
525
  // which results in the same pattern of behavior as migrations where we first create new fields
521
526
  // with VERY HIGH sequence numbers (e.g. 100,000 above what they will be approx) and then
522
527
  // we align them properly in sequential order from 1+ via this method below.
523
528
  const step3StartTime = new Date();
524
529
  if (!await this.updateExistingEntityFieldsFromSchema(pool, excludeSchemas)) {
525
- (0, status_logging_1.logError)('Error updating existing entity fields from schema');
530
+ logError('Error updating existing entity fields from schema');
526
531
  bSuccess = false;
527
532
  }
528
- (0, status_logging_1.logStatus)(` Updated existing entity fields from schema in ${(new Date().getTime() - step3StartTime.getTime()) / 1000} seconds`);
533
+ logStatus(` Updated existing entity fields from schema in ${(new Date().getTime() - step3StartTime.getTime()) / 1000} seconds`);
534
+ // Apply soft PK/FK configuration if config file exists
535
+ const stepConfigStartTime = new Date();
536
+ if (!await this.applySoftPKFKConfig(pool)) {
537
+ logError('Error applying soft PK/FK configuration');
538
+ }
539
+ logStatus(` Applied soft PK/FK configuration in ${(new Date().getTime() - stepConfigStartTime.getTime()) / 1000} seconds`);
529
540
  const step4StartTime = new Date();
530
541
  if (!await this.setDefaultColumnWidthWhereNeeded(pool, excludeSchemas)) {
531
- (0, status_logging_1.logError)('Error setting default column width where needed');
542
+ logError('Error setting default column width where needed');
532
543
  bSuccess = false;
533
544
  }
534
- (0, status_logging_1.logStatus)(` Set default column width where needed in ${(new Date().getTime() - step4StartTime.getTime()) / 1000} seconds`);
545
+ logStatus(` Set default column width where needed in ${(new Date().getTime() - step4StartTime.getTime()) / 1000} seconds`);
535
546
  const step5StartTime = new Date();
536
547
  if (!await this.updateEntityFieldDisplayNameWhereNull(pool, excludeSchemas)) {
537
- (0, status_logging_1.logError)('Error updating entity field display name where null');
548
+ logError('Error updating entity field display name where null');
538
549
  bSuccess = false;
539
550
  }
540
- (0, status_logging_1.logStatus)(` Updated entity field display name where null in ${(new Date().getTime() - step5StartTime.getTime()) / 1000} seconds`);
551
+ logStatus(` Updated entity field display name where null in ${(new Date().getTime() - step5StartTime.getTime()) / 1000} seconds`);
541
552
  if (!skipEntityFieldValues) {
542
553
  const step6StartTime = new Date();
543
- (0, status_logging_1.logStatus)(` Starting to manage entity field values...`);
554
+ logStatus(` Starting to manage entity field values...`);
544
555
  if (!await this.manageEntityFieldValuesAndValidatorFunctions(pool, excludeSchemas, currentUser, false)) {
545
- (0, status_logging_1.logError)('Error managing entity field values');
556
+ logError('Error managing entity field values');
546
557
  bSuccess = false;
547
558
  }
548
- (0, status_logging_1.logStatus)(` Managed entity field values in ${(new Date().getTime() - step6StartTime.getTime()) / 1000} seconds`);
559
+ logStatus(` Managed entity field values in ${(new Date().getTime() - step6StartTime.getTime()) / 1000} seconds`);
549
560
  }
550
561
  // Advanced Generation - Smart field identification and form layout
551
562
  if (!skipAdvancedGeneration) {
552
563
  const step7StartTime = new Date();
553
564
  if (!await this.applyAdvancedGeneration(pool, excludeSchemas, currentUser)) {
554
- (0, status_logging_1.logError)('Error applying advanced generation features');
565
+ logError('Error applying advanced generation features');
555
566
  // Don't fail the entire process - advanced generation is optional
556
567
  }
557
- (0, status_logging_1.logStatus)(` Applied advanced generation features in ${(new Date().getTime() - step7StartTime.getTime()) / 1000} seconds`);
568
+ logStatus(` Applied advanced generation features in ${(new Date().getTime() - step7StartTime.getTime()) / 1000} seconds`);
558
569
  }
559
- (0, status_logging_1.logStatus)(` Total time to manage entity fields: ${(new Date().getTime() - startTime.getTime()) / 1000} seconds`);
570
+ logStatus(` Total time to manage entity fields: ${(new Date().getTime() - startTime.getTime()) / 1000} seconds`);
560
571
  return bSuccess;
561
572
  }
562
573
  /**
@@ -567,7 +578,7 @@ class ManageMetadataBase {
567
578
  const sqlEntities = `SELECT
568
579
  *
569
580
  FROM
570
- [${(0, config_1.mj_core_schema)()}].vwEntities
581
+ [${mj_core_schema()}].vwEntities
571
582
  WHERE
572
583
  VirtualEntity=0 AND
573
584
  DeleteType='Soft' AND
@@ -582,21 +593,102 @@ class ManageMetadataBase {
582
593
  FROM INFORMATION_SCHEMA.COLUMNS
583
594
  WHERE
584
595
  ${entities.map((e) => `(TABLE_SCHEMA='${e.SchemaName}' AND TABLE_NAME='${e.BaseTable}')`).join(' OR ')}
585
- AND COLUMN_NAME='${core_1.EntityInfo.DeletedAtFieldName}'`;
596
+ AND COLUMN_NAME='${EntityInfo.DeletedAtFieldName}'`;
586
597
  const resultResult = await pool.request().query(sql);
587
598
  const result = resultResult.recordset;
588
599
  for (const e of entities) {
589
600
  const eResult = result.filter((r) => r.TABLE_NAME === e.BaseTable && r.TABLE_SCHEMA === e.SchemaName); // get just the fields for this entity
590
- const deletedAt = eResult.find((r) => r.COLUMN_NAME.trim().toLowerCase() === core_1.EntityInfo.DeletedAtFieldName.trim().toLowerCase());
601
+ const deletedAt = eResult.find((r) => r.COLUMN_NAME.trim().toLowerCase() === EntityInfo.DeletedAtFieldName.trim().toLowerCase());
591
602
  // now, if we have the fields, we need to check the default value and update if necessary
592
- const fieldResult = await this.ensureSpecialDateFieldExistsAndHasCorrectDefaultValue(pool, e, core_1.EntityInfo.DeletedAtFieldName, deletedAt, true);
603
+ const fieldResult = await this.ensureSpecialDateFieldExistsAndHasCorrectDefaultValue(pool, e, EntityInfo.DeletedAtFieldName, deletedAt, true);
593
604
  overallResult = overallResult && fieldResult;
594
605
  }
595
606
  }
596
607
  return overallResult;
597
608
  }
598
609
  catch (e) {
599
- (0, status_logging_1.logError)(e);
610
+ logError(e);
611
+ return false;
612
+ }
613
+ }
614
+ /**
615
+ * Applies soft PK/FK configuration from a JSON file specified in mj.config.cjs (additionalSchemaInfo property).
616
+ * For soft PKs: Sets BOTH IsPrimaryKey=1 AND IsSoftPrimaryKey=1 (IsPrimaryKey is source of truth, IsSoftPrimaryKey protects from schema sync).
617
+ * For soft FKs: Sets RelatedEntityID/RelatedEntityFieldName + IsSoftForeignKey=1 (RelatedEntityID is source of truth, IsSoftForeignKey protects from schema sync).
618
+ * All UPDATE statements are logged to migration files via LogSQLAndExecute() for CI/CD traceability.
619
+ */
620
+ async applySoftPKFKConfig(pool) {
621
+ // Check if additionalSchemaInfo is configured in mj.config.cjs
622
+ if (!configInfo.additionalSchemaInfo) {
623
+ // No additional schema info configured - this is fine, it's optional
624
+ return true;
625
+ }
626
+ const configPath = path.join(currentWorkingDirectory, configInfo.additionalSchemaInfo);
627
+ if (!fs.existsSync(configPath)) {
628
+ logStatus(` ⚠️ additionalSchemaInfo configured but file not found: ${configPath}`);
629
+ return true;
630
+ }
631
+ try {
632
+ logStatus(` Found ${configInfo.additionalSchemaInfo}, applying soft PK/FK configuration...`);
633
+ const config = ManageMetadataBase.getSoftPKFKConfig();
634
+ let totalPKs = 0;
635
+ let totalFKs = 0;
636
+ const schema = mj_core_schema();
637
+ for (const table of config.tables || []) {
638
+ // Look up entity ID (SELECT query - no need to log to migration file)
639
+ const entityLookupSQL = `SELECT ID FROM [${schema}].[Entity] WHERE SchemaName = '${table.schemaName}' AND BaseTable = '${table.tableName}'`;
640
+ const entityResult = await pool.request().query(entityLookupSQL);
641
+ if (entityResult.recordset.length === 0) {
642
+ logStatus(` ⚠️ Entity not found for ${table.schemaName}.${table.tableName} - skipping`);
643
+ continue;
644
+ }
645
+ const entityId = entityResult.recordset[0].ID;
646
+ // Process primary keys - set BOTH IsPrimaryKey = 1 AND IsSoftPrimaryKey = 1
647
+ // IsPrimaryKey is the source of truth, IsSoftPrimaryKey protects it from schema sync
648
+ if (table.primaryKeys && table.primaryKeys.length > 0) {
649
+ for (const pk of table.primaryKeys) {
650
+ const sSQL = `UPDATE [${schema}].[EntityField]
651
+ SET ${EntityInfo.UpdatedAtFieldName}=GETUTCDATE(),
652
+ [IsPrimaryKey] = 1,
653
+ [IsSoftPrimaryKey] = 1
654
+ WHERE [EntityID] = '${entityId}' AND [Name] = '${pk.fieldName}'`;
655
+ const result = await this.LogSQLAndExecute(pool, sSQL, `Set soft PK for ${table.schemaName}.${table.tableName}.${pk.fieldName}`);
656
+ if (result !== null) {
657
+ logStatus(` ✓ Set IsPrimaryKey=1, IsSoftPrimaryKey=1 for ${table.tableName}.${pk.fieldName}`);
658
+ totalPKs++;
659
+ }
660
+ }
661
+ }
662
+ // Process foreign keys - set RelatedEntityID, RelatedEntityFieldName, and IsSoftForeignKey = 1
663
+ if (table.foreignKeys && table.foreignKeys.length > 0) {
664
+ for (const fk of table.foreignKeys) {
665
+ // Look up related entity ID (SELECT query - no need to log to migration file)
666
+ const relatedLookupSQL = `SELECT ID FROM [${schema}].[Entity] WHERE SchemaName = '${fk.relatedSchema}' AND BaseTable = '${fk.relatedTable}'`;
667
+ const relatedEntityResult = await pool.request().query(relatedLookupSQL);
668
+ if (relatedEntityResult.recordset.length === 0) {
669
+ logStatus(` ⚠️ Related entity not found for ${fk.relatedSchema}.${fk.relatedTable} - skipping FK ${fk.fieldName}`);
670
+ continue;
671
+ }
672
+ const relatedEntityId = relatedEntityResult.recordset[0].ID;
673
+ const sSQL = `UPDATE [${schema}].[EntityField]
674
+ SET ${EntityInfo.UpdatedAtFieldName}=GETUTCDATE(),
675
+ [RelatedEntityID] = '${relatedEntityId}',
676
+ [RelatedEntityFieldName] = '${fk.relatedField}',
677
+ [IsSoftForeignKey] = 1
678
+ WHERE [EntityID] = '${entityId}' AND [Name] = '${fk.fieldName}'`;
679
+ const result = await this.LogSQLAndExecute(pool, sSQL, `Set soft FK for ${table.schemaName}.${table.tableName}.${fk.fieldName} → ${fk.relatedTable}.${fk.relatedField}`);
680
+ if (result !== null) {
681
+ logStatus(` ✓ Set soft FK for ${table.tableName}.${fk.fieldName} → ${fk.relatedTable}.${fk.relatedField}`);
682
+ totalFKs++;
683
+ }
684
+ }
685
+ }
686
+ }
687
+ logStatus(` Applied ${totalPKs} soft PK(s) and ${totalFKs} soft FK(s) from configuration`);
688
+ return true;
689
+ }
690
+ catch (e) {
691
+ logError(`Error applying soft PK/FK configuration: ${e}`);
600
692
  return false;
601
693
  }
602
694
  }
@@ -611,7 +703,7 @@ class ManageMetadataBase {
611
703
  const sqlEntities = `SELECT
612
704
  *
613
705
  FROM
614
- [${(0, config_1.mj_core_schema)()}].vwEntities
706
+ [${mj_core_schema()}].vwEntities
615
707
  WHERE
616
708
  VirtualEntity = 0 AND
617
709
  TrackRecordChanges = 1 AND
@@ -627,24 +719,24 @@ class ManageMetadataBase {
627
719
  FROM INFORMATION_SCHEMA.COLUMNS
628
720
  WHERE
629
721
  ${entities.map((e) => `(TABLE_SCHEMA='${e.SchemaName}' AND TABLE_NAME='${e.BaseTable}')`).join(' OR ')}
630
- AND COLUMN_NAME IN ('${core_1.EntityInfo.CreatedAtFieldName}','${core_1.EntityInfo.UpdatedAtFieldName}')`;
722
+ AND COLUMN_NAME IN ('${EntityInfo.CreatedAtFieldName}','${EntityInfo.UpdatedAtFieldName}')`;
631
723
  const resultResult = await pool.request().query(sqlCreatedUpdated);
632
724
  const result = resultResult.recordset;
633
725
  for (const e of entities) {
634
726
  // result has both created at and updated at fields, so filter on the result for each and do what we need to based on that
635
727
  const eResult = result.filter((r) => r.TABLE_NAME === e.BaseTable && r.TABLE_SCHEMA === e.SchemaName); // get just the fields for this entity
636
- const createdAt = eResult.find((r) => r.COLUMN_NAME.trim().toLowerCase() === core_1.EntityInfo.CreatedAtFieldName.trim().toLowerCase());
637
- const updatedAt = eResult.find((r) => r.COLUMN_NAME.trim().toLowerCase() === core_1.EntityInfo.UpdatedAtFieldName.trim().toLowerCase());
728
+ const createdAt = eResult.find((r) => r.COLUMN_NAME.trim().toLowerCase() === EntityInfo.CreatedAtFieldName.trim().toLowerCase());
729
+ const updatedAt = eResult.find((r) => r.COLUMN_NAME.trim().toLowerCase() === EntityInfo.UpdatedAtFieldName.trim().toLowerCase());
638
730
  // now, if we have the fields, we need to check the default value and update if necessary
639
- const fieldResult = await this.ensureSpecialDateFieldExistsAndHasCorrectDefaultValue(pool, e, core_1.EntityInfo.CreatedAtFieldName, createdAt, false) &&
640
- await this.ensureSpecialDateFieldExistsAndHasCorrectDefaultValue(pool, e, core_1.EntityInfo.UpdatedAtFieldName, updatedAt, false);
731
+ const fieldResult = await this.ensureSpecialDateFieldExistsAndHasCorrectDefaultValue(pool, e, EntityInfo.CreatedAtFieldName, createdAt, false) &&
732
+ await this.ensureSpecialDateFieldExistsAndHasCorrectDefaultValue(pool, e, EntityInfo.UpdatedAtFieldName, updatedAt, false);
641
733
  overallResult = overallResult && fieldResult;
642
734
  }
643
735
  }
644
736
  return overallResult;
645
737
  }
646
738
  catch (e) {
647
- (0, status_logging_1.logError)(e);
739
+ logError(e);
648
740
  return false;
649
741
  }
650
742
  }
@@ -680,7 +772,7 @@ class ManageMetadataBase {
680
772
  // field that is NOT NULL
681
773
  if (!allowNull) {
682
774
  const defaultValue = currentFieldData.COLUMN_DEFAULT;
683
- const realDefaultValue = (0, core_1.ExtractActualDefaultValue)(defaultValue);
775
+ const realDefaultValue = ExtractActualDefaultValue(defaultValue);
684
776
  if (!realDefaultValue || realDefaultValue.trim().toLowerCase() !== 'getutcdate()') {
685
777
  await this.dropAndCreateDefaultConstraintForSpecialDateField(pool, entity, fieldName);
686
778
  }
@@ -691,7 +783,7 @@ class ManageMetadataBase {
691
783
  return true;
692
784
  }
693
785
  catch (e) {
694
- (0, status_logging_1.logError)(e);
786
+ logError(e);
695
787
  return false;
696
788
  }
697
789
  }
@@ -700,11 +792,11 @@ class ManageMetadataBase {
700
792
  */
701
793
  async createDefaultConstraintForSpecialDateField(pool, entity, fieldName) {
702
794
  try {
703
- const sqlAddDefaultConstraint = `ALTER TABLE [${entity.SchemaName}].[${entity.BaseTable}] ADD CONSTRAINT DF_${entity.SchemaName}_${(0, core_1.CodeNameFromString)(entity.BaseTable)}_${fieldName} DEFAULT GETUTCDATE() FOR [${fieldName}]`;
795
+ const sqlAddDefaultConstraint = `ALTER TABLE [${entity.SchemaName}].[${entity.BaseTable}] ADD CONSTRAINT DF_${entity.SchemaName}_${CodeNameFromString(entity.BaseTable)}_${fieldName} DEFAULT GETUTCDATE() FOR [${fieldName}]`;
704
796
  await this.LogSQLAndExecute(pool, sqlAddDefaultConstraint, `SQL text to add default constraint for special date field ${fieldName} in entity ${entity.SchemaName}.${entity.BaseTable}`);
705
797
  }
706
798
  catch (e) {
707
- (0, status_logging_1.logError)(e);
799
+ logError(e);
708
800
  }
709
801
  }
710
802
  /**
@@ -748,7 +840,7 @@ class ManageMetadataBase {
748
840
  await this.LogSQLAndExecute(pool, sqlDropDefaultConstraint, `SQL text to drop default existing default constraints in entity ${entity.SchemaName}.${entity.BaseTable}`);
749
841
  }
750
842
  catch (e) {
751
- (0, status_logging_1.logError)(e);
843
+ logError(e);
752
844
  }
753
845
  }
754
846
  /**
@@ -760,18 +852,18 @@ class ManageMetadataBase {
760
852
  */
761
853
  async generateNewEntityDescriptions(pool, md, currentUser) {
762
854
  // for the list of new entities, go through and attempt to generate new entity descriptions
763
- const ag = new advanced_generation_1.AdvancedGeneration();
855
+ const ag = new AdvancedGeneration();
764
856
  if (ag.featureEnabled('EntityDescriptions')) {
765
857
  // we have the feature enabled, so let's loop through the new entities and generate descriptions for them
766
858
  for (let e of ManageMetadataBase.newEntityList) {
767
- const dataResult = await pool.request().query(`SELECT * FROM [${(0, config_1.mj_core_schema)()}].vwEntities WHERE Name = '${e}'`);
859
+ const dataResult = await pool.request().query(`SELECT * FROM [${mj_core_schema()}].vwEntities WHERE Name = '${e}'`);
768
860
  const data = dataResult.recordset;
769
- const fieldsResult = await pool.request().query(`SELECT * FROM [${(0, config_1.mj_core_schema)()}].vwEntityFields WHERE EntityID='${data[0].ID}'`);
861
+ const fieldsResult = await pool.request().query(`SELECT * FROM [${mj_core_schema()}].vwEntityFields WHERE EntityID='${data[0].ID}'`);
770
862
  const fields = fieldsResult.recordset;
771
863
  // Use new API to generate entity description
772
864
  const result = await ag.generateEntityDescription(e, data[0].BaseTable, fields.map((f) => ({ Name: f.Name, Type: f.Type, IsNullable: f.AllowsNull, Description: f.Description })), currentUser);
773
865
  if (result?.entityDescription && result.entityDescription.length > 0) {
774
- const sSQL = `UPDATE [${(0, config_1.mj_core_schema)()}].Entity SET Description = '${result.entityDescription}' WHERE Name = '${e}'`;
866
+ const sSQL = `UPDATE [${mj_core_schema()}].Entity SET Description = '${result.entityDescription}' WHERE Name = '${e}'`;
775
867
  await this.LogSQLAndExecute(pool, sSQL, `SQL text to update entity description for entity ${e}`);
776
868
  }
777
869
  else {
@@ -793,9 +885,9 @@ class ManageMetadataBase {
793
885
  const sql = `SELECT
794
886
  ef.ID, ef.Name
795
887
  FROM
796
- [${(0, config_1.mj_core_schema)()}].vwEntityFields ef
888
+ [${mj_core_schema()}].vwEntityFields ef
797
889
  INNER JOIN
798
- [${(0, config_1.mj_core_schema)()}].vwEntities e
890
+ [${mj_core_schema()}].vwEntities e
799
891
  ON
800
892
  ef.EntityID = e.ID
801
893
  WHERE
@@ -808,16 +900,16 @@ class ManageMetadataBase {
808
900
  const fields = fieldsResult.recordset;
809
901
  if (fields && fields.length > 0)
810
902
  for (const field of fields) {
811
- const sDisplayName = (0, global_1.stripTrailingChars)((0, global_1.convertCamelCaseToHaveSpaces)(field.Name), 'ID', true).trim();
903
+ const sDisplayName = stripTrailingChars(convertCamelCaseToHaveSpaces(field.Name), 'ID', true).trim();
812
904
  if (sDisplayName.length > 0 && sDisplayName.toLowerCase().trim() !== field.Name.toLowerCase().trim()) {
813
- const sSQL = `UPDATE [${(0, config_1.mj_core_schema)()}].EntityField SET ${core_1.EntityInfo.UpdatedAtFieldName}=GETUTCDATE(), DisplayName = '${sDisplayName}' WHERE ID = '${field.ID}'`;
905
+ const sSQL = `UPDATE [${mj_core_schema()}].EntityField SET ${EntityInfo.UpdatedAtFieldName}=GETUTCDATE(), DisplayName = '${sDisplayName}' WHERE ID = '${field.ID}'`;
814
906
  await this.LogSQLAndExecute(pool, sSQL, `SQL text to update display name for field ${field.Name}`);
815
907
  }
816
908
  }
817
909
  return true;
818
910
  }
819
911
  catch (e) {
820
- (0, status_logging_1.logError)(e);
912
+ logError(e);
821
913
  return false;
822
914
  }
823
915
  }
@@ -831,12 +923,12 @@ class ManageMetadataBase {
831
923
  */
832
924
  async setDefaultColumnWidthWhereNeeded(pool, excludeSchemas) {
833
925
  try {
834
- const sSQL = `EXEC ${(0, config_1.mj_core_schema)()}.spSetDefaultColumnWidthWhereNeeded @ExcludedSchemaNames='${excludeSchemas.join(',')}'`;
926
+ const sSQL = `EXEC ${mj_core_schema()}.spSetDefaultColumnWidthWhereNeeded @ExcludedSchemaNames='${excludeSchemas.join(',')}'`;
835
927
  await this.LogSQLAndExecute(pool, sSQL, `SQL text to set default column width where needed`, true);
836
928
  return true;
837
929
  }
838
930
  catch (e) {
839
- (0, status_logging_1.logError)(e);
931
+ logError(e);
840
932
  return false;
841
933
  }
842
934
  }
@@ -858,7 +950,7 @@ class ManageMetadataBase {
858
950
  EntityID,
859
951
  ISNULL(MAX(Sequence), 0) AS MaxSequence
860
952
  FROM
861
- [${(0, config_1.mj_core_schema)()}].EntityField
953
+ [${mj_core_schema()}].EntityField
862
954
  GROUP BY
863
955
  EntityID
864
956
  ),
@@ -877,9 +969,9 @@ NumberedRows AS (
877
969
  sf.AllowsNull,
878
970
  sf.DefaultValue,
879
971
  sf.AutoIncrement,
880
- IIF(sf.IsVirtual = 1, 0, IIF(sf.FieldName = '${core_1.EntityInfo.CreatedAtFieldName}' OR
881
- sf.FieldName = '${core_1.EntityInfo.UpdatedAtFieldName}' OR
882
- sf.FieldName = '${core_1.EntityInfo.DeletedAtFieldName}' OR
972
+ IIF(sf.IsVirtual = 1, 0, IIF(sf.FieldName = '${EntityInfo.CreatedAtFieldName}' OR
973
+ sf.FieldName = '${EntityInfo.UpdatedAtFieldName}' OR
974
+ sf.FieldName = '${EntityInfo.DeletedAtFieldName}' OR
883
975
  pk.ColumnName IS NOT NULL, 0, 1)) AllowUpdateAPI,
884
976
  sf.IsVirtual,
885
977
  e.RelationshipDefaultDisplayType,
@@ -901,34 +993,34 @@ NumberedRows AS (
901
993
  END,
902
994
  ROW_NUMBER() OVER (PARTITION BY sf.EntityID, sf.FieldName ORDER BY (SELECT NULL)) AS rn
903
995
  FROM
904
- [${(0, config_1.mj_core_schema)()}].vwSQLColumnsAndEntityFields sf
996
+ [${mj_core_schema()}].vwSQLColumnsAndEntityFields sf
905
997
  LEFT OUTER JOIN
906
998
  MaxSequences ms
907
999
  ON
908
1000
  sf.EntityID = ms.EntityID
909
1001
  LEFT OUTER JOIN
910
- [${(0, config_1.mj_core_schema)()}].Entity e
1002
+ [${mj_core_schema()}].Entity e
911
1003
  ON
912
1004
  sf.EntityID = e.ID
913
1005
  LEFT OUTER JOIN
914
- [${(0, config_1.mj_core_schema)()}].vwForeignKeys fk
1006
+ [${mj_core_schema()}].vwForeignKeys fk
915
1007
  ON
916
1008
  sf.FieldName = fk.[column] AND
917
1009
  e.BaseTable = fk.[table] AND
918
1010
  e.SchemaName = fk.[schema_name]
919
1011
  LEFT OUTER JOIN
920
- [${(0, config_1.mj_core_schema)()}].Entity re -- Related Entity
1012
+ [${mj_core_schema()}].Entity re -- Related Entity
921
1013
  ON
922
1014
  re.BaseTable = fk.referenced_table AND
923
1015
  re.SchemaName = fk.[referenced_schema]
924
1016
  LEFT OUTER JOIN
925
- [${(0, config_1.mj_core_schema)()}].vwTablePrimaryKeys pk
1017
+ [${mj_core_schema()}].vwTablePrimaryKeys pk
926
1018
  ON
927
1019
  e.BaseTable = pk.TableName AND
928
1020
  sf.FieldName = pk.ColumnName AND
929
1021
  e.SchemaName = pk.SchemaName
930
1022
  LEFT OUTER JOIN
931
- [${(0, config_1.mj_core_schema)()}].vwTableUniqueKeys uk
1023
+ [${mj_core_schema()}].vwTableUniqueKeys uk
932
1024
  ON
933
1025
  e.BaseTable = uk.TableName AND
934
1026
  sf.FieldName = uk.ColumnName AND
@@ -969,22 +1061,22 @@ NumberedRows AS (
969
1061
  const isPrimaryKey = n.FieldName?.trim().toLowerCase() === 'id';
970
1062
  const isForeignKey = n.RelatedEntityID && n.RelatedEntityID.length > 0; // Foreign keys have RelatedEntityID set
971
1063
  const isNameField = n.FieldName?.trim().toLowerCase() === 'name' || n.IsNameField;
972
- const isEarlySequence = n.Sequence <= config_1.configInfo.newEntityDefaults?.IncludeFirstNFieldsAsDefaultInView;
1064
+ const isEarlySequence = n.Sequence <= configInfo.newEntityDefaults?.IncludeFirstNFieldsAsDefaultInView;
973
1065
  const bDefaultInView = (isNameField || isEarlySequence) && !isPrimaryKey && !isForeignKey;
974
1066
  const escapedDescription = n.Description ? `'${n.Description.replace(/'/g, "''")}'` : 'NULL';
975
1067
  let fieldDisplayName = '';
976
1068
  switch (n.FieldName.trim().toLowerCase()) {
977
- case core_1.EntityInfo.CreatedAtFieldName.trim().toLowerCase():
1069
+ case EntityInfo.CreatedAtFieldName.trim().toLowerCase():
978
1070
  fieldDisplayName = "Created At";
979
1071
  break;
980
- case core_1.EntityInfo.UpdatedAtFieldName.trim().toLowerCase():
1072
+ case EntityInfo.UpdatedAtFieldName.trim().toLowerCase():
981
1073
  fieldDisplayName = "Updated At";
982
1074
  break;
983
- case core_1.EntityInfo.DeletedAtFieldName.trim().toLowerCase():
1075
+ case EntityInfo.DeletedAtFieldName.trim().toLowerCase():
984
1076
  fieldDisplayName = "Deleted At";
985
1077
  break;
986
1078
  default:
987
- fieldDisplayName = (0, global_1.convertCamelCaseToHaveSpaces)(n.FieldName).trim();
1079
+ fieldDisplayName = convertCamelCaseToHaveSpaces(n.FieldName).trim();
988
1080
  break;
989
1081
  }
990
1082
  const parsedDefaultValue = this.parseDefaultValue(n.DefaultValue);
@@ -993,13 +1085,13 @@ NumberedRows AS (
993
1085
  // in the above we are setting quotedDefaultValue to NULL if the parsed default value is an empty string or the string 'NULL' (case insensitive)
994
1086
  return `
995
1087
  IF NOT EXISTS (
996
- SELECT 1 FROM [${(0, config_1.mj_core_schema)()}].EntityField
1088
+ SELECT 1 FROM [${mj_core_schema()}].EntityField
997
1089
  WHERE ID = '${newEntityFieldUUID}' OR
998
1090
  (EntityID = '${n.EntityID}' AND Name = '${n.FieldName}')
999
1091
  -- check to make sure we're not inserting a duplicate entity field metadata record
1000
1092
  )
1001
1093
  BEGIN
1002
- INSERT INTO [${(0, config_1.mj_core_schema)()}].EntityField
1094
+ INSERT INTO [${mj_core_schema()}].EntityField
1003
1095
  (
1004
1096
  ID,
1005
1097
  EntityID,
@@ -1100,7 +1192,7 @@ NumberedRows AS (
1100
1192
  }
1101
1193
  catch (e) {
1102
1194
  // this is here so we can catch the error for debug. We want the transaction to die
1103
- (0, status_logging_1.logError)(`Error inserting new entity field. SQL: \n${sSQLInsert}`);
1195
+ logError(`Error inserting new entity field. SQL: \n${sSQLInsert}`);
1104
1196
  throw e;
1105
1197
  }
1106
1198
  }
@@ -1118,7 +1210,7 @@ NumberedRows AS (
1118
1210
  return true;
1119
1211
  }
1120
1212
  catch (e) {
1121
- (0, status_logging_1.logError)(e);
1213
+ logError(e);
1122
1214
  return false;
1123
1215
  }
1124
1216
  }
@@ -1131,20 +1223,20 @@ NumberedRows AS (
1131
1223
  */
1132
1224
  async updateEntityFieldRelatedEntityNameFieldMap(pool, entityFieldID, relatedEntityNameFieldMap) {
1133
1225
  try {
1134
- const sSQL = `EXEC [${(0, config_1.mj_core_schema)()}].spUpdateEntityFieldRelatedEntityNameFieldMap
1226
+ const sSQL = `EXEC [${mj_core_schema()}].spUpdateEntityFieldRelatedEntityNameFieldMap
1135
1227
  @EntityFieldID='${entityFieldID}',
1136
1228
  @RelatedEntityNameFieldMap='${relatedEntityNameFieldMap}'`;
1137
1229
  await this.LogSQLAndExecute(pool, sSQL, `SQL text to update entity field related entity name field map for entity field ID ${entityFieldID}`);
1138
1230
  return true;
1139
1231
  }
1140
1232
  catch (e) {
1141
- (0, status_logging_1.logError)(e);
1233
+ logError(e);
1142
1234
  return false;
1143
1235
  }
1144
1236
  }
1145
1237
  async updateExistingEntitiesFromSchema(pool, excludeSchemas) {
1146
1238
  try {
1147
- const sSQL = `EXEC [${(0, config_1.mj_core_schema)()}].spUpdateExistingEntitiesFromSchema @ExcludedSchemaNames='${excludeSchemas.join(',')}'`;
1239
+ const sSQL = `EXEC [${mj_core_schema()}].spUpdateExistingEntitiesFromSchema @ExcludedSchemaNames='${excludeSchemas.join(',')}'`;
1148
1240
  const result = await this.LogSQLAndExecute(pool, sSQL, `SQL text to update existing entities from schema`, true);
1149
1241
  // result contains the updated entities, and there is a property of each row called Name which has the entity name that was modified
1150
1242
  // add these to the modified entity list if they're not already in there
@@ -1154,7 +1246,7 @@ NumberedRows AS (
1154
1246
  return true;
1155
1247
  }
1156
1248
  catch (e) {
1157
- (0, status_logging_1.logError)(e);
1249
+ logError(e);
1158
1250
  return false;
1159
1251
  }
1160
1252
  }
@@ -1169,7 +1261,7 @@ NumberedRows AS (
1169
1261
  }
1170
1262
  async updateExistingEntityFieldsFromSchema(pool, excludeSchemas) {
1171
1263
  try {
1172
- const sSQL = `EXEC [${(0, config_1.mj_core_schema)()}].spUpdateExistingEntityFieldsFromSchema @ExcludedSchemaNames='${excludeSchemas.join(',')}'`;
1264
+ const sSQL = `EXEC [${mj_core_schema()}].spUpdateExistingEntityFieldsFromSchema @ExcludedSchemaNames='${excludeSchemas.join(',')}'`;
1173
1265
  const result = await this.LogSQLAndExecute(pool, sSQL, `SQL text to update existing entity fields from schema`, true);
1174
1266
  // result contains the updated entity fields
1175
1267
  // there is a field in there called EntityName. Get a distinct list of entity names from this and add them
@@ -1180,7 +1272,7 @@ NumberedRows AS (
1180
1272
  return true;
1181
1273
  }
1182
1274
  catch (e) {
1183
- (0, status_logging_1.logError)(e);
1275
+ logError(e);
1184
1276
  return false;
1185
1277
  }
1186
1278
  }
@@ -1194,21 +1286,21 @@ NumberedRows AS (
1194
1286
  */
1195
1287
  async updateSchemaInfoFromDatabase(pool, excludeSchemas) {
1196
1288
  try {
1197
- const sSQL = `EXEC [${(0, config_1.mj_core_schema)()}].spUpdateSchemaInfoFromDatabase @ExcludedSchemaNames='${excludeSchemas.join(',')}'`;
1289
+ const sSQL = `EXEC [${mj_core_schema()}].spUpdateSchemaInfoFromDatabase @ExcludedSchemaNames='${excludeSchemas.join(',')}'`;
1198
1290
  const result = await this.LogSQLAndExecute(pool, sSQL, `SQL text to sync schema info from database schemas`, true);
1199
1291
  if (result && result.length > 0) {
1200
- (0, status_logging_1.logStatus)(` > Updated/created ${result.length} SchemaInfo records`);
1292
+ logStatus(` > Updated/created ${result.length} SchemaInfo records`);
1201
1293
  }
1202
1294
  return true;
1203
1295
  }
1204
1296
  catch (e) {
1205
- (0, status_logging_1.logError)(e);
1297
+ logError(e);
1206
1298
  return false;
1207
1299
  }
1208
1300
  }
1209
1301
  async deleteUnneededEntityFields(pool, excludeSchemas) {
1210
1302
  try {
1211
- const sSQL = `EXEC [${(0, config_1.mj_core_schema)()}].spDeleteUnneededEntityFields @ExcludedSchemaNames='${excludeSchemas.join(',')}'`;
1303
+ const sSQL = `EXEC [${mj_core_schema()}].spDeleteUnneededEntityFields @ExcludedSchemaNames='${excludeSchemas.join(',')}'`;
1212
1304
  const result = await this.LogSQLAndExecute(pool, sSQL, `SQL text to delete unneeded entity fields`, true);
1213
1305
  // result contains the DELETED entity fields
1214
1306
  // there is a field in there called Entity. Get a distinct list of entity names from this and add them
@@ -1219,7 +1311,7 @@ NumberedRows AS (
1219
1311
  return true;
1220
1312
  }
1221
1313
  catch (e) {
1222
- (0, status_logging_1.logError)(e);
1314
+ logError(e);
1223
1315
  return false;
1224
1316
  }
1225
1317
  }
@@ -1230,13 +1322,13 @@ NumberedRows AS (
1230
1322
  // for the field and sync that up with the EntityFieldValue table. If it is not a simple series of OR statements, we will not be able to parse it and we'll
1231
1323
  // just ignore it.
1232
1324
  const filter = excludeSchemas && excludeSchemas.length > 0 ? ` WHERE SchemaName NOT IN (${excludeSchemas.map(s => `'${s}'`).join(',')})` : '';
1233
- const sSQL = `SELECT * FROM [${(0, config_1.mj_core_schema)()}].vwEntityFieldsWithCheckConstraints${filter}`;
1325
+ const sSQL = `SELECT * FROM [${mj_core_schema()}].vwEntityFieldsWithCheckConstraints${filter}`;
1234
1326
  const resultResult = await pool.request().query(sSQL);
1235
1327
  const result = resultResult.recordset;
1236
- const efvSQL = `SELECT * FROM [${(0, config_1.mj_core_schema)()}].EntityFieldValue`;
1328
+ const efvSQL = `SELECT * FROM [${mj_core_schema()}].EntityFieldValue`;
1237
1329
  const allEntityFieldValuesResult = await pool.request().query(efvSQL);
1238
1330
  const allEntityFieldValues = allEntityFieldValuesResult.recordset;
1239
- const efSQL = `SELECT * FROM [${(0, config_1.mj_core_schema)()}].vwEntityFields ORDER BY EntityID, Sequence`;
1331
+ const efSQL = `SELECT * FROM [${mj_core_schema()}].vwEntityFields ORDER BY EntityID, Sequence`;
1240
1332
  const allEntityFieldsResult = await pool.request().query(efSQL);
1241
1333
  const allEntityFields = allEntityFieldsResult.recordset;
1242
1334
  const generationPromises = [];
@@ -1258,11 +1350,11 @@ NumberedRows AS (
1258
1350
  await this.syncEntityFieldValues(pool, r.EntityFieldID, parsedValues, allEntityFieldValues);
1259
1351
  // finally, make sure the ValueListType column within the EntityField table is set to "List" because for check constraints we only allow the values specified in the list.
1260
1352
  // check to see if the ValueListType is already set to "List", if not, update it
1261
- const sSQLCheck = `SELECT ValueListType FROM [${(0, config_1.mj_core_schema)()}].EntityField WHERE ID='${r.EntityFieldID}'`;
1353
+ const sSQLCheck = `SELECT ValueListType FROM [${mj_core_schema()}].EntityField WHERE ID='${r.EntityFieldID}'`;
1262
1354
  const checkResultResult = await pool.request().query(sSQLCheck);
1263
1355
  const checkResult = checkResultResult.recordset;
1264
1356
  if (checkResult && checkResult.length > 0 && checkResult[0].ValueListType.trim().toLowerCase() !== 'list') {
1265
- const sSQL = `UPDATE [${(0, config_1.mj_core_schema)()}].EntityField SET ValueListType='List' WHERE ID='${r.EntityFieldID}'`;
1357
+ const sSQL = `UPDATE [${mj_core_schema()}].EntityField SET ValueListType='List' WHERE ID='${r.EntityFieldID}'`;
1266
1358
  await this.LogSQLAndExecute(pool, sSQL, `SQL text to update ValueListType for entity field ID ${r.EntityFieldID}`);
1267
1359
  }
1268
1360
  }
@@ -1273,8 +1365,8 @@ NumberedRows AS (
1273
1365
  else {
1274
1366
  // if we get here that means we don't have a simple condition in the check constraint that the RegEx could parse. If Advanced Generation is enabled, we will
1275
1367
  // attempt to use an LLM to do things fancier now
1276
- if (config_1.configInfo.advancedGeneration?.enableAdvancedGeneration &&
1277
- config_1.configInfo.advancedGeneration?.features.find(f => f.name === 'ParseCheckConstraints' && f.enabled)) {
1368
+ if (configInfo.advancedGeneration?.enableAdvancedGeneration &&
1369
+ configInfo.advancedGeneration?.features.find(f => f.name === 'ParseCheckConstraints' && f.enabled)) {
1278
1370
  // the user has the feature turned on, let's generate a description of the constraint and then build a Validate function for the constraint
1279
1371
  // run this in parallel
1280
1372
  generationPromises.push(this.runValidationGeneration(r, allEntityFields, !skipDBUpdate, currentUser));
@@ -1284,8 +1376,8 @@ NumberedRows AS (
1284
1376
  }
1285
1377
  // now for the table level constraints run the process for advanced generation
1286
1378
  for (const r of tableLevelResults) {
1287
- if (config_1.configInfo.advancedGeneration?.enableAdvancedGeneration &&
1288
- config_1.configInfo.advancedGeneration?.features.find(f => f.name === 'ParseCheckConstraints' && f.enabled)) {
1379
+ if (configInfo.advancedGeneration?.enableAdvancedGeneration &&
1380
+ configInfo.advancedGeneration?.features.find(f => f.name === 'ParseCheckConstraints' && f.enabled)) {
1289
1381
  // the user has the feature turned on, let's generate a description of the constraint and then build a Validate function for the constraint
1290
1382
  // run this in parallel
1291
1383
  generationPromises.push(this.runValidationGeneration(r, allEntityFields, !skipDBUpdate, currentUser));
@@ -1296,7 +1388,7 @@ NumberedRows AS (
1296
1388
  return true;
1297
1389
  }
1298
1390
  catch (e) {
1299
- (0, status_logging_1.logError)(e);
1391
+ logError(e);
1300
1392
  return false;
1301
1393
  }
1302
1394
  }
@@ -1311,7 +1403,7 @@ NumberedRows AS (
1311
1403
  return await this.manageEntityFieldValuesAndValidatorFunctions(pool, [], currentUser, true);
1312
1404
  }
1313
1405
  catch (e) {
1314
- (0, status_logging_1.logError)(e);
1406
+ logError(e);
1315
1407
  return false;
1316
1408
  }
1317
1409
  }
@@ -1357,9 +1449,9 @@ NumberedRows AS (
1357
1449
  }
1358
1450
  }
1359
1451
  try {
1360
- if (generateNewCode && config_1.configInfo.advancedGeneration?.enableAdvancedGeneration && config_1.configInfo.advancedGeneration?.features.find(f => f.name === 'ParseCheckConstraints' && f.enabled)) {
1452
+ if (generateNewCode && configInfo.advancedGeneration?.enableAdvancedGeneration && configInfo.advancedGeneration?.features.find(f => f.name === 'ParseCheckConstraints' && f.enabled)) {
1361
1453
  // feature is enabled, so let's call the AI to generate a function for us
1362
- const ag = new advanced_generation_1.AdvancedGeneration();
1454
+ const ag = new AdvancedGeneration();
1363
1455
  const entityFieldListInfo = allEntityFields.filter(item => item.Entity.trim().toLowerCase() === data.EntityName.trim().toLowerCase()).map(item => ` * ${item.Name} - ${item.Type}${item.AllowsNull ? ' (nullable)' : ' (not null)'}`).join('\n');
1364
1456
  // Use new API to parse check constraint
1365
1457
  const result = await ag.parseCheckConstraint(constraintDefinition, entityFieldListInfo, generatedValidationFunctionName, currentUser);
@@ -1372,12 +1464,12 @@ NumberedRows AS (
1372
1464
  returnResult.success = true;
1373
1465
  }
1374
1466
  else {
1375
- (0, status_logging_1.logError)(`Error generating field validator function from check constraint for entity ${entityName} and field ${fieldName}. LLM returned invalid result.`);
1467
+ logError(`Error generating field validator function from check constraint for entity ${entityName} and field ${fieldName}. LLM returned invalid result.`);
1376
1468
  }
1377
1469
  }
1378
1470
  }
1379
1471
  catch (e) {
1380
- (0, status_logging_1.logError)(e);
1472
+ logError(e);
1381
1473
  }
1382
1474
  finally {
1383
1475
  return returnResult;
@@ -1396,7 +1488,7 @@ NumberedRows AS (
1396
1488
  for (const ev of existingValues) {
1397
1489
  if (!possibleValues.find(v => v === ev.Value)) {
1398
1490
  // delete the value from the database
1399
- const sSQLDelete = `DELETE FROM [${(0, config_1.mj_core_schema)()}].EntityFieldValue WHERE ID='${ev.ID}'`;
1491
+ const sSQLDelete = `DELETE FROM [${mj_core_schema()}].EntityFieldValue WHERE ID='${ev.ID}'`;
1400
1492
  await this.LogSQLAndExecute(ds, sSQLDelete, `SQL text to delete entity field value ID ${ev.ID}`);
1401
1493
  numRemoved++;
1402
1494
  }
@@ -1406,9 +1498,9 @@ NumberedRows AS (
1406
1498
  for (const v of possibleValues) {
1407
1499
  if (!existingValues.find((ev) => ev.Value === v)) {
1408
1500
  // Generate a UUID for this new EntityFieldValue record
1409
- const newId = (0, uuid_1.v4)();
1501
+ const newId = uuidv4();
1410
1502
  // add the value to the database with explicit ID
1411
- const sSQLInsert = `INSERT INTO [${(0, config_1.mj_core_schema)()}].EntityFieldValue
1503
+ const sSQLInsert = `INSERT INTO [${mj_core_schema()}].EntityFieldValue
1412
1504
  (ID, EntityFieldID, Sequence, Value, Code)
1413
1505
  VALUES
1414
1506
  ('${newId}', '${entityFieldID}', ${1 + possibleValues.indexOf(v)}, '${v}', '${v}')`;
@@ -1422,7 +1514,7 @@ NumberedRows AS (
1422
1514
  const ev = existingValues.find((ev) => ev.Value === v);
1423
1515
  if (ev && ev.Sequence !== 1 + possibleValues.indexOf(v)) {
1424
1516
  // update the sequence to match the order in the possible values list, if it doesn't already match
1425
- const sSQLUpdate = `UPDATE [${(0, config_1.mj_core_schema)()}].EntityFieldValue SET Sequence=${1 + possibleValues.indexOf(v)} WHERE ID='${ev.ID}'`;
1517
+ const sSQLUpdate = `UPDATE [${mj_core_schema()}].EntityFieldValue SET Sequence=${1 + possibleValues.indexOf(v)} WHERE ID='${ev.ID}'`;
1426
1518
  await this.LogSQLAndExecute(ds, sSQLUpdate, `SQL text to update entity field value sequence`);
1427
1519
  numUpdated++;
1428
1520
  }
@@ -1436,7 +1528,7 @@ NumberedRows AS (
1436
1528
  return true;
1437
1529
  }
1438
1530
  catch (e) {
1439
- (0, status_logging_1.logError)(e);
1531
+ logError(e);
1440
1532
  return false;
1441
1533
  }
1442
1534
  }
@@ -1495,9 +1587,9 @@ NumberedRows AS (
1495
1587
  createExcludeTablesAndSchemasFilter(fieldPrefix) {
1496
1588
  let sExcludeTables = '';
1497
1589
  let sExcludeSchemas = '';
1498
- if (config_1.configInfo.excludeTables) {
1499
- for (let i = 0; i < config_1.configInfo.excludeTables.length; ++i) {
1500
- const t = config_1.configInfo.excludeTables[i];
1590
+ if (configInfo.excludeTables) {
1591
+ for (let i = 0; i < configInfo.excludeTables.length; ++i) {
1592
+ const t = configInfo.excludeTables[i];
1501
1593
  sExcludeTables += (sExcludeTables.length > 0 ? ' AND ' : '') +
1502
1594
  (t.schema.indexOf('%') > -1 ? ` NOT ( ${fieldPrefix}SchemaName LIKE '${t.schema}'` :
1503
1595
  ` NOT ( ${fieldPrefix}SchemaName = '${t.schema}'`);
@@ -1505,9 +1597,9 @@ NumberedRows AS (
1505
1597
  ` AND ${fieldPrefix}TableName = '${t.table}') `);
1506
1598
  }
1507
1599
  }
1508
- if (config_1.configInfo.excludeSchemas) {
1509
- for (let i = 0; i < config_1.configInfo.excludeSchemas.length; ++i) {
1510
- const s = config_1.configInfo.excludeSchemas[i];
1600
+ if (configInfo.excludeSchemas) {
1601
+ for (let i = 0; i < configInfo.excludeSchemas.length; ++i) {
1602
+ const s = configInfo.excludeSchemas[i];
1511
1603
  sExcludeSchemas += (sExcludeSchemas.length > 0 ? ' AND ' : '') +
1512
1604
  (s.indexOf('%') > -1 ? `${fieldPrefix}SchemaName NOT LIKE '${s}'` : `${fieldPrefix}SchemaName <> '${s}'`);
1513
1605
  }
@@ -1519,11 +1611,11 @@ NumberedRows AS (
1519
1611
  }
1520
1612
  async createNewEntities(pool, currentUser) {
1521
1613
  try {
1522
- const sSQL = `SELECT * FROM [${(0, config_1.mj_core_schema)()}].vwSQLTablesAndEntities WHERE EntityID IS NULL ` + this.createExcludeTablesAndSchemasFilter('');
1614
+ const sSQL = `SELECT * FROM [${mj_core_schema()}].vwSQLTablesAndEntities WHERE EntityID IS NULL ` + this.createExcludeTablesAndSchemasFilter('');
1523
1615
  const newEntitiesResult = await pool.request().query(sSQL);
1524
1616
  const newEntities = newEntitiesResult.recordset;
1525
1617
  if (newEntities && newEntities.length > 0) {
1526
- const md = new core_1.Metadata();
1618
+ const md = new Metadata();
1527
1619
  const transaction = new sql.Transaction(pool);
1528
1620
  await transaction.begin();
1529
1621
  try {
@@ -1540,14 +1632,14 @@ NumberedRows AS (
1540
1632
  }
1541
1633
  if (ManageMetadataBase.newEntityList.length > 0) {
1542
1634
  // only do this if we actually created new entities
1543
- (0, core_1.LogStatus)(` Done creating entities, refreshing metadata to reflect new entities...`);
1635
+ LogStatus(` Done creating entities, refreshing metadata to reflect new entities...`);
1544
1636
  await md.Refresh(); // refresh now since we've added some new entities
1545
1637
  }
1546
1638
  }
1547
1639
  return true; // if we get here, we succeeded
1548
1640
  }
1549
1641
  catch (e) {
1550
- (0, core_1.LogError)(e);
1642
+ LogError(e);
1551
1643
  return false;
1552
1644
  }
1553
1645
  }
@@ -1556,11 +1648,16 @@ NumberedRows AS (
1556
1648
  // criteria:
1557
1649
  // 1) entity has a field that is a primary key
1558
1650
  // validate all of these factors by getting the sql from SQL Server and check the result, if failure, shouldCreate=false and generate validation message, otherwise return empty validation message and true for shouldCreate.
1559
- const query = `EXEC ${core_1.Metadata.Provider.ConfigData.MJCoreSchemaName}.spGetPrimaryKeyForTable @TableName='${newEntity.TableName}', @SchemaName='${newEntity.SchemaName}'`;
1651
+ const query = `EXEC ${Metadata.Provider.ConfigData.MJCoreSchemaName}.spGetPrimaryKeyForTable @TableName='${newEntity.TableName}', @SchemaName='${newEntity.SchemaName}'`;
1560
1652
  try {
1561
1653
  const resultResult = await ds.request().query(query);
1562
1654
  const result = resultResult.recordset;
1563
1655
  if (result.length === 0) {
1656
+ // No database PK constraint found - check if there's a soft PK defined in config
1657
+ if (this.hasSoftPrimaryKeyInConfig(newEntity.SchemaName, newEntity.TableName)) {
1658
+ logStatus(` ✓ No database PK for ${newEntity.SchemaName}.${newEntity.TableName}, but soft PK found in config - allowing entity creation`);
1659
+ return { shouldCreate: true, validationMessage: '' };
1660
+ }
1564
1661
  return { shouldCreate: false, validationMessage: "No primary key found" };
1565
1662
  }
1566
1663
  return { shouldCreate: true, validationMessage: '' };
@@ -1571,8 +1668,40 @@ NumberedRows AS (
1571
1668
  return { shouldCreate: false, validationMessage: errorMsg };
1572
1669
  }
1573
1670
  }
1671
+ /**
1672
+ * Checks if a table has a soft primary key defined in the additionalSchemaInfo JSON file (configured in mj.config.cjs)
1673
+ */
1674
+ hasSoftPrimaryKeyInConfig(schemaName, tableName) {
1675
+ // Check if additionalSchemaInfo is configured
1676
+ if (!configInfo.additionalSchemaInfo) {
1677
+ return false;
1678
+ }
1679
+ const configPath = path.join(currentWorkingDirectory, configInfo.additionalSchemaInfo);
1680
+ if (!fs.existsSync(configPath)) {
1681
+ logStatus(` [Soft PK Check] Config file not found at: ${configPath}`);
1682
+ return false;
1683
+ }
1684
+ try {
1685
+ const config = ManageMetadataBase.getSoftPKFKConfig();
1686
+ if (!config || !config.tables) {
1687
+ logStatus(` [Soft PK Check] Config file found but no tables array`);
1688
+ return false;
1689
+ }
1690
+ const tableConfig = config.tables.find((t) => t.schemaName?.toLowerCase() === schemaName?.toLowerCase() &&
1691
+ t.tableName?.toLowerCase() === tableName?.toLowerCase());
1692
+ const found = Boolean(tableConfig?.primaryKeys && tableConfig.primaryKeys.length > 0);
1693
+ if (!found) {
1694
+ logStatus(` [Soft PK Check] No config found for ${schemaName}.${tableName} (config has ${config.tables.length} tables)`);
1695
+ }
1696
+ return found;
1697
+ }
1698
+ catch (e) {
1699
+ logStatus(` [Soft PK Check] Error reading config: ${e}`);
1700
+ return false;
1701
+ }
1702
+ }
1574
1703
  async createNewEntityName(newEntity, currentUser) {
1575
- const ag = new advanced_generation_1.AdvancedGeneration();
1704
+ const ag = new AdvancedGeneration();
1576
1705
  if (ag.featureEnabled('EntityNames')) {
1577
1706
  return this.newEntityNameWithAdvancedGeneration(ag, newEntity, currentUser);
1578
1707
  }
@@ -1612,8 +1741,8 @@ NumberedRows AS (
1612
1741
  }
1613
1742
  }
1614
1743
  simpleNewEntityName(schemaName, tableName) {
1615
- const convertedTableName = (0, global_1.convertCamelCaseToHaveSpaces)(tableName);
1616
- const pluralName = (0, global_1.generatePluralName)(convertedTableName, { capitalizeFirstLetterOnly: true });
1744
+ const convertedTableName = convertCamelCaseToHaveSpaces(tableName);
1745
+ const pluralName = generatePluralName(convertedTableName, { capitalizeFirstLetterOnly: true });
1617
1746
  return this.markupEntityName(schemaName, pluralName);
1618
1747
  }
1619
1748
  /**
@@ -1633,18 +1762,18 @@ NumberedRows AS (
1633
1762
  }
1634
1763
  }
1635
1764
  getNewEntityNameRule(schemaName) {
1636
- const rule = config_1.configInfo.newEntityDefaults?.NameRulesBySchema?.find(r => {
1765
+ const rule = configInfo.newEntityDefaults?.NameRulesBySchema?.find(r => {
1637
1766
  let schemaNameToUse = r.SchemaName;
1638
1767
  if (schemaNameToUse?.trim().toLowerCase() === '${mj_core_schema}') {
1639
1768
  // markup for this is to be replaced with the mj_core_schema() config
1640
- schemaNameToUse = (0, config_1.mj_core_schema)();
1769
+ schemaNameToUse = mj_core_schema();
1641
1770
  }
1642
1771
  return schemaNameToUse.trim().toLowerCase() === schemaName.trim().toLowerCase();
1643
1772
  });
1644
1773
  return rule;
1645
1774
  }
1646
1775
  createNewUUID() {
1647
- return (0, uuid_1.v4)();
1776
+ return uuidv4();
1648
1777
  }
1649
1778
  async createNewEntity(pool, newEntity, md, currentUser) {
1650
1779
  try {
@@ -1660,7 +1789,7 @@ NumberedRows AS (
1660
1789
  // the generated name is already in place, so we need another name
1661
1790
  suffix = '__' + newEntity.SchemaName;
1662
1791
  newEntityName = newEntityName + suffix;
1663
- (0, core_1.LogError)(` >>>> WARNING: Entity name already exists, so using ${newEntityName} instead. If you did not intend for this, please rename the ${newEntity.SchemaName}.${newEntity.TableName} table in the database.`);
1792
+ LogError(` >>>> WARNING: Entity name already exists, so using ${newEntityName} instead. If you did not intend for this, please rename the ${newEntity.SchemaName}.${newEntity.TableName} table in the database.`);
1664
1793
  }
1665
1794
  const isNewSchema = await this.isSchemaNew(pool, newEntity.SchemaName);
1666
1795
  const newEntityID = this.createNewUUID();
@@ -1672,7 +1801,7 @@ NumberedRows AS (
1672
1801
  // next, check if this entity is in a schema that is new (e.g. no other entities have been added to this schema yet), if so and if
1673
1802
  // our config option is set to create new applications from new schemas, then create a new application for this schema
1674
1803
  let apps;
1675
- if (isNewSchema && config_1.configInfo.newSchemaDefaults.CreateNewApplicationWithSchemaName) {
1804
+ if (isNewSchema && configInfo.newSchemaDefaults.CreateNewApplicationWithSchemaName) {
1676
1805
  // new schema and config option is to create a new application from the schema name so do that
1677
1806
  // check to see if the app already exists
1678
1807
  apps = await this.getApplicationIDForSchema(pool, newEntity.SchemaName);
@@ -1684,7 +1813,7 @@ NumberedRows AS (
1684
1813
  apps = [newAppID];
1685
1814
  }
1686
1815
  else {
1687
- (0, core_1.LogError)(` >>>> ERROR: Unable to create new application for schema ${newEntity.SchemaName}`);
1816
+ LogError(` >>>> ERROR: Unable to create new application for schema ${newEntity.SchemaName}`);
1688
1817
  }
1689
1818
  await md.Refresh(); // refresh now since we've added a new application, not super efficient to do this for each new application but that won't happen super
1690
1819
  // often so not a huge deal, would be more efficient do this in batch after all new apps are created but that would be an over optimization IMO
@@ -1695,12 +1824,12 @@ NumberedRows AS (
1695
1824
  apps = await this.getApplicationIDForSchema(pool, newEntity.SchemaName);
1696
1825
  }
1697
1826
  if (apps && apps.length > 0) {
1698
- if (config_1.configInfo.newEntityDefaults.AddToApplicationWithSchemaName) {
1827
+ if (configInfo.newEntityDefaults.AddToApplicationWithSchemaName) {
1699
1828
  // only do this if the configuration setting is set to add new entities to applications for schema names
1700
1829
  for (const appUUID of apps) {
1701
- const sSQLInsertApplicationEntity = `INSERT INTO ${(0, config_1.mj_core_schema)()}.ApplicationEntity
1830
+ const sSQLInsertApplicationEntity = `INSERT INTO ${mj_core_schema()}.ApplicationEntity
1702
1831
  (ApplicationID, EntityID, Sequence) VALUES
1703
- ('${appUUID}', '${newEntityID}', (SELECT ISNULL(MAX(Sequence),0)+1 FROM ${(0, config_1.mj_core_schema)()}.ApplicationEntity WHERE ApplicationID = '${appUUID}'))`;
1832
+ ('${appUUID}', '${newEntityID}', (SELECT ISNULL(MAX(Sequence),0)+1 FROM ${mj_core_schema()}.ApplicationEntity WHERE ApplicationID = '${appUUID}'))`;
1704
1833
  await this.LogSQLAndExecute(pool, sSQLInsertApplicationEntity, `SQL generated to add new entity ${newEntityName} to application ID: '${appUUID}'`);
1705
1834
  }
1706
1835
  }
@@ -1710,91 +1839,85 @@ NumberedRows AS (
1710
1839
  }
1711
1840
  else {
1712
1841
  // this is an error condition, we should have an application for this schema, if we don't, log an error, non fatal, but should be logged
1713
- (0, core_1.LogError)(` >>>> ERROR: Unable to add new entity ${newEntityName} to an application because an Application record for schema ${newEntity.SchemaName} does not exist.`);
1842
+ LogError(` >>>> ERROR: Unable to add new entity ${newEntityName} to an application because an Application record for schema ${newEntity.SchemaName} does not exist.`);
1714
1843
  }
1715
1844
  // next up, we need to check if we're configured to add permissions for new entities, and if so, add them
1716
- if (config_1.configInfo.newEntityDefaults.PermissionDefaults && config_1.configInfo.newEntityDefaults.PermissionDefaults.AutoAddPermissionsForNewEntities) {
1845
+ if (configInfo.newEntityDefaults.PermissionDefaults && configInfo.newEntityDefaults.PermissionDefaults.AutoAddPermissionsForNewEntities) {
1717
1846
  // we are asked to add permissions for new entities, so do that by looping through the permissions and adding them
1718
- const permissions = config_1.configInfo.newEntityDefaults.PermissionDefaults.Permissions;
1847
+ const permissions = configInfo.newEntityDefaults.PermissionDefaults.Permissions;
1719
1848
  for (const p of permissions) {
1720
1849
  const RoleID = md.Roles.find(r => r.Name.trim().toLowerCase() === p.RoleName.trim().toLowerCase())?.ID;
1721
1850
  if (RoleID) {
1722
- const sSQLInsertPermission = `INSERT INTO ${(0, config_1.mj_core_schema)()}.EntityPermission
1851
+ const sSQLInsertPermission = `INSERT INTO ${mj_core_schema()}.EntityPermission
1723
1852
  (EntityID, RoleID, CanRead, CanCreate, CanUpdate, CanDelete) VALUES
1724
1853
  ('${newEntityID}', '${RoleID}', ${p.CanRead ? 1 : 0}, ${p.CanCreate ? 1 : 0}, ${p.CanUpdate ? 1 : 0}, ${p.CanDelete ? 1 : 0})`;
1725
1854
  await this.LogSQLAndExecute(pool, sSQLInsertPermission, `SQL generated to add new permission for entity ${newEntityName} for role ${p.RoleName}`);
1726
1855
  }
1727
1856
  else
1728
- (0, core_1.LogError)(` >>>> ERROR: Unable to find Role ID for role ${p.RoleName} to add permissions for new entity ${newEntityName}`);
1857
+ LogError(` >>>> ERROR: Unable to find Role ID for role ${p.RoleName} to add permissions for new entity ${newEntityName}`);
1729
1858
  }
1730
1859
  }
1731
- (0, core_1.LogStatus)(` Created new entity ${newEntityName} for table ${newEntity.SchemaName}.${newEntity.TableName}`);
1860
+ LogStatus(` Created new entity ${newEntityName} for table ${newEntity.SchemaName}.${newEntity.TableName}`);
1732
1861
  }
1733
1862
  else {
1734
- (0, core_1.LogStatus)(` Skipping new entity ${newEntity.TableName} because it doesn't qualify to be created. Reason: ${validationMessage}`);
1863
+ LogStatus(` Skipping new entity ${newEntity.TableName} because it doesn't qualify to be created. Reason: ${validationMessage}`);
1735
1864
  return;
1736
1865
  }
1737
1866
  }
1738
1867
  catch (e) {
1739
- (0, core_1.LogError)(`Failed to create new entity ${newEntity?.TableName}`);
1868
+ LogError(`Failed to create new entity ${newEntity?.TableName}`);
1740
1869
  }
1741
1870
  }
1742
1871
  async isSchemaNew(pool, schemaName) {
1743
1872
  // check to see if there are any entities in the db with this schema name
1744
- const sSQL = `SELECT COUNT(*) AS Count FROM [${(0, config_1.mj_core_schema)()}].Entity WHERE SchemaName = '${schemaName}'`;
1873
+ const sSQL = `SELECT COUNT(*) AS Count FROM [${mj_core_schema()}].Entity WHERE SchemaName = '${schemaName}'`;
1745
1874
  const resultResult = await pool.request().query(sSQL);
1746
1875
  const result = resultResult.recordset;
1747
1876
  return result && result.length > 0 ? result[0].Count === 0 : true;
1748
1877
  }
1749
1878
  /**
1750
- * Creates a new application using the entity framework.
1751
- * This ensures the server-side entity extension is used, which handles:
1752
- * - Auto-generation of Path from Name (via ApplicationEntityServerEntity)
1753
- * - Any other server-side business logic
1879
+ * Creates a new application using direct SQL INSERT to ensure it's captured in SQL logging.
1880
+ * The Path field is auto-generated from Name using the same slug logic as ApplicationEntityServerEntity.
1754
1881
  *
1755
- * @param pool SQL connection pool (unused but kept for signature compatibility)
1882
+ * @param pool SQL connection pool
1756
1883
  * @param appID Pre-generated UUID for the application
1757
1884
  * @param appName Name of the application
1758
1885
  * @param schemaName Schema name for SchemaAutoAddNewEntities
1759
- * @param currentUser Current user for entity operations
1886
+ * @param currentUser Current user for entity operations (unused but kept for signature compatibility)
1760
1887
  * @returns The application ID if successful, null otherwise
1761
1888
  */
1762
1889
  async createNewApplication(pool, appID, appName, schemaName, currentUser) {
1763
1890
  try {
1764
- const md = new core_1.Metadata();
1765
- const app = await md.GetEntityObject('Applications', currentUser);
1766
- app.NewRecord();
1767
- app.ID = appID;
1768
- app.Name = appName;
1769
- app.Description = 'Generated for schema';
1770
- app.SchemaAutoAddNewEntities = schemaName;
1771
- // Path and AutoUpdatePath will be handled by the server-side entity extension
1772
- // which auto-generates Path from Name when AutoUpdatePath is true (default)
1773
- const saved = await app.Save();
1774
- if (saved) {
1775
- (0, core_1.LogStatus)(`Created new application ${appName} with Path: ${app.Path}`);
1776
- return appID;
1777
- }
1778
- else {
1779
- const errorMsg = app.LatestResult ? JSON.stringify(app.LatestResult) : 'Unknown error';
1780
- (0, core_1.LogError)(`Failed to save new application ${appName}: ${errorMsg}`);
1781
- return null;
1782
- }
1891
+ // Generate Path from Name using slug conversion:
1892
+ // 1. Convert to lowercase
1893
+ // 2. Replace spaces with hyphens
1894
+ // 3. Remove special characters (keep only alphanumeric and hyphens)
1895
+ const path = appName
1896
+ .toLowerCase()
1897
+ .replace(/\s+/g, '-') // spaces to hyphens
1898
+ .replace(/[^a-z0-9-]/g, '') // remove special chars
1899
+ .replace(/-+/g, '-') // collapse multiple hyphens
1900
+ .replace(/^-|-$/g, ''); // trim hyphens from start/end
1901
+ const sSQL = `INSERT INTO [${mj_core_schema()}].Application (ID, Name, Description, SchemaAutoAddNewEntities, Path, AutoUpdatePath)
1902
+ VALUES ('${appID}', '${appName}', 'Generated for schema', '${schemaName}', '${path}', 1)`;
1903
+ await this.LogSQLAndExecute(pool, sSQL, `SQL generated to create new application ${appName}`);
1904
+ LogStatus(`Created new application ${appName} with Path: ${path}`);
1905
+ return appID;
1783
1906
  }
1784
1907
  catch (e) {
1785
- (0, core_1.LogError)(`Failed to create new application ${appName} for schema ${schemaName}`, null, e);
1908
+ LogError(`Failed to create new application ${appName} for schema ${schemaName}`, null, e);
1786
1909
  return null;
1787
1910
  }
1788
1911
  }
1789
1912
  async applicationExists(pool, applicationName) {
1790
- const sSQL = `SELECT ID FROM [${(0, config_1.mj_core_schema)()}].Application WHERE Name = '${applicationName}'`;
1913
+ const sSQL = `SELECT ID FROM [${mj_core_schema()}].Application WHERE Name = '${applicationName}'`;
1791
1914
  const resultResult = await pool.request().query(sSQL);
1792
1915
  const result = resultResult.recordset;
1793
1916
  return result && result.length > 0 ? result[0].ID.length > 0 : false;
1794
1917
  }
1795
1918
  async getApplicationIDForSchema(pool, schemaName) {
1796
1919
  // get all the apps each time from DB as we might be adding, don't use Metadata here for that reason
1797
- const sSQL = `SELECT ID, Name, SchemaAutoAddNewEntities FROM [${(0, config_1.mj_core_schema)()}].vwApplications`;
1920
+ const sSQL = `SELECT ID, Name, SchemaAutoAddNewEntities FROM [${mj_core_schema()}].vwApplications`;
1798
1921
  const resultResult = await pool.request().query(sSQL);
1799
1922
  const result = resultResult.recordset;
1800
1923
  if (!result || result.length === 0) {
@@ -1814,10 +1937,10 @@ NumberedRows AS (
1814
1937
  }
1815
1938
  }
1816
1939
  createNewEntityInsertSQL(newEntityUUID, newEntityName, newEntity, newEntitySuffix, newEntityDisplayName) {
1817
- const newEntityDefaults = config_1.configInfo.newEntityDefaults;
1940
+ const newEntityDefaults = configInfo.newEntityDefaults;
1818
1941
  const newEntityDescriptionEscaped = newEntity.Description ? `'${newEntity.Description.replace(/'/g, "''")}` : null;
1819
1942
  const sSQLInsert = `
1820
- INSERT INTO [${(0, config_1.mj_core_schema)()}].Entity (
1943
+ INSERT INTO [${mj_core_schema()}].Entity (
1821
1944
  ID,
1822
1945
  Name,
1823
1946
  DisplayName,
@@ -1844,7 +1967,7 @@ NumberedRows AS (
1844
1967
  ${newEntityDescriptionEscaped ? newEntityDescriptionEscaped : 'NULL' /*if no description, then null*/},
1845
1968
  ${newEntitySuffix && newEntitySuffix.length > 0 ? `'${newEntitySuffix}'` : 'NULL'},
1846
1969
  '${newEntity.TableName}',
1847
- 'vw${(0, global_1.generatePluralName)(newEntity.TableName, { capitalizeFirstLetterOnly: true }) + (newEntitySuffix && newEntitySuffix.length > 0 ? newEntitySuffix : '')}',
1970
+ 'vw${generatePluralName(newEntity.TableName, { capitalizeFirstLetterOnly: true }) + (newEntitySuffix && newEntitySuffix.length > 0 ? newEntitySuffix : '')}',
1848
1971
  '${newEntity.SchemaName}',
1849
1972
  1,
1850
1973
  ${newEntityDefaults.AllowUserSearchAPI === undefined ? 1 : newEntityDefaults.AllowUserSearchAPI ? 1 : 0}
@@ -1865,7 +1988,7 @@ NumberedRows AS (
1865
1988
  */
1866
1989
  async applyAdvancedGeneration(pool, excludeSchemas, currentUser) {
1867
1990
  try {
1868
- const ag = new advanced_generation_1.AdvancedGeneration();
1991
+ const ag = new AdvancedGeneration();
1869
1992
  if (!ag.enabled) {
1870
1993
  return true;
1871
1994
  }
@@ -1874,13 +1997,13 @@ NumberedRows AS (
1874
1997
  // Otherwise, only process new or modified entities
1875
1998
  let entitiesToProcess = [];
1876
1999
  let whereClause = '';
1877
- if (config_1.configInfo.forceRegeneration?.enabled) {
2000
+ if (configInfo.forceRegeneration?.enabled) {
1878
2001
  // Force regeneration mode - process all entities (or filtered by entityWhereClause)
1879
- (0, status_logging_1.logStatus)(` Force regeneration enabled - processing all entities...`);
2002
+ logStatus(` Force regeneration enabled - processing all entities...`);
1880
2003
  whereClause = 'e.VirtualEntity = 0';
1881
- if (config_1.configInfo.forceRegeneration.entityWhereClause && config_1.configInfo.forceRegeneration.entityWhereClause.trim().length > 0) {
1882
- whereClause += ` AND (${config_1.configInfo.forceRegeneration.entityWhereClause})`;
1883
- (0, status_logging_1.logStatus)(` Filtered by: ${config_1.configInfo.forceRegeneration.entityWhereClause}`);
2004
+ if (configInfo.forceRegeneration.entityWhereClause && configInfo.forceRegeneration.entityWhereClause.trim().length > 0) {
2005
+ whereClause += ` AND (${configInfo.forceRegeneration.entityWhereClause})`;
2006
+ logStatus(` Filtered by: ${configInfo.forceRegeneration.entityWhereClause}`);
1884
2007
  }
1885
2008
  whereClause += ` AND e.SchemaName NOT IN (${excludeSchemas.map(s => `'${s}'`).join(',')})`;
1886
2009
  }
@@ -1896,7 +2019,7 @@ NumberedRows AS (
1896
2019
  if (entitiesToProcess.length === 0) {
1897
2020
  return true;
1898
2021
  }
1899
- (0, status_logging_1.logStatus)(` Advanced Generation enabled, processing ${entitiesToProcess.length} entities...`);
2022
+ logStatus(` Advanced Generation enabled, processing ${entitiesToProcess.length} entities...`);
1900
2023
  whereClause = `e.VirtualEntity = 0 AND e.Name IN (${entitiesToProcess.map(name => `'${name}'`).join(',')}) AND e.SchemaName NOT IN (${excludeSchemas.map(s => `'${s}'`).join(',')})`;
1901
2024
  }
1902
2025
  // Get entity details for entities that need processing
@@ -1908,7 +2031,7 @@ NumberedRows AS (
1908
2031
  e.SchemaName,
1909
2032
  e.BaseTable
1910
2033
  FROM
1911
- [${(0, config_1.mj_core_schema)()}].vwEntities e
2034
+ [${mj_core_schema()}].vwEntities e
1912
2035
  WHERE
1913
2036
  ${whereClause}
1914
2037
  ORDER BY
@@ -1941,7 +2064,7 @@ NumberedRows AS (
1941
2064
  ef.EntityIDFieldName,
1942
2065
  ef.RelatedEntity
1943
2066
  FROM
1944
- [${(0, config_1.mj_core_schema)()}].vwEntityFields ef
2067
+ [${mj_core_schema()}].vwEntityFields ef
1945
2068
  WHERE
1946
2069
  ef.EntityID IN (${entityIds})
1947
2070
  ORDER BY
@@ -1957,7 +2080,7 @@ NumberedRows AS (
1957
2080
  es.Name,
1958
2081
  es.Value
1959
2082
  FROM
1960
- [${(0, config_1.mj_core_schema)()}].EntitySetting es
2083
+ [${mj_core_schema()}].EntitySetting es
1961
2084
  WHERE
1962
2085
  es.EntityID IN (${entityIds})
1963
2086
  AND es.Name IN ('FieldCategoryIcons', 'FieldCategoryInfo')
@@ -1980,7 +2103,7 @@ NumberedRows AS (
1980
2103
  return await this.processEntitiesBatched(pool, entities, allFields, ag, currentUser);
1981
2104
  }
1982
2105
  catch (error) {
1983
- (0, status_logging_1.logError)(`Advanced Generation failed: ${error}`);
2106
+ logError(`Advanced Generation failed: ${error}`);
1984
2107
  return false;
1985
2108
  }
1986
2109
  }
@@ -2008,12 +2131,12 @@ NumberedRows AS (
2008
2131
  }
2009
2132
  else {
2010
2133
  errorCount++;
2011
- (0, status_logging_1.logError)(` Error processing entity: ${result.reason}`);
2134
+ logError(` Error processing entity: ${result.reason}`);
2012
2135
  }
2013
2136
  }
2014
- (0, status_logging_1.logStatus)(` Progress: ${processedCount}/${entities.length} entities processed`);
2137
+ logStatus(` Progress: ${processedCount}/${entities.length} entities processed`);
2015
2138
  }
2016
- (0, status_logging_1.logStatus)(` Advanced Generation complete: ${processedCount} entities processed, ${errorCount} errors`);
2139
+ logStatus(` Advanced Generation complete: ${processedCount} entities processed, ${errorCount} errors`);
2017
2140
  return errorCount === 0;
2018
2141
  }
2019
2142
  /**
@@ -2053,7 +2176,7 @@ NumberedRows AS (
2053
2176
  }, currentUser, isNewEntity);
2054
2177
  if (layoutAnalysis) {
2055
2178
  await this.applyFormLayout(pool, entity.ID, fields, layoutAnalysis, isNewEntity);
2056
- (0, status_logging_1.logStatus)(` Applied form layout for ${entity.Name}`);
2179
+ logStatus(` Applied form layout for ${entity.Name}`);
2057
2180
  }
2058
2181
  }
2059
2182
  }
@@ -2066,26 +2189,26 @@ NumberedRows AS (
2066
2189
  const nameField = fields.find(f => f.Name === result.nameField);
2067
2190
  if (nameField && nameField.AutoUpdateIsNameField && nameField.ID) {
2068
2191
  sqlStatements.push(`
2069
- UPDATE [${(0, config_1.mj_core_schema)()}].EntityField
2192
+ UPDATE [${mj_core_schema()}].EntityField
2070
2193
  SET IsNameField = 1
2071
2194
  WHERE ID = '${nameField.ID}'
2072
2195
  AND AutoUpdateIsNameField = 1
2073
2196
  `);
2074
2197
  }
2075
2198
  else if (!nameField) {
2076
- (0, status_logging_1.logError)(`Smart field identification returned invalid nameField: '${result.nameField}' not found in entity fields`);
2199
+ logError(`Smart field identification returned invalid nameField: '${result.nameField}' not found in entity fields`);
2077
2200
  }
2078
2201
  // Find all default in view fields (one or more)
2079
2202
  const defaultInViewFields = fields.filter(f => result.defaultInView.includes(f.Name) && f.AutoUpdateDefaultInView && f.ID);
2080
2203
  // Warn about any fields that weren't found
2081
2204
  const missingFields = result.defaultInView.filter(name => !fields.some(f => f.Name === name));
2082
2205
  if (missingFields.length > 0) {
2083
- (0, status_logging_1.logError)(`Smart field identification returned invalid defaultInView fields: ${missingFields.join(', ')} not found in entity`);
2206
+ logError(`Smart field identification returned invalid defaultInView fields: ${missingFields.join(', ')} not found in entity`);
2084
2207
  }
2085
2208
  // Build update statements for all default in view fields
2086
2209
  for (const field of defaultInViewFields) {
2087
2210
  sqlStatements.push(`
2088
- UPDATE [${(0, config_1.mj_core_schema)()}].EntityField
2211
+ UPDATE [${mj_core_schema()}].EntityField
2089
2212
  SET DefaultInView = 1
2090
2213
  WHERE ID = '${field.ID}'
2091
2214
  AND AutoUpdateDefaultInView = 1
@@ -2097,12 +2220,12 @@ NumberedRows AS (
2097
2220
  // Warn about any fields that weren't found
2098
2221
  const missingSearchableFields = result.searchableFields.filter(name => !fields.some(f => f.Name === name));
2099
2222
  if (missingSearchableFields.length > 0) {
2100
- (0, status_logging_1.logError)(`Smart field identification returned invalid searchableFields: ${missingSearchableFields.join(', ')} not found in entity`);
2223
+ logError(`Smart field identification returned invalid searchableFields: ${missingSearchableFields.join(', ')} not found in entity`);
2101
2224
  }
2102
2225
  // Build update statements for all searchable fields
2103
2226
  for (const field of searchableFields) {
2104
2227
  sqlStatements.push(`
2105
- UPDATE [${(0, config_1.mj_core_schema)()}].EntityField
2228
+ UPDATE [${mj_core_schema()}].EntityField
2106
2229
  SET IncludeInUserSearchAPI = 1
2107
2230
  WHERE ID = '${field.ID}'
2108
2231
  AND AutoUpdateIncludeInUserSearchAPI = 1
@@ -2153,7 +2276,7 @@ NumberedRows AS (
2153
2276
  if (fieldHasExistingCategory && categoryIsNew) {
2154
2277
  // LLM is trying to move an existing field to a brand new category
2155
2278
  // This could be an attempt to rename a category - reject it
2156
- (0, status_logging_1.logStatus)(` Rejected category change for field '${field.Name}': cannot move from existing category '${field.Category}' to new category '${category}'. Keeping original category.`);
2279
+ logStatus(` Rejected category change for field '${field.Name}': cannot move from existing category '${field.Category}' to new category '${category}'. Keeping original category.`);
2157
2280
  category = field.Category; // Keep the original category
2158
2281
  }
2159
2282
  // Build SET clause with all available metadata
@@ -2175,14 +2298,14 @@ NumberedRows AS (
2175
2298
  const codeType = fieldCategory.codeType === null ? 'NULL' : `'${fieldCategory.codeType.replace(/'/g, "''")}'`;
2176
2299
  setClauses.push(`CodeType = ${codeType}`);
2177
2300
  }
2178
- const updateSQL = `UPDATE [${(0, config_1.mj_core_schema)()}].EntityField
2301
+ const updateSQL = `UPDATE [${mj_core_schema()}].EntityField
2179
2302
  SET ${setClauses.join(',\n ')}
2180
2303
  WHERE ID = '${field.ID}'
2181
2304
  AND AutoUpdateCategory = 1`;
2182
2305
  sqlStatements.push(updateSQL);
2183
2306
  }
2184
2307
  else if (!field) {
2185
- (0, status_logging_1.logError)(`Form layout generation returned invalid fieldName: '${fieldCategory.fieldName}' not found in entity`);
2308
+ logError(`Form layout generation returned invalid fieldName: '${fieldCategory.fieldName}' not found in entity`);
2186
2309
  }
2187
2310
  }
2188
2311
  // Execute all field updates in one batch
@@ -2194,7 +2317,7 @@ NumberedRows AS (
2194
2317
  if (result.entityIcon && result.entityIcon.trim().length > 0) {
2195
2318
  // Check if entity already has an icon
2196
2319
  const checkEntitySQL = `
2197
- SELECT Icon FROM [${(0, config_1.mj_core_schema)()}].Entity
2320
+ SELECT Icon FROM [${mj_core_schema()}].Entity
2198
2321
  WHERE ID = '${entityId}'
2199
2322
  `;
2200
2323
  const entityCheck = await pool.request().query(checkEntitySQL);
@@ -2204,13 +2327,13 @@ NumberedRows AS (
2204
2327
  if (!currentIcon || currentIcon.trim().length === 0) {
2205
2328
  const escapedIcon = result.entityIcon.replace(/'/g, "''");
2206
2329
  const updateEntitySQL = `
2207
- UPDATE [${(0, config_1.mj_core_schema)()}].Entity
2330
+ UPDATE [${mj_core_schema()}].Entity
2208
2331
  SET Icon = '${escapedIcon}',
2209
2332
  __mj_UpdatedAt = GETUTCDATE()
2210
2333
  WHERE ID = '${entityId}'
2211
2334
  `;
2212
2335
  await this.LogSQLAndExecute(pool, updateEntitySQL, `Set entity icon to ${result.entityIcon}`, false);
2213
- (0, status_logging_1.logStatus)(` ✓ Set entity icon: ${result.entityIcon}`);
2336
+ logStatus(` ✓ Set entity icon: ${result.entityIcon}`);
2214
2337
  }
2215
2338
  }
2216
2339
  }
@@ -2224,14 +2347,14 @@ NumberedRows AS (
2224
2347
  const infoJSON = JSON.stringify(categoryInfoToStore).replace(/'/g, "''");
2225
2348
  // First check if new format setting already exists
2226
2349
  const checkNewSQL = `
2227
- SELECT ID FROM [${(0, config_1.mj_core_schema)()}].EntitySetting
2350
+ SELECT ID FROM [${mj_core_schema()}].EntitySetting
2228
2351
  WHERE EntityID = '${entityId}' AND Name = 'FieldCategoryInfo'
2229
2352
  `;
2230
2353
  const existingNew = await pool.request().query(checkNewSQL);
2231
2354
  if (existingNew.recordset.length > 0) {
2232
2355
  // Update existing setting
2233
2356
  const updateSQL = `
2234
- UPDATE [${(0, config_1.mj_core_schema)()}].EntitySetting
2357
+ UPDATE [${mj_core_schema()}].EntitySetting
2235
2358
  SET Value = '${infoJSON}',
2236
2359
  __mj_UpdatedAt = GETUTCDATE()
2237
2360
  WHERE EntityID = '${entityId}' AND Name = 'FieldCategoryInfo'
@@ -2240,9 +2363,9 @@ NumberedRows AS (
2240
2363
  }
2241
2364
  else {
2242
2365
  // Insert new setting
2243
- const newId = (0, uuid_1.v4)();
2366
+ const newId = uuidv4();
2244
2367
  const insertSQL = `
2245
- INSERT INTO [${(0, config_1.mj_core_schema)()}].EntitySetting (ID, EntityID, Name, Value, __mj_CreatedAt, __mj_UpdatedAt)
2368
+ INSERT INTO [${mj_core_schema()}].EntitySetting (ID, EntityID, Name, Value, __mj_CreatedAt, __mj_UpdatedAt)
2246
2369
  VALUES ('${newId}', '${entityId}', 'FieldCategoryInfo', '${infoJSON}', GETUTCDATE(), GETUTCDATE())
2247
2370
  `;
2248
2371
  await this.LogSQLAndExecute(pool, insertSQL, `Insert FieldCategoryInfo setting for entity`, false);
@@ -2257,13 +2380,13 @@ NumberedRows AS (
2257
2380
  }
2258
2381
  const iconsJSON = JSON.stringify(iconsOnly).replace(/'/g, "''");
2259
2382
  const checkLegacySQL = `
2260
- SELECT ID FROM [${(0, config_1.mj_core_schema)()}].EntitySetting
2383
+ SELECT ID FROM [${mj_core_schema()}].EntitySetting
2261
2384
  WHERE EntityID = '${entityId}' AND Name = 'FieldCategoryIcons'
2262
2385
  `;
2263
2386
  const existingLegacy = await pool.request().query(checkLegacySQL);
2264
2387
  if (existingLegacy.recordset.length > 0) {
2265
2388
  const updateSQL = `
2266
- UPDATE [${(0, config_1.mj_core_schema)()}].EntitySetting
2389
+ UPDATE [${mj_core_schema()}].EntitySetting
2267
2390
  SET Value = '${iconsJSON}',
2268
2391
  __mj_UpdatedAt = GETUTCDATE()
2269
2392
  WHERE EntityID = '${entityId}' AND Name = 'FieldCategoryIcons'
@@ -2271,9 +2394,9 @@ NumberedRows AS (
2271
2394
  await this.LogSQLAndExecute(pool, updateSQL, `Update FieldCategoryIcons setting for entity (legacy format)`, false);
2272
2395
  }
2273
2396
  else {
2274
- const newId = (0, uuid_1.v4)();
2397
+ const newId = uuidv4();
2275
2398
  const insertSQL = `
2276
- INSERT INTO [${(0, config_1.mj_core_schema)()}].EntitySetting (ID, EntityID, Name, Value, __mj_CreatedAt, __mj_UpdatedAt)
2399
+ INSERT INTO [${mj_core_schema()}].EntitySetting (ID, EntityID, Name, Value, __mj_CreatedAt, __mj_UpdatedAt)
2277
2400
  VALUES ('${newId}', '${entityId}', 'FieldCategoryIcons', '${iconsJSON}', GETUTCDATE(), GETUTCDATE())
2278
2401
  `;
2279
2402
  await this.LogSQLAndExecute(pool, insertSQL, `Insert FieldCategoryIcons setting for entity (legacy format)`, false);
@@ -2285,14 +2408,14 @@ NumberedRows AS (
2285
2408
  const defaultForNewUser = result.entityImportance.defaultForNewUser ? 1 : 0;
2286
2409
  // Update all ApplicationEntity records for this entity
2287
2410
  const updateAppEntitySQL = `
2288
- UPDATE [${(0, config_1.mj_core_schema)()}].ApplicationEntity
2411
+ UPDATE [${mj_core_schema()}].ApplicationEntity
2289
2412
  SET DefaultForNewUser = ${defaultForNewUser},
2290
2413
  __mj_UpdatedAt = GETUTCDATE()
2291
2414
  WHERE EntityID = '${entityId}'
2292
2415
  `;
2293
2416
  await this.LogSQLAndExecute(pool, updateAppEntitySQL, `Set DefaultForNewUser=${defaultForNewUser} for NEW entity based on AI analysis (category: ${result.entityImportance.entityCategory}, confidence: ${result.entityImportance.confidence})`, false);
2294
- (0, status_logging_1.logStatus)(` ✓ Entity importance (NEW Entity): ${result.entityImportance.entityCategory} (defaultForNewUser: ${result.entityImportance.defaultForNewUser}, confidence: ${result.entityImportance.confidence})`);
2295
- (0, status_logging_1.logStatus)(` Reasoning: ${result.entityImportance.reasoning}`);
2417
+ logStatus(` ✓ Entity importance (NEW Entity): ${result.entityImportance.entityCategory} (defaultForNewUser: ${result.entityImportance.defaultForNewUser}, confidence: ${result.entityImportance.confidence})`);
2418
+ logStatus(` Reasoning: ${result.entityImportance.reasoning}`);
2296
2419
  }
2297
2420
  }
2298
2421
  /**
@@ -2306,8 +2429,7 @@ NumberedRows AS (
2306
2429
  * @returns - The result of the query execution.
2307
2430
  */
2308
2431
  async LogSQLAndExecute(pool, query, description, isRecurringScript = false) {
2309
- return await sql_logging_1.SQLLogging.LogSQLAndExecute(pool, query, description, isRecurringScript);
2432
+ return await SQLLogging.LogSQLAndExecute(pool, query, description, isRecurringScript);
2310
2433
  }
2311
2434
  }
2312
- exports.ManageMetadataBase = ManageMetadataBase;
2313
2435
  //# sourceMappingURL=manage-metadata.js.map