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:
parent
55456b4214
commit
00f76d1391
@ -8,6 +8,7 @@
|
||||
|
||||
### Major Features and Improvements
|
||||
|
||||
* `nodes` and `relationships` functions added.
|
||||
|
||||
### Bug Fixes and Other Changes
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -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:
|
||||
|
@ -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());
|
||||
|
Loading…
Reference in New Issue
Block a user