@pothos/plugin-prisma 3.12.1 → 3.13.2
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/CHANGELOG.md +27 -2
- package/README.md +10 -16
- package/dts/field-builder.d.ts.map +1 -1
- package/dts/global-types.d.ts +7 -0
- package/dts/global-types.d.ts.map +1 -1
- package/dts/index.d.ts +4 -2
- package/dts/index.d.ts.map +1 -1
- package/dts/model-loader.d.ts +1 -0
- package/dts/model-loader.d.ts.map +1 -1
- package/dts/prisma-field-builder.d.ts +9 -0
- package/dts/prisma-field-builder.d.ts.map +1 -1
- package/dts/types.d.ts +3 -2
- package/dts/types.d.ts.map +1 -1
- package/dts/util/cursors.d.ts +1 -1
- package/dts/util/cursors.d.ts.map +1 -1
- package/dts/util/datamodel.d.ts.map +1 -1
- package/dts/util/map-query.d.ts +2 -1
- package/dts/util/map-query.d.ts.map +1 -1
- package/esm/field-builder.js +5 -1
- package/esm/field-builder.js.map +1 -1
- package/esm/global-types.js.map +1 -1
- package/esm/index.js +2 -1
- package/esm/index.js.map +1 -1
- package/esm/model-loader.js +30 -0
- package/esm/model-loader.js.map +1 -1
- package/esm/prisma-field-builder.js +53 -26
- package/esm/prisma-field-builder.js.map +1 -1
- package/esm/schema-builder.js +7 -2
- package/esm/schema-builder.js.map +1 -1
- package/esm/types.js.map +1 -1
- package/esm/util/cursors.js.map +1 -1
- package/esm/util/datamodel.js +18 -2
- package/esm/util/datamodel.js.map +1 -1
- package/esm/util/map-query.js +4 -1
- package/esm/util/map-query.js.map +1 -1
- package/lib/field-builder.js +25 -59
- package/lib/field-builder.js.map +1 -1
- package/lib/generator.js +20 -17
- package/lib/generator.js.map +1 -1
- package/lib/index.js +42 -36
- package/lib/index.js.map +1 -1
- package/lib/model-loader.js +46 -13
- package/lib/model-loader.js.map +1 -1
- package/lib/node-ref.js +8 -6
- package/lib/node-ref.js.map +1 -1
- package/lib/object-ref.js +11 -4
- package/lib/object-ref.js.map +1 -1
- package/lib/prisma-field-builder.js +71 -41
- package/lib/prisma-field-builder.js.map +1 -1
- package/lib/schema-builder.js +37 -29
- package/lib/schema-builder.js.map +1 -1
- package/lib/types.js +4 -2
- package/lib/types.js.map +1 -1
- package/lib/util/cursors.js +22 -14
- package/lib/util/cursors.js.map +1 -1
- package/lib/util/datamodel.js +38 -16
- package/lib/util/datamodel.js.map +1 -1
- package/lib/util/deep-equal.js +4 -1
- package/lib/util/deep-equal.js.map +1 -1
- package/lib/util/get-client.js +12 -4
- package/lib/util/get-client.js.map +1 -1
- package/lib/util/loader-map.js +13 -5
- package/lib/util/loader-map.js.map +1 -1
- package/lib/util/map-query.js +39 -28
- package/lib/util/map-query.js.map +1 -1
- package/lib/util/relation-map.js +12 -5
- package/lib/util/relation-map.js.map +1 -1
- package/lib/util/selections.js +17 -9
- package/lib/util/selections.js.map +1 -1
- package/package.json +7 -7
- package/src/field-builder.ts +3 -1
- package/src/global-types.ts +16 -0
- package/src/index.ts +17 -1
- package/src/model-loader.ts +36 -0
- package/src/prisma-field-builder.ts +110 -22
- package/src/schema-builder.ts +11 -5
- package/src/types.ts +6 -3
- package/src/util/cursors.ts +1 -1
- package/src/util/datamodel.ts +21 -3
- package/src/util/map-query.ts +10 -1
- package/tsconfig.type.json +3 -3
- package/tsconfig.type.tsbuildinfo +1 -1
package/src/model-loader.ts
CHANGED
|
@@ -144,6 +144,35 @@ export class ModelLoader {
|
|
|
144
144
|
return result;
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
+
static getCursorSelection<Types extends SchemaTypes>(
|
|
148
|
+
ref: ObjectRef<unknown>,
|
|
149
|
+
modelName: string,
|
|
150
|
+
cursor: string,
|
|
151
|
+
builder: PothosSchemaTypes.SchemaBuilder<Types>,
|
|
152
|
+
): Record<string, boolean> {
|
|
153
|
+
const model = getModel(modelName, builder);
|
|
154
|
+
const field = model.fields.find((field) => field.name === cursor);
|
|
155
|
+
|
|
156
|
+
if (field) {
|
|
157
|
+
return { [field.name]: true };
|
|
158
|
+
}
|
|
159
|
+
const index = [model.primaryKey, ...model.uniqueIndexes]
|
|
160
|
+
.filter(Boolean)
|
|
161
|
+
.find((idx) => (idx!.name ?? idx!.fields.join('_')) === cursor);
|
|
162
|
+
|
|
163
|
+
if (!index) {
|
|
164
|
+
throw new Error(`Can't find "${cursor}" field or index for ${ref.name}`);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const selection: Record<string, boolean> = {};
|
|
168
|
+
|
|
169
|
+
for (const column of index.fields) {
|
|
170
|
+
selection[column] = true;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return selection;
|
|
174
|
+
}
|
|
175
|
+
|
|
147
176
|
static getFindUniqueForField<Types extends SchemaTypes>(
|
|
148
177
|
ref: ObjectRef<unknown>,
|
|
149
178
|
modelName: string,
|
|
@@ -206,6 +235,13 @@ export class ModelLoader {
|
|
|
206
235
|
this.modelName,
|
|
207
236
|
);
|
|
208
237
|
|
|
238
|
+
if (delegate.findUniqueOrThrow) {
|
|
239
|
+
return delegate.findUniqueOrThrow({
|
|
240
|
+
...selectionToQuery(state),
|
|
241
|
+
where: { ...(this.findUnique(this.model, context) as {}) },
|
|
242
|
+
} as never) as Promise<Record<string, unknown>>;
|
|
243
|
+
}
|
|
244
|
+
|
|
209
245
|
return delegate.findUnique({
|
|
210
246
|
rejectOnNotFound: true,
|
|
211
247
|
...selectionToQuery(state),
|
|
@@ -14,12 +14,14 @@ import {
|
|
|
14
14
|
SchemaTypes,
|
|
15
15
|
TypeParam,
|
|
16
16
|
} from '@pothos/core';
|
|
17
|
+
import { ModelLoader } from './model-loader';
|
|
17
18
|
import { PrismaObjectRef } from './object-ref';
|
|
18
19
|
import {
|
|
19
20
|
PrismaModelTypes,
|
|
20
21
|
RelatedConnectionOptions,
|
|
21
22
|
RelatedFieldOptions,
|
|
22
23
|
RelationCountOptions,
|
|
24
|
+
SelectionMap,
|
|
23
25
|
ShapeFromConnection,
|
|
24
26
|
VariantFieldOptions,
|
|
25
27
|
} from './types';
|
|
@@ -43,6 +45,27 @@ const RootBuilder: {
|
|
|
43
45
|
): PothosSchemaTypes.RootFieldBuilder<Types, Shape, Kind>;
|
|
44
46
|
} = RootFieldBuilder as never;
|
|
45
47
|
|
|
48
|
+
type ContextForAuth<
|
|
49
|
+
Types extends SchemaTypes,
|
|
50
|
+
Scopes extends {} = {},
|
|
51
|
+
> = PothosSchemaTypes.ScopeAuthContextForAuth<Types, Scopes> extends {
|
|
52
|
+
Context: infer T;
|
|
53
|
+
}
|
|
54
|
+
? T extends object
|
|
55
|
+
? T
|
|
56
|
+
: object
|
|
57
|
+
: object;
|
|
58
|
+
|
|
59
|
+
type FieldAuthScopes<
|
|
60
|
+
Types extends SchemaTypes,
|
|
61
|
+
Parent,
|
|
62
|
+
Args extends {} = {},
|
|
63
|
+
> = PothosSchemaTypes.ScopeAuthFieldAuthScopes<Types, Parent, Args> extends {
|
|
64
|
+
Scopes: infer T;
|
|
65
|
+
}
|
|
66
|
+
? T
|
|
67
|
+
: never;
|
|
68
|
+
|
|
46
69
|
export class PrismaObjectFieldBuilder<
|
|
47
70
|
Types extends SchemaTypes,
|
|
48
71
|
Model extends PrismaModelTypes,
|
|
@@ -63,6 +86,17 @@ export class PrismaObjectFieldBuilder<
|
|
|
63
86
|
exposeIDList = this.createExpose(['ID']);
|
|
64
87
|
exposeStringList = this.createExpose(['String']);
|
|
65
88
|
|
|
89
|
+
withAuth: 'scopeAuth' extends PluginName
|
|
90
|
+
? <Scopes extends FieldAuthScopes<Types, Shape, Record<string, unknown>>>(
|
|
91
|
+
scopes: Scopes,
|
|
92
|
+
) => PothosSchemaTypes.PrismaObjectFieldBuilder<
|
|
93
|
+
Omit<Types, 'Context'> & { Context: ContextForAuth<Types, Scopes> },
|
|
94
|
+
Model,
|
|
95
|
+
NeedsResolve,
|
|
96
|
+
Shape
|
|
97
|
+
>
|
|
98
|
+
: '@pothos/plugin-scope-auth is required to use this method' = (() => {}) as never;
|
|
99
|
+
|
|
66
100
|
relatedConnection: 'relay' extends PluginName
|
|
67
101
|
? <
|
|
68
102
|
Field extends Model['ListRelations'],
|
|
@@ -133,35 +167,53 @@ export class PrismaObjectFieldBuilder<
|
|
|
133
167
|
args,
|
|
134
168
|
}),
|
|
135
169
|
});
|
|
170
|
+
const cursorSelection = ModelLoader.getCursorSelection(
|
|
171
|
+
ref,
|
|
172
|
+
relationField.type,
|
|
173
|
+
cursor,
|
|
174
|
+
this.builder,
|
|
175
|
+
);
|
|
136
176
|
|
|
137
177
|
const relationSelect = (
|
|
138
178
|
args: object,
|
|
139
179
|
context: object,
|
|
140
180
|
nestedQuery: (query: unknown, path: unknown) => unknown,
|
|
141
|
-
) =>
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
{
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
181
|
+
) => {
|
|
182
|
+
const nested = nestedQuery(
|
|
183
|
+
{
|
|
184
|
+
...((typeof query === 'function' ? query(args, context) : query) as {}),
|
|
185
|
+
...prismaCursorConnectionQuery({
|
|
186
|
+
parseCursor,
|
|
187
|
+
maxSize,
|
|
188
|
+
defaultSize,
|
|
189
|
+
args,
|
|
190
|
+
}),
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
getType: () => {
|
|
194
|
+
if (!typeName) {
|
|
195
|
+
typeName = this.builder.configStore.getTypeConfig(ref).name;
|
|
196
|
+
}
|
|
197
|
+
return typeName;
|
|
152
198
|
},
|
|
153
|
-
{
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
199
|
+
path: [{ name: 'edges' }, { name: 'node' }],
|
|
200
|
+
},
|
|
201
|
+
) as SelectionMap;
|
|
202
|
+
|
|
203
|
+
return {
|
|
204
|
+
select: {
|
|
205
|
+
[name]: nested?.select
|
|
206
|
+
? {
|
|
207
|
+
...nested,
|
|
208
|
+
select: {
|
|
209
|
+
...cursorSelection,
|
|
210
|
+
...nested.select,
|
|
211
|
+
},
|
|
157
212
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
),
|
|
163
|
-
},
|
|
164
|
-
});
|
|
213
|
+
: nested,
|
|
214
|
+
},
|
|
215
|
+
};
|
|
216
|
+
};
|
|
165
217
|
|
|
166
218
|
const fieldRef = (
|
|
167
219
|
this as unknown as {
|
|
@@ -448,3 +500,39 @@ export class PrismaObjectFieldBuilder<
|
|
|
448
500
|
};
|
|
449
501
|
}
|
|
450
502
|
}
|
|
503
|
+
|
|
504
|
+
const prismaFieldBuilderProto = PrismaObjectFieldBuilder.prototype as {} as Omit<
|
|
505
|
+
PrismaObjectFieldBuilder<SchemaTypes, PrismaModelTypes, false, {}>,
|
|
506
|
+
'withAuth'
|
|
507
|
+
> & {
|
|
508
|
+
withAuth: (scopes: {}) => unknown;
|
|
509
|
+
};
|
|
510
|
+
|
|
511
|
+
prismaFieldBuilderProto.withAuth = function withAuth(scopes) {
|
|
512
|
+
return addScopes(
|
|
513
|
+
scopes,
|
|
514
|
+
new PrismaObjectFieldBuilder(
|
|
515
|
+
this.typename,
|
|
516
|
+
this.builder,
|
|
517
|
+
this.model,
|
|
518
|
+
this.prismaFieldMap,
|
|
519
|
+
) as never,
|
|
520
|
+
);
|
|
521
|
+
};
|
|
522
|
+
|
|
523
|
+
function addScopes(
|
|
524
|
+
scopes: unknown,
|
|
525
|
+
builder: { createField: (options: Record<string, unknown>) => unknown },
|
|
526
|
+
) {
|
|
527
|
+
const originalCreateField = builder.createField;
|
|
528
|
+
|
|
529
|
+
// eslint-disable-next-line no-param-reassign
|
|
530
|
+
builder.createField = function createField(options) {
|
|
531
|
+
return originalCreateField.call(this, {
|
|
532
|
+
authScopes: scopes,
|
|
533
|
+
...options,
|
|
534
|
+
});
|
|
535
|
+
};
|
|
536
|
+
|
|
537
|
+
return builder as never;
|
|
538
|
+
}
|
package/src/schema-builder.ts
CHANGED
|
@@ -97,11 +97,17 @@ schemaBuilderProto.prismaNode = function prismaNode(
|
|
|
97
97
|
) => {
|
|
98
98
|
const query = queryFromInfo(context, info, typeName);
|
|
99
99
|
const delegate = getDelegateFromModel(getClient(this, context), type);
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
100
|
+
|
|
101
|
+
const record = await (delegate.findUniqueOrThrow
|
|
102
|
+
? delegate.findUniqueOrThrow({
|
|
103
|
+
...query,
|
|
104
|
+
where: rawFindUnique ? rawFindUnique(id, context) : { [fieldName]: idParser!(id) },
|
|
105
|
+
} as never)
|
|
106
|
+
: delegate.findUnique({
|
|
107
|
+
...query,
|
|
108
|
+
rejectOnNotFound: true,
|
|
109
|
+
where: rawFindUnique ? rawFindUnique(id, context) : { [fieldName]: idParser!(id) },
|
|
110
|
+
} as never));
|
|
105
111
|
|
|
106
112
|
brandWithType(record, typeName as OutputType<SchemaTypes>);
|
|
107
113
|
|
package/src/types.ts
CHANGED
|
@@ -24,6 +24,7 @@ import { PrismaObjectFieldBuilder } from './field-builder';
|
|
|
24
24
|
import { PrismaObjectRef } from './object-ref';
|
|
25
25
|
|
|
26
26
|
export interface PrismaDelegate {
|
|
27
|
+
findUniqueOrThrow?: (...args: any[]) => Promise<unknown>;
|
|
27
28
|
findUnique: (...args: any[]) => Promise<unknown>;
|
|
28
29
|
}
|
|
29
30
|
|
|
@@ -473,7 +474,8 @@ export type PrismaConnectionFieldOptions<
|
|
|
473
474
|
ParentShape,
|
|
474
475
|
Param,
|
|
475
476
|
Nullable,
|
|
476
|
-
Args &
|
|
477
|
+
(InputFieldMap extends Args ? {} : Args) &
|
|
478
|
+
InputFieldsFromShape<PothosSchemaTypes.DefaultConnectionArguments>,
|
|
477
479
|
Kind,
|
|
478
480
|
ParentShape,
|
|
479
481
|
ResolveReturnShape
|
|
@@ -517,10 +519,11 @@ export type RelatedConnectionOptions<
|
|
|
517
519
|
Model['Shape'],
|
|
518
520
|
ObjectRef<unknown>,
|
|
519
521
|
Nullable,
|
|
520
|
-
Args
|
|
522
|
+
(InputFieldMap extends Args ? {} : Args) &
|
|
523
|
+
InputFieldsFromShape<PothosSchemaTypes.DefaultConnectionArguments>,
|
|
521
524
|
unknown
|
|
522
525
|
>,
|
|
523
|
-
'resolve' | 'type'
|
|
526
|
+
'resolve' | 'type' | 'args'
|
|
524
527
|
> &
|
|
525
528
|
Omit<
|
|
526
529
|
PothosSchemaTypes.ConnectionFieldOptions<
|
package/src/util/cursors.ts
CHANGED
|
@@ -174,7 +174,7 @@ export function serializeID(id: unknown, dataType: string) {
|
|
|
174
174
|
}
|
|
175
175
|
|
|
176
176
|
export function parseCompositeCursor(fields: string[]) {
|
|
177
|
-
return (cursor:
|
|
177
|
+
return (cursor: unknown) => {
|
|
178
178
|
const parsed = parseRawCursor(cursor) as unknown[];
|
|
179
179
|
|
|
180
180
|
if (!Array.isArray(parsed)) {
|
package/src/util/datamodel.ts
CHANGED
|
@@ -72,8 +72,15 @@ export function getCursorFormatter<Types extends SchemaTypes>(
|
|
|
72
72
|
) {
|
|
73
73
|
const modelData = getModel(name, builder);
|
|
74
74
|
const primaryKey = modelData.primaryKey?.name ?? modelData.primaryKey?.fields.join('_');
|
|
75
|
+
if (primaryKey === cursor) {
|
|
76
|
+
return formatCursor(modelData.primaryKey!.fields);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const uniqueIndex = modelData.uniqueIndexes.find(
|
|
80
|
+
(idx) => (idx.name ?? idx.fields.join('_')) === cursor,
|
|
81
|
+
);
|
|
75
82
|
|
|
76
|
-
return formatCursor(
|
|
83
|
+
return formatCursor(uniqueIndex?.fields ?? cursor);
|
|
77
84
|
}
|
|
78
85
|
|
|
79
86
|
export function getCursorParser<Types extends SchemaTypes>(
|
|
@@ -84,8 +91,19 @@ export function getCursorParser<Types extends SchemaTypes>(
|
|
|
84
91
|
const modelData = getModel(name, builder);
|
|
85
92
|
const primaryKey = modelData.primaryKey?.name ?? modelData.primaryKey?.fields.join('_');
|
|
86
93
|
|
|
87
|
-
|
|
88
|
-
|
|
94
|
+
let parser = parseRawCursor;
|
|
95
|
+
|
|
96
|
+
if (primaryKey === cursor) {
|
|
97
|
+
parser = parseCompositeCursor(modelData.primaryKey!.fields);
|
|
98
|
+
} else {
|
|
99
|
+
const uniqueIndex = modelData.uniqueIndexes.find(
|
|
100
|
+
(idx) => (idx.name ?? idx.fields.join('_')) === cursor,
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
if (uniqueIndex) {
|
|
104
|
+
parser = parseCompositeCursor(uniqueIndex.fields);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
89
107
|
|
|
90
108
|
return (rawCursor: string) => ({
|
|
91
109
|
[cursor]: parser(rawCursor),
|
package/src/util/map-query.ts
CHANGED
|
@@ -306,10 +306,19 @@ function addFieldSelection(
|
|
|
306
306
|
}
|
|
307
307
|
}
|
|
308
308
|
|
|
309
|
-
export function queryFromInfo(
|
|
309
|
+
export function queryFromInfo(
|
|
310
|
+
context: object,
|
|
311
|
+
info: GraphQLResolveInfo,
|
|
312
|
+
typeName?: string,
|
|
313
|
+
initialSelection?: SelectionMap,
|
|
314
|
+
): {} {
|
|
310
315
|
const type = typeName ? info.schema.getTypeMap()[typeName] : getNamedType(info.returnType);
|
|
311
316
|
const state = createStateForType(type, info);
|
|
312
317
|
|
|
318
|
+
if (initialSelection) {
|
|
319
|
+
mergeSelection(state, initialSelection);
|
|
320
|
+
}
|
|
321
|
+
|
|
313
322
|
addTypeSelectionsForField(type, context, info, state, info.fieldNodes[0], []);
|
|
314
323
|
|
|
315
324
|
setLoaderMappings(context, info, state.mappings);
|