drizzle-databend
v0.1.15
Published
A drizzle ORM driver for use with Databend. Based on drizzle's Postgres driver surface.
Readme
drizzle-databend
This driver was created to power drizzle-cube (an embeddable semantic layer built on Drizzle) and drizby (an open source BI platform built on drizzle-cube). It enables both projects to query Databend natively via Drizzle ORM.
A Drizzle ORM driver for Databend. Built on a standalone databend-core dialect module with ? positional parameters and double-quote identifier quoting.
Uses databend-driver (NAPI-RS bindings) as the underlying client.
Parameter binding
Queries are sent with ? placeholders and a separate parameter array. On Databend
server > 1.2.900 with databend-driver >= 0.34.0, parameters are bound server-side
via the /v1/query params field, so values are never interpolated into the SQL text.
Against older servers the driver transparently falls back to client-side interpolation
using its own SQL-standard escaping. Either way the driver owns escaping; this adapter no
longer pre-escapes values. databend-driver >= 0.34.0 is required.
Install
npm install drizzle-databend drizzle-orm databend-driverQuick start
import { drizzle, databendTable, integer, varchar, text } from 'drizzle-databend';
import { eq } from 'drizzle-orm';
const users = databendTable('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 {
databendTable,
databendVariant,
databendArray,
databendTuple,
databendMap,
databendTimestamp,
databendDate,
integer,
} from 'drizzle-databend';
const events = databendTable('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
npm install # Install dependencies
npm run build # Build (dist/index.mjs + type declarations)
npm run typecheck # Type-check with tsc
npm run lint # Lint with biome
npm test # Run all tests (requires running Databend)Architecture
src/databend-core/-- Standalone dialect module (ported from drizzle-orm's gel-core)dialect.ts-- SQL generation with?params and"identifier quotingsession.ts-- Abstract session, prepared query, and transaction base classesdb.ts--DatabendDatabasewith select/insert/update/delete/execute/CTE supporttable.ts--databendTable()table definition functioncolumns/-- Column type builders (integer, varchar, boolean, timestamp, etc.)query-builders/-- SELECT, INSERT, UPDATE, DELETE query builders
src/driver.ts--drizzle()factory, connection management, pool creationsrc/session.ts-- Concrete session with databend-driver query executionsrc/client.ts-- Low-level execution wrappingdatabend-driver'sConnectionAPIsrc/pool.ts-- Connection pooling viaClient.getConn()src/columns.ts-- Custom column types (VARIANT, ARRAY, TUPLE, MAP, TIMESTAMP, DATE)src/sql/result-mapper.ts-- Maps Databend results to Drizzle's expected format
License
MIT
