feat: return schema and column positions with select

This commit is contained in:
Jindřich Moravec 2024-01-23 20:56:07 +01:00
parent ebabf50291
commit 1d746430d2
5 changed files with 84 additions and 43 deletions

View file

@ -1,6 +1,7 @@
use crate::type_system::Value; use crate::type_system::Value;
use std::ops::{Index, IndexMut}; use std::ops::{Index, IndexMut};
use std::slice::SliceIndex; use std::slice::SliceIndex;
use crate::restricted_row::RestrictedRow;
pub type ColumnPosition = usize; pub type ColumnPosition = usize;
@ -58,14 +59,15 @@ impl Row {
self.0.get(column_position) self.0.get(column_position)
} }
pub fn restrict_columns(&self, columns: &Vec<ColumnPosition>) -> Row { pub fn restrict_columns(&self, columns: &Vec<ColumnPosition>) -> RestrictedRow {
// If the index from `columns` is non-existant in `row`, it will just ignore it. // If the index from `columns` is non-existant in `row`, it will just ignore it.
let mut subrow: Row = Row::new(); let mut subrow: Vec<(ColumnPosition, Value)> = vec![];
for column_position in columns { for column_position in columns {
if let Some(value) = self.get(*column_position) { if let Some(value) = self.get(*column_position) {
subrow.0.push(value.clone()) subrow.push((*column_position, value.clone()));
} }
} }
subrow
subrow.into()
} }
} }

View file

