Data modeling
This guide introduces the best practices on data modeling.
Design model ID
Teo has a flexible schema language for modeling data. So does defining model ID.
Teo supports integer ID, string ID, object id
MongoDB Only, and compound ID. To specify a model's ID, use
the @id
decorator.
Integer ID
To declare an integer ID, specify the field's type to be Int
or Int64
:
model MyModel {
@id
id: Int
}
model MyModelWithLongId {
@id
id: Int64
}
Auto Incremental
In model designing with SQL databases, auto incremental IDs are common. Add an
extra decorator @autoIncrement
for a database generated default value. By the
way, a @readonly
could be added if this field is designed not to change
externally.
model MyModel {
@id @autoIncrement @readonly
id: Int
}
String ID
Teo supports string ID. While these IDs could be provided by the frontend, or randomly generated by Teo. When the value is supposed to be generated by the frontend, do not specify a default value.
UUID
To declare a UUID ID, use the default decorator with the $uuid
pipeline item:
model MyModel {
@id @default($uuid)
id: String
}
CUID
To declare a CUID ID, use the default decorator with the $cuid
pipeline item:
model MyModel {
@id @default($cuid)
id: String
}
Slug
To declare a slug ID, use the default decorator with the $slug
pipeline item:
model MyModel {
@id @default($slug)
id: String
}
Custom string ID strategy
To use a custom random string ID strategy, custom pipeline item is required.
Object ID
Object ID is mapped to MongoDB's
ObjectId
type. Thus this is a MongoDB only feature.
An ObjectId is generated by MongoDB internally. And its "column name" is always "_id"
.
Normally declare it with these four decorators:
model MyModel {
@id @auto @map("_id") @readonly
id: ObjectId
}
Compound ID
A model's primary key could be a combination of various fields. Move the decorator up to the model, multiple field name arguments are accepted.
@id([.a, .b])
model MyModel {
a: String
b: String
}
Design model fields
A model represents a table or collection in the underlying database. Teo models are shaped models which means developer need to define fields on a model with field types and other information related to a field. To understand the concepts, see Model, Model field and Model property.
Field or property
A model field represents a normal "table column". While a property with a setter is a shortcut for setting values of fields. A property with a getter represents calculated result.
model User {
firstName: String
lastName: String
@getter($self.get(.firstName).presents.append(" ").append($self.get(.lastName).presents))
@setter($assign(.firstName, $split(" ").get(0).presents).assign(.lastName, $split(" ").get(1).presents))
fullName: String
}
Virtual field
Use virtual field if some argument is required for input but it doesn't need to be stored in the database.
model User {
phoneNo: String
password: String
@virtual
oldPassword: String?
}
Cached property
A cached property is stored in the database. This is useful for properties which involves heavy calculating.
model User {
firstName: String
lastName: String
@getter($self.get(.firstName).presents.append(" ").append($self.get(.lastName).presents))
@cached @deps([.firstName, .lastName])
fullName: String
}
Design model relations
Teo is great for working with model relations. Define model relations with @relation
decorator and developer can get nested mutation and query for free.
Relations without join table
The difference between one-to-one relation and one-to-many relation is whether the field type is array or not.
This example represents a one-to-one-relation:
model User {
@id
id: String
name: String
@relation(fields: .id, references: .userId)
post: Post
}
model Post {
@id
id: String
name: String
@relation(fields: .userId, references: .id)
user: User
@foreignKey
userId: String
}
This example represents a one-to-many or many-to-one relation:
model User {
@id
id: String
name: String
@relation(fields: .id, references: .userId)
posts: Post[]
}
model Post {
@id
id: String
name: String
@relation(fields: .userId, references: .id)
user: User
@foreignKey
userId: String
}
Relations with join table
There isn't an easy and unified way to implement a many-to-many relation without a join table. Teo prefers and supports declaring join table explicitly.
model Artist {
@id
id: String
name: String
@relation(through: Perform, local: .artist, foreign: .song)
songs: Song[]
}
model Song {
@id
id: String
name: String
@relation(through: Perform, local: .song, foreign: .artist)
artists: Artist[]
}
@id([.artistId, .songId])
model Perform {
@foreignKey
artistId: String
@foreignKey
songId: String
@relation(fields: .artistId, references: .id)
artist: Artist
@relation(fields: .songId, references: .id)
song: Song
}