Skip to content

Instantly share code, notes, and snippets.

@laughedelic
Last active August 25, 2022 00:15
Show Gist options
  • Save laughedelic/55a288f3780b11d4da3526c23cc5142e to your computer and use it in GitHub Desktop.
Save laughedelic/55a288f3780b11d4da3526c23cc5142e to your computer and use it in GitHub Desktop.

To test it locally:

  1. Set GITHUB_TOKEN env var to your GitHub personall access token
  2. Run with
deno run https://gist.githubusercontent.com/laughedelic/55a288f3780b11d4da3526c23cc5142e/raw/74f03b7e8c56f93b2d6e31895967a7c3a18124f8/paginate-graphql-test.ts

You can get the latest link by clicking Raw button on the paginate-graphql-test.ts file.

import { Octokit } from "https://cdn.skypack.dev/@octokit/core?dts";
import { Kind, parse, visit } from "https://cdn.skypack.dev/graphql?dts";
interface PaginationItem {
location: string;
cursorVariableName: string;
}
const extractPaginatedItems = (query: string): PaginationItem[] => {
const ast = parse(query, { noLocation: true });
const currentPath: string[] = [];
const paginationInfos: PaginationItem[] = [];
visit(ast, {
enter(node, key, parent, path, ancestors) {
if (node.kind === Kind.FIELD) {
currentPath.push(node.name.value);
}
if (
node.kind === Kind.ARGUMENT &&
node.name.value === "after" &&
node.value.kind === Kind.VARIABLE
) {
paginationInfos.push({
location: currentPath.join("."),
cursorVariableName: node.value.name.value,
});
}
},
leave(node) {
if (node.kind === Kind.FIELD) {
currentPath.pop();
}
},
});
return paginationInfos;
};
const getObjectByPosition = (obj: any, positionStr: string) => {
const position = positionStr.split(".");
return position.reduce((current, nextProperty) => current[nextProperty], obj);
};
const paginateComplex = (octokit: Octokit) => {
return async (query: string) => {
// Find Argument with name 'after' and get
// 1. the value.name.value of a type 'Variable'
// 2. the path to the paginated entity (which is either nodes or edges)
const paginationItems = extractPaginatedItems(query);
const { cursorVariableName, location } = paginationItems[0];
let hasNextPage = true;
let nextCursor = undefined;
let allNodes = [];
while (hasNextPage) {
const result = await octokit.graphql(query, {
[cursorVariableName]: nextCursor,
}) as any;
const paginatedEntity = getObjectByPosition(result, location);
const { nodes, pageInfo } = paginatedEntity;
allNodes.push(...nodes);
hasNextPage = pageInfo.hasNextPage;
nextCursor = pageInfo.endCursor;
}
return {
repository: {
issues: allNodes,
},
};
};
};
//////////////////////////////////////////////////////////////////////////////////////////////
const octokit = new Octokit({
auth: Deno.env.get("GITHUB_TOKEN"),
});
const paginate = paginateComplex(octokit);
const result = await paginate(`#graphql
query paginate($cursor1: String) {
repository(owner: "octokit", name: "rest.js") {
issues(first: 10, after: $cursor1) {
pageInfo {
endCursor
hasNextPage
}
nodes {
title
}
}
}
}
`);
console.log(JSON.stringify(result, null, 2));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment