improvement to iterating through patch arrays

This commit is contained in:
WasabiRaptor 2024-03-07 18:06:30 -05:00
parent 89fe1bf15b
commit f5400e5877
4 changed files with 42 additions and 25 deletions

View File

@ -667,6 +667,38 @@ ByteArray Assets::read(String const& path) const {
throw AssetException(strf("No such asset '{}'", path));
}
Json Assets::checkPatchArray(String const& path, AssetSourcePtr const& source, Json const result, JsonArray const patchData, Maybe<Json> const external) const {
auto externalRef = external.value();
auto newResult = result;
for (auto const patch : patchData) {
switch(patch.type()){
case Json::Type::Array: // if the patch is an array, go down recursively until we get objects
try {
newResult = checkPatchArray(path, source, newResult, patch.toArray(), externalRef);
} catch (JsonPatchTestFail const& e) {
Logger::debug("Patch test failure from file %s in source: '%s' at '%s'. Caused by: %s", path, source->metadata().value("name", ""), m_assetSourcePaths.getLeft(source), e.what());
} catch (JsonPatchException const& e) {
Logger::error("Could not apply patch from file %s in source: '%s' at '%s'. Caused by: %s", path, source->metadata().value("name", ""), m_assetSourcePaths.getLeft(source), e.what());
}
break;
case Json::Type::Object: // if its an object, check for operations, or for if an external file is needed for patches to reference
newResult = JsonPatching::applyOperation(newResult, patch, externalRef);
break;
case Json::Type::String:
try {
externalRef = json(patch.toString());
} catch (...) {
throw JsonPatchTestFail(strf("Unable to load reference asset: %s", patch.toString()));
}
break;
default:
throw JsonPatchException(strf("Patch data is wrong type: %s", Json::typeName(patch.type())));
break;
}
}
return newResult;
}
Json Assets::readJson(String const& path) const {
ByteArray streamData = read(path);
try {
@ -677,40 +709,24 @@ Json Assets::readJson(String const& path) const {
if (patchJson.isType(Json::Type::Array)) {
auto patchData = patchJson.toArray();
try {
if (patchData.size()) {
if (patchData.at(0).type() == Json::Type::Array) {
for (auto const& patch : patchData) {
try {
result = jsonPatch(result, patch.toArray());
} catch (JsonPatchTestFail const& e) {
Logger::debug("Patch test failure from file {} in source: {}. Caused by: {}", pair.first, m_assetSourcePaths.getLeft(pair.second), e.what());
}
}
} else if (patchData.at(0).type() == Json::Type::Object) {
try {
result = jsonPatch(result, patchData);
} catch (JsonPatchTestFail const& e) {
Logger::debug("Patch test failure from file {} in source: {}. Caused by: {}", pair.first, m_assetSourcePaths.getLeft(pair.second), e.what());
}
} else {
throw JsonPatchException(strf("Patch data is wrong type: {}", Json::typeName(patchData.at(0).type())));
}
}
result = checkPatchArray(pair.first, pair.second, result, patchData, {});
} catch (JsonPatchTestFail const& e) {
Logger::debug("Patch test failure from file %s in source: '%s' at '%s'. Caused by: %s", pair.first, pair.second->metadata().value("name", ""), m_assetSourcePaths.getLeft(pair.second), e.what());
} catch (JsonPatchException const& e) {
Logger::error("Could not apply patch from file {} in source: {}. Caused by: {}", pair.first, m_assetSourcePaths.getLeft(pair.second), e.what());
Logger::error("Could not apply patch from file %s in source: '%s' at '%s'. Caused by: %s", pair.first, pair.second->metadata().value("name", ""), m_assetSourcePaths.getLeft(pair.second), e.what());
}
}
else if (patchJson.isType(Json::Type::Object)) { //Kae: Do a good ol' json merge instead if the .patch file is a Json object
} else if (patchJson.isType(Json::Type::Object)) { //Kae: Do a good ol' json merge instead if the .patch file is a Json object
auto patchData = patchJson.toObject();
result = jsonMerge(result, patchData);
}
}
return result;
} catch (std::exception const& e) {
throw JsonParsingException(strf("Cannot parse json file: {}", path), e);
throw JsonParsingException(strf("Cannot parse json file: %s", path), e);
}
}
bool Assets::doLoad(AssetId const& id) const {
try {
// loadAsset automatically manages the queue and freshens the asset

View File

@ -269,6 +269,7 @@ private:
ByteArray read(String const& basePath) const;
Json readJson(String const& basePath) const;
Json checkPatchArray(String const& path, AssetSourcePtr const& source, Json const result, JsonArray const patchData, Maybe<Json> const external) const;
// Load / post process an asset and log any exception. Returns true if the
// work was performed (whether successful or not), false if the work is

View File

@ -27,7 +27,7 @@ namespace JsonPatching {
{"copy", std::bind(applyCopyOperation, _1, _2)},
};
Json applyOperation(Json const& base, Json const& op) {
Json applyOperation(Json const& base, Json const& op, Maybe<Json> const& external) {
try {
auto operation = op.getString("op");
return JsonPatching::functionMap.get(operation)(base, op);

View File

@ -13,7 +13,7 @@ Json jsonPatch(Json const& base, JsonArray const& patch);
namespace JsonPatching {
// Applies the given single operation
Json applyOperation(Json const& base, Json const& op);
Json applyOperation(Json const& base, Json const& op, Maybe<Json> const& external = {});
// Tests for "value" at "path"
// Returns base or throws JsonPatchException