1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
use crate::{
config::{Config, ConfigBuilder, Database, LiveConfig},
errors::Result,
pool::{create_pool, ConnectionPool},
query::Query,
stream::DetachedRowStream,
txn::Txn,
};
/// A neo4j database abstraction.
/// This type can be cloned and shared across threads, internal resources
/// are reference-counted.
#[derive(Clone)]
pub struct Graph {
config: LiveConfig,
pool: ConnectionPool,
}
/// Returns a [`Query`] which provides methods like [`Query::param`] to add parameters to the query
pub fn query(q: &str) -> Query {
Query::new(q.to_owned())
}
impl Graph {
/// Connects to the database with configurations provided.
///
/// You can build a config using [`ConfigBuilder::default()`].
pub async fn connect(config: Config) -> Result<Self> {
let pool = create_pool(&config).await?;
let config = config.into_live_config();
Ok(Graph { config, pool })
}
/// Connects to the database with default configurations
pub async fn new(
uri: impl Into<String>,
user: impl Into<String>,
password: impl Into<String>,
) -> Result<Self> {
let config = ConfigBuilder::default()
.uri(uri)
.user(user)
.password(password)
.build()?;
Self::connect(config).await
}
/// Starts a new transaction on the configured database.
/// All queries that needs to be run/executed within the transaction
/// should be executed using either [`Txn::run`] or [`Txn::execute`]
pub async fn start_txn(&self) -> Result<Txn> {
self.start_txn_on(self.config.db.clone()).await
}
/// Starts a new transaction on the provided database.
/// All queries that needs to be run/executed within the transaction
/// should be executed using either [`Txn::run`] or [`Txn::execute`]
pub async fn start_txn_on(&self, db: impl Into<Database>) -> Result<Txn> {
let connection = self.pool.get().await?;
Txn::new(db.into(), self.config.fetch_size, connection).await
}
/// Runs a query on the configured database using a connection from the connection pool,
/// It doesn't return any [`RowStream`] as the `run` abstraction discards any stream.
///
/// Use [`Graph::run`] for cases where you just want a write operation
///
/// use [`Graph::execute`] when you are interested in the result stream
pub async fn run(&self, q: Query) -> Result<()> {
self.run_on(&self.config.db, q).await
}
/// Runs a query on the provided database using a connection from the connection pool.
/// It doesn't return any [`RowStream`] as the `run` abstraction discards any stream.
///
/// Use [`Graph::run`] for cases where you just want a write operation
///
/// use [`Graph::execute`] when you are interested in the result stream
pub async fn run_on(&self, db: &str, q: Query) -> Result<()> {
let mut connection = self.pool.get().await?;
q.run(db, &mut connection).await
}
/// Executes a query on the configured database and returns a [`DetachedRowStream`]
pub async fn execute(&self, q: Query) -> Result<DetachedRowStream> {
self.execute_on(&self.config.db, q).await
}
/// Executes a query on the provided database and returns a [`DetaRowStream`]
pub async fn execute_on(&self, db: &str, q: Query) -> Result<DetachedRowStream> {
let connection = self.pool.get().await?;
q.execute(db, self.config.fetch_size, connection).await
}
}
const _: () = {
const fn assert_send_sync<T: ?Sized + Send + Sync>() {}
assert_send_sync::<Graph>();
};