Browse Source

reverted change to lotto.json, added test case for functions in predicates

pull/103/head
Matt Greenwood 10 years ago
parent
commit
6c083d3a51
  1. 1
      json-path-assert/src/test/resources/lotto.json
  2. 23
      json-path/src/main/java/com/jayway/jsonpath/AggregationMapReduce.java
  3. 2
      json-path/src/main/java/com/jayway/jsonpath/internal/function/numeric/Min.java
  4. 12
      json-path/src/main/java/com/jayway/jsonpath/internal/token/FunctionPathToken.java
  5. 7
      json-path/src/main/java/com/jayway/jsonpath/internal/token/PathToken.java
  6. 7
      json-path/src/test/java/com/jayway/jsonpath/functions/BaseFunctionTest.java
  7. 73
      json-path/src/test/java/com/jayway/jsonpath/functions/JSONEntityFunctionTest.java
  8. 4
      json-path/src/test/java/com/jayway/jsonpath/functions/NumericFunctionTest.java

1
json-path-assert/src/test/resources/lotto.json

@ -1,6 +1,5 @@
{ {
"lotto": { "lotto": {
"maxAverage": 100,
"lottoId": 5, "lottoId": 5,
"winning-numbers": [ "winning-numbers": [
2, 2,

23
json-path/src/main/java/com/jayway/jsonpath/AggregationMapReduce.java

@ -1,23 +0,0 @@
package com.jayway.jsonpath;
import java.io.File;
import java.io.IOException;
import java.util.List;
/**
* Defines a pattern for taking a collection of input streams and executing the same path operation across all files
* map / reducing the results as they come in to provide an aggregation function on top of the
*
* Created by matt@mjgreenwood.net on 6/26/15.
*/
public class AggregationMapReduce {
public static void main(String args[]) throws IOException {
ReadContext ctx = JsonPath.parse(new File("/home/mattg/dev/JsonPath/json-path-assert/src/test/resources/lotto.json"));
List<String> numbers = ctx.read("$.lotto.winners..numbers.%sum()");
Object value = ctx.read("$.lotto.winners.[?(@.winnerId > $.lotto.winners.%length())].numbers.%avg()");
System.out.println(numbers);
System.out.println(value);
}
}

2
json-path/src/main/java/com/jayway/jsonpath/internal/function/numeric/Min.java

@ -10,7 +10,7 @@ public class Min extends AbstractAggregation {
@Override @Override
protected void next(Number value) { protected void next(Number value) {
if (min < value.doubleValue()) { if (min > value.doubleValue()) {
min = value.doubleValue(); min = value.doubleValue();
} }
} }

12
json-path/src/main/java/com/jayway/jsonpath/internal/token/FunctionPathToken.java

@ -34,17 +34,23 @@ public class FunctionPathToken extends PathToken {
@Override @Override
public void evaluate(String currentPath, PathRef parent, Object model, EvaluationContextImpl ctx) { public void evaluate(String currentPath, PathRef parent, Object model, EvaluationContextImpl ctx) {
Function function = FunctionFactory.newFunction(functionName); Function function = FunctionFactory.newFunction(functionName);
ctx.addResult(currentPath, parent, function.invoke(currentPath, parent, model, ctx)); Object result = function.invoke(currentPath, parent, model, ctx);
ctx.addResult(currentPath, parent, result);
} }
/**
* Return the actual value by indicating true. If this return was false then we'd return the value in an array which
* isn't what is desired - true indicates the raw value is returned.
*
* @return
*/
@Override @Override
boolean isTokenDefinite() { boolean isTokenDefinite() {
return false; return true;
} }
@Override @Override
String getPathFragment() { String getPathFragment() {
return pathFragment; return pathFragment;
} }
} }

7
json-path/src/main/java/com/jayway/jsonpath/internal/token/PathToken.java

@ -73,9 +73,6 @@ public abstract class PathToken {
PathRef pathRef = ctx.forUpdate() ? PathRef.create(model, property) : PathRef.NO_OP; PathRef pathRef = ctx.forUpdate() ? PathRef.create(model, property) : PathRef.NO_OP;
if (isLeaf()) { if (isLeaf()) {
ctx.addResult(evalPath, pathRef, propertyVal); ctx.addResult(evalPath, pathRef, propertyVal);
// } else if (isFunction()) {
// Function function = FunctionFactory.newFunction(next.getPathFragment());
// next.invoke(function, evalPath, pathRef, propertyVal, ctx);
} }
else { else {
next().evaluate(evalPath, pathRef, propertyVal, ctx); next().evaluate(evalPath, pathRef, propertyVal, ctx);
@ -153,10 +150,6 @@ public abstract class PathToken {
return next == null; return next == null;
} }
// boolean isFunction() {
// return null != next && next.getPathFragment().startsWith("['%");
// }
boolean isRoot() { boolean isRoot() {
return prev == null; return prev == null;
} }

7
json-path/src/test/java/com/jayway/jsonpath/functions/BaseFunctionTest.java

@ -2,6 +2,9 @@ package com.jayway.jsonpath.functions;
import com.jayway.jsonpath.Configuration; import com.jayway.jsonpath.Configuration;
import java.io.IOException;
import java.util.Scanner;
import static com.jayway.jsonpath.JsonPath.using; import static com.jayway.jsonpath.JsonPath.using;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@ -33,4 +36,8 @@ public class BaseFunctionTest {
protected void verifyMathFunction(String pathExpr, Object expectedValue) { protected void verifyMathFunction(String pathExpr, Object expectedValue) {
verifyFunction(pathExpr, NUMBER_SERIES, expectedValue); verifyFunction(pathExpr, NUMBER_SERIES, expectedValue);
} }
protected String getResourceAsText(String resourceName) throws IOException {
return new Scanner(BaseFunctionTest.class.getResourceAsStream(resourceName), "UTF-8").useDelimiter("\\A").next();
}
} }

73
json-path/src/test/java/com/jayway/jsonpath/functions/JSONEntityFunctionTest.java

@ -1,7 +1,10 @@
package com.jayway.jsonpath.functions; package com.jayway.jsonpath.functions;
import net.minidev.json.JSONArray;
import org.junit.Test; import org.junit.Test;
import java.io.IOException;
/** /**
* Verifies methods that are helper implementations of functions for manipulating JSON entities, i.e. * Verifies methods that are helper implementations of functions for manipulating JSON entities, i.e.
* length, etc. * length, etc.
@ -9,6 +12,42 @@ import org.junit.Test;
* Created by mattg on 6/27/15. * Created by mattg on 6/27/15.
*/ */
public class JSONEntityFunctionTest extends BaseFunctionTest { public class JSONEntityFunctionTest extends BaseFunctionTest {
private static final String BATCH_JSON = "{\n" +
" \"batches\": {\n" +
" \"minBatchSize\": 10,\n" +
" \"results\": [\n" +
" {\n" +
" \"productId\": 23,\n" +
" \"values\": [\n" +
" 2,\n" +
" 45,\n" +
" 34,\n" +
" 23,\n" +
" 3,\n" +
" 5,\n" +
" 4,\n" +
" 3,\n" +
" 2,\n" +
" 1,\n" +
" ]\n" +
" },\n" +
" {\n" +
" \"productId\": 23,\n" +
" \"values\": [\n" +
" 52,\n" +
" 3,\n" +
" 12,\n" +
" 11,\n" +
" 18,\n" +
" 22,\n" +
" 1\n" +
" ]\n" +
" }\n" +
" ]\n" +
" }\n" +
"}";
@Test @Test
public void testLengthOfTextArray() { public void testLengthOfTextArray() {
// The length of JSONArray is an integer // The length of JSONArray is an integer
@ -20,4 +59,38 @@ public class JSONEntityFunctionTest extends BaseFunctionTest {
// The length of JSONArray is an integer // The length of JSONArray is an integer
verifyFunction("$.numbers.%length()", NUMBER_SERIES, 10); verifyFunction("$.numbers.%length()", NUMBER_SERIES, 10);
} }
/**
* The fictitious use-case/story - is we have a collection of batches with values indicating some quality metric.
* We want to determine the average of the values for only the batch's values where the number of items in the batch
* is greater than the min batch size which is encoded in the JSON document.
*
* We use the length function in the predicate to determine the number of values in each batch and then for those
* batches where the count is greater than min we calculate the average batch value.
*
* Its completely contrived example, however, this test exercises functions within predicates.
*/
@Test
public void testPredicateWithFunctionCallSingleMatch() {
String path = "$.batches.results[?(@.values.%length() >= $.batches.minBatchSize)].values.%avg()";
// Its an array because in some use-cases the min size might match more than one batch and thus we'll get
// the average out for each collection
JSONArray values = new JSONArray();
values.add(12.2d);
verifyFunction(path, BATCH_JSON, values);
}
@Test
public void testPredicateWithFunctionCallTwoMatches() {
String path = "$.batches.results[?(@.values.%length() >= 3)].values.%avg()";
// Its an array because in some use-cases the min size might match more than one batch and thus we'll get
// the average out for each collection
JSONArray values = new JSONArray();
values.add(12.2d);
values.add(17d);
verifyFunction(path, BATCH_JSON, values);
}
} }

4
json-path/src/test/java/com/jayway/jsonpath/functions/NumericFunctionTest.java

@ -25,7 +25,7 @@ public class NumericFunctionTest extends BaseFunctionTest {
@Test @Test
public void testAverageOfDoubles() { public void testAverageOfDoubles() {
verifyMathFunction("$.numbers.%average()", (10d * (10d + 1d)) / 2d); verifyMathFunction("$.numbers.%avg()", 5.5);
} }
@Test @Test
@ -45,7 +45,7 @@ public class NumericFunctionTest extends BaseFunctionTest {
@Test @Test
public void testStdDevOfDouble() { public void testStdDevOfDouble() {
verifyMathFunction("$.numbers.%stddev()", 1d); verifyMathFunction("$.numbers.%stddev()", 2.8722813232690143d);
} }
/** /**

Loading…
Cancel
Save