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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant