1.0.9 • Published 6 months ago

@drizzle-adapter/libsql v1.0.9

Weekly downloads
-
License
-
Repository
-
Last release
6 months ago

@drizzle-adapter/libsql

LibSQL adapter implementation for the Drizzle Adapter ecosystem, supporting both local SQLite databases and Turso.

Overview

The @drizzle-adapter/libsql package provides the LibSQL implementation for the Drizzle Adapter interface. While you don't interact with this package directly (you use @drizzle-adapter/core instead), it enables support for LibSQL and Turso in the Drizzle Adapter ecosystem.

Why LibSQL/Turso?

LibSQL and Turso offer unique advantages:

  • Embedded or Serverless: Use locally or as a serverless database with Turso
  • SQLite Compatible: Built on SQLite with additional features
  • WebSocket Protocol: Efficient binary protocol for lower latency
  • Automatic Replication: Built-in replication with Turso
  • Edge Computing: Global distribution with Turso's edge network
  • Local Development: Easy local development with file-based SQLite
  • Cost Effective: Free tier and usage-based pricing with Turso
  • Multi-Region: Automatic multi-region deployment with Turso

Perfect For:

  1. Edge Applications: Data served from the closest location
  2. Local Development: Embedded database for development
  3. Hybrid Deployments: Mix local and serverless as needed
  4. Cost-Sensitive Projects: Start free and scale as needed
  5. Global Applications: Automatic global distribution with Turso

Installation

# Install both the core package and the LibSQL adapter
pnpm install @drizzle-adapter/core @drizzle-adapter/libsql

Important: Adapter Registration

For the adapter to work correctly with the DrizzleAdapterFactory, you must import it for its self-registration side effects:

// Import for side effects - adapter will self-register
import '@drizzle-adapter/libsql';

// Now you can use the factory
import { DrizzleAdapterFactory } from '@drizzle-adapter/core';

Usage

Configuration

import { DrizzleAdapterFactory, TypeDrizzleDatabaseConfig } from '@drizzle-adapter/core';

// Local SQLite database
const localConfig: TypeDrizzleDatabaseConfig = {
  DATABASE_DRIVER: 'libsql',
  DATABASE_URL: 'file:local.db'
};

// Turso database
const tursoConfig: TypeDrizzleDatabaseConfig = {
  DATABASE_DRIVER: 'libsql',
  DATABASE_URL: 'libsql://your-database-url.turso.io',
  DATABASE_AUTH_TOKEN: 'your-auth-token',
  DATABASE_SYNC_URL: 'file:local-replica.db' // Optional sync URL for replica
};

const factory = new DrizzleAdapterFactory();
const adapter = factory.create(config);

Schema Definition

const dataTypes = adapter.getDataTypes();

const users = dataTypes.dbTable('users', {
  id: dataTypes.dbInteger('id').primaryKey().autoincrement(),
  name: dataTypes.dbText('name').notNull(),
  email: dataTypes.dbText('email').notNull().unique(),
  metadata: dataTypes.dbText('metadata'), // JSON stored as text
  createdAt: dataTypes.dbInteger('created_at')
    .default(sql`(strftime('%s', 'now'))`)
});

const posts = dataTypes.dbTable('posts', {
  id: dataTypes.dbInteger('id').primaryKey().autoincrement(),
  userId: dataTypes.dbInteger('user_id')
    .references(() => users.id),
  title: dataTypes.dbText('title').notNull(),
  content: dataTypes.dbText('content').notNull(),
  published: dataTypes.dbInteger('published').default(0),
  createdAt: dataTypes.dbInteger('created_at')
    .default(sql`(strftime('%s', 'now'))`)
});

Basic CRUD Operations

import { eq, and, or, desc, sql } from 'drizzle-orm';

const client = await adapter.getConnection().getClient();

// INSERT
// Single insert with returning
const [newUser] = await client
  .insert(users)
  .values({
    name: 'John Doe',
    email: 'john@example.com',
    metadata: JSON.stringify({ role: 'user' })
  })
  .returning();

// Bulk insert
await client
  .insert(posts)
  .values([
    {
      userId: newUser.id,
      title: 'First Post',
      content: 'Hello, world!'
    },
    {
      userId: newUser.id,
      title: 'Second Post',
      content: 'Another post'
    }
  ]);

// SELECT
// Select all
const allUsers = await client
  .select()
  .from(users);

// Select with conditions
const user = await client
  .select()
  .from(users)
  .where(eq(users.email, 'john@example.com'));

// Select with join
const userPosts = await client
  .select({
    userName: users.name,
    postTitle: posts.title,
    content: posts.content,
    metadata: users.metadata,
    createdAt: sql`datetime(${posts.createdAt}, 'unixepoch')`
  })
  .from(posts)
  .leftJoin(users, eq(posts.userId, users.id))
  .where(eq(posts.published, 1))
  .orderBy(desc(posts.createdAt));

// UPDATE
await client
  .update(users)
  .set({
    name: 'John Smith',
    metadata: JSON.stringify({ role: 'admin' })
  })
  .where(eq(users.id, newUser.id));

// DELETE
await client
  .delete(posts)
  .where(
    and(
      eq(posts.userId, newUser.id),
      eq(posts.published, 0)
    )
  );

Full-Text Search

// Create FTS table
await client.execute(sql`
  CREATE VIRTUAL TABLE posts_fts USING fts5(
    title, content,
    content='posts',
    content_rowid='id'
  )
`);

// Search posts
const searchResults = await client
  .select({
    title: posts.title,
    content: posts.content,
    author: users.name,
    rank: sql`rank`
  })
  .from(posts)
  .leftJoin(users, eq(posts.userId, users.id))
  .where(sql`posts.id IN (
    SELECT rowid 
    FROM posts_fts 
    WHERE posts_fts MATCH ${searchTerm}
    ORDER BY rank
  )`);

Best Practices

Local Development

// Use file-based SQLite for development
const devAdapter = factory.create({
  DATABASE_DRIVER: 'libsql',
  DATABASE_URL: 'file:dev.db'
});

Production with Turso

// Use Turso for production
const prodAdapter = factory.create({
  DATABASE_DRIVER: 'libsql',
  DATABASE_URL: process.env.DATABASE_URL,
  DATABASE_AUTH_TOKEN: process.env.DATABASE_AUTH_TOKEN
});

Replica Support

// Use local replica for better performance
const replicaAdapter = factory.create({
  DATABASE_DRIVER: 'libsql',
  DATABASE_URL: process.env.DATABASE_URL,
  DATABASE_AUTH_TOKEN: process.env.DATABASE_AUTH_TOKEN,
  DATABASE_SYNC_URL: 'file:local-replica.db'
});

Best Practices

  1. Development Flow: Use file-based SQLite for development
  2. Production: Use Turso for production deployments
  3. Replicas: Leverage local replicas for better performance
  4. JSON Handling: Store JSON as TEXT and parse/stringify as needed
  5. Query Optimization: Use indexes and FTS for better performance

Contributing

We welcome contributions! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.

Related Packages

1.0.9

6 months ago

1.0.8

8 months ago

1.0.7

10 months ago

1.0.5

11 months ago

1.0.4

11 months ago

1.0.3

11 months ago

1.0.1

11 months ago

1.0.0

11 months ago