Skip to content

Commit 45879c5

Browse files
committed
Easier context binding with instantiation expressions
1 parent b651f33 commit 45879c5

File tree

11 files changed

+750
-204
lines changed

11 files changed

+750
-204
lines changed

.changeset/purple-beers-mate.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
---
2+
"@graphql-ts/schema": major
3+
---
4+
5+
The `g` export exported from `@graphql-ts/schema` directly is now deprecated. Using `initG` is now the recommended way to use `@graphql-ts/schema` instead of the instance of `g` exported by `@graphql-ts/schema` or creating multiple files to setup `g` though using those is still possible.
6+
7+
```ts
8+
import { GraphQLSchema } from "graphql";
9+
import { initG } from "@graphql-ts/schema";
10+
11+
type Context = {
12+
something: string;
13+
};
14+
15+
const g = initG<Context>();
16+
type g<T> = initG<T>;
17+
18+
const Query = g.object()({
19+
name: "Query",
20+
fields: {
21+
something: g.field({
22+
type: g.String,
23+
resolve(_, __, context) {
24+
return context.something;
25+
},
26+
}),
27+
},
28+
});
29+
30+
const schema = new GraphQLSchema({
31+
query: Query,
32+
});
33+
```
34+
35+
All types available at `g.*` like `g.ObjectType<Source>` can written instead like `g<typeof g.object<Source>>`/`GObjectType<Source, Context>` instead of being accessible directly on `g`.

packages/schema/README.md

Lines changed: 62 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,45 @@ constructing GraphQL Schemas while avoiding type-generation, [declaration mergin
66
and [decorators](https://www.typescriptlang.org/docs/handbook/decorators.html).
77

88
```ts
9-
import { g } from "@graphql-ts/schema";
9+
import { initG } from "@graphql-ts/schema";
1010
import { GraphQLSchema, graphql } from "graphql";
1111

12+
type Context = {
13+
loadPerson: (id: string) => Person;
14+
loadFriends: (id: string) => Person[];
15+
};
16+
const g = initG<Context>();
17+
type g<T> = initG<T>;
18+
19+
type Person = {
20+
id: string;
21+
name: string;
22+
};
23+
24+
const Person: g<typeof g.object<Person>> = g.object<Person>()({
25+
name: "Person",
26+
fields: () => ({
27+
id: g.field({ type: g.ID }),
28+
name: g.field({ type: g.String }),
29+
friends: g.field({
30+
type: g.list(Person),
31+
resolve(source, _, context) {
32+
return context.loadFriends(source.id);
33+
},
34+
}),
35+
}),
36+
});
37+
1238
const Query = g.object()({
1339
name: "Query",
1440
fields: {
15-
hello: g.field({
16-
type: g.String,
17-
resolve() {
18-
return "Hello!";
41+
person: g.field({
42+
type: Person,
43+
args: {
44+
id: g.arg({ type: g.ID }),
45+
},
46+
resolve(_, args, context) {
47+
return context.loadPerson(args.id);
1948
},
2049
}),
2150
},
@@ -25,13 +54,37 @@ const schema = new GraphQLSchema({
2554
query: Query,
2655
});
2756

57+
const people = new Map<string, Person>([
58+
["1", { id: "1", name: "Alice" }],
59+
["2", { id: "2", name: "Bob" }],
60+
]);
61+
const friends = new Map<string, string[]>([
62+
["1", ["2"]],
63+
["2", ["1"]],
64+
]);
65+
2866
graphql({
2967
source: `
30-
query {
31-
hello
32-
}
33-
`,
68+
query {
69+
person(id: "1") {
70+
id
71+
name
72+
friends {
73+
id
74+
name
75+
}
76+
}
77+
}
78+
`,
3479
schema,
80+
context: {
81+
loadPerson: (id) => people.get(id),
82+
loadFriends: (id) => {
83+
return (friends.get(id) ?? [])
84+
.map((id) => people.get(id))
85+
.filter((person) => person !== undefined);
86+
},
87+
},
3588
}).then((result) => {
3689
console.log(result);
3790
});

