Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Respect group flag in status query filter #513

Merged
merged 1 commit into from
Mar 20, 2024
Merged
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
3 changes: 1 addition & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion pueue/src/client/display/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
21 changes: 18 additions & 3 deletions pueue/src/client/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<String>,

/// The list of selected columns based.
pub selected_columns: Vec<Rule>,

Expand All @@ -30,14 +33,23 @@ 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)>,
}

impl QueryResult {
/// Take a list of tasks and apply all filters to it.
pub fn apply_filters(&self, tasks: Vec<Task>) -> Vec<Task> {
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::<Vec<Task>>()
.into_iter();
}

for filter in self.filters.iter() {
iter = iter.filter(filter).collect::<Vec<Task>>().into_iter();
}
Expand Down Expand Up @@ -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<QueryResult> {
pub fn apply_query(query: &str, group: &Option<String>) -> Result<QueryResult> {
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.
Expand Down
32 changes: 22 additions & 10 deletions pueue/tests/client/unit/status_query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ pub fn test_tasks() -> Vec<Task> {
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
Expand All @@ -80,10 +81,10 @@ pub fn test_tasks() -> Vec<Task> {
tasks
}

fn test_tasks_with_query(query: &str) -> Result<Vec<Task>> {
fn test_tasks_with_query(query: &str, group: &Option<String>) -> Result<Vec<Task>> {
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);
Expand All @@ -94,7 +95,7 @@ fn test_tasks_with_query(query: &str) -> Result<Vec<Task>> {
/// 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]
Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -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 },
Expand All @@ -153,21 +154,32 @@ 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);

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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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.
Expand Down
Loading