Skip to content

Commit

Permalink
feat(ts): support input object in selection set (#736)
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonkuhrt authored Mar 25, 2024
1 parent 0d1e1a6 commit f9ad67a
Show file tree
Hide file tree
Showing 19 changed files with 308 additions and 245 deletions.
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@
"graphql": "14 - 16"
},
"devDependencies": {
"@tsconfig/node16": "^16.1.1",
"@tsconfig/node16": "^16.1.2",
"@types/body-parser": "^1.19.5",
"@types/express": "^4.17.21",
"@types/json-bigint": "^1.0.4",
Expand All @@ -104,10 +104,10 @@
"get-port": "^7.1.0",
"graphql": "^16.8.1",
"graphql-tag": "^2.12.6",
"happy-dom": "^14.3.1",
"happy-dom": "^14.3.6",
"json-bigint": "^1.0.0",
"tsx": "^4.7.1",
"type-fest": "^4.13.1",
"type-fest": "^4.14.0",
"typescript": "^5.4.3",
"vitest": "^1.4.0"
}
Expand Down
40 changes: 20 additions & 20 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 11 additions & 11 deletions src/ResultSet/ResultSet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export type Object<$SelectionSet, $Node extends Schema.Named.Object, $Index exte
*/
?
{
[$Key in keyof $Node['fields'] as $Node['fields'][$Key] extends Schema.Field.Field<Schema.Field.Type.__typename> | {'typeUnwrapped':{kind:'Scalar'}} ? $Key : never]:
[$Key in keyof $Node['fields'] as $Node['fields'][$Key] extends Schema.Field.Field<Schema.Field.Type.Output.__typename> | {'typeUnwrapped':{kind:'Scalar'}} ? $Key : never]:
// eslint-disable-next-line
// @ts-ignore infinite depth issue, can this be fixed?
Field<$SelectionSet, Schema.Field.As<$Node['fields'][$Key]>, $Index>
Expand Down Expand Up @@ -74,18 +74,18 @@ type Field<$SelectionSet, $Field extends Schema.Field.Field, $Index extends Sche
// dprint-ignore
type FieldType<
$SelectionSet,
$Type extends Schema.Field.Type.Any,
$Type extends Schema.Field.Type.Output.Any,
$Index extends Schema.Index
> =Simplify<
$Type extends Schema.Field.Type.__typename<infer $Value> ? $Value :
$Type extends Schema.Field.Type.Nullable<infer $InnerType> ? null | FieldType<$SelectionSet, $InnerType, $Index> :
$Type extends Schema.Field.Type.List<infer $InnerType> ? Array<FieldType<$SelectionSet, $InnerType, $Index>> :
$Type extends Schema.Named.Enum<infer _, infer $Members> ? $Members[number] :
$Type extends Schema.Named.Scalar.Any ? ReturnType<$Type['constructor']> :
$Type extends Schema.Named.Object ? Object<$SelectionSet,$Type,$Index> :
$Type extends Schema.Named.Interface ? Interface<$SelectionSet,$Type,$Index> :
$Type extends Schema.Named.Union ? Union<$SelectionSet,$Type,$Index> :
TSError<'FieldType', `Unknown type`, { $Type: $Type }>
$Type extends Schema.Field.Type.Output.__typename<infer $Value> ? $Value :
$Type extends Schema.Field.Type.Output.Nullable<infer $InnerType> ? null | FieldType<$SelectionSet, $InnerType, $Index> :
$Type extends Schema.Field.Type.Output.List<infer $InnerType> ? Array<FieldType<$SelectionSet, $InnerType, $Index>> :
$Type extends Schema.Named.Enum<infer _, infer $Members> ? $Members[number] :
$Type extends Schema.Named.Scalar.Any ? ReturnType<$Type['constructor']> :
$Type extends Schema.Named.Object ? Object<$SelectionSet,$Type,$Index> :
$Type extends Schema.Named.Interface ? Interface<$SelectionSet,$Type,$Index> :
$Type extends Schema.Named.Union ? Union<$SelectionSet,$Type,$Index> :
TSError<'FieldType', `Unknown type`, { $Type: $Type }>
>

// dprint-ignore
Expand Down
17 changes: 5 additions & 12 deletions src/Schema/Field/Field.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import type { NamedType } from '../NamedType/__.js'
import type { Scalar } from '../NamedType/Scalar/_.js'
import type * as Type from './Type.js'
import { unwrap } from './Type.js'
import * as Type from './Type.js'

export type * as Type from './Type.js'

Expand All @@ -17,33 +16,27 @@ export type Number<$Args extends Args | null = null> = Field<Scalar.Int, $Args>

export type Boolean<$Args extends Args | null = null> = Field<Scalar.Boolean, $Args>

export namespace Input {
export type Nullable = Type.Nullable<any>
export type List = Type.List<any>
export type Any = Scalar.Any | List | Nullable
}

// export interface Args<$Fields extends Record<keyof $Fields, InputFieldType> = Record<string, InputFieldType>> {
export interface Args<$Fields extends any = any> {
allOptional: Exclude<$Fields[keyof $Fields], Type.Nullable<any>> extends never ? true : false
allOptional: Exclude<$Fields[keyof $Fields], Type.Output.Nullable<any>> extends never ? true : false
fields: $Fields
}

export const field = <$Type extends Type.Any, $Args extends null | Args = null>(
export const field = <$Type extends Type.Output.Any, $Args extends null | Args = null>(
type: $Type,
args: $Args = null as $Args,
): Field<$Type, $Args> => {
return {
// eslint-disable-next-line
// @ts-ignore infinite depth issue, can this be fixed?
typeUnwrapped: unwrap(type),
typeUnwrapped: Type.Output.unwrap(type),
type,
args,
}
}

export type Field<$Type extends any = any, $Args extends Args | null = Args | null> = {
typeUnwrapped: Type.Unwrap<$Type>
typeUnwrapped: Type.Output.Unwrap<$Type>
type: $Type
args: $Args
}
63 changes: 38 additions & 25 deletions src/Schema/Field/Type.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,51 @@
import type { TSError } from '../../lib/TSError.js'
import type { NamedType } from '../NamedType/__.js'

export interface __typename<$Type extends string = string> {
kind: 'typename'
type: $Type
}
export interface Nullable<$Type extends Any> {
kind: 'nullable'
type: $Type
}
export interface List<$Type extends Any> {
kind: 'list'
type: $Type
export namespace Base {
export interface Nullable<$Type> {
kind: 'nullable'
type: $Type
}
export interface List<$Type> {
kind: 'list'
type: $Type
}
}

export type Any = List<any> | __typename<any> | Nullable<any> | NamedType.Any
export namespace Output {
export interface __typename<$Type extends string = string> {
kind: 'typename'
type: $Type
}
export type Nullable<$Type extends Any> = Base.Nullable<$Type>
export type List<$Type extends Any> = Base.List<$Type>

export type Any = Output.List<any> | __typename<any> | Base.Nullable<any> | NamedType.AnyOutput

export const __typename = <$Type extends string>(type: $Type): __typename<$Type> => ({ kind: `typename`, type })
export const nullable = <$Type extends __typename<any> | List<any>>(type: $Type): Nullable<$Type> => ({
kind: `nullable`,
type,
})
export const list = <$Type extends Any>(type: $Type): List<$Type> => ({ kind: `list`, type })
export const __typename = <$Type extends string>(type: $Type): __typename<$Type> => ({ kind: `typename`, type })
export const nullable = <$Type extends __typename<any> | List<any>>(type: $Type): Nullable<$Type> => ({
kind: `nullable`,
type,
})
export const list = <$Type extends Any>(type: $Type): List<$Type> => ({ kind: `list`, type })

// todo extends any because of infinite depth issue in generated schema types
// dprint-ignore
export type Unwrap<$Type extends any> =
// todo extends any because of infinite depth issue in generated schema types
// dprint-ignore
export type Unwrap<$Type extends any> =
$Type extends List<infer $innerType> ? Unwrap<$innerType> :
$Type extends Nullable<infer $innerType> ? Unwrap<$innerType> :
$Type extends __typename ? $Type['type'] :
$Type extends NamedType.Any ? $Type :
$Type extends NamedType.AnyOutput ? $Type :
TSError<'Unwrap', 'Unknown $Type', { $Type: $Type }>

export const unwrap = <$Type extends Any>(type: $Type): Unwrap<$Type> => {
// @ts-expect-error fixme
return type.kind === `named` ? type.type : unwrap(type.type)
export const unwrap = <$Type extends Any>(type: $Type): Unwrap<$Type> => {
// @ts-expect-error fixme
return type.kind === `named` ? type.type : unwrap(type.type)
}
}

export namespace Input {
export type Nullable<$InnerType extends Any = Any> = Base.Nullable<$InnerType>
export type List<$InnerType extends Any = Any> = Base.List<$InnerType>
export type Any = List<any> | Nullable<any> | NamedType.AnyInput
}
2 changes: 0 additions & 2 deletions src/Schema/NamedType/Enum.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import type { __typename } from '../__.js'

export interface Enum<
$Name extends string = string,
$Members extends [string, ...string[]] = [string, ...string[]],
Expand Down
23 changes: 23 additions & 0 deletions src/Schema/NamedType/InputObjet.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/* eslint-disable @typescript-eslint/ban-types */

type Fields = Record<string, any>

export interface InputObject<
$Name extends string = string,
$Fields extends Fields = Fields,
> {
kind: 'InputObject'
name: $Name
fields: $Fields
}

export const InputObject = <$Name extends string, $Fields extends Record<keyof $Fields, any>>(
name: $Name,
fields: $Fields,
): InputObject<$Name, $Fields> => ({
kind: `InputObject`,
name: name,
fields: {
...fields,
},
})
1 change: 0 additions & 1 deletion src/Schema/NamedType/Interface.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
/* eslint-disable @typescript-eslint/ban-types */

import type { __typename } from '../__.js'
import type { Field } from '../Field/Field.js'
import type { Object } from './Object.js'

Expand Down
5 changes: 4 additions & 1 deletion src/Schema/NamedType/NamedType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@

import type { Digit, Letter } from '../../lib/prelude.js'
import type { Enum } from './Enum.js'
import type { InputObject } from './InputObjet.js'
import type { Interface } from './Interface.js'
import type { Object } from './Object.js'
import type { Scalar } from './Scalar/_.js'
import type { Union } from './Union.js'

export type Any = Interface | Enum | Object | Scalar.Any | Union
export type AnyOutput = Interface | Enum | Object | Scalar.Any | Union
export type AnyInput = Enum | Scalar.Any | InputObject
export type Any = AnyOutput | AnyInput

/**
* @see http://spec.graphql.org/draft/#sec-Names
Expand Down
8 changes: 4 additions & 4 deletions src/Schema/NamedType/Object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

import type { Field } from '../Field/Field.js'
import { field } from '../Field/Field.js'
import { __typename } from '../Field/Type.js'
import { Output } from '../Field/Type.js'

export type Fields = Record<string, Field<any>>

export type ObjectFields = {
__typename: Field<__typename>
__typename: Field<Output.__typename>
} & Fields

export interface Object<
Expand All @@ -16,7 +16,7 @@ export interface Object<
> {
kind: 'Object'
fields: {
__typename: Field<__typename<$Name>>
__typename: Field<Output.__typename<$Name>>
} & $Fields
}

Expand All @@ -26,7 +26,7 @@ export const Object = <$Name extends string, $Fields extends Record<keyof $Field
): Object<$Name, $Fields> => ({
kind: `Object`,
fields: {
__typename: field(__typename(name)),
__typename: field(Output.__typename(name)),
...fields,
},
})
Loading

0 comments on commit f9ad67a

Please sign in to comment.