sikanhe / gqtx

Code-first Typescript GraphQL Server without codegen or metaprogramming
458 stars 13 forks source link

Nullable input type #55

Open emcell opened 3 years ago

emcell commented 3 years ago

I don't understand how to create a nullable input field


const t = createTypesFactory<ResolverContext>();
t.inputObjectType<{ asdf: string }>({
  name: 'test',
  fields: () => ({
    asdf: {
      type: t.NonNullInput(t.String),
      description: 'asdf',
    },
  }),
});

Am I missing something or is the function or type t.Input(t.String), just missing?

n1ru4l commented 3 years ago

You have to wrap input field with t.arg: https://github.com/n1ru4l/character-overlay/blob/b7f3188a4a67241c2a1a928653dd01a833f6aa77/server/schema.ts#L187-L193

const GraphQLUpdateCharacterInput = t.inputObjectType({
  name: "UpdateCharacterInput",
  fields: () => ({
    editHash: t.arg(t.NonNullInput(t.String)),
    updates: t.arg(t.NonNullInput(GraphQLCharacterUpdateFields)),
  }),
});
n1ru4l commented 3 years ago

@emcell Did this resolve your question?

emcell commented 3 years ago

Thank you for your answer. I understand it, but have not tried it yet. I'm working on this project in the next week again.

n1ru4l commented 3 years ago

@sikanhe Is the distinction between NonNullInput and NonNull actually necessary or could we apply some TypeScript magic to make both use-cases inferring the correct type?

Ericnr commented 3 years ago

@n1ru4l that'd be nice. I'm currently trying to wrap gqtx's api into an api which is more pleasing and with better defaults (imo) ex:

  string: <T extends boolean = false>(opts?: {
    nullable: T;
  }): T extends true ? Scalar<string | null> : OutputType<Context, string> => {
    if (opts?.nullable === true) return t.String;
    return t.NonNull(t.String);
  },

  list: <Src>(ofType: OutputType<Context, Src>): OutputType<Context, Src[]> =>
    t.NonNull(t.List(ofType)),

problem is I cant use either string and list in inputObjectType because of t.NonNullInput and t.ListInput

n1ru4l commented 3 years ago

@Ericnr I did some changes over here: https://github.com/sikanhe/gqtx/pull/52

Contributions are welcome :)

Ericnr commented 3 years ago

I'm not great with complex types, but I explored it for a little bit with a type that would be returned by .List and .NonNull

export type AllType<Ctx, Src, IsInput extends boolean> = IsInput extends true
  ? InputType<Src>
  : OutputType<Ctx, Src>;

in the end I couldn't get it to work, which is always my frustration when trying to do complicated TS stuff

Ericnr commented 3 years ago

here's the fork if anyone's interested https://github.com/Ericnr/gqtx/commit/d37c034ba29eab6f4e9ae9c0b148192d04bd5f34

tonyxiao commented 2 years ago
  fields: () => ({
    asdf: {
      type: t.NonNullInput(t.String),
      description: 'asdf',
    },
  }),

Is this a valid way of defining? I need to explicitly return an array for fields and cannot use the object hash format.

visomi-dev commented 1 year ago

Here my worked code, I expect help:

import type { Field } from 'gqtx';

import { createTypesFactory } from 'gqtx';

import type { GraphQLContext } from '~/entities/graphql';
import type { Color as ColorName } from '~/entities/ui';

type Color = { name: ColorName; value: string | null };

export type Fields = [
  Field<GraphQLContext, unknown, any, {}>,
  ...Field<GraphQLContext, unknown, any, {}>[],
];

export const typesFactory = createTypesFactory<GraphQLContext>();

export const ColorNameEnum = typesFactory.enumType<ColorName>({
  name: 'ColorName',
  values: [
    { name: 'pink', value: 'pink' },
    { name: 'purple', value: 'purple' },
    { name: 'blue', value: 'blue' },
    { name: 'green', value: 'green' },
    { name: 'yellow', value: 'yellow' },
    { name: 'custom', value: 'custom' },
  ],
});

export const ColorType = typesFactory.objectType<Color>({
  name: 'Color',
  description: 'A color',
  fields: () => [
    typesFactory.field({
      name: 'name',
      type: typesFactory.NonNull(ColorNameEnum),
    }),
    typesFactory.field({
      name: 'value',
      type: typesFactory.String,
    }),
  ],
});

// Here the example you need
export const ColorInputType = typesFactory.inputObjectType<Color>({
  name: 'ColorInput',
  fields: () => ({
    name: {
      type: typesFactory.NonNullInput(ColorNameEnum),
    },
    value: {
      type: typesFactory.String,
    },
  }),
});