Skip to content

Commit

Permalink
improve: prefix data term in return mode (#966)
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonkuhrt authored Jul 5, 2024
1 parent f72ceb0 commit ee3781d
Show file tree
Hide file tree
Showing 9 changed files with 172 additions and 177 deletions.
16 changes: 8 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,8 @@
"@types/express": "^4.17.21",
"@types/json-bigint": "^1.0.4",
"@types/node": "^20.14.9",
"@typescript-eslint/eslint-plugin": "^7.14.1",
"@typescript-eslint/parser": "^7.14.1",
"@typescript-eslint/eslint-plugin": "^7.15.0",
"@typescript-eslint/parser": "^7.15.0",
"apollo-server-express": "^3.13.0",
"body-parser": "^1.20.2",
"doctoc": "^2.2.1",
Expand All @@ -123,7 +123,7 @@
"eslint-plugin-deprecation": "^3.0.0",
"eslint-plugin-only-warn": "^1.1.0",
"eslint-plugin-prefer-arrow": "^1.2.3",
"eslint-plugin-simple-import-sort": "^12.1.0",
"eslint-plugin-simple-import-sort": "^12.1.1",
"eslint-plugin-tsdoc": "^0.3.0",
"eslint-typescript": "^1.1.0",
"express": "^4.19.2",
Expand All @@ -132,14 +132,14 @@
"graphql-scalars": "^1.23.0",
"graphql-tag": "^2.12.6",
"graphql-upload-minimal": "^1.6.1",
"graphql-yoga": "^5.5.0",
"graphql-yoga": "^5.6.0",
"jsdom": "^24.1.0",
"json-bigint": "^1.0.0",
"publint": "^0.2.8",
"tsx": "^4.16.0",
"type-fest": "^4.20.1",
"typescript": "^5.5.2",
"typescript-eslint": "^7.14.1",
"tsx": "^4.16.2",
"type-fest": "^4.21.0",
"typescript": "^5.5.3",
"typescript-eslint": "^7.15.0",
"vitest": "^1.6.0"
}
}
277 changes: 139 additions & 138 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/layers/3_SelectionSet/encode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ export const resolveObjectLikeFieldValue = (
* Inject __typename field for result fields that are missing it.
*/
// dprint-ignore
if (rootTypeName && context.config.returnMode === `successData` && context.schemaIndex.error.rootResultFields[rootTypeName][fieldName.actual]) {
if (rootTypeName && context.config.returnMode === `dataSuccess` && context.schemaIndex.error.rootResultFields[rootTypeName][fieldName.actual]) {
(ss as Record<string, boolean>)[`__typename`] = true
}
return `${toGraphQLFieldName(fieldName)} ${resolveFieldValue(context, schemaField, ss)}`
Expand Down
15 changes: 7 additions & 8 deletions src/layers/5_client/Config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import type { SelectionSet } from '../3_SelectionSet/__.js'
export type ReturnModeType =
| ReturnModeTypeGraphQL
| ReturnModeTypeGraphQLSuccess
| ReturnModeTypeSuccessData
| ReturnModeTypeDataSuccess
| ReturnModeTypeData
| ReturnModeTypeDataAndErrors

Expand All @@ -26,8 +26,7 @@ export type ReturnModeTypeData = 'data'

export type ReturnModeTypeDataAndErrors = 'dataAndErrors'

// todo rename to dataSuccess
export type ReturnModeTypeSuccessData = 'successData'
export type ReturnModeTypeDataSuccess = 'dataSuccess'

export type OptionsInput = {
returnMode: ReturnModeType | undefined
Expand All @@ -50,14 +49,14 @@ export type ApplyInputDefaults<Input extends OptionsInput> = {
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]> } :
$Config['returnMode'] extends 'dataSuccess' ? { [$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> :
$Config['returnMode'] extends 'dataSuccess' ? ExcludeSchemaErrors<$Index, $Data> :
$Data | GraphQLExecutionResultError

export type ExcludeSchemaErrors<$Index extends Schema.Index, $Data> = Exclude<
Expand All @@ -66,12 +65,12 @@ export type ExcludeSchemaErrors<$Index extends Schema.Index, $Data> = Exclude<
>

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

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

type TypenameSelection = { __typename: true }
Expand All @@ -82,7 +81,7 @@ export type CreateSelectionTypename<$Config extends Config, $Index extends Schem

// dprint-ignore
export type IsNeedSelectionTypename<$Config extends Config, $Index extends Schema.Index> =
$Config['returnMode'] extends 'successData' ? GlobalRegistry.HasSchemaErrorsViaName<$Index['name']> extends true ? true :
$Config['returnMode'] extends 'dataSuccess' ? GlobalRegistry.HasSchemaErrorsViaName<$Index['name']> extends true ? true :
false :
false

Expand Down
9 changes: 2 additions & 7 deletions src/layers/5_client/client.extend.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,13 @@ const headers = { 'x-foo': 'bar' }

// todo each extension added should copy, not mutate the client

describe(`entrypoint request`, () => {
test(`can add header to request`, async ({ fetch }) => {
describe(`entrypoint pack`, () => {
test(`can add header`, async ({ fetch }) => {
fetch.mockImplementationOnce(async (input: Request) => {
expect(input.headers.get('x-foo')).toEqual(headers['x-foo'])
return createResponse({ data: { id: db.id } })
})
const client2 = client.use(async ({ pack }) => {
// todo should be raw input types but rather resolved
// todo should be URL instance?
// todo these input type tests should be moved down to Anyware
// expectTypeOf(exchange).toEqualTypeOf<NetworkRequestHook>()
// expect(exchange.input).toEqual({ url: 'https://foo', document: `query { id \n }` })
return await pack({ input: { ...pack.input, headers } })
})
expect(await client2.query.id()).toEqual(db.id)
Expand Down
4 changes: 2 additions & 2 deletions src/layers/5_client/client.input.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ test(`works`, () => {
Graffle.create({ schema, returnMode: `graphql` })
Graffle.create({ schema, returnMode: `data` })
Graffle.create({ schema, returnMode: `dataAndErrors` })
Graffle.create({ schema, returnMode: `successData` })
Graffle.create({ schema, returnMode: `dataSuccess` })

QueryOnly.create({ schema, returnMode: `graphql` })
QueryOnly.create({ schema, returnMode: `data` })
QueryOnly.create({ schema, returnMode: `dataAndErrors` })
// @ts-expect-error bad returnMode
QueryOnly.create({ schema, name: `QueryOnly`, returnMode: `successData` })
QueryOnly.create({ schema, name: `QueryOnly`, returnMode: `dataSuccess` })
})
4 changes: 2 additions & 2 deletions src/layers/5_client/client.returnMode.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ describe('data', () => {
})

// dprint-ignore
describe('successData', () => {
const graffle = Graffle.create({ schema, returnMode: 'successData' })
describe('dataSuccess', () => {
const graffle = Graffle.create({ schema, returnMode: 'dataSuccess' })
test(`document.run`, async () => {
expectTypeOf(graffle.document({ x: { query: { id: true } } }).run()).resolves.toEqualTypeOf<{ id: string | null }>()
})
Expand Down
4 changes: 2 additions & 2 deletions src/layers/5_client/client.returnMode.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ describe('dataAndErrors', () => {
})

// dprint-ignore
describe('successData', () => {
const graffle = Graffle.create({ schema, returnMode: 'successData' })
describe('dataSuccess', () => {
const graffle = Graffle.create({ schema, returnMode: 'dataSuccess' })
test(`document.run`, async () => {
expect(graffle.document({ x: { query: { id: true } } }).run()).resolves.toEqual({ id: db.id })
})
Expand Down
18 changes: 9 additions & 9 deletions src/layers/5_client/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import type {
Config,
ReturnModeType,
ReturnModeTypeBase,
ReturnModeTypeSuccessData,
ReturnModeTypeDataSuccess,
} from './Config.js'
import type { DocumentFn } from './document.js'
import type { GetRootTypeMethods } from './RootTypeMethods.js'
Expand Down Expand Up @@ -89,7 +89,7 @@ export type InputRaw = {
export type InputPrefilled<$Schema extends GlobalRegistry.SchemaList> = $Schema extends any ? {
returnMode?:
| ReturnModeTypeBase
| (GlobalRegistry.HasSchemaErrors<$Schema> extends true ? ReturnModeTypeSuccessData : never)
| (GlobalRegistry.HasSchemaErrors<$Schema> extends true ? ReturnModeTypeDataSuccess : never)
} & InputRaw
: never

Expand Down Expand Up @@ -217,7 +217,7 @@ export const createInternal = (
const isSelectedTypeScalarOrTypeName = selectedNamedType.kind === `Scalar` || selectedNamedType.kind === `typename` // todo fix type here, its valid
const isFieldHasArgs = Boolean(context.schemaIndex.Root[rootTypeName]?.fields[rootTypeFieldName]?.args)
// We should only need to add __typename for result type fields, but the return handler doesn't yet know how to look beyond a plain object type so we have to add all those cases here.
const needsTypenameAdded = context.config.returnMode === `successData`
const needsTypenameAdded = context.config.returnMode === `dataSuccess`
&& (selectedNamedType.kind === `Object` || selectedNamedType.kind === `Interface`
|| selectedNamedType.kind === `Union`)
const rootTypeFieldSelectionSet = isSelectedTypeScalarOrTypeName
Expand All @@ -231,7 +231,7 @@ export const createInternal = (
} as GraphQLObjectSelection)
if (result instanceof Error) return result
return context.config.returnMode === `data` || context.config.returnMode === `dataAndErrors`
|| context.config.returnMode === `successData`
|| context.config.returnMode === `dataSuccess`
// @ts-expect-error
? result[rootTypeFieldName]
: result
Expand Down Expand Up @@ -382,7 +382,7 @@ const handleReturn = (
switch (context.config.returnMode) {
case `graphqlSuccess`:
case `dataAndErrors`:
case `successData`:
case `dataSuccess`:
case `data`: {
if (result instanceof Error || (result.errors && result.errors.length > 0)) {
const error = result instanceof Error ? result : (new Errors.ContextualAggregateError(
Expand All @@ -391,14 +391,14 @@ const handleReturn = (
result.errors!,
))
if (
context.config.returnMode === `data` || context.config.returnMode === `successData`
context.config.returnMode === `data` || context.config.returnMode === `dataSuccess`
|| context.config.returnMode === `graphqlSuccess`
) throw error
return error
}

if (isTypedContext(context)) {
if (context.config.returnMode === `successData`) {
if (context.config.returnMode === `dataSuccess`) {
if (!isPlainObject(result.data)) throw new Error(`Expected data to be an object.`)
const schemaErrors = Object.entries(result.data).map(([rootFieldName, rootFieldValue]) => {
// todo this check would be nice but it doesn't account for aliases right now. To achieve this we would
Expand Down Expand Up @@ -444,10 +444,10 @@ const handleReturn = (
}

const applyOrThrowToContext = <$Context extends Context>(context: $Context): $Context => {
if (context.config.returnMode === `successData` || context.config.returnMode === `graphqlSuccess`) {
if (context.config.returnMode === `dataSuccess` || context.config.returnMode === `graphqlSuccess`) {
return context
}
const newMode = context.config.returnMode === `graphql` ? `graphqlSuccess` : `successData`
const newMode = context.config.returnMode === `graphql` ? `graphqlSuccess` : `dataSuccess`
return updateContextConfig(context, { returnMode: newMode })
}

Expand Down

0 comments on commit ee3781d

Please sign in to comment.