@memberjunction/server 0.9.165 → 0.9.166

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.
@@ -10,7 +10,7 @@ import { promisify } from 'util';
10
10
  const gzip = promisify(zlib.gzip);
11
11
 
12
12
  import { PUSH_STATUS_UPDATES_TOPIC } from '../generic/PushStatusResolver';
13
- import { ConversationDetailEntity, ConversationEntity, DataContextEntity, DataContextItemEntity, UserNotificationEntity, UserViewEntityExtended } from '@memberjunction/core-entities';
13
+ import { ConversationDetailEntity, ConversationEntity, DataContextEntity, DataContextItemEntity, UserNotificationEntity, UserViewEntity, UserViewEntityExtended } from '@memberjunction/core-entities';
14
14
  import { DataSource } from 'typeorm';
15
15
  import { ___skipAPIOrgId, ___skipAPIurl } from '../config';
16
16
 
@@ -64,16 +64,16 @@ export class AskSkipResolver {
64
64
  @Query(() => AskSkipResultType)
65
65
  async ExecuteAskSkipAnalysisQuery(
66
66
  @Arg('UserQuestion', () => String) UserQuestion: string,
67
- @Arg('ViewId', () => Int) ViewId: number,
68
67
  @Arg('ConversationId', () => Int) ConversationId: number,
69
68
  @Ctx() { dataSource, userPayload }: AppContext,
70
- @PubSub() pubSub: PubSubEngine
69
+ @PubSub() pubSub: PubSubEngine,
70
+ @Arg('DataContextId', () => Int, { nullable: true }) DataContextId?: number
71
71
  ) {
72
72
  const md = new Metadata();
73
73
  const user = UserCache.Instance.Users.find((u) => u.Email === userPayload.email);
74
74
  if (!user) throw new Error(`User ${userPayload.email} not found in UserCache`);
75
75
 
76
- const {convoEntity, dataContextEntity, convoDetailEntity, dataContext} = await this.HandleCreationOfEntityObjects(dataSource, ConversationId, UserQuestion, user, userPayload, md, ViewId);
76
+ const {convoEntity, dataContextEntity, convoDetailEntity, dataContext} = await this.HandleSkipInitialObjectLoading(dataSource, ConversationId, UserQuestion, user, userPayload, md, DataContextId);
77
77
 
78
78
  const OrganizationId = ___skipAPIOrgId;
79
79
 
@@ -100,16 +100,17 @@ export class AskSkipResolver {
100
100
  return this.HandleSkipRequest(input, UserQuestion, user, dataSource, ConversationId, userPayload, pubSub, md, convoEntity, convoDetailEntity, dataContext, dataContextEntity);
101
101
  }
102
102
 
103
- protected async HandleCreationOfEntityObjects(dataSource: DataSource,
104
- ConversationId: number,
105
- UserQuestion: string,
106
- user: UserInfo,
107
- userPayload: UserPayload,
108
- md: Metadata,
109
- ViewId: number): Promise<{convoEntity: ConversationEntity,
110
- dataContextEntity: DataContextEntity,
111
- convoDetailEntity: ConversationDetailEntity,
112
- dataContext: SkipDataContext}> {
103
+
104
+ protected async HandleSkipInitialObjectLoading(dataSource: DataSource,
105
+ ConversationId: number,
106
+ UserQuestion: string,
107
+ user: UserInfo,
108
+ userPayload: UserPayload,
109
+ md: Metadata,
110
+ DataContextId: number): Promise<{convoEntity: ConversationEntity,
111
+ dataContextEntity: DataContextEntity,
112
+ convoDetailEntity: ConversationDetailEntity,
113
+ dataContext: SkipDataContext}> {
113
114
  const convoEntity = <ConversationEntity>await md.GetEntityObject('Conversations', user);
114
115
  let dataContextEntity: DataContextEntity;
115
116
 
@@ -121,21 +122,27 @@ export class AskSkipResolver {
121
122
  convoEntity.Name = AskSkipResolver._defaultNewChatName;
122
123
 
123
124
  dataContextEntity = await md.GetEntityObject<DataContextEntity>('Data Contexts', user);
124
- dataContextEntity.NewRecord();
125
- dataContextEntity.UserID = user.ID;
126
- dataContextEntity.Name = 'Data Context for Skip Conversation';
127
- if (await dataContextEntity.Save()) {
128
- convoEntity.DataContextID = dataContextEntity.ID;
129
- if (await convoEntity.Save()) {
130
- ConversationId = convoEntity.ID;
125
+ if (!DataContextId || DataContextId <= 0) {
126
+ dataContextEntity.NewRecord();
127
+ dataContextEntity.UserID = user.ID;
128
+ dataContextEntity.Name = 'Data Context for Skip Conversation';
129
+ if (!await dataContextEntity.Save())
130
+ throw new Error(`Creating a new data context failed`);
131
+ }
132
+ else {
133
+ await dataContextEntity.Load(DataContextId);
134
+ }
135
+ convoEntity.DataContextID = dataContextEntity.ID;
136
+ if (await convoEntity.Save()) {
137
+ ConversationId = convoEntity.ID;
138
+ if (!DataContextId || dataContextEntity.ID <= 0) {
139
+ // only do this if we created a new data context for this conversation
131
140
  dataContextEntity.Name += ` ${ConversationId}`;
132
- await dataContextEntity.Save();
141
+ await dataContextEntity.Save();
133
142
  }
134
- else
135
- throw new Error(`Creating a new conversation failed`);
136
143
  }
137
- else
138
- throw new Error(`Creating a new data context failed`);
144
+ else
145
+ throw new Error(`Creating a new conversation failed`);
139
146
  }
140
147
  else {
141
148
  throw new Error(`User ${userPayload.email} not found in UserCache`);
@@ -143,6 +150,11 @@ export class AskSkipResolver {
143
150
  } else {
144
151
  await convoEntity.Load(ConversationId); // load the existing conversation, will need it later
145
152
  dataContextEntity = await md.GetEntityObject<DataContextEntity>('Data Contexts', user);
153
+
154
+ // note - we ignore the parameter DataContextId if it is passed in, we will use the data context from the conversation that is saved. If a user wants to change the data context for a convo, they can do that elsewhere
155
+ if (DataContextId && DataContextId > 0 && DataContextId !== convoEntity.DataContextID)
156
+ console.log(`AskSkipResolver: DataContextId ${DataContextId} was passed in but it was ignored because it was different than the DataContextID in the conversation ${convoEntity.DataContextID}`);
157
+
146
158
  await dataContextEntity.Load(convoEntity.DataContextID);
147
159
  }
148
160
 
@@ -169,23 +181,50 @@ export class AskSkipResolver {
169
181
  for (const r of result) {
170
182
  const item = new SkipDataContextItem();
171
183
  item.Type = r.Type;
172
- item.RecordID = r.RecordID;
173
- item.RecordName = r.RecordName;
184
+ switch (item.Type) {
185
+ case 'full_entity':
186
+ item.EntityID = r.EntityID;
187
+ break;
188
+ case 'single_record':
189
+ item.RecordID = r.RecordID;
190
+ item.EntityID = r.EntityID;
191
+ break;
192
+ case 'query':
193
+ item.QueryID = r.QueryID; // map the QueryID in our database to the RecordID field in the object model for runtime use
194
+ break;
195
+ case 'sql':
196
+ item.SQL = r.SQL;
197
+ break;
198
+ case 'view':
199
+ item.ViewID = r.ViewID;
200
+ item.EntityID = r.EntityID;
201
+ break;
202
+ }
203
+ if (item.EntityID) {
204
+ item.Entity = md.Entities.find((e) => e.ID === item.EntityID);
205
+ item.EntityName = item.Entity.Name;
206
+ if (item.Type === 'full_entity')
207
+ item.RecordName = item.EntityName;
208
+ }
209
+ if (item.Type === 'query' && item.QueryID) {
210
+ const q = md.Queries.find((q) => q.ID === item.QueryID);
211
+ item.RecordName = q?.Name;
212
+ }
213
+ if (item.Type === 'view' && item.ViewID) {
214
+ const v = await md.GetEntityObject<UserViewEntityExtended>('User Views', user);
215
+ await v.Load(item.ViewID);
216
+ item.RecordName = v.Name;
217
+ item.ViewEntity = v;
218
+ }
174
219
  item.Data = r.Data && r.Data.length > 0 ? JSON.parse(r.Data) : item.Data; // parse the stored data if it was saved, otherwise leave it to whatever the object's default is
175
220
  item.AdditionalDescription = r.AdditionalDescription;
221
+ item.DataContextItemID = r.ID;
176
222
  dataContext.Items.push(item);
177
223
  }
178
224
  }
179
225
 
180
- // now if we don't already have this view in our data context, we will add it
181
- if (ViewId && !dataContext.Items.find(i => i.Type === 'view' && i.RecordID === ViewId))
182
- dataContext.Items.push(
183
- {
184
- Type: 'view',
185
- RecordID: ViewId,
186
- Data: await this.getViewData(ViewId, user),
187
- } as SkipDataContextItem
188
- );
226
+
227
+ /// TODO next up we need to modify MJExplorer to handle the data context stuff and then we can finish this method
189
228
 
190
229
  return {dataContext, convoEntity, dataContextEntity, convoDetailEntity};
191
230
  }
@@ -410,7 +449,7 @@ export class AskSkipResolver {
410
449
  const item = new SkipDataContextItem();
411
450
  item.Type = 'sql';
412
451
  item.Data = result;
413
- item.RecordName = dr.text;
452
+ item.SQL = dr.text;
414
453
  item.AdditionalDescription = dr.description;
415
454
  dataContext.Items.push(item);
416
455
  break;
@@ -424,7 +463,7 @@ export class AskSkipResolver {
424
463
  const item = new SkipDataContextItem();
425
464
  item.Type = 'query';
426
465
  item.Data = result.Results;
427
- item.RecordID = query.ID;
466
+ item.QueryID = query.ID;
428
467
  item.RecordName = query.Name;
429
468
  item.AdditionalDescription = dr.description;
430
469
  dataContext.Items.push(item);
@@ -532,9 +571,24 @@ export class AskSkipResolver {
532
571
  dciEntity.NewRecord();
533
572
  dciEntity.DataContextID = dataContextEntity.ID;
534
573
  dciEntity.Type = item.Type;
535
- dciEntity.RecordID = item.RecordID;
536
- if (item.Type === 'sql')
537
- dciEntity.SQL = item.RecordName; // the SQL field in the database is where we store the SQL, in the object model it ends up in the RecordName property, mapping it here
574
+ switch (item.Type) {
575
+ case 'full_entity':
576
+ case 'single_record':
577
+ const e = item.Entity || md.Entities.find((e) => e.Name === item.EntityName);
578
+ dciEntity.EntityID = e.ID;
579
+ if (item.Type === 'single_record')
580
+ dciEntity.RecordID = item.RecordID;
581
+ break;
582
+ case 'view':
583
+ dciEntity.ViewID = item.ViewID;
584
+ break;
585
+ case 'query':
586
+ dciEntity.QueryID = item.QueryID;
587
+ break;
588
+ case 'sql':
589
+ dciEntity.SQL = item.SQL;
590
+ break;
591
+ }
538
592
  dciEntity.DataJSON = JSON.stringify(item.Data);
539
593
  await dciEntity.Save();
540
594
  }