eventium-sqlite: SQLite implementations for eventium

This is a package candidate release! Here you can preview how this package release will appear once published to the main package index (which can be accomplished via the 'maintain' link below). Please note that once a package has been published to the main package index it cannot be undone! Please consult the package uploading documentation for more information.

[maintain] [Publish]

Eventium-sqlite provides a SQLite-based event store implementation for the Eventium event sourcing framework. It uses the Persistent library for type-safe database access and provides efficient event storage and retrieval with support for aggregate streams, event versioning, and optimistic concurrency control. This backend is ideal for single-process applications, embedded systems, and scenarios where a lightweight database is preferred.


[Skip to Readme]

Properties

Versions 0.1.0, 0.1.0
Change log CHANGELOG.md
Dependencies aeson (>=1.5 && <2.3), base (>=4.9 && <5), bytestring (>=0.10 && <0.13), eventium-core (>=0.1.0 && <0.2.0), eventium-sql-common (>=0.1.0 && <0.2.0), mtl (>=2.2 && <2.4), persistent (>=2.13 && <2.15), text (>=1.2 && <2.2), uuid (>=1.3 && <1.4) [details]
License MIT
Author
Maintainer Alexander Sidorenko
Category Database, Eventsourcing, SQLite
Home page https://github.com/aleks-sidorenko/eventium#readme
Bug tracker https://github.com/aleks-sidorenko/eventium/issues
Source repo head: git clone https://github.com/aleks-sidorenko/eventium
Uploaded by aleks_sidorenko at 2025-12-12T21:56:27Z

Modules

[Index] [Quick Jump]

Downloads

Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees


Readme for eventium-sqlite-0.1.0

[back to package description]

Eventium SQLite

SQLite-based event store implementation for embedded and single-process applications.

Overview

eventium-sqlite provides a lightweight, file-based event store implementation using SQLite. It's perfect for single-process applications, embedded systems, mobile apps, and scenarios where you want persistent storage without the complexity of a database server.

Features

When to Use SQLite

✅ Good Fit

⚠️ Consider Alternatives

Installation

Add to your package.yaml:

dependencies:
  - eventium-core
  - eventium-sql-common
  - eventium-sqlite
  - persistent-sqlite  # SQLite driver

Usage

import Eventium.Store.Sqlite
import Database.Persist.Sqlite

main :: IO ()
main = do
  -- Use file-based storage
  withSqlitePool "events.db" 1 $ \pool -> do
    -- Initialize schema
    flip runSqlPool pool $ do
      runMigration migrateAll
      
      -- Create event store
      let store = makeSqliteEventStore pool
      
      -- Use with command handlers
      result <- applyCommandHandler 
        (eventStoreWriter store)
        (eventStoreReader store)
        commandHandler
        aggregateId
        command

Database Location

File-Based Storage

-- Relative path
withSqlitePool "events.db" 1 $ \pool -> ...

-- Absolute path
withSqlitePool "/var/lib/myapp/events.db" 1 $ \pool -> ...

-- User-specific location
home <- getHomeDirectory
let dbPath = home </> ".myapp" </> "events.db"
withSqlitePool dbPath 1 $ \pool -> ...

In-Memory Storage (Testing)

-- Temporary in-memory database
withSqlitePool ":memory:" 1 $ \pool -> ...

Configuration

Connection Pool

SQLite works best with a single connection per process:

-- Recommended for SQLite
withSqlitePool "events.db" 1 $ \pool -> ...

Enable Write-Ahead Logging for better concurrent read performance:

withSqlitePool "events.db" 1 $ \pool -> do
  flip runSqlPool pool $ do
    rawExecute "PRAGMA journal_mode=WAL;" []
    runMigration migrateAll

Benefits:

Performance

Typical SQLite event store performance:

Optimization Tips

  1. Use WAL Mode - Better concurrent access
  2. Batch Writes - Multiple events per transaction
  3. Index Strategy - Default indexes cover common queries
  4. VACUUM Regularly - Reclaim space from deleted data
  5. Synchronous Mode - Balance durability vs speed

Backup & Recovery

Simple File Copy

# Stop application or ensure no writes
cp events.db events.db.backup

# Or use SQLite backup command
sqlite3 events.db ".backup events.db.backup"

Continuous Backup

# With WAL mode, backup while app runs
sqlite3 events.db ".backup events.db.backup"

Migration from In-Memory

-- Development: in-memory
development :: IO ()
development = withSqlitePool ":memory:" 1 $ \pool -> ...

-- Production: file-based
production :: IO ()
production = withSqlitePool "events.db" 1 $ \pool -> ...

Example: Complete CLI Application

import Eventium.Store.Sqlite
import System.Directory (getAppUserDataDirectory)

main :: IO ()
main = do
  -- Store in application data directory
  dataDir <- getAppUserDataDirectory "myapp"
  createDirectoryIfMissing True dataDir
  
  let dbPath = dataDir </> "events.db"
  
  withSqlitePool dbPath 1 $ \pool -> do
    -- Initialize on first run
    flip runSqlPool pool $ do
      rawExecute "PRAGMA journal_mode=WAL;" []
      runMigration migrateAll
    
    -- Run application
    runApp pool

Tools

SQLite CLI

# Open database
sqlite3 events.db

# Inspect schema
.schema

# Query events
SELECT * FROM events ORDER BY version DESC LIMIT 10;

# Check database size
.dbinfo

Limitations

Documentation

License

MIT - see LICENSE.md