Skip to content

Commit 0dfc938

Browse files
authored
resp: Add enhanced multi-row support (#28)
* derive: add `FromRow` derive * resp: Enhance multi-row decode support
1 parent 209bfe4 commit 0dfc938

File tree

5 files changed

+94
-3
lines changed

5 files changed

+94
-3
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ version = "0.8.8"
1414
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
1515
[dependencies]
1616
# internal deps
17-
sky-derive = "0.2.2"
17+
sky-derive = "0.2.3"
1818
# external deps
1919
tokio = { version = "1.38.0", features = ["full"] }
2020
native-tls = "0.2.12"

examples/multi_row.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
use skytable::{query, response::Rows, Config, Query, Response};
2+
3+
#[derive(Query, Response)]
4+
pub struct User {
5+
username: String,
6+
password: String,
7+
followers: u64,
8+
email: Option<String>,
9+
}
10+
11+
fn main() {
12+
let mut db = Config::new_default("user", "password").connect().unwrap();
13+
let users: Rows<User> = db
14+
.query_parse(&query!(
15+
"select all username, password, followers, email from myspace.mymodel limit ?",
16+
1000u64
17+
))
18+
.unwrap();
19+
// assume the first row has username set to 'sayan'
20+
assert_eq!(users[0].username, "sayan");
21+
}

sky-derive/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "sky-derive"
3-
version = "0.2.2"
3+
version = "0.2.3"
44
edition = "2021"
55
license = "Apache-2.0"
66
description = "Macros for the Skytable client driver"

sky-derive/src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@ pub fn derive_response(input: TokenStream) -> TokenStream {
5454
Ok(#struct_instantiation)
5555
}
5656
}
57+
impl #impl_generics skytable::response::FromRow for #name #ty_generics #where_clause {
58+
fn from_row(row: skytable::response::Row) -> skytable::ClientResult<Self> {
59+
let #tuple_pattern = skytable::response::FromRow::from_row(row)?;
60+
Ok(#struct_instantiation)
61+
}
62+
}
5763
}
5864
}
5965
_ => unimplemented!(),

src/response.rs

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,10 @@
3232
//! ```
3333
//!
3434
35-
use crate::error::{ClientResult, Error, ParseError};
35+
use {
36+
crate::error::{ClientResult, Error, ParseError},
37+
std::ops::Deref,
38+
};
3639

3740
/// The value directly returned by the server without any additional type parsing and/or casting
3841
#[derive(Debug, PartialEq, Clone)]
@@ -92,6 +95,13 @@ pub struct Row {
9295
values: Vec<Value>,
9396
}
9497

98+
impl Deref for Row {
99+
type Target = [Value];
100+
fn deref(&self) -> &Self::Target {
101+
&self.values
102+
}
103+
}
104+
95105
impl Row {
96106
pub(crate) fn new(values: Vec<Value>) -> Self {
97107
Self { values }
@@ -267,6 +277,15 @@ macro_rules! from_response_row {
267277
Ok(($($elem::from_value(values.next().unwrap())?),*,))
268278
}
269279
}
280+
impl<$($elem: FromValue),*> FromRow for ($($elem),*,) {
281+
fn from_row(row: Row) -> ClientResult<Self> {
282+
if row.values().len() != $size {
283+
return Err(Error::ParseError(ParseError::TypeMismatch));
284+
}
285+
let mut values = row.into_values().into_iter();
286+
Ok(($($elem::from_value(values.next().unwrap())?),*,))
287+
}
288+
}
270289
)*
271290
}
272291
}
@@ -323,3 +342,48 @@ impl FromResponse for Vec<Row> {
323342
}
324343
}
325344
}
345+
346+
/// Trait for parsing a row into a custom type
347+
pub trait FromRow: Sized {
348+
/// Parse a row into a custom type
349+
fn from_row(row: Row) -> ClientResult<Self>;
350+
}
351+
352+
impl FromRow for Row {
353+
fn from_row(row: Row) -> ClientResult<Self> {
354+
Ok(row)
355+
}
356+
}
357+
358+
#[derive(Debug, PartialEq)]
359+
/// A collection of rows
360+
pub struct Rows<T: FromRow = Row>(Vec<T>);
361+
362+
impl<T: FromRow> Rows<T> {
363+
/// Consume the [`Rows`] object and get all the rows as a vector
364+
pub fn into_rows(self) -> Vec<T> {
365+
self.0
366+
}
367+
}
368+
369+
impl<T: FromRow> FromResponse for Rows<T> {
370+
fn from_response(resp: Response) -> ClientResult<Self> {
371+
match resp {
372+
Response::Rows(rows) => {
373+
let mut ret = vec![];
374+
for row in rows {
375+
ret.push(T::from_row(row)?);
376+
}
377+
Ok(Self(ret))
378+
}
379+
_ => Err(Error::ParseError(ParseError::ResponseMismatch)),
380+
}
381+
}
382+
}
383+
384+
impl<T: FromRow> Deref for Rows<T> {
385+
type Target = [T];
386+
fn deref(&self) -> &Self::Target {
387+
&self.0
388+
}
389+
}

0 commit comments

Comments
 (0)