Add nodes and relationships functions

Reviewers: teon.banek, florijan

Reviewed By: florijan

Subscribers: pullbot

Differential Revision: https://phabricator.memgraph.io/D942
This commit is contained in:
Mislav Bradac 2017-10-30 10:45:36 +01:00
parent 55456b4214
commit 00f76d1391
5 changed files with 139 additions and 48 deletions
CHANGELOG.md
docs/user_technical
src/query/interpret
tests
qa/tck_engine/tests/memgraph_V1/features
unit

View File

@ -8,6 +8,7 @@
### Major Features and Improvements
* `nodes` and `relationships` functions added.
### Bug Fixes and Other Changes

View File

@ -456,51 +456,53 @@ You have already been introduced to one type of functions, [aggregating
functions](#aggregating). This section contains the list of other supported
functions.
Name | Description
--------------|------------
`coalesce` | Returns the first non null argument.
`startNode` | Returns the starting node of an edge.
`endNode` | Returns the destination node of an edge.
`degree` | Returns the number of edges (both incoming and outgoing) of a node.
`head` | Returns the first element of a list.
`last` | Returns the last element of a list.
`properties` | Returns the properties of a node or an edge.
`size` | Returns the number of elements in a list or a map. When given a string it returns the number of characters. When given a path it returns the number of expansions (edges) in that path.
`toBoolean` | Converts the argument to a boolean.
`toFloat` | Converts the argument to a floating point number.
`toInteger` | Converts the argument to an integer.
`type` | Returns the type of an edge as a character string.
`keys` | Returns a list keys of properties from an edge or a node. Each key is represented as a string of characters.
`labels` | Return a list of labels from a node. Each label is represented as a character string.
`range` | Constructs a list of value in given range.
`tail` | Returns all elements after the first of a given list.
`abs` | Returns the absolute value of a number.
`ceil` | Returns the smallest integer greater than or equal to given number.
`floor` | Returns the largest integer smaller than or equal to given number.
`round` | Returns the number, rounded to the nearest integer. Tie-breaking is done using the *commercial rounding*, where -1.5 produces -2 and 1.5 produces 2.
`exp` | Calculates `e^n` where `e` is the base of the natural logarithm, and `n` is the given number.
`log` | Calculates the natural logarithm of a given number.
`log10` | Calculates the logarithm (base 10) of a given number.
`sqrt` | Calculates the square root of a given number.
`acos` | Calculates the arccosine of a given number.
`asin` | Calculates the arcsine of a given number.
`atan` | Calculates the arctangent of a given number.
`atan2` | Calculates the arctangent2 of a given number.
`cos` | Calculates the cosine of a given number.
`sin` | Calculates the sine of a given number.
`tan` | Calculates the tangent of a given number.
`sign` | Applies the signum function to a given number and returns the result. The signum of positive numbers is 1, of negative -1 and for 0 returns 0.
`e` | Returns the base of the natural logarithm.
`pi` | Returns the constant *pi*.
`rand` | Returns a random floating point number between 0 (inclusive) and 1 (exclusive).
`startsWith` | Check if the first argument starts with the second.
`endsWith` | Check if the first argument ends with the second.
`contains` | Check if the first argument has an element which is equal to the second argument.
`all` | Check if all elements of a list satisfy a predicate.<br/>The syntax is: `all(variable IN list WHERE predicate)`.
`assert` | Raises an exception reported to the client if the given argument is not `true`.
`counter` | Generates integers that are guaranteed to be unique on the database level, for the given counter name.
`counterSet` | Sets the counter with the given name to the given value.
`indexInfo` | Returns a list of all the indexes available in the database. The list includes indexes that are not yet ready for use (they are concurrently being built by another transaction).
Name | Description
-----------------|------------
`coalesce` | Returns the first non null argument.
`startNode` | Returns the starting node of an edge.
`endNode` | Returns the destination node of an edge.
`degree` | Returns the number of edges (both incoming and outgoing) of a node.
`head` | Returns the first element of a list.
`last` | Returns the last element of a list.
`properties` | Returns the properties of a node or an edge.
`size` | Returns the number of elements in a list or a map. When given a string it returns the number of characters. When given a path it returns the number of expansions (edges) in that path.
`toBoolean` | Converts the argument to a boolean.
`toFloat` | Converts the argument to a floating point number.
`toInteger` | Converts the argument to an integer.
`type` | Returns the type of an edge as a character string.
`keys` | Returns a list keys of properties from an edge or a node. Each key is represented as a string of characters.
`labels` | Returns a list of labels from a node. Each label is represented as a character string.
`nodes` | Returns a list of nodes from a path.
`relationships` | Returns a list of relationships from a path.
`range` | Constructs a list of value in given range.
`tail` | Returns all elements after the first of a given list.
`abs` | Returns the absolute value of a number.
`ceil` | Returns the smallest integer greater than or equal to given number.
`floor` | Returns the largest integer smaller than or equal to given number.
`round` | Returns the number, rounded to the nearest integer. Tie-breaking is done using the *commercial rounding*, where -1.5 produces -2 and 1.5 produces 2.
`exp` | Calculates `e^n` where `e` is the base of the natural logarithm, and `n` is the given number.
`log` | Calculates the natural logarithm of a given number.
`log10` | Calculates the logarithm (base 10) of a given number.
`sqrt` | Calculates the square root of a given number.
`acos` | Calculates the arccosine of a given number.
`asin` | Calculates the arcsine of a given number.
`atan` | Calculates the arctangent of a given number.
`atan2` | Calculates the arctangent2 of a given number.
`cos` | Calculates the cosine of a given number.
`sin` | Calculates the sine of a given number.
`tan` | Calculates the tangent of a given number.
`sign` | Applies the signum function to a given number and returns the result. The signum of positive numbers is 1, of negative -1 and for 0 returns 0.
`e` | Returns the base of the natural logarithm.
`pi` | Returns the constant *pi*.
`rand` | Returns a random floating point number between 0 (inclusive) and 1 (exclusive).
`startsWith` | Check if the first argument starts with the second.
`endsWith` | Check if the first argument ends with the second.
`contains` | Check if the first argument has an element which is equal to the second argument.
`all` | Check if all elements of a list satisfy a predicate.<br/>The syntax is: `all(variable IN list WHERE predicate)`.
`assert` | Raises an exception reported to the client if the given argument is not `true`.
`counter` | Generates integers that are guaranteed to be unique on the database level, for the given counter name.
`counterSet` | Sets the counter with the given name to the given value.
`indexInfo` | Returns a list of all the indexes available in the database. The list includes indexes that are not yet ready for use (they are concurrently being built by another transaction).
#### String Operators
@ -622,8 +624,6 @@ General purpose functions:
* `length()` is named `size()` in Memgraph.
Path functions:
* `nodes()`
* `relationships()`
* `extract()`
Aggregation functions:

View File

@ -30,7 +30,6 @@ namespace {
// TODO: Implement timestamp, every time it is called in a query it needs to
// return same time. We need to store query start time somwhere.
// TODO: Implement rest of the list functions.
// TODO: Implement rand
// TODO: Implement degrees, haversin, radians
// TODO: Implement string and spatial functions
@ -300,6 +299,31 @@ TypedValue Labels(const std::vector<TypedValue> &args,
}
}
TypedValue Nodes(const std::vector<TypedValue> &args, GraphDbAccessor &) {
if (args.size() != 1U) {
throw QueryRuntimeException("nodes requires one argument");
}
if (args[0].IsNull()) return TypedValue::Null;
if (!args[0].IsPath()) {
throw QueryRuntimeException("nodes called with incompatible type");
}
auto &vertices = args[0].ValuePath().vertices();
return std::vector<TypedValue>(vertices.begin(), vertices.end());
}
TypedValue Relationships(const std::vector<TypedValue> &args,
GraphDbAccessor &) {
if (args.size() != 1U) {
throw QueryRuntimeException("relationships requires one argument");
}
if (args[0].IsNull()) return TypedValue::Null;
if (!args[0].IsPath()) {
throw QueryRuntimeException("relationships called with incompatible type");
}
auto &edges = args[0].ValuePath().edges();
return std::vector<TypedValue>(edges.begin(), edges.end());
}
TypedValue Range(const std::vector<TypedValue> &args, GraphDbAccessor &) {
if (args.size() != 2U && args.size() != 3U) {
throw QueryRuntimeException("range requires two or three arguments");
@ -575,6 +599,8 @@ NameToFunction(const std::string &function_name) {
if (function_name == "TYPE") return Type;
if (function_name == "KEYS") return Keys;
if (function_name == "LABELS") return Labels;
if (function_name == "NODES") return Nodes;
if (function_name == "RELATIONSHIPS") return Relationships;
if (function_name == "RANGE") return Range;
if (function_name == "TAIL") return Tail;
if (function_name == "ABS") return Abs;

View File

@ -516,6 +516,34 @@ Feature: Functions
| n | a | b |
| null | [1, 2] | 1 |
Scenario: Nodes test:
Given an empty graph
And having executed:
"""
CREATE (:L1)-[:E1]->(:L2)-[:E2]->(:L3)
"""
When executing query:
"""
MATCH p=()-[]->()-[]->() RETURN nodes(p) AS ns
"""
Then the result should be:
| ns |
| [(:L1), (:L2), (:L3)] |
Scenario: Relationships test:
Given an empty graph
And having executed:
"""
CREATE (:L1)-[:E1]->(:L2)-[:E2]->(:L3)
"""
When executing query:
"""
MATCH p=()-[]->()-[]->() RETURN relationships(p) as rels
"""
Then the result should be:
| rels |
| [[:E1], [:E2]] |
Scenario: Labels test:
Given an empty graph
And having executed:

View File

@ -14,6 +14,7 @@
#include "query/interpret/awesome_memgraph_functions.hpp"
#include "query/interpret/eval.hpp"
#include "query/interpret/frame.hpp"
#include "query/path.hpp"
#include "utils/string.hpp"
#include "query_common.hpp"
@ -910,6 +911,41 @@ TEST(ExpressionEvaluator, FunctionLabels) {
ASSERT_THROW(EvaluateFunction("LABELS", {2}), QueryRuntimeException);
}
TEST(ExpressionEvaluator, FunctionNodesRelationships) {
EXPECT_THROW(EvaluateFunction("NODES", {}), QueryRuntimeException);
EXPECT_THROW(EvaluateFunction("RELATIONSHIPS", {}), QueryRuntimeException);
EXPECT_TRUE(EvaluateFunction("NODES", {TypedValue::Null}).IsNull());
EXPECT_TRUE(EvaluateFunction("RELATIONSHIPS", {TypedValue::Null}).IsNull());
{
GraphDb db;
GraphDbAccessor dba(db);
auto v1 = dba.InsertVertex();
auto v2 = dba.InsertVertex();
auto v3 = dba.InsertVertex();
auto e1 = dba.InsertEdge(v1, v2, dba.EdgeType("Type"));
auto e2 = dba.InsertEdge(v2, v3, dba.EdgeType("Type"));
query::Path path(v1, e1, v2, e2, v3);
auto _nodes = EvaluateFunction("NODES", {path}).ValueList();
std::vector<VertexAccessor> nodes;
for (const auto &node : _nodes) {
nodes.push_back(node.ValueVertex());
}
EXPECT_THAT(nodes, ElementsAre(v1, v2, v3));
auto _edges = EvaluateFunction("RELATIONSHIPS", {path}).ValueList();
std::vector<EdgeAccessor> edges;
for (const auto &edge : _edges) {
edges.push_back(edge.ValueEdge());
}
EXPECT_THAT(edges, ElementsAre(e1, e2));
}
EXPECT_THROW(EvaluateFunction("NODES", {2}), QueryRuntimeException);
EXPECT_THROW(EvaluateFunction("RELATIONSHIPS", {2}), QueryRuntimeException);
}
TEST(ExpressionEvaluator, FunctionRange) {
EXPECT_THROW(EvaluateFunction("RANGE", {}), QueryRuntimeException);
EXPECT_TRUE(EvaluateFunction("RANGE", {1, 2, TypedValue::Null}).IsNull());