Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 114 additions & 22 deletions gen-models/src/block_group.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,56 @@ pub struct NewBlockGroup<'a> {
pub is_default: bool,
}

#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct BlockGroupSelect<'a> {
pub collection_name: Option<&'a str>,
pub sample_name: Option<&'a str>,
pub name: Option<&'a str>,
pub page: PageRequest,
pub order_by: Vec<(String, Direction)>,
}

impl ModelSelect for BlockGroupSelect<'_> {
fn source_clause(&self) -> String {
"block_groups".to_string()
}

fn filters(&self) -> Vec<SqlFilter> {
let mut filters = vec![];

if let Some(collection_name) = self.collection_name {
filters.push(SqlFilter::new(
"collection_name = ?",
vec![SQLValue::from(collection_name.to_string())],
));
}

if let Some(sample_name) = self.sample_name {
filters.push(SqlFilter::new(
"sample_name = ?",
vec![SQLValue::from(sample_name.to_string())],
));
}

if let Some(name) = self.name {
filters.push(SqlFilter::new(
"name = ?",
vec![SQLValue::from(name.to_string())],
));
}

filters
}

fn order_by(&self) -> &[(String, Direction)] {
&self.order_by
}

fn page(&self) -> PageRequest {
self.page
}
}

#[derive(Clone, Debug)]
pub struct PathChange {
pub block_group_id: HashId,
Expand Down Expand Up @@ -194,6 +244,10 @@ impl<'a> PathCache<'a> {
}

impl BlockGroup {
pub fn select(conn: &GraphConnection, select: &BlockGroupSelect<'_>) -> Vec<BlockGroup> {
<Self as QuerySelect>::select(conn, select)
}

pub fn create(conn: &GraphConnection, new_block_group: NewBlockGroup<'_>) -> BlockGroup {
Sample::get_or_create(conn, new_block_group.sample_name);
let hash = BlockGroup::get_id(
Expand Down Expand Up @@ -328,12 +382,18 @@ impl BlockGroup {
group_name: &str,
parent_samples: Vec<String>,
) -> Result<Vec<BlockGroup>, QueryError> {
let existing_block_groups = BlockGroup::query(
let existing_block_groups = BlockGroup::select(
conn,
"select * from block_groups
where collection_name = ?1 AND sample_name = ?2 AND name = ?3
order by created_on, id",
params![collection_name, sample_name, group_name],
&BlockGroupSelect {
collection_name: Some(collection_name),
sample_name: Some(sample_name),
name: Some(group_name),
order_by: vec![
("created_on".to_string(), Direction::Asc),
("id".to_string(), Direction::Asc),
],
..Default::default()
},
);

if !existing_block_groups.is_empty() {
Expand Down Expand Up @@ -1010,32 +1070,41 @@ impl BlockGroup {
}

pub fn get_current_path(conn: &GraphConnection, block_group_id: &HashId) -> Path {
let paths = Path::query(
Path::select(
conn,
"SELECT * FROM paths WHERE block_group_id = ?1 ORDER BY created_on DESC",
params![block_group_id],
);
paths[0].clone()
&crate::path::PathSelect {
block_group_id: Some(block_group_id),
page: PageRequest::first(1),
order_by: vec![
("paths.created_on".to_string(), Direction::Desc),
("paths.id".to_string(), Direction::Desc),
],
..Default::default()
},
)[0]
.clone()
}

pub fn get_path_by_name(
conn: &GraphConnection,
block_group_id: &HashId,
path_name: &str,
) -> Option<Path> {
let paths = Path::query(
Path::select(
conn,
"SELECT * FROM paths WHERE block_group_id = ?1 ORDER BY created_on DESC",
params![block_group_id],
);

for path in &paths {
if path.name == path_name {
return Some(path.clone());
}
}

None
&crate::path::PathSelect {
block_group_id: Some(block_group_id),
name: Some(path_name),
page: PageRequest::first(1),
order_by: vec![
("paths.created_on".to_string(), Direction::Desc),
("paths.id".to_string(), Direction::Desc),
],
..Default::default()
},
)
.into_iter()
.next()
}

#[allow(clippy::too_many_arguments)]
Expand Down Expand Up @@ -1321,6 +1390,29 @@ mod tests {
assert_eq!(block_group, deserialized);
}

#[test]
fn test_search_supports_sort_and_pagination() {
let conn = &get_connection(None).unwrap();
Collection::create(conn, "test");

let alpha = create_bg(conn, "test", "sample-a", "alpha");
let beta = create_bg(conn, "test", "sample-a", "beta");
let gamma = create_bg(conn, "test", "sample-b", "gamma");

let matches = BlockGroup::select(
conn,
&BlockGroupSelect {
collection_name: Some("test"),
page: PageRequest::new(Some(2), 1),
order_by: vec![("created_on".to_string(), Direction::Asc)],
..Default::default()
},
);

assert_eq!(matches, vec![beta, gamma]);
assert_eq!(alpha.name, "alpha");
}

#[test]
fn test_capnp_deserialization_defaults_missing_parent_to_none() {
let created_on = Utc::now().timestamp_nanos_opt().unwrap();
Expand Down
116 changes: 111 additions & 5 deletions gen-models/src/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,68 @@ pub struct PathData {
pub block_group_id: HashId,
}

#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct PathSelect<'a> {
pub collection_name: Option<&'a str>,
pub sample_name: Option<&'a str>,
pub block_group_id: Option<&'a HashId>,
pub name: Option<&'a str>,
pub page: PageRequest,
pub order_by: Vec<(String, Direction)>,
}

impl ModelSelect for PathSelect<'_> {
fn source_clause(&self) -> String {
"paths LEFT JOIN block_groups ON paths.block_group_id = block_groups.id".to_string()
}

fn select_clause(&self) -> &'static str {
"paths.*"
}

fn filters(&self) -> Vec<SqlFilter> {
let mut filters = vec![];

if let Some(collection_name) = self.collection_name {
filters.push(SqlFilter::new(
"block_groups.collection_name = ?",
vec![SQLValue::from(collection_name.to_string())],
));
}

if let Some(sample_name) = self.sample_name {
filters.push(SqlFilter::new(
"block_groups.sample_name = ?",
vec![SQLValue::from(sample_name.to_string())],
));
}

if let Some(block_group_id) = self.block_group_id {
filters.push(SqlFilter::new(
"paths.block_group_id = ?",
vec![SQLValue::from(*block_group_id)],
));
}

if let Some(name) = self.name {
filters.push(SqlFilter::new(
"paths.name = ?",
vec![SQLValue::from(name.to_string())],
));
}

filters
}

fn order_by(&self) -> &[(String, Direction)] {
&self.order_by
}

fn page(&self) -> PageRequest {
self.page
}
}

// interesting gist here: https://gist.github.com/mbhall88/cd900add6335c96127efea0e0f6a9f48, see if we
// can expand this to ambiguous bases/keep case
pub fn revcomp(seq: &str) -> String {
Expand Down Expand Up @@ -227,18 +289,35 @@ impl Path {
Path::get(conn, "select * from paths where id = ?1;", params![path_id]).unwrap()
}

pub fn select(conn: &GraphConnection, select: &PathSelect<'_>) -> Vec<Path> {
<Self as QuerySelect>::select(conn, select)
}

pub fn query_for_collection(conn: &GraphConnection, collection_name: &str) -> Vec<Path> {
let query = "SELECT * FROM paths JOIN block_groups ON paths.block_group_id = block_groups.id WHERE block_groups.collection_name = ?1";
Path::query(conn, query, params![collection_name])
Path::select(
conn,
&PathSelect {
collection_name: Some(collection_name),
order_by: vec![("paths.created_on".to_string(), Direction::Desc)],
..Default::default()
},
)
}

pub fn query_for_collection_and_sample(
conn: &GraphConnection,
collection_name: &str,
sample_name: &str,
) -> Vec<Path> {
let query = "SELECT * FROM paths JOIN block_groups ON paths.block_group_id = block_groups.id WHERE block_groups.collection_name = ?1 AND block_groups.sample_name = ?2";
Path::query(conn, query, params![collection_name, sample_name])
Path::select(
conn,
&PathSelect {
collection_name: Some(collection_name),
sample_name: Some(sample_name),
order_by: vec![("paths.created_on".to_string(), Direction::Desc)],
..Default::default()
},
)
}

pub fn sequence(&self, conn: &GraphConnection) -> String {
Expand Down Expand Up @@ -849,7 +928,7 @@ mod tests {
block_group::{BlockGroup, NewBlockGroup},
block_group_edge::BlockGroupEdgeData,
collection::Collection,
test_helpers::get_connection,
test_helpers::{get_connection, setup_block_group},
};

fn create_test_block_group(conn: &GraphConnection) -> BlockGroup {
Expand Down Expand Up @@ -881,6 +960,33 @@ mod tests {
assert_eq!(path, deserialized);
}

#[test]
fn test_search_supports_sort_and_pagination() {
let conn = &get_connection(None).unwrap();
let (block_group_id, seed_path) = setup_block_group(conn);
let edge_ids = PathEdge::edges_for_path(conn, &seed_path.id)
.into_iter()
.map(|edge| edge.id)
.collect::<Vec<_>>();

let alpha = Path::create(conn, "alpha", &block_group_id, &edge_ids);
let beta = Path::create(conn, "beta", &block_group_id, &edge_ids);
let gamma = Path::create(conn, "gamma", &block_group_id, &edge_ids);

let matches = Path::select(
conn,
&PathSelect {
collection_name: Some("test"),
page: PageRequest::new(Some(2), 1),
order_by: vec![("paths.created_on".to_string(), Direction::Asc)],
..Default::default()
},
);

assert_eq!(matches, vec![alpha, beta]);
assert_eq!(gamma.name, "gamma");
}

#[test]
fn test_path_delete() {
let conn = &get_connection(None).unwrap();
Expand Down
Loading
Loading