Skip to main content

evento_sql_migrator/
lib.rs

1//! SQL database migrations for the Evento event sourcing library.
2//!
3//! This crate provides database schema migrations required for storing events, snapshots,
4//! and subscriber state in SQL databases. It supports SQLite, MySQL, and PostgreSQL through
5//! feature flags.
6//!
7//! # Features
8//!
9//! - **`sqlite`** - Enables SQLite database support
10//! - **`mysql`** - Enables MySQL database support
11//! - **`postgres`** - Enables PostgreSQL database support
12//!
13//! All features are enabled by default. You can selectively enable only the databases you need:
14//!
15//! ```toml
16//! [dependencies]
17//! evento-sql-migrator = { version = "1.8", default-features = false, features = ["postgres"] }
18//! ```
19//!
20//! # Usage
21//!
22//! The main entry point is the [`new`] function, which creates a [`Migrator`]
23//! instance configured with all Evento migrations.
24//!
25//! ```rust,ignore
26//! use sqlx_migrator::{Migrate, Plan};
27//!
28//! // Acquire a database connection
29//! let mut conn = pool.acquire().await?;
30//!
31//! // Create the migrator for your database type
32//! let migrator = evento_sql_migrator::new::<sqlx::Sqlite>()?;
33//!
34//! // Run all pending migrations
35//! migrator.run(&mut *conn, &Plan::apply_all()).await?;
36//! ```
37//!
38//! When using the main `evento` crate, the migrator is re-exported:
39//!
40//! ```rust,ignore
41//! let migrator = evento::sql_migrator::new::<sqlx::Sqlite>()?;
42//! ```
43//!
44//! # Migrations
45//!
46//! The crate includes the following migrations:
47//!
48//! - [`InitMigration`] - Creates the initial database schema (event, snapshot, subscriber tables)
49//! - [`M0002`] - Adds `timestamp_subsec` column for sub-second precision timestamps
50//! - [`M0003`] - Drops the snapshot table and extends the event name column length
51//! - [`M0004`] - Replaces `idx_event_type` with a composite cursor-scan index
52//!
53//! # Database Schema
54//!
55//! After running all migrations, the database will contain:
56//!
57//! ## Event Table
58//!
59//! Stores all domain events:
60//!
61//! | Column | Type | Description |
62//! |--------|------|-------------|
63//! | `id` | VARCHAR(26) | Event ID (ULID format) |
64//! | `name` | VARCHAR(50) | Event type name |
65//! | `aggregator_type` | VARCHAR(50) | Aggregate root type |
66//! | `aggregator_id` | VARCHAR(26) | Aggregate root instance ID |
67//! | `version` | INTEGER | Event sequence number |
68//! | `data` | BLOB | Serialized event data |
69//! | `metadata` | BLOB | Serialized event metadata |
70//! | `routing_key` | VARCHAR(50) | Optional routing key |
71//! | `timestamp` | BIGINT | Event timestamp (seconds) |
72//! | `timestamp_subsec` | BIGINT | Sub-second precision |
73//!
74//! ## Subscriber Table
75//!
76//! Tracks event subscription progress:
77//!
78//! | Column | Type | Description |
79//! |--------|------|-------------|
80//! | `key` | VARCHAR(50) | Subscriber identifier (primary key) |
81//! | `worker_id` | VARCHAR(26) | Associated worker ID |
82//! | `cursor` | TEXT | Current event stream position |
83//! | `lag` | INTEGER | Subscription lag counter |
84//! | `enabled` | BOOLEAN | Whether subscription is active |
85//! | `created_at` | TIMESTAMP | Creation timestamp |
86//! | `updated_at` | TIMESTAMP | Last update timestamp |
87
88use sqlx_migrator::{Info, Migrator};
89
90#[cfg(feature = "accord")]
91mod accord;
92mod m0001;
93mod m0002;
94mod m0003;
95mod m0004;
96
97#[cfg(feature = "accord")]
98pub use accord::AccordMigration;
99pub use m0001::InitMigration;
100pub use m0002::M0002;
101pub use m0003::M0003;
102pub use m0004::M0004;
103
104/// Creates a new [`Migrator`] instance with all Evento migrations registered.
105///
106/// The migrator is generic over the database type and works with SQLite, MySQL, and PostgreSQL
107/// when the corresponding feature is enabled.
108///
109/// # Example
110///
111/// ```rust,ignore
112/// use sqlx_migrator::{Migrate, Plan};
113///
114/// // For SQLite
115/// let migrator = evento_sql_migrator::new::<sqlx::Sqlite>()?;
116///
117/// // For PostgreSQL
118/// let migrator = evento_sql_migrator::new::<sqlx::Postgres>()?;
119///
120/// // For MySQL
121/// let migrator = evento_sql_migrator::new::<sqlx::MySql>()?;
122///
123/// // Run migrations
124/// migrator.run(&mut *conn, &Plan::apply_all()).await?;
125/// ```
126///
127/// # Errors
128///
129/// Returns an error if migration registration fails.
130// Two definitions: the `accord` build adds the consensus-journal migration (and its
131// extra trait bound); the default build is unchanged — so the `AccordMigration` bound
132// never leaks onto callers (e.g. evento-sql's generic test harness) that don't opt in.
133#[cfg(not(feature = "accord"))]
134pub fn new<DB: sqlx::Database>() -> Result<Migrator<DB>, sqlx_migrator::Error>
135where
136    InitMigration: sqlx_migrator::Migration<DB>,
137    M0002: sqlx_migrator::Migration<DB>,
138    M0003: sqlx_migrator::Migration<DB>,
139    M0004: sqlx_migrator::Migration<DB>,
140{
141    let mut migrator = Migrator::default();
142    migrator.add_migration(Box::new(InitMigration))?;
143    migrator.add_migration(Box::new(M0002))?;
144    migrator.add_migration(Box::new(M0003))?;
145    migrator.add_migration(Box::new(M0004))?;
146    Ok(migrator)
147}
148
149#[cfg(feature = "accord")]
150pub fn new<DB: sqlx::Database>() -> Result<Migrator<DB>, sqlx_migrator::Error>
151where
152    InitMigration: sqlx_migrator::Migration<DB>,
153    M0002: sqlx_migrator::Migration<DB>,
154    M0003: sqlx_migrator::Migration<DB>,
155    M0004: sqlx_migrator::Migration<DB>,
156    AccordMigration: sqlx_migrator::Migration<DB>,
157{
158    let mut migrator = Migrator::default();
159    migrator.add_migration(Box::new(InitMigration))?;
160    migrator.add_migration(Box::new(M0002))?;
161    migrator.add_migration(Box::new(M0003))?;
162    migrator.add_migration(Box::new(M0004))?;
163    // The optional evento-accord consensus-journal tables.
164    migrator.add_migration(Box::new(AccordMigration))?;
165    Ok(migrator)
166}