Skip to content

Conversation

@enki
Copy link

@enki enki commented Oct 23, 2025

Summary

Adds native support for SQLite's ATTACH DATABASE feature. Query and JOIN across multiple database files in a single query.

Changes

  • sqliteSchema(name) - Define tables with schema prefix (all SQLite drivers)
  • db.$attach(name, path) - Execute ATTACH DATABASE (libSQL only)
  • db.$detach(name) - Remove attached database (libSQL only)
  • Integration tests with 7 test cases

Example Usage

Basic: Query Attached Database

import { sqliteSchema } from 'drizzle-orm/sqlite-core';
import { text, integer } from 'drizzle-orm/sqlite-core';

// Define schema for analytics.db
const analytics = sqliteSchema('analytics');

const events = analytics.table('events', {
  id: text('id').primaryKey(),
  userId: text('user_id'),
  action: text('action'),
  timestamp: integer('timestamp'),
});

// Attach and query
await db.$attach('analytics', './analytics.db');
const recentEvents = await db.select().from(events).all();
// SQL: SELECT * FROM "analytics"."events"

Advanced: Cross-Database JOIN

// Main database
const users = sqliteTable('users', {
  id: text('id').primaryKey(),
  name: text('name'),
});

// Analytics database (attached)
const analytics = sqliteSchema('analytics');
const events = analytics.table('events', {
  userId: text('user_id'),
  action: text('action'),
});

await db.$attach('analytics', './analytics.db');

// JOIN across databases
const userActivity = await db
  .select({
    userName: users.name,
    action: events.action,
  })
  .from(users)
  .leftJoin(events, eq(users.id, events.userId))
  .all();

Other SQLite Drivers

For better-sqlite3, d1, etc., use raw SQL for ATTACH:

sqlite.exec("ATTACH DATABASE './analytics.db' AS analytics");
// Then use sqliteSchema('analytics') for typed queries

Use Cases

- Analytics pipelines (main + analytics databases)
- Multi-tenant apps (one database per tenant)
- Time-series partitioning (one database per month)
- Turso read-only ATTACH for scaling reads

Testing

cd integration-tests && pnpm test libsql-attach.test.ts

All 7 tests pass including cross-database JOINs.

Implementation

- Follows PostgreSQL pgSchema() pattern
- ~200 lines total (150 implementation + 160 tests)
- No breaking changes

Checklist

- Signed commits
- Integration tests pass
- Follows existing patterns
- Code comments for documentation
enki added 2 commits October 23, 2025 03:55
Implementation complete - tests pending.

- Add sqliteSchema() function (mirrors pgSchema pattern)
- Add $attach() and $detach() methods to LibSQLDatabase
- Export sqliteTableWithSchema() and sqliteViewWithSchema()
- Add schema parameter to view builders
- Infrastructure already existed (schema in TableConfig, SQL generation)

Next: Add integration tests in integration-tests/tests/sqlite/
- Test sqliteSchema() creates tables with schema prefix
- Test $attach() executes ATTACH DATABASE statement
- Test querying attached schemas via Drizzle ORM
- Test cross-database JOINs
- Test SQL generation includes schema prefixes
- Test $detach() removes attached databases

All 7 tests pass, validating the implementation works
at both type level and runtime.
@enki enki marked this pull request as draft October 23, 2025 08:08
@enki enki marked this pull request as ready for review October 23, 2025 08:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

1 participant