Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Lucid models

A model is a class that matches a database table, and each object of that class is one row of the table. Instead of SQL you call model methods: Post.find(1), post.save(). It is the counterpart of Eloquent models in Laravel, except that columns are listed in the class explicitly.

Creating a model

node ace make:model Post

The file app/models/post.ts appears. The Post model works with the posts table by default. With the -m flag the command also creates a migration: node ace make:model Comment -m.

Describing columns

Each table column is declared as a property with the @column decorator:

// app/models/post.ts
import { DateTime } from 'luxon'
import { BaseModel, column } from '@adonisjs/lucid/orm'
 
export default class Post extends BaseModel {
  @column({ isPrimary: true })
  declare id: number
 
  @column()
  declare title: string
 
  @column()
  declare body: string
 
  @column()
  declare isPublished: boolean
 
  @column.dateTime({ autoCreate: true })
  declare createdAt: DateTime
 
  @column.dateTime({ autoCreate: true, autoUpdate: true })
  declare updatedAt: DateTime
}

Properties are written in camelCase, and Lucid maps them to snake_case columns itself: isPublished is is_published. Dates arrive as DateTime objects from the Luxon library. autoCreate and autoUpdate fill in the creation and update times.

Creating a record

// app/controllers/posts_controller.ts
import Post from '#models/post'
 
const post = await Post.create({
  title: 'First post',
  body: 'Post text',
})
 
console.log(post.id)

create inserts a row into the table and returns the model with id filled in. The same result comes from new Post(), assigning properties and await post.save().

Reading

// app/controllers/posts_controller.ts
const posts = await Post.all()
const post = await Post.find(1)
const bySlug = await Post.findBy('slug', 'hello')

all returns an array of models, find the model with the given id or null, findBy the first record with the given column value.

Updating and deleting

// app/controllers/posts_controller.ts
const post = await Post.findOrFail(1)
post.merge({ title: 'New title' })
await post.save()
 
await post.delete()

merge assigns several properties at once, save writes the changes to the database, delete removes the row.

A model in a controller and a template

// app/controllers/posts_controller.ts
async show({ params, view }: HttpContext) {
  const post = await Post.findOrFail(params.id)
  return view.render('pages/posts/show', { post })
}
{{-- resources/views/pages/posts/show.edge --}}
@layout({ title: post.title })
  <h1>{{ post.title }}</h1>
  <p>{{ post.createdAt.toFormat('dd.MM.yyyy') }}</p>
  <div>{{ post.body }}</div>
@end

Open /posts/1 — the post appears with its date. If the record does not exist, findOrFail throws an exception and the visitor sees a 404 page.

Common mistake

If you forget @column on a property, Lucid does not know about the column: when reading, the property is undefined, and with create the value does not reach the database. Declare a decorated property for every table column you need in code.

Thanks for reading!

Donate to the site — we work hard for you.