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

Generating type names end of specified suffix for avoiding conflict of name of GraphQLObjectType #115

Open
oooplz opened this issue Aug 25, 2021 · 4 comments
Labels
needs/discussion Something needs deciding, new info changes issue scope/spec, unforeseen challenges, etc. type/feat Add a new capability or enhance an existing one

Comments

@oooplz
Copy link

oooplz commented Aug 25, 2021

nexus-prisma is awesome lib for me. I am hoping nexus-prisma more popular, so some helpful suggestion be written in below:

  1. Using nexus-prisma generates code of name end of specified suffix, User_、Post_、UserWhereUniqueInput_、PostWhereUniqueInput_、UserWhereInput_ and PostWhereInput_, for avoiding conflict of name of GraphQLObjectType.

  2. Providing inputObjectType and objectType Function be expose.

  3. Below code can implement namedescriptionfilterField and excludeField features etc.

How to use:

const User = objectType(User_)
const Post = objectType(Post_, {
  name: "Post",
  description: 'customDescription',
  // description: (it) => `prefix_${it}`,
  fields: [Post_.id, Post_.author]
  // fields: (it) => _.omit(it, 'id'),
  // fields: (it) => _.pick(it, 'id', 'author'),
})

const schema = makeSchema({
  types: { User, Post },
  contextType: {
    module: require.resolve('./context'),
    export: 'Context',
  },
  sourceTypes: {
    modules: [
      {
        module: '@prisma/client',
        alias: 'prisma',
      },
    ],
  },
})

Generating below code:

import { list, nonNull, nullable } from 'nexus'

export const User_ = {
  $name: 'User',
  $description: undefined,
  id: {
    name: 'id',
    type: nullable('ID'),
    description: undefined,
    resolve: undefined,
  },
  posts: {
    name: 'posts',
    type: nonNull(list(nonNull('Post'))),
    description: undefined,
    resolve: undefined,
  },
}

export const Post_ = {
  $name: 'Post',
  $description: undefined,
  id: {
    name: 'id',
    type: nullable('ID'),
    description: undefined,
    resolve: undefined,
  },
  author: {
    name: 'author',
    type: nullable('User'),
    description: undefined,
    resolve: undefined,
  },
}

export const UserWhereUniqueInput_ = {
  $name: 'UserWhereUniqueInput',
  $description: undefined,
  id: {
    name: 'id',
    type: nullable('ID'),
    description: undefined,
  },
  posts: {
    name: 'posts',
    type: nullable('PostWhereUniqueInput'),
    description: undefined,
  },
}

export const PostWhereUniqueInput_ = {
  $name: 'PostWhereUniqueInput',
  $description: undefined,
  id: {
    name: 'id',
    type: nullable('ID'),
    description: undefined,
  },
  author: {
    name: 'author',
    type: nullable('UserWhereUniqueInput'),
    description: undefined,
  },
}

// export const UserWhereInput_
// export const PostWhereInput_
// export const UserCreateInput_
// export const PostCreateInput_
// export const UserUpdateInput_
// export const PostUpdateInput_
// export const UserOrderBy_
// export const PostOrderBy_

Implementation of isInputField and inputObjectType function

import * as NexusCore from 'nexus/dist/core'
import { inputObjectType as nexusInputObjectType, objectType as nexusObjectType } from 'nexus/dist/core'

interface InputType {
  readonly $name: string
  readonly $description?: string

  readonly [key: string]: InputField | string | undefined
}

interface InputField {
  readonly name: string
  readonly type: NexusCore.NexusNullDef<any> | NexusCore.NexusNonNullDef<any> | NexusCore.NexusListDef<any>
  readonly description?: string
}

function isInputField(source: InputField | string | undefined): source is InputField {
  return typeof source === 'object'
}

export function inputObjectType(inputType: InputType) {
  return nexusInputObjectType({
    name: inputType.$name,
    description: inputType.$description,
    definition(t) {
      Object.values(inputType)
        .filter(isInputField)
        .forEach((it) => t.field(it))
    },
  })
}