@ -3,6 +3,7 @@ use std::collections::{BTreeMap, HashMap, HashSet};
use crate::error::Error; use crate::error::Error;
use crate::internals::column_index::ColumnIndex; use crate::internals::column_index::ColumnIndex;
use crate::internals::row::{ColumnPosition, Row}; use crate::internals::row::{ColumnPosition, Row};
use crate::restricted_row::RestrictedRow;
use crate::schema::{ColumnName, TableSchema, TableName}; use crate::schema::{ColumnName, TableSchema, TableName};
use crate::result::DbResult; use crate::result::DbResult;
use crate::type_system::{IndexableValue, Uuid, Value}; use crate::type_system::{IndexableValue, Uuid, Value};
@ -67,7 +68,7 @@ impl Table {
.collect() .collect()
} }
pub fn select_all_rows<'a>(&'a self, selected_column_positions: Vec<ColumnPosition>) -> impl Iterator<Item=Row> + 'a { pub fn select_all_rows<'a>(&'a self, selected_column_positions: Vec<ColumnPosition>) -> impl Iterator<Item=RestrictedRow> + 'a {
self.rows self.rows
.values() .values()
.map(move |row| row.restrict_columns(&selected_column_positions)) .map(move |row| row.restrict_columns(&selected_column_positions))
@ -78,7 +79,7 @@ impl Table {
selected_column_positions: Vec<ColumnPosition>, selected_column_positions: Vec<ColumnPosition>,
column_position: ColumnPosition, column_position: ColumnPosition,
value: Value, value: Value,
) -> DbResult<impl Iterator<Item=Row> + 'a> { ) -> DbResult<impl Iterator<Item=RestrictedRow> + 'a> {
let restrict_columns_of_row = move |row: Row| row.restrict_columns(&selected_column_positions); let restrict_columns_of_row = move |row: Row| row.restrict_columns(&selected_column_positions);
match value { match value {
Value::Indexable(value) => match self.fetch_ids_from_index(column_position, &value)? { Value::Indexable(value) => match self.fetch_ids_from_index(column_position, &value)? {

View file

@ -1,11 +1,12 @@
use crate::error::Error; use crate::error::Error;
use crate::internals::row::{ColumnPosition, Row}; use crate::internals::row::ColumnPosition;
use crate::schema::{TableName, TableSchema}; use crate::schema::{TableName, TableSchema};
use crate::internals::table::Table; use crate::internals::table::Table;
use crate::operation::{ColumnSelection, Condition, Operation}; use crate::operation::{ColumnSelection, Condition, Operation};
use crate::result::DbResult; use crate::result::DbResult;
use crate::type_system::{DbType, IndexableValue, Value}; use crate::type_system::{DbType, IndexableValue, Value};
use bimap::BiMap; use bimap::BiMap;
use crate::restricted_row::RestrictedRow;
// Use `TablePosition` as index // Use `TablePosition` as index
pub type Tables = Vec<Table>; pub type Tables = Vec<Table>;
@ -20,7 +21,7 @@ pub struct State {
// #[derive(Debug)] // #[derive(Debug)]
pub enum Response<'a> { pub enum Response<'a> {
Selected(Box<dyn Iterator<Item=Row> + 'a>), Selected(&'a TableSchema, Box<dyn Iterator<Item=RestrictedRow> + 'a>),
Inserted, Inserted,
Deleted(usize), // how many were deleted Deleted(usize), // how many were deleted
TableCreated, TableCreated,
@ -31,7 +32,7 @@ impl std::fmt::Debug for Response<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
use Response::*; use Response::*;
match self { match self {
Selected(_rows) => Selected(_schema, _rows) =>
// TODO: How can we iterate through the rows without having to take ownership of // TODO: How can we iterate through the rows without having to take ownership of
// them? // them?
f.write_str("Some rows... trust me"), f.write_str("Some rows... trust me"),
@ -99,7 +100,7 @@ impl State {
let selected_rows = match maybe_condition { let selected_rows = match maybe_condition {
None => { None => {
let x = table.select_all_rows(selected_column_positions); let x = table.select_all_rows(selected_column_positions);
Box::new(x) as Box<dyn Iterator<Item=Row> + 'a> Box::new(x) as Box<dyn Iterator<Item=RestrictedRow> + 'a>
}, },
Some(Condition::Eq(eq_column_name, value)) => { Some(Condition::Eq(eq_column_name, value)) => {
@ -112,11 +113,11 @@ impl State {
eq_column_position, eq_column_position,
value, value,
)?; )?;
Box::new(x) as Box<dyn Iterator<Item=Row> + 'a> Box::new(x) as Box<dyn Iterator<Item=RestrictedRow> + 'a>
} }
}; };
Ok(Response::Selected(selected_rows)) Ok(Response::Selected(table.schema(), selected_rows))
} }
Insert(table_name, values) => { Insert(table_name, values) => {
let table: &mut Table = self.table_from_name_mut(&table_name)?; let table: &mut Table = self.table_from_name_mut(&table_name)?;
@ -210,8 +211,8 @@ mod tests {
let response: Response = state let response: Response = state
.interpret(Operation::Select(users.clone(), ColumnSelection::All, None)) .interpret(Operation::Select(users.clone(), ColumnSelection::All, None))
.unwrap(); .unwrap();
assert!(matches!(response, Response::Selected(_))); assert!(matches!(response, Response::Selected(_, _)));
let Response::Selected(rows) = response else { let Response::Selected(schema, rows) = response else {
panic!() panic!()
}; };
let rows: Vec<_> = rows.collect(); let rows: Vec<_> = rows.collect();
@ -263,8 +264,8 @@ mod tests {
.interpret(Operation::Select(users.clone(), ColumnSelection::All, None)) .interpret(Operation::Select(users.clone(), ColumnSelection::All, None))
.unwrap(); .unwrap();
assert!(matches!(response, Response::Selected(_))); assert!(matches!(response, Response::Selected(_, _)));
let Response::Selected(rows) = response else { let Response::Selected(schema, rows) = response else {
panic!() panic!()
}; };
let rows: Vec<_> = rows.collect(); let rows: Vec<_> = rows.collect();
@ -272,9 +273,9 @@ mod tests {
let row = &rows[0]; let row = &rows[0];
assert!(row.len() == 3); assert!(row.len() == 3);
assert!(row[0] == id); assert!(row[0].1 == id);
assert!(row[1] == name); assert!(row[1].1 == name);
assert!(row[2] == age); assert!(row[2].1 == age);
} }
#[test] #[test]
@ -328,24 +329,25 @@ mod tests {
{ {
let response: Response = state.interpret(Select(users.clone(), All, None)).unwrap(); let response: Response = state.interpret(Select(users.clone(), All, None)).unwrap();
assert!(matches!(response, Response::Selected(_))); assert!(matches!(response, Response::Selected(_, _)));
let Response::Selected(rows) = response else { let Response::Selected(_, rows) = response else {
panic!() panic!()
}; };
let rows: Vec<_> = rows.collect();
let rows: Vec<_> = rows.collect();
assert!(rows.len() == 2); assert!(rows.len() == 2);
let row0 = &rows[0]; let row0 = &rows[0];
let row1 = &rows[1]; let row1 = &rows[1];
assert!(row0.len() == 3); assert!(row0.len() == 3);
assert!(row0[0] == id0); assert!(row0[0].1 == id0);
assert!(row0[1] == name0); assert!(row0[1].1 == name0);
assert!(row0[2] == age0); assert!(row0[2].1 == age0);
assert!(row1.len() == 3); assert!(row1.len() == 3);
assert!(row1[0] == id1); assert!(row1[0].1 == id1);
assert!(row1[1] == name1); assert!(row1[1].1 == name1);
assert!(row1[2] == age1); assert!(row1[2].1 == age1);
} }
{ {
@ -356,8 +358,8 @@ mod tests {
Some(Eq("id".to_string(), id0.clone())), Some(Eq("id".to_string(), id0.clone())),
)) ))
.unwrap(); .unwrap();
assert!(matches!(response, Response::Selected(_))); assert!(matches!(response, Response::Selected(_, _)));
let Response::Selected(rows) = response else { let Response::Selected(_, rows) = response else {
panic!() panic!()
}; };
let rows: Vec<_> = rows.collect(); let rows: Vec<_> = rows.collect();
@ -365,9 +367,9 @@ mod tests {
let row0 = &rows[0]; let row0 = &rows[0];
assert!(row0.len() == 3); assert!(row0.len() == 3);
assert!(row0[0] == id0); assert!(row0[0].1 == id0);
assert!(row0[1] == name0); assert!(row0[1].1 == name0);
assert!(row0[2] == age0); assert!(row0[2].1 == age0);
} }
{ {
@ -378,8 +380,8 @@ mod tests {
Some(Eq("id".to_string(), id0.clone())), Some(Eq("id".to_string(), id0.clone())),
)) ))
.unwrap(); .unwrap();
assert!(matches!(response, Response::Selected(_))); assert!(matches!(response, Response::Selected(_, _)));
let Response::Selected(rows) = response else { let Response::Selected(_, rows) = response else {
panic!() panic!()
}; };
let rows: Vec<_> = rows.collect(); let rows: Vec<_> = rows.collect();
@ -387,8 +389,8 @@ mod tests {
let row0 = &rows[0]; let row0 = &rows[0];
assert!(row0.len() == 2); assert!(row0.len() == 2);
assert!(row0[0] == name0); assert!(row0[0].1 == name0);
assert!(row0[1] == id0); assert!(row0[1].1 == id0);
} }
} }
@ -452,8 +454,8 @@ mod tests {
let response: Response = state.interpret(Select(users.clone(), All, None)).unwrap(); let response: Response = state.interpret(Select(users.clone(), All, None)).unwrap();
assert!(matches!(response, Response::Selected(_))); assert!(matches!(response, Response::Selected(_, _)));
let Response::Selected(rows) = response else { let Response::Selected(_, rows) = response else {
panic!() panic!()
}; };
let rows: Vec<_> = rows.collect(); let rows: Vec<_> = rows.collect();
@ -461,9 +463,9 @@ mod tests {
let row = &rows[0]; let row = &rows[0];
assert!(row.len() == 3); assert!(row.len() == 3);
assert!(row[0] == id1); assert!(row[0].1 == id1);
assert!(row[1] == name1); assert!(row[1].1 == name1);
assert!(row[2] == age1); assert!(row[2].1 == age1);
} }
#[test] #[test]

View file

@ -5,3 +5,4 @@ pub mod type_system;
mod error; mod error;
mod internals; mod internals;
mod result; mod result;
pub mod restricted_row;

View file

@ -0,0 +1,35 @@
use std::ops::Index;
use std::slice::SliceIndex;
use crate::internals::row::ColumnPosition;
use crate::type_system::Value;
#[derive(Debug, Clone)]
pub struct RestrictedRow(Vec<(ColumnPosition, Value)>);
impl<Idx> Index<Idx> for RestrictedRow
where
Idx: SliceIndex<[(ColumnPosition, Value)]>,
{
type Output = Idx::Output;
fn index(&self, index: Idx) -> &Self::Output {
&self.0[index]
}
}
impl From<Vec<(ColumnPosition, Value)>> for RestrictedRow {
fn from(v: Vec<(ColumnPosition, Value)>) -> Self {
RestrictedRow(v)
}
}
impl RestrictedRow {
pub fn len(&self) -> usize {
self.0.len()
}
pub fn iter(&self) -> impl Iterator<Item=&(ColumnPosition, Value)> {
self.0.iter()
}
}