Full-stack Web Technologies

CHAPTER 3
Models

Models are the equivalent of "entities" for Relational Databases or Document Databases. They are the types of things we want to store.

Declaring Models

The model comprises a sequence of model entries which define the entities in your model. You can also define enum types.

The naming convention for models is singular and PascalCase, so an entity representing a movie would be called Movie:

model Movie {
  // ...
}

Once the model is synchronized with the database, these names are preserved exactly, so they usually have to be written within double-quotes (especially in Postgres or SQLite3):

SELECT * FROM "Movie";

Field Definition

Each field has:

  • A name.
  • A type, with optional type modifiers.
  • Optional attributes.
model Movie {
  id          Int      @id @default(autoincrement())
  title       String
  year        Int
  duration    Int
  forFamilies Boolean  @default(false)
  createdAt   DateTime @default(now())
  @@unique([title, year])
}
Scalar Types

Scalar types are: String, Boolean, Int, BigInt, Float, Decimal, DateTime , Json and Bytes.

Type modifiers

You can append the following modifiers to any type:

  • ? a field is "optional" (it can be null).
  • [] the field is then a list.
Attributes

Field attributes include:

@idThe field is a primary key
@default(x)The default value for the field is x
@uniqueThe field must have a unique constraint
@relation(...)To describe how entites are related
@map(name)To use a different name in the database

Entity attributes include:

@@id(f1, f2, ...)A primary key with more than one field
@@index(f1, f2, ...)An index is needed on certain fields
@@map(name)Alternate name in the database
@@unique(f1, f2, ...)Unique constraint on field set
IDs in MongoDB

Since MongoDB always introduces the _id field as a primary key, in Prisma the IDs have to be defined as follows if the underlying database is MongoDB:

model User {
  id String @id @default(auto()) @map("_id") @db.ObjectId
  // ...
}

Relationships

In relationships, the field's model type is another model. A relation involver, actually, two ways of working. From the perspective of the parent, a fields could include an array of all the children. From the perspective of the child, a field could contain all the data of the parent.

An example can illustrate this:

model Post {
  postId   Int       @id @default(autoincrement())
  comments Comment[]
}
model Comment {
  commentId  Int  @id @default(uuid())
  postId     Int  // <- special field for the hierarchical relationship
  parentPost Post @relation(fields: [postId], references: [postId])
}

The following line in the Post model

comments Comment[]

says that a Post can have many comments (a hierarchical relationship). It could have zero, also.

On the child side, we have to be specific about what fields are involved:

postId     Int // maybe there is no parent
parentPost Post @relation(fields: [postId], references: [id])
Generating relationships automatically with the Prisma VSCode extension

One nice thing about the Prisma VSCode extension is that you can automatically generate the relationship fields if you just declare one side of the relationship. By typing the line comments Comment[] in the Post (and having declared the Comment model as well), then, upon reformatting the code, the fields for the comments appear automatically. It is good to check them and adapt any parts that you want to customize.

Many to many relationships

A many to many relationship would be implemented in the following way:

model User {
  id        String    @id @default(uuid()) // generates a UUID
  firstName String
  lastName  String

  messages  Message[]
}

model Chat {
  id       String    @id @default(uuid())
  title    String
  
  messages Message[]
}

model Message {
  id       String @id @default(uuid())
  text     String

  authorId String
  author   User   @relation(fields: [authorId], references: [id])

  chatId   String
  chat     Chat   @relation(fields: [chatId], references: [id])
}

In this case, we have a "pivot table", Message, which is a type of entity which sits below both User and Chat, since messages have that specific context, the author and the chat to which they belong. It is, as explained when modelling data, just the application of 2 hierarchical relationships that coincide inside an entity, in this case Message.