Skip to content

2.0.0-preview024

Pre-release
Pre-release
Compare
Choose a tag to compare
@nikolasburk nikolasburk released this 12 Mar 18:13

Today, we are issuing the twenty-fourth Preview release: 2.0.0-preview024 (short: preview024).

Major improvements

Reduced size of Prisma Client & Azure functions support

This release contains major improvements for Prisma Client. It now supports Windows Azure functions. In addition to that, the generated Prisma Client code inside your node_modules directory now is a lot smaller.

Another improvement is a better debugging experience. When setting the DEBUG environment variable (e.g. with export DEBUG="*"), the logging output now contains the names of Prisma Client API calls.

Use relation fields as ID on a Prisma model

In this release, it's now possible to use relation fields of Prisma models as IDs. In "database-speak", this means that you can now have both a primary key and a foreign key constraint on the same column.

Reference a single-field ID

For example, a Movie could always be identified by its Director:

model Movie {
  director Director @id
  title    String
}

model Director {
  id Int @id @default(@autoincrement())
  name String
}

This is what the corresponding SQL (in SQLite dialect) looks like:

CREATE TABLE "Movie" (
    "director" INTEGER NOT NULL  ,
    "title" TEXT NOT NULL DEFAULT '' ,
    PRIMARY KEY ("director"),
    FOREIGN KEY ("director") REFERENCES "Director"("id")
);

CREATE TABLE "Director" (
    "id" INTEGER NOT NULL  PRIMARY KEY AUTOINCREMENT,
    "name" TEXT NOT NULL DEFAULT '' 
);
Expand to view an example for creating `Movie`s and `Director`s in Prisma Client

Nested write to create Movie with Director:

// Run inside `async` function
const movie = await prisma.movie.create({
  data: {
    title: "Hello World",
    director: {
      create: {
        name: "Alice"
      }
    }
  },
})

Nested write to create Director with Movie:

// Run inside `async` function
const director = await prisma.director.create({
  data: {
    name: "Bob",
    movies: {
      create: [{
        title: "Hello World"
      }]
    }
  },
})

Reference a multi-field ID

You can also create a relation to a multi-field ID:

model Movie {
  director Director @id @map(["firstName", "lastName"]) 
  title    String
}

model Director {
  firstName   String
  lastName    String

  @@id([firstName, lastName])
}

Note that in this case, the Movie table in the underlying database will actually have two physical columns called firstName and lastName. These are referencing the respective firstName and lastName column on the Director table.

Here is what the above models correspond to in SQL:

CREATE TABLE "Movie" (
    "firstName" TEXT NOT NULL  ,
    "lastName" TEXT NOT NULL  ,
    "title" TEXT NOT NULL DEFAULT '' ,
    PRIMARY KEY ("firstName","lastName"),
    FOREIGN KEY ("firstName","lastName") REFERENCES "Director"("firstName","lastName") 
);

CREATE TABLE "Director" (
    "firstName" TEXT NOT NULL DEFAULT '' ,
    "lastName" TEXT NOT NULL DEFAULT '' ,
    PRIMARY KEY ("firstName","lastName")
);

In many cases, it might make sense to name the columns on Movie differently. For example, they could be called directorFirstName and directorLastName. This can be achieved via adding the @map attribute to the field:

model Movie {
  director Director @id @map(["directorFirstName", "directorLastName"]) @relation(references: [firstName, lastName])
  title    String
}

model Director {
  firstName   String
  lastName    String

  @@id([firstName, lastName])
}

Note that in this case you could also omit the @relation attribute, the result would be the same:

model Movie {
  director Director @id @map(["directorFirstName", "directorLastName"])
  title    String
}

model Director {
  firstName   String
  lastName    String

  @@id([firstName, lastName])
}

In this case, the field names in @map on Movie get matched with the field names in @@id on Director.

Both cases correspond to the following SQL:

CREATE TABLE "Movie" (
    "directorFirstName" TEXT NOT NULL  ,
    "directorLastName" TEXT NOT NULL  ,
    "title" TEXT NOT NULL DEFAULT '' ,
    PRIMARY KEY ("directorFirstName","directorLastName"),
    FOREIGN KEY ("directorFirstName","directorLastName") REFERENCES "Director"("firstName","lastName")
);

CREATE TABLE "Director" (
    "firstName" TEXT NOT NULL DEFAULT '' ,
    "lastName" TEXT NOT NULL DEFAULT '' ,
    PRIMARY KEY ("firstName","lastName")
);
Expand to view an example for creating `Movie`s and `Director`s in Prisma Client

Nested write to create Movie with Director:

// Run inside `async` function
const movie = await prisma.movie.create({
  data: {
    title: 'Hello World',
    director: {
      create: {
        firstName: 'Alice',
        lastName: 'Allen',
      },
    },
  },
})

