Decorators

All of the ORM decorators can be imported as follows:

import {
column,
hasOne,
scope,
beforeSave,
beforeFind,
// ... and so on
} from '@ioc:Adonis/Lucid/Orm'

column

The column decorator marks a model property as a database column.

import { column, BaseModel } from '@ioc:Adonis/Lucid/Orm'
class User extends BaseModel {
@column()
public email: string
}

You can also define any of the following optional properties.

OptionDescription
columnNameThe name of the column inside the database. If not defined, We will use the naming strategy to create the name.
serializeAsThe property name to be used when serializing the model. Setting the value to null will remove the property from the serialized object.
isPrimaryMark column as primary. One model can only have one primary column.
serializeA custom function to handle the column value serialization. For example: Serialize luxon date objects to a string.
prepareA custom function to transform the value before it is saved inside the database.
consumeA custom function to transform the after fetching it from the database and before defining it on the model instance.
metaThe meta object holds arbitrary metadata for the property. 3rd party libraries extending the model's functionality can use this property.
import Encryption from '@ioc:Adonis/Core/Encryption'
import { column, BaseModel } from '@ioc:Adonis/Lucid/Orm'
class User extends BaseModel {
@column({
prepare: (value: string) => Encryption.encrypt(value),
consume: (value: string) => Encryption.decrypt(value),
})
public email: string
@column({
serializeAs: null
})
public password: string
}

column.date / column.dateTime

The column.date decorator marks the column as a date. The decorator enforces the property type to be an instance of luxon.DateTime .

The decorator self defines the prepare, consume and the serialize methods to ensure

  • You are constantly working with an instance of luxon.DateTime in your codebase
  • The date is serialized as an ISO date
  • The date is formatted correctly as per the underlying database driver.
import { DateTime } from 'luxon'
import { column, BaseModel } from '@ioc:Adonis/Lucid/Orm'
class User extends BaseModel {
@column.date()
public dob: DateTime
}

Additionally, you can also define autoCreate and autoUpdate options to always set/update the value when an insert or update query is executed.

You will mainly use these attributes with the createdAt and updatedAt timestamps.

class User extends BaseModel {
@column.dateTime({ autoCreate: true })
public createdAt: DateTime
@column.dateTime({ autoUpdate: true })
public updatedAt: DateTime
}

computed

You can use the computed decorator to serialize a model property when converting the model instance to a JSON object.

import { column, computed, BaseModel } from '@ioc:Adonis/Lucid/Orm'
class User extends BaseModel {
@column()
public firstName: string
@column()
public lastName: string
@computed()
public get fullName() {
return `${this.firstName} ${this.lastName}`
}
}

Now serializing the model will include the fullName as well.

const user = new User()
user.firstName = 'Harminder'
user.lastName = 'Virk'
console.log(user.serialize())
/**
{
firstName: 'Harminder',
lastName: 'Virk',
fullName: 'Harminder Virk'
}
*/

hasOne

The hasOne decorator marks a property as a Has one relationship. It accepts a callback as the first argument. The callback must return the relationship model.

import { hasOne, HasOne, BaseModel } from '@ioc:Adonis/Lucid/Orm'
class User extends Model {
@hasOne(() => Profile)
public profile: HasOne<typeof Profile>
}

Optionally, you can define following options as the 2nd argument.

OptionDescription
foreignKeyThe foreign key for the relationship. You must define the model property name here and Lucid will infer the table column name automatically.
localKeyThe local key is the property name on the current model that forms a relationship with the foreign key
serializeAsThe property name to be used when serializing the relationship. Setting the value to null will remove the relationship from the serialized object.
onQueryA callback to modify all relationship queries. The callback will run for all the select, update and delete operations executed using the relationship query builder.

hasMany

The hasMany decorator marks a property as a hasMany relationship. It accepts a callback as the first argument. The callback must return the relationship model.

