@memberjunction/codegen-lib 1.0.6 → 1.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/dist/advanced_generation.d.ts +3 -0
  2. package/dist/advanced_generation.d.ts.map +1 -1
  3. package/dist/advanced_generation.js +39 -26
  4. package/dist/advanced_generation.js.map +1 -1
  5. package/dist/angular_client_codegen.d.ts +45 -2
  6. package/dist/angular_client_codegen.d.ts.map +1 -1
  7. package/dist/angular_client_codegen.js +423 -399
  8. package/dist/angular_client_codegen.js.map +1 -1
  9. package/dist/createNewUser.d.ts +6 -1
  10. package/dist/createNewUser.d.ts.map +1 -1
  11. package/dist/createNewUser.js +68 -53
  12. package/dist/createNewUser.js.map +1 -1
  13. package/dist/dbSchema.d.ts +10 -3
  14. package/dist/dbSchema.d.ts.map +1 -1
  15. package/dist/dbSchema.js +144 -130
  16. package/dist/dbSchema.js.map +1 -1
  17. package/dist/entity_subclasses_codegen.d.ts +11 -6
  18. package/dist/entity_subclasses_codegen.d.ts.map +1 -1
  19. package/dist/entity_subclasses_codegen.js +144 -131
  20. package/dist/entity_subclasses_codegen.js.map +1 -1
  21. package/dist/graphql_server_codegen.d.ts +28 -5
  22. package/dist/graphql_server_codegen.d.ts.map +1 -1
  23. package/dist/graphql_server_codegen.js +552 -531
  24. package/dist/graphql_server_codegen.js.map +1 -1
  25. package/dist/logging.d.ts +20 -0
  26. package/dist/logging.d.ts.map +1 -1
  27. package/dist/logging.js +61 -26
  28. package/dist/logging.js.map +1 -1
  29. package/dist/manageMetadata.d.ts +128 -7
  30. package/dist/manageMetadata.d.ts.map +1 -1
  31. package/dist/manageMetadata.js +992 -898
  32. package/dist/manageMetadata.js.map +1 -1
  33. package/dist/runCodeGen.d.ts +16 -0
  34. package/dist/runCodeGen.d.ts.map +1 -1
  35. package/dist/runCodeGen.js +185 -140
  36. package/dist/runCodeGen.js.map +1 -1
  37. package/dist/runCommand.d.ts +7 -2
  38. package/dist/runCommand.d.ts.map +1 -1
  39. package/dist/runCommand.js +104 -90
  40. package/dist/runCommand.js.map +1 -1
  41. package/dist/sql.d.ts +21 -16
  42. package/dist/sql.d.ts.map +1 -1
  43. package/dist/sql.js +98 -87
  44. package/dist/sql.js.map +1 -1
  45. package/dist/sql_codegen.d.ts +56 -13
  46. package/dist/sql_codegen.d.ts.map +1 -1
  47. package/dist/sql_codegen.js +836 -795
  48. package/dist/sql_codegen.js.map +1 -1
  49. package/dist/util.js +0 -2
  50. package/dist/util.js.map +1 -1
  51. package/package.json +32 -32
  52. package/readme.md +2 -2
  53. package/dist/graphql_client_codegen.d.ts +0 -4
  54. package/dist/graphql_client_codegen.js +0 -161
  55. package/dist/graphql_client_codegen.js.map +0 -1
  56. package/dist/react_client_codegen.d.ts +0 -4
  57. package/dist/react_client_codegen.js +0 -147
  58. package/dist/react_client_codegen.js.map +0 -1
@@ -1,575 +1,596 @@
1
1
  "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
2
8
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
9
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
10
  };
5
11
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.generateEntitySpecificServerFileHeader = exports.generateAllEntitiesServerFileHeader = exports.generateServerEntityString = exports.generateGraphQLServerCode = void 0;
12
+ exports.GraphQLServerGeneratorBase = void 0;
7
13
  const core_1 = require("@memberjunction/core");
8
14
  const fs_1 = __importDefault(require("fs"));
9
15
  const path_1 = __importDefault(require("path"));
10
16
  const logging_1 = require("./logging");
11
17
  const config_1 = require("./config");
12
18
  const util_1 = require("./util");
