Skip to content

Commit

Permalink
add old get_matching_values()
Browse files Browse the repository at this point in the history
  • Loading branch information
lmcmicu committed Jan 14, 2024
1 parent 5ba639c commit f475a26
Showing 1 changed file with 190 additions and 6 deletions.
196 changes: 190 additions & 6 deletions src/validate.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
use crate::{
ast::Expression, cast_column_sql_to_text, cast_sql_param_from_text, error, get_column_value,
get_sql_type_from_global_config, is_sql_type_error, local_sql_syntax, ColumnRule,
CompiledCondition, ParsedStructure, SerdeMap, ValveError, ValveRow, SQL_PARAM,
};
use chrono::Utc;
use enquote::unquote;
use indexmap::IndexMap;
use serde_json::{json, Value as SerdeValue};
use sqlx::{
Expand All @@ -7,12 +13,6 @@ use sqlx::{
};
use std::collections::HashMap;

use crate::{
cast_sql_param_from_text, error, get_column_value, get_sql_type_from_global_config,
is_sql_type_error, local_sql_syntax, ColumnRule, CompiledCondition, SerdeMap, ValveError,
ValveRow,
};

/// Represents a particular cell in a particular row of data with vaildation results.
#[derive(Clone, Debug)]
pub struct ResultCell {
Expand Down Expand Up @@ -49,6 +49,190 @@ pub struct QueryAsIf {
pub row: Option<ValveRow>,
}

pub async fn get_matching_values_old(
config: &SerdeMap,
compiled_datatype_conditions: &HashMap<String, CompiledCondition>,
parsed_structure_conditions: &HashMap<String, ParsedStructure>,
pool: &AnyPool,
table_name: &str,
column_name: &str,
matching_string: Option<&str>,
) -> Result<SerdeValue, sqlx::Error> {
let dt_name = config
.get("table")
.and_then(|t| t.as_object())
.and_then(|t| t.get(table_name))
.and_then(|t| t.as_object())
.and_then(|t| t.get("column"))
.and_then(|c| c.as_object())
.and_then(|c| c.get(column_name))
.and_then(|c| c.as_object())
.and_then(|c| c.get("datatype"))
.and_then(|d| d.as_str())
.unwrap();

let dt_condition = compiled_datatype_conditions
.get(dt_name)
.and_then(|d| Some(d.parsed.clone()));

let mut values = vec![];
match dt_condition {
Some(Expression::Function(name, args)) if name == "in" => {
for arg in args {
if let Expression::Label(arg) = *arg {
// Remove the enclosing quotes from the values being returned:
let label = unquote(&arg).unwrap_or_else(|_| arg);
if let Some(s) = matching_string {
if label.contains(s) {
values.push(label);
}
}
}
}
}
_ => {
// If the datatype for the column does not correspond to an `in(...)` function, then we
// check the column's structure constraints. If they include a
// `from(foreign_table.foreign_column)` condition, then the values are taken from the
// foreign column. Otherwise if the structure includes an
// `under(tree_table.tree_column, value)` condition, then get the values from the tree
// column that are under `value`.
let structure = parsed_structure_conditions.get(
config
.get("table")
.and_then(|t| t.as_object())
.and_then(|t| t.get(table_name))
.and_then(|t| t.as_object())
.and_then(|t| t.get("column"))
.and_then(|c| c.as_object())
.and_then(|c| c.get(column_name))
.and_then(|c| c.as_object())
.and_then(|c| c.get("structure"))
.and_then(|d| d.as_str())
.unwrap_or_else(|| ""),
);

let sql_type =
get_sql_type_from_global_config(&config, table_name, &column_name, pool).unwrap();

match structure {
Some(ParsedStructure { original, parsed }) => {
let matching_string = {
match matching_string {
None => "%".to_string(),
Some(s) => format!("%{}%", s),
}
};

match parsed {
Expression::Function(name, args) if name == "from" => {
let foreign_key = &args[0];
if let Expression::Field(ftable, fcolumn) = &**foreign_key {
let fcolumn_text = cast_column_sql_to_text(&fcolumn, &sql_type);
let sql = local_sql_syntax(
&pool,
&format!(
r#"SELECT "{}" FROM "{}" WHERE {} LIKE {}"#,
fcolumn, ftable, fcolumn_text, SQL_PARAM
),
);
let rows = sqlx_query(&sql)
.bind(&matching_string)
.fetch_all(pool)
.await?;
for row in rows.iter() {
values.push(get_column_value(&row, &fcolumn, &sql_type));
}
}
}
Expression::Function(name, args) if name == "under" || name == "tree" => {
let mut tree_col = "not set";
let mut under_val = Some("not set".to_string());
if name == "under" {
if let Expression::Field(_, column) = &**&args[0] {
tree_col = column;
}
if let Expression::Label(label) = &**&args[1] {
under_val = Some(label.to_string());
}
} else {
let tree_key = &args[0];
if let Expression::Label(label) = &**tree_key {
tree_col = label;
under_val = None;
}
}

let tree = config
.get("constraints")
.and_then(|c| c.as_object())
.and_then(|c| c.get("tree"))
.and_then(|t| t.as_object())
.and_then(|t| t.get(table_name))
.and_then(|t| t.as_array())
.and_then(|t| {
t.iter().find(|o| o.get("child").unwrap() == tree_col)
})
.expect(
format!("No tree: '{}.{}' found", table_name, tree_col)
.as_str(),
)
.as_object()
.unwrap();
let child_column = tree.get("child").and_then(|c| c.as_str()).unwrap();

let (tree_sql, mut params) = with_tree_sql(
&config,
tree,
&table_name.to_string(),
&table_name.to_string(),
under_val.as_ref(),
None,
pool,
);
let child_column_text =
cast_column_sql_to_text(&child_column, &sql_type);
let sql = local_sql_syntax(
&pool,
&format!(
r#"{} SELECT "{}" FROM "tree" WHERE {} LIKE {}"#,
tree_sql, child_column, child_column_text, SQL_PARAM
),
);
params.push(matching_string);

let mut query = sqlx_query(&sql);
for param in &params {
query = query.bind(param);
}

let rows = query.fetch_all(pool).await?;
for row in rows.iter() {
values.push(get_column_value(&row, &child_column, &sql_type));
}
}
_ => panic!("Unrecognised structure: {}", original),
};
}
None => (),
};
}
};

let mut typeahead_values = vec![];
for (i, v) in values.iter().enumerate() {
// enumerate() begins at 0 but we need to begin at 1:
let i = i + 1;
typeahead_values.push(json!({
"id": v,
"label": v,
"order": i,
}));
}

Ok(json!(typeahead_values))
}

pub async fn validate_row_old(
config: &SerdeMap,
compiled_datatype_conditions: &HashMap<String, CompiledCondition>,
Expand Down

0 comments on commit f475a26

Please sign in to comment.