- Data model definition
- Example
- Models
- Fields
- Embeds
- Enums
- Type definitions
- Attributes
- Functions
- Scalar types
- Relations
- Reserved model names
The data model definition (short: data model or datamodel) is part of your schema file.
It describes the shape of the data per data source. For example, when connecting to a relational database as a data source, the data model definition is a declarative representation of the database schema (tables, columns, indexes, ...). For a REST API, it describes the shapes of the resources that can be retrieved and manipulated via the API.
Here is an example based on a local SQLite database located in the same directory of the schema file (called data.db
):
// schema.prisma
datasource mysql {
url = "file:data.db"
provider = "sqlite"
}
model User {
id Int @id
createdAt DateTime @default(now())
email String @unique
name String?
role Role @default(USER)
posts Post[]
profile Profile?
address Address?
}
embed Address {
street String
zipCode String
}
model Profile {
id Int @id
user User
bio String
}
model Post {
id Int @id
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
author User
title String
published Boolean @default(false)
categories Category[]
}
model Category {
id Int @id
name String
posts Post[]
}
enum Role {
USER
ADMIN
}
While this file mostly consists of the data model definition, it is a valid schema file because it also specifies a data source connector (for SQLite, in this case).
Models represent the entities of your application domain. They are defined using model
blocks in the data model.
On a technical level, a model maps to the underlying structures of the data source, for example:
- In PostgreSQL, a model maps to a table
- In MongoDB, a model maps to a collection
- In REST, a model maps to a resource
Models are typically spelled in PascalCase and use the singular form (e.g. User
instead of Users
).
Technically, a model can be named anything that adheres to this regular expression:
[A-Za-z_][A-Za-z0-9_]*
Every model in the data model definition will result into a number of CRUD operations in the generated Photon API:
findMany
findOne
create
update
upsert
delete
updateMany
deleteMany
The operations are accessible via a generated property on the Photon instance. By default the name of the property is the plural, lowercase form of the model name, e.g. users
for a User
model or posts
for a Post
model.
Here is an example illustrating the use of a users
property from the Photon JS API:
const newUser = await photon.users.create({ data: {
name: "Alice"
}})
const allUsers = await photon.users.findMany()
Note that for Photon JS the name of the users
property is auto-generated using the pluralize
package.
The properties of a model are called fields. A field consists of several parts:
- Name
- Type
- Type modifier (optional)
- Attributes (optional)
You can see examples of fields on the sample models above.
Field names are typically spelled in camelCase starting with a lowercase letter.
Technically, a model can be named anything that adheres to this regular expression:
[A-Za-z_][A-Za-z0-9_]*
The type of a field determines its structure. A type falls in either of three categories:
- Scalar type (includes enums)
- Model
- Embed
The type of a field can be modified by appending either of two modifiers:
[]
: Make a field a list?
: Make a field optional
In the main example above, the field name
on the User
model is optional and the posts
field is a list.
Lists can also be optional and will give the list a third state (which is null
):
Blog[]
: Empty list or non-empty list (default:[]
)Blog[]?
:null
, empty list or non-empty list (default:null
)
The default value for a required list is an empty list. The default value for an optional list is null
.
Learn more about attributes below.
Embeds are defined via the embed
blocks in the datamodel and define structures that are embedded in a model. For a relational database this is often called an embedded type, for document databases, an embedded document.
Embeds are always included in the default selection set of the generated API Photon.
The example above defines only one embed
(called Address
) which is used exactly once on the User
model:
model User {
id Int @id
address Address?
}
embed Address {
street String
zipCode String
}
Named embeds can be reused across multiple models.
In the above example, the named embed Address
is only used once. In this case, it is possible to omit the name and define the embed
block directly inline:
model User {
id Int @id
address embed {
street String
zipCode String
}?
}
Inline embeds can also be nested.
An enum describes a type that has a predefined set of values and is defined via an enum
block:
enum Color {
Red
Teal
}
You can map the values of an enum to the respective values in the data source:
enum Color {
Red = "RED"
Teal = "TEAL"
}
Prisma currently only supports string enum value types.
Type definitions use the type
keyword. They can be used to consolidate various type specifications into a single type:
type Numeric = Float @pg.numeric(precision: 5, scale: 2)
@ms.decimal(precision: 5, scale: 2)
model User {
id Int @id
weight Numeric
}
Attributes modify the behavior of a field or block (model, embed, ...). There are two ways to add attributes to your data model:
- Field attributes are prefixed with
@
. - Block attributes are prefixed with
@@
.
Depending on their signature, attributes may be called in the following cases:
Case 1. No arguments
- Signature:
@attribute
- Description: Parenthesis must be omitted.
- Examples:
@id
@unique
@updatedAt
Case 2. One positional argument
- Signature:
@attribute(_ p0: T0, p1: T1, ...)
- Description: There may be up to one positional argument that doesn't need to be named.
- Examples:
@field("my_column")
@default(10)
@createdAt(now())
For arrays with a single parameter, you may omit the surrounding brackets:
@attribute([email]) // is the same as
@attribute(email)
Case 3. Many named arguments
- Signature:
@attribute(_ p0: T0, p1: T1, ...)
- Description: There may be any number of named arguments. If there is a positional argument, then it may appear anywhere in the function signature, but if it's present and required, the caller must place it before any named arguments. Named arguments may appear in any order.
- Examples:
@@pg.index([ email, first_name ], name: "my_index", partial: true)
@@pg.index([ first_name, last_name ], unique: true, name: "my_index")
@@check(a > b, name: "a_b_constraint")
@pg.numeric(precision: 5, scale: 2)
You must not have multiple arguments with the same name:
// compiler error
@attribute(key: "a", key: "b")
For arrays with a single parameter, you may omit the surrounding brackets:
@attribute([item], key: [item]) // is the same as
@attribute(item, key: item)
Field attributes are marked by an @
prefix placed at the end of the field definition. A field can have any number of field arguments, potentially spanning multiple lines:
// A field with one attribute
model _ {
myField String @attribute
}
// A field with two attributes
embed _ {
myField String @attribute @attribute2
}
// A type definition with three attributes
type MyType String @attribute("input")
@attribute2("input", key: "value", key2: "value2")
@attribute3
Block attributes are marked by an @@
prefix placed anywhere inside a block. You can have as many block attributes as you want and they may also span multiple lines:
model \_ { @@attribute0
---
@@attribute1("input") @attribute2("input", key: "value", key2: "value2")
---
@@attribute3 }
embed \_ { @@attribute0
---
@@attribute1 @@attribute2("input") }
Core attributes must be implemented by every data source connector (with a best-effort implementation), this means they will be available in any Prisma setup.
They may be used in model
and embed
blocks as well as on type
definitions.
Here is a list of all available core field attributes:
@id
: Defines the primary key.@unique
: Defines a unique constraint.@map(_ name: String)
: Defines the raw column name the field is mapped to.@default(_ expr: Expr)
: Specifies a default value.@relation(_ fields?: Field[], name?: String, onDelete?: CascadeEnum)
: Disambiguates relationships when needed. More details here.@updatedAt
: Updates the time tonow()
whenever a record is updated.
Here is a list of all available core block attributes:
@@map(_ name: String)
: Defines the raw table name the field is mapped to.
Connector attributes let you use the native features of your data source. With a PostgreSQL database, you can use it for example to X.
Here is where you can find the documentation of connector attributes per data source connector:
Prisma core provides a set of functions that must be implemented by every connector with a best-effort implementation. Functions only work inside field and block attributes that accept them:
uuid()
: Generates a fresh UUIDcuid()
: Generates a fresh cuidbetween(min, max)
: Generates a random int in the specified rangenow()
: Current date and time
Default values using a dynamic generator can be specified as follows:
model User {
age Int @default(between([ 1, 5 ]))
height Float @default(between([ 1, 5 ]))
createdAt DateTime @default(now())
}
Functions will always be provided at the Prisma level by the query engine.
The data types that these functions return will be defined by the data source connectors. For example, now()
in a PostgreSQL database will return a timestamp with time zone
, while now()
with a JSON connector would return an ISOString
.
Prisma core provides the following scalar types:
Prisma Type | Description |
---|---|
String |
Variable length text |
Boolean |
True or false value |
Int |
Integer value |
Float |
Floating point number |
DateTime |
Timestamp |
The data source connector determines what native database type each of these types map to. Similarly, the generator determines what type in the target programming language each of these types map to.
Expand below to see the mappings per connector and generator.
Scalar mapping to connectors and generators
Connectors
Prisma Type | PostgreSQL | MySQL | SQLite | Mongo | Raw JSON |
---|---|---|---|---|---|
String |
text |
TEXT |
TEXT |
string |
string |
Boolean |
boolean |
BOOLEAN |
N/A | bool |
boolean |
Int |
integer |
INT |
INTEGER |
int32 |
number |
Float |
real |
FLOAT |
REAL |
double |
number |
DateTime |
timestamp |
TIMESTAMP |
N/A | date |
N/A |
N/A: Means that there is no perfect equivalent, but we can probably get pretty close.
Generators
Prisma Type | JS / TS | Go |
---|---|---|
String |
string |
string |
Boolean |
boolean |
bool |
Int |
number |
int |
Float |
number |
float64 |
DateTime |
Date |
time.Time |
Learn more about relations here.
When generating Photon JS based on your data model definition, there are a number of reserved names that you can't use for your models. Here is a list of the reserved names:
String
Int
Float
Subscription
DateTime
WhereInput
IDFilter
StringFilter