13
- function generateGraphQLServerCode(entities, outputDirectory, generatedEntitiesImportLibrary, excludeRelatedEntitiesExternalToSchema) {
14
- let sRet = '';
15
- try {
16
- sRet = generateAllEntitiesServerFileHeader(entities, generatedEntitiesImportLibrary);
17
- for (let i = 0; i < entities.length; ++i) {
18
- sRet += generateServerEntityString(entities[i], false, generatedEntitiesImportLibrary, excludeRelatedEntitiesExternalToSchema);
19
+ const global_1 = require("@memberjunction/global");
20
+ /**
21
+ * This class is responsible for generating the GraphQL Server resolvers and types for the entities, you can sub-class this class to extend/modify the logic, make sure to use @memberjunction/global RegisterClass decorator
22
+ * so that your class is used.
23
+ */
24
+ let GraphQLServerGeneratorBase = class GraphQLServerGeneratorBase {
25
+ constructor() {
26
+ this._graphQLTypeSuffix = '_';
27
+ }
28
+ generateGraphQLServerCode(entities, outputDirectory, generatedEntitiesImportLibrary, excludeRelatedEntitiesExternalToSchema) {
29
+ let sRet = '';
30
+ try {
31
+ sRet = this.generateAllEntitiesServerFileHeader(entities, generatedEntitiesImportLibrary);
32
+ for (let i = 0; i < entities.length; ++i) {
33
+ sRet += this.generateServerEntityString(entities[i], false, generatedEntitiesImportLibrary, excludeRelatedEntitiesExternalToSchema);
34
+ }
35
+ (0, util_1.makeDir)(outputDirectory);
36
+ fs_1.default.writeFileSync(path_1.default.join(outputDirectory, 'generated.ts'), sRet);
37
+ return true;
38
+ }
39
+ catch (err) {
40
+ (0, logging_1.logError)(err);
41
+ return false;
19
42
  }
20
- (0, util_1.makeDir)(outputDirectory);
21
- fs_1.default.writeFileSync(path_1.default.join(outputDirectory, 'generated.ts'), sRet);
22
- return true;
23
43
  }
24
- catch (err) {
25
- (0, logging_1.logError)(err);
26
- return false;
44
+ /**
45
+ * The suffix to append to the GraphQL Type name, default is an underscore, override this property in your sub-class to change the suffix
46
+ */
47
+ get GraphQLTypeSuffix() {
48
+ return this._graphQLTypeSuffix;
27
49
  }
28
- }
29
- exports.generateGraphQLServerCode = generateGraphQLServerCode;
30
- const _graphQLTypeSuffix = '_';
31
- function generateServerEntityString(entity, includeFileHeader, generatedEntitiesImportLibrary, excludeRelatedEntitiesExternalToSchema) {
32
- let sEntityOutput = '';
33
- try {
34
- const md = new core_1.Metadata();
35
- const fields = entity.Fields;
36
- const serverGraphQLTypeName = entity.ClassName + _graphQLTypeSuffix;
37
- if (includeFileHeader)
38
- sEntityOutput = generateEntitySpecificServerFileHeader(entity, generatedEntitiesImportLibrary, excludeRelatedEntitiesExternalToSchema);
39
- sEntityOutput += generateServerEntityHeader(entity, serverGraphQLTypeName);
40
- // now generate the fields by looping through the fields collection from the database
41
- for (let j = 0; j < fields.length; ++j) {
42
- sEntityOutput += generateServerField(fields[j]);
43
- }
44
- for (let j = 0; j < entity.RelatedEntities.length; ++j) {
45
- const r = entity.RelatedEntities[j];
46
- const re = md.Entities.find(e => e.Name.toLowerCase() === r.RelatedEntity.toLowerCase());
47
- // only include the relationship if we are IncludeInAPI for the related entity
48
- if (re.IncludeInAPI) {
49
- if (!excludeRelatedEntitiesExternalToSchema || re.SchemaName === entity.SchemaName) {
50
- // only include the relationship if either we are NOT excluding related entities external to the schema
51
- // or if the related entity is in the same schema as the current entity
52
- sEntityOutput += generateServerRelationship(md, entity.RelatedEntities[j]);
50
+ generateServerEntityString(entity, includeFileHeader, generatedEntitiesImportLibrary, excludeRelatedEntitiesExternalToSchema) {
51
+ let sEntityOutput = '';
52
+ try {
53
+ const md = new core_1.Metadata();
54
+ const fields = entity.Fields;
55
+ const serverGraphQLTypeName = entity.ClassName + this.GraphQLTypeSuffix;
56
+ if (includeFileHeader)
57
+ sEntityOutput = this.generateEntitySpecificServerFileHeader(entity, generatedEntitiesImportLibrary, excludeRelatedEntitiesExternalToSchema);
58
+ sEntityOutput += this.generateServerEntityHeader(entity, serverGraphQLTypeName);
59
+ // now generate the fields by looping through the fields collection from the database
60
+ for (let j = 0; j < fields.length; ++j) {
61
+ sEntityOutput += this.generateServerField(fields[j]);
62
+ }
63
+ for (let j = 0; j < entity.RelatedEntities.length; ++j) {
64
+ const r = entity.RelatedEntities[j];
65
+ const re = md.Entities.find(e => e.Name.toLowerCase() === r.RelatedEntity.toLowerCase());
66
+ // only include the relationship if we are IncludeInAPI for the related entity
67
+ if (re.IncludeInAPI) {
68
+ if (!excludeRelatedEntitiesExternalToSchema || re.SchemaName === entity.SchemaName) {
69
+ // only include the relationship if either we are NOT excluding related entities external to the schema
70
+ // or if the related entity is in the same schema as the current entity
71
+ sEntityOutput += this.generateServerRelationship(md, entity.RelatedEntities[j]);
72
+ }
73
+ }
74
+ else {
75
+ sEntityOutput += `// Relationship to ${r.RelatedEntity} is not included in the API because it is not marked as IncludeInAPI\n`;
53
76
  }
54
77
  }
55
- else {
56
- sEntityOutput += `// Relationship to ${r.RelatedEntity} is not included in the API because it is not marked as IncludeInAPI\n`;
78
+ // finally, close it up with the footer
79
+ sEntityOutput += this.generateServerEntityFooter(entity);
80
+ sEntityOutput += this.generateServerGraphQLResolver(entity, serverGraphQLTypeName, excludeRelatedEntitiesExternalToSchema);
81
+ }
82
+ catch (err) {
83
+ (0, logging_1.logError)(err);
84
+ }
85
+ finally {
86
+ return sEntityOutput;
87
+ }
88
+ }
89
+ generateAllEntitiesServerFileHeader(entities, importLibrary) {
90
+ let sRet = `/********************************************************************************
91
+ * ALL ENTITIES - TypeGraphQL Type Class Definition - AUTO GENERATED FILE
92
+ * Generated Entities and Resolvers for Server
93
+ *
94
+ * GENERATED: ${new Date().toLocaleString()}
95
+ *
96
+ * >>> DO NOT MODIFY THIS FILE!!!!!!!!!!!!
97
+ * >>> YOUR CHANGES WILL BE OVERWRITTEN
98
+ * >>> THE NEXT TIME THIS FILE IS GENERATED
99
+ *
100
+ **********************************************************************************/
101
+ import { Arg, Ctx, Int, Query, Resolver, Field, Float, ObjectType, FieldResolver, Root, InputType, Mutation,
102
+ PubSub, PubSubEngine, ResolverBase, RunViewByIDInput, RunViewByNameInput, RunDynamicViewInput } from '@memberjunction/server';
103
+ import { Metadata, EntityPermissionType } from '@memberjunction/core'
104
+ import { AppContext } from '@memberjunction/server';
105
+
106
+ import { MaxLength } from 'class-validator';
107
+ import { DataSource } from 'typeorm';
108
+ ${importLibrary.trim().toLowerCase() === '@memberjunction/core-entities' ? `import { mj_core_schema } from '../config';\n` : ''}
109
+ import * as mj_core_schema_server_object_types from '@memberjunction/server'
110
+
111
+ import { ${entities.map(e => `${e.ClassName}Entity`).join(', ')} } from '${importLibrary}';
112
+ `;
113
+ return sRet;
114
+ }
115
+ generateEntitySpecificServerFileHeader(entity, importLibrary, excludeRelatedEntitiesExternalToSchema) {
116
+ const md = new core_1.Metadata();
117
+ let sRet = `/********************************************************************************
118
+ * ${entity.Name} TypeORM/TypeGraphQL Type Class Definition - AUTO GENERATED FILE
119
+ *
120
+ * GENERATED: ${new Date().toLocaleString()}
121
+ *
122
+ * >>> DO NOT MODIFY THIS FILE!!!!!!!!!!!!
123
+ * >>> YOUR CHANGES WILL BE OVERWRITTEN
124
+ * >>> THE NEXT TIME THIS FILE IS GENERATED
125
+ *
126
+ **********************************************************************************/
127
+ import { MaxLength } from 'class-validator';
128
+ import { Field, ${entity._floatCount > 0 ? 'Float, ' : ''}Int, ObjectType } from '@memberjunction/server';
129
+ import { ${`${entity.ClassName}Entity`} } from '${importLibrary}';
130
+ `;
131
+ for (let i = 0; i < entity.RelatedEntities.length; ++i) {
132
+ const r = entity.RelatedEntities[i];
133
+ const re = md.Entities.find(e => e.Name.toLowerCase() == r.RelatedEntity.toLowerCase());
134
+ if (!excludeRelatedEntitiesExternalToSchema || re.SchemaName === entity.SchemaName) {
135
+ // we only include entities that are in the same schema as the current entity
136
+ // OR if we are not excluding related entities external to the schema
137
+ const tableName = entity.RelatedEntities[i].RelatedEntityBaseTableCodeName;
138
+ sRet += `\nimport ${tableName} from './${tableName}';`;
57
139
  }
58
140
  }
59
- // finally, close it up with the footer
60
- sEntityOutput += generateServerEntityFooter(entity);
61
- sEntityOutput += generateServerGraphQLResolver(entity, serverGraphQLTypeName, excludeRelatedEntitiesExternalToSchema);
141
+ return sRet;
62
142
  }
63
- catch (err) {
64
- (0, logging_1.logError)(err);
143
+ generateServerEntityHeader(entity, serverGraphQLTypeName) {
144
+ let sDescription = entity.Description?.trim().length > 0 ? entity.Description : '';
145
+ if (sDescription.includes("'"))
146
+ sDescription = sDescription.replace(/'/g, "\\'");
147
+ return `
148
+
149
+ //****************************************************************************
150
+ // ENTITY CLASS for ${entity.Name}
151
+ //****************************************************************************
152
+ @ObjectType(${sDescription.length > 0 ? `{ description: '${sDescription}' }` : ''})
153
+ export class ${serverGraphQLTypeName} {`;
65
154
  }
66
- finally {
67
- return sEntityOutput;
155
+ generateServerEntityFooter(entity) {
156
+ if (!entity)
157
+ (0, logging_1.logError)("entity parameter must be passed in to generateServerEntityFooter()");
158
+ return `\n}`;
68
159
  }
69
- }
70
- exports.generateServerEntityString = generateServerEntityString;
71
- function generateAllEntitiesServerFileHeader(entities, importLibrary) {
72
- let sRet = `/********************************************************************************
73
- * ALL ENTITIES - TypeGraphQL Type Class Definition - AUTO GENERATED FILE
74
- * Generated Entities and Resolvers for Server
75
- *
76
- * GENERATED: ${new Date().toLocaleString()}
77
- *
78
- * >>> DO NOT MODIFY THIS FILE!!!!!!!!!!!!
79
- * >>> YOUR CHANGES WILL BE OVERWRITTEN
80
- * >>> THE NEXT TIME THIS FILE IS GENERATED
81
- *
82
- **********************************************************************************/
83
- import { Arg, Ctx, Int, Query, Resolver, Field, Float, ObjectType, FieldResolver, Root, InputType, Mutation,
84
- PubSub, PubSubEngine, ResolverBase, RunViewByIDInput, RunViewByNameInput, RunDynamicViewInput } from '@memberjunction/server';
85
- import { Metadata, EntityPermissionType } from '@memberjunction/core'
86
- import { AppContext } from '@memberjunction/server';
87
-
88
- import { MaxLength } from 'class-validator';
89
- import { DataSource } from 'typeorm';
90
- ${importLibrary.trim().toLowerCase() === '@memberjunction/core-entities' ? `import { mj_core_schema } from '../config';\n` : ''}
91
- import * as mj_core_schema_server_object_types from '@memberjunction/server'
92
-
93
- import { ${entities.map(e => `${e.ClassName}Entity`).join(', ')} } from '${importLibrary}';
94
- `;
95
- return sRet;
96
- }
97
- exports.generateAllEntitiesServerFileHeader = generateAllEntitiesServerFileHeader;
98
- function generateEntitySpecificServerFileHeader(entity, importLibrary, excludeRelatedEntitiesExternalToSchema) {
99
- const md = new core_1.Metadata();
100
- let sRet = `/********************************************************************************
101
- * ${entity.Name} TypeORM/TypeGraphQL Type Class Definition - AUTO GENERATED FILE
102
- *
103
- * GENERATED: ${new Date().toLocaleString()}
104
- *
105
- * >>> DO NOT MODIFY THIS FILE!!!!!!!!!!!!
106
- * >>> YOUR CHANGES WILL BE OVERWRITTEN
107
- * >>> THE NEXT TIME THIS FILE IS GENERATED
108
- *
109
- **********************************************************************************/
110
- import { MaxLength } from 'class-validator';
111
- import { Field, ${entity._floatCount > 0 ? 'Float, ' : ''}Int, ObjectType } from '@memberjunction/server';
112
- import { ${`${entity.ClassName}Entity`} } from '${importLibrary}';
113
- `;
114
- for (let i = 0; i < entity.RelatedEntities.length; ++i) {
115
- const r = entity.RelatedEntities[i];
116
- const re = md.Entities.find(e => e.Name.toLowerCase() == r.RelatedEntity.toLowerCase());
117
- if (!excludeRelatedEntitiesExternalToSchema || re.SchemaName === entity.SchemaName) {
118
- // we only include entities that are in the same schema as the current entity
119
- // OR if we are not excluding related entities external to the schema
120
- const tableName = entity.RelatedEntities[i].RelatedEntityBaseTableCodeName;
121
- sRet += `\nimport ${tableName} from './${tableName}';`;
160
+ generateServerField(fieldInfo) {
161
+ const fieldString = this.getTypeGraphQLFieldString(fieldInfo);
162
+ let fieldOptions = '';
163
+ if (fieldInfo.AllowsNull)
164
+ fieldOptions += 'nullable: true';
165
+ if (fieldInfo.Description !== null && fieldInfo.Description.trim().length > 0)
166
+ fieldOptions += (fieldOptions.length > 0 ? ', ' : '') + `description: '${fieldInfo.Description.replace(/'/g, "\\'")}'`;
167
+ return `
168
+ @Field(${fieldString}${fieldOptions.length > 0 ? (fieldString == '' ? '' : ', ') + `{${fieldOptions}}` : ''}) ${fieldInfo.Length > 0 && fieldString == '' /*string*/ ? '\n @MaxLength(' + fieldInfo.Length + ')' : ''}
169
+ ${fieldInfo.CodeName}${fieldInfo.AllowsNull ? '?' : ''}: ${(0, core_1.TypeScriptTypeFromSQLType)(fieldInfo.Type)};
170
+ `;
171
+ }
172
+ getTypeGraphQLFieldString(fieldInfo) {
173
+ switch (fieldInfo.Type.toLowerCase()) {
174
+ case 'text':
175
+ case 'char':
176
+ case 'varchar':
177
+ case 'ntext':
178
+ case 'nchar':
179
+ case 'nvarchar':
180
+ case 'uniqueidentifier': //treat this as a string
181
+ return '';
182
+ case 'datetime':
183
+ case 'datetimeoffset':
184
+ case 'date':
185
+ case 'time':
186
+ return '';
187
+ case 'bit':
188
+ return "() => Boolean";
189
+ case 'decimal':
190
+ case 'numeric':
191
+ case 'float':
192
+ case 'real':
193
+ case 'money':
194
+ case 'smallmoney':
195
+ fieldInfo.IsFloat = true; // used by calling functions to determine if we need to import Float
196
+ return '() => Float';
197
+ default:
198
+ return '() => Int';
122
199
  }
123
200
  }
124
- return sRet;
125
- }
126
- exports.generateEntitySpecificServerFileHeader = generateEntitySpecificServerFileHeader;
127
- function generateServerEntityHeader(entity, serverGraphQLTypeName) {
128
- let sDescription = entity.Description?.trim().length > 0 ? entity.Description : '';
129
- if (sDescription.includes("'"))
130
- sDescription = sDescription.replace(/'/g, "\\'");
131
- return `
132
-
133
- //****************************************************************************
134
- // ENTITY CLASS for ${entity.Name}
135
- //****************************************************************************
136
- @ObjectType(${sDescription.length > 0 ? `{ description: '${sDescription}' }` : ''})
137
- export class ${serverGraphQLTypeName} {`;
138
- }
139
- function generateServerEntityFooter(entity) {
140
- if (!entity)
141
- (0, logging_1.logError)("entity parameter must be passed in to generateServerEntityFooter()");
142
- return `\n}`;
143
- }
144
- function generateServerField(fieldInfo) {
145
- const fieldString = getTypeGraphQLFieldString(fieldInfo);
146
- let fieldOptions = '';
147
- if (fieldInfo.AllowsNull)
148
- fieldOptions += 'nullable: true';
149
- if (fieldInfo.Description !== null && fieldInfo.Description.trim().length > 0)
150
- fieldOptions += (fieldOptions.length > 0 ? ', ' : '') + `description: '${fieldInfo.Description.replace(/'/g, "\\'")}'`;
151
- return `
152
- @Field(${fieldString}${fieldOptions.length > 0 ? (fieldString == '' ? '' : ', ') + `{${fieldOptions}}` : ''}) ${fieldInfo.Length > 0 && fieldString == '' /*string*/ ? '\n @MaxLength(' + fieldInfo.Length + ')' : ''}
153
- ${fieldInfo.CodeName}${fieldInfo.AllowsNull ? '?' : ''}: ${(0, core_1.TypeScriptTypeFromSQLType)(fieldInfo.Type)};
201
+ generateServerRelationship(md, r) {
202
+ const re = md.Entities.find(e => e.Name.toLowerCase() === r.RelatedEntity.toLowerCase());
203
+ const classPackagePrefix = re.SchemaName === config_1.mjCoreSchema ? 'mj_core_schema_server_object_types.' : '';
204
+ const relatedClassName = classPackagePrefix + r.RelatedEntityBaseTableCodeName;
205
+ if (r.Type.toLowerCase().trim() == 'one to many') {
206
+ return `
207
+ @Field(() => [${relatedClassName + this.GraphQLTypeSuffix}])
208
+ ${r.RelatedEntityCodeName}Array: ${relatedClassName + this.GraphQLTypeSuffix}[]; // Link to ${r.RelatedEntityCodeName}
154
209
  `;
155
- }
156
- function getTypeGraphQLFieldString(fieldInfo) {
157
- switch (fieldInfo.Type.toLowerCase()) {
158
- case 'text':
159
- case 'char':
160
- case 'varchar':
161
- case 'ntext':
162
- case 'nchar':
163
- case 'nvarchar':
164
- case 'uniqueidentifier': //treat this as a string
165
- return '';
166
- case 'datetime':
167
- case 'datetimeoffset':
168
- case 'date':
169
- case 'time':
170
- return '';
171
- case 'bit':
172
- return "() => Boolean";
173
- case 'decimal':
174
- case 'numeric':
175
- case 'float':
176
- case 'real':
177
- case 'money':
178
- case 'smallmoney':
179
- fieldInfo.IsFloat = true; // used by calling functions to determine if we need to import Float
180
- return '() => Float';
181
- default:
182
- return '() => Int';
210
+ }
211
+ else { // many to many
212
+ return `
213
+ @Field(() => [${relatedClassName + this.GraphQLTypeSuffix}])
214
+ ${r.RelatedEntityCodeName}Array: ${relatedClassName + this.GraphQLTypeSuffix}[]; // Link to ${r.RelatedEntity}
215
+ `;
216
+ }
183
217
  }
218
+ generateServerGraphQLResolver(entity, serverGraphQLTypeName, excludeRelatedEntitiesExternalToSchema) {
219
+ const md = new core_1.Metadata();
220
+ let sRet = '';
221
+ // we only generate resolvers for entities that have a primary key field
222
+ if (entity.PrimaryKeys.length > 0) {
223
+ // first add in the base resolver query to lookup by ID for all entities
224
+ const auditAccessCode = entity.AuditRecordAccess ? `
225
+ this.createRecordAccessAuditLogRecord(userPayload, '${entity.Name}', ${entity.PrimaryKey.Name})` : '';
226
+ sRet = `
227
+ //****************************************************************************
228
+ // RESOLVER for ${entity.Name}
229
+ //****************************************************************************
230
+ @ObjectType()
231
+ export class Run${entity.BaseTableCodeName}ViewResult {
232
+ @Field(() => [${serverGraphQLTypeName}])
233
+ Results: ${serverGraphQLTypeName}[];
234
+
235
+ @Field(() => Int, {nullable: true})
236
+ UserViewRunID?: number;
237
+
238
+ @Field(() => Int, {nullable: true})
239
+ RowCount: number;
240
+
241
+ @Field(() => Int, {nullable: true})
242
+ TotalRowCount: number;
243
+
244
+ @Field(() => Int, {nullable: true})
245
+ ExecutionTime: number;
246
+
247
+ @Field({nullable: true})
248
+ ErrorMessage?: string;
249
+
250
+ @Field(() => Boolean, {nullable: false})
251
+ Success: boolean;
184
252
  }
185
- function generateServerRelationship(md, r) {
186
- const re = md.Entities.find(e => e.Name.toLowerCase() === r.RelatedEntity.toLowerCase());
187
- const classPackagePrefix = re.SchemaName === config_1.mjCoreSchema ? 'mj_core_schema_server_object_types.' : '';
188
- const relatedClassName = classPackagePrefix + r.RelatedEntityBaseTableCodeName;
189
- if (r.Type.toLowerCase().trim() == 'one to many') {
190
- return `
191
- @Field(() => [${relatedClassName + _graphQLTypeSuffix}])
192
- ${r.RelatedEntityCodeName}Array: ${relatedClassName + _graphQLTypeSuffix}[]; // Link to ${r.RelatedEntityCodeName}
193
- `;
194
- }
195
- else { // many to many
196
- return `
197
- @Field(() => [${relatedClassName + _graphQLTypeSuffix}])
198
- ${r.RelatedEntityCodeName}Array: ${relatedClassName + _graphQLTypeSuffix}[]; // Link to ${r.RelatedEntity}
199
- `;
253
+
254
+ @Resolver(${serverGraphQLTypeName})
255
+ export class ${entity.BaseTableCodeName}Resolver${entity.CustomResolverAPI ? 'Base' : ''} extends ResolverBase {
256
+ @Query(() => Run${entity.BaseTableCodeName}ViewResult)
257
+ async Run${entity.BaseTableCodeName}ViewByID(@Arg('input', () => RunViewByIDInput) input: RunViewByIDInput, @Ctx() { dataSource, userPayload }: AppContext, @PubSub() pubSub: PubSubEngine) {
258
+ return super.RunViewByIDGeneric(input, dataSource, userPayload, pubSub);
200
259
  }
201
- }
202
- function generateServerGraphQLResolver(entity, serverGraphQLTypeName, excludeRelatedEntitiesExternalToSchema) {
203
- const md = new core_1.Metadata();
204
- let sRet = '';
205
- // we only generate resolvers for entities that have a primary key field
206
- if (entity.PrimaryKeys.length > 0) {
207
- // first add in the base resolver query to lookup by ID for all entities
208
- const auditAccessCode = entity.AuditRecordAccess ? `
209
- this.createRecordAccessAuditLogRecord(userPayload, '${entity.Name}', ${entity.PrimaryKey.Name})` : '';
210
- sRet = `
211
- //****************************************************************************
212
- // RESOLVER for ${entity.Name}
213
- //****************************************************************************
214
- @ObjectType()
215
- export class Run${entity.BaseTableCodeName}ViewResult {
216
- @Field(() => [${serverGraphQLTypeName}])
217
- Results: ${serverGraphQLTypeName}[];
218
-
219
- @Field(() => Int, {nullable: true})
220
- UserViewRunID?: number;
221
-
222
- @Field(() => Int, {nullable: true})
223
- RowCount: number;
224
-
225
- @Field(() => Int, {nullable: true})
226
- TotalRowCount: number;
227
-
228
- @Field(() => Int, {nullable: true})
229
- ExecutionTime: number;
230
-
231
- @Field({nullable: true})
232
- ErrorMessage?: string;
233
-
234
- @Field(() => Boolean, {nullable: false})
235
- Success: boolean;
236
- }
237
-
238
- @Resolver(${serverGraphQLTypeName})
239
- export class ${entity.BaseTableCodeName}Resolver${entity.CustomResolverAPI ? 'Base' : ''} extends ResolverBase {
240
- @Query(() => Run${entity.BaseTableCodeName}ViewResult)
241
- async Run${entity.BaseTableCodeName}ViewByID(@Arg('input', () => RunViewByIDInput) input: RunViewByIDInput, @Ctx() { dataSource, userPayload }: AppContext, @PubSub() pubSub: PubSubEngine) {
242
- return super.RunViewByIDGeneric(input, dataSource, userPayload, pubSub);
243
- }
244
-
245
- @Query(() => Run${entity.BaseTableCodeName}ViewResult)
246
- async Run${entity.BaseTableCodeName}ViewByName(@Arg('input', () => RunViewByNameInput) input: RunViewByNameInput, @Ctx() { dataSource, userPayload }: AppContext, @PubSub() pubSub: PubSubEngine) {
247
- return super.RunViewByNameGeneric(input, dataSource, userPayload, pubSub);
248
- }
249
-
250
- @Query(() => Run${entity.BaseTableCodeName}ViewResult)
251
- async Run${entity.BaseTableCodeName}DynamicView(@Arg('input', () => RunDynamicViewInput) input: RunDynamicViewInput, @Ctx() { dataSource, userPayload }: AppContext, @PubSub() pubSub: PubSubEngine) {
252
- input.EntityName = '${entity.Name}';
253
- return super.RunDynamicViewGeneric(input, dataSource, userPayload, pubSub);
260
+
261
+ @Query(() => Run${entity.BaseTableCodeName}ViewResult)
262
+ async Run${entity.BaseTableCodeName}ViewByName(@Arg('input', () => RunViewByNameInput) input: RunViewByNameInput, @Ctx() { dataSource, userPayload }: AppContext, @PubSub() pubSub: PubSubEngine) {
263
+ return super.RunViewByNameGeneric(input, dataSource, userPayload, pubSub);
264
+ }
265
+
266
+ @Query(() => Run${entity.BaseTableCodeName}ViewResult)
267
+ async Run${entity.BaseTableCodeName}DynamicView(@Arg('input', () => RunDynamicViewInput) input: RunDynamicViewInput, @Ctx() { dataSource, userPayload }: AppContext, @PubSub() pubSub: PubSubEngine) {
268
+ input.EntityName = '${entity.Name}';
269
+ return super.RunDynamicViewGeneric(input, dataSource, userPayload, pubSub);
254
270
  }`;
255
- let graphQLPKEYArgs = '';
256
- let whereClause = '';
257
- for (let i = 0; i < entity.PrimaryKeys.length; i++) {
258
- const pk = entity.PrimaryKeys[i];
259
- const idQuotes = pk.NeedsQuotes ? "'" : '';
260
- graphQLPKEYArgs += (graphQLPKEYArgs.length > 0 ? ', ' : '');
261
- graphQLPKEYArgs += `@Arg('${pk.CodeName}', () => ${pk.GraphQLType}) `;
262
- graphQLPKEYArgs += `${pk.CodeName}: ${pk.TSType}`;
263
- whereClause += (whereClause.length > 0 ? ' AND ' : '');
264
- whereClause += `[${pk.CodeName}]=${idQuotes}\${${pk.CodeName}}${idQuotes}`;
265
- }
266
- sRet += `
267
- @Query(() => ${serverGraphQLTypeName}, { nullable: true })
268
- async ${entity.BaseTableCodeName}(${graphQLPKEYArgs}, @Ctx() { dataSource, userPayload }: AppContext, @PubSub() pubSub: PubSubEngine): Promise<${serverGraphQLTypeName} | null> {
269
- this.CheckUserReadPermissions('${entity.Name}', userPayload);
270
- const sSQL = \`SELECT * FROM [${schemaName(entity)}].[${entity.BaseView}] WHERE ${whereClause} \` + this.getRowLevelSecurityWhereClause('${entity.Name}', userPayload, EntityPermissionType.Read, 'AND');${auditAccessCode}
271
- const result = this.MapFieldNamesToCodeNames('${entity.Name}', await dataSource.query(sSQL).then((r) => r && r.length > 0 ? r[0] : {}))
272
- return result;
273
- }
274
- `;
275
- if (entity.AllowAllRowsAPI) {
276
- // this entity allows a query to return all rows, so include that type of query next
277
- sRet += `
278
- @Query(() => [${serverGraphQLTypeName}])
279
- async All${entity.CodeName}(@Ctx() { dataSource, userPayload }: AppContext, @PubSub() pubSub: PubSubEngine) {
280
- this.CheckUserReadPermissions('${entity.Name}', userPayload);
281
- const sSQL = \`SELECT * FROM [${schemaName(entity)}].[${entity.BaseView}]\` + this.getRowLevelSecurityWhereClause('${entity.Name}', userPayload, EntityPermissionType.Read, ' WHERE');
282
- const result = this.ArrayMapFieldNamesToCodeNames('${entity.Name}', await dataSource.query(sSQL));
283
- return result;
284
- }
285
- `;
286
- }
287
- // now, generate the FieldResolvers for each of the one-to-many relationships
288
- for (let i = 0; i < entity.RelatedEntities.length; i++) {
289
- const r = entity.RelatedEntities[i];
290
- const re = md.Entities.find(e => e.Name.toLowerCase() === r.RelatedEntity.toLowerCase());
291
- // only include the relationship if we are IncludeInAPI for the related entity
292
- if (re.IncludeInAPI) {
293
- if (!excludeRelatedEntitiesExternalToSchema || re.SchemaName === entity.SchemaName) {
294
- // only include the relationship if either we are NOT excluding related entities external to the schema
295
- // or if the related entity is in the same schema as the current entity
296
- if (r.Type.toLowerCase().trim() == 'many to many')
297
- sRet += generateManyToManyFieldResolver(entity, r);
298
- else
299
- sRet += generateOneToManyFieldResolver(entity, r);
271
+ let graphQLPKEYArgs = '';
272
+ let whereClause = '';
273
+ for (let i = 0; i < entity.PrimaryKeys.length; i++) {
274
+ const pk = entity.PrimaryKeys[i];
275
+ const idQuotes = pk.NeedsQuotes ? "'" : '';
276
+ graphQLPKEYArgs += (graphQLPKEYArgs.length > 0 ? ', ' : '');
277
+ graphQLPKEYArgs += `@Arg('${pk.CodeName}', () => ${pk.GraphQLType}) `;
278
+ graphQLPKEYArgs += `${pk.CodeName}: ${pk.TSType}`;
279
+ whereClause += (whereClause.length > 0 ? ' AND ' : '');
280
+ whereClause += `[${pk.CodeName}]=${idQuotes}\${${pk.CodeName}}${idQuotes}`;
281
+ }
282
+ sRet += `
283
+ @Query(() => ${serverGraphQLTypeName}, { nullable: true })
284
+ async ${entity.BaseTableCodeName}(${graphQLPKEYArgs}, @Ctx() { dataSource, userPayload }: AppContext, @PubSub() pubSub: PubSubEngine): Promise<${serverGraphQLTypeName} | null> {
285
+ this.CheckUserReadPermissions('${entity.Name}', userPayload);
286
+ const sSQL = \`SELECT * FROM [${this.schemaName(entity)}].[${entity.BaseView}] WHERE ${whereClause} \` + this.getRowLevelSecurityWhereClause('${entity.Name}', userPayload, EntityPermissionType.Read, 'AND');${auditAccessCode}
287
+ const result = this.MapFieldNamesToCodeNames('${entity.Name}', await dataSource.query(sSQL).then((r) => r && r.length > 0 ? r[0] : {}))
288
+ return result;
289
+ }
290
+ `;
291
+ if (entity.AllowAllRowsAPI) {
292
+ // this entity allows a query to return all rows, so include that type of query next
293
+ sRet += `
294
+ @Query(() => [${serverGraphQLTypeName}])
295
+ async All${entity.CodeName}(@Ctx() { dataSource, userPayload }: AppContext, @PubSub() pubSub: PubSubEngine) {
296
+ this.CheckUserReadPermissions('${entity.Name}', userPayload);
297
+ const sSQL = \`SELECT * FROM [${this.schemaName(entity)}].[${entity.BaseView}]\` + this.getRowLevelSecurityWhereClause('${entity.Name}', userPayload, EntityPermissionType.Read, ' WHERE');
298
+ const result = this.ArrayMapFieldNamesToCodeNames('${entity.Name}', await dataSource.query(sSQL));
299
+ return result;
300
+ }
301
+ `;
302
+ }
303
+ // now, generate the FieldResolvers for each of the one-to-many relationships
304
+ for (let i = 0; i < entity.RelatedEntities.length; i++) {
305
+ const r = entity.RelatedEntities[i];
306
+ const re = md.Entities.find(e => e.Name.toLowerCase() === r.RelatedEntity.toLowerCase());
307
+ // only include the relationship if we are IncludeInAPI for the related entity
308
+ if (re.IncludeInAPI) {
309
+ if (!excludeRelatedEntitiesExternalToSchema || re.SchemaName === entity.SchemaName) {
310
+ // only include the relationship if either we are NOT excluding related entities external to the schema
311
+ // or if the related entity is in the same schema as the current entity
312
+ if (r.Type.toLowerCase().trim() == 'many to many')
313
+ sRet += this.generateManyToManyFieldResolver(entity, r);
314
+ else
315
+ sRet += this.generateOneToManyFieldResolver(entity, r);
316
+ }
317
+ }
318
+ else {
319
+ sRet += `// Relationship to ${r.RelatedEntity} is not included in the API because it is not marked as IncludeInAPI\n`;
300
320
  }
301
321
  }
302
- else {
303
- sRet += `// Relationship to ${r.RelatedEntity} is not included in the API because it is not marked as IncludeInAPI\n`;
322
+ // now do the mutations
323
+ const sInputType = this.generateServerGraphQLInputType(entity);
324
+ if (sInputType !== '') {
325
+ // only generate mutations if we have input type, because otherwsie we don't need em
326
+ sRet += this.generateServerGraphQLMutations(entity, serverGraphQLTypeName);
327
+ }
328
+ sRet += `\n}`;
329
+ if (sInputType !== '') {
330
+ sRet = sInputType + sRet; // put the input type before the resolver as the decorators have to be evaluated ahead of their use in the resolver
304
331
  }
305
332
  }
306
- // now do the mutations
307
- const sInputType = generateServerGraphQLInputType(entity);
308
- if (sInputType !== '') {
309
- // only generate mutations if we have input type, because otherwsie we don't need em
310
- sRet += generateServerGraphQLMutations(entity, serverGraphQLTypeName);
311
- }
312
- sRet += `\n}`;
313
- if (sInputType !== '') {
314
- sRet = sInputType + sRet; // put the input type before the resolver as the decorators have to be evaluated ahead of their use in the resolver
333
+ return sRet;
334
+ }
335
+ schemaName(entity) {
336
+ if (entity.SchemaName === config_1.mjCoreSchema) {
337
+ return '${Metadata.Provider.ConfigData.MJCoreSchemaName}';
315
338
  }
339
+ else
340
+ return entity.SchemaName; // put the actual schema name in
316
341
  }
317
- return sRet;
318
- }
319
- function schemaName(entity) {
320
- if (entity.SchemaName === config_1.mjCoreSchema) {
321
- return '${Metadata.Provider.ConfigData.MJCoreSchemaName}';
342
+ generateServerGraphQLInputType(entity) {
343
+ let sRet = '';
344
+ if (entity.AllowCreateAPI)
345
+ sRet += this.generateServerGraphQLInputTypeInner(entity, false, 'Create');
346
+ if (entity.AllowUpdateAPI)
347
+ sRet += this.generateServerGraphQLInputTypeInner(entity, true, 'Update');
348
+ return sRet;
322
349
  }
323
- else
324
- return entity.SchemaName; // put the actual schema name in
325
- }
326
- function generateServerGraphQLInputType(entity) {
327
- let sRet = '';
328
- if (entity.AllowCreateAPI)
329
- sRet += generateServerGraphQLInputTypeInner(entity, false, 'Create');
330
- if (entity.AllowUpdateAPI)
331
- sRet += generateServerGraphQLInputTypeInner(entity, true, 'Update');
332
- return sRet;
333
- }
334
- function generateServerGraphQLInputTypeInner(entity, isUpdate, classPrefix) {
335
- let sRet = '';
336
- sRet += `\n
337
- //****************************************************************************
338
- // INPUT TYPE for ${entity.Name}
339
- //****************************************************************************
340
- @InputType()
350
+ generateServerGraphQLInputTypeInner(entity, isUpdate, classPrefix) {
351
+ let sRet = '';
352
+ sRet += `\n
353
+ //****************************************************************************
354
+ // INPUT TYPE for ${entity.Name}
355
+ //****************************************************************************
356
+ @InputType()
341
357
  export class ${classPrefix}${entity.BaseTableCodeName}Input {`;
342
- for (let i = 0; i < entity.Fields.length; i++) {
343
- const f = entity.Fields[i];
344
- const sTypeGraphQLString = getTypeGraphQLFieldString(f);
345
- const sNull = f.AllowsNull ? '{ nullable: true }' : '';
346
- const sFullTypeGraphQLString = sTypeGraphQLString + (sNull === '' || sTypeGraphQLString === '' ? '' : ', ') + sNull;
347
- // always include ID becuase it is used for UPDATES
348
- const includePrimaryKey = isUpdate || (!f.AutoIncrement && f.Type !== 'uniqueidentifier'); // include primary key for updates and also for creates if it is not an autoincrement field or a uniqueidentifier
349
- if ((includePrimaryKey && f.IsPrimaryKey) || (!f.IsPrimaryKey && !f.IsVirtual && f.AllowUpdateAPI && f.Type.trim().toLowerCase() !== 'uniqueidentifier')) {
350
- sRet += `
351
- @Field(${sFullTypeGraphQLString})
352
- ${f.CodeName}: ${(0, core_1.TypeScriptTypeFromSQLType)(f.Type)};
353
- `;
358
+ for (let i = 0; i < entity.Fields.length; i++) {
359
+ const f = entity.Fields[i];
360
+ const sTypeGraphQLString = this.getTypeGraphQLFieldString(f);
361
+ const sNull = f.AllowsNull ? '{ nullable: true }' : '';
362
+ const sFullTypeGraphQLString = sTypeGraphQLString + (sNull === '' || sTypeGraphQLString === '' ? '' : ', ') + sNull;
363
+ // always include ID becuase it is used for UPDATES
364
+ const includePrimaryKey = isUpdate || (!f.AutoIncrement && f.Type !== 'uniqueidentifier'); // include primary key for updates and also for creates if it is not an autoincrement field or a uniqueidentifier
365
+ if ((includePrimaryKey && f.IsPrimaryKey) || (!f.IsPrimaryKey && !f.IsVirtual && f.AllowUpdateAPI && f.Type.trim().toLowerCase() !== 'uniqueidentifier')) {
366
+ sRet += `
367
+ @Field(${sFullTypeGraphQLString})
368
+ ${f.CodeName}: ${(0, core_1.TypeScriptTypeFromSQLType)(f.Type)};
369
+ `;
370
+ }
354
371
  }
355
- }
356
- sRet += `}
357
- `;
358
- return sRet;
359
- }
360
- function generateServerGraphQLMutations(entity, serverGraphQLTypeName) {
361
- let sRet = '';
362
- // MUTATIONS
363
- // First, determine if the entity has either Create/Edit allowed, if either, we need to generate a InputType
364
- if (entity.AllowCreateAPI && !entity.VirtualEntity) {
365
- // generate a create mutation
366
- sRet += `
367
- @Mutation(() => ${serverGraphQLTypeName})
368
- async Create${entity.BaseTableCodeName}(
369
- @Arg('input', () => Create${entity.BaseTableCodeName}Input) input: Create${entity.BaseTableCodeName}Input,
370
- @Ctx() { dataSource, userPayload }: AppContext,
371
- @PubSub() pubSub: PubSubEngine
372
- ) {
373
- if (await this.BeforeCreate(dataSource, input)) { // fire event and proceed if it wasn't cancelled
374
- const entityObject = <${`${entity.ClassName}Entity`}>await new Metadata().GetEntityObject('${entity.Name}', this.GetUserFromPayload(userPayload));
375
- await entityObject.NewRecord();
376
- entityObject.SetMany(input);
377
- if (await entityObject.Save()) {
378
- // save worked, fire the AfterCreate event and then return all the data
379
- await this.AfterCreate(dataSource, input); // fire event
380
- return entityObject.GetAll();
381
- }
382
- else
383
- // save failed, return null
384
- return null;
385
- }
386
- else
387
- return null;
388
- }
389
-
390
- // Before/After CREATE Event Hooks for Sub-Classes to Override
391
- protected async BeforeCreate(dataSource: DataSource, input: Create${entity.BaseTableCodeName}Input): Promise<boolean> {
392
- return true;
393
- }
394
- protected async AfterCreate(dataSource: DataSource, input: Create${entity.BaseTableCodeName}Input) {
395
- }
372
+ sRet += `}
396
373
  `;
374
+ return sRet;
375
+ }
376
+ generateServerGraphQLMutations(entity, serverGraphQLTypeName) {
377
+ let sRet = '';
378
+ // MUTATIONS
379
+ // First, determine if the entity has either Create/Edit allowed, if either, we need to generate a InputType
380
+ if (entity.AllowCreateAPI && !entity.VirtualEntity) {
381
+ // generate a create mutation
382
+ sRet += `
383
+ @Mutation(() => ${serverGraphQLTypeName})
384
+ async Create${entity.BaseTableCodeName}(
385
+ @Arg('input', () => Create${entity.BaseTableCodeName}Input) input: Create${entity.BaseTableCodeName}Input,
386
+ @Ctx() { dataSource, userPayload }: AppContext,
387
+ @PubSub() pubSub: PubSubEngine
388
+ ) {
389
+ if (await this.BeforeCreate(dataSource, input)) { // fire event and proceed if it wasn't cancelled
390
+ const entityObject = <${`${entity.ClassName}Entity`}>await new Metadata().GetEntityObject('${entity.Name}', this.GetUserFromPayload(userPayload));
391
+ await entityObject.NewRecord();
392
+ entityObject.SetMany(input);
393
+ if (await entityObject.Save()) {
394
+ // save worked, fire the AfterCreate event and then return all the data
395
+ await this.AfterCreate(dataSource, input); // fire event
396
+ return entityObject.GetAll();
397
+ }
398
+ else
399
+ // save failed, return null
400
+ return null;
401
+ }
402
+ else
403
+ return null;
404
+ }
405
+
406
+ // Before/After CREATE Event Hooks for Sub-Classes to Override
407
+ protected async BeforeCreate(dataSource: DataSource, input: Create${entity.BaseTableCodeName}Input): Promise<boolean> {
408
+ return true;
397
409
  }
398
- if (entity.AllowUpdateAPI && !entity.VirtualEntity) {
399
- // generate an edit mutation
400
- const loadParamString = entity.PrimaryKeys.map(f => `input.${f.CodeName}`).join(', ');
401
- sRet += `
402
- @Mutation(() => ${serverGraphQLTypeName})
403
- async Update${entity.BaseTableCodeName}(
404
- @Arg('input', () => Update${entity.BaseTableCodeName}Input) input: Update${entity.BaseTableCodeName}Input,
405
- @Ctx() { dataSource, userPayload }: AppContext,
406
- @PubSub() pubSub: PubSubEngine
407
- ) {
408
- if (await this.BeforeUpdate(dataSource, input)) { // fire event and proceed if it wasn't cancelled
409
- const entityObject = <${`${entity.ClassName}Entity`}>await new Metadata().GetEntityObject('${entity.Name}', this.GetUserFromPayload(userPayload));
410
+ protected async AfterCreate(dataSource: DataSource, input: Create${entity.BaseTableCodeName}Input) {
411
+ }
412
+ `;
413
+ }
414
+ if (entity.AllowUpdateAPI && !entity.VirtualEntity) {
415
+ // generate an edit mutation
416
+ const loadParamString = entity.PrimaryKeys.map(f => `input.${f.CodeName}`).join(', ');
417
+ sRet += `
418
+ @Mutation(() => ${serverGraphQLTypeName})
419
+ async Update${entity.BaseTableCodeName}(
420
+ @Arg('input', () => Update${entity.BaseTableCodeName}Input) input: Update${entity.BaseTableCodeName}Input,
421
+ @Ctx() { dataSource, userPayload }: AppContext,
422
+ @PubSub() pubSub: PubSubEngine
423
+ ) {
424
+ if (await this.BeforeUpdate(dataSource, input)) { // fire event and proceed if it wasn't cancelled
425
+ const entityObject = <${`${entity.ClassName}Entity`}>await new Metadata().GetEntityObject('${entity.Name}', this.GetUserFromPayload(userPayload));
410
426
  ${entity.TrackRecordChanges ? `await entityObject.Load(${loadParamString}) // Track Changes is turned on, so we need to get the latest data from DB first before we save` :
411
- `entityObject.LoadFromData(input) // using the input instead of loading from DB because TrackChanges is turned off for ${entity.Name}`}
412
- ${entity.TrackRecordChanges ? 'entityObject.SetMany(input);' : ''}
413
- if (await entityObject.Save(${entity.TrackRecordChanges ? '' : '{ IgnoreDirtyState: true /*flag used because of LoadFromData() call above*/ }'})) {
414
- // save worked, fire afterevent and return all the data
415
- await this.AfterUpdate(dataSource, input); // fire event
416
- return entityObject.GetAll();
417
- }
418
- else
419
- return null; // save failed, return null
420
- }
421
- else
422
- return null;
423
- }
424
-
425
- // Before/After UPDATE Event Hooks for Sub-Classes to Override
426
- protected async BeforeUpdate(dataSource: DataSource, input: Update${entity.BaseTableCodeName}Input): Promise<boolean> {
427
- const i = input, d = dataSource; // prevent error
428
- return true;
429
- }
430
- protected async AfterUpdate(dataSource: DataSource, input: Update${entity.BaseTableCodeName}Input) {
431
- const i = input, d = dataSource; // prevent error
432
- }
433
- `;
434
- }
435
- if (entity.AllowDeleteAPI && !entity.VirtualEntity) {
436
- let graphQLPKEYArgs = '';
437
- let simplePKEYArgs = '';
438
- let pkeys = '';
439
- let whereClause = '';
440
- for (let i = 0; i < entity.PrimaryKeys.length; i++) {
441
- const pk = entity.PrimaryKeys[i];
442
- const idQuotes = pk.NeedsQuotes ? "'" : '';
443
- graphQLPKEYArgs += (graphQLPKEYArgs.length > 0 ? ', ' : '');
444
- graphQLPKEYArgs += `@Arg('${pk.CodeName}', () => ${pk.GraphQLType}) `;
445
- graphQLPKEYArgs += `${pk.CodeName}: ${pk.TSType}`;
446
- simplePKEYArgs += (simplePKEYArgs.length > 0 ? ', ' : '');
447
- simplePKEYArgs += `${pk.CodeName}: ${pk.TSType}`;
448
- pkeys += (pkeys.length > 0 ? ', ' : '');
449
- pkeys += `${pk.CodeName}`;
450
- whereClause += (whereClause.length > 0 ? ' AND ' : '');
451
- whereClause += `[${pk.CodeName}]=${idQuotes}\${${pk.CodeName}}${idQuotes}`;
427
+ `entityObject.LoadFromData(input) // using the input instead of loading from DB because TrackChanges is turned off for ${entity.Name}`}
428
+ ${entity.TrackRecordChanges ? 'entityObject.SetMany(input);' : ''}
429
+ if (await entityObject.Save(${entity.TrackRecordChanges ? '' : '{ IgnoreDirtyState: true /*flag used because of LoadFromData() call above*/ }'})) {
430
+ // save worked, fire afterevent and return all the data
431
+ await this.AfterUpdate(dataSource, input); // fire event
432
+ return entityObject.GetAll();
433
+ }
434
+ else
435
+ return null; // save failed, return null
452
436
  }
453
- sRet += `
454
- @Mutation(() => ${serverGraphQLTypeName})
455
- async Delete${entity.BaseTableCodeName}(${graphQLPKEYArgs}, @Ctx() { dataSource, userPayload }: AppContext, @PubSub() pubSub: PubSubEngine) {
456
- if (await this.BeforeDelete(dataSource, ${pkeys})) { // fire event and proceed if it wasn't cancelled
457
- const entityObject = <${`${entity.ClassName}Entity`}>await new Metadata().GetEntityObject('${entity.Name}', this.GetUserFromPayload(userPayload));
458
- await entityObject.Load(${pkeys});
459
- const returnValue = entityObject.GetAll(); // grab the values before we delete so we can return last state before delete if we are successful.
460
- if (await entityObject.Delete()) {
461
- await this.AfterDelete(dataSource, ${pkeys}); // fire event
462
- return returnValue;
463
- }
464
- else
465
- return null; // delete failed, this will cause an exception
466
- }
467
- else
468
- return null; // BeforeDelete canceled the operation, this will cause an exception
469
- }
470
-
471
- // Before/After UPDATE Event Hooks for Sub-Classes to Override
472
- protected async BeforeDelete(dataSource: DataSource, ${simplePKEYArgs}): Promise<boolean> {
473
- const i = ${entity.PrimaryKey.Name}, d = dataSource; // prevent error;
474
- return true;
475
- }
476
- protected async AfterDelete(dataSource: DataSource, ${simplePKEYArgs}) {
477
- const i = ${entity.PrimaryKey.Name}, d = dataSource; // prevent error
478
- }
479
- `;
480
- }
481
- return sRet;
482
- }
483
- // function generateSPParams(entity: EntityInfo, isUpdate: boolean): string {
484
- // let sRet: string = '',bFirst: boolean = true;
485
- // for (let i = 0; i < entity.Fields.length; i++) {
486
- // const f = entity.Fields[i];
487
- // if (!f.IsVirtual) {
488
- // switch (f.Name.toLowerCase()) {
489
- // case 'id':
490
- // if (isUpdate) {
491
- // sRet += generateSingleSPParam(f, bFirst);
492
- // bFirst = false;
493
- // }
494
- // break;
495
- // case 'createdat':
496
- // case 'updatedat':
497
- // // do nothing
498
- // break;
499
- // default:
500
- // if (f.Type.trim().toLowerCase() !== 'uniqueidentifier') {
501
- // // DO NOT INCLUDE UNIQUEIDENTIFIER FIELDS
502
- // // FOR CREATE/UPDATE, THEY ARE GENERATED BY THE DB
503
- // sRet += generateSingleSPParam(f, bFirst);
504
- // bFirst = false;
505
- // }
506
- // break;
507
- // }
508
- // }
509
- // }
510
- // return sRet;
511
- // }
512
- // function generateSingleSPParam(f: EntityFieldInfo, isFirst: boolean): string {
513
- // let sRet: string = '';
514
- // let quotes: string = '';
515
- // switch ( TypeScriptTypeFromSQLType(f.Type).toLowerCase() ) {
516
- // case 'string':
517
- // case 'date':
518
- // quotes = "'";
519
- // break;
520
- // default:
521
- // break;
522
- // }
523
- // if (!isFirst)
524
- // sRet += ',\n ';
525
- // sRet += `@${f.Name}=\${this.packageSPParam(input.${f.Name},"${quotes}")}`
526
- // return sRet;
527
- // }
528
- function generateOneToManyFieldResolver(entity, r) {
529
- // let keyFieldTS: string = 'number';
530
- // if (r.EntityKeyField) {
531
- // const keyField = entity.Fields.find(f => f.Name.toLowerCase() == r.EntityKeyField.toLowerCase())
532
- // keyFieldTS = keyField ? TypeScriptTypeFromSQLType(keyField.Type) : 'int';
533
- // }
534
- const md = new core_1.Metadata();
535
- const re = md.Entities.find(e => e.Name.toLowerCase() == r.RelatedEntity.toLowerCase());
536
- const instanceName = entity.BaseTableCodeName.toLowerCase() + _graphQLTypeSuffix;
537
- const filterFieldName = !r.EntityKeyField ? entity.PrimaryKey.Name : r.EntityKeyField;
538
- const filterField = entity.Fields.find(f => f.Name.toLowerCase() == filterFieldName.toLowerCase());
539
- if (!filterField)
540
- throw new Error(`Field ${filterFieldName} not found in entity ${entity.Name} - check the relationship ${r.ID} and the EntityKeyField property`);
541
- const quotes = filterField.NeedsQuotes ? "'" : '';
542
- const serverPackagePrefix = re.SchemaName === config_1.mjCoreSchema ? 'mj_core_schema_server_object_types.' : '';
543
- const serverClassName = serverPackagePrefix + r.RelatedEntityBaseTableCodeName + _graphQLTypeSuffix;
544
- return `
545
- @FieldResolver(() => [${serverClassName}])
546
- async ${r.RelatedEntityCodeName}Array(@Root() ${instanceName}: ${entity.BaseTableCodeName + _graphQLTypeSuffix}, @Ctx() { dataSource, userPayload }: AppContext, @PubSub() pubSub: PubSubEngine) {
547
- this.CheckUserReadPermissions('${r.RelatedEntity}', userPayload);
548
- const sSQL = \`SELECT * FROM [${schemaName(re)}].[${r.RelatedEntityBaseView}]\ WHERE [${r.RelatedEntityJoinField}]=${quotes}\${${instanceName}.${filterFieldName}}${quotes} \` + this.getRowLevelSecurityWhereClause('${r.RelatedEntity}', userPayload, EntityPermissionType.Read, 'AND');
549
- const result = this.ArrayMapFieldNamesToCodeNames('${r.RelatedEntity}', await dataSource.query(sSQL));
550
- return result;
551
- }
437
+ else
438
+ return null;
439
+ }
440
+
441
+ // Before/After UPDATE Event Hooks for Sub-Classes to Override
442
+ protected async BeforeUpdate(dataSource: DataSource, input: Update${entity.BaseTableCodeName}Input): Promise<boolean> {
443
+ const i = input, d = dataSource; // prevent error
444
+ return true;
445
+ }
446
+ protected async AfterUpdate(dataSource: DataSource, input: Update${entity.BaseTableCodeName}Input) {
447
+ const i = input, d = dataSource; // prevent error
448
+ }
552
449
  `;
553
- }
554
- function generateManyToManyFieldResolver(entity, r) {
555
- const md = new core_1.Metadata();
556
- const re = md.Entities.find(e => e.Name.toLowerCase() == r.RelatedEntity.toLowerCase());
557
- const instanceName = entity.BaseTableCodeName.toLowerCase() + _graphQLTypeSuffix;
558
- const filterFieldName = !r.EntityKeyField ? entity.PrimaryKey.Name : r.EntityKeyField;
559
- const filterField = entity.Fields.find(f => f.Name.toLowerCase() == filterFieldName.toLowerCase());
560
- if (!filterField)
561
- throw new Error(`Field ${filterFieldName} not found in entity ${entity.Name} - check the relationship ${r.ID} and the EntityKeyField property`);
562
- const quotes = filterField.NeedsQuotes ? "'" : '';
563
- const serverPackagePrefix = re.SchemaName === config_1.mjCoreSchema ? 'mj_core_schema_server_object_types.' : '';
564
- const serverClassName = serverPackagePrefix + r.RelatedEntityBaseTableCodeName + _graphQLTypeSuffix;
565
- return `
566
- @FieldResolver(() => [${serverClassName}])
567
- async ${r.RelatedEntityCodeName}Array(@Root() ${instanceName}: ${entity.BaseTableCodeName + _graphQLTypeSuffix}, @Ctx() { dataSource, userPayload }: AppContext, @PubSub() pubSub: PubSubEngine) {
568
- this.CheckUserReadPermissions('${r.RelatedEntity}', userPayload);
569
- const sSQL = \`SELECT * FROM [${schemaName(re)}].[${r.RelatedEntityBaseView}]\ WHERE [${re.PrimaryKey.Name}] IN (SELECT [${r.JoinEntityInverseJoinField}] FROM [${schemaName(re)}].[${r.JoinView}] WHERE [${r.JoinEntityJoinField}]=${quotes}\${${instanceName}.${filterFieldName}}${quotes}) \` + this.getRowLevelSecurityWhereClause('${r.RelatedEntity}', userPayload, EntityPermissionType.Read, 'AND');
570
- const result = this.ArrayMapFieldNamesToCodeNames('${r.RelatedEntity}', await dataSource.query(sSQL));
571
- return result;
572
- }
450
+ }
451
+ if (entity.AllowDeleteAPI && !entity.VirtualEntity) {
452
+ let graphQLPKEYArgs = '';
453
+ let simplePKEYArgs = '';
454
+ let pkeys = '';
455
+ let whereClause = '';
456
+ for (let i = 0; i < entity.PrimaryKeys.length; i++) {
457
+ const pk = entity.PrimaryKeys[i];
458
+ const idQuotes = pk.NeedsQuotes ? "'" : '';
459
+ graphQLPKEYArgs += (graphQLPKEYArgs.length > 0 ? ', ' : '');
460
+ graphQLPKEYArgs += `@Arg('${pk.CodeName}', () => ${pk.GraphQLType}) `;
461
+ graphQLPKEYArgs += `${pk.CodeName}: ${pk.TSType}`;
462
+ simplePKEYArgs += (simplePKEYArgs.length > 0 ? ', ' : '');
463
+ simplePKEYArgs += `${pk.CodeName}: ${pk.TSType}`;
464
+ pkeys += (pkeys.length > 0 ? ', ' : '');
465
+ pkeys += `${pk.CodeName}`;
466
+ whereClause += (whereClause.length > 0 ? ' AND ' : '');
467
+ whereClause += `[${pk.CodeName}]=${idQuotes}\${${pk.CodeName}}${idQuotes}`;
468
+ }
469
+ sRet += `
470
+ @Mutation(() => ${serverGraphQLTypeName})
471
+ async Delete${entity.BaseTableCodeName}(${graphQLPKEYArgs}, @Ctx() { dataSource, userPayload }: AppContext, @PubSub() pubSub: PubSubEngine) {
472
+ if (await this.BeforeDelete(dataSource, ${pkeys})) { // fire event and proceed if it wasn't cancelled
473
+ const entityObject = <${`${entity.ClassName}Entity`}>await new Metadata().GetEntityObject('${entity.Name}', this.GetUserFromPayload(userPayload));
474
+ await entityObject.Load(${pkeys});
475
+ const returnValue = entityObject.GetAll(); // grab the values before we delete so we can return last state before delete if we are successful.
476
+ if (await entityObject.Delete()) {
477
+ await this.AfterDelete(dataSource, ${pkeys}); // fire event
478
+ return returnValue;
479
+ }
480
+ else
481
+ return null; // delete failed, this will cause an exception
482
+ }
483
+ else
484
+ return null; // BeforeDelete canceled the operation, this will cause an exception
485
+ }
486
+
487
+ // Before/After UPDATE Event Hooks for Sub-Classes to Override
488
+ protected async BeforeDelete(dataSource: DataSource, ${simplePKEYArgs}): Promise<boolean> {
489
+ const i = ${entity.PrimaryKey.Name}, d = dataSource; // prevent error;
490
+ return true;
491
+ }
492
+ protected async AfterDelete(dataSource: DataSource, ${simplePKEYArgs}) {
493
+ const i = ${entity.PrimaryKey.Name}, d = dataSource; // prevent error
494
+ }
573
495
  `;
574
- }
496
+ }
497
+ return sRet;
498
+ }
499
+ // function generateSPParams(entity: EntityInfo, isUpdate: boolean): string {
500
+ // let sRet: string = '',bFirst: boolean = true;
501
+ // for (let i = 0; i < entity.Fields.length; i++) {
502
+ // const f = entity.Fields[i];
503
+ // if (!f.IsVirtual) {
504
+ // switch (f.Name.toLowerCase()) {
505
+ // case 'id':
506
+ // if (isUpdate) {
507
+ // sRet += generateSingleSPParam(f, bFirst);
508
+ // bFirst = false;
509
+ // }
510
+ // break;
511
+ // case 'createdat':
512
+ // case 'updatedat':
513
+ // // do nothing
514
+ // break;
515
+ // default:
516
+ // if (f.Type.trim().toLowerCase() !== 'uniqueidentifier') {
517
+ // // DO NOT INCLUDE UNIQUEIDENTIFIER FIELDS
518
+ // // FOR CREATE/UPDATE, THEY ARE GENERATED BY THE DB
519
+ // sRet += generateSingleSPParam(f, bFirst);
520
+ // bFirst = false;
521
+ // }
522
+ // break;
523
+ // }
524
+ // }
525
+ // }
526
+ // return sRet;
527
+ // }
528
+ // function generateSingleSPParam(f: EntityFieldInfo, isFirst: boolean): string {
529
+ // let sRet: string = '';
530
+ // let quotes: string = '';
531
+ // switch ( TypeScriptTypeFromSQLType(f.Type).toLowerCase() ) {
532
+ // case 'string':
533
+ // case 'date':
534
+ // quotes = "'";
535
+ // break;
536
+ // default:
537
+ // break;
538
+ // }
539
+ // if (!isFirst)
540
+ // sRet += ',\n ';
541
+ // sRet += `@${f.Name}=\${this.packageSPParam(input.${f.Name},"${quotes}")}`
542
+ // return sRet;
543
+ // }
544
+ generateOneToManyFieldResolver(entity, r) {
545
+ // let keyFieldTS: string = 'number';
546
+ // if (r.EntityKeyField) {
547
+ // const keyField = entity.Fields.find(f => f.Name.toLowerCase() == r.EntityKeyField.toLowerCase())
548
+ // keyFieldTS = keyField ? TypeScriptTypeFromSQLType(keyField.Type) : 'int';
549
+ // }
550
+ const md = new core_1.Metadata();
551
+ const re = md.Entities.find(e => e.Name.toLowerCase() == r.RelatedEntity.toLowerCase());
552
+ const instanceName = entity.BaseTableCodeName.toLowerCase() + this.GraphQLTypeSuffix;
553
+ const filterFieldName = !r.EntityKeyField ? entity.PrimaryKey.Name : r.EntityKeyField;
554
+ const filterField = entity.Fields.find(f => f.Name.toLowerCase() == filterFieldName.toLowerCase());
555
+ if (!filterField)
556
+ throw new Error(`Field ${filterFieldName} not found in entity ${entity.Name} - check the relationship ${r.ID} and the EntityKeyField property`);
557
+ const quotes = filterField.NeedsQuotes ? "'" : '';
558
+ const serverPackagePrefix = re.SchemaName === config_1.mjCoreSchema ? 'mj_core_schema_server_object_types.' : '';
559
+ const serverClassName = serverPackagePrefix + r.RelatedEntityBaseTableCodeName + this.GraphQLTypeSuffix;
560
+ return `
561
+ @FieldResolver(() => [${serverClassName}])
562
+ async ${r.RelatedEntityCodeName}Array(@Root() ${instanceName}: ${entity.BaseTableCodeName + this.GraphQLTypeSuffix}, @Ctx() { dataSource, userPayload }: AppContext, @PubSub() pubSub: PubSubEngine) {
563
+ this.CheckUserReadPermissions('${r.RelatedEntity}', userPayload);
564
+ const sSQL = \`SELECT * FROM [${this.schemaName(re)}].[${r.RelatedEntityBaseView}]\ WHERE [${r.RelatedEntityJoinField}]=${quotes}\${${instanceName}.${filterFieldName}}${quotes} \` + this.getRowLevelSecurityWhereClause('${r.RelatedEntity}', userPayload, EntityPermissionType.Read, 'AND');
565
+ const result = this.ArrayMapFieldNamesToCodeNames('${r.RelatedEntity}', await dataSource.query(sSQL));
566
+ return result;
567
+ }
568
+ `;
569
+ }
570
+ generateManyToManyFieldResolver(entity, r) {
571
+ const md = new core_1.Metadata();
572
+ const re = md.Entities.find(e => e.Name.toLowerCase() == r.RelatedEntity.toLowerCase());
573
+ const instanceName = entity.BaseTableCodeName.toLowerCase() + this.GraphQLTypeSuffix;
574
+ const filterFieldName = !r.EntityKeyField ? entity.PrimaryKey.Name : r.EntityKeyField;
575
+ const filterField = entity.Fields.find(f => f.Name.toLowerCase() == filterFieldName.toLowerCase());
576
+ if (!filterField)
577
+ throw new Error(`Field ${filterFieldName} not found in entity ${entity.Name} - check the relationship ${r.ID} and the EntityKeyField property`);
578
+ const quotes = filterField.NeedsQuotes ? "'" : '';
579
+ const serverPackagePrefix = re.SchemaName === config_1.mjCoreSchema ? 'mj_core_schema_server_object_types.' : '';
580
+ const serverClassName = serverPackagePrefix + r.RelatedEntityBaseTableCodeName + this.GraphQLTypeSuffix;
581
+ return `
582
+ @FieldResolver(() => [${serverClassName}])
583
+ async ${r.RelatedEntityCodeName}Array(@Root() ${instanceName}: ${entity.BaseTableCodeName + this.GraphQLTypeSuffix}, @Ctx() { dataSource, userPayload }: AppContext, @PubSub() pubSub: PubSubEngine) {
584
+ this.CheckUserReadPermissions('${r.RelatedEntity}', userPayload);
585
+ const sSQL = \`SELECT * FROM [${this.schemaName(re)}].[${r.RelatedEntityBaseView}]\ WHERE [${re.PrimaryKey.Name}] IN (SELECT [${r.JoinEntityInverseJoinField}] FROM [${this.schemaName(re)}].[${r.JoinView}] WHERE [${r.JoinEntityJoinField}]=${quotes}\${${instanceName}.${filterFieldName}}${quotes}) \` + this.getRowLevelSecurityWhereClause('${r.RelatedEntity}', userPayload, EntityPermissionType.Read, 'AND');
586
+ const result = this.ArrayMapFieldNamesToCodeNames('${r.RelatedEntity}', await dataSource.query(sSQL));
587
+ return result;
588
+ }
589
+ `;
590
+ }
591
+ };
592
+ exports.GraphQLServerGeneratorBase = GraphQLServerGeneratorBase;
593
+ exports.GraphQLServerGeneratorBase = GraphQLServerGeneratorBase = __decorate([
594
+ (0, global_1.RegisterClass)(GraphQLServerGeneratorBase)
595
+ ], GraphQLServerGeneratorBase);
575
596
  //# sourceMappingURL=graphql_server_codegen.js.map