import { hasMany, HasMany, BaseModel } from '@ioc:Adonis/Lucid/Orm'
class User extends Model {
@hasMany(() => Post)
public posts: HasMany<typeof Post>
}

Optionally, you can define following options as the 2nd argument.

OptionDescription
foreignKeyThe foreign key for the relationship. You must define the model property name here and Lucid will infer the table column name automatically.
localKeyThe local key is the property name on the current model that forms a relationship with the foreign key
serializeAsThe property name to be used when serializing the relationship. Setting the value to null will remove the relationship from the serialized object.
onQueryA callback to modify all relationship queries. The callback will run for all the select, update and delete operations executed using the relationship query builder.

belongsTo

The belongsTo decorator marks a property as a belongsTo relationship. It accepts a callback as the first argument. The callback must return the relationship model.

import { belongsTo, BelongsTo, BaseModel } from '@ioc:Adonis/Lucid/Orm'
class User extends Model {
@belongsTo(() => Team)
public team: BelongsTo<typeof Team>
}
OptionDescription
foreignKeyThe foreign key for the relationship. In case of belongs to, the foreignKey must be on the current model
localKeyThe local key is the property name on the related model that forms a relationship with the foreign key
serializeAsThe property name to be used when serializing the relationship. Setting the value to null will remove the relationship from the serialized object.
onQueryA callback to modify all relationship queries. The callback will run for all the select, update and delete operations executed using the relationship query builder.

manyToMany

The manyToMany decorator marks a property as a many to many relationship. It accepts a callback as the first argument. The callback must return the relationship model.

import { manyToMany, ManyToMany, BaseModel } from '@ioc:Adonis/Lucid/Orm'
class User extends Model {
@manyToMany(() => Subject)
public subjects: ManyToMany<typeof Subject>
}
OptionDescription
pivotForeignKeyThe foreign key of the current model inside the pivot table.
pivotRelatedForeignKeyThe foreign key of the related model inside the pivot table.
localKeyThe local key is the property name on the current model that forms a relationship with the foreign key
relatedKeyThe related key is the property name on the related model that forms a relationship with the foreign key
serializeAsThe property name to be used when serializing the relationship. Setting the value to null will remove the relationship from the serialized object.
onQueryA callback to modify all relationship queries. The callback will run for all the select, update and delete operations executed using the relationship query builder.

hasManyThrough

The hasManyThrough decorator marks a property as a has many through relationship. It accepts an array of callbacks as the first argument.

  • The first callback returns the related model
  • The second callback returns the through model
import { hasManyThrough, HasManyThrough, BaseModel } from '@ioc:Adonis/Lucid/Orm'
class Country extends Model {
@hasManyThrough([
() => Post,
() => User,
])
public posts: HasManyThrough<typeof Post>
}
OptionDescription
foreignKeyThe foreign key for the relationship. The foreign key forms the relationship between the current model and the through model. ie. The countryId on the User model.
localKeyThe local key is the property name on the current model that forms a relationship with the foreign key
throughForeignKeyThe foreign key that forms the relationship between the through and the related model. ie. The userId on the Post model.
throughLocalKeyThe local key on the through model that forms a relationship with the throughForeignKey.
serializeAsThe property name to be used when serializing the relationship. Setting the value to null will remove the relationship from the serialized object.
onQueryA callback to modify all relationship queries. The callback will run for all the select, update and delete operations executed using the relationship query builder.

beforeSave

The beforeSave decorator registers a given function as a before hook invoked before the insert and the update query.

import { beforeSave, BaseModel } from '@ioc:Adonis/Lucid/Orm'
class User extends BaseModel {
@beforeSave()
public static async hashPassword(user: User) {
if (user.$dirty.password) {
user.password = await Hash.make(user.password)
}
}
}

The after save variant is also supported using the afterSave decorator.


beforeCreate

The beforeCreate decorator registers the function to be invoked just before the insert operation.

