주요 변경사항
참고:
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 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 스키마 내에서 확장을 생성하는 특별한 코드는 없습니다. vector 타입, 인덱스, 쿼리를 사용하는 경우
pg_vector확장이 설치된 PostgreSQL 데이터베이스를 사용한다고 가정합니다.
이제 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)}`;
}원하는 대로 이름을 지정하고 연산자를 변경하세요. 이 예제는 숫자 배열, 문자열 배열, 문자열 또는 select 쿼리도 허용합니다. 원하는 다른 타입을 자유롭게 만들거나 PR을 제출할 수도 있습니다.
예제
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 Geometric Types의 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 스키마 내에서 확장을 생성하는 특별한 코드는 없습니다. 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 }로 타입이 지정됩니다.
type
현재 릴리스에는 미리 정의된 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 스키마 업데이트 및 모든 긍정/부정 케이스 테스트 작성
- kit config에서 전체 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: Error: Connection terminated unexpectedly - #435
- SQLite 마이그레이션을 로컬에서 실행할 수 없음 - #432
- error: unknown option ‘—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의 모든 속성에 대한 인덱스 변경 사항에 의해 트리거되므로 여기에는 제한사항이 없습니다.