better_duck_core/asynchronous/
database.rs1use std::path::Path;
2
3use crate::{
4 asynchronous::connection::AsyncConnection,
5 database::Database,
6 error::{Error, Result},
7};
8
9#[derive(Clone, Debug)]
13pub struct AsyncDatabase {
14 inner: Database,
15}
16
17impl AsyncDatabase {
18 pub fn from_database(db: Database) -> AsyncDatabase {
20 AsyncDatabase { inner: db }
21 }
22
23 pub fn database(&self) -> &Database {
25 &self.inner
26 }
27
28 pub async fn open<P>(path: P) -> Result<AsyncDatabase>
34 where
35 P: AsRef<Path> + Send + 'static,
36 {
37 let db = tokio::task::spawn_blocking(move || Database::open(path))
38 .await
39 .map_err(|e| Error::BackgroundTaskFailed(e.to_string()))??;
40 Ok(AsyncDatabase::from_database(db))
41 }
42
43 pub async fn open_in_memory() -> Result<AsyncDatabase> {
49 let db = tokio::task::spawn_blocking(Database::open_in_memory)
50 .await
51 .map_err(|e| Error::BackgroundTaskFailed(e.to_string()))??;
52 Ok(AsyncDatabase::from_database(db))
53 }
54
55 pub async fn connect(&self) -> Result<AsyncConnection> {
61 let db = self.inner.clone();
62 let conn = tokio::task::spawn_blocking(move || db.connect())
63 .await
64 .map_err(|e| Error::BackgroundTaskFailed(e.to_string()))??;
65 Ok(AsyncConnection::new(conn))
66 }
67}
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72
73 #[tokio::test]
74 async fn async_database_parallel_connections() {
75 let db = AsyncDatabase::open_in_memory().await.unwrap();
76 let a = db.connect().await.unwrap();
77 a.execute_batch("CREATE TABLE t (id INTEGER)").await.unwrap();
78
79 let mut handles = Vec::new();
80 for i in 0..8 {
81 let db = db.clone();
82 handles.push(tokio::spawn(async move {
83 let conn = db.connect().await.unwrap();
84 conn.execute_batch(format!("INSERT INTO t VALUES ({i})")).await.unwrap();
85 }));
86 }
87 for h in handles {
88 h.await.unwrap();
89 }
90
91 let result = a.execute("SELECT count(*) AS c FROM t").await.unwrap();
92 match result.rows()[0].get("c").unwrap() {
93 crate::types::value::DuckValue::BigInt(n) => assert_eq!(*n, 8),
94 other => panic!("expected BigInt, got {other:?}"),
95 }
96 }
97}