fix: preserve accepted Ticket query filters
This commit is contained in:
@@ -354,11 +354,11 @@ impl SqliteWorkspaceAuthority {
|
|||||||
}
|
}
|
||||||
if let Some(value) = &query.updated_after {
|
if let Some(value) = &query.updated_after {
|
||||||
let value = bind(SqlValue::Text(value.clone()));
|
let value = bind(SqlValue::Text(value.clone()));
|
||||||
predicates.push(format!("COALESCE(t.updated_at,'')>={value}"));
|
predicates.push(format!("COALESCE(t.updated_at,'')>{value}"));
|
||||||
}
|
}
|
||||||
if let Some(value) = &query.updated_before {
|
if let Some(value) = &query.updated_before {
|
||||||
let value = bind(SqlValue::Text(value.clone()));
|
let value = bind(SqlValue::Text(value.clone()));
|
||||||
predicates.push(format!("COALESCE(t.updated_at,'')<={value}"));
|
predicates.push(format!("COALESCE(t.updated_at,'')<{value}"));
|
||||||
}
|
}
|
||||||
if let Some(value) = &query.linked_objective_id {
|
if let Some(value) = &query.linked_objective_id {
|
||||||
let value = bind(SqlValue::Text(value.clone()));
|
let value = bind(SqlValue::Text(value.clone()));
|
||||||
@@ -373,7 +373,9 @@ impl SqliteWorkspaceAuthority {
|
|||||||
.relation_kind
|
.relation_kind
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|value| bind(SqlValue::Text(value.clone())));
|
.map(|value| bind(SqlValue::Text(value.clone())));
|
||||||
let related = related.map(|value| format!("AND ((r.ticket_id=t.ticket_id AND r.target={value}) OR (r.target=t.ticket_id AND r.ticket_id={value}))")).unwrap_or_default();
|
let related = related
|
||||||
|
.map(|value| format!("AND r.ticket_id=t.ticket_id AND r.target={value}"))
|
||||||
|
.unwrap_or_else(|| "AND r.ticket_id=t.ticket_id".to_string());
|
||||||
let kind = kind
|
let kind = kind
|
||||||
.map(|value| format!("AND r.kind={value}"))
|
.map(|value| format!("AND r.kind={value}"))
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
@@ -427,14 +429,20 @@ impl SqliteWorkspaceAuthority {
|
|||||||
"CASE WHEN {merge_request_id} IS NULL THEN 'none' WHEN {review_decision}='approve' THEN 'approved' WHEN {review_decision}='request_changes' THEN 'request_changes' ELSE 'pending' END"
|
"CASE WHEN {merge_request_id} IS NULL THEN 'none' WHEN {review_decision}='approve' THEN 'approved' WHEN {review_decision}='request_changes' THEN 'request_changes' ELSE 'pending' END"
|
||||||
);
|
);
|
||||||
let has_commit = format!(
|
let has_commit = format!(
|
||||||
"({merge_request_id} IS NOT NULL OR EXISTS (SELECT 1 FROM typed_ticket_event_references reference WHERE reference.workspace_id=t.workspace_id AND reference.ticket_id=t.ticket_id AND reference.kind='commit'))"
|
"({review_subject} IS NOT NULL OR EXISTS (SELECT 1 FROM typed_ticket_event_references reference WHERE reference.workspace_id=t.workspace_id AND reference.ticket_id=t.ticket_id AND reference.kind='commit'))"
|
||||||
);
|
);
|
||||||
for event_kind in &query.event_kinds {
|
if !query.event_kinds.is_empty() {
|
||||||
let event_kind = bind(SqlValue::Text(event_kind.clone()));
|
let event_kinds = query
|
||||||
predicates.push(format!("EXISTS (SELECT 1 FROM typed_ticket_events event WHERE event.workspace_id=t.workspace_id AND event.ticket_id=t.ticket_id AND event.kind={event_kind})"));
|
.event_kinds
|
||||||
|
.iter()
|
||||||
|
.map(|event_kind| bind(SqlValue::Text(event_kind.clone())))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
predicates.push(format!("EXISTS (SELECT 1 FROM typed_ticket_events event WHERE event.workspace_id=t.workspace_id AND event.ticket_id=t.ticket_id AND event.kind IN ({}))", event_kinds.join(",")));
|
||||||
}
|
}
|
||||||
for evidence in &query.evidence {
|
for evidence in &query.evidence {
|
||||||
predicates.push(match evidence.as_str() {
|
predicates.push(match evidence.as_str() {
|
||||||
|
"implementation_report" => format!("{report_index} IS NOT NULL"),
|
||||||
|
"implementation_report_after_rescope" => current_report.clone(),
|
||||||
"merge_request" => format!("{merge_request_id} IS NOT NULL"),
|
"merge_request" => format!("{merge_request_id} IS NOT NULL"),
|
||||||
"commit" => has_commit.clone(),
|
"commit" => has_commit.clone(),
|
||||||
"approved_review" => format!("{review_status}='approved'"),
|
"approved_review" => format!("{review_status}='approved'"),
|
||||||
@@ -446,7 +454,7 @@ impl SqliteWorkspaceAuthority {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
if let Some(status) = &query.review_status {
|
if let Some(status) = &query.review_status {
|
||||||
let status = if status == "unresolved_changes" {
|
let status = if matches!(status.as_str(), "unresolved_changes" | "changes_requested") {
|
||||||
"request_changes"
|
"request_changes"
|
||||||
} else {
|
} else {
|
||||||
status.as_str()
|
status.as_str()
|
||||||
@@ -457,15 +465,29 @@ impl SqliteWorkspaceAuthority {
|
|||||||
for attention in &query.attention {
|
for attention in &query.attention {
|
||||||
predicates.push(match attention.as_str() {
|
predicates.push(match attention.as_str() {
|
||||||
"done_not_closed" => "t.workflow_state='done'".to_string(),
|
"done_not_closed" => "t.workflow_state='done'".to_string(),
|
||||||
"unresolved_review" | "unresolved_changes" => format!("{review_status}='request_changes'"),
|
"implementation_report_not_closed" => {
|
||||||
|
format!("{report_index} IS NOT NULL AND t.workflow_state!='closed'")
|
||||||
|
}
|
||||||
|
"report_after_rescope" => current_report.clone(),
|
||||||
|
"unresolved_review" | "unresolved_changes" => {
|
||||||
|
format!("{review_status}='request_changes'")
|
||||||
|
}
|
||||||
"missing_commit" => format!("NOT {has_commit}"),
|
"missing_commit" => format!("NOT {has_commit}"),
|
||||||
"blocked" => blocker.to_string(),
|
"blocked" => blocker.to_string(),
|
||||||
"unblocked" => format!("NOT {blocker}"),
|
"unblocked" => format!("NOT {blocker}"),
|
||||||
"ready" => format!("t.workflow_state='ready' AND NOT {active_blocker}"),
|
"ready" => format!("t.workflow_state='ready' AND NOT {blocker}"),
|
||||||
"awaiting_review" => format!("t.workflow_state='inprogress' AND {current_report} AND {review_status}='pending'"),
|
"awaiting_review" => format!("{review_status}='pending'"),
|
||||||
"stale_after_rescope" => format!("{report_index} IS NOT NULL AND {edit_index}>{report_index}"),
|
"stale_after_rescope" => {
|
||||||
"missing_evidence" => format!("NOT ({current_report} AND {has_commit} AND {review_status}='approved')"),
|
format!("{report_index} IS NOT NULL AND NOT {current_report}")
|
||||||
other => return Err(Error::InvalidRecordId(format!("unsupported attention filter `{other}`"))),
|
}
|
||||||
|
"missing_evidence" => format!(
|
||||||
|
"NOT ({current_report} AND {has_commit} AND {review_status}='approved')"
|
||||||
|
),
|
||||||
|
other => {
|
||||||
|
return Err(Error::InvalidRecordId(format!(
|
||||||
|
"unsupported attention filter `{other}`"
|
||||||
|
)));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
let rank_expression = match sort {
|
let rank_expression = match sort {
|
||||||
@@ -561,11 +583,11 @@ impl SqliteWorkspaceAuthority {
|
|||||||
}
|
}
|
||||||
if let Some(value) = &query.updated_after {
|
if let Some(value) = &query.updated_after {
|
||||||
let value = bind(SqlValue::Text(value.clone()));
|
let value = bind(SqlValue::Text(value.clone()));
|
||||||
predicates.push(format!("o.updated_at>={value}"));
|
predicates.push(format!("o.updated_at>{value}"));
|
||||||
}
|
}
|
||||||
if let Some(value) = &query.updated_before {
|
if let Some(value) = &query.updated_before {
|
||||||
let value = bind(SqlValue::Text(value.clone()));
|
let value = bind(SqlValue::Text(value.clone()));
|
||||||
predicates.push(format!("o.updated_at<={value}"));
|
predicates.push(format!("o.updated_at<{value}"));
|
||||||
}
|
}
|
||||||
if let Some(value) = &query.linked_ticket_id {
|
if let Some(value) = &query.linked_ticket_id {
|
||||||
let value = bind(SqlValue::Text(value.clone()));
|
let value = bind(SqlValue::Text(value.clone()));
|
||||||
@@ -2576,6 +2598,34 @@ mod tests {
|
|||||||
.any(|item| item.id == "00000000001J2"),
|
.any(|item| item.id == "00000000001J2"),
|
||||||
"review-status storage predicate must query the authoritative MR thread schema"
|
"review-status storage predicate must query the authoritative MR thread schema"
|
||||||
);
|
);
|
||||||
|
for evidence in [
|
||||||
|
"implementation_report",
|
||||||
|
"implementation_report_after_rescope",
|
||||||
|
] {
|
||||||
|
authority
|
||||||
|
.query_tickets(TicketQueryRequest {
|
||||||
|
evidence: vec![evidence.to_string()],
|
||||||
|
limit: Some(10),
|
||||||
|
..TicketQueryRequest::default()
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|error| panic!("accepted evidence filter {evidence}: {error}"));
|
||||||
|
}
|
||||||
|
for attention in ["implementation_report_not_closed", "report_after_rescope"] {
|
||||||
|
authority
|
||||||
|
.query_tickets(TicketQueryRequest {
|
||||||
|
attention: vec![attention.to_string()],
|
||||||
|
limit: Some(10),
|
||||||
|
..TicketQueryRequest::default()
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|error| panic!("accepted attention filter {attention}: {error}"));
|
||||||
|
}
|
||||||
|
authority
|
||||||
|
.query_tickets(TicketQueryRequest {
|
||||||
|
review_status: Some("changes_requested".to_string()),
|
||||||
|
limit: Some(10),
|
||||||
|
..TicketQueryRequest::default()
|
||||||
|
})
|
||||||
|
.expect("accepted review-status alias must execute");
|
||||||
let historical_event_query = authority
|
let historical_event_query = authority
|
||||||
.query_tickets(TicketQueryRequest {
|
.query_tickets(TicketQueryRequest {
|
||||||
query: Some("Historical event marker".to_string()),
|
query: Some("Historical event marker".to_string()),
|
||||||
|
|||||||
Reference in New Issue
Block a user