Skip to content
This repository has been archived by the owner on Jun 12, 2024. It is now read-only.

Commit

Permalink
#1: Implement positional parameters for SQL
Browse files Browse the repository at this point in the history
  • Loading branch information
proofrock committed Oct 9, 2023
1 parent c55c9ac commit 59efcdc
Show file tree
Hide file tree
Showing 5 changed files with 172 additions and 57 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ Obtaining an answer of:
- Directly call `sqliterg` on a database (as above), many options available using a YAML companion file;
- [**In-memory DBs**](https://docs.sqliterg.dev/documentation/running#file-based-and-in-memory) are supported;
- Serving of [**multiple databases**](https://docs.sqliterg.dev/documentation/configuration-file) in the same server instance;
- Named or positional parameters in SQL are supported;
- [**Batching**](https://docs.sqliterg.dev/documentation/requests#batch-parameter-values-for-a-statement) of multiple value sets for a single statement;
- All queries of a call are executed in a [**transaction**](https://docs.sqliterg.dev/documentation/requests);
- For each query/statement, specify if a failure should rollback the whole transaction, or the failure is [**limited**](https://docs.sqliterg.dev/documentation/errors#managed-errors) to that query;
Expand Down
14 changes: 14 additions & 0 deletions src/commons.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,3 +179,17 @@ impl From<Vec<(String, Box<dyn rusqlite::types::ToSql>)>> for NamedParamsContain
Self(src)
}
}

pub struct PositionalParamsContainer(Vec<Box<dyn rusqlite::types::ToSql>>);

impl PositionalParamsContainer {
pub fn slice(&self) -> Vec<&dyn rusqlite::types::ToSql> {
self.0.iter().map(|el| (el.borrow())).collect()
}
}

impl From<Vec<Box<dyn rusqlite::types::ToSql>>> for PositionalParamsContainer {
fn from(src: Vec<Box<dyn rusqlite::types::ToSql>>) -> Self {
Self(src)
}
}
55 changes: 48 additions & 7 deletions src/logic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use serde_json::{json, Map as JsonMap, Value as JsonValue};

use crate::{
auth::process_auth,
commons::{check_stored_stmt, NamedParamsContainer},
commons::{check_stored_stmt, NamedParamsContainer, PositionalParamsContainer},
db_config::{AuthMode, DbConfig},
main_config::Db,
req_res::{self, Response, ResponseItem},
Expand Down Expand Up @@ -56,6 +56,21 @@ fn calc_named_params(params: &JsonMap<String, JsonValue>) -> NamedParamsContaine
NamedParamsContainer::from(named_params)
}

fn calc_positional_params(params: &Vec<JsonValue>) -> PositionalParamsContainer {
let mut ret_params: Vec<Box<dyn ToSql>> = Vec::new();

for v in params {
let val: Box<dyn ToSql> = if v.is_string() {
Box::new(v.as_str().unwrap().to_owned())
} else {
Box::new(v.to_owned())
};
ret_params.push(val);
}

PositionalParamsContainer::from(ret_params)
}

#[allow(clippy::type_complexity)]
fn do_query(
tx: &Transaction,
Expand All @@ -70,8 +85,17 @@ fn do_query(
.collect();
let mut rows = match values {
Some(p) => {
let map = p.as_object().unwrap();
stmt.query(calc_named_params(map).slice().as_slice())?
// FIXME this code is repeated three times; I wish I could make a common
// function but, no matter how I try, it seems not to be possible
if p.is_object() {
let map = p.as_object().unwrap();
stmt.query(calc_named_params(map).slice().as_slice())?
} else if p.is_array() {
let array = p.as_array().unwrap();
stmt.query(calc_positional_params(array).slice().as_slice())?
} else {
return Err(eyre!("Values are neither positional nor named".to_string()));
}
}
None => stmt.query([])?,
};
Expand Down Expand Up @@ -107,16 +131,33 @@ fn do_statement(
let changed_rows = tx.execute(sql, [])?;
(None, Some(changed_rows), None)
} else if values.is_some() {
let map = values.as_ref().unwrap().as_object().unwrap();
let changed_rows = tx.execute(sql, calc_named_params(map).slice().as_slice())?;
let p = values.as_ref().unwrap();
let changed_rows = if p.is_object() {
let map = p.as_object().unwrap();
tx.execute(sql, calc_named_params(map).slice().as_slice())?
} else if p.is_array() {
let array = p.as_array().unwrap();
tx.execute(sql, calc_positional_params(array).slice().as_slice())?
} else {
return Err(eyre!("Values are neither positional nor named".to_string()));
};

(None, Some(changed_rows), None)
} else {
// values_batch.is_some()
let mut stmt = tx.prepare(sql)?;
let mut ret = vec![];
for p in values_batch.as_ref().unwrap() {
let map = p.as_object().unwrap();
let changed_rows = stmt.execute(calc_named_params(map).slice().as_slice())?;
let changed_rows = if p.is_object() {
let map = p.as_object().unwrap();
stmt.execute(calc_named_params(map).slice().as_slice())?
} else if p.is_array() {
let array = p.as_array().unwrap();
stmt.execute(calc_positional_params(array).slice().as_slice())?
} else {
return Err(eyre!("Values are neither positional nor named".to_string()));
};

ret.push(changed_rows);
}
(None, None, Some(ret))
Expand Down
Loading

0 comments on commit 59efcdc

Please sign in to comment.