Skip to content

Commit 141e496

Browse files
committed
Support serde deserialize row
1 parent 0a0521b commit 141e496

File tree

6 files changed

+188
-38
lines changed

6 files changed

+188
-38
lines changed

README.md

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,28 +6,36 @@ crossdb = { git = "https://github.com/crossdb-org/crossdb-rust" }
66
```
77

88
```rs
9-
use crossdb::{Connection, Result};
9+
#[derive(Debug, serde::Deserialize)]
10+
struct User {
11+
id: i32,
12+
name: String,
13+
age: Option<i8>,
14+
}
1015

11-
fn main() -> Result<()> {
12-
let mut conn = Connection::open_with_memory()?;
16+
fn main() -> crossdb::Result<()> {
17+
let mut conn = crossdb::Connection::open_with_memory()?;
1318

14-
conn.execute("create table if not exists users(id int, name CHAR(255));")?;
15-
let stmt = conn.prepare("insert into users (id, name) values (?, ?);")?;
19+
conn.execute("CREATE TABLE IF NOT EXISTS users(id INT, name CHAR(255), age TINYINT);")?;
20+
let stmt = conn.prepare("INSERT INTO users (id, name, age) values (?, ?, ?);")?;
1621

17-
stmt.execute((1, "Alex"))?;
18-
stmt.execute((2, "Thorne"))?;
19-
stmt.execute((3, "Ryder"))?;
22+
stmt.execute((1, "Alex", 18))?;
23+
stmt.execute((2, "Thorne", 22))?;
24+
stmt.execute((3, "Ryder", 36))?;
2025

21-
let mut query = conn.query("select * from users;")?;
26+
let mut query = conn.query("SELECT * FROM users;")?;
2227

23-
for (name, datatype) in query.columns() {
24-
println!("Column : {} {}", name, datatype);
28+
for col in query.columns() {
29+
println!("Column: {col}");
2530
}
2631

27-
while let Some(row) = query.fetch_row() {
28-
println!("User: {}, Name: {}", row.get("id"), row.get("name"));
32+
while let Some(user) = query.fetch_row_as::<User>() {
33+
dbg!(user);
2934
}
3035

36+
let affected_rows = conn.execute("DELETE FROM users;")?;
37+
assert_eq!(affected_rows, 3);
38+
3139
Ok(())
3240
}
3341
```

examples/basic.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ fn main() {
44
let conn = Connection::open("test").unwrap();
55
let mut query = conn.query("select * from system.databases;").unwrap();
66

7-
for (name, datatype) in query.columns() {
8-
println!("Column : {} {}", name, datatype);
7+
for col in query.columns() {
8+
println!("Column: {col}");
99
}
1010

1111
while let Some(row) = query.fetch_row() {
12-
dbg!(row.values());
12+
dbg!(row);
1313
}
1414
}

src/column.rs

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ impl DataType {
7777

7878
#[derive(Debug, Clone)]
7979
pub struct Columns {
80-
inner: Rc<Vec<(String, DataType)>>,
80+
inner: Rc<Vec<Column>>,
8181
}
8282

8383
impl Columns {
@@ -91,7 +91,7 @@ impl Columns {
9191
.unwrap()
9292
.to_string();
9393
let datatype = DataType::from_meta(res.col_meta, i);
94-
columns.push((name, datatype));
94+
columns.push(Column::new(name, datatype));
9595
}
9696
}
9797
Self {
@@ -104,11 +104,11 @@ impl Columns {
104104
}
105105

106106
pub fn name(&self, i: usize) -> &str {
107-
self.inner[i].0.as_str()
107+
self.inner[i].name()
108108
}
109109

110110
pub fn datatype(&self, i: usize) -> DataType {
111-
self.inner[i].1
111+
self.inner[i].datatype()
112112
}
113113

114114
pub fn iter(&self) -> ColumnsIter {
@@ -117,27 +117,53 @@ impl Columns {
117117
}
118118
}
119119

120-
pub fn into_inner(self) -> Option<Vec<(String, DataType)>> {
120+
pub fn into_inner(self) -> Option<Vec<Column>> {
121121
Rc::into_inner(self.inner)
122122
}
123123
}
124124

125125
pub struct ColumnsIter<'a> {
126-
inner: Iter<'a, (String, DataType)>,
126+
inner: Iter<'a, Column>,
127127
}
128128

129129
impl<'a> Iterator for ColumnsIter<'a> {
130-
type Item = &'a (String, DataType);
130+
type Item = &'a Column;
131131
fn next(&mut self) -> Option<Self::Item> {
132132
self.inner.next()
133133
}
134134
}
135135

136136
impl<'a> IntoIterator for &'a Columns {
137-
type Item = &'a (String, DataType);
137+
type Item = &'a Column;
138138
type IntoIter = ColumnsIter<'a>;
139139

140140
fn into_iter(self) -> Self::IntoIter {
141141
self.iter()
142142
}
143143
}
144+
145+
#[derive(Debug, Clone)]
146+
pub struct Column {
147+
name: String,
148+
datatype: DataType,
149+
}
150+
151+
impl Column {
152+
pub fn new(name: String, datatype: DataType) -> Self {
153+
Self { name, datatype }
154+
}
155+
156+
pub fn name(&self) -> &str {
157+
self.name.as_str()
158+
}
159+
160+
pub fn datatype(&self) -> DataType {
161+
self.datatype
162+
}
163+
}
164+
165+
impl Display for Column {
166+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
167+
write!(f, "{} [{}]", self.name, self.datatype)
168+
}
169+
}

src/de.rs

Lines changed: 125 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,18 @@
1-
use crate::Row;
2-
use serde::de::{value::Error as DeError, Error, Visitor};
3-
use serde::Deserializer;
1+
use crate::{Row, Value};
2+
use serde::de::{
3+
self, value::Error as DeError, DeserializeSeed, Deserializer, Error, IntoDeserializer,
4+
MapAccess, Visitor,
5+
};
46

57
pub(crate) struct RowDeserializer<'de> {
6-
pub(crate) row: &'de Row<'de>,
8+
row: &'de Row<'de>,
9+
index: usize,
10+
}
11+
12+
impl<'de> RowDeserializer<'de> {
13+
pub(crate) fn new(row: &'de Row<'de>) -> Self {
14+
Self { row, index: 0 }
15+
}
716
}
817

918
impl<'de> Deserializer<'de> for RowDeserializer<'de> {
@@ -20,17 +29,125 @@ impl<'de> Deserializer<'de> for RowDeserializer<'de> {
2029
self,
2130
_name: &'static str,
2231
_fields: &'static [&'static str],
23-
_visitor: V,
32+
visitor: V,
2433
) -> Result<V::Value, Self::Error>
2534
where
2635
V: Visitor<'de>,
2736
{
28-
todo!()
37+
visitor.visit_map(self)
2938
}
3039

3140
serde::forward_to_deserialize_any! {
32-
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
33-
bytes byte_buf option unit unit_struct newtype_struct seq tuple
41+
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string option
42+
bytes byte_buf unit unit_struct newtype_struct seq tuple
3443
tuple_struct map enum identifier ignored_any
3544
}
3645
}
46+
47+
impl<'de> MapAccess<'de> for RowDeserializer<'de> {
48+
type Error = DeError;
49+
50+
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
51+
where
52+
K: DeserializeSeed<'de>,
53+
{
54+
if self.index >= self.row.columns.len() {
55+
return Ok(None);
56+
}
57+
let name = self.row.columns.name(self.index);
58+
seed.deserialize(name.into_deserializer()).map(Some)
59+
}
60+
61+
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
62+
where
63+
V: DeserializeSeed<'de>,
64+
{
65+
if self.index >= self.row.values.len() {
66+
return Err(de::Error::custom("Value index out of bounds"));
67+
}
68+
let value = &self.row.values[self.index];
69+
let result = seed.deserialize(ValueDeserializer(value));
70+
self.index += 1;
71+
result
72+
}
73+
}
74+
75+
struct ValueDeserializer<'a>(&'a Value<'a>);
76+
77+
impl<'de> Deserializer<'de> for ValueDeserializer<'de> {
78+
type Error = DeError;
79+
80+
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
81+
where
82+
V: Visitor<'de>,
83+
{
84+
match *self.0 {
85+
Value::Null => visitor.visit_none(),
86+
Value::I8(v) => visitor.visit_i8(v),
87+
Value::I16(v) => visitor.visit_i16(v),
88+
Value::I32(v) => visitor.visit_i32(v),
89+
Value::I64(v) => visitor.visit_i64(v),
90+
Value::F32(v) => visitor.visit_f32(v),
91+
Value::F64(v) => visitor.visit_f64(v),
92+
Value::Char(v) => visitor.visit_str(v),
93+
}
94+
}
95+
96+
fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Self::Error>
97+
where
98+
V: Visitor<'de>,
99+
{
100+
visitor.visit_unit()
101+
}
102+
103+
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
104+
where
105+
V: Visitor<'de>,
106+
{
107+
match *self.0 {
108+
Value::Null => visitor.visit_none(),
109+
_ => visitor.visit_some(self),
110+
}
111+
}
112+
113+
serde::forward_to_deserialize_any! {
114+
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
115+
bytes byte_buf unit_struct newtype_struct seq tuple
116+
tuple_struct map enum identifier ignored_any struct
117+
}
118+
}
119+
120+
#[cfg(test)]
121+
mod tests {
122+
use super::*;
123+
use serde::Deserialize;
124+
use std::fmt::Debug;
125+
126+
#[test]
127+
fn test_deserialize_value() {
128+
fn de<'a, T: Debug + PartialEq + Deserialize<'a>>(v: &'a Value<'a>, expected: T) {
129+
let v = ValueDeserializer(v);
130+
assert_eq!(Deserialize::deserialize(v), Ok(expected));
131+
}
132+
133+
de(&Value::Null, ());
134+
de(&Value::Null, None::<i8>);
135+
de(&Value::Null, None::<String>);
136+
137+
de(&Value::I8(1), 1i8);
138+
de(&Value::I8(1), Some(1i8));
139+
de(&Value::I8(1), Some(1_u128));
140+
141+
de(&Value::I16(1), 1i16);
142+
de(&Value::I16(1), Some(1i16));
143+
de(&Value::I16(1), Some(1_u128));
144+
145+
de(&Value::Char("Hello"), String::from("Hello"));
146+
de(&Value::Char("Hello"), Some(String::from("Hello")));
147+
}
148+
149+
#[test]
150+
fn test_deserialize_row() {
151+
// TODO
152+
}
153+
}

src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ mod row;
1717
mod statement;
1818
mod value;
1919

20-
pub use column::{Columns, DataType};
20+
pub use column::{Column, Columns, ColumnsIter, DataType};
2121
pub use error::{Error, Result};
2222
pub use params::{IntoParams, Params, Value as ParamValue};
2323
pub use row::{IntoValueIndex, Row, ValueIndex};
@@ -170,7 +170,7 @@ impl Query {
170170
self.fetch_row().map(|row| row.deserialize())
171171
}
172172

173-
pub fn fetch_rows_as<'a, T: DeserializeOwned>(mut self) -> Result<Vec<T>, DeError> {
173+
pub fn fetch_rows_as<'a, T: DeserializeOwned>(&mut self) -> Result<Vec<T>, DeError> {
174174
let mut rows = Vec::with_capacity(self.row_count());
175175
while let Some(row) = self.fetch_row() {
176176
rows.push(row.deserialize()?);

src/row.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,21 @@ impl Row<'_> {
1717
}
1818

1919
pub fn get<'i>(&self, index: impl IntoValueIndex<'i>) -> &Value<'_> {
20-
unsafe { self.try_get(index).unwrap_unchecked() }
20+
self.try_get(index).expect("Row index out of bounds")
2121
}
2222

2323
pub fn try_get<'i>(&self, index: impl IntoValueIndex<'i>) -> Option<&Value<'_>> {
2424
match index.into_index() {
2525
ValueIndex::ColumnName(name) => {
26-
let i = self.columns.iter().position(|(n, _)| n == name)?;
26+
let i = self.columns.iter().position(|c| c.name() == name)?;
2727
self.values.get(i)
2828
}
2929
ValueIndex::ColumnIndex(i) => self.values.get(i),
3030
}
3131
}
3232

3333
pub fn deserialize<T: DeserializeOwned>(&self) -> Result<T, DeError> {
34-
let deserializer = RowDeserializer { row: self };
35-
T::deserialize(deserializer)
34+
T::deserialize(RowDeserializer::new(self))
3635
}
3736
}
3837

0 commit comments

Comments
 (0)