Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@pothos/plugin-relay

Package Overview
Dependencies
Maintainers
1
Versions
81
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@pothos/plugin-relay - npm Package Compare versions

Comparing version 3.12.1 to 3.13.0

6

CHANGELOG.md
# Change Log
## 3.13.0
### Minor Changes
- 79e69c2b: Add resolveCursorConnection helper for relay plugin
## 3.12.1

@@ -4,0 +10,0 @@

@@ -8,2 +8,14 @@ import { MaybePromise, SchemaTypes } from '@pothos/core';

}
export interface ResolveCursorConnectionOptions<T> {
args: DefaultConnectionArguments;
defaultSize?: number;
maxSize?: number;
toCursor: (value: T) => string;
}
export interface ResolveCursorConnectionArgs {
before?: string;
after?: string;
limit: number;
inverted: boolean;
}
interface ResolveArrayConnectionOptions {

@@ -27,3 +39,5 @@ args: DefaultConnectionArguments;

}, false>;
declare type NodeType<T> = T extends Promise<(infer N)[] | null> | (infer N)[] | null ? N : never;
export declare function resolveCursorConnection<U extends Promise<unknown[] | null> | unknown[] | null>(options: ResolveCursorConnectionOptions<NodeType<U>>, resolve: (params: ResolveCursorConnectionArgs) => U): Promise<ConnectionShape<SchemaTypes, NodeType<U>, false, false, false>>;
export {};
//# sourceMappingURL=connections.d.ts.map

@@ -99,2 +99,61 @@ const OFFSET_CURSOR_PREFIX = "OffsetConnection:";

}
function parseCurserArgs(options) {
const { before, after, first, last } = options.args;
var _defaultSize;
const defaultSize = (_defaultSize = options.defaultSize) !== null && _defaultSize !== void 0 ? _defaultSize : DEFAULT_SIZE;
var _maxSize;
const maxSize = (_maxSize = options.maxSize) !== null && _maxSize !== void 0 ? _maxSize : DEFAULT_MAX_SIZE;
if (first != null && first < 0) {
throw new TypeError("Argument \"first\" must be a non-negative integer");
}
if (last != null && last < 0) {
throw new Error("Argument \"last\" must be a non-negative integer");
}
var ref;
const limit = Math.min((ref = first !== null && first !== void 0 ? first : last) !== null && ref !== void 0 ? ref : defaultSize, maxSize) + 1;
const inverted = after ? !!last && !first : !!before && !first || !first && !!last;
return {
before: before !== null && before !== void 0 ? before : void 0,
after: after !== null && after !== void 0 ? after : void 0,
limit,
expectedSize: limit - 1,
inverted,
hasPreviousPage: (resultSize) => !!after || resultSize >= limit && !first,
hasNextPage: (resultSize) => !!before || !last && resultSize >= limit
};
}
export async function resolveCursorConnection(options, resolve) {
var ref, ref1;
const { before, after, limit, inverted, expectedSize, hasPreviousPage, hasNextPage } = parseCurserArgs(options);
const nodes = await resolve({
before,
after,
limit,
inverted
});
if (!nodes) {
return nodes;
}
const trimmed = nodes.slice(0, expectedSize);
if (inverted) {
trimmed.reverse();
}
const edges = trimmed.map((value) => value == null ? null : {
cursor: options.toCursor(value),
node: value
});
var _after, ref2;
const startCursor = edges.length > 0 ? (ref = edges[0]) === null || ref === void 0 ? void 0 : ref.cursor : (ref2 = (_after = options.args.after) !== null && _after !== void 0 ? _after : options.args.before) !== null && ref2 !== void 0 ? ref2 : "";
var _after1, ref3;
const endCursor = edges.length > 0 ? (ref1 = edges[edges.length - 1]) === null || ref1 === void 0 ? void 0 : ref1.cursor : (ref3 = (_after1 = options.args.after) !== null && _after1 !== void 0 ? _after1 : options.args.before) !== null && ref3 !== void 0 ? ref3 : "";
return {
edges: edges,
pageInfo: {
startCursor,
endCursor,
hasPreviousPage: hasPreviousPage(nodes.length),
hasNextPage: hasNextPage(nodes.length)
}
};
}
//# sourceMappingURL=connections.js.map

