diff --git a/data/src/db/mod.rs b/data/src/db/mod.rs
index 9d67e43..fab55b8 100644
--- a/data/src/db/mod.rs
+++ b/data/src/db/mod.rs
@@ -5,7 +5,7 @@
use crate::geo::CountryIsoCode;
use crate::model::*;
-use rest_utils::db::{DbError, DbResult};
+use rest_utils::db::{BareTx, DbError, DbResult};
use std::collections::BTreeMap;
use uuid::Uuid;
#[cfg(test)]
@@ -25,10 +25,7 @@ impl From<ModelError> for DbError {
/// A transaction with high-level operations that deal with our types.
#[async_trait::async_trait]
-pub(crate) trait DataTx {
- /// Commits the transaction. The transaction is rolled back on drop unless this is called.
- async fn commit(self) -> DbResult<()>;
-
+pub(crate) trait DataTx: BareTx {
/// Gets a `Site` based on its `site_id`.
async fn get_site(&mut self, site_id: Uuid) -> DbResult<Site>;
diff --git a/data/src/db/pgsql.rs b/data/src/db/pgsql.rs
index 0e24aff..1f9566b 100644
--- a/data/src/db/pgsql.rs
+++ b/data/src/db/pgsql.rs
@@ -7,6 +7,7 @@ use crate::db::{count_as_usize, parse_country_iso_code, parse_url, DataTx, DbErr
use crate::geo::CountryIsoCode;
use crate::model::*;
use futures::TryStreamExt;
+use rest_utils::db::BareTx;
use sqlx::postgres::PgDatabaseError;
use sqlx::{Postgres, Row, Transaction};
use std::collections::BTreeMap;
@@ -56,11 +57,14 @@ impl From<Transaction<'static, Postgres>> for PostgresDataTx {
}
#[async_trait::async_trait]
-impl DataTx for PostgresDataTx {
+impl BareTx for PostgresDataTx {
async fn commit(mut self) -> DbResult<()> {
self.tx.commit().await.map_err(map_sqlx_error)
}
+}
+#[async_trait::async_trait]
+impl DataTx for PostgresDataTx {
async fn get_site(&mut self, site_id: Uuid) -> DbResult<Site> {
let query_str = "SELECT title, email FROM sites WHERE site_id = $1";
let row = sqlx::query(query_str)
diff --git a/data/src/db/sqlite.rs b/data/src/db/sqlite.rs
index 7edc250..f571266 100644
--- a/data/src/db/sqlite.rs
+++ b/data/src/db/sqlite.rs
@@ -9,6 +9,7 @@ use crate::model::*;
use futures::lock::Mutex;
use futures::TryStreamExt;
use rest_utils::db::sqlite::map_sqlx_error;
+use rest_utils::db::BareTx;
use sqlx::{Row, Sqlite, Transaction};
use std::collections::BTreeMap;
use std::convert::{TryFrom, TryInto};
@@ -95,12 +96,15 @@ impl From<Mutex<Transaction<'static, Sqlite>>> for SqliteDataTx {
}
#[async_trait::async_trait]
-impl DataTx for SqliteDataTx {
- async fn commit(self) -> DbResult<()> {
+impl BareTx for SqliteDataTx {
+ async fn commit(mut self) -> DbResult<()> {
let tx = self.tx.into_inner();
tx.commit().await.map_err(map_sqlx_error)
}
+}
+#[async_trait::async_trait]
+impl DataTx for SqliteDataTx {
async fn get_site(&mut self, site_id: Uuid) -> DbResult<Site> {
let mut tx = self.tx.lock().await;
diff --git a/data/src/driver/batch.rs b/data/src/driver/batch.rs
index f8c5d8a..df618b1 100644
--- a/data/src/driver/batch.rs
+++ b/data/src/driver/batch.rs
@@ -8,7 +8,7 @@ use crate::abuse::AbusePolicy;
use crate::db::DataTx;
use crate::model::{Comment, HttpMethod, Request, VoteCounts, VoteId, VoteReaction};
use log::warn;
-use rest_utils::db::{Db, DbError};
+use rest_utils::db::{BareTx, Db, DbError};
use uuid::Uuid;
/// Operations requested in batch for the page.
diff --git a/data/src/driver/count_votes.rs b/data/src/driver/count_votes.rs
index d061f06..dbc9922 100644
--- a/data/src/driver/count_votes.rs
+++ b/data/src/driver/count_votes.rs
@@ -9,7 +9,7 @@ use crate::{
db::DataTx,
model::{VoteCounts, VoteId, VoteReaction},
};
-use rest_utils::db::{Db, DbError};
+use rest_utils::db::{BareTx, Db, DbError};
use url::Url;
use uuid::Uuid;
diff --git a/data/src/driver/delete_vote.rs b/data/src/driver/delete_vote.rs
index 992ea16..2bf3089 100644
--- a/data/src/driver/delete_vote.rs
+++ b/data/src/driver/delete_vote.rs
@@ -5,7 +5,7 @@
use super::{ensure_path_in_site, Driver, DriverResult};
use crate::{abuse::AbusePolicy, db::DataTx, model::VoteId};
-use rest_utils::db::Db;
+use rest_utils::db::{BareTx, Db};
impl<A, D> Driver<A, D>
where
diff --git a/data/src/driver/get_comments.rs b/data/src/driver/get_comments.rs
index a56982b..6f96803 100644
--- a/data/src/driver/get_comments.rs
+++ b/data/src/driver/get_comments.rs
@@ -5,7 +5,7 @@
use super::{ensure_path_in_site, Driver, DriverResult};
use crate::{abuse::AbusePolicy, db::DataTx, model::Comment};
-use rest_utils::db::Db;
+use rest_utils::db::{BareTx, Db};
use url::Url;
use uuid::Uuid;
diff --git a/data/src/driver/put_comment.rs b/data/src/driver/put_comment.rs
index a7ebb77..2824344 100644
--- a/data/src/driver/put_comment.rs
+++ b/data/src/driver/put_comment.rs
@@ -5,7 +5,7 @@
use super::{ensure_path_in_site, Driver, DriverResult};
use crate::{abuse::AbusePolicy, db::DataTx, model::Comment};
-use rest_utils::db::Db;
+use rest_utils::db::{BareTx, Db};
use uuid::Uuid;
impl<A, D> Driver<A, D>
diff --git a/data/src/driver/put_request.rs b/data/src/driver/put_request.rs
index ff497d9..fddbb3f 100644
--- a/data/src/driver/put_request.rs
+++ b/data/src/driver/put_request.rs
@@ -6,7 +6,7 @@
use super::{ensure_path_in_site, Driver, DriverResult};
use crate::{abuse::AbusePolicy, db::DataTx, model::Request};
use log::warn;
-use rest_utils::db::Db;
+use rest_utils::db::{BareTx, Db};
use uuid::Uuid;
/// Information computed when storing a request that may be useful to the client.
diff --git a/data/src/driver/put_vote.rs b/data/src/driver/put_vote.rs
index 1acbfc8..a816561 100644
--- a/data/src/driver/put_vote.rs
+++ b/data/src/driver/put_vote.rs
@@ -7,7 +7,7 @@ use super::{ensure_path_in_site, Driver, DriverResult};
use crate::abuse::AbusePolicy;
use crate::db::DataTx;
use crate::model::{Vote, VoteId};
-use rest_utils::db::Db;
+use rest_utils::db::{BareTx, Db};
impl<A, D> Driver<A, D>
where
diff --git a/rest-utils/src/db/mod.rs b/rest-utils/src/db/mod.rs
index 420331a..61b0713 100644
--- a/rest-utils/src/db/mod.rs
+++ b/rest-utils/src/db/mod.rs
@@ -3,6 +3,8 @@
//! Generic features and types to access a database.
+use async_trait::async_trait;
+
#[cfg(feature = "postgres")]
pub mod postgres;
#[cfg(feature = "sqlite")]
@@ -38,15 +40,21 @@ pub enum DbError {
pub type DbResult<T> = Result<T, DbError>;
/// Abstraction over the database connection.
-#[async_trait::async_trait]
+#[async_trait]
pub trait Db {
/// Type of the wrapped sqlx transaction.
type SqlxTx;
/// Type of the transaction wrapper type to generate.
- // DO NOT SUBMIT: Add BareTx.
- type Tx: From<Self::SqlxTx> + Send + Sync + 'static;
+ type Tx: BareTx + From<Self::SqlxTx> + Send + Sync + 'static;
/// Begins a transaction.
async fn begin(&self) -> DbResult<Self::Tx>;
}
+
+/// Common operations for all transactions.
+#[async_trait]
+pub trait BareTx {
+ /// Commits the transaction.
+ async fn commit(mut self) -> DbResult<()>;
+}
diff --git a/rest-utils/src/db/postgres.rs b/rest-utils/src/db/postgres.rs
index a887d1f..e2398f3 100644
--- a/rest-utils/src/db/postgres.rs
+++ b/rest-utils/src/db/postgres.rs
@@ -3,7 +3,7 @@
//! Common utilities to interact with a PostgreSQL database.
-use crate::db::{Db, DbError, DbResult};
+use crate::db::{BareTx, Db, DbError, DbResult};
use derivative::Derivative;
use sqlx::postgres::{PgConnectOptions, PgDatabaseError, PgPool, PgPoolOptions, Postgres};
use sqlx::Transaction;
@@ -96,7 +96,7 @@ impl PostgresOptions {
#[derivative(Clone(bound = ""))]
pub struct PostgresDb<T>
where
- T: From<Transaction<'static, Postgres>> + Send + Sync + 'static,
+ T: BareTx + From<Transaction<'static, Postgres>> + Send + Sync + 'static,
{
/// Shared PostgreSQL connection pool. This is a cloneable type that all concurrent
/// transactions can use it concurrently.
@@ -108,7 +108,7 @@ where
impl<T> PostgresDb<T>
where
- T: From<Transaction<'static, Postgres>> + Send + Sync + 'static,
+ T: BareTx + From<Transaction<'static, Postgres>> + Send + Sync + 'static,
{
/// Creates a new connection with a set of pool options.
fn connect_lazy_with_pool_options(opts: PostgresOptions, pool_options: PgPoolOptions) -> Self {
@@ -173,7 +173,7 @@ where
impl<T> Drop for PostgresDb<T>
where
- T: From<Transaction<'static, Postgres>> + Send + Sync + 'static,
+ T: BareTx + From<Transaction<'static, Postgres>> + Send + Sync + 'static,
{
#[allow(unused_must_use)]
fn drop(&mut self) {
@@ -190,7 +190,7 @@ where
#[async_trait::async_trait]
impl<T> Db for PostgresDb<T>
where
- T: From<Transaction<'static, Postgres>> + Send + Sync + 'static,
+ T: BareTx + From<Transaction<'static, Postgres>> + Send + Sync + 'static,
{
type SqlxTx = Transaction<'static, Postgres>;
type Tx = T;
@@ -209,7 +209,7 @@ pub mod testutils {
/// Creates a new connection to the test database and initializes it.
pub async fn setup<T>(schema: &str) -> PostgresDb<T>
where
- T: From<Transaction<'static, Postgres>> + Send + Sync + 'static,
+ T: BareTx + From<Transaction<'static, Postgres>> + Send + Sync + 'static,
{
let _can_fail = env_logger::builder().is_test(true).try_init();
diff --git a/rest-utils/src/db/sqlite.rs b/rest-utils/src/db/sqlite.rs
index 5e29399..afd5435 100644
--- a/rest-utils/src/db/sqlite.rs
+++ b/rest-utils/src/db/sqlite.rs
@@ -3,14 +3,13 @@
//! Common utilities to interact with an SQLite database.
-use std::marker::PhantomData;
-
-use crate::db::{Db, DbError, DbResult};
+use crate::db::{BareTx, Db, DbError, DbResult};
use derivative::Derivative;
use futures::lock::Mutex;
use futures::TryStreamExt;
use sqlx::sqlite::{Sqlite, SqlitePool};
use sqlx::Transaction;
+use std::marker::PhantomData;
/// Takes a raw SQLx error `e` and converts it to our generic error type.
pub fn map_sqlx_error(e: sqlx::Error) -> DbError {
@@ -28,7 +27,7 @@ pub fn map_sqlx_error(e: sqlx::Error) -> DbError {
#[derivative(Clone(bound = ""))]
pub struct SqliteDb<T>
where
- T: From<Mutex<Transaction<'static, Sqlite>>> + Send + Sync + 'static,
+ T: BareTx + From<Mutex<Transaction<'static, Sqlite>>> + Send + Sync + 'static,
{
/// Shared SQLite connection pool. This is a cloneable type that all concurrent
/// transactions can use it concurrently.
@@ -40,7 +39,7 @@ where
impl<T> SqliteDb<T>
where
- T: From<Mutex<Transaction<'static, Sqlite>>> + Send + Sync + 'static,
+ T: BareTx + From<Mutex<Transaction<'static, Sqlite>>> + Send + Sync + 'static,
{
/// Creates a new connection and sets the database schema.
pub async fn connect(schema: &str) -> DbResult<Self> {
@@ -62,7 +61,7 @@ where
#[async_trait::async_trait]
impl<T> Db for SqliteDb<T>
where
- T: From<Mutex<Transaction<'static, Sqlite>>> + Send + Sync + 'static,
+ T: BareTx + From<Mutex<Transaction<'static, Sqlite>>> + Send + Sync + 'static,
{
type SqlxTx = Mutex<Transaction<'static, Sqlite>>;
type Tx = T;
@@ -81,7 +80,7 @@ pub mod testutils {
/// Initializes the test database with a schema.
pub async fn setup<T>(schema: &str) -> SqliteDb<T>
where
- T: From<Mutex<Transaction<'static, Sqlite>>> + Send + Sync + 'static,
+ T: BareTx + From<Mutex<Transaction<'static, Sqlite>>> + Send + Sync + 'static,
{
let _can_fail = env_logger::builder().is_test(true).try_init();
Code
I don't have a minimal repro, but I do have a relatively small diff of the change that triggered the problem. I am hiding it behind a "Details" section, like the backtrace, to keep the overview of the bug report short.
What I am doing, essentially, is adding a new trait to act as the supertrait of other two traits, and moving one common function to it.
Code diff
Meta
rustc --version --verbose:Error output
Backtrace