From ccaa450848b0abd806e6bad6c8d9bae91f4bd541 Mon Sep 17 00:00:00 2001 From: Sayan Nandan Date: Wed, 26 Jun 2024 11:15:13 +0530 Subject: [PATCH] resp: Enhance multi-row decode support --- Cargo.toml | 2 +- examples/multi_row.rs | 21 ++++++++++++++ src/response.rs | 66 ++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 examples/multi_row.rs diff --git a/Cargo.toml b/Cargo.toml index 4570beb..5271980 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ version = "0.8.8" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] # internal deps -sky-derive = "0.2.2" +sky-derive = "0.2.3" # external deps tokio = { version = "1.38.0", features = ["full"] } native-tls = "0.2.12" diff --git a/examples/multi_row.rs b/examples/multi_row.rs new file mode 100644 index 0000000..d282c18 --- /dev/null +++ b/examples/multi_row.rs @@ -0,0 +1,21 @@ +use skytable::{query, response::Rows, Config, Query, Response}; + +#[derive(Query, Response)] +pub struct User { + username: String, + password: String, + followers: u64, + email: Option, +} + +fn main() { + let mut db = Config::new_default("user", "password").connect().unwrap(); + let users: Rows = db + .query_parse(&query!( + "select all username, password, followers, email from myspace.mymodel limit ?", + 1000u64 + )) + .unwrap(); + // assume the first row has username set to 'sayan' + assert_eq!(users[0].username, "sayan"); +} diff --git a/src/response.rs b/src/response.rs index 9483df4..2c44580 100644 --- a/src/response.rs +++ b/src/response.rs @@ -32,7 +32,10 @@ //! ``` //! -use crate::error::{ClientResult, Error, ParseError}; +use { + crate::error::{ClientResult, Error, ParseError}, + std::ops::Deref, +}; /// The value directly returned by the server without any additional type parsing and/or casting #[derive(Debug, PartialEq, Clone)] @@ -92,6 +95,13 @@ pub struct Row { values: Vec, } +impl Deref for Row { + type Target = [Value]; + fn deref(&self) -> &Self::Target { + &self.values + } +} + impl Row { pub(crate) fn new(values: Vec) -> Self { Self { values } @@ -267,6 +277,15 @@ macro_rules! from_response_row { Ok(($($elem::from_value(values.next().unwrap())?),*,)) } } + impl<$($elem: FromValue),*> FromRow for ($($elem),*,) { + fn from_row(row: Row) -> ClientResult { + if row.values().len() != $size { + return Err(Error::ParseError(ParseError::TypeMismatch)); + } + let mut values = row.into_values().into_iter(); + Ok(($($elem::from_value(values.next().unwrap())?),*,)) + } + } )* } } @@ -323,3 +342,48 @@ impl FromResponse for Vec { } } } + +/// Trait for parsing a row into a custom type +pub trait FromRow: Sized { + /// Parse a row into a custom type + fn from_row(row: Row) -> ClientResult; +} + +impl FromRow for Row { + fn from_row(row: Row) -> ClientResult { + Ok(row) + } +} + +#[derive(Debug, PartialEq)] +/// A collection of rows +pub struct Rows(Vec); + +impl Rows { + /// Consume the [`Rows`] object and get all the rows as a vector + pub fn into_rows(self) -> Vec { + self.0 + } +} + +impl FromResponse for Rows { + fn from_response(resp: Response) -> ClientResult { + match resp { + Response::Rows(rows) => { + let mut ret = vec![]; + for row in rows { + ret.push(T::from_row(row)?); + } + Ok(Self(ret)) + } + _ => Err(Error::ParseError(ParseError::ResponseMismatch)), + } + } +} + +impl Deref for Rows { + type Target = [T]; + fn deref(&self) -> &Self::Target { + &self.0 + } +}