Revise user visible error messages

Summary: A quick clean-up of user visible error messages. Tried to make them gramatically correct by capitalizing the first word in the sentence and putting a dot at the end.

Reviewers: teon.banek, buda, ipaljak

Reviewed By: teon.banek

Subscribers: pullbot

Differential Revision: https://phabricator.memgraph.io/D1571
This commit is contained in:
Marin Tomic 2018-08-29 11:05:34 +02:00
parent 28ba872668
commit bff56bcf89
13 changed files with 297 additions and 278 deletions

View File

@ -9,7 +9,7 @@ namespace mvcc {
class SerializationError : public utils::BasicException {
static constexpr const char *default_message =
"Can't serialize due to concurrent operations";
"Can't serialize due to concurrent operations.";
public:
using utils::BasicException::BasicException;

View File

@ -18,7 +18,7 @@ int64_t ParseIntegerLiteral(const std::string &s) {
// Not really correct since long long can have a bigger range than int64_t.
return static_cast<int64_t>(std::stoll(s, 0, 0));
} catch (const std::out_of_range &) {
throw SemanticException("Integer literal exceeds 64 bits");
throw SemanticException("Integer literal exceeds 64 bits.");
}
}
@ -55,12 +55,12 @@ std::string ParseStringLiteral(const std::string &s) {
// t is high surrogate pair. Expect one more utf16 codepoint.
j = i + kShortUnicodeLength + 1;
if (j >= static_cast<int>(s.size()) - 1 || s[j] != '\\') {
throw SemanticException("Invalid utf codepoint");
throw SemanticException("Invalid UTF codepoint.");
}
++j;
if (j >= static_cast<int>(s.size()) - 1 ||
(s[j] != 'u' && s[j] != 'U')) {
throw SemanticException("Invalid utf codepoint");
throw SemanticException("Invalid UTF codepoint.");
}
++j;
int k = j;
@ -69,7 +69,7 @@ std::string ParseStringLiteral(const std::string &s) {
++k;
}
if (k != j + kShortUnicodeLength) {
throw SemanticException("Invalid utf codepoint");
throw SemanticException("Invalid UTF codepoint.");
}
char16_t surrogates[3] = {t,
static_cast<char16_t>(stoi(
@ -131,14 +131,14 @@ std::string ParseStringLiteral(const std::string &s) {
try {
unescaped += EncodeEscapedUnicodeCodepointUtf32(s, i);
} catch (const std::range_error &) {
throw SemanticException("Invalid utf codepoint");
throw SemanticException("Invalid UTF codepoint.");
}
break;
case 'u':
try {
unescaped += EncodeEscapedUnicodeCodepointUtf16(s, i);
} catch (const std::range_error &) {
throw SemanticException("Invalid utf codepoint");
throw SemanticException("Invalid UTF codepoint.");
}
break;
default:
@ -161,7 +161,7 @@ double ParseDoubleLiteral(const std::string &s) {
try {
return utils::ParseDouble(s);
} catch (const utils::BasicException &) {
throw SemanticException("Couldn't parse string to double");
throw SemanticException("Couldn't parse string to double.");
}
}
@ -229,7 +229,7 @@ bool TypedValueCompare(const TypedValue &a, const TypedValue &b) {
// the same type, or int+float combinations
if ((a.type() != b.type() && !(a.IsNumeric() && b.IsNumeric())))
throw QueryRuntimeException(
"Can't compare value of type {} to value of type {}", a.type(),
"Can't compare value of type {} to value of type {}.", a.type(),
b.type());
switch (a.type()) {
@ -253,7 +253,7 @@ bool TypedValueCompare(const TypedValue &a, const TypedValue &b) {
case TypedValue::Type::Edge:
case TypedValue::Type::Path:
throw QueryRuntimeException(
"Comparison is not defined for values of type {}", a.type());
"Comparison is not defined for values of type {}.", a.type());
default:
LOG(FATAL) << "Unhandled comparison for types";
}

View File

@ -46,13 +46,13 @@ class SemanticException : public QueryException {
class UnboundVariableError : public SemanticException {
public:
explicit UnboundVariableError(const std::string &name)
: SemanticException("Unbound variable: " + name) {}
: SemanticException("Unbound variable: " + name + ".") {}
};
class RedeclareVariableError : public SemanticException {
public:
explicit RedeclareVariableError(const std::string &name)
: SemanticException("Redeclaring variable: " + name) {}
: SemanticException("Redeclaring variable: " + name + ".") {}
};
class TypeMismatchError : public SemanticException {
@ -60,7 +60,7 @@ class TypeMismatchError : public SemanticException {
TypeMismatchError(const std::string &name, const std::string &datum,
const std::string &expected)
: SemanticException(fmt::format(
"Type mismatch: '{}' already defined as '{}', but expected '{}'.",
"Type mismatch: {} already defined as {}, expected {}.",
name, datum, expected)) {}
};
@ -74,7 +74,7 @@ class IndexInMulticommandTxException : public QueryException {
using QueryException::QueryException;
IndexInMulticommandTxException()
: QueryException(
"Index creation not allowed in multicommand transactions") {}
"CREATE INDEX not allowed in multicommand transactions.") {}
};
/**
@ -96,7 +96,7 @@ class HintedAbortError : public utils::BasicException {
: utils::BasicException(
"Transaction was asked to abort, most likely because it was "
"executing longer than time specified by "
"--query-execution-time-sec flag") {}
"--query-execution-time-sec flag.") {}
};
class ReconstructionException : public QueryException {
@ -111,7 +111,7 @@ class RemoveAttachedVertexException : public QueryRuntimeException {
public:
RemoveAttachedVertexException()
: QueryRuntimeException(
"Failed to remove vertex because of it's existing "
"Failed to remove node because of it's existing "
"connections. Consider using DETACH DELETE.") {}
};
@ -119,14 +119,15 @@ class UserModificationInMulticommandTxException : public QueryException {
public:
UserModificationInMulticommandTxException()
: QueryException(
"User modification not allowed in multicommand transactions") {}
"Authentication clause not allowed in multicommand transactions.") {
}
};
class StreamClauseInMulticommandTxException : public QueryException {
public:
StreamClauseInMulticommandTxException()
: QueryException(
"Stream clause not allowed in multicommand transactions") {}
"Stream clause not allowed in multicommand transactions.") {}
};
} // namespace query

View File

@ -129,16 +129,17 @@ antlrcpp::Any CypherMainVisitor::visitSingleQuery(
if (dynamic_cast<Unwind *>(clause)) {
if (has_update || has_return) {
throw SemanticException(
"Unwind can't be after return or update clause");
"UNWIND can't be put after RETURN clause or after an update.");
}
} else if (auto *match = dynamic_cast<Match *>(clause)) {
if (has_update || has_return) {
throw SemanticException("Match can't be after return or update clause");
throw SemanticException(
"MATCH can't be put after RETURN clause or after an update.");
}
if (match->optional_) {
has_optional_match = true;
} else if (has_optional_match) {
throw SemanticException("Match can't be after optional match");
throw SemanticException("MATCH can't be put after OPTIONAL MATCH.");
}
} else if (dynamic_cast<Create *>(clause) ||
dynamic_cast<Delete *>(clause) ||
@ -149,24 +150,24 @@ antlrcpp::Any CypherMainVisitor::visitSingleQuery(
dynamic_cast<RemoveLabels *>(clause) ||
dynamic_cast<Merge *>(clause)) {
if (has_return) {
throw SemanticException("Update clauses can't be after return");
throw SemanticException("Update clause can't be used after RETURN.");
}
has_update = true;
} else if (dynamic_cast<Return *>(clause)) {
if (has_return) {
throw SemanticException("There can be only one return in a clause");
throw SemanticException("There can only be one RETURN in a clause.");
}
has_return = true;
} else if (dynamic_cast<With *>(clause)) {
if (has_return) {
throw SemanticException("Return can't be before with");
throw SemanticException("RETURN can't be put before WITH.");
}
has_update = has_return = has_optional_match = false;
} else if (dynamic_cast<CreateIndex *>(clause)) {
// If there is CreateIndex clause then there shouldn't be anything else.
if (single_query->clauses_.size() != 1U) {
throw SemanticException(
"CreateIndex must be only clause in the query.");
"CREATE INDEX must be the only clause in a query.");
}
has_create_index = true;
} else {
@ -272,7 +273,7 @@ antlrcpp::Any CypherMainVisitor::visitUserOrRoleName(
std::string value = ctx->symbolicName()->accept(this).as<std::string>();
const std::regex NAME_REGEX("[a-zA-Z0-9_.+-]+");
if (!std::regex_match(value, NAME_REGEX)) {
throw SyntaxException("invalid user or role name");
throw SyntaxException("Invalid user or role name.");
}
return value;
}
@ -319,7 +320,7 @@ antlrcpp::Any CypherMainVisitor::visitCreateUser(
auth->user_ = ctx->user->accept(this).as<std::string>();
if (ctx->password) {
if (!ctx->password->StringLiteral() && !ctx->literal()->CYPHERNULL()) {
throw SyntaxException("password should be a string literal or NULL");
throw SyntaxException("Password should be a string literal or null.");
}
auth->password_ = ctx->password->accept(this);
}
@ -335,7 +336,7 @@ antlrcpp::Any CypherMainVisitor::visitSetPassword(
auth->action_ = AuthQuery::Action::SET_PASSWORD;
auth->user_ = ctx->user->accept(this).as<std::string>();
if (!ctx->password->StringLiteral() && !ctx->literal()->CYPHERNULL()) {
throw SyntaxException("password should be a string literal or NULL");
throw SyntaxException("Password should be a string literal or null.");
}
auth->password_ = ctx->password->accept(this);
return auth;
@ -499,17 +500,17 @@ antlrcpp::Any CypherMainVisitor::visitCreateStream(
MemgraphCypher::CreateStreamContext *ctx) {
std::string stream_name(ctx->streamName()->getText());
if (!ctx->streamUri->StringLiteral()) {
throw SyntaxException("Stream URI should be a string literal!");
throw SyntaxException("Stream URI should be a string literal.");
}
Expression *stream_uri = ctx->streamUri->accept(this);
if (!ctx->streamTopic->StringLiteral()) {
throw SyntaxException("Topic should be a string literal!");
throw SyntaxException("Topic should be a string literal.");
}
Expression *stream_topic = ctx->streamTopic->accept(this);
if (!ctx->transformUri->StringLiteral()) {
throw SyntaxException("Transform URI should be a string literal!");
throw SyntaxException("Transform URI should be a string literal.");
}
Expression *transform_uri = ctx->transformUri->accept(this);
@ -535,7 +536,7 @@ antlrcpp::Any CypherMainVisitor::visitBatchIntervalOption(
MemgraphCypher::BatchIntervalOptionContext *ctx) {
if (!ctx->literal()->numberLiteral() ||
!ctx->literal()->numberLiteral()->integerLiteral()) {
throw SyntaxException("Batch interval should be an integer literal!");
throw SyntaxException("Batch interval should be an integer.");
}
return ctx->literal()->accept(this);
}
@ -547,7 +548,7 @@ antlrcpp::Any CypherMainVisitor::visitBatchSizeOption(
MemgraphCypher::BatchSizeOptionContext *ctx) {
if (!ctx->literal()->numberLiteral() ||
!ctx->literal()->numberLiteral()->integerLiteral()) {
throw SyntaxException("Batch size should be an integer literal!");
throw SyntaxException("Batch size should be an integer.");
}
return ctx->literal()->accept(this);
}
@ -579,7 +580,7 @@ antlrcpp::Any CypherMainVisitor::visitStartStopStream(
if (ctx->limitBatchesOption()) {
if (!is_start) {
throw SyntaxException("Stop stream clause can't set batch limit!");
throw SyntaxException("STOP STREAM can't set batch limit.");
}
limit_batches = ctx->limitBatchesOption()->accept(this);
}
@ -594,7 +595,7 @@ antlrcpp::Any CypherMainVisitor::visitLimitBatchesOption(
MemgraphCypher::LimitBatchesOptionContext *ctx) {
if (!ctx->literal()->numberLiteral() ||
!ctx->literal()->numberLiteral()->integerLiteral()) {
throw SyntaxException("Batch limit should be an integer literal!");
throw SyntaxException("Batch limit should be an integer.");
}
return ctx->literal()->accept(this);
}
@ -673,7 +674,7 @@ antlrcpp::Any CypherMainVisitor::visitReturnItem(
std::string(ctx->variable()->accept(this).as<std::string>());
} else {
if (in_with_ && !dynamic_cast<Identifier *>(named_expr->expression_)) {
throw SemanticException("Only variables can be non aliased in with");
throw SemanticException("Only variables can be non-aliased in WITH.");
}
named_expr->name_ = std::string(ctx->getText());
named_expr->token_position_ =
@ -752,7 +753,7 @@ antlrcpp::Any CypherMainVisitor::visitMapLiteral(
ctx->propertyKeyName()[i]->accept(this);
Expression *value = ctx->expression()[i]->accept(this);
if (!map.insert({key, value}).second) {
throw SemanticException("Same key can't appear twice in map literal");
throw SemanticException("Same key can't appear twice in a map literal.");
}
}
return map;
@ -900,7 +901,8 @@ antlrcpp::Any CypherMainVisitor::visitRelationshipPattern(
if (relationshipDetail->total_weight &&
edge->type_ != EdgeAtom::Type::WEIGHTED_SHORTEST_PATH)
throw SemanticException(
"Variable for total weight is allowed only in wShortest");
"Variable for total weight is allowed only with weighted shortest "
"path expansion.");
auto visit_lambda = [this](auto *lambda) {
EdgeAtom::Lambda edge_lambda;
std::string traversed_edge_variable =
@ -927,7 +929,8 @@ antlrcpp::Any CypherMainVisitor::visitRelationshipPattern(
case 0:
if (edge->type_ == EdgeAtom::Type::WEIGHTED_SHORTEST_PATH)
throw SemanticException(
"Lambda for calculating weights is mandatory");
"Lambda for calculating weights is mandatory with weighted "
"shortest path expansion.");
// In variable expansion inner variables are mandatory.
anonymous_identifiers.push_back(&edge->filter_lambda_.inner_edge);
anonymous_identifiers.push_back(&edge->filter_lambda_.inner_node);
@ -948,17 +951,17 @@ antlrcpp::Any CypherMainVisitor::visitRelationshipPattern(
break;
case 2:
if (edge->type_ != EdgeAtom::Type::WEIGHTED_SHORTEST_PATH)
throw SemanticException("Only one relationship lambda allowed");
throw SemanticException("Only one filter lambda can be supplied.");
edge->weight_lambda_ = visit_lambda(relationshipLambdas[0]);
visit_total_weight();
edge->filter_lambda_ = visit_lambda(relationshipLambdas[1]);
break;
default:
throw SemanticException("Only one relationship lambda allowed");
throw SemanticException("Only one filter lambda can be supplied.");
}
} else if (!relationshipLambdas.empty()) {
throw SemanticException(
"Relationship lambda only supported in variable length expansion");
"Filter lambda is only allowed in variable length expansion.");
}
auto properties = relationshipDetail->properties();
@ -974,7 +977,8 @@ antlrcpp::Any CypherMainVisitor::visitRelationshipPattern(
break;
}
default:
throw SemanticException("Only one property map supported in edge");
throw SemanticException(
"Only one property map can be supplied for edge.");
}
return edge;
@ -1037,7 +1041,8 @@ antlrcpp::Any CypherMainVisitor::visitVariableExpansion(
upper = ctx->expression()[1]->accept(this);
}
if (lower && edge_type == EdgeAtom::Type::WEIGHTED_SHORTEST_PATH)
throw SemanticException("Lower bound is not allowed in wShortest.");
throw SemanticException(
"Lower bound is not allowed in weighted shortest path expansion.");
return std::make_tuple(edge_type, lower, upper);
}
@ -1301,7 +1306,7 @@ antlrcpp::Any CypherMainVisitor::visitAtom(MemgraphCypher::AtomContext *ctx) {
Expression *list_expr =
ctx->filterExpression()->idInColl()->expression()->accept(this);
if (!ctx->filterExpression()->where()) {
throw SyntaxException("all(...) requires a WHERE predicate");
throw SyntaxException("ALL(...) requires a WHERE predicate.");
}
Where *where = ctx->filterExpression()->where()->accept(this);
return static_cast<Expression *>(
@ -1315,7 +1320,7 @@ antlrcpp::Any CypherMainVisitor::visitAtom(MemgraphCypher::AtomContext *ctx) {
Expression *list_expr =
ctx->filterExpression()->idInColl()->expression()->accept(this);
if (!ctx->filterExpression()->where()) {
throw SyntaxException("single(...) requires a WHERE predicate");
throw SyntaxException("SINGLE(...) requires a WHERE predicate.");
}
Where *where = ctx->filterExpression()->where()->accept(this);
return static_cast<Expression *>(

View File

@ -51,7 +51,7 @@ void SymbolGenerator::VisitReturnBody(ReturnBody &body, Where *where) {
user_symbols.emplace_back(sym_pair.second);
}
if (user_symbols.empty()) {
throw SemanticException("There are no variables in scope to use for '*'");
throw SemanticException("There are no variables in scope to use for '*'.");
}
}
// WITH/RETURN clause removes declarations of all the previous variables and
@ -132,7 +132,7 @@ bool SymbolGenerator::PreVisit(CypherUnion &) {
bool SymbolGenerator::PostVisit(CypherUnion &cypher_union) {
if (prev_return_names_ != curr_return_names_) {
throw SemanticException(
"All sub queries in an UNION must have the same column names");
"All subqueries in an UNION must have the same column names.");
}
// create new symbols for the result of the union
@ -238,7 +238,7 @@ bool SymbolGenerator::Visit(TestStream &) { return true; }
SymbolGenerator::ReturnType SymbolGenerator::Visit(Identifier &ident) {
if (scope_.in_skip || scope_.in_limit) {
throw SemanticException("Variables are not allowed in {}",
throw SemanticException("Variables are not allowed in {}.",
scope_.in_skip ? "SKIP" : "LIMIT");
}
Symbol symbol;
@ -297,12 +297,12 @@ bool SymbolGenerator::PreVisit(Aggregation &aggr) {
if ((!scope_.in_return && !scope_.in_with) || scope_.in_order_by ||
scope_.in_skip || scope_.in_limit || scope_.in_where) {
throw SemanticException(
"Aggregation functions are only allowed in WITH and RETURN");
"Aggregation functions are only allowed in WITH and RETURN.");
}
if (scope_.in_aggregation) {
throw SemanticException(
"Using aggregation functions inside aggregation functions is not "
"allowed");
"allowed.");
}
if (scope_.num_if_operators) {
// Neo allows aggregations here and produces very interesting behaviors.
@ -313,7 +313,7 @@ bool SymbolGenerator::PreVisit(Aggregation &aggr) {
// TODO: Rethink of allowing aggregations in some parts of the CASE
// construct.
throw SemanticException(
"Using aggregation functions inside of CASE is not allowed");
"Using aggregation functions inside of CASE is not allowed.");
}
// Create a virtual symbol for aggregation result.
// Currently, we only have aggregation operators which return numbers.

View File

@ -56,7 +56,7 @@ StrippedQuery::StrippedQuery(const std::string &query) : original_(query) {
update(MatchEscapedName(i), Token::ESCAPED_NAME);
update(MatchUnescapedName(i), Token::UNESCAPED_NAME);
update(MatchWhitespaceAndComments(i), Token::SPACE);
if (token == Token::UNMATCHED) throw LexingException("Invalid query");
if (token == Token::UNMATCHED) throw LexingException("Invalid query.");
tokens.emplace_back(token, original_.substr(i, len));
i += len;
}
@ -233,26 +233,26 @@ std::string GetFirstUtf8Symbol(const char *_s) {
if ((*s >> 7) == 0x00) return std::string(_s, _s + 1);
if ((*s >> 5) == 0x06) {
auto *s1 = s + 1;
if ((*s1 >> 6) != 0x02) throw LexingException("Invalid character");
if ((*s1 >> 6) != 0x02) throw LexingException("Invalid character.");
return std::string(_s, _s + 2);
}
if ((*s >> 4) == 0x0e) {
auto *s1 = s + 1;
if ((*s1 >> 6) != 0x02) throw LexingException("Invalid character");
if ((*s1 >> 6) != 0x02) throw LexingException("Invalid character.");
auto *s2 = s + 2;
if ((*s2 >> 6) != 0x02) throw LexingException("Invalid character");
if ((*s2 >> 6) != 0x02) throw LexingException("Invalid character.");
return std::string(_s, _s + 3);
}
if ((*s >> 3) == 0x1e) {
auto *s1 = s + 1;
if ((*s1 >> 6) != 0x02) throw LexingException("Invalid character");
if ((*s1 >> 6) != 0x02) throw LexingException("Invalid character.");
auto *s2 = s + 2;
if ((*s2 >> 6) != 0x02) throw LexingException("Invalid character");
if ((*s2 >> 6) != 0x02) throw LexingException("Invalid character.");
auto *s3 = s + 3;
if ((*s3 >> 6) != 0x02) throw LexingException("Invalid character");
if ((*s3 >> 6) != 0x02) throw LexingException("Invalid character.");
return std::string(_s, _s + 4);
}
throw LexingException("Invalid character");
throw LexingException("Invalid character.");
}
// Return codepoint of first utf8 symbol and its encoded length.
@ -264,28 +264,28 @@ std::pair<int, int> GetFirstUtf8SymbolCodepoint(const char *_s) {
if ((*s >> 7) == 0x00) return {*s & 0x7f, 1};
if ((*s >> 5) == 0x06) {
auto *s1 = s + 1;
if ((*s1 >> 6) != 0x02) throw LexingException("Invalid character");
if ((*s1 >> 6) != 0x02) throw LexingException("Invalid character.");
return {((*s & 0x1f) << 6) | (*s1 & 0x3f), 2};
}
if ((*s >> 4) == 0x0e) {
auto *s1 = s + 1;
if ((*s1 >> 6) != 0x02) throw LexingException("Invalid character");
if ((*s1 >> 6) != 0x02) throw LexingException("Invalid character.");
auto *s2 = s + 2;
if ((*s2 >> 6) != 0x02) throw LexingException("Invalid character");
if ((*s2 >> 6) != 0x02) throw LexingException("Invalid character.");
return {((*s & 0x0f) << 12) | ((*s1 & 0x3f) << 6) | (*s2 & 0x3f), 3};
}
if ((*s >> 3) == 0x1e) {
auto *s1 = s + 1;
if ((*s1 >> 6) != 0x02) throw LexingException("Invalid character");
if ((*s1 >> 6) != 0x02) throw LexingException("Invalid character.");
auto *s2 = s + 2;
if ((*s2 >> 6) != 0x02) throw LexingException("Invalid character");
if ((*s2 >> 6) != 0x02) throw LexingException("Invalid character.");
auto *s3 = s + 3;
if ((*s3 >> 6) != 0x02) throw LexingException("Invalid character");
if ((*s3 >> 6) != 0x02) throw LexingException("Invalid character.");
return {((*s & 0x07) << 18) | ((*s1 & 0x3f) << 12) | ((*s2 & 0x3f) << 6) |
(*s3 & 0x3f),
4};
}
throw LexingException("Invalid character");
throw LexingException("Invalid character.");
}
// From here until end of file there are functions that calculate matches for

View File

@ -34,7 +34,7 @@ namespace {
TypedValue Coalesce(const std::vector<TypedValue> &args, Context *) {
if (args.size() == 0U) {
throw QueryRuntimeException("coalesce requires at least one argument");
throw QueryRuntimeException("'coalesce' requires at least one argument.");
}
for (auto &arg : args) {
if (arg.type() != TypedValue::Type::Null) {
@ -46,7 +46,7 @@ TypedValue Coalesce(const std::vector<TypedValue> &args, Context *) {
TypedValue EndNode(const std::vector<TypedValue> &args, Context *) {
if (args.size() != 1U) {
throw QueryRuntimeException("endNode requires one argument");
throw QueryRuntimeException("'endNode' requires exactly one argument.");
}
switch (args[0].type()) {
case TypedValue::Type::Null:
@ -54,13 +54,13 @@ TypedValue EndNode(const std::vector<TypedValue> &args, Context *) {
case TypedValue::Type::Edge:
return args[0].Value<EdgeAccessor>().to();
default:
throw QueryRuntimeException("endNode argument should be an edge");
throw QueryRuntimeException("'endNode' argument must be an edge.");
}
}
TypedValue Head(const std::vector<TypedValue> &args, Context *) {
if (args.size() != 1U) {
throw QueryRuntimeException("head requires one argument");
throw QueryRuntimeException("'head' requires exactly one argument.");
}
switch (args[0].type()) {
case TypedValue::Type::Null:
@ -71,13 +71,13 @@ TypedValue Head(const std::vector<TypedValue> &args, Context *) {
return list[0];
}
default:
throw QueryRuntimeException("head argument should be a list");
throw QueryRuntimeException("'head' argument must be a list.");
}
}
TypedValue Last(const std::vector<TypedValue> &args, Context *) {
if (args.size() != 1U) {
throw QueryRuntimeException("last requires one argument");
throw QueryRuntimeException("'last' requires exactly one argument.");
}
switch (args[0].type()) {
case TypedValue::Type::Null:
@ -88,13 +88,13 @@ TypedValue Last(const std::vector<TypedValue> &args, Context *) {
return list.back();
}
default:
throw QueryRuntimeException("last argument should be a list");
throw QueryRuntimeException("'last' argument must be a list.");
}
}
TypedValue Properties(const std::vector<TypedValue> &args, Context *ctx) {
if (args.size() != 1U) {
throw QueryRuntimeException("properties requires one argument");
throw QueryRuntimeException("'properties' requires exactly one argument.");
}
auto get_properties = [&](const auto &record_accessor) {
std::map<std::string, TypedValue> properties;
@ -113,13 +113,13 @@ TypedValue Properties(const std::vector<TypedValue> &args, Context *ctx) {
return get_properties(args[0].Value<EdgeAccessor>());
default:
throw QueryRuntimeException(
"properties argument should be a vertex or an edge");
"'properties' argument must be a node or an edge.");
}
}
TypedValue Size(const std::vector<TypedValue> &args, Context *) {
if (args.size() != 1U) {
throw QueryRuntimeException("size requires one argument");
throw QueryRuntimeException("'size' requires exactly one argument.");
}
switch (args[0].type()) {
case TypedValue::Type::Null:
@ -138,13 +138,13 @@ TypedValue Size(const std::vector<TypedValue> &args, Context *) {
return static_cast<int64_t>(args[0].ValuePath().edges().size());
default:
throw QueryRuntimeException(
"size argument should be a string, a collection or a path");
"'size' argument must be a string, a collection or a path.");
}
}
TypedValue StartNode(const std::vector<TypedValue> &args, Context *) {
if (args.size() != 1U) {
throw QueryRuntimeException("startNode requires one argument");
throw QueryRuntimeException("'startNode' requires exactly one argument.");
}
switch (args[0].type()) {
case TypedValue::Type::Null:
@ -152,13 +152,13 @@ TypedValue StartNode(const std::vector<TypedValue> &args, Context *) {
case TypedValue::Type::Edge:
return args[0].Value<EdgeAccessor>().from();
default:
throw QueryRuntimeException("startNode argument should be an edge");
throw QueryRuntimeException("'startNode' argument must be an edge.");
}
}
TypedValue Degree(const std::vector<TypedValue> &args, Context *) {
if (args.size() != 1U) {
throw QueryRuntimeException("degree requires one argument");
throw QueryRuntimeException("'degree' requires exactly one argument.");
}
switch (args[0].type()) {
case TypedValue::Type::Null:
@ -168,13 +168,13 @@ TypedValue Degree(const std::vector<TypedValue> &args, Context *) {
return static_cast<int64_t>(vertex.out_degree() + vertex.in_degree());
}
default:
throw QueryRuntimeException("degree argument should be a vertex");
throw QueryRuntimeException("'degree' argument must be a node.");
}
}
TypedValue ToBoolean(const std::vector<TypedValue> &args, Context *) {
if (args.size() != 1U) {
throw QueryRuntimeException("toBoolean requires one argument");
throw QueryRuntimeException("'toBoolean' requires exactly one argument.");
}
switch (args[0].type()) {
case TypedValue::Type::Null:
@ -193,13 +193,13 @@ TypedValue ToBoolean(const std::vector<TypedValue> &args, Context *) {
}
default:
throw QueryRuntimeException(
"toBoolean argument should be an integer, a string or a boolean");
"'toBoolean' argument must be an integer, a string or a boolean.");
}
}
TypedValue ToFloat(const std::vector<TypedValue> &args, Context *) {
if (args.size() != 1U) {
throw QueryRuntimeException("toFloat requires one argument");
throw QueryRuntimeException("'toFloat' requires exactly one argument.");
}
switch (args[0].type()) {
case TypedValue::Type::Null:
@ -216,13 +216,13 @@ TypedValue ToFloat(const std::vector<TypedValue> &args, Context *) {
}
default:
throw QueryRuntimeException(
"toFloat argument should be a string or a number");
"'toFloat' argument must be a string or a number.");
}
}
TypedValue ToInteger(const std::vector<TypedValue> &args, Context *) {
if (args.size() != 1U) {
throw QueryRuntimeException("toInteger requires one argument");
throw QueryRuntimeException("'toInteger' requires exactly one argument'");
}
switch (args[0].type()) {
case TypedValue::Type::Null:
@ -244,13 +244,13 @@ TypedValue ToInteger(const std::vector<TypedValue> &args, Context *) {
}
default:
throw QueryRuntimeException(
"toInteger argument should be a string, a boolean or a number");
"'toInteger' argument must be a string, a boolean or a number.");
}
}
TypedValue Type(const std::vector<TypedValue> &args, Context *ctx) {
if (args.size() != 1U) {
throw QueryRuntimeException("type requires one argument");
throw QueryRuntimeException("'type' requires exactly one argument.");
}
switch (args[0].type()) {
case TypedValue::Type::Null:
@ -259,13 +259,13 @@ TypedValue Type(const std::vector<TypedValue> &args, Context *ctx) {
return ctx->db_accessor_.EdgeTypeName(
args[0].Value<EdgeAccessor>().EdgeType());
default:
throw QueryRuntimeException("type argument should be an edge");
throw QueryRuntimeException("'type' argument must be an edge.");
}
}
TypedValue Keys(const std::vector<TypedValue> &args, Context *ctx) {
if (args.size() != 1U) {
throw QueryRuntimeException("keys requires one argument");
throw QueryRuntimeException("'keys' requires exactly one argument.");
}
auto get_keys = [&](const auto &record_accessor) {
std::vector<TypedValue> keys;
@ -282,14 +282,13 @@ TypedValue Keys(const std::vector<TypedValue> &args, Context *ctx) {
case TypedValue::Type::Edge:
return get_keys(args[0].Value<EdgeAccessor>());
default:
throw QueryRuntimeException(
"keys argument should be a vertex or an edge");
throw QueryRuntimeException("'keys' argument must be a node or an edge.");
}
}
TypedValue Labels(const std::vector<TypedValue> &args, Context *ctx) {
if (args.size() != 1U) {
throw QueryRuntimeException("labels requires one argument");
throw QueryRuntimeException("'labels' requires exactly one argument.");
}
switch (args[0].type()) {
case TypedValue::Type::Null:
@ -302,17 +301,17 @@ TypedValue Labels(const std::vector<TypedValue> &args, Context *ctx) {
return labels;
}
default:
throw QueryRuntimeException("labels argument should be a vertex");
throw QueryRuntimeException("'labels' argument must be a node.");
}
}
TypedValue Nodes(const std::vector<TypedValue> &args, Context *) {
if (args.size() != 1U) {
throw QueryRuntimeException("nodes requires one argument");
throw QueryRuntimeException("'nodes' requires exactly one argument.");
}
if (args[0].IsNull()) return TypedValue::Null;
if (!args[0].IsPath()) {
throw QueryRuntimeException("nodes argument should be a path");
throw QueryRuntimeException("'nodes' argument should be a path.");
}
auto &vertices = args[0].ValuePath().vertices();
return std::vector<TypedValue>(vertices.begin(), vertices.end());
@ -320,11 +319,12 @@ TypedValue Nodes(const std::vector<TypedValue> &args, Context *) {
TypedValue Relationships(const std::vector<TypedValue> &args, Context *) {
if (args.size() != 1U) {
throw QueryRuntimeException("relationships requires one argument");
throw QueryRuntimeException(
"'relationships' requires exactly one argument.");
}
if (args[0].IsNull()) return TypedValue::Null;
if (!args[0].IsPath()) {
throw QueryRuntimeException("relationships argument should be a path");
throw QueryRuntimeException("'relationships' argument must be a path.");
}
auto &edges = args[0].ValuePath().edges();
return std::vector<TypedValue>(edges.begin(), edges.end());
@ -332,14 +332,14 @@ TypedValue Relationships(const std::vector<TypedValue> &args, Context *) {
TypedValue Range(const std::vector<TypedValue> &args, Context *) {
if (args.size() != 2U && args.size() != 3U) {
throw QueryRuntimeException("range requires two or three arguments");
throw QueryRuntimeException("'range' requires two or three arguments.");
}
bool has_null = false;
auto check_type = [&](const TypedValue &t) {
if (t.IsNull()) {
has_null = true;
} else if (t.type() != TypedValue::Type::Int) {
throw QueryRuntimeException("arguments of range should be integers");
throw QueryRuntimeException("arguments of 'range' must be integers.");
}
};
std::for_each(args.begin(), args.end(), check_type);
@ -348,7 +348,7 @@ TypedValue Range(const std::vector<TypedValue> &args, Context *) {
auto rbound = args[1].Value<int64_t>();
int64_t step = args.size() == 3U ? args[2].Value<int64_t>() : 1;
if (step == 0) {
throw QueryRuntimeException("step argument in range can't be zero");
throw QueryRuntimeException("step argument of 'range' can't be zero.");
}
std::vector<TypedValue> list;
if (lbound <= rbound && step > 0) {
@ -365,7 +365,7 @@ TypedValue Range(const std::vector<TypedValue> &args, Context *) {
TypedValue Tail(const std::vector<TypedValue> &args, Context *) {
if (args.size() != 1U) {
throw QueryRuntimeException("tail requires one argument");
throw QueryRuntimeException("'tail' requires exactly one argument.");
}
switch (args[0].type()) {
case TypedValue::Type::Null:
@ -377,13 +377,13 @@ TypedValue Tail(const std::vector<TypedValue> &args, Context *) {
return list;
}
default:
throw QueryRuntimeException("tail argument should be a list");
throw QueryRuntimeException("'tail' argument must be a list.");
}
}
TypedValue Abs(const std::vector<TypedValue> &args, Context *) {
if (args.size() != 1U) {
throw QueryRuntimeException("abs requires one argument");
throw QueryRuntimeException("'abs' requires exactly one argument.");
}
switch (args[0].type()) {
case TypedValue::Type::Null:
@ -394,26 +394,27 @@ TypedValue Abs(const std::vector<TypedValue> &args, Context *) {
case TypedValue::Type::Double:
return std::abs(args[0].Value<double>());
default:
throw QueryRuntimeException("abs argument should be a number");
throw QueryRuntimeException("'abs' argument should be a number.");
}
}
#define WRAP_CMATH_FLOAT_FUNCTION(name, lowercased_name) \
TypedValue name(const std::vector<TypedValue> &args, Context *) { \
if (args.size() != 1U) { \
throw QueryRuntimeException(#lowercased_name " requires one argument"); \
} \
switch (args[0].type()) { \
case TypedValue::Type::Null: \
return TypedValue::Null; \
case TypedValue::Type::Int: \
return lowercased_name(args[0].Value<int64_t>()); \
case TypedValue::Type::Double: \
return lowercased_name(args[0].Value<double>()); \
default: \
throw QueryRuntimeException(#lowercased_name \
" argument should be a number"); \
} \
#define WRAP_CMATH_FLOAT_FUNCTION(name, lowercased_name) \
TypedValue name(const std::vector<TypedValue> &args, Context *) { \
if (args.size() != 1U) { \
throw QueryRuntimeException("'" #lowercased_name \
"' requires exactly one argument."); \
} \
switch (args[0].type()) { \
case TypedValue::Type::Null: \
return TypedValue::Null; \
case TypedValue::Type::Int: \
return lowercased_name(args[0].Value<int64_t>()); \
case TypedValue::Type::Double: \
return lowercased_name(args[0].Value<double>()); \
default: \
throw QueryRuntimeException(#lowercased_name \
" argument must be a number."); \
} \
}
WRAP_CMATH_FLOAT_FUNCTION(Ceil, ceil)
@ -436,7 +437,7 @@ WRAP_CMATH_FLOAT_FUNCTION(Tan, tan)
TypedValue Atan2(const std::vector<TypedValue> &args, Context *) {
if (args.size() != 2U) {
throw QueryRuntimeException("atan2 requires two arguments");
throw QueryRuntimeException("'atan2' requires two arguments.");
}
if (args[0].type() == TypedValue::Type::Null) return TypedValue::Null;
if (args[1].type() == TypedValue::Type::Null) return TypedValue::Null;
@ -447,7 +448,7 @@ TypedValue Atan2(const std::vector<TypedValue> &args, Context *) {
case TypedValue::Type::Double:
return t.Value<double>();
default:
throw QueryRuntimeException("arguments of atan2 should be numbers");
throw QueryRuntimeException("Arguments of 'atan2' must be numbers.");
}
};
double y = to_double(args[0]);
@ -457,7 +458,7 @@ TypedValue Atan2(const std::vector<TypedValue> &args, Context *) {
TypedValue Sign(const std::vector<TypedValue> &args, Context *) {
if (args.size() != 1U) {
throw QueryRuntimeException("sign requires one argument");
throw QueryRuntimeException("'sign' requires exactly one argument.");
}
auto sign = [](auto x) { return (0 < x) - (x < 0); };
switch (args[0].type()) {
@ -468,20 +469,20 @@ TypedValue Sign(const std::vector<TypedValue> &args, Context *) {
case TypedValue::Type::Double:
return sign(args[0].Value<double>());
default:
throw QueryRuntimeException("sign argument should be a number");
throw QueryRuntimeException("'sign' argument must be a number.");
}
}
TypedValue E(const std::vector<TypedValue> &args, Context *) {
if (args.size() != 0U) {
throw QueryRuntimeException("e requires no arguments");
throw QueryRuntimeException("'e' requires no arguments.");
}
return M_E;
}
TypedValue Pi(const std::vector<TypedValue> &args, Context *) {
if (args.size() != 0U) {
throw QueryRuntimeException("pi requires no arguments");
throw QueryRuntimeException("'pi' requires no arguments.");
}
return M_PI;
}
@ -490,7 +491,7 @@ TypedValue Rand(const std::vector<TypedValue> &args, Context *) {
static thread_local std::mt19937 pseudo_rand_gen_{std::random_device{}()};
static thread_local std::uniform_real_distribution<> rand_dist_{0, 1};
if (args.size() != 0U) {
throw QueryRuntimeException("rand requires no arguments");
throw QueryRuntimeException("'rand' requires no arguments.");
}
return rand_dist_(pseudo_rand_gen_);
}
@ -499,7 +500,7 @@ template <bool (*Predicate)(const std::string &s1, const std::string &s2)>
TypedValue StringMatchOperator(const std::vector<TypedValue> &args, Context *) {
if (args.size() != 2U) {
throw QueryRuntimeException(
"startsWith and endsWith require two arguments");
"'startsWith' and 'endsWith' require two arguments.");
}
bool has_null = false;
auto check_arg = [&](const TypedValue &t) {
@ -507,7 +508,7 @@ TypedValue StringMatchOperator(const std::vector<TypedValue> &args, Context *) {
has_null = true;
} else if (t.type() != TypedValue::Type::String) {
throw QueryRuntimeException(
"arguments of startsWith and endsWith should be strings");
"Arguments of 'startsWith' and 'endsWith' must be strings.");
}
};
check_arg(args[0]);
@ -541,15 +542,18 @@ auto Contains = StringMatchOperator<ContainsPredicate>;
TypedValue Assert(const std::vector<TypedValue> &args, Context *) {
if (args.size() < 1U || args.size() > 2U) {
throw QueryRuntimeException("assert requires one or two arguments");
throw QueryRuntimeException("'assert' requires one or two arguments");
}
if (args[0].type() != TypedValue::Type::Bool)
throw QueryRuntimeException("first argument of assert must be a boolean");
throw QueryRuntimeException(
"First argument of 'assert' must be a boolean.");
if (args.size() == 2U && args[1].type() != TypedValue::Type::String)
throw QueryRuntimeException("second argument of assert must be a string");
throw QueryRuntimeException(
"Second argument of 'assert' must be a string.");
if (!args[0].ValueBool()) {
std::string message("assertion failed");
std::string message("Assertion failed");
if (args.size() == 2U) message += ": " + args[1].ValueString();
message += ".";
throw QueryRuntimeException(message);
}
return args[0];
@ -557,31 +561,31 @@ TypedValue Assert(const std::vector<TypedValue> &args, Context *) {
TypedValue Counter(const std::vector<TypedValue> &args, Context *ctx) {
if (args.size() != 1U) {
throw QueryRuntimeException("counter requires one argument");
throw QueryRuntimeException("'counter' requires exactly one argument.");
}
if (!args[0].IsString())
throw QueryRuntimeException("counter argument must be a string");
throw QueryRuntimeException("'counter' argument must be a string.");
return ctx->db_accessor_.Counter(args[0].ValueString());
}
TypedValue CounterSet(const std::vector<TypedValue> &args, Context *ctx) {
if (args.size() != 2U) {
throw QueryRuntimeException("counterSet requires two arguments");
throw QueryRuntimeException("'counterSet' requires two arguments.");
}
if (!args[0].IsString())
throw QueryRuntimeException(
"first argument of counterSet must be a string");
"First argument of 'counterSet' must be a string.");
if (!args[1].IsInt())
throw QueryRuntimeException(
"second argument of counterSet must be an integer");
"Second argument of 'counterSet' must be an integer.");
ctx->db_accessor_.CounterSet(args[0].ValueString(), args[1].ValueInt());
return TypedValue::Null;
}
TypedValue IndexInfo(const std::vector<TypedValue> &args, Context *ctx) {
if (args.size() != 0U)
throw QueryRuntimeException("indexInfo requires no arguments");
throw QueryRuntimeException("'indexInfo' requires no arguments.");
auto info = ctx->db_accessor_.IndexInfo();
return std::vector<TypedValue>(info.begin(), info.end());
@ -589,7 +593,7 @@ TypedValue IndexInfo(const std::vector<TypedValue> &args, Context *ctx) {
TypedValue WorkerId(const std::vector<TypedValue> &args, Context *) {
if (args.size() != 1U) {
throw QueryRuntimeException("workerId requires one argument");
throw QueryRuntimeException("'workerId' requires exactly one argument.");
}
auto &arg = args[0];
switch (arg.type()) {
@ -599,13 +603,13 @@ TypedValue WorkerId(const std::vector<TypedValue> &args, Context *) {
return arg.ValueEdge().GlobalAddress().worker_id();
default:
throw QueryRuntimeException(
"workerId argument must be a vertex or an edge");
"'workerId' argument must be a node or an edge.");
}
}
TypedValue Id(const std::vector<TypedValue> &args, Context *ctx) {
if (args.size() != 1U) {
throw QueryRuntimeException("id requires one argument");
throw QueryRuntimeException("'id' requires exactly one argument.");
}
auto &arg = args[0];
switch (arg.type()) {
@ -616,13 +620,13 @@ TypedValue Id(const std::vector<TypedValue> &args, Context *ctx) {
return TypedValue(arg.ValueEdge().cypher_id());
}
default:
throw QueryRuntimeException("id argument must be a vertex or an edge");
throw QueryRuntimeException("'id' argument must be a node or an edge.");
}
}
TypedValue ToString(const std::vector<TypedValue> &args, Context *) {
if (args.size() != 1U) {
throw QueryRuntimeException("toString requires one argument");
throw QueryRuntimeException("'toString' requires exactly one argument.");
}
auto &arg = args[0];
switch (arg.type()) {
@ -638,20 +642,20 @@ TypedValue ToString(const std::vector<TypedValue> &args, Context *) {
return arg.ValueBool() ? "true" : "false";
default:
throw QueryRuntimeException(
"toString argument must be a number, a string or a boolean");
"'toString' argument must be a number, a string or a boolean.");
}
}
TypedValue Timestamp(const std::vector<TypedValue> &args, Context *ctx) {
if (args.size() != 0) {
throw QueryRuntimeException("timestamp requires no arguments");
throw QueryRuntimeException("'timestamp' requires no arguments.");
}
return ctx->timestamp_;
}
TypedValue Left(const std::vector<TypedValue> &args, Context *ctx) {
if (args.size() != 2) {
throw QueryRuntimeException("left requires two arguments");
throw QueryRuntimeException("'left' requires two arguments.");
}
switch (args[0].type()) {
case TypedValue::Type::Null:
@ -659,21 +663,21 @@ TypedValue Left(const std::vector<TypedValue> &args, Context *ctx) {
return TypedValue::Null;
}
throw QueryRuntimeException(
"second argument of left must be a non-negative integer");
"Second argument of 'left' must be a non-negative integer.");
case TypedValue::Type::String:
if (args[1].IsInt() && args[1].ValueInt() >= 0) {
return args[0].ValueString().substr(0, args[1].ValueInt());
}
throw QueryRuntimeException(
"second argument of left must be a non-negative integer");
"Second argument of 'left' must be a non-negative integer.");
default:
throw QueryRuntimeException("first argument of left must be a string");
throw QueryRuntimeException("First argument of 'left' must be a string.");
}
}
TypedValue Right(const std::vector<TypedValue> &args, Context *ctx) {
if (args.size() != 2) {
throw QueryRuntimeException("right requires two arguments");
throw QueryRuntimeException("'right' requires two arguments.");
}
switch (args[0].type()) {
case TypedValue::Type::Null:
@ -681,7 +685,7 @@ TypedValue Right(const std::vector<TypedValue> &args, Context *ctx) {
return TypedValue::Null;
}
throw QueryRuntimeException(
"second argument of right must be a non-negative integer");
"Second argument of 'right' must be a non-negative integer.");
case TypedValue::Type::String: {
const auto &str = args[0].ValueString();
if (args[1].IsInt() && args[1].ValueInt() >= 0) {
@ -689,27 +693,29 @@ TypedValue Right(const std::vector<TypedValue> &args, Context *ctx) {
return len <= str.size() ? str.substr(str.size() - len, len) : str;
}
throw QueryRuntimeException(
"second argument of right must be a non-negative integer");
"Second argument of 'right' must be a non-negative integer.");
}
default:
throw QueryRuntimeException("first argument of right must be a string");
throw QueryRuntimeException(
"First argument of 'right' must be a string.");
}
}
#define WRAP_STRING_FUNCTION(name, lowercased_name, function) \
TypedValue name(const std::vector<TypedValue> &args, Context *) { \
if (args.size() != 1U) { \
throw QueryRuntimeException(#lowercased_name " requires one argument"); \
} \
switch (args[0].type()) { \
case TypedValue::Type::Null: \
return TypedValue::Null; \
case TypedValue::Type::String: \
return function(args[0].ValueString()); \
default: \
throw QueryRuntimeException(#lowercased_name \
" argument should be a string"); \
} \
#define WRAP_STRING_FUNCTION(name, lowercased_name, function) \
TypedValue name(const std::vector<TypedValue> &args, Context *) { \
if (args.size() != 1U) { \
throw QueryRuntimeException("'" #lowercased_name \
"' requires exactly one argument."); \
} \
switch (args[0].type()) { \
case TypedValue::Type::Null: \
return TypedValue::Null; \
case TypedValue::Type::String: \
return function(args[0].ValueString()); \
default: \
throw QueryRuntimeException("'" #lowercased_name \
"' argument should be a string."); \
} \
}
WRAP_STRING_FUNCTION(LTrim, lTrim, utils::LTrim);
@ -721,17 +727,19 @@ WRAP_STRING_FUNCTION(ToUpper, toUpper, utils::ToUpperCase);
TypedValue Replace(const std::vector<TypedValue> &args, Context *ctx) {
if (args.size() != 3U) {
throw QueryRuntimeException("replace requires three arguments");
throw QueryRuntimeException("'replace' requires three arguments.");
}
if (!args[0].IsNull() && !args[0].IsString()) {
throw QueryRuntimeException("first argument of replace should be a string");
throw QueryRuntimeException(
"First argument of 'replace' should be a string.");
}
if (!args[1].IsNull() && !args[1].IsString()) {
throw QueryRuntimeException(
"second argument of replace should be a string");
"Second argument of 'replace' should be a string.");
}
if (!args[2].IsNull() && !args[2].IsString()) {
throw QueryRuntimeException("third argument of replace should be a string");
throw QueryRuntimeException(
"Third argument of 'replace' should be a string.");
}
if (args[0].IsNull() || args[1].IsNull() || args[2].IsNull()) {
return TypedValue::Null;
@ -742,13 +750,15 @@ TypedValue Replace(const std::vector<TypedValue> &args, Context *ctx) {
TypedValue Split(const std::vector<TypedValue> &args, Context *ctx) {
if (args.size() != 2U) {
throw QueryRuntimeException("split requires two arguments");
throw QueryRuntimeException("'split' requires two arguments.");
}
if (!args[0].IsNull() && !args[0].IsString()) {
throw QueryRuntimeException("first argument of split should be a string");
throw QueryRuntimeException(
"First argument of 'split' should be a string.");
}
if (!args[1].IsNull() && !args[1].IsString()) {
throw QueryRuntimeException("second argument of split should be a string");
throw QueryRuntimeException(
"Second argument of 'split' should be a string.");
}
if (args[0].IsNull() || args[1].IsNull()) {
return TypedValue::Null;
@ -763,19 +773,19 @@ TypedValue Split(const std::vector<TypedValue> &args, Context *ctx) {
TypedValue Substring(const std::vector<TypedValue> &args, Context *) {
if (args.size() != 2U && args.size() != 3U) {
throw QueryRuntimeException("substring requires two or three arguments");
throw QueryRuntimeException("'substring' requires two or three arguments.");
}
if (!args[0].IsNull() && !args[0].IsString()) {
throw QueryRuntimeException(
"first argument of substring should be a string");
"First argument of 'substring' should be a string.");
}
if (!args[1].IsInt() || args[1].ValueInt() < 0) {
throw QueryRuntimeException(
"second argument of substring should be a non-negative integer");
"Second argument of 'substring' should be a non-negative integer.");
}
if (args.size() == 3U && (!args[2].IsInt() || args[2].ValueInt() < 0)) {
throw QueryRuntimeException(
"third argument of substring should be a non-negative integer");
"Third argument of 'substring' should be a non-negative integer.");
}
if (args[0].IsNull()) {
return TypedValue::Null;

View File

@ -80,20 +80,20 @@ class ExpressionEvaluator : public TreeVisitor<TypedValue> {
try { \
return val1 CPP_OP val2; \
} catch (const TypedValueException &) { \
throw QueryRuntimeException("Invalid types: {} and {} for '{}'", \
throw QueryRuntimeException("Invalid types: {} and {} for '{}'.", \
val1.type(), val2.type(), #CYPHER_OP); \
} \
}
#define UNARY_OPERATOR_VISITOR(OP_NODE, CPP_OP, CYPHER_OP) \
TypedValue Visit(OP_NODE &op) override { \
auto val = op.expression_->Accept(*this); \
try { \
return CPP_OP val; \
} catch (const TypedValueException &) { \
throw QueryRuntimeException("Invalid type {} for '{}'", val.type(), \
#CYPHER_OP); \
} \
#define UNARY_OPERATOR_VISITOR(OP_NODE, CPP_OP, CYPHER_OP) \
TypedValue Visit(OP_NODE &op) override { \
auto val = op.expression_->Accept(*this); \
try { \
return CPP_OP val; \
} catch (const TypedValueException &) { \
throw QueryRuntimeException("Invalid type {} for '{}'.", val.type(), \
#CYPHER_OP); \
} \
}
BINARY_OPERATOR_VISITOR(OrOperator, ||, OR);
@ -127,7 +127,7 @@ class ExpressionEvaluator : public TreeVisitor<TypedValue> {
try {
return value1 && value2;
} catch (const TypedValueException &) {
throw QueryRuntimeException("Invalid types: {} and {} for 'AND'",
throw QueryRuntimeException("Invalid types: {} and {} for AND.",
value1.type(), value2.type());
}
}
@ -139,8 +139,8 @@ class ExpressionEvaluator : public TreeVisitor<TypedValue> {
}
if (condition.type() != TypedValue::Type::Bool) {
// At the moment IfOperator is used only in CASE construct.
throw QueryRuntimeException(
"'CASE' expected boolean expression, but got {}", condition.type());
throw QueryRuntimeException("CASE expected boolean expression, got {}.",
condition.type());
}
if (condition.Value<bool>()) {
return if_operator.then_expression_->Accept(*this);
@ -157,7 +157,7 @@ class ExpressionEvaluator : public TreeVisitor<TypedValue> {
// Exceptions have higher priority than returning nulls when list expression
// is not null.
if (_list.type() != TypedValue::Type::List) {
throw QueryRuntimeException("'IN' expected a list, but got {}",
throw QueryRuntimeException("IN expected a list, got {}.",
_list.type());
}
auto list = _list.Value<std::vector<TypedValue>>();
@ -190,14 +190,14 @@ class ExpressionEvaluator : public TreeVisitor<TypedValue> {
if (!lhs.IsList() && !lhs.IsMap() && !lhs.IsVertex() && !lhs.IsEdge() &&
!lhs.IsNull())
throw QueryRuntimeException(
"Expected a list, a map, a vertex or an edge to index with '[]', but "
"got {}",
"Expected a list, a map, a node or an edge to index with '[]', got "
"{}.",
lhs.type());
if (lhs.IsNull() || index.IsNull()) return TypedValue::Null;
if (lhs.IsList()) {
if (!index.IsInt())
throw QueryRuntimeException(
"Expected an int as a list index, but got {}", index.type());
"Expected an integer as a list index, got {}.", index.type());
auto index_int = index.Value<int64_t>();
const auto &list = lhs.Value<std::vector<TypedValue>>();
if (index_int < 0) {
@ -210,8 +210,8 @@ class ExpressionEvaluator : public TreeVisitor<TypedValue> {
if (lhs.IsMap()) {
if (!index.IsString())
throw QueryRuntimeException(
"Expected a string as a map index, but got {}", index.type());
throw QueryRuntimeException("Expected a string as a map index, got {}.",
index.type());
const auto &map = lhs.Value<std::map<std::string, TypedValue>>();
auto found = map.find(index.Value<std::string>());
if (found == map.end()) return TypedValue::Null;
@ -221,7 +221,7 @@ class ExpressionEvaluator : public TreeVisitor<TypedValue> {
if (lhs.IsVertex()) {
if (!index.IsString())
throw QueryRuntimeException(
"Expected a string as a property name, but got {}", index.type());
"Expected a string as a property name, got {}.", index.type());
return lhs.Value<VertexAccessor>().PropsAt(
context_->db_accessor_.Property(index.Value<std::string>()));
}
@ -229,7 +229,7 @@ class ExpressionEvaluator : public TreeVisitor<TypedValue> {
if (lhs.IsEdge()) {
if (!index.IsString())
throw QueryRuntimeException(
"Expected a string as a property name, but got {}", index.type());
"Expected a string as a property name, got {}.", index.type());
return lhs.Value<EdgeAccessor>().PropsAt(
context_->db_accessor_.Property(index.Value<std::string>()));
}
@ -249,7 +249,7 @@ class ExpressionEvaluator : public TreeVisitor<TypedValue> {
is_null = true;
} else if (bound.type() != TypedValue::Type::Int) {
throw QueryRuntimeException(
"Expected an int for a bound in list slicing, but got {}",
"Expected an integer for a bound in list slicing, got {}.",
bound.type());
}
return bound;
@ -264,7 +264,7 @@ class ExpressionEvaluator : public TreeVisitor<TypedValue> {
if (_list.type() == TypedValue::Type::Null) {
is_null = true;
} else if (_list.type() != TypedValue::Type::List) {
throw QueryRuntimeException("Expected a list to slice, but got {}",
throw QueryRuntimeException("Expected a list to slice, got {}.",
_list.type());
}
@ -313,7 +313,7 @@ class ExpressionEvaluator : public TreeVisitor<TypedValue> {
}
default:
throw QueryRuntimeException(
"Expected Node, Edge or Map for property lookup");
"Only nodes, edges and maps have properties to be looked-up.");
}
}
@ -332,7 +332,7 @@ class ExpressionEvaluator : public TreeVisitor<TypedValue> {
return true;
}
default:
throw QueryRuntimeException("Expected Node in labels test");
throw QueryRuntimeException("Only nodes have labels.");
}
}
@ -379,7 +379,7 @@ class ExpressionEvaluator : public TreeVisitor<TypedValue> {
return TypedValue::Null;
}
if (list_value.type() != TypedValue::Type::List) {
throw QueryRuntimeException("'REDUCE' expected a list, but got {}",
throw QueryRuntimeException("REDUCE expected a list, got {}.",
list_value.type());
}
const auto &list = list_value.Value<std::vector<TypedValue>>();
@ -402,7 +402,7 @@ class ExpressionEvaluator : public TreeVisitor<TypedValue> {
return TypedValue::Null;
}
if (list_value.type() != TypedValue::Type::List) {
throw QueryRuntimeException("'EXTRACT' expected a list, but got {}",
throw QueryRuntimeException("EXTRACT expected a list, got {}.",
list_value.type());
}
const auto &list = list_value.Value<std::vector<TypedValue>>();
@ -427,7 +427,7 @@ class ExpressionEvaluator : public TreeVisitor<TypedValue> {
return TypedValue::Null;
}
if (list_value.type() != TypedValue::Type::List) {
throw QueryRuntimeException("'ALL' expected a list, but got {}",
throw QueryRuntimeException("ALL expected a list, got {}.",
list_value.type());
}
const auto &list = list_value.Value<std::vector<TypedValue>>();
@ -437,8 +437,7 @@ class ExpressionEvaluator : public TreeVisitor<TypedValue> {
auto result = all.where_->expression_->Accept(*this);
if (!result.IsNull() && result.type() != TypedValue::Type::Bool) {
throw QueryRuntimeException(
"Predicate of 'ALL' needs to evaluate to 'Boolean', but it "
"resulted in '{}'",
"Predicate of ALL must evaluate to boolean, got {}.",
result.type());
}
if (result.IsNull() || !result.Value<bool>()) {
@ -454,7 +453,7 @@ class ExpressionEvaluator : public TreeVisitor<TypedValue> {
return TypedValue::Null;
}
if (list_value.type() != TypedValue::Type::List) {
throw QueryRuntimeException("'SINGLE' expected a list, but got {}",
throw QueryRuntimeException("SINGLE expected a list, got {}.",
list_value.type());
}
const auto &list = list_value.Value<std::vector<TypedValue>>();
@ -465,8 +464,7 @@ class ExpressionEvaluator : public TreeVisitor<TypedValue> {
auto result = single.where_->expression_->Accept(*this);
if (!result.IsNull() && result.type() != TypedValue::Type::Bool) {
throw QueryRuntimeException(
"Predicate of 'SINGLE' needs to evaluate to 'Boolean', but it "
"resulted in '{}'",
"Predicate of SINGLE must evaluate to boolean, got {}.",
result.type());
}
if (result.IsNull() || !result.Value<bool>()) {

View File

@ -46,7 +46,7 @@ Interpreter::Results Interpreter::operator()(
auto param_it = params.find(param_pair.second);
if (param_it == params.end()) {
throw query::UnprovidedParameterError(
fmt::format("Parameter ${} not provided", param_pair.second));
fmt::format("Parameter ${} not provided.", param_pair.second));
}
ctx.parameters_.Add(param_pair.first, param_it->second);
}

View File

@ -208,13 +208,13 @@ class RemotePuller {
break;
case distributed::PullState::SERIALIZATION_ERROR:
throw mvcc::SerializationError(
"Serialization error occured during PullRemote !");
"Serialization error occured during PullRemote!");
case distributed::PullState::LOCK_TIMEOUT_ERROR:
throw utils::LockTimeoutException(
"LockTimeout error occured during PullRemote !");
"LockTimeout error occured during PullRemote!");
case distributed::PullState::UPDATE_DELETED_ERROR:
throw QueryRuntimeException(
"RecordDeleted error ocured during PullRemote !");
"RecordDeleted error ocured during PullRemote!");
case distributed::PullState::RECONSTRUCTION_ERROR:
throw query::ReconstructionException();
case distributed::PullState::UNABLE_TO_DELETE_VERTEX_ERROR:
@ -223,7 +223,7 @@ class RemotePuller {
throw HintedAbortError();
case distributed::PullState::QUERY_ERROR:
throw QueryRuntimeException(
"Query runtime error occurred during PullRemote !");
"Query runtime error occurred during PullRemote!");
}
}
}
@ -501,23 +501,23 @@ class SynchronizeCursor : public Cursor {
continue;
case distributed::PullState::CURSOR_IN_PROGRESS:
throw QueryRuntimeException(
"Expected exhausted cursor after remote pull accumulate");
"Expected exhausted cursor after remote pull accumulate!");
case distributed::PullState::SERIALIZATION_ERROR:
throw mvcc::SerializationError(
"Failed to perform remote accumulate due to "
"SerializationError");
"SerializationError!");
case distributed::PullState::UPDATE_DELETED_ERROR:
throw QueryRuntimeException(
"Failed to perform remote accumulate due to "
"RecordDeletedError");
"RecordDeletedError!");
case distributed::PullState::LOCK_TIMEOUT_ERROR:
throw utils::LockTimeoutException(
"Failed to perform remote accumulate due to "
"LockTimeoutException");
"LockTimeoutException!");
case distributed::PullState::RECONSTRUCTION_ERROR:
throw QueryRuntimeException(
"Failed to perform remote accumulate due to "
"ReconstructionError");
"ReconstructionError!");
case distributed::PullState::UNABLE_TO_DELETE_VERTEX_ERROR:
throw RemoveAttachedVertexException();
case distributed::PullState::HINTED_ABORT_ERROR:
@ -525,7 +525,7 @@ class SynchronizeCursor : public Cursor {
case distributed::PullState::QUERY_ERROR:
throw QueryRuntimeException(
"Failed to perform remote accumulate due to Query runtime "
"error");
"error!");
}
}
@ -541,15 +541,15 @@ class SynchronizeCursor : public Cursor {
switch (future.get()) {
case distributed::UpdateResult::SERIALIZATION_ERROR:
throw mvcc::SerializationError(
"Failed to apply deferred updates due to SerializationError");
"Failed to apply deferred updates due to SerializationError!");
case distributed::UpdateResult::UNABLE_TO_DELETE_VERTEX_ERROR:
throw RemoveAttachedVertexException();
case distributed::UpdateResult::UPDATE_DELETED_ERROR:
throw QueryRuntimeException(
"Failed to apply deferred updates due to RecordDeletedError");
"Failed to apply deferred updates due to RecordDeletedError!");
case distributed::UpdateResult::LOCK_TIMEOUT_ERROR:
throw utils::LockTimeoutException(
"Failed to apply deferred update due to LockTimeoutException");
"Failed to apply deferred update due to LockTimeoutException!");
case distributed::UpdateResult::DONE:
break;
}

View File

@ -93,7 +93,8 @@ bool EvaluateFilter(ExpressionEvaluator &evaluator, Expression *filter) {
if (result.IsNull()) return false;
if (result.type() != TypedValue::Type::Bool)
throw QueryRuntimeException(
"Filter expression must be a bool or null, but got {}.", result.type());
"Filter expression must evaluate to bool or null, got {}.",
result.type());
return result.Value<bool>();
}
@ -885,7 +886,7 @@ class ExpandVariableCursor : public Cursor {
auto value = EvaluateInt(&evaluator, bound, "Variable expansion bound");
if (value < 0)
throw QueryRuntimeException(
"Variable expansion bound must be positive or zero");
"Variable expansion bound must be a non-negative integer.");
return value;
};
@ -1281,7 +1282,7 @@ class SingleSourceShortestPathCursor : public query::plan::Cursor {
break;
default:
throw QueryRuntimeException(
"Expansion condition must be boolean or null");
"Expansion condition must evaluate to boolean or null.");
}
}
to_visit_next_.emplace_back(edge, vertex);
@ -1331,8 +1332,7 @@ class SingleSourceShortestPathCursor : public query::plan::Cursor {
: std::numeric_limits<int64_t>::max();
if (upper_bound_ < 1)
throw QueryRuntimeException(
"Max depth in breadth-first expansion must be greater then "
"zero");
"Maximum depth in breadth-first expansion must be at least 1.");
// go back to loop start and see if we expanded anything
continue;
@ -1433,11 +1433,11 @@ class ExpandWeightedShortestPathCursor : public query::plan::Cursor {
self_.weight_lambda_->expression->Accept(evaluator);
if (!typed_weight.IsNumeric()) {
throw QueryRuntimeException("Calculated weight must be numeric, got {}",
typed_weight.type());
throw QueryRuntimeException(
"Calculated weight must be numeric, got {}.", typed_weight.type());
}
if ((typed_weight < 0).Value<bool>()) {
throw QueryRuntimeException("Calculated weight can't be negative!");
throw QueryRuntimeException("Calculated weight must be non-negative!");
}
auto next_state = create_state(vertex, depth);
@ -1491,8 +1491,8 @@ class ExpandWeightedShortestPathCursor : public query::plan::Cursor {
}
if (upper_bound_ < 1)
throw QueryRuntimeException(
"Max depth in weighted shortest path expansion must be greater "
"than zero");
"Maximum depth in weighted shortest path expansion must be at "
"least 1.");
// Clear existing data structures.
previous_.clear();
@ -1880,7 +1880,7 @@ bool Delete::DeleteCursor::Pull(Frame &frame, Context &context) {
break;
// check we're not trying to delete anything except vertices and edges
default:
throw QueryRuntimeException("Can only delete edges and vertices");
throw QueryRuntimeException("Only edges and vertices can be deleted.");
}
return true;
@ -1935,7 +1935,7 @@ bool SetProperty::SetPropertyCursor::Pull(Frame &frame, Context &context) {
// TODO: fix above described bug
default:
throw QueryRuntimeException(
"Properties can only be set on Vertices and Edges");
"Properties can only be set on edges and vertices.");
}
return true;
}
@ -1983,7 +1983,7 @@ bool SetProperties::SetPropertiesCursor::Pull(Frame &frame, Context &context) {
break;
default:
throw QueryRuntimeException(
"Properties can only be set on Vertices and Edges");
"Properties can only be set on edges and vertices.");
}
return true;
}
@ -2026,7 +2026,8 @@ void SetProperties::SetPropertiesCursor::Set(TRecordAccessor &record,
}
default:
throw QueryRuntimeException(
"Can only set Vertices, Edges and maps as properties");
"Right-hand side in SET expression must be a node, an edge or a "
"map.");
}
}
@ -2069,7 +2070,7 @@ bool SetLabels::SetLabelsCursor::Pull(Frame &frame, Context &context) {
try {
for (auto label : self_.labels_) vertex.add_label(label);
} catch (const RecordDeletedError &) {
throw QueryRuntimeException("Trying to set labels on a deleted Vertex");
throw QueryRuntimeException("Trying to set labels on a deleted node.");
}
return true;
@ -2111,7 +2112,7 @@ bool RemoveProperty::RemovePropertyCursor::Pull(Frame &frame,
lhs.Value<VertexAccessor>().PropsErase(self_.lhs_->property_);
} catch (const RecordDeletedError &) {
throw QueryRuntimeException(
"Trying to remove properties from a deleted Vertex");
"Trying to remove properties from a deleted node.");
}
break;
case TypedValue::Type::Edge:
@ -2119,7 +2120,7 @@ bool RemoveProperty::RemovePropertyCursor::Pull(Frame &frame,
lhs.Value<EdgeAccessor>().PropsErase(self_.lhs_->property_);
} catch (const RecordDeletedError &) {
throw QueryRuntimeException(
"Trying to remove properties from a deleted Edge");
"Trying to remove properties from a deleted edge.");
}
break;
case TypedValue::Type::Null:
@ -2127,7 +2128,7 @@ bool RemoveProperty::RemovePropertyCursor::Pull(Frame &frame,
break;
default:
throw QueryRuntimeException(
"Properties can only be removed on Vertices and Edges");
"Properties can only be removed from vertices and edges.");
}
return true;
}
@ -2168,7 +2169,7 @@ bool RemoveLabels::RemoveLabelsCursor::Pull(Frame &frame, Context &context) {
for (auto label : self_.labels_) vertex.remove_label(label);
} catch (const RecordDeletedError &) {
throw QueryRuntimeException(
"Trying to remove labels from a deleted Vertex");
"Trying to remove labels from a deleted node.");
}
return true;
@ -2497,7 +2498,7 @@ void Aggregate::AggregateCursor::Update(
case Aggregation::Op::COLLECT_MAP:
auto key = agg_elem_it->key->Accept(evaluator);
if (key.type() != TypedValue::Type::String)
throw QueryRuntimeException("Map key must be a string");
throw QueryRuntimeException("Map key must be a string.");
value_it->Value<std::map<std::string, TypedValue>>().emplace(
key.Value<std::string>(), input_value);
break;
@ -2519,7 +2520,7 @@ void Aggregate::AggregateCursor::Update(
// safe to assume a bool TypedValue
if (comparison_result.Value<bool>()) *value_it = input_value;
} catch (const TypedValueException &) {
throw QueryRuntimeException("Unable to get MIN of '{}' and '{}'",
throw QueryRuntimeException("Unable to get MIN of '{}' and '{}'.",
input_value.type(), value_it->type());
}
break;
@ -2531,7 +2532,7 @@ void Aggregate::AggregateCursor::Update(
TypedValue comparison_result = input_value > *value_it;
if (comparison_result.Value<bool>()) *value_it = input_value;
} catch (const TypedValueException &) {
throw QueryRuntimeException("Unable to get MAX of '{}' and '{}'",
throw QueryRuntimeException("Unable to get MAX of '{}' and '{}'.",
input_value.type(), value_it->type());
}
break;
@ -2549,7 +2550,7 @@ void Aggregate::AggregateCursor::Update(
case Aggregation::Op::COLLECT_MAP:
auto key = agg_elem_it->key->Accept(evaluator);
if (key.type() != TypedValue::Type::String)
throw QueryRuntimeException("Map key must be a string");
throw QueryRuntimeException("Map key must be a string.");
value_it->Value<std::map<std::string, TypedValue>>().emplace(
key.Value<std::string>(), input_value);
break;
@ -2574,8 +2575,8 @@ void Aggregate::AggregateCursor::EnsureOkForMinMax(
return;
default:
throw QueryRuntimeException(
"Only Bool, Int, Double and String values are allowed in "
"MIN and MAX aggregations");
"Only boolean, numeric and string values are allowed in "
"MIN and MAX aggregations.");
}
}
void Aggregate::AggregateCursor::EnsureOkForAvgSum(
@ -2586,7 +2587,7 @@ void Aggregate::AggregateCursor::EnsureOkForAvgSum(
return;
default:
throw QueryRuntimeException(
"Only numeric values allowed in SUM and AVG aggregations");
"Only numeric values allowed in SUM and AVG aggregations.");
}
}
@ -2631,12 +2632,13 @@ bool Skip::SkipCursor::Pull(Frame &frame, Context &context) {
ExpressionEvaluator evaluator(frame, &context, GraphView::OLD);
TypedValue to_skip = self_.expression_->Accept(evaluator);
if (to_skip.type() != TypedValue::Type::Int)
throw QueryRuntimeException("Result of SKIP expression must be an int");
throw QueryRuntimeException(
"Number of elements to skip must be an integer.");
to_skip_ = to_skip.Value<int64_t>();
if (to_skip_ < 0)
throw QueryRuntimeException(
"Result of SKIP expression must be greater or equal to zero");
"Number of elements to skip must be non-negative.");
}
if (skipped_++ < to_skip_) continue;
@ -2686,12 +2688,13 @@ bool Limit::LimitCursor::Pull(Frame &frame, Context &context) {
ExpressionEvaluator evaluator(frame, &context, GraphView::OLD);
TypedValue limit = self_.expression_->Accept(evaluator);
if (limit.type() != TypedValue::Type::Int)
throw QueryRuntimeException("Result of LIMIT expression must be an int");
throw QueryRuntimeException(
"Limit on number of returned elements must be an integer.");
limit_ = limit.Value<int64_t>();
if (limit_ < 0)
throw QueryRuntimeException(
"Result of LIMIT expression must be greater or equal to zero");
"Limit on number of returned elements must be non-negative.");
}
// check we have not exceeded the limit before pulling
@ -2976,8 +2979,9 @@ bool Unwind::UnwindCursor::Pull(Frame &frame, Context &context) {
ExpressionEvaluator evaluator(frame, &context, GraphView::OLD);
TypedValue input_value = self_.input_expression_->Accept(evaluator);
if (input_value.type() != TypedValue::Type::List)
throw QueryRuntimeException("UNWIND only accepts list values, got '{}'",
input_value.type());
throw QueryRuntimeException(
"Argument of UNWIND must be a list, but '{}' was provided.",
input_value.type());
input_value_ = input_value.Value<std::vector<TypedValue>>();
input_value_it_ = input_value_.begin();
}
@ -3377,7 +3381,8 @@ class AuthHandlerCursor : public Cursor {
auto password_tv = self_.password()->Accept(evaluator);
if (!password_tv.IsString() && !password_tv.IsNull()) {
throw QueryRuntimeException(
"Password must be a string or null, not '{}'!", password_tv.type());
"Expected string or null for password, got {}.",
password_tv.type());
}
if (password_tv.IsString()) {
password = password_tv.ValueString();
@ -3391,7 +3396,7 @@ class AuthHandlerCursor : public Cursor {
std::lock_guard<std::mutex> lock(auth.WithLock());
auto user = auth.AddUser(self_.user(), password);
if (!user) {
throw QueryRuntimeException("User or role '{}' already exists!",
throw QueryRuntimeException("User or role '{}' already exists.",
self_.user());
}
return false;
@ -3401,10 +3406,10 @@ class AuthHandlerCursor : public Cursor {
std::lock_guard<std::mutex> lock(auth.WithLock());
auto user = auth.GetUser(self_.user());
if (!user) {
throw QueryRuntimeException("User '{}' doesn't exist!", self_.user());
throw QueryRuntimeException("User '{}' doesn't exist.", self_.user());
}
if (!auth.RemoveUser(self_.user())) {
throw QueryRuntimeException("Couldn't remove user '{}'!",
throw QueryRuntimeException("Couldn't remove user '{}'.",
self_.user());
}
return false;
@ -3414,7 +3419,7 @@ class AuthHandlerCursor : public Cursor {
std::lock_guard<std::mutex> lock(auth.WithLock());
auto user = auth.GetUser(self_.user());
if (!user) {
throw QueryRuntimeException("User '{}' doesn't exist!", self_.user());
throw QueryRuntimeException("User '{}' doesn't exist.", self_.user());
}
user->UpdatePassword(password);
auth.SaveUser(*user);
@ -3425,7 +3430,7 @@ class AuthHandlerCursor : public Cursor {
std::lock_guard<std::mutex> lock(auth.WithLock());
auto role = auth.AddRole(self_.role());
if (!role) {
throw QueryRuntimeException("User or role '{}' already exists!",
throw QueryRuntimeException("User or role '{}' already exists.",
self_.role());
}
return false;
@ -3435,10 +3440,10 @@ class AuthHandlerCursor : public Cursor {
std::lock_guard<std::mutex> lock(auth.WithLock());
auto role = auth.GetRole(self_.role());
if (!role) {
throw QueryRuntimeException("Role '{}' doesn't exist!", self_.role());
throw QueryRuntimeException("Role '{}' doesn't exist.", self_.role());
}
if (!auth.RemoveRole(self_.role())) {
throw QueryRuntimeException("Couldn't remove role '{}'!",
throw QueryRuntimeException("Couldn't remove role '{}'.",
self_.role());
}
return false;
@ -3478,15 +3483,15 @@ class AuthHandlerCursor : public Cursor {
std::lock_guard<std::mutex> lock(auth.WithLock());
auto user = auth.GetUser(self_.user());
if (!user) {
throw QueryRuntimeException("User '{}' doesn't exist!", self_.user());
throw QueryRuntimeException("User '{}' doesn't exist.", self_.user());
}
auto role = auth.GetRole(self_.role());
if (!role) {
throw QueryRuntimeException("Role '{}' doesn't exist!", self_.role());
throw QueryRuntimeException("Role '{}' doesn't exist.", self_.role());
}
if (user->role()) {
throw QueryRuntimeException(
"User '{}' is already a member of role '{}'!", self_.user(),
"User '{}' is already a member of role '{}'.", self_.user(),
user->role()->rolename());
}
user->SetRole(*role);
@ -3498,7 +3503,7 @@ class AuthHandlerCursor : public Cursor {
std::lock_guard<std::mutex> lock(auth.WithLock());
auto user = auth.GetUser(self_.user());
if (!user) {
throw QueryRuntimeException("User '{}' doesn't exist!", self_.user());
throw QueryRuntimeException("User '{}' doesn't exist.", self_.user());
}
user->ClearRole();
auth.SaveUser(*user);
@ -3512,7 +3517,7 @@ class AuthHandlerCursor : public Cursor {
auto user = auth.GetUser(self_.user_or_role());
auto role = auth.GetRole(self_.user_or_role());
if (!user && !role) {
throw QueryRuntimeException("User or role '{}' doesn't exist!",
throw QueryRuntimeException("User or role '{}' doesn't exist.",
self_.user_or_role());
}
auto permissions = GetAuthPermissions();
@ -3554,7 +3559,7 @@ class AuthHandlerCursor : public Cursor {
auto user = auth.GetUser(self_.user_or_role());
auto role = auth.GetRole(self_.user_or_role());
if (!user && !role) {
throw QueryRuntimeException("User or role '{}' doesn't exist!",
throw QueryRuntimeException("User or role '{}' doesn't exist.",
self_.user_or_role());
}
if (user) {
@ -3580,7 +3585,7 @@ class AuthHandlerCursor : public Cursor {
std::lock_guard<std::mutex> lock(auth.WithLock());
auto user = auth.GetUser(self_.user());
if (!user) {
throw QueryRuntimeException("User '{}' doesn't exist!", self_.user());
throw QueryRuntimeException("User '{}' doesn't exist.", self_.user());
}
if (user->role()) {
frame[self_.role_symbol()] = user->role()->rolename();
@ -3596,7 +3601,7 @@ class AuthHandlerCursor : public Cursor {
std::lock_guard<std::mutex> lock(auth.WithLock());
auto role = auth.GetRole(self_.role());
if (!role) {
throw QueryRuntimeException("Role '{}' doesn't exist!",
throw QueryRuntimeException("Role '{}' doesn't exist.",
self_.role());
}
users_.emplace(auth.AllUsersForRole(self_.role()));

View File

@ -36,7 +36,7 @@
- name: integration__auth
cd: auth
commands: TIMEOUT=600 ./runner.py
commands: TIMEOUT=820 ./runner.py
infiles:
- runner.py # runner script
- ../../../build_debug/memgraph # memgraph binary

View File

@ -1403,7 +1403,7 @@ TEST(ExpressionEvaluator, FunctionAssert) {
try {
EvaluateFunction("ASSERT", {false, "bbgba"});
} catch (QueryRuntimeException &e) {
ASSERT_TRUE(utils::EndsWith(e.what(), "bbgba"));
ASSERT_TRUE(std::string(e.what()).find("bbgba") != std::string::npos);
}
// Valid calls, assertion passes.