@memberjunction/server 1.2.2 → 1.3.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.
Files changed (58) hide show
  1. package/CHANGELOG.json +225 -1
  2. package/CHANGELOG.md +53 -2
  3. package/dist/entitySubclasses/DuplicateRunEntity.server.d.ts +6 -0
  4. package/dist/entitySubclasses/DuplicateRunEntity.server.d.ts.map +1 -0
  5. package/dist/entitySubclasses/DuplicateRunEntity.server.js +37 -0
  6. package/dist/entitySubclasses/DuplicateRunEntity.server.js.map +1 -0
  7. package/dist/generated/generated.d.ts +257 -245
  8. package/dist/generated/generated.d.ts.map +1 -1
  9. package/dist/generated/generated.js +464 -389
  10. package/dist/generated/generated.js.map +1 -1
  11. package/dist/generic/ResolverBase.d.ts +1 -1
  12. package/dist/generic/ResolverBase.d.ts.map +1 -1
  13. package/dist/generic/ResolverBase.js +17 -4
  14. package/dist/generic/ResolverBase.js.map +1 -1
  15. package/dist/generic/RunViewResolver.d.ts +3 -0
  16. package/dist/generic/RunViewResolver.d.ts.map +1 -1
  17. package/dist/generic/RunViewResolver.js +21 -0
  18. package/dist/generic/RunViewResolver.js.map +1 -1
  19. package/dist/index.d.ts +1 -0
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +1 -0
  22. package/dist/index.js.map +1 -1
  23. package/dist/resolvers/AskSkipResolver.d.ts +2 -2
  24. package/dist/resolvers/AskSkipResolver.d.ts.map +1 -1
  25. package/dist/resolvers/AskSkipResolver.js +6 -6
  26. package/dist/resolvers/AskSkipResolver.js.map +1 -1
  27. package/dist/resolvers/EntityRecordNameResolver.d.ts +5 -5
  28. package/dist/resolvers/EntityRecordNameResolver.d.ts.map +1 -1
  29. package/dist/resolvers/EntityRecordNameResolver.js +19 -19
  30. package/dist/resolvers/EntityRecordNameResolver.js.map +1 -1
  31. package/dist/resolvers/FileResolver.d.ts +4 -1
  32. package/dist/resolvers/FileResolver.d.ts.map +1 -1
  33. package/dist/resolvers/FileResolver.js +35 -3
  34. package/dist/resolvers/FileResolver.js.map +1 -1
  35. package/dist/resolvers/MergeRecordsResolver.d.ts +9 -8
  36. package/dist/resolvers/MergeRecordsResolver.d.ts.map +1 -1
  37. package/dist/resolvers/MergeRecordsResolver.js +28 -27
  38. package/dist/resolvers/MergeRecordsResolver.js.map +1 -1
  39. package/dist/resolvers/PotentialDuplicateRecordResolver.d.ts +20 -7
  40. package/dist/resolvers/PotentialDuplicateRecordResolver.d.ts.map +1 -1
  41. package/dist/resolvers/PotentialDuplicateRecordResolver.js +66 -16
  42. package/dist/resolvers/PotentialDuplicateRecordResolver.js.map +1 -1
  43. package/dist/resolvers/UserFavoriteResolver.d.ts +6 -6
  44. package/dist/resolvers/UserFavoriteResolver.d.ts.map +1 -1
  45. package/dist/resolvers/UserFavoriteResolver.js +14 -13
  46. package/dist/resolvers/UserFavoriteResolver.js.map +1 -1
  47. package/package.json +16 -14
  48. package/src/entitySubclasses/DuplicateRunEntity.server.ts +29 -0
  49. package/src/generated/generated.ts +319 -260
  50. package/src/generic/ResolverBase.ts +20 -0
  51. package/src/generic/RunViewResolver.ts +21 -0
  52. package/src/index.ts +1 -0
  53. package/src/resolvers/AskSkipResolver.ts +6 -5
  54. package/src/resolvers/EntityRecordNameResolver.ts +16 -16
  55. package/src/resolvers/FileResolver.ts +39 -5
  56. package/src/resolvers/MergeRecordsResolver.ts +14 -13
  57. package/src/resolvers/PotentialDuplicateRecordResolver.ts +49 -14
  58. package/src/resolvers/UserFavoriteResolver.ts +13 -12
