use std::sync::Arc;
use super::error::{Error, Result};
use super::value::Value;
#[derive(Debug, Clone, PartialEq)]
pub struct Column {
pub name: String,
pub declared_type: Option<String>,
pub nullable: bool,
}
#[derive(Debug, Clone)]
pub struct Row {
pub columns: Vec<Column>,
pub values: Vec<Value>,
}
impl Row {
#[inline]
pub fn get_i64(&self, index: impl ColumnIndex) -> Result<i64> {
match self.values.get(index.index(&self.columns)?) {
Some(Value::I64(value)) => Ok(*value),
Some(Value::Null) => Err(Error::new("column is null")),
Some(other) => Err(Error::new(format!("column is not i64: {other:?}"))),
None => Err(Error::new("column index out of bounds")),
}
}
#[inline]
pub fn get_f64(&self, index: impl ColumnIndex) -> Result<f64> {
match self.values.get(index.index(&self.columns)?) {
Some(Value::F64(value)) => Ok(*value),
Some(Value::I64(value)) => Ok(*value as f64),
Some(Value::Null) => Err(Error::new("column is null")),
Some(other) => Err(Error::new(format!("column is not f64: {other:?}"))),
None => Err(Error::new("column index out of bounds")),
}
}
#[inline]
pub fn get_str(&self, index: impl ColumnIndex) -> Result<&str> {
match self.values.get(index.index(&self.columns)?) {
Some(Value::String(value)) => Ok(value),
Some(Value::Null) => Err(Error::new("column is null")),
Some(other) => Err(Error::new(format!("column is not text: {other:?}"))),
None => Err(Error::new("column index out of bounds")),
}
}
#[inline]
pub fn get_bytes(&self, index: impl ColumnIndex) -> Result<&[u8]> {
match self.values.get(index.index(&self.columns)?) {
Some(Value::Bytes(value)) => Ok(value),
Some(Value::String(value)) => Ok(value.as_bytes()),
Some(Value::Null) => Err(Error::new("column is null")),
Some(other) => Err(Error::new(format!("column is not bytes: {other:?}"))),
None => Err(Error::new("column index out of bounds")),
}
}
}
pub struct RowRef<'a> {
columns: &'a [Column],
values: &'a [Value],
}
impl<'a> RowRef<'a> {
#[inline]
pub fn get_i64(&self, index: impl ColumnIndex) -> Result<i64> {
match self.values.get(index.index(self.columns)?) {
Some(Value::I64(value)) => Ok(*value),
Some(Value::Null) => Err(Error::new("column is null")),
Some(other) => Err(Error::new(format!("column is not i64: {other:?}"))),
None => Err(Error::new("column index out of bounds")),
}
}
#[inline]
pub fn get_f64(&self, index: impl ColumnIndex) -> Result<f64> {
match self.values.get(index.index(self.columns)?) {
Some(Value::F64(value)) => Ok(*value),
Some(Value::I64(value)) => Ok(*value as f64),
Some(Value::Null) => Err(Error::new("column is null")),
Some(other) => Err(Error::new(format!("column is not f64: {other:?}"))),
None => Err(Error::new("column index out of bounds")),
}
}
#[inline]
pub fn get_str(&self, index: impl ColumnIndex) -> Result<&str> {
match self.values.get(index.index(self.columns)?) {
Some(Value::String(value)) => Ok(value),
Some(Value::Null) => Err(Error::new("column is null")),
Some(other) => Err(Error::new(format!("column is not text: {other:?}"))),
None => Err(Error::new("column index out of bounds")),
}
}
#[inline]
pub fn get_bytes(&self, index: impl ColumnIndex) -> Result<&[u8]> {
match self.values.get(index.index(self.columns)?) {
Some(Value::Bytes(value)) => Ok(value),
Some(Value::String(value)) => Ok(value.as_bytes()),
Some(Value::Null) => Err(Error::new("column is null")),
Some(other) => Err(Error::new(format!("column is not bytes: {other:?}"))),
None => Err(Error::new("column index out of bounds")),
}
}
#[inline]
pub fn to_owned(&self) -> Row {
Row {
columns: self.columns.to_vec(),
values: self.values.to_vec(),
}
}
}
pub trait ColumnIndex {
fn index(&self, columns: &[Column]) -> Result<usize>;
}
impl ColumnIndex for usize {
fn index(&self, columns: &[Column]) -> Result<usize> {
if *self < columns.len() {
Ok(*self)
} else {
Err(Error::new(format!("column {} out of bounds", self)))
}
}
}
impl ColumnIndex for &str {
fn index(&self, columns: &[Column]) -> Result<usize> {
columns
.iter()
.position(|column| column.name == *self)
.ok_or_else(|| Error::new(format!("unknown column {}", self)))
}
}
pub struct ResultSet {
columns: Arc<[Column]>,
rows: Vec<Vec<Value>>,
pos: usize,
}
impl ResultSet {
pub(crate) fn new(columns: Vec<Column>, rows: Vec<Vec<Value>>) -> Self {
Self {
columns: Arc::from(columns),
rows,
pos: 0,
}
}
#[inline]
pub fn columns(&self) -> &[Column] {
&self.columns
}
pub async fn next(&mut self) -> Result<Option<RowRef<'_>>> {
if self.pos >= self.rows.len() {
return Ok(None);
}
let values = &self.rows[self.pos];
self.pos += 1;
Ok(Some(RowRef {
columns: &self.columns,
values,
}))
}
}