@axinom/mosaic-graphql-common 0.22.0-rc.6 → 0.22.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/plugins/bulk-edit/bulk-edit-async-plugin-factory.d.ts +13 -0
- package/dist/plugins/bulk-edit/bulk-edit-async-plugin-factory.d.ts.map +1 -0
- package/dist/plugins/bulk-edit/bulk-edit-async-plugin-factory.js +278 -0
- package/dist/plugins/bulk-edit/bulk-edit-async-plugin-factory.js.map +1 -0
- package/dist/plugins/index.d.ts +1 -0
- package/dist/plugins/index.d.ts.map +1 -1
- package/dist/plugins/index.js +1 -0
- package/dist/plugins/index.js.map +1 -1
- package/package.json +9 -3
- package/src/plugins/bulk-edit/bulk-edit-async-plugin-factory.ts +624 -0
- package/src/plugins/index.ts +1 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { MultiTenantMessagingSettings } from '@axinom/mosaic-message-bus-abstractions';
|
|
2
|
+
import { BasicDBConfig } from '@axinom/mosaic-service-common';
|
|
3
|
+
import { Plugin } from 'postgraphile';
|
|
4
|
+
/**
|
|
5
|
+
* This factory will generate a Postgraphile plugin that adds a mutation to the selected entities allowing the user to perform a bulk edit operation on the specified entity and its relations.
|
|
6
|
+
*
|
|
7
|
+
* @param tableName Name of the table to enable the BulkEdit mutation
|
|
8
|
+
* @param bulkEditMutationName Name of the BulkEdit mutation to be generated
|
|
9
|
+
* @param messageSettings The settings for the MultiTenantMessaging for the service that implements the ItemChangeCommand (e.g. ImageServiceMultiTenantMessagingSettings.ImageServicePerformItemChange)
|
|
10
|
+
* @returns The Postgraphile plugin that enables the BulkEdit mutation.
|
|
11
|
+
*/
|
|
12
|
+
export declare const BulkEditAsyncPluginFactory: (tableName: string, bulkEditMutationName: string, messageSettings: MultiTenantMessagingSettings, getLongLivedToken: (originalToken: string, config: BasicDBConfig) => Promise<string>) => Plugin;
|
|
13
|
+
//# sourceMappingURL=bulk-edit-async-plugin-factory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bulk-edit-async-plugin-factory.d.ts","sourceRoot":"","sources":["../../../src/plugins/bulk-edit/bulk-edit-async-plugin-factory.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,4BAA4B,EAAE,MAAM,yCAAyC,CAAC;AACvF,OAAO,EAEL,aAAa,EAEd,MAAM,+BAA+B,CAAC;AAgBvC,OAAO,EAAqB,MAAM,EAAiB,MAAM,cAAc,CAAC;AA4BxE;;;;;;;GAOG;AACH,eAAO,MAAM,0BAA0B,cAC1B,MAAM,wBACK,MAAM,mBACX,4BAA4B,qCAE5B,MAAM,UACb,aAAa,KAClB,QAAQ,MAAM,CAAC,KACnB,MA0JF,CAAC"}
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BulkEditAsyncPluginFactory = void 0;
|
|
4
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
5
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
6
|
+
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
|
7
|
+
const mosaic_db_common_1 = require("@axinom/mosaic-db-common");
|
|
8
|
+
const mosaic_message_bus_1 = require("@axinom/mosaic-message-bus");
|
|
9
|
+
const graphile_utils_1 = require("graphile-utils");
|
|
10
|
+
const graphql_1 = require("graphql");
|
|
11
|
+
const pg_transactional_outbox_1 = require("pg-transactional-outbox");
|
|
12
|
+
/**
|
|
13
|
+
* This factory will generate a Postgraphile plugin that adds a mutation to the selected entities allowing the user to perform a bulk edit operation on the specified entity and its relations.
|
|
14
|
+
*
|
|
15
|
+
* @param tableName Name of the table to enable the BulkEdit mutation
|
|
16
|
+
* @param bulkEditMutationName Name of the BulkEdit mutation to be generated
|
|
17
|
+
* @param messageSettings The settings for the MultiTenantMessaging for the service that implements the ItemChangeCommand (e.g. ImageServiceMultiTenantMessagingSettings.ImageServicePerformItemChange)
|
|
18
|
+
* @returns The Postgraphile plugin that enables the BulkEdit mutation.
|
|
19
|
+
*/
|
|
20
|
+
const BulkEditAsyncPluginFactory = (tableName, bulkEditMutationName, messageSettings, getLongLivedToken) => {
|
|
21
|
+
return (builder) => {
|
|
22
|
+
builder.hook('GraphQLObjectType:fields', (fields, build, ctx) => {
|
|
23
|
+
var _a;
|
|
24
|
+
const inflection = build.inflection;
|
|
25
|
+
if (ctx.scope.isRootMutation && fields !== undefined) {
|
|
26
|
+
const pgIntrospectionResultsByKind = build.pgIntrospectionResultsByKind;
|
|
27
|
+
const pgTable = pgIntrospectionResultsByKind.class.find((cls) => cls.name === tableName);
|
|
28
|
+
if (!pgTable) {
|
|
29
|
+
// TODO: Log a warning for `Table "${tableName}" not found.`
|
|
30
|
+
return fields;
|
|
31
|
+
}
|
|
32
|
+
if (((_a = pgTable.primaryKeyConstraint) === null || _a === void 0 ? void 0 : _a.keyAttributes.length) !== 1) {
|
|
33
|
+
// TODO: Log a warning for `Table "${tableName}" skipped since the PK attribute count is not exactly 1.`
|
|
34
|
+
return fields;
|
|
35
|
+
}
|
|
36
|
+
const graphQLObjectTypeName = inflection.tableType(pgTable);
|
|
37
|
+
const graphQLObjectType = build.getTypeByName(graphQLObjectTypeName);
|
|
38
|
+
const connectionFilterType = build.connectionFilterTypesByTypeName[`${graphQLObjectTypeName}Filter`];
|
|
39
|
+
const patchType = build.getTypeByName(inflection.patchType(graphQLObjectType.name));
|
|
40
|
+
const addInputTypeForFKs = generateInputTypeForFKs(build, pgTable, 'Add');
|
|
41
|
+
const removeInputTypeForFKs = generateInputTypeForFKs(build, pgTable, 'Remove');
|
|
42
|
+
// TODO: Handle this to work even when the same Payload type is used multiple times (i.e. per each table with BulkEdit feature)
|
|
43
|
+
const BulkEditPayloadType = new graphql_1.GraphQLObjectType({
|
|
44
|
+
name: 'BulkEditAsyncPayloadType',
|
|
45
|
+
fields: () => ({
|
|
46
|
+
filterMatchedIds: {
|
|
47
|
+
type: new graphql_1.GraphQLList(graphql_1.GraphQLString),
|
|
48
|
+
},
|
|
49
|
+
}),
|
|
50
|
+
});
|
|
51
|
+
const args = {
|
|
52
|
+
filter: {
|
|
53
|
+
type: connectionFilterType,
|
|
54
|
+
},
|
|
55
|
+
set: {
|
|
56
|
+
type: patchType,
|
|
57
|
+
},
|
|
58
|
+
relatedEntitiesToRemove: {
|
|
59
|
+
type: removeInputTypeForFKs,
|
|
60
|
+
},
|
|
61
|
+
relatedEntitiesToAdd: {
|
|
62
|
+
type: addInputTypeForFKs,
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
const operation = {
|
|
66
|
+
type: BulkEditPayloadType,
|
|
67
|
+
args,
|
|
68
|
+
async resolve(parent, input, context, resolveInfo) {
|
|
69
|
+
var _a;
|
|
70
|
+
const { config, jwtToken, subject, ownerPool, envOwnerPool, storeInboxMessage, } = context;
|
|
71
|
+
const longLivedToken = await getLongLivedToken(jwtToken, config);
|
|
72
|
+
const entityIds = await getEntityIds({
|
|
73
|
+
filterName: connectionFilterType.name,
|
|
74
|
+
queryName: inflection.allRows(pgTable),
|
|
75
|
+
primaryKeyFieldName: inflection.column((_a = pgTable.primaryKeyConstraint) === null || _a === void 0 ? void 0 : _a.keyAttributes[0]),
|
|
76
|
+
}, build.graphql, input, context, resolveInfo.schema);
|
|
77
|
+
const { set, relatedEntitiesToRemove, relatedEntitiesToAdd } = input;
|
|
78
|
+
const { removals, additions } = getFkResolverPayload(build, pgTable, relatedEntitiesToRemove, relatedEntitiesToAdd);
|
|
79
|
+
await asyncResolverImplementation(messageSettings, {
|
|
80
|
+
set: getMainResolverPayload(build, pgTable, set),
|
|
81
|
+
removals,
|
|
82
|
+
additions,
|
|
83
|
+
}, entityIds, config, ownerPool, envOwnerPool, longLivedToken, subject, storeInboxMessage);
|
|
84
|
+
return {
|
|
85
|
+
filterMatchedIds: entityIds,
|
|
86
|
+
};
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
build.extend(fields, {
|
|
90
|
+
[bulkEditMutationName]: operation,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
return fields;
|
|
94
|
+
});
|
|
95
|
+
};
|
|
96
|
+
};
|
|
97
|
+
exports.BulkEditAsyncPluginFactory = BulkEditAsyncPluginFactory;
|
|
98
|
+
/**
|
|
99
|
+
* Get all the database IDs from the entities that were selected via the GraphQL filter
|
|
100
|
+
*/
|
|
101
|
+
const getEntityIds = async (metadata, graphql, args, context, schema) => {
|
|
102
|
+
var _a, _b;
|
|
103
|
+
const queryResult = await graphql.execute(schema, (0, graphile_utils_1.gql) `
|
|
104
|
+
query getEntityIds($filter: ${metadata.filterName}) {
|
|
105
|
+
entities: ${metadata.queryName}(filter: $filter) {
|
|
106
|
+
nodes {
|
|
107
|
+
${metadata.primaryKeyFieldName}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
`, undefined, context, args);
|
|
112
|
+
return (_b = (_a = queryResult === null || queryResult === void 0 ? void 0 : queryResult.data) === null || _a === void 0 ? void 0 : _a.entities) === null || _b === void 0 ? void 0 : _b.nodes.map((entity) => {
|
|
113
|
+
return entity[metadata.primaryKeyFieldName];
|
|
114
|
+
});
|
|
115
|
+
};
|
|
116
|
+
function getMainResolverPayload(build, pgTable, set) {
|
|
117
|
+
const inflection = build.inflection;
|
|
118
|
+
return {
|
|
119
|
+
mainTableName: pgTable.name,
|
|
120
|
+
gqlFieldNameToColumnNameMap: pgTable.attributes.reduce((map, curr) => {
|
|
121
|
+
map[inflection.column(curr)] = curr.name;
|
|
122
|
+
return map;
|
|
123
|
+
}, {}),
|
|
124
|
+
inputData: set,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
// TODO: Can be potentially optimized (i.e. with getAffectedForeignKeyRelations or with asyncResolverImplementation)
|
|
128
|
+
function getFkResolverPayload(build, pgTable, relatedEntitiesToRemove, relatedEntitiesToAdd) {
|
|
129
|
+
var _a, _b;
|
|
130
|
+
const inflection = build.inflection;
|
|
131
|
+
const foreignKeyRelations = getAffectedForeignKeyRelations(pgTable);
|
|
132
|
+
const fkProcessingMetadata = {};
|
|
133
|
+
for (const fkConstraint of foreignKeyRelations) {
|
|
134
|
+
const parentKey = fkConstraint.keyAttributes[fkConstraint.foreignKeyAttributeNums.indexOf((_b = (_a = pgTable.primaryKeyConstraint) === null || _a === void 0 ? void 0 : _a.keyAttributes[0].num) !== null && _b !== void 0 ? _b : -1)];
|
|
135
|
+
fkProcessingMetadata[fkConstraint.class.name] = {
|
|
136
|
+
fkGqlFieldNameToColumnNameMap: fkConstraint.class.attributes.reduce((map, curr) => {
|
|
137
|
+
map[inflection.column(curr)] = curr.name;
|
|
138
|
+
return map;
|
|
139
|
+
}, {}),
|
|
140
|
+
fkGqlFieldName: inflection.allRows(fkConstraint.class),
|
|
141
|
+
parentKeyFieldName: inflection.column(parentKey),
|
|
142
|
+
parentKeyColumnName: parentKey.name,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
const additions = {};
|
|
146
|
+
const removals = {};
|
|
147
|
+
for (const fkProps of Object.keys(fkProcessingMetadata)) {
|
|
148
|
+
if (relatedEntitiesToAdd) {
|
|
149
|
+
additions[fkProps] = {
|
|
150
|
+
parentKeyColumnName: fkProcessingMetadata[fkProps].parentKeyColumnName,
|
|
151
|
+
inputData: relatedEntitiesToAdd[fkProcessingMetadata[fkProps].fkGqlFieldName],
|
|
152
|
+
fkGqlFieldNameToColumnNameMap: fkProcessingMetadata[fkProps].fkGqlFieldNameToColumnNameMap,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
if (relatedEntitiesToRemove) {
|
|
156
|
+
removals[fkProps] = {
|
|
157
|
+
parentKeyColumnName: fkProcessingMetadata[fkProps].parentKeyColumnName,
|
|
158
|
+
inputData: relatedEntitiesToRemove[fkProcessingMetadata[fkProps].fkGqlFieldName],
|
|
159
|
+
fkGqlFieldNameToColumnNameMap: fkProcessingMetadata[fkProps].fkGqlFieldNameToColumnNameMap,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return { additions, removals };
|
|
164
|
+
}
|
|
165
|
+
async function asyncResolverImplementation(messageSettings, bulkItemChangePayload, entityIds, config, ownerPool, envOwnerPool, longLivedToken, subject, storeInboxMessage) {
|
|
166
|
+
const pool = envOwnerPool ? envOwnerPool : ownerPool;
|
|
167
|
+
const dbRole = envOwnerPool ? config.dbEnvOwner : config.dbOwner;
|
|
168
|
+
const pgSettings = (0, mosaic_db_common_1.buildPgSettings)(subject, dbRole, config.serviceId);
|
|
169
|
+
await (0, mosaic_db_common_1.transactionWithContext)(pool, pg_transactional_outbox_1.IsolationLevel.ReadCommitted, pgSettings, async (txn) => {
|
|
170
|
+
// Iterate all the entity IDs
|
|
171
|
+
for (const entity_id of entityIds) {
|
|
172
|
+
if (bulkItemChangePayload.set.inputData) {
|
|
173
|
+
// Generate the SET payload
|
|
174
|
+
const actionSetPayload = {
|
|
175
|
+
table_name: bulkItemChangePayload.set.mainTableName,
|
|
176
|
+
action: 'SET',
|
|
177
|
+
stringified_condition: JSON.stringify({ id: entity_id }),
|
|
178
|
+
stringified_payload: JSON.stringify(mapGqlInputObjectToSqlColumnNames(bulkItemChangePayload.set.inputData, bulkItemChangePayload.set.gqlFieldNameToColumnNameMap)),
|
|
179
|
+
};
|
|
180
|
+
// TODO: Add a DEBUG log for `actionSetPayload`
|
|
181
|
+
await sendMessage(storeInboxMessage, messageSettings, actionSetPayload, txn, longLivedToken);
|
|
182
|
+
}
|
|
183
|
+
if (bulkItemChangePayload.removals) {
|
|
184
|
+
const fkTableNames = Object.keys(bulkItemChangePayload.removals);
|
|
185
|
+
// Iterate each related FK table where entities will be removed
|
|
186
|
+
for (const fkTableName of fkTableNames) {
|
|
187
|
+
const fkRemovalMetadata = bulkItemChangePayload.removals[fkTableName];
|
|
188
|
+
if (fkRemovalMetadata.inputData) {
|
|
189
|
+
// Generate the REMOVE payload per entity of the FK table
|
|
190
|
+
for (const itemToRemove of fkRemovalMetadata.inputData) {
|
|
191
|
+
const removePayload = {
|
|
192
|
+
table_name: fkTableName,
|
|
193
|
+
action: 'REMOVE',
|
|
194
|
+
stringified_condition: '',
|
|
195
|
+
stringified_payload: JSON.stringify(Object.assign({ [fkRemovalMetadata.parentKeyColumnName]: entity_id }, mapGqlInputObjectToSqlColumnNames(itemToRemove, fkRemovalMetadata.fkGqlFieldNameToColumnNameMap))),
|
|
196
|
+
};
|
|
197
|
+
// TODO: Add a DEBUG log for `removePayload`
|
|
198
|
+
await sendMessage(storeInboxMessage, messageSettings, removePayload, txn, longLivedToken);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
if (Object.keys(bulkItemChangePayload.additions).length > 0) {
|
|
204
|
+
const fkTables = Object.keys(bulkItemChangePayload.additions);
|
|
205
|
+
// Iterate each related FK table where entities will be added
|
|
206
|
+
for (const fkTable of fkTables) {
|
|
207
|
+
const fkAdditionMetadata = bulkItemChangePayload.additions[fkTable];
|
|
208
|
+
if (fkAdditionMetadata.inputData) {
|
|
209
|
+
// Generate the ADD payload per entity of the FK table
|
|
210
|
+
for (const itemToAdd of fkAdditionMetadata.inputData) {
|
|
211
|
+
const addPayload = {
|
|
212
|
+
table_name: fkTable,
|
|
213
|
+
action: 'ADD',
|
|
214
|
+
stringified_condition: '',
|
|
215
|
+
stringified_payload: JSON.stringify(Object.assign({ [fkAdditionMetadata.parentKeyColumnName]: entity_id }, mapGqlInputObjectToSqlColumnNames(itemToAdd, fkAdditionMetadata.fkGqlFieldNameToColumnNameMap))),
|
|
216
|
+
};
|
|
217
|
+
// TODO: Add a DEBUG log for `addPayload`
|
|
218
|
+
await sendMessage(storeInboxMessage, messageSettings, addPayload, txn, longLivedToken);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
async function sendMessage(storeInboxMessage, messageSettings, changeSetPayload, client, longLivedToken) {
|
|
227
|
+
return storeInboxMessage(mosaic_message_bus_1.MULTIPLE_AGGREGATE_IDS, messageSettings, changeSetPayload, client, {
|
|
228
|
+
metadata: { authToken: longLivedToken },
|
|
229
|
+
concurrency: 'sequential',
|
|
230
|
+
segment: `${changeSetPayload.table_name}.${changeSetPayload.action}`,
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
function mapGqlInputObjectToSqlColumnNames(sourceGqlInputObject, gqlToSqlColumnNameMap) {
|
|
234
|
+
const gqlFiledNames = Object.keys(sourceGqlInputObject);
|
|
235
|
+
return gqlFiledNames.reduce((map, gqlFieldName) => {
|
|
236
|
+
map[gqlToSqlColumnNameMap[gqlFieldName]] =
|
|
237
|
+
sourceGqlInputObject[gqlFieldName];
|
|
238
|
+
return map;
|
|
239
|
+
}, {});
|
|
240
|
+
}
|
|
241
|
+
// TODO: Handle `insertable` | `deletable` GRANTS for FK Relations
|
|
242
|
+
function generateInputTypeForFKs(build, pgTable, action) {
|
|
243
|
+
var _a, _b;
|
|
244
|
+
const inflection = build.inflection;
|
|
245
|
+
const allFkInputTypesFieldMap = {};
|
|
246
|
+
// Filter only the interesting FK relations
|
|
247
|
+
const foreignKeyRelations = getAffectedForeignKeyRelations(pgTable);
|
|
248
|
+
for (const fkConstraint of foreignKeyRelations) {
|
|
249
|
+
const parentPgTable = fkConstraint.foreignClass;
|
|
250
|
+
const parentKey = fkConstraint.keyAttributes[fkConstraint.foreignKeyAttributeNums.indexOf((_b = (_a = parentPgTable === null || parentPgTable === void 0 ? void 0 : parentPgTable.primaryKeyConstraint) === null || _a === void 0 ? void 0 : _a.keyAttributes[0].num) !== null && _b !== void 0 ? _b : -1)];
|
|
251
|
+
const parentKeyFieldName = inflection.column(parentKey);
|
|
252
|
+
const fkTableInput = build.pgGetGqlInputTypeByTypeIdAndModifier(fkConstraint.class.type.id, null);
|
|
253
|
+
const fkTableInputTypeGqlFieldMap = {};
|
|
254
|
+
for (const key of Object.keys(fkTableInput.getFields())) {
|
|
255
|
+
if (key !== parentKeyFieldName) {
|
|
256
|
+
fkTableInputTypeGqlFieldMap[key] = fkTableInput.getFields()[key];
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
allFkInputTypesFieldMap[inflection.allRows(fkConstraint.class)] = {
|
|
260
|
+
type: new graphql_1.GraphQLList(new graphql_1.GraphQLInputObjectType({
|
|
261
|
+
name: `BulkEditAsync${inflection.tableType(parentPgTable)}${action}${inflection.tableType(fkConstraint.class)}Input`,
|
|
262
|
+
fields: () => (Object.assign({}, fkTableInputTypeGqlFieldMap)),
|
|
263
|
+
})),
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
const BulkEditAddInputTypeForFK = new graphql_1.GraphQLInputObjectType({
|
|
267
|
+
name: `BulkEditAsync${inflection.tableType(pgTable)}${action}Input`,
|
|
268
|
+
fields: () => (Object.assign({}, allFkInputTypesFieldMap)),
|
|
269
|
+
});
|
|
270
|
+
build.addType(BulkEditAddInputTypeForFK);
|
|
271
|
+
return BulkEditAddInputTypeForFK;
|
|
272
|
+
}
|
|
273
|
+
function getAffectedForeignKeyRelations(pgTable) {
|
|
274
|
+
return pgTable.foreignConstraints.filter((constraint) => constraint.type === 'f' &&
|
|
275
|
+
(constraint.isFake === undefined || constraint.isFake === false) &&
|
|
276
|
+
!constraint.name.startsWith('multitenancy_relation_'));
|
|
277
|
+
}
|
|
278
|
+
//# sourceMappingURL=bulk-edit-async-plugin-factory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bulk-edit-async-plugin-factory.js","sourceRoot":"","sources":["../../../src/plugins/bulk-edit/bulk-edit-async-plugin-factory.ts"],"names":[],"mappings":"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"}
|
package/dist/plugins/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export * from './add-error-codes-enum-plugin';
|
|
2
2
|
export * from './annotate-types-with-permissions-plugin';
|
|
3
|
+
export * from './bulk-edit/bulk-edit-async-plugin-factory';
|
|
3
4
|
export * from './deprecate-stray-node-id-fields-plugin';
|
|
4
5
|
export * from './generic-bulk-plugin-factory';
|
|
5
6
|
export * from './graphiql-management-mode-plugin-hook';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/plugins/index.ts"],"names":[],"mappings":"AAAA,cAAc,+BAA+B,CAAC;AAC9C,cAAc,0CAA0C,CAAC;AACzD,cAAc,yCAAyC,CAAC;AACxD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,wCAAwC,CAAC;AACvD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,4CAA4C,CAAC;AAC3D,cAAc,gCAAgC,CAAC;AAC/C,cAAc,gCAAgC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/plugins/index.ts"],"names":[],"mappings":"AAAA,cAAc,+BAA+B,CAAC;AAC9C,cAAc,0CAA0C,CAAC;AACzD,cAAc,4CAA4C,CAAC;AAC3D,cAAc,yCAAyC,CAAC;AACxD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,wCAAwC,CAAC;AACvD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,4CAA4C,CAAC;AAC3D,cAAc,gCAAgC,CAAC;AAC/C,cAAc,gCAAgC,CAAC"}
|
package/dist/plugins/index.js
CHANGED
|
@@ -16,6 +16,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("./add-error-codes-enum-plugin"), exports);
|
|
18
18
|
__exportStar(require("./annotate-types-with-permissions-plugin"), exports);
|
|
19
|
+
__exportStar(require("./bulk-edit/bulk-edit-async-plugin-factory"), exports);
|
|
19
20
|
__exportStar(require("./deprecate-stray-node-id-fields-plugin"), exports);
|
|
20
21
|
__exportStar(require("./generic-bulk-plugin-factory"), exports);
|
|
21
22
|
__exportStar(require("./graphiql-management-mode-plugin-hook"), exports);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/plugins/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,gEAA8C;AAC9C,2EAAyD;AACzD,0EAAwD;AACxD,gEAA8C;AAC9C,yEAAuD;AACvD,gEAA8C;AAC9C,6EAA2D;AAC3D,iEAA+C;AAC/C,iEAA+C"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/plugins/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,gEAA8C;AAC9C,2EAAyD;AACzD,6EAA2D;AAC3D,0EAAwD;AACxD,gEAA8C;AAC9C,yEAAuD;AACvD,gEAA8C;AAC9C,6EAA2D;AAC3D,iEAA+C;AAC/C,iEAA+C"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@axinom/mosaic-graphql-common",
|
|
3
|
-
"version": "0.22.0
|
|
3
|
+
"version": "0.22.0",
|
|
4
4
|
"description": "Common GraphQL and PostGraphile related functionality.",
|
|
5
5
|
"author": "Axinom",
|
|
6
6
|
"license": "PROPRIETARY",
|
|
@@ -31,6 +31,11 @@
|
|
|
31
31
|
"lint": "eslint . --ext .ts,.tsx,.js --color --cache"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
+
"@axinom/mosaic-db-common": "^0.46.0",
|
|
35
|
+
"@axinom/mosaic-message-bus": "^0.36.0",
|
|
36
|
+
"@axinom/mosaic-message-bus-abstractions": "^0.23.0",
|
|
37
|
+
"@axinom/mosaic-service-common": "^0.58.0",
|
|
38
|
+
"@axinom/mosaic-transactional-inbox-outbox": "^0.18.0",
|
|
34
39
|
"@graphile/pg-pubsub": "^4.12.3",
|
|
35
40
|
"endent": "^2.1.0",
|
|
36
41
|
"express": "^4.17.1",
|
|
@@ -42,10 +47,11 @@
|
|
|
42
47
|
"jest": "^29",
|
|
43
48
|
"jest-expect-message": "^1.1.3",
|
|
44
49
|
"pg": "^8.11.3",
|
|
50
|
+
"pg-transactional-outbox": "^0.5.7",
|
|
45
51
|
"postgraphile": "^4.13.0"
|
|
46
52
|
},
|
|
47
53
|
"devDependencies": {
|
|
48
|
-
"@axinom/mosaic-dev-be-common": "^0.14.0
|
|
54
|
+
"@axinom/mosaic-dev-be-common": "^0.14.0",
|
|
49
55
|
"@types/express": "^4.17.17",
|
|
50
56
|
"@types/inflection": "^1.5.28",
|
|
51
57
|
"@types/jest": "^29",
|
|
@@ -59,5 +65,5 @@
|
|
|
59
65
|
"publishConfig": {
|
|
60
66
|
"access": "public"
|
|
61
67
|
},
|
|
62
|
-
"gitHead": "
|
|
68
|
+
"gitHead": "c3802f0be74822f25268d4fdf7497a1c1577309d"
|
|
63
69
|
}
|
|
@@ -0,0 +1,624 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
3
|
+
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
|
4
|
+
import {
|
|
5
|
+
DbClient,
|
|
6
|
+
PgAuthenticatedManagementSubject,
|
|
7
|
+
buildPgSettings,
|
|
8
|
+
transactionWithContext,
|
|
9
|
+
} from '@axinom/mosaic-db-common';
|
|
10
|
+
import { MULTIPLE_AGGREGATE_IDS } from '@axinom/mosaic-message-bus';
|
|
11
|
+
import { MultiTenantMessagingSettings } from '@axinom/mosaic-message-bus-abstractions';
|
|
12
|
+
import {
|
|
13
|
+
BasicConfig,
|
|
14
|
+
BasicDBConfig,
|
|
15
|
+
BasicManagedServiceConfig,
|
|
16
|
+
} from '@axinom/mosaic-service-common';
|
|
17
|
+
import { StoreInboxMessage } from '@axinom/mosaic-transactional-inbox-outbox';
|
|
18
|
+
import {
|
|
19
|
+
PgClass,
|
|
20
|
+
PgConstraint,
|
|
21
|
+
PgIntrospectionResultsByKind,
|
|
22
|
+
} from 'graphile-build-pg';
|
|
23
|
+
import { gql as gqlExtended } from 'graphile-utils';
|
|
24
|
+
import GraphQL, {
|
|
25
|
+
GraphQLInputFieldMap,
|
|
26
|
+
GraphQLInputObjectType,
|
|
27
|
+
GraphQLList,
|
|
28
|
+
GraphQLObjectType,
|
|
29
|
+
GraphQLString,
|
|
30
|
+
} from 'graphql';
|
|
31
|
+
import { DatabaseClient, IsolationLevel } from 'pg-transactional-outbox';
|
|
32
|
+
import { Build, Inflection, Plugin, SchemaBuilder } from 'postgraphile';
|
|
33
|
+
|
|
34
|
+
type MinimalConfig = Pick<BasicConfig, 'serviceId'> &
|
|
35
|
+
(Pick<BasicDBConfig, 'dbOwner'> &
|
|
36
|
+
Pick<BasicManagedServiceConfig, 'dbEnvOwner'>);
|
|
37
|
+
|
|
38
|
+
type BulkActionType = 'SET' | 'ADD' | 'REMOVE';
|
|
39
|
+
|
|
40
|
+
// TODO: Consider reusable types generated from the messages-lib
|
|
41
|
+
interface GenericServicePerformItemChangeCommand {
|
|
42
|
+
/**
|
|
43
|
+
* The string has a minimum length of one character and it cannot consist of only whitespace characters.
|
|
44
|
+
*/
|
|
45
|
+
table_name: string;
|
|
46
|
+
/**
|
|
47
|
+
* The type of action to perform on the database table.
|
|
48
|
+
*/
|
|
49
|
+
action: BulkActionType;
|
|
50
|
+
/**
|
|
51
|
+
* The string has a minimum length of one character and it cannot consist of only whitespace characters.
|
|
52
|
+
*/
|
|
53
|
+
stringified_condition: string;
|
|
54
|
+
/**
|
|
55
|
+
* The string has a minimum length of one character and it cannot consist of only whitespace characters.
|
|
56
|
+
*/
|
|
57
|
+
stringified_payload: string;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* This factory will generate a Postgraphile plugin that adds a mutation to the selected entities allowing the user to perform a bulk edit operation on the specified entity and its relations.
|
|
62
|
+
*
|
|
63
|
+
* @param tableName Name of the table to enable the BulkEdit mutation
|
|
64
|
+
* @param bulkEditMutationName Name of the BulkEdit mutation to be generated
|
|
65
|
+
* @param messageSettings The settings for the MultiTenantMessaging for the service that implements the ItemChangeCommand (e.g. ImageServiceMultiTenantMessagingSettings.ImageServicePerformItemChange)
|
|
66
|
+
* @returns The Postgraphile plugin that enables the BulkEdit mutation.
|
|
67
|
+
*/
|
|
68
|
+
export const BulkEditAsyncPluginFactory = (
|
|
69
|
+
tableName: string,
|
|
70
|
+
bulkEditMutationName: string,
|
|
71
|
+
messageSettings: MultiTenantMessagingSettings,
|
|
72
|
+
getLongLivedToken: (
|
|
73
|
+
originalToken: string,
|
|
74
|
+
config: BasicDBConfig,
|
|
75
|
+
) => Promise<string>,
|
|
76
|
+
): Plugin => {
|
|
77
|
+
return (builder: SchemaBuilder): void => {
|
|
78
|
+
builder.hook('GraphQLObjectType:fields', (fields, build, ctx) => {
|
|
79
|
+
const inflection: Inflection = build.inflection;
|
|
80
|
+
|
|
81
|
+
if (ctx.scope.isRootMutation && fields !== undefined) {
|
|
82
|
+
const pgIntrospectionResultsByKind: PgIntrospectionResultsByKind =
|
|
83
|
+
build.pgIntrospectionResultsByKind;
|
|
84
|
+
|
|
85
|
+
const pgTable = pgIntrospectionResultsByKind.class.find(
|
|
86
|
+
(cls) => cls.name === tableName,
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
if (!pgTable) {
|
|
90
|
+
// TODO: Log a warning for `Table "${tableName}" not found.`
|
|
91
|
+
return fields;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (pgTable.primaryKeyConstraint?.keyAttributes.length !== 1) {
|
|
95
|
+
// TODO: Log a warning for `Table "${tableName}" skipped since the PK attribute count is not exactly 1.`
|
|
96
|
+
return fields;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const graphQLObjectTypeName = inflection.tableType(pgTable);
|
|
100
|
+
const graphQLObjectType = build.getTypeByName(graphQLObjectTypeName);
|
|
101
|
+
|
|
102
|
+
const connectionFilterType: GraphQLInputObjectType =
|
|
103
|
+
build.connectionFilterTypesByTypeName[
|
|
104
|
+
`${graphQLObjectTypeName}Filter`
|
|
105
|
+
];
|
|
106
|
+
|
|
107
|
+
const patchType: GraphQLInputObjectType = build.getTypeByName(
|
|
108
|
+
inflection.patchType(graphQLObjectType.name),
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
const addInputTypeForFKs = generateInputTypeForFKs(
|
|
112
|
+
build,
|
|
113
|
+
pgTable,
|
|
114
|
+
'Add',
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
const removeInputTypeForFKs = generateInputTypeForFKs(
|
|
118
|
+
build,
|
|
119
|
+
pgTable,
|
|
120
|
+
'Remove',
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
// TODO: Handle this to work even when the same Payload type is used multiple times (i.e. per each table with BulkEdit feature)
|
|
124
|
+
const BulkEditPayloadType = new GraphQLObjectType({
|
|
125
|
+
name: 'BulkEditAsyncPayloadType',
|
|
126
|
+
fields: () => ({
|
|
127
|
+
filterMatchedIds: {
|
|
128
|
+
type: new GraphQLList(GraphQLString),
|
|
129
|
+
},
|
|
130
|
+
}),
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
const args = {
|
|
134
|
+
filter: {
|
|
135
|
+
type: connectionFilterType,
|
|
136
|
+
},
|
|
137
|
+
set: {
|
|
138
|
+
type: patchType,
|
|
139
|
+
},
|
|
140
|
+
relatedEntitiesToRemove: {
|
|
141
|
+
type: removeInputTypeForFKs,
|
|
142
|
+
},
|
|
143
|
+
relatedEntitiesToAdd: {
|
|
144
|
+
type: addInputTypeForFKs,
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
const operation = {
|
|
149
|
+
type: BulkEditPayloadType,
|
|
150
|
+
args,
|
|
151
|
+
async resolve(
|
|
152
|
+
parent: unknown,
|
|
153
|
+
input: {
|
|
154
|
+
filter: { [key: string]: any };
|
|
155
|
+
set?: { [key: string]: any };
|
|
156
|
+
relatedEntitiesToRemove?: { [key: string]: [any] };
|
|
157
|
+
relatedEntitiesToAdd?: { [key: string]: [any] };
|
|
158
|
+
},
|
|
159
|
+
context: { [str: string]: unknown },
|
|
160
|
+
resolveInfo: GraphQL.GraphQLResolveInfo,
|
|
161
|
+
) {
|
|
162
|
+
const {
|
|
163
|
+
config,
|
|
164
|
+
jwtToken,
|
|
165
|
+
subject,
|
|
166
|
+
ownerPool,
|
|
167
|
+
envOwnerPool,
|
|
168
|
+
storeInboxMessage,
|
|
169
|
+
} = context;
|
|
170
|
+
|
|
171
|
+
const longLivedToken = await getLongLivedToken(
|
|
172
|
+
jwtToken as string,
|
|
173
|
+
config as BasicDBConfig,
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
const entityIds = await getEntityIds(
|
|
177
|
+
{
|
|
178
|
+
filterName: connectionFilterType.name,
|
|
179
|
+
queryName: inflection.allRows(pgTable),
|
|
180
|
+
primaryKeyFieldName: inflection.column(
|
|
181
|
+
pgTable.primaryKeyConstraint?.keyAttributes[0],
|
|
182
|
+
),
|
|
183
|
+
},
|
|
184
|
+
build.graphql,
|
|
185
|
+
input,
|
|
186
|
+
context,
|
|
187
|
+
resolveInfo.schema,
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
const { set, relatedEntitiesToRemove, relatedEntitiesToAdd } =
|
|
191
|
+
input;
|
|
192
|
+
|
|
193
|
+
const { removals, additions } = getFkResolverPayload(
|
|
194
|
+
build,
|
|
195
|
+
pgTable,
|
|
196
|
+
relatedEntitiesToRemove,
|
|
197
|
+
relatedEntitiesToAdd,
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
await asyncResolverImplementation(
|
|
201
|
+
messageSettings,
|
|
202
|
+
{
|
|
203
|
+
set: getMainResolverPayload(build, pgTable, set),
|
|
204
|
+
removals,
|
|
205
|
+
additions,
|
|
206
|
+
},
|
|
207
|
+
entityIds,
|
|
208
|
+
config as MinimalConfig,
|
|
209
|
+
ownerPool as DbClient,
|
|
210
|
+
envOwnerPool as DbClient,
|
|
211
|
+
longLivedToken,
|
|
212
|
+
subject as PgAuthenticatedManagementSubject,
|
|
213
|
+
storeInboxMessage as StoreInboxMessage,
|
|
214
|
+
);
|
|
215
|
+
|
|
216
|
+
return {
|
|
217
|
+
filterMatchedIds: entityIds,
|
|
218
|
+
};
|
|
219
|
+
},
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
build.extend(fields, {
|
|
223
|
+
[bulkEditMutationName]: operation,
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return fields;
|
|
228
|
+
});
|
|
229
|
+
};
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Get all the database IDs from the entities that were selected via the GraphQL filter
|
|
234
|
+
*/
|
|
235
|
+
const getEntityIds = async (
|
|
236
|
+
metadata: {
|
|
237
|
+
filterName: string;
|
|
238
|
+
queryName: string;
|
|
239
|
+
primaryKeyFieldName: string;
|
|
240
|
+
},
|
|
241
|
+
graphql: typeof GraphQL,
|
|
242
|
+
args: { [argName: string]: unknown },
|
|
243
|
+
context: unknown,
|
|
244
|
+
schema: GraphQL.GraphQLSchema,
|
|
245
|
+
): Promise<string[]> => {
|
|
246
|
+
const queryResult = await graphql.execute(
|
|
247
|
+
schema,
|
|
248
|
+
gqlExtended`
|
|
249
|
+
query getEntityIds($filter: ${metadata.filterName}) {
|
|
250
|
+
entities: ${metadata.queryName}(filter: $filter) {
|
|
251
|
+
nodes {
|
|
252
|
+
${metadata.primaryKeyFieldName}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
`,
|
|
257
|
+
undefined,
|
|
258
|
+
context,
|
|
259
|
+
args,
|
|
260
|
+
);
|
|
261
|
+
|
|
262
|
+
return queryResult?.data?.entities?.nodes.map(
|
|
263
|
+
(entity: Record<string, unknown>) => {
|
|
264
|
+
return entity[metadata.primaryKeyFieldName];
|
|
265
|
+
},
|
|
266
|
+
);
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
interface FKProcessingMetadata {
|
|
270
|
+
[fKTableName: string]: {
|
|
271
|
+
fkGqlFieldNameToColumnNameMap: { [key: string]: string };
|
|
272
|
+
fkGqlFieldName: string;
|
|
273
|
+
parentKeyFieldName: string;
|
|
274
|
+
parentKeyColumnName: string;
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
interface MainResolverPayload {
|
|
279
|
+
mainTableName: string;
|
|
280
|
+
gqlFieldNameToColumnNameMap: { [key: string]: string };
|
|
281
|
+
inputData?: { [key: string]: any };
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
interface FkResolverPayload {
|
|
285
|
+
[fKTableName: string]: {
|
|
286
|
+
parentKeyColumnName: string;
|
|
287
|
+
fkGqlFieldNameToColumnNameMap: { [key: string]: string };
|
|
288
|
+
inputData?: [{ [key: string]: any }];
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
interface BulkItemChangePayload {
|
|
293
|
+
set: MainResolverPayload;
|
|
294
|
+
removals: FkResolverPayload;
|
|
295
|
+
additions: FkResolverPayload;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
function getMainResolverPayload(
|
|
299
|
+
build: Build,
|
|
300
|
+
pgTable: PgClass,
|
|
301
|
+
set: { [key: string]: any } | undefined,
|
|
302
|
+
): MainResolverPayload {
|
|
303
|
+
const inflection: Inflection = build.inflection;
|
|
304
|
+
|
|
305
|
+
return {
|
|
306
|
+
mainTableName: pgTable.name,
|
|
307
|
+
gqlFieldNameToColumnNameMap: pgTable.attributes.reduce((map: any, curr) => {
|
|
308
|
+
map[inflection.column(curr)] = curr.name;
|
|
309
|
+
|
|
310
|
+
return map;
|
|
311
|
+
}, {}),
|
|
312
|
+
inputData: set,
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// TODO: Can be potentially optimized (i.e. with getAffectedForeignKeyRelations or with asyncResolverImplementation)
|
|
317
|
+
function getFkResolverPayload(
|
|
318
|
+
build: Build,
|
|
319
|
+
pgTable: PgClass,
|
|
320
|
+
relatedEntitiesToRemove:
|
|
321
|
+
| {
|
|
322
|
+
[key: string]: [any];
|
|
323
|
+
}
|
|
324
|
+
| undefined,
|
|
325
|
+
relatedEntitiesToAdd:
|
|
326
|
+
| {
|
|
327
|
+
[key: string]: [any];
|
|
328
|
+
}
|
|
329
|
+
| undefined,
|
|
330
|
+
): {
|
|
331
|
+
additions: FkResolverPayload;
|
|
332
|
+
removals: FkResolverPayload;
|
|
333
|
+
} {
|
|
334
|
+
const inflection: Inflection = build.inflection;
|
|
335
|
+
const foreignKeyRelations = getAffectedForeignKeyRelations(pgTable);
|
|
336
|
+
|
|
337
|
+
const fkProcessingMetadata: FKProcessingMetadata = {};
|
|
338
|
+
|
|
339
|
+
for (const fkConstraint of foreignKeyRelations) {
|
|
340
|
+
const parentKey =
|
|
341
|
+
fkConstraint.keyAttributes[
|
|
342
|
+
fkConstraint.foreignKeyAttributeNums.indexOf(
|
|
343
|
+
pgTable.primaryKeyConstraint?.keyAttributes[0].num ?? -1,
|
|
344
|
+
)
|
|
345
|
+
];
|
|
346
|
+
|
|
347
|
+
fkProcessingMetadata[fkConstraint.class.name] = {
|
|
348
|
+
fkGqlFieldNameToColumnNameMap: fkConstraint.class.attributes.reduce(
|
|
349
|
+
(map: any, curr) => {
|
|
350
|
+
map[inflection.column(curr)] = curr.name;
|
|
351
|
+
|
|
352
|
+
return map;
|
|
353
|
+
},
|
|
354
|
+
{},
|
|
355
|
+
),
|
|
356
|
+
fkGqlFieldName: inflection.allRows(fkConstraint.class),
|
|
357
|
+
parentKeyFieldName: inflection.column(parentKey),
|
|
358
|
+
parentKeyColumnName: parentKey.name,
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
const additions: FkResolverPayload = {};
|
|
363
|
+
const removals: FkResolverPayload = {};
|
|
364
|
+
|
|
365
|
+
for (const fkProps of Object.keys(fkProcessingMetadata)) {
|
|
366
|
+
if (relatedEntitiesToAdd) {
|
|
367
|
+
additions[fkProps] = {
|
|
368
|
+
parentKeyColumnName: fkProcessingMetadata[fkProps].parentKeyColumnName,
|
|
369
|
+
inputData:
|
|
370
|
+
relatedEntitiesToAdd[fkProcessingMetadata[fkProps].fkGqlFieldName],
|
|
371
|
+
fkGqlFieldNameToColumnNameMap:
|
|
372
|
+
fkProcessingMetadata[fkProps].fkGqlFieldNameToColumnNameMap,
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
if (relatedEntitiesToRemove) {
|
|
377
|
+
removals[fkProps] = {
|
|
378
|
+
parentKeyColumnName: fkProcessingMetadata[fkProps].parentKeyColumnName,
|
|
379
|
+
inputData:
|
|
380
|
+
relatedEntitiesToRemove[fkProcessingMetadata[fkProps].fkGqlFieldName],
|
|
381
|
+
fkGqlFieldNameToColumnNameMap:
|
|
382
|
+
fkProcessingMetadata[fkProps].fkGqlFieldNameToColumnNameMap,
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
return { additions, removals };
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
async function asyncResolverImplementation(
|
|
391
|
+
messageSettings: MultiTenantMessagingSettings,
|
|
392
|
+
bulkItemChangePayload: BulkItemChangePayload,
|
|
393
|
+
entityIds: string[],
|
|
394
|
+
config: MinimalConfig,
|
|
395
|
+
ownerPool: DbClient,
|
|
396
|
+
envOwnerPool: DbClient,
|
|
397
|
+
longLivedToken: string,
|
|
398
|
+
subject: PgAuthenticatedManagementSubject,
|
|
399
|
+
storeInboxMessage: StoreInboxMessage,
|
|
400
|
+
) {
|
|
401
|
+
const pool = envOwnerPool ? envOwnerPool : ownerPool;
|
|
402
|
+
const dbRole = envOwnerPool ? config.dbEnvOwner : config.dbOwner;
|
|
403
|
+
|
|
404
|
+
const pgSettings = buildPgSettings(subject, dbRole, config.serviceId);
|
|
405
|
+
|
|
406
|
+
await transactionWithContext(
|
|
407
|
+
pool,
|
|
408
|
+
IsolationLevel.ReadCommitted,
|
|
409
|
+
pgSettings,
|
|
410
|
+
async (txn) => {
|
|
411
|
+
// Iterate all the entity IDs
|
|
412
|
+
for (const entity_id of entityIds) {
|
|
413
|
+
if (bulkItemChangePayload.set.inputData) {
|
|
414
|
+
// Generate the SET payload
|
|
415
|
+
const actionSetPayload: GenericServicePerformItemChangeCommand = {
|
|
416
|
+
table_name: bulkItemChangePayload.set.mainTableName,
|
|
417
|
+
action: 'SET',
|
|
418
|
+
stringified_condition: JSON.stringify({ id: entity_id }),
|
|
419
|
+
stringified_payload: JSON.stringify(
|
|
420
|
+
mapGqlInputObjectToSqlColumnNames(
|
|
421
|
+
bulkItemChangePayload.set.inputData,
|
|
422
|
+
bulkItemChangePayload.set.gqlFieldNameToColumnNameMap,
|
|
423
|
+
),
|
|
424
|
+
),
|
|
425
|
+
};
|
|
426
|
+
|
|
427
|
+
// TODO: Add a DEBUG log for `actionSetPayload`
|
|
428
|
+
|
|
429
|
+
await sendMessage(
|
|
430
|
+
storeInboxMessage,
|
|
431
|
+
messageSettings,
|
|
432
|
+
actionSetPayload,
|
|
433
|
+
txn,
|
|
434
|
+
longLivedToken,
|
|
435
|
+
);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
if (bulkItemChangePayload.removals) {
|
|
439
|
+
const fkTableNames = Object.keys(bulkItemChangePayload.removals);
|
|
440
|
+
|
|
441
|
+
// Iterate each related FK table where entities will be removed
|
|
442
|
+
for (const fkTableName of fkTableNames) {
|
|
443
|
+
const fkRemovalMetadata =
|
|
444
|
+
bulkItemChangePayload.removals[fkTableName];
|
|
445
|
+
if (fkRemovalMetadata.inputData) {
|
|
446
|
+
// Generate the REMOVE payload per entity of the FK table
|
|
447
|
+
for (const itemToRemove of fkRemovalMetadata.inputData) {
|
|
448
|
+
const removePayload: GenericServicePerformItemChangeCommand = {
|
|
449
|
+
table_name: fkTableName,
|
|
450
|
+
action: 'REMOVE',
|
|
451
|
+
stringified_condition: '',
|
|
452
|
+
stringified_payload: JSON.stringify({
|
|
453
|
+
[fkRemovalMetadata.parentKeyColumnName]: entity_id,
|
|
454
|
+
...mapGqlInputObjectToSqlColumnNames(
|
|
455
|
+
itemToRemove,
|
|
456
|
+
fkRemovalMetadata.fkGqlFieldNameToColumnNameMap,
|
|
457
|
+
),
|
|
458
|
+
}),
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
// TODO: Add a DEBUG log for `removePayload`
|
|
462
|
+
|
|
463
|
+
await sendMessage(
|
|
464
|
+
storeInboxMessage,
|
|
465
|
+
messageSettings,
|
|
466
|
+
removePayload,
|
|
467
|
+
txn,
|
|
468
|
+
longLivedToken,
|
|
469
|
+
);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
if (Object.keys(bulkItemChangePayload.additions).length > 0) {
|
|
476
|
+
const fkTables = Object.keys(bulkItemChangePayload.additions);
|
|
477
|
+
|
|
478
|
+
// Iterate each related FK table where entities will be added
|
|
479
|
+
for (const fkTable of fkTables) {
|
|
480
|
+
const fkAdditionMetadata = bulkItemChangePayload.additions[fkTable];
|
|
481
|
+
if (fkAdditionMetadata.inputData) {
|
|
482
|
+
// Generate the ADD payload per entity of the FK table
|
|
483
|
+
for (const itemToAdd of fkAdditionMetadata.inputData) {
|
|
484
|
+
const addPayload: GenericServicePerformItemChangeCommand = {
|
|
485
|
+
table_name: fkTable,
|
|
486
|
+
action: 'ADD',
|
|
487
|
+
stringified_condition: '',
|
|
488
|
+
stringified_payload: JSON.stringify({
|
|
489
|
+
[fkAdditionMetadata.parentKeyColumnName]: entity_id,
|
|
490
|
+
...mapGqlInputObjectToSqlColumnNames(
|
|
491
|
+
itemToAdd,
|
|
492
|
+
fkAdditionMetadata.fkGqlFieldNameToColumnNameMap,
|
|
493
|
+
),
|
|
494
|
+
}),
|
|
495
|
+
};
|
|
496
|
+
|
|
497
|
+
// TODO: Add a DEBUG log for `addPayload`
|
|
498
|
+
|
|
499
|
+
await sendMessage(
|
|
500
|
+
storeInboxMessage,
|
|
501
|
+
messageSettings,
|
|
502
|
+
addPayload,
|
|
503
|
+
txn,
|
|
504
|
+
longLivedToken,
|
|
505
|
+
);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
},
|
|
512
|
+
);
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
async function sendMessage(
|
|
516
|
+
storeInboxMessage: StoreInboxMessage,
|
|
517
|
+
messageSettings: MultiTenantMessagingSettings,
|
|
518
|
+
changeSetPayload: GenericServicePerformItemChangeCommand,
|
|
519
|
+
client: DatabaseClient,
|
|
520
|
+
longLivedToken: string,
|
|
521
|
+
): Promise<void> {
|
|
522
|
+
return storeInboxMessage(
|
|
523
|
+
MULTIPLE_AGGREGATE_IDS,
|
|
524
|
+
messageSettings,
|
|
525
|
+
changeSetPayload,
|
|
526
|
+
client,
|
|
527
|
+
{
|
|
528
|
+
metadata: { authToken: longLivedToken },
|
|
529
|
+
concurrency: 'sequential',
|
|
530
|
+
segment: `${changeSetPayload.table_name}.${changeSetPayload.action}`,
|
|
531
|
+
},
|
|
532
|
+
);
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
function mapGqlInputObjectToSqlColumnNames(
|
|
536
|
+
sourceGqlInputObject: {
|
|
537
|
+
[gqlFieldName: string]: any;
|
|
538
|
+
},
|
|
539
|
+
gqlToSqlColumnNameMap: {
|
|
540
|
+
[gqlFieldName: string]: string;
|
|
541
|
+
},
|
|
542
|
+
): { [sqlColumnName: string]: any } {
|
|
543
|
+
const gqlFiledNames = Object.keys(sourceGqlInputObject);
|
|
544
|
+
|
|
545
|
+
return gqlFiledNames.reduce((map: any, gqlFieldName) => {
|
|
546
|
+
map[gqlToSqlColumnNameMap[gqlFieldName]] =
|
|
547
|
+
sourceGqlInputObject[gqlFieldName];
|
|
548
|
+
|
|
549
|
+
return map;
|
|
550
|
+
}, {});
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
// TODO: Handle `insertable` | `deletable` GRANTS for FK Relations
|
|
554
|
+
function generateInputTypeForFKs(
|
|
555
|
+
build: Build,
|
|
556
|
+
pgTable: PgClass,
|
|
557
|
+
action: 'Add' | 'Remove',
|
|
558
|
+
): GraphQLInputObjectType {
|
|
559
|
+
const inflection: Inflection = build.inflection;
|
|
560
|
+
const allFkInputTypesFieldMap: GraphQL.Thunk<GraphQL.GraphQLInputFieldConfigMap> =
|
|
561
|
+
{};
|
|
562
|
+
|
|
563
|
+
// Filter only the interesting FK relations
|
|
564
|
+
const foreignKeyRelations = getAffectedForeignKeyRelations(pgTable);
|
|
565
|
+
|
|
566
|
+
for (const fkConstraint of foreignKeyRelations) {
|
|
567
|
+
const parentPgTable = fkConstraint.foreignClass;
|
|
568
|
+
|
|
569
|
+
const parentKey =
|
|
570
|
+
fkConstraint.keyAttributes[
|
|
571
|
+
fkConstraint.foreignKeyAttributeNums.indexOf(
|
|
572
|
+
parentPgTable?.primaryKeyConstraint?.keyAttributes[0].num ?? -1,
|
|
573
|
+
)
|
|
574
|
+
];
|
|
575
|
+
|
|
576
|
+
const parentKeyFieldName = inflection.column(parentKey);
|
|
577
|
+
|
|
578
|
+
const fkTableInput: GraphQLInputObjectType =
|
|
579
|
+
build.pgGetGqlInputTypeByTypeIdAndModifier(
|
|
580
|
+
fkConstraint.class.type.id,
|
|
581
|
+
null,
|
|
582
|
+
);
|
|
583
|
+
|
|
584
|
+
const fkTableInputTypeGqlFieldMap: GraphQLInputFieldMap = {};
|
|
585
|
+
for (const key of Object.keys(fkTableInput.getFields())) {
|
|
586
|
+
if (key !== parentKeyFieldName) {
|
|
587
|
+
fkTableInputTypeGqlFieldMap[key] = fkTableInput.getFields()[key];
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
allFkInputTypesFieldMap[inflection.allRows(fkConstraint.class)] = {
|
|
592
|
+
type: new GraphQLList(
|
|
593
|
+
new GraphQLInputObjectType({
|
|
594
|
+
name: `BulkEditAsync${inflection.tableType(
|
|
595
|
+
parentPgTable,
|
|
596
|
+
)}${action}${inflection.tableType(fkConstraint.class)}Input`,
|
|
597
|
+
fields: () => ({
|
|
598
|
+
...fkTableInputTypeGqlFieldMap,
|
|
599
|
+
}),
|
|
600
|
+
}),
|
|
601
|
+
),
|
|
602
|
+
};
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
const BulkEditAddInputTypeForFK = new GraphQLInputObjectType({
|
|
606
|
+
name: `BulkEditAsync${inflection.tableType(pgTable)}${action}Input`,
|
|
607
|
+
fields: () => ({
|
|
608
|
+
...allFkInputTypesFieldMap,
|
|
609
|
+
}),
|
|
610
|
+
});
|
|
611
|
+
|
|
612
|
+
build.addType(BulkEditAddInputTypeForFK);
|
|
613
|
+
|
|
614
|
+
return BulkEditAddInputTypeForFK;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
function getAffectedForeignKeyRelations(pgTable: PgClass) {
|
|
618
|
+
return pgTable.foreignConstraints.filter(
|
|
619
|
+
(constraint: PgConstraint & { isFake?: boolean }) =>
|
|
620
|
+
constraint.type === 'f' &&
|
|
621
|
+
(constraint.isFake === undefined || constraint.isFake === false) &&
|
|
622
|
+
!constraint.name.startsWith('multitenancy_relation_'),
|
|
623
|
+
);
|
|
624
|
+
}
|
package/src/plugins/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export * from './add-error-codes-enum-plugin';
|
|
2
2
|
export * from './annotate-types-with-permissions-plugin';
|
|
3
|
+
export * from './bulk-edit/bulk-edit-async-plugin-factory';
|
|
3
4
|
export * from './deprecate-stray-node-id-fields-plugin';
|
|
4
5
|
export * from './generic-bulk-plugin-factory';
|
|
5
6
|
export * from './graphiql-management-mode-plugin-hook';
|