@memberjunction/server 2.95.0 → 2.97.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/dist/context.d.ts.map +1 -1
  2. package/dist/context.js +4 -0
  3. package/dist/context.js.map +1 -1
  4. package/dist/resolvers/ActionResolver.d.ts.map +1 -1
  5. package/dist/resolvers/ActionResolver.js +5 -4
  6. package/dist/resolvers/ActionResolver.js.map +1 -1
  7. package/dist/resolvers/AskSkipResolver.d.ts +4 -4
  8. package/dist/resolvers/AskSkipResolver.d.ts.map +1 -1
  9. package/dist/resolvers/AskSkipResolver.js +9 -9
  10. package/dist/resolvers/AskSkipResolver.js.map +1 -1
  11. package/dist/resolvers/CreateQueryResolver.d.ts +2 -2
  12. package/dist/resolvers/CreateQueryResolver.d.ts.map +1 -1
  13. package/dist/resolvers/CreateQueryResolver.js +30 -18
  14. package/dist/resolvers/CreateQueryResolver.js.map +1 -1
  15. package/dist/resolvers/DatasetResolver.d.ts +2 -2
  16. package/dist/resolvers/DatasetResolver.d.ts.map +1 -1
  17. package/dist/resolvers/DatasetResolver.js +6 -5
  18. package/dist/resolvers/DatasetResolver.js.map +1 -1
  19. package/dist/resolvers/EntityRecordNameResolver.d.ts +4 -4
  20. package/dist/resolvers/EntityRecordNameResolver.d.ts.map +1 -1
  21. package/dist/resolvers/EntityRecordNameResolver.js +6 -5
  22. package/dist/resolvers/EntityRecordNameResolver.js.map +1 -1
  23. package/dist/resolvers/FileCategoryResolver.d.ts.map +1 -1
  24. package/dist/resolvers/FileCategoryResolver.js +10 -11
  25. package/dist/resolvers/FileCategoryResolver.js.map +1 -1
  26. package/dist/resolvers/FileResolver.d.ts.map +1 -1
  27. package/dist/resolvers/FileResolver.js +5 -6
  28. package/dist/resolvers/FileResolver.js.map +1 -1
  29. package/dist/resolvers/GetDataContextDataResolver.js +2 -2
  30. package/dist/resolvers/GetDataContextDataResolver.js.map +1 -1
  31. package/dist/resolvers/GetDataResolver.js +3 -3
  32. package/dist/resolvers/GetDataResolver.js.map +1 -1
  33. package/dist/resolvers/MergeRecordsResolver.d.ts +3 -3
  34. package/dist/resolvers/MergeRecordsResolver.d.ts.map +1 -1
  35. package/dist/resolvers/MergeRecordsResolver.js +8 -7
  36. package/dist/resolvers/MergeRecordsResolver.js.map +1 -1
  37. package/dist/resolvers/PotentialDuplicateRecordResolver.d.ts +1 -1
  38. package/dist/resolvers/PotentialDuplicateRecordResolver.d.ts.map +1 -1
  39. package/dist/resolvers/PotentialDuplicateRecordResolver.js +4 -3
  40. package/dist/resolvers/PotentialDuplicateRecordResolver.js.map +1 -1
  41. package/dist/resolvers/QueryResolver.d.ts.map +1 -1
  42. package/dist/resolvers/QueryResolver.js +19 -14
  43. package/dist/resolvers/QueryResolver.js.map +1 -1
  44. package/dist/resolvers/ReportResolver.d.ts +2 -2
  45. package/dist/resolvers/ReportResolver.d.ts.map +1 -1
  46. package/dist/resolvers/ReportResolver.js +8 -6
  47. package/dist/resolvers/ReportResolver.js.map +1 -1
  48. package/dist/resolvers/RunAIAgentResolver.d.ts +3 -7
  49. package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
  50. package/dist/resolvers/RunAIAgentResolver.js +8 -5
  51. package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
  52. package/dist/resolvers/RunAIPromptResolver.d.ts +3 -7
  53. package/dist/resolvers/RunAIPromptResolver.d.ts.map +1 -1
  54. package/dist/resolvers/RunAIPromptResolver.js +10 -8
  55. package/dist/resolvers/RunAIPromptResolver.js.map +1 -1
  56. package/dist/resolvers/RunTemplateResolver.d.ts +2 -4
  57. package/dist/resolvers/RunTemplateResolver.d.ts.map +1 -1
  58. package/dist/resolvers/RunTemplateResolver.js +5 -4
  59. package/dist/resolvers/RunTemplateResolver.js.map +1 -1
  60. package/dist/resolvers/SqlLoggingConfigResolver.d.ts.map +1 -1
  61. package/dist/resolvers/SqlLoggingConfigResolver.js +7 -7
  62. package/dist/resolvers/SqlLoggingConfigResolver.js.map +1 -1
  63. package/dist/resolvers/UserFavoriteResolver.d.ts +3 -4
  64. package/dist/resolvers/UserFavoriteResolver.d.ts.map +1 -1
  65. package/dist/resolvers/UserFavoriteResolver.js +10 -68
  66. package/dist/resolvers/UserFavoriteResolver.js.map +1 -1
  67. package/dist/resolvers/UserViewResolver.d.ts +1 -1
  68. package/dist/resolvers/UserViewResolver.d.ts.map +1 -1
  69. package/dist/resolvers/UserViewResolver.js +3 -4
  70. package/dist/resolvers/UserViewResolver.js.map +1 -1
  71. package/package.json +39 -39
  72. package/src/context.ts +5 -0
  73. package/src/resolvers/ActionResolver.ts +5 -4
  74. package/src/resolvers/AskSkipResolver.ts +13 -13
  75. package/src/resolvers/CreateQueryResolver.ts +34 -19
  76. package/src/resolvers/DatasetResolver.ts +5 -4
  77. package/src/resolvers/EntityRecordNameResolver.ts +8 -6
  78. package/src/resolvers/FileCategoryResolver.ts +9 -10
  79. package/src/resolvers/FileResolver.ts +6 -7
  80. package/src/resolvers/GetDataContextDataResolver.ts +2 -2
  81. package/src/resolvers/GetDataResolver.ts +2 -2
  82. package/src/resolvers/InfoResolver.ts +1 -1
  83. package/src/resolvers/MergeRecordsResolver.ts +7 -6
  84. package/src/resolvers/PotentialDuplicateRecordResolver.ts +3 -2
  85. package/src/resolvers/QueryResolver.ts +22 -15
  86. package/src/resolvers/ReportResolver.ts +9 -6
  87. package/src/resolvers/RunAIAgentResolver.ts +12 -4
  88. package/src/resolvers/RunAIPromptResolver.ts +12 -8
  89. package/src/resolvers/RunTemplateResolver.ts +5 -5
  90. package/src/resolvers/SqlLoggingConfigResolver.ts +7 -6
  91. package/src/resolvers/UserFavoriteResolver.ts +8 -67
  92. package/src/resolvers/UserViewResolver.ts +3 -3
