Skip to content
Draft
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
2 changes: 0 additions & 2 deletions cot-macros/src/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,6 @@ impl ModelBuilder {

#[must_use]
fn build_model_impl(&self) -> TokenStream {
let crate_ident = cot_ident();
let orm_ident = orm_ident();

let name = &self.name;
Expand All @@ -176,7 +175,6 @@ impl ModelBuilder {
let fields_as_get_values = &self.fields_as_get_values;

quote! {
#[#crate_ident::__private::async_trait]
#[automatically_derived]
impl #orm_ident::Model for #name {
type Fields = #fields_struct_name;
Expand Down
25 changes: 14 additions & 11 deletions cot/src/auth/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -615,7 +615,7 @@ mod tests {
let mut mock_db = MockDatabaseBackend::new();
mock_db
.expect_insert::<DatabaseUser>()
.returning(|_| Ok(()));
.returning(|_| Box::pin(async { Ok(()) }));

let username = "testuser".to_string();
let password = Password::new("password123");
Expand All @@ -636,9 +636,10 @@ mod tests {
&Password::new("password123"),
);

mock_db
.expect_get::<DatabaseUser>()
.returning(move |_| Ok(Some(user.clone())));
mock_db.expect_get::<DatabaseUser>().returning(move |_| {
let user = user.clone();
Box::pin(async move { Ok(Some(user.clone())) })
});

let result = DatabaseUser::get_by_id(&mock_db, 1).await.unwrap();
assert!(result.is_some());
Expand All @@ -655,9 +656,10 @@ mod tests {
&Password::new("password123"),
);

mock_db
.expect_get::<DatabaseUser>()
.returning(move |_| Ok(Some(user.clone())));
mock_db.expect_get::<DatabaseUser>().returning(move |_| {
let user = user.clone();
Box::pin(async move { Ok(Some(user.clone())) })
});

let credentials =
DatabaseUserCredentials::new("testuser".to_string(), Password::new("password123"));
Expand All @@ -675,7 +677,7 @@ mod tests {

mock_db
.expect_get::<DatabaseUser>()
.returning(move |_| Ok(None));
.returning(|_| Box::pin(async { Ok(None) }));

let credentials =
DatabaseUserCredentials::new("testuser".to_string(), Password::new("password123"));
Expand All @@ -695,9 +697,10 @@ mod tests {
&Password::new("password123"),
);

mock_db
.expect_get::<DatabaseUser>()
.returning(move |_| Ok(Some(user.clone())));
mock_db.expect_get::<DatabaseUser>().returning(move |_| {
let user = user.clone();
Box::pin(async move { Ok(Some(user.clone())) })
});

let credentials =
DatabaseUserCredentials::new("testuser".to_string(), Password::new("invalid"));
Expand Down
56 changes: 25 additions & 31 deletions cot/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ use std::hash::Hash;
use std::str::FromStr;
use std::sync::Arc;

use async_trait::async_trait;
use cot_core::error::impl_into_cot_error;
pub use cot_macros::{model, query};
use derive_more::{Debug, Deref, Display};
Expand Down Expand Up @@ -151,7 +150,6 @@ pub type Result<T> = std::result::Result<T, DatabaseError>;
/// name: String,
/// }
/// ```
#[async_trait]
#[diagnostic::on_unimplemented(
message = "`{Self}` is not marked as a database model",
label = "`{Self}` is not annotated with `#[cot::db::model]`",
Expand Down Expand Up @@ -228,10 +226,10 @@ pub trait Model: Sized + Send + 'static {
/// This method can return an error if the model instance could not be
/// found in the database, or there was a problem with the database
/// connection.
async fn get_by_primary_key<DB: DatabaseBackend>(
fn get_by_primary_key<DB: DatabaseBackend>(
db: &DB,
pk: Self::PrimaryKey,
) -> Result<Option<Self>>;
) -> impl Future<Output = Result<Option<Self>>>;

/// Inserts the model instance to the database, or updates an instance
/// with the same primary key if it already exists.
Expand All @@ -245,9 +243,8 @@ pub trait Model: Sized + Send + 'static {
/// inserted into the database, for instance because the migrations
/// haven't been applied, or there was a problem with the database
/// connection.
async fn save<DB: DatabaseBackend>(&mut self, db: &DB) -> Result<()> {
db.insert_or_update(self).await?;
Ok(())
fn save<DB: DatabaseBackend>(&mut self, db: &DB) -> impl Future<Output = Result<()>> {
async move { db.insert_or_update(self).await }
}

/// Insert the model instance to the database.
Expand All @@ -258,9 +255,8 @@ pub trait Model: Sized + Send + 'static {
/// inserted into the database, for instance because the migrations
/// haven't been applied, or there was a problem with the database
/// connection.
async fn insert<DB: DatabaseBackend>(&mut self, db: &DB) -> Result<()> {
db.insert(self).await?;
Ok(())
fn insert<DB: DatabaseBackend>(&mut self, db: &DB) -> impl Future<Output = Result<()>> {
async move { db.insert(self).await }
}

/// Update the model instance in the database.
Expand All @@ -274,9 +270,8 @@ pub trait Model: Sized + Send + 'static {
///
/// This method can return an error if the model with the given primary key
/// could not be found in the database.
async fn update<DB: DatabaseBackend>(&mut self, db: &DB) -> Result<()> {
db.update(self).await?;
Ok(())
fn update<DB: DatabaseBackend>(&mut self, db: &DB) -> impl Future<Output = Result<()>> {
async move { db.update(self).await }
}

/// Bulk insert multiple model instances to the database in a single query.
Expand Down Expand Up @@ -318,9 +313,11 @@ pub trait Model: Sized + Send + 'static {
/// // After insertion, all todos have populated IDs
/// assert!(todos[0].id.is_fixed());
/// ```
async fn bulk_insert<DB: DatabaseBackend>(db: &DB, instances: &mut [Self]) -> Result<()> {
db.bulk_insert(instances).await?;
Ok(())
fn bulk_insert<DB: DatabaseBackend>(
db: &DB,
instances: &mut [Self],
) -> impl Future<Output = Result<()>> {
async move { db.bulk_insert(instances).await }
}

/// Bulk insert multiple model instances to the database in a single query,
Expand Down Expand Up @@ -357,12 +354,11 @@ pub trait Model: Sized + Send + 'static {
/// // After insertion, all todos have populated IDs
/// assert!(todos[0].id.is_fixed());
/// ```
async fn bulk_insert_or_update<DB: DatabaseBackend>(
fn bulk_insert_or_update<DB: DatabaseBackend>(
db: &DB,
instances: &mut [Self],
) -> Result<()> {
db.bulk_insert_or_update(instances).await?;
Ok(())
) -> impl Future<Output = Result<()>> {
async move { db.bulk_insert_or_update(instances).await }
}
}

Expand Down Expand Up @@ -1590,7 +1586,6 @@ impl ColumnTypeMapper for Database {
///
/// This trait is used to provide a backend for the database.
#[cfg_attr(test, automock)]
#[async_trait]
pub trait DatabaseBackend: Send + Sync {
/// Inserts a new row into the database, or updates an existing row if it
/// already exists.
Expand All @@ -1600,7 +1595,7 @@ pub trait DatabaseBackend: Send + Sync {
/// This method can return an error if the row could not be inserted into
/// the database, for instance because the migrations haven't been
/// applied, or there was a problem with the database connection.
async fn insert_or_update<T: Model>(&self, data: &mut T) -> Result<()>;
fn insert_or_update<T: Model>(&self, data: &mut T) -> impl Future<Output = Result<()>>;

/// Inserts a new row into the database.
///
Expand All @@ -1609,7 +1604,7 @@ pub trait DatabaseBackend: Send + Sync {
/// This method can return an error if the row could not be inserted into
/// the database, for instance because the migrations haven't been
/// applied, or there was a problem with the database connection.
async fn insert<T: Model>(&self, data: &mut T) -> Result<()>;
fn insert<T: Model>(&self, data: &mut T) -> impl Future<Output = Result<()>>;

/// Updates an existing row in the database.
///
Expand All @@ -1618,7 +1613,7 @@ pub trait DatabaseBackend: Send + Sync {
/// This method can return an error if the row could not be updated in the
/// database, for instance because the migrations haven't been applied, or
/// there was a problem with the database connection.
async fn update<T: Model>(&self, data: &mut T) -> Result<()>;
fn update<T: Model>(&self, data: &mut T) -> impl Future<Output = Result<()>>;

/// Bulk inserts multiple rows into the database.
///
Expand All @@ -1627,7 +1622,7 @@ pub trait DatabaseBackend: Send + Sync {
/// This method can return an error if the rows could not be inserted into
/// the database, for instance because the migrations haven't been
/// applied, or there was a problem with the database connection.
async fn bulk_insert<T: Model>(&self, data: &mut [T]) -> Result<()>;
fn bulk_insert<T: Model>(&self, data: &mut [T]) -> impl Future<Output = Result<()>>;

/// Bulk inserts multiple rows into the database, or updates existing rows
/// if they already exist.
Expand All @@ -1637,7 +1632,7 @@ pub trait DatabaseBackend: Send + Sync {
/// This method can return an error if the rows could not be inserted into
/// the database, for instance because the migrations haven't been
/// applied, or there was a problem with the database connection.
async fn bulk_insert_or_update<T: Model>(&self, data: &mut [T]) -> Result<()>;
fn bulk_insert_or_update<T: Model>(&self, data: &mut [T]) -> impl Future<Output = Result<()>>;

/// Executes a query and returns the results converted to the model type.
///
Expand All @@ -1650,7 +1645,7 @@ pub trait DatabaseBackend: Send + Sync {
/// generated or applied).
///
/// Can return an error if the database connection is lost.
async fn query<T: Model>(&self, query: &Query<T>) -> Result<Vec<T>>;
fn query<T: Model>(&self, query: &Query<T>) -> impl Future<Output = Result<Vec<T>>>;

/// Returns the first row that matches the given query. If no rows match the
/// query, returns `None`.
Expand All @@ -1664,7 +1659,7 @@ pub trait DatabaseBackend: Send + Sync {
/// applied).
///
/// Can return an error if the database connection is lost.
async fn get<T: Model>(&self, query: &Query<T>) -> Result<Option<T>>;
fn get<T: Model>(&self, query: &Query<T>) -> impl Future<Output = Result<Option<T>>>;

/// Returns whether a row exists that matches the given query.
///
Expand All @@ -1677,7 +1672,7 @@ pub trait DatabaseBackend: Send + Sync {
/// applied).
///
/// Can return an error if the database connection is lost.
async fn exists<T: Model>(&self, query: &Query<T>) -> Result<bool>;
fn exists<T: Model>(&self, query: &Query<T>) -> impl Future<Output = Result<bool>>;

/// Deletes all rows that match the given query.
///
Expand All @@ -1690,10 +1685,9 @@ pub trait DatabaseBackend: Send + Sync {
/// applied).
///
/// Can return an error if the database connection is lost.
async fn delete<T: Model>(&self, query: &Query<T>) -> Result<StatementResult>;
fn delete<T: Model>(&self, query: &Query<T>) -> impl Future<Output = Result<StatementResult>>;
}

#[async_trait]
impl DatabaseBackend for Database {
async fn insert_or_update<T: Model>(&self, data: &mut T) -> Result<()> {
Database::insert_or_update(self, data).await
Expand Down
13 changes: 8 additions & 5 deletions cot/src/db/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1481,7 +1481,8 @@ mod tests {
#[cot::test]
async fn query_all() {
let mut db = MockDatabaseBackend::new();
db.expect_query().returning(|_| Ok(Vec::<MockModel>::new()));
db.expect_query()
.returning(|_| Box::pin(async { Ok(Vec::<MockModel>::new()) }));
let query: Query<MockModel> = Query::new();

let result = query.all(&db).await;
Expand All @@ -1492,7 +1493,8 @@ mod tests {
#[cot::test]
async fn query_get() {
let mut db = MockDatabaseBackend::new();
db.expect_get().returning(|_| Ok(Option::<MockModel>::None));
db.expect_get()
.returning(|_| Box::pin(async { Ok(Option::<MockModel>::None) }));
let query: Query<MockModel> = Query::new();

let result = query.get(&db).await;
Expand All @@ -1504,7 +1506,7 @@ mod tests {
async fn query_exists() {
let mut db = MockDatabaseBackend::new();
db.expect_exists()
.returning(|_: &Query<MockModel>| Ok(false));
.returning(|_: &Query<MockModel>| Box::pin(async { Ok(false) }));

let query: Query<MockModel> = Query::new();

Expand All @@ -1515,8 +1517,9 @@ mod tests {
#[cot::test]
async fn query_delete() {
let mut db = MockDatabaseBackend::new();
db.expect_delete()
.returning(|_: &Query<MockModel>| Ok(StatementResult::new(RowsNum(0))));
db.expect_delete().returning(|_: &Query<MockModel>| {
Box::pin(async { Ok(StatementResult::new(RowsNum(0))) })
});
let query: Query<MockModel> = Query::new();

let result = query.delete(&db).await;
Expand Down
3 changes: 1 addition & 2 deletions cot/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@ pub(crate) mod utils;

#[cfg(feature = "openapi")]
pub use aide;
pub use bytes;
/// A wrapper around a handler that's used in [`Bootstrapper`].
///
/// It is returned by [`Bootstrapper::finish`]. Typically, you don't need to
Expand Down Expand Up @@ -182,9 +181,9 @@ pub use cot_macros::e2e_test;
/// ```
pub use cot_macros::main;
pub use cot_macros::test;
pub use http;
#[cfg(feature = "openapi")]
pub use schemars;
pub use {bytes, http};

pub use crate::__private::askama::{Template, filter_fn};
pub use crate::project::{
Expand Down
Loading