pub struct DoConnection { /* private fields */ }Expand description
A connection to a Durable Object’s SQL storage.
There is no socket behind it and nothing to pool: the database lives in
the Durable Object itself. Build one from the object’s storage with
DoConnection::new, in its constructor or per request.
Both &mut DoConnection and &DoConnection are sqlx executors, so a
connection kept in the object’s struct serves every request through
&self.
Implementations§
Source§impl DoConnection
impl DoConnection
Sourcepub fn execute_batch<'q, I>(
&self,
queries: I,
) -> impl Future<Output = Result<Vec<DoQueryResult>, Error>> + Send + '_
pub fn execute_batch<'q, I>( &self, queries: I, ) -> impl Future<Output = Result<Vec<DoQueryResult>, Error>> + Send + '_
Runs queries in order and atomically: if any statement fails, none
of them take effect.
This is the Durable Object answer to a transaction, which sql.exec
does not allow (see DoTransactionManager).
The statements run inside transaction, and a
failing one rolls the others back. Returns what each statement did, in the order
given; for the rows each statement returns as well, see
fetch_batch.
let results = conn
.execute_batch([
sqlx::query("UPDATE accounts SET balance = balance - ?1 WHERE id = ?2")
.bind(amount)
.bind(from),
sqlx::query("UPDATE accounts SET balance = balance + ?1 WHERE id = ?2")
.bind(amount)
.bind(to),
])
.await?;§Errors
When binding an argument fails, in which case nothing ran, or when any statement fails – in which case the whole batch was rolled back.
Sourcepub fn fetch_batch<'q, I>(
&self,
queries: I,
) -> impl Stream<Item = Result<DoBatchResult, Error>> + Send + '_
pub fn fetch_batch<'q, I>( &self, queries: I, ) -> impl Stream<Item = Result<DoBatchResult, Error>> + Send + '_
Runs queries in order and atomically, as
execute_batch does, and streams each
statement’s rows along with what it did, in the order given.
The shape sqlc’s :batchexec, :batchone and :batchmany queries
take, each a stream with one item per statement – but atomic. So
unlike a loop of queries it is not lazy: the whole batch runs when the
stream is first polled, and a failure is the one item it yields, with
nothing applied.
use futures_util::TryStreamExt;
use sqlx::Row;
let names: Vec<String> = conn
.fetch_batch([1_i64, 2, 3].map(|id| {
sqlx::query("SELECT name FROM users WHERE id = ?").bind(id)
}))
.map_ok(|result| result.rows()[0].get("name"))
.try_collect()
.await?;§Errors
The stream’s one item is an error when binding an argument fails, in which case nothing ran, or when any statement fails – in which case the whole batch was rolled back.
Source§impl DoConnection
impl DoConnection
Sourcepub fn storage(&self) -> &Storage
pub fn storage(&self) -> &Storage
The storage this connection wraps, for anything this crate does not cover – the key-value API, alarms – while keeping the connection.
Sourcepub fn sql(&self) -> &SqlStorage
pub fn sql(&self) -> &SqlStorage
The SQL API this connection runs queries through.
Sourcepub fn into_storage(self) -> Storage
pub fn into_storage(self) -> Storage
The storage this connection wraps, giving up the connection. See
storage to borrow it instead.
Source§impl DoConnection
impl DoConnection
Sourcepub fn transaction<F, Fut, T, E>(
&self,
callback: F,
) -> impl Future<Output = Result<T, E>> + Send + '_
pub fn transaction<F, Fut, T, E>( &self, callback: F, ) -> impl Future<Output = Result<T, E>> + Send + '_
Runs callback in a transaction: it commits if the callback returns
Ok, and rolls back every write the callback made if it returns
Err.
A real interactive transaction, unlike a batch: the callback reads its
own writes, and one statement can use what the one before it returned.
It runs inside Storage::transaction, and the callback’s value – or
its error, as it returned it – is what this resolves to.
let id = conn
.transaction(move |tx| async move {
let id: i64 = sqlx::query_scalar("INSERT INTO users (email) VALUES (?) RETURNING id")
.bind(email)
.fetch_one(&tx)
.await?;
sqlx::query("INSERT INTO posts (user_id, title) VALUES (?, 'hello')")
.bind(id)
.execute(&tx)
.await?;
Ok::<_, sqlx::Error>(id)
})
.await?;§The callback owns what it uses
Storage::transaction takes a 'static callback, so it cannot borrow
the connection or anything else from the caller: move what it needs
in, and run its queries through the DoTransaction it is handed.
That is also why this is a callback and not sqlx’s begin(), which
borrows the connection – begin() still fails.
§It holds the whole object
The Durable Object delivers no other request until the transaction
ends – even while the callback awaits something that is not storage.
That is what keeps other requests’ writes out of it, and why it should
be short: an awaited fetch() inside it stalls every caller of the
object, and a request to the object itself would never be answered.
§Errors
The callback’s own error, after rolling back; or, converted into E,
an error from storage when the transaction could not commit.
Trait Implementations§
Source§impl<'c> Acquire<'c> for &'c mut DoConnection
impl<'c> Acquire<'c> for &'c mut DoConnection
Source§impl Connection for DoConnection
impl Connection for DoConnection
Source§fn begin(
&mut self,
) -> impl Future<Output = Result<Transaction<'_, Do>, Error>> + Send + '_
fn begin( &mut self, ) -> impl Future<Output = Result<Transaction<'_, Do>, Error>> + Send + '_
Always fails – see DoTransactionManager.
type Database = Do
type Options = DoConnectOptions
Source§fn close(self) -> impl Future<Output = Result<(), Error>> + Send + 'static
fn close(self) -> impl Future<Output = Result<(), Error>> + Send + 'static
Source§fn ping(&mut self) -> impl Future<Output = Result<(), Error>> + Send + '_
fn ping(&mut self) -> impl Future<Output = Result<(), Error>> + Send + '_
Source§fn shrink_buffers(&mut self)
fn shrink_buffers(&mut self)
Source§fn begin_with(
&mut self,
statement: impl SqlSafeStr,
) -> impl Future<Output = Result<Transaction<'_, Self::Database>, Error>> + Sendwhere
Self: Sized,
fn begin_with(
&mut self,
statement: impl SqlSafeStr,
) -> impl Future<Output = Result<Transaction<'_, Self::Database>, Error>> + Sendwhere
Self: Sized,
Source§fn is_in_transaction(&self) -> bool
fn is_in_transaction(&self) -> bool
true if the connection is currently in a transaction. Read moreSource§fn transaction<'a, F, R, E>(
&'a mut self,
callback: F,
) -> impl Future<Output = Result<R, E>> + Send + 'a
fn transaction<'a, F, R, E>( &'a mut self, callback: F, ) -> impl Future<Output = Result<R, E>> + Send + 'a
Source§impl Debug for DoConnection
impl Debug for DoConnection
Source§impl<'c> Executor<'c> for &'c DoConnection
impl<'c> Executor<'c> for &'c DoConnection
Source§fn execute<'e, 'q: 'e, E>(
self,
query: E,
) -> BoxFuture<'e, Result<DoQueryResult, Error>>
fn execute<'e, 'q: 'e, E>( self, query: E, ) -> BoxFuture<'e, Result<DoQueryResult, Error>>
Reports rows_affected and last_insert_rowid but no rows.
Source§fn fetch_many<'e, 'q: 'e, E>(
self,
query: E,
) -> BoxStream<'e, Result<Either<DoQueryResult, DoRow>, Error>>
fn fetch_many<'e, 'q: 'e, E>( self, query: E, ) -> BoxStream<'e, Result<Either<DoQueryResult, DoRow>, Error>>
Yields the rows only, never a DoQueryResult. Use
execute for what a statement changed.
type Database = Do
Source§fn execute_many<'e, 'q: 'e, E>(
self,
query: E,
) -> BoxStream<'e, Result<DoQueryResult, Error>>
fn execute_many<'e, 'q: 'e, E>( self, query: E, ) -> BoxStream<'e, Result<DoQueryResult, Error>>
Source§fn fetch_optional<'e, 'q: 'e, E>(
self,
query: E,
) -> BoxFuture<'e, Result<Option<DoRow>, Error>>
fn fetch_optional<'e, 'q: 'e, E>( self, query: E, ) -> BoxFuture<'e, Result<Option<DoRow>, Error>>
Source§fn prepare_with<'e>(
self,
sql: SqlStr,
_parameters: &'e [DoTypeInfo],
) -> BoxFuture<'e, Result<DoStatement, Error>>where
'c: 'e,
fn prepare_with<'e>(
self,
sql: SqlStr,
_parameters: &'e [DoTypeInfo],
) -> BoxFuture<'e, Result<DoStatement, Error>>where
'c: 'e,
Source§fn fetch<'e, 'q, E>(
self,
query: E,
) -> Pin<Box<dyn Stream<Item = Result<<Self::Database as Database>::Row, Error>> + Send + 'e>>
fn fetch<'e, 'q, E>( self, query: E, ) -> Pin<Box<dyn Stream<Item = Result<<Self::Database as Database>::Row, Error>> + Send + 'e>>
Source§fn fetch_all<'e, 'q, E>(
self,
query: E,
) -> Pin<Box<dyn Future<Output = Result<Vec<<Self::Database as Database>::Row>, Error>> + Send + 'e>>
fn fetch_all<'e, 'q, E>( self, query: E, ) -> Pin<Box<dyn Future<Output = Result<Vec<<Self::Database as Database>::Row>, Error>> + Send + 'e>>
Vec.Source§impl<'c> Executor<'c> for &'c mut DoConnection
impl<'c> Executor<'c> for &'c mut DoConnection
type Database = Do
Source§fn execute<'e, 'q: 'e, E>(
self,
query: E,
) -> BoxFuture<'e, Result<DoQueryResult, Error>>
fn execute<'e, 'q: 'e, E>( self, query: E, ) -> BoxFuture<'e, Result<DoQueryResult, Error>>
Source§fn execute_many<'e, 'q: 'e, E>(
self,
query: E,
) -> BoxStream<'e, Result<DoQueryResult, Error>>
fn execute_many<'e, 'q: 'e, E>( self, query: E, ) -> BoxStream<'e, Result<DoQueryResult, Error>>
Source§fn fetch_many<'e, 'q: 'e, E>(
self,
query: E,
) -> BoxStream<'e, Result<Either<DoQueryResult, DoRow>, Error>>
fn fetch_many<'e, 'q: 'e, E>( self, query: E, ) -> BoxStream<'e, Result<Either<DoQueryResult, DoRow>, Error>>
Source§fn fetch_optional<'e, 'q: 'e, E>(
self,
query: E,
) -> BoxFuture<'e, Result<Option<DoRow>, Error>>
fn fetch_optional<'e, 'q: 'e, E>( self, query: E, ) -> BoxFuture<'e, Result<Option<DoRow>, Error>>
Source§fn prepare_with<'e>(
self,
sql: SqlStr,
parameters: &'e [DoTypeInfo],
) -> BoxFuture<'e, Result<DoStatement, Error>>where
'c: 'e,
fn prepare_with<'e>(
self,
sql: SqlStr,
parameters: &'e [DoTypeInfo],
) -> BoxFuture<'e, Result<DoStatement, Error>>where
'c: 'e,
Source§fn fetch<'e, 'q, E>(
self,
query: E,
) -> Pin<Box<dyn Stream<Item = Result<<Self::Database as Database>::Row, Error>> + Send + 'e>>
fn fetch<'e, 'q, E>( self, query: E, ) -> Pin<Box<dyn Stream<Item = Result<<Self::Database as Database>::Row, Error>> + Send + 'e>>
Source§fn fetch_all<'e, 'q, E>(
self,
query: E,
) -> Pin<Box<dyn Future<Output = Result<Vec<<Self::Database as Database>::Row>, Error>> + Send + 'e>>
fn fetch_all<'e, 'q, E>( self, query: E, ) -> Pin<Box<dyn Future<Output = Result<Vec<<Self::Database as Database>::Row>, Error>> + Send + 'e>>
Vec.Source§impl From<Storage> for DoConnection
impl From<Storage> for DoConnection
impl Send for DoConnection
impl Sync for DoConnection
Auto Trait Implementations§
impl Freeze for DoConnection
impl RefUnwindSafe for DoConnection
impl Unpin for DoConnection
impl UnsafeUnpin for DoConnection
impl UnwindSafe for DoConnection
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more