Table 构建器

Table 构建器

本指南是在 createTablealterTable 回调中使用的 table 构建器 API 的参考。你将学会如何:

  • 添加每种支持类型的列
  • 应用列修饰符,如 notNullabledefaultTounsigned 和索引
  • 定义外键,包括级联规则和可延迟约束
  • 添加 check 约束以在数据库层进行值验证
  • 在表级别创建复合索引和约束
  • 修改、删除和重命名列
  • 应用表级选项,如引擎和字符集

概述

Table 构建器是在 schema 构建器的 createTablealterTable 回调中定义列级和表级结构的 API。

import { BaseSchema } from '@adonisjs/lucid/schema'
export default class extends BaseSchema {
async up() {
this.schema.createTable('posts', (table) => {
table.increments('id')
table.string('title').notNullable()
table.text('body')
table.integer('user_id').unsigned().references('users.id').onDelete('CASCADE')
table.timestamps(true, true)
})
}
}

有关 schema 本身的操作(createTablealterTabledropTable 等),请参见 schema 构建器参考。有关迁移类相关内容如 this.deferthis.now() 和事务控制,请参见迁移介绍

列类型

increments

自增整数列。默认标记为主键。

table.increments('id')
table.increments('id', { primaryKey: false }) // 跳过自动主键

PostgreSQL 使用 serial;MySQL 使用 int unsigned auto_increment;Redshift 使用 integer identity (1,1)

bigIncrements

自增 bigint 列。默认标记为主键。

table.bigIncrements('id')

integer

标准整数列。

table.integer('view_count')

tinyint、smallint、mediumint、bigInteger

更小和更大的整数类型。bigInteger 在 PostgreSQL 和 MySQL 上是 bigint;在没有原生 bigint 的方言上回退为普通整数。bigintbigInteger 的别名。

table.tinyint('flag_byte')
table.smallint('priority')
table.mediumint('view_bucket') // 仅限 MySQL
table.bigInteger('snowflake_id')

Bigint 值在查询结果中以字符串形式返回,以避免 JavaScript 精度丢失。

float

浮点列,可选精度(默认 8)和小数位(默认 2)。

table.float('rating')
table.float('price', 8, 2)

double

双精度浮点列。与 float 相同的精度和小数位参数。

table.double('balance', 14, 4)

decimal

固定精度小数列。将 null 作为精度传入以允许任意精度(PostgreSQL、SQLite、Oracle)。

table.decimal('price')
table.decimal('price', 8, 2)
table.decimal('amount', null) // 任意精度

boolean

布尔列。许多方言将布尔值表示为 0/1 并以此形式返回。

table.boolean('is_published')

string

可变长度字符串列,可选长度(默认 255)。

table.string('title')
table.string('title', 100)

text

长文本列。在 MySQL 上传入 'mediumtext''longtext' 作为第二个参数;在其他方言上被忽略。

table.text('body')
table.text('body', 'longtext')

date

日期列(无时间部分)。

table.date('dob')

time

时间列(无日期)。MySQL 接受精度选项。

table.time('starts_at')
table.time('starts_at', { precision: 6 })

dateTime

DateTime 列,可选时区和精度。dateTimedatetime 是别名。

table.dateTime('starts_at', { useTz: true })
table.dateTime('starts_at', { precision: 6 }).defaultTo(this.now(6))

useTz: true 在 PostgreSQL 上生成 timestamptz,在 MSSQL 上生成 DATETIME2

timestamp

时间戳列。与 dateTime 相同的 options 对象。

table.timestamp('created_at')
table.timestamp('created_at', { useTz: true })
table.timestamp('created_at', { precision: 6 })

timestamps

便捷方法,添加 created_atupdated_at 列。签名为 timestamps(useTimestamps, defaultToNow)

table.timestamps() // DATETIME 列,无默认值
table.timestamps(true) // TIMESTAMP 列,无默认值
table.timestamps(true, true) // TIMESTAMP 列,默认 CURRENT_TIMESTAMP

对于需要索引、自定义精度或时区感知列的应用,优先使用两个 table.timestamp(...) 调用而非 timestampstimestamps 快捷方式返回 void,因此你无法在它创建的列上链式调用修饰符。

binary

二进制 blob 列,可选长度参数(仅限 MySQL)。

table.binary('document')
table.binary('document', 1024)

uuid

UUID 列。在 PostgreSQL 上使用原生 uuid 类型,在其他地方使用 char(36)

table.uuid('id').primary().defaultTo(this.raw('gen_random_uuid()'))

在较旧的 PostgreSQL 版本上,在使用 uuid 列之前,在单独的迁移中安装 uuid-ossp 扩展:

