diff --git a/src/exports/fasta.rs b/src/exports/fasta.rs index 159dd17..5c118e5 100644 --- a/src/exports/fasta.rs +++ b/src/exports/fasta.rs @@ -1,4 +1,5 @@ use noodles::fasta; +use rusqlite; use rusqlite::{types::Value as SQLValue, Connection}; use std::fs::File; use std::path::PathBuf; @@ -17,16 +18,16 @@ pub fn export_fasta( block_groups = BlockGroup::query( conn, "select * from block_groups where collection_name = ?1 AND sample_name = ?2;", - vec![ + rusqlite::params!( SQLValue::from(collection_name.to_string()), SQLValue::from(sample_name.to_string()), - ], + ), ); } else { block_groups = BlockGroup::query( conn, "select * from block_groups where collection_name = ?1 AND sample_name IS NULL;", - vec![SQLValue::from(collection_name.to_string())], + rusqlite::params!(SQLValue::from(collection_name.to_string())), ); } diff --git a/src/exports/gfa.rs b/src/exports/gfa.rs index 7fff442..448dd52 100644 --- a/src/exports/gfa.rs +++ b/src/exports/gfa.rs @@ -34,10 +34,10 @@ pub fn export_gfa( let block_groups = BlockGroup::query( conn, "select * from block_groups where collection_name = ?1 AND sample_name = ?2;", - vec![ + rusqlite::params!( SQLValue::from(collection_name.to_string()), SQLValue::from(sample.clone()), - ], + ), ); if block_groups.is_empty() { panic!( @@ -176,7 +176,7 @@ fn write_paths( collection_name: &str, blocks: &[GroupBlock], ) { - let paths = Path::get_paths_for_collection(conn, collection_name); + let paths = Path::query_for_collection(conn, collection_name); let edges_by_path_id = PathEdge::edges_for_paths(conn, paths.iter().map(|path| path.id).collect()); @@ -362,7 +362,7 @@ mod tests { assert_eq!(all_sequences, all_sequences2); - let paths = Path::get_paths_for_collection(&conn, "test collection 2"); + let paths = Path::query_for_collection(&conn, "test collection 2"); assert_eq!(paths.len(), 1); assert_eq!(paths[0].sequence(&conn), "AAAATTTTGGGGCCCC"); } diff --git a/src/gfa_reader.rs b/src/gfa_reader.rs index 0bd93c6..1ccf4d3 100644 --- a/src/gfa_reader.rs +++ b/src/gfa_reader.rs @@ -702,7 +702,7 @@ impl<'a, T: SampleType, S: Opt, U: Opt> Pansn<'a, T, S, U> { /// Get all path #[allow(clippy::type_complexity)] - pub fn get_paths_direct(&self) -> Vec<(String, Vec<&Path>)> { + pub fn query_direct(&self) -> Vec<(String, Vec<&Path>)> { let mut result = Vec::new(); for x in self.genomes.iter() { for y in x.haplotypes.iter() { @@ -720,6 +720,6 @@ impl<'a, T: SampleType, S: Opt, U: Opt> Pansn<'a, T, S, U> { "Number of individual haplotypes: {}", self.get_haplo_path().len() ); - println!("Total number of paths: {}", self.get_paths_direct().len()); + println!("Total number of paths: {}", self.query_direct().len()); } } diff --git a/src/imports/fasta.rs b/src/imports/fasta.rs index 4244563..87da8b6 100644 --- a/src/imports/fasta.rs +++ b/src/imports/fasta.rs @@ -16,6 +16,7 @@ use crate::models::{ }; use crate::{calculate_hash, operation_management}; use noodles::fasta; +use rusqlite; use rusqlite::{session, Connection}; pub fn import_fasta( @@ -205,7 +206,10 @@ mod tests { conn, op_conn, ); - assert_eq!(Node::query(conn, "select * from nodes;", vec![]).len(), 3); + assert_eq!( + Node::query(conn, "select * from nodes;", rusqlite::params!()).len(), + 3 + ); import_fasta( &fasta_path.to_str().unwrap().to_string(), &collection, @@ -213,6 +217,9 @@ mod tests { conn, op_conn, ); - assert_eq!(Node::query(conn, "select * from nodes;", vec![]).len(), 3); + assert_eq!( + Node::query(conn, "select * from nodes;", rusqlite::params!()).len(), + 3 + ); } } diff --git a/src/imports/gfa.rs b/src/imports/gfa.rs index ac66c48..73b2110 100644 --- a/src/imports/gfa.rs +++ b/src/imports/gfa.rs @@ -1,3 +1,4 @@ +use rusqlite; use rusqlite::Connection; use std::collections::{HashMap, HashSet}; use std::path::Path as FilePath; @@ -234,20 +235,20 @@ mod tests { import_gfa(&gfa_path, &collection_name, conn); let block_group_id = BlockGroup::get_id(conn, &collection_name, None, ""); - let path = Path::get_paths( + let path = Path::query( conn, "select * from paths where block_group_id = ?1 AND name = ?2", - vec![ + rusqlite::params!( SQLValue::from(block_group_id), SQLValue::from("m123".to_string()), - ], + ), )[0] .clone(); let result = path.sequence(conn); assert_eq!(result, "ATCGATCGATCGATCGATCGGGAACACACAGAGA"); - let node_count = Node::query(conn, "select * from nodes", vec![]).len() as i64; + let node_count = Node::query(conn, "select * from nodes", rusqlite::params!()).len() as i64; assert_eq!(node_count, 6); } @@ -266,7 +267,7 @@ mod tests { HashSet::from_iter(vec!["AAAATTTTGGGGCCCC".to_string()]) ); - let node_count = Node::query(conn, "select * from nodes", vec![]).len() as i64; + let node_count = Node::query(conn, "select * from nodes", rusqlite::params!()).len() as i64; assert_eq!(node_count, 6); } @@ -279,20 +280,20 @@ mod tests { import_gfa(&gfa_path, &collection_name, conn); let block_group_id = BlockGroup::get_id(conn, &collection_name, None, ""); - let path = Path::get_paths( + let path = Path::query( conn, "select * from paths where block_group_id = ?1 AND name = ?2", - vec![ + rusqlite::params!( SQLValue::from(block_group_id), SQLValue::from("291344".to_string()), - ], + ), )[0] .clone(); let result = path.sequence(conn); assert_eq!(result, "ACCTACAAATTCAAAC"); - let node_count = Node::query(conn, "select * from nodes", vec![]).len() as i64; + let node_count = Node::query(conn, "select * from nodes", rusqlite::params!()).len() as i64; assert_eq!(node_count, 6); } @@ -305,20 +306,20 @@ mod tests { import_gfa(&gfa_path, &collection_name, conn); let block_group_id = BlockGroup::get_id(conn, &collection_name, None, ""); - let path = Path::get_paths( + let path = Path::query( conn, "select * from paths where block_group_id = ?1 AND name = ?2", - vec![ + rusqlite::params!( SQLValue::from(block_group_id), SQLValue::from("124".to_string()), - ], + ), )[0] .clone(); let result = path.sequence(conn); assert_eq!(result, "TATGCCAGCTGCGAATA"); - let node_count = Node::query(conn, "select * from nodes", vec![]).len() as i64; + let node_count = Node::query(conn, "select * from nodes", rusqlite::params!()).len() as i64; assert_eq!(node_count, 6); } @@ -330,17 +331,17 @@ mod tests { let conn = &get_connection(None); import_gfa(&gfa_path, &collection_name, conn); - let paths = Path::get_paths_for_collection(conn, &collection_name); + let paths = Path::query_for_collection(conn, &collection_name); assert_eq!(paths.len(), 20); let block_group_id = BlockGroup::get_id(conn, &collection_name, None, ""); - let path = Path::get_paths( + let path = Path::query( conn, "select * from paths where block_group_id = ?1 AND name = ?2", - vec![ + rusqlite::params!( SQLValue::from(block_group_id), SQLValue::from("BBa_J23100".to_string()), - ], + ), )[0] .clone(); @@ -423,7 +424,7 @@ mod tests { assert_eq!(all_sequences.len(), 1024); assert_eq!(all_sequences, expected_sequences); - let node_count = Node::query(conn, "select * from nodes", vec![]).len() as i64; + let node_count = Node::query(conn, "select * from nodes", rusqlite::params!()).len() as i64; assert_eq!(node_count, 28); } @@ -437,13 +438,13 @@ mod tests { import_gfa(&gfa_path, &collection_name, conn); let block_group_id = BlockGroup::get_id(conn, &collection_name, None, ""); - let path = Path::get_paths( + let path = Path::query( conn, "select * from paths where block_group_id = ?1 AND name = ?2", - vec![ + rusqlite::params!( SQLValue::from(block_group_id), SQLValue::from("124".to_string()), - ], + ), )[0] .clone(); @@ -453,7 +454,7 @@ mod tests { let all_sequences = BlockGroup::get_all_sequences(conn, block_group_id, false); assert_eq!(all_sequences, HashSet::from_iter(vec!["AA".to_string()])); - let node_count = Node::query(conn, "select * from nodes", vec![]).len() as i64; + let node_count = Node::query(conn, "select * from nodes", rusqlite::params!()).len() as i64; assert_eq!(node_count, 4); } } diff --git a/src/models/accession.rs b/src/models/accession.rs index 6685db9..f58ee0f 100644 --- a/src/models/accession.rs +++ b/src/models/accession.rs @@ -1,6 +1,6 @@ use crate::models::edge::EdgeData; use crate::models::strand::Strand; -use crate::models::traits::Query; +use crate::models::traits::*; use rusqlite::types::Value; use rusqlite::{params_from_iter, Connection, Result as SQLResult, Row}; use serde::{Deserialize, Serialize}; @@ -199,7 +199,7 @@ impl AccessionEdge { let formatted_edge_rows = edge_rows.join(", "); let select_statement = format!("SELECT * FROM accession_edges WHERE (source_node_id, source_coordinate, source_strand, target_node_id, target_coordinate, target_strand, chromosome_index) in ({0});", formatted_edge_rows); - let existing_edges = AccessionEdge::query(conn, &select_statement, vec![]); + let existing_edges = AccessionEdge::query(conn, &select_statement, rusqlite::params!()); for edge in existing_edges.iter() { edge_map.insert(AccessionEdgeData::from(edge), edge.id); } @@ -333,7 +333,7 @@ mod tests { Accession::query( conn, "select * from accessions where name = ?1", - vec![Value::from("test".to_string())] + rusqlite::params!(Value::from("test".to_string())), ), vec![Accession { id: accession.id, diff --git a/src/models/block_group.rs b/src/models/block_group.rs index 4aac2f2..a3413fe 100644 --- a/src/models/block_group.rs +++ b/src/models/block_group.rs @@ -1,8 +1,8 @@ use std::collections::{HashMap, HashSet}; +use std::rc::Rc; use interavl::IntervalTree as IT2; use intervaltree::IntervalTree; -use itertools::Itertools; use petgraph::graphmap::DiGraphMap; use petgraph::Direction; use rusqlite::{params_from_iter, types::Value as SQLValue, Connection, Row}; @@ -71,10 +71,10 @@ impl PathCache<'_> { if let Some(path) = path_lookup { path.clone() } else { - let new_path = Path::get_paths( + let new_path = Path::query( path_cache.conn, "select * from paths where block_group_id = ?1 AND name = ?2", - vec![SQLValue::from(block_group_id), SQLValue::from(name)], + rusqlite::params!(SQLValue::from(block_group_id), SQLValue::from(name)), )[0] .clone(); @@ -178,10 +178,10 @@ impl BlockGroup { } pub fn clone(conn: &Connection, source_block_group_id: i64, target_block_group_id: i64) { - let existing_paths = Path::get_paths( + let existing_paths = Path::query( conn, "SELECT * from paths where block_group_id = ?1 ORDER BY id ASC;", - vec![SQLValue::from(source_block_group_id)], + rusqlite::params!(SQLValue::from(source_block_group_id)), ); let edge_ids = BlockGroupEdge::edges_for_block_group(conn, source_block_group_id) @@ -203,16 +203,18 @@ impl BlockGroup { for accession in Accession::query( conn, - &format!( - "select * from accessions where path_id IN ({path_ids});", - path_ids = existing_paths.iter().map(|path| path.id).join(",") - ), - vec![], + "select * from accessions where path_id IN rarray(?1);", + rusqlite::params!(Rc::new( + existing_paths + .iter() + .map(|path| SQLValue::from(path.id)) + .collect::>() + )), ) { let edges = AccessionPath::query( conn, "Select * from accession_paths where accession_id = ?1 order by index_in_path ASC;", - vec![SQLValue::from(accession.id)], + rusqlite::params!(SQLValue::from(accession.id)), ); let new_path_id = path_map[&accession.path_id]; let obj = Accession::create( @@ -802,10 +804,10 @@ impl BlockGroup { } pub fn get_current_path(conn: &Connection, block_group_id: i64) -> Path { - let paths = Path::get_paths( + let paths = Path::query( conn, "SELECT * FROM paths WHERE block_group_id = ?1 ORDER BY id DESC", - vec![SQLValue::from(block_group_id)], + rusqlite::params!(SQLValue::from(block_group_id)), ); paths[0].clone() } @@ -872,7 +874,7 @@ mod tests { Accession::query( conn, "select * from accessions where name = ?1", - vec![SQLValue::from("test".to_string())] + rusqlite::params!(SQLValue::from("test".to_string())), ), vec![Accession { id: acc_1.id, @@ -890,7 +892,7 @@ mod tests { Accession::query( conn, "select * from accessions where name = ?1", - vec![SQLValue::from("test".to_string())] + rusqlite::params!(SQLValue::from("test".to_string())), ), vec![ Accession { @@ -1773,7 +1775,7 @@ mod tests { let new_path = Path::query( conn, "select * from paths where block_group_id = ?1", - vec![SQLValue::from(new_bg_id)], + rusqlite::params!(SQLValue::from(new_bg_id)), ); let insert_sequence = Sequence::new() .sequence_type("DNA") @@ -1951,7 +1953,7 @@ mod tests { let new_path = Path::query( conn, "select * from paths where block_group_id = ?1", - vec![SQLValue::from(new_bg_id)], + rusqlite::params!(SQLValue::from(new_bg_id)), ); let insert_sequence = Sequence::new() .sequence_type("DNA") @@ -2000,7 +2002,7 @@ mod tests { let new_path = Path::query( conn, "select * from paths where block_group_id = ?1", - vec![SQLValue::from(gc_bg_id)], + rusqlite::params!(SQLValue::from(gc_bg_id)), ); let insert = PathBlock { @@ -2046,7 +2048,7 @@ mod tests { let new_path = Path::query( conn, "select * from paths where block_group_id = ?1", - vec![SQLValue::from(new_bg_id)], + rusqlite::params!(SQLValue::from(new_bg_id)), ); let insert_sequence = Sequence::new() .sequence_type("DNA") @@ -2098,7 +2100,7 @@ mod tests { let new_path = Path::query( conn, "select * from paths where block_group_id = ?1", - vec![SQLValue::from(gc_bg_id)], + rusqlite::params!(SQLValue::from(gc_bg_id)), ); let insert_sequence = Sequence::new() @@ -2156,7 +2158,7 @@ mod tests { let new_path = Path::query( conn, "select * from paths where block_group_id = ?1", - vec![SQLValue::from(new_bg_id)], + rusqlite::params!(SQLValue::from(new_bg_id)), ); // This is a heterozygous replacement of 5 bases with 4 bases, so positions // downstream of this are not addressable. @@ -2210,7 +2212,7 @@ mod tests { let new_path = Path::query( conn, "select * from paths where block_group_id = ?1", - vec![SQLValue::from(gc_bg_id)], + rusqlite::params!(SQLValue::from(gc_bg_id)), ); let insert_sequence = Sequence::new() diff --git a/src/models/block_group_edge.rs b/src/models/block_group_edge.rs index dce5894..4b525b3 100644 --- a/src/models/block_group_edge.rs +++ b/src/models/block_group_edge.rs @@ -1,5 +1,7 @@ use crate::models::edge::Edge; use crate::models::traits::*; +use rusqlite; +use rusqlite::types::Value; use rusqlite::{Connection, Row}; #[derive(Clone, Debug)] @@ -40,11 +42,11 @@ impl BlockGroupEdge { } pub fn edges_for_block_group(conn: &Connection, block_group_id: i64) -> Vec { - let query = format!( - "select * from block_group_edges where block_group_id = {};", - block_group_id + let block_group_edges = BlockGroupEdge::query( + conn, + "select * from block_group_edges where block_group_id = ?1;", + rusqlite::params!(Value::from(block_group_id)), ); - let block_group_edges = BlockGroupEdge::query(conn, &query, vec![]); let edge_ids = block_group_edges .into_iter() .map(|block_group_edge| block_group_edge.edge_id) diff --git a/src/models/edge.rs b/src/models/edge.rs index 8f7dd8e..28cbcc5 100644 --- a/src/models/edge.rs +++ b/src/models/edge.rs @@ -5,6 +5,7 @@ use rusqlite::{params_from_iter, Connection, Result as SQLResult, Row}; use serde::{Deserialize, Serialize}; use std::collections::{HashMap, HashSet}; use std::hash::{Hash, RandomState}; +use std::rc::Rc; use crate::graph::{GraphEdge, GraphNode}; use crate::models::node::{Node, PATH_END_NODE_ID, PATH_START_NODE_ID}; @@ -200,13 +201,12 @@ impl Edge { } pub fn bulk_load(conn: &Connection, edge_ids: &[i64]) -> Vec { - let formatted_edge_ids = edge_ids + let query_edge_ids = edge_ids .iter() - .map(|edge_id| edge_id.to_string()) - .collect::>() - .join(","); - let query = format!("select id, source_node_id, source_coordinate, source_strand, target_node_id, target_coordinate, target_strand, chromosome_index, phased from edges where id in ({});", formatted_edge_ids); - Edge::query(conn, &query, vec![]) + .map(|edge_id| Value::from(*edge_id)) + .collect::>(); + let query = "select id, source_node_id, source_coordinate, source_strand, target_node_id, target_coordinate, target_strand, chromosome_index, phased from edges where id in rarray(?1);"; + Edge::query(conn, query, rusqlite::params!(Rc::new(query_edge_ids))) } pub fn bulk_create(conn: &Connection, edges: &Vec) -> Vec { @@ -231,7 +231,7 @@ impl Edge { let formatted_edge_rows = edge_rows.join(", "); let select_statement = format!("SELECT * FROM edges WHERE (source_node_id, source_coordinate, source_strand, target_node_id, target_coordinate, target_strand, chromosome_index, phased) in ({0});", formatted_edge_rows); - let existing_edges = Edge::query(conn, &select_statement, vec![]); + let existing_edges = Edge::query(conn, &select_statement, rusqlite::params!()); for edge in existing_edges.iter() { edge_map.insert(EdgeData::from(edge), edge.id); } @@ -669,7 +669,7 @@ mod tests { let binding = Edge::query( conn, "select * from edges where id = ?1;", - vec![Value::from(*id)], + rusqlite::params!(Value::from(*id)), ); let edge = binding.first().unwrap(); assert_eq!(EdgeData::from(edge), edges[index]); @@ -685,7 +685,7 @@ mod tests { let binding = Edge::query( conn, "select * from edges where id = ?1;", - vec![Value::from(*id)], + rusqlite::params!(Value::from(*id)), ); let edge = binding.first().unwrap(); assert_eq!(EdgeData::from(edge), edges[index]); diff --git a/src/models/node.rs b/src/models/node.rs index 2da7225..a2d6fd2 100644 --- a/src/models/node.rs +++ b/src/models/node.rs @@ -1,6 +1,7 @@ use rusqlite::{params_from_iter, types::Value as SQLValue, Connection, Row}; use serde::{Deserialize, Serialize}; use std::collections::HashMap; +use std::rc::Rc; use crate::models::sequence::Sequence; use crate::models::traits::*; @@ -65,13 +66,14 @@ impl Node { pub fn get_nodes(conn: &Connection, node_ids: Vec) -> Vec { let mut nodes: Vec = vec![]; for chunk in node_ids.chunks(1000) { + let query_node_ids: Vec = chunk + .iter() + .map(|node_id| SQLValue::from(*node_id)) + .collect(); nodes.extend(Node::query( conn, - &format!( - "SELECT * FROM nodes WHERE id IN ({})", - chunk.iter().map(|_| "?").collect::>().join(", ") - ), - chunk.iter().map(|id| SQLValue::Integer(*id)).collect(), + "SELECT * FROM nodes WHERE id IN rarray(?1);", + rusqlite::params!(Rc::new(query_node_ids)), )) } nodes diff --git a/src/models/operations.rs b/src/models/operations.rs index 02a6488..e0ce07f 100644 --- a/src/models/operations.rs +++ b/src/models/operations.rs @@ -1,10 +1,11 @@ use crate::graph::all_simple_paths; use crate::models::file_types::FileTypes; +use crate::models::traits::*; use petgraph::graphmap::{DiGraphMap, UnGraphMap}; use petgraph::visit::{Dfs, Reversed}; use petgraph::Direction; use rusqlite::types::Value; -use rusqlite::{params_from_iter, Connection}; +use rusqlite::{params_from_iter, Connection, Row}; use std::collections::HashSet; use std::string::ToString; @@ -95,7 +96,7 @@ impl Operation { pub fn get_operation_graph(conn: &Connection) -> DiGraphMap { let mut graph: DiGraphMap = DiGraphMap::new(); - let operations = Operation::query(conn, "select * from operation;", vec![]); + let operations = Operation::query(conn, "select * from operation;", rusqlite::params![]); for op in operations.iter() { graph.add_node(op.id); if let Some(v) = op.parent_id { @@ -148,28 +149,6 @@ impl Operation { patch_path } - pub fn query(conn: &Connection, query: &str, placeholders: Vec) -> Vec { - let mut stmt = conn.prepare(query).unwrap(); - let rows = stmt - .query_map(params_from_iter(placeholders), |row| { - Ok(Operation { - id: row.get(0)?, - db_uuid: row.get(1)?, - parent_id: row.get(2)?, - branch_id: row.get(3)?, - collection_name: row.get(4)?, - change_type: row.get(5)?, - change_id: row.get(6)?, - }) - }) - .unwrap(); - let mut objs = vec![]; - for row in rows { - objs.push(row.unwrap()); - } - objs - } - pub fn get(conn: &Connection, query: &str, placeholders: Vec) -> Operation { let mut stmt = conn.prepare(query).unwrap(); let mut rows = stmt @@ -197,6 +176,21 @@ impl Operation { } } +impl Query for Operation { + type Model = Operation; + fn process_row(row: &Row) -> Self::Model { + Operation { + id: row.get(0).unwrap(), + db_uuid: row.get(1).unwrap(), + parent_id: row.get(2).unwrap(), + branch_id: row.get(3).unwrap(), + collection_name: row.get(4).unwrap(), + change_type: row.get(5).unwrap(), + change_id: row.get(6).unwrap(), + } + } +} + pub struct FileAddition { pub id: i64, pub file_path: String, @@ -423,7 +417,7 @@ impl Branch { Operation::query( conn, "select * from operation where branch_id = ?1;", - vec![Value::from(branch_id)], + rusqlite::params!(Value::from(branch_id)), ) .iter() .map(|op| op.id) diff --git a/src/models/path.rs b/src/models/path.rs index decd87d..89fde60 100644 --- a/src/models/path.rs +++ b/src/models/path.rs @@ -4,7 +4,7 @@ use std::collections::{HashMap, HashSet}; use intervaltree::IntervalTree; use itertools::Itertools; use rusqlite::types::Value; -use rusqlite::{params_from_iter, Connection}; +use rusqlite::{params_from_iter, Connection, Row}; use serde::{Deserialize, Serialize}; use crate::models::block_group::NodeIntervalBlock; @@ -14,6 +14,7 @@ use crate::models::{ path_edge::PathEdge, sequence::Sequence, strand::Strand, + traits::*, }; use crate::range::{Range, RangeMapping}; @@ -147,32 +148,13 @@ impl Path { rows.next().unwrap().unwrap() } - pub fn get_paths(conn: &Connection, query: &str, placeholders: Vec) -> Vec { - let mut stmt = conn.prepare(query).unwrap(); - let rows = stmt - .query_map(params_from_iter(placeholders), |row| { - let path_id = row.get(0).unwrap(); - Ok(Path { - id: path_id, - block_group_id: row.get(1)?, - name: row.get(2)?, - }) - }) - .unwrap(); - let mut paths = vec![]; - for row in rows { - paths.push(row.unwrap()); - } - paths - } - - pub fn query(conn: &Connection, query: &str, placeholders: Vec) -> Vec { - Path::get_paths(conn, query, placeholders) - } - - pub fn get_paths_for_collection(conn: &Connection, collection_name: &str) -> Vec { + pub fn query_for_collection(conn: &Connection, collection_name: &str) -> Vec { let query = "SELECT * FROM paths JOIN block_groups ON paths.block_group_id = block_groups.id WHERE block_groups.collection_name = ?1"; - Path::get_paths(conn, query, vec![Value::from(collection_name.to_string())]) + Path::query( + conn, + query, + rusqlite::params!(Value::from(collection_name.to_string())), + ) } pub fn sequence(&self, conn: &Connection) -> String { @@ -596,6 +578,17 @@ impl Path { } } +impl Query for Path { + type Model = Path; + fn process_row(row: &Row) -> Self::Model { + Path { + id: row.get(0).unwrap(), + block_group_id: row.get(1).unwrap(), + name: row.get(2).unwrap(), + } + } +} + #[cfg(test)] mod tests { // Note this useful idiom: importing names from outer (for mod tests) scope. diff --git a/src/models/path_edge.rs b/src/models/path_edge.rs index 34ebba0..a47b564 100644 --- a/src/models/path_edge.rs +++ b/src/models/path_edge.rs @@ -1,7 +1,9 @@ use itertools::Itertools; +use rusqlite; use rusqlite::types::Value; use rusqlite::{params_from_iter, Connection, Row}; use std::collections::HashMap; +use std::rc::Rc; use crate::models::edge::Edge; use crate::models::traits::*; @@ -95,7 +97,7 @@ impl PathEdge { let path_edges = PathEdge::query( conn, "select * from path_edges where path_id = ?1 order by index_in_path ASC", - vec![Value::from(path_id)], + rusqlite::params!(Value::from(path_id)), ); let edge_ids = path_edges .into_iter() @@ -113,18 +115,14 @@ impl PathEdge { } pub fn edges_for_paths(conn: &Connection, path_ids: Vec) -> HashMap> { - let placeholder_string = path_ids.iter().map(|_| "?").join(","); + let query_path_ids = path_ids + .iter() + .map(|path_id| Value::from(*path_id)) + .collect::>(); let path_edges = PathEdge::query( conn, - format!( - "select * from path_edges where path_id in ({}) ORDER BY path_id, index_in_path", - placeholder_string - ) - .as_str(), - path_ids - .into_iter() - .map(Value::from) - .collect::>(), + "select * from path_edges where path_id in rarray(?1) ORDER BY path_id, index_in_path", + rusqlite::params!(Rc::new(query_path_ids)), ); let edge_ids = path_edges .clone() diff --git a/src/models/traits.rs b/src/models/traits.rs index a73a72a..069f3e4 100644 --- a/src/models/traits.rs +++ b/src/models/traits.rs @@ -1,14 +1,12 @@ use rusqlite::types::Value; -use rusqlite::{params_from_iter, Connection, Result, Row}; +use rusqlite::{params_from_iter, Connection, Params, Result, Row}; pub trait Query { type Model; - fn query(conn: &Connection, query: &str, placeholders: Vec) -> Vec { + fn query(conn: &Connection, query: &str, params: impl Params) -> Vec { let mut stmt = conn.prepare(query).unwrap(); let rows = stmt - .query_map(params_from_iter(placeholders), |row| { - Ok(Self::process_row(row)) - }) + .query_map(params, |row| Ok(Self::process_row(row))) .unwrap(); let mut objs = vec![]; for row in rows { diff --git a/src/operation_management.rs b/src/operation_management.rs index 7732b07..72926e9 100644 --- a/src/operation_management.rs +++ b/src/operation_management.rs @@ -5,6 +5,7 @@ use std::{fs, path::PathBuf, str}; use fallible_streaming_iterator::FallibleStreamingIterator; use itertools::Itertools; use petgraph::Direction; +use rusqlite; use rusqlite::session::ChangesetIter; use rusqlite::types::{FromSql, Value}; use rusqlite::{session, Connection}; @@ -216,7 +217,7 @@ pub fn get_changeset_dependencies(conn: &Connection, mut changes: &[u8]) -> Vec< "select * from block_groups where id in ({ids})", ids = previous_block_groups.iter().join(",") ), - vec![], + rusqlite::params!(), ), nodes: vec![], edges: Edge::query( @@ -225,15 +226,15 @@ pub fn get_changeset_dependencies(conn: &Connection, mut changes: &[u8]) -> Vec< "select * from edges where id in ({ids})", ids = previous_edges.iter().join(",") ), - vec![], + rusqlite::params!(), ), - paths: Path::get_paths( + paths: Path::query( conn, &format!( "select * from paths where id in ({ids})", ids = previous_paths.iter().join(",") ), - vec![], + rusqlite::params!(), ), accessions: Accession::query( conn, @@ -241,7 +242,7 @@ pub fn get_changeset_dependencies(conn: &Connection, mut changes: &[u8]) -> Vec< "select * from accessions where id in ({ids})", ids = previous_accessions.iter().join(",") ), - vec![], + rusqlite::params!(), ), accession_edges: AccessionEdge::query( conn, @@ -249,7 +250,7 @@ pub fn get_changeset_dependencies(conn: &Connection, mut changes: &[u8]) -> Vec< "select * from accession_edges where id in ({ids})", ids = previous_accession_edges.iter().join(",") ), - vec![], + rusqlite::params!(), ), }; serde_json::to_vec(&s).unwrap() @@ -742,7 +743,7 @@ pub fn reset(conn: &Connection, operation_conn: &Connection, db_uuid: &str, op_i for op in Operation::query( operation_conn, "select * from operation where parent_id = ?1", - vec![Value::from(op_id)], + rusqlite::params!(Value::from(op_id)), ) .iter() { @@ -925,7 +926,7 @@ mod tests { let binding = BlockGroup::query( conn, "select * from block_groups where id = ?1;", - vec![Value::from(bg_id)], + rusqlite::params!(Value::from(bg_id)), ); let dep_bg = binding.first().unwrap(); @@ -994,10 +995,15 @@ mod tests { conn, operation_conn, ); - let edge_count = Edge::query(conn, "select * from edges", vec![]).len(); - let node_count = Node::query(conn, "select * from nodes", vec![]).len(); - let sample_count = Sample::query(conn, "select * from samples", vec![]).len(); - let op_count = Operation::query(operation_conn, "select * from operation", vec![]).len(); + let edge_count = Edge::query(conn, "select * from edges", rusqlite::params!()).len(); + let node_count = Node::query(conn, "select * from nodes", rusqlite::params!()).len(); + let sample_count = Sample::query(conn, "select * from samples", rusqlite::params!()).len(); + let op_count = Operation::query( + operation_conn, + "select * from operation", + rusqlite::params!(), + ) + .len(); assert_eq!(edge_count, 2); assert_eq!(node_count, 3); assert_eq!(sample_count, 0); @@ -1011,10 +1017,15 @@ mod tests { operation_conn, None, ); - let edge_count = Edge::query(conn, "select * from edges", vec![]).len(); - let node_count = Node::query(conn, "select * from nodes", vec![]).len(); - let sample_count = Sample::query(conn, "select * from samples", vec![]).len(); - let op_count = Operation::query(operation_conn, "select * from operation", vec![]).len(); + let edge_count = Edge::query(conn, "select * from edges", rusqlite::params!()).len(); + let node_count = Node::query(conn, "select * from nodes", rusqlite::params!()).len(); + let sample_count = Sample::query(conn, "select * from samples", rusqlite::params!()).len(); + let op_count = Operation::query( + operation_conn, + "select * from operation", + rusqlite::params!(), + ) + .len(); // NOTE: The edge count is 10 because of the following: // * 1 edge from the source node to the node created by the fasta import // * 1 edge from the node created by the fasta import to the sink node @@ -1041,10 +1052,15 @@ mod tests { ), ); - let edge_count = Edge::query(conn, "select * from edges", vec![]).len(); - let node_count = Node::query(conn, "select * from nodes", vec![]).len(); - let sample_count = Sample::query(conn, "select * from samples", vec![]).len(); - let op_count = Operation::query(operation_conn, "select * from operation", vec![]).len(); + let edge_count = Edge::query(conn, "select * from edges", rusqlite::params!()).len(); + let node_count = Node::query(conn, "select * from nodes", rusqlite::params!()).len(); + let sample_count = Sample::query(conn, "select * from samples", rusqlite::params!()).len(); + let op_count = Operation::query( + operation_conn, + "select * from operation", + rusqlite::params!(), + ) + .len(); assert_eq!(edge_count, 2); assert_eq!(node_count, 3); assert_eq!(sample_count, 0); @@ -1057,10 +1073,15 @@ mod tests { OperationState::get_operation(operation_conn, &db_uuid).unwrap(), ), ); - let edge_count = Edge::query(conn, "select * from edges", vec![]).len(); - let node_count = Node::query(conn, "select * from nodes", vec![]).len(); - let sample_count = Sample::query(conn, "select * from samples", vec![]).len(); - let op_count = Operation::query(operation_conn, "select * from operation", vec![]).len(); + let edge_count = Edge::query(conn, "select * from edges", rusqlite::params!()).len(); + let node_count = Node::query(conn, "select * from nodes", rusqlite::params!()).len(); + let sample_count = Sample::query(conn, "select * from samples", rusqlite::params!()).len(); + let op_count = Operation::query( + operation_conn, + "select * from operation", + rusqlite::params!(), + ) + .len(); assert_eq!(edge_count, 10); assert_eq!(node_count, 5); assert_eq!(sample_count, 3); @@ -1118,7 +1139,7 @@ mod tests { patch_1_seqs ); assert_eq!( - BlockGroup::query(conn, "select * from block_groups;", vec![]) + BlockGroup::query(conn, "select * from block_groups;", rusqlite::params!()) .iter() .map(|v| v.sample_name.clone().unwrap_or("".to_string())) .collect::>(), @@ -1158,7 +1179,7 @@ mod tests { ); assert_ne!(patch_1_seqs, patch_2_seqs); assert_eq!( - BlockGroup::query(conn, "select * from block_groups;", vec![]) + BlockGroup::query(conn, "select * from block_groups;", rusqlite::params!()) .iter() .map(|v| v.sample_name.clone().unwrap_or("".to_string())) .collect::>(), @@ -1180,7 +1201,7 @@ mod tests { patch_2_seqs ); assert_eq!( - BlockGroup::query(conn, "select * from block_groups;", vec![]) + BlockGroup::query(conn, "select * from block_groups;", rusqlite::params!()) .iter() .map(|v| v.sample_name.clone().unwrap_or("".to_string())) .collect::>(), @@ -1224,10 +1245,15 @@ mod tests { conn, operation_conn, ); - let edge_count = Edge::query(conn, "select * from edges", vec![]).len(); - let node_count = Node::query(conn, "select * from nodes", vec![]).len(); - let sample_count = Sample::query(conn, "select * from samples", vec![]).len(); - let op_count = Operation::query(operation_conn, "select * from operation", vec![]).len(); + let edge_count = Edge::query(conn, "select * from edges", rusqlite::params!()).len(); + let node_count = Node::query(conn, "select * from nodes", rusqlite::params!()).len(); + let sample_count = Sample::query(conn, "select * from samples", rusqlite::params!()).len(); + let op_count = Operation::query( + operation_conn, + "select * from operation", + rusqlite::params!(), + ) + .len(); assert_eq!(edge_count, 2); assert_eq!(node_count, 3); assert_eq!(sample_count, 0); @@ -1252,10 +1278,15 @@ mod tests { operation_conn, None, ); - let edge_count = Edge::query(conn, "select * from edges", vec![]).len(); - let node_count = Node::query(conn, "select * from nodes", vec![]).len(); - let sample_count = Sample::query(conn, "select * from samples", vec![]).len(); - let op_count = Operation::query(operation_conn, "select * from operation", vec![]).len(); + let edge_count = Edge::query(conn, "select * from edges", rusqlite::params!()).len(); + let node_count = Node::query(conn, "select * from nodes", rusqlite::params!()).len(); + let sample_count = Sample::query(conn, "select * from samples", rusqlite::params!()).len(); + let op_count = Operation::query( + operation_conn, + "select * from operation", + rusqlite::params!(), + ) + .len(); assert_eq!(edge_count, 10); assert_eq!(node_count, 5); assert_eq!(sample_count, 3); @@ -1276,10 +1307,15 @@ mod tests { ); // ensure branch 1 operations have been undone - let edge_count = Edge::query(conn, "select * from edges", vec![]).len(); - let node_count = Node::query(conn, "select * from nodes", vec![]).len(); - let sample_count = Sample::query(conn, "select * from samples", vec![]).len(); - let op_count = Operation::query(operation_conn, "select * from operation", vec![]).len(); + let edge_count = Edge::query(conn, "select * from edges", rusqlite::params!()).len(); + let node_count = Node::query(conn, "select * from nodes", rusqlite::params!()).len(); + let sample_count = Sample::query(conn, "select * from samples", rusqlite::params!()).len(); + let op_count = Operation::query( + operation_conn, + "select * from operation", + rusqlite::params!(), + ) + .len(); assert_eq!(edge_count, 2); assert_eq!(node_count, 3); assert_eq!(sample_count, 0); @@ -1295,10 +1331,15 @@ mod tests { operation_conn, None, ); - let edge_count = Edge::query(conn, "select * from edges", vec![]).len(); - let node_count = Node::query(conn, "select * from nodes", vec![]).len(); - let sample_count = Sample::query(conn, "select * from samples", vec![]).len(); - let op_count = Operation::query(operation_conn, "select * from operation", vec![]).len(); + let edge_count = Edge::query(conn, "select * from edges", rusqlite::params!()).len(); + let node_count = Node::query(conn, "select * from nodes", rusqlite::params!()).len(); + let sample_count = Sample::query(conn, "select * from samples", rusqlite::params!()).len(); + let op_count = Operation::query( + operation_conn, + "select * from operation", + rusqlite::params!(), + ) + .len(); assert_eq!(edge_count, 6); assert_eq!(node_count, 4); assert_eq!(sample_count, 1); @@ -1317,10 +1358,15 @@ mod tests { branch_1.id ); - let edge_count = Edge::query(conn, "select * from edges", vec![]).len(); - let node_count = Node::query(conn, "select * from nodes", vec![]).len(); - let sample_count = Sample::query(conn, "select * from samples", vec![]).len(); - let op_count = Operation::query(operation_conn, "select * from operation", vec![]).len(); + let edge_count = Edge::query(conn, "select * from edges", rusqlite::params!()).len(); + let node_count = Node::query(conn, "select * from nodes", rusqlite::params!()).len(); + let sample_count = Sample::query(conn, "select * from samples", rusqlite::params!()).len(); + let op_count = Operation::query( + operation_conn, + "select * from operation", + rusqlite::params!(), + ) + .len(); assert_eq!(edge_count, 10); assert_eq!(node_count, 5); assert_eq!(sample_count, 3); diff --git a/src/test_helpers.rs b/src/test_helpers.rs index 385a5a5..823e9e5 100644 --- a/src/test_helpers.rs +++ b/src/test_helpers.rs @@ -192,14 +192,14 @@ where pub fn get_sample_bg<'a>(conn: &Connection, sample_name: impl Into>) -> BlockGroup { let sample_name = sample_name.into(); - let mut placeholders = vec![]; - let query; + let mut results; if let Some(name) = sample_name { - query = "select * from block_groups where sample_name = ?1"; - placeholders.push(Value::from(name.to_string())); + let query = "select * from block_groups where sample_name = ?1"; + let params = rusqlite::params!(Value::from(name.to_string())); + results = BlockGroup::query(conn, query, params); } else { - query = "select * from block_groups where sample_name is null"; + let query = "select * from block_groups where sample_name is null"; + results = BlockGroup::query(conn, query, rusqlite::params!()); } - let mut results = BlockGroup::query(conn, query, placeholders); results.pop().unwrap() } diff --git a/src/updates/fasta.rs b/src/updates/fasta.rs index 704158d..1093c93 100644 --- a/src/updates/fasta.rs +++ b/src/updates/fasta.rs @@ -45,16 +45,16 @@ pub fn update_with_fasta( block_groups = BlockGroup::query( conn, "select * from block_groups where collection_name = ?1 AND sample_name = ?2;", - vec![ + rusqlite::params!( SQLValue::from(collection_name.to_string()), SQLValue::from(parent_name.to_string()), - ], + ), ); } else { block_groups = BlockGroup::query( conn, "select * from block_groups where collection_name = ?1 AND sample_name IS NULL;", - vec![SQLValue::from(collection_name.to_string())], + rusqlite::params!(SQLValue::from(collection_name.to_string())), ); } @@ -131,13 +131,13 @@ pub fn update_with_fasta( let edge_to_new_node = Edge::query( conn, "select * from edges where target_node_id = ?1", - vec![SQLValue::from(node_id)], + rusqlite::params!(SQLValue::from(node_id)), )[0] .clone(); let edge_from_new_node = Edge::query( conn, "select * from edges where source_node_id = ?1", - vec![SQLValue::from(node_id)], + rusqlite::params!(SQLValue::from(node_id)), )[0] .clone(); let new_path = path.new_path_with( @@ -217,10 +217,10 @@ mod tests { let block_groups = BlockGroup::query( conn, "select * from block_groups where collection_name = ?1 AND sample_name = ?2;", - vec![ + rusqlite::params!( SQLValue::from(collection), SQLValue::from("child sample".to_string()), - ], + ), ); assert_eq!(block_groups.len(), 1); assert_eq!( @@ -289,10 +289,10 @@ mod tests { let block_groups = BlockGroup::query( conn, "select * from block_groups where collection_name = ?1 AND sample_name = ?2;", - vec![ + rusqlite::params!( SQLValue::from(collection), SQLValue::from("grandchild sample".to_string()), - ], + ), ); assert_eq!(block_groups.len(), 1); assert_eq!( @@ -361,10 +361,10 @@ mod tests { let block_groups = BlockGroup::query( conn, "select * from block_groups where collection_name = ?1 AND sample_name = ?2;", - vec![ + rusqlite::params!( SQLValue::from(collection), SQLValue::from("grandchild sample".to_string()), - ], + ), ); assert_eq!(block_groups.len(), 1); assert_eq!( @@ -439,10 +439,10 @@ mod tests { let block_groups = BlockGroup::query( conn, "select * from block_groups where collection_name = ?1 AND sample_name = ?2;", - vec![ + rusqlite::params!( SQLValue::from(collection), SQLValue::from("grandchild sample".to_string()), - ], + ), ); assert_eq!(block_groups.len(), 1); assert_eq!( @@ -511,10 +511,10 @@ mod tests { let block_groups = BlockGroup::query( conn, "select * from block_groups where collection_name = ?1 AND sample_name = ?2;", - vec![ + rusqlite::params!( SQLValue::from(collection), SQLValue::from("grandchild sample".to_string()), - ], + ), ); assert_eq!(block_groups.len(), 1); assert_eq!( @@ -581,10 +581,10 @@ mod tests { let block_groups = BlockGroup::query( conn, "select * from block_groups where collection_name = ?1 AND sample_name = ?2;", - vec![ + rusqlite::params!( SQLValue::from(collection), SQLValue::from("grandchild sample".to_string()), - ], + ), ); assert_eq!(block_groups.len(), 1); assert_eq!( diff --git a/src/updates/library.rs b/src/updates/library.rs index c3aaaf8..c8ad782 100644 --- a/src/updates/library.rs +++ b/src/updates/library.rs @@ -16,6 +16,7 @@ use crate::models::operations::{FileAddition, Operation, OperationSummary}; use crate::models::path::Path; use crate::models::sequence::Sequence; use crate::models::strand::Strand; +use crate::models::traits::*; use crate::{calculate_hash, operation_management}; #[allow(clippy::too_many_arguments)] @@ -45,10 +46,10 @@ pub fn update_with_library( let mut parts_reader = fasta::io::reader::Builder.build_from_path(parts_file_path)?; - let path = Path::get_paths( + let path = Path::query( conn, "select * from paths where name = ?1", - vec![SQLValue::from(path_name.to_string())], + rusqlite::params!(SQLValue::from(path_name.to_string())), )[0] .clone(); diff --git a/src/updates/vcf.rs b/src/updates/vcf.rs index 701619c..2462cb2 100644 --- a/src/updates/vcf.rs +++ b/src/updates/vcf.rs @@ -22,6 +22,7 @@ use noodles::vcf::variant::record::samples::series::Value; use noodles::vcf::variant::record::samples::Sample as NoodlesSample; use noodles::vcf::variant::record::AlternateBases; use noodles::vcf::variant::Record; +use rusqlite; use rusqlite::{session, types::Value as SQLValue, Connection}; #[derive(Debug)] @@ -380,7 +381,7 @@ pub fn update_with_vcf<'a>( let sequence_string = sequence.get_sequence(None, None); let parent_path_id : i64 = *parent_block_groups.entry((collection_name, vcf_entry.path.id)).or_insert_with(|| { - let parent_bg = BlockGroup::query(conn, "select * from block_groups where collection_name = ?1 AND sample_name is null and name = ?2", vec![SQLValue::from(collection_name.to_string()), SQLValue::from(vcf_entry.path.name.clone())]); + let parent_bg = BlockGroup::query(conn, "select * from block_groups where collection_name = ?1 AND sample_name is null and name = ?2", rusqlite::params!(SQLValue::from(collection_name.to_string()), SQLValue::from(vcf_entry.path.name.clone()))); if parent_bg.is_empty() { vcf_entry.path.id } else { @@ -463,7 +464,6 @@ mod tests { use crate::models::accession::Accession; use crate::models::node::Node; use crate::models::operations::setup_db; - use crate::models::traits::Query; use crate::test_helpers::{ get_connection, get_operation_connection, get_sample_bg, setup_gen_dir, }; @@ -516,7 +516,7 @@ mod tests { let test_bg = BlockGroup::query( conn, "select * from block_groups where sample_name = ?1", - vec![SQLValue::from("G1".to_string())], + rusqlite::params!(SQLValue::from("G1".to_string())), ); assert_eq!( BlockGroup::get_all_sequences(conn, test_bg[0].id, false), @@ -617,7 +617,7 @@ mod tests { let missing_allele_bg = BlockGroup::query( conn, "select * from block_groups where sample_name = ?1", - vec![SQLValue::from("unknown".to_string())], + rusqlite::params!(SQLValue::from("unknown".to_string())), ); assert_eq!( @@ -709,7 +709,7 @@ mod tests { None, ); - let nodes = Node::query(conn, "select * from nodes;", vec![]); + let nodes = Node::query(conn, "select * from nodes;", rusqlite::params!()); assert_eq!(nodes.len(), 5); update_with_vcf( @@ -721,7 +721,7 @@ mod tests { op_conn, None, ); - let nodes = Node::query(conn, "select * from nodes;", vec![]); + let nodes = Node::query(conn, "select * from nodes;", rusqlite::params!()); assert_eq!(nodes.len(), 5); } @@ -747,7 +747,10 @@ mod tests { op_conn, ); - assert_eq!(Node::query(conn, "select * from nodes;", vec![]).len(), 5); + assert_eq!( + Node::query(conn, "select * from nodes;", rusqlite::params!()).len(), + 5 + ); update_with_vcf( &vcf_path.to_str().unwrap().to_string(), @@ -759,7 +762,7 @@ mod tests { None, ); - let nodes = Node::query(conn, "select * from nodes;", vec![]); + let nodes = Node::query(conn, "select * from nodes;", rusqlite::params!()); assert_eq!(nodes.len(), 8); update_with_vcf( @@ -771,7 +774,7 @@ mod tests { op_conn, None, ); - let nodes = Node::query(conn, "select * from nodes;", vec![]); + let nodes = Node::query(conn, "select * from nodes;", rusqlite::params!()); assert_eq!(nodes.len(), 8); } @@ -846,7 +849,7 @@ mod tests { Accession::query( conn, "select * from accessions where name = ?1;", - vec![SQLValue::from("del1".to_string())] + rusqlite::params!(SQLValue::from("del1".to_string())), ) .len(), 1 @@ -856,7 +859,7 @@ mod tests { Accession::query( conn, "select * from accessions where name = ?1;", - vec![SQLValue::from("lp1".to_string())] + rusqlite::params!(SQLValue::from("lp1".to_string())), ) .len(), 1 @@ -900,7 +903,7 @@ mod tests { Accession::query( conn, "select * from accessions where name = ?1", - vec![SQLValue::from("lp1".to_string())] + rusqlite::params!(SQLValue::from("lp1".to_string())) ) .len(), 1