packages/schema/src/api-without-context/index.ts

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export {
1+
import {
22
arg,
33
inputObject,
44
Boolean,
@@ -8,10 +8,24 @@ export {
88
String,
99
list,
1010
nonNull,
11-
enum,
11+
enum as enumType,
1212
enumValues,
1313
scalar,
1414
} from "../api-with-context/api-with-context";
15+
export {
16+
arg,
17+
inputObject,
18+
Boolean,
19+
Float,
20+
ID,
21+
Int,
22+
String,
23+
list,
24+
nonNull,
25+
enumType as enum,
26+
enumValues,
27+
scalar,
28+
};
1529
export type {
1630
InferValueFromOutputType,
1731
InferValueFromArg,
@@ -32,26 +46,38 @@ import type {
3246
GType,
3347
} from "../types";
3448

35-
/** @deprecated Use {@link GEnumType} instead */
49+
/**
50+
* @deprecated Use {@link GEnumType} or {@link enumType `g<typeof g.enum<...>>`}
51+
* instead
52+
*/
3653
export type EnumType<Values extends { [key: string]: unknown }> =
3754
GEnumType<Values>;
38-
/** @deprecated Use {@link GArg} instead */
55+
/** @deprecated Use {@link GArg} or {@link arg `g<typeof g.arg<...>>`} instead */
3956
export type Arg<
4057
Type extends GInputType,
4158
HasDefaultValue extends boolean = boolean,
4259
> = GArg<Type, HasDefaultValue>;
43-
/** @deprecated Use {@link GList} instead */
60+
/** @deprecated Use {@link GList} or {@link list `g<typeof g.list<...>>`} instead */
4461
export type ListType<Of extends GType<any>> = GList<Of>;
45-
/** @deprecated Use {@link GNonNull} instead */
62+
/**
63+
* @deprecated Use {@link GNonNull} or {@link nonNull `g<typeof g.nonNull<...>>`}
64+
* instead
65+
*/
4666
export type NonNullType<Of extends GNullableType<any>> = GNonNull<Of>;
4767

48-
/** @deprecated Use {@link GScalarType} instead */
68+
/**
69+
* @deprecated Use {@link GScalarType} or {@link scalar `g<typeof g.scalar<...>>`}
70+
* instead
71+
*/
4972
export type ScalarType<Internal, External = Internal> = GScalarType<
5073
Internal,
5174
External
5275
>;
5376

54-
/** @deprecated Use {@link GInputObjectType} instead */
77+
/**
78+
* @deprecated Use {@link GInputObjectType} or
79+
* {@link inputObject `g<typeof g.inputObject<...>>`} instead
80+
*/
5581
export type InputObjectType<
5682
Fields extends {
5783
[key: string]: IsOneOf extends true

packages/schema/src/index.ts

Lines changed: 73 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,45 @@
77
* [decorators](https://www.typescriptlang.org/docs/handbook/decorators.html).
88
*
99
* ```ts
10-
* import { g } from "@graphql-ts/schema";
10+
* import { initG } from "@graphql-ts/schema";
1111
* import { GraphQLSchema, graphql } from "graphql";
1212
*
13+
* type Context = {
14+
* loadPerson: (id: string) => Person;
15+
* loadFriends: (id: string) => Person[];
16+
* };
17+
* const g = initG<Context>();
18+
* type g<T> = initG<T>;
19+
*
20+
* type Person = {
21+
* id: string;
22+
* name: string;
23+
* };
24+
*
25+
* const Person: g<typeof g.object<Person>> = g.object<Person>()({
26+
* name: "Person",
27+
* fields: () => ({
28+
* id: g.field({ type: g.ID }),
29+
* name: g.field({ type: g.String }),
30+
* friends: g.field({
31+
* type: g.list(Person),
32+
* resolve(source, _, context) {
33+
* return context.loadFriends(source.id);
34+
* },
35+
* }),
36+
* }),
37+
* });
38+
*
1339
* const Query = g.object()({
1440
* name: "Query",
1541
* fields: {
16-
* hello: g.field({
17-
* type: g.String,
18-
* resolve() {
19-
* return "Hello!";
42+
* person: g.field({
43+
* type: Person,
44+
* args: {
45+
* id: g.arg({ type: g.ID }),
46+
* },
47+
* resolve(_, args, context) {
48+
* return context.loadPerson(args.id);
2049
* },
2150
* }),
2251
* },
@@ -26,22 +55,47 @@
2655
* query: Query,
2756
* });
2857
*
58+
* const people = new Map<string, Person>([
59+
* ["1", { id: "1", name: "Alice" }],
60+
* ["2", { id: "2", name: "Bob" }],
61+
* ]);
62+
* const friends = new Map<string, string[]>([
63+
* ["1", ["2"]],
64+
* ["2", ["1"]],
65+
* ]);
66+
*
2967
* graphql({
3068
* source: `
31-
* query {
32-
* hello
33-
* }
34-
* `,
69+
* query {
70+
* person(id: "1") {
71+
* id
72+
* name
73+
* friends {
74+
* id
75+
* name
76+
* }
77+
* }
78+
* }
79+
* `,
3580
* schema,
81+
* context: {
82+
* loadPerson: (id) => people.get(id),
83+
* loadFriends: (id) => {
84+
* return (friends.get(id) ?? [])
85+
* .map((id) => people.get(id))
86+
* .filter((person) => person !== undefined);
87+
* },
88+
* },
3689
* }).then((result) => {
3790
* console.log(result);
3891
* });
3992
* ```
4093
*
4194
* @module
4295
*/
43-
export * as g from "./schema-api";
44-
export { initG, type GWithContext } from "./output";
96+
import { initG, type GWithContext } from "./output";
97+
export { initG };
98+
export type { GWithContext };
4599

46100
export {
47101
GObjectType,
@@ -67,6 +121,14 @@ export {
67121
type InferValueFromArgs,
68122
type InferValueFromInputType,
69123
} from "./types";
124+
/**
125+
* @deprecated Use {@link initG} bound to a specific context instead of the this
126+
* `g` bound to an unknown context
127+
*/
128+
declare module "./schema-api" {}
129+
export type g<T> = initG<T>;
130+
export * as g from "./schema-api";
131+
70132
export type {
71133
Arg,
72134
EnumType,

0 commit comments

Comments
 (0)