this.schema.raw('CREATE EXTENSION IF NOT EXISTS "uuid-ossp"')

json

JSON 列。在 PostgreSQL、MySQL 和 SQLite 上使用原生 json 类型,在不支持 JSON 的方言上回退为 text 列。

table.json('settings')

jsonb

以二进制表示存储的 JSON 列,支持索引访问。仅限 PostgreSQL;在其他地方回退为 json

table.jsonb('preferences')

enum / enu

枚举列。传入列名、允许值数组和 options 对象。

table.enu('status', ['draft', 'published', 'archived'])

当你使用 useNative 并提供唯一的 enumName 时,PostgreSQL 支持原生枚举类型。当类型已存在于数据库中时,设置 existingType: true

table.enu('status', ['draft', 'published', 'archived'], {
useNative: true,
enumName: 'post_status',
existingType: false,
schemaName: 'public',
})

当删除使用原生枚举类型的表时,同时删除该类型以避免留下孤儿:

this.schema.raw('DROP TYPE IF EXISTS "post_status"')
this.schema.dropTable('posts')

enu 是较旧的名称;enum 是后来添加的别名,因为 enum 在某些构建设置中是保留关键字。

geometry、geography、point

空间列。在 PostgreSQL(配合 PostGIS)、MySQL 和其他具有空间支持的方言上可用。

table.geometry('shape')
table.geography('coverage_area')
table.point('location')

specificType

当构建器未原生暴露该类型时,使用原始类型字符串定义列。

table.specificType('mac_address', 'macaddr')
table.specificType('tags', 'text[]') // PostgreSQL 数组

列修饰符

以下方法可在任何列类型方法的结果上链式调用。它们修改正在创建(或修改)的列。

defaultTo

为插入设置默认值。

table.boolean('is_published').defaultTo(false)
table.timestamp('created_at').defaultTo(this.now())
table.uuid('id').defaultTo(this.raw('gen_random_uuid()'))

在 MSSQL 上,传入 constraintName 选项以控制生成的默认约束的名称:

table.boolean('is_published').defaultTo(false, { constraintName: 'df_posts_is_published' })

notNullable 和 nullable

将列标记为 NOT NULLNULL

table.string('email').notNullable()
table.text('bio').nullable()

修改现有列时,优先使用 setNullabledropNullable(如下所述),使约束变更更加明确。

unsigned

将数值列标记为无符号。在 PostgreSQL 上无效,因为它不支持无符号整数。

table.integer('user_id').unsigned()

primary

将列标记为主键。传入可选的 options 对象,包含 constraintNamedeferrable

table.uuid('id').primary()
table.uuid('id').primary({ constraintName: 'posts_pk' })

对于复合主键,使用下面展示的表级 table.primary([...])

unique

在列上添加唯一索引。传入可选的 options 对象,包含 indexNamedeferrable

table.string('email').unique()
table.string('email').unique({ indexName: 'users_email_unique' })

对于复合唯一索引,使用表级 table.unique([...])

index

在列上添加索引。传入可选的索引名和可选的索引类型(PostgreSQL 和 MySQL)。

table.string('slug').index()
table.string('slug').index('posts_slug_idx')
table.json('payload').index('posts_payload_gin', 'gin')

first 和 after

将列定位在表的开头(first)或特定列之后(after)。仅限 MySQL。

table.string('email').first()
table.string('avatar_url').after('password')

comment

在列上设置注释。

table.string('avatar_url').comment('Stored as a relative path')

collate

设置列的排序规则。仅限 MySQL。

table.string('email').collate('utf8_unicode_ci')

外键

外键可以作为列修饰符内联声明,也可以在表级别声明用于复合键。两种形式共享相同的下游方法。

references 和 inTable

定义引用的列和表。简写形式 references('table.column') 将两者合并。

// 完整形式
table.integer('user_id').references('id').inTable('users')
// 简写形式
table.integer('user_id').references('users.id')
// 表级别(允许复合键和命名约束)
table.foreign('user_id').references('users.id')
table.foreign(['tenant_id', 'user_id']).references(['tenant_id', 'id']).inTable('users')

onDelete 和 onUpdate

指定当引用行被删除或更新时采取的操作。标准 SQL 操作:CASCADESET NULLRESTRICTNO ACTIONSET DEFAULT

table
.integer('user_id')
.references('users.id')
.onDelete('CASCADE')
.onUpdate('RESTRICT')

withKeyName

覆盖自动生成的外键约束名称。当你后续需要按名称删除或修改约束时很有用。

table
.integer('user_id')
.references('users.id')
.withKeyName('posts_user_id_fk')

deferrable

将外键标记为可延迟,使约束检查延迟到提交时。仅限 PostgreSQL。接受 'deferred''immediate''not deferrable'