@@ -80,6 +80,7 @@ export class ResolverBase {
80
80
  viewInput.ExcludeDataFromAllPriorViewRuns,
81
81
  viewInput.ForceAuditLog,
82
82
  viewInput.AuditLogDescription,
83
+ viewInput.ResultType,
83
84
  userPayload,
84
85
  pubSub
85
86
  );
@@ -106,6 +107,7 @@ export class ResolverBase {
106
107
  viewInput.ExcludeDataFromAllPriorViewRuns,
107
108
  viewInput.ForceAuditLog,
108
109
  viewInput.AuditLogDescription,
110
+ viewInput.ResultType,
109
111
  userPayload,
110
112
  pubSub
111
113
  );
@@ -142,6 +144,7 @@ export class ResolverBase {
142
144
  false,
143
145
  viewInput.ForceAuditLog,
144
146
  viewInput.AuditLogDescription,
147
+ viewInput.ResultType,
145
148
  userPayload,
146
149
  pubSub
147
150
  );
@@ -180,6 +183,7 @@ export class ResolverBase {
180
183
  excludeDataFromAllPriorViewRuns: boolean | undefined,
181
184
  forceAuditLog: boolean | undefined,
182
185
  auditLogDescription: string | undefined,
186
+ resultType: string | undefined,
183
187
  userPayload: UserPayload | null,
184
188
  pubSub: PubSubEngine
185
189
  ) {
@@ -193,6 +197,21 @@ export class ResolverBase {
193
197
  if (!entityInfo) throw new Error(`Entity ${viewInfo.Entity} not found in metadata`);
194
198
 
195
199
  const rv = new RunView();
200
+
201
+ // figure out the result type from the input string (if provided)
202
+ let rt: 'simple' | 'entity_object' | 'count_only' = 'simple';
203
+ switch (resultType?.trim().toLowerCase()) {
204
+ case 'entity_object':
205
+ rt = 'entity_object';
206
+ break;
207
+ case 'count_only':
208
+ rt = 'count_only';
209
+ break;
210
+ default:
211
+ rt = 'simple';
212
+ break;
213
+ }
214
+
196
215
  const result = await rv.RunView(
197
216
  {
198
217
  ViewID: viewInfo.ID,
@@ -209,6 +228,7 @@ export class ResolverBase {
209
228
  IgnoreMaxRows: ignoreMaxRows,
210
229
  ForceAuditLog: forceAuditLog,
211
230
  AuditLogDescription: auditLogDescription,
231
+ ResultType: rt,
212
232
  },
213
233
  user
214
234
  );
@@ -92,6 +92,13 @@ export class RunViewByIDInput {
92
92
  "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.",
93
93
  })
94
94
  AuditLogDescription?: string;
95
+
96
+ @Field(() => String, {
97
+ nullable: true,
98
+ description:
99
+ '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',
100
+ })
101
+ ResultType?: string;
95
102
  }
96
103
 
97
104
  @InputType()
@@ -174,6 +181,13 @@ export class RunViewByNameInput {
174
181
  "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.",
175
182
  })
176
183
  AuditLogDescription?: string;
184
+
185
+ @Field(() => String, {
186
+ nullable: true,
187
+ description:
188
+ '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',
189
+ })
190
+ ResultType?: string;
177
191
  }
178
192
  @InputType()
179
193
  export class RunDynamicViewInput {
@@ -241,6 +255,13 @@ export class RunDynamicViewInput {
241
255
  "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.",
242
256
  })
243
257
  AuditLogDescription?: string;
258
+
259
+ @Field(() => String, {
260
+ nullable: true,
261
+ description:
262
+ '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',
263
+ })
264
+ ResultType?: string;
244
265
  }
245
266
 
246
267
  @ObjectType()
package/src/index.ts CHANGED
@@ -33,6 +33,7 @@ export { configInfo } from './config';
33
33
  export * from './directives';
34
34
  export * from './entitySubclasses/userViewEntity.server';
35
35
  export * from './entitySubclasses/entityPermissions.server';
36
+ export * from './entitySubclasses/DuplicateRunEntity.server';
36
37
  export * from './types';
37
38
  export { TokenExpiredError } from './auth';
38
39
 
@@ -1,5 +1,5 @@
1
1
  import { Arg, Ctx, Field, Int, ObjectType, PubSub, PubSubEngine, Query, Resolver } from 'type-graphql';
