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:

NameRequiredTypeDescription
providerYesDatabaseDescribes which database connector to use.
urlYesString (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 or connector 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.

.env
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+srv://root:password@cluster1.test1.mongodb.net/testing?retryWrites=true&w=majority"
}

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/testing"
}

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:

NameRequiredTypeDescription
bindYes(String, Int)Describes which IP and port this Teo server binds to.
pathPrefixNoString?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 or server 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:

NameRequiredTypeDescription
providerYesRuntimeDescribes which server end programming language to use for generated model entities.
destYesString (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 or entity 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

NameRequiredTypeDescription
providerYesClientLanguageDescribes what type of client package to generate.
destYesString (Path)Into which directory the client is generated.
hostYesString (URL)To which host this client connects to.
packageNoBoolGenerate 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 or client kotlin.
  • The javaScript provider and the typeScript 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

NameRequiredTypeDescription
destYesString (Path)Into which directory the admin dashboard is generated.
hostYesString (URL)To which host this admin dashboard connects to. Same with client generator.
languagesNoLanguage[]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 or admin 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 of user, users or Users)

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

NameRequiredTypeDescription
fieldsYesFieldIndexes<Self>[]A list of field names.
mapNoString?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

NameRequiredTypeDescription
fieldsYesFieldIndexes<Self>[]A list of field names.
mapNoString?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

NameRequiredTypeDescription
fieldsYesFieldIndexes<Self>[]A list of field names.
mapNoString?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

NameRequiredTypeDescription
tableNameYesStringThe 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

NameRequiredTypeDescription
renamedNoEnumerable<String>?The names that this model previously used.
versionNoString?Annotate this model with a version number.
dropNoBool?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

PositionRequiredTypeDescription
0YesPipeline<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

PositionRequiredTypeDescription
0YesPipeline<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

PositionRequiredTypeDescription
0YesPipeline<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

PositionRequiredTypeDescription
0YesPipeline<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

PositionRequiredTypeDescription
0YesPipeline<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

PositionRequiredTypeDescription
0YesPipeline<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

NameRequiredTypeDescription
generateYesBoolWhether 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

NameRequiredTypeDescription
generateYesBoolWhether 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

NameRequiredTypeDescription
showYesBoolWhether 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

NameRequiredTypeDescription
synthesizeYesBoolWhether 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

ConnectorDefault mapping
MySQLVARCHAR(191)
PostgreSQLtext
SQLiteTEXT
MongoDBString

Bool

Bool represents boolean values aka true and false.

Default type mappings

ConnectorDefault mapping
MySQLTINYINT(1)
PostgreSQLboolean
SQLiteINTEGER
MongoDBBool

Int

Int represents integer number values.

Remarks

  • By default, Int is 32 bits. Int32 and Int64 are available for optimization.

Default type mappings

ConnectorDefault mapping
MySQLINT
PostgreSQLinteger
SQLiteINTEGER
MongoDBInt

Float

Float represents floating point number values.

Remarks

  • By default, Float is 64 bits. Float32 and Float64 are available for optimization.

Default type mappings

ConnectorDefault mapping
MySQLDOUBLE
PostgreSQLdouble precision
SQLiteREAL
MongoDBDouble

Decimal

Decimal represents a decimal number which is accurate and safe for math calculating.

Remarks

  • MongoDB doesn't support Decimal type.

Default type mappings

ConnectorDefault mapping
MySQLdecimal(32,16)
PostgreSQLDecimal(65,30)
SQLiteDECIMAL

Date

Date represents date values including year, month and day.

Default type mappings

ConnectorDefault mapping
MySQLDATE
PostgreSQLDATE
SQLiteString
MongoDBDate

DateTime

DateTime represents date time values.

Default type mappings

ConnectorDefault mapping
MySQLDATETIME(3)
PostgreSQLtimestamp(3)
SQLiteString
MongoDBDate

ObjectId

ObjectId represents a Bson ObjectId type.

Remarks

  • This is MongoDB only data type.

Default type mappings

ConnectorDefault mapping
MongoDBObjectId

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

NameRequiredTypeDescription
sortNoSort?The index sorting order.
lengthNoInt?The index length.
mapNoString?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

NameRequiredTypeDescription
sortNoSort?The index sorting order.
lengthNoInt?The index length.
mapNoString?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

NameRequiredTypeDescription
sortNoSort?The index sorting order.
lengthNoInt?The index length.
mapNoString?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

NameRequiredTypeDescription
columnNameYesStringThe 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

NameRequiredTypeDescription
typeYesMySQLDatabaseType, PostgreSQLDatabaseType, SQLiteDatabaseType, MongoDBDatabaseTypeThe 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 or autoIncrement if you want the database to generate a default value

Signature

declare unique model field decorator default(value?: ThisFieldType | Pipeline<Null, ThisFieldType>)

Arguments

NameRequiredTypeDescription
nameYesThisFieldType | 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

NameRequiredTypeDescription
condYesPipeline<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

NameRequiredTypeDescription
condYesPipeline<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

NameRequiredTypeDescription
fieldsYesEnumerable<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

NameRequiredTypeDescription
fieldsYesEnumerable<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

NameRequiredTypeDescription
condYesPipeline<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

NameRequiredTypeDescription
pipelineYesPipeline<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

NameRequiredTypeDescription
pipelineYesPipeline<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

NameRequiredTypeDescription
pipelineYesPipeline<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

NameRequiredTypeDescription
renamedNoEnumerable<String>?The names that this model field previously used.
versionNoString?Annotate this model field with a version number.
defaultNoThisFieldType?Specify a default value for this new model field.
priorityNoInt?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 and references, 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

NameRequiredTypeDescription
fieldsNoEnumerable<SerializableScalarFields<Self>>Local fields.
referencesNoEnumerable<SerializableScalarFields<ThisFieldType>>Foreign fields.
throughNoT: ModelModel which is used as the join table.
localNoDirectRelations<T>Relation to this model on join table.
foreignNoDirectRelations<T>Relation to other model on join table.
onUpdateNoUpdate?The update rule.
onDeleteNoDelete?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

NameRequiredTypeDescription
pipelineYesPipeline<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

NameRequiredTypeDescription
pipelineYesPipeline<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

NameRequiredTypeDescription
depsYesEnumerable<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

NameRequiredTypeDescription
sortNoSort?The index sorting order.
lengthNoInt?The index length.
mapNoString?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

NameRequiredTypeDescription
sortNoSort?The index sorting order.
lengthNoInt?The index length.
mapNoString?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

NameRequiredTypeDescription
methodNoMethod?The HTTP request method. Default to .post.
pathNoString?The URL path.
ignorePrefixNoBool?Whether ignore the namespace and handler group prefix.
interfaceNoString?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"]