Skip to content

Commit

Permalink
feat(ts-client): returnMode successData (#804)
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonkuhrt committed Apr 27, 2024
1 parent c0127d3 commit 80e050c
Show file tree
Hide file tree
Showing 26 changed files with 780 additions and 160 deletions.
8 changes: 8 additions & 0 deletions src/Schema/core/Index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import type { GlobalRegistry } from '../../globalRegistry.js'
import type { Output } from '../Output/__.js'

export interface Index {
name: GlobalRegistry.SchemaNames
Root: {
Query: null | Output.Object$2
Mutation: null | Output.Object$2
Expand All @@ -11,5 +13,11 @@ export interface Index {
interfaces: Record<string, Output.Interface>
error: {
objects: Record<string, Output.Object$2>
objectsTypename: Record<string, { __typename: string }>
rootResultFields: {
Query: Record<string, string>
Mutation: Record<string, string>
Subscription: Record<string, string>
}
}
}
58 changes: 51 additions & 7 deletions src/client/Config.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
import type { ExecutionResult } from 'graphql'
import type { GlobalRegistry } from '../globalRegistry.js'
import type { GraphQLExecutionResultError } from '../lib/graphql.js'
import type { SetProperty } from '../lib/prelude.js'
import type { Schema } from '../Schema/__.js'

export type ReturnModeType =
| ReturnModeTypeGraphQL
| ReturnModeTypeSuccessData
| ReturnModeTypeData
| ReturnModeTypeDataAndSchemaErrors
| ReturnModeTypeDataAllErrors
| ReturnModeTypeDataAndErrors

export type ReturnModeTypeBase = ReturnModeTypeGraphQL | ReturnModeTypeData | ReturnModeTypeDataAllErrors
export type ReturnModeTypeBase = ReturnModeTypeGraphQL | ReturnModeTypeDataAndErrors | ReturnModeTypeData

export type ReturnModeTypeGraphQL = 'graphql'

export type ReturnModeTypeData = 'data'

export type ReturnModeTypeDataAllErrors = 'dataAndAllErrors'
export type ReturnModeTypeDataAndErrors = 'dataAndErrors'

export type ReturnModeTypeDataAndSchemaErrors = 'dataAndSchemaErrors'
export type ReturnModeTypeSuccessData = 'successData'

export type OptionsInput = {
returnMode: ReturnModeType | undefined
Expand All @@ -36,10 +38,52 @@ export type ApplyInputDefaults<Input extends OptionsInput> = {
}

// dprint-ignore
export type ReturnMode<$Config extends Config, $Data, $DataRaw = undefined> =
export type ReturnModeRootType<$Config extends Config, $Index extends Schema.Index, $Data extends object> =
$Config['returnMode'] extends 'graphql' ? ExecutionResult<$Data> :
$Config['returnMode'] extends 'data' ? $Data :
$Config['returnMode'] extends 'successData' ? { [$Key in keyof $Data]: ExcludeSchemaErrors<$Index, $Data[$Key]> } :
$Data | GraphQLExecutionResultError

// dprint-ignore
export type ReturnModeRootField<$Config extends Config, $Index extends Schema.Index, $Data, $DataRaw = undefined> =
$Config['returnMode'] extends 'graphql' ? ExecutionResult<$DataRaw extends undefined ? $Data : $DataRaw> :
$Config['returnMode'] extends 'data' ? $Data :
$Config['returnMode'] extends 'successData' ? ExcludeSchemaErrors<$Index, $Data> :
$Data | GraphQLExecutionResultError

export type ExcludeSchemaErrors<$Index extends Schema.Index, $Data> = Exclude<
$Data,
$Index['error']['objectsTypename'][keyof $Index['error']['objectsTypename']]
>

export type OrThrowifyConfig<$Config extends Config> = $Config['returnMode'] extends 'graphql' ? $Config
: SetProperty<$Config, 'returnMode', 'data'>
: SetProperty<$Config, 'returnMode', 'successData'>

/**
* We inject __typename select when:
* 1. using schema errors
* 2. using return mode successData
*/

type TypenameSelection = { __typename: true }

// dprint-ignore
export type CreateSelectionTypename<$Config extends Config, $Index extends Schema.Index> =
IsNeedSelectionTypename<$Config, $Index> extends true ? TypenameSelection : {} // eslint-disable-line

// dprint-ignore
export type IsNeedSelectionTypename<$Config extends Config, $Index extends Schema.Index> =
$Config['returnMode'] extends 'successData' ? GlobalRegistry.HasSchemaErrors<$Index['name']> extends true ? true :
false :
false
export type AugmentRootTypeSelectionWithTypename<
$Config extends Config,
$Index extends Schema.Index,
$RootTypeName extends Schema.RootTypeName,
$Selection extends object,
> = IsNeedSelectionTypename<$Config, $Index> extends true ? {
[$Key in keyof $Selection]:
& $Selection[$Key]
& ($Key extends keyof $Index['error']['rootResultFields'][$RootTypeName] ? TypenameSelection : {}) // eslint-disable-line
}
: $Selection
16 changes: 11 additions & 5 deletions src/client/RootTypeMethods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,14 @@ import type { OperationName } from '../lib/graphql.js'
import type { Exact } from '../lib/prelude.js'
import type { TSError } from '../lib/TSError.js'
import type { InputFieldsAllNullable, Schema } from '../Schema/__.js'
import type { Config, OrThrowifyConfig, ReturnMode } from './Config.js'
import type {
AugmentRootTypeSelectionWithTypename,
Config,
CreateSelectionTypename,
OrThrowifyConfig,
ReturnModeRootField,
ReturnModeRootType,
} from './Config.js'
import type { ResultSet } from './ResultSet/__.js'
import type { SelectionSet } from './SelectionSet/__.js'

Expand Down Expand Up @@ -54,10 +61,9 @@ export type RootTypeMethods<$Config extends Config, $Index extends Schema.Index,
// dprint-ignore
type RootMethod<$Config extends Config, $Index extends Schema.Index, $RootTypeName extends Schema.RootTypeName> =
<$SelectionSet extends object>(selectionSet: Exact<$SelectionSet, SelectionSet.Root<$Index, $RootTypeName>>) =>
Promise<ReturnMode<$Config, ResultSet.Root<$SelectionSet, $Index, $RootTypeName>>>
Promise<ReturnModeRootType<$Config, $Index, ResultSet.Root<AugmentRootTypeSelectionWithTypename<$Config,$Index,$RootTypeName,$SelectionSet>, $Index, $RootTypeName>>>

// dprint-ignore
// type RootTypeFieldMethod<$Config extends OptionsInputDefaults, $Index extends Schema.Index, $RootTypeName extends Schema.RootTypeName, $RootTypeFieldName extends string> =
type RootTypeFieldMethod<$Context extends RootTypeFieldContext> =
RootTypeFieldMethod_<$Context, $Context['Field']['type']>

Expand All @@ -73,7 +79,7 @@ type RootTypeFieldMethod_<$Context extends RootTypeFieldContext, $Type extends S
// dprint-ignore
type ObjectLikeFieldMethod<$Context extends RootTypeFieldContext> =
<$SelectionSet>(selectionSet: Exact<$SelectionSet, SelectionSet.Field<$Context['Field'], $Context['Index'], { hideDirectives: true }>>) =>
Promise<ReturnModeForFieldMethod<$Context, ResultSet.Field<$SelectionSet, $Context['Field'], $Context['Index']>>>
Promise<ReturnModeForFieldMethod<$Context, ResultSet.Field<$SelectionSet & CreateSelectionTypename<$Context['Config'],$Context['Index']>, $Context['Field'], $Context['Index']>>>

// dprint-ignore
type ScalarFieldMethod<$Context extends RootTypeFieldContext> =
Expand All @@ -82,4 +88,4 @@ type ScalarFieldMethod<$Context extends RootTypeFieldContext> =
(() => Promise<ReturnModeForFieldMethod<$Context, ResultSet.Field<true, $Context['Field'], $Context['Index']>>>)
// dprint-ignore
type ReturnModeForFieldMethod<$Context extends RootTypeFieldContext, $Data> =
ReturnMode<$Context['Config'], $Data, { [k in $Context['RootTypeFieldName']] : $Data }>
ReturnModeRootField<$Context['Config'], $Context['Index'], $Data, { [k in $Context['RootTypeFieldName']] : $Data }>
2 changes: 1 addition & 1 deletion src/client/SelectionSet/_.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export * from './SelectionSet.js'
export * from './toGraphQLDocumentString.js'
export * as Print from './toGraphQLDocumentString.js'
Original file line number Diff line number Diff line change
Expand Up @@ -669,6 +669,25 @@ exports[`args > Query 4`] = `
"
`;

exports[`enum > Query 1`] = `
"
{
"result": {
"$": {
"case": "Object1"
},
"__typename": true
}
}
--------------
{
result(case: Object1) {
__typename
}
}
"
`;

exports[`other > Query 1`] = `
"
{
Expand Down
15 changes: 13 additions & 2 deletions src/client/SelectionSet/toGraphQLDocumentString.test.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import { parse, print } from 'graphql'
import { describe, expect, test } from 'vitest'
import type { Index } from '../../../tests/_/schema/generated/Index.js'
import { $Index as schemaIndex } from '../../../tests/_/schema/generated/SchemaRuntime.js'
import type { SelectionSet } from './__.js'
import { toGraphQLDocumentSelectionSet } from './toGraphQLDocumentString.js'
import type { Context } from './toGraphQLDocumentString.js'
import { rootTypeSelectionSet } from './toGraphQLDocumentString.js'

// eslint-disable-next-line
// @ts-ignore
type Q = SelectionSet.Query<Index>
const s = (selectionSet: Q) => selectionSet
const prepareResult = (ss: Q) => {
const graphqlDocumentString = toGraphQLDocumentSelectionSet(ss as any)
const context: Context = { schemaIndex, config: { returnMode: `data` } }
const graphqlDocumentString = rootTypeSelectionSet(context, schemaIndex[`Root`][`Query`], ss as any)
// Should parse, ensures is syntactically valid graphql document.
const document = parse(graphqlDocumentString)
const graphqlDocumentStringFormatted = print(document)
Expand All @@ -21,6 +24,14 @@ const prepareResult = (ss: Q) => {
return beforeAfter
}

describe(`enum`, () => {
test.each([
s({ result: { $: { case: `Object1` }, __typename: true } }),
])(`Query`, (ss) => {
expect(prepareResult(ss)).toMatchSnapshot()
})
})

describe(`union`, () => {
test.each([
s({ unionFooBar: { __typename: true } }),
Expand Down

0 comments on commit 80e050c

Please sign in to comment.