Skip to content

Commit 85798be

Browse files
committed
fix: handle filter projections with array field access
Fixes issue where expressions like [?stack==''].branch[?starts_with(@, 'one')] would fail with invalid-type error. The FilterProjection interpreter now correctly handles array-of-arrays by applying filters to sub-elements while maintaining projection structure. Fixes #23 <!-- ps-id: 01fb2a2e-8823-477c-b9d2-1dadc433b26a -->
1 parent 05955bc commit 85798be

File tree

2 files changed

+53
-0
lines changed

2 files changed

+53
-0
lines changed

src/TreeInterpreter.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,43 @@ export class TreeInterpreter {
165165
return null;
166166
}
167167

168+
// Check if we need to handle array-of-arrays case for proper filter projection
169+
// where the left side returns an array of arrays that should be processed
170+
// as a projection over each sub-array
171+
const hasArrayElements = base.some(elem => Array.isArray(elem));
172+
if (hasArrayElements) {
173+
// If some elements are arrays, we need to apply the filter to each sub-array
174+
// and collect the results, maintaining the projection structure
175+
const results: JSONArray = [];
176+
for (const elem of base) {
177+
if (Array.isArray(elem)) {
178+
const subResults: JSONArray = [];
179+
for (const subElem of elem) {
180+
const matched = this.visit(condition, subElem);
181+
if (isFalse(matched)) {
182+
continue;
183+
}
184+
const result = this.visit(right, subElem) as JSONValue;
185+
if (result !== null) {
186+
subResults.push(result);
187+
}
188+
}
189+
results.push(subResults);
190+
} else {
191+
// For non-array elements, apply the filter directly
192+
const matched = this.visit(condition, elem);
193+
if (!isFalse(matched)) {
194+
const result = this.visit(right, elem) as JSONValue;
195+
if (result !== null) {
196+
results.push(result);
197+
}
198+
}
199+
}
200+
}
201+
return results;
202+
}
203+
204+
// Standard filter projection for non-nested arrays
168205
const results: JSONArray = [];
169206
for (const elem of base) {
170207
const matched = this.visit(condition, elem);

test/jmespath-interpreter.spec.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,20 @@ describe('Searches compiled ast', () => {
55
it('search a compiled expression', () => {
66
expect(search({ foo: { bar: 'BAZ' } }, 'foo.bar')).toEqual('BAZ');
77
});
8+
9+
it('handles filter projections with array field access', () => {
10+
const data = [
11+
{
12+
stack: '',
13+
branch: ['one/', 'two/'],
14+
},
15+
{
16+
stack: null,
17+
branch: ['three/', 'four/'],
18+
},
19+
];
20+
21+
const result = search(data, "[?stack==''].branch[?starts_with(@, 'one')]");
22+
expect(result).toEqual([['one/']]);
23+
});
824
});

0 commit comments

Comments
 (0)