Skip to content

SQLite Database Adapter

The @zintrust/db-sqlite package provides a SQLite driver for ZinTrust's database system, enabling lightweight, file-based database operations.

Installation

bash
zin add  @zintrust/db-sqlite

Configuration

Add the SQLite database configuration to your environment:

typescript
// config/database.ts
import { DatabaseConfig } from '@zintrust/core';

export const database: DatabaseConfig = {
  driver: 'sqlite',
  sqlite: {
    filename: process.env.SQLITE_FILENAME || './database.sqlite',
    options: {
      verbose: process.env.NODE_ENV === 'development' ? console.log : undefined,
      baseDir: process.env.SQLITE_BASE_DIR,
      busyTimeout: 30000,
      maxConnections: 1,
    },
  },
};

Environment Variables

bash
SQLITE_FILENAME=./database.sqlite
SQLITE_BASE_DIR=./data
NODE_ENV=development

Usage

typescript
import { Model } from '@zintrust/core';

// Define a model
const User = Model.define({
  tableName: 'users',
  schema: {
    id: { type: 'number', primary: true, autoIncrement: true },
    name: { type: 'string', required: true },
    email: { type: 'string', required: true, unique: true },
    created_at: { type: 'datetime', default: () => new Date() },
    metadata: { type: 'json' }, // JSON support via TEXT
  },
});

// Create operations
const user = await User.create({
  name: 'John Doe',
  email: 'john@example.com',
  metadata: { preferences: { theme: 'dark' } },
});

// Query operations
const users = await User.where('name', 'John').get();
const user = await User.find(1);

// Update operations
await User.where('id', 1).update({ name: 'Jane Doe' });

// Delete operations
await User.where('id', 1).delete();

// Raw queries with SQLite-specific features
const results = await Model.raw(`
  SELECT *, json_extract(metadata, '$.theme') as theme
  FROM users
  WHERE json_extract(metadata, '$.status') = 'active'
`);

Features

  • File-Based: No server required, file-based storage
  • Zero Configuration: Ready to use out of the box
  • ACID Compliant: Full ACID transaction support
  • Type Safety: Full TypeScript support
  • JSON Support: JSON operations via SQLite JSON1 extension
  • Full-Text Search: SQLite FTS5 support
  • Migrations: Database migration support
  • Memory Mode: In-memory database support

Options

OptionTypeDefaultDescription
filenamestringrequiredDatabase file path
baseDirstringundefinedBase directory for database files
busyTimeoutnumber30000Busy timeout in ms
maxConnectionsnumber1Max connections (SQLite recommends 1)
verbosefunctionundefinedLogging function
foreignKeysbooleantrueEnable foreign key constraints

Advanced Configuration

Memory Database

typescript
export const database: DatabaseConfig = {
  driver: 'sqlite',
  sqlite: {
    filename: ':memory:', // In-memory database
    options: {
      foreignKeys: true,
    },
  },
};

Temporary Database

typescript
export const database: DatabaseConfig = {
  driver: 'sqlite',
  sqlite: {
    filename: '', // Temporary database
  },
};

WAL Mode (Write-Ahead Logging)

typescript
export const database: DatabaseConfig = {
  driver: 'sqlite',
  sqlite: {
    filename: './database.sqlite',
    options: {
      // Enable WAL mode for better concurrency
      pragma: {
        journal_mode: 'WAL',
        synchronous: 'NORMAL',
        cache_size: 1000,
        temp_store: 'MEMORY',
      },
    },
  },
};

SQLite-Specific Features

JSON Operations

typescript
// JSON queries using SQLite JSON1 extension
const usersWithPreferences = await Model.raw(`
  SELECT * FROM users
  WHERE json_extract(metadata, '$.theme') = 'dark'
`);

// JSON path queries
const nestedData = await Model.raw(`
  SELECT json_extract(metadata, '$.preferences.theme') as theme
  FROM users
`);

// Update JSON fields
await Model.raw(
  `
  UPDATE users
  SET metadata = json_set(metadata, '$.last_login', ?)
  WHERE id = ?
`,
  [new Date().toISOString(), 1]
);
typescript
// Create FTS5 virtual table
await Model.raw(`
  CREATE VIRTUAL TABLE users_fts USING fts5(name, email, content='users', content_rowid='id')
`);

// Trigger to keep FTS table updated
await Model.raw(`
  CREATE TRIGGER users_fts_insert AFTER INSERT ON users BEGIN
    INSERT INTO users_fts(rowid, name, email) VALUES (new.id, new.name, new.email);
  END
`);

// Search
const searchResults = await Model.raw(
  `
  SELECT users.* FROM users_fts
  JOIN users ON users.id = users_fts.rowid
  WHERE users_fts MATCH ?
  ORDER BY rank
`,
  ['john']
);

Transactions

typescript
import { Database } from '@zintrust/core';

// Simple transaction
await Database.transaction(async (trx) => {
  await User.create({ name: 'John' }, { transaction: trx });
  await User.create({ name: 'Jane' }, { transaction: trx });
});

// Savepoints
await Database.transaction(async (trx) => {
  await trx.savepoint('user_created');

  try {
    await User.create({ name: 'Bob' }, { transaction: trx });
    await trx.release('user_created');
  } catch (error) {
    await trx.rollbackToSavepoint('user_created');
  }
});

Migrations

typescript
// migrations/001_create_users_table.ts
export const up = async (db) => {
  await db.schema.createTable('users', (table) => {
    table.increments('id').primary();
    table.string('name').notNullable();
    table.string('email').unique().notNullable();
    table.text('metadata'); // JSON stored as TEXT
    table.timestamps(true, true);

    // Indexes
    table.index(['email'], 'idx_email');
  });

  // Create FTS table
  await db.raw(`
    CREATE VIRTUAL TABLE users_fts USING fts5(name, email, content='users', content_rowid='id')
  `);
};

export const down = async (db) => {
  await db.schema.dropTable('users_fts');
  await db.schema.dropTable('users');
};

Performance Optimization

  1. WAL Mode: Enable WAL for better concurrency
  2. Indexing: Add appropriate indexes
  3. Pragma Settings: Optimize SQLite pragmas
  4. Connection Management: Use connection pooling
  5. Batch Operations: Use transactions for bulk operations
  6. Memory Management: Monitor memory usage

Error Handling

The SQLite adapter handles:

  • Database locking errors
  • Disk I/O errors
  • Constraint violations
  • Syntax errors
  • Connection issues
  • File permission errors

Security Features

  • SQL Injection Prevention: Prepared statements
  • File Permissions: Proper file access controls
  • Encryption: Database encryption support
  • Backup/Restore: Built-in backup functions

Backup and Restore

typescript
// Create backup
await Model.raw(`
  VACUUM INTO 'backup_database.sqlite'
`);

// Online backup
await Model.raw(`
  BACKUP DATABASE TO 'backup.sqlite'
`);

// Restore from backup
const fs = require('fs');
const backupData = fs.readFileSync('backup.sqlite');
fs.writeFileSync('database.sqlite', backupData);

Limitations

  • Concurrency: Limited concurrent writes
  • Network Access: No remote access
  • Stored Procedures: Limited stored procedure support
  • User Management: No user management system

Released under the MIT License.