Make TypedValue constructor explicit for primitive types

Reviewers: mtomic, mferencevic, msantl

Reviewed By: mtomic, msantl

Subscribers: pullbot

Differential Revision: https://phabricator.memgraph.io/D2127
This commit is contained in:
Teon Banek 2019-06-05 15:50:29 +02:00
parent 6d3e3ac4aa
commit b3bc4d6809
16 changed files with 564 additions and 529 deletions

View File

@ -88,19 +88,19 @@ void Load(query::TypedValue *value, slk::Reader *reader,
case static_cast<uint8_t>(1): {
bool v;
slk::Load(&v, reader);
*value = v;
*value = query::TypedValue(v);
return;
}
case static_cast<uint8_t>(2): {
int64_t v;
slk::Load(&v, reader);
*value = v;
*value = query::TypedValue(v);
return;
}
case static_cast<uint8_t>(3): {
double v;
slk::Load(&v, reader);
*value = v;
*value = query::TypedValue(v);
return;
}
case static_cast<uint8_t>(4): {

View File

@ -120,17 +120,16 @@ TypedValue Size(TypedValue *args, int64_t nargs, const EvaluationContext &,
case TypedValue::Type::Null:
return TypedValue();
case TypedValue::Type::List:
return static_cast<int64_t>(
args[0].ValueList().size());
return TypedValue(static_cast<int64_t>(args[0].ValueList().size()));
case TypedValue::Type::String:
return static_cast<int64_t>(args[0].ValueString().size());
return TypedValue(static_cast<int64_t>(args[0].ValueString().size()));
case TypedValue::Type::Map:
// neo4j doesn't implement size for map, but I don't see a good reason not
// to do it.
return static_cast<int64_t>(
args[0].ValueMap().size());
return TypedValue(static_cast<int64_t>(args[0].ValueMap().size()));
case TypedValue::Type::Path:
return static_cast<int64_t>(args[0].ValuePath().edges().size());
return TypedValue(
static_cast<int64_t>(args[0].ValuePath().edges().size()));
default:
throw QueryRuntimeException(
"'size' argument must be a string, a collection or a path.");
@ -162,7 +161,8 @@ TypedValue Degree(TypedValue *args, int64_t nargs, const EvaluationContext &,
return TypedValue();
case TypedValue::Type::Vertex: {
auto &vertex = args[0].Value<VertexAccessor>();
return static_cast<int64_t>(vertex.out_degree() + vertex.in_degree());
return TypedValue(
static_cast<int64_t>(vertex.out_degree() + vertex.in_degree()));
}
default:
throw QueryRuntimeException("'degree' argument must be a node.");
@ -180,7 +180,7 @@ TypedValue InDegree(TypedValue *args, int64_t nargs, const EvaluationContext &,
return TypedValue();
case TypedValue::Type::Vertex: {
auto &vertex = args[0].Value<VertexAccessor>();
return static_cast<int64_t>(vertex.in_degree());
return TypedValue(static_cast<int64_t>(vertex.in_degree()));
}
default:
throw QueryRuntimeException("'inDegree' argument must be a node.");
@ -198,7 +198,7 @@ TypedValue OutDegree(TypedValue *args, int64_t nargs, const EvaluationContext &,
return TypedValue();
case TypedValue::Type::Vertex: {
auto &vertex = args[0].Value<VertexAccessor>();
return static_cast<int64_t>(vertex.out_degree());
return TypedValue(static_cast<int64_t>(vertex.out_degree()));
}
default:
throw QueryRuntimeException("'outDegree' argument must be a node.");
@ -214,13 +214,13 @@ TypedValue ToBoolean(TypedValue *args, int64_t nargs, const EvaluationContext &,
case TypedValue::Type::Null:
return TypedValue();
case TypedValue::Type::Bool:
return args[0].Value<bool>();
return TypedValue(args[0].Value<bool>());
case TypedValue::Type::Int:
return args[0].ValueInt() != 0L;
return TypedValue(args[0].ValueInt() != 0L);
case TypedValue::Type::String: {
auto s = utils::ToUpperCase(utils::Trim(args[0].ValueString()));
if (s == "TRUE") return true;
if (s == "FALSE") return false;
if (s == "TRUE") return TypedValue(true);
if (s == "FALSE") return TypedValue(false);
// I think this is just stupid and that exception should be thrown, but
// neo4j does it this way...
return TypedValue();
@ -240,12 +240,13 @@ TypedValue ToFloat(TypedValue *args, int64_t nargs, const EvaluationContext &,
case TypedValue::Type::Null:
return TypedValue();
case TypedValue::Type::Int:
return static_cast<double>(args[0].Value<int64_t>());
return TypedValue(static_cast<double>(args[0].Value<int64_t>()));
case TypedValue::Type::Double:
return args[0];
case TypedValue::Type::String:
try {
return utils::ParseDouble(utils::Trim(args[0].ValueString()));
return TypedValue(
utils::ParseDouble(utils::Trim(args[0].ValueString())));
} catch (const utils::BasicException &) {
return TypedValue();
}
@ -264,17 +265,17 @@ TypedValue ToInteger(TypedValue *args, int64_t nargs, const EvaluationContext &,
case TypedValue::Type::Null:
return TypedValue();
case TypedValue::Type::Bool:
return args[0].ValueBool() ? 1L : 0L;
return TypedValue(args[0].ValueBool() ? 1L : 0L);
case TypedValue::Type::Int:
return args[0];
case TypedValue::Type::Double:
return static_cast<int64_t>(args[0].Value<double>());
return TypedValue(static_cast<int64_t>(args[0].Value<double>()));
case TypedValue::Type::String:
try {
// Yup, this is correct. String is valid if it has floating point
// number, then it is parsed and converted to int.
return static_cast<int64_t>(
utils::ParseDouble(utils::Trim(args[0].ValueString())));
return TypedValue(static_cast<int64_t>(
utils::ParseDouble(utils::Trim(args[0].ValueString()))));
} catch (const utils::BasicException &) {
return TypedValue();
}
@ -395,11 +396,11 @@ TypedValue Range(TypedValue *args, int64_t nargs, const EvaluationContext &,
std::vector<TypedValue> list;
if (lbound <= rbound && step > 0) {
for (auto i = lbound; i <= rbound; i += step) {
list.push_back(i);
list.emplace_back(i);
}
} else if (lbound >= rbound && step < 0) {
for (auto i = lbound; i >= rbound; i += step) {
list.push_back(i);
list.emplace_back(i);
}
}
return list;
@ -471,10 +472,9 @@ TypedValue Abs(TypedValue *args, int64_t nargs, const EvaluationContext &,
case TypedValue::Type::Null:
return TypedValue();
case TypedValue::Type::Int:
return static_cast<int64_t>(
std::abs(static_cast<long long>(args[0].Value<int64_t>())));
return TypedValue(std::abs(args[0].Value<int64_t>()));
case TypedValue::Type::Double:
return std::abs(args[0].Value<double>());
return TypedValue(std::abs(args[0].Value<double>()));
default:
throw QueryRuntimeException("'abs' argument should be a number.");
}
@ -491,9 +491,9 @@ TypedValue Abs(TypedValue *args, int64_t nargs, const EvaluationContext &,
case TypedValue::Type::Null: \
return TypedValue(); \
case TypedValue::Type::Int: \
return lowercased_name(args[0].Value<int64_t>()); \
return TypedValue(lowercased_name(args[0].Value<int64_t>())); \
case TypedValue::Type::Double: \
return lowercased_name(args[0].Value<double>()); \
return TypedValue(lowercased_name(args[0].Value<double>())); \
default: \
throw QueryRuntimeException(#lowercased_name \
" argument must be a number."); \
@ -537,7 +537,7 @@ TypedValue Atan2(TypedValue *args, int64_t nargs, const EvaluationContext &,
};
double y = to_double(args[0]);
double x = to_double(args[1]);
return atan2(y, x);
return TypedValue(atan2(y, x));
}
TypedValue Sign(TypedValue *args, int64_t nargs, const EvaluationContext &,
@ -545,7 +545,7 @@ TypedValue Sign(TypedValue *args, int64_t nargs, const EvaluationContext &,
if (nargs != 1) {
throw QueryRuntimeException("'sign' requires exactly one argument.");
}
auto sign = [](auto x) { return (0 < x) - (x < 0); };
auto sign = [](auto x) { return TypedValue((0 < x) - (x < 0)); };
switch (args[0].type()) {
case TypedValue::Type::Null:
return TypedValue();
@ -563,7 +563,7 @@ TypedValue E(TypedValue *, int64_t nargs, const EvaluationContext &,
if (nargs != 0) {
throw QueryRuntimeException("'e' requires no arguments.");
}
return M_E;
return TypedValue(M_E);
}
TypedValue Pi(TypedValue *, int64_t nargs, const EvaluationContext &,
@ -571,7 +571,7 @@ TypedValue Pi(TypedValue *, int64_t nargs, const EvaluationContext &,
if (nargs != 0) {
throw QueryRuntimeException("'pi' requires no arguments.");
}
return M_PI;
return TypedValue(M_PI);
}
TypedValue Rand(TypedValue *, int64_t nargs, const EvaluationContext &,
@ -581,7 +581,7 @@ TypedValue Rand(TypedValue *, int64_t nargs, const EvaluationContext &,
if (nargs != 0) {
throw QueryRuntimeException("'rand' requires no arguments.");
}
return rand_dist_(pseudo_rand_gen_);
return TypedValue(rand_dist_(pseudo_rand_gen_));
}
template <bool (*Predicate)(const TypedValue::TString &s1,
@ -607,7 +607,7 @@ TypedValue StringMatchOperator(TypedValue *args, int64_t nargs,
if (has_null) return TypedValue();
const auto &s1 = args[0].ValueString();
const auto &s2 = args[1].ValueString();
return Predicate(s1, s2);
return TypedValue(Predicate(s1, s2));
}
// Check if s1 starts with s2.
@ -682,7 +682,7 @@ TypedValue Counter(TypedValue *args, int64_t nargs,
auto value = it->second;
it->second += step;
return value;
return TypedValue(value);
}
#endif
@ -695,9 +695,9 @@ TypedValue WorkerId(TypedValue *args, int64_t nargs, const EvaluationContext &,
auto &arg = args[0];
switch (arg.type()) {
case TypedValue::Type::Vertex:
return arg.ValueVertex().GlobalAddress().worker_id();
return TypedValue(arg.ValueVertex().GlobalAddress().worker_id());
case TypedValue::Type::Edge:
return arg.ValueEdge().GlobalAddress().worker_id();
return TypedValue(arg.ValueEdge().GlobalAddress().worker_id());
default:
throw QueryRuntimeException(
"'workerId' argument must be a node or an edge.");
@ -739,7 +739,7 @@ TypedValue ToString(TypedValue *args, int64_t nargs, const EvaluationContext &,
case TypedValue::Type::Double:
return std::to_string(arg.ValueDouble());
case TypedValue::Type::Bool:
return arg.ValueBool() ? "true" : "false";
return TypedValue(arg.ValueBool() ? "true" : "false");
default:
throw QueryRuntimeException(
"'toString' argument must be a number, a string or a boolean.");
@ -751,7 +751,7 @@ TypedValue Timestamp(TypedValue *, int64_t nargs, const EvaluationContext &ctx,
if (nargs != 0) {
throw QueryRuntimeException("'timestamp' requires no arguments.");
}
return ctx.timestamp;
return TypedValue(ctx.timestamp);
}
TypedValue Left(TypedValue *args, int64_t nargs, const EvaluationContext &,

View File

@ -137,7 +137,7 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
// element in the list since result of every comparison will be NULL. There
// is one special case that we must test explicitly: if list is empty then
// result is false since no comparison will be performed.
if (list.size() == 0U) return false;
if (list.empty()) return TypedValue(false);
if (literal.IsNull()) return TypedValue();
auto has_null = false;
@ -146,13 +146,13 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
if (result.IsNull()) {
has_null = true;
} else if (result.Value<bool>()) {
return true;
return TypedValue(true);
}
}
if (has_null) {
return TypedValue();
}
return false;
return TypedValue(false);
}
TypedValue Visit(SubscriptOperator &list_indexing) override {
@ -261,7 +261,7 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
TypedValue Visit(IsNullOperator &is_null) override {
auto value = is_null.expression_->Accept(*this);
return value.IsNull();
return TypedValue(value.IsNull());
}
TypedValue Visit(PropertyLookup &property_lookup) override {
@ -296,10 +296,10 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
auto vertex = expression_result.Value<VertexAccessor>();
for (const auto label : labels_test.labels_) {
if (!vertex.has_label(GetLabel(label))) {
return false;
return TypedValue(false);
}
}
return true;
return TypedValue(true);
}
default:
throw QueryRuntimeException("Only nodes have labels.");
@ -440,7 +440,7 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
return result;
}
}
return true;
return TypedValue(true);
}
TypedValue Visit(Single &single) override {
@ -468,12 +468,12 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
}
// Return false if more than one element satisfies the predicate.
if (predicate_satisfied) {
return false;
return TypedValue(false);
} else {
predicate_satisfied = true;
}
}
return predicate_satisfied;
return TypedValue(predicate_satisfied);
}
TypedValue Visit(ParameterLookup &param_lookup) override {
@ -500,7 +500,7 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
const auto &target_string = target_string_value.ValueString();
try {
std::regex regex(regex_value.ValueString());
return std::regex_match(target_string, regex);
return TypedValue(std::regex_match(target_string, regex));
} catch (const std::regex_error &e) {
throw QueryRuntimeException("Regex error in '{}': {}",
regex_value.ValueString(), e.what());

View File

@ -674,7 +674,7 @@ Callback HandleInfoQuery(InfoQuery *info_query,
return db_accessor->PropertyName(p);
});
std::vector<TypedValue> constraint{"unique",
std::vector<TypedValue> constraint{TypedValue("unique"),
db_accessor->LabelName(e.label),
utils::Join(property_names, ",")};
@ -691,8 +691,10 @@ Callback HandleInfoQuery(InfoQuery *info_query,
callback.header = {"info", "value"};
callback.fn = [db_accessor] {
std::vector<std::vector<TypedValue>> results(
{{"is_leader", db_accessor->raft()->IsLeader()},
{"term_id", static_cast<int64_t>(db_accessor->raft()->TermId())}});
{{TypedValue("is_leader"),
TypedValue(db_accessor->raft()->IsLeader())},
{TypedValue("term_id"), TypedValue(static_cast<int64_t>(
db_accessor->raft()->TermId()))}});
return results;
};
// It is critical to abort this query because it can be executed on

View File

@ -1398,12 +1398,12 @@ class ExpandWeightedShortestPathCursor : public query::plan::Cursor {
throw QueryRuntimeException(
"Calculated weight must be numeric, got {}.", typed_weight.type());
}
if ((typed_weight < 0).Value<bool>()) {
if ((typed_weight < TypedValue(0)).Value<bool>()) {
throw QueryRuntimeException("Calculated weight must be non-negative!");
}
auto next_state = create_state(vertex, depth);
auto next_weight = weight + typed_weight;
auto next_weight = TypedValue(weight) + typed_weight;
auto found_it = total_cost_.find(next_state);
if (found_it != total_cost_.end() &&
found_it->second.Value<double>() <= next_weight.Value<double>())
@ -2520,7 +2520,8 @@ class AggregateCursor : public Cursor {
AggregationValue &agg_value = kv.second;
int count = agg_value.counts_[pos];
if (count > 0)
agg_value.values_[pos] = agg_value.values_[pos] / (double)count;
agg_value.values_[pos] =
agg_value.values_[pos] / TypedValue(static_cast<double>(count));
}
}
}

View File

@ -52,8 +52,9 @@ class ProfilingStatsToTableHelper {
auto cycles = IndividualCycles(cumulative_stats);
rows_.emplace_back(std::vector<TypedValue>{
FormatOperator(cumulative_stats.name), cumulative_stats.actual_hits,
FormatRelativeTime(cycles), FormatAbsoluteTime(cycles)});
FormatOperator(cumulative_stats.name),
TypedValue(cumulative_stats.actual_hits), FormatRelativeTime(cycles),
FormatAbsoluteTime(cycles)});
for (size_t i = 1; i < cumulative_stats.children.size(); ++i) {
Branch(cumulative_stats.children[i]);
@ -68,7 +69,8 @@ class ProfilingStatsToTableHelper {
private:
void Branch(const ProfilingStats &cumulative_stats) {
rows_.emplace_back(std::vector<TypedValue>{"|\\", "", "", ""});
rows_.emplace_back(std::vector<TypedValue>{
TypedValue("|\\"), TypedValue(""), TypedValue(""), TypedValue("")});
++depth_;
Output(cumulative_stats);

View File

@ -121,27 +121,26 @@ class TypedValue {
*/
TypedValue(TypedValue &&other, utils::MemoryResource *memory);
// constructors for primitive types
TypedValue(bool value,
utils::MemoryResource *memory = utils::NewDeleteResource())
explicit TypedValue(
bool value, utils::MemoryResource *memory = utils::NewDeleteResource())
: memory_(memory), type_(Type::Bool) {
bool_v = value;
}
TypedValue(int value,
utils::MemoryResource *memory = utils::NewDeleteResource())
explicit TypedValue(
int value, utils::MemoryResource *memory = utils::NewDeleteResource())
: memory_(memory), type_(Type::Int) {
int_v = value;
}
TypedValue(int64_t value,
utils::MemoryResource *memory = utils::NewDeleteResource())
explicit TypedValue(
int64_t value, utils::MemoryResource *memory = utils::NewDeleteResource())
: memory_(memory), type_(Type::Int) {
int_v = value;
}
TypedValue(double value,
utils::MemoryResource *memory = utils::NewDeleteResource())
explicit TypedValue(
double value, utils::MemoryResource *memory = utils::NewDeleteResource())
: memory_(memory), type_(Type::Double) {
double_v = value;
}
@ -156,8 +155,8 @@ class TypedValue {
new (&string_v) TString(value, memory_);
}
TypedValue(const char *value,
utils::MemoryResource *memory = utils::NewDeleteResource())
explicit TypedValue(const char *value, utils::MemoryResource *memory =
utils::NewDeleteResource())
: memory_(memory), type_(Type::String) {
new (&string_v) TString(value, memory_);
}

View File

@ -326,7 +326,7 @@ static void Aggregate(benchmark::State &state) {
evaluation_context};
TMemory memory;
auto cursor = aggregate.MakeCursor(&dba, memory.get());
frame[symbols.front()] = 0; // initial group_by value
frame[symbols.front()] = query::TypedValue(0); // initial group_by value
while (cursor->Pull(frame, execution_context))
frame[symbols.front()].ValueInt()++; // new group_by value
}

View File

@ -27,10 +27,10 @@ int main(int argc, char *argv[]) {
cluster.Execute("UNWIND range(0, $pos_count) AS id CREATE (:Pos {id:id})",
{{"pos_count", kPosCount - 1}});
CheckResults(cluster.Execute("MATCH (:Pos) RETURN count(1)"), {{kPosCount}},
"Failed to create POS");
CheckResults(cluster.Execute("MATCH (:Card) RETURN count(1)"), {{kCardCount}},
"Failed to create Cards");
CheckResults(cluster.Execute("MATCH (:Pos) RETURN count(1)"),
{{query::TypedValue(kPosCount)}}, "Failed to create POS");
CheckResults(cluster.Execute("MATCH (:Card) RETURN count(1)"),
{{query::TypedValue(kCardCount)}}, "Failed to create Cards");
std::atomic<int> tx_counter{0};
auto create_tx = [&cluster, kCardCount, kPosCount, &tx_counter](int count) {
@ -50,7 +50,7 @@ int main(int argc, char *argv[]) {
{{"pos", rint(kPosCount)},
{"card", rint(kCardCount)},
{"tx", tx_counter++}});
CheckResults(res, {{1}}, "Transaction creation");
CheckResults(res, {{query::TypedValue(1)}}, "Transaction creation");
} catch (utils::LockTimeoutException &) {
--i;
} catch (mvcc::SerializationError &) {
@ -68,9 +68,10 @@ int main(int argc, char *argv[]) {
tx_creators.emplace_back(create_tx, FLAGS_tx_per_thread);
for (auto &t : tx_creators) t.join();
CheckResults(cluster.Execute("MATCH (:Transaction) RETURN count(1)"),
{{FLAGS_num_tx_creators * FLAGS_tx_per_thread}},
"Failed to create Transactions");
CheckResults(
cluster.Execute("MATCH (:Transaction) RETURN count(1)"),
{{query::TypedValue(FLAGS_num_tx_creators * FLAGS_tx_per_thread)}},
"Failed to create Transactions");
LOG(INFO) << "Test terminated successfully";
return 0;

View File

@ -54,10 +54,13 @@ class Base {
}
}
void CheckLiteral(Expression *expression, const TypedValue &expected,
template <class TValue>
void CheckLiteral(Expression *expression, const TValue &expected,
const std::optional<int> &token_position = std::nullopt) {
TypedValue value;
if (!expected.IsNull() && context_.is_query_cached) {
// NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
TypedValue expected_tv(expected);
if (!expected_tv.IsNull() && context_.is_query_cached) {
auto *param_lookup = dynamic_cast<ParameterLookup *>(expression);
ASSERT_TRUE(param_lookup);
if (token_position)
@ -69,7 +72,7 @@ class Base {
if (token_position) ASSERT_EQ(literal->token_position_, *token_position);
value = literal->value_;
}
EXPECT_TRUE(TypedValue::BoolEqual{}(value, expected));
EXPECT_TRUE(TypedValue::BoolEqual{}(value, expected_tv));
}
};
@ -2076,13 +2079,14 @@ TEST_P(CypherMainVisitorTest, CreateUser) {
check_auth_query(&ast_generator, "CREATE USER user",
AuthQuery::Action::CREATE_USER, "user", "", "", {}, {});
check_auth_query(&ast_generator, "CREATE USER user IDENTIFIED BY 'password'",
AuthQuery::Action::CREATE_USER, "user", "", "", "password",
{});
check_auth_query(&ast_generator, "CREATE USER user IDENTIFIED BY ''",
AuthQuery::Action::CREATE_USER, "user", "", "", "", {});
check_auth_query(&ast_generator, "CREATE USER user IDENTIFIED BY null",
AuthQuery::Action::CREATE_USER, "user", "", "",
TypedValue(), {});
TypedValue("password"), {});
check_auth_query(&ast_generator, "CREATE USER user IDENTIFIED BY ''",
AuthQuery::Action::CREATE_USER, "user", "", "",
TypedValue(""), {});
check_auth_query(&ast_generator, "CREATE USER user IDENTIFIED BY null",
AuthQuery::Action::CREATE_USER, "user", "", "", TypedValue(),
{});
ASSERT_THROW(
ast_generator.ParseQuery("CRATE USER user IDENTIFIED BY password"),
SyntaxException);
@ -2101,8 +2105,8 @@ TEST_P(CypherMainVisitorTest, SetPassword) {
AuthQuery::Action::SET_PASSWORD, "user", "", "",
TypedValue(), {});
check_auth_query(&ast_generator, "SET PASSWORD FOR user TO 'password'",
AuthQuery::Action::SET_PASSWORD, "user", "", "", "password",
{});
AuthQuery::Action::SET_PASSWORD, "user", "", "",
TypedValue("password"), {});
ASSERT_THROW(ast_generator.ParseQuery("SET PASSWORD FOR user To 5"),
SyntaxException);
}

View File

@ -50,10 +50,13 @@ class Base {
}
}
void CheckLiteral(Expression *expression, const TypedValue &expected,
template <class TValue>
void CheckLiteral(Expression *expression, const TValue &expected,
const std::optional<int> &token_position = std::nullopt) {
TypedValue value;
if (!expected.IsNull() && context_.is_query_cached) {
// NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
TypedValue expected_tv(expected);
if (!expected_tv.IsNull() && context_.is_query_cached) {
auto *param_lookup = dynamic_cast<ParameterLookup *>(expression);
ASSERT_TRUE(param_lookup);
if (token_position)
@ -65,7 +68,7 @@ class Base {
if (token_position) ASSERT_EQ(literal->token_position_, *token_position);
value = literal->value_;
}
EXPECT_TRUE(TypedValue::BoolEqual{}(value, expected));
EXPECT_TRUE(TypedValue::BoolEqual{}(value, expected_tv));
}
};
@ -2180,13 +2183,14 @@ TEST_P(CypherMainVisitorTest, CreateUser) {
check_auth_query(&ast_generator, "CREATE USER user",
AuthQuery::Action::CREATE_USER, "user", "", "", {}, {});
check_auth_query(&ast_generator, "CREATE USER user IDENTIFIED BY 'password'",
AuthQuery::Action::CREATE_USER, "user", "", "", "password",
{});
check_auth_query(&ast_generator, "CREATE USER user IDENTIFIED BY ''",
AuthQuery::Action::CREATE_USER, "user", "", "", "", {});
check_auth_query(&ast_generator, "CREATE USER user IDENTIFIED BY null",
AuthQuery::Action::CREATE_USER, "user", "", "",
TypedValue(), {});
TypedValue("password"), {});
check_auth_query(&ast_generator, "CREATE USER user IDENTIFIED BY ''",
AuthQuery::Action::CREATE_USER, "user", "", "",
TypedValue(""), {});
check_auth_query(&ast_generator, "CREATE USER user IDENTIFIED BY null",
AuthQuery::Action::CREATE_USER, "user", "", "", TypedValue(),
{});
ASSERT_THROW(
ast_generator.ParseQuery("CRATE USER user IDENTIFIED BY password"),
SyntaxException);
@ -2205,8 +2209,8 @@ TEST_P(CypherMainVisitorTest, SetPassword) {
AuthQuery::Action::SET_PASSWORD, "user", "", "",
TypedValue(), {});
check_auth_query(&ast_generator, "SET PASSWORD FOR user TO 'password'",
AuthQuery::Action::SET_PASSWORD, "user", "", "", "password",
{});
AuthQuery::Action::SET_PASSWORD, "user", "", "",
TypedValue("password"), {});
ASSERT_THROW(ast_generator.ParseQuery("SET PASSWORD FOR user To 5"),
SyntaxException);
}

View File

@ -343,7 +343,7 @@ TEST_F(DistributedQueryPlan, PullRemoteOrderBy) {
ASSERT_EQ(results.size(), 300);
for (int j = 0; j < 300; ++j) {
EXPECT_TRUE(TypedValue::BoolEqual{}(results[j][0], j));
EXPECT_TRUE(TypedValue::BoolEqual{}(results[j][0], TypedValue(j)));
}
}

File diff suppressed because it is too large Load Diff

View File

@ -591,13 +591,13 @@ TEST(QueryPlan, Unwind) {
ASSERT_EQ(4, results.size());
const std::vector<int> expected_x_card{3, 3, 3, 1};
auto expected_x_card_it = expected_x_card.begin();
const std::vector<TypedValue> expected_y{1, true, "x", "bla"};
const std::vector<TypedValue> expected_y{TypedValue(1), TypedValue(true),
TypedValue("x"), TypedValue("bla")};
auto expected_y_it = expected_y.begin();
for (const auto &row : results) {
ASSERT_EQ(2, row.size());
ASSERT_EQ(row[0].type(), TypedValue::Type::List);
EXPECT_EQ(row[0].ValueList().size(),
*expected_x_card_it);
EXPECT_EQ(row[0].ValueList().size(), *expected_x_card_it);
EXPECT_EQ(row[1].type(), expected_y_it->type());
expected_x_card_it++;
expected_y_it++;

View File

@ -1542,11 +1542,20 @@ TEST(QueryPlan, Distinct) {
}
};
check_distinct({1, 1, 2, 3, 3, 3}, {1, 2, 3}, true);
check_distinct({3, 2, 3, 5, 3, 5, 2, 1, 2}, {3, 2, 5, 1}, true);
check_distinct({TypedValue(1), TypedValue(1), TypedValue(2), TypedValue(3),
TypedValue(3), TypedValue(3)},
{TypedValue(1), TypedValue(2), TypedValue(3)}, true);
check_distinct({TypedValue(3), TypedValue(2), TypedValue(3), TypedValue(5),
TypedValue(3), TypedValue(5), TypedValue(2), TypedValue(1),
TypedValue(2)},
{TypedValue(3), TypedValue(2), TypedValue(5), TypedValue(1)},
true);
check_distinct(
{3, "two", TypedValue(), 3, true, false, "TWO", TypedValue()},
{3, "two", TypedValue(), true, false, "TWO"}, false);
{TypedValue(3), TypedValue("two"), TypedValue(), TypedValue(3),
TypedValue(true), TypedValue(false), TypedValue("TWO"), TypedValue()},
{TypedValue(3), TypedValue("two"), TypedValue(), TypedValue(true),
TypedValue(false), TypedValue("TWO")},
false);
}
TEST(QueryPlan, ScanAllByLabel) {
@ -1625,14 +1634,20 @@ TEST(QueryPlan, ScanAllByLabelProperty) {
};
// normal ranges that return something
check(false, Bound::Type::INCLUSIVE, true, Bound::Type::EXCLUSIVE, {false});
check(false, Bound::Type::EXCLUSIVE, true, Bound::Type::INCLUSIVE, {true});
check("a", Bound::Type::EXCLUSIVE, "c", Bound::Type::EXCLUSIVE, {"b"});
check(0, Bound::Type::EXCLUSIVE, 2, Bound::Type::INCLUSIVE, {0.5, 1, 1.5, 2});
check(1.5, Bound::Type::EXCLUSIVE, 2.5, Bound::Type::INCLUSIVE, {2, 2.5});
check(std::vector<TypedValue>{0.5}, Bound::Type::EXCLUSIVE,
std::vector<TypedValue>{1.5}, Bound::Type::INCLUSIVE,
{TypedValue(std::vector<TypedValue>{1})});
check(TypedValue(false), Bound::Type::INCLUSIVE, TypedValue(true),
Bound::Type::EXCLUSIVE, {TypedValue(false)});
check(TypedValue(false), Bound::Type::EXCLUSIVE, TypedValue(true),
Bound::Type::INCLUSIVE, {TypedValue(true)});
check(TypedValue("a"), Bound::Type::EXCLUSIVE, TypedValue("c"),
Bound::Type::EXCLUSIVE, {TypedValue("b")});
check(TypedValue(0), Bound::Type::EXCLUSIVE, TypedValue(2),
Bound::Type::INCLUSIVE,
{TypedValue(0.5), TypedValue(1), TypedValue(1.5), TypedValue(2)});
check(TypedValue(1.5), Bound::Type::EXCLUSIVE, TypedValue(2.5),
Bound::Type::INCLUSIVE, {TypedValue(2), TypedValue(2.5)});
check(std::vector<TypedValue>{TypedValue(0.5)}, Bound::Type::EXCLUSIVE,
std::vector<TypedValue>{TypedValue(1.5)}, Bound::Type::INCLUSIVE,
{TypedValue(std::vector<TypedValue>{TypedValue(1)})});
// when a range contains different types, nothing should get returned
for (const auto &value_a : values)
@ -1682,7 +1697,7 @@ TEST(QueryPlan, ScanAllByLabelPropertyEqualityNoError) {
auto vertex = row[0].Value<VertexAccessor>();
auto value = vertex.PropsAt(prop);
TypedValue::BoolEqual eq;
EXPECT_TRUE(eq(value, 42));
EXPECT_TRUE(eq(value, TypedValue(42)));
}
TEST(QueryPlan, ScanAllByLabelPropertyValueError) {

View File

@ -28,17 +28,17 @@ class AllTypesFixture : public testing::Test {
values_.emplace_back(3.14);
values_.emplace_back("something");
values_.emplace_back(
std::vector<TypedValue>{true, "something", 42, 0.5, TypedValue()});
std::vector<TypedValue>{TypedValue(true), TypedValue("something"),
TypedValue(42), TypedValue(0.5), TypedValue()});
values_.emplace_back(
std::map<std::string, TypedValue>{{"a", true},
{"b", "something"},
{"c", 42},
{"d", 0.5},
std::map<std::string, TypedValue>{{"a", TypedValue(true)},
{"b", TypedValue("something")},
{"c", TypedValue(42)},
{"d", TypedValue(0.5)},
{"e", TypedValue()}});
auto vertex = dba_.InsertVertex();
values_.emplace_back(vertex);
values_.emplace_back(
dba_.InsertEdge(vertex, vertex, dba_.EdgeType("et")));
values_.emplace_back(dba_.InsertEdge(vertex, vertex, dba_.EdgeType("et")));
values_.emplace_back(query::Path(dba_.InsertVertex()));
}
};
@ -113,22 +113,31 @@ TEST(TypedValue, Equals) {
EXPECT_PROP_EQ(TypedValue(std::string("str3")), TypedValue("str3"));
EXPECT_PROP_NE(TypedValue(std::vector<TypedValue>{1}), TypedValue(1));
EXPECT_PROP_NE(TypedValue(std::vector<TypedValue>{1, true, "a"}),
TypedValue(std::vector<TypedValue>{1, true, "b"}));
EXPECT_PROP_EQ(TypedValue(std::vector<TypedValue>{1, true, "a"}),
TypedValue(std::vector<TypedValue>{1, true, "a"}));
EXPECT_PROP_NE(TypedValue(std::vector<TypedValue>{
TypedValue(1), TypedValue(true), TypedValue("a")}),
TypedValue(std::vector<TypedValue>{
TypedValue(1), TypedValue(true), TypedValue("b")}));
EXPECT_PROP_EQ(TypedValue(std::vector<TypedValue>{
TypedValue(1), TypedValue(true), TypedValue("a")}),
TypedValue(std::vector<TypedValue>{
TypedValue(1), TypedValue(true), TypedValue("a")}));
EXPECT_PROP_EQ(TypedValue(std::map<std::string, TypedValue>{{"a", 1}}),
TypedValue(std::map<std::string, TypedValue>{{"a", 1}}));
EXPECT_PROP_NE(TypedValue(std::map<std::string, TypedValue>{{"a", 1}}),
TypedValue(1));
EXPECT_PROP_NE(TypedValue(std::map<std::string, TypedValue>{{"a", 1}}),
TypedValue(std::map<std::string, TypedValue>{{"b", 1}}));
EXPECT_PROP_NE(TypedValue(std::map<std::string, TypedValue>{{"a", 1}}),
TypedValue(std::map<std::string, TypedValue>{{"a", 2}}));
EXPECT_PROP_EQ(
TypedValue(std::map<std::string, TypedValue>{{"a", TypedValue(1)}}),
TypedValue(std::map<std::string, TypedValue>{{"a", TypedValue(1)}}));
EXPECT_PROP_NE(
TypedValue(std::map<std::string, TypedValue>{{"a", 1}}),
TypedValue(std::map<std::string, TypedValue>{{"a", 1}, {"b", 1}}));
TypedValue(std::map<std::string, TypedValue>{{"a", TypedValue(1)}}),
TypedValue(1));
EXPECT_PROP_NE(
TypedValue(std::map<std::string, TypedValue>{{"a", TypedValue(1)}}),
TypedValue(std::map<std::string, TypedValue>{{"b", TypedValue(1)}}));
EXPECT_PROP_NE(
TypedValue(std::map<std::string, TypedValue>{{"a", TypedValue(1)}}),
TypedValue(std::map<std::string, TypedValue>{{"a", TypedValue(2)}}));
EXPECT_PROP_NE(
TypedValue(std::map<std::string, TypedValue>{{"a", TypedValue(1)}}),
TypedValue(std::map<std::string, TypedValue>{{"a", TypedValue(1)},
{"b", TypedValue(1)}}));
}
TEST(TypedValue, BoolEquals) {
@ -148,20 +157,26 @@ TEST(TypedValue, Hash) {
EXPECT_EQ(hash(TypedValue(1.5)), hash(TypedValue(1.5)));
EXPECT_EQ(hash(TypedValue()), hash(TypedValue()));
EXPECT_EQ(hash(TypedValue("bla")), hash(TypedValue("bla")));
EXPECT_EQ(hash(TypedValue(std::vector<TypedValue>{1, 2})),
hash(TypedValue(std::vector<TypedValue>{1, 2})));
EXPECT_EQ(hash(TypedValue(std::map<std::string, TypedValue>{{"a", 1}})),
hash(TypedValue(std::map<std::string, TypedValue>{{"a", 1}})));
EXPECT_EQ(
hash(TypedValue(std::vector<TypedValue>{TypedValue(1), TypedValue(2)})),
hash(TypedValue(std::vector<TypedValue>{TypedValue(1), TypedValue(2)})));
EXPECT_EQ(
hash(TypedValue(std::map<std::string, TypedValue>{{"a", TypedValue(1)}})),
hash(
TypedValue(std::map<std::string, TypedValue>{{"a", TypedValue(1)}})));
// these tests are not really true since they expect
// hashes to differ, but it's the thought that counts
EXPECT_NE(hash(TypedValue(1)), hash(TypedValue(42)));
EXPECT_NE(hash(TypedValue(1.5)), hash(TypedValue(2.5)));
EXPECT_NE(hash(TypedValue("bla")), hash(TypedValue("johnny")));
EXPECT_NE(hash(TypedValue(std::vector<TypedValue>{1, 1})),
hash(TypedValue(std::vector<TypedValue>{1, 2})));
EXPECT_NE(hash(TypedValue(std::map<std::string, TypedValue>{{"b", 1}})),
hash(TypedValue(std::map<std::string, TypedValue>{{"a", 1}})));
EXPECT_NE(
hash(TypedValue(std::vector<TypedValue>{TypedValue(1), TypedValue(1)})),
hash(TypedValue(std::vector<TypedValue>{TypedValue(1), TypedValue(2)})));
EXPECT_NE(
hash(TypedValue(std::map<std::string, TypedValue>{{"b", TypedValue(1)}})),
hash(
TypedValue(std::map<std::string, TypedValue>{{"a", TypedValue(1)}})));
}
TEST_F(AllTypesFixture, Less) {
@ -223,7 +238,7 @@ TEST(TypedValue, LogicalNot) {
TEST(TypedValue, UnaryMinus) {
EXPECT_TRUE((-TypedValue()).type() == TypedValue::Type::Null);
EXPECT_PROP_EQ((-TypedValue(2).Value<int64_t>()), -2);
EXPECT_PROP_EQ(TypedValue(-TypedValue(2).Value<int64_t>()), TypedValue(-2));
EXPECT_FLOAT_EQ((-TypedValue(2.0).Value<double>()), -2.0);
EXPECT_THROW(-TypedValue(true), TypedValueException);
@ -233,7 +248,7 @@ TEST(TypedValue, UnaryMinus) {
TEST(TypedValue, UnaryPlus) {
EXPECT_TRUE((+TypedValue()).type() == TypedValue::Type::Null);
EXPECT_PROP_EQ((+TypedValue(2).Value<int64_t>()), 2);
EXPECT_PROP_EQ(TypedValue(+TypedValue(2).Value<int64_t>()), TypedValue(2));
EXPECT_FLOAT_EQ((+TypedValue(2.0).Value<double>()), 2.0);
EXPECT_THROW(+TypedValue(true), TypedValueException);
@ -298,26 +313,25 @@ TEST_F(TypedValueArithmeticTest, Sum) {
// sum of props of the same type
EXPECT_EQ((TypedValue(2) + TypedValue(3)).Value<int64_t>(), 5);
EXPECT_FLOAT_EQ((TypedValue(2.5) + TypedValue(1.25)).Value<double>(), 3.75);
EXPECT_EQ((TypedValue("one") + TypedValue("two")).ValueString(),
"onetwo");
EXPECT_EQ((TypedValue("one") + TypedValue("two")).ValueString(), "onetwo");
// sum of string and numbers
EXPECT_EQ((TypedValue("one") + TypedValue(1)).ValueString(), "one1");
EXPECT_EQ((TypedValue(1) + TypedValue("one")).ValueString(), "1one");
EXPECT_EQ((TypedValue("one") + TypedValue(3.2)).ValueString(),
"one3.2");
EXPECT_EQ((TypedValue(3.2) + TypedValue("one")).ValueString(),
"3.2one");
std::vector<TypedValue> in = {1, 2, true, "a"};
std::vector<TypedValue> out1 = {2, 1, 2, true, "a"};
std::vector<TypedValue> out2 = {1, 2, true, "a", 2};
std::vector<TypedValue> out3 = {1, 2, true, "a", 1, 2, true, "a"};
EXPECT_PROP_EQ(
(TypedValue(2) + TypedValue(in)).ValueList(), out1);
EXPECT_PROP_EQ(
(TypedValue(in) + TypedValue(2)).ValueList(), out2);
EXPECT_PROP_EQ(
(TypedValue(in) + TypedValue(in)).ValueList(), out3);
EXPECT_EQ((TypedValue("one") + TypedValue(3.2)).ValueString(), "one3.2");
EXPECT_EQ((TypedValue(3.2) + TypedValue("one")).ValueString(), "3.2one");
std::vector<TypedValue> in{TypedValue(1), TypedValue(2), TypedValue(true),
TypedValue("a")};
std::vector<TypedValue> out1{TypedValue(2), TypedValue(1), TypedValue(2),
TypedValue(true), TypedValue("a")};
std::vector<TypedValue> out2{TypedValue(1), TypedValue(2), TypedValue(true),
TypedValue("a"), TypedValue(2)};
std::vector<TypedValue> out3{
TypedValue(1), TypedValue(2), TypedValue(true), TypedValue("a"),
TypedValue(1), TypedValue(2), TypedValue(true), TypedValue("a")};
EXPECT_PROP_EQ((TypedValue(2) + TypedValue(in)).ValueList(), out1);
EXPECT_PROP_EQ((TypedValue(in) + TypedValue(2)).ValueList(), out2);
EXPECT_PROP_EQ((TypedValue(in) + TypedValue(in)).ValueList(), out3);
}
TEST_F(TypedValueArithmeticTest, Difference) {