@@ -9,2 +9,3 @@ "use strict";

exports.resolveArrayConnection = resolveArrayConnection;
exports.resolveCursorConnection = resolveCursorConnection;
const OFFSET_CURSOR_PREFIX = 'OffsetConnection:';

@@ -108,3 +109,62 @@ const DEFAULT_MAX_SIZE = 100;

}
function parseCurserArgs(options) {
const { before , after , first , last } = options.args;
var _defaultSize;
const defaultSize = (_defaultSize = options.defaultSize) !== null && _defaultSize !== void 0 ? _defaultSize : DEFAULT_SIZE;
var _maxSize;
const maxSize = (_maxSize = options.maxSize) !== null && _maxSize !== void 0 ? _maxSize : DEFAULT_MAX_SIZE;
if (first != null && first < 0) {
throw new TypeError('Argument "first" must be a non-negative integer');
}
if (last != null && last < 0) {
throw new Error('Argument "last" must be a non-negative integer');
}
var ref;
const limit = Math.min((ref = first !== null && first !== void 0 ? first : last) !== null && ref !== void 0 ? ref : defaultSize, maxSize) + 1;
const inverted = after ? !!last && !first : !!before && !first || !first && !!last;
return {
before: before !== null && before !== void 0 ? before : void 0,
after: after !== null && after !== void 0 ? after : void 0,
limit,
expectedSize: limit - 1,
inverted,
hasPreviousPage: (resultSize)=>!!after || resultSize >= limit && !first,
hasNextPage: (resultSize)=>!!before || !last && resultSize >= limit
};
}
async function resolveCursorConnection(options, resolve) {
var ref, ref1;
const { before , after , limit , inverted , expectedSize , hasPreviousPage , hasNextPage } = parseCurserArgs(options);
const nodes = await resolve({
before,
after,
limit,
inverted
});
if (!nodes) {
return nodes;
}
const trimmed = nodes.slice(0, expectedSize);
if (inverted) {
trimmed.reverse();
}
const edges = trimmed.map((value)=>value == null ? null : {
cursor: options.toCursor(value),
node: value
});
var _after, ref2;
const startCursor = edges.length > 0 ? (ref = edges[0]) === null || ref === void 0 ? void 0 : ref.cursor : (ref2 = (_after = options.args.after) !== null && _after !== void 0 ? _after : options.args.before) !== null && ref2 !== void 0 ? ref2 : '';
var _after1, ref3;
const endCursor = edges.length > 0 ? (ref1 = edges[edges.length - 1]) === null || ref1 === void 0 ? void 0 : ref1.cursor : (ref3 = (_after1 = options.args.after) !== null && _after1 !== void 0 ? _after1 : options.args.before) !== null && ref3 !== void 0 ? ref3 : '';
return {
edges: edges,
pageInfo: {
startCursor,
endCursor,
hasPreviousPage: hasPreviousPage(nodes.length),
hasNextPage: hasNextPage(nodes.length)
}
};
}
//# sourceMappingURL=connections.js.map

4

package.json
{
"name": "@pothos/plugin-relay",
"version": "3.12.1",
"version": "3.13.0",
"description": "A Pothos plugin for adding relay style connections, nodes, and cursor based pagination to your GraphQL schema",

@@ -40,3 +40,3 @@ "main": "./lib/index.js",

"devDependencies": {
"@pothos/core": "3.11.1",
"@pothos/core": "3.12.0",
"@pothos/test-utils": "1.2.2",

@@ -43,0 +43,0 @@ "graphql": "16.5.0",

@@ -97,3 +97,3 @@ # Relay Plugin

resolve(parent, args) {
console.log(`Get request for type ${args.id.type} with id ${args.id.typename}`);
console.log(`Get request for type ${args.id.typename} with id ${args.id.id}`);
return true;

@@ -175,19 +175,21 @@ },

resolve: (parent, { first, last, before, after }) => {
return resolveOffsetConnection({ args }, ({ limit, offset }) => {
return {
pageInfo: {
hasNextPage: false,
hasPreviousPage: false,
startCursor: 'abc',
endCursor: 'def',
return {
pageInfo: {
hasNextPage: false,
hasPreviousPage: false,
startCursor: 'abc',
endCursor: 'def',
},
edges: [
{
cursor: 'abc',
node: new NumberThing(123),
},
edges: [
{
cursor: 'xyz',
node: new NumberThing(123),
},
],
};
});
},
{
cursor: 'def',
node: new NumberThing(123),
},
]
}
}),
},

