tiberius/result.rs
1pub use crate::tds::stream::{QueryItem, ResultMetadata};
2use crate::{
3 client::Connection,
4 tds::stream::{ReceivedToken, TokenStream},
5};
6use futures_util::io::{AsyncRead, AsyncWrite};
7use futures_util::stream::TryStreamExt;
8use std::fmt::Debug;
9
10/// A result from a query execution, listing the number of affected rows.
11///
12/// If executing multiple queries, the resulting counts will be come separately,
13/// marking the rows affected for each query.
14///
15/// # Example
16///
17/// ```no_run
18/// # use tiberius::Config;
19/// # use tokio_util::compat::TokioAsyncWriteCompatExt;
20/// # use std::env;
21/// # #[tokio::main]
22/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
23/// # let c_str = env::var("TIBERIUS_TEST_CONNECTION_STRING").unwrap_or(
24/// # "server=tcp:localhost,1433;integratedSecurity=true;TrustServerCertificate=true".to_owned(),
25/// # );
26/// # let config = Config::from_ado_string(&c_str)?;
27/// # let tcp = tokio::net::TcpStream::connect(config.get_addr()).await?;
28/// # tcp.set_nodelay(true)?;
29/// # let mut client = tiberius::Client::connect(config, tcp.compat_write()).await?;
30/// let result = client
31/// .execute(
32/// "INSERT INTO #Test (id) VALUES (@P1); INSERT INTO #Test (id) VALUES (@P2, @P3)",
33/// &[&1i32, &2i32, &3i32],
34/// )
35/// .await?;
36///
37/// assert_eq!(&[1, 2], result.rows_affected());
38/// # Ok(())
39/// # }
40/// ```
41///
42/// [`Client`]: struct.Client.html
43/// [`Rows`]: struct.Row.html
44/// [`next_resultset`]: #method.next_resultset
45#[derive(Debug)]
46pub struct ExecuteResult {
47 rows_affected: Vec<u64>,
48}
49
50impl<'a> ExecuteResult {
51 pub(crate) async fn new<S: AsyncRead + AsyncWrite + Unpin + Send>(
52 connection: &'a mut Connection<S>,
53 ) -> crate::Result<Self> {
54 let mut token_stream = TokenStream::new(connection).try_unfold();
55 let mut rows_affected = Vec::new();
56
57 while let Some(token) = token_stream.try_next().await? {
58 match token {
59 ReceivedToken::DoneProc(done) if done.is_final() => (),
60 ReceivedToken::DoneProc(done) => rows_affected.push(done.rows()),
61 ReceivedToken::DoneInProc(done) => rows_affected.push(done.rows()),
62 ReceivedToken::Done(done) => rows_affected.push(done.rows()),
63 _ => (),
64 }
65 }
66
67 Ok(Self { rows_affected })
68 }
69
70 /// A slice of numbers of rows affected in the same order as the given
71 /// queries.
72 pub fn rows_affected(&self) -> &[u64] {
73 self.rows_affected.as_slice()
74 }
75
76 /// Aggregates all resulting row counts into a sum.
77 ///
78 /// # Example
79 ///
80 /// ```no_run
81 /// # use tiberius::Config;
82 /// # use tokio_util::compat::TokioAsyncWriteCompatExt;
83 /// # use std::env;
84 /// # #[tokio::main]
85 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
86 /// # let c_str = env::var("TIBERIUS_TEST_CONNECTION_STRING").unwrap_or(
87 /// # "server=tcp:localhost,1433;integratedSecurity=true;TrustServerCertificate=true".to_owned(),
88 /// # );
89 /// # let config = Config::from_ado_string(&c_str)?;
90 /// # let tcp = tokio::net::TcpStream::connect(config.get_addr()).await?;
91 /// # tcp.set_nodelay(true)?;
92 /// # let mut client = tiberius::Client::connect(config, tcp.compat_write()).await?;
93 /// let rows_affected = client
94 /// .execute(
95 /// "INSERT INTO #Test (id) VALUES (@P1); INSERT INTO #Test (id) VALUES (@P2, @P3)",
96 /// &[&1i32, &2i32, &3i32],
97 /// )
98 /// .await?;
99 ///
100 /// assert_eq!(3, rows_affected.total());
101 /// # Ok(())
102 /// # }
103 pub fn total(self) -> u64 {
104 self.rows_affected.into_iter().sum()
105 }
106}
107
108impl IntoIterator for ExecuteResult {
109 type Item = u64;
110 type IntoIter = std::vec::IntoIter<Self::Item>;
111
112 fn into_iter(self) -> Self::IntoIter {
113 self.rows_affected.into_iter()
114 }
115}