@pothos/plugin-prisma 0.15.1 → 0.16.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. package/.turbo/turbo-build.log +5 -5
  2. package/.turbo/turbo-test.log +8 -7
  3. package/.turbo/turbo-type.log +5 -0
  4. package/CHANGELOG.md +24 -0
  5. package/README.md +3 -3
  6. package/esm/cursors.d.ts +0 -0
  7. package/esm/cursors.d.ts.map +0 -0
  8. package/esm/cursors.js +0 -0
  9. package/esm/cursors.js.map +0 -0
  10. package/esm/field-builder.d.ts +0 -0
  11. package/esm/field-builder.d.ts.map +1 -1
  12. package/esm/field-builder.js +5 -3
  13. package/esm/field-builder.js.map +1 -1
  14. package/esm/generator.d.ts +0 -0
  15. package/esm/generator.d.ts.map +0 -0
  16. package/esm/generator.js +1 -0
  17. package/esm/generator.js.map +1 -1
  18. package/esm/global-types.d.ts +5 -4
  19. package/esm/global-types.d.ts.map +1 -1
  20. package/esm/global-types.js +0 -0
  21. package/esm/global-types.js.map +0 -0
  22. package/esm/index.d.ts +0 -0
  23. package/esm/index.d.ts.map +0 -0
  24. package/esm/index.js +0 -0
  25. package/esm/index.js.map +0 -0
  26. package/esm/loader-map.d.ts +0 -0
  27. package/esm/loader-map.d.ts.map +0 -0
  28. package/esm/loader-map.js +0 -0
  29. package/esm/loader-map.js.map +0 -0
  30. package/esm/model-loader.d.ts +2 -1
  31. package/esm/model-loader.d.ts.map +1 -1
  32. package/esm/model-loader.js +23 -11
  33. package/esm/model-loader.js.map +1 -1
  34. package/esm/node-ref.d.ts +4 -2
  35. package/esm/node-ref.d.ts.map +1 -1
  36. package/esm/node-ref.js +3 -2
  37. package/esm/node-ref.js.map +1 -1
  38. package/esm/object-ref.d.ts +7 -0
  39. package/esm/object-ref.d.ts.map +1 -0
  40. package/esm/object-ref.js +5 -0
  41. package/esm/object-ref.js.map +1 -0
  42. package/esm/prisma-field-builder.d.ts +6 -0
  43. package/esm/prisma-field-builder.d.ts.map +1 -1
  44. package/esm/prisma-field-builder.js +33 -5
  45. package/esm/prisma-field-builder.js.map +1 -1
  46. package/esm/refs.d.ts +4 -2
  47. package/esm/refs.d.ts.map +1 -1
  48. package/esm/refs.js +2 -1
  49. package/esm/refs.js.map +1 -1
  50. package/esm/schema-builder.d.ts +0 -0
  51. package/esm/schema-builder.d.ts.map +0 -0
  52. package/esm/schema-builder.js +8 -11
  53. package/esm/schema-builder.js.map +1 -1
  54. package/esm/types.d.ts +15 -5
  55. package/esm/types.d.ts.map +1 -1
  56. package/esm/types.js +0 -0
  57. package/esm/types.js.map +0 -0
  58. package/esm/util/index.d.ts +0 -0
  59. package/esm/util/index.d.ts.map +0 -0
  60. package/esm/util/index.js +0 -0
  61. package/esm/util/index.js.map +0 -0
  62. package/esm/util/map-includes.d.ts +1 -0
  63. package/esm/util/map-includes.d.ts.map +1 -1
  64. package/esm/util/map-includes.js +23 -7
  65. package/esm/util/map-includes.js.map +1 -1
  66. package/esm/util/merge-includes.d.ts +0 -0
  67. package/esm/util/merge-includes.d.ts.map +0 -0
  68. package/esm/util/merge-includes.js +0 -0
  69. package/esm/util/merge-includes.js.map +0 -0
  70. package/lib/cursors.d.ts +0 -0
  71. package/lib/cursors.d.ts.map +0 -0
  72. package/lib/cursors.js +0 -0
  73. package/lib/cursors.js.map +0 -0
  74. package/lib/field-builder.d.ts +0 -0
  75. package/lib/field-builder.d.ts.map +1 -1
  76. package/lib/field-builder.js +5 -3
  77. package/lib/field-builder.js.map +1 -1
  78. package/lib/generator.d.ts +0 -0
  79. package/lib/generator.d.ts.map +0 -0
  80. package/lib/generator.js +1 -0
  81. package/lib/generator.js.map +1 -1
  82. package/lib/global-types.d.ts +5 -4
  83. package/lib/global-types.d.ts.map +1 -1
  84. package/lib/global-types.js +0 -0
  85. package/lib/global-types.js.map +0 -0
  86. package/lib/index.d.ts +0 -0
  87. package/lib/index.d.ts.map +0 -0
  88. package/lib/index.js +0 -0
  89. package/lib/index.js.map +0 -0
  90. package/lib/loader-map.d.ts +0 -0
  91. package/lib/loader-map.d.ts.map +0 -0
  92. package/lib/loader-map.js +0 -0
  93. package/lib/loader-map.js.map +0 -0
  94. package/lib/model-loader.d.ts +2 -1
  95. package/lib/model-loader.d.ts.map +1 -1
  96. package/lib/model-loader.js +23 -11
  97. package/lib/model-loader.js.map +1 -1
  98. package/lib/node-ref.d.ts +4 -2
  99. package/lib/node-ref.d.ts.map +1 -1
  100. package/lib/node-ref.js +2 -1
  101. package/lib/node-ref.js.map +1 -1
  102. package/lib/object-ref.d.ts +7 -0
  103. package/lib/object-ref.d.ts.map +1 -0
  104. package/lib/object-ref.js +9 -0
  105. package/lib/object-ref.js.map +1 -0
  106. package/lib/prisma-field-builder.d.ts +6 -0
  107. package/lib/prisma-field-builder.d.ts.map +1 -1
  108. package/lib/prisma-field-builder.js +32 -4
  109. package/lib/prisma-field-builder.js.map +1 -1
  110. package/lib/refs.d.ts +4 -2
  111. package/lib/refs.d.ts.map +1 -1
  112. package/lib/refs.js +2 -1
  113. package/lib/refs.js.map +1 -1
  114. package/lib/schema-builder.d.ts +0 -0
  115. package/lib/schema-builder.d.ts.map +0 -0
  116. package/lib/schema-builder.js +8 -11
  117. package/lib/schema-builder.js.map +1 -1
  118. package/lib/types.d.ts +15 -5
  119. package/lib/types.d.ts.map +1 -1
  120. package/lib/types.js +0 -0
  121. package/lib/types.js.map +0 -0
  122. package/lib/util/index.d.ts +0 -0
  123. package/lib/util/index.d.ts.map +0 -0
  124. package/lib/util/index.js +0 -0
  125. package/lib/util/index.js.map +0 -0
  126. package/lib/util/map-includes.d.ts +1 -0
  127. package/lib/util/map-includes.d.ts.map +1 -1
  128. package/lib/util/map-includes.js +24 -8
  129. package/lib/util/map-includes.js.map +1 -1
  130. package/lib/util/merge-includes.d.ts +0 -0
  131. package/lib/util/merge-includes.d.ts.map +0 -0
  132. package/lib/util/merge-includes.js +0 -0
  133. package/lib/util/merge-includes.js.map +0 -0
  134. package/package.json +8 -7
  135. package/src/field-builder.ts +7 -5
  136. package/src/generator.ts +7 -0
  137. package/src/global-types.ts +17 -7
  138. package/src/model-loader.ts +30 -13
  139. package/src/node-ref.ts +7 -2
  140. package/src/object-ref.ts +8 -0
  141. package/src/prisma-field-builder.ts +52 -3
  142. package/src/refs.ts +5 -3
  143. package/src/schema-builder.ts +5 -7
  144. package/src/types.ts +63 -35
  145. package/src/util/map-includes.ts +35 -4
  146. package/tsconfig.tsbuildinfo +1 -1
  147. package/generated.ts +0 -54
@@ -1,16 +1,16 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.queryFromInfo = exports.includesFromSelectionSet = void 0;
3
+ exports.queryFromInfo = exports.includesFromSelectionSet = exports.SELF_RELATION = void 0;
4
4
  /* eslint-disable no-underscore-dangle */
5
5
  /* eslint-disable no-param-reassign */
6
6
  /* eslint-disable no-continue */
7
- /* eslint-disable @typescript-eslint/no-use-before-define */
8
7
  const graphql_1 = require("graphql");
9
8
  const values_1 = require("graphql/execution/values");
10
9
  const loader_map_1 = require("../loader-map");
11
10
  const _1 = require(".");