@@ -3,6 +3,7 @@ import { Arg, Ctx, Field, InputType, Int, Mutation, ObjectType, PubSub, PubSubEn
3
3
  import { AppContext } from '../types.js';
4
4
  import { CompositeKeyInputType, CompositeKeyOutputType } from '../generic/KeyInputOutputTypes.js';
5
5
  import { z } from 'zod';
6
+ import { GetReadOnlyProvider, GetReadWriteProvider } from '../util.js';
6
7
 
7
8
  @ObjectType()
8
9
  export class EntityDependencyResult {
@@ -21,11 +22,11 @@ export class EntityDependencyResolver {
21
22
  @Query(() => [EntityDependencyResult])
22
23
  async GetEntityDependencies(
23
24
  @Arg('entityName', () => String) entityName: string,
24
- @Ctx() { dataSource, userPayload }: AppContext,
25
+ @Ctx() { dataSource, userPayload, providers }: AppContext,
25
26
  @PubSub() pubSub: PubSubEngine
26
27
  ) {
27
28
  try {
28
- const md = new Metadata();
29
+ const md = GetReadOnlyProvider(providers);
29
30
  return md.GetEntityDependencies(entityName);
30
31
  } catch (err) {
31
32
  LogError(err);
@@ -57,11 +58,11 @@ export class RecordDependencyResolver {
57
58
  async GetRecordDependencies(
58
59
  @Arg('entityName', () => String) entityName: string,
59
60
  @Arg('CompositeKey', () => CompositeKeyInputType) ckInput: CompositeKeyInputType,
60
- @Ctx() { dataSource, userPayload }: AppContext,
61
+ @Ctx() { dataSource, userPayload, providers }: AppContext,
61
62
  @PubSub() pubSub: PubSubEngine
62
63
  ) {
63
64
  try {
64
- const md = new Metadata();
65
+ const md = GetReadOnlyProvider(providers);
65
66
  const ck = new CompositeKey(ckInput.KeyValuePairs);
66
67
  const result = await md.GetRecordDependencies(entityName, ck);
67
68
 
@@ -165,11 +166,11 @@ export class RecordMergeResolver {
165
166
  @Mutation(() => RecordMergeResult)
166
167
  async MergeRecords(
167
168
  @Arg('request', () => RecordMergeRequest) request: RecordMergeRequest,
168
- @Ctx() { dataSource, userPayload }: AppContext,
169
+ @Ctx() { dataSource, userPayload, providers }: AppContext,
169
170
  @PubSub() pubSub: PubSubEngine
170
171
  ) {
171
172
  try {
172
- const md = new Metadata();
173
+ const md = GetReadWriteProvider(providers);
173
174
  const options = {};
174
175
  const result = await md.MergeRecords(request, userPayload.userRecord, options);
175
176
  return result;
@@ -14,6 +14,7 @@ import { UserCache } from '@memberjunction/sqlserver-dataprovider';
14
14
  import { LoadMistralEmbedding } from '@memberjunction/ai-mistral';
15
15
  import { LoadPineconeVectorDB } from '@memberjunction/ai-vectors-pinecone';
16
16
  import { CompositeKeyInputType, CompositeKeyOutputType, KeyValuePairOutputType } from '../generic/KeyInputOutputTypes.js';
17
+ import { GetReadOnlyProvider } from '../util.js';
17
18
  LoadMistralEmbedding();
18
19
  LoadPineconeVectorDB();
19
20
 
@@ -75,10 +76,10 @@ export class PotentialDuplicateResponseType extends PotentialDuplicateResponse {
75
76
  export class DuplicateRecordResolver {
76
77
  @Query(() => PotentialDuplicateResponseType)
77
78
  async GetRecordDuplicates(
78
- @Ctx() { dataSource, userPayload }: AppContext,
79
+ @Ctx() { dataSource, userPayload, providers }: AppContext,
79
80
  @Arg('params') params: PotentialDuplicateRequestType
80
81
  ): Promise<PotentialDuplicateResponseType> {
81
- const md = new Metadata();
82
+ const md = GetReadOnlyProvider(providers);
82
83
 
83
84
  const user = UserCache.Instance.Users.find((u) => u.Email.trim().toLowerCase() === userPayload.email.trim().toLowerCase());
84
85
  if (!user) {
@@ -1,9 +1,10 @@
1
1
  import { Arg, Ctx, ObjectType, Query, Resolver, Field, Int } from 'type-graphql';
2
- import { RunQuery, QueryInfo } from '@memberjunction/core';
2
+ import { RunQuery, QueryInfo, IRunQueryProvider, IMetadataProvider } from '@memberjunction/core';
3
3
  import { AppContext } from '../types.js';
4
4
  import { RequireSystemUser } from '../directives/RequireSystemUser.js';
5
5
  import { GraphQLJSONObject } from 'graphql-type-json';
6
6
  import { Metadata } from '@memberjunction/core';
7
+ import { GetReadOnlyProvider } from '../util.js';
7
8
 
8
9
  @ObjectType()
9
10
  export class RunQueryResultType {
@@ -43,9 +44,7 @@ export class RunQueryResultType {
43
44
 
44
45
  @Resolver()
45
46
  export class RunQueryResolver {
46
- private async findQuery(QueryID: string, QueryName?: string, CategoryID?: string, CategoryPath?: string, refreshMetadataIfNotFound: boolean = false): Promise<QueryInfo | null> {
47
- const md = new Metadata();
48
-
47
+ private async findQuery(md: IMetadataProvider, QueryID: string, QueryName?: string, CategoryID?: string, CategoryPath?: string, refreshMetadataIfNotFound: boolean = false): Promise<QueryInfo | null> {
49
48
  // Filter queries based on provided criteria
50
49
  const queries = md.Queries.filter(q => {
51
50
  if (QueryID) {
@@ -67,7 +66,7 @@ export class RunQueryResolver {
67
66
  if (refreshMetadataIfNotFound) {
68
67
  // If we didn't find the query, refresh metadata and try again
69
68
  await md.Refresh();
70
- return this.findQuery(QueryID, QueryName, CategoryID, CategoryPath, false); // change the refresh flag to false so we don't loop infinitely
69
+ return this.findQuery(md, QueryID, QueryName, CategoryID, CategoryPath, false); // change the refresh flag to false so we don't loop infinitely
71
70
  }
72
71
  else {
73
72
  return null; // No query found and not refreshing metadata
@@ -87,9 +86,11 @@ export class RunQueryResolver {
87
86
  @Arg('StartRow', () => Int, {nullable: true}) StartRow?: number,
88
87
  @Arg('ForceAuditLog', () => Boolean, {nullable: true}) ForceAuditLog?: boolean,
89
88
  @Arg('AuditLogDescription', () => String, {nullable: true}) AuditLogDescription?: string): Promise<RunQueryResultType> {
90
- const runQuery = new RunQuery();
89
+ const provider = GetReadOnlyProvider(context.providers, {allowFallbackToReadWrite: true});
90
+ const md = provider as unknown as IMetadataProvider;
91
+ const rq = new RunQuery(provider as unknown as IRunQueryProvider);
91
92
  console.log('GetQueryData called with:', { QueryID, Parameters, MaxRows, StartRow, ForceAuditLog, AuditLogDescription });
92
- const result = await runQuery.RunQuery(
93
+ const result = await rq.RunQuery(
93
94
  {
94
95
  QueryID: QueryID,
95
96
  CategoryID: CategoryID,
@@ -111,7 +112,7 @@ export class RunQueryResolver {
111
112
  let queryName = result.QueryName;
112
113
  if (!queryName) {
113
114
  try {
114
- const queryInfo = await this.findQuery(QueryID, undefined, CategoryID, CategoryPath, true);
115
+ const queryInfo = await this.findQuery(md, QueryID, undefined, CategoryID, CategoryPath, true);
115
116
  if (queryInfo) {
116
117
  queryName = queryInfo.Name;
117
118
  }
@@ -145,8 +146,9 @@ export class RunQueryResolver {
145
146
  @Arg('StartRow', () => Int, {nullable: true}) StartRow?: number,
146
147
  @Arg('ForceAuditLog', () => Boolean, {nullable: true}) ForceAuditLog?: boolean,
147
148
  @Arg('AuditLogDescription', () => String, {nullable: true}) AuditLogDescription?: string): Promise<RunQueryResultType> {
148
- const runQuery = new RunQuery();
149
- const result = await runQuery.RunQuery(
149
+ const provider = GetReadOnlyProvider(context.providers, {allowFallbackToReadWrite: true});
150
+ const rq = new RunQuery(provider as unknown as IRunQueryProvider);
151
+ const result = await rq.RunQuery(
150
152
  {
151
153
  QueryName: QueryName,
152
154
  CategoryID: CategoryID,
@@ -185,8 +187,11 @@ export class RunQueryResolver {
185
187
  @Arg('StartRow', () => Int, {nullable: true}) StartRow?: number,
186
188
  @Arg('ForceAuditLog', () => Boolean, {nullable: true}) ForceAuditLog?: boolean,
187
189
  @Arg('AuditLogDescription', () => String, {nullable: true}) AuditLogDescription?: string): Promise<RunQueryResultType> {
188
- const runQuery = new RunQuery();
189
- const result = await runQuery.RunQuery(
190
+ const provider = GetReadOnlyProvider(context.providers, {allowFallbackToReadWrite: true});
191
+ const md = provider as unknown as IMetadataProvider;
192
+ const rq = new RunQuery(provider as unknown as IRunQueryProvider);
193
+
194
+ const result = await rq.RunQuery(
190
195
  {
191
196
  QueryID: QueryID,
192
197
  CategoryID: CategoryID,
@@ -203,7 +208,7 @@ export class RunQueryResolver {
203
208
  let queryName = result.QueryName;
204
209
  if (!queryName) {
205
210
  try {
206
- const queryInfo = await this.findQuery(QueryID, undefined, CategoryID, CategoryPath, true);
211
+ const queryInfo = await this.findQuery(md, QueryID, undefined, CategoryID, CategoryPath, true);
207
212
  if (queryInfo) {
208
213
  queryName = queryInfo.Name;
209
214
  }
@@ -238,8 +243,10 @@ export class RunQueryResolver {
238
243
  @Arg('StartRow', () => Int, {nullable: true}) StartRow?: number,
239
244
  @Arg('ForceAuditLog', () => Boolean, {nullable: true}) ForceAuditLog?: boolean,
240
245
  @Arg('AuditLogDescription', () => String, {nullable: true}) AuditLogDescription?: string): Promise<RunQueryResultType> {
241
- const runQuery = new RunQuery();
242
- const result = await runQuery.RunQuery(
246
+ const provider = GetReadOnlyProvider(context.providers, {allowFallbackToReadWrite: true});
247
+ const rq = new RunQuery(provider as unknown as IRunQueryProvider);
248
+
249
+ const result = await rq.RunQuery(
243
250
  {
244
251
  QueryName: QueryName,
245
252
  CategoryID: CategoryID,
@@ -1,4 +1,4 @@
1
- import { EntitySaveOptions, Metadata, RunReport } from '@memberjunction/core';
1
+ import { EntitySaveOptions, IRunReportProvider, Metadata, RunReport } from '@memberjunction/core';
2
2
  import { Arg, Ctx, Field, Int, Mutation, ObjectType, Query, Resolver } from 'type-graphql';
3
3
  import { AppContext } from '../types.js';
4
4
  import { ConversationDetailEntity, ReportEntity } from '@memberjunction/core-entities';
@@ -7,6 +7,7 @@ import { DataContext } from '@memberjunction/data-context';
7
7
  import { UserCache } from '@memberjunction/sqlserver-dataprovider';
8
8
  import { z } from 'zod';
9
9
  import mssql from 'mssql';
10
+ import { GetReadOnlyProvider, GetReadWriteProvider } from '../util.js';
10
11
 
11
12
  @ObjectType()
12
13
  export class RunReportResultType {
@@ -47,9 +48,11 @@ export class CreateReportResultType {
47
48
  @Resolver(RunReportResultType)
48
49
  export class ReportResolverExtended {
49
50
  @Query(() => RunReportResultType)
50
- async GetReportData(@Arg('ReportID', () => String) ReportID: string, @Ctx() {}: AppContext): Promise<RunReportResultType> {
51
- const runReport = new RunReport();
52
- const result = await runReport.RunReport({ ReportID: ReportID });
51
+ async GetReportData(@Arg('ReportID', () => String) ReportID: string, @Ctx() context: AppContext): Promise<RunReportResultType> {
52
+ const provider = GetReadOnlyProvider(context.providers, {allowFallbackToReadWrite: true});
53
+ const rp = new RunReport(provider as unknown as IRunReportProvider);
54
+
55
+ const result = await rp.RunReport({ ReportID: ReportID });
53
56
  return {
54
57
  ReportID: ReportID,
55
58
  Success: result.Success,
@@ -66,10 +69,10 @@ export class ReportResolverExtended {
66
69
  @Mutation(() => CreateReportResultType)
67
70
  async CreateReportFromConversationDetailID(
68
71
  @Arg('ConversationDetailID', () => String) ConversationDetailID: string,
69
- @Ctx() { dataSource, userPayload }: AppContext
72
+ @Ctx() { dataSource, userPayload, providers }: AppContext
70
73
  ): Promise<CreateReportResultType> {
71
74
  try {
72
- const md = new Metadata();
75
+ const md = GetReadWriteProvider(providers);
73
76
 
74
77
  const u = UserCache.Users.find((u) => u.Email?.trim().toLowerCase() === userPayload?.email?.trim().toLowerCase());
75
78
  if (!u) throw new Error('Unable to find user');
@@ -1,6 +1,6 @@
1
1
  import { Resolver, Mutation, Query, Arg, Ctx, ObjectType, Field, PubSub, PubSubEngine, Subscription, Root, ResolverFilterData, ID } from 'type-graphql';
2
- import { UserPayload } from '../types.js';
3
- import { LogError, LogStatus } from '@memberjunction/core';
2
+ import { AppContext, UserPayload } from '../types.js';
3
+ import { DatabaseProviderBase, LogError, LogStatus } from '@memberjunction/core';
4
4
  import { AIAgentEntityExtended } from '@memberjunction/core-entities';
5
5
  import { AgentRunner } from '@memberjunction/ai-agents';
6
6
  import { ExecuteAgentResult } from '@memberjunction/ai-core-plus';
@@ -8,6 +8,7 @@ import { AIEngine } from '@memberjunction/aiengine';
8
8
  import { ResolverBase } from '../generic/ResolverBase.js';
9
9
  import { PUSH_STATUS_UPDATES_TOPIC } from '../generic/PushStatusResolver.js';
10
10
  import { RequireSystemUser } from '../directives/RequireSystemUser.js';
11
+ import { GetReadWriteProvider } from '../util.js';
11
12
 
12
13
  @ObjectType()
13
14
  export class AIAgentRunResult {
@@ -304,6 +305,7 @@ export class RunAIAgentResolver extends ResolverBase {
304
305
  * @private
305
306
  */
306
307
  private async executeAIAgent(
308
+ p: DatabaseProviderBase,
307
309
  agentId: string,
308
310
  userPayload: UserPayload,
309
311
  messagesJson: string,
@@ -339,6 +341,8 @@ export class RunAIAgentResolver extends ResolverBase {
339
341
  // Validate agent
340
342
  const agentEntity = await this.validateAgent(agentId, currentUser);
341
343
 
344
+ // @jordanfanapour IMPORTANT TO-DO for various engine classes (via base engine class) and here for AI Agent Runner and for AI Prompt Runner, need to be able to pass in a IMetadataProvider for it to use
345
+ // for multi-user server environments like this one
342
346
  // Create AI agent runner
343
347
  const agentRunner = new AgentRunner();
344
348
 
@@ -453,7 +457,7 @@ export class RunAIAgentResolver extends ResolverBase {
453
457
  @Mutation(() => AIAgentRunResult)
454
458
  async RunAIAgent(
455
459
  @Arg('agentId') agentId: string,
456
- @Ctx() { userPayload }: { userPayload: UserPayload },
460
+ @Ctx() { userPayload, providers }: AppContext,
457
461
  @Arg('messages') messagesJson: string,
458
462
  @Arg('sessionId') sessionId: string,
459
463
  @PubSub() pubSub: PubSubEngine,
@@ -463,7 +467,9 @@ export class RunAIAgentResolver extends ResolverBase {
463
467
  @Arg('autoPopulateLastRunPayload', { nullable: true }) autoPopulateLastRunPayload?: boolean,
464
468
  @Arg('configurationId', { nullable: true }) configurationId?: string
465
469
  ): Promise<AIAgentRunResult> {
470
+ const p = GetReadWriteProvider(providers);
466
471
  return this.executeAIAgent(
472
+ p,
467
473
  agentId,
468
474
  userPayload,
469
475
  messagesJson,
@@ -485,7 +491,7 @@ export class RunAIAgentResolver extends ResolverBase {
485
491
  @Query(() => AIAgentRunResult)
486
492
  async RunAIAgentSystemUser(
487
493
  @Arg('agentId') agentId: string,
488
- @Ctx() { userPayload }: { userPayload: UserPayload },
494
+ @Ctx() { userPayload, providers }: AppContext,
489
495
  @Arg('messages') messagesJson: string,
490
496
  @Arg('sessionId') sessionId: string,
491
497
  @PubSub() pubSub: PubSubEngine,
@@ -495,7 +501,9 @@ export class RunAIAgentResolver extends ResolverBase {
495
501
  @Arg('autoPopulateLastRunPayload', { nullable: true }) autoPopulateLastRunPayload?: boolean,
496
502
  @Arg('configurationId', { nullable: true }) configurationId?: string
497
503
  ): Promise<AIAgentRunResult> {
504
+ const p = GetReadWriteProvider(providers);
498
505
  return this.executeAIAgent(
506
+ p,
499
507
  agentId,
500
508
  userPayload,
501
509
  messagesJson,
@@ -1,6 +1,6 @@
1
1
  import { Resolver, Mutation, Query, Arg, Ctx, ObjectType, Field, Int } from 'type-graphql';
2
- import { UserPayload } from '../types.js';
3
- import { LogError, LogStatus, Metadata } from '@memberjunction/core';
2
+ import { AppContext, UserPayload } from '../types.js';
3
+ import { DatabaseProviderBase, LogError, LogStatus, Metadata } from '@memberjunction/core';
4
4
  import { AIPromptEntityExtended, AIModelEntityExtended } from '@memberjunction/core-entities';
5
5
  import { AIPromptRunner } from '@memberjunction/ai-prompts';
6
6
  import { AIPromptParams } from '@memberjunction/ai-core-plus';
@@ -9,6 +9,7 @@ import { RequireSystemUser } from '../directives/RequireSystemUser.js';
9
9
  import { AIEngine } from '@memberjunction/aiengine';
10
10
  import { ChatParams, ChatMessage, ChatMessageRole, GetAIAPIKey, BaseLLM } from '@memberjunction/ai';
11
11
  import { MJGlobal } from '@memberjunction/global';
12
+ import { GetReadWriteProvider } from '../util.js';
12
13
 
13
14
  @ObjectType()
14
15
  export class AIPromptRunResult {
@@ -87,6 +88,7 @@ export class RunAIPromptResolver extends ResolverBase {
87
88
  * @private
88
89
  */
89
90
  private async executeAIPrompt(
91
+ p: DatabaseProviderBase,
90
92
  promptId: string,
91
93
  userPayload: UserPayload,
92
94
  data?: string,
@@ -152,11 +154,9 @@ export class RunAIPromptResolver extends ResolverBase {
152
154
  executionTimeMs: Date.now() - startTime
153
155
  };
154
156
  }
155
-
156
- const md = new Metadata();
157
-
157
+
158
158
  // Load the AI prompt entity
159
- const promptEntity = await md.GetEntityObject<AIPromptEntityExtended>('AI Prompts', currentUser);
159
+ const promptEntity = await p.GetEntityObject<AIPromptEntityExtended>('AI Prompts', currentUser);
160
160
  await promptEntity.Load(promptId);
161
161
 
162
162
  if (!promptEntity.IsSaved) {
@@ -283,7 +283,7 @@ export class RunAIPromptResolver extends ResolverBase {
283
283
  @Mutation(() => AIPromptRunResult)
284
284
  async RunAIPrompt(
285
285
  @Arg('promptId') promptId: string,
286
- @Ctx() { userPayload }: { userPayload: UserPayload },
286
+ @Ctx() { userPayload, providers }: AppContext,
287
287
  @Arg('data', { nullable: true }) data?: string,
288
288
  @Arg('overrideModelId', { nullable: true }) overrideModelId?: string,
289
289
  @Arg('overrideVendorId', { nullable: true }) overrideVendorId?: string,
@@ -305,7 +305,9 @@ export class RunAIPromptResolver extends ResolverBase {
305
305
  @Arg('rerunFromPromptRunID', { nullable: true }) rerunFromPromptRunID?: string,
306
306
  @Arg('systemPromptOverride', { nullable: true }) systemPromptOverride?: string
307
307
  ): Promise<AIPromptRunResult> {
308
+ const p = GetReadWriteProvider(providers);
308
309
  return this.executeAIPrompt(
310
+ p,
309
311
  promptId,
310
312
  userPayload,
311
313
  data,
@@ -339,7 +341,7 @@ export class RunAIPromptResolver extends ResolverBase {
339
341
  @Query(() => AIPromptRunResult)
340
342
  async RunAIPromptSystemUser(
341
343
  @Arg('promptId') promptId: string,
342
- @Ctx() { userPayload }: { userPayload: UserPayload },
344
+ @Ctx() { userPayload, providers }: AppContext,
343
345
  @Arg('data', { nullable: true }) data?: string,
344
346
  @Arg('overrideModelId', { nullable: true }) overrideModelId?: string,
345
347
  @Arg('overrideVendorId', { nullable: true }) overrideVendorId?: string,
@@ -361,7 +363,9 @@ export class RunAIPromptResolver extends ResolverBase {
361
363
  @Arg('rerunFromPromptRunID', { nullable: true }) rerunFromPromptRunID?: string,
362
364
  @Arg('systemPromptOverride', { nullable: true }) systemPromptOverride?: string
363
365
  ): Promise<AIPromptRunResult> {
366
+ const p = GetReadWriteProvider(providers);
364
367
  return this.executeAIPrompt(
368
+ p,
365
369
  promptId,
366
370
  userPayload,
367
371
  data,
@@ -1,10 +1,11 @@
1
1
  import { Resolver, Mutation, Arg, Ctx, ObjectType, Field } from 'type-graphql';
2
- import { UserPayload } from '../types.js';
2
+ import { AppContext, UserPayload } from '../types.js';
3
3
  import { LogError, LogStatus, Metadata, RunView } from '@memberjunction/core';
4
4
  import { TemplateContentEntity } from '@memberjunction/core-entities';
5
5
  import { TemplateEngineServer } from '@memberjunction/templates';
6
6
  import { TemplateEntityExtended } from '@memberjunction/templates-base-types';
7
7
  import { ResolverBase } from '../generic/ResolverBase.js';
8
+ import { GetReadWriteProvider } from '../util.js';
8
9
 
9
10
  @ObjectType()
10
11
  export class TemplateRunResult {
@@ -26,7 +27,7 @@ export class RunTemplateResolver extends ResolverBase {
26
27
  @Mutation(() => TemplateRunResult)
27
28
  async RunTemplate(
28
29
  @Arg('templateId') templateId: string,
29
- @Ctx() { userPayload }: { userPayload: UserPayload },
30
+ @Ctx() { userPayload, providers }: AppContext,
30
31
  @Arg('contextData', { nullable: true }) contextData?: string
31
32
  ): Promise<TemplateRunResult> {
32
33
  const startTime = Date.now();
@@ -58,10 +59,9 @@ export class RunTemplateResolver extends ResolverBase {
58
59
  };
59
60
  }
60
61
 
61
- const md = new Metadata();
62
-
62
+ const p = GetReadWriteProvider(providers);
63
63
  // Load the template entity
64
- const templateEntity = await md.GetEntityObject<TemplateEntityExtended>('Templates', currentUser);
64
+ const templateEntity = await p.GetEntityObject<TemplateEntityExtended>('Templates', currentUser);
65
65
  await templateEntity.Load(templateId);
66
66
 
67
67
  if (!templateEntity.IsSaved) {
@@ -8,6 +8,7 @@ import * as path from 'path';
8
8
  import * as fs from 'fs/promises';
9
9
  import { loadConfig } from '../config.js';
10
10
  import { ResolverBase } from '../generic/ResolverBase.js';
11
+ import { GetReadOnlyProvider } from '../util.js';
11
12
 
12
13
  /**
13
14
  * Configuration options for SQL logging sessions.
@@ -279,7 +280,7 @@ export class SqlLoggingConfigResolver extends ResolverBase {
279
280
  async sqlLoggingConfig(@Ctx() context: AppContext): Promise<SqlLoggingConfig> {
280
281
  await this.checkOwnerAccess(context);
281
282
  const config = await loadConfig();
282
- const provider = Metadata.Provider as SQLServerDataProvider;
283
+ const provider = GetReadOnlyProvider(context.providers, {allowFallbackToReadWrite: true}) as SQLServerDataProvider;
283
284
  const activeSessions = provider.GetActiveSqlLoggingSessions();
284
285
 
285
286
  return {
@@ -334,7 +335,7 @@ export class SqlLoggingConfigResolver extends ResolverBase {
334
335
  @Query(() => [SqlLoggingSession])
335
336
  async activeSqlLoggingSessions(@Ctx() context: AppContext): Promise<SqlLoggingSession[]> {
336
337
  await this.checkOwnerAccess(context);
337
- const provider = Metadata.Provider as SQLServerDataProvider;
338
+ const provider = GetReadOnlyProvider(context.providers, {allowFallbackToReadWrite: true}) as SQLServerDataProvider;
338
339
  const sessions = provider.GetActiveSqlLoggingSessions();
339
340
 
340
341
  return sessions.map(session => ({
@@ -399,7 +400,7 @@ export class SqlLoggingConfigResolver extends ResolverBase {
399
400
  }
400
401
 
401
402
  // Check max active sessions
402
- const provider = Metadata.Provider as SQLServerDataProvider;
403
+ const provider = GetReadOnlyProvider(context.providers, {allowFallbackToReadWrite: true}) as SQLServerDataProvider;
403
404
  const activeSessions = provider.GetActiveSqlLoggingSessions();
404
405
  if (activeSessions.length >= (config.sqlLogging.maxActiveSessions ?? 5)) {
405
406
  throw new Error(`Maximum number of active SQL logging sessions (${config.sqlLogging.maxActiveSessions}) reached`);
@@ -480,7 +481,7 @@ export class SqlLoggingConfigResolver extends ResolverBase {
480
481
  @Ctx() context: AppContext
481
482
  ): Promise<boolean> {
482
483
  await this.checkOwnerAccess(context);
483
- const provider = Metadata.Provider as SQLServerDataProvider;
484
+ const provider = GetReadOnlyProvider(context.providers, {allowFallbackToReadWrite: true}) as SQLServerDataProvider;
484
485
 
485
486
  // Get the actual session from the private map to call dispose
486
487
  const sessionMap = (provider as any)._sqlLoggingSessions as Map<string, any>;
@@ -517,7 +518,7 @@ export class SqlLoggingConfigResolver extends ResolverBase {
517
518
  @Mutation(() => Boolean)
518
519
  async stopAllSqlLogging(@Ctx() context: AppContext): Promise<boolean> {
519
520
  await this.checkOwnerAccess(context);
520
- const provider = Metadata.Provider as SQLServerDataProvider;
521
+ const provider = GetReadOnlyProvider(context.providers, {allowFallbackToReadWrite: true}) as SQLServerDataProvider;
521
522
  await provider.DisposeAllSqlLoggingSessions();
522
523
  return true;
523
524
  }
@@ -607,7 +608,7 @@ export class SqlLoggingConfigResolver extends ResolverBase {
607
608
  }
608
609
 
609
610
  // Find the session
610
- const provider = Metadata.Provider as SQLServerDataProvider;
611
+ const provider = GetReadOnlyProvider(context.providers, {allowFallbackToReadWrite: true}) as SQLServerDataProvider;
611
612
  const sessions = provider.GetActiveSqlLoggingSessions();
612
613
  const session = sessions.find(s => s.id === sessionId);
613
614
 
@@ -81,30 +81,30 @@ export class UserFavoriteResolver extends UserFavoriteResolverBase {
81
81
  }
82
82
 
83
83
  @Query(() => UserFavoriteResult)
84
- async GetRecordFavoriteStatus(@Arg('params', () => UserFavoriteSearchParams) params: UserFavoriteSearchParams, @Ctx() {userPayload}: AppContext) {
85
- const md = new Metadata();
84
+ async GetRecordFavoriteStatus(@Arg('params', () => UserFavoriteSearchParams) params: UserFavoriteSearchParams, @Ctx() {providers, userPayload}: AppContext) {
85
+ const p = GetReadOnlyProvider(providers, {allowFallbackToReadWrite: true});
86
86
  const pk = new CompositeKey(params.CompositeKey.KeyValuePairs);
87
87
 
88
- const e = md.Entities.find((e) => e.ID === params.EntityID);
88
+ const e = p.Entities.find((e) => e.ID === params.EntityID);
89
89
  if (e)
90
90
  return {
91
91
  EntityID: params.EntityID,
92
92
  UserID: params.UserID,
93
93
  CompositeKey: pk,
94
- IsFavorite: await md.GetRecordFavoriteStatus(params.UserID, e.Name, pk, userPayload.userRecord),
94
+ IsFavorite: await p.GetRecordFavoriteStatus(params.UserID, e.Name, pk, userPayload.userRecord),
95
95
  Success: true,
96
96
  };
97
97
  else throw new Error(`Entity ID:${params.EntityID} not found`);
98
98
  }
99
99
 
100
100
  @Mutation(() => UserFavoriteResult)
101
- SetRecordFavoriteStatus(@Arg('params', () => UserFavoriteSetParams) params: UserFavoriteSetParams, @Ctx() { userPayload }: AppContext) {
102
- const md = new Metadata();
101
+ async SetRecordFavoriteStatus(@Arg('params', () => UserFavoriteSetParams) params: UserFavoriteSetParams, @Ctx() { userPayload, providers }: AppContext) {
102
+ const p = GetReadOnlyProvider(providers, {allowFallbackToReadWrite: true});
103
103
  const pk = new CompositeKey(params.CompositeKey.KeyValuePairs);
104
- const e = md.Entities.find((e) => e.ID === params.EntityID);
104
+ const e = p.Entities.find((e) => e.ID === params.EntityID);
105
105
  const u = UserCache.Users.find((u) => u.ID === userPayload.userRecord.ID);
106
106
  if (e) {
107
- md.SetRecordFavoriteStatus(params.UserID, e.Name, pk, params.IsFavorite, u);
107
+ await p.SetRecordFavoriteStatus(params.UserID, e.Name, pk, params.IsFavorite, u);
108
108
  return {
109
109
  Success: true,
110
110
  EntityID: params.EntityID,
@@ -114,65 +114,6 @@ export class UserFavoriteResolver extends UserFavoriteResolverBase {
114
114
  };
115
115
  } else throw new Error(`Entity ID:${params.EntityID} not found`);
116
116
  }
117
-
118
- private GetTestData() {
119
- return [
120
- {
121
- firstName: 'John',
122
- lastName: 'Doe',
123
- title: 'Software Engineer II',
124
- email: 'amith+john.doe@nagarajan.org',
125
- age: 25,
126
- address: {
127
- street: '123 Main St',
128
- city: 'Springfield',
129
- state: 'IL',
130
- zip: '62701',
131
- },
132
- recommendedArticles: [
133
- {
134
- title: 'How to Write Better Code',
135
- url: 'https://example.com/article1',
136
- },
137
- {
138
- title: 'The Art of Debugging',
139
- url: 'https://example.com/article2',
140
- },
141
- {
142
- title: 'Using Templates Effectively',
143
- url: 'https://example.com/article3',
144
- },
145
- ],
146
- },
147
- {
148
- firstName: 'Jane',
149
- lastName: 'Smith',
150
- title: 'Executive Vice President of Software Development',
151
- email: 'amith+jane.smith@nagarajan.org',
152
- age: 30,
153
- address: {
154
- street: '456 Elm St',
155
- city: 'Chicago',
156
- state: 'IL',
157
- zip: '62702',
158
- },
159
- recommendedArticles: [
160
- {
161
- title: 'Exemplifying the Importance of Code Reviews',
162
- url: 'https://example.com/article1',
163
- },
164
- {
165
- title: 'AI and Software Development: A New Frontier',
166
- url: 'https://example.com/article2',
167
- },
168
- {
169
- title: 'Gardening Tips for Fun Loving Software Developers',
170
- url: 'https://example.com/article3',
171
- },
172
- ],
173
- },
174
- ];
175
- }
176
117
  }
177
118
 
178
119
  export default UserFavoriteResolver;
@@ -47,14 +47,14 @@ export class UserViewResolver extends UserViewResolverBase {
47
47
  }
48
48
 
49
49
  @Query(() => [UserView_])
50
- async UpdateWhereClause(@Arg('ID', () => String) ID: string, @Ctx() { userPayload }: AppContext) {
50
+ async UpdateWhereClause(@Arg('ID', () => String) ID: string, @Ctx() { userPayload, providers }: AppContext) {
51
51
  // in this query we want to update the uesrView record in the DB with a new where clause
52
52
  // this should normally not be a factor but we have this exposed in the GraphQL API so that
53
53
  // a dev can force the update if desired from the client. The normal path is just to update
54
54
  // filter state which in turn will be used to update the where clause in the entity sub-class.
55
- const md = new Metadata();
55
+ const p = GetReadOnlyProvider(providers, {allowFallbackToReadWrite: true});
56
56
  const u = this.GetUserFromPayload(userPayload);
57
- const viewEntity = <UserViewEntityExtended>await md.GetEntityObject('User Views', u);
57
+ const viewEntity = <UserViewEntityExtended>await p.GetEntityObject('User Views', u);
58
58
  await viewEntity.Load(ID);
59
59
  viewEntity.UpdateWhereClause();
60
60