use crate::traits::expressive::{Expressive, ExpressiveEnum};
use crate::traits::selectable::{Selectable, SourceRef};
use crate::{Expression, expr};
type Value = serde_json::Value;
#[derive(Debug, Clone, Default)]
pub struct MockSelect {
source: Option<String>,
fields: Vec<String>,
where_conditions: Vec<Expression<serde_json::Value>>,
order_by: Vec<(Expression<serde_json::Value>, bool)>,
distinct: bool,
limit: Option<i64>,
skip: Option<i64>,
}
impl MockSelect {
pub fn new() -> Self {
Self::default()
}
pub fn source(&self) -> Option<&str> {
self.source.as_deref()
}
pub fn fields(&self) -> &[String] {
&self.fields
}
pub fn where_conditions(&self) -> &[Expression<serde_json::Value>] {
&self.where_conditions
}
fn render(&self) -> Expression<serde_json::Value> {
let mut query = String::from("SELECT");
if self.distinct {
query.push_str(" DISTINCT");
}
if self.fields.is_empty() {
query.push_str(" *");
} else {
query.push(' ');
query.push_str(&self.fields.join(", "));
}
if let Some(source) = &self.source {
query.push_str(" FROM ");
query.push_str(source);
}
if !self.where_conditions.is_empty() {
query.push_str(" WHERE ");
let conditions: Vec<String> = self
.where_conditions
.iter()
.map(|c| c.template.clone())
.collect();
query.push_str(&conditions.join(" AND "));
}
if !self.order_by.is_empty() {
query.push_str(" ORDER BY ");
let orders: Vec<String> = self
.order_by
.iter()
.map(|(e, asc)| {
if *asc {
format!("{} ASC", e.template)
} else {
format!("{} DESC", e.template)
}
})
.collect();
query.push_str(&orders.join(", "));
}
match (self.limit, self.skip) {
(Some(limit), Some(skip)) => {
query.push_str(&format!(" LIMIT {} OFFSET {}", limit, skip))
}
(Some(limit), None) => query.push_str(&format!(" LIMIT {}", limit)),
(None, Some(skip)) => query.push_str(&format!(" OFFSET {}", skip)),
(None, None) => {}
}
Expression::new(query, vec![])
}
}
impl Selectable<serde_json::Value> for MockSelect {
fn add_source(
&mut self,
source: impl Into<SourceRef<serde_json::Value>>,
_alias: Option<String>,
) {
match source.into().into_expressive_enum() {
ExpressiveEnum::Scalar(serde_json::Value::String(s)) => {
self.source = Some(s);
}
_ => panic!("You may only use string source with this mock"),
}
}
fn add_field(&mut self, field: impl Into<String>) {
self.fields.push(field.into());
}
fn add_expression(&mut self, _expression: impl Expressive<Value>) {
panic!("You may only use field() in this mock")
}
fn add_where_condition(&mut self, condition: impl Into<Expression<Value>>) {
self.where_conditions.push(condition.into());
}
fn set_distinct(&mut self, distinct: bool) {
self.distinct = distinct;
}
fn add_order_by(&mut self, order: impl Into<Expression<Value>>, direction: crate::Order) {
self.order_by.push((order.into(), direction.ascending));
}
fn add_group_by(&mut self, _expression: impl Expressive<Value>) {
}
fn set_limit(&mut self, limit: Option<i64>, skip: Option<i64>) {
self.limit = limit;
self.skip = skip;
}
fn clear_fields(&mut self) {
self.fields.clear();
}
fn clear_where_conditions(&mut self) {
self.where_conditions.clear();
}
fn clear_order_by(&mut self) {
self.order_by.clear();
}
fn clear_group_by(&mut self) {
}
fn has_fields(&self) -> bool {
!self.fields.is_empty()
}
fn has_where_conditions(&self) -> bool {
!self.where_conditions.is_empty()
}
fn has_order_by(&self) -> bool {
!self.order_by.is_empty()
}
fn has_group_by(&self) -> bool {
false }
fn is_distinct(&self) -> bool {
self.distinct
}
fn get_limit(&self) -> Option<i64> {
self.limit
}
fn get_skip(&self) -> Option<i64> {
self.skip
}
fn as_count(&self) -> Expression<serde_json::Value> {
let source = self.source.as_ref().unwrap().as_str();
expr!("SELECT COUNT(*) FROM {}", source)
}
fn as_sum(&self, column: impl Expressive<Value>) -> Expression<Value> {
let source = self.source.as_ref().unwrap().as_str();
expr!("SELECT SUM({}) FROM {}", (column), source)
}
fn as_max(&self, column: impl Expressive<Value>) -> Expression<Value> {
let source = self.source.as_ref().unwrap().as_str();
expr!("SELECT MAX({}) FROM {}", (column), source)
}
fn as_min(&self, column: impl Expressive<Value>) -> Expression<Value> {
let source = self.source.as_ref().unwrap().as_str();
expr!("SELECT MIN({}) FROM {}", (column), source)
}
}
impl From<MockSelect> for Expression<serde_json::Value> {
fn from(val: MockSelect) -> Self {
val.render()
}
}
impl crate::traits::expressive::Expressive<serde_json::Value> for MockSelect {
fn expr(&self) -> Expression<serde_json::Value> {
self.render()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::expr;
#[test]
fn test_mock_select_basic() {
let mut select = MockSelect::new();
select.add_source("users", None);
let query: Expression<serde_json::Value> = select.into();
assert_eq!(query.preview(), "SELECT * FROM users");
}
#[test]
fn test_mock_select_with_fields() {
let mut select = MockSelect::new();
select.add_source("users", None);
select.add_field("name");
select.add_field("email");
let query: Expression<serde_json::Value> = select.into();
assert_eq!(query.preview(), "SELECT name, email FROM users");
}
#[test]
fn test_mock_select_with_conditions() {
let mut select = MockSelect::new();
select.add_source("users", None);
select.add_field("name");
select.add_where_condition(expr!("age > 18"));
let query: Expression<serde_json::Value> = select.into();
assert_eq!(query.preview(), "SELECT name FROM users WHERE age > 18");
}
}