Skip to content

Commit

Permalink
refactor: colocate custom scalars logic (#1177)
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonkuhrt authored Oct 9, 2024
1 parent d3ffdc2 commit c580407
Show file tree
Hide file tree
Showing 44 changed files with 542 additions and 472 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,23 @@ ContextualError: There was an error in the core implementation of hook "exchange
at runPipeline (/some/path/to/runPipeline.ts:XX:XX:18)
at async runPipeline (/some/path/to/runPipeline.ts:XX:XX:14)
at async runPipeline (/some/path/to/runPipeline.ts:XX:XX:14)
... 2 lines matching cause stack trace ...
at async Object.run (/some/path/to/main.ts:XX:XX:22)
at async Object.send (/some/path/to/gql.ts:XX:XX:26)
at async <anonymous> (/some/path/to/output_preset__standard-graphql.ts:XX:XX:16) {
context: { hookName: 'exchange', source: 'implementation' },
[cause]: TypeError: Failed to parse URL from ...
at new Request (node:internal/deps/undici/undici:XX:XX)
at Object.run (/some/path/to/core.ts:XX:XX:29)
... 6 lines matching cause stack trace ...
at async <anonymous> (/some/path/to/output_preset__standard-graphql.ts:XX:XX:16) {
... 3 lines matching cause stack trace ...
at async applyBody (/some/path/to/main.ts:XX:XX:22) {
[cause]: TypeError: Invalid URL
at new URL (node:internal/url:XX:XX)
at new Request (node:internal/deps/undici/undici:XX:XX)
at Object.run (/some/path/to/core.ts:XX:XX:29)
at runHook (/some/path/to/runHook.ts:XX:XX:37)
at runPipeline (/some/path/to/runPipeline.ts:XX:XX:8)
at runPipeline (/some/path/to/runPipeline.ts:XX:XX:20)
at async runPipeline (/some/path/to/runPipeline.ts:XX:XX:14)
at async Object.run (/some/path/to/main.ts:XX:XX:22)
at async Object.send (/some/path/to/gql.ts:XX:XX:26)
at async <anonymous> (/some/path/to/output_preset__standard-graphql.ts:XX:XX:16) {
at <anonymous> (/some/path/to/runHook.ts:XX:XX:14)
at onRequest (/some/path/to/extension.ts:XX:XX:32)
at async applyBody (/some/path/to/main.ts:XX:XX:22) {
code: 'ERR_INVALID_URL',
input: '...'
}
Expand Down
2 changes: 1 addition & 1 deletion src/entrypoints/schema.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export * from '../layers/1_Schema/__.js'
export { Select } from '../layers/2_Select/__.js'
export { ResultSet } from '../layers/3_Result/__.js'
export { InferResult } from '../layers/3_InferResult/__.js'
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import type { mergeObjectArray, ValuesOrEmptyObject } from '../../../lib/prelude.js'
import type { Schema } from '../../1_Schema/__.js'
import type { Select } from '../../2_Select/__.js'
import type { SchemaIndex } from '../../4_generator/generators/SchemaIndex.js'
import type { InferField } from './Field.js'
import type { mergeObjectArray, ValuesOrEmptyObject } from '../../lib/prelude.js'
import type { Schema } from '../1_Schema/__.js'
import type { Select } from '../2_Select/__.js'
import type { SchemaIndex } from '../4_generator/generators/SchemaIndex.js'
import type { Field } from './Field.js'

// dprint-ignore
export type InferSelectionSelectAlias<
export type Alias<
$SelectionSet,
$Schema extends SchemaIndex,
$Node extends Schema.Output.Object$2
Expand All @@ -28,7 +28,7 @@ export type InferSelectionSelectAlias<
>

// dprint-ignore
export type InferSelectAlias<
type InferSelectAlias<
$SelectAlias extends Select.SelectAlias.SelectAlias,
$FieldName extends string,
$Schema extends SchemaIndex,
Expand All @@ -55,5 +55,5 @@ type InferSelectAliasOne<
$Schema extends SchemaIndex,
$Node extends Schema.Output.Object$2,
> = {
[_ in $SelectAliasOne[0]]: InferField<$SelectAliasOne[1], $Node['fields'][$FieldName], $Schema>
[_ in $SelectAliasOne[0]]: Field<$SelectAliasOne[1], $Node['fields'][$FieldName], $Schema>
}
Original file line number Diff line number Diff line change
@@ -1,46 +1,48 @@
import type { Simplify } from 'type-fest'
import type { TSError } from '../../../lib/TSError.js'
import type { Schema } from '../../1_Schema/__.js'
import type { Select } from '../../2_Select/__.js'
import type { SchemaIndex } from '../../4_generator/generators/SchemaIndex.js'
import type { InferInterface, InferObject, InferUnion } from './root.js'
import type { TSError } from '../../lib/TSError.js'
import type { Schema } from '../1_Schema/__.js'
import type { Select } from '../2_Select/__.js'
import type { SchemaIndex } from '../4_generator/generators/SchemaIndex.js'
import type { Interface } from './Interface.js'
import type { Object } from './Object.js'
import type { Union } from './Union.js'

// dprint-ignore
export type InferField<$SelectionSet, $Field extends Schema.SomeField, $Schema extends SchemaIndex> =
export type Field<$SelectionSet, $Field extends Schema.SomeField, $Schema extends SchemaIndex> =
Simplify<
$SelectionSet extends Select.Directive.Include.FieldStates.Negative | Select.Directive.Skip.FieldStates.Positive ?
null :
(
| FieldDirectiveInclude<$SelectionSet>
| FieldDirectiveSkip<$SelectionSet>
| InferFieldType<Omit<$SelectionSet, '$'>, $Field['type'], $Schema>
| FieldType<Omit<$SelectionSet, '$'>, $Field['type'], $Schema>
)
>

// dprint-ignore
type InferFieldType<
type FieldType<
$SelectionSet,
$Type extends Schema.Output.Any,
$Schema extends SchemaIndex
> =
$Type extends Schema.__typename<infer $Value> ? $Value :
$Type extends Schema.Output.Nullable<infer $InnerType> ? null | InferFieldType<$SelectionSet, $InnerType, $Schema> :
$Type extends Schema.Output.List<infer $InnerType> ? Array<InferFieldType<$SelectionSet, $InnerType, $Schema>> :
$Type extends Schema.Output.Nullable<infer $InnerType> ? null | FieldType<$SelectionSet, $InnerType, $Schema> :
$Type extends Schema.Output.List<infer $InnerType> ? Array<FieldType<$SelectionSet, $InnerType, $Schema>> :
$Type extends Schema.Enum<infer _, infer $Members> ? $Members[number] :
$Type extends Schema.Scalar.$Any ? ReturnType<$Type['codec']['decode']> :
$Type extends Schema.Object$2 ? InferObject<$SelectionSet, $Schema, $Type> :
$Type extends Schema.Interface ? InferInterface<$SelectionSet, $Schema, $Type> :
$Type extends Schema.Union ? InferUnion<$SelectionSet, $Schema, $Type> :
TSError<'InferFieldType', `Unknown type`, { $Type: $Type; $SelectionSet: $SelectionSet; $Schema:$Schema }>
$Type extends Schema.Object$2 ? Object<$SelectionSet, $Schema, $Type> :
$Type extends Schema.Interface ? Interface<$SelectionSet, $Schema, $Type> :
$Type extends Schema.Union ? Union<$SelectionSet, $Schema, $Type> :
TSError<'FieldType', `Unknown type`, { $Type: $Type; $SelectionSet: $SelectionSet; $Schema:$Schema }>

// dprint-ignore
type FieldDirectiveInclude<$SelectionSet> =
$SelectionSet extends Select.Directive.Include.Field ? $SelectionSet extends Select.Directive.Include.FieldStates.Positive ? never
: null
: never
: null
: never

// dprint-ignore
type FieldDirectiveSkip<$SelectionSet> =
$SelectionSet extends Select.Directive.Skip.Field ? $SelectionSet extends Select.Directive.Skip.FieldStates.Negative ? never
: null
: never
: null
: never
20 changes: 20 additions & 0 deletions src/layers/3_InferResult/InlineFragment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { type GetKeyOr } from '../../lib/prelude.js'
import type { Schema } from '../1_Schema/__.js'
import type { Select } from '../2_Select/__.js'
import type { SchemaIndex } from '../4_generator/generators/SchemaIndex.js'
import type { Object } from './Object.js'

// dprint-ignore
export type InlineFragmentTypeConditional<$SelectionSet, $Node extends Schema.Output.Object$2, $Index extends SchemaIndex> =
$Node extends any // force distribution
? Object<
& GetKeyOr<
$SelectionSet,
`${Select.InlineFragment.TypeConditionalKeyPrefix}${$Node['fields']['__typename']['type']['type']}`,
{}
>
& Select.InlineFragment.OmitInlineFragmentsWithTypeConditions<$SelectionSet>,
$Index,
$Node
>
: never
7 changes: 7 additions & 0 deletions src/layers/3_InferResult/Interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type { Schema } from '../1_Schema/__.js'
import type { SchemaIndex } from '../4_generator/generators/SchemaIndex.js'
import type { InlineFragmentTypeConditional } from './InlineFragment.js'

// dprint-ignore
export type Interface<$SelectionSet, $Index extends SchemaIndex, $Node extends Schema.Output.Interface> =
InlineFragmentTypeConditional<$SelectionSet, $Node['implementors'][number], $Index>
46 changes: 46 additions & 0 deletions src/layers/3_InferResult/Object.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import type { Simplify } from 'type-fest'
import { type StringKeyof } from '../../lib/prelude.js'
import type { TSError } from '../../lib/TSError.js'
import type { Schema } from '../1_Schema/__.js'
import type { Select } from '../2_Select/__.js'
import type { SchemaIndex } from '../4_generator/generators/SchemaIndex.js'
import type { Alias } from './Alias.js'
import type { Field } from './Field.js'
import type { ScalarsWildcard } from './ScalarsWildcard.js'

// dprint-ignore
export type Object<$SelectionSet, $Schema extends SchemaIndex, $Node extends Schema.Output.Object$2> =
Select.SelectScalarsWildcard.IsSelectScalarsWildcard<$SelectionSet> extends true
// todo what about when scalars wildcard is combined with other fields like relations?
? ScalarsWildcard<$SelectionSet, $Schema,$Node>
:
Simplify<(
& SelectionNonSelectAlias<$SelectionSet, $Schema, $Node>
& Alias<$SelectionSet, $Schema, $Node>
)>

// dprint-ignore
type SelectionNonSelectAlias<$SelectionSet , $Schema extends SchemaIndex, $Node extends Schema.Output.Object$2> =
{
[$Select in PickSelectsPositiveIndicatorAndNotSelectAlias<$SelectionSet>]:
$Select extends keyof $Node['fields']
? Field<$SelectionSet[$Select], $Node['fields'][$Select], $Schema>
: Errors.UnknownFieldName<$Select, $Node>
}

// dprint-ignore
export namespace Errors {
export type UnknownFieldName<$FieldName extends string, $Object extends Schema.Object$2 | Schema.Output.RootType> =
TSError<'Object', `field "${$FieldName}" does not exist on object "${$Object['fields']['__typename']['type']['type']}"`>
}

// dprint-ignore
export type PickSelectsPositiveIndicatorAndNotSelectAlias<$SelectionSet> = StringKeyof<{
[
$FieldName in keyof $SelectionSet as $SelectionSet[$FieldName] extends Select.Indicator.Negative
? never
: $SelectionSet[$FieldName] extends any[]
? never
: $FieldName
]: 0
}>
21 changes: 21 additions & 0 deletions src/layers/3_InferResult/ScalarsWildcard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { Schema } from '../1_Schema/__.js'
import type { SchemaIndex } from '../4_generator/generators/SchemaIndex.js'
import type { Field } from './Field.js'

export type ScalarsWildcard<
$SelectionSet,
$Index extends SchemaIndex,
$Node extends Schema.Output.Object$2,
> = {
[$Key in keyof PickScalarFields<$Node>]: Field<$SelectionSet, $Node['fields'][$Key], $Index>
}

// dprint-ignore
type PickScalarFields<$Object extends Schema.Output.Object$2> = {
[
$Key in keyof $Object['fields']
as Schema.Output.UnwrapToNamed<$Object['fields'][$Key]['type']> extends Schema.Hybrid.Scalar.$Any | Schema.Output.__typename
? $Key
: never
]: $Object['fields'][$Key]
}
7 changes: 7 additions & 0 deletions src/layers/3_InferResult/Union.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type { Schema } from '../1_Schema/__.js'
import type { SchemaIndex } from '../4_generator/generators/SchemaIndex.js'
import type { InlineFragmentTypeConditional } from './InlineFragment.js'

// dprint-ignore
export type Union<$SelectionSet, $Index extends SchemaIndex, $Node extends Schema.Output.Union> =
InlineFragmentTypeConditional<$SelectionSet, $Node['members'][number], $Index>
7 changes: 7 additions & 0 deletions src/layers/3_InferResult/_.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export * from './Alias.js'
export * from './Field.js'
export * from './Interface.js'
export * from './Object.js'
export * from './root.js'
export * from './ScalarsWildcard.js'
export * from './Union.js'
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
import type * as Schema from '../../../../tests/_/schemas/kitchen-sink/graffle/modules/SchemaBuildtime.js'
import type { Index } from '../../../../tests/_/schemas/kitchen-sink/graffle/modules/SchemaIndex.js'
import type * as SelectionSets from '../../../../tests/_/schemas/kitchen-sink/graffle/modules/SelectionSets.js'
import { AssertEqual } from '../../../lib/assert-equal.js'
import type { ResultSet } from '../__.js'
import type { PickSelectsPositiveIndicatorAndNotSelectAlias } from './root.js'
import type * as Schema from '../../../tests/_/schemas/kitchen-sink/graffle/modules/SchemaBuildtime.js'
import type { Index } from '../../../tests/_/schemas/kitchen-sink/graffle/modules/SchemaIndex.js'
import type * as SelectionSets from '../../../tests/_/schemas/kitchen-sink/graffle/modules/SelectionSets.js'
import { AssertEqual } from '../../lib/assert-equal.js'
import type { InferResult } from './__.js'
import type { PickSelectsPositiveIndicatorAndNotSelectAlias } from './Object.js'

type $<$SelectionSet extends SelectionSets.Query> = ResultSet.Query<$SelectionSet, Index>
type $<$SelectionSet extends SelectionSets.Query> = InferResult.Query<$SelectionSet, Index>

// dprint-ignore
{

AssertEqual<PickSelectsPositiveIndicatorAndNotSelectAlias<{ a: true }>, 'a'>()
AssertEqual<PickSelectsPositiveIndicatorAndNotSelectAlias<{ a: ['b', true]; b: true }>, 'b'>()

}

// dprint-ignore
{

AssertEqual<$<{ __typename: true }>, { __typename: 'Query' }>()

// Scalar
Expand Down Expand Up @@ -84,8 +88,8 @@ AssertEqual<$<{ id: ['id2', true] }>, { id2: null | string }>()
AssertEqual<$<{ idNonNull: ['id2', true] }>, { id2: string }>()
// multi
AssertEqual<$<{ id: [['id1', true],['id2', true]] }>, { id1: null | string; id2: null | string }>()
// AssertEqual<RS<{ id_as: true }>, { id_as: ResultSet.Errors.UnknownFieldName<'id_as', Schema.Root.Query> }>()
// AssertEqual<RS<{ id_as_$: true }>, { id_as_$: ResultSet.Errors.UnknownFieldName<'id_as_$', Schema.Root.Query> }>()
// AssertEqual<RS<{ id_as: true }>, { id_as: InferResult.Errors.UnknownFieldName<'id_as', Schema.Root.Query> }>()
// AssertEqual<RS<{ id_as_$: true }>, { id_as_$: InferResult.Errors.UnknownFieldName<'id_as_$', Schema.Root.Query> }>()
// union fragment
AssertEqual<$<{ unionFooBar: { ___on_Foo: { id: ['id2', true] } } }>, { unionFooBar: null | {} | { id2: null|string } }>()

Expand Down Expand Up @@ -133,6 +137,6 @@ AssertEqual<$<{ stringWithArgs: { $: { string: '' } } }>, { stringWithArgs: null
// @ts-expect-error invalid query
type Result = $<{ id2: true }>
// unknown field
AssertEqual<Result, { id2: ResultSet.Errors.UnknownFieldName<'id2', Schema.Root.Query> }>()
AssertEqual<Result, { id2: InferResult.Errors.UnknownFieldName<'id2', Schema.Root.Query> }>()

}
1 change: 1 addition & 0 deletions src/layers/3_InferResult/__.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * as InferResult from './_.js'
32 changes: 32 additions & 0 deletions src/layers/3_InferResult/root.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { type ExcludeNull } from '../../lib/prelude.js'
import type { Schema } from '../1_Schema/__.js'
import type { SchemaIndex } from '../4_generator/generators/SchemaIndex.js'
import type { Object } from './Object.js'

export type RootViaObject<
$SelectionSet,
$Schema extends SchemaIndex,
$RootType extends Schema.Output.RootType,
> = Root<
$SelectionSet,
$Schema,
$RootType['fields']['__typename']['type']['type']
>

// dprint-ignore
export type Query<$SelectionSet, $Schema extends SchemaIndex> =
Root<$SelectionSet, $Schema, 'Query'>

// dprint-ignore
export type Mutation<$SelectionSet, $Schema extends SchemaIndex> =
Root<$SelectionSet, $Schema, 'Mutation'>

// dprint-ignore
export type Subscription<$SelectionSet, $Schema extends SchemaIndex> =
Root<$SelectionSet, $Schema, 'Subscription'>

export type Root<
$SelectionSet,
$Schema extends SchemaIndex,
$RootTypeName extends Schema.RootTypeName,
> = Object<$SelectionSet, $Schema, ExcludeNull<$Schema['Root'][$RootTypeName]>>
1 change: 0 additions & 1 deletion src/layers/3_Result/_.ts

This file was deleted.

1 change: 0 additions & 1 deletion src/layers/3_Result/__.ts

This file was deleted.

3 changes: 0 additions & 3 deletions src/layers/3_Result/infer/_.ts

This file was deleted.

Loading

0 comments on commit c580407

Please sign in to comment.