{"id":19580446,"url":"https://github.com/vinpac/nexus-typeorm-plugin","last_synced_at":"2025-04-27T08:32:18.395Z","repository":{"id":36204154,"uuid":"210489353","full_name":"vinpac/nexus-typeorm-plugin","owner":"vinpac","description":null,"archived":false,"fork":false,"pushed_at":"2023-01-04T11:14:59.000Z","size":2219,"stargazers_count":14,"open_issues_count":20,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-19T08:15:42.182Z","etag":null,"topics":["api","database","dataloader","graphql","nexus","typeorm","typescript"],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vinpac.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-09-24T01:58:25.000Z","updated_at":"2023-03-08T16:09:37.000Z","dependencies_parsed_at":"2023-01-16T23:30:49.497Z","dependency_job_id":null,"html_url":"https://github.com/vinpac/nexus-typeorm-plugin","commit_stats":null,"previous_names":["vinpac/typeql"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vinpac%2Fnexus-typeorm-plugin","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vinpac%2Fnexus-typeorm-plugin/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vinpac%2Fnexus-typeorm-plugin/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vinpac%2Fnexus-typeorm-plugin/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vinpac","download_url":"https://codeload.github.com/vinpac/nexus-typeorm-plugin/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251112549,"owners_count":21538162,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","database","dataloader","graphql","nexus","typeorm","typescript"],"created_at":"2024-11-11T07:26:05.953Z","updated_at":"2025-04-27T08:32:16.218Z","avatar_url":"https://github.com/vinpac.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![CircleCI](https://circleci.com/gh/vinpac/nexus-typeorm-plugin/tree/master.svg?style=svg)](https://circleci.com/gh/vinpac/nexus-typeorm-plugin/tree/master)\n\n# nexus-typeorm-plugin\n\nCreate a [GraphQL.js](https://github.com/graphql/graphql-js) schema from your [TypeORM](https://github.com/typeorm/typeorm) Entities.\n\n## Usage\n\nHere's example [Apollo Server](https://github.com/apollographql/apollo-server) with a `posts` resolver to paginate over the `Post` entity.\n\n```typescript\nimport 'reflect-metadata'\n\nimport * as path from 'path'\nimport dotenv from 'dotenv'\nimport { ApolloServer } from 'apollo-server'\nimport {\n  Column,\n  ManyToOne,\n  OneToMany,\n  PrimaryGeneratedColumn,\n  createConnection,\n  ManyToMany,\n} from 'typeorm'\nimport {\n  NexusEntity,\n  nexusTypeORMPlugin,\n  entityType,\n  FindManyResolveFnContext,\n} from 'nexus-typeorm-plugin'\nimport { queryType, makeSchema } from 'nexus'\nimport { propertyPathToAlias } from 'nexus-typeorm-plugin/dist/query-builder'\n\ndotenv.config()\n\n@NexusEntity()\nexport class User {\n  @PrimaryGeneratedColumn()\n  public id!: number\n\n  @Column()\n  public name: string\n\n  @Column()\n  public age: number\n\n  @OneToMany(() =\u003e Post, post =\u003e post.author)\n  public posts: Post[]\n\n  @ManyToMany(() =\u003e Category, category =\u003e category.posts)\n  public categories?: Category[]\n\n  constructor(name: string, age: number, posts: Post[], categories?: Category[]) {\n    this.name = name\n    this.age = age\n    this.posts = posts\n    this.categories = categories\n  }\n}\n\n@NexusEntity()\nclass Category {\n  @PrimaryGeneratedColumn()\n  public id!: number\n\n  @Column()\n  public name: string\n\n  @ManyToMany(() =\u003e Post, post =\u003e post.categories)\n  public posts?: Post[]\n\n  constructor(name: string, posts?: Post[]) {\n    this.name = name\n    this.posts = posts\n  }\n}\n\n@NexusEntity()\nclass Post {\n  @PrimaryGeneratedColumn()\n  public id!: number\n\n  @Column()\n  public title: string\n\n  @ManyToOne(() =\u003e User, user =\u003e user.posts)\n  public author: User\n\n  @ManyToMany(() =\u003e Category, category =\u003e category.posts)\n  public categories?: Category[]\n\n  constructor(title: string, author: User, categories?: Category[]) {\n    this.title = title\n    this.author = author\n    this.categories = categories\n  }\n}\n\nconst { DB_HOST, DB_TYPE, DB_NAME, DB_USERNAME, DB_PASSWORD, DB_PORT } = process.env\n\nasync function main() {\n  await createConnection({\n    entities: [User, Post, Category],\n    host: DB_HOST,\n    type: DB_TYPE as 'postgres',\n    database: DB_NAME,\n    username: DB_USERNAME,\n    password: DB_PASSWORD,\n    port: DB_PORT ? parseInt(DB_PORT as any, 10) : undefined,\n    synchronize: true,\n  })\n\n  const query = queryType({\n    definition: t =\u003e {\n      t.crud.posts()\n      t.crud.users('listUsers')\n      t.crud.users('listUsersWithNameJohn', {\n        resolve: (ctx: FindManyResolveFnContext\u003cUser, User, any, any\u003e) =\u003e {\n          ctx.args.where = {\n            ...ctx.args.where,\n            name: 'John',\n          }\n\n          return ctx.next(ctx)\n        },\n      })\n      t.crudField('listPostsWithCategoryFoo', {\n        entity: 'Post',\n        type: 'Post',\n        method: 'findMany',\n        resolve: ctx =\u003e {\n          return ctx.next({\n            ...ctx,\n            queryBuilderConfig: config =\u003e ({\n              ...config,\n              joins: [\n                ...(config.joins || []),\n                {\n                  type: 'inner',\n                  select: false,\n                  propertyPath: 'categories',\n                  where: {\n                    expression: `${propertyPathToAlias('categories')}.id = :id`,\n                    params: { id: 1 },\n                  },\n                },\n              ],\n            }),\n          })\n        },\n      })\n    },\n  })\n\n  const schema = makeSchema({\n    types: [nexusTypeORMPlugin(), query, entityType(User), entityType(Post), entityType(Category)],\n    outputs: {\n      schema: path.resolve('generated', 'schema.graphql'),\n      typegen: path.resolve('generated', 'nexus-typegen.ts'),\n    },\n  })\n  new ApolloServer({ schema }).listen(3000)\n  console.log('Server running at http://localhost:3000')\n}\n\nmain().catch(error =\u003e {\n  // eslint-disable-next-line no-console\n  console.error(error)\n  process.exit(1)\n})\n```\n\n## Features\n\n### Entity field definition\n\nHelps you create an `objectType` for an entity faster and simpler.\n\n```typescript\nexport const User = entityType\u003cUser\u003e(User, {\n  definition: t =\u003e {\n    t.entity.id()\n    // Either t.entityField('name') or\n    t.entity.name()\n\n    // Either t.crudField('followers', { entity: 'UserFollow', ... or\n    t.crud.userFollows('followers', {\n      type: 'User',\n      resolve: async (source: User, args, ctx, info, next) =\u003e {\n        const follows = await next(source, args, ctx, info)\n\n        return getConnection()\n          .getRepository(User)\n          .createQueryBuilder()\n          .where('id IN (:...ids)', {\n            ids: follows.map((follow: UserFollows) =\u003e follow.followerId),\n          })\n          .getMany()\n      },\n    })\n  },\n})\n```\n\n# CRUD\n\n## Find Many\n\nCreates a field that resolves into a list of instances of the choosen entity. It includes the `first`, `last`, `after`, `before`, `skip`, `where`, and the `orderBy` arguments.\n\n```typescript\nexport const Query = queryType({\n  definition(t) {\n    t.crud.posts()\n    t.crud.users('listUsers')\n    t.crud.users('listUsersWithNameJohn', {\n      resolve: ctx =\u003e {\n        ctx.args.where = {\n          ...ctx.args.where,\n          name: 'John',\n        }\n\n        return ctx.next(ctx)\n      },\n    })\n    t.crudField('listPostsWithCategoryFoo', {\n      entity: 'Post',\n      method: 'findMany',\n      resolve: ctx =\u003e {\n        return ctx.next({\n          ...ctx,\n          queryBuilderConfig: config =\u003e ({\n            ...config,\n            joins: [\n              ...config.joins,\n              {\n                type: 'inner',\n                select: false,\n                propertyPath: 'categories',\n                where: {\n                  expression: `${propertyPathToAlias('categories')}.id = :id`,\n                  params: { id: 1 },\n                },\n              },\n            ],\n          }),\n        })\n      },\n    })\n  },\n})\n```\n\n### Find One\n\nCreates a field that resolves into one entity instance. It includes the `where` and the `orderBy` arguments.\n\n```typescript\nexport const Query = queryType({\n  definition(t) {\n    t.crud.user()\n    t.crud.post()\n    t.crud.post('postsByUserId', {\n      args: args =\u003e ({ ...args, userId: stringArg({ nullable: false }) }),\n      resolve: ctx =\u003e\n        ctx.next({\n          ...ctx,\n          args: { ...ctx.args, where: { ...ctx.args.where, userId: ctx.args.userId } },\n        }),\n    })\n  },\n})\n```\n\n### Create One\n\nCreates a field that resolves into one entity instance. It includes the `where` and the `orderBy` arguments.\n\n```typescript\nexport const Mutation = mutationType({\n  definition(t) {\n    t.crud.createOneUser()\n    t.crud.createOnePost()\n  },\n})\n```\n\n**Example**\n\n```graphql\nmutation {\n  createOneUser(\n    data: {\n      name: \"John with posts\"\n      age: 42\n      type: NORMAL\n      profile: { create: { slug: \"john-with-posts\", displayName: \"displayName\" } }\n      posts: {\n        create: [\n          {\n            title: \"created post\"\n            isPublic: false\n            categories: { create: [{ name: \"create category 1\" }, { name: \"create category 2\" }] }\n          }\n          { title: \"created post 2\", isPublic: true }\n        ]\n      }\n    }\n  ) {\n    id\n    name\n    age\n    profile {\n      slug\n      displayName\n    }\n    posts {\n      title\n      isPublic\n      categories {\n        name\n      }\n    }\n  }\n}\n```\n\n### Add business logic\n\n```typescript\nexport const Mutation = mutationType({\n  definition(t) {\n    t.crud.createOneUser('addUser', {\n      args: {\n        name: stringArg({ nullable: false }),\n        postsIds: stringArg({ list: true, nullable: false }),\n      },\n      resolve: ctx =\u003e {\n        const { name, postsIds } = ctx.args\n        return ctx.next({\n          ...ctx,\n          args: {\n            data: {\n              name,\n              posts: {\n                connect: { id_in: postsIds },\n              },\n            },\n          },\n        })\n      },\n    })\n  },\n})\n```\n\n### Auto join\n\nIn order to speed up requests and decrease the number of queries made to the database, this plugin analyzes each graphql query and makes the necessary joins automatically.\n\n```gql\n{\n  user {\n    id\n    posts {\n      id\n    }\n  }\n}\n```\n\nGenerates a SQL query that left joins Post.\n\n```SQL\nSELECT * from User ... LEFT JOIN Post\n```\n\nCheckout the `tests/` directory to see examples.\n\n## Contributing\n\nTo run tests create `.env` file at the project root and fill it with database information.\n\n```bash\nTEST_DB_HOST=localhost\nTEST_DB_TYPE=mysql\nTEST_DB_NAME=test\nTEST_DB_USERNAME=root\nTEST_DB_PASSWORD=mypassword\nTEST_DB_PORT=3316\n```\n\nIf you want, you can run a Docker container of MySQL for test based on `.env` file.\n\n```bash\ndocker-compose up -d\n```\n\nNow you can run tests.\n\n```bash\nyarn test\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvinpac%2Fnexus-typeorm-plugin","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvinpac%2Fnexus-typeorm-plugin","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvinpac%2Fnexus-typeorm-plugin/lists"}