import { beforeCreate, BaseModel } from '@ioc:Adonis/Lucid/Orm'
class User extends BaseModel {
@beforeCreate()
public static assignAvatar(user: User) {
user.avatarUrl = getRandomAvatar()
}
}

You can use the afterCreate decorator to define a hook that runs after creating a new row.


beforeUpdate

The beforeUpdate decorator registers the function to be invoked just before the update operation.

import { beforeUpdate, BaseModel } from '@ioc:Adonis/Lucid/Orm'
class User extends BaseModel {
@beforeUpdate()
public static async assignAvatar(user: User) {
user.avatarUrl = getRandomAvatar()
}
}

You can use the afterUpdate decorator to define a hook that runs after updating a row.


beforeDelete

The beforeDelete decorator registers the function to be invoked just before the delete operation.

import { beforeDelete, BaseModel } from '@ioc:Adonis/Lucid/Orm'
class Post extends BaseModel {
@beforeDelete()
public static async removeFromCache(post: Post) {
await Cache.remove(`post-${post.id}`)
}
}

You can use the afterDelete decorator to define a hook that runs after deleting a row.


beforeFind

The beforeFind decorator registers the function to be invoked just before the find operation.

Find operations are one's that intentionally selects a single database row. For example:

  • Model.find()
  • Model.findBy()
  • Model.first()
import {
beforeFind,
BaseModel,
ModelQueryBuilderContract
} from '@ioc:Adonis/Lucid/Orm'
type PostQuery = ModelQueryBuilderContract<typeof Post>
class Post extends BaseModel {
@beforeFind()
public static withoutSoftDeletes(query: PostQuery) {
query.whereNull('deleted_at')
}
}

afterFind

You can use the afterFind decorator to define a hook that runs after finding the row from the database.

The hook receives the model instance as the only argument.

import { afterFind, BaseModel } from '@ioc:Adonis/Lucid/Orm'
class Post extends BaseModel {
@afterFind()
public static async processMarkdown(post) {
post.html = await markdownIt(post.body)
}
}

beforeFetch

The beforeFetch decorator registers the function to be invoked just before the fetch operation.

All select queries except the find operations are considered as fetch operations.

import {
beforeFetch,
BaseModel,
ModelQueryBuilderContract
} from '@ioc:Adonis/Lucid/Orm'
type PostQuery = ModelQueryBuilderContract<typeof Post>
class Post extends BaseModel {
@beforeFetch()
public static withoutSoftDeletes(query: PostQuery) {
query.whereNull('deleted_at')
}
}

afterFetch

The afterFetch decorator registers the function to be invoked after the fetch operation.

The after fetch hook receives an array of model instances as the only argument.

import { afterFetch, BaseModel } from '@ioc:Adonis/Lucid/Orm'
class Post extends BaseModel {
@afterFetch()
public static async processMarkdown(posts: Post[]) {
await Promise.all(posts.map((post) => {
return markdownIt(post.body)
}))
}
}

beforePaginate

The beforePaginate decorator registers the function to be invoked just before the paginate operation.

import {
beforePaginate,
BaseModel,
ModelQueryBuilderContract
} from '@ioc:Adonis/Lucid/Orm'
type PostQuery = ModelQueryBuilderContract<typeof Post>
class Post extends BaseModel {
@beforePaginate()
public static withoutSoftDeletes(
[countQuery, query]: [PostQuery, PostQuery]
) {
countQuery.whereNull('deleted_at')
query.whereNull('deleted_at')
}
}

afterPaginate

The afterPaginate decorator registers the function to be invoked after the paginate operation.

The after paginate hook receives an instance of the paginator .

import {
afterPaginate,
BaseModel,
ModelPaginatorContract
} from '@ioc:Adonis/Lucid/Orm'
type PostPaginator = ModelPaginatorContract<Post>
class Post extends BaseModel {
@afterPaginate()
public static async processMarkdown(paginator: PostPaginator) {
await Promise.all(paginator.all().map((post) => {
return markdownIt(post.body)
}))
}
}