diff --git a/src/columnvalueops.rs b/src/columnvalueops.rs new file mode 100644 index 0000000..99adf24 --- /dev/null +++ b/src/columnvalueops.rs @@ -0,0 +1,15 @@ +use std::borrow::Cow; + +pub trait ColumnValueOps: Sized { + fn from_string_literal(s: Cow) -> Result>; + fn from_number_literal(s: Cow) -> Result>; + + /// Used for predicate logic (such as the entire WHERE expression). + fn tests_true(&self) -> bool; + + fn equals(&self, rhs: &Self) -> Self; + fn not_equals(&self, rhs: &Self) -> Self; + fn and(&self, rhs: &Self) -> Self; + fn or(&self, rhs: &Self) -> Self; + fn concat(&self, rhs: &Self) -> Self; +} diff --git a/src/databaseinfo.rs b/src/databaseinfo.rs index 09a3a87..5a991f6 100644 --- a/src/databaseinfo.rs +++ b/src/databaseinfo.rs @@ -1,6 +1,6 @@ +use columnvalueops::ColumnValueOps; use identifier::Identifier; use types::DbType; -use std::borrow::Cow; use std::fmt; /// A read-only interface to information about the database schema. @@ -32,17 +32,3 @@ pub trait ColumnInfo { fn get_name(&self) -> &Identifier; fn get_dbtype(&self) -> &DbType; } - -pub trait ColumnValueOps: Sized { - fn from_string_literal(s: Cow) -> Result>; - fn from_number_literal(s: Cow) -> Result>; - - /// Used for predicate logic (such as the entire WHERE expression). - fn tests_true(&self) -> bool; - - fn equals(&self, rhs: &Self) -> Self; - fn not_equals(&self, rhs: &Self) -> Self; - fn and(&self, rhs: &Self) -> Self; - fn or(&self, rhs: &Self) -> Self; - fn concat(&self, rhs: &Self) -> Self; -} diff --git a/src/queryplan/execute.rs b/src/queryplan/execute.rs index 79864b3..aeb7084 100644 --- a/src/queryplan/execute.rs +++ b/src/queryplan/execute.rs @@ -1,4 +1,5 @@ -use databaseinfo::{DatabaseInfo, ColumnValueOps}; +use columnvalueops::ColumnValueOps; +use databaseinfo::DatabaseInfo; use databasestorage::DatabaseStorage; use super::sexpression::SExpression; diff --git a/src/queryplan/mod.rs b/src/queryplan/mod.rs index afd0806..e1343c4 100644 --- a/src/queryplan/mod.rs +++ b/src/queryplan/mod.rs @@ -1,4 +1,5 @@ -use databaseinfo::{DatabaseInfo, TableInfo, ColumnValueOps}; +use columnvalueops::ColumnValueOps; +use databaseinfo::{DatabaseInfo, TableInfo}; use identifier::Identifier; use sqlsyntax::ast; diff --git a/src/tempdb/mod.rs b/src/tempdb/mod.rs index b70b8a8..2a577d4 100644 --- a/src/tempdb/mod.rs +++ b/src/tempdb/mod.rs @@ -5,11 +5,10 @@ use std::borrow::Cow; use std::collections::BTreeSet; -use std::fmt; -use databaseinfo::{DatabaseInfo, TableInfo, ColumnInfo, ColumnValueOps}; +use databaseinfo::{DatabaseInfo, TableInfo, ColumnInfo}; use identifier::Identifier; -use types::DbType; +use types::{DbType, Variant}; use sqlsyntax::ast; mod table; @@ -31,103 +30,9 @@ pub struct ResultSet<'a> { pub type ExecuteStatementResult<'a> = Result, String>; - -#[derive(Clone)] -pub enum ColumnValue { - Null, - StringLiteral(String), - Number(u64) -} - -impl fmt::Display for ColumnValue { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - match self { - &ColumnValue::Null => write!(f, "NULL"), - &ColumnValue::StringLiteral(ref s) => write!(f, "\"{}\"", s), - &ColumnValue::Number(n) => write!(f, "{}", n) - } - } -} - -impl ColumnValue { - fn from_bool(value: bool) -> ColumnValue { - ColumnValue::Number(if value { 1 } else { 0 }) - } -} - -impl ColumnValueOps for ColumnValue { - fn from_string_literal(s: Cow) -> Result> { - Ok(ColumnValue::StringLiteral(s.into_owned())) - } - - fn from_number_literal(s: Cow) -> Result> { - match s.parse() { - Ok(number) => Ok(ColumnValue::Number(number)), - Err(_) => Err(s) - } - } - - fn tests_true(&self) -> bool { - match self { - &ColumnValue::Null => false, - &ColumnValue::StringLiteral(ref s) => !s.is_empty(), - &ColumnValue::Number(n) => n != 0 - } - } - - fn equals(&self, rhs: &Self) -> Self { - match (self, rhs) { - (&ColumnValue::Null, _) | (_, &ColumnValue::Null) => { - // NULL does not compare. - ColumnValue::Null - }, - (&ColumnValue::StringLiteral(ref l), &ColumnValue::StringLiteral(ref r)) => { - ColumnValue::from_bool(l == r) - }, - (&ColumnValue::Number(l), &ColumnValue::Number(r)) => { - ColumnValue::from_bool(l == r) - }, - _ => ColumnValue::from_bool(false) - } - } - - fn not_equals(&self, rhs: &Self) -> Self { - match (self, rhs) { - (&ColumnValue::Null, _) | (_, &ColumnValue::Null) => { - // NULL does not compare. - ColumnValue::Null - }, - (&ColumnValue::StringLiteral(ref l), &ColumnValue::StringLiteral(ref r)) => { - ColumnValue::from_bool(l != r) - }, - (&ColumnValue::Number(l), &ColumnValue::Number(r)) => { - ColumnValue::from_bool(l != r) - }, - _ => ColumnValue::from_bool(true) - } - } - - fn and(&self, rhs: &Self) -> Self { - ColumnValue::from_bool(self.tests_true() && rhs.tests_true()) - } - - fn or(&self, rhs: &Self) -> Self { - ColumnValue::from_bool(self.tests_true() || rhs.tests_true()) - } - - fn concat(&self, rhs: &Self) -> Self { - match (self, rhs) { - (&ColumnValue::StringLiteral(ref l), &ColumnValue::StringLiteral(ref r)) => { - ColumnValue::StringLiteral(format!("{}{}", l, r)) - }, - (e, _) => e.clone() - } - } -} - impl DatabaseInfo for TempDb { type Table = Table; - type ColumnValue = ColumnValue; + type ColumnValue = Variant; fn find_table_by_name(&self, name: &Identifier) -> Option<&Table> { self.tables.iter().find(|t| &t.name == name) diff --git a/src/types/mod.rs b/src/types/mod.rs index 3d2a833..0ead4b1 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -1,5 +1,8 @@ use identifier::Identifier; +mod variant; +pub use self::variant::Variant; + use std::borrow::Cow; #[derive(Debug, Copy)] diff --git a/src/types/variant.rs b/src/types/variant.rs new file mode 100644 index 0000000..1e434a7 --- /dev/null +++ b/src/types/variant.rs @@ -0,0 +1,94 @@ +use columnvalueops::ColumnValueOps; +use std::borrow::Cow; +use std::fmt; + +#[derive(Clone)] +pub enum Variant { + Null, + StringLiteral(String), + Number(u64) +} + +impl fmt::Display for Variant { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + match self { + &Variant::Null => write!(f, "NULL"), + &Variant::StringLiteral(ref s) => write!(f, "\"{}\"", s), + &Variant::Number(n) => write!(f, "{}", n) + } + } +} + +fn from_bool(value: bool) -> Variant { + Variant::Number(if value { 1 } else { 0 }) +} + +impl ColumnValueOps for Variant { + fn from_string_literal(s: Cow) -> Result> { + Ok(Variant::StringLiteral(s.into_owned())) + } + + fn from_number_literal(s: Cow) -> Result> { + match s.parse() { + Ok(number) => Ok(Variant::Number(number)), + Err(_) => Err(s) + } + } + + fn tests_true(&self) -> bool { + match self { + &Variant::Null => false, + &Variant::StringLiteral(ref s) => !s.is_empty(), + &Variant::Number(n) => n != 0 + } + } + + fn equals(&self, rhs: &Self) -> Self { + match (self, rhs) { + (&Variant::Null, _) | (_, &Variant::Null) => { + // NULL does not compare. + Variant::Null + }, + (&Variant::StringLiteral(ref l), &Variant::StringLiteral(ref r)) => { + from_bool(l == r) + }, + (&Variant::Number(l), &Variant::Number(r)) => { + from_bool(l == r) + }, + _ => from_bool(false) + } + } + + fn not_equals(&self, rhs: &Self) -> Self { + match (self, rhs) { + (&Variant::Null, _) | (_, &Variant::Null) => { + // NULL does not compare. + Variant::Null + }, + (&Variant::StringLiteral(ref l), &Variant::StringLiteral(ref r)) => { + from_bool(l != r) + }, + (&Variant::Number(l), &Variant::Number(r)) => { + from_bool(l != r) + }, + _ => from_bool(true) + } + } + + fn and(&self, rhs: &Self) -> Self { + from_bool(self.tests_true() && rhs.tests_true()) + } + + fn or(&self, rhs: &Self) -> Self { + from_bool(self.tests_true() || rhs.tests_true()) + } + + fn concat(&self, rhs: &Self) -> Self { + match (self, rhs) { + (&Variant::StringLiteral(ref l), &Variant::StringLiteral(ref r)) => { + Variant::StringLiteral(format!("{}{}", l, r)) + }, + (e, _) => e.clone() + } + } +}