Skip to content

Commit

Permalink
migrations everywhere!
Browse files Browse the repository at this point in the history
  • Loading branch information
levkk committed Dec 9, 2024
1 parent 7386258 commit 31c623d
Show file tree
Hide file tree
Showing 16 changed files with 149 additions and 57 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

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

Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DROP TABLE rwf_auth_users;
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
CREATE TABLE rwf_auth_users (
id BIGSERIAL PRIMARY KEY,
identifier VARCHAR NOT NULL UNIQUE,
password VARCHAR NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW ()
);

CREATE INDEX ON rwf_auth_users USING btree (created_at);
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
DROP TABLE IF EXISTS rwf_requests;

DROP TABLE IF EXISTS rwf_jobs;
45 changes: 45 additions & 0 deletions examples/users/migrations/1733778837089567000_rwf_init.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@

CREATE TABLE IF NOT EXISTS rwf_jobs (
id BIGSERIAL PRIMARY KEY,
name VARCHAR NOT NULL,
args JSONB NOT NULL DEFAULT '{}'::jsonb,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
start_after TIMESTAMPTZ NOT NULL DEFAULT NOW(),
started_at TIMESTAMPTZ,
attempts INT NOT NULL DEFAULT 0,
retries BIGINT NOT NULL DEFAULT 25,
completed_at TIMESTAMPTZ,
error VARCHAR
);

-- Pending jobs
CREATE INDEX IF NOT EXISTS rwf_jobs_pending_idx ON rwf_jobs USING btree(start_after, created_at) WHERE
completed_at IS NULL
AND started_at IS NULL
AND attempts < retries;

-- Running jobs
CREATE INDEX IF NOT EXISTS rwf_jobs_runnin_idx ON rwf_jobs USING btree(start_after, created_at) WHERE
completed_at IS NULL
AND started_at IS NOT NULL
AND attempts < retries;

CREATE INDEX IF NOT EXISTS rwf_jobs_name_completed_at_idx ON rwf_jobs USING btree(name, completed_at);

CREATE TABLE IF NOT EXISTS rwf_requests (
id BIGSERIAL PRIMARY KEY,
path VARCHAR NOT NULL,
method VARCHAR NOT NULL DEFAULT 'GET',
query JSONB NOT NULL DEFAULT '{}'::jsonb,
code INTEGER NOT NULL DEFAULT 200,
client_ip INET,
client_id UUID NOT NULL DEFAULT gen_random_uuid(),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
duration REAL NOT NULL
);

CREATE INDEX IF NOT EXISTS rwf_requests_path_created_at ON rwf_requests USING btree(created_at, path, client_id);

CREATE INDEX IF NOT EXISTS rwf_requests_errors ON rwf_requests USING btree(created_at, code, client_id) WHERE code >= 400;

CREATE INDEX IF NOT EXISTS rwf_requests_too_slow ON rwf_requests USING btree(created_at, duration, client_id) WHERE duration >= 1000.0; -- the unit is milliseconds
2 changes: 1 addition & 1 deletion examples/users/rwf.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[general]
secret_key = "9Sk2t2G40QC3QrdVr6e6RzYAKJLGTFjpDiRrmA7eGQk="
log_queries = true
# log_queries = true

[database]
name = "rwf_users"
4 changes: 4 additions & 0 deletions rwf-auth/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,7 @@ pub async fn migrate() -> Result<Migrations, Error> {
let path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
rwf::model::migrate(Some(path)).await
}

pub fn migrations_path() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("migrations")
}
2 changes: 1 addition & 1 deletion rwf-cli/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rwf-cli"
version = "0.1.14"
version = "0.2.2"
edition = "2021"
license = "MIT"
description = "Rust Web Framework CLI"
Expand Down
11 changes: 9 additions & 2 deletions rwf-cli/src/migrate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use rwf::model::migrations::{Direction, Migrations};
use std::path::Path;
use time::OffsetDateTime;

use log::info;
use regex::Regex;
use tokio::fs::{create_dir, File};

