Schema 构建器

Schema 构建器

本指南是在迁移文件中公开的 schema 构建器 API 的参考。你将学会如何:

  • 创建、修改、重命名和删除表
  • 在运行时检查表或列是否存在
  • 创建和删除 PostgreSQL schema
  • 创建和管理视图(包括物化视图)
  • 当构建器无法表达你需要的内容时运行原始 DDL 语句

概述

Schema 构建器是在迁移中发出 DDL 语句(CREATE、ALTER、DROP)的 API。通过扩展 BaseSchema 的类上的 this.schema 访问它。

import { BaseSchema } from '@adonisjs/lucid/schema'
export default class extends BaseSchema {
protected tableName = 'users'
async up() {
this.schema.createTable(this.tableName, (table) => {
table.increments('id')
table.string('email').unique().notNullable()
table.timestamps(true, true)
})
}
async down() {
this.schema.dropTable(this.tableName)
}
}

有关列级配置(列类型、约束、索引、外键),请参见 table 构建器参考。有关包括 this.deferthis.now() 和其他助手在内的完整迁移类 API,请参见迁移介绍

createTable

创建一个新表。传入表名和接收 table 构建器的回调。

this.schema.createTable('posts', (table) => {
table.increments('id')
table.string('title').notNullable()
table.text('body')
table.timestamps(true, true)
})

createTableIfNotExists

仅在表不存在时创建它。当同一迁移可能针对已通过带外方式创建了表的环境运行时很有用。

this.schema.createTableIfNotExists('posts', (table) => {
table.increments('id')
table.string('title').notNullable()
})

createTableLike

将现有表的结构复制到新表中。可选地传入回调以向新表添加列。

this.schema.createTableLike('posts_archive', 'posts')
this.schema.createTableLike('posts_archive', 'posts', (table) => {
table.timestamp('archived_at')
})

支持因方言而异;PostgreSQL 和 MySQL 原生实现它,而其他方言则模拟它。

alterTable

修改现有表。相同的回调接收 table 构建器,但只有修改方法(添加、删除、重命名、修改列)会生效。

this.schema.alterTable('users', (table) => {
table.string('first_name')
table.string('last_name')
table.dropColumn('name')
})

this.schema.table(name, callback)alterTable 的别名。

renameTable

重命名表。返回 Promise<void> 而不是 schema 构建器,因此不能链式调用。

await this.schema.renameTable('user', 'users')

dropTable

删除现有表。在迁移的 down 方法中使用它来撤销 createTable

this.schema.dropTable('users')

dropTableIfExists

仅在表存在时删除它。对于表可能已被删除的清理迁移很有用。

this.schema.dropTableIfExists('legacy_audit')

存在性检查

Schema 构建器公开异步助手,为表或列的存在性返回布尔值。使用它们来编写适应当前数据库状态的条件迁移。

hasTable

async up() {
const exists = await this.schema.hasTable('legacy_audit')
if (!exists) {
return
}
this.defer(async (db) => {
await db.from('legacy_audit').delete()
})
this.schema.dropTable('legacy_audit')
}

hasColumn

async up() {
const hasOldName = await this.schema.hasColumn('users', 'name')
if (!hasOldName) {
return
}
this.schema.alterTable('users', (table) => {
table.renameColumn('name', 'full_name')
})
}

当同一迁移必须在具有不同历史的环境之间工作时,将条件 schema 操作包装在这些 await 检查中。

Schemas

PostgreSQL 将表分组到 schemas(数据库内的逻辑命名空间)。Schema 构建器公开用于创建和删除 schemas 的助手,以及针对特定 schema 执行后续操作。

createSchema

创建一个 schema。

this.schema.createSchema('analytics')

createSchemaIfNotExists

仅在 schema 不存在时创建它。

this.schema.createSchemaIfNotExists('analytics')

dropSchema

删除一个 schema。将 true 作为第二个参数传入以级联删除 schema 内的所有对象。

this.schema.dropSchema('analytics')
this.schema.dropSchema('analytics', true)

dropSchemaIfExists

仅在 schema 存在时删除它。接受相同的 cascade 参数。

this.schema.dropSchemaIfExists('analytics', true)

withSchema

为下一个 DDL 操作针对非默认 schema。

this.schema
.withSchema('analytics')
.createTable('events', (table) => {
table.increments('id')
table.string('name').notNullable()
table.timestamp('occurred_at', { useTz: true })
})

视图

视图是作为虚拟表公开的已保存查询定义。Schema 构建器公开标准视图操作集,在 PostgreSQL 上还包括物化视图系列。

createView

从接收视图构建器的回调创建视图。使用视图构建器的 as(query) 方法定义底层查询。

this.schema.createView('active_users', (view) => {
view.columns(['id', 'email'])
view.as(this.knex().select('id', 'email').from('users').where('is_active', true))
})

createViewOrReplace

在单个语句中创建或替换现有视图。在 PostgreSQL 和 MySQL 上受支持。

this.schema.createViewOrReplace('active_users', (view) => {
view.as(this.knex().select('id', 'email').from('users').where('is_active', true))
})

alterView

修改现有视图。注意某些方言不支持就地修改视图定义;在这些情况下,删除并重新创建视图。

this.schema.alterView('active_users', (view) => {
view.column('id').rename('user_id')
})

this.schema.view(name, callback)alterView 的别名。

renameView

重命名视图。在 PostgreSQL 上受支持。

this.schema.renameView('active_users', 'enabled_users')

dropView 和 dropViewIfExists

删除视图。IfExists 变体仅在视图存在时删除它。

this.schema.dropView('active_users')
this.schema.dropViewIfExists('active_users')

createMaterializedView

创建物化视图,它将查询结果存储在磁盘上并按需刷新。仅限 PostgreSQL。

this.schema.createMaterializedView('user_stats', (view) => {
view.columns(['user_id', 'post_count'])
view.as(
this.knex()
.select('user_id', this.raw('count(*) as post_count'))
.from('posts')
.groupBy('user_id')
)
})

refreshMaterializedView

刷新物化视图内的数据。为 concurrently 参数传入 true 以在不阻塞并发读取的情况下刷新(PostgreSQL)。

this.schema.refreshMaterializedView('user_stats')
this.schema.refreshMaterializedView('user_stats', true)

dropMaterializedView 和 dropMaterializedViewIfExists

删除物化视图。IfExists 变体仅在视图存在时删除它。

this.schema.dropMaterializedView('user_stats')
this.schema.dropMaterializedViewIfExists('user_stats')

原始 SQL

当构建器无法表达你需要的 DDL(供应商特定选项、自定义触发器、扩展管理)时,降级到原始 SQL。

this.schema.raw("CREATE EXTENSION IF NOT EXISTS \"uuid-ossp\"")
this.schema
.raw("SET sql_mode='TRADITIONAL'")
.alterTable('users', (table) => {
table.dropColumn('name')
table.string('first_name')
table.string('last_name')
})

Schema 构建器的 raw 方法仅接受 SQL 字符串,不接受绑定。当你需要参数化 SQL 时,改用 BaseSchemathis.raw(sql, bindings?),它返回一个 Knex Raw 实例,你可以将其传入列默认值或其他构建器方法。

this.schema.alterTable('users', (table) => {
table.uuid('uuid').defaultTo(this.raw('gen_random_uuid()'))
})

参见迁移介绍了解完整的 BaseSchema API,包括 this.now()this.knex()this.defer()