2
- import { LogError, LogStatus, Metadata, PrimaryKeyValue, RunView, UserInfo } from '@memberjunction/core';
2
+ import { LogError, LogStatus, Metadata, KeyValuePair, RunView, UserInfo, CompositeKey } from '@memberjunction/core';
3
3
  import { AppContext, UserPayload } from '../types';
4
4
  import { UserCache } from '@memberjunction/sqlserver-dataprovider';
5
5
  import { DataContext } from '@memberjunction/data-context'
@@ -18,7 +18,8 @@ import { registerEnumType } from "type-graphql";
18
18
  import { MJGlobal, CopyScalarsAndArrays } from '@memberjunction/global';
19
19
  import { sendPostRequest } from '../util';
20
20
  import { GetAIAPIKey } from '@memberjunction/ai';
21
- import { PrimaryKeyValueInputType } from './MergeRecordsResolver';
21
+ import { KeyValuePairInputType } from './MergeRecordsResolver';
22
+ import { CompositeKeyInputType } from './PotentialDuplicateRecordResolver';
22
23
 
23
24
 
24
25
  enum SkipResponsePhase {
@@ -73,7 +74,7 @@ export class AskSkipResolver {
73
74
  async ExecuteAskSkipRecordChat(@Arg('UserQuestion', () => String) UserQuestion: string,
74
75
  @Arg('ConversationId', () => Int) ConversationId: number,
75
76
  @Arg('EntityName', () => String) EntityName: string,
76
- @Arg('PrimaryKeys', () => [PrimaryKeyValueInputType]) PrimaryKeys: PrimaryKeyValueInputType[],
77
+ @Arg('CompositeKey', () => CompositeKeyInputType) CompositeKey: CompositeKeyInputType,
77
78
  @Ctx() { dataSource, userPayload }: AppContext,
78
79
  @PubSub() pubSub: PubSubEngine) {
79
80
  // In this function we're simply going to call the Skip API and pass along the message from the user
@@ -96,7 +97,7 @@ export class AskSkipResolver {
96
97
  dci.DataContextID = dataContext.ID;
97
98
  dci.Type = 'single_record';
98
99
  dci.EntityID = md.Entities.find((e) => e.Name === EntityName)?.ID;
99
- dci.RecordID = PrimaryKeys.map((pk) => pk.Value).join(',');
100
+ dci.RecordID = CompositeKey.Values();
100
101
  await dci.Save();
101
102
 
102
103
  await dataContext.Load(dataContext.ID, dataSource, false, true, 10, user); // load again because we added a new data context item
@@ -104,7 +105,7 @@ export class AskSkipResolver {
104
105
 
105
106
  // also, in the situation for a new convo, we need to update the Conversation ID to have a LinkedEntity and LinkedRecord
106
107
  convoEntity.LinkedEntityID = dci.EntityID;
107
- convoEntity.LinkedRecordID = PrimaryKeys.map((pk) => pk.Value).join(',');
108
+ convoEntity.LinkedRecordID = CompositeKey.Values();
108
109
  convoEntity.DataContextID = dataContext.ID;
109
110
  await convoEntity.Save();
110
111
  }
@@ -1,15 +1,15 @@
1
- import { Metadata, PrimaryKeyValue } from '@memberjunction/core';
1
+ import { Metadata, CompositeKey } from '@memberjunction/core';
2
2
  import { Arg, Ctx, Field, InputType, ObjectType, Query, Resolver } from 'type-graphql';
3
3
  import { AppContext } from '../types';
4
- import { PrimaryKeyValueInputType, PrimaryKeyValueOutputType } from './MergeRecordsResolver';
4
+ import { CompositeKeyInputType, CompositeKeyOutputType } from './PotentialDuplicateRecordResolver';
5
5
 
6
6
  @InputType()
7
7
  export class EntityRecordNameInput {
8
8
  @Field(() => String)
9
9
  EntityName: string;
10
10
 
11
- @Field(() => [PrimaryKeyValueInputType])
12
- PrimaryKeyValues: PrimaryKeyValue[];
11
+ @Field(() => CompositeKeyInputType)
12
+ CompositeKey: CompositeKey;
13
13
  }
14
14
 
15
15
  @ObjectType()
@@ -20,8 +20,8 @@ export class EntityRecordNameResult {
20
20
  @Field(() => String)
21
21
  Status: string;
22
22
 
23
- @Field(() => [PrimaryKeyValueOutputType])
24
- PrimaryKeyValues: PrimaryKeyValue[];
23
+ @Field(() => CompositeKeyOutputType)
24
+ CompositeKey: CompositeKey;
25
25
 
26
26
  @Field(() => String)
27
27
  EntityName: string;
@@ -35,11 +35,11 @@ export class EntityRecordNameResolver {
35
35
  @Query(() => EntityRecordNameResult)
36
36
  async GetEntityRecordName(
37
37
  @Arg('EntityName', () => String) EntityName: string,
38
- @Arg('PrimaryKeyValues', () => [PrimaryKeyValueInputType]) PrimaryKeyValues: PrimaryKeyValue[],
38
+ @Arg('CompositeKey', () => CompositeKeyInputType) CompositeKey: CompositeKey,
39
39
  @Ctx() {}: AppContext
40
40
  ): Promise<EntityRecordNameResult> {
41
41
  const md = new Metadata();
42
- return await this.InnerGetEntityRecordName(md, EntityName, PrimaryKeyValues);
42
+ return await this.InnerGetEntityRecordName(md, EntityName, CompositeKey);
43
43
  }
44
44
 
45
45
  @Query(() => [EntityRecordNameResult])
@@ -50,27 +50,27 @@ export class EntityRecordNameResolver {
50
50
  const result: EntityRecordNameResult[] = [];
51
51
  const md = new Metadata();
52
52
  for (const i of info) {
53
- result.push(await this.InnerGetEntityRecordName(md, i.EntityName, i.PrimaryKeyValues));
53
+ result.push(await this.InnerGetEntityRecordName(md, i.EntityName, i.CompositeKey));
54
54
  }
55
55
  return result;
56
56
  }
57
57
 
58
- async InnerGetEntityRecordName(md: Metadata, EntityName: string, primaryKeyValues: PrimaryKeyValue[]): Promise<EntityRecordNameResult> {
58
+ async InnerGetEntityRecordName(md: Metadata, EntityName: string, CompositeKey: CompositeKey): Promise<EntityRecordNameResult> {
59
59
  const e = md.Entities.find((e) => e.Name === EntityName);
60
60
  if (e) {
61
- const recordName = await md.GetEntityRecordName(e.Name, primaryKeyValues);
61
+ const recordName = await md.GetEntityRecordName(e.Name, CompositeKey);
62
62
  if (recordName)
63
- return { Success: true, Status: 'OK', PrimaryKeyValues: primaryKeyValues, RecordName: recordName, EntityName: EntityName };
63
+ return { Success: true, Status: 'OK', CompositeKey, RecordName: recordName, EntityName };
64
64
  else
65
65
  return {
66
66
  Success: false,
67
- Status: `Name for record, or record ${primaryKeyValues.map(pkv => pkv.FieldName + ':' + pkv.Value).join(',')} itself not found, could be an access issue if user doesn't have Row Level Access (RLS) if RLS is enabled for this entity`,
68
- PrimaryKeyValues: primaryKeyValues,
69
- EntityName: EntityName,
67
+ Status: `Name for record, or record ${CompositeKey.ToString()} itself not found, could be an access issue if user doesn't have Row Level Access (RLS) if RLS is enabled for this entity`,
68
+ CompositeKey,
69
+ EntityName
70
70
  };
71
71
  }
72
72
  else
73
- return { Success: false, Status: `Entity ${EntityName} not found`, PrimaryKeyValues: primaryKeyValues, EntityName: EntityName };
73
+ return { Success: false, Status: `Entity ${EntityName} not found`, CompositeKey, EntityName };
74
74
  }
75
75
  }
76
76
 
@@ -15,8 +15,8 @@ import {
15
15
  Resolver,
16
16
  Root,
17
17
  } from '@memberjunction/server';
18
- import { createDownloadUrl, createUploadUrl, deleteObject } from '@memberjunction/storage';
19
- import { CreateFileInput, FileResolver as FileResolverBase, File_ } from '../generated/generated';
18
+ import { createDownloadUrl, createUploadUrl, deleteObject, moveObject } from '@memberjunction/storage';
19
+ import { CreateFileInput, FileResolver as FileResolverBase, File_, UpdateFileInput } from '../generated/generated';
20
20
 
21
21
  @InputType()
22
22
  export class CreateUploadURLInput {
@@ -30,6 +30,8 @@ export class CreateFilePayload {
30
30
  File: File_;
31
31
  @Field(() => String)
32
32
  UploadUrl: string;
33
+ @Field(() => Boolean)
34
+ NameExists: boolean;
33
35
  }
34
36
 
35
37
  @ObjectType()
@@ -52,6 +54,10 @@ export class FileResolver extends FileResolverBase {
52
54
  const providerEntity = await md.GetEntityObject<FileStorageProviderEntity>('File Storage Providers', user);
53
55
  fileEntity.CheckPermissions(EntityPermissionType.Create, true);
54
56
 
57
+ // Check to see if there's already an object with that name
58
+ const [sameName] = await this.findBy(dataSource, 'Files', { Name: input.Name, ProviderID: input.ProviderID });
59
+ const NameExists = Boolean(sameName);
60
+
55
61
  const fileRecord = (await super.CreateFile({ ...input, Status: 'Pending' }, { dataSource, userPayload }, pubSub)) as File_;
56
62
 
57
63
  // If there's a problem creating the file record, the base resolver will return null
@@ -68,7 +74,7 @@ export class FileResolver extends FileResolverBase {
68
74
  await fileEntity.Save();
69
75
  const File = fileEntity.GetAll();
70
76
 
71
- return { File, UploadUrl };
77
+ return { File, UploadUrl, NameExists };
72
78
  }
73
79
 
74
80
  @FieldResolver(() => String)
@@ -81,11 +87,39 @@ export class FileResolver extends FileResolverBase {
81
87
  const providerEntity = await md.GetEntityObject<FileStorageProviderEntity>('File Storage Providers', user);
82
88
  await providerEntity.Load(file.ProviderID);
83
89
 
84
- const url = await createDownloadUrl(providerEntity, file.ProviderKey ?? file.ID);
90
+ const url = await createDownloadUrl(providerEntity, file.ProviderKey ?? file.Name);
85
91
 
86
92
  return url;
87
93
  }
88
94
 
95
+ @Mutation(() => File_)
96
+ async UpdateFile(
97
+ @Arg('input', () => UpdateFileInput) input: UpdateFileInput,
98
+ @Ctx() { dataSource, userPayload }: AppContext,
99
+ @PubSub() pubSub: PubSubEngine
100
+ ) {
101
+ // if the name is changing, rename the target object as well
102
+ const md = new Metadata();
103
+ const user = this.GetUserFromPayload(userPayload);
104
+ const fileEntity = await md.GetEntityObject<FileEntity>('Files', user);
105
+ fileEntity.CheckPermissions(EntityPermissionType.Update, true);
106
+
107
+ await fileEntity.Load(input.ID);
108
+
109
+ if (fileEntity.Name !== input.Name) {
110
+ const providerEntity = await md.GetEntityObject<FileStorageProviderEntity>('File Storage Providers', user);
111
+ await providerEntity.Load(fileEntity.ProviderID);
112
+
113
+ const success = await moveObject(providerEntity, fileEntity.Name, input.Name);
114
+ if (!success) {
115
+ throw new Error('Error updating object name');
116
+ }
117
+ }
118
+
119
+ const updatedFile = await super.UpdateFile(input, { dataSource, userPayload }, pubSub);
120
+ return updatedFile;
121
+ }
122
+
89
123
  @Mutation(() => File_)
90
124
  async DeleteFile(@Arg('ID', () => Int) ID: number, @Ctx() { dataSource, userPayload }: AppContext, @PubSub() pubSub: PubSubEngine) {
91
125
  const md = new Metadata();
@@ -102,7 +136,7 @@ export class FileResolver extends FileResolverBase {
102
136
  if (fileEntity.Status === 'Uploaded') {
103
137
  const providerEntity = await md.GetEntityObject<FileStorageProviderEntity>('File Storage Providers', userInfo);
104
138
  await providerEntity.Load(fileEntity.ProviderID);
105
- await deleteObject(providerEntity, fileEntity.ProviderKey ?? fileEntity.ID);
139
+ await deleteObject(providerEntity, fileEntity.ProviderKey ?? fileEntity.Name);
106
140
  }
107
141
 
108
142
  return super.DeleteFile(ID, { dataSource, userPayload }, pubSub);
@@ -1,6 +1,7 @@
1
- import { LogError, Metadata, PrimaryKeyValue } from '@memberjunction/core';
1
+ import { LogError, Metadata, CompositeKey } from '@memberjunction/core';
2
2
  import { Arg, Ctx, Field, InputType, Int, Mutation, ObjectType, PubSub, PubSubEngine, Query, Resolver } from 'type-graphql';
3
3
  import { AppContext } from '../types';
4
+ import { CompositeKeyInputType, CompositeKeyOutputType } from './PotentialDuplicateRecordResolver';
4
5
 
5
6
  @ObjectType()
6
7
  export class EntityDependencyResult {
@@ -36,7 +37,7 @@ export class EntityDependencyResolver {
36
37
 
37
38
 
38
39
  @InputType()
39
- export class PrimaryKeyValueInputType {
40
+ export class KeyValuePairInputType {
40
41
  @Field(() => String)
41
42
  FieldName: string;
42
43
 
@@ -45,7 +46,7 @@ export class PrimaryKeyValueInputType {
45
46
  }
46
47
 
47
48
  @ObjectType()
48
- export class PrimaryKeyValueOutputType {
49
+ export class KeyValuePairOutputType {
49
50
  @Field(() => String)
50
51
  FieldName: string;
51
52
 
@@ -65,8 +66,8 @@ export class RecordDependencyResult {
65
66
  @Field(() => String)
66
67
  FieldName: string; // required
67
68
 
68
- @Field(() => String)
69
- PrimaryKeyValue: string;
69
+ @Field(() => CompositeKeyOutputType)
70
+ CompositeKey: CompositeKey;
70
71
  }
71
72
 
72
73
 
@@ -77,13 +78,13 @@ export class RecordDependencyResolver {
77
78
  @Query(() => [RecordDependencyResult])
78
79
  async GetRecordDependencies(
79
80
  @Arg('entityName', () => String) entityName: string,
80
- @Arg('primaryKeyValues', () => [PrimaryKeyValueInputType]) primaryKeyValues: PrimaryKeyValue[],
81
+ @Arg('CompositeKey', () => CompositeKeyInputType) CompositeKey: CompositeKey,
81
82
  @Ctx() { dataSource, userPayload }: AppContext,
82
83
  @PubSub() pubSub: PubSubEngine
83
84
  ) {
84
85
  try {
85
86
  const md = new Metadata();
86
- const result = await md.GetRecordDependencies(entityName, primaryKeyValues)
87
+ const result = await md.GetRecordDependencies(entityName, CompositeKey);
87
88
  return result;
88
89
  }
89
90
  catch (e) {
@@ -116,11 +117,11 @@ export class RecordMergeRequest {
116
117
  @Field(() => String)
117
118
  EntityName: string;
118
119
 
119
- @Field(() => [PrimaryKeyValueInputType])
120
- SurvivingRecordPrimaryKeyValues: PrimaryKeyValue[];
120
+ @Field(() => CompositeKeyInputType)
121
+ SurvivingRecordCompositeKey: CompositeKey;
121
122
 
122
- @Field(() => [[PrimaryKeyValueInputType]])
123
- RecordsToMerge: PrimaryKeyValue[][];
123
+ @Field(() => [CompositeKeyInputType])
124
+ RecordsToMerge: CompositeKey[];
124
125
 
125
126
  @Field(() => [FieldMapping], { nullable: true })
126
127
  FieldMap?: FieldMapping[];
@@ -144,8 +145,8 @@ export class RecordMergeRequestOutput {
144
145
 
145
146
  @ObjectType()
146
147
  export class RecordMergeDetailResult {
147
- @Field(() => [PrimaryKeyValueOutputType])
148
- PrimaryKeyValues: PrimaryKeyValue[];
148
+ @Field(() => CompositeKeyOutputType)
149
+ CompositeKey: CompositeKeyOutputType;
149
150
 
150
151
  @Field(() => Boolean)
151
152
  Success: boolean;
@@ -1,26 +1,43 @@
1
1
  import { Arg, Ctx, Field, Float, InputType, Int, ObjectType, Query, Resolver } from "type-graphql";
2
- import { PotentialDuplicateRequest, PotentialDuplicateResponse, PotentialDuplicate, Metadata, PrimaryKeyValue, LogError } from '@memberjunction/core';
3
- import {PrimaryKeyValueInputType, PrimaryKeyValueOutputType} from './MergeRecordsResolver'
2
+ import { PotentialDuplicateRequest, PotentialDuplicateResponse, PotentialDuplicate, Metadata, KeyValuePair, LogError, CompositeKey, PotentialDuplicateResult } from '@memberjunction/core';
3
+ import {KeyValuePairInputType, KeyValuePairOutputType} from './MergeRecordsResolver'
4
4
  import { AppContext } from "../types";
5
5
  import { UserCache } from "@memberjunction/sqlserver-dataprovider";
6
6
 
7
+ //load the default vectorDB and embedding model
8
+ import {LoadMistralEmbedding} from '@memberjunction/ai-mistral';
9
+ import {LoadPineconeVectorDB} from '@memberjunction/ai-vectors-pinecone';
10
+ LoadMistralEmbedding();
11
+ LoadPineconeVectorDB();
12
+
7
13
  @InputType()
8
14
  export class PotentialDuplicateRequestType extends PotentialDuplicateRequest {
9
15
  @Field(() => Int)
10
- EntityDocumentID: number;
16
+ EntityID: number;
11
17
 
12
- @Field(() => [PrimaryKeyValueInputType])
13
- PrimaryKeyValues: PrimaryKeyValueInputType[];
18
+ @Field(() => [CompositeKeyInputType])
19
+ RecordIDs: CompositeKey[];
14
20
 
15
21
  @Field(() => Int, { nullable: true })
16
- EntitiyID: number;
17
-
18
- @Field(() => String, { nullable: true })
19
- EntityName: string;
22
+ EntityDocumentID: number;
20
23
 
21
24
  @Field(() => Int, { nullable: true })
22
25
  ProbabilityScore: number;
26
+
27
+ @Field(() => Int)
28
+ ListID: number;
29
+ }
30
+
31
+ @InputType()
32
+ export class CompositeKeyInputType extends CompositeKey {
33
+ @Field(() => [KeyValuePairInputType])
34
+ KeyValuePairs: KeyValuePair[];
35
+ }
23
36
 
37
+ @ObjectType()
38
+ export class CompositeKeyOutputType extends CompositeKey {
39
+ @Field(() => [KeyValuePairOutputType])
40
+ KeyValuePairs: KeyValuePair[];
24
41
  }
25
42
 
26
43
  @ObjectType()
@@ -28,18 +45,36 @@ export class PotentialDuplicateType extends PotentialDuplicate {
28
45
  @Field(() => Float)
29
46
  ProbabilityScore: number;
30
47
 
31
- @Field(() => [PrimaryKeyValueOutputType])
32
- PrimaryKeyValues: PrimaryKeyValueOutputType[];
48
+ @Field(() => [KeyValuePairOutputType])
49
+ KeyValuePairs: KeyValuePairOutputType[];
33
50
  }
34
51
 
35
52
  @ObjectType()
36
- export class PotentialDuplicateResponseType extends PotentialDuplicateResponse{
37
-
38
- @Field(() => Int)
53
+ export class PotentialDuplicateResultType extends PotentialDuplicateResult {
54
+ @Field(() => Int, { nullable: true })
39
55
  EntityID: number;
40
56
 
41
57
  @Field(() => [PotentialDuplicateType])
42
58
  Duplicates: PotentialDuplicateType[];
59
+
60
+ @Field(() => CompositeKeyOutputType)
61
+ RecordPrimaryKeys: CompositeKey;
62
+
63
+ @Field(() => [Int])
64
+ DuplicateRunDetailMatchRecordIDs: number[];
65
+ }
66
+
67
+ @ObjectType()
68
+ export class PotentialDuplicateResponseType extends PotentialDuplicateResponse{
69
+
70
+ @Field(() => String)
71
+ Status: 'Inprogress' | 'Success' | 'Error';
72
+
73
+ @Field(() => String, { nullable: true })
74
+ ErrorMessage?: string;
75
+
76
+ @Field(() => [PotentialDuplicateResultType])
77
+ PotentialDuplicateResult: PotentialDuplicateResult[]
43
78
  }
44
79
 
45
80
  @Resolver(PotentialDuplicateResponseType)
@@ -1,9 +1,10 @@
1
- import { Metadata, PrimaryKeyValue } from '@memberjunction/core';
2
- import { AppContext, Arg, Ctx, Field, InputType, Int, Mutation, ObjectType, PrimaryKeyValueInputType, PrimaryKeyValueOutputType, Query, Resolver } from '@memberjunction/server';
1
+ import { Metadata, KeyValuePair, CompositeKey } from '@memberjunction/core';
2
+ import { AppContext, Arg, Ctx, Field, InputType, Int, Mutation, ObjectType, KeyValuePairInputType, KeyValuePairOutputType, Query, Resolver } from '@memberjunction/server';
3
3
  import { UserCache } from '@memberjunction/sqlserver-dataprovider';
4
4
  import { UserFavoriteEntity } from '@memberjunction/core-entities';
5
5
 
6
6
  import { UserFavorite_, UserFavoriteResolverBase } from '../generated/generated';
7
+ import { CompositeKeyInputType, CompositeKeyOutputType } from './PotentialDuplicateRecordResolver';
7
8
 
8
9
  //****************************************************************************
9
10
  // INPUT TYPE for User Favorite Queries
@@ -13,8 +14,8 @@ export class UserFavoriteSearchParams {
13
14
  @Field(() => Int)
14
15
  EntityID: number;
15
16
 
16
- @Field(() => [PrimaryKeyValueInputType])
17
- PrimaryKeyValues: PrimaryKeyValue[];
17
+ @Field(() => CompositeKeyInputType)
18
+ CompositeKey: CompositeKey;
18
19
 
19
20
  @Field(() => Int)
20
21
  UserID: number;
@@ -25,8 +26,8 @@ export class UserFavoriteSetParams {
25
26
  @Field(() => Int)
26
27
  EntityID: number;
27
28
 
28
- @Field(() => [PrimaryKeyValueInputType])
29
- PrimaryKeyValues: PrimaryKeyValue[];
29
+ @Field(() => CompositeKeyInputType)
30
+ CompositeKey: CompositeKey;
30
31
 
31
32
  @Field(() => Int)
32
33
  UserID: number;
@@ -40,8 +41,8 @@ export class UserFavoriteResult {
40
41
  @Field(() => Int)
41
42
  EntityID: number;
42
43
 
43
- @Field(() => [PrimaryKeyValueOutputType])
44
- PrimaryKeyValues: PrimaryKeyValue[];
44
+ @Field(() => CompositeKeyOutputType)
45
+ CompositeKey: CompositeKey;
45
46
 
46
47
  @Field(() => Int)
47
48
  UserID: number;
@@ -73,8 +74,8 @@ export class UserFavoriteResolver extends UserFavoriteResolverBase {
73
74
  return {
74
75
  EntityID: params.EntityID,
75
76
  UserID: params.UserID,
76
- PrimaryKeyValues: params.PrimaryKeyValues,
77
- IsFavorite: await md.GetRecordFavoriteStatus(params.UserID, e.Name, params.PrimaryKeyValues),
77
+ CompositeKey: params.CompositeKey,
78
+ IsFavorite: await md.GetRecordFavoriteStatus(params.UserID, e.Name, params.CompositeKey),
78
79
  Success: true,
79
80
  };
80
81
  else throw new Error(`Entity ID:${params.EntityID} not found`);
@@ -86,12 +87,12 @@ export class UserFavoriteResolver extends UserFavoriteResolverBase {
86
87
  const e = md.Entities.find((e) => e.ID === params.EntityID);
87
88
  const u = UserCache.Users.find((u) => u.ID === userPayload.userRecord.ID);
88
89
  if (e) {
89
- md.SetRecordFavoriteStatus(params.UserID, e.Name, params.PrimaryKeyValues, params.IsFavorite, u);
90
+ md.SetRecordFavoriteStatus(params.UserID, e.Name, params.CompositeKey, params.IsFavorite, u);
90
91
  return {
91
92
  Success: true,
92
93
  EntityID: params.EntityID,
93
94
  UserID: params.UserID,
94
- PrimaryKeyValues: params.PrimaryKeyValues,
95
+ CompositeKey: params.CompositeKey,
95
96
  IsFavorite: params.IsFavorite,
96
97
  };
97
98
  } else throw new Error(`Entity ID:${params.EntityID} not found`);