Nested write to create Director with Movie:

// Run inside `async` function
const director = await prisma.director.create({
  data: {
    firstName: 'Bob',
    lastName: 'Nolan',
    movies: {
      create: [
        {
          title: 'Hello World',
        },
      ],
    },
  },
})

Multi-field ID with a relation field (which targets a model with a single-field ID)

You can also create a multi-field ID on a model that contains a relation field:

model Movie {
  director Director
  title    String

  @@id([director, title])
}

model Director {
  id   String @id @default(cuid())
  name String
}

This corresponds to the following SQL:

CREATE TABLE "Movie" (
    "director" TEXT NOT NULL  ,
    "title" TEXT NOT NULL DEFAULT '' ,
    PRIMARY KEY ("director","title"),
    FOREIGN KEY ("director") REFERENCES "Director"("id")
);

CREATE TABLE "Director" (
    "id" TEXT NOT NULL  ,
    "name" TEXT NOT NULL DEFAULT '' ,
    PRIMARY KEY ("id")
);
Expand to view an example for creating `Movie`s and `Director`s in Prisma Client

Nested write to create Movie with Director:

// Run inside `async` function
const movie = await prisma.movie.create({
  data: {
    title: 'Hello World',
    director: {
      create: {
        name: 'Alice',
      },
    },
  },
})

Nested write to create Director with Movie:

// Run inside `async` function
const director = await prisma.director.create({
  data: {
    name: 'Bob',
    movies: {
      create: [
        {
          title: 'Hello World 2',
        },
      ],
    },
  },
})

Multi-field ID with a relation field (which targets a model with a multi-field ID)

You can also define a multi-field ID on a model which contains a relation field that targets a model with a multi-field ID:

model Movie {
  director Director
  title    String

  @@id([director, title])
}

model Director {
  firstName String
  lastName  String

  @@id([firstName, lastName])
}

This is what the above code translates to in SQL:

CREATE TABLE "Movie" (
    "director_firstName" TEXT NOT NULL  ,
    "director_lastName" TEXT NOT NULL  ,
    "title" TEXT NOT NULL DEFAULT '' ,
    PRIMARY KEY ("director_firstName","director_lastName","title"),
    FOREIGN KEY ("director_firstName","director_lastName") REFERENCES "Director"("firstName","lastName") 
);

CREATE TABLE "Director" (
    "firstName" TEXT NOT NULL DEFAULT '' ,
    "lastName" TEXT NOT NULL DEFAULT '' ,
    PRIMARY KEY ("firstName","lastName")
);

Similar to the case before, you can also give names to the added columns on Movie by using the @map attributed:

model Movie {
  director Director @map(["directorFirstName", "directorLastName"]) @relation(references: [firstName, lastName])
  title    String

  @@id([director, title])
}

model Director {
  firstName String
  lastName  String

  @@id([firstName, lastName])
}

And as before you can also omit the @relation attribute in this scenario:

model Movie {
  director Director @map(["directorFirstName", "directorLastName"])
  title    String

  @@id([director, title])
}

model Director {
  firstName String
  lastName  String

  @@id([firstName, lastName])
}

In both cases, the models correspond to the following tables:

CREATE TABLE "Movie" (
    "directorFirstName" TEXT NOT NULL  ,
    "directorLastName" TEXT NOT NULL  ,
    "title" TEXT NOT NULL DEFAULT '' ,
    PRIMARY KEY ("directorFirstName","directorLastName","title"),
    FOREIGN KEY ("directorFirstName","directorLastName") REFERENCES "Director"("firstName","lastName")
);

CREATE TABLE "Director" (
    "firstName" TEXT NOT NULL DEFAULT '' ,
    "lastName" TEXT NOT NULL DEFAULT '' ,
    PRIMARY KEY ("firstName","lastName")
);
Expand to view an example for creating `Movie`s and `Director`s in Prisma Client

Nested write to create Movie with Director:

// Run inside `async` function
const movie = await prisma.movie.create({
  data: {
    title: 'Hello World',
    director: {
      create: {
        firstName: 'Alice',
        lastName: 'Allen',
      },
    },
  },
})

Nested write to create Director with Movie:

// Run inside `async` function
const director = await prisma.director.create({
  data: {
    firstName: 'Bob',
    lastName: 'Nolan',
    movies: {
      create: [
        {
          title: 'Hello World',
        },
      ],
    },
  },
})

Breaking changes

MODELGetSelectPayload and MODELGetIncludePayload have been merged into MODELGetPayload. More info here.

Fixes and improvements per Prisma 2 repository

prisma2

migrate

prisma-client-js

prisma-engines