Skip to content

Commit

Permalink
Support for root field tags (#162) (#163)
Browse files Browse the repository at this point in the history
* Support for root field tags (#162)

* Support for root field tags

Right now the mechanism for defining root fields is just too cumbersome. It requires defining a type `type Query = unknown` is nonsensicle _and_ is part of the very first hello world.

Additionally, it requires defining functions with unused initial arguments:

```typescript
/** @gqlField */
export function greeting(_: Query): string {
  return "Hello";
}
```

This is confusing and nonsensicle, but also prevents these fields being reused for non-GraphQL use cases which goes aginst the goals of Grats, which includes lettting people expose thier _existing_ TypeScript code.

This PR adds three new tags to let you define Query/Mutation/Subscription fields without needing to explictly define or reference these types.

[ghstack-poisoned]

* Update on "Support for root field tags"


Right now the mechanism for defining root fields is just too cumbersome. It requires defining a type `type Query = unknown` is nonsensicle _and_ is part of the very first hello world.

Additionally, it requires defining functions with unused initial arguments:

```typescript
/** gqlField */
export function greeting(_: Query): string {
  return "Hello";
}
```

This is confusing and nonsensicle, but also prevents these fields being reused for non-GraphQL use cases which goes aginst the goals of Grats, which includes lettting people expose thier _existing_ TypeScript code.

This PR adds three new tags to let you define Query/Mutation/Subscription fields without needing to explictly define or reference these types.

[ghstack-poisoned]

* Update on "Support for root field tags"


Right now the mechanism for defining root fields is just too cumbersome. It requires defining a type `type Query = unknown` is nonsensicle _and_ is part of the very first hello world.

Additionally, it requires defining functions with unused initial arguments:

```typescript
/** gqlField */
export function greeting(_: Query): string {
  return "Hello";
}
```

This is confusing and nonsensicle, but also prevents these fields being reused for non-GraphQL use cases which goes against the goals of Grats, which includes lettting people expose their _existing_ TypeScript code.

Now such fields can be defined using:

```typescript
/** gqlQueryField */
export function greeting(): string {
  return "Hello";
}
```

This PR adds three new tags to let you define Query/Mutation/Subscription fields without needing to explictly define or reference these types.

[ghstack-poisoned]

* Clean up source in docs generated ts
  • Loading branch information
captbaritone authored Dec 16, 2024
1 parent 831703d commit 237d72c
Show file tree
Hide file tree
Showing 156 changed files with 1,257 additions and 939 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,17 @@

Changes in this section are not yet released. If you need access to these changes before we cut a release, check out our `@main` NPM releases. Each commit on the main branch is [published to NPM](https://www.npmjs.com/package/grats?activeTab=versions) under the `main` tag.

### Root Field Tags

Fields on `Query`, `Mutation` and `Subscription` may now be defined using the new docblock tags `@gqlQueryField`, `@gqlMutationField` and `@gqlSubscriptionField`. These tags can be added to functions or static methods.

```typescript
/** @gqlQueryField */
export function greeting(): string {
return "Hello world";
}
```

- **Features**
- Custom error messages when types or interfaces are missing fields which suggests adding a `@gqlField` docblock tag.
- Custom error message when your project has no types defined. Intended to help guide new users.
Expand Down
11 changes: 2 additions & 9 deletions examples/apollo-server/Query.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,7 @@
import IPerson from "./interfaces/IPerson";
import User from "./models/User";

/** @gqlType */
export type Query = unknown;

/** @gqlField */
export function me(_: Query): User {
return new User();
}
/** @gqlField */
export function person(_: Query): IPerson {
/** @gqlQueryField */
export function person(): IPerson {
return new User();
}
14 changes: 9 additions & 5 deletions examples/apollo-server/models/User.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import IPerson from "../interfaces/IPerson";
import { Query } from "../Query";
import Group from "./Group";

/** @gqlType User */
Expand All @@ -12,9 +11,14 @@ export default class UserResolver implements IPerson {
groups(): Group[] {
return [new Group()];
}
}

/** @gqlField */
export function allUsers(_: Query): UserResolver[] {
return [new UserResolver(), new UserResolver()];
/** @gqlQueryField */
static me(): UserResolver {
return new UserResolver();
}

/** @gqlQueryField */
static allUsers(): UserResolver[] {
return [new UserResolver(), new UserResolver()];
}
}
16 changes: 8 additions & 8 deletions examples/apollo-server/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
* Do not manually edit. Regenerate by running `npx grats`.
*/
import UserClass from "./models/User";
import { allUsers as queryAllUsersResolver } from "./models/User";
import { me as queryMeResolver } from "./Query";
import queryAllUsersResolver from "./models/User";
import queryMeResolver from "./models/User";
import { person as queryPersonResolver } from "./Query";
import { GraphQLSchema, GraphQLObjectType, GraphQLNonNull, GraphQLList, GraphQLString, GraphQLInterfaceType } from "graphql";
export function getSchema(): GraphQLSchema {
Expand Down Expand Up @@ -64,22 +64,22 @@ export function getSchema(): GraphQLSchema {
allUsers: {
name: "allUsers",
type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(UserType))),
resolve(source) {
return queryAllUsersResolver(source);
resolve() {
return queryAllUsersResolver.allUsers();
}
},
me: {
name: "me",
type: new GraphQLNonNull(UserType),
resolve(source) {
return queryMeResolver(source);
resolve() {
return queryMeResolver.me();
}
},
person: {
name: "person",
type: new GraphQLNonNull(IPersonType),
resolve(source) {
return queryPersonResolver(source);
resolve() {
return queryPersonResolver();
}
}
};
Expand Down
15 changes: 0 additions & 15 deletions examples/express-graphql-http/Query.ts

This file was deleted.

7 changes: 7 additions & 0 deletions examples/express-graphql-http/interfaces/IPerson.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import User from "../models/User";

/** @gqlInterface */
export default interface IPerson {
/** @gqlField */
name(): string;
}

/** @gqlQueryField */
export function person(): IPerson {
return new User();
}
17 changes: 10 additions & 7 deletions examples/express-graphql-http/models/User.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import IPerson from "../interfaces/IPerson";
import { Query } from "../Query";
import Group from "./Group";

/** @gqlType User */
export default class UserResolver implements IPerson {
/** @gqlType */
export default class User implements IPerson {
/** @gqlField */
name(): string {
return "Alice";
Expand All @@ -12,9 +11,13 @@ export default class UserResolver implements IPerson {
groups(): Group[] {
return [new Group()];
}
}
/** @gqlQueryField */
static allUsers(): User[] {
return [new User(), new User()];
}

/** @gqlField */
export function allUsers(_: Query): UserResolver[] {
return [new UserResolver(), new UserResolver()];
/** @gqlQueryField */
static me(): User {
return new User();
}
}
18 changes: 9 additions & 9 deletions examples/express-graphql-http/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
* Do not manually edit. Regenerate by running `npx grats`.
*/
import UserClass from "./models/User";
import { allUsers as queryAllUsersResolver } from "./models/User";
import { me as queryMeResolver } from "./Query";
import { person as queryPersonResolver } from "./Query";
import queryAllUsersResolver from "./models/User";
import queryMeResolver from "./models/User";
import { person as queryPersonResolver } from "./interfaces/IPerson";
import { GraphQLSchema, GraphQLObjectType, GraphQLNonNull, GraphQLList, GraphQLString, GraphQLInterfaceType } from "graphql";
export function getSchema(): GraphQLSchema {
const GroupType: GraphQLObjectType = new GraphQLObjectType({
Expand Down Expand Up @@ -64,22 +64,22 @@ export function getSchema(): GraphQLSchema {
allUsers: {
name: "allUsers",
type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(UserType))),
resolve(source) {
return queryAllUsersResolver(source);
resolve() {
return queryAllUsersResolver.allUsers();
}
},
me: {
name: "me",
type: new GraphQLNonNull(UserType),
resolve(source) {
return queryMeResolver(source);
resolve() {
return queryMeResolver.me();
}
},
person: {
name: "person",
type: new GraphQLNonNull(IPersonType),
resolve(source) {
return queryPersonResolver(source);
resolve() {
return queryPersonResolver();
}
}
};
Expand Down
15 changes: 0 additions & 15 deletions examples/express-graphql/Query.ts

This file was deleted.

7 changes: 7 additions & 0 deletions examples/express-graphql/interfaces/IPerson.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import User from "../models/User";

/** @gqlInterface */
export default interface IPerson {
/** @gqlField */
name(): string;
}

/** @gqlQueryField */
export function person(): IPerson {
return new User();
}
13 changes: 8 additions & 5 deletions examples/express-graphql/models/User.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import IPerson from "../interfaces/IPerson";
import { Query } from "../Query";
import Group from "./Group";

/** @gqlType User */
Expand All @@ -12,9 +11,13 @@ export default class UserResolver implements IPerson {
groups(): Group[] {
return [new Group()];
}
}
/** @gqlQueryField */
static allUsers(): UserResolver[] {
return [new UserResolver(), new UserResolver()];
}

/** @gqlField */
export function allUsers(_: Query): UserResolver[] {
return [new UserResolver(), new UserResolver()];
/** @gqlQueryField */
static me(): UserResolver {
return new UserResolver();
}
}
18 changes: 9 additions & 9 deletions examples/express-graphql/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
* Do not manually edit. Regenerate by running `npx grats`.
*/
import UserClass from "./models/User";
import { allUsers as queryAllUsersResolver } from "./models/User";
import { me as queryMeResolver } from "./Query";
import { person as queryPersonResolver } from "./Query";
import queryAllUsersResolver from "./models/User";
import queryMeResolver from "./models/User";
import { person as queryPersonResolver } from "./interfaces/IPerson";
import { GraphQLSchema, GraphQLObjectType, GraphQLNonNull, GraphQLList, GraphQLString, GraphQLInterfaceType } from "graphql";
export function getSchema(): GraphQLSchema {
const GroupType: GraphQLObjectType = new GraphQLObjectType({
Expand Down Expand Up @@ -64,22 +64,22 @@ export function getSchema(): GraphQLSchema {
allUsers: {
name: "allUsers",
type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(UserType))),
resolve(source) {
return queryAllUsersResolver(source);
resolve() {
return queryAllUsersResolver.allUsers();
}
},
me: {
name: "me",
type: new GraphQLNonNull(UserType),
resolve(source) {
return queryMeResolver(source);
resolve() {
return queryMeResolver.me();
}
},
person: {
name: "person",
type: new GraphQLNonNull(IPersonType),
resolve(source) {
return queryPersonResolver(source);
resolve() {
return queryPersonResolver();
}
}
};
Expand Down
7 changes: 2 additions & 5 deletions examples/incremental-migration/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,8 @@ faker.seed(123);
* - User.id
*/

/** @gqlType */
type Query = unknown;

/** @gqlField */
export function user(_: Query, id: ID): User | undefined {
/** @gqlQueryField */
export function user(id: ID): User | undefined {
return Users.get(id);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ export function getSchema(): GraphQLSchema {
type: new GraphQLNonNull(GraphQLID)
}
},
resolve(source, args) {
return queryUserResolver(source, args.id);
resolve(_source, args) {
return queryUserResolver(args.id);
}
}
};
Expand Down
11 changes: 4 additions & 7 deletions examples/next-js/app/api/graphql/Query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,11 @@
import IPerson from "./interfaces/IPerson";
import User from "./models/User";

/** @gqlType */
export type Query = unknown;

/** @gqlField */
export function me(_: Query): User {
/** @gqlQueryField */
export function me(): User {
return new User();
}
/** @gqlField */
export function person(_: Query): IPerson {
/** @gqlQueryField */
export function person(): IPerson {
return new User();
}
9 changes: 4 additions & 5 deletions examples/next-js/app/api/graphql/models/User.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import IPerson from "../interfaces/IPerson";
import { Query } from "../Query";
import Group from "./Group";

/** @gqlType User */
Expand All @@ -12,9 +11,9 @@ export default class UserResolver implements IPerson {
groups(): Group[] {
return [new Group()];
}
}

/** @gqlField */
export function allUsers(_: Query): UserResolver[] {
return [new UserResolver(), new UserResolver()];
/** @gqlQueryField */
static allUsers(): UserResolver[] {
return [new UserResolver(), new UserResolver()];
}
}
Loading

0 comments on commit 237d72c

Please sign in to comment.