Skip to content

Commit

Permalink
Introduce JSON_EXTRACT function
Browse files Browse the repository at this point in the history
close: #3513
Note, we don't support the path argument in this phase
  • Loading branch information
wey-gu committed Oct 19, 2022
1 parent 95e0f43 commit 3c9b0b2
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 0 deletions.
18 changes: 18 additions & 0 deletions src/common/datatypes/Map.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

#include <unordered_map>

#include <folly/json.h>

#include "common/datatypes/Value.h"

namespace nebula {
Expand All @@ -22,6 +24,22 @@ struct Map {
kvs = std::move(values);
}

// constructor to convert from json string
explicit Map(const std::string& json) {
auto obj = folly::parseJson(json);
for (auto& kv : obj.items()) {
kvs.emplace(kv.first.getString(), Value(kv.second));
}
}

// constructor to convert from Value::Type::STRING in JSON format
explicit Map(const Value& value) {
auto obj = folly::parseJson(value.getStr());
for (auto& kv : obj.items()) {
kvs.emplace(kv.first.getString(), Value(kv.second));
}
}

Map& operator=(const Map& rhs) {
if (this == &rhs) {
return *this;
Expand Down
15 changes: 15 additions & 0 deletions src/common/function/FunctionManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,7 @@ std::unordered_map<std::string, std::vector<TypeSignature>> FunctionManager::typ
TypeSignature({Value::Type::MAP}, Value::Type::DURATION)}},
{"extract", {TypeSignature({Value::Type::STRING, Value::Type::STRING}, Value::Type::LIST)}},
{"_nodeid", {TypeSignature({Value::Type::PATH, Value::Type::INT}, Value::Type::INT)}},
{"json_extract", {TypeSignature({Value::Type::STRING}, Value::Type::MAP)}},
};

// static
Expand Down Expand Up @@ -2766,6 +2767,20 @@ FunctionManager::FunctionManager() {
}
};
}
{
auto &attr = functions_["json_extract"];
// note, we don't support second argument(path) like MySQL JSON_EXTRACT for now
attr.minArity_ = 1;
attr.maxArity_ = 1;
attr.isAlwaysPure_ = true;
attr.body_ = [](const auto &args) -> Value {
if (!args[0].get().isStr()) {
return Value::kNullBadType;
}
auto json = args[0].get().getStr();
return Map(json);
};
}
} // NOLINT

// static
Expand Down
16 changes: 16 additions & 0 deletions src/common/function/test/FunctionManagerTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1962,6 +1962,22 @@ TEST_F(FunctionManagerTest, PurityTest) {
ASSERT_TRUE(result.ok() && result.value() == true);
}

TEST_F(FunctionManagerTest, JsonExtract) {
{
std::vector<Value> args = {Value(R"({"a": 1, "b": 2})")};
TEST_FUNCTION(jsonExtract, args, {Map({{"a", 1}, {"b", 2}})});
}
// empty string
{
std::vector<Value> args = {Value("")};
TEST_FUNCTION(jsonExtract, args, Value::kNullBadData);
}
// invalid json string
{
std::vector<Value> args = {Value(R"({a: 1, "b": 2})")};
TEST_FUNCTION(jsonExtract, args, Value::kNullBadData);
}

} // namespace nebula

int main(int argc, char **argv) {
Expand Down

0 comments on commit 3c9b0b2

Please sign in to comment.