重大变更
注意:
drizzle-orm@0.31.0
可以与drizzle-kit@0.22.0
或更高版本一起使用。这同样适用于 Drizzle Kit。如果你运行 Drizzle Kit 命令,它将检查并提示你进行升级(如果需要)。你可以查看 Drizzle Kit 的更新。below
PostgreSQL 索引 API 已更改
之前的 Drizzle+PostgreSQL 索引 API 不正确,并且与 PostgreSQL 文档不一致。好消息是,它没有在查询中使用,而且 drizzle-kit 并不支持索引的所有属性。这意味着我们现在可以将 API 更改为正确的 API,并在 drizzle-kit 中提供对其的全面支持。
之前的 API
-
无法在
.on
中定义 SQL 表达式。 -
在我们的例子中,
.using
和.on
是同一个,因此此处的 API 不正确。 -
索引中的每个列或表达式都应该指定
.asc()
、.desc()
、.nullsFirst()
和.nullsLast()
,但索引本身不需要。
// Index declaration reference
index('name')
.on(table.column1, table.column2, ...) or .onOnly(table.column1, table.column2, ...)
.concurrently()
.using(sql``) // sql expression
.asc() or .desc()
.nullsFirst() or .nullsLast()
.where(sql``) // sql expression
当前 API
// First example, with `.on()`
index('name')
.on(table.column1.asc(), table.column2.nullsFirst(), ...) or .onOnly(table.column1.desc().nullsLast(), table.column2, ...)
.concurrently()
.where(sql``)
.with({ fillfactor: '70' })
// Second Example, with `.using()`
index('name')
.using('btree', table.column1.asc(), sql`lower(${table.column2})`, table.column1.op('text_ops'))
.where(sql``) // sql expression
.with({ fillfactor: '70' })
新功能
🎉 “pg_vector” 扩展支持
Drizzle 模式中没有用于创建扩展的特定代码。我们假设如果你使用向量类型、索引和查询,则你已安装
pg_vector
扩展的 PostgreSQL 数据库。
你现在可以为 pg_vector
指定索引,并使用 pg_vector
函数进行查询、排序等操作。
让我们从 pg_vector
文档中选取一些 pg_vector
索引的示例,并将它们转换为 Drizzle 格式。
L2 距离、内积和余弦距离
// CREATE INDEX ON items USING hnsw (embedding vector_l2_ops);
// CREATE INDEX ON items USING hnsw (embedding vector_ip_ops);
// CREATE INDEX ON items USING hnsw (embedding vector_cosine_ops);
const table = pgTable('items', {
embedding: vector('embedding', { dimensions: 3 })
}, (table) => ({
l2: index('l2_index').using('hnsw', table.embedding.op('vector_l2_ops'))
ip: index('ip_index').using('hnsw', table.embedding.op('vector_ip_ops'))
cosine: index('cosine_index').using('hnsw', table.embedding.op('vector_cosine_ops'))
}))
L1 距离、汉明距离和杰卡德距离 - 在 pg_vector 0.7.0 版本中添加
// CREATE INDEX ON items USING hnsw (embedding vector_l1_ops);
// CREATE INDEX ON items USING hnsw (embedding bit_hamming_ops);
// CREATE INDEX ON items USING hnsw (embedding bit_jaccard_ops);
const table = pgTable('table', {
embedding: vector('embedding', { dimensions: 3 })
}, (table) => ({
l1: index('l1_index').using('hnsw', table.embedding.op('vector_l1_ops'))
hamming: index('hamming_index').using('hnsw', table.embedding.op('bit_hamming_ops'))
bit: index('bit_jaccard_index').using('hnsw', table.embedding.op('bit_jaccard_ops'))
}))
对于查询,你可以使用预定义的向量函数,也可以使用 SQL 模板运算符创建自定义函数。
你还可以使用以下辅助程序:
import { l2Distance, l1Distance, innerProduct,
cosineDistance, hammingDistance, jaccardDistance } from 'drizzle-orm'
l2Distance(table.column, [3, 1, 2]) // table.column <-> '[3, 1, 2]'
l1Distance(table.column, [3, 1, 2]) // table.column <+> '[3, 1, 2]'
innerProduct(table.column, [3, 1, 2]) // table.column <#> '[3, 1, 2]'
cosineDistance(table.column, [3, 1, 2]) // table.column <=> '[3, 1, 2]'
hammingDistance(table.column, '101') // table.column <~> '101'
jaccardDistance(table.column, '101') // table.column <%> '101'
如果 pg_vector
需要使用其他函数,你可以从我们现有的实现中复制实现。具体操作如下
export function l2Distance(
column: SQLWrapper | AnyColumn,
value: number[] | string[] | TypedQueryBuilder<any> | string,
): SQL {
if (is(value, TypedQueryBuilder<any>) || typeof value === 'string') {
return sql`${column} <-> ${value}`;
}
return sql`${column} <-> ${JSON.stringify(value)}`;
}
你可以根据需要命名它并更改操作符。此示例允许使用数字数组、字符串数组、字符串,甚至是选择查询。你可以随意创建任何其他类型,甚至可以贡献代码并提交 PR。
示例
让我们从 pg_vector
文档中选取一些 pg_vector
查询的示例,并将它们转换为 Drizzle 格式。
import { l2Distance } from 'drizzle-orm';
// SELECT * FROM items ORDER BY embedding <-> '[3,1,2]' LIMIT 5;
db.select().from(items).orderBy(l2Distance(items.embedding, [3,1,2]))
// SELECT embedding <-> '[3,1,2]' AS distance FROM items;
db.select({ distance: l2Distance(items.embedding, [3,1,2]) })
// SELECT * FROM items ORDER BY embedding <-> (SELECT embedding FROM items WHERE id = 1) LIMIT 5;
const subquery = db.select({ embedding: items.embedding }).from(items).where(eq(items.id, 1));
db.select().from(items).orderBy(l2Distance(items.embedding, subquery)).limit(5)
// SELECT (embedding <#> '[3,1,2]') * -1 AS inner_product FROM items;
db.select({ innerProduct: sql`(${maxInnerProduct(items.embedding, [3,1,2])}) * -1` }).from(items)
// and more!
🎉 新的 PostgreSQL 类型:point
, line
你现在可以从 PostgreSQL 几何类型 中使用 point
和 line
。
类型 point
有两种数据库映射模式:tuple
和 xy
。
-
tuple
将被接受用于插入操作,并在选择时映射到元组。因此,使用 drizzle 后,数据库 Point(1,2) 的类型将被设置为 [1,2]。 -
xy
将被接受用于插入,并在选择时映射到具有 x、y 坐标的对象。因此,使用 drizzle 后,数据库 Point(1,2) 的类型将被设置为{ x: 1, y: 2 }
。
const items = pgTable('items', {
point: point('point'),
pointObj: point('point_xy', { mode: 'xy' }),
});
类型 line
有两种数据库映射模式:tuple
和 abc
。
-
tuple
将被接受用于插入操作,并在选择时映射到元组。因此,使用 drizzle 后,数据库 Line3 的类型将被设置为 [1,2,3]。 -
abc
将被接受用于插入,并在选择时映射到具有方程式Ax + By + C = 0
中的 a、b 和 c 常量的对象。因此,使用 drizzle 后,数据库 Line3 的类型将被设置为{ a: 1, b: 2, c: 3 }
。
const items = pgTable('items', {
line: line('line'),
lineObj: line('line_abc', { mode: 'abc' }),
});
🎉 基本 “postgis” 扩展支持
Drizzle 模式中没有用于创建扩展的特定代码。我们假设如果你使用 Postgis 类型、索引和查询,则你已安装
postgis
扩展的 PostgreSQL 数据库。
来自 Postgis 扩展的 geometry
类型:
const items = pgTable('items', {
geo: geometry('geo', { type: 'point' }),
geoObj: geometry('geo_obj', { type: 'point', mode: 'xy' }),
geoSrid: geometry('geo_options', { type: 'point', mode: 'xy', srid: 4000 }),
});
模式类型 geometry
有两种从数据库映射的模式:tuple
和 xy
。
-
tuple
将被接受用于插入操作,并在选择时映射到元组。因此,使用 drizzle 后,数据库 geom 的类型将被设置为 [1,2]。 -
xy
将被接受用于插入,并在选择时映射到具有 x、y 坐标的对象。因此,使用 drizzle 后,数据库 geom 的类型将被设置为{ x: 1, y: 2 }
。
type
当前版本具有预定义类型:point
,是 PostgreSQL PostGIS 扩展中的 geometry(Point)
类型。如果你想使用其他类型,你可以在其中指定任何字符串。
Drizzle Kit 更新:drizzle-kit@0.22.0
此处的发行说明部分内容与 drizzle-kit@0.22.0 重复。
新功能
🎉 支持新类型
Drizzle Kit 现在可以处理:
-
PostgreSQL 中的
point
和line
-
vector
来自 PostgreSQLpg_vector
扩展 -
geometry
来自 PostgreSQLPostGIS
扩展
🎉 drizzle.config 中的新参数 - extensionsFilters
PostGIS 扩展在 public
模式中创建了一些内部表。这意味着,如果你的数据库带有 PostGIS 扩展并使用 push
或 introspect
,所有这些表都将包含在 diff
操作中。在这种情况下,你需要指定 tablesFilter
,查找扩展程序创建的所有表,并在此参数中列出它们。
我们已经解决了这个问题,因此你无需执行所有这些步骤。只需使用所用扩展名指定 extensionsFilters
,Drizzle 就会跳过所有必要的表。
目前,我们仅支持 postgis
选项,但如果它们在 public
模式下创建表,我们计划添加更多扩展。
postgis
选项将跳过 geography_columns
、geometry_columns
和 spatial_ref_sys
表
import { defineConfig } from 'drizzle-kit'
export default defaultConfig({
dialect: "postgresql",
extensionsFilters: ["postgis"],
})
改进
更新数据库凭据的 zod 模式,并针对所有正/负情况编写测试
- 在套件配置中支持完整的 SSL 参数集,并提供 node:tls 连接的类型
import { defineConfig } from 'drizzle-kit'
export default defaultConfig({
dialect: "postgresql",
dbCredentials: {
ssl: true, //"require" | "allow" | "prefer" | "verify-full" | options from node:tls
}
})
import { defineConfig } from 'drizzle-kit'
export default defaultConfig({
dialect: "mysql",
dbCredentials: {
ssl: "", // string | SslOptions (ssl options from mysql2 package)
}
})
为 libsql
和 better-sqlite3
驱动程序规范化 SQLite URL
这些驱动程序具有不同的文件路径模式,Drizzle Kit 会同时接受这两种驱动程序,并为每个驱动程序创建合适的文件路径格式。
更新 MySQL 和 SQLite 索引作为表达式的行为
在此版本中,MySQL 和 SQLite 将正确地将表达式映射到 SQL 查询中。表达式不会在字符串中转义,但列会。
export const users = sqliteTable(
'users',
{
id: integer('id').primaryKey(),
email: text('email').notNull(),
},
(table) => ({
emailUniqueIndex: uniqueIndex('emailUniqueIndex').on(sql`lower(${table.email})`),
}),
);
-- before
CREATE UNIQUE INDEX `emailUniqueIndex` ON `users` (`lower("users"."email")`);
-- now
CREATE UNIQUE INDEX `emailUniqueIndex` ON `users` (lower("email"));
错误修复
-
[BUG]:不添加多个约束(仅生成第一个约束) - #2341
-
Drizzle Studio:错误:连接意外终止 - #435
-
无法在本地运行 SQLite 迁移 - #432
-
错误:未知选项 ‘—config’ - #423
push
和 generate
如何用于索引
限制
如果至少一个表达式上有索引,则应手动指定索引名称
示例
index().on(table.id, table.email) // will work well and name will be autogeneretaed
index('my_name').on(table.id, table.email) // will work well
// but
index().on(sql`lower(${table.email})`) // error
index('my_name').on(sql`lower(${table.email})`) // will work well
如果现有索引中的以下字段(见下文)发生更改,则推送操作不会生成语句:
-
.on()
和.using()
中的表达式 -
.where()
声明 -
操作符类
.op()
作用于列
如果你正在使用 push
工作流并希望更改索引中的这些字段,则需要:
-
注释掉索引
-
推送
-
取消索引的注释并更改相关字段
-
再次推送
对于 generate
命令,新的 drizzle 索引 API 中任何属性的索引更改都会触发 drizzle-kit
,因此这里没有限制。