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

tests: test & document 1:n relation projection #38

Merged
merged 5 commits into from
May 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
206 changes: 193 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,18 @@ Official Prisma plugin for Nexus.
- [Limitation: Hardcoded key for Prisma Client on GraphQL Context](#limitation-hardcoded-key-for-prisma-client-on-graphql-context)
- [Example: Exposing Prisma Client on GraphQL Context with Apollo Server](#example-exposing-prisma-client-on-graphql-context-with-apollo-server)
- [Project 1:1 Relation](#project-11-relation)
- [Example: Tests](#example-tests)
- [Example: Full 1:1](#example-full-11)
- [Limitation: Nullable on Without-Relation-Scalar Side](#limitation-nullable-on-without-relation-scalar-side)
- [Project 1:n Relation](#project-1n-relation)
- [Example: Tests](#example-tests-1)
- [Example: Full 1:n](#example-full-1n)
- [Prisma ID field to GraphQL ID scalar type mapping](#prisma-id-field-to-graphql-id-scalar-type-mapping)
- [Prisma Schema docs re-used for GraphQL schema doc](#prisma-schema-docs-re-used-for-graphql-schema-doc)
- [Prisma Schema docs re-used for JSDoc](#prisma-schema-docs-re-used-for-jsdoc)
- [Refined DX](#refined-dx)
- [Recipes](#recipes)
- [Project relation with custom resolver logic](#project-relation-with-custom-resolver-logic)
- [Supply custom custom scalars to your GraphQL schema](#supply-custom-custom-scalars-to-your-graphql-schema)
- [Notes](#notes)

Expand Down Expand Up @@ -97,15 +102,15 @@ export const schema = makeSchema({
- [x] ([#4](https://github.com/prisma/nexus-prisma/issues/4)) Support for Prisma Model field types that map to standard GraphQL scalars
- [x] ([#8](https://github.com/prisma/nexus-prisma/issues/8)) Support for Prisma Model field types of `DateTime` & `Json`
- [x] ([#16](https://github.com/prisma/nexus-prisma/issues/16)) Support for Prisma enums
- [x] ([#25](https://github.com/prisma/nexus-prisma/pull/25), [#36](https://github.com/prisma/nexus-prisma/issues/36)) Basic support for Prisma Model field types relating to other Models 1:1
- [x] ([#38](https://github.com/prisma/nexus-prisma/pull/38)) Basic support for Prisma Model field types relating to other Models 1:n

##### Shortterm

- [ ] Support for Prisma Model field types of remaining scalars (`Bytes`, etc.)

##### Midterm

- [x] ([#25](https://github.com/prisma/nexus-prisma/pull/25), [#36](https://github.com/prisma/nexus-prisma/issues/36)) Support for Prisma Model field types relating to other Models 1:1
- [ ] Support for Prisma Model field types relating to other Models 1:n
- [ ] Support for Prisma Model field types relating to other Models n:n

##### Longterm
Expand Down Expand Up @@ -237,6 +242,13 @@ new ApolloServer({

You can project [1:1 relationships](https://www.prisma.io/docs/concepts/components/prisma-schema/relations#one-to-one-relations) into your API.

#### Example: Tests

The integration test suite is a useful reference as it is declarative (easy to read) and gives a known-working example spanning from database all the way to executed GraphQL document.

- [Tests](https://github.com/prisma/nexus-prisma/blob/main/tests/integration/relation1To1.test.ts)
- [Snapshots](https://github.com/prisma/nexus-prisma/blob/main/tests/integration/__snapshots__/relation1To1.test.ts.snap)

#### Example: Full 1:1

```prisma
Expand All @@ -259,6 +271,17 @@ model Profile {

import { User, Profile } from 'nexus-prisma'

queryType({
definition(t) {
t.nonNull.list.nonNull.field('users', {
type: 'User',
resolve(_, __, ctx) {
return ctx.prisma.user.findMany()
},
})
},
})

objectType({
name: User.$name,
definition(t) {
Expand All @@ -273,22 +296,15 @@ objectType({
t.field(Profile.id.name, Profile.id)
},
})

queryType({
definition(t) {
t.list.field('users', {
type: 'User',
resolve(_, __, ctx) {
return ctx.prisma.user.findMany()
},
})
},
})
```

```graphql
# API Schema Represented in GraphQL SDL (this is generated by Nexus)

type Query {
users: [User!]!
}

type User {
id: ID
profile: Profile
Expand Down Expand Up @@ -408,6 +424,129 @@ objectType({
})
```

### Project 1:n Relation

You can project [1:n relationships](https://www.prisma.io/docs/concepts/components/prisma-schema/relations#one-to-many-relations) into your API.

#### Example: Tests

The integration test suite is a useful reference as it is declarative (easy to read) and gives a known-working example spanning from database all the way to executed GraphQL document.

- [Tests](https://github.com/prisma/nexus-prisma/blob/main/tests/integration/relation1ToN.test.ts)
- [Snapshots](https://github.com/prisma/nexus-prisma/blob/main/tests/integration/__snapshots__/relation1ToN.test.ts.snap)

#### Example: Full 1:n

```prisma
// Database Schema

model User {
id String @id
posts Post[]
}

model Post {
id String @id
author User? @relation(fields: [authorId], references: [id])
authorId String
}
```

```ts
// API Schema

import { User, Post } from 'nexus-prisma'

queryType({
definition(t) {
t.nonNull.list.nonNull.field('users', {
type: 'User',
resolve(_, __, ctx) {
return ctx.prisma.user.findMany()
},
})
},
})

objectType({
name: User.$name,
definition(t) {
t.field(User.id.name, User.id)
t.field(User.posts.name, User.posts)
},
})

objectType({
name: Post.$name,
definition(t) {
t.field(Post.id.name, Post.id)
},
})
```

```graphql
# API Schema Represented in GraphQL SDL (this is generated by Nexus)

type Query {
users: [User]
}

type User {
id: ID!
posts: [Post!]!
}

type Post {
id: ID!
}
```

```ts
// Example Database Data (for following example)

await prisma.user.create({
data: {
id: 'user1',
posts: {
create: [{ id: 'post1' }, { id: 'post2' }],
},
},
})
```

```graphql
# Example API Client Query

query {
users {
id
posts {
id
}
}
}
```

```json
{
"data": {
"users": [
{
"id": "user1",
"posts": [
{
"id": "post1"
},
{
"id": "post2"
}
]
}
]
}
}
```

### Prisma ID field to GraphQL ID scalar type mapping

All `@id` fields in your Prisma Schema get projected as `ID` types, not `String` types.
Expand Down Expand Up @@ -521,6 +660,47 @@ PEER_DEPENDENCY_CHECK=false|0

## Recipes

### Project relation with custom resolver logic

Nexus Prisma generates default GraphQL resolvers for your model _relation fields_. However you may want to run custom logic in the resolver. This is easy to do. The following show a few ways.

1. **Wrap Style** You can access the default resolver within your own custom resolver.

```ts
objectType({
name: User.$name,
definition(t) {
t.field(User.id.name, User.id)
t.field(User.posts.name, {
...User.posts,
resolve(...args) {
// Your custom before-logic here
const result = await User.posts.resolve(...args)
// Your custom afer-logic here
return result
},
})
},
})
```

2. **Replace Style** You can simply opt out of using the default resolver completely:

```ts
objectType({
name: User.$name,
definition(t) {
t.field(User.id.name, User.id)
t.field(User.posts.name, {
...User.posts,
resolve(...args) {
// Your custom logic here
},
})
},
})
```

### Supply custom custom scalars to your GraphQL schema

The following is a brief example how you could add your own custom GraphQL custom scalars to satisfy Nexus Prisma. Note that most of the time using the defaults exported by `nexus-prisma/scalars` will probably be good enough for you.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"nexus_prisma": "./dist/cli/nexus-prisma.js"
},
"scripts": {
"reflect:toc": "markdown-toc README.md -i --maxdepth 4",
"reflect:toc": "markdown-toc README.md -i --maxdepth 4 && prettier --write README.md",
"format": "prettier --write .",
"format:check": "prettier --check .",
"lint": "eslint . --ext .ts,.tsx --fix",
Expand Down
40 changes: 38 additions & 2 deletions tests/integration/__snapshots__/relation1To1.test.ts.snap
Original file line number Diff line number Diff line change
@@ -1,5 +1,41 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Nullable on Without-Relation-Scalar Side limitation can be worked around by wrapping type in an explicit nonNull: graphqlOperationExecutionResult 1`] = `
Object {
"data": Object {
"users": Array [
Object {
"id": "user1",
"profile": Object {
"id": "profile1",
"user": Object {
"id": "user1",
},
},
},
],
},
}
`;

exports[`Nullable on Without-Relation-Scalar Side limitation can be worked around by wrapping type in an explicit nonNull: graphqlSchemaSDL 1`] = `
"
type Query {
users: [User!]!
}

type User {
id: ID!
profile: Profile!
}

type Profile {
id: ID!
user: User!
}
"
`;

exports[`can project relationship in opposite direction of where @relation is defined, but the field will be nullable: graphqlOperationExecutionResult 1`] = `
Object {
"data": Object {
Expand All @@ -21,7 +57,7 @@ Object {
exports[`can project relationship in opposite direction of where @relation is defined, but the field will be nullable: graphqlSchemaSDL 1`] = `
"
type Query {
users: [User]
users: [User!]!
}

type User {
Expand Down Expand Up @@ -54,7 +90,7 @@ Object {
exports[`can project user-to-profile relationship: graphqlSchemaSDL 1`] = `
"
type Query {
users: [User]
users: [User!]!
}

type User {
Expand Down
38 changes: 38 additions & 0 deletions tests/integration/__snapshots__/relation1ToN.test.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`can project user-to-posts relationship: graphqlOperationExecutionResult 1`] = `
Object {
"data": Object {
"users": Array [
Object {
"id": "user1",
"posts": Array [
Object {
"id": "post1",
},
Object {
"id": "post2",
},
],
},
],
},
}
`;

exports[`can project user-to-posts relationship: graphqlSchemaSDL 1`] = `
"
type Query {
users: [User!]!
}

type User {
id: ID!
posts: [Post!]!
}

type Post {
id: ID!
}
"
`;
Loading