Skip to content

Commit

Permalink
Merge pull request #98 from eiiches/feature/20210808-bracket-index-wi…
Browse files Browse the repository at this point in the history
…th-array

implement "index array with array" feature
  • Loading branch information
eiiches authored Aug 7, 2021
2 parents a13c1c7 + 9017783 commit 4edf735
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.fasterxml.jackson.databind.node.NullNode;

import net.thisptr.jackson.jq.exception.JsonQueryException;
import net.thisptr.jackson.jq.path.ArrayIndexOfPath;
import net.thisptr.jackson.jq.path.ArrayIndexPath;
import net.thisptr.jackson.jq.path.ArrayRangeIndexPath;
import net.thisptr.jackson.jq.path.InvalidPath;
Expand Down Expand Up @@ -35,6 +36,8 @@ public static Path toPath(final JsonNode pathObj) throws JsonQueryException {
path = new ArrayIndexPath(path, segObj);
} else if (segObj.isTextual()) {
path = new ObjectFieldPath(path, segObj.asText());
} else if (segObj.isArray()) {
path = new ArrayIndexOfPath(path, segObj);
} else {
path = new InvalidPath(path, segObj);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ public void apply(final Scope scope, final JsonNode in, final Path path, final P
emitArrayIndexPath(permissive, accessor, pobj, ppath, output, requirePath);
} else if (accessor.isTextual()) {
emitObjectFieldPath(permissive, accessor.asText(), pobj, ppath, output, requirePath);
} else if (accessor.isArray()) {
emitArrayIndexOfPath(permissive, accessor, pobj, ppath, output, requirePath);
} else {
if (!permissive)
throw new JsonQueryTypeException("Cannot index %s with %s", pobj.getNodeType(), accessor.getNodeType());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import net.thisptr.jackson.jq.exception.JsonQueryTypeException;
import net.thisptr.jackson.jq.internal.misc.JsonNodeUtils;
import net.thisptr.jackson.jq.internal.misc.Strings;
import net.thisptr.jackson.jq.path.ArrayIndexOfPath;
import net.thisptr.jackson.jq.path.ArrayIndexPath;
import net.thisptr.jackson.jq.path.ArrayRangeIndexPath;
import net.thisptr.jackson.jq.path.ObjectFieldPath;
Expand Down Expand Up @@ -62,6 +63,13 @@ protected static void emitArrayIndexPath(boolean permissive, final JsonNode inde
ArrayIndexPath.resolve(pobj, ppath, output, index, permissive);
}

protected static void emitArrayIndexOfPath(boolean permissive, final JsonNode subseqToLookFor, final JsonNode pobj, final Path ppath, final PathOutput output, final boolean requirePath) throws JsonQueryException {
assert subseqToLookFor.isArray();
if (requirePath && ppath == null)
throw new JsonQueryException("Invalid path expression near attempt to access element %s of %s", JsonNodeUtils.toString(subseqToLookFor), JsonNodeUtils.toString(pobj));
ArrayIndexOfPath.resolve(pobj, ppath, output, subseqToLookFor, permissive);
}

private static final ObjectMapper MAPPER = new ObjectMapper(); // FIXME

protected static void emitArrayRangeIndexPath(boolean permissive, final JsonNode start, final JsonNode end, final JsonNode pobj, final Path ppath, final PathOutput output, final boolean requirePath) throws JsonQueryException {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package net.thisptr.jackson.jq.path;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.IntNode;

import net.thisptr.jackson.jq.PathOutput;
import net.thisptr.jackson.jq.exception.JsonQueryException;
import net.thisptr.jackson.jq.exception.JsonQueryTypeException;
import net.thisptr.jackson.jq.internal.misc.JsonNodeComparator;

public class ArrayIndexOfPath implements Path {
public final JsonNode subseq; // sub sequence to look for
private final Path parent;

public static ArrayIndexOfPath chainIfNotNull(final Path parent, final JsonNode subseq) {
if (parent == null)
return null;
return new ArrayIndexOfPath(parent, subseq);
}

public ArrayIndexOfPath(final Path parent, final JsonNode subseq) {
if (parent == null)
throw new NullPointerException("parent must not be null");
this.parent = parent;
if (subseq == null)
throw new NullPointerException("subseq must not be null");
if (!subseq.isArray())
throw new IllegalArgumentException("subseq must be an array ");
this.subseq = subseq;
}

@Override
public void toJsonNode(final ArrayNode out) throws JsonQueryException {
parent.toJsonNode(out);
out.add(subseq);
}

@Override
public void get(final JsonNode in, final Path ipath, final PathOutput output, boolean permissive) throws JsonQueryException {
parent.get(in, ipath, (parent, ppath) -> {
resolve(parent, ppath, output, subseq, permissive);
}, permissive);
}

private static final ObjectMapper MAPPER = new ObjectMapper();

@Override
public JsonNode mutate(final JsonNode in, final Mutation mutation, final boolean makeParent) throws JsonQueryException {
return parent.mutate(in, (oldval) -> {
throw new JsonQueryException("Cannot update field at array index of array");
}, makeParent);
}

private static ArrayNode indexOfAll(final JsonNode seq, final JsonNode subseq) {
final JsonNodeComparator comparator = JsonNodeComparator.getInstance();
final ArrayNode out = MAPPER.createArrayNode();

shift: for (int i = 0; i < seq.size() - subseq.size() + 1; ++i) {
for (int j = 0; j < subseq.size(); ++j) {
final int r = comparator.compare(seq.get(i + j), subseq.get(j));
if (r != 0)
continue shift;
}
out.add(IntNode.valueOf(i));
}

return out;
}

public static void resolve(final JsonNode pobj, final Path ppath, final PathOutput output, final JsonNode subseq, final boolean permissive) throws JsonQueryException {
assert subseq.isArray();
if (pobj.isArray()) {
final ArrayNode indexList = indexOfAll(pobj, subseq);
output.emit(indexList, ArrayIndexOfPath.chainIfNotNull(ppath, subseq));
} else {
if (!permissive)
throw new JsonQueryTypeException("Cannot index %s with array", pobj.getNodeType());
}
}
}
20 changes: 20 additions & 0 deletions jackson-jq/src/test/resources/tests/constructs/array_index.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,23 @@
- q: '.[]."\("a","b")"'
in: [{"a": 1, "b": 3}, {"a": 2, "b": 4}]
out: [1, 2, 3, 4]

- q: '.[["a","b"]]'
in: ["a", "b", "a", "a", "b"]
out:
- [0, 3]

- q: 'path(.[["a","b"]])'
in: ["a", "b", "a", "a", "b"]
out:
- [["a", "b"]]

- q: 'getpath([["a","b"]])'
in: ["a", "b", "a", "a", "b"]
out:
- [0, 3]

- q: 'try(.[["a","b"]] |= "c") catch .'
in: ["a", "b", "a", "a", "b"]
out:
- "Cannot update field at array index of array"

0 comments on commit 4edf735

Please sign in to comment.