Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
## Crates

- `v-api` - Dropshot endpoint, context, authentication, and authorization framework for the v-api service.
- `v-api-installer` - Embedded Diesel migration runner for installing the v-model Postgres schema.
- `v-api-param` - Configuration parameter helpers for inline strings or file-backed secret values.
- `v-api-permission-derive` - Procedural macro for deriving v-api permission traits on application enums.
- `v-model` - Shared data models, Diesel schema, migrations, storage traits, and Postgres implementations.
Expand Down
9 changes: 0 additions & 9 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
[workspace]
members = [
"v-api",
"v-api-installer",
"v-api-param",
"v-api-permission-derive",
"v-model",
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ The crate assumes that the hosting application is using a Postgres database or c
connection to one. Want a different backend? Please contribute, it will be gladly welcome.

The `v-model` crate contains [diesel](https://diesel.rs/) migrations for initializing the necessary
tables in a database. `v-model-installer` exposes embedded migrations via [diesel_migrations](https://docs.rs/diesel_migrations/latest/diesel_migrations/).
tables in a database. `v-model` exposes embedded migrations via [diesel_migrations](https://docs.rs/diesel_migrations/latest/diesel_migrations/).

To add the endpoints in to the hosting server:

Expand Down
17 changes: 0 additions & 17 deletions v-api-installer/Cargo.toml

This file was deleted.

21 changes: 0 additions & 21 deletions v-api-installer/src/lib.rs

This file was deleted.

15 changes: 0 additions & 15 deletions v-api-installer/src/main.rs

This file was deleted.

3 changes: 1 addition & 2 deletions v-model/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ async-trait = { workspace = true }
bb8 = { workspace = true }
chrono = { workspace = true, features = ["serde"] }
diesel = { workspace = true, features = ["chrono", "uuid", "serde_json"] }
diesel_migrations = { workspace = true, features = ["postgres"] }
mockall = { workspace = true, optional = true }
newtype-uuid = { workspace = true }
partial-struct = { workspace = true }
Expand All @@ -28,6 +29,4 @@ tracing = { workspace = true }
uuid = { workspace = true, features = ["v4", "serde"] }

[dev-dependencies]
diesel_migrations = { version = "2.3.2", features = ["postgres"] }
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }
v-api-installer = { path = "../v-api-installer" }
3 changes: 2 additions & 1 deletion v-api-installer/build.rs → v-model/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

fn main() {
println!("cargo:rerun-if-changed=../v-model/migrations");
println!("cargo:rerun-if-changed=migrations");
println!("cargo:rerun-if-changed=src/saga/migrations");
}
1 change: 1 addition & 0 deletions v-model/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use std::{
use thiserror::Error;

pub mod db;
pub mod migrations;
pub mod permissions;
#[cfg(feature = "sagas")]
pub mod saga;
Expand Down
39 changes: 39 additions & 0 deletions v-model/src/migrations.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use diesel::{
PgConnection,
r2d2::{ConnectionManager, ManageConnection},
};
use diesel_migrations::{EmbeddedMigrations, MigrationHarness, embed_migrations};

/// Core v-model migrations that are always applied.
pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!("migrations");

/// Saga-specific migrations, only available when the `sagas` feature is enabled.
#[cfg(feature = "sagas")]
pub const SAGA_MIGRATIONS: EmbeddedMigrations = embed_migrations!("src/saga/migrations");

/// Returns all embedded migration sets that should be applied based on the
/// currently enabled features.
fn all_migrations() -> Vec<EmbeddedMigrations> {
let mut migrations = vec![MIGRATIONS];

#[cfg(feature = "sagas")]
migrations.push(SAGA_MIGRATIONS);

migrations
}

/// Runs all pending migrations for each enabled feature against the database
/// at the provided connection string. Migration sets are applied in dependency
/// order (core first, then feature-specific).
pub fn run_migrations(url: &str) {
let conn: ConnectionManager<PgConnection> = ConnectionManager::new(url);
let mut conn = conn.connect().unwrap();

for migrations in all_migrations() {
conn.run_pending_migrations(migrations).unwrap();
}
}
13 changes: 13 additions & 0 deletions v-model/src/saga/migrations/2026-05-19-172630_sagas/down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
DROP INDEX IF EXISTS idx_saga_events_saga_id_id;
DROP INDEX IF EXISTS idx_saga_events_event_type;
DROP INDEX IF EXISTS idx_saga_events_saga_id;

DROP INDEX IF EXISTS idx_sagas_node_claimed_at;
DROP INDEX IF EXISTS idx_sagas_current_node_id;
DROP INDEX IF EXISTS idx_sagas_created_at;
DROP INDEX IF EXISTS idx_sagas_name;
DROP INDEX IF EXISTS idx_sagas_state;

-- Drop tables (saga_events first due to foreign key constraint)
DROP TABLE IF EXISTS saga_events;
DROP TABLE IF EXISTS sagas;
29 changes: 29 additions & 0 deletions v-model/src/saga/migrations/2026-05-19-172630_sagas/up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
CREATE TABLE sagas (
saga_id UUID PRIMARY KEY,
name TEXT NOT NULL,
dag JSONB NOT NULL,
state TEXT NOT NULL,
current_node_id UUID,
node_claimed_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE INDEX idx_sagas_state ON sagas (state);
CREATE INDEX idx_sagas_name ON sagas (name);
CREATE INDEX idx_sagas_created_at ON sagas (created_at);
CREATE INDEX idx_sagas_current_node_id ON sagas (current_node_id);
CREATE INDEX idx_sagas_node_claimed_at ON sagas (node_claimed_at) WHERE current_node_id IS NOT NULL;

CREATE TABLE saga_events (
id BIGSERIAL PRIMARY KEY,
saga_id UUID NOT NULL REFERENCES sagas(saga_id) ON DELETE CASCADE,
node_id BIGINT NOT NULL,
event_type TEXT NOT NULL,
event_data JSONB NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE INDEX idx_saga_events_saga_id ON saga_events (saga_id);
CREATE INDEX idx_saga_events_event_type ON saga_events (event_type);
CREATE INDEX idx_saga_events_saga_id_id ON saga_events (saga_id, id);
2 changes: 1 addition & 1 deletion v-model/tests/postgres.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::ops::{Add, Sub};
use uuid::Uuid;
use v_api_installer::run_migrations;
use v_model::{
NewApiKey, NewApiUser, NewMagicLink, NewMagicLinkAttempt, UserId,
migrations::run_migrations,
schema_ext::MagicLinkAttemptState,
storage::{
ApiKeyFilter, ApiKeyStore, ApiUserFilter, ApiUserStore, ListPagination,
Expand Down
Loading