diff options
Diffstat (limited to 'document/src/main/java')
7 files changed, 77 insertions, 40 deletions
diff --git a/document/src/main/java/com/yahoo/document/fieldpathupdate/AddFieldPathUpdate.java b/document/src/main/java/com/yahoo/document/fieldpathupdate/AddFieldPathUpdate.java index b1e06bb1278..d66de429b3c 100644 --- a/document/src/main/java/com/yahoo/document/fieldpathupdate/AddFieldPathUpdate.java +++ b/document/src/main/java/com/yahoo/document/fieldpathupdate/AddFieldPathUpdate.java @@ -79,8 +79,8 @@ public class AddFieldPathUpdate extends FieldPathUpdate { reader.read(this); } - public AddFieldPathUpdate(DocumentType type) { - super(FieldPathUpdate.Type.ADD, type); + public AddFieldPathUpdate(DocumentType type, String fieldPath) { + super(FieldPathUpdate.Type.ADD, type, fieldPath, null); } public void setNewValues(Array value) { diff --git a/document/src/main/java/com/yahoo/document/fieldpathupdate/AssignFieldPathUpdate.java b/document/src/main/java/com/yahoo/document/fieldpathupdate/AssignFieldPathUpdate.java index 62bc4ac775b..92fc0458d4e 100644 --- a/document/src/main/java/com/yahoo/document/fieldpathupdate/AssignFieldPathUpdate.java +++ b/document/src/main/java/com/yahoo/document/fieldpathupdate/AssignFieldPathUpdate.java @@ -160,8 +160,8 @@ public class AssignFieldPathUpdate extends FieldPathUpdate { reader.read(this); } - public AssignFieldPathUpdate(DocumentType type) { - super(FieldPathUpdate.Type.ASSIGN, type); + public AssignFieldPathUpdate(DocumentType type, String fieldPath) { + super(FieldPathUpdate.Type.ASSIGN, type, fieldPath, null); } /** diff --git a/document/src/main/java/com/yahoo/document/fieldpathupdate/FieldPathUpdate.java b/document/src/main/java/com/yahoo/document/fieldpathupdate/FieldPathUpdate.java index 5672f51beab..9ecdb6f27f0 100644 --- a/document/src/main/java/com/yahoo/document/fieldpathupdate/FieldPathUpdate.java +++ b/document/src/main/java/com/yahoo/document/fieldpathupdate/FieldPathUpdate.java @@ -144,18 +144,6 @@ public abstract class FieldPathUpdate { throw new IllegalArgumentException("Field path update type '" + type + "' not supported."); } - public static FieldPathUpdate create(Type type, DocumentType docType) { - switch (type) { - case ASSIGN: - return new AssignFieldPathUpdate(docType); - case ADD: - return new AddFieldPathUpdate(docType); - case REMOVE: - return new RemoveFieldPathUpdate(docType); - } - throw new IllegalArgumentException("Field path update type '" + type + "' not supported."); - } - @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/document/src/main/java/com/yahoo/document/fieldpathupdate/RemoveFieldPathUpdate.java b/document/src/main/java/com/yahoo/document/fieldpathupdate/RemoveFieldPathUpdate.java index 403631322de..96a3fadc66c 100644 --- a/document/src/main/java/com/yahoo/document/fieldpathupdate/RemoveFieldPathUpdate.java +++ b/document/src/main/java/com/yahoo/document/fieldpathupdate/RemoveFieldPathUpdate.java @@ -44,10 +44,6 @@ public class RemoveFieldPathUpdate extends FieldPathUpdate { handler = new IteratorHandler(); } - public RemoveFieldPathUpdate(DocumentType type) { - super(FieldPathUpdate.Type.REMOVE, type); - } - FieldPathIteratorHandler getIteratorHandler(Document doc) { return handler; } diff --git a/document/src/main/java/com/yahoo/document/json/DocumentUpdateJsonSerializer.java b/document/src/main/java/com/yahoo/document/json/DocumentUpdateJsonSerializer.java index 7356bd72dda..2fd09181a44 100644 --- a/document/src/main/java/com/yahoo/document/json/DocumentUpdateJsonSerializer.java +++ b/document/src/main/java/com/yahoo/document/json/DocumentUpdateJsonSerializer.java @@ -29,6 +29,7 @@ import com.yahoo.document.fieldpathupdate.AddFieldPathUpdate; import com.yahoo.document.fieldpathupdate.AssignFieldPathUpdate; import com.yahoo.document.fieldpathupdate.FieldPathUpdate; import com.yahoo.document.fieldpathupdate.RemoveFieldPathUpdate; +import com.yahoo.document.json.readers.SingleValueReader; import com.yahoo.document.serialization.DocumentUpdateWriter; import com.yahoo.document.serialization.FieldWriter; import com.yahoo.document.update.AddValueUpdate; @@ -48,6 +49,7 @@ import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; import java.util.Optional; +import java.util.regex.Matcher; import java.util.stream.Collectors; import static com.yahoo.document.json.JsonSerializationHelper.*; @@ -122,12 +124,13 @@ public class DocumentUpdateJsonSerializer generator.writeObjectFieldStart(fieldPath.toString()); for (FieldPathUpdate update : fieldPathUpdates) { + if (writeArithmeticFieldPathUpdate(update, generator)) continue; generator.writeFieldName(update.getUpdateType().name().toLowerCase()); if (update instanceof AssignFieldPathUpdate) { AssignFieldPathUpdate assignUp = (AssignFieldPathUpdate) update; if (assignUp.getExpression() != null) { - generator.writeString(assignUp.getExpression()); + throw new RuntimeException("Unable to parse expression: " + assignUp.getExpression()); } else { assignUp.getNewValue().serialize(null, this); } @@ -143,6 +146,24 @@ public class DocumentUpdateJsonSerializer generator.writeEndObject(); } + // Returns true if fieldpath update was an arithmetic operation after writing it to the generator + private boolean writeArithmeticFieldPathUpdate(FieldPathUpdate fieldPathUpdate, JsonGenerator generator) throws IOException { + if (! (fieldPathUpdate instanceof AssignFieldPathUpdate)) return false; + String expression = ((AssignFieldPathUpdate) fieldPathUpdate).getExpression(); + if (expression == null) return false; + + Matcher matcher = SingleValueReader.matchArithmeticOperation(expression); + if (matcher.find()) { + String updateOperation = SingleValueReader.ARITHMETIC_SIGN_TO_UPDATE_OPERATION.get(matcher.group(1)); + double value = Double.valueOf(matcher.group(2)); + + generator.writeNumberField(updateOperation, value); + return true; + } + + return false; + } + @Override public void write(FieldUpdate fieldUpdate) { wrapIOException(() -> { diff --git a/document/src/main/java/com/yahoo/document/json/readers/SingleValueReader.java b/document/src/main/java/com/yahoo/document/json/readers/SingleValueReader.java index 2f8826354f3..067513b24dc 100644 --- a/document/src/main/java/com/yahoo/document/json/readers/SingleValueReader.java +++ b/document/src/main/java/com/yahoo/document/json/readers/SingleValueReader.java @@ -11,6 +11,12 @@ import com.yahoo.document.json.TokenBuffer; import com.yahoo.document.update.ValueUpdate; import org.apache.commons.codec.binary.Base64; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + public class SingleValueReader { public static final String UPDATE_ASSIGN = "assign"; public static final String UPDATE_INCREMENT = "increment"; @@ -18,6 +24,22 @@ public class SingleValueReader { public static final String UPDATE_MULTIPLY = "multiply"; public static final String UPDATE_DIVIDE = "divide"; + public static final Map<String, String> UPDATE_OPERATION_TO_ARITHMETIC_SIGN = new HashMap<>(); + public static final Map<String, String> ARITHMETIC_SIGN_TO_UPDATE_OPERATION; + private static final Pattern arithmeticExpressionPattern; + + static { + UPDATE_OPERATION_TO_ARITHMETIC_SIGN.put(UPDATE_INCREMENT, "+"); + UPDATE_OPERATION_TO_ARITHMETIC_SIGN.put(UPDATE_DECREMENT, "-"); + UPDATE_OPERATION_TO_ARITHMETIC_SIGN.put(UPDATE_MULTIPLY, "*"); + UPDATE_OPERATION_TO_ARITHMETIC_SIGN.put(UPDATE_DIVIDE, "/"); + ARITHMETIC_SIGN_TO_UPDATE_OPERATION = UPDATE_OPERATION_TO_ARITHMETIC_SIGN.entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey)); + + String validSigns = Pattern.quote(String.join("", UPDATE_OPERATION_TO_ARITHMETIC_SIGN.values())); + arithmeticExpressionPattern = Pattern.compile("^\\$\\w+\\s*([" + validSigns + "])\\s*(\\d+(.\\d+)?)$"); + } + public static FieldValue readSingleValue(TokenBuffer buffer, DataType expectedType) { if (buffer.currentToken().isScalarValue()) { return readAtomic(buffer.currentText(), expectedType); @@ -57,6 +79,10 @@ public class SingleValueReader { return update; } + public static Matcher matchArithmeticOperation(String expression) { + return arithmeticExpressionPattern.matcher(expression.trim()); + } + public static FieldValue readAtomic(String field, DataType expectedType) { if (expectedType.equals(DataType.RAW)) { return expectedType.createFieldValue(new Base64().decode(field)); diff --git a/document/src/main/java/com/yahoo/document/json/readers/VespaJsonDocumentReader.java b/document/src/main/java/com/yahoo/document/json/readers/VespaJsonDocumentReader.java index 9fde7aeae62..c384e77b6ea 100644 --- a/document/src/main/java/com/yahoo/document/json/readers/VespaJsonDocumentReader.java +++ b/document/src/main/java/com/yahoo/document/json/readers/VespaJsonDocumentReader.java @@ -10,7 +10,6 @@ import com.yahoo.document.DocumentRemove; import com.yahoo.document.DocumentType; import com.yahoo.document.DocumentUpdate; import com.yahoo.document.Field; -import com.yahoo.document.NumericDataType; import com.yahoo.document.datatypes.Array; import com.yahoo.document.datatypes.FieldValue; import com.yahoo.document.fieldpathupdate.AddFieldPathUpdate; @@ -19,7 +18,6 @@ import com.yahoo.document.fieldpathupdate.FieldPathUpdate; import com.yahoo.document.fieldpathupdate.RemoveFieldPathUpdate; import com.yahoo.document.json.JsonReaderException; import com.yahoo.document.json.TokenBuffer; -import com.yahoo.document.select.parser.ParseException; import com.yahoo.document.update.FieldUpdate; import static com.yahoo.document.json.readers.AddRemoveCreator.createAdds; @@ -29,6 +27,7 @@ import static com.yahoo.document.json.readers.JsonParserHelpers.expectObjectEnd; import static com.yahoo.document.json.readers.JsonParserHelpers.expectObjectStart; import static com.yahoo.document.json.readers.MapReader.UPDATE_MATCH; import static com.yahoo.document.json.readers.MapReader.createMapUpdate; +import static com.yahoo.document.json.readers.SingleValueReader.UPDATE_ASSIGN; import static com.yahoo.document.json.readers.SingleValueReader.readSingleUpdate; /** @@ -132,25 +131,33 @@ public class VespaJsonDocumentReader { buffer.next(); while (localNesting <= buffer.nesting()) { - FieldPathUpdate.Type fieldPathUpdateType = FieldPathUpdate.Type.valueOf(buffer.currentName().toUpperCase()); - FieldPathUpdate fieldPathUpdate = FieldPathUpdate.create(fieldPathUpdateType, update.getType()); - - fieldPathUpdate.setFieldPath(fieldPath); - DataType dt = fieldPathUpdate.getFieldPath().getResultingDataType(); - if (fieldPathUpdate instanceof AssignFieldPathUpdate) { - if (dt instanceof NumericDataType) { - ((AssignFieldPathUpdate) fieldPathUpdate).setExpression(buffer.currentText()); - } else { - FieldValue fv = SingleValueReader.readSingleValue(buffer, dt); - ((AssignFieldPathUpdate) fieldPathUpdate).setNewValue(fv); - } - - } else if (fieldPathUpdate instanceof AddFieldPathUpdate) { - FieldValue fv = SingleValueReader.readSingleValue(buffer, dt); + String fieldPathOperation = buffer.currentName().toLowerCase(); + FieldPathUpdate fieldPathUpdate; + if (fieldPathOperation.equals(UPDATE_ASSIGN)) { + fieldPathUpdate = new AssignFieldPathUpdate(update.getType(), fieldPath); + FieldValue fv = SingleValueReader.readSingleValue( + buffer, fieldPathUpdate.getFieldPath().getResultingDataType()); + ((AssignFieldPathUpdate) fieldPathUpdate).setNewValue(fv); + + } else if (fieldPathOperation.equals(UPDATE_ADD)) { + fieldPathUpdate = new AddFieldPathUpdate(update.getType(), fieldPath); + FieldValue fv = SingleValueReader.readSingleValue( + buffer, fieldPathUpdate.getFieldPath().getResultingDataType()); ((AddFieldPathUpdate) fieldPathUpdate).setNewValues((Array) fv); - } else if (fieldPathUpdate instanceof RemoveFieldPathUpdate) { + } else if (fieldPathOperation.equals(UPDATE_REMOVE)) { + fieldPathUpdate = new RemoveFieldPathUpdate(update.getType(), fieldPath); buffer.next(); + + } else if (SingleValueReader.UPDATE_OPERATION_TO_ARITHMETIC_SIGN.containsKey(fieldPathOperation)) { + fieldPathUpdate = new AssignFieldPathUpdate(update.getType(), fieldPath); + double value = Double.valueOf(buffer.currentText()); + String expression = String.format("$value %s %s", + SingleValueReader.UPDATE_OPERATION_TO_ARITHMETIC_SIGN.get(fieldPathOperation), value); + ((AssignFieldPathUpdate) fieldPathUpdate).setExpression(expression); + + } else { + throw new IllegalArgumentException("Field path update type '" + fieldPathOperation + "' not supported."); } update.addFieldPathUpdate(fieldPathUpdate); buffer.next(); @@ -158,7 +165,6 @@ public class VespaJsonDocumentReader { } - private static boolean isFieldPath(String field) { return field.matches("^.*?[.\\[\\{].*$"); } |