Expand All @@ -10,10 +11,16 @@ use crate::{logging::created, util::package_info};
pub async fn migrate(version: Option<i64>) {
let info = package_info().await.expect("couldn't get package info");

info!("Installing migrations from rwf");
Migrations::install(rwf::migrations_path())
.await
.expect("install rwf migrations failed");

if info.rwf_auth {
rwf_auth::migrate()
info!("Installing migrations from rwf-auth");
Migrations::install(rwf_auth::migrations_path())
.await
.expect("rwf-auth migrations failed to apply");
.expect("install rwf-auth migrations failed");
}

let migrations = Migrations::sync(None)
Expand Down
1 change: 1 addition & 0 deletions rwf/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ homepage = "https://levkk.github.io/rwf/"
repository = "https://github.com/levkk/rwf"
keywords = ["mvc", "web", "framework", "http", "orm"]
authors = ["Lev Kokotov <[email protected]>"]
include = ["src/", "migrations/"]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

Expand Down
3 changes: 3 additions & 0 deletions rwf/migrations/1733778837089567000_rwf_init.down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
DROP TABLE IF EXISTS rwf_requests;

DROP TABLE IF EXISTS rwf_jobs;
45 changes: 45 additions & 0 deletions rwf/migrations/1733778837089567000_rwf_init.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@

CREATE TABLE IF NOT EXISTS rwf_jobs (
id BIGSERIAL PRIMARY KEY,
name VARCHAR NOT NULL,
args JSONB NOT NULL DEFAULT '{}'::jsonb,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
start_after TIMESTAMPTZ NOT NULL DEFAULT NOW(),
started_at TIMESTAMPTZ,
attempts INT NOT NULL DEFAULT 0,
retries BIGINT NOT NULL DEFAULT 25,
completed_at TIMESTAMPTZ,
error VARCHAR
);

-- Pending jobs
CREATE INDEX IF NOT EXISTS rwf_jobs_pending_idx ON rwf_jobs USING btree(start_after, created_at) WHERE
completed_at IS NULL
AND started_at IS NULL
AND attempts < retries;

-- Running jobs
CREATE INDEX IF NOT EXISTS rwf_jobs_runnin_idx ON rwf_jobs USING btree(start_after, created_at) WHERE
completed_at IS NULL
AND started_at IS NOT NULL
AND attempts < retries;

CREATE INDEX IF NOT EXISTS rwf_jobs_name_completed_at_idx ON rwf_jobs USING btree(name, completed_at);

CREATE TABLE IF NOT EXISTS rwf_requests (
id BIGSERIAL PRIMARY KEY,
path VARCHAR NOT NULL,
method VARCHAR NOT NULL DEFAULT 'GET',
query JSONB NOT NULL DEFAULT '{}'::jsonb,
code INTEGER NOT NULL DEFAULT 200,
client_ip INET,
client_id UUID NOT NULL DEFAULT gen_random_uuid(),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
duration REAL NOT NULL
);

CREATE INDEX IF NOT EXISTS rwf_requests_path_created_at ON rwf_requests USING btree(created_at, path, client_id);

CREATE INDEX IF NOT EXISTS rwf_requests_errors ON rwf_requests USING btree(created_at, code, client_id) WHERE code >= 400;

CREATE INDEX IF NOT EXISTS rwf_requests_too_slow ON rwf_requests USING btree(created_at, duration, client_id) WHERE duration >= 1000.0; -- the unit is milliseconds
7 changes: 6 additions & 1 deletion rwf/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ pub use tokio;
/// Asynchronous PostgreSQL driver.
pub use tokio_postgres;

use std::net::SocketAddr;
use std::{net::SocketAddr, path::PathBuf};

/// Convert text to snake_case.
pub fn snake_case(string: &str) -> String {
Expand Down Expand Up @@ -176,3 +176,8 @@ pub fn peer_addr(addr: &str) -> Option<SocketAddr> {

None
}

/// Migrations path for rwf.
pub fn migrations_path() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("migrations")
}
54 changes: 5 additions & 49 deletions rwf/src/model/migrations/bootstrap.sql
Original file line number Diff line number Diff line change
@@ -1,53 +1,9 @@
SET LOCAL client_min_messages TO WARNING;
SET
LOCAL client_min_messages TO WARNING;

CREATE TABLE IF NOT EXISTS rwf_migrations (
id BIGSERIAL PRIMARY KEY,
version BIGINT NOT NULL,
name VARCHAR UNIQUE NOT NULL,
applied_at TIMESTAMPTZ
);

CREATE TABLE IF NOT EXISTS rwf_jobs (
id BIGSERIAL PRIMARY KEY,
name VARCHAR NOT NULL,
args JSONB NOT NULL DEFAULT '{}'::jsonb,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
start_after TIMESTAMPTZ NOT NULL DEFAULT NOW(),
started_at TIMESTAMPTZ,
attempts INT NOT NULL DEFAULT 0,
retries BIGINT NOT NULL DEFAULT 25,
completed_at TIMESTAMPTZ,
error VARCHAR
version BIGINT NOT NULL,
name VARCHAR UNIQUE NOT NULL,
applied_at TIMESTAMPTZ
);

-- Pending jobs
CREATE INDEX IF NOT EXISTS rwf_jobs_pending_idx ON rwf_jobs USING btree(start_after, created_at) WHERE
completed_at IS NULL
AND started_at IS NULL
AND attempts < retries;

-- Running jobs
CREATE INDEX IF NOT EXISTS rwf_jobs_runnin_idx ON rwf_jobs USING btree(start_after, created_at) WHERE
completed_at IS NULL
AND started_at IS NOT NULL
AND attempts < retries;

CREATE INDEX IF NOT EXISTS rwf_jobs_name_completed_at_idx ON rwf_jobs USING btree(name, completed_at);

CREATE TABLE IF NOT EXISTS rwf_requests (
id BIGSERIAL PRIMARY KEY,
path VARCHAR NOT NULL,
method VARCHAR NOT NULL DEFAULT 'GET',
query JSONB NOT NULL DEFAULT '{}'::jsonb,
code INTEGER NOT NULL DEFAULT 200,
client_ip INET,
client_id UUID NOT NULL DEFAULT gen_random_uuid(),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
duration REAL NOT NULL
);

CREATE INDEX IF NOT EXISTS rwf_requests_path_created_at ON rwf_requests USING btree(created_at, path, client_id);

CREATE INDEX IF NOT EXISTS rwf_requests_errors ON rwf_requests USING btree(created_at, code, client_id) WHERE code >= 400;

CREATE INDEX IF NOT EXISTS rwf_requests_too_slow ON rwf_requests USING btree(created_at, duration, client_id) WHERE duration >= 1000.0; -- the unit is milliseconds
18 changes: 16 additions & 2 deletions rwf/src/model/migrations/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use std::path::{Path, PathBuf};
use once_cell::sync::Lazy;
use regex::Regex;
use time::OffsetDateTime;
use tokio::fs::{read_dir, read_to_string};
use tokio::fs::{copy, read_dir, read_to_string};
use tracing::{error, info};

/// Migrations found in the `"migrations"` folder. Some of them
Expand Down Expand Up @@ -100,7 +100,8 @@ impl MigrationFile {
}

impl Migrations {
fn root_path(path: Option<PathBuf>) -> Result<PathBuf, Error> {
/// Get the migrations folder.
pub fn root_path(path: Option<PathBuf>) -> Result<PathBuf, Error> {
let path = PathBuf::from(
if let Some(path) = path {
path
Expand All @@ -120,6 +121,19 @@ impl Migrations {
}
}

/// Install migrations from specified path.
pub async fn install(from_path: PathBuf) -> Result<(), Error> {
let migrations_path = Self::root_path(None)?;
let mut entries = read_dir(from_path).await?;
while let Some(entry) = entries.next_entry().await? {
let src = entry.path();
let dest = migrations_path.join(entry.path().file_name().unwrap());
copy(src, dest).await.expect("copy");
}

Ok(())
}

async fn load(root_path: Option<PathBuf>) -> Result<Self, Error> {
let mut conn = get_connection().await?;
let migrations = Migration::all().fetch_all(&mut conn).await?;
Expand Down

0 comments on commit 31c623d

Please sign in to comment.