Skip to content
Merged
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
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1225,6 +1225,15 @@ Example:
}
```

#### `$add`

The `$add` operation allows for adding a value to an array.

- `$add`
- `path` : The [JSON path](https://github.com/json-path/JsonPath#readme) to the array
- `value` : The value to add. If the given value is a string, variable placeholders of the form `${...}` will be replaced from the environment variables and the resulting string can be converted by setting value-type.
- `value-type` : **optional** [see below](#valuetype)

### ValueType

One of the following identifiers or can be prefixed with `list of ` to indicate a list of the identified type:
Expand Down
8 changes: 8 additions & 0 deletions src/main/java/me/itzg/helpers/patch/PatchSetProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import me.itzg.helpers.env.Interpolator;
import me.itzg.helpers.env.Interpolator.Result;
import me.itzg.helpers.env.MissingVariablesException;
import me.itzg.helpers.patch.model.PatchAddOperation;
import me.itzg.helpers.patch.model.PatchDefinition;
import me.itzg.helpers.patch.model.PatchOperation;
import me.itzg.helpers.patch.model.PatchPutOperation;
Expand Down Expand Up @@ -151,6 +152,13 @@ private void applyOps(Map<String, Object> data, List<PatchOperation> ops) throws
"put", putOp + " at " + putOp.getPath(),
obj -> doc.put(putOp.getPath(), putOp.getKey(), obj)
);
} else if (op instanceof PatchAddOperation) {
final PatchAddOperation addOp = (PatchAddOperation) op;
processValueType(
addOp.getValue(), addOp.getValueType(),
"add", addOp + " at " + addOp.getPath(),
obj -> doc.add(addOp.getPath(), obj)
);
}
}
}
Expand Down
25 changes: 25 additions & 0 deletions src/main/java/me/itzg/helpers/patch/model/PatchAddOperation.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package me.itzg.helpers.patch.model;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.Data;
import lombok.EqualsAndHashCode;

@EqualsAndHashCode(callSuper = true)
@Data
public class PatchAddOperation extends PatchOperation {
@JsonProperty(required = true)
@JsonPropertyDescription("The JSON path to the array to add to.")
String path;

@JsonProperty(required = true)
@JsonPropertyDescription(VALUE_DESCRIPTION)
JsonNode value;

@JsonProperty("value-type")
@JsonPropertyDescription(VALUE_TYPE_DESCRIPTION)
@JsonInclude(JsonInclude.Include.NON_NULL)
String valueType;
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
@JsonTypeInfo(include = JsonTypeInfo.As.WRAPPER_OBJECT, use = JsonTypeInfo.Id.NAME)
@JsonSubTypes({
@JsonSubTypes.Type(value = PatchSetOperation.class, name = "$set"),
@JsonSubTypes.Type(value = PatchPutOperation.class, name = "$put")
@JsonSubTypes.Type(value = PatchPutOperation.class, name = "$put"),
@JsonSubTypes.Type(value = PatchAddOperation.class, name = "$add"),
})
public abstract class PatchOperation {
protected static final String VALUE_DESCRIPTION = "The value to set." +
Expand Down
27 changes: 27 additions & 0 deletions src/test/java/me/itzg/helpers/patch/PatchSetProcessorTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static java.util.Collections.singletonList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.*;
import static uk.org.webcompere.modelassert.json.JsonAssertions.assertJson;
import static uk.org.webcompere.modelassert.json.JsonAssertions.assertYaml;

import com.fasterxml.jackson.databind.node.ArrayNode;
Expand All @@ -19,6 +20,7 @@
import java.util.stream.Stream;
import me.itzg.helpers.env.EnvironmentVariablesProvider;
import me.itzg.helpers.env.Interpolator;
import me.itzg.helpers.patch.model.PatchAddOperation;
import me.itzg.helpers.patch.model.PatchDefinition;
import me.itzg.helpers.patch.model.PatchPutOperation;
import me.itzg.helpers.patch.model.PatchSet;
Expand Down Expand Up @@ -74,6 +76,31 @@ void setInJson(String file, boolean allowComments, @TempDir Path tempDir) throws
);
}

@Test
void addToArray(@TempDir Path tempDir) throws IOException {
final Path src = tempDir.resolve("testing.json");
Files.copy(Paths.get("src/test/resources/patch/testing-with-array.json"), src);

final PatchSetProcessor processor = new PatchSetProcessor(
new Interpolator(environmentVariablesProvider, "CFG_")
);

processor.process(new PatchSet()
.setPatches(singletonList(
new PatchDefinition()
.setFile(src.toString())
.setOps(singletonList(
new PatchAddOperation()
.setPath("$.outer.array")
.setValue(new TextNode("new value"))
))
))
);

assertJson(src)
.at("/outer/array/0").hasValue("new value");
}

@Test
void setInJson5(@TempDir Path tempDir) throws IOException {
final Path src = tempDir.resolve("testing.json5");
Expand Down
5 changes: 5 additions & 0 deletions src/test/resources/patch/testing-with-array.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"outer": {
"array": []
}
}