Schema reference
connector
Defines a database connector CONCEPT in the namespace CONCEPT. Each namespace has 1 connector at most. The connector of current namespace is inherited from the parent namespace. Teo supports multiple databases. Each connector represents a pool of connections to one database. If a namespace doesn't have a connector, model definitions are not available. Teo can be used without database connections.
Fields
A connector
config block accepts the following fields:
Name | Required | Type | Description |
---|---|---|---|
provider | Yes | Database | Describes which database connector to use. |
url | Yes | String (URL) | Connection URL including authentication info. |
Remarks
- You can have zero or one
connector
config block in a namespace. - You can give
connector
a name just like any other config blocks - for example,connector mysql
orconnector db
. - If not connectors are defined in a namespace, connector from parent namespace is inherited.
- If no connectors are specified in the schema, Teo runs without a database connection.
Examples
Specify a PostgreSQL connector
This example introduces how to connect to a PostgreSQL database. Let's say, the target database is available with the following credentials:
- User: johndoe
- Password: mypassword
- Host: localhost
- Port: 5432
- Database name: mydb
- Schema name: public
connector {
provider: .postgres,
url: "postgresql://johndoe:mypassword@localhost:5432/mydb?schema=public"
}
Specify a PostgreSQL connector via an environment variable
In this example, the target database is available with an environment variable:
connector {
provider: .postgres,
url: ENV["DATABASE_URL"]!
}
When running a Teo CLI command that needs the database connection URL, you need to make sure that the environment variable is set.
One way to do so is by creating a .env
file in your project root directory
with the following contents. Teo CLI will automatically pick up your
environment variables defined in this file.
DATABASE_URL=postgresql://johndoe:mypassword@localhost:5432/mydb?schema=public
Specify a MySQL connector
This example introduces how to connect to a MySQL database. In this example, the target database is available with the following credentials:
- User: johndoe
- Password: mypassword
- Host: localhost
- Port: 3306
- Database name: mydb
connector {
provider: .mysql,
url: "mysql://johndoe:mypassword@localhost:3306/mydb"
}
Specify a SQLite connector
This example introduces how to connect to a SQLite database. In this example, the target database is located in a file called dev.db:
connector {
provider: .sqlite,
url: "sqlite:./dev.db" // or "file:./dev.db"
}
Specify a SQLite in memory connector
connector {
provider: .sqlite,
url: "sqlite::memory:"
}
Specify a MongoDB connector
This example introduces how to connect to a MongoDB database. In this example, the target database is available with the following credentials:
- User: root
- Password: password
- Host: cluster1.test1.mongodb.net
- Port: N/A
- Database name: testing
connector {
provider: .mongo,
url: "mongodb://localhost:27017/yourdb"
}
Specify a default URL besides environment variable
Teo schema language supports nullish coalescing. A database url can be provided with a default value when environment variable is not defined.
connector {
provider: .mongo,
url: ENV["MONGO_URL"] ?? "mongodb://127.0.0.1:27017/yourdb"
}
server
Defines a server CONCEPT in the Teo schema. This config block is required. You must define this in the main namespace CONCEPT.
Fields
A server
config block accepts the following fields:
Name | Required | Type | Description |
---|---|---|---|
bind | Yes | (String, Int) | Describes which IP and port this Teo server binds to. |
pathPrefix | No | String? | The path prefix to be prepended to the request URL. |
Remarks
- A
server
config block is required for Teo server to start. - You must have one
server
config block in the main namespace. - You can give
server
a name just like any other config blocks - for example,server http
orserver myServer
.
Examples
Listening on port X
This example introduces how to write a server
config block in order to run a
Teo server. In this example, this server is listening on port 5100.
server {
bind: ("0.0.0.0", 5100)
}
Specify a path prefix
In this example, the server serves under "/v1"
path.
server http {
bind ("0.0.0.0", 5100)
pathPrefix "/v1"
}
entity
Defines an
entity generator
CONCEPT in the Teo schema. This config block
is optional. Normally, only one entity generator is needed for a project. Which
programming language is used for writing server code, which language's entities
are generated. The entity
config block must be placed at the main namespace.
Fields
A entity
config block accepts the following fields:
Name | Required | Type | Description |
---|---|---|---|
provider | Yes | Runtime | Describes which server end programming language to use for generated model entities. |
dest | Yes | String (Path) | Into which directory the model entities are generated. |
Remarks
- You can have zero or more
entity
config blocks in a schema. But normally only one is needed. - You need to give
entity
a name if there are more than one entity generators. For example,entity rust
orentity nodejs
. - The
entity
config block must be placed at the main namespace.
Examples
Generate Rust model entities inside the project
This example demostrates how to declare an entity generator config block which generates model entities for the current working Rust project.
entity rust {
provider: .rust,
dest: "./src/entities"
}
Generate Node.js model entities inside the project
This example demostrates how to declare an entity generator config block which generates model entities for the current working javaScript or TypeScript project.
entity nodejs {
provider: .node,
dest: "./src/entities"
}
Generate Python model entities inside the project
This example demostrates how to declare an entity generator config block which generates model entities for the current working Python project.
entity python {
provider: .python,
dest: "./entities"
}
client
Defines a
client generator
CONCEPT in the Teo schema. This config block
is optional. If multiple clients are specified, each of them should have a
unique config block name. client
config blocks must be placed at the main
namespace.
Fields
Name | Required | Type | Description |
---|---|---|---|
provider | Yes | ClientLanguage | Describes what type of client package to generate. |
dest | Yes | String (Path) | Into which directory the client is generated. |
host | Yes | String (URL) | To which host this client connects to. |
package | No | Bool | Generate a full package or generate just client files. |
Remarks
- You can have zero or more
client
config blocks in a schema. If multiple clients are specified, each of them should have a unique config block name. - You need to give
client
a name if there are more than one entity generators. for example,client swift
orclient kotlin
. - The
javaScript
provider and thetypeScript
provider are the same provider just with two names. - The
client
config blocks must be placed at the main namespace.
Examples
Generate TypeScript client package
This example demostrates how to declare an client generator config block which generates TypeScript and javaScript client package into a directory.
client ts {
provider: .typeScript,
dest: "../my-client",
host: "http://localhost:5100",
package: true
}
Generate TypeScript client code
This example demostrates how to declare an client generator config block which generates TypeScript and javaScript client code without a package into a directory.
client ts {
provider: .typeScript,
dest: "../my-website/src/api-client",
host: "http://localhost:5100",
package: false
}
Generate Swift client package
This example demostrates how to declare an client generator config block which generates Swift client package into a directory.
client swift {
provider: .swift,
dest: "../my-client",
host: "http://localhost:5100",
package: true
}
Generate Swift client code
This example demostrates how to declare an client generator config block which generates Swift client code without a package into a directory.
client swift {
provider: .swift,
dest: "../my-website/src/api-client",
host: "http://localhost:5100",
package: false
}
Generate Kotlin client package
This example demostrates how to declare an client generator config block which generates Kotlin client package into a directory.
client kotlin {
provider: .kotlin,
dest: "../my-client",
host: "http://localhost:5100",
package: true
}
Generate Kotlin client code
This example demostrates how to declare an client generator config block which generates Kotlin client code without a package into a directory.
client kotlin {
provider: .kotlin,
dest: "../my-website/src/api-client",
host: "http://localhost:5100",
package: false
}
Generate C# client package
This example demostrates how to declare an client generator config block which generates C# client package into a directory.
client cs {
provider: .cSharp,
dest: "../my-client",
host: "http://localhost:5100",
package: true
}
Generate C# client code
This example demostrates how to declare an client generator config block which generates client code without a package into a directory.
client cs {
provider .cSharp
dest "../my-website/src/api-client"
host "http://localhost:5100"
package false
}
Generate Dart client package
This example demostrates how to declare an client generator config block which generates Dart and Flutter client package into a directory.
client dart {
provider .dart
dest "../my-client"
host "http://localhost:5100"
package true
}
Generate Dart client code
This example demostrates how to declare an client generator config block which generates Dart and Flutter client code without a package into a directory.
client dart {
provider .dart
dest "../my-website/src/api-client"
host "http://localhost:5100"
package false
}
Use environment variable to specify client code directory
If different developers generate client into different directories or integarting with CI, use an environment variable to specify the environment specific destination.
entity rust {
provider .dart
dest ENV["CLIENT_DIR"]!
host "http://localhost:5100"
package false
}
admin
Defines an
admin dashboard generator
CONCEPT in the Teo schema. This config block
is optional. If multiple admins are specified, each of them should have a
unique config block name. admin
config blocks must be placed at the main
namespace.
Fields
Name | Required | Type | Description |
---|---|---|---|
dest | Yes | String (Path) | Into which directory the admin dashboard is generated. |
host | Yes | String (URL) | To which host this admin dashboard connects to. Same with client generator. |
languages | No | Language[] | The supported human languages of the admin dashboard. |
Remarks
- You can have zero or more
admin
config blocks in a schema. If multiple clients are specified, each of them should have a unique config block name. - You need to give
admin
a name if there are more than one entity generators. for example,admin a
oradmin b
. - The
admin
config blocks must be placed at the main namespace. - The
languages
field defaults to[.enUs]
.
Examples
Define an admin dashboard
This example defines an admin dashboard which supports a bunch of human languages.
admin {
dest: "../hello-teo-admin-dashboard",
host: .inject("process.env.TEO_HOST"),
languages: [.enUs, .enUk, .de, .es, .fr, .he, .hi, .ja, .ko, .zhCn, .zhTw]
}
model
Defines a Teo model CONCEPT.
Remarks
- Every record of a model must be uniquely identifiable. You must define one
field with
@id
decorator or decorate the model with@id
with multiple fields to achieve a compound identifier.
Model naming convension
- Model names must start with a capitalized letter and are typically spelled in PascalCase.
- Model names should use the singular pascal case form (for example,
User
instead ofuser
,users
orUsers
)
Note: You can use the @map decorator to map a model (for example, User) to a table with a different name that does not match model naming conventions (for example, users).
Examples
A model named User with two scalar fields
model User {
@id
email: String
name: String?
}
A model named Student with a composite ID
@id([.class, .name])
model Student {
class: String
name: String
}
Model Decorators
Model decorators modify the behavior of a model.
@id
Defines a multi-field composite ID on the model.
Remarks
- This is
PRIMARY KEY
for SQL databases. For MongoDB, unless the only primary field maps to"_id"
, a compound unique index is used. - Can be defined on string and number types.
- For MongoDB, it can be defined on
ObjectId
type, too.
Signature
declare unique model decorator id(fields?: FieldIndexes<Self>[], map?: String?)
Arguments
Name | Required | Type | Description |
---|---|---|---|
fields | Yes | FieldIndexes<Self>[] | A list of field names. |
map | No | String? | The database index name to map. |
Examples
Specify a multi-field ID on two String fields
@id([.class, .name])
model Student {
class: String
name: String
email: String?
age: Int?
}
@unique
Defines a multi-field unique composite constraint on the model.
Remarks
- This is
UNIQUE
for SQL databases. For MongoDB, a compound unique index is created. - Can be defined on string, bool, date and number types.
Signature
declare unique model decorator id(fields?: FieldIndexes<Self>[], map?: String?)
Arguments
Name | Required | Type | Description |
---|---|---|---|
fields | Yes | FieldIndexes<Self>[] | A list of field names. |
map | No | String? | The database index name to map. |
Examples
Specify a multi-field unique constraint on three fields
@unique([.name, .year, .artist])
model Album {
@id
id: Int
name: String
year: Int
artist: String
}
@index
Defines a multi-field composite index on the model.
Remarks
- This is
INDEX
for SQL databases. For MongoDB, a compound index is created. - Can be defined on string, bool, date and number types.
Signature
declare model decorator index(fields?: FieldIndexes<Self>[], map?: String?)
Arguments
Name | Required | Type | Description |
---|---|---|---|
fields | Yes | FieldIndexes<Self>[] | A list of field names. |
map | No | String? | The database index name to map. |
Examples
Specify a multi-field composite index on two fields
@index([.year, .name])
model Album {
@id
id: Int
name: String
year: Int
artist: String
}
@map
Maps the Teo schema model name to a different table name. By default, the original name is used.
Signature
declare unique model decorator map(tableName?: String)
Arguments
Name | Required | Type | Description |
---|---|---|---|
tableName | Yes | String | The database table or collection name. |
Examples
Map Person
model to a database table with the name "people"
@map("people")
model Person {
@id
id: Int
name: String
age: Int
}
@migration
Give auto migration instructions on how this model should be handled.
Signature
declare unique model decorator migration(renamed: Enumerable<String>?, version: String?, drop: Bool?)
Arguments
Name | Required | Type | Description |
---|---|---|---|
renamed | No | Enumerable<String>? | The names that this model previously used. |
version | No | String? | Annotate this model with a version number. |
drop | No | Bool? | When new unique records are added and existing records are presented, drop the table instead of panic. |
Examples
Perfrom auto renaming a table
@map("people") @migration(renamed: ["peoples", "person", "Person"])
model Person {
@id
id: Int
name: String
age: Int
}
@beforeSave
This pipeline callback is triggered before an object is being saved.
Signature
declare unique model decorator beforeSave(pipeline?: Pipeline<Self, Ignored>)
Arguments
Position | Required | Type | Description |
---|---|---|---|
0 | Yes | Pipeline<Null, Void> | The pipeline being triggered. |
Examples
Call a custom callback before object is saved
@beforeSave($self.print)
model AuthCode {
@id
id: Int
@unique
email: String
@internal @onSave($randomDigits(4))
code: String
}
@afterSave
This pipeline callback is triggered after an object is being saved.
Signature
declare unique model decorator afterSave(pipeline?: Pipeline<Null, Ignored>)
Arguments
Position | Required | Type | Description |
---|---|---|---|
0 | Yes | Pipeline<Null, Void> | The pipeline being triggered. |
Examples
Call a custom callback after object is saved
@afterSave($self.print)
model AuthCode {
@id
id: Int
@unique
email: String
@internal @onSave($randomDigits(4))
code: String
}
@beforeDelete
This pipeline callback is triggered before an object is being deleted.
Signature
declare unique model decorator beforeDelete(pipeline?: Pipeline<Null, Ignored>)
Arguments
Position | Required | Type | Description |
---|---|---|---|
0 | Yes | Pipeline<Null, Void> | The pipeline being triggered. |
Examples
Call a custom callback before object is deleted
@beforeDelete($self.print)
model AuthCode {
@id
id: Int
@unique
email: String
@internal @onSave($randomDigits(4))
code: String
}
@afterDelete
This pipeline callback is triggered after an object is being deleted.
Signature
declare unique model decorator afterDelete(pipeline?: Pipeline<Null, Ignored>)
Arguments
Position | Required | Type | Description |
---|---|---|---|
0 | Yes | Pipeline<Null, Void> | The pipeline being triggered. |
Examples
Call a custom callback before object is deleted
@afterDelete($self.print)
model AuthCode {
@id
id: Int
@unique
email: String
@internal @onSave($randomDigits(4))
code: String
}
@canRead
This api needs revamp. Use this api when we updated the identity system.
This pipeline performs a permission check whether this current identity can read this object.
Signature
declare unique model decorator canRead(pipeline?: Pipeline<Null, Ignored>)
Arguments
Position | Required | Type | Description |
---|---|---|---|
0 | Yes | Pipeline<Null, Void> | The pipeline which is used for checking. |
Examples
Perform a read permission check
@canRead($self.get(.id).eq(1))
model AuthCode {
@id
id: Int
@unique
email: String
@internal @onSave($randomDigits(4))
code: String
}
@canMutate
This api needs revamp. Use this api when we updated the identity system.
This pipeline performs a permission check whether this current identity can mutate this object.
Signature
declare unique model decorator canMutate(pipeline?: Pipeline<Null, Ignored>)
Arguments
Position | Required | Type | Description |
---|---|---|---|
0 | Yes | Pipeline<Null, Void> | The pipeline which is used for checking. |
Examples
Perform a mutating permission check
@canMutate($self.get(.id).eq(1))
model AuthCode {
@id
id: Int
@unique
email: String
@internal @onSave($randomDigits(4))
code: String
}
@generateClient
Whether generate this model into query clients. The default is true
.
Signature
declare unique model decorator generateClient(generate?: Bool)
Arguments
Name | Required | Type | Description |
---|---|---|---|
generate | Yes | Bool | Whether generate this model into query clients. |
Examples
Do not generate a model into query clients
@generateClient(false)
model MyHiddenModel {
@id
id: Int
value: String
}
@generateEntity
Whether generate this model into model entities. The default is true
.
Signature
declare unique model decorator generateEntity(generate?: Bool)
Arguments
Name | Required | Type | Description |
---|---|---|---|
generate | Yes | Bool | Whether generate this model into model entities. |
Examples
Do not generate a model into model entities
@generateEntity(false)
model MyHiddenModel {
@id
id: Int
value: String
}
@showInStudio
Whether show this model in the Teo Studio app.
The Teo Studio app is currently under developing. It will be a database viewer and request sender for debugging and user experience.
Signature
declare unique model decorator showInStudio(show?: Bool)
Arguments
Name | Required | Type | Description |
---|---|---|---|
show | Yes | Bool | Whether show this model in Teo Studio app. |
Examples
Do not show a model in Teo Studio
@showInStudio(false)
model MyHiddenModel {
@id
id: Int
value: String
}
@synthesizeShapes
Whether synthesize this model's shapes CONCEPT.
Signature
declare unique model decorator synthesizeShapes(synthesize?: Bool)
Arguments
Name | Required | Type | Description |
---|---|---|---|
synthesize | Yes | Bool | Whether synthesize this model's shapes or not. |
Examples
Do not synthesize a model's shapes
@synthesizeShapes(false)
model MyHiddenModel {
@id
id: Int
value: String
}
Model fields
Model fields CONCEPT are contents of a model.
Remarks
- A model field contains a field name, a field type, and optionaly a list of field decorators.
- Model fields are divided into three categories: fields CONCEPT, relations CONCEPT, and properties CONCEPT in nature.
Naming convensions
- Must start with a letter
- Typically spelled in camelCase
- letters, digits and underscores are allowed
Examples
A model with fields and relations
model Article {
@id
id: Int
name: String
@foreignKey
authorId: Int
@relation(fields: .authorId, references: .id)
author: Author
}
model
field scalar types
The database connector determines what native database type each of Teo scalar type maps to. Similarly, the model entity generator and client entity generator determine what type in the target programming language each of these types map to.
String
String represents text.
Default type mappings
Connector | Default mapping |
---|---|
MySQL | VARCHAR(191) |
PostgreSQL | text |
SQLite | TEXT |
MongoDB | String |
Bool
Bool represents boolean values aka true and false.
Default type mappings
Connector | Default mapping |
---|---|
MySQL | TINYINT(1) |
PostgreSQL | boolean |
SQLite | INTEGER |
MongoDB | Bool |
Int
Int represents integer number values.
Remarks
- By default,
Int
is 32 bits.Int32
andInt64
are available for optimization.
Default type mappings
Connector | Default mapping |
---|---|
MySQL | INT |
PostgreSQL | integer |
SQLite | INTEGER |
MongoDB | Int |
Float
Float represents floating point number values.
Remarks
- By default,
Float
is 64 bits.Float32
andFloat64
are available for optimization.
Default type mappings
Connector | Default mapping |
---|---|
MySQL | DOUBLE |
PostgreSQL | double precision |
SQLite | REAL |
MongoDB | Double |
Decimal
Decimal represents a decimal number which is accurate and safe for math calculating.
Remarks
- MongoDB doesn't support
Decimal
type.
Default type mappings
Connector | Default mapping |
---|---|
MySQL | decimal(32,16) |
PostgreSQL | Decimal(65,30) |
SQLite | DECIMAL |
Date
Date represents date values including year
, month
and day
.
Default type mappings
Connector | Default mapping |
---|---|
MySQL | DATE |
PostgreSQL | DATE |
SQLite | String |
MongoDB | Date |
DateTime
DateTime represents date time values.
Default type mappings
Connector | Default mapping |
---|---|
MySQL | DATETIME(3) |
PostgreSQL | timestamp(3) |
SQLite | String |
MongoDB | Date |
ObjectId
ObjectId represents a Bson ObjectId
type.
Remarks
- This is MongoDB only data type.
Default type mappings
Connector | Default mapping |
---|---|
MongoDB | ObjectId |
Model field decorators
Field decorators modify the behavior of a model data field.
@id
Defines an primary key on the field.
Remarks
- This is
PRIMARY KEY
for SQL databases. For MongoDB, If the field doesn't map to_id
, a unique index is used and_id
becomes a hidden field. - Can be defined on string and number types. For MongoDB database,
ObjectId
is also supported. - Most of the times, you want the database to generate an ID and make it readonly.
Signature
declare exclusive model field decorator id(sort: Sort?, length: Int?, map: String?)
Arguments
Name | Required | Type | Description |
---|---|---|---|
sort | No | Sort? | The index sorting order. |
length | No | Int? | The index length. |
map | No | String? | The index name in the database. |
Examples
Specify a SQL readonly auto generated ID
model Student {
@id @autoIncrement @readonly
id: Int
class: String
name: String
email: String?
age: Int?
}
Specify a MongoDB readonly auto generated ID
model Student {
@id @auto @map("_id") @readonly
id: ObjectId
class: String
name: String
email: String?
age: Int?
}
Specify a readonly UUID ID
model Student {
@id @readonly @default($uuid)
id: String
class: String
name: String
email: String?
age: Int?
}
@unique
Defines a unique constraint on the field.
Remarks
- This is
UNIQUE
for SQL databases. For MongoDB, a unique index is created. - Can be defined on string, bool, date and number types.
Signature
declare unique model field decorator index(sort: Sort?, length: Int?, map: String?)
Arguments
Name | Required | Type | Description |
---|---|---|---|
sort | No | Sort? | The index sorting order. |
length | No | Int? | The index length. |
map | No | String? | The index name in the database. |
Examples
Specify a unique constraint on a field
model User {
@id @autoIncrement @readonly
id: Int
@unique
name: String
}
@index
Defines an index on the field.
Remarks
- This is
INDEX
for SQL databases. For MongoDB, an index is created. - Can be defined on string, bool, date and number types.
Signature
declare unique model field decorator unique(sort: Sort?, length: Int?, map: String?)
Arguments
Name | Required | Type | Description |
---|---|---|---|
sort | No | Sort? | The index sorting order. |
length | No | Int? | The index length. |
map | No | String? | The index name in the database. |
Examples
Specify an index on a field
model Album {
@id
id: Int
name: String
@index
year: Int
artist: String
}
@map
Maps the field name to a different database table column name. By default, the original field name is used as is.
Signature
declare unique model field decorator map(columnName?: String)
Arguments
Name | Required | Type | Description |
---|---|---|---|
columnName | Yes | String | The database table column name. |
Examples
Map userId
field to a database column with the name "user_id"
model Person {
@id
id: Int
@map("user_id")
userId: Int
}
@db
Specify the database type to use.
Remarks
- The parameter depends on the current connector provider type. Different databases have different database types.
Signature
#if available(mysql)
declare unique model field decorator db(type?: MySQLDatabaseType)
#end
#if available(postgres)
declare unique model field decorator db(type?: PostgreSQLDatabaseType)
#end
#if available(sqlite)
declare unique model field decorator db(type?: SQLiteDatabaseType)
#end
#if available(mongo)
declare unique model field decorator db(type?: MongoDBDatabaseType)
#end
Arguments
Name | Required | Type | Description |
---|---|---|---|
type | Yes | MySQLDatabaseType, PostgreSQLDatabaseType, SQLiteDatabaseType, MongoDBDatabaseType | The database specific database type. |
Examples
Custom MySQL text type
model Person {
@id
id: Int
@db(.text)
name: String
}
@auto
Defines a field which value is auto generated by the underlying database.
This modifier only exists for MongoDB connector. Use
@autoIncrement
for SQL databases.
Signature
declare unique model field decorator auto
Examples
Declare a MongoDB ID field
model User {
@id @auto @map("_id") @readonly
id: ObjectId
name: String
}
@autoIncrement
Defines a field which value is auto generated with a incremented counter by the underlying database.
This modifier only exists for SQL connectors. Use
@auto
if you are using MongoDB.
Signature
declare unique model field decorator autoIncrement
Examples
Declare an auto increment ID field
model User {
@id @autoIncrement @readonly
id: Int
name: String
}
@default
Defines a default value for a field.
Remarks
- A value of field type is accepted
- A pipeline which returns a value of field type is accepted
- Use
auto
orautoIncrement
if you want the database to generate a default value
Signature
declare unique model field decorator default(value?: ThisFieldType | Pipeline<Null, ThisFieldType>)
Arguments
Name | Required | Type | Description |
---|---|---|---|
name | Yes | ThisFieldType | Pipeline<Null, ThisFieldType> | A default value or a pipeline which returns a default value. |
Examples
Define a field with a default value
model Adult {
@id
id: Int
@default(18)
age: Int
}
Define a field with a default value from pipeline result
model Post {
@id
name: String
@default($self.get(.name))
localizedName: String
}
@foreignKey
Defines a foreign key field.
Remarks
- Teo requires this marking
- Teo doesn't create a foreign key on the database level. Instead, Teo tracks foreign key relationships when delete and update.
- Manually modifying a foreign key may interrupt the relationship between records.
- A foreign key should be used in a relationship.
Signature
declare unique model field decorator foreignKey
Examples
Declare a foreign key used in a relationship
model User {
@id
id: Int
@foreignKey
profileId: Int
@relation(fields: .profileId, references: .id)
profile: Profile
}
@readonly
Defines a readonly field.
Remarks
- You can use a
@default
decorator to apply a default value to a readonly field.
Signature
declare unique model field decorator readonly
Examples
Define a readonly field
model User {
@id @readonly @autoIncrement
id: Int
@default($now) @readonly
createdAt: DateTime
}
@writeonly
Defines a writeonly field.
Signature
declare unique model field decorator writeonly
Examples
Define a writeonly password field
model User {
@id @readonly @autoIncrement
id: Int
@writeonly
password: String
}
@internal
Defines an internal field. @internal
is equivalent to
@readonly
and @writeonly
.
Remarks
- Use pipelines and callbacks to set a value to be internally used.
- Use custom handlers to access the ORM api in order to read and write the value.
Signature
declare unique model field decorator internal
Examples
Define an internal auth code field
model AuthCode {
@id
phone: String
@internal @onSave($randomDigits(4))
code: String
}
@readwrite
Defines a readwrite field. This is the default behavior.
Remarks
- Readwrite is the default field behavior. Only use this decorator when you want to stress on its accessibility.
Signature
declare unique model field decorator readwrite
Examples
Define a field marked with readwrite
model AuthCode {
@id
phone: String
@readwrite @onSave($randomDigits(4))
code: String
}
@writeNonnull
Defines a write nonnull field. Initially, the field value can be null. Only non null value could be updated on this field.
Signature
declare unique model field decorator writeNonNull
Examples
Define a write nonnull enum field
In this example, a user can be created and updated without a sex. Once a valid sex value is set, this value can still be changed into male or female, but not null.
enum Sex {
MALE
FEMALE
}
model User {
@id
phone: String
@writeNonnull
sex: Sex?
}
@writeOnCreate
Defines a write on create field. When updating, this field becomes readonly.
Signature
declare unique model field decorator writeOnCreate
Examples
Define a write on create enum field
In this example, a user can be created and updated with or without a sex. Once created, this value cannot be changed anymore. A user must be created with a target sex. Once created, this value cannot be changed, too.
enum Sex {
MALE
FEMALE
}
model User {
@id
phone: String
@writeOnCreate
sex: Sex?
@writeOnCreate
targetSex: Sex
}
@writeOnce
Defines a write once field. As long as the current value is null, this field can be updated.
Signature
declare unique model field decorator writeOnce
Examples
Define a write once enum field
In this example, a user can be created without a sex. Once a valid sex is set, this value can't be changed anymore.
enum Sex {
MALE
FEMALE
}
model User {
@id
phone: String
@writeOnce
sex: Sex?
}
@readIf
Defines a field which is readable in some cases.
Signature
declare unique model field decorator readIf(cond?: Pipeline<Self, Ignored>)
Arguments
Name | Required | Type | Description |
---|---|---|---|
cond | Yes | Pipeline<Self, Ignored> | A pipeline that validates. |
Examples
Define a field which is readable when an other field value is true
model Article {
@id
id: Int
readable: Bool
@readIf($self.get(.readable).isTrue)
content: String
}
@writeIf
Defines a field which is writable in some cases.
Signature
declare unique model field decorator writeIf(cond?: Pipeline<Self, Ignored>)
Arguments
Name | Required | Type | Description |
---|---|---|---|
cond | Yes | Pipeline<Self, Ignored> | A pipeline that validates. |
Examples
Define a field which is writable when an other field value is true
model Article {
@id
id: Int
writable: Bool
@writeIf($self.get(.writable).isTrue)
content: String
}
@virtual
Defines a virtual field.
Signature
declare unique model field decorator virtual
Examples
Define a virtual field
model User {
@id
id: Int
@virtual
oldPassword: String?
}
@atomic
Defines an atomic field.
Remarks
- An atomic field can be updated with atomic updator
@atomic
can only be applied on number and array fields- An atomic field cannot have
@onSet
and@onSave
pipeline callbacks.
Signature
declare unique model field decorator atomic
Examples
Define an atomic field
model City {
@id
id: Int
name: String
@atomic
viewCount: Int
}
@nonatomic
Defines a nonatomic field.
Remarks
- This is the default field behavior.
- Only use this decorator when you want to stress on its atomicity.
Signature
declare unique model field decorator nonatomic
Examples
Define an nonatomic field
model City {
@id
id: Int
name: String
@nonatomic
viewCount: Int
}
@presentWith
Defines a field which is required when some other field value is present.
Signature
declare unique model field decorator presentWith(fields?: Enumerable<ScalarFields<Self>>)
Arguments
Name | Required | Type | Description |
---|---|---|---|
fields | Yes | Enumerable<ScalarFields<Self>> | A field name or a list of field names. |
Examples
Define a calling code which is required when phone number is present
model User {
@id
id: Int
@presentWith(.phoneNumber)
callingCode: String?
phoneNumber: String?
}
@presentWithout
Defines a field which is required when some other field value is missing.
Signature
declare unique model field decorator presentWithout(fields?: Enumerable<ScalarFields<Self>>)
Arguments
Name | Required | Type | Description |
---|---|---|---|
fields | Yes | Enumerable<ScalarFields<Self>> | A field name or a list of names. |
Examples
Define a phone which is required if email is missing, vice versa
model User {
@id
id: Int
@presentWithout(.email)
phone: String?
@presentWithout(.phone)
email: String?
}
@presentIf
Defines a field which is required in some cases.
Signature
declare unique model field decorator presentIf(cond?: Pipeline<Self, Ignored>)
Arguments
Name | Required | Type | Description |
---|---|---|---|
cond | Yes | Pipeline<Self, Ignored> | A pipeline that validates. |
Examples
Define a field which is required when an other field value is true
model Article {
@id
id: Int
contentRequired: Bool
@presentIf($self.get(.contentRequired).isTrue)
content: String?
}
@inputOmissible
Define a field which input marked with optional when the original definition cannot infer.
Signature
declare unique model field decorator inputOmissible
Examples
Define an input omissible field
model Article {
@id
id: Int
title: String
@inputOmissible
content: String
}
@outputOmissible
Define a field which input is marked with optional when the original definition cannot infer.
Signature
declare unique model field decorator outputOmissible
Examples
Define an output omissible field
model Article {
@id
id: Int
title: String
@outputOmissible
content: String
}
@onSet
Define an on set pipeline callback for the field. When a new value is set
through the set
ORM api, the create
input, and the update
input, this
pipeline is triggered.
Signature
declare unique model field decorator onSet(pipeline?: Pipeline<ThisFieldType?, ThisFieldType?>)
Arguments
Name | Required | Type | Description |
---|---|---|---|
pipeline | Yes | Pipeline<ThisFieldType?, ThisFieldType?> | A pipeline that is performed with the passed in value. |
Examples
Validate email on value set
model User {
@id
id: Int
@unique @onSet($isEmail)
email: String
}
@onSave
Define an on save pipeline callback for the field. When this value is created or updated and a new value is going to be written into the database, this pipeline is triggered.
Signature
declare unique model field decorator onSave(pipeline?: Pipeline<ThisFieldType?, ThisFieldType>)
Arguments
Name | Required | Type | Description |
---|---|---|---|
pipeline | Yes | Pipeline<ThisFieldType?, ThisFieldType> | A pipeline that is performed with the field value. |
Examples
Generate a default value on save
model User {
@id
id: Int
@unique
email: String
@onSave($now)
updatedAt: DateTime
}
@onOutput
Define an on output pipeline callback for the field. This pipeline is triggered
when the object is going to be displayed with the toTeon
ORM api.
Signature
declare unique model field decorator onOutput(pipeline?: Pipeline<ThisFieldType, ThisFieldType>)
Arguments
Name | Required | Type | Description |
---|---|---|---|
pipeline | Yes | Pipeline<ThisFieldType, ThisFieldType> | A pipeline that is performed when toTeon is called. |
Examples
Adding prefix for a value on output
model User {
@id
id: Int
@unique @onOutput($prepend("Email: "))
email: String
}
@queryable
Define a queryable field.
Remarks
- This is the default field behavior. Only use this when you want to stress on the query ability of the field.
Signature
declare unique model field decorator queryable
Examples
Define a queryable field
model User {
@id
id: Int
@queryable
age: Int
}
@unqueryable
Define an unqueryable field.
Signature
declare unique model field decorator unqueryable
Examples
Define an unqueryable field
model User {
@id
id: Int
@unqueryable
age: Int
}
@sortable
Define a sortable field.
Remarks
- This is the default field behavior. Only use this when you want to stress on the sort ability of the field.
Signature
declare unique model field decorator sortable
Examples
Define a sortable field
model User {
@id
id: Int
@sortable
age: Int
}
@unsortable
Define an unsortable field.
Signature
declare unique model field decorator unsortable
Examples
Define a unsortable field
model User {
@id
id: Int
@unsortable
age: Int
}
@migration
Give auto migration instructions on how this model field should be handled.
Signature
declare unique model field decorator migration(
renamed: Enumerable<String>?,
version: String?,
default: ThisFieldType?,
priority: Int?
)
Arguments
Name | Required | Type | Description |
---|---|---|---|
renamed | No | Enumerable<String>? | The names that this model field previously used. |
version | No | String? | Annotate this model field with a version number. |
default | No | ThisFieldType? | Specify a default value for this new model field. |
priority | No | Int? | Determines the order of fields to modify when doing migration. |
Examples
Perfrom auto renaming a table column
model Person {
@id
id: Int
@migration(renamed: "fullName")
name: String
age: Int
}
@dropped
Marks the model field is dropped. This is used for migration. After migration, this field can be deleted safely.
Signature
declare unique model field decorator dropped
Example
Mark a dropped field
model Person {
@id
id: Int
age: Int
@dropped
oldAge: Int
}
Model relation decorators
Model relation decorators define and modify the behavior of a model relation field.
@relation
Define a model relation.
Remarks
- Unlike Prisma, a relation in Teo must be explicitly declared.
- When specifying
fields
andreferences
, an enum value can be specified instead of an array for simplicity.
Signature
declare unique model relation decorator relation {
variant(fields: Enumerable<SerializableScalarFields<Self>>, references: Enumerable<SerializableScalarFields<ThisFieldType>>, onUpdate: Update?, onDelete: Delete?)
variant<T>(through: T, local: DirectRelations<T>, foreign: DirectRelations<T>, onUpdate: Update?, onDelete: Delete?) where T: Model
}
Arguments
Name | Required | Type | Description |
---|---|---|---|
fields | No | Enumerable<SerializableScalarFields<Self>> | Local fields. |
references | No | Enumerable<SerializableScalarFields<ThisFieldType>> | Foreign fields. |
through | No | T: Model | Model which is used as the join table. |
local | No | DirectRelations<T> | Relation to this model on join table. |
foreign | No | DirectRelations<T> | Relation to other model on join table. |
onUpdate | No | Update? | The update rule. |
onDelete | No | Delete? | The delete rule. |
Examples
Declare a one to one relation
model User {
@id
id: Int
name: String
@relation(fields: .id, references: .userId)
profile: Profile
}
model Profile {
@id
id: Int
age: Int
@foreignKey
userId: Int
@relation(fields: .userId, references: .id)
user: User
}
Declare a one to many relation
model User {
@id
id: Int
age: Int?
name: String
@relation(fields: .id, references: .userId)
posts: Post[]
}
model Post {
@id
id: Int
title: String
@foreignKey
userId: Int?
@relation(fields: .userId, references: .id)
user: User?
}
Declare a many to many relation
model Artist {
@id
id: Int
name: String
@relation(through: Perform, local: .artist, foreign: .song)
songs: Song[]
}
model Song {
@id
id: Int
name: String
@relation(through: Perform, local: .song, foreign: .artist)
artists: Artist[]
}
@id([.artistId, .songId])
model Perform {
@foreignKey
artistId: Int
@foreignKey
songId: Int
@relation(fields: .artistId, references: .id)
artist: Artist
@relation(fields: .songId, references: .id)
song: Song
}
Model property decorators
Property decorators define and modify the behavior of a model property field.
@getter
Define a property getter and mark the field as a property.
Signature
declare unique model property decorator getter(pipeline?: Pipeline<Self, ThisFieldType>)
Arguments
Name | Required | Type | Description |
---|---|---|---|
pipeline | Yes | Pipeline<Self, ThisFieldType> | A pipeline to retrieve the property's value. |
Examples
Define a readonly property
model User {
@id
id: Int
firstName: String
lastName: String
@getter($self.get(.firstName).presents.append(" ").append($self.get(.lastName).presents))
name: String
}
@setter
Define a property setter and mark the field as a property.
Signature
declare unique model property decorator setter(pipeline?: Pipeline<Self, Ignored>)
Arguments
Name | Required | Type | Description |
---|---|---|---|
pipeline | Yes | Pipeline<Self, Ignored> | A pipeline to assign values to the model object. |
Examples
Define a shorthand writeonly property
model User {
@id
id: Int
firstName: String
lastName: String
@setter($split(" ").assign(.firstName, $get(0)).assign(.lastName, $get(1)))
name: String
}
@cached
Define a cached property.
Remarks
- A cached property has a database column.
- Unlike a field, cached property's value is calculated.
@deps
must be specified
Signature
declare unique model property decorator cached
Examples
Define a cached property
model User {
@id
id: Int
firstName: String
lastName: String
@getter($self.get(.firstName).presents.append(" ").append($self.get(.lastName).presents))
@cached @deps([.firstName, .lastName])
name: String
}
@deps
Define field dependencies for a cached property.
Signature
declare unique model property decorator deps(deps?: Enumerable<SerializableScalarFields<Self>>)
Arguments
Name | Required | Type | Description |
---|---|---|---|
deps | Yes | Enumerable<SerializableScalarFields<Self>> | Dependency fields. |
Examples
Define dependencies for a property
model User {
@id
id: Int
firstName: String
lastName: String
@getter($self.get(.firstName).presents.append(" ").append($self.get(.lastName).presents))
@deps([.firstName, .lastName])
name: String
}
@unique
Defines a unique constraint on the cached property.
Remarks
- This is
UNIQUE
for SQL databases. For MongoDB, a unique index is created. - Can be defined on string, bool, date and number types.
Signature
declare unique model property decorator unique(sort: Sort?, length: Int?, map: String?)
Arguments
Name | Required | Type | Description |
---|---|---|---|
sort | No | Sort? | The index sorting order. |
length | No | Int? | The index length. |
map | No | String? | The index name in the database. |
Examples
Specify a unique constraint on a cached property
model Album {
@id
id: Int
name: String
@index
year: Int
@getter($self.get(.year)) @cached @deps(.year) @unique
yearProperty: Int
artist: String
}
@index
Defines an index on the cached property.
Remarks
- This is
INDEX
for SQL databases. For MongoDB, an index is created. - Can be defined on string, bool, date and number types.
Signature
declare unique model property decorator index(sort: Sort?, length: Int?, map: String?)
Arguments
Name | Required | Type | Description |
---|---|---|---|
sort | No | Sort? | The index sorting order. |
length | No | Int? | The index length. |
map | No | String? | The index name in the database. |
Examples
Specify an index on a cached property
model Album {
@id
id: Int
name: String
@index
year: Int
@getter($self.get(.year)) @cached @deps(.year) @index
yearProperty: Int
artist: String
}
Handler decorators
@map
Specify the custom handler's HTTP request method, path and URL path arguments.
Signature
declare unique handler decorator map(method?: Method?, path?: String?, ignorePrefix: Bool?, interface: String?)
Arguments
Name | Required | Type | Description |
---|---|---|---|
method | No | Method? | The HTTP request method. Default to .post . |
path | No | String? | The URL path. |
ignorePrefix | No | Bool? | Whether ignore the namespace and handler group prefix. |
interface | No | String? | The generated interface name in query clients and model entities. |
Examples
Specify custom HTTP method and request path for a handler
@map(.patch, "/api/v1/:id", interface: "MyCustomAPIPathArgs")
declare handler myCustomHandler(MyCustomInput): MyCustomOutput
enum
Defines an enum CONCEPT.
Remarks
- Enums are natively supported by PostgreSQL and MySQL
- Enums are implemented and enforced at Teo level in other databases
Naming conventions
- Enum names must start with a letter
- Typically spelled in PascalCase
- letters, digits and underscores are allowed
Examples
Specify an enum
with two possible values
enum Role {
USER
ADMIN
}
model User {
@id @autoIncrement
id: Int
role: Role
}
Specify an enum
with two possible values and set a default value
enum Role {
USER
ADMIN
}
model User {
@id @autoIncrement
id: Int
@default(.USER)
role: Role
}
Data structures
Database
Database
is an enum describes what type of database connector to use.
interface enum Database {
mongo
mysql
postgres
sqlite
}
ClientLanguage
ClientLanguage
is an interface enum describes which client language to use
for the generated query client.
interface enum ClientLanguage {
javaScript
typeScript
swift
kotlin
cSharp
dart
}
Runtime
Runtime
is an interface enum describes which server programming language to
use for generated model entities.
interface enum Runtime {
rust
node
python
}
MySQLDatabaseType
MySQLDatabaseType
represents available MySQL database types to be used with
the @db
decorator.
#if available(mysql)
interface enum MySQLDatabaseType {
varChar(len?: Int)
text
char(len?: Int)
tinyText
mediumText
longText
bit(len?: Int)
tinyInt(len?: Int, signed: Bool)
int(signed: Bool)
smallInt(signed: Bool)
mediumInt(signed: Bool)
bigInt(signed: Bool)
year
float
double
decimal(precision?: Int, scale?: Int)
dateTime(len?: Int)
date
time(len?: Int)
timestamp(len?: Int)
json
longBlob
binary
varBinary
tinyBlob
blob
mediumBlob
}
#end
PostgreSQLDatabaseType
PostgreSQLDatabaseType
represents available PostgreSQL database types to be
used with the @db
decorator.
#if available(postgres)
interface enum PostgreSQLDatabaseType {
text
char(len?: Int)
varChar(len?: Int)
bit(len?: Int)
varBit
uuid
xml
inet
boolean
integer
smallInt
int
bigInt
oid
doublePrecision
real
decimal(precision?: Int, scale?: Int)
money
timestamp(len?: Int)
timestampTz(len?: Int)
date
time
timeTz
json
jsonB
byteA
}
#end
SQLiteDatabaseType
SQLiteDatabaseType
represents available SQLite database types to be used with
the @db
decorator.
#if available(sqlite)
interface enum SQLiteDatabaseType {
text
integer
real
decimal
blob
}
#end
MongoDBDatabaseType
MongoDBDatabaseType
represents available MongoDB database types to be used
with the @db
decorator.
#if available(mongo)
interface enum MongoDBDatabaseType {
string
bool
int
long
double
date
timestamp
binData
}
#end
Method
Method
represents the HTTP request method.
interface enum Method {
get
post
put
patch
delete
}
Delete
Delete
represents the delete rule for relation mutation.
interface enum Delete {
noAction
nullify
cascade
deny
default
}
Update
Update
represents the update rule for relation mutation.
interface enum Update {
noAction
nullify
update
delete
deny
default
}
Sort
Sort
represents the sorting order.
enum Sort {
asc
desc
}
Action
The type of actions CONCEPT.
interface option enum Action {
create = 1
update = 1 << 1
delete = 1 << 2
copy = 1 << 3
find = 1 << 4
first = 1 << 5
connect = 1 << 6
disconnect = 1 << 7
set = 1 << 8
join = 1 << 9
count = 1 << 10
aggregate = 1 << 11
groupBy = 1 << 12
codeName = 1 << 13
upsert = .create | .update
connectOrCreate = .connect | .create
joinCreate = .join | .create
joinDelete = .join | .delete
findFirst = .find | .first
entry = 1 << 14
nested = 1 << 15
codePosition = 1 << 16
single = 1 << 17
many = 1 << 18
codeAmount = 1 << 19
}
Data
Data
represents a normal Teo response interface with only a data field.
interface Data<T> {
data: T
}
DataMeta
DataMeta
represents a normal Teo response interface with a data field and a
meta field.
interface DataMeta<T, U> {
data: T
meta: U
}
PagingInfo
PagingInfo
represents a paging info response entry in a findMany
handler.
interface PagingInfo {
count: Int64
numberOfPages: Int64?
}
ResponseError
ResponseError
represents the typical shape of an error response in Teo.
interface ResponseError {
type: String
message: String
fields: String{} | Null
}
Constants
ENV
The ENV
object represents environment variables.
Examples
Retrieve a environment variable
let dbUrl: String? = ENV["DATABASE_URL"]