@memberjunction/codegen-lib 2.111.0 → 2.112.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.
- package/dist/Angular/angular-codegen.d.ts +1 -1
- package/dist/Angular/angular-codegen.d.ts.map +1 -1
- package/dist/Angular/angular-codegen.js +119 -80
- package/dist/Angular/angular-codegen.js.map +1 -1
- package/dist/Angular/join-grid-related-entity-component.d.ts +1 -1
- package/dist/Angular/join-grid-related-entity-component.d.ts.map +1 -1
- package/dist/Angular/join-grid-related-entity-component.js +12 -12
- package/dist/Angular/join-grid-related-entity-component.js.map +1 -1
- package/dist/Angular/related-entity-components.d.ts +1 -1
- package/dist/Angular/related-entity-components.d.ts.map +1 -1
- package/dist/Angular/related-entity-components.js +14 -14
- package/dist/Angular/related-entity-components.js.map +1 -1
- package/dist/Config/config.d.ts.map +1 -1
- package/dist/Config/config.js +3 -3
- package/dist/Config/config.js.map +1 -1
- package/dist/Database/dbSchema.d.ts +1 -1
- package/dist/Database/dbSchema.d.ts.map +1 -1
- package/dist/Database/dbSchema.js +14 -10
- package/dist/Database/dbSchema.js.map +1 -1
- package/dist/Database/manage-metadata.d.ts +3 -3
- package/dist/Database/manage-metadata.d.ts.map +1 -1
- package/dist/Database/manage-metadata.js +167 -139
- package/dist/Database/manage-metadata.js.map +1 -1
- package/dist/Database/sql.d.ts +1 -1
- package/dist/Database/sql.d.ts.map +1 -1
- package/dist/Database/sql.js +17 -17
- package/dist/Database/sql.js.map +1 -1
- package/dist/Database/sql_codegen.d.ts +2 -2
- package/dist/Database/sql_codegen.d.ts.map +1 -1
- package/dist/Database/sql_codegen.js +128 -119
- package/dist/Database/sql_codegen.js.map +1 -1
- package/dist/Misc/action_subclasses_codegen.d.ts.map +1 -1
- package/dist/Misc/action_subclasses_codegen.js +17 -17
- package/dist/Misc/action_subclasses_codegen.js.map +1 -1
- package/dist/Misc/advanced_generation.d.ts +2 -2
- package/dist/Misc/advanced_generation.d.ts.map +1 -1
- package/dist/Misc/advanced_generation.js +29 -29
- package/dist/Misc/advanced_generation.js.map +1 -1
- package/dist/Misc/createNewUser.d.ts +1 -1
- package/dist/Misc/createNewUser.d.ts.map +1 -1
- package/dist/Misc/createNewUser.js +30 -30
- package/dist/Misc/createNewUser.js.map +1 -1
- package/dist/Misc/entity_subclasses_codegen.d.ts +1 -1
- package/dist/Misc/entity_subclasses_codegen.d.ts.map +1 -1
- package/dist/Misc/entity_subclasses_codegen.js +56 -37
- package/dist/Misc/entity_subclasses_codegen.js.map +1 -1
- package/dist/Misc/graphql_server_codegen.d.ts +1 -1
- package/dist/Misc/graphql_server_codegen.d.ts.map +1 -1
- package/dist/Misc/graphql_server_codegen.js +15 -17
- package/dist/Misc/graphql_server_codegen.js.map +1 -1
- package/dist/Misc/status_logging.d.ts +2 -2
- package/dist/Misc/status_logging.d.ts.map +1 -1
- package/dist/Misc/status_logging.js +22 -22
- package/dist/Misc/status_logging.js.map +1 -1
- package/dist/runCodeGen.d.ts.map +1 -1
- package/dist/runCodeGen.js +4 -4
- package/dist/runCodeGen.js.map +1 -1
- package/package.json +9 -10
|
@@ -29,31 +29,31 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
29
29
|
exports.ManageMetadataBase = exports.ValidatorResult = void 0;
|
|
30
30
|
const sql = __importStar(require("mssql"));
|
|
31
31
|
const config_1 = require("../Config/config");
|
|
32
|
-
const
|
|
32
|
+
const global_1 = require("@memberjunction/global");
|
|
33
33
|
const status_logging_1 = require("../Misc/status_logging");
|
|
34
34
|
const sql_1 = require("./sql");
|
|
35
35
|
const advanced_generation_1 = require("../Misc/advanced_generation");
|
|
36
|
-
const
|
|
36
|
+
const global_2 = require("@memberjunction/global");
|
|
37
37
|
const uuid_1 = require("uuid");
|
|
38
38
|
const fs = __importStar(require("fs"));
|
|
39
39
|
const path_1 = __importDefault(require("path"));
|
|
40
40
|
const sql_logging_1 = require("../Misc/sql_logging");
|
|
41
41
|
const aiengine_1 = require("@memberjunction/aiengine");
|
|
42
42
|
class ValidatorResult {
|
|
43
|
-
entityName =
|
|
43
|
+
entityName = '';
|
|
44
44
|
fieldName;
|
|
45
|
-
sourceCheckConstraint =
|
|
46
|
-
functionText =
|
|
47
|
-
functionName =
|
|
48
|
-
functionDescription =
|
|
45
|
+
sourceCheckConstraint = '';
|
|
46
|
+
functionText = '';
|
|
47
|
+
functionName = '';
|
|
48
|
+
functionDescription = '';
|
|
49
49
|
/**
|
|
50
50
|
* The ID value in the Generated Codes entity that was created for this validator.
|
|
51
51
|
*/
|
|
52
|
-
generatedCodeId =
|
|
52
|
+
generatedCodeId = '';
|
|
53
53
|
/**
|
|
54
54
|
* The ID for the AI Model that was used to generate the code
|
|
55
55
|
*/
|
|
56
|
-
aiModelID =
|
|
56
|
+
aiModelID = '';
|
|
57
57
|
wasGenerated = true;
|
|
58
58
|
success = false;
|
|
59
59
|
}
|
|
@@ -63,7 +63,7 @@ exports.ValidatorResult = ValidatorResult;
|
|
|
63
63
|
* to properly register your subclass with a priority of 1+ to ensure it gets instantiated.
|
|
64
64
|
*/
|
|
65
65
|
class ManageMetadataBase {
|
|
66
|
-
_sqlUtilityObject =
|
|
66
|
+
_sqlUtilityObject = global_2.MJGlobal.Instance.ClassFactory.CreateInstance(sql_1.SQLUtilityBase);
|
|
67
67
|
get SQLUtilityObject() {
|
|
68
68
|
return this._sqlUtilityObject;
|
|
69
69
|
}
|
|
@@ -94,53 +94,51 @@ class ManageMetadataBase {
|
|
|
94
94
|
* @returns
|
|
95
95
|
*/
|
|
96
96
|
async manageMetadata(pool, currentUser) {
|
|
97
|
-
const md = new
|
|
97
|
+
const md = new global_1.Metadata();
|
|
98
98
|
const excludeSchemas = config_1.configInfo.excludeSchemas ? config_1.configInfo.excludeSchemas : [];
|
|
99
99
|
let bSuccess = true;
|
|
100
100
|
let start = new Date();
|
|
101
101
|
(0, status_logging_1.logStatus)(' Creating new entities...');
|
|
102
|
-
if (!await this.createNewEntities(pool)) {
|
|
102
|
+
if (!(await this.createNewEntities(pool))) {
|
|
103
103
|
(0, status_logging_1.logError)(' Error creating new entities');
|
|
104
104
|
bSuccess = false;
|
|
105
105
|
}
|
|
106
106
|
(0, status_logging_1.logStatus)(` > Created new entities in ${(new Date().getTime() - start.getTime()) / 1000} seconds`);
|
|
107
107
|
start = new Date();
|
|
108
108
|
(0, status_logging_1.logStatus)(' Updating existing entities...');
|
|
109
|
-
if (!await this.updateExistingEntitiesFromSchema(pool, excludeSchemas)) {
|
|
109
|
+
if (!(await this.updateExistingEntitiesFromSchema(pool, excludeSchemas))) {
|
|
110
110
|
(0, status_logging_1.logError)(' Error updating existing entities');
|
|
111
111
|
bSuccess = false;
|
|
112
112
|
}
|
|
113
113
|
(0, status_logging_1.logStatus)(` > Updated existing entities in ${(new Date().getTime() - start.getTime()) / 1000} seconds`);
|
|
114
114
|
start = new Date();
|
|
115
115
|
(0, status_logging_1.logStatus)(' Scanning for tables that were deleted where entity metadata still exists...');
|
|
116
|
-
if (!await this.checkAndRemoveMetadataForDeletedTables(pool, excludeSchemas)) {
|
|
116
|
+
if (!(await this.checkAndRemoveMetadataForDeletedTables(pool, excludeSchemas))) {
|
|
117
117
|
(0, status_logging_1.logError)(' Error removing metadata for tables that were removed');
|
|
118
118
|
bSuccess = false;
|
|
119
119
|
}
|
|
120
120
|
(0, status_logging_1.logStatus)(` > Removed metadata for deleted tables in ${(new Date().getTime() - start.getTime()) / 1000} seconds`);
|
|
121
121
|
start = new Date();
|
|
122
122
|
(0, status_logging_1.logStatus)(' Recompiling base views...');
|
|
123
|
-
const sqlUtility =
|
|
123
|
+
const sqlUtility = global_2.MJGlobal.Instance.ClassFactory.CreateInstance(sql_1.SQLUtilityBase);
|
|
124
124
|
const adminSchema = (0, config_1.getSettingValue)('mj_core_schema', '__mj');
|
|
125
|
-
const schemasToExclude = (0, config_1.getSettingValue)('recompile_mj_views', true)
|
|
126
|
-
|
|
127
|
-
:
|
|
128
|
-
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*/)) {
|
|
129
|
-
(0, status_logging_1.logMessage)(' Warning: Non-Fatal error recompiling base views', core_1.SeverityType.Warning, false);
|
|
125
|
+
const schemasToExclude = (0, config_1.getSettingValue)('recompile_mj_views', true) ? excludeSchemas.filter((s) => s !== adminSchema) : excludeSchemas;
|
|
126
|
+
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*/))) {
|
|
127
|
+
(0, status_logging_1.logMessage)(' Warning: Non-Fatal error recompiling base views', global_1.SeverityType.Warning, false);
|
|
130
128
|
// many times the former versions of base views will NOT succesfully recompile, so don't consider that scenario to be a
|
|
131
129
|
// failure for this entire function
|
|
132
130
|
}
|
|
133
131
|
(0, status_logging_1.logStatus)(` > Recompiled base views in ${(new Date().getTime() - start.getTime()) / 1000} seconds`);
|
|
134
132
|
start = new Date();
|
|
135
133
|
(0, status_logging_1.logStatus)(' Managing entity fields...');
|
|
136
|
-
if (!await this.manageEntityFields(pool, excludeSchemas, false, false, currentUser)) {
|
|
134
|
+
if (!(await this.manageEntityFields(pool, excludeSchemas, false, false, currentUser))) {
|
|
137
135
|
(0, status_logging_1.logError)(' Error managing entity fields');
|
|
138
136
|
bSuccess = false;
|
|
139
137
|
}
|
|
140
138
|
(0, status_logging_1.logStatus)(` > Managed entity fields in ${(new Date().getTime() - start.getTime()) / 1000} seconds`);
|
|
141
139
|
start = new Date();
|
|
142
140
|
(0, status_logging_1.logStatus)(' Managing entity relationships...');
|
|
143
|
-
if (!await this.manageEntityRelationships(pool, excludeSchemas, md)) {
|
|
141
|
+
if (!(await this.manageEntityRelationships(pool, excludeSchemas, md))) {
|
|
144
142
|
(0, status_logging_1.logError)(' Error managing entity relationships');
|
|
145
143
|
bSuccess = false;
|
|
146
144
|
}
|
|
@@ -201,23 +199,23 @@ class ManageMetadataBase {
|
|
|
201
199
|
if (veFields && veFields.length > 0) {
|
|
202
200
|
// we have 1+ fields, now loop through them and process each one
|
|
203
201
|
// first though, remove any fields that are no longer in the view
|
|
204
|
-
const md = new
|
|
202
|
+
const md = new global_1.Metadata();
|
|
205
203
|
const entity = md.EntityByName(virtualEntity.Name);
|
|
206
204
|
if (entity) {
|
|
207
205
|
const removeList = [];
|
|
208
|
-
const fieldsToRemove = entity.Fields.filter(f => !veFields.find((vf) => vf.FieldName === f.Name));
|
|
206
|
+
const fieldsToRemove = entity.Fields.filter((f) => !veFields.find((vf) => vf.FieldName === f.Name));
|
|
209
207
|
for (const f of fieldsToRemove) {
|
|
210
208
|
removeList.push(f.ID);
|
|
211
209
|
}
|
|
212
210
|
if (removeList.length > 0) {
|
|
213
|
-
const sqlRemove = `DELETE FROM [${(0, config_1.mj_core_schema)()}].EntityField WHERE ID IN (${removeList.map(removeId => `'${removeId}'`).join(',')})`;
|
|
211
|
+
const sqlRemove = `DELETE FROM [${(0, config_1.mj_core_schema)()}].EntityField WHERE ID IN (${removeList.map((removeId) => `'${removeId}'`).join(',')})`;
|
|
214
212
|
// this removes the fields that shouldn't be there anymore
|
|
215
213
|
await this.LogSQLAndExecute(pool, sqlRemove, `SQL text to remove fields from entity ${virtualEntity.Name}`);
|
|
216
214
|
bUpdated = true;
|
|
217
215
|
}
|
|
218
216
|
// check to see if any of the fields in the virtual entity have Pkey attribute set. If not, we will default to the first field
|
|
219
217
|
// as pkey and user can change this.
|
|
220
|
-
const hasPkey = entity.Fields.find(f => f.IsPrimaryKey) !== undefined;
|
|
218
|
+
const hasPkey = entity.Fields.find((f) => f.IsPrimaryKey) !== undefined;
|
|
221
219
|
// now create/update the fields that are in the view
|
|
222
220
|
for (let i = 0; i < veFields.length; i++) {
|
|
223
221
|
const vef = veFields[i];
|
|
@@ -232,7 +230,7 @@ class ManageMetadataBase {
|
|
|
232
230
|
}
|
|
233
231
|
if (bUpdated) {
|
|
234
232
|
// finally make sure we update the UpdatedAt field for the entity if we made changes to its fields
|
|
235
|
-
const sqlUpdate = `UPDATE [${(0, config_1.mj_core_schema)()}].Entity SET [${
|
|
233
|
+
const sqlUpdate = `UPDATE [${(0, config_1.mj_core_schema)()}].Entity SET [${global_1.EntityInfo.UpdatedAtFieldName}]=GETUTCDATE() WHERE ID='${virtualEntity.ID}'`;
|
|
236
234
|
await this.LogSQLAndExecute(pool, sqlUpdate, `SQL text to update virtual entity updated date for ${virtualEntity.Name}`);
|
|
237
235
|
}
|
|
238
236
|
return { success: bSuccess, updatedEntity: bUpdated };
|
|
@@ -246,12 +244,12 @@ class ManageMetadataBase {
|
|
|
246
244
|
// this protected checks to see if the field exists in the entity definition, and if not, adds it
|
|
247
245
|
// if it exist it updates the entity field to match the view's data type and nullability attributes
|
|
248
246
|
// first, get the entity definition
|
|
249
|
-
const md = new
|
|
247
|
+
const md = new global_1.Metadata();
|
|
250
248
|
const entity = md.EntityByName(virtualEntity.Name);
|
|
251
249
|
let newEntityFieldUUID = null;
|
|
252
250
|
let didUpdate = false;
|
|
253
251
|
if (entity) {
|
|
254
|
-
const field = entity.Fields.find(f => f.Name.trim().toLowerCase() === veField.FieldName.trim().toLowerCase());
|
|
252
|
+
const field = entity.Fields.find((f) => f.Name.trim().toLowerCase() === veField.FieldName.trim().toLowerCase());
|
|
255
253
|
if (field) {
|
|
256
254
|
// have a match, so the field exists in the entity definition, now check to see if it needs to be updated
|
|
257
255
|
if (makePrimaryKey ||
|
|
@@ -304,8 +302,8 @@ class ManageMetadataBase {
|
|
|
304
302
|
*/
|
|
305
303
|
async manageEntityRelationships(pool, excludeSchemas, md, batchItems = 5) {
|
|
306
304
|
let bResult = true;
|
|
307
|
-
bResult = bResult && await this.manageManyToManyEntityRelationships(pool, excludeSchemas, batchItems);
|
|
308
|
-
bResult = bResult && await this.manageOneToManyEntityRelationships(pool, excludeSchemas, md, batchItems);
|
|
305
|
+
bResult = bResult && (await this.manageManyToManyEntityRelationships(pool, excludeSchemas, batchItems));
|
|
306
|
+
bResult = bResult && (await this.manageOneToManyEntityRelationships(pool, excludeSchemas, md, batchItems));
|
|
309
307
|
return bResult;
|
|
310
308
|
}
|
|
311
309
|
/**
|
|
@@ -335,7 +333,7 @@ class ManageMetadataBase {
|
|
|
335
333
|
WHERE
|
|
336
334
|
RelatedEntityID IS NOT NULL AND
|
|
337
335
|
IsVirtual = 0 AND
|
|
338
|
-
EntityID NOT IN (SELECT ID FROM ${(0, config_1.mj_core_schema)()}.Entity WHERE SchemaName IN (${excludeSchemas.map(s => `'${s}'`).join(',')}))
|
|
336
|
+
EntityID NOT IN (SELECT ID FROM ${(0, config_1.mj_core_schema)()}.Entity WHERE SchemaName IN (${excludeSchemas.map((s) => `'${s}'`).join(',')}))
|
|
339
337
|
ORDER BY RelatedEntityID`;
|
|
340
338
|
const entityFieldsResult = await pool.request().query(sSQL);
|
|
341
339
|
const entityFields = entityFieldsResult.recordset;
|
|
@@ -359,7 +357,7 @@ class ManageMetadataBase {
|
|
|
359
357
|
const relationships = allRelationships.filter((r) => r.EntityID === f.RelatedEntityID && r.RelatedEntityID === f.EntityID);
|
|
360
358
|
if (relationships && relationships.length === 0) {
|
|
361
359
|
// no relationship exists, so create it
|
|
362
|
-
const e = md.Entities.find(e => e.ID === f.EntityID);
|
|
360
|
+
const e = md.Entities.find((e) => e.ID === f.EntityID);
|
|
363
361
|
// calculate the sequence by getting the count of existing relationships for the entity and adding 1 and then increment the count for future inserts in this loop
|
|
364
362
|
const relCount = relationshipCountMap.get(f.EntityID) || 0;
|
|
365
363
|
const sequence = relCount + 1;
|
|
@@ -428,7 +426,7 @@ class ManageMetadataBase {
|
|
|
428
426
|
}
|
|
429
427
|
}
|
|
430
428
|
// if we get here we now need to refresh our metadata object
|
|
431
|
-
const md = new
|
|
429
|
+
const md = new global_1.Metadata();
|
|
432
430
|
await md.Refresh();
|
|
433
431
|
}
|
|
434
432
|
return true;
|
|
@@ -488,15 +486,15 @@ class ManageMetadataBase {
|
|
|
488
486
|
let bSuccess = true;
|
|
489
487
|
const startTime = new Date();
|
|
490
488
|
if (!skipCreatedAtUpdatedAtDeletedAtFieldValidation) {
|
|
491
|
-
if (!await this.ensureCreatedAtUpdatedAtFieldsExist(pool, excludeSchemas) ||
|
|
492
|
-
!await this.ensureDeletedAtFieldsExist(pool, excludeSchemas)) {
|
|
493
|
-
(0, status_logging_1.logError)(`Error ensuring ${
|
|
489
|
+
if (!(await this.ensureCreatedAtUpdatedAtFieldsExist(pool, excludeSchemas)) ||
|
|
490
|
+
!(await this.ensureDeletedAtFieldsExist(pool, excludeSchemas))) {
|
|
491
|
+
(0, status_logging_1.logError)(`Error ensuring ${global_1.EntityInfo.CreatedAtFieldName}, ${global_1.EntityInfo.UpdatedAtFieldName} and ${global_1.EntityInfo.DeletedAtFieldName} fields exist`);
|
|
494
492
|
bSuccess = false;
|
|
495
493
|
}
|
|
496
|
-
(0, status_logging_1.logStatus)(` Ensured ${
|
|
494
|
+
(0, status_logging_1.logStatus)(` Ensured ${global_1.EntityInfo.CreatedAtFieldName}/${global_1.EntityInfo.UpdatedAtFieldName}/${global_1.EntityInfo.DeletedAtFieldName} fields exist in ${(new Date().getTime() - startTime.getTime()) / 1000} seconds`);
|
|
497
495
|
}
|
|
498
496
|
const step1StartTime = new Date();
|
|
499
|
-
if (!await this.deleteUnneededEntityFields(pool, excludeSchemas)) {
|
|
497
|
+
if (!(await this.deleteUnneededEntityFields(pool, excludeSchemas))) {
|
|
500
498
|
(0, status_logging_1.logError)('Error deleting unneeded entity fields');
|
|
501
499
|
bSuccess = false;
|
|
502
500
|
}
|
|
@@ -504,7 +502,8 @@ class ManageMetadataBase {
|
|
|
504
502
|
// AN: 14-June-2025 - See note below about the new order of these steps, this must
|
|
505
503
|
// happen before we update existing entity fields from schema.
|
|
506
504
|
const step2StartTime = new Date();
|
|
507
|
-
if (!await this.createNewEntityFieldsFromSchema(pool)) {
|
|
505
|
+
if (!(await this.createNewEntityFieldsFromSchema(pool))) {
|
|
506
|
+
// has its own internal filtering for exclude schema/table so don't pass in
|
|
508
507
|
(0, status_logging_1.logError)('Error creating new entity fields from schema');
|
|
509
508
|
bSuccess = false;
|
|
510
509
|
}
|
|
@@ -514,19 +513,19 @@ class ManageMetadataBase {
|
|
|
514
513
|
// with VERY HIGH sequence numbers (e.g. 100,000 above what they will be approx) and then
|
|
515
514
|
// we align them properly in sequential order from 1+ via this method below.
|
|
516
515
|
const step3StartTime = new Date();
|
|
517
|
-
if (!await this.updateExistingEntityFieldsFromSchema(pool, excludeSchemas)) {
|
|
516
|
+
if (!(await this.updateExistingEntityFieldsFromSchema(pool, excludeSchemas))) {
|
|
518
517
|
(0, status_logging_1.logError)('Error updating existing entity fields from schema');
|
|
519
518
|
bSuccess = false;
|
|
520
519
|
}
|
|
521
520
|
(0, status_logging_1.logStatus)(` Updated existing entity fields from schema in ${(new Date().getTime() - step3StartTime.getTime()) / 1000} seconds`);
|
|
522
521
|
const step4StartTime = new Date();
|
|
523
|
-
if (!await this.setDefaultColumnWidthWhereNeeded(pool, excludeSchemas)) {
|
|
522
|
+
if (!(await this.setDefaultColumnWidthWhereNeeded(pool, excludeSchemas))) {
|
|
524
523
|
(0, status_logging_1.logError)('Error setting default column width where needed');
|
|
525
524
|
bSuccess = false;
|
|
526
525
|
}
|
|
527
526
|
(0, status_logging_1.logStatus)(` Set default column width where needed in ${(new Date().getTime() - step4StartTime.getTime()) / 1000} seconds`);
|
|
528
527
|
const step5StartTime = new Date();
|
|
529
|
-
if (!await this.updateEntityFieldDisplayNameWhereNull(pool, excludeSchemas)) {
|
|
528
|
+
if (!(await this.updateEntityFieldDisplayNameWhereNull(pool, excludeSchemas))) {
|
|
530
529
|
(0, status_logging_1.logError)('Error updating entity field display name where null');
|
|
531
530
|
bSuccess = false;
|
|
532
531
|
}
|
|
@@ -534,7 +533,7 @@ class ManageMetadataBase {
|
|
|
534
533
|
if (!skipEntityFieldValues) {
|
|
535
534
|
const step6StartTime = new Date();
|
|
536
535
|
(0, status_logging_1.logStatus)(` Starting to manage entity field values...`);
|
|
537
|
-
if (!await this.manageEntityFieldValuesAndValidatorFunctions(pool, excludeSchemas, currentUser, false)) {
|
|
536
|
+
if (!(await this.manageEntityFieldValuesAndValidatorFunctions(pool, excludeSchemas, currentUser, false))) {
|
|
538
537
|
(0, status_logging_1.logError)('Error managing entity field values');
|
|
539
538
|
bSuccess = false;
|
|
540
539
|
}
|
|
@@ -555,7 +554,7 @@ class ManageMetadataBase {
|
|
|
555
554
|
WHERE
|
|
556
555
|
VirtualEntity=0 AND
|
|
557
556
|
DeleteType='Soft' AND
|
|
558
|
-
SchemaName NOT IN (${excludeSchemas.map(s => `'${s}'`).join(',')})`;
|
|
557
|
+
SchemaName NOT IN (${excludeSchemas.map((s) => `'${s}'`).join(',')})`;
|
|
559
558
|
const entitiesResult = await pool.request().query(sqlEntities);
|
|
560
559
|
const entities = entitiesResult.recordset;
|
|
561
560
|
let overallResult = true;
|
|
@@ -566,14 +565,14 @@ class ManageMetadataBase {
|
|
|
566
565
|
FROM INFORMATION_SCHEMA.COLUMNS
|
|
567
566
|
WHERE
|
|
568
567
|
${entities.map((e) => `(TABLE_SCHEMA='${e.SchemaName}' AND TABLE_NAME='${e.BaseTable}')`).join(' OR ')}
|
|
569
|
-
AND COLUMN_NAME='${
|
|
568
|
+
AND COLUMN_NAME='${global_1.EntityInfo.DeletedAtFieldName}'`;
|
|
570
569
|
const resultResult = await pool.request().query(sql);
|
|
571
570
|
const result = resultResult.recordset;
|
|
572
571
|
for (const e of entities) {
|
|
573
572
|
const eResult = result.filter((r) => r.TABLE_NAME === e.BaseTable && r.TABLE_SCHEMA === e.SchemaName); // get just the fields for this entity
|
|
574
|
-
const deletedAt = eResult.find((r) => r.COLUMN_NAME.trim().toLowerCase() ===
|
|
573
|
+
const deletedAt = eResult.find((r) => r.COLUMN_NAME.trim().toLowerCase() === global_1.EntityInfo.DeletedAtFieldName.trim().toLowerCase());
|
|
575
574
|
// now, if we have the fields, we need to check the default value and update if necessary
|
|
576
|
-
const fieldResult = await this.ensureSpecialDateFieldExistsAndHasCorrectDefaultValue(pool, e,
|
|
575
|
+
const fieldResult = await this.ensureSpecialDateFieldExistsAndHasCorrectDefaultValue(pool, e, global_1.EntityInfo.DeletedAtFieldName, deletedAt, true);
|
|
577
576
|
overallResult = overallResult && fieldResult;
|
|
578
577
|
}
|
|
579
578
|
}
|
|
@@ -599,7 +598,7 @@ class ManageMetadataBase {
|
|
|
599
598
|
WHERE
|
|
600
599
|
VirtualEntity = 0 AND
|
|
601
600
|
TrackRecordChanges = 1 AND
|
|
602
|
-
SchemaName NOT IN (${excludeSchemas.map(s => `'${s}'`).join(',')})`;
|
|
601
|
+
SchemaName NOT IN (${excludeSchemas.map((s) => `'${s}'`).join(',')})`;
|
|
603
602
|
const entitiesResult = await pool.request().query(sqlEntities);
|
|
604
603
|
const entities = entitiesResult.recordset;
|
|
605
604
|
let overallResult = true;
|
|
@@ -611,17 +610,17 @@ class ManageMetadataBase {
|
|
|
611
610
|
FROM INFORMATION_SCHEMA.COLUMNS
|
|
612
611
|
WHERE
|
|
613
612
|
${entities.map((e) => `(TABLE_SCHEMA='${e.SchemaName}' AND TABLE_NAME='${e.BaseTable}')`).join(' OR ')}
|
|
614
|
-
AND COLUMN_NAME IN ('${
|
|
613
|
+
AND COLUMN_NAME IN ('${global_1.EntityInfo.CreatedAtFieldName}','${global_1.EntityInfo.UpdatedAtFieldName}')`;
|
|
615
614
|
const resultResult = await pool.request().query(sqlCreatedUpdated);
|
|
616
615
|
const result = resultResult.recordset;
|
|
617
616
|
for (const e of entities) {
|
|
618
617
|
// 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
|
|
619
618
|
const eResult = result.filter((r) => r.TABLE_NAME === e.BaseTable && r.TABLE_SCHEMA === e.SchemaName); // get just the fields for this entity
|
|
620
|
-
const createdAt = eResult.find((r) => r.COLUMN_NAME.trim().toLowerCase() ===
|
|
621
|
-
const updatedAt = eResult.find((r) => r.COLUMN_NAME.trim().toLowerCase() ===
|
|
619
|
+
const createdAt = eResult.find((r) => r.COLUMN_NAME.trim().toLowerCase() === global_1.EntityInfo.CreatedAtFieldName.trim().toLowerCase());
|
|
620
|
+
const updatedAt = eResult.find((r) => r.COLUMN_NAME.trim().toLowerCase() === global_1.EntityInfo.UpdatedAtFieldName.trim().toLowerCase());
|
|
622
621
|
// now, if we have the fields, we need to check the default value and update if necessary
|
|
623
|
-
const fieldResult = await this.ensureSpecialDateFieldExistsAndHasCorrectDefaultValue(pool, e,
|
|
624
|
-
await this.ensureSpecialDateFieldExistsAndHasCorrectDefaultValue(pool, e,
|
|
622
|
+
const fieldResult = (await this.ensureSpecialDateFieldExistsAndHasCorrectDefaultValue(pool, e, global_1.EntityInfo.CreatedAtFieldName, createdAt, false)) &&
|
|
623
|
+
(await this.ensureSpecialDateFieldExistsAndHasCorrectDefaultValue(pool, e, global_1.EntityInfo.UpdatedAtFieldName, updatedAt, false));
|
|
625
624
|
overallResult = overallResult && fieldResult;
|
|
626
625
|
}
|
|
627
626
|
}
|
|
@@ -664,7 +663,7 @@ class ManageMetadataBase {
|
|
|
664
663
|
// field that is NOT NULL
|
|
665
664
|
if (!allowNull) {
|
|
666
665
|
const defaultValue = currentFieldData.COLUMN_DEFAULT;
|
|
667
|
-
const realDefaultValue = (0,
|
|
666
|
+
const realDefaultValue = (0, global_1.ExtractActualDefaultValue)(defaultValue);
|
|
668
667
|
if (!realDefaultValue || realDefaultValue.trim().toLowerCase() !== 'getutcdate()') {
|
|
669
668
|
await this.dropAndCreateDefaultConstraintForSpecialDateField(pool, entity, fieldName);
|
|
670
669
|
}
|
|
@@ -684,7 +683,7 @@ class ManageMetadataBase {
|
|
|
684
683
|
*/
|
|
685
684
|
async createDefaultConstraintForSpecialDateField(pool, entity, fieldName) {
|
|
686
685
|
try {
|
|
687
|
-
const sqlAddDefaultConstraint = `ALTER TABLE [${entity.SchemaName}].[${entity.BaseTable}] ADD CONSTRAINT DF_${entity.SchemaName}_${(0,
|
|
686
|
+
const sqlAddDefaultConstraint = `ALTER TABLE [${entity.SchemaName}].[${entity.BaseTable}] ADD CONSTRAINT DF_${entity.SchemaName}_${(0, global_1.CodeNameFromString)(entity.BaseTable)}_${fieldName} DEFAULT GETUTCDATE() FOR [${fieldName}]`;
|
|
688
687
|
await this.LogSQLAndExecute(pool, sqlAddDefaultConstraint, `SQL text to add default constraint for special date field ${fieldName} in entity ${entity.SchemaName}.${entity.BaseTable}`);
|
|
689
688
|
}
|
|
690
689
|
catch (e) {
|
|
@@ -754,9 +753,12 @@ class ManageMetadataBase {
|
|
|
754
753
|
for (let e of ManageMetadataBase.newEntityList) {
|
|
755
754
|
const dataResult = await pool.request().query(`SELECT * FROM [${(0, config_1.mj_core_schema)()}].vwEntities WHERE Name = '${e}'`);
|
|
756
755
|
const data = dataResult.recordset;
|
|
757
|
-
const fieldsResult = await pool
|
|
756
|
+
const fieldsResult = await pool
|
|
757
|
+
.request()
|
|
758
|
+
.query(`SELECT * FROM [${(0, config_1.mj_core_schema)()}].vwEntityFields WHERE EntityID='${data[0].ID}'`);
|
|
758
759
|
const fields = fieldsResult.recordset;
|
|
759
|
-
const entityUserMessage = userMessage +
|
|
760
|
+
const entityUserMessage = userMessage +
|
|
761
|
+
`Entity Name: ${e},
|
|
760
762
|
Base Table: ${data[0].BaseTable},
|
|
761
763
|
Schema: ${data[0].SchemaName}.
|
|
762
764
|
Fields:
|
|
@@ -766,13 +768,13 @@ class ManageMetadataBase {
|
|
|
766
768
|
messages: [
|
|
767
769
|
{
|
|
768
770
|
role: 'system',
|
|
769
|
-
content: systemPrompt
|
|
771
|
+
content: systemPrompt,
|
|
770
772
|
},
|
|
771
773
|
{
|
|
772
774
|
role: 'user',
|
|
773
|
-
content: entityUserMessage
|
|
774
|
-
}
|
|
775
|
-
]
|
|
775
|
+
content: entityUserMessage,
|
|
776
|
+
},
|
|
777
|
+
],
|
|
776
778
|
});
|
|
777
779
|
if (result?.success) {
|
|
778
780
|
const resultText = result?.data.choices[0].message.content;
|
|
@@ -787,7 +789,10 @@ class ManageMetadataBase {
|
|
|
787
789
|
}
|
|
788
790
|
}
|
|
789
791
|
catch (e) {
|
|
790
|
-
console.warn(' >>> Advanced Generation Error: LLM returned invalid result, skipping entity description for entity ' +
|
|
792
|
+
console.warn(' >>> Advanced Generation Error: LLM returned invalid result, skipping entity description for entity ' +
|
|
793
|
+
e +
|
|
794
|
+
'. Result from LLM: ' +
|
|
795
|
+
resultText, e);
|
|
791
796
|
}
|
|
792
797
|
}
|
|
793
798
|
else {
|
|
@@ -818,15 +823,15 @@ class ManageMetadataBase {
|
|
|
818
823
|
ef.DisplayName IS NULL AND
|
|
819
824
|
ef.DisplayName <> ef.Name AND
|
|
820
825
|
ef.Name <> \'ID\' AND
|
|
821
|
-
e.SchemaName NOT IN (${excludeSchemas.map(s => `'${s}'`).join(',')})
|
|
826
|
+
e.SchemaName NOT IN (${excludeSchemas.map((s) => `'${s}'`).join(',')})
|
|
822
827
|
`;
|
|
823
828
|
const fieldsResult = await pool.request().query(sql);
|
|
824
829
|
const fields = fieldsResult.recordset;
|
|
825
830
|
if (fields && fields.length > 0)
|
|
826
831
|
for (const field of fields) {
|
|
827
|
-
const sDisplayName = (0,
|
|
832
|
+
const sDisplayName = (0, global_2.stripTrailingChars)((0, global_2.convertCamelCaseToHaveSpaces)(field.Name), 'ID', true).trim();
|
|
828
833
|
if (sDisplayName.length > 0 && sDisplayName.toLowerCase().trim() !== field.Name.toLowerCase().trim()) {
|
|
829
|
-
const sSQL = `UPDATE [${(0, config_1.mj_core_schema)()}].EntityField SET ${
|
|
834
|
+
const sSQL = `UPDATE [${(0, config_1.mj_core_schema)()}].EntityField SET ${global_1.EntityInfo.UpdatedAtFieldName}=GETUTCDATE(), DisplayName = '${sDisplayName}' WHERE ID = '${field.ID}'`;
|
|
830
835
|
await this.LogSQLAndExecute(pool, sSQL, `SQL text to update display name for field ${field.Name}`);
|
|
831
836
|
}
|
|
832
837
|
}
|
|
@@ -893,9 +898,9 @@ NumberedRows AS (
|
|
|
893
898
|
sf.AllowsNull,
|
|
894
899
|
sf.DefaultValue,
|
|
895
900
|
sf.AutoIncrement,
|
|
896
|
-
IIF(sf.IsVirtual = 1, 0, IIF(sf.FieldName = '${
|
|
897
|
-
sf.FieldName = '${
|
|
898
|
-
sf.FieldName = '${
|
|
901
|
+
IIF(sf.IsVirtual = 1, 0, IIF(sf.FieldName = '${global_1.EntityInfo.CreatedAtFieldName}' OR
|
|
902
|
+
sf.FieldName = '${global_1.EntityInfo.UpdatedAtFieldName}' OR
|
|
903
|
+
sf.FieldName = '${global_1.EntityInfo.DeletedAtFieldName}' OR
|
|
899
904
|
pk.ColumnName IS NOT NULL, 0, 1)) AllowUpdateAPI,
|
|
900
905
|
sf.IsVirtual,
|
|
901
906
|
e.RelationshipDefaultDisplayType,
|
|
@@ -980,34 +985,39 @@ NumberedRows AS (
|
|
|
980
985
|
* @returns
|
|
981
986
|
*/
|
|
982
987
|
getPendingEntityFieldINSERTSQL(newEntityFieldUUID, n) {
|
|
983
|
-
const bDefaultInView =
|
|
988
|
+
const bDefaultInView = n.FieldName?.trim().toLowerCase() === 'id' ||
|
|
984
989
|
n.FieldName?.trim().toLowerCase() === 'name' ||
|
|
985
990
|
n.Sequence <= config_1.configInfo.newEntityDefaults?.IncludeFirstNFieldsAsDefaultInView ||
|
|
986
|
-
n.IsNameField
|
|
991
|
+
n.IsNameField
|
|
992
|
+
? true
|
|
993
|
+
: false;
|
|
987
994
|
const escapedDescription = n.Description ? `'${n.Description.replace(/'/g, "''")}'` : 'NULL';
|
|
988
995
|
let fieldDisplayName = '';
|
|
989
996
|
switch (n.FieldName.trim().toLowerCase()) {
|
|
990
|
-
case
|
|
991
|
-
fieldDisplayName =
|
|
997
|
+
case global_1.EntityInfo.CreatedAtFieldName.trim().toLowerCase():
|
|
998
|
+
fieldDisplayName = 'Created At';
|
|
992
999
|
break;
|
|
993
|
-
case
|
|
994
|
-
fieldDisplayName =
|
|
1000
|
+
case global_1.EntityInfo.UpdatedAtFieldName.trim().toLowerCase():
|
|
1001
|
+
fieldDisplayName = 'Updated At';
|
|
995
1002
|
break;
|
|
996
|
-
case
|
|
997
|
-
fieldDisplayName =
|
|
1003
|
+
case global_1.EntityInfo.DeletedAtFieldName.trim().toLowerCase():
|
|
1004
|
+
fieldDisplayName = 'Deleted At';
|
|
998
1005
|
break;
|
|
999
1006
|
default:
|
|
1000
|
-
fieldDisplayName = (0,
|
|
1007
|
+
fieldDisplayName = (0, global_2.convertCamelCaseToHaveSpaces)(n.FieldName).trim();
|
|
1001
1008
|
break;
|
|
1002
1009
|
}
|
|
1003
1010
|
const parsedDefaultValue = this.parseDefaultValue(n.DefaultValue);
|
|
1004
|
-
const quotedDefaultValue = parsedDefaultValue?.trim().length === 0
|
|
1005
|
-
|
|
1011
|
+
const quotedDefaultValue = parsedDefaultValue?.trim().length === 0
|
|
1012
|
+
? 'NULL'
|
|
1013
|
+
: parsedDefaultValue?.trim().toLowerCase() === 'null'
|
|
1014
|
+
? 'NULL'
|
|
1015
|
+
: `'${parsedDefaultValue}'`;
|
|
1006
1016
|
// in the above we are setting quotedDefaultValue to NULL if the parsed default value is an empty string or the string 'NULL' (case insensitive)
|
|
1007
1017
|
return `
|
|
1008
1018
|
IF NOT EXISTS (
|
|
1009
|
-
SELECT 1 FROM [${(0, config_1.mj_core_schema)()}].EntityField
|
|
1010
|
-
WHERE ID = '${newEntityFieldUUID}' OR
|
|
1019
|
+
SELECT 1 FROM [${(0, config_1.mj_core_schema)()}].EntityField
|
|
1020
|
+
WHERE ID = '${newEntityFieldUUID}' OR
|
|
1011
1021
|
(EntityID = '${n.EntityID}' AND Name = '${n.FieldName}')
|
|
1012
1022
|
-- check to make sure we're not inserting a duplicate entity field metadata record
|
|
1013
1023
|
)
|
|
@@ -1084,9 +1094,9 @@ NumberedRows AS (
|
|
|
1084
1094
|
sResult = sqlDefaultValue.substring(1, sqlDefaultValue.length - 1);
|
|
1085
1095
|
else
|
|
1086
1096
|
sResult = sqlDefaultValue;
|
|
1087
|
-
if (sResult.toUpperCase().startsWith(
|
|
1097
|
+
if (sResult.toUpperCase().startsWith("N'") && sResult.endsWith("'"))
|
|
1088
1098
|
sResult = sResult.substring(2, sResult.length - 1);
|
|
1089
|
-
if (sResult.startsWith('
|
|
1099
|
+
if (sResult.startsWith("'") && sResult.endsWith("'"))
|
|
1090
1100
|
sResult = sResult.substring(1, sResult.length - 1);
|
|
1091
1101
|
}
|
|
1092
1102
|
return sResult;
|
|
@@ -1220,7 +1230,7 @@ NumberedRows AS (
|
|
|
1220
1230
|
// evaluate it to see if it is a simple series of OR statements or not, if it is a simple series of OR statements, we can parse the possible values
|
|
1221
1231
|
// 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
|
|
1222
1232
|
// just ignore it.
|
|
1223
|
-
const filter = excludeSchemas && excludeSchemas.length > 0 ? ` WHERE SchemaName NOT IN (${excludeSchemas.map(s => `'${s}'`).join(',')})` : '';
|
|
1233
|
+
const filter = excludeSchemas && excludeSchemas.length > 0 ? ` WHERE SchemaName NOT IN (${excludeSchemas.map((s) => `'${s}'`).join(',')})` : '';
|
|
1224
1234
|
const sSQL = `SELECT * FROM [${(0, config_1.mj_core_schema)()}].vwEntityFieldsWithCheckConstraints${filter}`;
|
|
1225
1235
|
const resultResult = await pool.request().query(sSQL);
|
|
1226
1236
|
const result = resultResult.recordset;
|
|
@@ -1265,8 +1275,8 @@ NumberedRows AS (
|
|
|
1265
1275
|
// 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
|
|
1266
1276
|
// attempt to use an LLM to do things fancier now
|
|
1267
1277
|
if (config_1.configInfo.advancedGeneration?.enableAdvancedGeneration &&
|
|
1268
|
-
config_1.configInfo.advancedGeneration?.features.find(f => f.name === 'ParseCheckConstraints' && f.enabled)) {
|
|
1269
|
-
// the user has the feature turned on, let's generate a description of the constraint and then build a Validate function for the constraint
|
|
1278
|
+
config_1.configInfo.advancedGeneration?.features.find((f) => f.name === 'ParseCheckConstraints' && f.enabled)) {
|
|
1279
|
+
// the user has the feature turned on, let's generate a description of the constraint and then build a Validate function for the constraint
|
|
1270
1280
|
// run this in parallel
|
|
1271
1281
|
generationPromises.push(this.runValidationGeneration(r, allEntityFields, !skipDBUpdate, currentUser));
|
|
1272
1282
|
}
|
|
@@ -1276,8 +1286,8 @@ NumberedRows AS (
|
|
|
1276
1286
|
// now for the table level constraints run the process for advanced generation
|
|
1277
1287
|
for (const r of tableLevelResults) {
|
|
1278
1288
|
if (config_1.configInfo.advancedGeneration?.enableAdvancedGeneration &&
|
|
1279
|
-
config_1.configInfo.advancedGeneration?.features.find(f => f.name === 'ParseCheckConstraints' && f.enabled)) {
|
|
1280
|
-
// the user has the feature turned on, let's generate a description of the constraint and then build a Validate function for the constraint
|
|
1289
|
+
config_1.configInfo.advancedGeneration?.features.find((f) => f.name === 'ParseCheckConstraints' && f.enabled)) {
|
|
1290
|
+
// the user has the feature turned on, let's generate a description of the constraint and then build a Validate function for the constraint
|
|
1281
1291
|
// run this in parallel
|
|
1282
1292
|
generationPromises.push(this.runValidationGeneration(r, allEntityFields, !skipDBUpdate, currentUser));
|
|
1283
1293
|
}
|
|
@@ -1348,7 +1358,9 @@ NumberedRows AS (
|
|
|
1348
1358
|
}
|
|
1349
1359
|
}
|
|
1350
1360
|
try {
|
|
1351
|
-
if (generateNewCode &&
|
|
1361
|
+
if (generateNewCode &&
|
|
1362
|
+
config_1.configInfo.advancedGeneration?.enableAdvancedGeneration &&
|
|
1363
|
+
config_1.configInfo.advancedGeneration?.features.find((f) => f.name === 'ParseCheckConstraints' && f.enabled)) {
|
|
1352
1364
|
// feature is enabled, so let's call the LLM to generate a function for us
|
|
1353
1365
|
const ag = new advanced_generation_1.AdvancedGeneration();
|
|
1354
1366
|
const llm = ag.LLM;
|
|
@@ -1358,42 +1370,45 @@ NumberedRows AS (
|
|
|
1358
1370
|
return returnResult;
|
|
1359
1371
|
}
|
|
1360
1372
|
await aiengine_1.AIEngine.Instance.Config(false, currentUser); // make sure metadata loaded
|
|
1361
|
-
const model = aiengine_1.AIEngine.Instance.Models.find(m => {
|
|
1373
|
+
const model = aiengine_1.AIEngine.Instance.Models.find((m) => {
|
|
1362
1374
|
const modelMatch = m.APINameOrName.trim().toLowerCase() === ag.AIModel.trim().toLowerCase();
|
|
1363
1375
|
if (!modelMatch)
|
|
1364
1376
|
return false;
|
|
1365
1377
|
// Check if model has a vendor matching the specified vendor
|
|
1366
|
-
const hasVendor = aiengine_1.AIEngine.Instance.ModelVendors.some(mv => mv.ModelID === m.ID &&
|
|
1367
|
-
mv.Vendor.trim().toLowerCase() === ag.AIVendor.trim().toLowerCase() &&
|
|
1368
|
-
mv.Status === 'Active');
|
|
1378
|
+
const hasVendor = aiengine_1.AIEngine.Instance.ModelVendors.some((mv) => mv.ModelID === m.ID && mv.Vendor.trim().toLowerCase() === ag.AIVendor.trim().toLowerCase() && mv.Status === 'Active');
|
|
1369
1379
|
return hasVendor;
|
|
1370
1380
|
});
|
|
1371
1381
|
if (!model)
|
|
1372
1382
|
throw new Error(` >>> Error generating validator function from check constraint. Unable to find AI Model with name ${ag.AIModel} and vendor ${ag.AIVendor}.`);
|
|
1373
1383
|
const prompt = ag.getPrompt('CheckConstraintParser');
|
|
1374
|
-
const entityFieldListInfo = allEntityFields
|
|
1375
|
-
|
|
1384
|
+
const entityFieldListInfo = allEntityFields
|
|
1385
|
+
.filter((item) => item.Entity.trim().toLowerCase() === data.EntityName.trim().toLowerCase())
|
|
1386
|
+
.map((item) => ` * ${item.Name} - ${item.Type}${item.AllowsNull ? ' (nullable)' : ' (not null)'}`)
|
|
1387
|
+
.join('\n');
|
|
1388
|
+
const existingMethodNameBlock = generatedValidationFunctionName
|
|
1389
|
+
? `Existing Method Name: ${generatedValidationFunctionName}\n Please reuse this SAME method name for the new generation`
|
|
1390
|
+
: '';
|
|
1376
1391
|
const markedUpSysPrompt = ag.fillTemplate(prompt.systemPrompt, {
|
|
1377
1392
|
ENTITY_FIELD_LIST: entityFieldListInfo,
|
|
1378
|
-
EXISTING_METHOD_NAME: existingMethodNameBlock
|
|
1393
|
+
EXISTING_METHOD_NAME: existingMethodNameBlock,
|
|
1379
1394
|
}); // prompt.systemPrompt.replace(/{{ENTITY_FIELD_LIST}}/g, entityFieldListInfo);
|
|
1380
1395
|
const result = await llm.ChatCompletion({
|
|
1381
1396
|
messages: [
|
|
1382
1397
|
{
|
|
1383
1398
|
role: 'system',
|
|
1384
|
-
content: markedUpSysPrompt
|
|
1399
|
+
content: markedUpSysPrompt,
|
|
1385
1400
|
},
|
|
1386
1401
|
{
|
|
1387
1402
|
role: 'user',
|
|
1388
|
-
content: `${constraintDefinition}
|
|
1389
|
-
}
|
|
1403
|
+
content: `${constraintDefinition}`,
|
|
1404
|
+
},
|
|
1390
1405
|
],
|
|
1391
1406
|
model: ag.AIModel,
|
|
1392
|
-
responseFormat: 'JSON'
|
|
1407
|
+
responseFormat: 'JSON',
|
|
1393
1408
|
});
|
|
1394
1409
|
if (result && result.success) {
|
|
1395
1410
|
const jsonResult = result.data.choices[0].message.content;
|
|
1396
|
-
const structuredResult = (0,
|
|
1411
|
+
const structuredResult = (0, global_2.SafeJSONParse)(jsonResult);
|
|
1397
1412
|
if (structuredResult?.Description && structuredResult?.Code && structuredResult?.MethodName) {
|
|
1398
1413
|
returnResult.functionText = structuredResult.Code;
|
|
1399
1414
|
returnResult.functionName = structuredResult.MethodName;
|
|
@@ -1429,7 +1444,7 @@ NumberedRows AS (
|
|
|
1429
1444
|
await transaction.begin();
|
|
1430
1445
|
try {
|
|
1431
1446
|
for (const ev of existingValues) {
|
|
1432
|
-
if (!possibleValues.find(v => v === ev.Value)) {
|
|
1447
|
+
if (!possibleValues.find((v) => v === ev.Value)) {
|
|
1433
1448
|
// delete the value from the database
|
|
1434
1449
|
const sSQLDelete = `DELETE FROM [${(0, config_1.mj_core_schema)()}].EntityFieldValue WHERE ID='${ev.ID}'`;
|
|
1435
1450
|
await this.LogSQLAndExecute(ds, sSQLDelete, `SQL text to delete entity field value ID ${ev.ID}`);
|
|
@@ -1533,18 +1548,21 @@ NumberedRows AS (
|
|
|
1533
1548
|
if (config_1.configInfo.excludeTables) {
|
|
1534
1549
|
for (let i = 0; i < config_1.configInfo.excludeTables.length; ++i) {
|
|
1535
1550
|
const t = config_1.configInfo.excludeTables[i];
|
|
1536
|
-
sExcludeTables +=
|
|
1537
|
-
(
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1551
|
+
sExcludeTables +=
|
|
1552
|
+
(sExcludeTables.length > 0 ? ' AND ' : '') +
|
|
1553
|
+
(t.schema.indexOf('%') > -1
|
|
1554
|
+
? ` NOT ( ${fieldPrefix}SchemaName LIKE '${t.schema}'`
|
|
1555
|
+
: ` NOT ( ${fieldPrefix}SchemaName = '${t.schema}'`);
|
|
1556
|
+
sExcludeTables +=
|
|
1557
|
+
t.table.indexOf('%') > -1 ? ` AND ${fieldPrefix}TableName LIKE '${t.table}') ` : ` AND ${fieldPrefix}TableName = '${t.table}') `;
|
|
1541
1558
|
}
|
|
1542
1559
|
}
|
|
1543
1560
|
if (config_1.configInfo.excludeSchemas) {
|
|
1544
1561
|
for (let i = 0; i < config_1.configInfo.excludeSchemas.length; ++i) {
|
|
1545
1562
|
const s = config_1.configInfo.excludeSchemas[i];
|
|
1546
|
-
sExcludeSchemas +=
|
|
1547
|
-
(
|
|
1563
|
+
sExcludeSchemas +=
|
|
1564
|
+
(sExcludeSchemas.length > 0 ? ' AND ' : '') +
|
|
1565
|
+
(s.indexOf('%') > -1 ? `${fieldPrefix}SchemaName NOT LIKE '${s}'` : `${fieldPrefix}SchemaName <> '${s}'`);
|
|
1548
1566
|
}
|
|
1549
1567
|
}
|
|
1550
1568
|
const sWhere = (sExcludeTables.length > 0 || sExcludeSchemas.length > 0 ? ` AND ` : '') +
|
|
@@ -1558,7 +1576,7 @@ NumberedRows AS (
|
|
|
1558
1576
|
const newEntitiesResult = await pool.request().query(sSQL);
|
|
1559
1577
|
const newEntities = newEntitiesResult.recordset;
|
|
1560
1578
|
if (newEntities && newEntities.length > 0) {
|
|
1561
|
-
const md = new
|
|
1579
|
+
const md = new global_1.Metadata();
|
|
1562
1580
|
const transaction = new sql.Transaction(pool);
|
|
1563
1581
|
await transaction.begin();
|
|
1564
1582
|
try {
|
|
@@ -1575,14 +1593,14 @@ NumberedRows AS (
|
|
|
1575
1593
|
}
|
|
1576
1594
|
if (ManageMetadataBase.newEntityList.length > 0) {
|
|
1577
1595
|
// only do this if we actually created new entities
|
|
1578
|
-
(0,
|
|
1596
|
+
(0, global_1.LogStatus)(` Done creating entities, refreshing metadata to reflect new entities...`);
|
|
1579
1597
|
await md.Refresh(); // refresh now since we've added some new entities
|
|
1580
1598
|
}
|
|
1581
1599
|
}
|
|
1582
1600
|
return true; // if we get here, we succeeded
|
|
1583
1601
|
}
|
|
1584
1602
|
catch (e) {
|
|
1585
|
-
(0,
|
|
1603
|
+
(0, global_1.LogError)(e);
|
|
1586
1604
|
return false;
|
|
1587
1605
|
}
|
|
1588
1606
|
}
|
|
@@ -1591,12 +1609,12 @@ NumberedRows AS (
|
|
|
1591
1609
|
// criteria:
|
|
1592
1610
|
// 1) entity has a field that is a primary key
|
|
1593
1611
|
// 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.
|
|
1594
|
-
const query = `EXEC ${
|
|
1612
|
+
const query = `EXEC ${global_1.Metadata.Provider.ConfigData.MJCoreSchemaName}.spGetPrimaryKeyForTable @TableName='${newEntity.TableName}', @SchemaName='${newEntity.SchemaName}'`;
|
|
1595
1613
|
try {
|
|
1596
1614
|
const resultResult = await ds.request().query(query);
|
|
1597
1615
|
const result = resultResult.recordset;
|
|
1598
1616
|
if (result.length === 0) {
|
|
1599
|
-
return { shouldCreate: false, validationMessage:
|
|
1617
|
+
return { shouldCreate: false, validationMessage: 'No primary key found' };
|
|
1600
1618
|
}
|
|
1601
1619
|
return { shouldCreate: true, validationMessage: '' };
|
|
1602
1620
|
}
|
|
@@ -1647,13 +1665,13 @@ NumberedRows AS (
|
|
|
1647
1665
|
messages: [
|
|
1648
1666
|
{
|
|
1649
1667
|
role: 'system',
|
|
1650
|
-
content: systemPrompt
|
|
1668
|
+
content: systemPrompt,
|
|
1651
1669
|
},
|
|
1652
1670
|
{
|
|
1653
1671
|
role: 'user',
|
|
1654
|
-
content: userMessage
|
|
1655
|
-
}
|
|
1656
|
-
]
|
|
1672
|
+
content: userMessage,
|
|
1673
|
+
},
|
|
1674
|
+
],
|
|
1657
1675
|
});
|
|
1658
1676
|
if (result?.success) {
|
|
1659
1677
|
const resultText = result?.data.choices[0].message.content;
|
|
@@ -1668,7 +1686,8 @@ NumberedRows AS (
|
|
|
1668
1686
|
}
|
|
1669
1687
|
}
|
|
1670
1688
|
catch (e) {
|
|
1671
|
-
console.warn(' >>> Advanced Generation Error: LLM returned invalid result, falling back to simple generated entity name. Result from LLM: ' +
|
|
1689
|
+
console.warn(' >>> Advanced Generation Error: LLM returned invalid result, falling back to simple generated entity name. Result from LLM: ' +
|
|
1690
|
+
resultText, e);
|
|
1672
1691
|
return this.simpleNewEntityName(newEntity.SchemaName, newEntity.TableName);
|
|
1673
1692
|
}
|
|
1674
1693
|
}
|
|
@@ -1678,8 +1697,8 @@ NumberedRows AS (
|
|
|
1678
1697
|
}
|
|
1679
1698
|
}
|
|
1680
1699
|
simpleNewEntityName(schemaName, tableName) {
|
|
1681
|
-
const convertedTableName = (0,
|
|
1682
|
-
const pluralName = (0,
|
|
1700
|
+
const convertedTableName = (0, global_2.convertCamelCaseToHaveSpaces)(tableName);
|
|
1701
|
+
const pluralName = (0, global_2.generatePluralName)(convertedTableName, { capitalizeFirstLetterOnly: true });
|
|
1683
1702
|
return this.markupEntityName(schemaName, pluralName);
|
|
1684
1703
|
}
|
|
1685
1704
|
/**
|
|
@@ -1699,7 +1718,7 @@ NumberedRows AS (
|
|
|
1699
1718
|
}
|
|
1700
1719
|
}
|
|
1701
1720
|
getNewEntityNameRule(schemaName) {
|
|
1702
|
-
const rule = config_1.configInfo.newEntityDefaults?.NameRulesBySchema?.find(r => {
|
|
1721
|
+
const rule = config_1.configInfo.newEntityDefaults?.NameRulesBySchema?.find((r) => {
|
|
1703
1722
|
let schemaNameToUse = r.SchemaName;
|
|
1704
1723
|
if (schemaNameToUse?.trim().toLowerCase() === '${mj_core_schema}') {
|
|
1705
1724
|
// markup for this is to be replaced with the mj_core_schema() config
|
|
@@ -1720,13 +1739,13 @@ NumberedRows AS (
|
|
|
1720
1739
|
let newEntityName = await this.createNewEntityName(newEntity);
|
|
1721
1740
|
const newEntityDisplayName = this.createNewEntityDisplayName(newEntity, newEntityName);
|
|
1722
1741
|
let suffix = '';
|
|
1723
|
-
const existingEntity = md.Entities.find(e => e.Name.toLowerCase() === newEntityName.toLowerCase());
|
|
1724
|
-
const existingEntityInNewEntityList = ManageMetadataBase.newEntityList.find(e => e === newEntityName); // check the newly created entity list to make sure we didn't create the new entity name along the way in this RUN of CodeGen as it wouldn't yet be in our metadata above
|
|
1742
|
+
const existingEntity = md.Entities.find((e) => e.Name.toLowerCase() === newEntityName.toLowerCase());
|
|
1743
|
+
const existingEntityInNewEntityList = ManageMetadataBase.newEntityList.find((e) => e === newEntityName); // check the newly created entity list to make sure we didn't create the new entity name along the way in this RUN of CodeGen as it wouldn't yet be in our metadata above
|
|
1725
1744
|
if (existingEntity || existingEntityInNewEntityList) {
|
|
1726
1745
|
// the generated name is already in place, so we need another name
|
|
1727
1746
|
suffix = '__' + newEntity.SchemaName;
|
|
1728
1747
|
newEntityName = newEntityName + suffix;
|
|
1729
|
-
(0,
|
|
1748
|
+
(0, global_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.`);
|
|
1730
1749
|
}
|
|
1731
1750
|
const isNewSchema = await this.isSchemaNew(pool, newEntity.SchemaName);
|
|
1732
1751
|
const newEntityID = this.createNewUUID();
|
|
@@ -1750,7 +1769,7 @@ NumberedRows AS (
|
|
|
1750
1769
|
apps = [newAppID];
|
|
1751
1770
|
}
|
|
1752
1771
|
else {
|
|
1753
|
-
(0,
|
|
1772
|
+
(0, global_1.LogError)(` >>>> ERROR: Unable to create new application for schema ${newEntity.SchemaName}`);
|
|
1754
1773
|
}
|
|
1755
1774
|
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
|
|
1756
1775
|
// 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
|
|
@@ -1776,14 +1795,15 @@ NumberedRows AS (
|
|
|
1776
1795
|
}
|
|
1777
1796
|
else {
|
|
1778
1797
|
// 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
|
|
1779
|
-
(0,
|
|
1798
|
+
(0, global_1.LogError)(` >>>> ERROR: Unable to add new entity ${newEntityName} to an application because an Application record for schema ${newEntity.SchemaName} does not exist.`);
|
|
1780
1799
|
}
|
|
1781
1800
|
// next up, we need to check if we're configured to add permissions for new entities, and if so, add them
|
|
1782
|
-
if (config_1.configInfo.newEntityDefaults.PermissionDefaults &&
|
|
1801
|
+
if (config_1.configInfo.newEntityDefaults.PermissionDefaults &&
|
|
1802
|
+
config_1.configInfo.newEntityDefaults.PermissionDefaults.AutoAddPermissionsForNewEntities) {
|
|
1783
1803
|
// we are asked to add permissions for new entities, so do that by looping through the permissions and adding them
|
|
1784
1804
|
const permissions = config_1.configInfo.newEntityDefaults.PermissionDefaults.Permissions;
|
|
1785
1805
|
for (const p of permissions) {
|
|
1786
|
-
const RoleID = md.Roles.find(r => r.Name.trim().toLowerCase() === p.RoleName.trim().toLowerCase())?.ID;
|
|
1806
|
+
const RoleID = md.Roles.find((r) => r.Name.trim().toLowerCase() === p.RoleName.trim().toLowerCase())?.ID;
|
|
1787
1807
|
if (RoleID) {
|
|
1788
1808
|
const sSQLInsertPermission = `INSERT INTO ${(0, config_1.mj_core_schema)()}.EntityPermission
|
|
1789
1809
|
(EntityID, RoleID, CanRead, CanCreate, CanUpdate, CanDelete) VALUES
|
|
@@ -1791,18 +1811,18 @@ NumberedRows AS (
|
|
|
1791
1811
|
await this.LogSQLAndExecute(pool, sSQLInsertPermission, `SQL generated to add new permission for entity ${newEntityName} for role ${p.RoleName}`);
|
|
1792
1812
|
}
|
|
1793
1813
|
else
|
|
1794
|
-
(0,
|
|
1814
|
+
(0, global_1.LogError)(` >>>> ERROR: Unable to find Role ID for role ${p.RoleName} to add permissions for new entity ${newEntityName}`);
|
|
1795
1815
|
}
|
|
1796
1816
|
}
|
|
1797
|
-
(0,
|
|
1817
|
+
(0, global_1.LogStatus)(` Created new entity ${newEntityName} for table ${newEntity.SchemaName}.${newEntity.TableName}`);
|
|
1798
1818
|
}
|
|
1799
1819
|
else {
|
|
1800
|
-
(0,
|
|
1820
|
+
(0, global_1.LogStatus)(` Skipping new entity ${newEntity.TableName} because it doesn't qualify to be created. Reason: ${validationMessage}`);
|
|
1801
1821
|
return;
|
|
1802
1822
|
}
|
|
1803
1823
|
}
|
|
1804
1824
|
catch (e) {
|
|
1805
|
-
(0,
|
|
1825
|
+
(0, global_1.LogError)(`Failed to create new entity ${newEntity?.TableName}`);
|
|
1806
1826
|
}
|
|
1807
1827
|
}
|
|
1808
1828
|
async isSchemaNew(pool, schemaName) {
|
|
@@ -1814,12 +1834,20 @@ NumberedRows AS (
|
|
|
1814
1834
|
}
|
|
1815
1835
|
async createNewApplication(pool, appID, appName, schemaName) {
|
|
1816
1836
|
try {
|
|
1817
|
-
const sSQL =
|
|
1837
|
+
const sSQL = 'INSERT INTO [' +
|
|
1838
|
+
(0, config_1.mj_core_schema)() +
|
|
1839
|
+
"].Application (ID, Name, Description, SchemaAutoAddNewEntities) VALUES ('" +
|
|
1840
|
+
appID +
|
|
1841
|
+
"', '" +
|
|
1842
|
+
appName +
|
|
1843
|
+
"', 'Generated for schema', '" +
|
|
1844
|
+
schemaName +
|
|
1845
|
+
"')";
|
|
1818
1846
|
await this.LogSQLAndExecute(pool, sSQL, `SQL generated to create new application ${appName}`);
|
|
1819
1847
|
return appID; // if we get here, we successfully created the application, so return the ID
|
|
1820
1848
|
}
|
|
1821
1849
|
catch (e) {
|
|
1822
|
-
(0,
|
|
1850
|
+
(0, global_1.LogError)(`Failed to create new application ${appName} for schema ${schemaName}`, null, e);
|
|
1823
1851
|
return null; // if we get here, we failed to create the application
|
|
1824
1852
|
}
|
|
1825
1853
|
}
|
|
@@ -1841,7 +1869,7 @@ NumberedRows AS (
|
|
|
1841
1869
|
else {
|
|
1842
1870
|
const apps = result.filter((a) => {
|
|
1843
1871
|
if (a.SchemaAutoAddNewEntities && a.SchemaAutoAddNewEntities.length > 0) {
|
|
1844
|
-
const schemas = a.SchemaAutoAddNewEntities.split(
|
|
1872
|
+
const schemas = a.SchemaAutoAddNewEntities.split(',');
|
|
1845
1873
|
if (schemas && schemas.length > 0) {
|
|
1846
1874
|
return schemas.find((s) => s.trim().toLowerCase() === schemaName.trim().toLowerCase());
|
|
1847
1875
|
}
|
|
@@ -1881,7 +1909,7 @@ NumberedRows AS (
|
|
|
1881
1909
|
${newEntityDescriptionEscaped ? newEntityDescriptionEscaped : 'NULL' /*if no description, then null*/},
|
|
1882
1910
|
${newEntitySuffix && newEntitySuffix.length > 0 ? `'${newEntitySuffix}'` : 'NULL'},
|
|
1883
1911
|
'${newEntity.TableName}',
|
|
1884
|
-
'vw${(0,
|
|
1912
|
+
'vw${(0, global_2.generatePluralName)(newEntity.TableName, { capitalizeFirstLetterOnly: true }) + (newEntitySuffix && newEntitySuffix.length > 0 ? newEntitySuffix : '')}',
|
|
1885
1913
|
'${newEntity.SchemaName}',
|
|
1886
1914
|
1,
|
|
1887
1915
|
${newEntityDefaults.AllowUserSearchAPI === undefined ? 1 : newEntityDefaults.AllowUserSearchAPI ? 1 : 0}
|
|
@@ -1892,7 +1920,7 @@ NumberedRows AS (
|
|
|
1892
1920
|
${newEntityDefaults.AllowCreateAPI === undefined ? '' : ', ' + (newEntityDefaults.AllowCreateAPI ? '1' : '0')}
|
|
1893
1921
|
${newEntityDefaults.AllowUpdateAPI === undefined ? '' : ', ' + (newEntityDefaults.AllowUpdateAPI ? '1' : '0')}
|
|
1894
1922
|
${newEntityDefaults.AllowDeleteAPI === undefined ? '' : ', ' + (newEntityDefaults.AllowDeleteAPI ? '1' : '0')}
|
|
1895
|
-
${newEntityDefaults.UserViewMaxRows === undefined ? '' : ', ' +
|
|
1923
|
+
${newEntityDefaults.UserViewMaxRows === undefined ? '' : ', ' + newEntityDefaults.UserViewMaxRows}
|
|
1896
1924
|
)
|
|
1897
1925
|
`;
|
|
1898
1926
|
return sSQLInsert;
|