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