重大变更
注意:
[email protected]
可与[email protected]
或更高版本一起使用。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 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 Schema 中没有用于创建扩展的特定代码。我们假定如果您使用向量类型、索引和查询,则您已安装了带
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)}`;
}
您可以随意命名并更改操作符。此示例允许使用数字数组、字符串数组、字符串,甚至是一个 SELECT 查询。您可以随意创建任何其他类型的函数,甚至可以通过提交 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
类型有 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
模式支持插入,并在查询时映射为包含方程Ax + By + C = 0
中 a、b、c 常量的对象。因此,数据库中的 Line3 在 Drizzle 中将被类型化为{ a: 1, b: 2, c: 3 }
。
const items = pgTable('items', {
line: line('line'),
lineObj: line('line_abc', { mode: 'abc' }),
});
🎉 基本支持 “postgis” 扩展
Drizzle Schema 中没有用于创建扩展的特定代码。我们假定如果您使用 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 }),
});
mode 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 更新:[email protected]
这里的发布说明部分复制自 [email protected]
新特性
🎉 支持新类型
Drizzle Kit 现在可以处理
- PostgreSQL 中的
point
和line
- PostgreSQL
pg_vector
扩展中的vector
- PostgreSQL
PostGIS
扩展中的geometry
🎉 drizzle.config
中的新参数 - extensionsFilters
PostGIS 扩展会在 public
schema 中创建一些内部表。这意味着如果您有一个带有 PostGIS 扩展的数据库并使用 push
或 introspect
命令,所有这些表都将包含在 diff
操作中。在这种情况下,您需要指定 tablesFilter
,找到所有由该扩展创建的表,并在此参数中列出它们。
我们已经解决了这个问题,因此您无需执行所有这些步骤。只需使用所用扩展的名称指定 extensionsFilters
,Drizzle 就会跳过所有必要的表。
目前,我们只支持 postgis
选项,但如果将来有其他扩展在 public
schema 中创建表,我们计划添加更多支持。
postgis
选项将跳过 geography_columns
、geometry_columns
和 spatial_ref_sys
表。
import { defineConfig } from 'drizzle-kit'
export default defaultConfig({
dialect: "postgresql",
extensionsFilters: ["postgis"],
})
改进
更新数据库凭证的 zod schema,并为所有正/负用例编写测试
- 在 Kit 配置中支持完整的 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
如果现有索引中的以下字段发生更改,push
命令将不会生成语句:
.on()
和.using()
内部的表达式.where()
语句- 列上的操作符类
.op()
如果您正在使用 push
工作流,并希望更改索引中的这些字段,则需要:
- 注释掉该索引
- 执行
push
命令 - 取消注释该索引并更改这些字段
- 再次执行
push
命令
对于 generate
命令,drizzle-kit
将对新 Drizzle 索引 API 中索引的任何属性的任何更改触发,因此此处没有限制。