Skip to content

Commit

Permalink
add some string handling functions
Browse files Browse the repository at this point in the history
  • Loading branch information
ljcui committed Nov 27, 2024
1 parent 055d41c commit cfa9755
Show file tree
Hide file tree
Showing 4 changed files with 195 additions and 2 deletions.
131 changes: 130 additions & 1 deletion src/cypher/arithmetic/arithmetic_expression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1292,11 +1292,140 @@ cypher::FieldData BuiltinFunction::Regexp(RTContext *ctx, const Record &record,
}

cypher::FieldData BuiltinFunction::Exists(RTContext *ctx, const Record &record,
const std::vector<ArithExprNode> &args) {
const std::vector<ArithExprNode> &args) {
auto res = args[1].Evaluate(ctx, record);
return cypher::FieldData(lgraph_api::FieldData(!res.IsNull()));
}

cypher::FieldData BuiltinFunction::ToLower(RTContext *ctx, const Record &record,
const std::vector<ArithExprNode> &args) {
if (args.size() != 2) CYPHER_ARGUMENT_ERROR();
auto arg1_entry = args[1].Evaluate(ctx, record);
std::string arg1 = arg1_entry.constant.scalar.AsString();
std::transform(arg1.begin(), arg1.end(), arg1.begin(), [](unsigned char c) {
return std::tolower(c);
});
return cypher::FieldData(lgraph_api::FieldData(arg1));
}

cypher::FieldData BuiltinFunction::ToUpper(RTContext *ctx, const Record &record,
const std::vector<ArithExprNode> &args) {
if (args.size() != 2) CYPHER_ARGUMENT_ERROR();
auto arg1_entry = args[1].Evaluate(ctx, record);
std::string arg1 = arg1_entry.constant.scalar.AsString();
std::transform(arg1.begin(), arg1.end(), arg1.begin(), [](unsigned char c) {
return std::toupper(c);
});
return cypher::FieldData(lgraph_api::FieldData(arg1));
}

static std::string ltrim(const std::string& s) {
auto it = std::find_if(s.begin(), s.end(), [](unsigned char ch) {
return !std::isspace(ch);
});
return {it, s.end()};
}

static std::string rtrim(const std::string& s) {
auto it = std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) {
return !std::isspace(ch);
});
return {s.begin(), it.base()};
}

static std::string trim(const std::string& s) {
return ltrim(rtrim(s));
}

cypher::FieldData BuiltinFunction::Trim(RTContext *ctx, const Record &record,
const std::vector<ArithExprNode> &args) {
if (args.size() != 2) CYPHER_ARGUMENT_ERROR();
auto arg1_entry = args[1].Evaluate(ctx, record);
std::string arg1 = arg1_entry.constant.scalar.AsString();
return cypher::FieldData(lgraph_api::FieldData(trim(arg1)));
}

cypher::FieldData BuiltinFunction::Ltrim(RTContext *ctx, const Record &record,
const std::vector<ArithExprNode> &args) {
if (args.size() != 2) CYPHER_ARGUMENT_ERROR();
auto arg1_entry = args[1].Evaluate(ctx, record);
std::string arg1 = arg1_entry.constant.scalar.AsString();
return cypher::FieldData(lgraph_api::FieldData(ltrim(arg1)));
}

cypher::FieldData BuiltinFunction::Rtrim(RTContext *ctx, const Record &record,
const std::vector<ArithExprNode> &args) {
if (args.size() != 2) CYPHER_ARGUMENT_ERROR();
auto arg1_entry = args[1].Evaluate(ctx, record);
std::string arg1 = arg1_entry.constant.scalar.AsString();
return cypher::FieldData(lgraph_api::FieldData(rtrim(arg1)));
}

cypher::FieldData BuiltinFunction::Replace(RTContext *ctx, const Record &record,
const std::vector<ArithExprNode> &args) {
if (args.size() != 4) CYPHER_ARGUMENT_ERROR();
auto arg1_entry = args[1].Evaluate(ctx, record);
std::string arg1 = arg1_entry.constant.scalar.AsString();
auto arg2_entry = args[2].Evaluate(ctx, record);
std::string arg2 = arg2_entry.constant.scalar.AsString();
auto arg3_entry = args[3].Evaluate(ctx, record);
std::string arg3 = arg3_entry.constant.scalar.AsString();
size_t pos = 0;
while ((pos = arg1.find(arg2, pos)) != std::string::npos) {
arg1.replace(pos, arg2.length(), arg3);
pos += arg3.length();
}
return cypher::FieldData(lgraph_api::FieldData(arg1));
}

