@pothos/plugin-prisma 3.21.1 → 3.23.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/src/types.ts CHANGED
@@ -495,30 +495,34 @@ export type PrismaConnectionFieldOptions<
495
495
  ResolveReturnShape
496
496
  >,
497
497
  'args' | 'resolve' | 'type'
498
- > & {
499
- type: Type;
500
- cursor: string & keyof Model['Where'];
501
- defaultSize?: number;
502
- maxSize?: number;
503
- resolve: (
504
- query: {
505
- include?: Model['Include'];
506
- cursor?: {};
507
- take: number;
508
- skip: number;
509
- },
510
- parent: ParentShape,
511
- args: InputShapeFromFields<Args> & PothosSchemaTypes.DefaultConnectionArguments,
512
- context: Types['Context'],
513
- info: GraphQLResolveInfo,
514
- ) => MaybePromise<Model['Shape'][]>;
515
- totalCount?: (
516
- parent: ParentShape,
517
- args: InputShapeFromFields<Args> & PothosSchemaTypes.DefaultConnectionArguments,
518
- context: Types['Context'],
519
- info: GraphQLResolveInfo,
520
- ) => MaybePromise<number>;
521
- };
498
+ > &
499
+ (InputShapeFromFields<Args> &
500
+ PothosSchemaTypes.DefaultConnectionArguments extends infer ConnectionArgs
501
+ ? {
502
+ type: Type;
503
+ cursor: string & keyof Model['Where'];
504
+ defaultSize?: number | ((args: ConnectionArgs, ctx: Types['Context']) => number);
505
+ maxSize?: number | ((args: ConnectionArgs, ctx: Types['Context']) => number);
506
+ resolve: (
507
+ query: {
508
+ include?: Model['Include'];
509
+ cursor?: {};
510
+ take: number;
511
+ skip: number;
512
+ },
513
+ parent: ParentShape,
514
+ args: ConnectionArgs,
515
+ context: Types['Context'],
516
+ info: GraphQLResolveInfo,
517
+ ) => MaybePromise<Model['Shape'][]>;
518
+ totalCount?: (
519
+ parent: ParentShape,
520
+ args: ConnectionArgs,
521
+ context: Types['Context'],
522
+ info: GraphQLResolveInfo,
523
+ ) => MaybePromise<number>;
524
+ }
525
+ : never);
522
526
 
523
527
  export type RelatedConnectionOptions<
524
528
  Types extends SchemaTypes,
@@ -551,43 +555,47 @@ export type RelatedConnectionOptions<
551
555
  unknown
552
556
  >,
553
557
  'resolve' | 'type'
554
- > & {
555
- description?: string | false;
556
- query?: QueryForField<Types, Args, Model['Include'][Field & keyof Model['Include']]>;
557
- type?: PrismaObjectRef<Model['Relations'][Field]['Types']>;
558
- cursor: CursorFromRelation<Model, Field>;
559
- defaultSize?: number;
560
- maxSize?: number;
561
- totalCount?: NeedsResolve extends false ? boolean : false;
562
- } & (NeedsResolve extends false
558
+ > &
559
+ (InputShapeFromFields<Args> &
560
+ PothosSchemaTypes.DefaultConnectionArguments extends infer ConnectionArgs
563
561
  ? {
564
- resolve?: (
565
- query: {
566
- include?: Model['Include'];
567
- cursor?: {};
568
- take: number;
569
- skip: number;
570
- },
571
- parent: Model['Shape'],
572
- args: InputShapeFromFields<Args>,
573
- context: Types['Context'],
574
- info: GraphQLResolveInfo,
575
- ) => MaybePromise<Model['Relations'][Field & keyof Model['Relations']]['Shape']>;
576
- }
577
- : {
578
- resolve: (
579
- query: {
580
- include?: Model['Include'];
581
- cursor?: {};
582
- take: number;
583
- skip: number;
584
- },
585
- parent: Model['Shape'],
586
- args: InputShapeFromFields<Args>,
587
- context: Types['Context'],
588
- info: GraphQLResolveInfo,
589
- ) => MaybePromise<Model['Relations'][Field & keyof Model['Relations']]['Shape']>;
590
- });
562
+ description?: string | false;
563
+ query?: QueryForField<Types, Args, Model['Include'][Field & keyof Model['Include']]>;
564
+ type?: PrismaObjectRef<Model['Relations'][Field]['Types']>;
565
+ cursor: CursorFromRelation<Model, Field>;
566
+ defaultSize?: number | ((args: ConnectionArgs, ctx: Types['Context']) => number);
567
+ maxSize?: number | ((args: ConnectionArgs, ctx: Types['Context']) => number);
568
+ totalCount?: NeedsResolve extends false ? boolean : false;
569
+ } & (NeedsResolve extends false
570
+ ? {
571
+ resolve?: (
572
+ query: {
573
+ include?: Model['Include'];
574
+ cursor?: {};
575
+ take: number;
576
+ skip: number;
577
+ },
578
+ parent: Model['Shape'],
579
+ args: ConnectionArgs,
580
+ context: Types['Context'],
581
+ info: GraphQLResolveInfo,
582
+ ) => MaybePromise<Model['Relations'][Field & keyof Model['Relations']]['Shape']>;
583
+ }
584
+ : {
585
+ resolve: (
586
+ query: {
587
+ include?: Model['Include'];
588
+ cursor?: {};
589
+ take: number;
590
+ skip: number;
591
+ },
592
+ parent: Model['Shape'],
593
+ args: ConnectionArgs,
594
+ context: Types['Context'],
595
+ info: GraphQLResolveInfo,
596
+ ) => MaybePromise<Model['Relations'][Field & keyof Model['Relations']]['Shape']>;
597
+ })
598
+ : never);
591
599
 
