@memberjunction/server 2.75.0 → 2.76.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.
- package/dist/generated/generated.d.ts +159 -0
- package/dist/generated/generated.d.ts.map +1 -1
- package/dist/generated/generated.js +978 -0
- package/dist/generated/generated.js.map +1 -1
- package/dist/resolvers/CreateQueryResolver.d.ts +12 -3
- package/dist/resolvers/CreateQueryResolver.d.ts.map +1 -1
- package/dist/resolvers/CreateQueryResolver.js +114 -64
- package/dist/resolvers/CreateQueryResolver.js.map +1 -1
- package/dist/resolvers/GetDataResolver.d.ts.map +1 -1
- package/dist/resolvers/GetDataResolver.js +3 -0
- package/dist/resolvers/GetDataResolver.js.map +1 -1
- package/dist/resolvers/QueryResolver.d.ts +4 -4
- package/dist/resolvers/QueryResolver.js +18 -18
- package/package.json +34 -34
- package/src/generated/generated.ts +613 -1
- package/src/resolvers/CreateQueryResolver.ts +94 -60
- package/src/resolvers/GetDataResolver.ts +3 -0
- package/src/resolvers/QueryResolver.ts +14 -14
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import { Arg, Ctx, Field, InputType, Mutation, ObjectType, registerEnumType } from 'type-graphql';
|
|
1
|
+
import { Arg, Ctx, Field, InputType, Mutation, ObjectType, registerEnumType, Resolver, PubSub, PubSubEngine } from 'type-graphql';
|
|
2
2
|
import { AppContext } from '../types.js';
|
|
3
|
-
import { LogError, Metadata, RunView, UserInfo } from '@memberjunction/core';
|
|
3
|
+
import { LogError, Metadata, RunView, UserInfo, CompositeKey } from '@memberjunction/core';
|
|
4
4
|
import { RequireSystemUser } from '../directives/RequireSystemUser.js';
|
|
5
|
-
import {
|
|
5
|
+
import { QueryCategoryEntity } from '@memberjunction/core-entities';
|
|
6
|
+
import { QueryResolver } from '../generated/generated.js';
|
|
7
|
+
import { GetReadWriteDataSource } from '../util.js';
|
|
8
|
+
import { DeleteOptionsInput } from '../generic/DeleteOptionsInput.js';
|
|
6
9
|
|
|
7
10
|
/**
|
|
8
11
|
* Query status enumeration for GraphQL
|
|
@@ -20,7 +23,7 @@ registerEnumType(QueryStatus, {
|
|
|
20
23
|
});
|
|
21
24
|
|
|
22
25
|
@InputType()
|
|
23
|
-
export class
|
|
26
|
+
export class CreateQuerySystemUserInput {
|
|
24
27
|
@Field(() => String)
|
|
25
28
|
Name!: string;
|
|
26
29
|
|
|
@@ -73,88 +76,119 @@ export class CreateQueryResultType {
|
|
|
73
76
|
QueryData?: string;
|
|
74
77
|
}
|
|
75
78
|
|
|
76
|
-
|
|
79
|
+
@ObjectType()
|
|
80
|
+
export class DeleteQueryResultType {
|
|
81
|
+
@Field(() => Boolean)
|
|
82
|
+
Success!: boolean;
|
|
83
|
+
|
|
84
|
+
@Field(() => String, { nullable: true })
|
|
85
|
+
ErrorMessage?: string;
|
|
86
|
+
|
|
87
|
+
@Field(() => String, { nullable: true })
|
|
88
|
+
QueryData?: string;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
@Resolver()
|
|
92
|
+
export class QueryResolverExtended extends QueryResolver {
|
|
77
93
|
/**
|
|
78
94
|
* Creates a new query with the provided attributes. This mutation is restricted to system users only.
|
|
79
|
-
* @param input -
|
|
95
|
+
* @param input - CreateQuerySystemUserInput containing all the query attributes
|
|
80
96
|
* @param context - Application context containing user information
|
|
81
97
|
* @returns CreateQueryResultType with success status and query data
|
|
82
98
|
*/
|
|
83
99
|
@RequireSystemUser()
|
|
84
100
|
@Mutation(() => CreateQueryResultType)
|
|
85
|
-
async
|
|
86
|
-
@Arg('input', () =>
|
|
87
|
-
@Ctx() context: AppContext
|
|
101
|
+
async CreateQuerySystemUser(
|
|
102
|
+
@Arg('input', () => CreateQuerySystemUserInput) input: CreateQuerySystemUserInput,
|
|
103
|
+
@Ctx() context: AppContext,
|
|
104
|
+
@PubSub() pubSub: PubSubEngine
|
|
88
105
|
): Promise<CreateQueryResultType> {
|
|
89
106
|
try {
|
|
90
|
-
const md = new Metadata();
|
|
91
|
-
const newQuery = await md.GetEntityObject<QueryEntity>("Queries", context.userPayload.userRecord);
|
|
92
|
-
|
|
93
107
|
// Handle CategoryPath if provided
|
|
94
108
|
let finalCategoryID = input.CategoryID;
|
|
95
109
|
if (input.CategoryPath) {
|
|
110
|
+
const md = new Metadata();
|
|
96
111
|
finalCategoryID = await this.findOrCreateCategoryPath(input.CategoryPath, md, context.userPayload.userRecord);
|
|
97
112
|
}
|
|
98
113
|
|
|
99
|
-
//
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
if (input.SQL != null) {
|
|
115
|
-
newQuery.SQL = input.SQL;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
if (input.TechnicalDescription != null) {
|
|
119
|
-
newQuery.TechnicalDescription = input.TechnicalDescription;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
if (input.OriginalSQL != null) {
|
|
123
|
-
newQuery.OriginalSQL = input.OriginalSQL;
|
|
124
|
-
}
|
|
114
|
+
// Create input for the inherited CreateRecord method
|
|
115
|
+
const createInput = {
|
|
116
|
+
Name: input.Name,
|
|
117
|
+
CategoryID: finalCategoryID,
|
|
118
|
+
UserQuestion: input.UserQuestion,
|
|
119
|
+
Description: input.Description,
|
|
120
|
+
SQL: input.SQL,
|
|
121
|
+
TechnicalDescription: input.TechnicalDescription,
|
|
122
|
+
OriginalSQL: input.OriginalSQL,
|
|
123
|
+
Feedback: input.Feedback,
|
|
124
|
+
Status: input.Status || 'Approved',
|
|
125
|
+
QualityRank: input.QualityRank || 0,
|
|
126
|
+
ExecutionCostRank: input.ExecutionCostRank,
|
|
127
|
+
UsesTemplate: input.UsesTemplate || false
|
|
128
|
+
};
|
|
125
129
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
130
|
+
// Use inherited CreateRecord method which bypasses AI processing
|
|
131
|
+
const connPool = GetReadWriteDataSource(context.dataSources);
|
|
132
|
+
const createdQuery = await this.CreateRecord('Queries', createInput, connPool, context.userPayload, pubSub);
|
|
129
133
|
|
|
130
|
-
if (
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
134
|
+
if (createdQuery) {
|
|
135
|
+
return {
|
|
136
|
+
Success: true,
|
|
137
|
+
QueryData: JSON.stringify(createdQuery)
|
|
138
|
+
};
|
|
139
|
+
} else {
|
|
140
|
+
return {
|
|
141
|
+
Success: false,
|
|
142
|
+
ErrorMessage: 'Failed to create query using CreateRecord method'
|
|
143
|
+
};
|
|
136
144
|
}
|
|
145
|
+
|
|
146
|
+
} catch (err) {
|
|
147
|
+
LogError(err);
|
|
148
|
+
return {
|
|
149
|
+
Success: false,
|
|
150
|
+
ErrorMessage: `QueryResolverExtended::CreateQuerySystemUser --- Error creating query: ${err instanceof Error ? err.message : String(err)}`
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Deletes a query by ID. This mutation is restricted to system users only.
|
|
157
|
+
* @param ID - The ID of the query to delete
|
|
158
|
+
* @param options - Delete options controlling action execution
|
|
159
|
+
* @param context - Application context containing user information
|
|
160
|
+
* @returns DeleteQueryResultType with success status and deleted query data
|
|
161
|
+
*/
|
|
162
|
+
@RequireSystemUser()
|
|
163
|
+
@Mutation(() => DeleteQueryResultType)
|
|
164
|
+
async DeleteQuerySystemResolver(
|
|
165
|
+
@Arg('ID', () => String) queryID: string,
|
|
166
|
+
@Arg('options', () => DeleteOptionsInput, { nullable: true }) options: DeleteOptionsInput | null,
|
|
167
|
+
@Ctx() context: AppContext,
|
|
168
|
+
@PubSub() pubSub: PubSubEngine
|
|
169
|
+
): Promise<DeleteQueryResultType> {
|
|
170
|
+
try {
|
|
171
|
+
const connPool = GetReadWriteDataSource(context.dataSources);
|
|
172
|
+
const key = new CompositeKey([{FieldName: 'ID', Value: queryID}]);
|
|
137
173
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
174
|
+
// Provide default options if none provided
|
|
175
|
+
const deleteOptions = options || {
|
|
176
|
+
SkipEntityAIActions: false,
|
|
177
|
+
SkipEntityActions: false
|
|
178
|
+
};
|
|
141
179
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// Save the query
|
|
147
|
-
const saveResult = await newQuery.Save();
|
|
180
|
+
// Use inherited DeleteRecord method from ResolverBase
|
|
181
|
+
const deletedQuery = await this.DeleteRecord('Queries', key, deleteOptions, connPool, context.userPayload, pubSub);
|
|
148
182
|
|
|
149
|
-
if (
|
|
183
|
+
if (deletedQuery) {
|
|
150
184
|
return {
|
|
151
185
|
Success: true,
|
|
152
|
-
QueryData: JSON.stringify(
|
|
186
|
+
QueryData: JSON.stringify(deletedQuery)
|
|
153
187
|
};
|
|
154
188
|
} else {
|
|
155
189
|
return {
|
|
156
190
|
Success: false,
|
|
157
|
-
ErrorMessage:
|
|
191
|
+
ErrorMessage: 'Failed to delete query using DeleteRecord method'
|
|
158
192
|
};
|
|
159
193
|
}
|
|
160
194
|
|
|
@@ -162,7 +196,7 @@ export class CreateQueryResolver {
|
|
|
162
196
|
LogError(err);
|
|
163
197
|
return {
|
|
164
198
|
Success: false,
|
|
165
|
-
ErrorMessage: `
|
|
199
|
+
ErrorMessage: `QueryResolverExtended::DeleteQuerySystemResolver --- Error deleting query: ${err instanceof Error ? err.message : String(err)}`
|
|
166
200
|
};
|
|
167
201
|
}
|
|
168
202
|
}
|
|
@@ -264,6 +264,9 @@ export function isTokenValid(token: string) {
|
|
|
264
264
|
export function recordTokenUse(token: string, usePayload: any) {
|
|
265
265
|
const t = __accessTokens.find((t) => t.Token === token);
|
|
266
266
|
if (t) {
|
|
267
|
+
if (!t.TokenUses) {
|
|
268
|
+
t.TokenUses = [];
|
|
269
|
+
}
|
|
267
270
|
t.TokenUses.push({ Token: token, UsedAt: new Date(), UsePayload: usePayload });
|
|
268
271
|
}
|
|
269
272
|
else {
|
|
@@ -38,7 +38,7 @@ export class RunQueryResultType {
|
|
|
38
38
|
|
|
39
39
|
@Resolver()
|
|
40
40
|
export class RunQueryResolver {
|
|
41
|
-
private async findQuery(QueryID: string, QueryName?: string, CategoryID?: string,
|
|
41
|
+
private async findQuery(QueryID: string, QueryName?: string, CategoryID?: string, CategoryPath?: string, refreshMetadataIfNotFound: boolean = false): Promise<QueryInfo | null> {
|
|
42
42
|
const md = new Metadata();
|
|
43
43
|
|
|
44
44
|
// Filter queries based on provided criteria
|
|
@@ -50,8 +50,8 @@ export class RunQueryResolver {
|
|
|
50
50
|
if (CategoryID) {
|
|
51
51
|
matches = matches && q.CategoryID?.trim().toLowerCase() === CategoryID.trim().toLowerCase();
|
|
52
52
|
}
|
|
53
|
-
if (
|
|
54
|
-
matches = matches && q.Category?.trim().toLowerCase() ===
|
|
53
|
+
if (CategoryPath) {
|
|
54
|
+
matches = matches && q.Category?.trim().toLowerCase() === CategoryPath.trim().toLowerCase();
|
|
55
55
|
}
|
|
56
56
|
return matches;
|
|
57
57
|
}
|
|
@@ -62,7 +62,7 @@ export class RunQueryResolver {
|
|
|
62
62
|
if (refreshMetadataIfNotFound) {
|
|
63
63
|
// If we didn't find the query, refresh metadata and try again
|
|
64
64
|
await md.Refresh();
|
|
65
|
-
return this.findQuery(QueryID, QueryName, CategoryID,
|
|
65
|
+
return this.findQuery(QueryID, QueryName, CategoryID, CategoryPath, false); // change the refresh flag to false so we don't loop infinitely
|
|
66
66
|
}
|
|
67
67
|
else {
|
|
68
68
|
return null; // No query found and not refreshing metadata
|
|
@@ -76,7 +76,7 @@ export class RunQueryResolver {
|
|
|
76
76
|
async GetQueryData(@Arg('QueryID', () => String) QueryID: string,
|
|
77
77
|
@Ctx() context: AppContext,
|
|
78
78
|
@Arg('CategoryID', () => String, {nullable: true}) CategoryID?: string,
|
|
79
|
-
@Arg('
|
|
79
|
+
@Arg('CategoryPath', () => String, {nullable: true}) CategoryPath?: string,
|
|
80
80
|
@Arg('Parameters', () => GraphQLJSONObject, {nullable: true}) Parameters?: Record<string, any>,
|
|
81
81
|
@Arg('MaxRows', () => Int, {nullable: true}) MaxRows?: number,
|
|
82
82
|
@Arg('StartRow', () => Int, {nullable: true}) StartRow?: number): Promise<RunQueryResultType> {
|
|
@@ -86,7 +86,7 @@ export class RunQueryResolver {
|
|
|
86
86
|
{
|
|
87
87
|
QueryID: QueryID,
|
|
88
88
|
CategoryID: CategoryID,
|
|
89
|
-
|
|
89
|
+
CategoryPath: CategoryPath,
|
|
90
90
|
Parameters: Parameters,
|
|
91
91
|
MaxRows: MaxRows,
|
|
92
92
|
StartRow: StartRow
|
|
@@ -102,7 +102,7 @@ export class RunQueryResolver {
|
|
|
102
102
|
let queryName = result.QueryName;
|
|
103
103
|
if (!queryName) {
|
|
104
104
|
try {
|
|
105
|
-
const queryInfo = await this.findQuery(QueryID, undefined, CategoryID,
|
|
105
|
+
const queryInfo = await this.findQuery(QueryID, undefined, CategoryID, CategoryPath, true);
|
|
106
106
|
if (queryInfo) {
|
|
107
107
|
queryName = queryInfo.Name;
|
|
108
108
|
}
|
|
@@ -128,7 +128,7 @@ export class RunQueryResolver {
|
|
|
128
128
|
async GetQueryDataByName(@Arg('QueryName', () => String) QueryName: string,
|
|
129
129
|
@Ctx() context: AppContext,
|
|
130
130
|
@Arg('CategoryID', () => String, {nullable: true}) CategoryID?: string,
|
|
131
|
-
@Arg('
|
|
131
|
+
@Arg('CategoryPath', () => String, {nullable: true}) CategoryPath?: string,
|
|
132
132
|
@Arg('Parameters', () => GraphQLJSONObject, {nullable: true}) Parameters?: Record<string, any>,
|
|
133
133
|
@Arg('MaxRows', () => Int, {nullable: true}) MaxRows?: number,
|
|
134
134
|
@Arg('StartRow', () => Int, {nullable: true}) StartRow?: number): Promise<RunQueryResultType> {
|
|
@@ -137,7 +137,7 @@ export class RunQueryResolver {
|
|
|
137
137
|
{
|
|
138
138
|
QueryName: QueryName,
|
|
139
139
|
CategoryID: CategoryID,
|
|
140
|
-
|
|
140
|
+
CategoryPath: CategoryPath,
|
|
141
141
|
Parameters: Parameters,
|
|
142
142
|
MaxRows: MaxRows,
|
|
143
143
|
StartRow: StartRow
|
|
@@ -162,7 +162,7 @@ export class RunQueryResolver {
|
|
|
162
162
|
async GetQueryDataSystemUser(@Arg('QueryID', () => String) QueryID: string,
|
|
163
163
|
@Ctx() context: AppContext,
|
|
164
164
|
@Arg('CategoryID', () => String, {nullable: true}) CategoryID?: string,
|
|
165
|
-
@Arg('
|
|
165
|
+
@Arg('CategoryPath', () => String, {nullable: true}) CategoryPath?: string,
|
|
166
166
|
@Arg('Parameters', () => GraphQLJSONObject, {nullable: true}) Parameters?: Record<string, any>,
|
|
167
167
|
@Arg('MaxRows', () => Int, {nullable: true}) MaxRows?: number,
|
|
168
168
|
@Arg('StartRow', () => Int, {nullable: true}) StartRow?: number): Promise<RunQueryResultType> {
|
|
@@ -171,7 +171,7 @@ export class RunQueryResolver {
|
|
|
171
171
|
{
|
|
172
172
|
QueryID: QueryID,
|
|
173
173
|
CategoryID: CategoryID,
|
|
174
|
-
|
|
174
|
+
CategoryPath: CategoryPath,
|
|
175
175
|
Parameters: Parameters,
|
|
176
176
|
MaxRows: MaxRows,
|
|
177
177
|
StartRow: StartRow
|
|
@@ -182,7 +182,7 @@ export class RunQueryResolver {
|
|
|
182
182
|
let queryName = result.QueryName;
|
|
183
183
|
if (!queryName) {
|
|
184
184
|
try {
|
|
185
|
-
const queryInfo = await this.findQuery(QueryID, undefined, CategoryID,
|
|
185
|
+
const queryInfo = await this.findQuery(QueryID, undefined, CategoryID, CategoryPath, true);
|
|
186
186
|
if (queryInfo) {
|
|
187
187
|
queryName = queryInfo.Name;
|
|
188
188
|
}
|
|
@@ -209,7 +209,7 @@ export class RunQueryResolver {
|
|
|
209
209
|
async GetQueryDataByNameSystemUser(@Arg('QueryName', () => String) QueryName: string,
|
|
210
210
|
@Ctx() context: AppContext,
|
|
211
211
|
@Arg('CategoryID', () => String, {nullable: true}) CategoryID?: string,
|
|
212
|
-
@Arg('
|
|
212
|
+
@Arg('CategoryPath', () => String, {nullable: true}) CategoryPath?: string,
|
|
213
213
|
@Arg('Parameters', () => GraphQLJSONObject, {nullable: true}) Parameters?: Record<string, any>,
|
|
214
214
|
@Arg('MaxRows', () => Int, {nullable: true}) MaxRows?: number,
|
|
215
215
|
@Arg('StartRow', () => Int, {nullable: true}) StartRow?: number): Promise<RunQueryResultType> {
|
|
@@ -218,7 +218,7 @@ export class RunQueryResolver {
|
|
|
218
218
|
{
|
|
219
219
|
QueryName: QueryName,
|
|
220
220
|
CategoryID: CategoryID,
|
|
221
|
-
|
|
221
|
+
CategoryPath: CategoryPath,
|
|
222
222
|
Parameters: Parameters,
|
|
223
223
|
MaxRows: MaxRows,
|
|
224
224
|
StartRow: StartRow
|