Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ts-client): returnMode successData #804

Merged
merged 9 commits into from
Apr 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading