drizzle-databend
v0.1.14
Published
A drizzle ORM driver for use with Databend. Based on drizzle's Postgres driver surface.
Downloads
3,437
Readme
drizzle-databend
A Drizzle ORM driver for Databend. Built on Drizzle's Postgres driver surface (pg-core) since Databend supports $1 positional parameters and double-quote identifier quoting.
Uses databend-driver (NAPI-RS bindings) as the underlying client.
Install
bun add drizzle-databend drizzle-orm databend-driverQuick start
import { drizzle } from 'drizzle-databend';
import { pgTable, integer, varchar, text } from 'drizzle-orm/pg-core';
import { eq } from 'drizzle-orm';
const users = pgTable('users', {
id: integer('id').notNull(),
name: varchar('name', { length: 256 }).notNull(),
email: text('email'),
});
const db = await drizzle('databend://databend:databend@localhost:8000/default?sslmode=disable');
// Insert
await db.insert(users).values({ id: 1, name: 'Alice', email: '[email protected]' });
// Select
const rows = await db.select().from(users).where(eq(users.name, 'Alice'));Databend-specific column types
import { databendVariant, databendArray, databendTuple, databendMap, databendTimestamp, databendDate } from 'drizzle-databend';
const events = pgTable('events', {
id: integer('id').notNull(),
payload: databendVariant('payload'), // VARIANT (semi-structured JSON)
tags: databendArray('tags', 'VARCHAR'), // ARRAY(VARCHAR)
coords: databendTuple('coords', ['FLOAT', 'FLOAT']), // TUPLE(FLOAT, FLOAT)
attrs: databendMap('attrs', 'VARCHAR', 'VARCHAR'), // MAP(VARCHAR, VARCHAR)
createdAt: databendTimestamp('created_at'), // TIMESTAMP
eventDate: databendDate('event_date'), // DATE
});Connection options
// DSN string (async, auto-pools with 4 connections)
const db = await drizzle('databend://user:pass@host:8000/db?sslmode=disable');
// With config
const db = await drizzle('databend://...', { pool: { size: 8 }, logger: true });
// Config object
const db = await drizzle({ connection: 'databend://...', schema: mySchema });
// Explicit client (sync, no pooling)
import { Client } from 'databend-driver';
const conn = await new Client('databend://...').getConn();
const db = drizzle({ client: conn });
// Disable pooling
const db = await drizzle('databend://...', { pool: false });Transactions
await db.transaction(async (tx) => {
await tx.insert(users).values({ id: 2, name: 'Bob', email: '[email protected]' });
await tx.update(users).set({ name: 'Robert' }).where(eq(users.id, 2));
});Note: Databend does not support savepoints. Nested transactions use a rollback-only fallback.
Migrations
import { migrate } from 'drizzle-databend';
await migrate(db, { migrationsFolder: './drizzle' });Development
Prerequisites
You need a running Databend instance. The quickest way is Docker:
docker run -d \
--name databend \
--network host \
-e MINIO_ENABLED=true \
-e QUERY_DEFAULT_USER=databend \
-e QUERY_DEFAULT_PASSWORD=databend \
-v minio_data_dir:/var/lib/minio \
--restart unless-stopped \
datafuselabs/databendSee the Databend self-hosted quickstart for more options.
Verify the connection:
bendsql -udatabend -pdatabendCommands
bun install # Install dependencies
bun run build # Build (dist/index.mjs + type declarations)
bun test # Run integration tests (requires running Databend)Seed data
Populate two sample tables (users and events) for manual testing:
bun run scripts/seed.tsThis creates 5 users and 10 events with VARIANT payloads and timestamps.
Architecture
Built on the same pattern as drizzle-duckdb:
driver.ts--drizzle()factory andDatabendDatabaseextendingPgDatabasesession.ts--DatabendSessionandDatabendPreparedQueryfor query executiondialect.ts--DatabendDialectextendingPgDialectwith Databend-specific migrations and type mappingclient.ts-- Low-level execution wrappingdatabend-driver'sConnectionAPIpool.ts-- Connection pooling viaClient.getConn()columns.ts-- Custom column types (VARIANT, ARRAY, TUPLE, MAP, TIMESTAMP, DATE)sql/result-mapper.ts-- Maps Databend results to Drizzle's expected format
License
MIT
