From 642e3722e342f212fd880f60ab709d4d525d19b4 Mon Sep 17 00:00:00 2001 From: Arne Beer Date: Wed, 20 Mar 2024 19:45:09 +0100 Subject: [PATCH] fix: Respect group flag in status query filter --- CHANGELOG.md | 3 +-- pueue/src/client/display/state.rs | 2 +- pueue/src/client/query/mod.rs | 21 +++++++++++++--- pueue/tests/client/unit/status_query.rs | 32 +++++++++++++++++-------- 4 files changed, 42 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0becc56e..74dccab0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,10 +15,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ### Fixed - Include priority in `Task`s' `Debug` output - - Fix reading of configuration files that lacks a `shared` section. - - Made the daemon exit gracefully (exit code 0) on SIGINT and SIGTEM. +- Respect the `-g` flag when using the `status` filter query. [#508](https://github.com/Nukesor/pueue/issues/508) ## [3.3.3] - 2024-01-04 diff --git a/pueue/src/client/display/state.rs b/pueue/src/client/display/state.rs index 2ddc515c..528c0ce1 100644 --- a/pueue/src/client/display/state.rs +++ b/pueue/src/client/display/state.rs @@ -32,7 +32,7 @@ pub fn print_state( let mut table_builder = TableBuilder::new(settings, style); if let Some(query) = query { - let query_result = apply_query(&query.join(" "))?; + let query_result = apply_query(&query.join(" "), &group_only)?; table_builder.set_visibility_by_rules(&query_result.selected_columns); tasks = query_result.apply_filters(tasks); tasks = query_result.order_tasks(tasks); diff --git a/pueue/src/client/query/mod.rs b/pueue/src/client/query/mod.rs index 504fba60..419840f5 100644 --- a/pueue/src/client/query/mod.rs +++ b/pueue/src/client/query/mod.rs @@ -21,6 +21,9 @@ type FilterFunction = dyn Fn(&Task) -> bool; /// All applicable information that has been extracted from the query. #[derive(Default)] pub struct QueryResult { + /// Filter results for a single group. + group: Option, + /// The list of selected columns based. pub selected_columns: Vec, @@ -30,7 +33,7 @@ pub struct QueryResult { /// A list of filter functions that should be applied to the list of tasks. order_by: Option<(Rule, Direction)>, - /// limit + /// Limit limit: Option<(Limit, usize)>, } @@ -38,6 +41,15 @@ impl QueryResult { /// Take a list of tasks and apply all filters to it. pub fn apply_filters(&self, tasks: Vec) -> Vec { let mut iter = tasks.into_iter(); + + // If requested, only look at tasks of a specific group. + if let Some(group) = &self.group { + iter = iter + .filter(|task| task.group == *group) + .collect::>() + .into_iter(); + } + for filter in self.filters.iter() { iter = iter.filter(filter).collect::>().into_iter(); } @@ -116,10 +128,13 @@ impl QueryResult { /// - TableBuilder: The component responsible for building the table and determining which /// columns should or need to be displayed. /// A `columns [columns]` statement will define the set of visible columns. -pub fn apply_query(query: &str) -> Result { +pub fn apply_query(query: &str, group: &Option) -> Result { let mut parsed = QueryParser::parse(Rule::query, query).context("Failed to parse query")?; - let mut query_result = QueryResult::default(); + let mut query_result = QueryResult { + group: group.clone(), + ..Default::default() + }; // Expect there to be exactly one pair for the full query. // Return early if we got an empty query. diff --git a/pueue/tests/client/unit/status_query.rs b/pueue/tests/client/unit/status_query.rs index 8b276309..189781b6 100644 --- a/pueue/tests/client/unit/status_query.rs +++ b/pueue/tests/client/unit/status_query.rs @@ -58,6 +58,7 @@ pub fn test_tasks() -> Vec { enqueue_at: Some(Local.with_ymd_and_hms(2022, 1, 10, 11, 0, 0).unwrap()), }; scheduled.id = 3; + scheduled.group = "testgroup".to_string(); tasks.insert(scheduled.id, scheduled); // Running task @@ -80,10 +81,10 @@ pub fn test_tasks() -> Vec { tasks } -fn test_tasks_with_query(query: &str) -> Result> { +fn test_tasks_with_query(query: &str, group: &Option) -> Result> { let mut tasks = test_tasks(); - let query_result = apply_query(query)?; + let query_result = apply_query(query, group)?; tasks = query_result.apply_filters(tasks); tasks = query_result.order_tasks(tasks); tasks = query_result.limit_tasks(tasks); @@ -94,7 +95,7 @@ fn test_tasks_with_query(query: &str) -> Result> { /// Select only specific columns for printing #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn column_selection() -> Result<()> { - let result = apply_query("columns=id,status,command")?; + let result = apply_query("columns=id,status,command", &None)?; assert_eq!( result.selected_columns, [Rule::column_id, Rule::column_status, Rule::column_command] @@ -106,7 +107,7 @@ async fn column_selection() -> Result<()> { /// Select the first few entries of the list #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn limit_first() -> Result<()> { - let tasks = test_tasks_with_query("first 4")?; + let tasks = test_tasks_with_query("first 4", &None)?; assert!(tasks.len() == 4); assert_eq!(tasks[0].id, 0); @@ -118,7 +119,7 @@ async fn limit_first() -> Result<()> { /// Select the last few entries of the list #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn limit_last() -> Result<()> { - let tasks = test_tasks_with_query("last 4")?; + let tasks = test_tasks_with_query("last 4", &None)?; assert!(tasks.len() == 4); assert_eq!(tasks[0].id, 3); @@ -130,7 +131,7 @@ async fn limit_last() -> Result<()> { /// Order the test state by task status. #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn order_by_status() -> Result<()> { - let tasks = test_tasks_with_query("order_by status")?; + let tasks = test_tasks_with_query("order_by status", &None)?; let expected = vec![ TaskStatus::Stashed { enqueue_at: None }, @@ -153,7 +154,7 @@ async fn order_by_status() -> Result<()> { /// Filter by start date #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn filter_start() -> Result<()> { - let tasks = test_tasks_with_query("start>2022-01-10 09:00:00")?; + let tasks = test_tasks_with_query("start>2022-01-10 09:00:00", &None)?; assert!(tasks.len() == 1); assert_eq!(tasks[0].id, 0); @@ -161,13 +162,24 @@ async fn filter_start() -> Result<()> { Ok(()) } +/// Filtering in combination with groups works as expected +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn filter_with_group() -> Result<()> { + let tasks = test_tasks_with_query("status=stashed", &Some("testgroup".to_string()))?; + + assert!(tasks.len() == 1); + assert_eq!(tasks[0].id, 3); + + Ok(()) +} + /// Filter by end date with the current time as a time and a date. #[rstest] #[case("2022-01-10")] #[case("2022-01-10 09:00:00")] #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn filter_end_with_time(#[case] format: &'static str) -> Result<()> { - let tasks = test_tasks_with_query(&format!("end<{format}"))?; + let tasks = test_tasks_with_query(&format!("end<{format}"), &None)?; assert!(tasks.len() == 1); assert_eq!(tasks[0].id, 1); @@ -195,7 +207,7 @@ async fn filter_status(#[case] status: TaskStatus, #[case] match_count: usize) - _ => anyhow::bail!("Got unexpected TaskStatus in filter_status"), }; - let tasks = test_tasks_with_query(&format!("status={status_filter}"))?; + let tasks = test_tasks_with_query(&format!("status={status_filter}"), &None)?; for task in tasks.iter() { let id = task.id; @@ -228,7 +240,7 @@ async fn filter_label( #[case] label_filter: &'static str, #[case] match_count: usize, ) -> Result<()> { - let tasks = test_tasks_with_query(&format!("label{operator}{label_filter}"))?; + let tasks = test_tasks_with_query(&format!("label{operator}{label_filter}"), &None)?; for task in tasks.iter() { // Make sure the task either has no label or the label doesn't match the filter.