table
.integer('user_id')
.references('users.id')
.deferrable('deferred')

Check 约束

Check 约束对每个插入或更新的行强制执行谓词。在 PostgreSQL、MySQL 8+、MSSQL、SQLite 和 Oracle 上可用。每个方法接受可选的约束名作为最后一个参数。

checkPositive、checkNegative

table.integer('balance').checkPositive()
table.integer('temperature_below_zero').checkNegative('temp_must_be_negative')

checkIn 和 checkNotIn

table.string('status').checkIn(['draft', 'published', 'archived'])
table.string('locale').checkNotIn(['xx', 'yy'], 'locale_blacklist')

checkBetween

传入 [min, max] 元组表示单个范围,或元组数组表示多个可接受范围。

table.integer('rating').checkBetween([1, 5])
table.integer('hour').checkBetween([[0, 11], [13, 23]]) // 跳过 12

checkLength

table.string('handle').checkLength('>=', 3)
table.string('handle').checkLength('<=', 30, 'handle_max_length')

checkRegex

正则检查,写为 SQL 兼容的模式(方言特定语法)。

table.string('handle').checkRegex('^[a-z0-9_]+$')

dropChecks

删除在列上定义的所有 check 约束。

table.dropChecks()

表级约束

这些方法位于 table 构建器上,而非链式调用在列上。用于复合索引、复合外键和命名约束。

primary

定义单列或复合主键。

table.primary(['tenant_id', 'user_id'])
table.primary(['tenant_id', 'user_id'], { constraintName: 'tenant_user_pk' })

unique

定义单列或复合唯一索引。

table.unique(['slug', 'tenant_id'])
table.unique(['slug', 'tenant_id'], { indexName: 'posts_slug_tenant_unique' })

index

跨一个或多个列添加索引。

table.index(['first_name', 'last_name'])
table.index(['first_name', 'last_name'], 'users_full_name_idx')
table.index(['payload'], 'posts_payload_gin', 'gin') // PostgreSQL:索引类型

foreign

添加外键约束,包括复合键。可使用相同的 referencesinTableonDeleteonUpdatewithKeyNamedeferrable 方法。

table.foreign('user_id').references('users.id').onDelete('CASCADE')
table
.foreign(['tenant_id', 'user_id'])
.references(['tenant_id', 'id'])
.inTable('users')
.withKeyName('posts_tenant_user_fk')

修改现有列

以下方法在 alterTable(或 this.schema.table(...))内部有效。

alter

将列定义标记为修改而非添加。修改是非增量的:你必须重新声明你希望列保留的每个约束。

this.schema.alterTable('posts', (table) => {
table.text('body').notNullable().alter()
})

传入选项以控制修改哪些方面:

table.text('body').alter({ alterNullable: true, alterType: false })

alter 在 SQLite 或 Redshift 上不受支持。

setNullable 和 dropNullable

切换现有列的可空性,而无需重新定义其类型。

this.schema.alterTable('users', (table) => {
table.setNullable('phone')
table.dropNullable('email')
})

当列已包含 NULL 值时,dropNullable 会失败;在应用之前先回填数据。

renameColumn

重命名列。

table.renameColumn('name', 'full_name')

删除列和约束

dropColumn 和 dropColumns

按名称删除一个或多个列。

table.dropColumn('legacy_field')
table.dropColumns('first_name', 'middle_name', 'last_name')

dropPrimary

删除主键约束。当约束使用自定义名称创建时,传入可选名称。

table.dropPrimary()
table.dropPrimary('posts_pk')

dropUnique

删除唯一索引。传入列和可选的索引名。

table.dropUnique(['email'])
table.dropUnique(['slug', 'tenant_id'], 'posts_slug_tenant_unique')

dropIndex

删除索引。传入列和可选的索引名。

table.dropIndex(['first_name', 'last_name'])
table.dropIndex(['first_name', 'last_name'], 'users_full_name_idx')

dropForeign

删除外键约束。传入列和可选的约束名。

table.dropForeign('user_id')
table.dropForeign(['tenant_id', 'user_id'], 'posts_tenant_user_fk')

dropTimestamps

删除由 timestamps() 添加的 created_atupdated_at 列。

table.dropTimestamps()

表选项

comment

在表上设置注释。

table.comment('Tracks every published article')

engine

设置存储引擎。仅限 MySQL。

table.engine('InnoDB')

charset

设置表级字符集。仅限 MySQL。

table.charset('utf8mb4')

collate

设置表级排序规则。仅限 MySQL。

table.collate('utf8mb4_unicode_ci')

inherits

设置用于继承的父表。仅限 PostgreSQL。

table.inherits('cities')