Replace SQL results with Op

This commit is contained in:
NGnius (Graham) 2022-08-01 16:33:37 -04:00
parent 175d304f1b
commit c70520b15d
5 changed files with 262 additions and 91 deletions

View file

@ -16,6 +16,7 @@ mod sorter;
//mod statement;
mod type_primitives;
pub(crate) mod utility;
mod vec_op;
pub use dictionary::LanguageDictionary;
pub(crate) use error::LanguageError;
@ -32,6 +33,7 @@ pub use single_op::SingleItem;
pub use sorter::{SortStatement, SortStatementFactory, Sorter, SorterFactory};
//pub(crate) use statement::Statement;
pub use type_primitives::TypePrimitive;
pub use vec_op::VecOp;
pub mod vocabulary;

View file

@ -0,0 +1,146 @@
use std::fmt::{Debug, Display, Error, Formatter};
use std::iter::Iterator;
use crate::lang::{IteratorItem, Op, RuntimeError};
use crate::lang::{RuntimeOp, RuntimeMsg, PseudoOp};
use crate::Context;
use crate::Item;
type IteratorItemMsg = Result<Item, RuntimeMsg>;
#[derive(Debug)]
pub struct VecOp<T> {
context: Option<Context>,
vec: Vec<T>,
index: usize,
}
impl<T> VecOp<T> {
pub fn new(items: Vec<T>) -> Self {
Self {
context: None,
vec: items,
index: 0,
}
}
}
impl<T> Display for VecOp<T> {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
write!(f, "*vec*[{}..{}]", self.index, self.vec.len())
}
}
impl<T: Clone> std::clone::Clone for VecOp<T> {
fn clone(&self) -> Self {
Self {
context: None,
vec: self.vec.clone(),
index: self.index,
}
}
}
impl Iterator for VecOp<IteratorItem> {
type Item = IteratorItem;
fn next(&mut self) -> Option<Self::Item> {
if self.index == self.vec.len() {
None
} else {
let item = self.vec[self.index].clone();
self.index += 1;
Some(item)
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.vec.len();
(len, Some(len))
}
}
impl Iterator for VecOp<IteratorItemMsg> {
type Item = IteratorItem;
fn next(&mut self) -> Option<Self::Item> {
if self.index == self.vec.len() {
None
} else {
let item = self.vec[self.index].clone();
self.index += 1;
Some(item.map_err(|e| e.with(RuntimeOp(PseudoOp::from_printable(self)))))
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.vec.len();
(len, Some(len))
}
}
impl Op for VecOp<IteratorItem> {
fn enter(&mut self, ctx: Context) {
self.context = Some(ctx)
}
fn escape(&mut self) -> Context {
self.context.take().unwrap()
}
fn is_resetable(&self) -> bool {
true
}
fn reset(&mut self) -> Result<(), RuntimeError> {
self.index = 0;
Ok(())
}
fn dup(&self) -> Box<dyn Op> {
Box::new(Self {
context: None,
vec: self.vec.clone(),
index: 0,
})
}
}
impl Op for VecOp<IteratorItemMsg> {
fn enter(&mut self, ctx: Context) {
self.context = Some(ctx)
}
fn escape(&mut self) -> Context {
self.context.take().unwrap()
}
fn is_resetable(&self) -> bool {
true
}
fn reset(&mut self) -> Result<(), RuntimeError> {
self.index = 0;
Ok(())
}
fn dup(&self) -> Box<dyn Op> {
Box::new(Self {
context: None,
vec: self.vec.clone(),
index: 0,
})
}
}
impl std::convert::From<Vec<IteratorItem>> for VecOp<IteratorItem> {
fn from(other: Vec<IteratorItem>) -> Self {
VecOp::new(other)
}
}
impl std::convert::From<Vec<IteratorItemMsg>> for VecOp<IteratorItemMsg> {
fn from(other: Vec<IteratorItemMsg>) -> Self {
VecOp::new(other)
}
}

View file

@ -6,56 +6,48 @@ use crate::lang::utility::assert_token;
use crate::lang::{
FunctionFactory, FunctionStatementFactory, IteratorItem, LanguageDictionary, Op, PseudoOp,
};
use crate::lang::{RuntimeError, RuntimeMsg, RuntimeOp, SyntaxError};
use crate::lang::{RuntimeError, RuntimeOp, SyntaxError};
use crate::tokens::Token;
use crate::Context;
use crate::Item;
//use super::db::*;
#[derive(Debug)]
pub struct SqlStatement {
query: String,
context: Option<Context>,
rows: Option<Vec<Result<Item, RuntimeMsg>>>,
current: usize,
rows: Option<Box<dyn Op>>,
is_complete: bool,
}
impl SqlStatement {
fn get_item(&mut self, increment: bool) -> Option<IteratorItem> {
let fake = PseudoOp::from_printable(self);
if let Some(rows) = &self.rows {
if increment {
if self.current == rows.len() {
return None;
}
self.current += 1;
}
if self.current >= rows.len() {
None
} else {
//Some(rows[self.current].clone())
match rows[self.current].clone() {
Ok(item) => Some(Ok(item)),
Err(e) => Some(Err(e.with(RuntimeOp(fake)))),
}
}
} else {
Some(Err(RuntimeError {
line: 0,
op: fake,
msg: "Context error: rows is None".to_string(),
}))
fn get_item(&mut self) -> Option<IteratorItem> {
let result = self.rows.as_mut().unwrap().next().map(|opt| opt.map_err(|mut e| {
e.op = PseudoOp::from_printable(self);
e
}));
if result.is_none() {
self.is_complete = true;
}
result
}
}
impl Op for SqlStatement {
fn enter(&mut self, ctx: Context) {
self.context = Some(ctx)
if let Some(rows) = &mut self.rows {
rows.enter(ctx);
} else {
self.context = Some(ctx);
}
}
fn escape(&mut self) -> Context {
if self.context.is_some() {
self.context.take().unwrap()
} else {
self.rows.as_mut().unwrap().escape()
}
}
fn is_resetable(&self) -> bool {
@ -63,8 +55,10 @@ impl Op for SqlStatement {
}
fn reset(&mut self) -> Result<(), RuntimeError> {
self.rows = None;
self.current = 0;
if let Some(mut rows) = self.rows.take() {
self.context = Some(rows.escape());
}
self.is_complete = false;
Ok(())
}
@ -73,7 +67,7 @@ impl Op for SqlStatement {
query: self.query.clone(),
context: None,
rows: None,
current: 0,
is_complete: false,
})
}
}
@ -84,7 +78,7 @@ impl std::clone::Clone for SqlStatement {
query: self.query.clone(),
context: None, // unecessary to include in clone (not used for displaying)
rows: None, // unecessary to include
current: self.current,
is_complete: self.is_complete,
}
}
}
@ -93,29 +87,31 @@ impl Iterator for SqlStatement {
type Item = IteratorItem;
fn next(&mut self) -> Option<Self::Item> {
if self.is_complete {
return None;
}
if self.rows.is_some() {
// query has executed, return another result
self.get_item(true)
self.get_item()
} else {
let fake = PseudoOp::from_printable(self);
let ctx = self.context.as_mut().unwrap();
// query has not been executed yet
match ctx.database.raw(&self.query) {
Err(e) => {
self.rows = Some(Vec::with_capacity(0));
Some(Err(e.with(RuntimeOp(fake))))
self.is_complete = true;
Some(Err(e.with(RuntimeOp(PseudoOp::from_printable(self)))))
}
Ok(rows) => {
Ok(mut rows) => {
rows.enter(self.context.take().unwrap());
self.rows = Some(rows);
self.get_item(false)
self.get_item()
}
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.rows.as_ref().map(|x| x.len());
(len.unwrap_or(0), len)
self.rows.as_ref().map(|x| x.size_hint()).unwrap_or_default()
}
}
@ -150,8 +146,8 @@ impl FunctionFactory<SqlStatement> for SqlFunctionFactory {
Ok(SqlStatement {
query: literal,
context: None,
current: 0,
rows: None,
is_complete: false,
})
}
}

View file

@ -6,10 +6,9 @@ use crate::lang::utility::assert_token;
use crate::lang::{
FunctionFactory, FunctionStatementFactory, IteratorItem, LanguageDictionary, Op, PseudoOp,
};
use crate::lang::{RuntimeError, RuntimeMsg, RuntimeOp, SyntaxError};
use crate::lang::{RuntimeError, RuntimeOp, SyntaxError};
use crate::tokens::Token;
use crate::Context;
use crate::Item;
#[derive(Debug, Clone)]
enum QueryMode {
@ -65,46 +64,39 @@ pub struct SimpleSqlStatement {
query: String,
mode: QueryMode,
context: Option<Context>,
rows: Option<Vec<Result<Item, RuntimeMsg>>>,
current: usize,
rows: Option<Box<dyn Op>>,
is_complete: bool,
}
impl SimpleSqlStatement {
fn get_item(&mut self, increment: bool) -> Option<IteratorItem> {
let fake = PseudoOp::from_printable(self);
if let Some(rows) = &self.rows {
if increment {
if self.current == rows.len() {
return None;
}
self.current += 1;
}
if self.current >= rows.len() {
None
} else {
//Some(rows[self.current].clone())
match rows[self.current].clone() {
Ok(item) => Some(Ok(item)),
Err(e) => Some(Err(e.with(RuntimeOp(fake)))),
}
}
} else {
Some(Err(RuntimeError {
line: 0,
op: fake,
msg: "Context error: rows is None".to_string(),
}))
fn get_item(&mut self) -> Option<IteratorItem> {
let result = self.rows.as_mut().unwrap().next().map(|opt| opt.map_err(|mut e| {
e.op = PseudoOp::from_printable(self);
e
}));
if result.is_none() {
self.is_complete = true;
}
result
}
}
impl Op for SimpleSqlStatement {
fn enter(&mut self, ctx: Context) {
self.context = Some(ctx)
if let Some(rows) = &mut self.rows {
rows.enter(ctx);
} else {
self.context = Some(ctx);
}
}
fn escape(&mut self) -> Context {
if self.context.is_some() {
self.context.take().unwrap()
} else {
self.rows.as_mut().unwrap().escape()
}
}
fn is_resetable(&self) -> bool {
@ -112,8 +104,10 @@ impl Op for SimpleSqlStatement {
}
fn reset(&mut self) -> Result<(), RuntimeError> {
self.rows = None;
self.current = 0;
if let Some(mut rows) = self.rows.take() {
self.context = Some(rows.escape());
}
self.is_complete = false;
Ok(())
}
@ -123,7 +117,7 @@ impl Op for SimpleSqlStatement {
mode: self.mode.clone(),
context: None,
rows: None,
current: 0,
is_complete: false,
})
}
}
@ -135,7 +129,7 @@ impl std::clone::Clone for SimpleSqlStatement {
mode: self.mode.clone(),
context: None, // unecessary to include in clone (not used for displaying)
rows: None, // unecessary to include
current: self.current,
is_complete: self.is_complete,
}
}
}
@ -144,11 +138,13 @@ impl Iterator for SimpleSqlStatement {
type Item = IteratorItem;
fn next(&mut self) -> Option<Self::Item> {
if self.is_complete {
return None;
}
if self.rows.is_some() {
// query has executed, return another result
self.get_item(true)
self.get_item()
} else {
let fake = PseudoOp::from_printable(self);
let ctx = self.context.as_mut().unwrap();
// query has not been executed yet
let query_result = match self.mode {
@ -159,20 +155,21 @@ impl Iterator for SimpleSqlStatement {
};
match query_result {
Err(e) => {
self.rows = Some(Vec::with_capacity(0));
Some(Err(e.with(RuntimeOp(fake))))
self.is_complete = true;
Some(Err(e.with(RuntimeOp(PseudoOp::from_printable(self)))))
}
Ok(rows) => {
Ok(mut rows) => {
//drop(ctx);
rows.enter(self.context.take().unwrap());
self.rows = Some(rows);
self.get_item(false)
self.get_item()
}
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.rows.as_ref().map(|x| x.len());
(len.unwrap_or(0), len)
self.rows.as_ref().map(|x| x.size_hint()).unwrap_or_default()
}
}
@ -208,7 +205,7 @@ impl FunctionFactory<SimpleSqlStatement> for SimpleSqlFunctionFactory {
query: literal,
mode: QueryMode::from_name(mode_name)?,
context: None,
current: 0,
is_complete: false,
rows: None,
})
}

View file

@ -4,9 +4,10 @@ use std::fmt::Write;
use crate::lang::db::*;
use crate::lang::RuntimeMsg;
use crate::lang::{Op, VecOp};
use crate::Item;
pub type QueryResult = Result<Vec<Result<Item, RuntimeMsg>>, RuntimeMsg>;
pub type QueryResult = Result<Box<dyn Op>, RuntimeMsg>;
/// SQL querying functionality, loosely de-coupled from any specific SQL dialect (excluding raw call)
pub trait DatabaseQuerier: Debug {
@ -56,10 +57,10 @@ impl SQLiteExecutor {
self.gen_db_maybe()?;
let conn = self.sqlite_connection.as_mut().unwrap();
match perform_single_param_query(conn, query, param) {
Ok(items) => Ok(items
Ok(items) => Ok(Box::new(VecOp::from(items
.into_iter()
.map(|item| item.map_err(|e| RuntimeMsg(format!("SQL item mapping error: {}", e))))
.collect()),
.collect::<Vec<_>>()))),
Err(e) => Err(RuntimeMsg(e)),
}
}
@ -71,10 +72,10 @@ impl DatabaseQuerier for SQLiteExecutor {
let conn = self.sqlite_connection.as_mut().unwrap();
// execute query
match perform_query(conn, query) {
Ok(items) => Ok(items
Ok(items) => Ok(Box::new(VecOp::from(items
.into_iter()
.map(|item| item.map_err(|e| RuntimeMsg(format!("SQL item mapping error: {}", e))))
.collect()),
.collect::<Vec<_>>()))),
Err(e) => Err(RuntimeMsg(e)),
}
}
@ -299,3 +300,32 @@ fn rows_to_item(
.set_field_chain("year", meta.date.into());
item
}
#[derive(Default, Debug)]
pub struct SQLiteTranspileExecutor;
impl DatabaseQuerier for SQLiteTranspileExecutor {
fn raw(&mut self, query: &str) -> QueryResult {
Err(RuntimeMsg("Unimplemented".to_owned()))
}
fn artist_like(&mut self, query: &str) -> QueryResult {
Err(RuntimeMsg("Unimplemented".to_owned()))
}
fn album_like(&mut self, query: &str) -> QueryResult {
Err(RuntimeMsg("Unimplemented".to_owned()))
}
fn song_like(&mut self, query: &str) -> QueryResult {
Err(RuntimeMsg("Unimplemented".to_owned()))
}
fn genre_like(&mut self, query: &str) -> QueryResult {
Err(RuntimeMsg("Unimplemented".to_owned()))
}
fn init_with_params(&mut self, _params: &HashMap<String, String>) -> Result<(), RuntimeMsg> {
Ok(())
}
}