From aba648e7539df68d50aa788bc762fa0ea58dd8d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Ma=C4=87kowski?= Date: Wed, 24 Dec 2025 03:20:05 +0100 Subject: [PATCH 1/3] refactor: use `Arc` internally in `Database` This makes the API more ergonomic, as `Arc` should really just be an implementation detail, rather than something exposed to the user. This is a followup to the discussion here: https://github.com/cot-rs/cot/pull/419#discussion_r2644558358 --- cot/src/auth/db.rs | 5 +-- cot/src/db.rs | 72 +++++++--------------------------- cot/src/openapi.rs | 2 +- cot/src/project.rs | 16 ++++---- cot/src/request.rs | 6 +-- cot/src/request/extractors.rs | 34 ++-------------- cot/src/session/store/db.rs | 5 +-- cot/src/test.rs | 14 +++---- examples/admin/src/main.rs | 5 +-- examples/forms/src/main.rs | 8 ++-- examples/todo-list/src/main.rs | 14 +++---- 11 files changed, 52 insertions(+), 129 deletions(-) diff --git a/cot/src/auth/db.rs b/cot/src/auth/db.rs index d7a7310d..0dce8eff 100644 --- a/cot/src/auth/db.rs +++ b/cot/src/auth/db.rs @@ -6,7 +6,6 @@ use std::any::Any; use std::borrow::Cow; use std::fmt::{Display, Formatter}; -use std::sync::Arc; use async_trait::async_trait; // Importing `Auto` from `cot` instead of `crate` so that the migration generator @@ -469,7 +468,7 @@ impl DatabaseUserCredentials { /// [`DatabaseUserCredentials`] struct and ignores all other credential types. #[derive(Debug, Clone)] pub struct DatabaseUserBackend { - database: Arc, + database: Database, } impl DatabaseUserBackend { @@ -495,7 +494,7 @@ impl DatabaseUserBackend { /// } /// ``` #[must_use] - pub fn new(database: Arc) -> Self { + pub fn new(database: Database) -> Self { Self { database } } } diff --git a/cot/src/db.rs b/cot/src/db.rs index 87d3421c..96d7cde9 100644 --- a/cot/src/db.rs +++ b/cot/src/db.rs @@ -18,6 +18,7 @@ mod sea_query_db; use std::fmt::{Display, Formatter, Write}; use std::hash::Hash; use std::str::FromStr; +use std::sync::Arc; use async_trait::async_trait; pub use cot_macros::{model, query}; @@ -789,10 +790,9 @@ pub trait SqlxValueRef<'r>: Sized { /// It is used to execute queries and interact with the database. The connection /// is established when the structure is created and closed when /// [`Self::close()`] is called. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Database { - _url: String, - inner: DatabaseImpl, + inner: Arc, } #[derive(Debug)] @@ -837,8 +837,7 @@ impl Database { if url.starts_with("sqlite:") { let inner = DatabaseSqlite::new(&url).await?; return Ok(Self { - _url: url, - inner: DatabaseImpl::Sqlite(inner), + inner: Arc::new(DatabaseImpl::Sqlite(inner)), }); } @@ -846,8 +845,7 @@ impl Database { if url.starts_with("postgresql:") { let inner = DatabasePostgres::new(&url).await?; return Ok(Self { - _url: url, - inner: DatabaseImpl::Postgres(inner), + inner: Arc::new(DatabaseImpl::Postgres(inner)), }); } @@ -855,8 +853,7 @@ impl Database { if url.starts_with("mysql:") { let inner = DatabaseMySql::new(&url).await?; return Ok(Self { - _url: url, - inner: DatabaseImpl::MySql(inner), + inner: Arc::new(DatabaseImpl::MySql(inner)), }); } @@ -886,7 +883,7 @@ impl Database { /// } /// ``` pub async fn close(&self) -> Result<()> { - match &self.inner { + match &*self.inner { #[cfg(feature = "sqlite")] DatabaseImpl::Sqlite(inner) => inner.close().await, #[cfg(feature = "postgres")] @@ -1124,7 +1121,7 @@ impl Database { return Ok(()); } - let max_params = match self.inner { + let max_params = match &*self.inner { // https://sqlite.org/limits.html#max_variable_number // Assuming SQLite > 3.32.0 (2020-05-22) #[cfg(feature = "sqlite")] @@ -1471,7 +1468,7 @@ impl Database { .collect::>(); let values = SqlxValues(sea_query::Values(values)); - let result = match &self.inner { + let result = match &*self.inner { #[cfg(feature = "sqlite")] DatabaseImpl::Sqlite(inner) => inner.raw_with(query, values).await?, #[cfg(feature = "postgres")] @@ -1487,7 +1484,7 @@ impl Database { where T: SqlxBinder + Send + Sync, { - let result = match &self.inner { + let result = match &*self.inner { #[cfg(feature = "sqlite")] DatabaseImpl::Sqlite(inner) => inner.fetch_option(statement).await?.map(Row::Sqlite), #[cfg(feature = "postgres")] @@ -1502,7 +1499,7 @@ impl Database { } fn supports_returning(&self) -> bool { - match self.inner { + match &*self.inner { #[cfg(feature = "sqlite")] DatabaseImpl::Sqlite(_) => true, #[cfg(feature = "postgres")] @@ -1516,7 +1513,7 @@ impl Database { where T: SqlxBinder + Send + Sync, { - let result = match &self.inner { + let result = match &*self.inner { #[cfg(feature = "sqlite")] DatabaseImpl::Sqlite(inner) => inner .fetch_all(statement) @@ -1547,7 +1544,7 @@ impl Database { where T: SqlxBinder + Send + Sync, { - let result = match &self.inner { + let result = match &*self.inner { #[cfg(feature = "sqlite")] DatabaseImpl::Sqlite(inner) => inner.execute_statement(statement).await?, #[cfg(feature = "postgres")] @@ -1563,7 +1560,7 @@ impl Database { &self, statement: T, ) -> Result { - let result = match &self.inner { + let result = match &*self.inner { #[cfg(feature = "sqlite")] DatabaseImpl::Sqlite(inner) => inner.execute_schema(statement).await?, #[cfg(feature = "postgres")] @@ -1578,7 +1575,7 @@ impl Database { impl ColumnTypeMapper for Database { fn sea_query_column_type_for(&self, column_type: ColumnType) -> sea_query::ColumnType { - match &self.inner { + match &*self.inner { #[cfg(feature = "sqlite")] DatabaseImpl::Sqlite(inner) => inner.sea_query_column_type_for(column_type), #[cfg(feature = "postgres")] @@ -1735,45 +1732,6 @@ impl DatabaseBackend for Database { } } -#[async_trait] -impl DatabaseBackend for std::sync::Arc { - async fn insert_or_update(&self, data: &mut T) -> Result<()> { - Database::insert_or_update(self, data).await - } - - async fn insert(&self, data: &mut T) -> Result<()> { - Database::insert(self, data).await - } - - async fn update(&self, data: &mut T) -> Result<()> { - Database::update(self, data).await - } - - async fn bulk_insert(&self, data: &mut [T]) -> Result<()> { - Database::bulk_insert(self, data).await - } - - async fn bulk_insert_or_update(&self, data: &mut [T]) -> Result<()> { - Database::bulk_insert_or_update(self, data).await - } - - async fn query(&self, query: &Query) -> Result> { - Database::query(self, query).await - } - - async fn get(&self, query: &Query) -> Result> { - Database::get(self, query).await - } - - async fn exists(&self, query: &Query) -> Result { - Database::exists(self, query).await - } - - async fn delete(&self, query: &Query) -> Result { - Database::delete(self, query).await - } -} - /// Result of a statement execution. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct StatementResult { diff --git a/cot/src/openapi.rs b/cot/src/openapi.rs index b7cc99d5..5be3cc05 100644 --- a/cot/src/openapi.rs +++ b/cot/src/openapi.rs @@ -837,7 +837,7 @@ impl ApiOperationPart for Method {} impl ApiOperationPart for Session {} impl ApiOperationPart for Auth {} #[cfg(feature = "db")] -impl ApiOperationPart for crate::request::extractors::RequestDb {} +impl ApiOperationPart for crate::db::Database {} impl ApiOperationPart for Json { fn modify_api_operation( diff --git a/cot/src/project.rs b/cot/src/project.rs index 50c3675d..d47e469d 100644 --- a/cot/src/project.rs +++ b/cot/src/project.rs @@ -1224,11 +1224,11 @@ impl Bootstrapper { } #[cfg(feature = "db")] - async fn init_database(config: &DatabaseConfig) -> cot::Result>> { + async fn init_database(config: &DatabaseConfig) -> cot::Result> { match &config.url { Some(url) => { let database = Database::new(url.as_str()).await?; - Ok(Some(Arc::new(database))) + Ok(Some(database)) } None => Ok(None), } @@ -1626,7 +1626,7 @@ impl BootstrapPhase for WithDatabase { type Apps = ::Apps; type Router = ::Router; #[cfg(feature = "db")] - type Database = Option>; + type Database = Option; type AuthBackend = ::AuthBackend; #[cfg(feature = "cache")] type Cache = (); @@ -1649,7 +1649,7 @@ impl BootstrapPhase for WithCache { type Apps = ::Apps; type Router = ::Router; #[cfg(feature = "db")] - type Database = Option>; + type Database = ::Database; type AuthBackend = ::AuthBackend; #[cfg(feature = "cache")] type Cache = Arc; @@ -1791,7 +1791,7 @@ impl ProjectContext { #[must_use] fn with_database( self, - #[cfg(feature = "db")] database: Option>, + #[cfg(feature = "db")] database: Option, ) -> ProjectContext { ProjectContext { config: self.config, @@ -1931,7 +1931,7 @@ impl>> ProjectContext { } #[cfg(feature = "db")] -impl>>> ProjectContext { +impl>> ProjectContext { /// Returns the database for the project, if it is enabled. /// /// # Examples @@ -1952,7 +1952,7 @@ impl>>> ProjectContext { /// ``` #[must_use] #[cfg(feature = "db")] - pub fn try_database(&self) -> Option<&Arc> { + pub fn try_database(&self) -> Option<&Database> { self.database.as_ref() } @@ -1980,7 +1980,7 @@ impl>>> ProjectContext { #[cfg(feature = "db")] #[must_use] #[track_caller] - pub fn database(&self) -> &Arc { + pub fn database(&self) -> &Database { self.try_database().expect( "Database missing. Did you forget to add the database when configuring CotProject?", ) diff --git a/cot/src/request.rs b/cot/src/request.rs index 092e0d57..687be839 100644 --- a/cot/src/request.rs +++ b/cot/src/request.rs @@ -207,7 +207,7 @@ pub trait RequestExt: private::Sealed { /// ``` #[cfg(feature = "db")] #[must_use] - fn db(&self) -> &Arc; + fn db(&self) -> &Database; /// Get the content type of the request. /// @@ -318,7 +318,7 @@ impl RequestExt for Request { } #[cfg(feature = "db")] - fn db(&self) -> &Arc { + fn db(&self) -> &Database { self.context().database() } @@ -378,7 +378,7 @@ impl RequestExt for RequestHead { } #[cfg(feature = "db")] - fn db(&self) -> &Arc { + fn db(&self) -> &Database { self.context().database() } diff --git a/cot/src/request/extractors.rs b/cot/src/request/extractors.rs index d4c0fc75..51672e4d 100644 --- a/cot/src/request/extractors.rs +++ b/cot/src/request/extractors.rs @@ -370,38 +370,10 @@ impl FromRequest for RequestForm { } } -/// An extractor that gets the database from the request extensions. -/// -/// # Example -/// -/// ``` -/// use cot::html::Html; -/// use cot::request::extractors::RequestDb; -/// -/// async fn my_handler(RequestDb(db): RequestDb) -> Html { -/// // ... do something with the database -/// # db.close().await.unwrap(); -/// # Html::new("") -/// } -/// -/// # #[tokio::main] -/// # async fn main() -> cot::Result<()> { -/// # use cot::RequestHandler; -/// # let request = cot::test::TestRequestBuilder::get("/") -/// # .database(cot::test::TestDatabase::new_sqlite().await?.database()) -/// # .build(); -/// # my_handler.handle(request).await?; -/// # Ok(()) -/// # } -/// ``` -#[cfg(feature = "db")] -#[derive(Debug)] -pub struct RequestDb(pub Arc); - #[cfg(feature = "db")] -impl FromRequestHead for RequestDb { +impl FromRequestHead for crate::db::Database { async fn from_request_head(head: &RequestHead) -> cot::Result { - Ok(Self(head.db().clone())) + Ok(head.db().clone()) } } @@ -787,7 +759,7 @@ mod tests { let db = crate::test::TestDatabase::new_sqlite().await.unwrap(); let mut test_request = TestRequestBuilder::get("/").database(db.database()).build(); - let RequestDb(extracted_db) = test_request.extract_from_head().await.unwrap(); + let extracted_db: crate::db::Database = test_request.extract_from_head().await.unwrap(); // check that we have a connection to the database extracted_db.close().await.unwrap(); diff --git a/cot/src/session/store/db.rs b/cot/src/session/store/db.rs index 1588629d..131de501 100644 --- a/cot/src/session/store/db.rs +++ b/cot/src/session/store/db.rs @@ -23,7 +23,6 @@ use std::collections::HashMap; use std::error::Error; -use std::sync::Arc; use async_trait::async_trait; use thiserror::Error; @@ -88,7 +87,7 @@ impl From for session_store::Error { /// ``` #[derive(Clone, Debug)] pub struct DbStore { - connection: Arc, + connection: Database, } impl DbStore { @@ -110,7 +109,7 @@ impl DbStore { /// } /// ``` #[must_use] - pub fn new(connection: Arc) -> DbStore { + pub fn new(connection: Database) -> DbStore { DbStore { connection } } } diff --git a/cot/src/test.rs b/cot/src/test.rs index ad1bea50..eec14261 100644 --- a/cot/src/test.rs +++ b/cot/src/test.rs @@ -227,7 +227,7 @@ pub struct TestRequestBuilder { auth_backend: Option, auth: Option, #[cfg(feature = "db")] - database: Option>, + database: Option, form_data: Option>, #[cfg(feature = "json")] json_data: Option, @@ -590,7 +590,7 @@ impl TestRequestBuilder { /// } /// ``` #[cfg(feature = "db")] - pub fn database>>(&mut self, database: DB) -> &mut Self { + pub fn database>(&mut self, database: DB) -> &mut Self { self.database = Some(database.into()); self } @@ -622,8 +622,8 @@ impl TestRequestBuilder { /// # } /// ``` #[cfg(feature = "db")] - pub async fn with_db_auth(&mut self, db: Arc) -> &mut Self { - self.auth_backend(DatabaseUserBackend::new(Arc::clone(&db))); + pub async fn with_db_auth(&mut self, db: Database) -> &mut Self { + self.auth_backend(DatabaseUserBackend::new(db.clone())); self.with_session(); self.database(db); self.auth = Some( @@ -851,7 +851,7 @@ impl TestRequestBuilder { #[cfg(feature = "db")] #[derive(Debug)] pub struct TestDatabase { - database: Arc, + database: Database, kind: TestDatabaseKind, migrations: Vec, } @@ -860,7 +860,7 @@ pub struct TestDatabase { impl TestDatabase { fn new(database: Database, kind: TestDatabaseKind) -> TestDatabase { Self { - database: Arc::new(database), + database, kind, migrations: Vec::new(), } @@ -1148,7 +1148,7 @@ impl TestDatabase { /// # } /// ``` #[must_use] - pub fn database(&self) -> Arc { + pub fn database(&self) -> Database { self.database.clone() } diff --git a/examples/admin/src/main.rs b/examples/admin/src/main.rs index 82e5447f..0547084d 100644 --- a/examples/admin/src/main.rs +++ b/examples/admin/src/main.rs @@ -13,12 +13,11 @@ use cot::config::{ StaticFilesConfig, StaticFilesPathRewriteMode, }; use cot::db::migrations::SyncDynMigration; -use cot::db::{Auto, Model, model}; +use cot::db::{Auto, Database, Model, model}; use cot::form::Form; use cot::html::Html; use cot::middleware::{AuthMiddleware, LiveReloadMiddleware, SessionMiddleware}; use cot::project::{MiddlewareContext, RegisterAppsContext, RootHandler}; -use cot::request::extractors::RequestDb; use cot::router::{Route, Router, Urls}; use cot::static_files::StaticFilesMiddleware; use cot::{App, AppBuilder, Project, ProjectContext}; @@ -44,7 +43,7 @@ struct IndexTemplate<'a> { todo_items: Vec, } -async fn index(urls: Urls, RequestDb(db): RequestDb) -> cot::Result { +async fn index(urls: Urls, db: Database) -> cot::Result { let todo_items = TodoItem::objects().all(&db).await?; let index_template = IndexTemplate { urls: &urls, diff --git a/examples/forms/src/main.rs b/examples/forms/src/main.rs index fa63c7a5..a8ffcc48 100644 --- a/examples/forms/src/main.rs +++ b/examples/forms/src/main.rs @@ -6,14 +6,14 @@ use chrono_tz::Tz; use cot::cli::CliMetadata; use cot::config::ProjectConfig; use cot::db::migrations::SyncDynMigration; -use cot::db::{Auto, Model, model}; +use cot::db::{Auto, Database, Model, model}; use cot::form::Form; use cot::form::fields::Step; use cot::html::Html; use cot::middleware::{AuthMiddleware, LiveReloadMiddleware, SessionMiddleware}; use cot::project::{MiddlewareContext, RegisterAppsContext, RootHandler, RootHandlerBuilder}; use cot::request::Request; -use cot::request::extractors::{RequestDb, RequestForm, StaticFiles}; +use cot::request::extractors::{RequestForm, StaticFiles}; use cot::response::Response; use cot::router::{Route, Router, Urls}; use cot::static_files::{StaticFile, StaticFilesMiddleware}; @@ -75,7 +75,7 @@ async fn index( urls: Urls, static_files: StaticFiles, mut request: Request, - RequestDb(db): RequestDb, + db: Database, ) -> cot::Result { let example_form_items = ExampleFormItem::objects().all(&db).await?; let index_template = IndexTemplate { @@ -91,7 +91,7 @@ async fn index( async fn add_example_form( urls: Urls, - RequestDb(db): RequestDb, + db: Database, RequestForm(example_form): RequestForm, ) -> cot::Result { let example_form = example_form.unwrap(); diff --git a/examples/todo-list/src/main.rs b/examples/todo-list/src/main.rs index 28837978..04c9961d 100644 --- a/examples/todo-list/src/main.rs +++ b/examples/todo-list/src/main.rs @@ -5,11 +5,11 @@ use cot::auth::db::DatabaseUserApp; use cot::cli::CliMetadata; use cot::config::{DatabaseConfig, ProjectConfig}; use cot::db::migrations::SyncDynMigration; -use cot::db::{Auto, Model, model, query}; +use cot::db::{Auto, Database, Model, model, query}; use cot::form::Form; use cot::html::Html; use cot::project::{MiddlewareContext, RegisterAppsContext, RootHandler}; -use cot::request::extractors::{Path, RequestDb, RequestForm}; +use cot::request::extractors::{Path, RequestForm}; use cot::response::Response; use cot::router::{Route, Router, Urls}; use cot::static_files::StaticFilesMiddleware; @@ -30,7 +30,7 @@ struct IndexTemplate<'a> { todo_items: Vec, } -async fn index(urls: Urls, RequestDb(db): RequestDb) -> cot::Result { +async fn index(urls: Urls, db: Database) -> cot::Result { let todo_items = TodoItem::objects().all(&db).await?; let index_template = IndexTemplate { urls: &urls, @@ -49,7 +49,7 @@ struct TodoForm { async fn add_todo( urls: Urls, - RequestDb(db): RequestDb, + db: Database, RequestForm(todo_form): RequestForm, ) -> cot::Result { let todo_form = todo_form.unwrap(); @@ -64,11 +64,7 @@ async fn add_todo( Ok(reverse_redirect!(urls, "index")?) } -async fn remove_todo( - urls: Urls, - RequestDb(db): RequestDb, - Path(todo_id): Path, -) -> cot::Result { +async fn remove_todo(urls: Urls, db: Database, Path(todo_id): Path) -> cot::Result { query!(TodoItem, $id == todo_id).delete(&db).await?; Ok(reverse_redirect!(urls, "index")?) From b5a5ec9fd3a7dff99fe64b7b567ab142a4d67267 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Ma=C4=87kowski?= Date: Sun, 28 Dec 2025 13:23:38 +0100 Subject: [PATCH 2/3] fix doctests --- cot/src/auth/db.rs | 14 +++++++------- cot/src/test.rs | 3 +-- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/cot/src/auth/db.rs b/cot/src/auth/db.rs index 0dce8eff..0184ebad 100644 --- a/cot/src/auth/db.rs +++ b/cot/src/auth/db.rs @@ -191,10 +191,10 @@ impl DatabaseUser { /// use cot::auth::UserId; /// use cot::auth::db::DatabaseUser; /// use cot::common_types::Password; + /// use cot::db::Database; /// use cot::html::Html; - /// use cot::request::extractors::RequestDb; /// - /// async fn view(RequestDb(db): RequestDb) -> cot::Result { + /// async fn view(db: Database) -> cot::Result { /// let user = /// DatabaseUser::create_user(&db, "testuser".to_string(), &Password::new("password123")) /// .await?; @@ -209,7 +209,7 @@ impl DatabaseUser { /// # use cot::test::{TestDatabase, TestRequestBuilder}; /// # let mut test_database = TestDatabase::new_sqlite().await?; /// # test_database.with_auth().run_migrations().await; - /// # view(RequestDb(test_database.database())).await?; + /// # view(test_database.database()).await?; /// # test_database.cleanup().await?; /// # Ok(()) /// # } @@ -283,10 +283,10 @@ impl DatabaseUser { /// use cot::auth::UserId; /// use cot::auth::db::DatabaseUser; /// use cot::common_types::Password; + /// use cot::db::Database; /// use cot::html::Html; - /// use cot::request::extractors::RequestDb; /// - /// async fn view(RequestDb(db): RequestDb) -> cot::Result { + /// async fn view(db: Database) -> cot::Result { /// let user = /// DatabaseUser::create_user(&db, "testuser".to_string(), &Password::new("password123")) /// .await?; @@ -326,10 +326,10 @@ impl DatabaseUser { /// use cot::auth::UserId; /// use cot::auth::db::DatabaseUser; /// use cot::common_types::Password; + /// use cot::db::Database; /// use cot::html::Html; - /// use cot::request::extractors::RequestDb; /// - /// async fn view(RequestDb(db): RequestDb) -> cot::Result { + /// async fn view(db: Database) -> cot::Result { /// let user = /// DatabaseUser::create_user(&db, "testuser".to_string(), &Password::new("password123")) /// .await?; diff --git a/cot/src/test.rs b/cot/src/test.rs index eec14261..49d6374c 100644 --- a/cot/src/test.rs +++ b/cot/src/test.rs @@ -563,9 +563,8 @@ impl TestRequestBuilder { /// use cot::db::Database; /// use cot::html::Html; /// use cot::test::TestRequestBuilder; - /// use cot::request::extractors::RequestDb; /// - /// async fn index(RequestDb(db): RequestDb) -> Html { + /// async fn index(db: Database) -> Html { /// // ... do something with db /// /// Html::new("Hello world!") From 6715dcc07cbded36be86886fd2b556783787c36e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Ma=C4=87kowski?= Date: Sun, 28 Dec 2025 13:29:38 +0100 Subject: [PATCH 3/3] fix test again --- cot/src/session/store/db.rs | 42 ++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/cot/src/session/store/db.rs b/cot/src/session/store/db.rs index 131de501..79b5d4e3 100644 --- a/cot/src/session/store/db.rs +++ b/cot/src/session/store/db.rs @@ -7,18 +7,18 @@ //! //! # Examples //! -//! ```no_run +//! ``` //! use std::sync::Arc; //! //! use cot::db::Database; //! use cot::session::store::db::DbStore; //! -//! #[tokio::main] -//! async fn main() -> cot::Result<()> { -//! let db = Arc::new(Database::new("sqlite://:memory:").await?); -//! let store = DbStore::new(db); -//! Ok(()) -//! } +//! # #[tokio::main] +//! # async fn main() -> cot::Result<()> { +//! let db = Database::new("sqlite://:memory:").await?; +//! let store = DbStore::new(db); +//! # Ok(()) +//! # } //! ``` use std::collections::HashMap; @@ -72,18 +72,18 @@ impl From for session_store::Error { /// /// # Examples /// -/// ```no_run +/// ``` /// use std::sync::Arc; /// /// use cot::db::Database; /// use cot::session::store::db::DbStore; /// -/// #[tokio::main] -/// async fn main() -> Result<(), cot::session::store::db::DbStoreError> { -/// let db = Arc::new(Database::new("sqlite://:memory:").await?); -/// let store = DbStore::new(db); -/// Ok(()) -/// } +/// # #[tokio::main] +/// # async fn main() -> Result<(), cot::session::store::db::DbStoreError> { +/// let db = Database::new("sqlite://:memory:").await?; +/// let store = DbStore::new(db); +/// # Ok(()) +/// # } /// ``` #[derive(Clone, Debug)] pub struct DbStore { @@ -95,18 +95,18 @@ impl DbStore { /// /// # Examples /// - /// ```no_run + /// ``` /// use std::sync::Arc; /// /// use cot::db::Database; /// use cot::session::store::db::DbStore; /// - /// #[tokio::main] - /// async fn main() -> Result<(), cot::session::store::db::DbStoreError> { - /// let db = Arc::new(Database::new("sqlite://:memory:").await?); - /// let store = DbStore::new(db); - /// Ok(()) - /// } + /// # #[tokio::main] + /// # async fn main() -> Result<(), cot::session::store::db::DbStoreError> { + /// let db = Database::new("sqlite://:memory:").await?; + /// let store = DbStore::new(db); + /// # Ok(()) + /// # } /// ``` #[must_use] pub fn new(connection: Database) -> DbStore {