重大变更
注意:
drizzle-orm@0.31.0
可以与drizzle-kit@0.22.0
或更高版本一起使用。Drizzle Kit 同样适用。如果您运行 Drizzle Kit 命令,它将检查并提示您是否需要升级。您可以在 下面 检查 Drizzle Kit 更新。
PostgreSQL 索引 API 已更改
之前的 Drizzle+PostgreSQL 索引 API 不正确,并且与 PostgreSQL 文档不一致。好消息是它在查询中未被使用,且 drizzle-kit 不支持所有索引的属性。这意味着我们现在可以将 API 更改为正确的形式,并在 drizzle-kit 中提供全面支持。
之前的 API
- 在
.on
中定义 SQL 表达式的方式。 - 在我们的情况下,
.using
和.on
是相同的,因此 API 在这里不正确。 .asc()
、.desc()
、.nullsFirst()
和.nullsLast()
应针对索引上的每一列或表达式指定,而不是针对索引本身。
// 索引声明参考
index('name')
.on(table.column1, table.column2, ...) 或 .onOnly(table.column1, table.column2, ...)
.concurrently()
.using(sql``) // sql 表达式
.asc() 或 .desc()
.nullsFirst() 或 .nullsLast()
.where(sql``) // sql 表达式
当前 API
// 第一个示例,使用 `.on()`
index('name')
.on(table.column1.asc(), table.column2.nullsFirst(), ...) 或 .onOnly(table.column1.desc().nullsLast(), table.column2, ...)
.concurrently()
.where(sql``)
.with({ fillfactor: '70' })
// 第二个示例,使用 `.using()`
index('name')
.using('btree', table.column1.asc(), sql`lower(${table.column2})`, table.column1.op('text_ops'))
.where(sql``) // sql 表达式
.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 距离、汉明距离和 Jaccard 距离 - 在 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)
// 以及更多!
🎉 新的 PostgreSQL 类型:point
, line
现在您可以使用 PostgreSQL 几何类型 中的 point
和 line
。
类型 point
有 2 种模式用于数据库的映射:tuple
和 xy
。
-
tuple
将被接受用于插入并在选择时映射为元组。因此,数据库的 Point(1,2) 将在 Drizzle 中被类型化为 [1,2]。 -
xy
将被接受用于插入并在选择时映射为带有 x, y 坐标的对象。因此,数据库的 Point(1,2) 将在 Drizzle 中被类型化为{ x: 1, y: 2 }
。
const items = pgTable('items', {
point: point('point'),
pointObj: point('point_xy', { mode: 'xy' }),
});
类型 line
有 2 种模式用于数据库的映射:tuple
和 abc
。
-
tuple
将被接受用于插入并在选择时映射为元组。因此,数据库的 Line3 将在 Drizzle 中被类型化为 [1,2,3]。 -
abc
将被接受用于插入并在选择时映射为带有 a, b 和 c 常数的对象,来自方程Ax + By + C = 0
。因此,数据库的 Line3 将在 Drizzle 中被类型化为{ a: 1, b: 2, c: 3 }
。
const items = pgTable('items', {
line: line('line'),
lineObj: point('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
具有 2 种模式用于数据库的映射:tuple
和 xy
。
tuple
将被接受用于插入并在选择时映射为元组。因此,数据库 geometry 将在 Drizzle 中被类型化为 [1,2]。xy
将被接受用于插入并在选择时映射为带有 x, y 坐标的对象。因此,数据库 geometry 将在 Drizzle 中被类型化为{ x: 1, y: 2 }
。
类型
本次发布具有预定义类型:point
,这是 PostgreSQL PostGIS 扩展中的 geometry(Point)
类型。如果您想使用其他类型,可以在此指定任何字符串。
Drizzle Kit 更新:drizzle-kit@0.22.0
此处的发行说明部分复制自 drizzle-kit@0.22.0
新特性
🎉 对新类型的支持
Drizzle Kit 现在可以处理:
- PostgreSQL 的
point
和line
- PostgreSQL
pg_vector
扩展中的vector
- PostgreSQL
PostGIS
扩展中的geometry
🎉 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)
}
})
规范化 SQLite 的 libsql 和 better-sqlite3 驱动程序的 URL
这些驱动程序具有不同的文件路径模式,Drizzle Kit 将接受两者并为每一个创建适当的文件路径格式。
更新 MySQL 和 SQLite 的 index-as-expression 行为
在本次发布中,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})`),
}),
);
-- 之前
CREATE UNIQUE INDEX `emailUniqueIndex` ON `users` (`lower("users"."email")`);
-- 现在
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) // 将正常工作,名称将自动生成
index('my_name').on(table.id, table.email) // 将正常工作
// 但是
index().on(sql`lower(${table.email})`) // 错误
index('my_name').on(sql`lower(${table.email})`) // 将正常工作
如果以下字段(列表如下)在现有索引中更改,push
将不会生成语句:
.on()
和.using()
中的表达式.where()
语句- 列上的操作符类
.op()
如果您使用 push
工作流并希望更改这些字段中的索引,您需要:
- 注释掉索引
- 推送
- 取消注释索引并更改这些字段
- 再次推送
对于 generate
命令,任何在新 drizzle 索引 API 中对索引的属性的更改都会触发 drizzle-kit
,因此在这里没有限制。