Skip to content

Commit

Permalink
improve(document-builder): simplification of all output cases! (#1269)
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonkuhrt authored Nov 19, 2024
1 parent 7fd4449 commit 8f78882
Show file tree
Hide file tree
Showing 20 changed files with 1,106 additions and 1,501 deletions.
66 changes: 44 additions & 22 deletions src/client/handleOutput.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import type { GraphQLError } from 'graphql'
import type { Simplify } from 'type-fest'
import type { SimplifyDeepExcept } from '../documentBuilder/Simplify.js'
import type { RunTypeHookOnRequestResult } from '../extension/extension.js'
import { Errors } from '../lib/errors/__.js'
import type { Grafaid } from '../lib/grafaid/__.js'
Expand Down Expand Up @@ -109,7 +111,15 @@ export const handleOutput = (

// dprint-ignore
export type HandleOutputGraffleRootField<$Context extends Context, $Data extends SomeObjectData, $RootFieldName extends string> =
HandleOutputGraffleRootField_Data<ExcludeNull<HandleOutput<$Context, $Data>>, $RootFieldName>
HandleOutputGraffleRootField_Data<
ExcludeNull<
HandleOutput<
$Context,
SimplifyDeepExcept<$Context['scalars']['typesDecoded'], $Data>
>
>,
$RootFieldName
>

// dprint-ignore
type HandleOutputGraffleRootField_Data<$Output extends Error | SomeObjectData | GraffleExecutionResultEnvelope, $RootFieldName extends string> =
Expand All @@ -119,7 +129,13 @@ type HandleOutputGraffleRootField_Data<$Output extends Error | SomeObjectData |

// dprint-ignore
export type HandleOutput<$Context extends Context, $Data extends SomeObjectData> =
HandleOutput_Extensions<$Context, Envelope<$Context, $Data>>
HandleOutput_Extensions<
$Context,
Envelope<
$Context,
SimplifyDeepExcept<$Context['scalars']['typesDecoded'], $Data>
>
>

type HandleOutput_Extensions<$Context extends Context, $Envelope extends GraffleExecutionResultEnvelope> =
HandleOutput_ErrorsReturn<
Expand Down Expand Up @@ -168,26 +184,32 @@ type ConfigResolveOutputErrorChannel<$Context extends Context, $Channel extends

// dprint-ignore
// todo use ObjMap for $Data
export type Envelope<$Context extends Context, $Data = unknown, $Errors extends ReadonlyArray<Error> = ReadonlyArray<GraphQLError>> =
& {
data?: $Data | null
extensions?: ObjMap
}
& (
$Context['config']['transport']['type'] extends 'http'
? { response: Response }
: {}
)
// todo remove use of errors type variable. Rely only on $Config.
& (
$Errors extends []
? {}
: IsEnvelopeWithoutErrors<$Context> extends true
? {}
: {
errors?: ReadonlyArray<GraphQLError>
}
)
export type Envelope<
$Context extends Context,
$Data = unknown,
$Errors extends ReadonlyArray<Error> = ReadonlyArray<GraphQLError>,
> =
Simplify<
& {
data?: $Data | null
extensions?: ObjMap
}
& (
$Context['config']['transport']['type'] extends 'http'
? { response: Response }
: {}
)
// todo remove use of errors type variable. Rely only on $Config.
& (
$Errors extends []
? {}
: IsEnvelopeWithoutErrors<$Context> extends true
? {}
: {
errors?: ReadonlyArray<GraphQLError>
}
)
>

type ObjMap<T = unknown> = {
[key: string]: T
Expand Down
6 changes: 4 additions & 2 deletions src/documentBuilder/InferResult/__.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import type { db } from '../../../tests/_/schemas/db.js'
import type { Schema } from '../../../tests/_/schemas/kitchen-sink/graffle/modules/schema.js'
import type * as SelectionSets from '../../../tests/_/schemas/kitchen-sink/graffle/modules/selection-sets.js'
import { assertEqual } from '../../lib/assert-equal.js'
import type { SimplifyDeep } from '../../lib/prelude.js'
import type { Registry } from '../../types/Schema/nodes/Scalar/helpers.js'
import type { DocumentBuilder } from '../__.js'
import type { InferResult } from './__.js'

type $<$SelectionSet extends SelectionSets.Query> = SimplifyDeep<InferResult.OperationQuery<$SelectionSet, Schema>>
type $<$SelectionSet extends SelectionSets.Query> = DocumentBuilder.SimplifyDeep<
InferResult.OperationQuery<$SelectionSet, Schema>
>

type $Registry = Registry.AddScalar<Registry.Empty, typeof DateScalar>

Expand Down
20 changes: 20 additions & 0 deletions src/documentBuilder/Simplify.test-d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { assertEqual } from '../lib/assert-equal.js'
import type { SimplifyDeep, SimplifyDeepExcept } from './Simplify.js'

// dprint-ignore
{

assertEqual<SimplifyDeep<{x:1|null}> , {x:1|null}>()
assertEqual<SimplifyDeep<null | {x:1}> , null | {x:1}>()
assertEqual<SimplifyDeep<null | {x?:1}> , null | {x?:1}>()
assertEqual<SimplifyDeep<null | {x?:1|null}> , null | {x?:1|null}>()

assertEqual<SimplifyDeepExcept<Date, null | Date> , null | Date>()
assertEqual<SimplifyDeepExcept<Date, {}> , {}>()
assertEqual<SimplifyDeepExcept<Date, { a: Date }> , { a: Date }>()
assertEqual<SimplifyDeepExcept<Date, { a: 1 }> , { a: 1 }>()
assertEqual<SimplifyDeepExcept<Date, { a: { b: Date } }> , { a: { b: Date } }>()
assertEqual<SimplifyDeepExcept<Date, { a: { b: Date } }> , { a: { b: Date } }>()
assertEqual<SimplifyDeepExcept<Date, { a: null | { b: Date } }> , { a: null | { b: Date } }>()

}
18 changes: 18 additions & 0 deletions src/documentBuilder/Simplify.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import type { IntrospectionQuery } from 'graphql'
import type { AnyAndUnknownToNever } from '../lib/prelude.js'

export type SimplifyDeep<T> = SimplifyDeepExcept<never, T>

// dprint-ignore
export type SimplifyDeepExcept<$ExcludeType, $Type> =
$Type extends any ? // distribute execution over $Type members

// todo allow extensions to augment this list, with arbitrary types, not just custom scalars.
$Type extends AnyAndUnknownToNever<$ExcludeType> | IntrospectionQuery
? $Type
: {
[$Key in keyof $Type]:
& SimplifyDeepExcept<$ExcludeType, $Type[$Key]>
& ({} | null)
}
: never
1 change: 1 addition & 0 deletions src/documentBuilder/_.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './Simplify.js'
1 change: 1 addition & 0 deletions src/documentBuilder/__.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * as DocumentBuilder from './_.js'
8 changes: 3 additions & 5 deletions src/documentBuilder/requestMethods/document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { type HandleOutput } from '../../client/handleOutput.js'
import type { InferResult } from '../../documentBuilder/InferResult/__.js'
import type { Select } from '../../documentBuilder/Select/__.js'
import type { Schema } from '../../entrypoints/schema.js'
import type { IsTupleMultiple, SimplifyDeepExcept } from '../../lib/prelude.js'
import type { IsTupleMultiple } from '../../lib/prelude.js'

// dprint-ignore
export type DocumentRunner<
Expand All @@ -18,17 +18,15 @@ export type DocumentRunner<
const $Name extends string = $Params extends [] ? $$Name : $Params[0],
>(...params: $Params) =>
Promise<
SimplifyDeepExcept<
$$Context['scalars']['typesDecoded'],
HandleOutput<
& ({} | null)
& HandleOutput<
$$Context,
InferResult.Operation<
Select.Document.GetOperation<$$Document, $Name>,
$$Schema,
Select.Document.GetOperationType<$$Document, $Name>
>
>
>
>
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ test(`query`, async () => {
// scalar with required arguments
expectTypeOf<Parameters<typeof graffle.query.stringWithRequiredArg>>().toEqualTypeOf<[input: Graffle.SelectionSets.Query.stringWithRequiredArg]>()
// scalar custom
const result = await graffle.query.date()
expectTypeOf(await graffle.query.date()).toMatchTypeOf<Date | null>()
// scalar with explicit indicators
// positive indicator
Expand Down
11 changes: 2 additions & 9 deletions src/entrypoints/utilities-for-generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,8 @@ export type { ConfigGetOutputError, HandleOutput, HandleOutputGraffleRootField }
export type { Config } from '../client/Settings/Config.js'
export { type DocumentRunner } from '../documentBuilder/requestMethods/document.js'
export * from '../documentBuilder/Select/__.js'
export {
type AssertExtendsObject,
type Exact,
type ExactNonEmpty,
type SimplifyDeep,
type SimplifyDeepExcept,
type SimplifyExcept,
type UnionExpanded,
} from '../lib/prelude.js'
export { type SimplifyDeep, type SimplifyDeepExcept } from '../documentBuilder/Simplify.js'
export { type AssertExtendsObject, type Exact, type ExactNonEmpty, type UnionExpanded } from '../lib/prelude.js'
export { TypeFunction } from '../lib/type-function/__.js'
export { type GlobalRegistry } from '../types/GlobalRegistry/GlobalRegistry.js'
export { Schema } from '../types/Schema/__.js'
Expand Down
3 changes: 1 addition & 2 deletions src/extensions/Introspection/Introspection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { getIntrospectionQuery, type IntrospectionQuery } from 'graphql'
import type { Context } from '../../client/context.js'
import type { HandleOutput } from '../../client/handleOutput.js'
import { createBuilderExtension, createExtension } from '../../entrypoints/extensionkit.js'
import type { SimplifyNullable } from '../../entrypoints/main.js'
import type { Builder } from '../../lib/builder/__.js'
import { type ConfigInput, createConfig } from './config.js'

Expand Down Expand Up @@ -73,7 +72,7 @@ interface BuilderExtension extends Builder.Extension {
}

interface BuilderExtension_<$Args extends Builder.Extension.Parameters<BuilderExtension>> {
introspect: () => Promise<SimplifyNullable<HandleOutput<$Args['context'], IntrospectionQuery>>>
introspect: () => Promise<(null | {}) & HandleOutput<$Args['context'], IntrospectionQuery>>
}

const knownPotentiallyUnsupportedFeatures = [`inputValueDeprecation`, `oneOf`] as const
Loading

0 comments on commit 8f78882

Please sign in to comment.