Skip to content

Commit da268c0

Browse files
committed
Add row struct
1 parent f761334 commit da268c0

File tree

8 files changed

+246
-80
lines changed

8 files changed

+246
-80
lines changed

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ homepage = "hhttps://github.com/crossdb-org/crossdb-rust"
99
repository = "https://github.com/crossdb-org/crossdb-rust.git"
1010

1111
[dependencies]
12+
serde = { version = "1.0.210", features = ["derive"] }
1213
thiserror = "1.0"
1314

1415
[build-dependencies]

README.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ fn main() {
1212
let conn = Connection::open_with_memory().unwrap();
1313
let mut rst = conn.exec("select * from system.databases;").unwrap();
1414

15-
for i in 0..rst.column_count() {
16-
println!("Column {i}: {} {}", rst.column_name(i), rst.column_type(i));
15+
for (name, datatype) in rst.columns() {
16+
println!("Column : {} {}", name, datatype);
1717
}
1818

1919
while let Some(row) = rst.fetch_row() {
20-
dbg!(row);
20+
dbg!(row.values());
2121
}
2222
}
2323
```

examples/basic.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ fn main() {
44
let conn = Connection::open("test.db").unwrap();
55
let mut rst = conn.exec("select * FROM system.databases;").unwrap();
66

7-
for i in 0..rst.column_count() {
8-
println!("Column {i}: {} {}", rst.column_name(i), rst.column_type(i));
7+
for (name, datatype) in rst.columns() {
8+
println!("Column : {} {}", name, datatype);
99
}
1010

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

src/column.rs

+107-50
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
use crate::*;
2+
use std::rc::Rc;
3+
use std::slice::Iter;
24

35
// https://crossdb.org/client/api-c/#xdb_type_t
46
#[derive(Debug, Clone, Copy)]
5-
pub enum ColumnType {
7+
pub enum DataType {
68
Null,
79
TinyInt,
810
SmallInt,
@@ -22,65 +24,120 @@ pub enum ColumnType {
2224
Max,
2325
}
2426

25-
impl From<u32> for ColumnType {
26-
#[allow(non_upper_case_globals)]
27-
fn from(value: u32) -> Self {
28-
match value {
29-
xdb_type_t_XDB_TYPE_NULL => ColumnType::Null,
30-
xdb_type_t_XDB_TYPE_TINYINT => ColumnType::TinyInt,
31-
xdb_type_t_XDB_TYPE_SMALLINT => ColumnType::SmallInt,
32-
xdb_type_t_XDB_TYPE_INT => ColumnType::Int,
33-
xdb_type_t_XDB_TYPE_BIGINT => ColumnType::BigInt,
34-
xdb_type_t_XDB_TYPE_UTINYINT => ColumnType::UTinyInt,
35-
xdb_type_t_XDB_TYPE_USMALLINT => ColumnType::USmallInt,
36-
xdb_type_t_XDB_TYPE_UINT => ColumnType::UInt,
37-
xdb_type_t_XDB_TYPE_UBIGINT => ColumnType::UBigInt,
38-
xdb_type_t_XDB_TYPE_FLOAT => ColumnType::Float,
39-
xdb_type_t_XDB_TYPE_DOUBLE => ColumnType::Double,
40-
xdb_type_t_XDB_TYPE_TIMESTAMP => ColumnType::Timestamp,
41-
xdb_type_t_XDB_TYPE_CHAR => ColumnType::Char,
42-
xdb_type_t_XDB_TYPE_BINARY => ColumnType::Binary,
43-
xdb_type_t_XDB_TYPE_VCHAR => ColumnType::VChar,
44-
xdb_type_t_XDB_TYPE_VBINARY => ColumnType::VBinary,
45-
xdb_type_t_XDB_TYPE_MAX => ColumnType::Max,
46-
_ => unreachable!(),
27+
impl Display for DataType {
28+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29+
match self {
30+
DataType::Null => write!(f, "NULL"),
31+
DataType::TinyInt => write!(f, "TINYINT"),
32+
DataType::SmallInt => write!(f, "SMALLINT"),
33+
DataType::Int => write!(f, "INT"),
34+
DataType::BigInt => write!(f, "BIGINT"),
35+
DataType::UTinyInt => write!(f, "UTINYINT"),
36+
DataType::USmallInt => write!(f, "USMALLINT"),
37+
DataType::UInt => write!(f, "UINT"),
38+
DataType::UBigInt => write!(f, "UBIGINT"),
39+
DataType::Float => write!(f, "FLOAT"),
40+
DataType::Double => write!(f, "DOUBLE"),
41+
DataType::Timestamp => write!(f, "TIMESTAMP"),
42+
DataType::Char => write!(f, "CHAR"),
43+
DataType::Binary => write!(f, "BINARY"),
44+
DataType::VChar => write!(f, "VCHAR"),
45+
DataType::VBinary => write!(f, "VBINARY"),
46+
DataType::Max => write!(f, "MAX"),
4747
}
4848
}
4949
}
5050

51-
impl Display for ColumnType {
52-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
53-
match self {
54-
ColumnType::Null => write!(f, "NULL"),
55-
ColumnType::TinyInt => write!(f, "TINYINT"),
56-
ColumnType::SmallInt => write!(f, "SMALLINT"),
57-
ColumnType::Int => write!(f, "INT"),
58-
ColumnType::BigInt => write!(f, "BIGINT"),
59-
ColumnType::UTinyInt => write!(f, "UTINYINT"),
60-
ColumnType::USmallInt => write!(f, "USMALLINT"),
61-
ColumnType::UInt => write!(f, "UINT"),
62-
ColumnType::UBigInt => write!(f, "UBIGINT"),
63-
ColumnType::Float => write!(f, "FLOAT"),
64-
ColumnType::Double => write!(f, "DOUBLE"),
65-
ColumnType::Timestamp => write!(f, "TIMESTAMP"),
66-
ColumnType::Char => write!(f, "CHAR"),
67-
ColumnType::Binary => write!(f, "BINARY"),
68-
ColumnType::VChar => write!(f, "VCHAR"),
69-
ColumnType::VBinary => write!(f, "VBINARY"),
70-
ColumnType::Max => write!(f, "MAX"),
51+
impl DataType {
52+
#[allow(non_upper_case_globals)]
53+
unsafe fn from_meta(meta: u64, col: u16) -> Self {
54+
let t = xdb_column_type(meta, col);
55+
match t {
56+
xdb_type_t_XDB_TYPE_NULL => Self::Null,
57+
xdb_type_t_XDB_TYPE_TINYINT => Self::TinyInt,
58+
xdb_type_t_XDB_TYPE_SMALLINT => Self::SmallInt,
59+
xdb_type_t_XDB_TYPE_INT => Self::Int,
60+
xdb_type_t_XDB_TYPE_BIGINT => Self::BigInt,
61+
xdb_type_t_XDB_TYPE_UTINYINT => Self::UTinyInt,
62+
xdb_type_t_XDB_TYPE_USMALLINT => Self::USmallInt,
63+
xdb_type_t_XDB_TYPE_UINT => Self::UInt,
64+
xdb_type_t_XDB_TYPE_UBIGINT => Self::UBigInt,
65+
xdb_type_t_XDB_TYPE_FLOAT => Self::Float,
66+
xdb_type_t_XDB_TYPE_DOUBLE => Self::Double,
67+
xdb_type_t_XDB_TYPE_TIMESTAMP => Self::Timestamp,
68+
xdb_type_t_XDB_TYPE_CHAR => Self::Char,
69+
xdb_type_t_XDB_TYPE_BINARY => Self::Binary,
70+
xdb_type_t_XDB_TYPE_VCHAR => Self::VChar,
71+
xdb_type_t_XDB_TYPE_VBINARY => Self::VBinary,
72+
xdb_type_t_XDB_TYPE_MAX => Self::Max,
73+
_ => unreachable!(),
7174
}
7275
}
7376
}
7477

75-
impl ColumnType {
76-
pub(crate) fn all(res: &xdb_res_t) -> Vec<Self> {
77-
let mut vec = Vec::with_capacity(res.col_count as usize);
78-
for i in 0..vec.capacity() {
78+
#[derive(Debug, Clone)]
79+
pub struct Columns {
80+
inner: Rc<Vec<(String, DataType)>>,
81+
}
82+
83+
impl Columns {
84+
pub(crate) unsafe fn from_res(ptr: *mut xdb_res_t) -> Self {
85+
let res = *ptr;
86+
let mut columns = Vec::with_capacity(res.col_count as usize);
87+
for i in 0..res.col_count {
7988
unsafe {
80-
let t = xdb_column_type(res.col_meta, i as u16);
81-
vec.push(Self::from(t));
89+
let name = CStr::from_ptr(xdb_column_name(res.col_meta, i))
90+
.to_str()
91+
.unwrap()
92+
.to_string();
93+
let datatype = DataType::from_meta(res.col_meta, i);
94+
columns.push((name, datatype));
8295
}
8396
}
84-
vec
97+
Self {
98+
inner: Rc::new(columns),
99+
}
100+
}
101+
102+
pub fn len(&self) -> usize {
103+
self.inner.len()
104+
}
105+
106+
pub fn name(&self, i: usize) -> &str {
107+
self.inner[i].0.as_str()
108+
}
109+
110+
pub fn datatype(&self, i: usize) -> DataType {
111+
self.inner[i].1
112+
}
113+
114+
pub fn iter(&self) -> ColumnsIter {
115+
ColumnsIter {
116+
inner: self.inner.iter(),
117+
}
118+
}
119+
120+
pub fn into_inner(self) -> Option<Vec<(String, DataType)>> {
121+
Rc::into_inner(self.inner)
122+
}
123+
}
124+
125+
pub struct ColumnsIter<'a> {
126+
inner: Iter<'a, (String, DataType)>,
127+
}
128+
129+
impl<'a> Iterator for ColumnsIter<'a> {
130+
type Item = &'a (String, DataType);
131+
fn next(&mut self) -> Option<Self::Item> {
132+
self.inner.next()
133+
}
134+
}
135+
136+
impl<'a> IntoIterator for &'a Columns {
137+
type Item = &'a (String, DataType);
138+
type IntoIter = ColumnsIter<'a>;
139+
140+
fn into_iter(self) -> Self::IntoIter {
141+
self.iter()
85142
}
86143
}

src/de.rs

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
use crate::Row;
2+
use serde::de::{value::Error as DeError, Error, Visitor};
3+
use serde::Deserializer;
4+
5+
pub(crate) struct RowDeserializer<'de> {
6+
pub(crate) row: &'de Row<'de>,
7+
}
8+
9+
impl<'de> Deserializer<'de> for RowDeserializer<'de> {
10+
type Error = DeError;
11+
12+
fn deserialize_any<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
13+
where
14+
V: Visitor<'de>,
15+
{
16+
Err(DeError::custom("Expects a struct"))
17+
}
18+
19+
fn deserialize_struct<V>(
20+
self,
21+
_name: &'static str,
22+
_fields: &'static [&'static str],
23+
_visitor: V,
24+
) -> Result<V::Value, Self::Error>
25+
where
26+
V: Visitor<'de>,
27+
{
28+
todo!()
29+
}
30+
31+
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
34+
tuple_struct map enum identifier ignored_any
35+
}
36+
}

src/lib.rs

+28-16
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,14 @@ mod crossdb_sys {
1010
}
1111

1212
mod column;
13+
mod de;
1314
mod error;
15+
mod row;
1416
mod value;
1517

16-
pub use column::ColumnType;
18+
pub use column::{Columns, DataType};
1719
pub use error::{Error, Result};
20+
pub use row::Row;
1821
pub use value::Value;
1922

2023
use crossdb_sys::*;
@@ -56,8 +59,11 @@ impl Connection {
5659
let msg = CStr::from_ptr(xdb_errmsg(ptr)).to_str()?.to_string();
5760
return Err(Error::Query(res.errcode, msg));
5861
}
59-
let types = ColumnType::all(&res);
60-
Ok(ExecResult { res, ptr, types })
62+
Ok(ExecResult {
63+
res,
64+
ptr,
65+
columns: Columns::from_res(ptr),
66+
})
6167
}
6268
}
6369

@@ -109,8 +115,11 @@ impl Stmt {
109115
let msg = CStr::from_ptr(xdb_errmsg(ptr)).to_str()?.to_string();
110116
return Err(Error::Query(res.errcode, msg));
111117
}
112-
let types = ColumnType::all(&res);
113-
Ok(ExecResult { res, ptr, types })
118+
Ok(ExecResult {
119+
res,
120+
ptr,
121+
columns: Columns::from_res(ptr),
122+
})
114123
}
115124
}
116125
}
@@ -119,7 +128,7 @@ impl Stmt {
119128
pub struct ExecResult {
120129
res: xdb_res_t,
121130
ptr: *mut xdb_res_t,
122-
types: Vec<ColumnType>,
131+
columns: Columns,
123132
}
124133

125134
impl Drop for ExecResult {
@@ -143,27 +152,30 @@ impl ExecResult {
143152
self.res.affected_rows
144153
}
145154

146-
pub fn column_name(&self, i: usize) -> &str {
147-
unsafe {
148-
let name = xdb_column_name(self.res.col_meta, i as u16);
149-
CStr::from_ptr(name).to_str().unwrap()
150-
}
155+
pub fn columns(&self) -> &Columns {
156+
&self.columns
151157
}
152158

153-
pub fn column_type(&self, i: usize) -> ColumnType {
154-
self.types[i]
159+
pub fn fetch_row(&mut self) -> Option<Row<'_>> {
160+
let columns = self.columns.clone();
161+
let values = self.inner_fetch_row_values()?;
162+
Some(Row { columns, values })
155163
}
156164

157-
pub fn fetch_row(&mut self) -> Option<Vec<Value<'_>>> {
165+
fn inner_fetch_row_values(&mut self) -> Option<Vec<Value<'_>>> {
158166
unsafe {
159167
let row = xdb_fetch_row(self.ptr);
160168
if row.is_null() {
161169
return None;
162170
}
163171
let mut values = Vec::with_capacity(self.column_count());
164172
for col in 0..self.column_count() {
165-
let value =
166-
Value::from_result(self.res.col_meta, row, col as u16, self.column_type(col));
173+
let value = Value::from_result(
174+
self.res.col_meta,
175+
row,
176+
col as u16,
177+
self.columns.datatype(col),
178+
);
167179
values.push(value);
168180
}
169181
Some(values)

0 commit comments

Comments
 (0)