@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.
- package/CHANGELOG.json +225 -1
- package/CHANGELOG.md +53 -2
- package/dist/entitySubclasses/DuplicateRunEntity.server.d.ts +6 -0
- package/dist/entitySubclasses/DuplicateRunEntity.server.d.ts.map +1 -0
- package/dist/entitySubclasses/DuplicateRunEntity.server.js +37 -0
- package/dist/entitySubclasses/DuplicateRunEntity.server.js.map +1 -0
- package/dist/generated/generated.d.ts +257 -245
- package/dist/generated/generated.d.ts.map +1 -1
- package/dist/generated/generated.js +464 -389
- package/dist/generated/generated.js.map +1 -1
- package/dist/generic/ResolverBase.d.ts +1 -1
- package/dist/generic/ResolverBase.d.ts.map +1 -1
- package/dist/generic/ResolverBase.js +17 -4
- package/dist/generic/ResolverBase.js.map +1 -1
- package/dist/generic/RunViewResolver.d.ts +3 -0
- package/dist/generic/RunViewResolver.d.ts.map +1 -1
- package/dist/generic/RunViewResolver.js +21 -0
- package/dist/generic/RunViewResolver.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/resolvers/AskSkipResolver.d.ts +2 -2
- package/dist/resolvers/AskSkipResolver.d.ts.map +1 -1
- package/dist/resolvers/AskSkipResolver.js +6 -6
- package/dist/resolvers/AskSkipResolver.js.map +1 -1
- package/dist/resolvers/EntityRecordNameResolver.d.ts +5 -5
- package/dist/resolvers/EntityRecordNameResolver.d.ts.map +1 -1
- package/dist/resolvers/EntityRecordNameResolver.js +19 -19
- package/dist/resolvers/EntityRecordNameResolver.js.map +1 -1
- package/dist/resolvers/FileResolver.d.ts +4 -1
- package/dist/resolvers/FileResolver.d.ts.map +1 -1
- package/dist/resolvers/FileResolver.js +35 -3
- package/dist/resolvers/FileResolver.js.map +1 -1
- package/dist/resolvers/MergeRecordsResolver.d.ts +9 -8
- package/dist/resolvers/MergeRecordsResolver.d.ts.map +1 -1
- package/dist/resolvers/MergeRecordsResolver.js +28 -27
- package/dist/resolvers/MergeRecordsResolver.js.map +1 -1
- package/dist/resolvers/PotentialDuplicateRecordResolver.d.ts +20 -7
- package/dist/resolvers/PotentialDuplicateRecordResolver.d.ts.map +1 -1
- package/dist/resolvers/PotentialDuplicateRecordResolver.js +66 -16
- package/dist/resolvers/PotentialDuplicateRecordResolver.js.map +1 -1
- package/dist/resolvers/UserFavoriteResolver.d.ts +6 -6
- package/dist/resolvers/UserFavoriteResolver.d.ts.map +1 -1
- package/dist/resolvers/UserFavoriteResolver.js +14 -13
- package/dist/resolvers/UserFavoriteResolver.js.map +1 -1
- package/package.json +16 -14
- package/src/entitySubclasses/DuplicateRunEntity.server.ts +29 -0
- package/src/generated/generated.ts +319 -260
- package/src/generic/ResolverBase.ts +20 -0
- package/src/generic/RunViewResolver.ts +21 -0
- package/src/index.ts +1 -0
- package/src/resolvers/AskSkipResolver.ts +6 -5
- package/src/resolvers/EntityRecordNameResolver.ts +16 -16
- package/src/resolvers/FileResolver.ts +39 -5
- package/src/resolvers/MergeRecordsResolver.ts +14 -13
- package/src/resolvers/PotentialDuplicateRecordResolver.ts +49 -14
- 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,
|
|
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 {
|
|
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('
|
|
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 =
|
|
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 =
|
|
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,
|
|
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 {
|
|
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(() =>
|
|
12
|
-
|
|
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(() =>
|
|
24
|
-
|
|
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('
|
|
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,
|
|
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.
|
|
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,
|
|
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,
|
|
61
|
+
const recordName = await md.GetEntityRecordName(e.Name, CompositeKey);
|
|
62
62
|
if (recordName)
|
|
63
|
-
return { Success: true, Status: 'OK',
|
|
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 ${
|
|
68
|
-
|
|
69
|
-
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`,
|
|
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.
|
|
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.
|
|
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,
|
|
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
|
|
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
|
|
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(() =>
|
|
69
|
-
|
|
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('
|
|
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,
|
|
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(() =>
|
|
120
|
-
|
|
120
|
+
@Field(() => CompositeKeyInputType)
|
|
121
|
+
SurvivingRecordCompositeKey: CompositeKey;
|
|
121
122
|
|
|
122
|
-
@Field(() => [
|
|
123
|
-
RecordsToMerge:
|
|
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(() =>
|
|
148
|
-
|
|
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,
|
|
3
|
-
import {
|
|
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
|
-
|
|
16
|
+
EntityID: number;
|
|
11
17
|
|
|
12
|
-
@Field(() => [
|
|
13
|
-
|
|
18
|
+
@Field(() => [CompositeKeyInputType])
|
|
19
|
+
RecordIDs: CompositeKey[];
|
|
14
20
|
|
|
15
21
|
@Field(() => Int, { nullable: true })
|
|
16
|
-
|
|
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(() => [
|
|
32
|
-
|
|
48
|
+
@Field(() => [KeyValuePairOutputType])
|
|
49
|
+
KeyValuePairs: KeyValuePairOutputType[];
|
|
33
50
|
}
|
|
34
51
|
|
|
35
52
|
@ObjectType()
|
|
36
|
-
export class
|
|
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,
|
|
2
|
-
import { AppContext, Arg, Ctx, Field, InputType, Int, Mutation, ObjectType,
|
|
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(() =>
|
|
17
|
-
|
|
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(() =>
|
|
29
|
-
|
|
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(() =>
|
|
44
|
-
|
|
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
|
-
|
|
77
|
-
IsFavorite: await md.GetRecordFavoriteStatus(params.UserID, e.Name, params.
|
|
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.
|
|
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
|
-
|
|
95
|
+
CompositeKey: params.CompositeKey,
|
|
95
96
|
IsFavorite: params.IsFavorite,
|
|
96
97
|
};
|
|
97
98
|
} else throw new Error(`Entity ID:${params.EntityID} not found`);
|