Skip to content

Commit

Permalink
Merge pull request #249 from HubSpot/support-selectattr-expression
Browse files Browse the repository at this point in the history
Support expressions in selectattr/rejectattr
  • Loading branch information
mattcoley authored Nov 7, 2018
2 parents c71bd76 + 25dd424 commit fcc1ec3
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 6 deletions.
28 changes: 26 additions & 2 deletions src/main/java/com/hubspot/jinjava/lib/filter/SelectAttrFilter.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ThreadLocalRandom;

import com.hubspot.jinjava.doc.annotations.JinjavaDoc;
import com.hubspot.jinjava.doc.annotations.JinjavaParam;
Expand All @@ -13,7 +14,6 @@
import com.hubspot.jinjava.lib.exptest.ExpTest;
import com.hubspot.jinjava.util.ForLoop;
import com.hubspot.jinjava.util.ObjectIterator;
import com.hubspot.jinjava.util.Variable;

@JinjavaDoc(
value = "Filters a sequence of objects by applying a test to an attribute of an object and only selecting the ones with the test succeeding.",
Expand Down Expand Up @@ -77,12 +77,36 @@ protected Object applyFilter(Object var, JinjavaInterpreter interpreter, Object[
while (loop.hasNext()) {
Object val = loop.next();

Object attrVal = new Variable(interpreter, String.format("%s.%s", "placeholder", attr)).resolve(val);
// push temporary variable to be resolved
String tempValue = generateTempVariable();
String expression = generateTempVariable(tempValue, attr);

// ensure this random value hasn't been seen before
while (interpreter.getContext().containsKey(tempValue) || interpreter.getContext().getResolvedExpressions().contains(expression)) {
tempValue = generateTempVariable();
}

interpreter.getContext().put(tempValue, val);

Object attrVal = interpreter.resolveELExpression(expression, interpreter.getLineNumber());

// cleanup
interpreter.getContext().remove(tempValue);

if (acceptObjects == expTest.evaluate(attrVal, interpreter, expArgs)) {
result.add(val);
}
}

return result;
}

private String generateTempVariable() {
return "jj_temp_" + Math.abs(ThreadLocalRandom.current().nextInt());
}

private String generateTempVariable(String tempValue, String expression) {
return String.format("%s.%s", tempValue, expression).trim();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
import static org.assertj.core.api.Assertions.assertThat;

import java.util.HashMap;
import java.util.List;

import org.junit.Before;
import org.junit.Test;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.hubspot.jinjava.Jinjava;

Expand All @@ -18,9 +20,9 @@ public class SelectAttrFilterTest {
public void setup() {
jinjava = new Jinjava();
jinjava.getGlobalContext().put("users", Lists.newArrayList(
new User(0, false, "[email protected]", new Option(0, "option0")),
new User(1, true, "[email protected]", new Option(1, "option1")),
new User(2, false, null, new Option(2, "option2"))));
new User(0, false, "[email protected]", new Option(0, "option0"), ImmutableList.of(new Option(0, "option0"))),
new User(1, true, "[email protected]", new Option(1, "option1"), ImmutableList.of(new Option(1, "option1"))),
new User(2, false, null, new Option(2, "option2"), ImmutableList.of(new Option(2, "option2")))));
}

@Test
Expand Down Expand Up @@ -56,18 +58,30 @@ public void selectAttrWithNestedProperty() {
.isEqualTo("[2]");
}

@Test
public void selectAttrWithNestedFilter() {

assertThat(jinjava.render("{{ users|selectattr(\"optionList|map('id')\", 'containing', 1) }}", new HashMap<String, Object>()))
.isEqualTo("[1]");

assertThat(jinjava.render("{{ users|selectattr(\"optionList|map('name')\", 'containing', 'option2') }}", new HashMap<String, Object>()))
.isEqualTo("[2]");
}


public static class User {
private long num;
private boolean isActive;
private String email;
private Option option;
private List<Option> optionList;

public User(long num, boolean isActive, String email, Option option) {
public User(long num, boolean isActive, String email, Option option, List<Option> optionList) {
this.num = num;
this.isActive = isActive;
this.email = email;
this.option = option;
this.optionList = optionList;
}

public long getNum() {
Expand All @@ -86,6 +100,10 @@ public Option getOption() {
return option;
}

public List<Option> getOptionList() {
return optionList;
}

@Override
public String toString() {
return num + "";
Expand Down

0 comments on commit fcc1ec3

Please sign in to comment.