use quickbooks_types::QBItem;
use crate::{Limit, Order, OrderClause, WhereClause};
#[derive(Debug, PartialEq, Clone)]
pub struct Query<QB> {
pub(crate) condition: Vec<WhereClause>,
pub(crate) order: Vec<OrderClause>,
pub(crate) limit: Option<Limit>,
_phantom: std::marker::PhantomData<QB>,
}
impl<QB: QBItem> Default for Query<QB> {
fn default() -> Self {
Self::new()
}
}
impl<QB: QBItem> Query<QB> {
#[must_use]
pub fn new() -> Self {
Query {
condition: Vec::new(),
order: Vec::new(),
limit: None,
_phantom: std::marker::PhantomData,
}
}
#[must_use]
pub unsafe fn condition(mut self, condition: WhereClause) -> Self {
self.condition.push(condition);
self
}
#[must_use]
pub fn typed_condition(mut self, condition: crate::TypedWhereClause<QB>) -> Self {
self.condition.push(condition.into());
self
}
#[must_use]
pub unsafe fn order(mut self, field: &'static str, order: Order) -> Self {
self.order.push(OrderClause { field, order });
self
}
#[must_use]
pub fn limit(mut self, number: u32, offset: Option<u32>) -> Self {
self.limit = Some(Limit { number, offset });
self
}
#[must_use]
pub fn query_string(&self) -> String {
let mut query = format!("select * from {}", QB::name());
if !self.condition.is_empty() {
query.push_str(" where");
for (i, cond) in self.condition.iter().enumerate() {
if i > 0 {
query.push_str(" and");
}
cond.extend_query(&mut query);
}
}
if !self.order.is_empty() {
query.push_str(" order by");
for (i, ord) in self.order.iter().enumerate() {
if i > 0 {
query.push(',');
}
ord.extend_query(&mut query);
}
}
if let Some(limit) = &self.limit {
limit.extend_query(&mut query);
}
query
}
#[cfg(feature = "api")]
pub fn execute(
&self,
qb: &quick_oxibooks::QBContext,
client: &ureq::Agent,
) -> Result<Vec<QB>, quick_oxibooks::error::APIError> {
unsafe { quick_oxibooks::functions::query::qb_query_raw::<QB>(self, qb, client) }
}
}
impl<QB: QBItem> std::fmt::Display for Query<QB> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.query_string())
}
}