Skip to content

Instantly share code, notes, and snippets.

@nikolasburk
Created January 15, 2021 16:00
Show Gist options
  • Select an option

  • Save nikolasburk/17650171aa21c7826e35938a34e45da9 to your computer and use it in GitHub Desktop.

Select an option

Save nikolasburk/17650171aa21c7826e35938a34e45da9 to your computer and use it in GitHub Desktop.

Revisions

  1. nikolasburk created this gist Jan 15, 2021.
    90 changes: 90 additions & 0 deletions relations-prisma-1.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,90 @@
    In Prisma 1, it wasn't necessary to specify both sides of a relation, this means this was allowed:

    ```graphql
    type User {
    id: ID! @unique @id
    questions: [Question]
    }

    type Question {
    id: ID! @unique @id
    }
    ```

    This only specifies one side of the relation, from `User` to `Question`, but not the other way around. If you wanted to be explicit about the second relation side, the datamodel would look as follows:

    ```graphql
    type User {
    id: ID! @unique @id
    questions: [Question]
    }

    type Question {
    id: ID! @unique @id
    user: User # now you have a second side of the relation
    }
    ```

    In fact, Prisma 1 automatically _infers_ this field. So even if you don't specify it as in the first code snippet above, it does exist _implicitly_ (as a foreign key in the underlying database schema and as a field in your generated GraphQL schema).

    In Prisma 2, the first version would not be allowed, you always _must_ specify both sides of the relation. The corresponding Prisma 2 schema looks as follows:

    ```prisma
    model User {
    id String @id @default(cuid())
    questions Question[]
    }

    model Question {
    id String @id @default(cuid())
    user User @relation(fields: [userId], references: [id]) // this is required in Prisma 2
    userId String @map("user") // this is required in Prisma 2
    }
    ```

    Note that we're using `@map("user")` to [map](https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#map) the `userId` field in the Prisma schema to the `user` column in the database. This is only necessary because the column was created by Prisma 1 and is called `user`. If you start out with Prisma 2 in a fresh project, the schema would typically look as follows (basically the same but without the extra `@map`):

    ```prisma
    model User {
    id String @id @default(cuid())
    questions Question[]
    }
    model Question {
    id String @id @default(cuid())
    user User @relation(fields: [userId], references: [id]) // this is required in Prisma 2
    userId String // this is required in Prisma 2
    }
    ```

    Now, one issue with your Prisma 1 datamodel was that you specified both sides of a relation, _but_ you added different names for the relation via the Prisma 1 `@relation` directive, for example:

    ```graphql
    type User {
    id: ID! @unique @id
    questions: [Question] @relation(name: "QuestionsUser")
    }

    type Question {
    id: ID! @unique @id
    poster: User! @relation(name: "QuestionPoster")
    }
    ```

    Here, you explicitly told Prisma 1 that these relation fields do not "belong together". Consequently, Prisma implicitly added the second side of the relation _implicitly_ to the schema (similar to the example above)! This means, the _actual_ schema that Prisma 1 created for you under the hood looked as follows:

    ```graphql
    type User {
    id: ID! @unique @id
    questions: [Question] @relation(name: "QuestionsUser")
    questions_QuestionPoster("QuestionPoster") # I'm actually not sure if this is the correct field name, but it should be somewhat similar
    }

    type Question {
    id: ID! @unique @id
    user: User @relation(name: "QuestionsUser")
    poster: User! @relation(name: "QuestionPoster")
    }
    ```

    As I mention in the comment, I'm actually not sure if `questions_QuestionPoster` is the correct field name Prisma 1 generates here, but it should be somewhat similar. Prisma 1 can't call it `questions` (which would be the default) because the existing field is already called like that.