use std::collections::HashMap;
use serde_json::Value;
use crate::error::Result;
use crate::sql_builder::SqlBuilder;
pub struct SealedQuery<'a> {
conn: &'a crate::connection::Connection,
}
impl<'a> SealedQuery<'a> {
pub fn new(conn: &'a crate::connection::Connection) -> Self {
Self { conn }
}
fn has_sealed_column(&self) -> bool {
let sql = "SELECT sealedProduct FROM sets LIMIT 0";
self.conn.execute(sql, &[]).is_ok()
}
pub fn list(
&self,
set_code: Option<&str>,
category: Option<&str>,
limit: Option<usize>,
) -> Result<Vec<Value>> {
self.conn.ensure_views(&["sets"])?;
if !self.has_sealed_column() {
return Ok(Vec::new());
}
let mut qb = SqlBuilder::new("sets");
qb.select(&["code", "name", "sealedProduct"]);
if let Some(sc) = set_code {
let upper = sc.to_uppercase();
qb.where_eq("code", &upper);
}
qb.where_clause("sealedProduct IS NOT NULL", &[]);
let (sql, params) = qb.build();
let rows = self.conn.execute(&sql, ¶ms)?;
let mut results: Vec<Value> = Vec::new();
let limit = limit.unwrap_or(100);
for row in rows {
let code = row
.get("code")
.and_then(|v| v.as_str())
.unwrap_or("")
.to_string();
let set_name = row
.get("name")
.and_then(|v| v.as_str())
.unwrap_or("")
.to_string();
if let Some(Value::Array(products)) = row.get("sealedProduct") {
for product in products {
let mut p = product.clone();
if let Value::Object(ref mut map) = p {
if let Some(cat) = category {
let product_cat = map
.get("category")
.and_then(|v| v.as_str())
.unwrap_or("");
if product_cat != cat {
continue;
}
}
map.insert("setCode".to_string(), Value::String(code.clone()));
map.insert("setName".to_string(), Value::String(set_name.clone()));
}
results.push(p);
if results.len() >= limit {
return Ok(results);
}
}
}
}
Ok(results)
}
pub fn get(&self, uuid: &str) -> Result<Option<Value>> {
self.conn.ensure_views(&["sets"])?;
if !self.has_sealed_column() {
return Ok(None);
}
let rows = self.conn.execute(
"SELECT code, name, sealedProduct FROM sets WHERE sealedProduct IS NOT NULL",
&[],
)?;
for row in rows {
let code = row
.get("code")
.and_then(|v| v.as_str())
.unwrap_or("")
.to_string();
let set_name = row
.get("name")
.and_then(|v| v.as_str())
.unwrap_or("")
.to_string();
if let Some(Value::Array(products)) = row.get("sealedProduct") {
for product in products {
let product_uuid = product
.get("uuid")
.and_then(|v| v.as_str())
.unwrap_or("");
if product_uuid == uuid {
let mut p = product.clone();
if let Value::Object(ref mut map) = p {
map.insert("setCode".to_string(), Value::String(code.clone()));
map.insert(
"setName".to_string(),
Value::String(set_name.clone()),
);
}
return Ok(Some(p));
}
}
}
}
Ok(None)
}
}
#[allow(dead_code)]
fn rows_to_values(rows: Vec<HashMap<String, Value>>) -> Vec<Value> {
rows.into_iter()
.map(|r| serde_json::to_value(r).unwrap_or(Value::Null))
.collect()
}