cypher::FieldData BuiltinFunction::Split(RTContext *ctx, const Record &record,
const std::vector<ArithExprNode> &args) {
if (args.size() != 3) CYPHER_ARGUMENT_ERROR();
auto arg1_entry = args[1].Evaluate(ctx, record);
std::string arg1 = arg1_entry.constant.scalar.AsString();
auto arg2_entry = args[2].Evaluate(ctx, record);
std::string arg2 = arg2_entry.constant.scalar.AsString();
std::vector<std::string> split_result;
boost::algorithm::split(split_result, arg1, boost::is_any_of(arg2));
std::vector<::lgraph::FieldData> res;
for (auto& item : split_result) {
res.emplace_back(std::move(item));
}
return cypher::FieldData(std::move(res));
}

cypher::FieldData BuiltinFunction::Left(RTContext *ctx, const Record &record,
const std::vector<ArithExprNode> &args) {
if (args.size() != 3) CYPHER_ARGUMENT_ERROR();
auto arg1_entry = args[1].Evaluate(ctx, record);
std::string arg1 = arg1_entry.constant.scalar.AsString();
auto arg2_entry = args[2].Evaluate(ctx, record);
int64_t arg2 = arg2_entry.constant.scalar.AsInt64();
if (arg2 < 0) THROW_CODE(InvalidParameter);
return cypher::FieldData(arg1.substr(0, std::min((size_t)arg2, arg1.size())));
}

cypher::FieldData BuiltinFunction::Right(RTContext *ctx, const Record &record,
const std::vector<ArithExprNode> &args) {
if (args.size() != 3) CYPHER_ARGUMENT_ERROR();
auto arg1_entry = args[1].Evaluate(ctx, record);
std::string arg1 = arg1_entry.constant.scalar.AsString();
auto arg2_entry = args[2].Evaluate(ctx, record);
int64_t arg2 = arg2_entry.constant.scalar.AsInt64();
if (arg2 < 0) THROW_CODE(InvalidParameter);
size_t len = std::min((size_t)arg2, arg1.size());
return cypher::FieldData(arg1.substr(arg1.size() - len, len));
}

cypher::FieldData BuiltinFunction::Reverse(RTContext *ctx, const Record &record,
const std::vector<ArithExprNode> &args) {
if (args.size() != 2) CYPHER_ARGUMENT_ERROR();
auto arg1_entry = args[1].Evaluate(ctx, record);
std::string arg1 = arg1_entry.constant.scalar.AsString();
std::reverse(arg1.begin(), arg1.end());
return cypher::FieldData(lgraph_api::FieldData(arg1));
}

