@graphprotocol/client-auto-pagination
Version:
`graph-client` implements automatic pagination using `first:` and `after:` filters of `graph-node`.
145 lines (144 loc) • 7.25 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.transformExecutionResponse = exports.transformExecutionRequest = exports.DEFAULT_OPTIONS = void 0;
const graphql_1 = require("graphql");
exports.DEFAULT_OPTIONS = {
limitOfRecords: 1000,
firstArgumentName: 'first',
skipArgumentName: 'skip',
lastIdArgumentName: 'where.id_gte',
skipArgumentLimit: 5000,
};
function transformExecutionRequest(executionRequest, options, delegationContext) {
const document = (0, graphql_1.visit)(executionRequest.document, {
SelectionSet: {
leave: (selectionSet) => {
const newSelections = [];
for (const selectionNode of selectionSet.selections) {
if (selectionNode.kind === graphql_1.Kind.FIELD &&
!selectionNode.name.value.startsWith('_') &&
!selectionNode.arguments?.some((argNode) => argNode.name.value === 'id')) {
const existingArgs = [];
let firstArg;
let skipArg;
for (const existingArg of selectionNode.arguments ?? []) {
if (existingArg.name.value === options.firstArgumentName) {
firstArg = existingArg;
}
else if (existingArg.name.value === options.skipArgumentName) {
skipArg = existingArg;
}
else {
existingArgs.push(existingArg);
}
}
if (firstArg != null) {
let numberOfTotalRecords;
if (firstArg.value.kind === graphql_1.Kind.INT) {
numberOfTotalRecords = parseInt(firstArg.value.value);
}
else if (firstArg.value.kind === graphql_1.Kind.VARIABLE) {
numberOfTotalRecords = executionRequest.variables?.[firstArg.value.name.value];
delete executionRequest.variables?.[firstArg.value.name.value];
}
if (numberOfTotalRecords != null && numberOfTotalRecords > options.limitOfRecords) {
const fieldName = selectionNode.name.value;
const aliasName = selectionNode.alias?.value || fieldName;
let initialSkip = 0;
if (skipArg?.value?.kind === graphql_1.Kind.INT) {
initialSkip = parseInt(skipArg.value.value);
}
else if (skipArg?.value?.kind === graphql_1.Kind.VARIABLE) {
initialSkip = executionRequest.variables?.[skipArg.value.name.value];
delete executionRequest.variables?.[skipArg.value.name.value];
}
let skip;
for (skip = initialSkip; numberOfTotalRecords - skip + initialSkip > 0; skip += options.limitOfRecords) {
newSelections.push({
...selectionNode,
alias: {
kind: graphql_1.Kind.NAME,
value: `splitted_${skip}_${aliasName}`,
},
arguments: [
...existingArgs,
{
kind: graphql_1.Kind.ARGUMENT,
name: {
kind: graphql_1.Kind.NAME,
value: options.firstArgumentName,
},
value: {
kind: graphql_1.Kind.INT,
value: Math.min(numberOfTotalRecords - skip + initialSkip, options.limitOfRecords).toString(),
},
},
{
kind: graphql_1.Kind.ARGUMENT,
name: {
kind: graphql_1.Kind.NAME,
value: options.skipArgumentName,
},
value: {
kind: graphql_1.Kind.INT,
value: skip.toString(),
},
},
],
});
}
continue;
}
}
}
newSelections.push(selectionNode);
}
return {
...selectionSet,
selections: newSelections,
};
},
},
});
if (delegationContext) {
delete delegationContext.args;
}
return {
...executionRequest,
document,
};
}
exports.transformExecutionRequest = transformExecutionRequest;
function transformExecutionResponse(originalResult) {
if (originalResult.data != null) {
return {
...originalResult,
data: mergeSplittedResults(originalResult.data),
};
}
return originalResult;
}
exports.transformExecutionResponse = transformExecutionResponse;
function mergeSplittedResults(originalData) {
if (originalData != null && typeof originalData === 'object') {
if (Array.isArray(originalData)) {
return originalData.map((record) => mergeSplittedResults(record));
}
const finalData = {};
for (const fullAliasName in originalData) {
if (fullAliasName.startsWith('splitted_')) {
const [, , ...rest] = fullAliasName.split('_');
const aliasName = rest.join('_');
finalData[aliasName] = finalData[aliasName] || [];
for (const record of originalData[fullAliasName]) {
finalData[aliasName].push(mergeSplittedResults(record));
}
}
else {
finalData[fullAliasName] = mergeSplittedResults(originalData[fullAliasName]);
}
}
return finalData;
}
return originalData;
}
;