Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ public class BuiltinFunctions {
public static Map<String, Macro> macros = new HashMap();
static {
macros.put("fallback", new BuiltinFunctions.Fallback());
macros.put("filter", new BuiltinFunctions.Filter());
}

private static abstract class AbstractMacro extends AbstractCallable implements Macro {
Expand Down Expand Up @@ -599,6 +600,33 @@ public JsonNode call(Scope scope, JsonNode input,
}
}

// ===== FILTER

public static class Filter extends AbstractMacro {

public Filter() {
super("filter", 2, 2);
}

public JsonNode call(Scope scope, JsonNode input,
ExpressionNode[] parameters) {
JsonNode array = parameters[0].apply(scope, input);
if (array.isNull())
return NullNode.instance;
if (!array.isArray())
throw new JsltException("filter() argument is not an array: " + array);

ArrayNode result = NodeUtils.mapper.createArrayNode();
for (int ix = 0; ix < array.size(); ix++) {
JsonNode element = array.get(ix);
JsonNode test = parameters[1].apply(scope, element);
if (NodeUtils.isTrue(test))
result.add(element);
}
return result;
}
}

// ===== IS-OBJECT

public static class IsObject extends AbstractFunction {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public static Collection<Object[]> data() {
List<Object[]> strings = new ArrayList();
strings.addAll(loadTests("query-error-tests.json"));
strings.addAll(loadTests("function-error-tests.json"));
strings.addAll(loadTests("filter-error-tests.json"));
strings.addAll(loadTests("function-declaration-tests.yaml"));
return strings;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ public static Collection<Object[]> data() {
strings.addAll(loadTests("query-tests.yaml"));
strings.addAll(loadTests("function-tests.json"));
strings.addAll(loadTests("experimental-tests.json"));
strings.addAll(loadTests("filter-tests.json"));
strings.addAll(loadTests("function-declaration-tests.yaml"));
return strings;
}
Expand Down
11 changes: 11 additions & 0 deletions core/src/test/resources/filter-error-tests.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"description" : "Error tests for the filter() macro.",
"tests" :
[
{
"query" : "filter(42, .active)",
"input" : "{}",
"error" : "filter() argument is not an array"
}
]
}
36 changes: 36 additions & 0 deletions core/src/test/resources/filter-tests.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"description" : "Tests for the filter() macro.",
"tests" :
[
{
"query" : "filter([{\"a\":1,\"active\":true},{\"a\":2,\"active\":false}], .active)",
"input" : "{}",
"output" : "[{\"a\":1,\"active\":true}]"
},
{
"query" : "filter([1, 2, 3, 4, 5], . > 3)",
"input" : "{}",
"output" : "[4, 5]"
},
{
"query" : "filter(null, .active)",
"input" : "{}",
"output" : "null"
},
{
"query" : "filter([], .active)",
"input" : "{}",
"output" : "[]"
},
{
"query" : "[for (filter([{\"id\":1,\"ok\":true},{\"id\":2,\"ok\":false}], .ok)) .id]",
"input" : "{}",
"output" : "[1]"
},
{
"query" : "size(filter([{\"active\":true},{\"active\":false},{\"active\":true}], .active))",
"input" : "{}",
"output" : "2"
}
]
}
18 changes: 18 additions & 0 deletions functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,24 @@ if (not(is-array(.things)))
error("'things' is not an array")
```

### _filter(array, expr) -> array_

Returns a new array containing only the elements of _array_ for which
_expr_ evaluates to a truthy value. _expr_ is evaluated with each
element as the context node (`.`).

If _array_ is `null` the result is `null`. If _array_ is empty the
result is `[]`.

Examples:

```
filter([1, 2, 3, 4, 5], . > 3) => [4, 5]
filter(.items, .active) => [{...}, ...]
size(filter(.items, .active)) => 2
[for (filter(.items, .active)) .id] => [...]
```

### _fallback(arg1, arg2, ...) -> value_

Returns the first argument that has a value. That is, the first
Expand Down