Skip to content

Commit

Permalink
Update graphql-ts-gql, and add graphql-codegen and graphql-gql.tada e…
Browse files Browse the repository at this point in the history
…xamples (#9457)
  • Loading branch information
emmatown authored Feb 6, 2025
1 parent 5b5aec1 commit 1baae47
Show file tree
Hide file tree
Showing 29 changed files with 3,231 additions and 325 deletions.
24 changes: 24 additions & 0 deletions examples/graphql-codegen/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
## Feature Example - Graphql types with GraphQL Code Generator

This project demonstrates how to generate GraphQL types using [GraphQL Code Generator](https://the-guild.dev/graphql/codegen) for `context.graphql` in a Keystone project

## Instructions

To run this project, clone the Keystone repository locally, run `pnpm install` at the root of the repository then navigate to this directory and run:

```shell
pnpm dev
```

This will start the Admin UI at [localhost:3000](http://localhost:3000).
You can use the Admin UI to create items in your database.

You can also access a GraphQL Playground at [localhost:3000/api/graphql](http://localhost:3000/api/graphql), which allows you to directly run GraphQL queries and mutations.

## Features

This project demonstrates how to use `context.graphql` with [GraphQL Code Generator](https://the-guild.dev/graphql/codegen).

## Try it out in CodeSandbox 🧪

You can play with this example online in a web browser using the free [codesandbox.io](https://codesandbox.io/) service. To launch this example, open the URL <https://githubbox.com/keystonejs/keystone/tree/main/examples/graphql-codegen>. You can also fork this sandbox to make your own changes.
14 changes: 14 additions & 0 deletions examples/graphql-codegen/codegen.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import type { CodegenConfig } from '@graphql-codegen/cli'

const config: CodegenConfig = {
schema: 'schema.graphql',
documents: ['**/*.{tsx,ts}','!**/node_modules','!**/.keystone'],
ignoreNoDocuments: true,
generates: {
'./gql/': {
preset: 'client',
}
}
}

export default config
87 changes: 87 additions & 0 deletions examples/graphql-codegen/gql/fragment-masking.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/* eslint-disable */
import { ResultOf, DocumentTypeDecoration, TypedDocumentNode } from '@graphql-typed-document-node/core';
import { FragmentDefinitionNode } from 'graphql';
import { Incremental } from './graphql';


export type FragmentType<TDocumentType extends DocumentTypeDecoration<any, any>> = TDocumentType extends DocumentTypeDecoration<
infer TType,
any
>
? [TType] extends [{ ' $fragmentName'?: infer TKey }]
? TKey extends string
? { ' $fragmentRefs'?: { [key in TKey]: TType } }
: never
: never
: never;

// return non-nullable if `fragmentType` is non-nullable
export function useFragment<TType>(
_documentNode: DocumentTypeDecoration<TType, any>,
fragmentType: FragmentType<DocumentTypeDecoration<TType, any>>
): TType;
// return nullable if `fragmentType` is undefined
export function useFragment<TType>(
_documentNode: DocumentTypeDecoration<TType, any>,
fragmentType: FragmentType<DocumentTypeDecoration<TType, any>> | undefined
): TType | undefined;
// return nullable if `fragmentType` is nullable
export function useFragment<TType>(
_documentNode: DocumentTypeDecoration<TType, any>,
fragmentType: FragmentType<DocumentTypeDecoration<TType, any>> | null
): TType | null;
// return nullable if `fragmentType` is nullable or undefined
export function useFragment<TType>(
_documentNode: DocumentTypeDecoration<TType, any>,
fragmentType: FragmentType<DocumentTypeDecoration<TType, any>> | null | undefined
): TType | null | undefined;
// return array of non-nullable if `fragmentType` is array of non-nullable
export function useFragment<TType>(
_documentNode: DocumentTypeDecoration<TType, any>,
fragmentType: Array<FragmentType<DocumentTypeDecoration<TType, any>>>
): Array<TType>;
// return array of nullable if `fragmentType` is array of nullable
export function useFragment<TType>(
_documentNode: DocumentTypeDecoration<TType, any>,
fragmentType: Array<FragmentType<DocumentTypeDecoration<TType, any>>> | null | undefined
): Array<TType> | null | undefined;
// return readonly array of non-nullable if `fragmentType` is array of non-nullable
export function useFragment<TType>(
_documentNode: DocumentTypeDecoration<TType, any>,
fragmentType: ReadonlyArray<FragmentType<DocumentTypeDecoration<TType, any>>>
): ReadonlyArray<TType>;
// return readonly array of nullable if `fragmentType` is array of nullable
export function useFragment<TType>(
_documentNode: DocumentTypeDecoration<TType, any>,
fragmentType: ReadonlyArray<FragmentType<DocumentTypeDecoration<TType, any>>> | null | undefined
): ReadonlyArray<TType> | null | undefined;
export function useFragment<TType>(
_documentNode: DocumentTypeDecoration<TType, any>,
fragmentType: FragmentType<DocumentTypeDecoration<TType, any>> | Array<FragmentType<DocumentTypeDecoration<TType, any>>> | ReadonlyArray<FragmentType<DocumentTypeDecoration<TType, any>>> | null | undefined
): TType | Array<TType> | ReadonlyArray<TType> | null | undefined {
return fragmentType as any;
}


export function makeFragmentData<
F extends DocumentTypeDecoration<any, any>,
FT extends ResultOf<F>
>(data: FT, _fragment: F): FragmentType<F> {
return data as FragmentType<F>;
}
export function isFragmentReady<TQuery, TFrag>(
queryNode: DocumentTypeDecoration<TQuery, any>,
fragmentNode: TypedDocumentNode<TFrag>,
data: FragmentType<TypedDocumentNode<Incremental<TFrag>, any>> | null | undefined
): data is FragmentType<typeof fragmentNode> {
const deferredFields = (queryNode as { __meta__?: { deferredFields: Record<string, (keyof TFrag)[]> } }).__meta__
?.deferredFields;

if (!deferredFields) return true;

const fragDef = fragmentNode.definitions[0] as FragmentDefinitionNode | undefined;
const fragName = fragDef?.name?.value;

const fields = (fragName && deferredFields[fragName]) || [];
return fields.length > 0 && fields.every(field => data && field in data);
}
43 changes: 43 additions & 0 deletions examples/graphql-codegen/gql/gql.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/* eslint-disable */
import * as types from './graphql';
import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';

/**
* Map of all GraphQL operations in the project.
*
* This map has several performance disadvantages:
* 1. It is not tree-shakeable, so it will include all operations in the project.
* 2. It is not minifiable, so the string of a GraphQL query will be multiple times inside the bundle.
* 3. It does not support dead code elimination, so it will add unused operations.
*
* Therefore it is highly recommended to use the babel or swc plugin for production.
* Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size
*/
const documents = {
"\n query LastestPostQuery($id: ID!) {\n author(where: { id: $id }) {\n id\n posts(orderBy: { publishDate: desc }, take: 1) {\n id\n }\n }\n }\n": types.LastestPostQueryDocument,
};

/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*
*
* @example
* ```ts
* const query = graphql(`query GetUser($id: ID!) { user(id: $id) { name } }`);
* ```
*
* The query argument is unknown!
* Please regenerate the types.
*/
export function graphql(source: string): unknown;

/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "\n query LastestPostQuery($id: ID!) {\n author(where: { id: $id }) {\n id\n posts(orderBy: { publishDate: desc }, take: 1) {\n id\n }\n }\n }\n"): (typeof documents)["\n query LastestPostQuery($id: ID!) {\n author(where: { id: $id }) {\n id\n posts(orderBy: { publishDate: desc }, take: 1) {\n id\n }\n }\n }\n"];

export function graphql(source: string) {
return (documents as any)[source] ?? {};
}

export type DocumentType<TDocumentNode extends DocumentNode<any, any>> = TDocumentNode extends DocumentNode< infer TType, any> ? TType : never;
Loading

0 comments on commit 1baae47

Please sign in to comment.