Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reformat docs; minor fixes #244

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
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
16 changes: 8 additions & 8 deletions lib_json/src/main/x/json/JsonArrayBuilder.x
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ class JsonArrayBuilder
/**
* Create a JSON array builder.
*
* @param template an optional `JsonArray` to use to populate
* the builder with an initial set of values
* @param factory a factory to create a new mutable `JsonArray`
* @param template (optional) an optional `JsonArray` to use to populate the builder with an
* initial set of values
* @param factory (optional) a factory to create a new mutable `JsonArray`
*/
construct(JsonArray? template = Null, Factory factory = () -> json.newArray()) {
this.factory = factory;
values = new Array();
this.values = new Array();
if (template.is(JsonArray)) {
values.addAll(template);
}
Expand Down Expand Up @@ -136,8 +136,8 @@ class JsonArrayBuilder
/**
* Merge a `JsonObject` into the array.
*
* All of the `JsonObject` keys must be strings that are integer literals
* in the range between zero and the current size of the array being built.
* All of the `JsonObject` keys must be strings that are integer literals in the range between
* zero and the current size of the array being built.
*/
@Override
protected void mergeObject(JsonObject o) {
Expand All @@ -147,8 +147,8 @@ class JsonArrayBuilder
Int? index = pointer.index;
assert index != Null as "Cannot merge JSON Object with non-Int keys into a JSON array";
assert 0 <= index < values.size as
$|Cannot merge JSON Object into JSON array - key\
| "{entry.key}" does not match an existing array entry in the range 0..<{values.size}
$|Cannot merge JSON Object into JSON array - key "{entry.key}" does not match \
|an existing array entry in the range 0..<{values.size}
;
map.put(pointer, entry.value);
}
Expand Down
97 changes: 47 additions & 50 deletions lib_json/src/main/x/json/JsonBuilder.x
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,10 @@ class JsonBuilder<JsonType extends JsonStruct, Id extends Int | String> {
@Abstract protected Id id(JsonPointer path);

/**
* Merge the specified `Doc` into the entry in this builder
* with the specified `Id`.
* Merge the specified `Doc` into the entry in this builder with the specified `Id`.
*
* The exact behaviour and merge rules will differ depending on the
* type of JSON value the builder builds.
* The exact behaviour and merge rules will differ depending on the type of JSON value the
* builder builds.
*/
@Abstract protected void merge(Id id, Doc doc);

Expand All @@ -41,30 +40,29 @@ class JsonBuilder<JsonType extends JsonStruct, Id extends Int | String> {
/**
* Return the `Doc` value the builder contains for the specified `Id`.
*
* As a `Doc` type can be `Null`, if there is no entry contained in the
* builder for the specified `Id` then a `Null` value will be returned,
* which is a valid `Doc` value.
* As a `Doc` type can be `Null`, if there is no entry contained in the builder for the
* specified `Id` then a `Null` value will be returned, which is a valid `Doc` value.
*/
@Abstract protected Doc get(Id id);

/**
* Perform a deep merge of the specified JSON structure with
* the JSON structure this builder is building.
* Perform a deep merge of the specified JSON structure with the JSON structure this builder is
* building.
*
* How the merge is performed will differ depending on the type of
* structure passed in and the structure being built.
* How the merge is performed will differ depending on the type of structure passed in and the
* structure being built.
*
* @param the `JsonStruct` to merge
* @param jsonStruct the `JsonStruct` to merge
*
* @return this `JsonBuilder`
*/
JsonBuilder deepMerge(JsonStruct s) {
switch (s.is(_)) {
JsonBuilder deepMerge(JsonStruct jsonStruct) {
switch (jsonStruct.is(_)) {
case JsonObject:
mergeObject(s);
mergeObject(jsonStruct);
break;
case JsonArray:
mergeArray(s);
mergeArray(jsonStruct);
break;
default:
assert;
Expand All @@ -88,13 +86,14 @@ class JsonBuilder<JsonType extends JsonStruct, Id extends Int | String> {
Doc existing = get(id);
switch (existing.is(_)) {
case JsonObject:
mergeObjectMember(existing, path, doc, id);
mergeIntoObjectMember(existing, path, doc, id);
break;
case JsonArray:
mergeArrayMember(existing, path, doc, id);
mergeIntoArrayMember(existing, path, doc, id);
break;
case Primitive:
mergePrimitiveMember(existing, path, doc, id);
// existing is a primitive so it cannot be merged into and is instead replaced
replaceMember(path, doc, id);
break;
default:
assert;
Expand All @@ -104,66 +103,64 @@ class JsonBuilder<JsonType extends JsonStruct, Id extends Int | String> {
}

/**
* Deeply merge the entries in a `JsonObject` into the JSON value being
* produced by this builder.
* Deeply merge the entries in a `JsonObject` into the JSON value being produced by this builder.
*
* @param o the `JsonObject` to merge
* @param jsonObj the `JsonObject` to merge
*/
protected void mergeObject(JsonObject o) {
for (Map.Entry<String, Doc> entry : o.entries) {
protected void mergeObject(JsonObject jsonObj) {
for (Map.Entry<String, Doc> entry : jsonObj.entries) {
deepMerge(JsonPointer.from(entry.key), entry.value);
}
}

/**
* Deeply merge a `JsonObject` value into this builder.
* Deeply merge a JSON value into a `JsonObject` in this builder.
*
* @param p the `JsonObject` to merge
* @param path the path to the location the object value should be merged into
* @param doc the value to merge the object into
* @param obj the `JsonObject` to merge into
* @param path the path to the location the `Doc` value should be merged into
* @param doc the JSON value to merge into the `JsonObject`
* @param id the id of the entry being merged into
*/
protected void mergeObjectMember(JsonObject o, JsonPointer path, Doc doc, Id id) {
protected void mergeIntoObjectMember(JsonObject obj, JsonPointer path, Doc doc, Id id) {
JsonPointer remainder = path.remainder ?: assert;
JsonObject updated = new JsonObjectBuilder(o).deepMerge(remainder, doc).build();
JsonObject updated = new JsonObjectBuilder(obj).deepMerge(remainder, doc).build();
update(id, updated);
}

/**
* Deeply merge the entries in a `JsonArray` into the JSON value being
* produced by this builder.
*
* @param a the `JsonArray` to merge
* @param array the `JsonArray` to merge
*/
protected void mergeArray(JsonArray a) {
for (Int i : 0 ..< a.size) {
deepMerge(JsonPointer.from(i.toString()), a[i]);
protected void mergeArray(JsonArray array) {
for (Int i : 0 ..< array.size) {
deepMerge(JsonPointer.from(i.toString()), array[i]);
}
}

/**
* Deeply merge a `JsonArray` value into this builder.
* Deeply merge a JSON value into a `JsonArray` value in this builder.
*
* @param a the `JsonArray` to merge
* @param path the path to the location the array value should be merged into
* @param doc the value to merge the array into
* @param id the id of the entry being merged into
* @param array the `JsonArray` to merge into
* @param path the path to the location the JSON value should be merged into
* @param doc the JSON value to merge the into the `JsonArray`
* @param id the id of the entry being merged into
*/
protected void mergeArrayMember(JsonArray a, JsonPointer path, Doc doc, Id id) {
protected void mergeIntoArrayMember(JsonArray array, JsonPointer path, Doc doc, Id id) {
JsonPointer remainder = path.remainder ?: assert;
JsonArray updated = new JsonArrayBuilder(a).deepMerge(remainder, doc).build();
JsonArray updated = new JsonArrayBuilder(array).deepMerge(remainder, doc).build();
update(id, updated);
}

/**
* Deeply merge a `Primitive` value into this builder.
* Replace a value in this builder with a specified value.
*
* @param p the `Primitive` to merge
* @param path the path to the location the primitive value should be merged into
* @param doc the value to merge the primitive into
* @param id the id of the entry being merged into
* @param path the path to the location of the value to replace
* @param doc the JSON value to replace any existing value with
* @param id the id of the entry being replaced
*/
protected void mergePrimitiveMember(Primitive p, JsonPointer path, Doc doc, Id id) {
protected void replaceMember(JsonPointer path, Doc doc, Id id) {
JsonPointer remainder = path.remainder ?: assert;
JsonObject updated = new JsonObjectBuilder().deepMerge(remainder, doc).build();
update(id, updated);
Expand Down Expand Up @@ -205,13 +202,13 @@ class JsonBuilder<JsonType extends JsonStruct, Id extends Int | String> {
/**
* Perform a deep copy of the specified JSON array.
*
* @param o the JSON array to copy
* @param array the JSON array to copy
*
* @return a mutable copy of the JSON array
*/
static JsonArray deepCopyArray(JsonArray a) {
static JsonArray deepCopyArray(JsonArray array) {
JsonArray copy = json.newArray();
for (Doc doc : a) {
for (Doc doc : array) {
copy.add(deepCopy(doc));
}
return copy;
Expand Down
93 changes: 70 additions & 23 deletions lib_json/src/main/x/json/JsonMergePatch.x
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
/**
* An implementation of a JSON Merge Patch as specified
* in [RFC7396](http://tools.ietf.org/html/rfc7396).
* An implementation of a JSON Merge Patch as specified in
* [JSON Merge Patch specification](http://tools.ietf.org/html/rfc7396).
*
* @param patch the JSON value to apply as a merge patch
*/
class JsonMergePatch(Doc patch) {

/**
* @return True iff this patch is empty, i.e. it will not apply any
* `True` iff this patch is empty, i.e. it will not apply to any.
*/
Boolean empty.get() {
Doc patch = this.patch;
Expand All @@ -21,42 +21,89 @@ class JsonMergePatch(Doc patch) {
* Apply this patch to the specified target.
*
* @param target the JSON value to apply this patch to
* @param inPlace True to modify the target in place (if applicable), or
* False to leave the target unmodified and return a patched
* copy of the target
* @param inPlace (optional) `True` to modify the target in place (if applicable), or `False`
* to leave the target unmodified and return a patched copy of the target
*
* @return the JSON value resulting from applying this patch to the target
*/
Doc apply(Doc target, Boolean inPlace = False) {
return merge(target, patch);
return merge(target, patch, inPlace);
}

/**
* Perform a merge as described by the pseudo code in RFC 7396.
*
* define MergePatch(Target, Patch):
* if Patch is an Object:
* if Target is not an Object:
* Target = {} # Ignore the contents and set it to an empty Object
* for each Name/Value pair in Patch:
* if Value is null:
* if Name exists in Target:
* remove the Name/Value pair from Target
* else:
* Target[Name] = MergePatch(Target[Name], Value)
* return Target
* else:
* return Patch
*
* * If the `patch` parameter is not a `JsonObject` the `patch` parameter is returned as the result.
*
* * If the target `Doc` is not a `JsonObject` it is ignored and the merge will be applied to
* a new empty `JsonObject`.
*
* * If the target `Doc` is a mutable `JsonObject` and the `inPlace` parameter is `True` the merge will be
* applied directly to the target.
*
* * A `Null` value for a key in the `patch` will cause the corresponding entry in the target to be removed.
* Any `Null` value in the `patch` will not appear in the merged result.
*
* @param doc that target JSON value to apply the patch to
* @param patch the JSON value representing the patch to apply
* @param inPlace (optional) `True` to modify the target in place (if applicable), or `False`
* to leave the target unmodified and return a patched copy of the target
*
* @return the JSON value resulting from applying this patch to the target
*/
private Doc merge(Doc doc, Doc patch, Boolean inPlace = False) {
if (patch.is(JsonObject)) {
JsonObject target;

if (doc.is(JsonObject)) {
target = doc;
if (doc.is(immutable) || !inPlace) {
// we can make in place true as we are making a new target so there is
// no point continually copying target elements from here on
inPlace = True;
target = json.newObject();
target.putAll(doc);
} else {
target = doc;
}
} else {
target = json.newObject();
// we can make in place true as we are making a new target so there is
// no point continually copying target elements from here on
inPlace = True;
target = json.newObject();
}

JsonObjectBuilder builder = new JsonObjectBuilder(target);
for (Map.Entry<String, Doc> entry : patch.entries) {
String key = entry.key;
Doc value = entry.value;
for ((String key, Doc value) : patch) {
if (value == Null) {
target.remove(key);
} else {
if (Doc targetValue := target.get(key)) {
merge(key, merge(targetValue, value, inPlace));
} else {
merge(key, merge(json.newObject(), value, True));
}
target[key] = merge(target[key], value, inPlace);
}
}
return builder.build();
// TODO JK:
// If the original target is immutable the target being returned will be a copy
// that is currently mutable. Should it be made immutable to match the original
// target doc parameter?
// Basically, should the mutability of the result match the mutability of the
// original doc parameter?
return target;
}
// TODO JK:
// Should a copy of the patch be returned and should it be immutable?
// If we do make a copy, should the mutability of the result match the mutability of the
// original doc parameter?
return patch;
}

Expand All @@ -73,10 +120,10 @@ class JsonMergePatch(Doc patch) {
}

/**
* Generate a JSON Merge Patch from the source and target {@code JsonValue}.
* Generate a JSON Merge Patch from the source and target `JsonValue`.
*
* @param source the source
* @param target the target
* @param source the source
* @param target the target
*
* @return a JSON Patch which when applied to the source, yields the target
*/
Expand Down
10 changes: 5 additions & 5 deletions lib_json/src/main/x/json/JsonObjectBuilder.x
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ class JsonObjectBuilder
/**
* Create a JSON object builder.
*
* @param template an optional `Map<String, Doc>` to use to populate
* the builder with an initial set of values
* @param factory a factory to create a new mutable `JsonArray`
* @param template (optional) an optional `Map<String, Doc>` to use to populate the builder
* with an initial set of values
* @param factory (optional) a factory to create a new mutable `JsonArray`
*/
construct(JsonObject? template = Null, Factory factory = () -> json.newObject()) {
this.factory = factory;
Expand Down Expand Up @@ -63,7 +63,7 @@ class JsonObjectBuilder
JsonObjectBuilder add(String key, JsonBuilder builder) = add(key, builder.build());

/**
* Add all the values contained in the `Map`
* Add all the values contained in the `Map`.
*
* @param map the map of values to add
*
Expand All @@ -75,7 +75,7 @@ class JsonObjectBuilder
}

/**
* Add all the values contained in the `JsonObject`
* Add all the values contained in the `JsonObject`.
*
* @param map the map of values to add
*
Expand Down
Loading
Loading