From b699061f2f76973cde5657763d162759780a839a Mon Sep 17 00:00:00 2001 From: Satya Date: Wed, 2 Sep 2026 10:55:04 -0400 Subject: [PATCH] Queryer: an explicit archived filter overrides the active-only default, per node MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Filter keys arrive as "path/field:$op", so the override check that compared the key to the bare "archived" never matched: the hidden NOT archived clause was always added and an explicit archived filter could not return archived rows. The match is on the node's own archived path, so a root filter lifts the default for the root only — nested includes the filter never mentioned keep hiding archived rows. The two queryer fixtures that filter on archived had snapshotted the contradiction (NOT archived AND archived = $1); they now expect the filter alone. 1286 library tests pass. Pinned by api's TestArchive_CascadesDownTheTree (test/punc/lineage_test.go). Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01AvkGU4kQ4wsqxHFpXtZKZM --- fixtures/queryer.json | 8 +++----- src/queryer/compiler.rs | 16 ++++++++++++++-- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/fixtures/queryer.json b/fixtures/queryer.json index 9a8b4d9..d92a0ce 100644 --- a/fixtures/queryer.json +++ b/fixtures/queryer.json @@ -1246,8 +1246,7 @@ " )", " FROM agreego.entity entity_1", " WHERE", - " NOT entity_1.archived", - " AND entity_1.archived = ($1 #>> '{}')::BOOLEAN", + " entity_1.archived = ($1 #>> '{}')::BOOLEAN", " AND entity_1.archived <> ($2 #>> '{}')::BOOLEAN", " AND entity_1.created_at = ($3 #>> '{}')::TIMESTAMPTZ", " AND entity_1.created_at > ($4 #>> '{}')::TIMESTAMPTZ", @@ -1718,8 +1717,7 @@ " JOIN agreego.organization organization_2 ON organization_2.id = entity_1.id", " JOIN agreego.person person_3 ON person_3.id = organization_2.id", " WHERE", - " NOT entity_1.archived", - " AND person_3.age = ($1 #>> '{}')::NUMERIC", + " person_3.age = ($1 #>> '{}')::NUMERIC", " AND person_3.age > ($2 #>> '{}')::NUMERIC", " AND person_3.age >= ($3 #>> '{}')::NUMERIC", " AND person_3.age < ($4 #>> '{}')::NUMERIC", @@ -2702,4 +2700,4 @@ } ] } -] \ No newline at end of file +] diff --git a/src/queryer/compiler.rs b/src/queryer/compiler.rs index 6c26986..7def47d 100644 --- a/src/queryer/compiler.rs +++ b/src/queryer/compiler.rs @@ -578,8 +578,20 @@ impl<'a> Compiler<'a> { let mut where_clauses = Vec::new(); // Dynamically apply the 'active-only' default ONLY if the client - // didn't explicitly request to filter on 'archived' themselves! - let has_archived_override = self.filter_keys.iter().any(|k| k == "archived"); + // didn't explicitly request to filter on 'archived' themselves — for THIS node. + // Keys arrive as "path/field:$op" (extract_filters), so match this node's own archived + // path, never the bare name: compared to "archived" alone it never matched (an explicit + // archived filter could not return archived rows), and matched on any key it would lift + // the default from every nested include the filter never mentioned. + let archived_path = if node.ast_path.is_empty() { + "archived".to_string() + } else { + format!("{}/archived", node.ast_path) + }; + let has_archived_override = self + .filter_keys + .iter() + .any(|k| k.split(':').next().unwrap_or(k) == archived_path); if !has_archived_override { where_clauses.push(format!("NOT {}.archived", entity_alias));