@memberjunction/codegen-lib 1.8.1 → 2.1.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.js +1 -1
- package/dist/Angular/angular-codegen.js.map +1 -1
- package/dist/Angular/join-grid-related-entity-component.d.ts +0 -1
- package/dist/Angular/join-grid-related-entity-component.d.ts.map +1 -1
- package/dist/Angular/join-grid-related-entity-component.js +0 -13
- package/dist/Angular/join-grid-related-entity-component.js.map +1 -1
- package/dist/Angular/related-entity-components.d.ts +11 -1
- package/dist/Angular/related-entity-components.d.ts.map +1 -1
- package/dist/Angular/related-entity-components.js +26 -1
- package/dist/Angular/related-entity-components.js.map +1 -1
- package/dist/Angular/timeline-related-entity-component.d.ts +36 -0
- package/dist/Angular/timeline-related-entity-component.d.ts.map +1 -0
- package/dist/Angular/timeline-related-entity-component.js +67 -0
- package/dist/Angular/timeline-related-entity-component.js.map +1 -0
- package/dist/Config/db-connection.d.ts +3 -0
- package/dist/Config/db-connection.d.ts.map +1 -1
- package/dist/Config/db-connection.js +46 -1
- package/dist/Config/db-connection.js.map +1 -1
- package/dist/Database/manage-metadata.d.ts +23 -8
- package/dist/Database/manage-metadata.d.ts.map +1 -1
- package/dist/Database/manage-metadata.js +362 -155
- package/dist/Database/manage-metadata.js.map +1 -1
- package/dist/Database/sql.d.ts +12 -1
- package/dist/Database/sql.d.ts.map +1 -1
- package/dist/Database/sql.js +196 -36
- package/dist/Database/sql.js.map +1 -1
- package/dist/Database/sql_codegen.d.ts +12 -4
- package/dist/Database/sql_codegen.d.ts.map +1 -1
- package/dist/Database/sql_codegen.js +210 -103
- package/dist/Database/sql_codegen.js.map +1 -1
- package/dist/Misc/createNewUser.d.ts.map +1 -1
- package/dist/Misc/createNewUser.js +2 -1
- package/dist/Misc/createNewUser.js.map +1 -1
- package/dist/Misc/util.d.ts +1 -0
- package/dist/Misc/util.d.ts.map +1 -1
- package/dist/Misc/util.js +24 -2
- package/dist/Misc/util.js.map +1 -1
- package/dist/action_subclasses_codegen.d.ts +1 -1
- package/dist/action_subclasses_codegen.js +1 -1
- package/dist/action_subclasses_codegen.js.map +1 -1
- package/dist/entity_subclasses_codegen.d.ts.map +1 -1
- package/dist/entity_subclasses_codegen.js +72 -75
- package/dist/entity_subclasses_codegen.js.map +1 -1
- package/dist/entity_types_codegen.d.ts +15 -0
- package/dist/entity_types_codegen.d.ts.map +1 -0
- package/dist/entity_types_codegen.js +106 -0
- package/dist/entity_types_codegen.js.map +1 -0
- package/dist/graphql_server_codegen.d.ts +4 -4
- package/dist/graphql_server_codegen.d.ts.map +1 -1
- package/dist/graphql_server_codegen.js +65 -58
- package/dist/graphql_server_codegen.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/runCodeGen.d.ts.map +1 -1
- package/dist/runCodeGen.js +27 -4
- package/dist/runCodeGen.js.map +1 -1
- package/package.json +8 -7
- package/dist/createNewUser.d.ts +0 -12
- package/dist/createNewUser.d.ts.map +0 -1
- package/dist/createNewUser.js +0 -113
- package/dist/createNewUser.js.map +0 -1
|
@@ -74,34 +74,39 @@ let SQLCodeGenBase = class SQLCodeGenBase {
|
|
|
74
74
|
const baselineEntities = entities.filter(e => e.IncludeInAPI);
|
|
75
75
|
const includedEntities = baselineEntities.filter(e => config_1.configInfo.excludeSchemas.find(s => s.toLowerCase() === e.SchemaName.toLowerCase()) === undefined); //only include entities that are NOT in the excludeSchemas list
|
|
76
76
|
const excludedEntities = baselineEntities.filter(e => config_1.configInfo.excludeSchemas.find(s => s.toLowerCase() === e.SchemaName.toLowerCase()) !== undefined); //only include entities that ARE in the excludeSchemas list in this array
|
|
77
|
-
// STEP 2(a) -
|
|
77
|
+
// STEP 2(a) - clean out all *.generated.sql and *.permissions.generated.sql files from the directory
|
|
78
|
+
this.deleteGeneratedEntityFiles(directory, baselineEntities);
|
|
79
|
+
// STEP 2(b) - generate all the SQL files and execute them
|
|
78
80
|
const step2StartTime = new Date();
|
|
79
|
-
|
|
80
|
-
|
|
81
|
+
const genResult = await this.generateAndExecuteEntitySQLToSeparateFiles(ds, includedEntities, directory, false, true);
|
|
82
|
+
if (!genResult.Success) {
|
|
83
|
+
(0, logging_1.logError)('Error generating all entities SQL to separate files');
|
|
81
84
|
return false;
|
|
82
85
|
}
|
|
83
|
-
// STEP 2(
|
|
84
|
-
|
|
85
|
-
|
|
86
|
+
// STEP 2(c) - for the excludedEntities, while we don't want to generate SQL, we do want to generate the permissions files for them
|
|
87
|
+
const genResult2 = await this.generateAndExecuteEntitySQLToSeparateFiles(ds, excludedEntities, directory, true, true);
|
|
88
|
+
if (!genResult2.Success) {
|
|
89
|
+
(0, logging_1.logError)('Error generating permissions SQL for excluded entities to separate files');
|
|
86
90
|
return false;
|
|
87
91
|
}
|
|
88
|
-
(0, logging_1.logStatus)(` Time to
|
|
89
|
-
// now that we've generated the SQL, let's create a combined file in each schema sub-directory for convenience for a DBA
|
|
90
|
-
this.createCombinedEntitySQLFiles(directory, baselineEntities);
|
|
92
|
+
(0, logging_1.logStatus)(` Time to generate entity SQL: ${(new Date().getTime() - step2StartTime.getTime()) / 1000} seconds`);
|
|
93
|
+
// STEP 2(d) now that we've generated the SQL, let's create a combined file in each schema sub-directory for convenience for a DBA
|
|
94
|
+
const allEntityFiles = this.createCombinedEntitySQLFiles(directory, baselineEntities);
|
|
95
|
+
// STEP 2(e) ---- FINALLY, we now execute all the combined files by schema;
|
|
96
|
+
const step2eStartTime = new Date();
|
|
97
|
+
if (!await this.SQLUtilityObject.executeSQLFiles(allEntityFiles, true)) {
|
|
98
|
+
(0, logging_1.logError)('Error executing combined entity SQL files');
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
const step2eEndTime = new Date();
|
|
102
|
+
(0, logging_1.logStatus)(` Time to Execute Combined Entity SQL: ${(step2eEndTime.getTime() - step2eStartTime.getTime()) / 1000} seconds`);
|
|
91
103
|
const manageMD = global_1.MJGlobal.Instance.ClassFactory.CreateInstance(manage_metadata_1.ManageMetadataBase);
|
|
92
104
|
// STEP 3 - re-run the process to manage entity fields since the Step 1 and 2 above might have resulted in differences in base view columns compared to what we had at first
|
|
93
|
-
|
|
105
|
+
// we CAN skip the entity field values part because that wouldn't change from the first time we ran it
|
|
106
|
+
if (!await manageMD.manageEntityFields(ds, config_1.configInfo.excludeSchemas, true, true)) {
|
|
94
107
|
(0, logging_1.logError)('Error managing entity fields');
|
|
95
108
|
return false;
|
|
96
109
|
}
|
|
97
|
-
// no logStatus/timer for this because manageEntityFields() has its own internal logging for this including the total, so it is redundant to log it here
|
|
98
|
-
// STEP 4- Apply permissions, executing all .permissions files
|
|
99
|
-
const step4StartTime = new Date();
|
|
100
|
-
if (!await this.applyPermissions(ds, directory, baselineEntities)) {
|
|
101
|
-
(0, logging_1.logError)('Error applying permissions');
|
|
102
|
-
return false;
|
|
103
|
-
}
|
|
104
|
-
(0, logging_1.logStatus)(` Time to Apply Permissions: ${(new Date().getTime() - step4StartTime.getTime()) / 1000} seconds`);
|
|
105
110
|
// STEP 5 - execute any custom SQL scripts that should run afterwards
|
|
106
111
|
const step5StartTime = new Date();
|
|
107
112
|
if (!await this.runCustomSQLScripts(ds, 'after-sql'))
|
|
@@ -125,7 +130,7 @@ let SQLCodeGenBase = class SQLCodeGenBase {
|
|
|
125
130
|
if (scripts) {
|
|
126
131
|
for (let i = 0; i < scripts.length; ++i) {
|
|
127
132
|
const s = scripts[i];
|
|
128
|
-
if (!await this.SQLUtilityObject.executeSQLFile(
|
|
133
|
+
if (!await this.SQLUtilityObject.executeSQLFile(s.scriptFile)) {
|
|
129
134
|
(0, logging_1.logError)(`Error executing custom '${when}' SQL script ${s.scriptFile}`);
|
|
130
135
|
bSuccess = false; // keep going if we have more scripts, but make sure we return false
|
|
131
136
|
}
|
|
@@ -150,7 +155,7 @@ let SQLCodeGenBase = class SQLCodeGenBase {
|
|
|
150
155
|
for (const f of files) {
|
|
151
156
|
const fullPath = path_1.default.join(directory, f);
|
|
152
157
|
if (fs.existsSync(fullPath)) {
|
|
153
|
-
if (!await this.SQLUtilityObject.executeSQLFile(
|
|
158
|
+
if (!await this.SQLUtilityObject.executeSQLFile(fullPath))
|
|
154
159
|
innerSuccess = false; // we keep going, just note that something failed
|
|
155
160
|
}
|
|
156
161
|
else {
|
|
@@ -181,7 +186,8 @@ let SQLCodeGenBase = class SQLCodeGenBase {
|
|
|
181
186
|
* @param directory The directory to save the generated SQL files to
|
|
182
187
|
* @param onlyPermissions If true, only the permissions files will be generated and executed, not the actual SQL files. Use this if you are simply setting permission changes but no actual changes to the entities have occured.
|
|
183
188
|
*/
|
|
184
|
-
async generateAndExecuteEntitySQLToSeparateFiles(ds, entities, directory, onlyPermissions, writeFiles = true, batchSize = 5) {
|
|
189
|
+
async generateAndExecuteEntitySQLToSeparateFiles(ds, entities, directory, onlyPermissions, skipExecution = false, writeFiles = true, batchSize = 5) {
|
|
190
|
+
const files = [];
|
|
185
191
|
try {
|
|
186
192
|
let bFail = false;
|
|
187
193
|
const totalEntities = entities.length;
|
|
@@ -191,46 +197,80 @@ let SQLCodeGenBase = class SQLCodeGenBase {
|
|
|
191
197
|
const pkeyField = e.Fields.find(f => f.IsPrimaryKey);
|
|
192
198
|
if (!pkeyField) {
|
|
193
199
|
(0, logging_1.logError)(`SKIPPING ENTITY: Entity ${e.Name}, because it does not have a primary key field defined. A table must have a primary key defined to quality to be a MemberJunction entity`);
|
|
194
|
-
return false;
|
|
200
|
+
return { Success: false, Files: [] };
|
|
195
201
|
}
|
|
196
|
-
return this.generateAndExecuteSingleEntitySQLToSeparateFiles(ds, e, directory, onlyPermissions, writeFiles);
|
|
202
|
+
return this.generateAndExecuteSingleEntitySQLToSeparateFiles(ds, e, directory, onlyPermissions, skipExecution, writeFiles);
|
|
197
203
|
});
|
|
198
204
|
const results = await Promise.all(promises);
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
205
|
+
results.forEach(r => {
|
|
206
|
+
if (!r.Success)
|
|
207
|
+
bFail = true; // keep going, but will return false at the end
|
|
208
|
+
files.push(...r.Files); // add the files to the main files array
|
|
209
|
+
});
|
|
202
210
|
}
|
|
203
|
-
return !bFail;
|
|
211
|
+
return { Success: !bFail, Files: files };
|
|
204
212
|
}
|
|
205
213
|
catch (err) {
|
|
206
214
|
(0, logging_1.logError)(err);
|
|
207
|
-
return false;
|
|
215
|
+
return { Success: false, Files: files };
|
|
208
216
|
}
|
|
209
217
|
}
|
|
210
|
-
|
|
218
|
+
deleteGeneratedEntityFiles(directory, entities) {
|
|
219
|
+
try {
|
|
220
|
+
// for the schemas associated with the specified entities, clean out all the generated files
|
|
221
|
+
const schemaNames = entities.map(e => e.SchemaName).filter((value, index, self) => self.indexOf(value) === index);
|
|
222
|
+
for (const s of schemaNames) {
|
|
223
|
+
const fullPath = path_1.default.join(directory, s);
|
|
224
|
+
// now, within each schema directory, clean out all the generated files
|
|
225
|
+
// the generated files map this pattern: *.generated.sql or *.permissions.generated.sql
|
|
226
|
+
if (fs.statSync(fullPath).isDirectory()) {
|
|
227
|
+
const files = fs.readdirSync(fullPath).filter(f => f.endsWith('.generated.sql') || f.endsWith('.permissions.generated.sql'));
|
|
228
|
+
for (const f of files) {
|
|
229
|
+
const filePath = path_1.default.join(fullPath, f);
|
|
230
|
+
fs.unlinkSync(filePath);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
catch (e) {
|
|
236
|
+
(0, logging_1.logError)(e);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
createCombinedEntitySQLFiles(directory, entities) {
|
|
211
240
|
// first, get a disinct list of schemanames from the entities
|
|
241
|
+
const files = [];
|
|
212
242
|
const schemaNames = entities.map(e => e.SchemaName).filter((value, index, self) => self.indexOf(value) === index);
|
|
213
243
|
for (const s of schemaNames) {
|
|
214
244
|
// generate the all-entities.sql file and all-entities.permissions.sql file in each schema folder
|
|
215
245
|
const fullPath = path_1.default.join(directory, s);
|
|
216
246
|
if (fs.statSync(fullPath).isDirectory()) {
|
|
217
247
|
(0, util_1.combineFiles)(fullPath, '_all_entities.sql', '*.generated.sql', true);
|
|
248
|
+
files.push(path_1.default.join(fullPath, '_all_entities.sql'));
|
|
218
249
|
(0, util_1.combineFiles)(fullPath, '_all_entities.permissions.sql', '*.permissions.generated.sql', true);
|
|
250
|
+
files.push(path_1.default.join(fullPath, '_all_entities.permissions.sql'));
|
|
219
251
|
}
|
|
220
252
|
}
|
|
253
|
+
return files;
|
|
221
254
|
}
|
|
222
|
-
async generateAndExecuteSingleEntitySQLToSeparateFiles(ds, entity, directory, onlyPermissions, writeFiles = true) {
|
|
255
|
+
async generateAndExecuteSingleEntitySQLToSeparateFiles(ds, entity, directory, onlyPermissions, skipExecution = false, writeFiles = true) {
|
|
223
256
|
try {
|
|
224
|
-
const { sql, permissionsSQL } = await this.generateSingleEntitySQLToSeparateFiles(ds, entity, directory, onlyPermissions, writeFiles); // this creates the files and returns a single string with all the SQL we can then execute
|
|
225
|
-
|
|
226
|
-
|
|
257
|
+
const { sql, permissionsSQL, files } = await this.generateSingleEntitySQLToSeparateFiles(ds, entity, directory, onlyPermissions, skipExecution, writeFiles); // this creates the files and returns a single string with all the SQL we can then execute
|
|
258
|
+
if (!skipExecution) {
|
|
259
|
+
return {
|
|
260
|
+
Success: await this.SQLUtilityObject.executeSQLScript(ds, sql + "\n\nGO\n\n" + permissionsSQL, true), // combine the SQL and permissions and execute it,
|
|
261
|
+
Files: files
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
else
|
|
265
|
+
return { Success: true, Files: files };
|
|
227
266
|
}
|
|
228
267
|
catch (err) {
|
|
229
268
|
(0, logging_1.logError)(err);
|
|
230
|
-
return false;
|
|
269
|
+
return { Success: false, Files: [] };
|
|
231
270
|
}
|
|
232
271
|
}
|
|
233
|
-
async generateSingleEntitySQLToSeparateFiles(ds, entity, directory, onlyPermissions, writeFiles = true) {
|
|
272
|
+
async generateSingleEntitySQLToSeparateFiles(ds, entity, directory, onlyPermissions, skipExecution = false, writeFiles = true) {
|
|
273
|
+
const files = [];
|
|
234
274
|
try {
|
|
235
275
|
// create the directory if it doesn't exist
|
|
236
276
|
if (writeFiles && !fs.existsSync(directory))
|
|
@@ -246,16 +286,21 @@ let SQLCodeGenBase = class SQLCodeGenBase {
|
|
|
246
286
|
// generate the base view
|
|
247
287
|
const s = this.generateSingleEntitySQLFileHeader(entity, entity.BaseView) + await this.generateBaseView(ds, entity);
|
|
248
288
|
const filePath = path_1.default.join(directory, this.SQLUtilityObject.getDBObjectFileName('view', entity.SchemaName, entity.BaseView, false, true));
|
|
249
|
-
if (writeFiles)
|
|
289
|
+
if (writeFiles) {
|
|
250
290
|
fs.writeFileSync(filePath, s);
|
|
291
|
+
files.push(filePath);
|
|
292
|
+
}
|
|
251
293
|
sRet += s + '\nGO\n';
|
|
252
294
|
}
|
|
253
295
|
// always generate permissions for the base view
|
|
254
296
|
const s = this.generateSingleEntitySQLFileHeader(entity, 'Permissions for ' + entity.BaseView) + this.generateViewPermissions(entity);
|
|
255
297
|
if (s.length > 0)
|
|
256
298
|
permissionsSQL += s + '\nGO\n';
|
|
257
|
-
if (writeFiles)
|
|
258
|
-
|
|
299
|
+
if (writeFiles) {
|
|
300
|
+
const filePath = path_1.default.join(directory, this.SQLUtilityObject.getDBObjectFileName('view', entity.SchemaName, entity.BaseView, true, true));
|
|
301
|
+
fs.writeFileSync(filePath, s);
|
|
302
|
+
files.push(filePath);
|
|
303
|
+
}
|
|
259
304
|
// now, append the permissions to the return string IF we did NOT generate the base view - because if we generated the base view, that
|
|
260
305
|
// means we already generated the permissions for it above and it is part of sRet already, but we always save it to a file, (per above line)
|
|
261
306
|
if (!entity.BaseViewGenerated)
|
|
@@ -266,15 +311,21 @@ let SQLCodeGenBase = class SQLCodeGenBase {
|
|
|
266
311
|
if (!onlyPermissions && entity.spCreateGenerated) {
|
|
267
312
|
// generate the create SP
|
|
268
313
|
const s = this.generateSingleEntitySQLFileHeader(entity, spName) + this.generateSPCreate(entity);
|
|
269
|
-
if (writeFiles)
|
|
270
|
-
|
|
314
|
+
if (writeFiles) {
|
|
315
|
+
const filePath = path_1.default.join(directory, this.SQLUtilityObject.getDBObjectFileName('sp', entity.SchemaName, spName, false, true));
|
|
316
|
+
fs.writeFileSync(filePath, s);
|
|
317
|
+
files.push(filePath);
|
|
318
|
+
}
|
|
271
319
|
sRet += s + '\nGO\n';
|
|
272
320
|
}
|
|
273
321
|
const s = this.generateSPPermissions(entity, spName, exports.SPType.Create) + '\n\n';
|
|
274
322
|
if (s.length > 0)
|
|
275
323
|
permissionsSQL += s + '\nGO\n';
|
|
276
|
-
if (writeFiles)
|
|
277
|
-
|
|
324
|
+
if (writeFiles) {
|
|
325
|
+
const filePath = path_1.default.join(directory, this.SQLUtilityObject.getDBObjectFileName('sp', entity.SchemaName, spName, true, true));
|
|
326
|
+
fs.writeFileSync(filePath, s);
|
|
327
|
+
files.push(filePath);
|
|
328
|
+
}
|
|
278
329
|
// now, append the permissions to the return string IF we did NOT generate the proc - because if we generated the proc, that
|
|
279
330
|
// means we already generated the permissions for it above and it is part of sRet already, but we always save it to a file, (per above line)
|
|
280
331
|
if (!entity.spCreateGenerated)
|
|
@@ -286,15 +337,21 @@ let SQLCodeGenBase = class SQLCodeGenBase {
|
|
|
286
337
|
if (!onlyPermissions && entity.spUpdateGenerated) {
|
|
287
338
|
// generate the update SP
|
|
288
339
|
const s = this.generateSingleEntitySQLFileHeader(entity, spName) + this.generateSPUpdate(entity);
|
|
289
|
-
if (writeFiles)
|
|
290
|
-
|
|
340
|
+
if (writeFiles) {
|
|
341
|
+
const filePath = path_1.default.join(directory, this.SQLUtilityObject.getDBObjectFileName('sp', entity.SchemaName, spName, false, true));
|
|
342
|
+
fs.writeFileSync(filePath, s);
|
|
343
|
+
files.push(filePath);
|
|
344
|
+
}
|
|
291
345
|
sRet += s + '\nGO\n';
|
|
292
346
|
}
|
|
293
347
|
const s = this.generateSPPermissions(entity, spName, exports.SPType.Update) + '\n\n';
|
|
294
348
|
if (s.length > 0)
|
|
295
349
|
permissionsSQL += s + '\nGO\n';
|
|
296
|
-
if (writeFiles)
|
|
297
|
-
|
|
350
|
+
if (writeFiles) {
|
|
351
|
+
const filePath = path_1.default.join(directory, this.SQLUtilityObject.getDBObjectFileName('sp', entity.SchemaName, spName, true, true));
|
|
352
|
+
fs.writeFileSync(filePath, s);
|
|
353
|
+
files.push(filePath);
|
|
354
|
+
}
|
|
298
355
|
// now, append the permissions to the return string IF we did NOT generate the proc - because if we generated the proc, that
|
|
299
356
|
// means we already generated the permissions for it above and it is part of sRet already, but we always save it to a file, (per above line)
|
|
300
357
|
if (!entity.spUpdateGenerated)
|
|
@@ -306,15 +363,21 @@ let SQLCodeGenBase = class SQLCodeGenBase {
|
|
|
306
363
|
if (!onlyPermissions && entity.spDeleteGenerated) {
|
|
307
364
|
// generate the delete SP
|
|
308
365
|
const s = this.generateSingleEntitySQLFileHeader(entity, spName) + this.generateSPDelete(entity);
|
|
309
|
-
if (writeFiles)
|
|
310
|
-
|
|
366
|
+
if (writeFiles) {
|
|
367
|
+
const filePath = path_1.default.join(directory, this.SQLUtilityObject.getDBObjectFileName('sp', entity.SchemaName, spName, false, true));
|
|
368
|
+
fs.writeFileSync(filePath, s);
|
|
369
|
+
files.push(filePath);
|
|
370
|
+
}
|
|
311
371
|
sRet += s + '\nGO\n';
|
|
312
372
|
}
|
|
313
373
|
const s = this.generateSPPermissions(entity, spName, exports.SPType.Delete) + '\n\n';
|
|
314
374
|
if (s.length > 0)
|
|
315
375
|
permissionsSQL += s + '\nGO\n';
|
|
316
|
-
if (writeFiles)
|
|
317
|
-
|
|
376
|
+
if (writeFiles) {
|
|
377
|
+
const filePath = path_1.default.join(directory, this.SQLUtilityObject.getDBObjectFileName('sp', entity.SchemaName, spName, true, true));
|
|
378
|
+
fs.writeFileSync(filePath, s);
|
|
379
|
+
files.push(filePath);
|
|
380
|
+
}
|
|
318
381
|
// now, append the permissions to the return string IF we did NOT generate the proc - because if we generated the proc, that
|
|
319
382
|
// means we already generated the permissions for it above and it is part of sRet already, but we always save it to a file, (per above line)
|
|
320
383
|
if (!entity.spDeleteGenerated)
|
|
@@ -327,22 +390,26 @@ let SQLCodeGenBase = class SQLCodeGenBase {
|
|
|
327
390
|
if (!onlyPermissions) {
|
|
328
391
|
// only write the actual sql out if we're not only generating permissions
|
|
329
392
|
const filePath = path_1.default.join(directory, this.SQLUtilityObject.getDBObjectFileName('full_text_search_function', entity.SchemaName, entity.BaseTable, false, true));
|
|
330
|
-
if (writeFiles)
|
|
393
|
+
if (writeFiles) {
|
|
331
394
|
fs.writeFileSync(filePath, ft.sql);
|
|
395
|
+
files.push(filePath);
|
|
396
|
+
}
|
|
332
397
|
sRet += ft.sql + '\nGO\n';
|
|
333
398
|
}
|
|
334
399
|
const sP = this.generateFullTextSearchFunctionPermissions(entity, ft.functionName) + '\n\n';
|
|
335
400
|
if (sP.length > 0)
|
|
336
401
|
permissionsSQL += sP + '\nGO\n';
|
|
337
402
|
const filePath = path_1.default.join(directory, this.SQLUtilityObject.getDBObjectFileName('full_text_search_function', entity.SchemaName, entity.BaseTable, true, true));
|
|
338
|
-
if (writeFiles)
|
|
403
|
+
if (writeFiles) {
|
|
339
404
|
fs.writeFileSync(filePath, sP);
|
|
405
|
+
files.push(filePath);
|
|
406
|
+
}
|
|
340
407
|
// now, append the permissions to the return string IF we did NOT generate the function - because if we generated the function, that
|
|
341
408
|
// means we already generated the permissions for it above and it is part of sRet already, but we always save it to a file, (per above line)
|
|
342
409
|
if (!entity.FullTextSearchFunctionGenerated)
|
|
343
410
|
sRet += sP + '\nGO\n';
|
|
344
411
|
}
|
|
345
|
-
return { sql: sRet, permissionsSQL: permissionsSQL };
|
|
412
|
+
return { sql: sRet, permissionsSQL: permissionsSQL, files: files };
|
|
346
413
|
}
|
|
347
414
|
catch (err) {
|
|
348
415
|
(0, logging_1.logError)(err);
|
|
@@ -555,6 +622,9 @@ let SQLCodeGenBase = class SQLCodeGenBase {
|
|
|
555
622
|
const relatedFieldsString = await this.generateBaseViewRelatedFieldsString(ds, entity.Fields);
|
|
556
623
|
const relatedFieldsJoinString = this.generateBaseViewJoins(entity.Fields);
|
|
557
624
|
const permissions = this.generateViewPermissions(entity);
|
|
625
|
+
const whereClause = entity.DeleteType === 'Soft' ? `WHERE
|
|
626
|
+
${baseTableFirstChar}.[${core_1.EntityInfo.DeletedAtFieldName}] IS NULL
|
|
627
|
+
` : '';
|
|
558
628
|
return `
|
|
559
629
|
------------------------------------------------------------
|
|
560
630
|
----- BASE VIEW FOR ENTITY: ${entity.Name}
|
|
@@ -571,7 +641,7 @@ SELECT
|
|
|
571
641
|
${baseTableFirstChar}.*${relatedFieldsString.length > 0 ? ',' : ''}${relatedFieldsString}
|
|
572
642
|
FROM
|
|
573
643
|
[${entity.SchemaName}].[${entity.BaseTable}] AS ${baseTableFirstChar}${relatedFieldsJoinString ? '\n' + relatedFieldsJoinString : ''}
|
|
574
|
-
GO${permissions}
|
|
644
|
+
${whereClause}GO${permissions}
|
|
575
645
|
`;
|
|
576
646
|
}
|
|
577
647
|
generateViewPermissions(entity) {
|
|
@@ -597,38 +667,37 @@ GO${permissions}
|
|
|
597
667
|
let sOutput = '';
|
|
598
668
|
let fieldCount = 0;
|
|
599
669
|
const manageMD = global_1.MJGlobal.Instance.ClassFactory.CreateInstance(manage_metadata_1.ManageMetadataBase);
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
}
|
|
630
|
-
fieldCount++;
|
|
670
|
+
// next get the fields that are related entities and have the IncludeRelatedEntityNameFieldInBaseView flag set to true
|
|
671
|
+
const qualifyingFields = entityFields.filter(f => f.RelatedEntityID && f.IncludeRelatedEntityNameFieldInBaseView);
|
|
672
|
+
for (const ef of qualifyingFields) {
|
|
673
|
+
const { nameField, nameFieldIsVirtual } = this.getIsNameFieldForSingleEntity(ef.RelatedEntity);
|
|
674
|
+
if (nameField !== '') {
|
|
675
|
+
// only add to the output, if we found a name field for the related entity.
|
|
676
|
+
ef._RelatedEntityTableAlias = ef.RelatedEntityClassName + '_' + ef.Name;
|
|
677
|
+
ef._RelatedEntityNameFieldIsVirtual = nameFieldIsVirtual;
|
|
678
|
+
// This next section generates a field name for the new virtual field and makes sure it doesn't collide with a field in the base table
|
|
679
|
+
const candidateName = this.stripID(ef.Name);
|
|
680
|
+
// check to make sure candidateName is not already a field name in the base table (other than a virtual field of course, as that is what we're creating)
|
|
681
|
+
// because if it is, we need to change it to something else
|
|
682
|
+
const bFound = entityFields.find(f => f.IsVirtual === false && f.Name.trim().toLowerCase() === candidateName.trim().toLowerCase()) !== undefined;
|
|
683
|
+
if (bFound)
|
|
684
|
+
ef._RelatedEntityNameFieldMap = candidateName + '_Virtual';
|
|
685
|
+
else
|
|
686
|
+
ef._RelatedEntityNameFieldMap = candidateName;
|
|
687
|
+
// now we have a safe field name alias for the new virtual field in the _RelatedEntityNameFieldMap property, so use it...
|
|
688
|
+
sOutput += `${fieldCount === 0 ? '' : ','}\n ${ef._RelatedEntityTableAlias}.[${nameField}] AS [${ef._RelatedEntityNameFieldMap}]`;
|
|
689
|
+
// check to see if the database already knows about the RelatedEntityNameFieldMap or not
|
|
690
|
+
if (ef.RelatedEntityNameFieldMap === null ||
|
|
691
|
+
ef.RelatedEntityNameFieldMap === undefined ||
|
|
692
|
+
ef.RelatedEntityNameFieldMap.trim().length === 0) {
|
|
693
|
+
// the database doesn't yet know about this RelatedEntityNameFieldMap, so we need to update it
|
|
694
|
+
// first update the actul field in the metadata object so it can be used from this point forward
|
|
695
|
+
// and it also reflects what the DB will hold
|
|
696
|
+
ef.RelatedEntityNameFieldMap = ef._RelatedEntityNameFieldMap;
|
|
697
|
+
// then update the database itself
|
|
698
|
+
await manageMD.updateEntityFieldRelatedEntityNameFieldMap(ds, ef.ID, ef.RelatedEntityNameFieldMap);
|
|
631
699
|
}
|
|
700
|
+
fieldCount++;
|
|
632
701
|
}
|
|
633
702
|
}
|
|
634
703
|
return sOutput;
|
|
@@ -673,9 +742,12 @@ GO${permissions}
|
|
|
673
742
|
}
|
|
674
743
|
generateSPCreate(entity) {
|
|
675
744
|
const spName = entity.spCreate ? entity.spCreate : `spCreate${entity.ClassName}`;
|
|
676
|
-
const
|
|
745
|
+
const firstKey = entity.FirstPrimaryKey;
|
|
746
|
+
const primaryKeyAutomatic = firstKey.AutoIncrement || (firstKey.Type.toLowerCase().trim() === 'uniqueidentifier' && firstKey.DefaultValue && firstKey.DefaultValue.trim().length > 0);
|
|
747
|
+
const efString = this.createEntityFieldsParamString(entity.Fields, !primaryKeyAutomatic);
|
|
677
748
|
const permissions = this.generateSPPermissions(entity, spName, exports.SPType.Create);
|
|
678
|
-
let
|
|
749
|
+
let preInsertCode = '';
|
|
750
|
+
let outputCode = '';
|
|
679
751
|
let selectInsertedRecord = '';
|
|
680
752
|
let additionalFieldList = '';
|
|
681
753
|
let additionalValueList = '';
|
|
@@ -683,10 +755,29 @@ GO${permissions}
|
|
|
683
755
|
selectInsertedRecord = `SELECT * FROM [${entity.SchemaName}].[${entity.BaseView}] WHERE [${entity.FirstPrimaryKey.Name}] = SCOPE_IDENTITY()`;
|
|
684
756
|
}
|
|
685
757
|
else if (entity.FirstPrimaryKey.Type.toLowerCase().trim() === 'uniqueidentifier') {
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
758
|
+
// our primary key is a uniqueidentifier. Two scenarios exist for this:
|
|
759
|
+
// 1) The default value is specified in the database (usually either NEWID() or NEWSEQUENTIALID()).
|
|
760
|
+
// 2) No default value is specified, so we need to generate a new GUID in the stored procedure using NEWID() --- NewSequentialID() is not allowed in a stored procedure, only usable as a default value.
|
|
761
|
+
// so, first check to see if there is a default value for the field or not
|
|
762
|
+
const hasDefaultValue = entity.FirstPrimaryKey.DefaultValue && entity.FirstPrimaryKey.DefaultValue.trim().length > 0;
|
|
763
|
+
// if we have a default value, then we do NOT want to insert a new value, let the database use the default
|
|
764
|
+
if (hasDefaultValue) {
|
|
765
|
+
// in this situation, we DO have a default value, so we do NOT insert a new value, we let the database use the default
|
|
766
|
+
// however, we need to do some extra preprocessing to use the OUTPUT from the INSERT statement and return the record that was
|
|
767
|
+
// just created, that is how we get the newly created GUID that was the default value
|
|
768
|
+
preInsertCode = `DECLARE @InsertedRow TABLE ([${entity.FirstPrimaryKey.Name}] UNIQUEIDENTIFIER)`;
|
|
769
|
+
outputCode = `OUTPUT INSERTED.[${entity.FirstPrimaryKey.Name}] INTO @InsertedRow
|
|
770
|
+
`;
|
|
771
|
+
selectInsertedRecord = `SELECT * FROM [${entity.SchemaName}].[${entity.BaseView}] WHERE [${entity.FirstPrimaryKey.Name}] = (SELECT [${entity.FirstPrimaryKey.Name}] FROM @InsertedRow)`;
|
|
772
|
+
}
|
|
773
|
+
else {
|
|
774
|
+
// we have no default value, so we use NEWID() to generate a new GUID and we manually insert it into the table
|
|
775
|
+
// as part of the sproc
|
|
776
|
+
preInsertCode = `DECLARE @newId UNIQUEIDENTIFIER = NEWID();\n SET @${entity.FirstPrimaryKey.Name} = @newId;\n`;
|
|
777
|
+
additionalFieldList = ',\n [' + entity.FirstPrimaryKey.Name + ']';
|
|
778
|
+
additionalValueList = ',\n @newId';
|
|
779
|
+
selectInsertedRecord = `SELECT * FROM [${entity.SchemaName}].[${entity.BaseView}] WHERE [${entity.FirstPrimaryKey.Name}] = @newId`;
|
|
780
|
+
}
|
|
690
781
|
}
|
|
691
782
|
else {
|
|
692
783
|
selectInsertedRecord = `SELECT * FROM [${entity.SchemaName}].[${entity.BaseView}] WHERE `;
|
|
@@ -710,13 +801,13 @@ CREATE PROCEDURE [${entity.SchemaName}].[${spName}]
|
|
|
710
801
|
AS
|
|
711
802
|
BEGIN
|
|
712
803
|
SET NOCOUNT ON;
|
|
713
|
-
${
|
|
804
|
+
${preInsertCode}
|
|
714
805
|
INSERT INTO
|
|
715
806
|
[${entity.SchemaName}].[${entity.BaseTable}]
|
|
716
807
|
(
|
|
717
808
|
${this.createEntityFieldsInsertString(entity, entity.Fields, '')}${additionalFieldList}
|
|
718
809
|
)
|
|
719
|
-
VALUES
|
|
810
|
+
${outputCode}VALUES
|
|
720
811
|
(
|
|
721
812
|
${this.createEntityFieldsInsertString(entity, entity.Fields, '@')}${additionalValueList}
|
|
722
813
|
)
|
|
@@ -822,14 +913,17 @@ ${updatedAtTrigger}
|
|
|
822
913
|
if ((!ef.IsPrimaryKey || !autoGeneratedPrimaryKey) &&
|
|
823
914
|
ef.IsVirtual === false &&
|
|
824
915
|
ef.AllowUpdateAPI &&
|
|
825
|
-
ef.AutoIncrement === false
|
|
826
|
-
ef.Type.trim().toLowerCase() !== 'uniqueidentifier') {
|
|
916
|
+
ef.AutoIncrement === false) {
|
|
827
917
|
if (!isFirst)
|
|
828
918
|
sOutput += ',\n ';
|
|
829
919
|
else
|
|
830
920
|
isFirst = false;
|
|
831
|
-
if (prefix !== '' && ef.IsSpecialDateField)
|
|
832
|
-
|
|
921
|
+
if (prefix !== '' && ef.IsSpecialDateField) {
|
|
922
|
+
if (ef.IsCreatedAtField || ef.IsUpdatedAtField)
|
|
923
|
+
sOutput += `GETUTCDATE()`; // we set the inserted row value to the current date for created and updated at fields
|
|
924
|
+
else
|
|
925
|
+
sOutput += `NULL`; // we don't set the deleted at field on an insert, only on a delete
|
|
926
|
+
}
|
|
833
927
|
else {
|
|
834
928
|
let sVal = prefix + (prefix !== '' ? ef.CodeName : ef.Name); // if we have a prefix, then we need to use the CodeName, otherwise we use the actual field name
|
|
835
929
|
if (!prefix || prefix.length === 0)
|
|
@@ -848,8 +942,7 @@ ${updatedAtTrigger}
|
|
|
848
942
|
!ef.IsVirtual &&
|
|
849
943
|
ef.AllowUpdateAPI &&
|
|
850
944
|
!ef.AutoIncrement &&
|
|
851
|
-
!ef.IsSpecialDateField
|
|
852
|
-
ef.Type.toLowerCase().trim() !== 'uniqueidentifier') {
|
|
945
|
+
!ef.IsSpecialDateField) {
|
|
853
946
|
if (!isFirst)
|
|
854
947
|
sOutput += ',\n ';
|
|
855
948
|
else
|
|
@@ -873,6 +966,23 @@ ${updatedAtTrigger}
|
|
|
873
966
|
sSelect += ', ';
|
|
874
967
|
sSelect += `@${k.CodeName} AS [${k.Name}]`;
|
|
875
968
|
}
|
|
969
|
+
// next up, create the delete code which is based on the type of delete the entity is set to
|
|
970
|
+
// start off by creating the where clause first and then prepend the delete or update statement to it
|
|
971
|
+
let deleteCode = ` WHERE
|
|
972
|
+
${entity.PrimaryKeys.map(k => `[${k.Name}] = @${k.CodeName}`).join(' AND ')}
|
|
973
|
+
`;
|
|
974
|
+
if (entity.DeleteType === 'Hard') {
|
|
975
|
+
deleteCode = ` DELETE FROM
|
|
976
|
+
[${entity.SchemaName}].[${entity.BaseTable}]
|
|
977
|
+
${deleteCode}`;
|
|
978
|
+
}
|
|
979
|
+
else {
|
|
980
|
+
deleteCode = ` UPDATE
|
|
981
|
+
[${entity.SchemaName}].[${entity.BaseTable}]
|
|
982
|
+
SET
|
|
983
|
+
${core_1.EntityInfo.DeletedAtFieldName} = GETUTCDATE()
|
|
984
|
+
${deleteCode} AND ${core_1.EntityInfo.DeletedAtFieldName} IS NULL -- don't update the record if it's already been deleted via a soft delete`;
|
|
985
|
+
}
|
|
876
986
|
return `
|
|
877
987
|
------------------------------------------------------------
|
|
878
988
|
----- DELETE PROCEDURE FOR ${entity.BaseTable}
|
|
@@ -886,10 +996,7 @@ AS
|
|
|
886
996
|
BEGIN
|
|
887
997
|
SET NOCOUNT ON;${sCascadeDeletes}
|
|
888
998
|
|
|
889
|
-
|
|
890
|
-
[${entity.SchemaName}].[${entity.BaseTable}]
|
|
891
|
-
WHERE
|
|
892
|
-
${entity.PrimaryKeys.map(k => `[${k.Name}] = @${k.CodeName}`).join(' AND ')}
|
|
999
|
+
${deleteCode}
|
|
893
1000
|
|
|
894
1001
|
SELECT ${sSelect} -- Return the primary key to indicate we successfully deleted the record
|
|
895
1002
|
END
|