cypher::FieldData BuiltinFunction::Bin(RTContext *ctx, const Record &record,
const std::vector<ArithExprNode> &args) {
if (args.size() != 2) CYPHER_ARGUMENT_ERROR();
Expand Down
34 changes: 34 additions & 0 deletions src/cypher/arithmetic/arithmetic_expression.h
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,29 @@ struct BuiltinFunction {
static cypher::FieldData Exists(RTContext *ctx, const Record &record,
const std::vector<ArithExprNode> &args);

static cypher::FieldData ToLower(RTContext *ctx, const Record &record,
const std::vector<ArithExprNode> &args);

static cypher::FieldData ToUpper(RTContext *ctx, const Record &record,
const std::vector<ArithExprNode> &args);

static cypher::FieldData Trim(RTContext *ctx, const Record &record,
const std::vector<ArithExprNode> &args);
static cypher::FieldData Ltrim(RTContext *ctx, const Record &record,
const std::vector<ArithExprNode> &args);
static cypher::FieldData Rtrim(RTContext *ctx, const Record &record,
const std::vector<ArithExprNode> &args);
static cypher::FieldData Replace(RTContext *ctx, const Record &record,
const std::vector<ArithExprNode> &args);
static cypher::FieldData Split(RTContext *ctx, const Record &record,
const std::vector<ArithExprNode> &args);
static cypher::FieldData Left(RTContext *ctx, const Record &record,
const std::vector<ArithExprNode> &args);
static cypher::FieldData Right(RTContext *ctx, const Record &record,
const std::vector<ArithExprNode> &args);
static cypher::FieldData Reverse(RTContext *ctx, const Record &record,
const std::vector<ArithExprNode> &args);

/* binary function (open cypher extension) */
static cypher::FieldData Bin(RTContext *ctx, const Record &record,
const std::vector<ArithExprNode> &args);
Expand Down Expand Up @@ -585,11 +608,22 @@ struct ArithOpNode {
ae_registered_funcs.emplace("polygon", BuiltinFunction::Polygon);
ae_registered_funcs.emplace("polygonwkb", BuiltinFunction::PolygonWKB);
ae_registered_funcs.emplace("polygonwkt", BuiltinFunction::PolygonWKT);

ae_registered_funcs.emplace("startswith", BuiltinFunction::StartsWith);
ae_registered_funcs.emplace("endswith", BuiltinFunction::EndsWith);
ae_registered_funcs.emplace("contains", BuiltinFunction::Contains);
ae_registered_funcs.emplace("regexp", BuiltinFunction::Regexp);
ae_registered_funcs.emplace("exists", BuiltinFunction::Exists);
ae_registered_funcs.emplace("tolower", BuiltinFunction::ToLower);
ae_registered_funcs.emplace("toupper", BuiltinFunction::ToUpper);
ae_registered_funcs.emplace("trim", BuiltinFunction::Trim);
ae_registered_funcs.emplace("ltrim", BuiltinFunction::Ltrim);
ae_registered_funcs.emplace("rtrim", BuiltinFunction::Rtrim);
ae_registered_funcs.emplace("replace", BuiltinFunction::Replace);
ae_registered_funcs.emplace("split", BuiltinFunction::Split);
ae_registered_funcs.emplace("left", BuiltinFunction::Left);
ae_registered_funcs.emplace("right", BuiltinFunction::Right);
ae_registered_funcs.emplace("reverse", BuiltinFunction::Reverse);

/* native API-like functions */
ae_registered_funcs.emplace("native.getedgefield", BuiltinFunction::NativeGetEdgeField);
Expand Down
20 changes: 20 additions & 0 deletions test/resource/unit_test/expression/cypher/expression.result
Original file line number Diff line number Diff line change
Expand Up @@ -254,3 +254,23 @@ RETURN datetimeComponent(1582705717, 'hour'),datetimeComponent(1582705717, 'minu
[{"datetimeComponent(1582705717, 'hour')":0,"datetimeComponent(1582705717, 'microsecond')":705717,"datetimeComponent(1582705717, 'minute')":26,"datetimeComponent(1582705717, 'second')":22}]
RETURN datetimeComponent(1582705717000, 'year'),datetimeComponent(1582705717000, 'second'), datetimeComponent(1582705717000, 'microsecond');
[{"datetimeComponent(1582705717000, 'microsecond')":717000,"datetimeComponent(1582705717000, 'second')":25,"datetimeComponent(1582705717000, 'year')":1970}]
RETURN toLower("TuGraph");
[{"toLower(\"TuGraph\")":"tugraph"}]
RETURN toUpper("TuGraph");
[{"toUpper(\"TuGraph\")":"TUGRAPH"}]
RETURN trim(" TuGraph ");
[{"trim(\" TuGraph \")":"TuGraph"}]
RETURN replace("Hello TuGraph", "TuGraph", "World");
[{"replace(\"Hello TuGraph\", \"TuGraph\", \"World\")":"Hello World"}]
RETURN split("TuGraph,Graph,Database", ",");
[{"split(\"TuGraph,Graph,Database\", \",\")":"[TuGraph,Graph,Database]"}]
RETURN left("TuGraph", 3);
[{"left(\"TuGraph\", 3)":"TuG"}]
RETURN right("TuGraph", 2);
[{"right(\"TuGraph\", 2)":"ph"}]
RETURN reverse("TuGraph");
[{"reverse(\"TuGraph\")":"hparGuT"}]
RETURN lTrim(" TuGraph ");
[{"lTrim(\" TuGraph \")":"TuGraph "}]
RETURN rTrim(" TuGraph ");
[{"rTrim(\" TuGraph \")":" TuGraph"}]
12 changes: 11 additions & 1 deletion test/resource/unit_test/expression/cypher/expression.test
Original file line number Diff line number Diff line change
Expand Up @@ -126,4 +126,14 @@ WITH bin('MjAyMAo=') AS bin1, bin('MjAxOQo=') AS bin2 RETURN bin1>bin2,bin1<bin2
RETURN dateComponent(12345, 'year'), datetimeComponent(12345, 'month'), datetimeComponent(12345, 'day');
RETURN datetimeComponent(1582705717, 'year'),datetimeComponent(1582705717, 'month'),datetimeComponent(1582705717, 'day');
RETURN datetimeComponent(1582705717, 'hour'),datetimeComponent(1582705717, 'minute'),datetimeComponent(1582705717, 'second'), datetimeComponent(1582705717, 'microsecond');
RETURN datetimeComponent(1582705717000, 'year'),datetimeComponent(1582705717000, 'second'), datetimeComponent(1582705717000, 'microsecond');
RETURN datetimeComponent(1582705717000, 'year'),datetimeComponent(1582705717000, 'second'), datetimeComponent(1582705717000, 'microsecond');
RETURN toLower("TuGraph");
RETURN toUpper("TuGraph");
RETURN trim(" TuGraph ");
RETURN replace("Hello TuGraph", "TuGraph", "World");
RETURN split("TuGraph,Graph,Database", ",");
RETURN left("TuGraph", 3);
RETURN right("TuGraph", 2);
RETURN reverse("TuGraph");
RETURN lTrim(" TuGraph ");
RETURN rTrim(" TuGraph ");

0 comments on commit cfa9755

Please sign in to comment.