export interface ObjectType {
  readonly $name: string
  readonly $description?: string

  readonly [key: string]: ObjectField | string | undefined
}

interface ObjectField {
  readonly name: string
  readonly type: NexusCore.NexusNullDef<any> | NexusCore.NexusNonNullDef<any> | NexusCore.NexusListDef<any>
  readonly description?: string
  readonly resolve: NexusCore.FieldResolver<any, any> | undefined
}

function isObjectField(source: ObjectField | string | undefined): source is ObjectField {
  return typeof source === 'object'
}

interface ObjectTypeConfig {
  readonly name?: string | ((name: string) => string)
  readonly description?: string | ((description?: string) => string)
  readonly fields?:
    | ObjectField[]
    | { string: ObjectField }
    | ((fields: { string: ObjectField }) => { string: ObjectField })
}

export function objectType(objectType: ObjectType, config?: ObjectTypeConfig) {
  let name: string
  let description: string | undefined
  let fields: ObjectField[]

  if (typeof config?.name === 'string') {
    name = config?.name
  } else if (config?.name instanceof Function) {
    name = config?.name(objectType.$name)
  } else {
    name = objectType.$name
  }

  if (typeof config?.description === 'string') {
    description = config?.description
  } else if (config?.description instanceof Function) {
    description = config?.description(objectType.$description)
  } else {
    description = objectType.$description
  }

  if (config?.fields && Array.isArray(config?.fields)) {
    fields = config?.fields
  } else if (typeof config?.fields === 'object') {
    fields = Object.values(config?.fields)
  } else if (config?.fields instanceof Function) {
    const x = Object.fromEntries(Object.entries(objectType).filter(([key, value]) => isObjectField(value))) as {
      string: ObjectField
    }
    fields = Object.values(config?.fields(x))
  } else {
    fields = Object.values(objectType).filter(isObjectField)
  }

  return nexusObjectType({
    name,
    description,
    definition(t) {
      fields.forEach((it) => t.field(it))
    },
  })
}
@jasonkuhrt
Copy link
Contributor

Using nexus-prisma generates code of name end of specified suffix, User_、Post_、UserWhereUniqueInput_、PostWhereUniqueInput_、UserWhereInput_ and PostWhereInput_, for avoiding conflict of name of GraphQLObjectType.

This can be achieved with namespace importing

import * as NexusPrisma from 'nexus-prisma'

const User = objectType(NexusPrisma.User)

I am open to adding an internal namespace to make auto-import trivial.

I am open to what this namespace could be called, a good name here (other than NexusPrisma) is unclear to me.

@jasonkuhrt
Copy link
Contributor

Providing inputObjectType and objectType Function be expose.

Please open an issue on Nexus about how to support this. I think it would be less confusing if the building blocks for this were made in core. Otherwise NP will have a similar but different API to N.

@jasonkuhrt jasonkuhrt added needs/discussion Something needs deciding, new info changes issue scope/spec, unforeseen challenges, etc. type/feat Add a new capability or enhance an existing one labels Aug 26, 2021
@oooplz
Copy link
Author

oooplz commented Aug 27, 2021

This can be achieved with namespace importing

import * as NexusPrisma from 'nexus-prisma'

const User = objectType(NexusPrisma.User)

I am open to adding an internal namespace to make auto-import trivial.

I am open to what this namespace could be called, a good name here (other than NexusPrisma) is unclear to me.

Thanks very much for your replied.

@oooplz
Copy link
Author

oooplz commented Aug 27, 2021

Please open an issue on Nexus about how to support this. I think it would be less confusing if the building blocks for this were made in core. Otherwise NP will have a similar but different API to N.

It is so hard to articulate by text that we need time to tidy it -- explaining inputObjectType and objectType is how to be supported.

Thanks you again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs/discussion Something needs deciding, new info changes issue scope/spec, unforeseen challenges, etc. type/feat Add a new capability or enhance an existing one
Projects
None yet
Development

No branches or pull requests

2 participants