11
+ exports.SELF_RELATION = '@self';
12
12
  function handleField(ctx, info, fields, selection, includes, counts, mappings, indirectMap) {
13
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
13
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
14
14
  if (selection.name.value.startsWith('__')) {
15
15
  return;
16
16
  }
@@ -56,7 +56,7 @@ function handleField(ctx, info, fields, selection, includes, counts, mappings, i
56
56
  const args = (0, values_1.getArgumentValues)(field, selection, info.variableValues);
57
57
  query = query(args, ctx);
58
58
  }
59
- const existingInclude = includes[relationName];
59
+ const existingInclude = relationName === exports.SELF_RELATION ? { include: includes } : includes[relationName];
60
60
  query = { ...query, include: newIncludes };
61
61
  if (typeof existingInclude === 'object') {
62
62
  query = (0, _1.mergeIncludes)(existingInclude, query);
@@ -64,20 +64,36 @@ function handleField(ctx, info, fields, selection, includes, counts, mappings, i
64
64
  return;
65
65
  }
66
66
  }
67
+ if (!mappings[relationName]) {
68
+ mappings[relationName] = [];
69
+ }
67
70
  const nestedIncludes = query.include;
68
71
  const nestedMappings = {};
69
72
  const nestedCounts = {
70
73
  current: {},
71
74
  parent: counts.current,
72
75
  };
73
- if (!mappings[relationName]) {
74
- mappings[relationName] = [];
76
+ if (relationName === exports.SELF_RELATION) {
77
+ mappings[relationName].push({
78
+ field: selection.name.value,
79
+ alias: (_j = selection.alias) === null || _j === void 0 ? void 0 : _j.value,
80
+ mappings: nestedMappings,
81
+ indirectPath: (_k = indirectMap === null || indirectMap === void 0 ? void 0 : indirectMap.path) !== null && _k !== void 0 ? _k : [],
82
+ });
83
+ const { include } = query;
84
+ if (selection.selectionSet) {
85
+ includesFromSelectionSet(ctx, type, info, includes, counts, nestedMappings, selection.selectionSet);
86
+ }
87
+ Object.keys(include).forEach((key) => {
88
+ includes[key] = include[key];
89
+ });
90
+ return;
75
91
  }
76
92
  mappings[relationName].push({
77
93
  field: selection.name.value,
78
- alias: (_j = selection.alias) === null || _j === void 0 ? void 0 : _j.value,
94
+ alias: (_l = selection.alias) === null || _l === void 0 ? void 0 : _l.value,
79
95
  mappings: nestedMappings,
80
- indirectPath: (_k = indirectMap === null || indirectMap === void 0 ? void 0 : indirectMap.path) !== null && _k !== void 0 ? _k : [],
96
+ indirectPath: (_m = indirectMap === null || indirectMap === void 0 ? void 0 : indirectMap.path) !== null && _m !== void 0 ? _m : [],
81
97
  });
82
98
  if (selection.selectionSet) {
83
99
  includesFromSelectionSet(ctx, type, info, nestedIncludes, nestedCounts, nestedMappings, selection.selectionSet);
@@ -1 +1 @@
1
- {"version":3,"file":"map-includes.js","sourceRoot":"","sources":["../../src/util/map-includes.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"map-includes.js","sourceRoot":"","sources":["../../src/util/map-includes.ts"],"names":[],"mappings":"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"}
File without changes
File without changes
File without changes
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pothos/plugin-prisma",
3
- "version": "0.15.1",
3
+ "version": "0.16.2",
4
4
  "description": "A Pothos plugin for more efficient integration with prisma",
5
5
  "main": "./lib/index.js",
6
6
  "types": "./lib/index.d.ts",
@@ -47,12 +47,13 @@
47
47
  "typescript": ">4.5.2"
48
48
  },
49
49
  "devDependencies": {
50
- "@pothos/core": "^3.0.0",
51
- "@pothos/plugin-errors": "^3.0.0",
52
- "@pothos/plugin-relay": "^3.0.0",
53
- "@pothos/test-utils": "^1.0.0",
50
+ "@pothos/core": "3.1.2",
51
+ "@pothos/plugin-errors": "3.0.1",
52
+ "@pothos/plugin-relay": "3.2.0",
53
+ "@pothos/plugin-scope-auth": "3.0.1",
54
+ "@pothos/test-utils": "1.0.0",
54
55
  "@prisma/client": "^3.8.1",
55
- "graphql": "16.2.0",
56
+ "graphql": "16.3.0",
56
57
  "graphql-tag": "^2.12.6",
57
58
  "prisma": "^3.8.1"
58
59
  },
@@ -66,5 +67,5 @@
66
67
  "esm:extensions": "ts-node --compiler-options \"{\\\"module\\\":\\\"commonjs\\\"}\" ../../.config/esm-transformer.ts",
67
68
  "test": "pnpm jest --runInBand"
68
69
  },
69
- "readme": "# Prisma Plugin for Pothos\n\nThis plugin provides tighter integration with prisma, making it easier to define prisma based object\ntypes, and helps solve n+1 queries for relations. It also has integrations for the relay plugin to\nmake defining nodes and connections easy and efficient.\n\n## Disclaimers\n\nThis plugin is experimental, and will have some breaking changes in the future. DO NOT USE this\nplugin unless you are willing to deal with breaking changes in upcoming versions. This plugin may\nintroduce BREAKING changes in minor versions until it's major version has been increased above 0.\n\nThis plugin is NOT required to build graphs backed by prisma models, and I would not recommend using\nit unless you have a solid understanding of how it will construct queries.\n\nThis plugin will allow common queries to be resolved through a single prisma query (prisma may still\nturn this into multiple SQL queries), and provides reasonable, predictable and safe fallbacks for\nmore complex queries and edge cases. That being said, graphql APIs are complex, and it is important\nto understand the queries your API is capable of executing.\n\nThe way this plugin resolves queries is designed to be efficient, while still being predictable and\neasy to understand. Tools that try to automatically generate queries are often hard to understand\nand reason about, so this plugin tries to make things as clear as possible by providing query\noptions to resolvers and a loading user code to initiate the actual queries. The options generally\nonly contain `include`s for nested relations (connection fields provide more complex query options).\nThe exception to this, is that we provide a default resolver for relations that can handle querying\nfor a relation if data was not pre-loaded by a parent field. This query used by this resolver is\nsimple, and described in detail below.\n\nWith this simple approach, we get an API that is easy to understand, but still provides a lot of\nvalue and functionality.\n\n## Example\n\nHere is a quick example of what an API using this plugin might look like. There is a more thorough\nbreakdown of what the methods and options used in the example below.\n\nIf you are looking for an example integrated with the\n[relay plugin](https://pothos-graphql.dev/plugins/relay), see the\n[Relay integration](#relay-integration) section below.\n\n```typescript\nbuilder.prismaObject('User', {\n include: {\n profile: true,\n },\n findUnique: (user) => ({ id: user.id }),\n fields: (t) => ({\n id: t.exposeID('id'),\n email: t.exposeString('email'),\n bio: t.string({\n resolve: (user) => user.profile.bio,\n }),\n posts: t.relation('posts', {\n args: {\n oldestFirst: t.arg.boolean(),\n },\n query: (args, context) => ({\n orderBy: {\n createdAt: args.oldestFirst ? 'asc' : 'desc',\n },\n }),\n }),\n }),\n});\n\nbuilder.prismaObject('Post', {\n findUnique: (post) => ({ id: post.id }),\n fields: (t) => ({\n id: t.exposeID('id'),\n title: t.exposeString('title'),\n author: t.relation('author'),\n }),\n});\n\nbuilder.queryType({\n fields: (t) => ({\n me: t.prismaField({\n type: 'User',\n resolve: async (query, root, args, ctx, info) =>\n prisma.user.findUnique({\n ...query,\n rejectOnNotFound: true,\n where: { id: ctx.userId },\n }),\n }),\n }),\n});\n```\n\nGiven this schema, you would be able to resolve a query like the following with a single prisma\nquery (which will still result in a few optimized SQL queries).\n\n```graphql\nquery {\n me {\n email\n posts {\n title\n author {\n id\n }\n }\n }\n}\n```\n\nA query like\n\n```graphql\nquery {\n me {\n email\n posts {\n title\n author {\n id\n }\n }\n oldPosts: posts(oldestFirst: true) {\n title\n author {\n id\n }\n }\n }\n}\n```\n\nWill result in 2 calls to prisma, one to resolve everything except `oldPosts`, and a second to\nresolve everything inside `oldPosts`. Prisma can only resolve each relation once in a single query,\nso we need a separate to handle the second `posts` relation. This may seem slightly magical, but\nshould be predictable and hopefully easy to understand after reading the documentation below.\n\n## Pothos + Prisma without a plugin\n\nIf you just want learn about the plugin, feel free to skip this section, but understanding how to\nuse prisma without a plugin may be useful for evaluating if this plugin is a good fit for your use\ncase.\n\nUsing prisma without a plugin is relatively straight forward using the `builder.objectRef` method.\n\nThe easiest way to create types backed by prisma looks something like:\n\n```typescript\nimport { Post, PrismaClient, User } from '@prisma/client';\n\nconst db = new PrismaClient();\nconst UserObject = builder.objectRef<User>('User');\nconst PostObject = builder.objectRef<Post>('Post');\n\nUserObject.implement({\n fields: (t) => ({\n id: t.exposeID('id'),\n email: t.exposeString('email'),\n posts: t.field({\n type: [PostObject],\n resolve: (user) =>\n db.post.findMany({\n where: { authorId: user.id },\n }),\n }),\n }),\n});\n\nPostObject.implement({\n fields: (t) => ({\n id: t.exposeID('id'),\n title: t.exposeString('title'),\n author: t.field({\n type: UserObject,\n resolve: (post) =>\n db.user.findUnique({ rejectOnNotFound: true, where: { id: post.authorId } }),\n }),\n }),\n});\n\nbuilder.queryType({\n fields: (t) => ({\n me: t.field({\n type: UserObject,\n resolve: (root, args, ctx) =>\n db.user.findUnique({ rejectOnNotFound: true, where: { id: ctx.userId } }),\n }),\n }),\n});\n```\n\nThis sets up User, and Post objects with a few fields, and a `me` query that returns the current\nuser. There are a few things to note in this setup:\n\n1. We split up the `builder.objectRef` and the `implement` calls, rather than calling\n `builder.objectRef(...).implement(...)`. This prevents typescript from getting tripped up by the\n circular references between posts and users.\n2. We use rejectOnNotFound with our `findUnique` calls because those fields are not nullable.\n Without this option, prisma will return a null if the object is not found. An alternative is to\n mark these fields as nullable.\n3. The refs to our object types are called `UserObject` and `PostObject`, this is because `User` and\n `Post` are the names of the types imported from prisma. We could instead alias the types when we\n import them so we can name the refs to our GraphQL types after the models.\n\nThis setup is fairly simple, but it is easy to see the n+1 issues we might run into. Prisma helps\nwith this by batching queries together, but there are also things we can do in our implementation to\nimprove things.\n\nOne thing we could do if we know we will usually be loading the author any time we load a post is to\nmake the author part of shape required for a post:\n\n```typescript\nconst UserObject = builder.objectRef<User>('User');\n// We add the author here in the objectRef\nconst PostObject = builder.objectRef<Post & { author: User }>('Post');\n\nUserObject.implement({\n fields: (t) => ({\n id: t.exposeID('id'),\n email: t.exposeString('email'),\n posts: t.field({\n type: [PostObject],\n resolve: (user) =>\n db.post.findMany({\n // We now need to include the author when we query for posts\n include: {\n author: true,\n },\n where: { authorId: user.id },\n }),\n }),\n }),\n});\n\nPostObject.implement({\n fields: (t) => ({\n id: t.exposeID('id'),\n title: t.exposeString('title'),\n author: t.field({\n type: UserObject,\n // Now we can just return the author from the post instead of querying for it\n resolve: (post) => post.author,\n }),\n }),\n});\n```\n\nWe may not always want to query for the author though, so we could make the author optional and fall\nback to using a query if it was not provided by the parent resolver:\n\n```typescript\nconst PostObject = builder.objectRef<Post & { author?: User }>('Post');\n\nPostObject.implement({\n fields: (t) => ({\n id: t.exposeID('id'),\n title: t.exposeString('title'),\n author: t.field({\n type: UserObject,\n resolve: (post) =>\n post.author ?? db.user.findUnique({ rejectOnNotFound: true, where: { id: post.authorId } }),\n }),\n }),\n});\n```\n\nWith this setup, a parent resolver has the option to include the author, but we have a fallback\nincase it does not.\n\nThere are other patterns like dataloaders than can be used to reduce n+1 issues, and make your graph\nmore efficient, but they are too complex to describe here.\n\n## Usage\n\n### Install\n\n```bash\nyarn add @pothos/plugin-prisma\n```\n\n### Setup\n\nThis plugin requires a little more setup than other plugins because it integrates with the prisma to\ngenerate some types that help the plugin better understand your prisma schema. Previous versions of\nthis plugin used to infer all required types from the prisma client itself, but this resulted in a\npoor dev experience because the complex types slowed down editors, and some more advanced use cases\ncould not be typed correctly.\n\n#### Add a the `pothos` generator to your prisma schema\n\n```\ngenerator pothos {\n provider = \"prisma-pothos-types\"\n}\n```\n\nNow the types Pothos uses will be generated whenever you re-generate your prisma client. Run the\nfollowing command to re-generate the client and create the new types:\n\n```bash\nnpx prisma generate\n```\n\nadditional options:\n\n- `clientOutput`: Where the generated code will import the PrismaClient from. The default is the\n full path of wherever the client is generated. If you are checking in the generated file, using\n `@prisma/client` is a good option.\n- `output`: Where to write the generated types\n\nExample with more options:\n\n```\ngenerator pothos {\n provider = \"prisma-pothos-types\"\n clientOutput = \"@prisma/client\"\n output = \"./pothos-types.ts\"\n}\n```\n\n#### Set up the builder\n\n```typescript\nimport SchemaBuilder from '@pothos/core';\nimport { PrismaClient } from '@prisma/client';\nimport PrismaPlugin from '@pothos/plugin-prisma';\n// This is the default location for the generator, but this can be customized as described above\n// Using a type only import will help avoid issues with undeclared exports in esm mode\nimport type PrismaTypes from '@pothos/plugin-prisma/generated';\n\nconst prisma = new PrismaClient({});\n\nconst builder = new SchemaBuilder<{\n PrismaTypes: PrismaTypes;\n}>({\n plugins: [PrismaPlugin],\n prisma: {\n client: prisma,\n },\n});\n```\n\nIt is strongly recommended NOT to put your prisma client into `Context`. This will result in slower\ntype-checking and a laggy developer experience in VSCode. See\nhttps://github.com/microsoft/TypeScript/issues/45405 for more details.\n\n### Creating some types with `builder.prismaObject`\n\n`builder.prismaObject` takes 2 arguments:\n\n1. `name`: The name of the prisma model this new type represents\n2. `options`: options for the type being created, this is very similar to the options for any other\n object type\n\n```typescript\nbuilder.prismaObject('User', {\n // Optional name for the object, defaults to the name of the prisma model\n name: 'PostAuthor',\n findUnique: null,\n fields: (t) => ({\n id: t.exposeID('id'),\n email: t.exposeString('email'),\n }),\n});\n\nbuilder.prismaObject('Post', {\n findUnique: null,\n fields: (t) => ({\n id: t.exposeID('id'),\n title: t.exposeString('title'),\n }),\n});\n```\n\nSo far, this is just creating some simple object types. They work just like any other object type in\nPothos. They main advantage of this is that we get the type information without using object refs,\nor needing imports from prisma client.\n\nThe `findUnique` option is described more below.\n\n### Adding prisma fields to non-prisma objects (including Query and Mutation)\n\nThere is a new `t.prismaField` method which can be used to define fields that resolve to your prisma\ntypes:\n\n```typescript\nbuilder.queryType({\n fields: (t) => ({\n me: t.prismaField({\n type: 'User',\n resolve: async (query, root, args, ctx, info) =>\n prisma.user.findUnique({\n ...query,\n rejectOnNotFound: true,\n where: { id: ctx.userId },\n }),\n }),\n }),\n});\n```\n\nThis method works just like th normal `t.field` method with a couple of differences:\n\n1. The `type` option must contain the name of the prisma model (eg. `User` or `[User]` for a list\n field).\n2. The `resolve` function has a new first argument `query` which should be spread into query prisma\n query. This will be used to load data for nested relationships.\n\nYou do not need to use this method, and the `builder.prismaObject` method returns an object ref than\ncan be used like any other object ref (with `t.field`), but using `t.prismaField` will allow you to\ntake advantage of more efficient queries.\n\nThe `query` object will contain an `include` object to pre-load data needed to resolve nested parts\nof the current query. This is based on fields defined with `t.relation` described below.\n\nIf there are no fields using `t.relation` in your query, everything is resolved exactly as it would\nbe without this plugin.\n\n### Adding relations\n\nYou can add fields for relations using the `t.relation` method:\n\n```typescript\nbuilder.prismaObject('User', {\n findUnique: null,\n fields: (t) => ({\n id: t.exposeID('id'),\n email: t.exposeString('email'),\n posts: t.relation('posts', {\n resolve: (query, user) =>\n db.post.findMany({\n ...query,\n where: { authorId: user.id },\n }),\n }),\n }),\n});\n\nbuilder.prismaObject('User', {\n findUnique: null,\n fields: (t) => ({\n id: t.exposeID('id'),\n title: t.exposeString('title'),\n author: t.relation('author', {\n resolve: (query, post) =>\n db.user.findUnique({ ...query, rejectOnNotFound: true, where: { id: post.authorId } }),\n }),\n }),\n});\n```\n\n`t.relation` defines a field that can be pre-loaded by a parent resolver, and most of the time, the\n`resolve` function will NOT be called. This is VERY IMPORTANT to understand, because it is the\nbiggest place where you can introduce inconsistencies into your API with this plugin. The `resolve`\nfunction is used to load the relationship if parent resolver did not pre-load the data needed to\nresolve the field. This happens for a number of reasons:\n\n1. The parent object was not loaded through a field defined with `t.prismaField`, or `t.relation`\n2. The `query` object for the parent field was not spread into the query\n3. The graphql query requested multiple fields that depended on the same relationship (described\n more below)\n\nThese are all okay, and expected situations. Graphql APIs are very flexible, and magically pushing\neverything into a single query is impossible for arbitrary queries. This is why we have a `resolve`\nfunction than can load the relation IF it was not already loaded by the parent.\n\nLike `t.prismaField`, the `resolve` function now as a new first argument that is a query that should\nbe spread into the query, and is used to load nested relationships.\n\n### Find Unique\n\nBecause the `resolve` function is only used as a fallback, it is harder to test, and if done\nincorrectly can introduce inconsistencies. While it shouldn't be too hard to get right, it might be\nbetter to avoid it entirely. To do this, we can let the Prisma plugin generate these resolve\nfunctions for you in a consistent and predictable way. We can do this by providing a findUnique\noption for our object type. Defining a `findUnique` that is not null, will make `resolve` optional.\n\n```typescript\nbuilder.prismaObject('User', {\n findUnique: (user) => ({ id: user.id }),\n fields: (t) => ({\n id: t.exposeID('id'),\n email: t.exposeString('email'),\n posts: t.relation('posts'),\n }),\n});\n\nbuilder.prismaObject('Post', {\n findUnique: (post) => ({ id: post.id }),\n fields: (t) => ({\n id: t.exposeID('id'),\n title: t.exposeString('title'),\n author: t.relation('author'),\n }),\n});\n```\n\nThis greatly simplifies our object types. In these cases, the fallback resolve functions will\nre-load the current object using the `findUnique` as the where clause, and then `include` the\nrelation for the current field. This can produce a slightly less efficient query than a manual\nimplementation because the parent object is re-loaded first, but it will batch multiple\nrelationships into one query, and the findUnique queries should be very fast.\n\nFor example, if a `User` was loaded without pre-loading, and both a `posts` and a `profile` relation\nwhere requested, the generated prisma call would be something like:\n\n```typescript\nprisma.user.findUnique({\n rejectOnNotFound: true,\n where: { id: user.id },\n include: {\n posts: true,\n profile: true,\n },\n});\n```\n\n### Filters, Sorting, and arguments\n\nSo far we have been describing very simple queries without any arguments, filtering, or sorting. For\n`t.prismaField` definitions, you can add arguments to your field like normal, and pass them into\nyour prisma query as needed. For `t.relation` the flow is slightly different because we need to make\nsure we are loading the right data if we are pre-loading data in a parent resolver. We do this by\nadding a `query` option to our field options.\n\n```typescript\nbuilder.prismaObject('User', {\n findUnique: (user) => ({ id: user.id }),\n fields: (t) => ({\n id: t.exposeID('id'),\n email: t.exposeString('email'),\n posts: t.relation('posts', {\n // We can define arguments like any other field\n args: {\n oldestFirst: t.arg.boolean(),\n },\n // Then we can generate our query conditions based on the arguments\n query: (args, context) => ({\n orderBy: {\n createdAt: args.oldestFirst ? 'asc' : 'desc',\n },\n }),\n }),\n }),\n});\n```\n\nThis query will be part of the `query` that gets passed into the first argument of `resolve`\nfunction for `t.relation` and `t.prismaField` based fields, and include things like `where`, `skip`,\n`take`, `orderBy`, etc. The `query` function will be passed the arguments for the field, and the\ncontext for the current request. Because it is used for pre-loading data, and solving n+1 issues, it\ncan not be passed the `parent` object because it may not be loaded yet.\n\nIf your field has a `resolve` method the generated `query` will be passed in as part of the first\narg to your resolve function\n\n```typescript\nbuilder.prismaObject('User', {\n findUnique: null,\n fields: (t) => ({\n id: t.exposeID('id'),\n email: t.exposeString('email'),\n posts: t.relation('posts', {\n // We can define arguments like any other field\n args: {\n oldestFirst: t.arg.boolean(),\n },\n // Then we can generate our query conditions based on the arguments\n query: (args, context) => ({\n orderBy: {\n createdAt: args.oldestFirst ? 'asc' : 'desc',\n },\n }),\n // query here will contain the orderBy (and any other properties returned by the query method)\n resolve: (query, post) => db.post.findMany({ ...query, where: { id: post.authorId } }),\n }),\n }),\n});\n```\n\nIt is VERY IMPORTANT to put all your filtering and sorting into the query method rather than your\nresolver because the resolver is only used as fallback, and any filtering that does not exist in the\nquery method will not be applied correctly. If you have a where in both your query and your\nresolver, you will need to ensure these are merged correctly. It is generally better NOT to use a\ncustom resolver.\n\n### Includes on types\n\nIn some cases, you may want to always pre-load certain relations. This can be helpful for defining\nfields directly on type where the underlying data may come from a related table.\n\n```typescript\nbuilder.prismaObject('User', {\n // This will always include the profile when a user object is loaded. Deeply nested relations can\n // also be included this way.\n include: {\n profile: true,\n },\n findUnique: (user) => ({ id: user.id }),\n fields: (t) => ({\n id: t.exposeID('id'),\n email: t.exposeString('email'),\n bio: t.string({\n // The profile relation will always be loaded, and user will now be typed to include the\n // profile field so you can return the bio from the nested profile relation.\n resolve: (user) => user.profile.bio,\n }),\n }),\n});\n```\n\n### relationCount\n\nPrisma supports querying for\n[relation counts](https://www.prisma.io/docs/concepts/components/prisma-client/aggregation-grouping-summarizing#count-relations)\nwhich allow including counts for relations along side other `includes`. This does not currently\nsupport any filters on the counts, but can give a total count for a relation.\n\n```typescript\nbuilder.prismaObject('User', {\n findUnique: (user) => ({ id: user.id }),\n fields: (t) => ({\n id: t.exposeID('id'),\n postCount: t.relationCount('posts'),\n }),\n});\n```\n\n## Relay integration\n\nThis plugin has extensive integration with the\n[relay plugin](https://pothos-graphql.dev/plugins/relay), which makes creating nodes and connections\nvery easy.\n\n### Example\n\nThe following example is similar to the one above with a few changes:\n\n- the `User` and `Post` objects are now relay nodes\n- the `posts` field on the `User` type is now a relay connection using cursor based pagination\n- there is a new `users` query that is also a relay connection\n\nEverything in this schema is still queryable via a single prisma query. The relay connections\nhandles pre-loading like all the other fields.\n\n```typescript\nbuilder.prismaNode('User', {\n findUnique: (id) => ({ id }),\n id: { resolve: (user) => user.id },\n fields: (t) => ({\n email: t.exposeString('email'),\n posts: t.relatedConnection('posts', {\n cursor: 'id',\n args: {\n oldestFirst: t.arg.boolean(),\n },\n query: (args, context) => ({\n orderBy: {\n createdAt: args.oldestFirst ? 'asc' : 'desc',\n },\n }),\n }),\n }),\n});\n\nbuilder.prismaNode('Post', {\n findUnique: (id) => ({ id }),\n id: { resolve: (post) => post.id },\n fields: (t) => ({\n title: t.exposeString('title'),\n author: t.relation('author'),\n }),\n});\n\nbuilder.queryType({\n fields: (t) => ({\n me: t.prismaField({\n type: 'User',\n resolve: async (query, root, args, ctx, info) =>\n prisma.user.findUnique({\n ...query,\n rejectOnNotFound: true,\n where: { id: ctx.userId },\n }),\n }),\n posts: t.prismaConnection({\n type: 'Post',\n cursor: 'id',\n resolve: (query) => prisma.post.findMany(query),\n }),\n }),\n});\n```\n\n### `prismaNode`\n\nThe `prismaNode` method works just like the `prismaObject` method with a couple of small\ndifferences:\n\n- the `findUnique` function now only receives an id. This is to support relays ability to load nodes\n by id.\n- there is a new `id` option that mirrors the `id` option from `node` method of the relay plugin,\n and must contain a resolve function that returns the id from an instance of the node.\n\n```typescript\nbuilder.prismaNode('Post', {\n // This is used to load the node by id\n findUnique: (id) => ({ id }),\n // This is used to get the id from a node\n id: { resolve: (post) => post.id },\n // fields work just like they do for builder.prismaObject\n fields: (t) => ({\n title: t.exposeString('title'),\n author: t.relation('author'),\n }),\n});\n```\n\n### `prismaConnection`\n\nThe `prismaConnection` method on a field builder can be used to create a relay `connection` field\nthat also pre-loads all the data nested inside that connection.\n\n```typescript\nbuilder.queryType({\n fields: (t) => ({\n posts: t.prismaConnection(\n {\n type: 'Post',\n cursor: 'id',\n resolve: (query, parent, args, context, info) => prisma.post.findMany({ ...query }),\n }),\n {}, // optional options for the Connection type\n {}, // optional options for the Edge type),\n ),\n }),\n});\n```\n\n#### options\n\n- `type`: the name of the prisma model being connected to\n- `cursor`: a `@unique` column of the model being connected to. This is used as the `cursor` option\n passed to prisma.\n- `defaultSize`: (default: 20) The default page size to use if `first` and `last` are not provided.\n- `maxSize`: (default: 100) The maximum number of nodes returned for a connection.\n- `resolve`: Like the resolver for `prismaField`, the first argument is a `query` object that should\n be spread into your prisma query. The `resolve` function should return an array of nodes for the\n connection. The `query` will contain the correct `take`, `skip`, and `cursor` options based on the\n connection arguments (`before`, `after`, `first`, `last`), along with `include` options for nested\n selections.\n\nThe created connection queries currently support the following combinations of connection arguments:\n\n- `first`, `last`, or `before`\n- `first` and `before`\n- `last` and `after`\n\nQueries for other combinations are not as useful, and generally requiring loading all records\nbetween 2 cursors, or between a cursor and the end of the set. Generating query options for these\ncases is more complex and likely very inefficient, so they will currently throw an Error indicating\nthe argument combinations are not supported.\n\n### `relatedConnection`\n\nThe `relatedConnection` method can be used to create a relay `connection` field based on a relation\nof the current model.\n\n```typescript\nbuilder.prismaNode('User', {\n findUnique: (id) => ({ id }),\n id: { resolve: (user) => user.id },\n fields: (t) => ({\n // Connections can be very simple to define\n simplePosts: t.relatedConnection('posts', {\n cursor: 'id',\n }),\n // Or they can include custom arguments, and other options\n posts: t.relatedConnection(\n 'posts',\n {\n cursor: 'id',\n args: {\n oldestFirst: t.arg.boolean(),\n },\n query: (args, context) => ({\n orderBy: {\n createdAt: args.oldestFirst ? 'asc' : 'desc',\n },\n }),\n },\n {}, // optional options for the Connection type\n {}, // optional options for the Edge type),\n ),\n }),\n});\n```\n\n#### options\n\n- `cursor`: a `@unique` column of the model being connected to. This is used as the `cursor` option\n passed to prisma.\n- `defaultSize`: (default: 20) The default page size to use if `first` and `last` are not provided.\n- `maxSize`: (default: 100) The maximum number of nodes returned for a connection.\n- `resolve`: (optional) Used as a fallback when a connection is not pre-loaded. It is optional, and\n generally should NOT be defined manually. If used it works like a combination of the `resolve`\n method of `relation` and `prismaConnection`. The default will use the `findUnique` of the current\n model, with an `include` for the current relation. It is also batched together with other\n relationships to improve query efficiency.\n- `totalCount`: when set to true, this will add a `totalCount` field to the connection object. see\n `relationCount` above for more details.\n"
70
+ "readme": "# Prisma Plugin for Pothos\n\nThis plugin provides tighter integration with prisma, making it easier to define prisma based object\ntypes, and helps solve n+1 queries for relations. It also has integrations for the relay plugin to\nmake defining nodes and connections easy and efficient.\n\n## Disclaimers\n\nThis plugin is experimental, and will have some breaking changes in the future. DO NOT USE this\nplugin unless you are willing to deal with breaking changes in upcoming versions. This plugin may\nintroduce BREAKING changes in minor versions until it's major version has been increased above 0.\n\nThis plugin is NOT required to build graphs backed by prisma models, and I would not recommend using\nit unless you have a solid understanding of how it will construct queries.\n\nThis plugin will allow common queries to be resolved through a single prisma query (prisma may still\nturn this into multiple SQL queries), and provides reasonable, predictable and safe fallbacks for\nmore complex queries and edge cases. That being said, graphql APIs are complex, and it is important\nto understand the queries your API is capable of executing.\n\nThe way this plugin resolves queries is designed to be efficient, while still being predictable and\neasy to understand. Tools that try to automatically generate queries are often hard to understand\nand reason about, so this plugin tries to make things as clear as possible by providing query\noptions to resolvers and a loading user code to initiate the actual queries. The options generally\nonly contain `include`s for nested relations (connection fields provide more complex query options).\nThe exception to this, is that we provide a default resolver for relations that can handle querying\nfor a relation if data was not pre-loaded by a parent field. This query used by this resolver is\nsimple, and described in detail below.\n\nWith this simple approach, we get an API that is easy to understand, but still provides a lot of\nvalue and functionality.\n\n## Example\n\nHere is a quick example of what an API using this plugin might look like. There is a more thorough\nbreakdown of what the methods and options used in the example below.\n\nIf you are looking for an example integrated with the\n[relay plugin](https://pothos-graphql.dev/docs/plugins/relay), see the\n[Relay integration](#relay-integration) section below.\n\n```typescript\nbuilder.prismaObject('User', {\n include: {\n profile: true,\n },\n findUnique: (user) => ({ id: user.id }),\n fields: (t) => ({\n id: t.exposeID('id'),\n email: t.exposeString('email'),\n bio: t.string({\n resolve: (user) => user.profile.bio,\n }),\n posts: t.relation('posts', {\n args: {\n oldestFirst: t.arg.boolean(),\n },\n query: (args, context) => ({\n orderBy: {\n createdAt: args.oldestFirst ? 'asc' : 'desc',\n },\n }),\n }),\n }),\n});\n\nbuilder.prismaObject('Post', {\n findUnique: (post) => ({ id: post.id }),\n fields: (t) => ({\n id: t.exposeID('id'),\n title: t.exposeString('title'),\n author: t.relation('author'),\n }),\n});\n\nbuilder.queryType({\n fields: (t) => ({\n me: t.prismaField({\n type: 'User',\n resolve: async (query, root, args, ctx, info) =>\n prisma.user.findUnique({\n ...query,\n rejectOnNotFound: true,\n where: { id: ctx.userId },\n }),\n }),\n }),\n});\n```\n\nGiven this schema, you would be able to resolve a query like the following with a single prisma\nquery (which will still result in a few optimized SQL queries).\n\n```graphql\nquery {\n me {\n email\n posts {\n title\n author {\n id\n }\n }\n }\n}\n```\n\nA query like\n\n```graphql\nquery {\n me {\n email\n posts {\n title\n author {\n id\n }\n }\n oldPosts: posts(oldestFirst: true) {\n title\n author {\n id\n }\n }\n }\n}\n```\n\nWill result in 2 calls to prisma, one to resolve everything except `oldPosts`, and a second to\nresolve everything inside `oldPosts`. Prisma can only resolve each relation once in a single query,\nso we need a separate to handle the second `posts` relation. This may seem slightly magical, but\nshould be predictable and hopefully easy to understand after reading the documentation below.\n\n## Pothos + Prisma without a plugin\n\nIf you just want learn about the plugin, feel free to skip this section, but understanding how to\nuse prisma without a plugin may be useful for evaluating if this plugin is a good fit for your use\ncase.\n\nUsing prisma without a plugin is relatively straight forward using the `builder.objectRef` method.\n\nThe easiest way to create types backed by prisma looks something like:\n\n```typescript\nimport { Post, PrismaClient, User } from '@prisma/client';\n\nconst db = new PrismaClient();\nconst UserObject = builder.objectRef<User>('User');\nconst PostObject = builder.objectRef<Post>('Post');\n\nUserObject.implement({\n fields: (t) => ({\n id: t.exposeID('id'),\n email: t.exposeString('email'),\n posts: t.field({\n type: [PostObject],\n resolve: (user) =>\n db.post.findMany({\n where: { authorId: user.id },\n }),\n }),\n }),\n});\n\nPostObject.implement({\n fields: (t) => ({\n id: t.exposeID('id'),\n title: t.exposeString('title'),\n author: t.field({\n type: UserObject,\n resolve: (post) =>\n db.user.findUnique({ rejectOnNotFound: true, where: { id: post.authorId } }),\n }),\n }),\n});\n\nbuilder.queryType({\n fields: (t) => ({\n me: t.field({\n type: UserObject,\n resolve: (root, args, ctx) =>\n db.user.findUnique({ rejectOnNotFound: true, where: { id: ctx.userId } }),\n }),\n }),\n});\n```\n\nThis sets up User, and Post objects with a few fields, and a `me` query that returns the current\nuser. There are a few things to note in this setup:\n\n1. We split up the `builder.objectRef` and the `implement` calls, rather than calling\n `builder.objectRef(...).implement(...)`. This prevents typescript from getting tripped up by the\n circular references between posts and users.\n2. We use rejectOnNotFound with our `findUnique` calls because those fields are not nullable.\n Without this option, prisma will return a null if the object is not found. An alternative is to\n mark these fields as nullable.\n3. The refs to our object types are called `UserObject` and `PostObject`, this is because `User` and\n `Post` are the names of the types imported from prisma. We could instead alias the types when we\n import them so we can name the refs to our GraphQL types after the models.\n\nThis setup is fairly simple, but it is easy to see the n+1 issues we might run into. Prisma helps\nwith this by batching queries together, but there are also things we can do in our implementation to\nimprove things.\n\nOne thing we could do if we know we will usually be loading the author any time we load a post is to\nmake the author part of shape required for a post:\n\n```typescript\nconst UserObject = builder.objectRef<User>('User');\n// We add the author here in the objectRef\nconst PostObject = builder.objectRef<Post & { author: User }>('Post');\n\nUserObject.implement({\n fields: (t) => ({\n id: t.exposeID('id'),\n email: t.exposeString('email'),\n posts: t.field({\n type: [PostObject],\n resolve: (user) =>\n db.post.findMany({\n // We now need to include the author when we query for posts\n include: {\n author: true,\n },\n where: { authorId: user.id },\n }),\n }),\n }),\n});\n\nPostObject.implement({\n fields: (t) => ({\n id: t.exposeID('id'),\n title: t.exposeString('title'),\n author: t.field({\n type: UserObject,\n // Now we can just return the author from the post instead of querying for it\n resolve: (post) => post.author,\n }),\n }),\n});\n```\n\nWe may not always want to query for the author though, so we could make the author optional and fall\nback to using a query if it was not provided by the parent resolver:\n\n```typescript\nconst PostObject = builder.objectRef<Post & { author?: User }>('Post');\n\nPostObject.implement({\n fields: (t) => ({\n id: t.exposeID('id'),\n title: t.exposeString('title'),\n author: t.field({\n type: UserObject,\n resolve: (post) =>\n post.author ?? db.user.findUnique({ rejectOnNotFound: true, where: { id: post.authorId } }),\n }),\n }),\n});\n```\n\nWith this setup, a parent resolver has the option to include the author, but we have a fallback\nincase it does not.\n\nThere are other patterns like dataloaders than can be used to reduce n+1 issues, and make your graph\nmore efficient, but they are too complex to describe here.\n\n## Usage\n\n### Install\n\n```bash\nyarn add @pothos/plugin-prisma\n```\n\n### Setup\n\nThis plugin requires a little more setup than other plugins because it integrates with the prisma to\ngenerate some types that help the plugin better understand your prisma schema. Previous versions of\nthis plugin used to infer all required types from the prisma client itself, but this resulted in a\npoor dev experience because the complex types slowed down editors, and some more advanced use cases\ncould not be typed correctly.\n\n#### Add a the `pothos` generator to your prisma schema\n\n```\ngenerator pothos {\n provider = \"prisma-pothos-types\"\n}\n```\n\nNow the types Pothos uses will be generated whenever you re-generate your prisma client. Run the\nfollowing command to re-generate the client and create the new types:\n\n```bash\nnpx prisma generate\n```\n\nadditional options:\n\n- `clientOutput`: Where the generated code will import the PrismaClient from. The default is the\n full path of wherever the client is generated. If you are checking in the generated file, using\n `@prisma/client` is a good option.\n- `output`: Where to write the generated types\n\nExample with more options:\n\n```\ngenerator pothos {\n provider = \"prisma-pothos-types\"\n clientOutput = \"@prisma/client\"\n output = \"./pothos-types.ts\"\n}\n```\n\n#### Set up the builder\n\n```typescript\nimport SchemaBuilder from '@pothos/core';\nimport { PrismaClient } from '@prisma/client';\nimport PrismaPlugin from '@pothos/plugin-prisma';\n// This is the default location for the generator, but this can be customized as described above\n// Using a type only import will help avoid issues with undeclared exports in esm mode\nimport type PrismaTypes from '@pothos/plugin-prisma/generated';\n\nconst prisma = new PrismaClient({});\n\nconst builder = new SchemaBuilder<{\n PrismaTypes: PrismaTypes;\n}>({\n plugins: [PrismaPlugin],\n prisma: {\n client: prisma,\n },\n});\n```\n\nIt is strongly recommended NOT to put your prisma client into `Context`. This will result in slower\ntype-checking and a laggy developer experience in VSCode. See\nhttps://github.com/microsoft/TypeScript/issues/45405 for more details.\n\n### Creating some types with `builder.prismaObject`\n\n`builder.prismaObject` takes 2 arguments:\n\n1. `name`: The name of the prisma model this new type represents\n2. `options`: options for the type being created, this is very similar to the options for any other\n object type\n\n```typescript\nbuilder.prismaObject('User', {\n // Optional name for the object, defaults to the name of the prisma model\n name: 'PostAuthor',\n findUnique: null,\n fields: (t) => ({\n id: t.exposeID('id'),\n email: t.exposeString('email'),\n }),\n});\n\nbuilder.prismaObject('Post', {\n findUnique: null,\n fields: (t) => ({\n id: t.exposeID('id'),\n title: t.exposeString('title'),\n }),\n});\n```\n\nSo far, this is just creating some simple object types. They work just like any other object type in\nPothos. They main advantage of this is that we get the type information without using object refs,\nor needing imports from prisma client.\n\nThe `findUnique` option is described more below.\n\n### Adding prisma fields to non-prisma objects (including Query and Mutation)\n\nThere is a new `t.prismaField` method which can be used to define fields that resolve to your prisma\ntypes:\n\n```typescript\nbuilder.queryType({\n fields: (t) => ({\n me: t.prismaField({\n type: 'User',\n resolve: async (query, root, args, ctx, info) =>\n prisma.user.findUnique({\n ...query,\n rejectOnNotFound: true,\n where: { id: ctx.userId },\n }),\n }),\n }),\n});\n```\n\nThis method works just like th normal `t.field` method with a couple of differences:\n\n1. The `type` option must contain the name of the prisma model (eg. `User` or `[User]` for a list\n field).\n2. The `resolve` function has a new first argument `query` which should be spread into query prisma\n query. This will be used to load data for nested relationships.\n\nYou do not need to use this method, and the `builder.prismaObject` method returns an object ref than\ncan be used like any other object ref (with `t.field`), but using `t.prismaField` will allow you to\ntake advantage of more efficient queries.\n\nThe `query` object will contain an `include` object to pre-load data needed to resolve nested parts\nof the current query. This is based on fields defined with `t.relation` described below.\n\nIf there are no fields using `t.relation` in your query, everything is resolved exactly as it would\nbe without this plugin.\n\n### Adding relations\n\nYou can add fields for relations using the `t.relation` method:\n\n```typescript\nbuilder.prismaObject('User', {\n findUnique: null,\n fields: (t) => ({\n id: t.exposeID('id'),\n email: t.exposeString('email'),\n posts: t.relation('posts', {\n resolve: (query, user) =>\n db.post.findMany({\n ...query,\n where: { authorId: user.id },\n }),\n }),\n }),\n});\n\nbuilder.prismaObject('User', {\n findUnique: null,\n fields: (t) => ({\n id: t.exposeID('id'),\n title: t.exposeString('title'),\n author: t.relation('author', {\n resolve: (query, post) =>\n db.user.findUnique({ ...query, rejectOnNotFound: true, where: { id: post.authorId } }),\n }),\n }),\n});\n```\n\n`t.relation` defines a field that can be pre-loaded by a parent resolver, and most of the time, the\n`resolve` function will NOT be called. This is VERY IMPORTANT to understand, because it is the\nbiggest place where you can introduce inconsistencies into your API with this plugin. The `resolve`\nfunction is used to load the relationship if parent resolver did not pre-load the data needed to\nresolve the field. This happens for a number of reasons:\n\n1. The parent object was not loaded through a field defined with `t.prismaField`, or `t.relation`\n2. The `query` object for the parent field was not spread into the query\n3. The graphql query requested multiple fields that depended on the same relationship (described\n more below)\n\nThese are all okay, and expected situations. Graphql APIs are very flexible, and magically pushing\neverything into a single query is impossible for arbitrary queries. This is why we have a `resolve`\nfunction than can load the relation IF it was not already loaded by the parent.\n\nLike `t.prismaField`, the `resolve` function now as a new first argument that is a query that should\nbe spread into the query, and is used to load nested relationships.\n\n### Find Unique\n\nBecause the `resolve` function is only used as a fallback, it is harder to test, and if done\nincorrectly can introduce inconsistencies. While it shouldn't be too hard to get right, it might be\nbetter to avoid it entirely. To do this, we can let the Prisma plugin generate these resolve\nfunctions for you in a consistent and predictable way. We can do this by providing a findUnique\noption for our object type. Defining a `findUnique` that is not null, will make `resolve` optional.\n\n```typescript\nbuilder.prismaObject('User', {\n findUnique: (user) => ({ id: user.id }),\n fields: (t) => ({\n id: t.exposeID('id'),\n email: t.exposeString('email'),\n posts: t.relation('posts'),\n }),\n});\n\nbuilder.prismaObject('Post', {\n findUnique: (post) => ({ id: post.id }),\n fields: (t) => ({\n id: t.exposeID('id'),\n title: t.exposeString('title'),\n author: t.relation('author'),\n }),\n});\n```\n\nThis greatly simplifies our object types. In these cases, the fallback resolve functions will\nre-load the current object using the `findUnique` as the where clause, and then `include` the\nrelation for the current field. This can produce a slightly less efficient query than a manual\nimplementation because the parent object is re-loaded first, but it will batch multiple\nrelationships into one query, and the findUnique queries should be very fast.\n\nFor example, if a `User` was loaded without pre-loading, and both a `posts` and a `profile` relation\nwhere requested, the generated prisma call would be something like:\n\n```typescript\nprisma.user.findUnique({\n rejectOnNotFound: true,\n where: { id: user.id },\n include: {\n posts: true,\n profile: true,\n },\n});\n```\n\n### Filters, Sorting, and arguments\n\nSo far we have been describing very simple queries without any arguments, filtering, or sorting. For\n`t.prismaField` definitions, you can add arguments to your field like normal, and pass them into\nyour prisma query as needed. For `t.relation` the flow is slightly different because we need to make\nsure we are loading the right data if we are pre-loading data in a parent resolver. We do this by\nadding a `query` option to our field options.\n\n```typescript\nbuilder.prismaObject('User', {\n findUnique: (user) => ({ id: user.id }),\n fields: (t) => ({\n id: t.exposeID('id'),\n email: t.exposeString('email'),\n posts: t.relation('posts', {\n // We can define arguments like any other field\n args: {\n oldestFirst: t.arg.boolean(),\n },\n // Then we can generate our query conditions based on the arguments\n query: (args, context) => ({\n orderBy: {\n createdAt: args.oldestFirst ? 'asc' : 'desc',\n },\n }),\n }),\n }),\n});\n```\n\nThis query will be part of the `query` that gets passed into the first argument of `resolve`\nfunction for `t.relation` and `t.prismaField` based fields, and include things like `where`, `skip`,\n`take`, `orderBy`, etc. The `query` function will be passed the arguments for the field, and the\ncontext for the current request. Because it is used for pre-loading data, and solving n+1 issues, it\ncan not be passed the `parent` object because it may not be loaded yet.\n\nIf your field has a `resolve` method the generated `query` will be passed in as part of the first\narg to your resolve function\n\n```typescript\nbuilder.prismaObject('User', {\n findUnique: null,\n fields: (t) => ({\n id: t.exposeID('id'),\n email: t.exposeString('email'),\n posts: t.relation('posts', {\n // We can define arguments like any other field\n args: {\n oldestFirst: t.arg.boolean(),\n },\n // Then we can generate our query conditions based on the arguments\n query: (args, context) => ({\n orderBy: {\n createdAt: args.oldestFirst ? 'asc' : 'desc',\n },\n }),\n // query here will contain the orderBy (and any other properties returned by the query method)\n resolve: (query, post) => db.post.findMany({ ...query, where: { id: post.authorId } }),\n }),\n }),\n});\n```\n\nIt is VERY IMPORTANT to put all your filtering and sorting into the query method rather than your\nresolver because the resolver is only used as fallback, and any filtering that does not exist in the\nquery method will not be applied correctly. If you have a where in both your query and your\nresolver, you will need to ensure these are merged correctly. It is generally better NOT to use a\ncustom resolver.\n\n### Includes on types\n\nIn some cases, you may want to always pre-load certain relations. This can be helpful for defining\nfields directly on type where the underlying data may come from a related table.\n\n```typescript\nbuilder.prismaObject('User', {\n // This will always include the profile when a user object is loaded. Deeply nested relations can\n // also be included this way.\n include: {\n profile: true,\n },\n findUnique: (user) => ({ id: user.id }),\n fields: (t) => ({\n id: t.exposeID('id'),\n email: t.exposeString('email'),\n bio: t.string({\n // The profile relation will always be loaded, and user will now be typed to include the\n // profile field so you can return the bio from the nested profile relation.\n resolve: (user) => user.profile.bio,\n }),\n }),\n});\n```\n\n### relationCount\n\nPrisma supports querying for\n[relation counts](https://www.prisma.io/docs/concepts/components/prisma-client/aggregation-grouping-summarizing#count-relations)\nwhich allow including counts for relations along side other `includes`. This does not currently\nsupport any filters on the counts, but can give a total count for a relation.\n\n```typescript\nbuilder.prismaObject('User', {\n findUnique: (user) => ({ id: user.id }),\n fields: (t) => ({\n id: t.exposeID('id'),\n postCount: t.relationCount('posts'),\n }),\n});\n```\n\n## Relay integration\n\nThis plugin has extensive integration with the\n[relay plugin](https://pothos-graphql.dev/docs/plugins/relay), which makes creating nodes and\nconnections very easy.\n\n### Example\n\nThe following example is similar to the one above with a few changes:\n\n- the `User` and `Post` objects are now relay nodes\n- the `posts` field on the `User` type is now a relay connection using cursor based pagination\n- there is a new `users` query that is also a relay connection\n\nEverything in this schema is still queryable via a single prisma query. The relay connections\nhandles pre-loading like all the other fields.\n\n```typescript\nbuilder.prismaNode('User', {\n findUnique: (id) => ({ id }),\n id: { resolve: (user) => user.id },\n fields: (t) => ({\n email: t.exposeString('email'),\n posts: t.relatedConnection('posts', {\n cursor: 'id',\n args: {\n oldestFirst: t.arg.boolean(),\n },\n query: (args, context) => ({\n orderBy: {\n createdAt: args.oldestFirst ? 'asc' : 'desc',\n },\n }),\n }),\n }),\n});\n\nbuilder.prismaNode('Post', {\n findUnique: (id) => ({ id }),\n id: { resolve: (post) => post.id },\n fields: (t) => ({\n title: t.exposeString('title'),\n author: t.relation('author'),\n }),\n});\n\nbuilder.queryType({\n fields: (t) => ({\n me: t.prismaField({\n type: 'User',\n resolve: async (query, root, args, ctx, info) =>\n prisma.user.findUnique({\n ...query,\n rejectOnNotFound: true,\n where: { id: ctx.userId },\n }),\n }),\n posts: t.prismaConnection({\n type: 'Post',\n cursor: 'id',\n resolve: (query) => prisma.post.findMany(query),\n }),\n }),\n});\n```\n\n### `prismaNode`\n\nThe `prismaNode` method works just like the `prismaObject` method with a couple of small\ndifferences:\n\n- the `findUnique` function now only receives an id. This is to support relays ability to load nodes\n by id.\n- there is a new `id` option that mirrors the `id` option from `node` method of the relay plugin,\n and must contain a resolve function that returns the id from an instance of the node.\n\n```typescript\nbuilder.prismaNode('Post', {\n // This is used to load the node by id\n findUnique: (id) => ({ id }),\n // This is used to get the id from a node\n id: { resolve: (post) => post.id },\n // fields work just like they do for builder.prismaObject\n fields: (t) => ({\n title: t.exposeString('title'),\n author: t.relation('author'),\n }),\n});\n```\n\n### `prismaConnection`\n\nThe `prismaConnection` method on a field builder can be used to create a relay `connection` field\nthat also pre-loads all the data nested inside that connection.\n\n```typescript\nbuilder.queryType({\n fields: (t) => ({\n posts: t.prismaConnection(\n {\n type: 'Post',\n cursor: 'id',\n resolve: (query, parent, args, context, info) => prisma.post.findMany({ ...query }),\n }),\n {}, // optional options for the Connection type\n {}, // optional options for the Edge type),\n ),\n }),\n});\n```\n\n#### options\n\n- `type`: the name of the prisma model being connected to\n- `cursor`: a `@unique` column of the model being connected to. This is used as the `cursor` option\n passed to prisma.\n- `defaultSize`: (default: 20) The default page size to use if `first` and `last` are not provided.\n- `maxSize`: (default: 100) The maximum number of nodes returned for a connection.\n- `resolve`: Like the resolver for `prismaField`, the first argument is a `query` object that should\n be spread into your prisma query. The `resolve` function should return an array of nodes for the\n connection. The `query` will contain the correct `take`, `skip`, and `cursor` options based on the\n connection arguments (`before`, `after`, `first`, `last`), along with `include` options for nested\n selections.\n\nThe created connection queries currently support the following combinations of connection arguments:\n\n- `first`, `last`, or `before`\n- `first` and `before`\n- `last` and `after`\n\nQueries for other combinations are not as useful, and generally requiring loading all records\nbetween 2 cursors, or between a cursor and the end of the set. Generating query options for these\ncases is more complex and likely very inefficient, so they will currently throw an Error indicating\nthe argument combinations are not supported.\n\n### `relatedConnection`\n\nThe `relatedConnection` method can be used to create a relay `connection` field based on a relation\nof the current model.\n\n```typescript\nbuilder.prismaNode('User', {\n findUnique: (id) => ({ id }),\n id: { resolve: (user) => user.id },\n fields: (t) => ({\n // Connections can be very simple to define\n simplePosts: t.relatedConnection('posts', {\n cursor: 'id',\n }),\n // Or they can include custom arguments, and other options\n posts: t.relatedConnection(\n 'posts',\n {\n cursor: 'id',\n args: {\n oldestFirst: t.arg.boolean(),\n },\n query: (args, context) => ({\n orderBy: {\n createdAt: args.oldestFirst ? 'asc' : 'desc',\n },\n }),\n },\n {}, // optional options for the Connection type\n {}, // optional options for the Edge type),\n ),\n }),\n});\n```\n\n#### options\n\n- `cursor`: a `@unique` column of the model being connected to. This is used as the `cursor` option\n passed to prisma.\n- `defaultSize`: (default: 20) The default page size to use if `first` and `last` are not provided.\n- `maxSize`: (default: 100) The maximum number of nodes returned for a connection.\n- `resolve`: (optional) Used as a fallback when a connection is not pre-loaded. It is optional, and\n generally should NOT be defined manually. If used it works like a combination of the `resolve`\n method of `relation` and `prismaConnection`. The default will use the `findUnique` of the current\n model, with an `include` for the current relation. It is also batched together with other\n relationships to improve query efficiency.\n- `totalCount`: when set to true, this will add a `totalCount` field to the connection object. see\n `relationCount` above for more details.\n"
70
71
  }
@@ -6,7 +6,6 @@ import {
6
6
  ObjectRef,
7
7
  RootFieldBuilder,
8
8
  SchemaTypes,
9
- TypeParam,
10
9
  } from '@pothos/core';
11
10
  import { resolvePrismaCursorConnection } from './cursors';
12
11
  import { getRefFromModel } from './refs';
@@ -22,9 +21,12 @@ const fieldBuilderProto = RootFieldBuilder.prototype as PothosSchemaTypes.RootFi
22
21
  >;
23
22
 
24
23
  fieldBuilderProto.prismaField = function prismaField({ type, resolve, ...options }) {
25
- const model: string = Array.isArray(type) ? type[0] : type;
26
- const typeRef = getRefFromModel(model, this.builder);
27
- const typeParam: TypeParam<SchemaTypes> = Array.isArray(type) ? [typeRef] : typeRef;
24
+ const modelOrRef = Array.isArray(type) ? type[0] : type;
25
+ const typeRef =
26
+ typeof modelOrRef === 'string'
27
+ ? getRefFromModel(modelOrRef, this.builder)
28
+ : (modelOrRef as ObjectRef<unknown>);
29
+ const typeParam = Array.isArray(type) ? ([typeRef] as [ObjectRef<unknown>]) : typeRef;
28
30
 
29
31
  return this.field({
30
32
  ...options,
@@ -66,7 +68,7 @@ fieldBuilderProto.prismaConnection = function prismaConnection<
66
68
  connectionOptions: {},
67
69
  edgeOptions: {},
68
70
  ) {
69
- const ref = getRefFromModel(type, this.builder);
71
+ const ref = typeof type === 'string' ? getRefFromModel(type, this.builder) : type;
70
72
  let typeName: string | undefined;
71
73
 
72
74
  const fieldRef = (
package/src/generator.ts CHANGED
@@ -45,7 +45,14 @@ generatorHandler({
45
45
  [],
46
46
  model.name,
47
47
  undefined,
48
+
48
49
  ts.factory.createTypeLiteralNode([
50
+ ts.factory.createPropertySignature(
51
+ [],
52
+ 'Name',
53
+ undefined,
54
+ ts.factory.createLiteralTypeNode(ts.factory.createStringLiteral(model.name)),
55
+ ),
49
56
  ts.factory.createPropertySignature(
50
57
  [],
51
58
  'Shape',
@@ -7,13 +7,13 @@ import {
7
7
  InputFieldMap,
8
8
  InterfaceParam,
9
9
  NormalizeArgs,
10
- ObjectRef,
11
10
  OutputType,
12
11
  PluginName,
13
12
  SchemaTypes,
14
13
  ShapeFromTypeParam,
15
14
  } from '@pothos/core';
16
15
  import PrismaNodeRef from './node-ref';
16
+ import { prismaModelKey, PrismaObjectRef } from './object-ref';
17
17
  import {
18
18
  PrismaConnectionFieldOptions,
19
19
  PrismaFieldOptions,
@@ -59,7 +59,7 @@ declare global {
59
59
  >(
60
60
  name: Name,
61
61
  options: PrismaObjectTypeOptions<Types, Model, Interfaces, FindUnique, Include, Shape>,
62
- ) => ObjectRef<Shape>;
62
+ ) => PrismaObjectRef<Model, Shape>;
63
63
 
64
64
  prismaNode: 'relay' extends PluginName
65
65
  ? <
@@ -71,7 +71,7 @@ declare global {
71
71
  >(
72
72
  name: Name,
73
73
  options: PrismaNodeOptions<Types, Model, Interfaces, Include, Shape>,
74
- ) => PrismaNodeRef<Shape>
74
+ ) => PrismaNodeRef<Model, Shape>
75
75
  : '@pothos/plugin-relay is required to use this method';
76
76
  }
77
77
 
@@ -82,15 +82,23 @@ declare global {
82
82
  > {
83
83
  prismaField: <
84
84
  Args extends InputFieldMap,
85
- TypeParam extends keyof Types['PrismaTypes'] | [keyof Types['PrismaTypes']],
85
+ TypeParam extends
86
+ | PrismaObjectRef<PrismaModelTypes>
87
+ | keyof Types['PrismaTypes']
88
+ | [keyof Types['PrismaTypes']]
89
+ | [PrismaObjectRef<PrismaModelTypes>],
86
90
  Nullable extends FieldNullability<Type>,
87
91
  ResolveReturnShape,
88
- Type extends TypeParam extends [keyof Types['PrismaTypes']]
92
+ Type extends TypeParam extends [unknown]
89
93
  ? [ObjectRef<Model['Shape']>]
90
94
  : ObjectRef<Model['Shape']>,
91
95
  Model extends PrismaModelTypes = PrismaModelTypes &
92
96
  (TypeParam extends [keyof Types['PrismaTypes']]
93
97
  ? Types['PrismaTypes'][TypeParam[0]]
98
+ : TypeParam extends [PrismaObjectRef<PrismaModelTypes>]
99
+ ? TypeParam[0][typeof prismaModelKey]
100
+ : TypeParam extends PrismaObjectRef<PrismaModelTypes>
101
+ ? TypeParam[typeof prismaModelKey]
94
102
  : TypeParam extends keyof Types['PrismaTypes']
95
103
  ? Types['PrismaTypes'][TypeParam]
96
104
  : never),
@@ -110,11 +118,13 @@ declare global {
110
118
 
111
119
  prismaConnection: 'relay' extends PluginName
112
120
  ? <
113
- Type extends keyof Types['PrismaTypes'],
121
+ Type extends PrismaObjectRef<PrismaModelTypes> | keyof Types['PrismaTypes'],
114
122
  Nullable extends boolean,
115
123
  ResolveReturnShape,
116
124
  Args extends InputFieldMap = {},
117
- Model extends PrismaModelTypes = PrismaModelTypes & Types['PrismaTypes'][Type],
125
+ Model extends PrismaModelTypes = Type extends PrismaObjectRef<infer T>
126
+ ? T
127
+ : PrismaModelTypes & Types['PrismaTypes'][Type & keyof Types['PrismaTypes']],
118
128
  >(
119
129
  ...args: NormalizeArgs<
120
130
  [
@@ -66,6 +66,20 @@ export class ModelLoader {
66
66
  return (result._count as Record<string, number>)[relation];
67
67
  }
68
68
 
69
+ async loadSelf(include: unknown, context: {}) {
70
+ for (const entry of this.staged) {
71
+ const merged = mergeIncludes(entry.include, include as Record<string, unknown>);
72
+
73
+ if (merged) {
74
+ entry.include = merged as Record<string, unknown>;
75
+
76
+ return entry.promise;
77
+ }
78
+ }
79
+
80
+ return this.initLoad(null, include, context);
81
+ }
82
+
69
83
  async loadRelation(relation: string, include: unknown, context: {}) {
70
84
  let promise;
71
85
  for (const entry of this.staged) {
@@ -96,18 +110,21 @@ export class ModelLoader {
96
110
  return result[relation];
97
111
  }
98
112
 
99
- async initLoad(relation: string, includeArg: unknown, context: {}, count = false) {
100
- const include: Record<string, unknown> = count
101
- ? {
102
- _count: {
103
- select: {
104
- [relation]: true,
105
- },
106
- },
107
- }
108
- : {
109
- [relation]: includeArg,
110
- };
113
+ async initLoad(relation: string | null, includeArg: unknown, context: {}, count = false) {
114
+ const include: Record<string, unknown> =
115
+ (relation &&
116
+ (count
117
+ ? {
118
+ _count: {
119
+ select: {
120
+ [relation]: true,
121
+ },
122
+ },
123
+ }
124
+ : {
125
+ [relation]: includeArg,
126
+ })) ||
127
+ {};
111
128
 
112
129
  const promise = new Promise<Record<string, unknown>>((resolve, reject) => {
113
130
  setTimeout(() => {
@@ -117,7 +134,7 @@ export class ModelLoader {
117
134
  this.delegate.findUnique({
118
135
  rejectOnNotFound: true,
119
136
  where: { ...(this.findUnique(this.model, context) as {}) },
120
- include,
137
+ include: Object.keys(include).length > 0 ? include : undefined,
121
138
  } as never) as Promise<Record<string, unknown>>,
122
139
  );
123
140
  }, 0);
package/src/node-ref.ts CHANGED
@@ -1,7 +1,12 @@
1
- import { abstractReturnShapeKey, brandWithType, ObjectRef, typeBrandKey } from '@pothos/core';
1
+ import { abstractReturnShapeKey, brandWithType, typeBrandKey } from '@pothos/core';
2
+ import { PrismaObjectRef } from './object-ref';
2
3
  import { WithBrand } from './types';
4
+ import { PrismaModelTypes } from '.';
3
5
 
4
- export default class PrismaNodeRef<T> extends ObjectRef<T, T> {
6
+ export default class PrismaNodeRef<Model extends PrismaModelTypes, T> extends PrismaObjectRef<
7
+ Model,
8
+ T
9
+ > {
5
10
  [abstractReturnShapeKey]: WithBrand<T>;
6
11
 
7
12
  addBrand<V extends T | T[]>(
@@ -0,0 +1,8 @@
1
+ import { ObjectRef } from '@pothos/core';
2
+ import { PrismaModelTypes } from '.';
3
+
4
+ export const prismaModelKey = Symbol.for('Pothos.prismaModelKey');
5
+
6
+ export class PrismaObjectRef<Model extends PrismaModelTypes, T = {}> extends ObjectRef<T> {
7
+ [prismaModelKey]: Model;
8
+ }
@@ -13,6 +13,7 @@ import {
13
13
  import { prismaCursorConnectionQuery, wrapConnectionResult } from './cursors';
14
14
  import { getLoaderMapping, setLoaderMappings } from './loader-map';
15
15
  import { ModelLoader } from './model-loader';
16
+ import { PrismaObjectRef } from './object-ref';
16
17
  import { getDelegateFromModel, getFindUniqueForRef, getRefFromModel, getRelation } from './refs';
17
18
  import {
18
19
  PrismaDelegate,
@@ -21,7 +22,8 @@ import {
21
22
  RelatedFieldOptions,
22
23
  RelationCountOptions,
23
24
  } from './types';
24
- import { queryFromInfo } from './util';
25
+ import { queryFromInfo, SELF_RELATION } from './util';
26
+ import { VariantFieldOptions } from '.';
25
27
 
26
28
  export class PrismaObjectFieldBuilder<
27
29
  Types extends SchemaTypes,
@@ -69,6 +71,7 @@ export class PrismaObjectFieldBuilder<
69
71
  totalCount,
70
72
  ...options
71
73
  }: {
74
+ type?: ObjectRef<unknown, unknown>;
72
75
  totalCount?: boolean;
73
76
  maxSize?: number;
74
77
  defaultSize?: number;
@@ -84,7 +87,7 @@ export class PrismaObjectFieldBuilder<
84
87
  const parentRef = getRefFromModel(this.model, this.builder);
85
88
  const relationTypeName =
86
89
  typeof relationField.type === 'string' ? relationField.type : relationField.type.name;
87
- const ref = getRefFromModel(relationTypeName, this.builder);
90
+ const ref = options.type ?? getRefFromModel(relationTypeName, this.builder);
88
91
  const findUnique = getFindUniqueForRef(parentRef, this.builder);
89
92
  const loaderCache = ModelLoader.forModel(this.model, this.builder);
90
93
  let typeName: string | undefined;
@@ -232,7 +235,7 @@ export class PrismaObjectFieldBuilder<
232
235
  const parentRef = getRefFromModel(this.model, this.builder);
233
236
  const relationTypeName =
234
237
  typeof relationField.type === 'string' ? relationField.type : relationField.type.name;
235
- const ref = getRefFromModel(relationTypeName, this.builder);
238
+ const ref = options.type ?? getRefFromModel(relationTypeName, this.builder);
236
239
  const findUnique = getFindUniqueForRef(parentRef, this.builder);
237
240
  const loaderCache = ModelLoader.forModel(this.model, this.builder);
238
241
 
@@ -321,4 +324,50 @@ export class PrismaObjectFieldBuilder<
321
324
  },
322
325
  }) as FieldRef<number, 'Object'>;
323
326
  }
327
+
328
+ variant<Variant extends Model['Name'] | PrismaObjectRef<Model>>(
329
+ ...allArgs: NormalizeArgs<
330
+ [
331
+ variant: Variant,
332
+ options?: VariantFieldOptions<
333
+ Types,
334
+ Model,
335
+ Variant extends PrismaObjectRef<Model> ? Variant : PrismaObjectRef<Model>
336
+ >,
337
+ ]
338
+ >
339
+ ): FieldRef<Model['Shape'], 'Object'> {
340
+ const [variant, options = {} as never] = allArgs;
341
+ const ref: PrismaObjectRef<PrismaModelTypes> =
342
+ typeof variant === 'string' ? getRefFromModel(variant, this.builder) : variant;
343
+ const parentRef = getRefFromModel(this.model, this.builder);
344
+ const findUnique = getFindUniqueForRef(parentRef, this.builder);
345
+ const loaderCache = ModelLoader.forModel(this.model, this.builder);
346
+
347
+ return this.field({
348
+ ...options,
349
+ type: ref,
350
+ extensions: {
351
+ ...options.extensions,
352
+ pothosPrismaRelation: SELF_RELATION,
353
+ },
354
+ resolve: (parent, args, context, info) => {
355
+ const mapping = getLoaderMapping(context, info.path);
356
+
357
+ if (mapping) {
358
+ setLoaderMappings(context, info.path, mapping);
359
+
360
+ return parent as never;
361
+ }
362
+
363
+ const queryOptions = queryFromInfo(context, info);
364
+
365
+ if (!findUnique) {
366
+ throw new Error(`Missing findUnique for Prisma type ${this.model}`);
367
+ }
368
+
369
+ return loaderCache(parent).loadSelf(queryOptions, context) as never;
370
+ },
371
+ }) as FieldRef<Model['Shape'], 'Object'>;
372
+ }
324
373
  }
package/src/refs.ts CHANGED
@@ -1,8 +1,10 @@
1
1
  import { ObjectRef, SchemaTypes } from '@pothos/core';
2
2
  import { Prisma } from '../tests/client';
3
+ import { PrismaObjectRef } from './object-ref';
3
4
  import { PrismaDelegate } from './types';
5
+ import { PrismaModelTypes } from '.';
4
6
 
5
- export const refMap = new WeakMap<object, Map<string, ObjectRef<unknown>>>();
7
+ export const refMap = new WeakMap<object, Map<string, PrismaObjectRef<PrismaModelTypes>>>();
6
8
  export const findUniqueMap = new WeakMap<
7
9
  object,
8
10
  Map<ObjectRef<unknown>, ((args: unknown, ctx: {}) => unknown) | null>
@@ -16,14 +18,14 @@ export const includeForRefMap = new WeakMap<
16
18
  export function getRefFromModel<Types extends SchemaTypes>(
17
19
  name: string,
18
20
  builder: PothosSchemaTypes.SchemaBuilder<Types>,
19
- ): ObjectRef<unknown> {
21
+ ): PrismaObjectRef<PrismaModelTypes> {
20
22
  if (!refMap.has(builder)) {
21
23
  refMap.set(builder, new Map());
22
24
  }
23
25
  const cache = refMap.get(builder)!;
24
26
 
25
27
  if (!cache.has(name)) {
26
- cache.set(name, builder.objectRef(name));
28
+ cache.set(name, new PrismaObjectRef(name));
27
29
  }
28
30
 
29
31
  return cache.get(name)!;