@@ -261,4 +263,38 @@ {

I am planning to add more helpers in the future.
Cursor based pagination can be implemented using the `resolveCursorConnection` method. The following
example uses prisma, but a similar solution should work with any data store that supports limits,
ordering, and filtering.
```typescript
import { resolveCursorConnection, ResolveCursorConnectionArgs } from '@pothos/plugin-relay';
builder.queryField('posts', (t) =>
t.connection({
type: Post,
resolve: (_, args) =>
resolveCursorConnection(
{
args,
toCursor: (post) => post.createdAt.toISOString(),
},
// Manually defining the arg type here is required
// so that typescript can correctly infer the return value
({ before, after, limit, inverted }: ResolveCursorConnectionArgs) =>
prisma.post.findMany({
take: limit,
where: {
createdAt: {
lt: before,
gt: after,
},
},
orderBy: {
createdAt: inverted ? 'desc' : 'asc',
},
}),
),
}),
);
```
### Relay Mutations

@@ -265,0 +301,0 @@

@@ -10,2 +10,16 @@ import { MaybePromise, SchemaTypes } from '@pothos/core';

export interface ResolveCursorConnectionOptions<T> {
args: DefaultConnectionArguments;
defaultSize?: number;
maxSize?: number;
toCursor: (value: T) => string;
}
export interface ResolveCursorConnectionArgs {
before?: string;
after?: string;
limit: number;
inverted: boolean;
}
interface ResolveArrayConnectionOptions {

@@ -166,1 +180,79 @@ args: DefaultConnectionArguments;

}
function parseCurserArgs(options: ResolveOffsetConnectionOptions) {
const { before, after, first, last } = options.args;
const defaultSize = options.defaultSize ?? DEFAULT_SIZE;
const maxSize = options.maxSize ?? DEFAULT_MAX_SIZE;
if (first != null && first < 0) {
throw new TypeError('Argument "first" must be a non-negative integer');
}
if (last != null && last < 0) {
throw new Error('Argument "last" must be a non-negative integer');
}
const limit = Math.min(first ?? last ?? defaultSize, maxSize) + 1;
const inverted = after ? !!last && !first : (!!before && !first) || (!first && !!last);
return {
before: before ?? void 0,
after: after ?? void 0,
limit,
expectedSize: limit - 1,
inverted,
hasPreviousPage: (resultSize: number) => !!after || (resultSize >= limit && !first),
hasNextPage: (resultSize: number) => !!before || (!last && resultSize >= limit),
};
}
type NodeType<T> = T extends Promise<(infer N)[] | null> | (infer N)[] | null ? N : never;
export async function resolveCursorConnection<
U extends Promise<unknown[] | null> | unknown[] | null,
>(
options: ResolveCursorConnectionOptions<NodeType<U>>,
resolve: (params: ResolveCursorConnectionArgs) => U,
): Promise<ConnectionShape<SchemaTypes, NodeType<U>, false, false, false>> {
const { before, after, limit, inverted, expectedSize, hasPreviousPage, hasNextPage } =
parseCurserArgs(options);
const nodes = (await resolve({ before, after, limit, inverted })) as NodeType<U>[] | null;
if (!nodes) {
return nodes as never;
}
const trimmed = nodes.slice(0, expectedSize);
if (inverted) {
trimmed.reverse();
}
const edges = trimmed.map((value) =>
value == null
? null
: {
cursor: options.toCursor(value),
node: value,
},
);
const startCursor =
edges.length > 0 ? edges[0]?.cursor : options.args.after ?? options.args.before ?? '';
const endCursor =
edges.length > 0
? edges[edges.length - 1]?.cursor
: options.args.after ?? options.args.before ?? '';
return {
edges: edges as never,
pageInfo: {
startCursor,
endCursor,
hasPreviousPage: hasPreviousPage(nodes.length),
hasNextPage: hasNextPage(nodes.length),
},
};
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc