Drizzle DuckDB 盘点鸭 带来 滴入外科手术 改为 DuckDB 函数,即进程内分析数据库。 DuckDB上方有Drizzle的型式安全查询构建器,迁移和TypeScript推论. 它与记忆数据库,本地文件, 妈妈 并运行 Postgres 服务器 pg_duckdb。 。 。 .
状态 : 实验 查询建筑,迁移和类型推论稳定. 一些DuckDB特有的类型和边缘案例仍在完善中.
每个文件页都有 标记下 (raw) 按钮,带有LLM友好源.
安装
bun add @duckdbfan/drizzle-duckdb drizzle-orm @duckdb/node-api
# or: npm install / pnpm add with the same packages
| 所需经费 | 支持的版本 |
|---|---|
drizzle-orm | 0.40.1或较新,低于0.46.0 |
@duckdb/node-api | 1.4.4或较新,低于1.6.0,包括 -r.N 建筑物,如 1.5.6-r.1 |
| 运行时间 | 节点18.17或较新(建议22或24),或Bun |
快速启动
import { drizzle } from '@duckdbfan/drizzle-duckdb';
import { sql } from 'drizzle-orm';
import { integer, pgTable, text } from 'drizzle-orm/pg-core';
const users = pgTable('users', {
id: integer('id').primaryKey(),
name: text('name').notNull(),
email: text('email').notNull(),
});
const db = await drizzle(':memory:');
await db.execute(sql`
CREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
email TEXT NOT NULL
)
`);
await db.insert(users).values([
{ id: 1, name: 'Alice', email: '[email protected]' },
{ id: 2, name: 'Bob', email: '[email protected]' },
]);
const allUsers = await db.select().from(users);
// ^? { id: number; name: string; email: string }[]
await db.close();
Schemas 使用常规 drizzle-orm/pg-core 建造者(pgTable, (中文(简体) ), pgSchema 所有标准的 Drizzle 查询方法都有效。 DuckDB SQL基本上是Postgres相容的,而方言则在不兼容的地方调整了查询.
连接中
通过一个路径, 驱动程序为您创建一个连接池 . await db.close() 关闭它.
import { drizzle } from '@duckdbfan/drizzle-duckdb';
// In-memory
const db = await drizzle(':memory:');
// Local file (created if missing)
const db = await drizzle('./my-database.duckdb');
// MotherDuck
const db = await drizzle({
connection: {
path: 'md:my_database',
options: { motherduck_token: process.env.MOTHERDUCK_TOKEN },
},
});
// DuckLake catalog
const db = await drizzle(':memory:', {
ducklake: {
catalog: './ducklake.duckdb',
attachOptions: { dataPath: './ducklake-data' },
},
});
使用同一文件路径的呼叫在一个过程中共享一个 DuckDB 实例,所以它们可以互相看到对方的写作. :memory: 永远不能共享.
你可以通过自己的连接,游泳池或 pg_duckdb 客户端。 这些电话是同步的:
import { DuckDBInstance } from '@duckdb/node-api';
import pg from 'pg';
// Existing DuckDB connection
const instance = await DuckDBInstance.create(':memory:');
const db = drizzle(await instance.connect());
// Postgres server with pg_duckdb. A pg.Client works too.
const db = drizzle(new pg.Pool({ connectionString: process.env.DATABASE_URL }));
A 类 pg.Pool 包裹着 createPgDuckConnectionPool(),所以每笔交易运行在一个集合客户端和 await db.close() 结束游泳池.
见 数据库连接 用于单子和无服务器模式.
连接集合
DuckDB每个连接运行一个查询,因此上面的路径表会创建一个池(默认大小为4).
- 设定大小或 MotherDuck 预设 :
pool: { size: 8 }, (中文(简体) ),pool: 'jumbo'或者说pool: 'giga'。 。 。 . - 电桶回收:
pool: { size: 8, idleTimeoutMs: 60_000, maxLifetimeMs: 10 * 60_000 }。 。 。 . - 禁用集合 :
pool: false。 。 。 . - 交易在他们整个一生中 都连接在一起.
pool当您通过连接或池实例时被忽略.
需要时自己创建游泳池 setup 钩子或想要分享它 drizzle() 实例 :
import { DuckDBInstance } from '@duckdb/node-api';
import { createDuckDBConnectionPool, drizzle } from '@duckdbfan/drizzle-duckdb';
const instance = await DuckDBInstance.create('md:', {
motherduck_token: process.env.MOTHERDUCK_TOKEN,
});
const pool = createDuckDBConnectionPool(instance, {
size: 8,
acquireTimeout: 20_000,
maxWaitingRequests: 200,
maxLifetimeMs: 10 * 60_000,
idleTimeoutMs: 60_000,
});
const db = drizzle(pool);
console.log(pool.stats()); // Leases, queue depth, waits, recycling and timeouts
acquireTimeout 限制游泳池队列中的时间。 连接创建和设置在此之后运行, 而此选项没有最后期限 。 检查 pool.stats() 由于更多的连接可以与 DuckDB 本身的查询线索相竞争,所以在增加池大小之前.
配置
import { DefaultLogger } from 'drizzle-orm';
const db = await drizzle(':memory:', {
// Log every query
logger: new DefaultLogger(),
// Pool size, preset, or timeout and recycling options
pool: { size: 8, idleTimeoutMs: 60_000 },
// Bind a bare Date in sql`...` as TIMESTAMPTZ instead of a naive TIMESTAMP
dateParams: 'timestamptz', // Default: 'timestamp'
// Preserve DECIMAL values as strings in raw, streaming and nested reads
decimalMode: 'string', // Default: 'number'
// Legacy raw SQL join qualification heuristic, opt in only if needed
qualifyRawJoinColumns: false,
// Throw on Postgres-style array literals like '{1,2,3}' (default: false)
rejectStringArrayLiterals: false,
// Map camelCase keys to snake_case column names
casing: 'snake_case',
// Schema for relational queries
schema: mySchema,
});
pool 财务报告和审定财务报表 ducklake 仅适用于路径和 { connection } 表单。 其他备选方案也与 drizzle(connection, { ... })。见 配置 完整名单.
DuckDB 类型
DuckDB 专列助手 : duckDbList, (中文(简体) ), duckDbArray, (中文(简体) ), duckDbStruct, (中文(简体) ), duckDbUnion, (中文(简体) ), duckDbMap, (中文(简体) ), duckDbJson, (中文(简体) ), duckDbBlob, (中文(简体) ), duckDbInet, (中文(简体) ), duckDbInterval, (中文(简体) ), duckDbTimestamp, (中文(简体) ), duckDbDate 财务报告和审定财务报表 duckDbTime。 。 。 .
duckDbTimestamp财务报告和审定财务报表duckDbTime可以保存存储变体, 如TIMESTAMP_NS, (中文(简体) ),TIMESTAMP_MS, (中文(简体) ),TIMESTAMP_S, (中文(简体) ),TIME_NS财务报告和审定财务报表TIME WITH TIME ZONE通过duckDbType财务报告和审定财务报表withTimezone选项.- 邮资
json财务报告和审定财务报表jsonb栏被拒绝。 使用duckDbJson()。 。 。 . - 浏览器安全导入在
@duckdbfan/drizzle-duckdb/helpers. 内观出此道.
见 列类型 为全API.
阵列
DuckDB 支持 @>, (中文(简体) ), <@ 财务报告和审定财务报表 && 列表和固定大小数组,所以 Drizzle 的 arrayContains, (中文(简体) ), arrayContained 财务报告和审定财务报表 arrayOverlaps 工作不变。 DuckDB 帮助者会发射 array_has_all 财务报告和审定财务报表 array_has_any数字 :
import {
duckDbArrayContained,
duckDbArrayContains,
duckDbArrayOverlaps,
} from '@duckdbfan/drizzle-duckdb';
// Tags include every value
db.select().from(products).where(duckDbArrayContains(products.tags, ['electronics', 'sale']));
// Tags are a subset of the values
db.select().from(products).where(duckDbArrayContained(products.tags, ['electronics', 'sale', 'featured']));
// Tags share at least one value
db.select().from(products).where(duckDbArrayOverlaps(products.tags, ['electronics', 'books']));
首选 array_lower(a, 1) 财务报告和审定财务报表 array_upper(a, 1) 电话重写为 array_length 表达式,因为 DuckDB 缺少这些函数.
交易
await db.transaction(async (tx) => {
await tx.insert(accounts).values({ balance: 100 });
await tx.update(accounts).set({ balance: 50 }).where(eq(accounts.id, 1));
});
DuckDB 与 Postgres 不同 :
- 没有
SAVEPOINT. Nested 交易重新使用外部交易,所以内部回滚会中止所有交易. - 没有游泳池,其他
db查询在交易打开共享连接时等待,而不是加入它. - 任何失败的语句都会中止整个交易 。 捕捉回调中的错误不会保留更早的写法 .
db.transaction()倒卷而拒之. - 这个
config参数( e)isolationLevel, (中文(简体) ),accessMode, (中文(简体) ),deferrable)被贬低并被一次性警告而忽略,因为 DuckDB 没有SET TRANSACTION。 。 。 .
移徙
import { migrate } from '@duckdbfan/drizzle-duckdb';
await migrate(db, { migrationsFolder: './drizzle' });
元数据到 drizzle.__drizzle_migrations 默认。 同时 migrate() 调用每个迁移一次, DuckLake 作为默认目录工作。 见 移徙 用于配置.
Schema 内览
由 CLI 的现有数据库生成 Drizzle 计划 :
bunx duckdb-introspect --url ./my-database.duckdb --out ./drizzle/schema.ts
或从代码:
import { introspect } from '@duckdbfan/drizzle-duckdb';
const result = await introspect(db, {
schemas: ['public', 'analytics'],
includeViews: true,
});
console.log(result.files.schemaTs);
见 回顾 所有选项.
分析员和Duck母亲助手
包件船的可堆叠 SQL 帮助分析工作:
- OLAP 帮手等
sumN, (中文(简体) ),percentileCont窗口助手和olap()分组措施制定者. - 兰斯矢量,全文和混合搜索.
- MotherDuck 表用于潜水、飞行、文件列表和访问令牌的功能,以及会话身份缩写等
mdCurrentEmail()财务报告和审定财务报表mdIsRoleInSession()。 。 。 . - 输入的 MotherDuck AI 构建器 :
mdPromptJev()分类文本或图像,并mdPrompt()生成文本或结构输出. duckLakeMergeAdjacentFiles()为"鸭子"收缩.- 批量和箭头读取
db.executeBatches(), (中文(简体) ),db.executeBatchesRaw()财务报告和审定财务报表db.executeArrow()。 。 。 . - 快速散装货物通过
db.appendRows(),它使用 DuckDB 的附件,而不是INSERT 语句.
import { sql } from 'drizzle-orm';
import { mdCreateFlight, mdListDives, mdRunFlight } from '@duckdbfan/drizzle-duckdb';
const dives = await db.execute(sql`
select id, title, updated_at
from ${mdListDives({ limit: 10, includeOrgShares: true })}
order by updated_at desc
`);
const [flight] = await db.execute(sql`
select flight_id, status
from ${mdCreateFlight({
name: 'daily-refresh',
sourceCode: 'print("hello")',
scheduleCron: '0 0 * * *',
maxRuntimeSec: 1_800,
instanceType: 'F16',
})}
`);
await db.execute(sql`
select run_number, status
from ${mdRunFlight(String(flight.flight_id), { config: { region: 'eu-west-1' } })}
`);
年长者 mdJobs() 财务报告和审定财务报表 mdFlights() 帮助者名称仍为已贬值的别名。 见 OLAP 帮助者 完整列表、飞行选项和日志标记,以及 妈妈 为人工智能的构建者.
已知的限制
| 特性 | 状态 |
|---|---|
| 基本 CRUD 操作 | 全力支持 |
| 组合和子组合 | 全力支持 |
| 交易 | 没有保存点(已记账的交易重复使用外接点) 。 配置被忽略 |
| JSON/JSONB栏 | 使用 duckDbJson() 换成 |
| 发言稿 | 每次跑步都准备好了 没有语句缓存和命名语句 |
| 成果的流出 | 读取 executeBatches(),没有光标流线 |
| 同时进行查询 | 每个连接一个查询 。 并行化使用集合 |
见 限制 详细情况.
实例
- Parquet 分析: 未导入表格的 Parquet 文件上的打入选择和分组措施
- 母亲Duck NYC出租车: 使用连接池查询 MotherDuck 样本 NYC 出租车数据集
- 分析盘:带有 DuckDB 类型和 Parquet 加载的本地内膜分析
- 本地鸭湖 财务报告和审定财务报表 鸭子在妈妈Duck上: 附加 DuckLake 目录
从寄存器根中运行 :
bun example/analytics-dashboard.ts
MOTHERDUCK_TOKEN=your_token bun example/motherduck-nyc-taxi.ts
见 实例/README.md 完整名单.
捐款
bun install # install dependencies
bun run test # run tests (Vitest, not `bun test`)
bun run t # watch mode with the UI
bun run build # build dist/
包含新特性的测试 test/<feature>.test.ts,注意您碰到的 DuckDB 怪事, 并使用简短的强制任务 .