nestjs-graphql-relay
Version:
@nestjs/graphql + graphql-relay + typeorm
93 lines (79 loc) • 2.33 kB
text/typescript
import * as Relay from "graphql-relay";
import { FindManyOptions, ObjectLiteral, Repository } from "typeorm";
import { ConnectionArgs } from "./connectionArgs";
export * from "./orderBy.input";
export * from "./pageInfo";
export { ConnectionArgs };
type PagingMeta =
| { pagingType: "forward"; after?: string; first: number }
| { pagingType: "backward"; before?: string; last: number }
| { pagingType: "none" };
function getMeta({
first = 0,
last = 0,
after,
before,
}: ConnectionArgs): PagingMeta {
const isForwardPaging = !!first || !!after;
const isBackwardPaging = !!last || !!before;
return isForwardPaging
? { pagingType: "forward", after, first }
: isBackwardPaging
? { pagingType: "backward", before, last }
: { pagingType: "none" };
}
/*
* Create a 'paging parameters' object with 'limit' and 'offset' fields based on the incoming
* cursor-paging arguments.
*/
export function getPagingParameters(args: ConnectionArgs) {
const meta = getMeta(args);
switch (meta.pagingType) {
case "forward": {
let offset = 0;
if (meta.after) {
offset = Relay.cursorToOffset(meta.after) + 1;
}
if (Number.isNaN(offset)) {
throw new Error("invalid before query");
}
return {
limit: meta.first,
offset,
};
}
case "backward": {
const { last, before } = meta;
let limit = last;
let offset = Relay.cursorToOffset(before || "") - last;
if (Number.isNaN(offset)) {
throw new Error("invalid before query");
}
// Check to see if our before-page is underflowing past the 0th item
if (offset < 0) {
// Adjust the limit with the underflow value
limit = Math.max(last + offset, 0);
offset = 0;
}
return { offset, limit };
}
default:
return {};
}
}
export async function findAndPaginate<T extends ObjectLiteral>(
condition: FindManyOptions<T>,
connArgs: ConnectionArgs,
repository: Repository<T>,
) {
const { limit, offset } = getPagingParameters(connArgs);
const [entities, count] = await repository.findAndCount({
...condition,
skip: offset,
take: limit,
});
return Relay.connectionFromArraySlice(entities, connArgs, {
arrayLength: count,
sliceStart: offset || 0,
});
}