Skip to content

Commit 1e36468

Browse files
nsdeschenesclaude
andcommitted
fix(explore): Recurse into logic groups when extracting filter keys
extractFilterKeys only iterated top-level tokens, so filter keys nested inside parenthesized groups (Token.LOGIC_GROUP) were never sent to the validation API. Add a recursive walk to inspect inner tokens. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent fdc3a60 commit 1e36468

File tree

2 files changed

+44
-3
lines changed

2 files changed

+44
-3
lines changed

static/app/views/explore/hooks/useAttributeValidation.spec.tsx

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,42 @@ describe('useAttributeValidation', () => {
115115
expect(mockValidate).toHaveBeenCalledTimes(1);
116116
});
117117

118+
it('extracts filter keys inside logical groups', async () => {
119+
const mockValidate = MockApiClient.addMockResponse({
120+
url: `/organizations/${ORG_SLUG}/trace-items/attributes/validate/`,
121+
method: 'POST',
122+
body: {
123+
attributes: {
124+
'span.op': {valid: true},
125+
'span.module': {valid: false, error: 'Unknown attribute'},
126+
},
127+
},
128+
});
129+
130+
const {result} = renderHookWithProviders(
131+
() =>
132+
useAttributeValidation(
133+
TraceItemDataset.SPANS,
134+
'(span.op:db OR span.module:http)',
135+
DEFAULT_SELECTION
136+
),
137+
{organization}
138+
);
139+
140+
await waitFor(() => {
141+
expect(result.current.invalidFilterKeys).toEqual(['span.module']);
142+
});
143+
144+
expect(mockValidate).toHaveBeenCalledWith(
145+
expect.any(String),
146+
expect.objectContaining({
147+
data: expect.objectContaining({
148+
attributes: expect.arrayContaining(['span.module', 'span.op']),
149+
}),
150+
})
151+
);
152+
});
153+
118154
it('re-validates when selection changes', async () => {
119155
const mockValidate = MockApiClient.addMockResponse({
120156
url: `/organizations/${ORG_SLUG}/trace-items/attributes/validate/`,

static/app/views/explore/hooks/useAttributeValidation.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,16 @@ function extractFilterKeys(parsedQuery: ParseResult | null): string[] {
4040
return EMPTY_KEYS;
4141
}
4242
const keySet = new Set<string>();
43-
for (const token of parsedQuery) {
44-
if (token.type === Token.FILTER) {
45-
keySet.add(getKeyName(token.key));
43+
function walk(tokens: ParseResult) {
44+
for (const token of tokens) {
45+
if (token.type === Token.FILTER) {
46+
keySet.add(getKeyName(token.key));
47+
} else if (token.type === Token.LOGIC_GROUP) {
48+
walk(token.inner);
49+
}
4650
}
4751
}
52+
walk(parsedQuery);
4853
return keySet.size > 0 ? [...keySet].sort() : EMPTY_KEYS;
4954
}
5055

0 commit comments

Comments
 (0)