@memberjunction/server 2.121.0 → 2.122.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,793 +1,793 @@
1
- import { Arg, Ctx, Field, InputType, Int, ObjectType, PubSubEngine, Query, Resolver } from 'type-graphql';
2
- import { AppContext } from '../types.js';
3
- import { ResolverBase } from './ResolverBase.js';
4
- import { LogError, LogStatus, EntityInfo } from '@memberjunction/core';
5
- import { RequireSystemUser } from '../directives/RequireSystemUser.js';
6
- import { GetReadOnlyProvider } from '../util.js';
7
- import { UserViewEntityExtended } from '@memberjunction/core-entities';
8
- import { KeyValuePairOutputType } from './KeyInputOutputTypes.js';
9
-
10
- /********************************************************************************
11
- * The PURPOSE of this resolver is to provide a generic way to run a view and return the results.
12
- * The best practice is to use the strongly typed sub-class of this resolver for each entity.
13
- * that way you get back strongly typed results. If you need a generic way to call a view and get
14
- * back the results, and have your own type checking in place, this resolver can be used.
15
- *
16
- */
17
- //****************************************************************************
18
- // INPUT TYPE for Running Views
19
- //****************************************************************************
20
- @InputType()
21
- export class RunViewByIDInput {
22
- @Field(() => String)
23
- ViewID: string;
24
-
25
- @Field(() => String, {
26
- nullable: true,
27
- description:
28
- 'Optional, pass in a valid condition to append to the view WHERE clause. For example, UpdatedAt >= Some Date - if not provided, no filter is applied',
29
- })
30
- ExtraFilter: string;
31
-
32
- @Field(() => String, {
33
- nullable: true,
34
- description:
35
- 'Optional, pass in a valid order by clause sort the results on the server. For example, CreatedAt DESC to order by row creation date in reverse order. Any Valid SQL Order By clause is okay - if not provided, no server-side sorting is applied',
36
- })
37
- OrderBy: string;
38
-
39
- @Field(() => [String], {
40
- nullable: true,
41
- description:
42
- 'Optional, array of entity field names, if not provided, ID and all other columns used in the view columns are returned. If provided, only the fields in the array are returned.',
43
- })
44
- Fields?: string[];
45
-
46
- @Field(() => String, { nullable: true })
47
- UserSearchString: string;
48
-
49
- @Field(() => String, { nullable: true, description: 'Pass in a UserViewRun ID value to exclude all records from that run from results' })
50
- ExcludeUserViewRunID?: string;
51
-
52
- @Field(() => String, {
53
- nullable: true,
54
- description:
55
- 'Pass in a valid condition to append to the view WHERE clause to override the Exclude List. For example, UpdatedAt >= Some Date',
56
- })
57
- OverrideExcludeFilter?: string;
58
-
59
- @Field(() => Boolean, {
60
- nullable: true,
61
- description:
62
- 'If set to True, the results of this view are saved into a new UserViewRun record and the UserViewRun.ID is passed back in the results.',
63
- })
64
- SaveViewResults?: boolean;
65
-
66
- @Field(() => Boolean, {
67
- nullable: true,
68
- description:
69
- 'if set to true, the resulting data will filter out ANY records that were ever returned by this view, when the SaveViewResults property was set to true. This is useful if you want to run a particular view over time and make sure the results returned each time are new to the view.',
70
- })
71
- ExcludeDataFromAllPriorViewRuns?: boolean;
72
-
73
- @Field(() => Boolean, {
74
- nullable: true,
75
- description:
76
- 'if set to true, if there IS any UserViewMaxRows property set for the entity in question, it will be IGNORED. This is useful in scenarios where you want to programmatically run a view and get ALL the data back, regardless of the MaxRows setting on the entity.',
77
- })
78
- IgnoreMaxRows?: boolean;
79
-
80
- @Field(() => Int, {
81
- nullable: true,
82
- description:
83
- 'if a value > 0 is provided, and IgnoreMaxRows is set to false, this value is used for the max rows to be returned by the view.',
84
- })
85
- MaxRows?: number;
86
-
87
- @Field(() => Boolean, {
88
- nullable: true,
89
- description:
90
- 'If set to true, an Audit Log record will be created for the view run, regardless of the property settings in the entity for auditing view runs',
91
- })
92
- ForceAuditLog?: boolean;
93
-
94
- @Field(() => String, {
95
- nullable: true,
96
- description:
97
- "if provided and either ForceAuditLog is set, or the entity's property settings for logging view runs are set to true, this will be used as the Audit Log Description.",
98
- })
99
- AuditLogDescription?: string;
100
-
101
- @Field(() => String, {
102
- nullable: true,
103
- description:
104
- 'Optional, pass in entity_object, simple, or count_only as options to specify the type of result you want back. Defaults to simple if not provided',
105
- })
106
- ResultType?: string;
107
-
108
- @Field(() => Int, {
109
- nullable: true,
110
- description: 'If a value > 0 is provided, this value will be used to offset the rows returned.',
111
- })
112
- StartRow?: number;
113
- }
114
-
115
- @InputType()
116
- export class RunViewByNameInput {
117
- @Field(() => String)
118
- ViewName: string;
119
-
120
- @Field(() => String, {
121
- nullable: true,
122
- description:
123
- 'Optional, pass in a valid condition to append to the view WHERE clause. For example, UpdatedAt >= Some Date - if not provided, no filter is applied',
124
- })
125
- ExtraFilter: string;
126
-
127
- @Field(() => String, {
128
- nullable: true,
129
- description:
130
- 'Optional, pass in a valid order by clause sort the results on the server. For example, CreatedAt DESC to order by row creation date in reverse order. Any Valid SQL Order By clause is okay - if not provided, no server-side sorting is applied',
131
- })
132
- OrderBy: string;
133
-
134
- @Field(() => [String], {
135
- nullable: true,
136
- description:
137
- 'Optional, array of entity field names, if not provided, ID and all other columns used in the view are returned. If provided, only the fields in the array are returned.',
138
- })
139
- Fields?: string[];
140
-
141
- @Field(() => String, { nullable: true })
142
- UserSearchString: string;
143
-
144
- @Field(() => String, { nullable: true, description: 'Pass in a UserViewRun ID value to exclude all records from that run from results' })
145
- ExcludeUserViewRunID?: string;
146
-
147
- @Field(() => String, {
148
- nullable: true,
149
- description:
150
- 'Pass in a valid condition to append to the view WHERE clause to override the Exclude List. For example, UpdatedAt >= Some Date',
151
- })
152
- OverrideExcludeFilter?: string;
153
-
154
- @Field(() => Boolean, {
155
- nullable: true,
156
- description:
157
- 'If set to True, the results of this view are saved into a new UserViewRun record and the UserViewRun.ID is passed back in the results.',
158
- })
159
- SaveViewResults?: boolean;
160
-
161
- @Field(() => Boolean, {
162
- nullable: true,
163
- description:
164
- 'if set to true, the resulting data will filter out ANY records that were ever returned by this view, when the SaveViewResults property was set to true. This is useful if you want to run a particular view over time and make sure the results returned each time are new to the view.',
165
- })
166
- ExcludeDataFromAllPriorViewRuns?: boolean;
167
-
168
- @Field(() => Boolean, {
169
- nullable: true,
170
- description:
171
- 'if set to true, if there IS any UserViewMaxRows property set for the entity in question, it will be IGNORED. This is useful in scenarios where you want to programmatically run a view and get ALL the data back, regardless of the MaxRows setting on the entity.',
172
- })
173
- IgnoreMaxRows?: boolean;
174
-
175
- @Field(() => Int, {
176
- nullable: true,
177
- description:
178
- 'if a value > 0 is provided, and IgnoreMaxRows is set to false, this value is used for the max rows to be returned by the view.',
179
- })
180
- MaxRows?: number;
181
-
182
- @Field(() => Boolean, {
183
- nullable: true,
184
- description:
185
- 'If set to true, an Audit Log record will be created for the view run, regardless of the property settings in the entity for auditing view runs',
186
- })
187
- ForceAuditLog?: boolean;
188
-
189
- @Field(() => String, {
190
- nullable: true,
191
- description:
192
- "if provided and either ForceAuditLog is set, or the entity's property settings for logging view runs are set to true, this will be used as the Audit Log Description.",
193
- })
194
- AuditLogDescription?: string;
195
-
196
- @Field(() => String, {
197
- nullable: true,
198
- description:
199
- 'Optional, pass in entity_object, simple, or count_only as options to specify the type of result you want back. Defaults to simple if not provided',
200
- })
201
- ResultType?: string;
202
-
203
- @Field(() => Int, {
204
- nullable: true,
205
- description: 'If a value > 0 is provided, this value will be used to offset the rows returned.',
206
- })
207
- StartRow?: number;
208
- }
209
-
210
- @InputType()
211
- export class RunDynamicViewInput {
212
- @Field(() => String)
213
- EntityName: string;
214
-
215
- @Field(() => String, {
216
- nullable: true,
217
- description:
218
- 'Optional, pass in a valid condition to use as the view WHERE clause. For example, UpdatedAt >= Some Date - if not provided, no filter is applied',
219
- })
220
- ExtraFilter: string;
221
-
222
- @Field(() => String, {
223
- nullable: true,
224
- description:
225
- 'Optional, pass in a valid order by clause sort the results on the server. For example, CreatedAt DESC to order by row creation date in reverse order. Any Valid SQL Order By clause is okay - if not provided, no server-side sorting is applied',
226
- })
227
- OrderBy: string;
228
-
229
- @Field(() => [String], {
230
- nullable: true,
231
- description:
232
- 'Optional, array of entity field names, if not provided, all columns are returned. If provided, only the fields in the array are returned.',
233
- })
234
- Fields?: string[];
235
-
236
- @Field(() => String, { nullable: true })
237
- UserSearchString: string;
238
-
239
- @Field(() => String, { nullable: true, description: 'Pass in a UserViewRun ID value to exclude all records from that run from results' })
240
- ExcludeUserViewRunID?: string;
241
-
242
- @Field(() => String, {
243
- nullable: true,
244
- description:
245
- 'Pass in a valid condition to append to the view WHERE clause to override the Exclude List. For example, UpdatedAt >= Some Date',
246
- })
247
- OverrideExcludeFilter?: string;
248
-
249
- @Field(() => Boolean, {
250
- nullable: true,
251
- description:
252
- 'if set to true, if there IS any UserViewMaxRows property set for the entity in question, it will be IGNORED. This is useful in scenarios where you want to programmatically run a view and get ALL the data back, regardless of the MaxRows setting on the entity.',
253
- })
254
- IgnoreMaxRows?: boolean;
255
-
256
- @Field(() => Int, {
257
- nullable: true,
258
- description:
259
- 'if a value > 0 is provided, and IgnoreMaxRows is set to false, this value is used for the max rows to be returned by the view.',
260
- })
261
- MaxRows?: number;
262
-
263
- @Field(() => Boolean, {
264
- nullable: true,
265
- description:
266
- 'If set to true, an Audit Log record will be created for the view run, regardless of the property settings in the entity for auditing view runs',
267
- })
268
- ForceAuditLog?: boolean;
269
-
270
- @Field(() => String, {
271
- nullable: true,
272
- description:
273
- "if provided and either ForceAuditLog is set, or the entity's property settings for logging view runs are set to true, this will be used as the Audit Log Description.",
274
- })
275
- AuditLogDescription?: string;
276
-
277
- @Field(() => String, {
278
- nullable: true,
279
- description:
280
- 'Optional, pass in entity_object, simple, or count_only as options to specify the type of result you want back. Defaults to simple if not provided',
281
- })
282
- ResultType?: string;
283
-
284
- @Field(() => Int, {
285
- nullable: true,
286
- description: 'If a value > 0 is provided, this value will be used to offset the rows returned.',
287
- })
288
- StartRow?: number;
289
- }
290
-
291
- @InputType()
292
- export class RunViewGenericInput {
293
- @Field(() => String)
294
- EntityName: string;
295
-
296
- @Field(() => String, {
297
- nullable: true,
298
- description:
299
- 'Optional, pass in a valid condition to use as the view WHERE clause. For example, UpdatedAt >= Some Date - if not provided, no filter is applied',
300
- })
301
- ExtraFilter: string;
302
-
303
- @Field(() => String, {
304
- nullable: true,
305
- description:
306
- 'Optional, pass in a valid order by clause sort the results on the server. For example, CreatedAt DESC to order by row creation date in reverse order. Any Valid SQL Order By clause is okay - if not provided, no server-side sorting is applied',
307
- })
308
- OrderBy: string;
309
-
310
- @Field(() => [String], {
311
- nullable: true,
312
- description:
313
- 'Optional, array of entity field names, if not provided, all columns are returned. If provided, only the fields in the array are returned.',
314
- })
315
- Fields?: string[];
316
-
317
- @Field(() => String, { nullable: true })
318
- UserSearchString: string;
319
-
320
- @Field(() => String, { nullable: true, description: 'Pass in a UserViewRun ID value to exclude all records from that run from results' })
321
- ExcludeUserViewRunID?: string;
322
-
323
- @Field(() => String, {
324
- nullable: true,
325
- description:
326
- 'Pass in a valid condition to append to the view WHERE clause to override the Exclude List. For example, UpdatedAt >= Some Date',
327
- })
328
- OverrideExcludeFilter?: string;
329
-
330
- @Field(() => Boolean, {
331
- nullable: true,
332
- description:
333
- 'If set to True, the results of this view are saved into a new UserViewRun record and the UserViewRun.ID is passed back in the results.',
334
- })
335
- SaveViewResults?: boolean;
336
-
337
- @Field(() => Boolean, {
338
- nullable: true,
339
- description:
340
- 'if set to true, the resulting data will filter out ANY records that were ever returned by this view, when the SaveViewResults property was set to true. This is useful if you want to run a particular view over time and make sure the results returned each time are new to the view.',
341
- })
342
- ExcludeDataFromAllPriorViewRuns?: boolean;
343
-
344
- @Field(() => Boolean, {
345
- nullable: true,
346
- description:
347
- 'if set to true, if there IS any UserViewMaxRows property set for the entity in question, it will be IGNORED. This is useful in scenarios where you want to programmatically run a view and get ALL the data back, regardless of the MaxRows setting on the entity.',
348
- })
349
- IgnoreMaxRows?: boolean;
350
-
351
- @Field(() => Int, {
352
- nullable: true,
353
- description:
354
- 'if a value > 0 is provided, and IgnoreMaxRows is set to false, this value is used for the max rows to be returned by the view.',
355
- })
356
- MaxRows?: number;
357
-
358
- @Field(() => Boolean, {
359
- nullable: true,
360
- description:
361
- 'If set to true, an Audit Log record will be created for the view run, regardless of the property settings in the entity for auditing view runs',
362
- })
363
- ForceAuditLog?: boolean;
364
-
365
- @Field(() => String, {
366
- nullable: true,
367
- description:
368
- "if provided and either ForceAuditLog is set, or the entity's property settings for logging view runs are set to true, this will be used as the Audit Log Description.",
369
- })
370
- AuditLogDescription?: string;
371
-
372
- @Field(() => String, {
373
- nullable: true,
374
- description:
375
- 'Optional, pass in entity_object, simple, or count_only as options to specify the type of result you want back. Defaults to simple if not provided',
376
- })
377
- ResultType?: string;
378
-
379
- @Field(() => Int, {
380
- nullable: true,
381
- description: 'If a value > 0 is provided, this value will be used to offset the rows returned.',
382
- })
383
- StartRow?: number;
384
- }
385
-
386
- @ObjectType()
387
- export class RunViewResultRow {
388
- @Field(() => [KeyValuePairOutputType], {
389
- description: 'Primary key values for the record'
390
- })
391
- PrimaryKey: KeyValuePairOutputType[];
392
-
393
- @Field(() => String)
394
- EntityID: string;
395
-
396
- @Field(() => String)
397
- Data: string;
398
- }
399
-
400
- @ObjectType()
401
- export class RunViewGenericResultRow {
402
- @Field(() => [KeyValuePairOutputType], {
403
- description: 'Primary key values for the record'
404
- })
405
- PrimaryKey: KeyValuePairOutputType[];
406
-
407
- @Field(() => String)
408
- EntityID: string;
409
-
410
- @Field(() => String)
411
- Data: string;
412
- }
413
-
414
- @ObjectType()
415
- export class RunViewResult {
416
- @Field(() => [RunViewResultRow])
417
- Results: RunViewResultRow[];
418
-
419
- @Field(() => String, { nullable: true })
420
- UserViewRunID?: string;
421
-
422
- @Field(() => Int, { nullable: true })
423
- RowCount: number;
424
-
425
- @Field(() => Int, { nullable: true })
426
- TotalRowCount: number;
427
-
428
- @Field(() => Int, { nullable: true })
429
- ExecutionTime: number;
430
-
431
- @Field(() => String, { nullable: true })
432
- ErrorMessage?: string;
433
-
434
- @Field(() => Boolean, { nullable: false })
435
- Success: boolean;
436
- }
437
-
438
- @ObjectType()
439
- export class RunViewGenericResult {
440
- @Field(() => [RunViewGenericResultRow])
441
- Results: RunViewGenericResultRow[];
442
-
443
- @Field(() => String, { nullable: true })
444
- UserViewRunID?: string;
445
-
446
- @Field(() => Int, { nullable: true })
447
- RowCount: number;
448
-
449
- @Field(() => Int, { nullable: true })
450
- TotalRowCount: number;
451
-
452
- @Field(() => Int, { nullable: true })
453
- ExecutionTime: number;
454
-
455
- @Field(() => String, { nullable: true })
456
- ErrorMessage?: string;
457
-
458
- @Field(() => Boolean, { nullable: false })
459
- Success: boolean;
460
- }
461
-
462
- @Resolver(RunViewResultRow)
463
- export class RunViewResolver extends ResolverBase {
464
- @Query(() => RunViewResult)
465
- async RunViewByName(
466
- @Arg('input', () => RunViewByNameInput) input: RunViewByNameInput,
467
- @Ctx() { providers, userPayload }: AppContext,
468
- pubSub: PubSubEngine
469
- ) {
470
- try {
471
- const provider = GetReadOnlyProvider(providers, { allowFallbackToReadWrite: true });
472
- const rawData = await super.RunViewByNameGeneric(input, provider, userPayload, pubSub);
473
- if (rawData === null)
474
- return null;
475
-
476
- const viewInfo = super.safeFirstArrayElement<UserViewEntityExtended>(await super.findBy<UserViewEntityExtended>(provider, "User Views", { Name: input.ViewName }, userPayload.userRecord));
477
- const entity = provider.Entities.find((e) => e.ID === viewInfo.EntityID);
478
- const returnData = this.processRawData(rawData.Results, viewInfo.EntityID, entity);
479
- return {
480
- Results: returnData,
481
- UserViewRunID: rawData?.UserViewRunID,
482
- RowCount: rawData?.RowCount,
483
- TotalRowCount: rawData?.TotalRowCount,
484
- ExecutionTime: rawData?.ExecutionTime,
485
- };
486
- } catch (err) {
487
- console.log(err);
488
- return null;
489
- }
490
- }
491
-
492
- @Query(() => RunViewResult)
493
- async RunViewByID(
494
- @Arg('input', () => RunViewByIDInput) input: RunViewByIDInput,
495
- @Ctx() { providers, userPayload }: AppContext,
496
- pubSub: PubSubEngine
497
- ) {
498
- try {
499
- const provider = GetReadOnlyProvider(providers, { allowFallbackToReadWrite: true });
500
- const rawData = await super.RunViewByIDGeneric(input, provider, userPayload, pubSub);
501
- if (rawData === null)
502
- return null;
503
-
504
- const viewInfo = super.safeFirstArrayElement<UserViewEntityExtended>(await super.findBy<UserViewEntityExtended>(provider, "User Views", { ID: input.ViewID }, userPayload.userRecord));
505
- const entity = provider.Entities.find((e) => e.ID === viewInfo.EntityID);
506
- const returnData = this.processRawData(rawData.Results, viewInfo.EntityID, entity);
507
- return {
508
- Results: returnData,
509
- UserViewRunID: rawData?.UserViewRunID,
510
- RowCount: rawData?.RowCount,
511
- TotalRowCount: rawData?.TotalRowCount,
512
- ExecutionTime: rawData?.ExecutionTime,
513
- };
514
- } catch (err) {
515
- console.log(err);
516
- return null;
517
- }
518
- }
519
-
520
- @Query(() => RunViewResult)
521
- async RunDynamicView(
522
- @Arg('input', () => RunDynamicViewInput) input: RunDynamicViewInput,
523
- @Ctx() { providers, userPayload }: AppContext,
524
- pubSub: PubSubEngine
525
- ) {
526
- try {
527
- const provider = GetReadOnlyProvider(providers, { allowFallbackToReadWrite: true });
528
- const rawData = await super.RunDynamicViewGeneric(input, provider, userPayload, pubSub);
529
- if (rawData === null) return null;
530
-
531
- const entity = provider.Entities.find((e) => e.Name === input.EntityName);
532
- const returnData = this.processRawData(rawData.Results, entity.ID, entity);
533
- return {
534
- Results: returnData,
535
- UserViewRunID: rawData?.UserViewRunID,
536
- RowCount: rawData?.RowCount,
537
- TotalRowCount: rawData?.TotalRowCount,
538
- ExecutionTime: rawData?.ExecutionTime,
539
- };
540
- } catch (err) {
541
- console.log(err);
542
- return null;
543
- }
544
- }
545
-
546
- @Query(() => [RunViewGenericResult])
547
- async RunViews(
548
- @Arg('input', () => [RunViewGenericInput]) input: (RunViewByNameInput & RunViewByIDInput & RunDynamicViewInput)[],
549
- @Ctx() { providers, userPayload }: AppContext,
550
- pubSub: PubSubEngine
551
- ) {
552
- try {
553
- const provider = GetReadOnlyProvider(providers, { allowFallbackToReadWrite: true });
554
- const rawData: RunViewGenericResult[] = await super.RunViewsGeneric(input, provider, userPayload);
555
- if (!rawData) {
556
- return null;
557
- }
558
-
559
- let results: RunViewGenericResult[] = [];
560
- for (const [index, data] of rawData.entries()) {
561
- const entity = provider.Entities.find((e) => e.Name === input[index].EntityName);
562
- const returnData: any[] = this.processRawData(data.Results, entity.ID, entity);
563
-
564
- results.push({
565
- Results: returnData,
566
- UserViewRunID: data?.UserViewRunID,
567
- RowCount: data?.RowCount,
568
- TotalRowCount: data?.TotalRowCount,
569
- ExecutionTime: data?.ExecutionTime,
570
- Success: data?.Success,
571
- });
572
- }
573
-
574
- return results;
575
- } catch (err) {
576
- LogError(err);
577
- return null;
578
- }
579
- }
580
-
581
- @RequireSystemUser()
582
- @Query(() => RunViewResult)
583
- async RunViewByNameSystemUser(
584
- @Arg('input', () => RunViewByNameInput) input: RunViewByNameInput,
585
- @Ctx() { providers, userPayload }: AppContext,
586
- pubSub: PubSubEngine
587
- ) {
588
- try {
589
- const provider = GetReadOnlyProvider(providers, { allowFallbackToReadWrite: true });
590
- const rawData = await super.RunViewByNameGeneric(input, provider, userPayload, pubSub);
591
- if (rawData === null) {
592
- return {
593
- Results: [],
594
- Success: false,
595
- ErrorMessage: `Failed to execute view: ${input.ViewName}`,
596
- RowCount: 0,
597
- TotalRowCount: 0,
598
- ExecutionTime: 0
599
- };
600
- }
601
-
602
- const entity = provider.Entities.find((e) => e.Name === input.ViewName);
603
- const entityId = entity ? entity.ID : null;
604
- const returnData = this.processRawData(rawData.Results, entityId, entity);
605
- return {
606
- Results: returnData,
607
- UserViewRunID: rawData?.UserViewRunID,
608
- RowCount: rawData?.RowCount,
609
- TotalRowCount: rawData?.TotalRowCount,
610
- ExecutionTime: rawData?.ExecutionTime,
611
- Success: rawData?.Success,
612
- ErrorMessage: rawData?.ErrorMessage,
613
- };
614
- } catch (err) {
615
- const errorMessage = err instanceof Error ? err.message : 'Unknown error occurred';
616
- LogError(err);
617
- return {
618
- Results: [],
619
- Success: false,
620
- ErrorMessage: errorMessage,
621
- RowCount: 0,
622
- TotalRowCount: 0,
623
- ExecutionTime: 0
624
- };
625
- }
626
- }
627
-
628
- @RequireSystemUser()
629
- @Query(() => RunViewResult)
630
- async RunViewByIDSystemUser(
631
- @Arg('input', () => RunViewByIDInput) input: RunViewByIDInput,
632
- @Ctx() { providers, userPayload }: AppContext,
633
- pubSub: PubSubEngine
634
- ) {
635
- try {
636
- const provider = GetReadOnlyProvider(providers, { allowFallbackToReadWrite: true });
637
- const rawData = await super.RunViewByIDGeneric(input, provider, userPayload, pubSub);
638
- if (rawData === null) {
639
- return {
640
- Results: [],
641
- Success: false,
642
- ErrorMessage: `Failed to execute view with ID: ${input.ViewID}`,
643
- RowCount: 0,
644
- TotalRowCount: 0,
645
- ExecutionTime: 0
646
- };
647
- }
648
-
649
- const viewInfo = super.safeFirstArrayElement<UserViewEntityExtended>(await super.findBy<UserViewEntityExtended>(provider, "User Views", { ID: input.ViewID }, userPayload.userRecord));
650
- const entity = provider.Entities.find((e) => e.ID === viewInfo.EntityID);
651
- const returnData = this.processRawData(rawData.Results, viewInfo.EntityID, entity);
652
- return {
653
- Results: returnData,
654
- UserViewRunID: rawData?.UserViewRunID,
655
- RowCount: rawData?.RowCount,
656
- TotalRowCount: rawData?.TotalRowCount,
657
- ExecutionTime: rawData?.ExecutionTime,
658
- Success: rawData?.Success,
659
- ErrorMessage: rawData?.ErrorMessage,
660
- };
661
- } catch (err) {
662
- const errorMessage = err instanceof Error ? err.message : 'Unknown error occurred';
663
- LogError(err);
664
- return {
665
- Results: [],
666
- Success: false,
667
- ErrorMessage: errorMessage,
668
- RowCount: 0,
669
- TotalRowCount: 0,
670
- ExecutionTime: 0
671
- };
672
- }
673
- }
674
-
675
- @RequireSystemUser()
676
- @Query(() => RunViewResult)
677
- async RunDynamicViewSystemUser(
678
- @Arg('input', () => RunDynamicViewInput) input: RunDynamicViewInput,
679
- @Ctx() { providers, userPayload }: AppContext,
680
- pubSub: PubSubEngine
681
- ) {
682
- try {
683
- const provider = GetReadOnlyProvider(providers, { allowFallbackToReadWrite: true });
684
- const rawData = await super.RunDynamicViewGeneric(input, provider, userPayload, pubSub);
685
- if (rawData === null) {
686
- return {
687
- Results: [],
688
- Success: false,
689
- ErrorMessage: 'Failed to execute dynamic view',
690
- RowCount: 0,
691
- TotalRowCount: 0,
692
- ExecutionTime: 0
693
- };
694
- }
695
-
696
- const entity = provider.Entities.find((e) => e.Name === input.EntityName);
697
- if (!entity) {
698
- const errorMsg = `Entity ${input.EntityName} not found in metadata`;
699
- LogError(new Error(errorMsg));
700
- return {
701
- Results: [],
702
- Success: false,
703
- ErrorMessage: errorMsg,
704
- RowCount: 0,
705
- TotalRowCount: 0,
706
- ExecutionTime: 0
707
- };
708
- }
709
- const returnData = this.processRawData(rawData.Results, entity.ID, entity);
710
- return {
711
- Results: returnData,
712
- UserViewRunID: rawData?.UserViewRunID,
713
- RowCount: rawData?.RowCount,
714
- TotalRowCount: rawData?.TotalRowCount,
715
- ExecutionTime: rawData?.ExecutionTime,
716
- Success: rawData?.Success,
717
- ErrorMessage: rawData?.ErrorMessage,
718
- };
719
- } catch (err) {
720
- const errorMessage = err instanceof Error ? err.message : 'Unknown error occurred';
721
- LogError(err);
722
- return {
723
- Results: [],
724
- Success: false,
725
- ErrorMessage: errorMessage,
726
- RowCount: 0,
727
- TotalRowCount: 0,
728
- ExecutionTime: 0
729
- };
730
- }
731
- }
732
-
733
- @RequireSystemUser()
734
- @Query(() => [RunViewGenericResult])
735
- async RunViewsSystemUser(
736
- @Arg('input', () => [RunViewGenericInput]) input: (RunViewByNameInput & RunViewByIDInput & RunDynamicViewInput)[],
737
- @Ctx() { providers, userPayload }: AppContext,
738
- pubSub: PubSubEngine
739
- ) {
740
- try {
741
- const provider = GetReadOnlyProvider(providers, { allowFallbackToReadWrite: true });
742
- const rawData: RunViewGenericResult[] = await super.RunViewsGeneric(input, provider, userPayload);
743
- if (!rawData) {
744
- return null;
745
- }
746
-
747
- let results: RunViewGenericResult[] = [];
748
- for (const [index, data] of rawData.entries()) {
749
- const entity = provider.Entities.find((e) => e.Name === input[index].EntityName);
750
- if (!entity) {
751
- LogError(new Error(`Entity with name ${input[index].EntityName} not found`));
752
- continue;
753
- }
754
- const returnData: any[] = this.processRawData(data.Results, entity.ID, entity);
755
-
756
- results.push({
757
- Results: returnData,
758
- UserViewRunID: data?.UserViewRunID,
759
- RowCount: data?.RowCount,
760
- TotalRowCount: data?.TotalRowCount,
761
- ExecutionTime: data?.ExecutionTime,
762
- Success: data?.Success,
763
- ErrorMessage: data?.ErrorMessage,
764
- });
765
- }
766
-
767
- return results;
768
- } catch (err) {
769
- LogError(err);
770
- return null;
771
- }
772
- }
773
-
774
- protected processRawData(rawData: any[], entityId: string, entityInfo: EntityInfo): RunViewResultRow[] {
775
- const returnResult = [];
776
- for (let i = 0; i < rawData.length; i++) {
777
- const row = rawData[i];
778
-
779
- // Build the primary key array from the entity's primary key fields
780
- const primaryKey: KeyValuePairOutputType[] = entityInfo.PrimaryKeys.map(pk => ({
781
- FieldName: pk.Name,
782
- Value: row[pk.Name]?.toString() || ''
783
- }));
784
-
785
- returnResult.push({
786
- PrimaryKey: primaryKey,
787
- EntityID: entityId,
788
- Data: JSON.stringify(row),
789
- });
790
- }
791
- return returnResult;
792
- }
793
- }
1
+ import { Arg, Ctx, Field, InputType, Int, ObjectType, PubSubEngine, Query, Resolver } from 'type-graphql';
2
+ import { AppContext } from '../types.js';
3
+ import { ResolverBase } from './ResolverBase.js';
4
+ import { LogError, LogStatus, EntityInfo } from '@memberjunction/core';
5
+ import { RequireSystemUser } from '../directives/RequireSystemUser.js';
6
+ import { GetReadOnlyProvider } from '../util.js';
7
+ import { UserViewEntityExtended } from '@memberjunction/core-entities';
8
+ import { KeyValuePairOutputType } from './KeyInputOutputTypes.js';
9
+
10
+ /********************************************************************************
11
+ * The PURPOSE of this resolver is to provide a generic way to run a view and return the results.
12
+ * The best practice is to use the strongly typed sub-class of this resolver for each entity.
13
+ * that way you get back strongly typed results. If you need a generic way to call a view and get
14
+ * back the results, and have your own type checking in place, this resolver can be used.
15
+ *
16
+ */
17
+ //****************************************************************************
18
+ // INPUT TYPE for Running Views
19
+ //****************************************************************************
20
+ @InputType()
21
+ export class RunViewByIDInput {
22
+ @Field(() => String)
23
+ ViewID: string;
24
+
25
+ @Field(() => String, {
26
+ nullable: true,
27
+ description:
28
+ 'Optional, pass in a valid condition to append to the view WHERE clause. For example, UpdatedAt >= Some Date - if not provided, no filter is applied',
29
+ })
30
+ ExtraFilter: string;
31
+
32
+ @Field(() => String, {
33
+ nullable: true,
34
+ description:
35
+ 'Optional, pass in a valid order by clause sort the results on the server. For example, CreatedAt DESC to order by row creation date in reverse order. Any Valid SQL Order By clause is okay - if not provided, no server-side sorting is applied',
36
+ })
37
+ OrderBy: string;
38
+
39
+ @Field(() => [String], {
40
+ nullable: true,
41
+ description:
42
+ 'Optional, array of entity field names, if not provided, ID and all other columns used in the view columns are returned. If provided, only the fields in the array are returned.',
43
+ })
44
+ Fields?: string[];
45
+
46
+ @Field(() => String, { nullable: true })
47
+ UserSearchString: string;
48
+
49
+ @Field(() => String, { nullable: true, description: 'Pass in a UserViewRun ID value to exclude all records from that run from results' })
50
+ ExcludeUserViewRunID?: string;
51
+
52
+ @Field(() => String, {
53
+ nullable: true,
54
+ description:
55
+ 'Pass in a valid condition to append to the view WHERE clause to override the Exclude List. For example, UpdatedAt >= Some Date',
56
+ })
57
+ OverrideExcludeFilter?: string;
58
+
59
+ @Field(() => Boolean, {
60
+ nullable: true,
61
+ description:
62
+ 'If set to True, the results of this view are saved into a new UserViewRun record and the UserViewRun.ID is passed back in the results.',
63
+ })
64
+ SaveViewResults?: boolean;
65
+
66
+ @Field(() => Boolean, {
67
+ nullable: true,
68
+ description:
69
+ 'if set to true, the resulting data will filter out ANY records that were ever returned by this view, when the SaveViewResults property was set to true. This is useful if you want to run a particular view over time and make sure the results returned each time are new to the view.',
70
+ })
71
+ ExcludeDataFromAllPriorViewRuns?: boolean;
72
+
73
+ @Field(() => Boolean, {
74
+ nullable: true,
75
+ description:
76
+ 'if set to true, if there IS any UserViewMaxRows property set for the entity in question, it will be IGNORED. This is useful in scenarios where you want to programmatically run a view and get ALL the data back, regardless of the MaxRows setting on the entity.',
77
+ })
78
+ IgnoreMaxRows?: boolean;
79
+
80
+ @Field(() => Int, {
81
+ nullable: true,
82
+ description:
83
+ 'if a value > 0 is provided, and IgnoreMaxRows is set to false, this value is used for the max rows to be returned by the view.',
84
+ })
85
+ MaxRows?: number;
86
+
87
+ @Field(() => Boolean, {
88
+ nullable: true,
89
+ description:
90
+ 'If set to true, an Audit Log record will be created for the view run, regardless of the property settings in the entity for auditing view runs',
91
+ })
92
+ ForceAuditLog?: boolean;
93
+
94
+ @Field(() => String, {
95
+ nullable: true,
96
+ description:
97
+ "if provided and either ForceAuditLog is set, or the entity's property settings for logging view runs are set to true, this will be used as the Audit Log Description.",
98
+ })
99
+ AuditLogDescription?: string;
100
+
101
+ @Field(() => String, {
102
+ nullable: true,
103
+ description:
104
+ 'Optional, pass in entity_object, simple, or count_only as options to specify the type of result you want back. Defaults to simple if not provided',
105
+ })
106
+ ResultType?: string;
107
+
108
+ @Field(() => Int, {
109
+ nullable: true,
110
+ description: 'If a value > 0 is provided, this value will be used to offset the rows returned.',
111
+ })
112
+ StartRow?: number;
113
+ }
114
+
115
+ @InputType()
116
+ export class RunViewByNameInput {
117
+ @Field(() => String)
118
+ ViewName: string;
119
+
120
+ @Field(() => String, {
121
+ nullable: true,
122
+ description:
123
+ 'Optional, pass in a valid condition to append to the view WHERE clause. For example, UpdatedAt >= Some Date - if not provided, no filter is applied',
124
+ })
125
+ ExtraFilter: string;
126
+
127
+ @Field(() => String, {
128
+ nullable: true,
129
+ description:
130
+ 'Optional, pass in a valid order by clause sort the results on the server. For example, CreatedAt DESC to order by row creation date in reverse order. Any Valid SQL Order By clause is okay - if not provided, no server-side sorting is applied',
131
+ })
132
+ OrderBy: string;
133
+
134
+ @Field(() => [String], {
135
+ nullable: true,
136
+ description:
137
+ 'Optional, array of entity field names, if not provided, ID and all other columns used in the view are returned. If provided, only the fields in the array are returned.',
138
+ })
139
+ Fields?: string[];
140
+
141
+ @Field(() => String, { nullable: true })
142
+ UserSearchString: string;
143
+
144
+ @Field(() => String, { nullable: true, description: 'Pass in a UserViewRun ID value to exclude all records from that run from results' })
145
+ ExcludeUserViewRunID?: string;
146
+
147
+ @Field(() => String, {
148
+ nullable: true,
149
+ description:
150
+ 'Pass in a valid condition to append to the view WHERE clause to override the Exclude List. For example, UpdatedAt >= Some Date',
151
+ })
152
+ OverrideExcludeFilter?: string;
153
+
154
+ @Field(() => Boolean, {
155
+ nullable: true,
156
+ description:
157
+ 'If set to True, the results of this view are saved into a new UserViewRun record and the UserViewRun.ID is passed back in the results.',
158
+ })
159
+ SaveViewResults?: boolean;
160
+
161
+ @Field(() => Boolean, {
162
+ nullable: true,
163
+ description:
164
+ 'if set to true, the resulting data will filter out ANY records that were ever returned by this view, when the SaveViewResults property was set to true. This is useful if you want to run a particular view over time and make sure the results returned each time are new to the view.',
165
+ })
166
+ ExcludeDataFromAllPriorViewRuns?: boolean;
167
+
168
+ @Field(() => Boolean, {
169
+ nullable: true,
170
+ description:
171
+ 'if set to true, if there IS any UserViewMaxRows property set for the entity in question, it will be IGNORED. This is useful in scenarios where you want to programmatically run a view and get ALL the data back, regardless of the MaxRows setting on the entity.',
172
+ })
173
+ IgnoreMaxRows?: boolean;
174
+
175
+ @Field(() => Int, {
176
+ nullable: true,
177
+ description:
178
+ 'if a value > 0 is provided, and IgnoreMaxRows is set to false, this value is used for the max rows to be returned by the view.',
179
+ })
180
+ MaxRows?: number;
181
+
182
+ @Field(() => Boolean, {
183
+ nullable: true,
184
+ description:
185
+ 'If set to true, an Audit Log record will be created for the view run, regardless of the property settings in the entity for auditing view runs',
186
+ })
187
+ ForceAuditLog?: boolean;
188
+
189
+ @Field(() => String, {
190
+ nullable: true,
191
+ description:
192
+ "if provided and either ForceAuditLog is set, or the entity's property settings for logging view runs are set to true, this will be used as the Audit Log Description.",
193
+ })
194
+ AuditLogDescription?: string;
195
+
196
+ @Field(() => String, {
197
+ nullable: true,
198
+ description:
199
+ 'Optional, pass in entity_object, simple, or count_only as options to specify the type of result you want back. Defaults to simple if not provided',
200
+ })
201
+ ResultType?: string;
202
+
203
+ @Field(() => Int, {
204
+ nullable: true,
205
+ description: 'If a value > 0 is provided, this value will be used to offset the rows returned.',
206
+ })
207
+ StartRow?: number;
208
+ }
209
+
210
+ @InputType()
211
+ export class RunDynamicViewInput {
212
+ @Field(() => String)
213
+ EntityName: string;
214
+
215
+ @Field(() => String, {
216
+ nullable: true,
217
+ description:
218
+ 'Optional, pass in a valid condition to use as the view WHERE clause. For example, UpdatedAt >= Some Date - if not provided, no filter is applied',
219
+ })
220
+ ExtraFilter: string;
221
+
222
+ @Field(() => String, {
223
+ nullable: true,
224
+ description:
225
+ 'Optional, pass in a valid order by clause sort the results on the server. For example, CreatedAt DESC to order by row creation date in reverse order. Any Valid SQL Order By clause is okay - if not provided, no server-side sorting is applied',
226
+ })
227
+ OrderBy: string;
228
+
229
+ @Field(() => [String], {
230
+ nullable: true,
231
+ description:
232
+ 'Optional, array of entity field names, if not provided, all columns are returned. If provided, only the fields in the array are returned.',
233
+ })
234
+ Fields?: string[];
235
+
236
+ @Field(() => String, { nullable: true })
237
+ UserSearchString: string;
238
+
239
+ @Field(() => String, { nullable: true, description: 'Pass in a UserViewRun ID value to exclude all records from that run from results' })
240
+ ExcludeUserViewRunID?: string;
241
+
242
+ @Field(() => String, {
243
+ nullable: true,
244
+ description:
245
+ 'Pass in a valid condition to append to the view WHERE clause to override the Exclude List. For example, UpdatedAt >= Some Date',
246
+ })
247
+ OverrideExcludeFilter?: string;
248
+
249
+ @Field(() => Boolean, {
250
+ nullable: true,
251
+ description:
252
+ 'if set to true, if there IS any UserViewMaxRows property set for the entity in question, it will be IGNORED. This is useful in scenarios where you want to programmatically run a view and get ALL the data back, regardless of the MaxRows setting on the entity.',
253
+ })
254
+ IgnoreMaxRows?: boolean;
255
+
256
+ @Field(() => Int, {
257
+ nullable: true,
258
+ description:
259
+ 'if a value > 0 is provided, and IgnoreMaxRows is set to false, this value is used for the max rows to be returned by the view.',
260
+ })
261
+ MaxRows?: number;
262
+
263
+ @Field(() => Boolean, {
264
+ nullable: true,
265
+ description:
266
+ 'If set to true, an Audit Log record will be created for the view run, regardless of the property settings in the entity for auditing view runs',
267
+ })
268
+ ForceAuditLog?: boolean;
269
+
270
+ @Field(() => String, {
271
+ nullable: true,
272
+ description:
273
+ "if provided and either ForceAuditLog is set, or the entity's property settings for logging view runs are set to true, this will be used as the Audit Log Description.",
274
+ })
275
+ AuditLogDescription?: string;
276
+
277
+ @Field(() => String, {
278
+ nullable: true,
279
+ description:
280
+ 'Optional, pass in entity_object, simple, or count_only as options to specify the type of result you want back. Defaults to simple if not provided',
281
+ })
282
+ ResultType?: string;
283
+
284
+ @Field(() => Int, {
285
+ nullable: true,
286
+ description: 'If a value > 0 is provided, this value will be used to offset the rows returned.',
287
+ })
288
+ StartRow?: number;
289
+ }
290
+
291
+ @InputType()
292
+ export class RunViewGenericInput {
293
+ @Field(() => String)
294
+ EntityName: string;
295
+
296
+ @Field(() => String, {
297
+ nullable: true,
298
+ description:
299
+ 'Optional, pass in a valid condition to use as the view WHERE clause. For example, UpdatedAt >= Some Date - if not provided, no filter is applied',
300
+ })
301
+ ExtraFilter: string;
302
+
303
+ @Field(() => String, {
304
+ nullable: true,
305
+ description:
306
+ 'Optional, pass in a valid order by clause sort the results on the server. For example, CreatedAt DESC to order by row creation date in reverse order. Any Valid SQL Order By clause is okay - if not provided, no server-side sorting is applied',
307
+ })
308
+ OrderBy: string;
309
+
310
+ @Field(() => [String], {
311
+ nullable: true,
312
+ description:
313
+ 'Optional, array of entity field names, if not provided, all columns are returned. If provided, only the fields in the array are returned.',
314
+ })
315
+ Fields?: string[];
316
+
317
+ @Field(() => String, { nullable: true })
318
+ UserSearchString: string;
319
+
320
+ @Field(() => String, { nullable: true, description: 'Pass in a UserViewRun ID value to exclude all records from that run from results' })
321
+ ExcludeUserViewRunID?: string;
322
+
323
+ @Field(() => String, {
324
+ nullable: true,
325
+ description:
326
+ 'Pass in a valid condition to append to the view WHERE clause to override the Exclude List. For example, UpdatedAt >= Some Date',
327
+ })
328
+ OverrideExcludeFilter?: string;
329
+
330
+ @Field(() => Boolean, {
331
+ nullable: true,
332
+ description:
333
+ 'If set to True, the results of this view are saved into a new UserViewRun record and the UserViewRun.ID is passed back in the results.',
334
+ })
335
+ SaveViewResults?: boolean;
336
+
337
+ @Field(() => Boolean, {
338
+ nullable: true,
339
+ description:
340
+ 'if set to true, the resulting data will filter out ANY records that were ever returned by this view, when the SaveViewResults property was set to true. This is useful if you want to run a particular view over time and make sure the results returned each time are new to the view.',
341
+ })
342
+ ExcludeDataFromAllPriorViewRuns?: boolean;
343
+
344
+ @Field(() => Boolean, {
345
+ nullable: true,
346
+ description:
347
+ 'if set to true, if there IS any UserViewMaxRows property set for the entity in question, it will be IGNORED. This is useful in scenarios where you want to programmatically run a view and get ALL the data back, regardless of the MaxRows setting on the entity.',
348
+ })
349
+ IgnoreMaxRows?: boolean;
350
+
351
+ @Field(() => Int, {
352
+ nullable: true,
353
+ description:
354
+ 'if a value > 0 is provided, and IgnoreMaxRows is set to false, this value is used for the max rows to be returned by the view.',
355
+ })
356
+ MaxRows?: number;
357
+
358
+ @Field(() => Boolean, {
359
+ nullable: true,
360
+ description:
361
+ 'If set to true, an Audit Log record will be created for the view run, regardless of the property settings in the entity for auditing view runs',
362
+ })
363
+ ForceAuditLog?: boolean;
364
+
365
+ @Field(() => String, {
366
+ nullable: true,
367
+ description:
368
+ "if provided and either ForceAuditLog is set, or the entity's property settings for logging view runs are set to true, this will be used as the Audit Log Description.",
369
+ })
370
+ AuditLogDescription?: string;
371
+
372
+ @Field(() => String, {
373
+ nullable: true,
374
+ description:
375
+ 'Optional, pass in entity_object, simple, or count_only as options to specify the type of result you want back. Defaults to simple if not provided',
376
+ })
377
+ ResultType?: string;
378
+
379
+ @Field(() => Int, {
380
+ nullable: true,
381
+ description: 'If a value > 0 is provided, this value will be used to offset the rows returned.',
382
+ })
383
+ StartRow?: number;
384
+ }
385
+
386
+ @ObjectType()
387
+ export class RunViewResultRow {
388
+ @Field(() => [KeyValuePairOutputType], {
389
+ description: 'Primary key values for the record'
390
+ })
391
+ PrimaryKey: KeyValuePairOutputType[];
392
+
393
+ @Field(() => String)
394
+ EntityID: string;
395
+
396
+ @Field(() => String)
397
+ Data: string;
398
+ }
399
+
400
+ @ObjectType()
401
+ export class RunViewGenericResultRow {
402
+ @Field(() => [KeyValuePairOutputType], {
403
+ description: 'Primary key values for the record'
404
+ })
405
+ PrimaryKey: KeyValuePairOutputType[];
406
+
407
+ @Field(() => String)
408
+ EntityID: string;
409
+
410
+ @Field(() => String)
411
+ Data: string;
412
+ }
413
+
414
+ @ObjectType()
415
+ export class RunViewResult {
416
+ @Field(() => [RunViewResultRow])
417
+ Results: RunViewResultRow[];
418
+
419
+ @Field(() => String, { nullable: true })
420
+ UserViewRunID?: string;
421
+
422
+ @Field(() => Int, { nullable: true })
423
+ RowCount: number;
424
+
425
+ @Field(() => Int, { nullable: true })
426
+ TotalRowCount: number;
427
+
428
+ @Field(() => Int, { nullable: true })
429
+ ExecutionTime: number;
430
+
431
+ @Field(() => String, { nullable: true })
432
+ ErrorMessage?: string;
433
+
434
+ @Field(() => Boolean, { nullable: false })
435
+ Success: boolean;
436
+ }
437
+
438
+ @ObjectType()
439
+ export class RunViewGenericResult {
440
+ @Field(() => [RunViewGenericResultRow])
441
+ Results: RunViewGenericResultRow[];
442
+
443
+ @Field(() => String, { nullable: true })
444
+ UserViewRunID?: string;
445
+
446
+ @Field(() => Int, { nullable: true })
447
+ RowCount: number;
448
+
449
+ @Field(() => Int, { nullable: true })
450
+ TotalRowCount: number;
451
+
452
+ @Field(() => Int, { nullable: true })
453
+ ExecutionTime: number;
454
+
455
+ @Field(() => String, { nullable: true })
456
+ ErrorMessage?: string;
457
+
458
+ @Field(() => Boolean, { nullable: false })
459
+ Success: boolean;
460
+ }
461
+
462
+ @Resolver(RunViewResultRow)
463
+ export class RunViewResolver extends ResolverBase {
464
+ @Query(() => RunViewResult)
465
+ async RunViewByName(
466
+ @Arg('input', () => RunViewByNameInput) input: RunViewByNameInput,
467
+ @Ctx() { providers, userPayload }: AppContext,
468
+ pubSub: PubSubEngine
469
+ ) {
470
+ try {
471
+ const provider = GetReadOnlyProvider(providers, { allowFallbackToReadWrite: true });
472
+ const rawData = await super.RunViewByNameGeneric(input, provider, userPayload, pubSub);
473
+ if (rawData === null)
474
+ return null;
475
+
476
+ const viewInfo = super.safeFirstArrayElement<UserViewEntityExtended>(await super.findBy<UserViewEntityExtended>(provider, "User Views", { Name: input.ViewName }, userPayload.userRecord));
477
+ const entity = provider.Entities.find((e) => e.ID === viewInfo.EntityID);
478
+ const returnData = this.processRawData(rawData.Results, viewInfo.EntityID, entity);
479
+ return {
480
+ Results: returnData,
481
+ UserViewRunID: rawData?.UserViewRunID,
482
+ RowCount: rawData?.RowCount,
483
+ TotalRowCount: rawData?.TotalRowCount,
484
+ ExecutionTime: rawData?.ExecutionTime,
485
+ };
486
+ } catch (err) {
487
+ console.log(err);
488
+ return null;
489
+ }
490
+ }
491
+
492
+ @Query(() => RunViewResult)
493
+ async RunViewByID(
494
+ @Arg('input', () => RunViewByIDInput) input: RunViewByIDInput,
495
+ @Ctx() { providers, userPayload }: AppContext,
496
+ pubSub: PubSubEngine
497
+ ) {
498
+ try {
499
+ const provider = GetReadOnlyProvider(providers, { allowFallbackToReadWrite: true });
500
+ const rawData = await super.RunViewByIDGeneric(input, provider, userPayload, pubSub);
501
+ if (rawData === null)
502
+ return null;
503
+
504
+ const viewInfo = super.safeFirstArrayElement<UserViewEntityExtended>(await super.findBy<UserViewEntityExtended>(provider, "User Views", { ID: input.ViewID }, userPayload.userRecord));
505
+ const entity = provider.Entities.find((e) => e.ID === viewInfo.EntityID);
506
+ const returnData = this.processRawData(rawData.Results, viewInfo.EntityID, entity);
507
+ return {
508
+ Results: returnData,
509
+ UserViewRunID: rawData?.UserViewRunID,
510
+ RowCount: rawData?.RowCount,
511
+ TotalRowCount: rawData?.TotalRowCount,
512
+ ExecutionTime: rawData?.ExecutionTime,
513
+ };
514
+ } catch (err) {
515
+ console.log(err);
516
+ return null;
517
+ }
518
+ }
519
+
520
+ @Query(() => RunViewResult)
521
+ async RunDynamicView(
522
+ @Arg('input', () => RunDynamicViewInput) input: RunDynamicViewInput,
523
+ @Ctx() { providers, userPayload }: AppContext,
524
+ pubSub: PubSubEngine
525
+ ) {
526
+ try {
527
+ const provider = GetReadOnlyProvider(providers, { allowFallbackToReadWrite: true });
528
+ const rawData = await super.RunDynamicViewGeneric(input, provider, userPayload, pubSub);
529
+ if (rawData === null) return null;
530
+
531
+ const entity = provider.Entities.find((e) => e.Name === input.EntityName);
532
+ const returnData = this.processRawData(rawData.Results, entity.ID, entity);
533
+ return {
534
+ Results: returnData,
535
+ UserViewRunID: rawData?.UserViewRunID,
536
+ RowCount: rawData?.RowCount,
537
+ TotalRowCount: rawData?.TotalRowCount,
538
+ ExecutionTime: rawData?.ExecutionTime,
539
+ };
540
+ } catch (err) {
541
+ console.log(err);
542
+ return null;
543
+ }
544
+ }
545
+
546
+ @Query(() => [RunViewGenericResult])
547
+ async RunViews(
548
+ @Arg('input', () => [RunViewGenericInput]) input: (RunViewByNameInput & RunViewByIDInput & RunDynamicViewInput)[],
549
+ @Ctx() { providers, userPayload }: AppContext,
550
+ pubSub: PubSubEngine
551
+ ) {
552
+ try {
553
+ const provider = GetReadOnlyProvider(providers, { allowFallbackToReadWrite: true });
554
+ const rawData: RunViewGenericResult[] = await super.RunViewsGeneric(input, provider, userPayload);
555
+ if (!rawData) {
556
+ return null;
557
+ }
558
+
559
+ let results: RunViewGenericResult[] = [];
560
+ for (const [index, data] of rawData.entries()) {
561
+ const entity = provider.Entities.find((e) => e.Name === input[index].EntityName);
562
+ const returnData: any[] = this.processRawData(data.Results, entity.ID, entity);
563
+
564
+ results.push({
565
+ Results: returnData,
566
+ UserViewRunID: data?.UserViewRunID,
567
+ RowCount: data?.RowCount,
568
+ TotalRowCount: data?.TotalRowCount,
569
+ ExecutionTime: data?.ExecutionTime,
570
+ Success: data?.Success,
571
+ });
572
+ }
573
+
574
+ return results;
575
+ } catch (err) {
576
+ LogError(err);
577
+ return null;
578
+ }
579
+ }
580
+
581
+ @RequireSystemUser()
582
+ @Query(() => RunViewResult)
583
+ async RunViewByNameSystemUser(
584
+ @Arg('input', () => RunViewByNameInput) input: RunViewByNameInput,
585
+ @Ctx() { providers, userPayload }: AppContext,
586
+ pubSub: PubSubEngine
587
+ ) {
588
+ try {
589
+ const provider = GetReadOnlyProvider(providers, { allowFallbackToReadWrite: true });
590
+ const rawData = await super.RunViewByNameGeneric(input, provider, userPayload, pubSub);
591
+ if (rawData === null) {
592
+ return {
593
+ Results: [],
594
+ Success: false,
595
+ ErrorMessage: `Failed to execute view: ${input.ViewName}`,
596
+ RowCount: 0,
597
+ TotalRowCount: 0,
598
+ ExecutionTime: 0
599
+ };
600
+ }
601
+
602
+ const entity = provider.Entities.find((e) => e.Name === input.ViewName);
603
+ const entityId = entity ? entity.ID : null;
604
+ const returnData = this.processRawData(rawData.Results, entityId, entity);
605
+ return {
606
+ Results: returnData,
607
+ UserViewRunID: rawData?.UserViewRunID,
608
+ RowCount: rawData?.RowCount,
609
+ TotalRowCount: rawData?.TotalRowCount,
610
+ ExecutionTime: rawData?.ExecutionTime,
611
+ Success: rawData?.Success,
612
+ ErrorMessage: rawData?.ErrorMessage,
613
+ };
614
+ } catch (err) {
615
+ const errorMessage = err instanceof Error ? err.message : 'Unknown error occurred';
616
+ LogError(err);
617
+ return {
618
+ Results: [],
619
+ Success: false,
620
+ ErrorMessage: errorMessage,
621
+ RowCount: 0,
622
+ TotalRowCount: 0,
623
+ ExecutionTime: 0
624
+ };
625
+ }
626
+ }
627
+
628
+ @RequireSystemUser()
629
+ @Query(() => RunViewResult)
630
+ async RunViewByIDSystemUser(
631
+ @Arg('input', () => RunViewByIDInput) input: RunViewByIDInput,
632
+ @Ctx() { providers, userPayload }: AppContext,
633
+ pubSub: PubSubEngine
634
+ ) {
635
+ try {
636
+ const provider = GetReadOnlyProvider(providers, { allowFallbackToReadWrite: true });
637
+ const rawData = await super.RunViewByIDGeneric(input, provider, userPayload, pubSub);
638
+ if (rawData === null) {
639
+ return {
640
+ Results: [],
641
+ Success: false,
642
+ ErrorMessage: `Failed to execute view with ID: ${input.ViewID}`,
643
+ RowCount: 0,
644
+ TotalRowCount: 0,
645
+ ExecutionTime: 0
646
+ };
647
+ }
648
+
649
+ const viewInfo = super.safeFirstArrayElement<UserViewEntityExtended>(await super.findBy<UserViewEntityExtended>(provider, "User Views", { ID: input.ViewID }, userPayload.userRecord));
650
+ const entity = provider.Entities.find((e) => e.ID === viewInfo.EntityID);
651
+ const returnData = this.processRawData(rawData.Results, viewInfo.EntityID, entity);
652
+ return {
653
+ Results: returnData,
654
+ UserViewRunID: rawData?.UserViewRunID,
655
+ RowCount: rawData?.RowCount,
656
+ TotalRowCount: rawData?.TotalRowCount,
657
+ ExecutionTime: rawData?.ExecutionTime,
658
+ Success: rawData?.Success,
659
+ ErrorMessage: rawData?.ErrorMessage,
660
+ };
661
+ } catch (err) {
662
+ const errorMessage = err instanceof Error ? err.message : 'Unknown error occurred';
663
+ LogError(err);
664
+ return {
665
+ Results: [],
666
+ Success: false,
667
+ ErrorMessage: errorMessage,
668
+ RowCount: 0,
669
+ TotalRowCount: 0,
670
+ ExecutionTime: 0
671
+ };
672
+ }
673
+ }
674
+
675
+ @RequireSystemUser()
676
+ @Query(() => RunViewResult)
677
+ async RunDynamicViewSystemUser(
678
+ @Arg('input', () => RunDynamicViewInput) input: RunDynamicViewInput,
679
+ @Ctx() { providers, userPayload }: AppContext,
680
+ pubSub: PubSubEngine
681
+ ) {
682
+ try {
683
+ const provider = GetReadOnlyProvider(providers, { allowFallbackToReadWrite: true });
684
+ const rawData = await super.RunDynamicViewGeneric(input, provider, userPayload, pubSub);
685
+ if (rawData === null) {
686
+ return {
687
+ Results: [],
688
+ Success: false,
689
+ ErrorMessage: 'Failed to execute dynamic view',
690
+ RowCount: 0,
691
+ TotalRowCount: 0,
692
+ ExecutionTime: 0
693
+ };
694
+ }
695
+
696
+ const entity = provider.Entities.find((e) => e.Name === input.EntityName);
697
+ if (!entity) {
698
+ const errorMsg = `Entity ${input.EntityName} not found in metadata`;
699
+ LogError(new Error(errorMsg));
700
+ return {
701
+ Results: [],
702
+ Success: false,
703
+ ErrorMessage: errorMsg,
704
+ RowCount: 0,
705
+ TotalRowCount: 0,
706
+ ExecutionTime: 0
707
+ };
708
+ }
709
+ const returnData = this.processRawData(rawData.Results, entity.ID, entity);
710
+ return {
711
+ Results: returnData,
712
+ UserViewRunID: rawData?.UserViewRunID,
713
+ RowCount: rawData?.RowCount,
714
+ TotalRowCount: rawData?.TotalRowCount,
715
+ ExecutionTime: rawData?.ExecutionTime,
716
+ Success: rawData?.Success,
717
+ ErrorMessage: rawData?.ErrorMessage,
718
+ };
719
+ } catch (err) {
720
+ const errorMessage = err instanceof Error ? err.message : 'Unknown error occurred';
721
+ LogError(err);
722
+ return {
723
+ Results: [],
724
+ Success: false,
725
+ ErrorMessage: errorMessage,
726
+ RowCount: 0,
727
+ TotalRowCount: 0,
728
+ ExecutionTime: 0
729
+ };
730
+ }
731
+ }
732
+
733
+ @RequireSystemUser()
734
+ @Query(() => [RunViewGenericResult])
735
+ async RunViewsSystemUser(
736
+ @Arg('input', () => [RunViewGenericInput]) input: (RunViewByNameInput & RunViewByIDInput & RunDynamicViewInput)[],
737
+ @Ctx() { providers, userPayload }: AppContext,
738
+ pubSub: PubSubEngine
739
+ ) {
740
+ try {
741
+ const provider = GetReadOnlyProvider(providers, { allowFallbackToReadWrite: true });
742
+ const rawData: RunViewGenericResult[] = await super.RunViewsGeneric(input, provider, userPayload);
743
+ if (!rawData) {
744
+ return null;
745
+ }
746
+
747
+ let results: RunViewGenericResult[] = [];
748
+ for (const [index, data] of rawData.entries()) {
749
+ const entity = provider.Entities.find((e) => e.Name === input[index].EntityName);
750
+ if (!entity) {
751
+ LogError(new Error(`Entity with name ${input[index].EntityName} not found`));
752
+ continue;
753
+ }
754
+ const returnData: any[] = this.processRawData(data.Results, entity.ID, entity);
755
+
756
+ results.push({
757
+ Results: returnData,
758
+ UserViewRunID: data?.UserViewRunID,
759
+ RowCount: data?.RowCount,
760
+ TotalRowCount: data?.TotalRowCount,
761
+ ExecutionTime: data?.ExecutionTime,
762
+ Success: data?.Success,
763
+ ErrorMessage: data?.ErrorMessage,
764
+ });
765
+ }
766
+
767
+ return results;
768
+ } catch (err) {
769
+ LogError(err);
770
+ return null;
771
+ }
772
+ }
773
+
774
+ protected processRawData(rawData: any[], entityId: string, entityInfo: EntityInfo): RunViewResultRow[] {
775
+ const returnResult = [];
776
+ for (let i = 0; i < rawData.length; i++) {
777
+ const row = rawData[i];
778
+
779
+ // Build the primary key array from the entity's primary key fields
780
+ const primaryKey: KeyValuePairOutputType[] = entityInfo.PrimaryKeys.map(pk => ({
781
+ FieldName: pk.Name,
782
+ Value: row[pk.Name]?.toString() || ''
783
+ }));
784
+
785
+ returnResult.push({
786
+ PrimaryKey: primaryKey,
787
+ EntityID: entityId,
788
+ Data: JSON.stringify(row),
789
+ });
790
+ }
791
+ return returnResult;
792
+ }
793
+ }