#![cfg(any(feature = "postgres-sync", feature = "tokio-postgres"))]
use crate::common::schema::postgres::*;
use drizzle::postgres::prelude::*;
#[derive(PostgresFromRow)]
struct TxSettings {
isolation: String,
read_only: String,
deferrable: String,
}
#[drizzle::test]
fn transaction_config_reaches_the_server(db: &mut TestDb<SimpleSchema>) {
let config = TransactionConfig::builder()
.serializable()
.read_only()
.deferrable()
.build();
result!(db.transaction(config, |tx| {
let settings: TxSettings = result!(tx.get(SQL::raw(
"SELECT current_setting('transaction_isolation') AS isolation, \
current_setting('transaction_read_only') AS read_only, \
current_setting('transaction_deferrable') AS deferrable"
)))?;
assert_eq!(settings.isolation, "serializable");
assert_eq!(settings.read_only, "on");
assert_eq!(settings.deferrable, "on");
Ok(())
}))?;
}
#[cfg(feature = "tokio-postgres")]
#[test]
fn test_pg_owned_prepared_send_sync() {
fn assert_send_sync<T: Send + Sync>() {}
assert_send_sync::<drizzle_postgres::builder::prepared::OwnedPreparedStatement>();
}
#[cfg(feature = "tokio-postgres")]
#[test]
fn test_tokio_postgres_transaction_futures_are_send() {
use drizzle::postgres::TransactionConfig;
fn assert_send<T: Send>(_: T) {}
fn transaction_future(db: &mut drizzle::postgres::tokio::Drizzle<SimpleSchema>) {
let SimpleSchema { simple } = SimpleSchema::new();
assert_send(
db.transaction(TransactionConfig::default(), async move |tx| {
tx.insert(simple)
.values([InsertSimple::new("sent")])
.execute()
.await?;
tx.update(simple)
.set(UpdateSimple::default().with_name("still sent"))
.execute()
.await?;
let rows: Vec<SelectSimple> = tx.select(()).from(simple).all().await?;
Ok(rows.len())
}),
);
}
let _ = transaction_future;
}
#[drizzle::test]
fn swallowed_statement_errors_fail_the_commit(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
let outcome = result!(db.transaction(TransactionConfig::default(), |tx| {
result!(
tx.insert(simple)
.values([InsertSimple::new("kept")])
.execute()
)?;
let _ = result!(tx.execute(SQL::raw("SELECT 1 / 0")));
Ok(())
}));
assert!(outcome.is_err(), "{outcome:?}");
let rows: Vec<SelectSimple> = db.select(()).from(simple).all();
assert!(rows.is_empty());
}
#[drizzle::test]
fn a_failed_statement_rolls_back_only_its_savepoint(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
result!(db.transaction(TransactionConfig::default(), |tx| {
result!(
tx.insert(simple)
.values([InsertSimple::new("outer")])
.execute()
)?;
let savepoint = result!(tx.savepoint(|sp| {
result!(
sp.insert(simple)
.values([InsertSimple::new("inner")])
.execute()
)?;
let _ = result!(sp.execute(SQL::raw("SELECT 1 / 0")));
Ok(())
}));
assert!(savepoint.is_err());
result!(
tx.insert(simple)
.values([InsertSimple::new("after")])
.execute()
)?;
Ok(())
}))?;
let names: Vec<String> = db
.select(simple.name)
.from(simple)
.order_by(asc(simple.name))
.all();
assert_eq!(names, ["after", "outer"]);
}
#[drizzle::test]
fn transactions_select_distinct_on(db: &mut TestDb<SimpleSchema>) {
let SimpleSchema { simple } = schema;
db.insert(simple)
.values([
InsertSimple::new("a"),
InsertSimple::new("a"),
InsertSimple::new("b"),
])
.execute();
let names = result!(db.transaction(TransactionConfig::default(), |tx| {
let rows: Vec<SelectSimple> = result!(
tx.select_distinct_on(simple.name, (simple.id, simple.name))
.from(simple)
.order_by((asc(simple.name), asc(simple.id)))
.all()
)?;
Ok(rows.into_iter().map(|row| row.name).collect::<Vec<_>>())
}))?;
assert_eq!(names, ["a", "b"]);
}