Skip to main content
Version: 3.0 Alpha

Model

The model construct is the core of ZModel. It defines the structure of your data and their relations. A model represents a domain entity, and is mapped to a database table.

Defining models

A typical model looks like this:

model User {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
email String @unique
name String
}

The simplest models are just a collection of fields. A model must be uniquely identifiable by some of its fields. For most cases, you'll have a field marked with the @id attribute (more about attributes later).

model User {
id Int @id
}

If your model needs a composite id, you can use the @@id model-level attribute to specify it:

model City {
country String
name String
@@id([country, name])
}

If no @id or @@id is specified, the ORM will resort to using a field (or fields) marked with the @unique or @@unique attribute as the identifier.

model User {
email String @unique
}

model City {
country String
name String
@@unique([country, name])
}

Model fields

Each model field must at least have a name and a type. A field can be typed in one of the following ways:

  1. Built-in types, including:

    • String
    • Boolean
    • Int
    • BigInt
    • Float
    • Decimal
    • DateTime
    • Json
    • Bytes
    • Unsupported

    The Unsupported type is for defining fields of types not supported by the ORM, however letting the migration engine know how to create the field in the database.

    // from Prisma docs
    model Star {
    id Int @id
    position Unsupported("circle")? @default(dbgenerated("'<(10,4),11>'::circle"))
    }
  2. Enum

    We'll talk about enums later.

    enum Role {
    USER
    ADMIN
    }

    model User {
    id Int @id
    role Role
    }
  3. Model

    It'll then form a relation. We'll cover that topic later.

    model Post {
    id Int @id
    author User @relation(fields: [authorId], references: [id])
    authorId Int
    }
  4. Custom type

    ZenStack allows you to define custom types in the schema and use that to type Json fields. This will be covered in more details in the Custom Types section.

    type Address {
    street String
    city String
    country String
    zip Int
    }

    model User {
    id Int @id
    address Address @json
    }

A field can be set optional by adding the ? suffix to its type, or list by adding the [] suffix. However, a field cannot be both optional and a list at the same time.

model User {
id Int @id
name String?
tags String[]
}

A default value can be specified for a field with the @default attribute. The value can be a literal, or a supported function call, including:

  • now(): returns the current timestamp
  • cuid(): returns a CUID
  • uuid(): returns a UUID
  • ulid(): returns a ULID
  • nanoid(): returns a Nano ID
  • autoincrement(): returns an auto-incrementing integer (only for integer fields)
  • dbgenerated("..."): calls a native db function
model User {
id Int @id @default(autoincrement())
role Role @default("USER")
createdAt DateTime @default(now())
}

Native type mapping

Besides giving field a type, you can also specify the native database type to use with the @db. series of attributes.

model User {
...
name String @db.VarChar(64)
}

These attributes control what data type is used when the migration engine maps the schema to DDL. You can find a full list of native type attributes in the ZModel Language Reference.

Name mapping

Quite often you want to use a different naming scheme for your models and fields than the database. You can achieve that with the @map attribute. The ORM respects the mapping when generation queries, and the migration engine uses it to generate the DDL.

model User {
id Int @id
name String @map("full_name")

@@map("users")
}
Comments
Feel free to ask questions, give feedback, or report issues.

Don't Spam


You can edit/delete your comments by going directly to the discussion, clicking on the 'comments' link below