use super::super::{naming::sql, types};
use crate::database::introspection::{Schema, Table};
pub(super) struct Selector {
pub parameters: String,
pub predicate: String,
pub binds: String,
pub arguments: String,
}
pub(super) fn render(table: &Table, schema: &Schema, key: &[String]) -> Selector {
build(table, schema, key, |position| format!("value_{position}"))
}
pub(super) fn update(table: &Table, schema: &Schema, key: &[String]) -> Selector {
build(table, schema, key, |position| key_argument(position, key.len()))
}
pub(super) fn key_argument(position: usize, count: usize) -> String {
if count == 1 {
"key".to_string()
} else {
format!("key_{position}")
}
}
fn build(table: &Table, schema: &Schema, key: &[String], name: impl Fn(usize) -> String) -> Selector {
let mut parameters = Vec::new();
let mut predicates = Vec::new();
let mut arguments = Vec::new();
let mut binds = String::new();
for (index, column_name) in key.iter().enumerate() {
let mut column = table.column(column_name).expect("known selector column").clone();
column.nullable = false;
let position = index + 1;
let argument = name(position);
parameters.push(format!("{argument}: {}", types::map(&column, schema).rust));
predicates.push(format!("{} = ${position}", sql(column_name)));
binds.push_str(&format!(".bind({argument})"));
arguments.push(argument);
}
Selector {
parameters: parameters.join(", "),
predicate: predicates.join(" AND "),
binds,
arguments: arguments.join(", "),
}
}