592
600
  export type WithBrand<T> = T & { [typeBrandKey]: string };
593
601
 
@@ -1,6 +1,5 @@
1
1
  /* eslint-disable no-nested-ternary */
2
- import { MaybePromise, SchemaTypes } from '@pothos/core';
3
- // eslint-disable-next-line import/no-cycle
2
+ import { decodeBase64, encodeBase64, MaybePromise, SchemaTypes } from '@pothos/core';
4
3
  import { getModel } from './datamodel';
5
4
  import { DMMFField } from './get-client';
6
5
 
@@ -27,12 +26,10 @@ export function formatCursorChunk(value: unknown) {
27
26
  export function formatCursor(fields: string | string[]) {
28
27
  return (value: Record<string, unknown>) => {
29
28
  if (typeof fields === 'string') {
30
- return Buffer.from(`GPC:${formatCursorChunk(value[fields])}`).toString('base64');
29
+ return encodeBase64(`GPC:${formatCursorChunk(value[fields])}`);
31
30
  }
32
31
 
33
- return Buffer.from(`GPC:J:${JSON.stringify(fields.map((name) => value[name]))}`).toString(
34
- 'base64',
35
- );
32
+ return encodeBase64(`GPC:J:${JSON.stringify(fields.map((name) => value[name]))}`);
36
33
  };
37
34
  }
38
35
 
@@ -42,7 +39,7 @@ export function parseRawCursor(cursor: unknown) {
42
39
  }
43
40
 
44
41
  try {
45
- const decoded = Buffer.from(cursor, 'base64').toString();
42
+ const decoded = decodeBase64(cursor);
46
43
  const [, type, value] = decoded.match(/^GPC:(\w):(.*)/) as [string, string, string];
47
44
 
48
45
  switch (type) {
@@ -199,8 +196,9 @@ export function parseCompositeCursor(fields: string[]) {
199
196
 
200
197
  export interface PrismaCursorConnectionQueryOptions {
201
198
  args: PothosSchemaTypes.DefaultConnectionArguments;
202
- defaultSize?: number;
203
- maxSize?: number;
199
+ ctx: {};
200
+ defaultSize?: number | ((args: {}, ctx: {}) => number);
201
+ maxSize?: number | ((args: {}, ctx: {}) => number);
204
202
  parseCursor: (cursor: string) => Record<string, unknown>;
205
203
  }
206
204
 
@@ -210,11 +208,13 @@ interface ResolvePrismaCursorConnectionOptions extends PrismaCursorConnectionQue
210
208
  }
211
209
 
212
210
  export function prismaCursorConnectionQuery({
213
- args: { before, after, first, last },
211
+ args,
212
+ ctx,
214
213
  maxSize = DEFAULT_MAX_SIZE,
215
214
  defaultSize = DEFAULT_SIZE,
216
215
  parseCursor,
217
216
  }: PrismaCursorConnectionQueryOptions) {
217
+ const { before, after, first, last } = args;
218
218
  if (first != null && first < 0) {
219
219
  throw new TypeError('Argument "first" must be a non-negative integer');
220
220
  }
@@ -227,10 +227,6 @@ export function prismaCursorConnectionQuery({
227
227
  throw new Error('Arguments "before" and "after" are not supported at the same time');
228
228
  }
229
229
 
230
- if (before != null && last == null) {
231
- throw new Error('Argument "last" must be provided when using "before"');
232
- }
233
-
234
230
  if (before != null && first != null) {
235
231
  throw new Error('Arguments "before" and "first" are not supported at the same time');
236
232
  }
@@ -241,7 +237,11 @@ export function prismaCursorConnectionQuery({
241
237
 
242
238
  const cursor = before ?? after;
243
239
 
244
- let take = Math.min(first ?? last ?? defaultSize, maxSize) + 1;
240
+ const maxSizeForConnection = typeof maxSize === 'function' ? maxSize(args, ctx) : maxSize;
241
+ const defaultSizeForConnection =
242
+ typeof defaultSize === 'function' ? defaultSize(args, ctx) : defaultSize;
243
+
244
+ let take = Math.min(first ?? last ?? defaultSizeForConnection, maxSizeForConnection) + 1;
245
245
 
246
246
  if (before) {
247
247
  take = -take;
@@ -304,3 +304,48 @@ export async function resolvePrismaCursorConnection<T extends {}>(
304
304
 
305
305
  return wrapConnectionResult(results, options.args, query.take, cursor, options.totalCount);
306
306
  }
307
+
308
+ export function getCursorFormatter<Types extends SchemaTypes>(
309
+ name: string,
310
+ builder: PothosSchemaTypes.SchemaBuilder<Types>,
311
+ cursor: string,
312
+ ) {
313
+ const modelData = getModel(name, builder);
314
+ const primaryKey = modelData.primaryKey?.name ?? modelData.primaryKey?.fields.join('_');
315
+ if (primaryKey === cursor) {
316
+ return formatCursor(modelData.primaryKey!.fields);
317
+ }
318
+
319
+ const uniqueIndex = modelData.uniqueIndexes.find(
320
+ (idx) => (idx.name ?? idx.fields.join('_')) === cursor,
321
+ );
322
+
323
+ return formatCursor(uniqueIndex?.fields ?? cursor);
324
+ }
325
+
326
+ export function getCursorParser<Types extends SchemaTypes>(
327
+ name: string,
328
+ builder: PothosSchemaTypes.SchemaBuilder<Types>,
329
+ cursor: string,
330
+ ) {
331
+ const modelData = getModel(name, builder);
332
+ const primaryKey = modelData.primaryKey?.name ?? modelData.primaryKey?.fields.join('_');
333
+
334
+ let parser = parseRawCursor;
335
+
336
+ if (primaryKey === cursor) {
337
+ parser = parseCompositeCursor(modelData.primaryKey!.fields);
338
+ } else {
339
+ const uniqueIndex = modelData.uniqueIndexes.find(
340
+ (idx) => (idx.name ?? idx.fields.join('_')) === cursor,
341
+ );
342
+
343
+ if (uniqueIndex) {
344
+ parser = parseCompositeCursor(uniqueIndex.fields);
345
+ }
346
+ }
347
+
348
+ return (rawCursor: string) => ({
349
+ [cursor]: parser(rawCursor),
350
+ });
351
+ }
@@ -1,8 +1,6 @@
1
1
  import { ObjectRef, SchemaTypes } from '@pothos/core';
2
2
  import { PrismaObjectRef } from '../object-ref';
3
3
  import { PrismaClient, PrismaDelegate, PrismaModelTypes } from '../types';
4
- // eslint-disable-next-line import/no-cycle
5
- import { formatCursor, parseCompositeCursor, parseRawCursor } from './cursors';
6
4
  import { getDMMF } from './get-client';
7
5
 
8
6
  export const refMap = new WeakMap<object, Map<string, PrismaObjectRef<PrismaModelTypes>>>();
@@ -76,51 +74,6 @@ export function getModel<Types extends SchemaTypes>(
76
74
  return modelData;
77
75
  }
78
76
 
79
- export function getCursorFormatter<Types extends SchemaTypes>(
80
- name: string,
81
- builder: PothosSchemaTypes.SchemaBuilder<Types>,
82
- cursor: string,
83
- ) {
84
- const modelData = getModel(name, builder);
85
- const primaryKey = modelData.primaryKey?.name ?? modelData.primaryKey?.fields.join('_');
86
- if (primaryKey === cursor) {
87
- return formatCursor(modelData.primaryKey!.fields);
88
- }
89
-
90
- const uniqueIndex = modelData.uniqueIndexes.find(
91
- (idx) => (idx.name ?? idx.fields.join('_')) === cursor,
92
- );
93
-
94
- return formatCursor(uniqueIndex?.fields ?? cursor);
95
- }
96
-
97
- export function getCursorParser<Types extends SchemaTypes>(
98
- name: string,
99
- builder: PothosSchemaTypes.SchemaBuilder<Types>,
100
- cursor: string,
101
- ) {
102
- const modelData = getModel(name, builder);
103
- const primaryKey = modelData.primaryKey?.name ?? modelData.primaryKey?.fields.join('_');
104
-
105
- let parser = parseRawCursor;
106
-
107
- if (primaryKey === cursor) {
108
- parser = parseCompositeCursor(modelData.primaryKey!.fields);
109
- } else {
110
- const uniqueIndex = modelData.uniqueIndexes.find(
111
- (idx) => (idx.name ?? idx.fields.join('_')) === cursor,
112
- );
113
-
114
- if (uniqueIndex) {
115
- parser = parseCompositeCursor(uniqueIndex.fields);
116
- }
117
- }
118
-
119
- return (rawCursor: string) => ({
120
- [cursor]: parser(rawCursor),
121
- });
122
- }
123
-
124
77
  export function getDelegateFromModel(client: PrismaClient, model: string) {
125
78
  const lowerCase = `${model.slice(0, 1).toLowerCase()}${model.slice(1)}`;
126
79