diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e68ddc4..7c24f23 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,6 +13,8 @@ jobs: build: runs-on: ubuntu-latest continue-on-error: ${{ matrix.nightly }} + env: + POSTGRESQL_VERSION: ${{ matrix.postgresql-version }} strategy: fail-fast: false @@ -21,7 +23,8 @@ jobs: toolchain: [ 'stable' ] nightly: [false] include: - - toolchain: 'nightly' + - postgresql-version: 14 + toolchain: 'nightly' nightly: true steps: @@ -78,6 +81,7 @@ jobs: - name: Run test - postgres | diesel run: | + export PATH="/usr/lib/postgresql/${POSTGRESQL_VERSION}/bin:$PATH" rustup run ${{ matrix.toolchain }} cargo test --features postgres,diesel --all-targets --verbose psql "postgresql://root:@127.0.0.1:5432/postgres" -c "DROP TABLE __diesel_schema_migrations,diesel_users" diff --git a/Cargo.toml b/Cargo.toml index 588dbb2..0bffeee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,7 @@ exclude = [".gitignore", ".github/", "README.tpl"] [workspace] members = [".", "examples/*"] default-members = ["."] -resolver = "2" +resolver = "3" [features] default = ["native-tls"] @@ -34,12 +34,12 @@ rustls = ["sqlx?/tls-rustls"] [dependencies] async-std = { version = "1", optional = true } # this has to include default due to task::block_on usage chrono = { version = "0.4", features = ["clock"], default-features = false } -diesel = { version = "2.1", optional = true, default-features = false } -diesel_migrations = { version = "2.1", optional = true, default-features = false} -http = "1.0.0" +diesel = { version = "2.3", optional = true, default-features = false } +diesel_migrations = { version = "2.3", optional = true, default-features = false} +http = "1.4" percent-encoding = { version = "2.3", optional = true } -sqlx = { version = "0.7", features = ["migrate", "macros"], optional = true, default-features = false } -thiserror = "1" +sqlx = { version = "0.9", features = ["migrate", "macros"], optional = true, default-features = false } +thiserror = "2" tokio = { version = "1", features = ["rt-multi-thread"], optional = true, default-features = false } tracing = { version = "0.1", default-features = false } url = { version = "2.5", optional = true } diff --git a/fixtures/diesel/postgres/diesel-postgres-structure.sql b/fixtures/diesel/postgres/diesel-postgres-structure.sql index f019df3..36464e6 100644 --- a/fixtures/diesel/postgres/diesel-postgres-structure.sql +++ b/fixtures/diesel/postgres/diesel-postgres-structure.sql @@ -1,6 +1,7 @@ SET statement_timeout = 0; SET lock_timeout = 0; SET idle_in_transaction_session_timeout = 0; +SET transaction_timeout = 0; SET client_encoding = 'UTF8'; SET standard_conforming_strings = on; SELECT pg_catalog.set_config('search_path', '', false); @@ -53,4 +54,3 @@ ALTER TABLE ONLY public.diesel_users -- -- PostgreSQL database dump complete -- - diff --git a/fixtures/sqlx/postgres/sqlx-postgres-structure.sql b/fixtures/sqlx/postgres/sqlx-postgres-structure.sql index 4abe57b..5a9d1d8 100644 --- a/fixtures/sqlx/postgres/sqlx-postgres-structure.sql +++ b/fixtures/sqlx/postgres/sqlx-postgres-structure.sql @@ -1,6 +1,7 @@ SET statement_timeout = 0; SET lock_timeout = 0; SET idle_in_transaction_session_timeout = 0; +SET transaction_timeout = 0; SET client_encoding = 'UTF8'; SET standard_conforming_strings = on; SELECT pg_catalog.set_config('search_path', '', false); @@ -57,4 +58,3 @@ ALTER TABLE ONLY public.sqlx_users -- -- PostgreSQL database dump complete -- - diff --git a/src/lib.rs b/src/lib.rs old mode 100644 new mode 100755 index d893297..d4fc0c7 --- a/src/lib.rs +++ b/src/lib.rs @@ -115,8 +115,8 @@ impl DatabaseSchemaBuilder { /// * `postgres`: `postgresql://[user[:password]@][netloc][:port][/dbname][?param1=value1&...]` - you can read more at [libpq docs](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING) /// /// * `sqlite`: `sqlite::memory:` in the case of `sqlx` and `:memory:` in the case of - /// `diesel` - you don't need to set this for `sqlite` as we auto-detect it as long as - /// you enable the `sqlite` feature. + /// `diesel` - you don't need to set this for `sqlite` as we auto-detect it as long as + /// you enable the `sqlite` feature. pub fn connection_url>(&mut self, connection_url: S) -> &mut Self { self.0.connection_url = ConnectionUrl(connection_url.into()); self diff --git a/src/macros.rs b/src/macros.rs index 0bf0f3f..63bba49 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -3,10 +3,10 @@ //! It provides the following macros: //! //! * `generate!` - Generate a `destination_path` file using migrations from the provided -//! `migrations_path` folder. +//! `migrations_path` folder. //! //! * `generate_using_defaults!` - Generate a `./structure.sql` file using migrations -//! from the `./migrations` folder. +//! from the `./migrations` folder. /// Generate a `destination_path` file using migrations from the provided /// `migrations_path` folder. diff --git a/src/mysql/mod.rs b/src/mysql/mod.rs index 5e3229e..53f3cc0 100644 --- a/src/mysql/mod.rs +++ b/src/mysql/mod.rs @@ -126,22 +126,15 @@ async fn migrate>( connection_url: &str, migrations_path: P, ) -> Result<(), sqlx::Error> { - use sqlx::{ - migrate::{Migrate, Migrator}, - mysql::MySqlConnectOptions, - ConnectOptions, - }; + use sqlx::{migrate::Migrator, mysql::MySqlConnectOptions, ConnectOptions}; use std::str::FromStr; let mut conn = MySqlConnectOptions::from_str(connection_url)? .connect() .await?; - // Ensure the migrations table exists before we run the migrations - conn.ensure_migrations_table().await?; - let migrator = Migrator::new(migrations_path.as_ref()).await?; - migrator.run_direct(&mut conn).await?; + migrator.run(&mut conn).await?; Ok(()) } diff --git a/src/postgres/mod.rs b/src/postgres/mod.rs index 8cf8f36..d23e13f 100644 --- a/src/postgres/mod.rs +++ b/src/postgres/mod.rs @@ -29,22 +29,15 @@ async fn migrate>( connection_url: &str, migrations_path: P, ) -> Result<(), sqlx::Error> { - use sqlx::{ - migrate::{Migrate, Migrator}, - postgres::PgConnectOptions, - ConnectOptions, - }; + use sqlx::{migrate::Migrator, postgres::PgConnectOptions, ConnectOptions}; use std::str::FromStr; let mut conn = PgConnectOptions::from_str(connection_url)? .connect() .await?; - // Ensure the migrations table exists before we run the migrations - conn.ensure_migrations_table().await?; - let migrator = Migrator::new(migrations_path.as_ref()).await?; - migrator.run_direct(&mut conn).await?; + migrator.run(&mut conn).await?; Ok(()) } @@ -83,10 +76,32 @@ mod tests { destination_filename.as_ref() ))?; let contents = std::fs::read_to_string(destination_path)?; - assert!(contents.contains(&expected)); + let contents = normalize_dump_output(&contents); + let expected = normalize_dump_output(&expected); + + for expected_fragment in expected + .split("\n\n") + .filter(|chunk| !chunk.trim().is_empty()) + { + assert!( + contents.contains(expected_fragment), + "missing expected pg_dump fragment:\n\n{expected_fragment}\n\nactual dump:\n\n{contents}" + ); + } Ok(()) } + fn normalize_dump_output(dump: &str) -> String { + dump.lines() + .filter(|line| { + !line.starts_with("\\restrict ") + && !line.starts_with("\\unrestrict ") + && *line != "SET transaction_timeout = 0;" + }) + .collect::>() + .join("\n") + } + #[cfg(all(feature = "sqlx", feature = "postgres"))] #[tokio::test] async fn test_write_structure_sql() -> Result<(), crate::error::Error> {