Skip to content

Commit

Permalink
add mask function (vesoft-inc#2489)
Browse files Browse the repository at this point in the history
  • Loading branch information
jievince authored Mar 17, 2023
1 parent 1a201d7 commit b22bf32
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 3 deletions.
42 changes: 41 additions & 1 deletion src/common/function/FunctionManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,12 @@ std::unordered_map<std::string, std::vector<TypeSignature>> FunctionManager::typ
{"json_extract",
{TypeSignature({Value::Type::STRING}, Value::Type::MAP),
TypeSignature({Value::Type::STRING}, Value::Type::NULLVALUE)}},
};
{
"mask",
{TypeSignature(
{Value::Type::STRING, Value::Type::INT, Value::Type::INT, Value::Type::STRING},
Value::Type::STRING)},
}};

// static
StatusOr<Value::Type> FunctionManager::getReturnType(const std::string &funcName,
Expand Down Expand Up @@ -2865,6 +2870,41 @@ FunctionManager::FunctionManager() {
return Value::kNullValue;
};
}
// mask(string str, int from, int to, char m)
// Returns a string with the characters in the range [from, to] replaced by the specified mask.
// The argument `from` and `to` should be in the range [1, length(str)].
{
auto &attr = functions_["mask"];
attr.minArity_ = 4;
attr.maxArity_ = 4;
attr.isAlwaysPure_ = true;
attr.body_ = [](const auto &args) -> Value {
if (!args[0].get().isStr() || !args[1].get().isInt() || !args[2].get().isInt() ||
!args[3].get().isStr()) {
return Value::kNullBadType;
}
auto &src = args[0].get().getStr();
auto from = args[1].get().getInt();
auto to = args[2].get().getInt();
auto &m = args[3].get().getStr();

if (m.length() != 1) {
return Value::kNullBadType;
}
char c = m[0];

int length = src.length();

if (from < 1 || to > length || from > to) {
return Value::kNullValue;
}
string dest = src;
for (int i = from - 1; i < to; i++) {
dest[i] = c;
}
return dest;
};
}
} // NOLINT

// static
Expand Down
21 changes: 21 additions & 0 deletions src/common/function/test/FunctionManagerTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -867,6 +867,27 @@ TEST_F(FunctionManagerTest, time) {
auto datetime = std::move(result).value()(genArgsRef({"2020-10-10T10:00:00"}));
TEST_FUNCTION(timestamp, {datetime}, 1602324000);
}
// Test function "Mask"
{
// Empty string
TEST_FUNCTION(mask, {"", 1, 3, "*"}, Value::kNullValue);

// Single character
TEST_FUNCTION(mask, {"a", 1, 1, "*"}, "*");

// Normal case
TEST_FUNCTION(mask, {"hello world", 3, 8, "*"}, "he******rld");
TEST_FUNCTION(mask, {"hello world", 1, 8, "*"}, "********rld");
TEST_FUNCTION(mask, {"hello world", 4, 4, "*"}, "hel*o world");

// Invalid range
TEST_FUNCTION(mask, {"hello", 1, 10, "*"}, Value::kNullValue);
TEST_FUNCTION(mask, {"hello world", -1, 8, "*"}, Value::kNullValue);
TEST_FUNCTION(mask, {"hello", 3, 1, "*"}, Value::kNullValue);

// Invalid replacement char
TEST_FUNCTION(mask, {"hello", 1, 5, "xyz"}, Value::kNullBadType);
}
}

TEST_F(FunctionManagerTest, returnType) {
Expand Down
1 change: 0 additions & 1 deletion src/graph/executor/test/JoinTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,6 @@ void JoinTest::testInnerJoin(std::string left, std::string right, DataSet& expec
EXPECT_EQ(result.state(), Result::State::kSuccess) << "LINE: " << line;
}


TEST_F(JoinTest, InnerJoin) {
DataSet expected;
expected.colNames = {"src", "dst", kVid, "tag_prop", "edge_prop", kDst};
Expand Down
23 changes: 22 additions & 1 deletion tests/tck/features/expression/FunctionCall.feature
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Feature: Function Call Expression
When executing query:
"""
YIELD sign(38) AS a, sign(-2) AS b, sign(0.421) AS c,
sign(-1.0) AS d, sign(0) AS e, sign(abs(-3)) AS f
sign(-1.0) AS d, sign(0) AS e, sign(abs(-3)) AS f
"""
Then the result should be, in any order:
| a | b | c | d | e | f |
Expand Down Expand Up @@ -201,3 +201,24 @@ Feature: Function Call Expression
RETURN datetime("2000-10-10T10:00:00") + 3
"""
Then a SemanticError should be raised at runtime: `(datetime("2000-10-10T10:00:00")+3)' is not a valid expression, can not apply `+' to `DATETIME' and `INT'.

Scenario: mask
When executing query:
"""
YIELD mask("hello world", 3, 6, "x") AS a, mask("", 1, 1, "x") AS b, mask("hello world", 1, 4, "*") AS c, mask("hello world", 0, 4, "*") AS d, mask("hello world", -1, 4, "*") AS e, mask("hello world", 2, 100, "*") AS f
"""
Then the result should be, in any order:
| a | b | c | d | e | f |
| "hexxxxworld" | NULL | "****o world" | NULL | NULL | NULL |
When executing query:
"""
RETURN mask("hello world", 1, 3, "x") AS a, mask("hello world", 5, 2, "x") AS b, mask("hello world", 1, 100, "*") AS c, mask("hello world", 1, 2, "*") AS d, mask("hello world", 3, 100, "*") AS e
"""
Then the result should be, in any order:
| a | b | c | d | e |
| "xxxlo world" | NULL | NULL | "**llo world" | NULL |
When executing query:
"""
RETURN mask("hello world", 1, 3, 1) AS a
"""
Then an SemanticError should be raised at runtime: `mask("hello world",1,3,1)' is not a valid expression : Parameter's type error

0 comments on commit b22bf32

Please sign in to comment.