diff --git a/docs/reference/graphql/graphql_API.md b/docs/reference/graphql/graphql_API.md
index 82ff44d718..3f85bd9b5c 100644
--- a/docs/reference/graphql/graphql_API.md
+++ b/docs/reference/graphql/graphql_API.md
@@ -3367,6 +3367,11 @@ Ordered list of view operations; each entry is a one-of variant applied to the r
|
+| weight |
+String |
+ |
+
+
| shortest_path |
[ShortestPathOutput!]! |
|
@@ -8279,6 +8284,30 @@ Optional `{start, end}` to restrict matches to edges active in that interval.
## Inputs
+### DegreeFilterNew
+
+
+
### EdgeAddition
@@ -9919,6 +9948,15 @@ Filters a built-in node field (ID, name, or type).
Filters a node property by name and condition.
+
+
+
+| degree |
+DegreeFilterNew |
+
+
+Filters a node's degree (in, out, or total) by a condition.
+
|
@@ -11580,6 +11618,45 @@ All properties.
+### DegreeDirection
+
+Filters nodes by computed degree with a directional scope.
+
+`DegreeFilterNew` lets callers filter on:
+- inbound degree (`IN`),
+- outbound degree (`OUT`),
+- or total degree (`BOTH`).
+
+The selected degree is compared using the `where` condition.
+
+Example (GraphQL):
+```graphql
+{ Degree: { direction: BOTH, where: { Gt: 10 } } }
+```
+
+
+
+
+| Value |
+Description |
+
+
+
+
+| IN |
+ |
+
+
+| OUT |
+ |
+
+
+| BOTH |
+ |
+
+
+
+
### GraphType
diff --git a/examples/rust/src/bin/crypto/main.rs b/examples/rust/src/bin/crypto/main.rs
index 5ee2f54836..1579eed22d 100644
--- a/examples/rust/src/bin/crypto/main.rs
+++ b/examples/rust/src/bin/crypto/main.rs
@@ -1,8 +1,7 @@
use itertools::Itertools;
use raphtory::{
algorithms::{
- centrality::pagerank::page_rank,
- pathing::temporal_reachability::temporally_reachable_nodes,
+ centrality::pagerank::page_rank, pathing::temporal_reachability::temporally_reachable_nodes,
},
db::api::view::*,
graph_loader::stable_coins::stable_coin_graph,
diff --git a/examples/rust/src/bin/pokec/main.rs b/examples/rust/src/bin/pokec/main.rs
index 776c7f685a..56bda2b968 100644
--- a/examples/rust/src/bin/pokec/main.rs
+++ b/examples/rust/src/bin/pokec/main.rs
@@ -1,7 +1,5 @@
use raphtory::{
- algorithms::{
- centrality::pagerank::page_rank, components::weakly_connected_components,
- },
+ algorithms::{centrality::pagerank::page_rank, components::weakly_connected_components},
db::{api::mutation::AdditionOps, graph::graph::Graph},
io::csv_loader::CsvLoader,
logging::global_info_logger,
diff --git a/python/python/raphtory/filter/__init__.pyi b/python/python/raphtory/filter/__init__.pyi
index 05eb32788e..af99dbcee9 100644
--- a/python/python/raphtory/filter/__init__.pyi
+++ b/python/python/raphtory/filter/__init__.pyi
@@ -341,6 +341,15 @@ class Node(object):
filter.FilterExpr:
"""
+ @staticmethod
+ def degree():
+ """
+ Selects total node degree for filtering.
+
+ Returns:
+ filter.FilterOps
+ """
+
@staticmethod
def id() -> filter.NodeIdFilterBuilder:
"""
@@ -350,6 +359,15 @@ class Node(object):
filter.NodeIdFilterBuilder:
"""
+ @staticmethod
+ def in_degree():
+ """
+ Selects incoming node degree for filtering.
+
+ Returns:
+ filter.FilterOps
+ """
+
@staticmethod
def is_active() -> filter.FilterExpr:
"""
@@ -424,6 +442,15 @@ class Node(object):
filter.NodeTypeFilterBuilder:
"""
+ @staticmethod
+ def out_degree():
+ """
+ Selects outgoing node degree for filtering.
+
+ Returns:
+ filter.FilterOps
+ """
+
@staticmethod
def property(name: str) -> filter.PropertyFilterOps:
"""
diff --git a/python/tests/test_base_install/test_filters/test_node_filter.py b/python/tests/test_base_install/test_filters/test_node_filter.py
index 18084b1261..fb32637fe4 100644
--- a/python/tests/test_base_install/test_filters/test_node_filter.py
+++ b/python/tests/test_base_install/test_filters/test_node_filter.py
@@ -36,62 +36,170 @@ def metric_value(node):
)
filtered_event_nodes = sort_vids(graph.filter(filter_expr).nodes.id)
- assert filtered_event_nodes == expected_filter_nodes, (
- f"{context} failed for event graph"
- )
+ assert (
+ filtered_event_nodes == expected_filter_nodes
+ ), f"{context} failed for event graph"
selected_event_nodes = sort_vids(graph.nodes[filter_expr].id)
- assert selected_event_nodes == expected_select_nodes, (
- f"{context} failed for event graph select"
- )
+ assert (
+ selected_event_nodes == expected_select_nodes
+ ), f"{context} failed for event graph select"
persistent_graph = graph.persistent_graph()
filtered_persistent_nodes = sort_vids(persistent_graph.filter(filter_expr).nodes.id)
- assert filtered_persistent_nodes == expected_filter_nodes, (
- f"{context} failed for persistent graph"
- )
+ assert (
+ filtered_persistent_nodes == expected_filter_nodes
+ ), f"{context} failed for persistent graph"
selected_persistent_nodes = sort_vids(persistent_graph.nodes[filter_expr].id)
- assert selected_persistent_nodes == expected_select_nodes, (
- f"{context} failed for persistent graph select"
- )
+ assert (
+ selected_persistent_nodes == expected_select_nodes
+ ), f"{context} failed for persistent graph select"
@pytest.mark.parametrize("value", range(0, 15))
def test_degree_filter_both_direction_comparison(value):
graph = degree_graph_with_add_node_and_add_edge(Graph())
- assert_filter(graph, filter.Node.degree() < value, "both", lambda d: d < value, f"BOTH < {value}")
- assert_filter(graph, filter.Node.degree() <= value, "both", lambda d: d <= value, f"BOTH <= {value}")
- assert_filter(graph, filter.Node.degree() == value, "both", lambda d: d == value, f"BOTH == {value}")
- assert_filter(graph, filter.Node.degree() != value, "both", lambda d: d != value, f"BOTH != {value}")
- assert_filter(graph, filter.Node.degree() >= value, "both", lambda d: d >= value, f"BOTH >= {value}")
- assert_filter(graph, filter.Node.degree() > value, "both", lambda d: d > value, f"BOTH > {value}")
+ assert_filter(
+ graph,
+ filter.Node.degree() < value,
+ "both",
+ lambda d: d < value,
+ f"BOTH < {value}",
+ )
+ assert_filter(
+ graph,
+ filter.Node.degree() <= value,
+ "both",
+ lambda d: d <= value,
+ f"BOTH <= {value}",
+ )
+ assert_filter(
+ graph,
+ filter.Node.degree() == value,
+ "both",
+ lambda d: d == value,
+ f"BOTH == {value}",
+ )
+ assert_filter(
+ graph,
+ filter.Node.degree() != value,
+ "both",
+ lambda d: d != value,
+ f"BOTH != {value}",
+ )
+ assert_filter(
+ graph,
+ filter.Node.degree() >= value,
+ "both",
+ lambda d: d >= value,
+ f"BOTH >= {value}",
+ )
+ assert_filter(
+ graph,
+ filter.Node.degree() > value,
+ "both",
+ lambda d: d > value,
+ f"BOTH > {value}",
+ )
@pytest.mark.parametrize("value", range(0, 15))
def test_degree_filter_in_direction_comparison(value):
graph = degree_graph_with_add_node_and_add_edge(Graph())
- assert_filter(graph, filter.Node.in_degree() < value, "in", lambda d: d < value, f"IN < {value}")
- assert_filter(graph, filter.Node.in_degree() <= value, "in", lambda d: d <= value, f"IN <= {value}")
- assert_filter(graph, filter.Node.in_degree() == value, "in", lambda d: d == value, f"IN == {value}")
- assert_filter(graph, filter.Node.in_degree() != value, "in", lambda d: d != value, f"IN != {value}")
- assert_filter(graph, filter.Node.in_degree() >= value, "in", lambda d: d >= value, f"IN >= {value}")
- assert_filter(graph, filter.Node.in_degree() > value, "in", lambda d: d > value, f"IN > {value}")
+ assert_filter(
+ graph,
+ filter.Node.in_degree() < value,
+ "in",
+ lambda d: d < value,
+ f"IN < {value}",
+ )
+ assert_filter(
+ graph,
+ filter.Node.in_degree() <= value,
+ "in",
+ lambda d: d <= value,
+ f"IN <= {value}",
+ )
+ assert_filter(
+ graph,
+ filter.Node.in_degree() == value,
+ "in",
+ lambda d: d == value,
+ f"IN == {value}",
+ )
+ assert_filter(
+ graph,
+ filter.Node.in_degree() != value,
+ "in",
+ lambda d: d != value,
+ f"IN != {value}",
+ )
+ assert_filter(
+ graph,
+ filter.Node.in_degree() >= value,
+ "in",
+ lambda d: d >= value,
+ f"IN >= {value}",
+ )
+ assert_filter(
+ graph,
+ filter.Node.in_degree() > value,
+ "in",
+ lambda d: d > value,
+ f"IN > {value}",
+ )
@pytest.mark.parametrize("value", range(0, 15))
def test_degree_filter_out_direction_comparison(value):
graph = degree_graph_with_add_node_and_add_edge(Graph())
- assert_filter(graph, filter.Node.out_degree() < value, "out", lambda d: d < value, f"OUT < {value}")
- assert_filter(graph, filter.Node.out_degree() <= value, "out", lambda d: d <= value, f"OUT <= {value}")
- assert_filter(graph, filter.Node.out_degree() == value, "out", lambda d: d == value, f"OUT == {value}")
- assert_filter(graph, filter.Node.out_degree() != value, "out", lambda d: d != value, f"OUT != {value}")
- assert_filter(graph, filter.Node.out_degree() >= value, "out", lambda d: d >= value, f"OUT >= {value}")
- assert_filter(graph, filter.Node.out_degree() > value, "out", lambda d: d > value, f"OUT > {value}")
+ assert_filter(
+ graph,
+ filter.Node.out_degree() < value,
+ "out",
+ lambda d: d < value,
+ f"OUT < {value}",
+ )
+ assert_filter(
+ graph,
+ filter.Node.out_degree() <= value,
+ "out",
+ lambda d: d <= value,
+ f"OUT <= {value}",
+ )
+ assert_filter(
+ graph,
+ filter.Node.out_degree() == value,
+ "out",
+ lambda d: d == value,
+ f"OUT == {value}",
+ )
+ assert_filter(
+ graph,
+ filter.Node.out_degree() != value,
+ "out",
+ lambda d: d != value,
+ f"OUT != {value}",
+ )
+ assert_filter(
+ graph,
+ filter.Node.out_degree() >= value,
+ "out",
+ lambda d: d >= value,
+ f"OUT >= {value}",
+ )
+ assert_filter(
+ graph,
+ filter.Node.out_degree() > value,
+ "out",
+ lambda d: d > value,
+ f"OUT > {value}",
+ )
@pytest.mark.parametrize("value", range(0, 15))
@@ -330,26 +438,134 @@ def test_degree_filter_with_string_threshold(value):
threshold_str = str(value)
parsed_str = int(threshold_str)
- assert_filter(graph, filter.Node.degree() < threshold_str, "both", lambda d: d < parsed_str, f"BOTH < string threshold parsed to u64 ({threshold_str})")
- assert_filter(graph, filter.Node.degree() <= threshold_str, "both", lambda d: d <= parsed_str, f"BOTH <= string threshold parsed to u64 ({threshold_str})")
- assert_filter(graph, filter.Node.degree() == threshold_str, "both", lambda d: d == parsed_str, f"BOTH == string threshold parsed to u64 ({threshold_str})")
- assert_filter(graph, filter.Node.degree() != threshold_str, "both", lambda d: d != parsed_str, f"BOTH != string threshold parsed to u64 ({threshold_str})")
- assert_filter(graph, filter.Node.degree() >= threshold_str, "both", lambda d: d >= parsed_str, f"BOTH >= string threshold parsed to u64 ({threshold_str})")
- assert_filter(graph, filter.Node.degree() > threshold_str, "both", lambda d: d > parsed_str, f"BOTH > string threshold parsed to u64 ({threshold_str})")
+ assert_filter(
+ graph,
+ filter.Node.degree() < threshold_str,
+ "both",
+ lambda d: d < parsed_str,
+ f"BOTH < string threshold parsed to u64 ({threshold_str})",
+ )
+ assert_filter(
+ graph,
+ filter.Node.degree() <= threshold_str,
+ "both",
+ lambda d: d <= parsed_str,
+ f"BOTH <= string threshold parsed to u64 ({threshold_str})",
+ )
+ assert_filter(
+ graph,
+ filter.Node.degree() == threshold_str,
+ "both",
+ lambda d: d == parsed_str,
+ f"BOTH == string threshold parsed to u64 ({threshold_str})",
+ )
+ assert_filter(
+ graph,
+ filter.Node.degree() != threshold_str,
+ "both",
+ lambda d: d != parsed_str,
+ f"BOTH != string threshold parsed to u64 ({threshold_str})",
+ )
+ assert_filter(
+ graph,
+ filter.Node.degree() >= threshold_str,
+ "both",
+ lambda d: d >= parsed_str,
+ f"BOTH >= string threshold parsed to u64 ({threshold_str})",
+ )
+ assert_filter(
+ graph,
+ filter.Node.degree() > threshold_str,
+ "both",
+ lambda d: d > parsed_str,
+ f"BOTH > string threshold parsed to u64 ({threshold_str})",
+ )
- assert_filter(graph, filter.Node.in_degree() < threshold_str, "in", lambda d: d < parsed_str, f"IN < string threshold parsed to u64 ({threshold_str})")
- assert_filter(graph, filter.Node.in_degree() <= threshold_str, "in", lambda d: d <= parsed_str, f"IN <= string threshold parsed to u64 ({threshold_str})")
- assert_filter(graph, filter.Node.in_degree() == threshold_str, "in", lambda d: d == parsed_str, f"IN == string threshold parsed to u64 ({threshold_str})")
- assert_filter(graph, filter.Node.in_degree() != threshold_str, "in", lambda d: d != parsed_str, f"IN != string threshold parsed to u64 ({threshold_str})")
- assert_filter(graph, filter.Node.in_degree() >= threshold_str, "in", lambda d: d >= parsed_str, f"IN >= string threshold parsed to u64 ({threshold_str})")
- assert_filter(graph, filter.Node.in_degree() > threshold_str, "in", lambda d: d > parsed_str, f"IN > string threshold parsed to u64 ({threshold_str})")
+ assert_filter(
+ graph,
+ filter.Node.in_degree() < threshold_str,
+ "in",
+ lambda d: d < parsed_str,
+ f"IN < string threshold parsed to u64 ({threshold_str})",
+ )
+ assert_filter(
+ graph,
+ filter.Node.in_degree() <= threshold_str,
+ "in",
+ lambda d: d <= parsed_str,
+ f"IN <= string threshold parsed to u64 ({threshold_str})",
+ )
+ assert_filter(
+ graph,
+ filter.Node.in_degree() == threshold_str,
+ "in",
+ lambda d: d == parsed_str,
+ f"IN == string threshold parsed to u64 ({threshold_str})",
+ )
+ assert_filter(
+ graph,
+ filter.Node.in_degree() != threshold_str,
+ "in",
+ lambda d: d != parsed_str,
+ f"IN != string threshold parsed to u64 ({threshold_str})",
+ )
+ assert_filter(
+ graph,
+ filter.Node.in_degree() >= threshold_str,
+ "in",
+ lambda d: d >= parsed_str,
+ f"IN >= string threshold parsed to u64 ({threshold_str})",
+ )
+ assert_filter(
+ graph,
+ filter.Node.in_degree() > threshold_str,
+ "in",
+ lambda d: d > parsed_str,
+ f"IN > string threshold parsed to u64 ({threshold_str})",
+ )
- assert_filter(graph, filter.Node.out_degree() < threshold_str, "out", lambda d: d < parsed_str, f"OUT < string threshold parsed to u64 ({threshold_str})")
- assert_filter(graph, filter.Node.out_degree() <= threshold_str, "out", lambda d: d <= parsed_str, f"OUT <= string threshold parsed to u64 ({threshold_str})")
- assert_filter(graph, filter.Node.out_degree() == threshold_str, "out", lambda d: d == parsed_str, f"OUT == string threshold parsed to u64 ({threshold_str})")
- assert_filter(graph, filter.Node.out_degree() != threshold_str, "out", lambda d: d != parsed_str, f"OUT != string threshold parsed to u64 ({threshold_str})")
- assert_filter(graph, filter.Node.out_degree() >= threshold_str, "out", lambda d: d >= parsed_str, f"OUT >= string threshold parsed to u64 ({threshold_str})")
- assert_filter(graph, filter.Node.out_degree() > threshold_str, "out", lambda d: d > parsed_str, f"OUT > string threshold parsed to u64 ({threshold_str})")
+ assert_filter(
+ graph,
+ filter.Node.out_degree() < threshold_str,
+ "out",
+ lambda d: d < parsed_str,
+ f"OUT < string threshold parsed to u64 ({threshold_str})",
+ )
+ assert_filter(
+ graph,
+ filter.Node.out_degree() <= threshold_str,
+ "out",
+ lambda d: d <= parsed_str,
+ f"OUT <= string threshold parsed to u64 ({threshold_str})",
+ )
+ assert_filter(
+ graph,
+ filter.Node.out_degree() == threshold_str,
+ "out",
+ lambda d: d == parsed_str,
+ f"OUT == string threshold parsed to u64 ({threshold_str})",
+ )
+ assert_filter(
+ graph,
+ filter.Node.out_degree() != threshold_str,
+ "out",
+ lambda d: d != parsed_str,
+ f"OUT != string threshold parsed to u64 ({threshold_str})",
+ )
+ assert_filter(
+ graph,
+ filter.Node.out_degree() >= threshold_str,
+ "out",
+ lambda d: d >= parsed_str,
+ f"OUT >= string threshold parsed to u64 ({threshold_str})",
+ )
+ assert_filter(
+ graph,
+ filter.Node.out_degree() > threshold_str,
+ "out",
+ lambda d: d > parsed_str,
+ f"OUT > string threshold parsed to u64 ({threshold_str})",
+ )
@pytest.mark.parametrize("value", range(0, 15))
@@ -359,9 +575,27 @@ def test_degree_filter_with_string_is_in(value):
threshold_b_str = str(value + 1)
set_values = [int(threshold_a_str), int(threshold_b_str)]
- assert_filter(graph, filter.Node.degree().is_in([threshold_a_str, threshold_b_str]), "both", lambda d: d in set_values, f"BOTH is_in(string thresholds parsed to u64) ({threshold_a_str}, {threshold_b_str})")
- assert_filter(graph, filter.Node.in_degree().is_in([threshold_a_str, threshold_b_str]), "in", lambda d: d in set_values, f"IN is_in(string thresholds parsed to u64) ({threshold_a_str}, {threshold_b_str})")
- assert_filter(graph, filter.Node.out_degree().is_in([threshold_a_str, threshold_b_str]), "out", lambda d: d in set_values, f"OUT is_in(string thresholds parsed to u64) ({threshold_a_str}, {threshold_b_str})")
+ assert_filter(
+ graph,
+ filter.Node.degree().is_in([threshold_a_str, threshold_b_str]),
+ "both",
+ lambda d: d in set_values,
+ f"BOTH is_in(string thresholds parsed to u64) ({threshold_a_str}, {threshold_b_str})",
+ )
+ assert_filter(
+ graph,
+ filter.Node.in_degree().is_in([threshold_a_str, threshold_b_str]),
+ "in",
+ lambda d: d in set_values,
+ f"IN is_in(string thresholds parsed to u64) ({threshold_a_str}, {threshold_b_str})",
+ )
+ assert_filter(
+ graph,
+ filter.Node.out_degree().is_in([threshold_a_str, threshold_b_str]),
+ "out",
+ lambda d: d in set_values,
+ f"OUT is_in(string thresholds parsed to u64) ({threshold_a_str}, {threshold_b_str})",
+ )
@pytest.mark.parametrize("value", range(0, 15))
@@ -371,9 +605,27 @@ def test_degree_filter_with_string_is_not_in(value):
threshold_b_str = str(value + 1)
set_values = [int(threshold_a_str), int(threshold_b_str)]
- assert_filter(graph, filter.Node.degree().is_not_in([threshold_a_str, threshold_b_str]), "both", lambda d: d not in set_values, f"BOTH is_not_in(string thresholds parsed to u64) ({threshold_a_str}, {threshold_b_str})")
- assert_filter(graph, filter.Node.in_degree().is_not_in([threshold_a_str, threshold_b_str]), "in", lambda d: d not in set_values, f"IN is_not_in(string thresholds parsed to u64) ({threshold_a_str}, {threshold_b_str})")
- assert_filter(graph, filter.Node.out_degree().is_not_in([threshold_a_str, threshold_b_str]), "out", lambda d: d not in set_values, f"OUT is_not_in(string thresholds parsed to u64) ({threshold_a_str}, {threshold_b_str})")
+ assert_filter(
+ graph,
+ filter.Node.degree().is_not_in([threshold_a_str, threshold_b_str]),
+ "both",
+ lambda d: d not in set_values,
+ f"BOTH is_not_in(string thresholds parsed to u64) ({threshold_a_str}, {threshold_b_str})",
+ )
+ assert_filter(
+ graph,
+ filter.Node.in_degree().is_not_in([threshold_a_str, threshold_b_str]),
+ "in",
+ lambda d: d not in set_values,
+ f"IN is_not_in(string thresholds parsed to u64) ({threshold_a_str}, {threshold_b_str})",
+ )
+ assert_filter(
+ graph,
+ filter.Node.out_degree().is_not_in([threshold_a_str, threshold_b_str]),
+ "out",
+ lambda d: d not in set_values,
+ f"OUT is_not_in(string thresholds parsed to u64) ({threshold_a_str}, {threshold_b_str})",
+ )
@pytest.mark.parametrize("value", range(0, 15))
@@ -572,8 +824,6 @@ def test_degree_filter_with_float_is_not_in(value):
)
-
-
@with_variants(init_graph)
def test_filter_nodes_for_node_name_eq():
def check(graph):
@@ -1034,4 +1284,4 @@ def check(graph):
with pytest.raises(AttributeError, match=r"has no attribute 'len'"):
filter.Node.name().len()
- return check
\ No newline at end of file
+ return check
diff --git a/python/tests/test_base_install/test_graphdb/test_algorithms.py b/python/tests/test_base_install/test_graphdb/test_algorithms.py
index e076376b44..efb191659e 100644
--- a/python/tests/test_base_install/test_graphdb/test_algorithms.py
+++ b/python/tests/test_base_install/test_graphdb/test_algorithms.py
@@ -369,9 +369,9 @@ def test_weighted_page_rank():
("3", 0.42311),
("4", 0.07837),
]:
- assert abs(actual[node]["pagerank_score"] - expected) < 1e-5, (
- f"node {node}: {actual[node]} != {expected}"
- )
+ assert (
+ abs(actual[node]["pagerank_score"] - expected) < 1e-5
+ ), f"node {node}: {actual[node]} != {expected}"
def test_weighted_page_rank_none_matches_unweighted():
diff --git a/python/tests/test_base_install/test_graphql/test_filters/test_node_filter_gql.py b/python/tests/test_base_install/test_graphql/test_filters/test_node_filter_gql.py
index a81fbf240b..8fd9d8e9be 100644
--- a/python/tests/test_base_install/test_graphql/test_filters/test_node_filter_gql.py
+++ b/python/tests/test_base_install/test_graphql/test_filters/test_node_filter_gql.py
@@ -1,7 +1,16 @@
import pytest
from raphtory import Graph, PersistentGraph
-from filters_setup import init_graph, init_graph2, degree_graph_with_add_node_and_add_edge
-from utils import run_graphql_test, run_graphql_error_test, run_graphql_error_test_contains, run_group_graphql_test
+from filters_setup import (
+ init_graph,
+ init_graph2,
+ degree_graph_with_add_node_and_add_edge,
+)
+from utils import (
+ run_graphql_test,
+ run_graphql_error_test,
+ run_graphql_error_test_contains,
+ run_group_graphql_test,
+)
EVENT_GRAPH = init_graph(Graph())
PERSISTENT_GRAPH = init_graph(PersistentGraph())
@@ -169,27 +178,35 @@ def test_nodes_filter_windowed_is_not_active(graph):
def _degree_value(node, direction):
- if direction == "BOTH":
- return node.degree()
- if direction == "IN":
- return node.in_degree()
- if direction == "OUT":
- return node.out_degree()
- raise ValueError(f"Unsupported direction: {direction}")
+ if direction == "BOTH":
+ return node.degree()
+ if direction == "IN":
+ return node.in_degree()
+ if direction == "OUT":
+ return node.out_degree()
+ raise ValueError(f"Unsupported direction: {direction}")
def _expected_degree_names(graph, direction, predicate):
- candidate_ids = [node.id for node in graph.nodes if predicate(_degree_value(node, direction))]
- subgraph = graph.subgraph(candidate_ids)
- return sorted(str(node.id) for node in subgraph.nodes if len(node.history.collect()) > 0)
+ candidate_ids = [
+ node.id for node in graph.nodes if predicate(_degree_value(node, direction))
+ ]
+ subgraph = graph.subgraph(candidate_ids)
+ return sorted(
+ str(node.id) for node in subgraph.nodes if len(node.history.collect()) > 0
+ )
def _expected_degree_select_names(graph, direction, predicate):
- return sorted(str(node.id) for node in graph.nodes if predicate(_degree_value(node, direction)))
+ return sorted(
+ str(node.id)
+ for node in graph.nodes
+ if predicate(_degree_value(node, direction))
+ )
def _degree_filter_nodes_query_expected_pair(expr, expected_names):
- query = f"""
+ query = f"""
query {{
graph(path: "g") {{
filterNodes(expr: {{ {expr} }}) {{
@@ -201,18 +218,18 @@ def _degree_filter_nodes_query_expected_pair(expr, expected_names):
}}
"""
- expected_output = {
- "graph": {
- "filterNodes": {
- "nodes": {"list": [{"name": name} for name in expected_names]}
- }
+ expected_output = {
+ "graph": {
+ "filterNodes": {
+ "nodes": {"list": [{"name": name} for name in expected_names]}
+ }
+ }
}
- }
- return query, expected_output
+ return query, expected_output
def _degree_select_nodes_query_expected_pair(expr, expected_names):
- query = f"""
+ query = f"""
query {{
graph(path: "g") {{
nodes {{
@@ -224,199 +241,293 @@ def _degree_select_nodes_query_expected_pair(expr, expected_names):
}}
"""
- expected_output = {
- "graph": {
- "nodes": {
- "select": {"list": [{"name": name} for name in expected_names]}
- }
+ expected_output = {
+ "graph": {
+ "nodes": {"select": {"list": [{"name": name} for name in expected_names]}}
+ }
}
- }
- return query, expected_output
+ return query, expected_output
@pytest.mark.parametrize("graph", [EVENT_GRAPH, PERSISTENT_GRAPH])
def test_filter_nodes_degree_ops_and_gql(graph):
- threshold = 4
- queries_and_expected_outputs = []
-
- for direction in ["BOTH", "IN", "OUT"]:
- queries_and_expected_outputs.append(_degree_select_nodes_query_expected_pair(
- f"degree: {{ direction: {direction}, where: {{ lt: {{ u64: {threshold} }} }} }}",
- _expected_degree_select_names(graph, direction, lambda d: d < threshold),
- ))
- queries_and_expected_outputs.append(_degree_filter_nodes_query_expected_pair(
- f"degree: {{ direction: {direction}, where: {{ lt: {{ u64: {threshold} }} }} }}",
- _expected_degree_names(graph, direction, lambda d: d < threshold),
- ))
- queries_and_expected_outputs.append(_degree_select_nodes_query_expected_pair(
- f"degree: {{ direction: {direction}, where: {{ le: {{ u64: {threshold} }} }} }}",
- _expected_degree_select_names(graph, direction, lambda d: d <= threshold),
- ))
- queries_and_expected_outputs.append(_degree_filter_nodes_query_expected_pair(
- f"degree: {{ direction: {direction}, where: {{ le: {{ u64: {threshold} }} }} }}",
- _expected_degree_names(graph, direction, lambda d: d <= threshold),
- ))
- queries_and_expected_outputs.append(_degree_select_nodes_query_expected_pair(
- f"degree: {{ direction: {direction}, where: {{ eq: {{ u64: {threshold} }} }} }}",
- _expected_degree_select_names(graph, direction, lambda d: d == threshold),
- ))
- queries_and_expected_outputs.append(_degree_filter_nodes_query_expected_pair(
- f"degree: {{ direction: {direction}, where: {{ eq: {{ u64: {threshold} }} }} }}",
- _expected_degree_names(graph, direction, lambda d: d == threshold),
- ))
- queries_and_expected_outputs.append(_degree_select_nodes_query_expected_pair(
- f"degree: {{ direction: {direction}, where: {{ ne: {{ u64: {threshold} }} }} }}",
- _expected_degree_select_names(graph, direction, lambda d: d != threshold),
- ))
- queries_and_expected_outputs.append(_degree_filter_nodes_query_expected_pair(
- f"degree: {{ direction: {direction}, where: {{ ne: {{ u64: {threshold} }} }} }}",
- _expected_degree_names(graph, direction, lambda d: d != threshold),
- ))
- queries_and_expected_outputs.append(_degree_select_nodes_query_expected_pair(
- f"degree: {{ direction: {direction}, where: {{ ge: {{ u64: {threshold} }} }} }}",
- _expected_degree_select_names(graph, direction, lambda d: d >= threshold),
- ))
- queries_and_expected_outputs.append(_degree_filter_nodes_query_expected_pair(
- f"degree: {{ direction: {direction}, where: {{ ge: {{ u64: {threshold} }} }} }}",
- _expected_degree_names(graph, direction, lambda d: d >= threshold),
- ))
- queries_and_expected_outputs.append(_degree_select_nodes_query_expected_pair(
- f"degree: {{ direction: {direction}, where: {{ gt: {{ u64: {threshold} }} }} }}",
- _expected_degree_select_names(graph, direction, lambda d: d > threshold),
- ))
- queries_and_expected_outputs.append(_degree_filter_nodes_query_expected_pair(
- f"degree: {{ direction: {direction}, where: {{ gt: {{ u64: {threshold} }} }} }}",
- _expected_degree_names(graph, direction, lambda d: d > threshold),
- ))
-
- run_group_graphql_test(queries_and_expected_outputs, graph, sort_output=True)
+ threshold = 4
+ queries_and_expected_outputs = []
+
+ for direction in ["BOTH", "IN", "OUT"]:
+ queries_and_expected_outputs.append(
+ _degree_select_nodes_query_expected_pair(
+ f"degree: {{ direction: {direction}, where: {{ lt: {{ u64: {threshold} }} }} }}",
+ _expected_degree_select_names(
+ graph, direction, lambda d: d < threshold
+ ),
+ )
+ )
+ queries_and_expected_outputs.append(
+ _degree_filter_nodes_query_expected_pair(
+ f"degree: {{ direction: {direction}, where: {{ lt: {{ u64: {threshold} }} }} }}",
+ _expected_degree_names(graph, direction, lambda d: d < threshold),
+ )
+ )
+ queries_and_expected_outputs.append(
+ _degree_select_nodes_query_expected_pair(
+ f"degree: {{ direction: {direction}, where: {{ le: {{ u64: {threshold} }} }} }}",
+ _expected_degree_select_names(
+ graph, direction, lambda d: d <= threshold
+ ),
+ )
+ )
+ queries_and_expected_outputs.append(
+ _degree_filter_nodes_query_expected_pair(
+ f"degree: {{ direction: {direction}, where: {{ le: {{ u64: {threshold} }} }} }}",
+ _expected_degree_names(graph, direction, lambda d: d <= threshold),
+ )
+ )
+ queries_and_expected_outputs.append(
+ _degree_select_nodes_query_expected_pair(
+ f"degree: {{ direction: {direction}, where: {{ eq: {{ u64: {threshold} }} }} }}",
+ _expected_degree_select_names(
+ graph, direction, lambda d: d == threshold
+ ),
+ )
+ )
+ queries_and_expected_outputs.append(
+ _degree_filter_nodes_query_expected_pair(
+ f"degree: {{ direction: {direction}, where: {{ eq: {{ u64: {threshold} }} }} }}",
+ _expected_degree_names(graph, direction, lambda d: d == threshold),
+ )
+ )
+ queries_and_expected_outputs.append(
+ _degree_select_nodes_query_expected_pair(
+ f"degree: {{ direction: {direction}, where: {{ ne: {{ u64: {threshold} }} }} }}",
+ _expected_degree_select_names(
+ graph, direction, lambda d: d != threshold
+ ),
+ )
+ )
+ queries_and_expected_outputs.append(
+ _degree_filter_nodes_query_expected_pair(
+ f"degree: {{ direction: {direction}, where: {{ ne: {{ u64: {threshold} }} }} }}",
+ _expected_degree_names(graph, direction, lambda d: d != threshold),
+ )
+ )
+ queries_and_expected_outputs.append(
+ _degree_select_nodes_query_expected_pair(
+ f"degree: {{ direction: {direction}, where: {{ ge: {{ u64: {threshold} }} }} }}",
+ _expected_degree_select_names(
+ graph, direction, lambda d: d >= threshold
+ ),
+ )
+ )
+ queries_and_expected_outputs.append(
+ _degree_filter_nodes_query_expected_pair(
+ f"degree: {{ direction: {direction}, where: {{ ge: {{ u64: {threshold} }} }} }}",
+ _expected_degree_names(graph, direction, lambda d: d >= threshold),
+ )
+ )
+ queries_and_expected_outputs.append(
+ _degree_select_nodes_query_expected_pair(
+ f"degree: {{ direction: {direction}, where: {{ gt: {{ u64: {threshold} }} }} }}",
+ _expected_degree_select_names(
+ graph, direction, lambda d: d > threshold
+ ),
+ )
+ )
+ queries_and_expected_outputs.append(
+ _degree_filter_nodes_query_expected_pair(
+ f"degree: {{ direction: {direction}, where: {{ gt: {{ u64: {threshold} }} }} }}",
+ _expected_degree_names(graph, direction, lambda d: d > threshold),
+ )
+ )
+
+ run_group_graphql_test(queries_and_expected_outputs, graph, sort_output=True)
@pytest.mark.parametrize("graph", [EVENT_GRAPH, PERSISTENT_GRAPH])
def test_filter_nodes_degree_logic_and_sets_gql(graph):
- threshold = 3
- upper = threshold + 5
- queries_and_expected_outputs = []
-
- for direction in ["BOTH", "IN", "OUT"]:
- queries_and_expected_outputs.append(_degree_select_nodes_query_expected_pair(
- "and: ["
- f"{{ degree: {{ direction: {direction}, where: {{ gt: {{ u64: {threshold} }} }} }} }},"
- f"{{ degree: {{ direction: {direction}, where: {{ lt: {{ u64: {upper} }} }} }} }}"
- "]",
- _expected_degree_select_names(graph, direction, lambda d: d > threshold and d < upper),
- ))
- queries_and_expected_outputs.append(_degree_filter_nodes_query_expected_pair(
- "and: ["
- f"{{ degree: {{ direction: {direction}, where: {{ gt: {{ u64: {threshold} }} }} }} }},"
- f"{{ degree: {{ direction: {direction}, where: {{ lt: {{ u64: {upper} }} }} }} }}"
- "]",
- _expected_degree_names(graph, direction, lambda d: d > threshold and d < upper),
- ))
-
- queries_and_expected_outputs.append(_degree_select_nodes_query_expected_pair(
- "or: ["
- f"{{ degree: {{ direction: {direction}, where: {{ lt: {{ u64: {threshold} }} }} }} }},"
- f"{{ degree: {{ direction: {direction}, where: {{ gt: {{ u64: {upper} }} }} }} }}"
- "]",
- _expected_degree_select_names(graph, direction, lambda d: d < threshold or d > upper),
- ))
- queries_and_expected_outputs.append(_degree_filter_nodes_query_expected_pair(
- "or: ["
- f"{{ degree: {{ direction: {direction}, where: {{ lt: {{ u64: {threshold} }} }} }} }},"
- f"{{ degree: {{ direction: {direction}, where: {{ gt: {{ u64: {upper} }} }} }} }}"
- "]",
- _expected_degree_names(graph, direction, lambda d: d < threshold or d > upper),
- ))
-
- queries_and_expected_outputs.append(_degree_select_nodes_query_expected_pair(
- "or: ["
- f"{{ degree: {{ direction: {direction}, where: {{ lt: {{ u64: {threshold} }} }} }} }},"
- "{ not: "
- f"{{ degree: {{ direction: {direction}, where: {{ gt: {{ u64: {upper} }} }} }} }}"
- " }"
- "]",
- _expected_degree_select_names(graph, direction, lambda d: d < threshold or d <= upper),
- ))
- queries_and_expected_outputs.append(_degree_filter_nodes_query_expected_pair(
- "or: ["
- f"{{ degree: {{ direction: {direction}, where: {{ lt: {{ u64: {threshold} }} }} }} }},"
- "{ not: "
- f"{{ degree: {{ direction: {direction}, where: {{ gt: {{ u64: {upper} }} }} }} }}"
- " }"
- "]",
- _expected_degree_names(graph, direction, lambda d: d < threshold or d <= upper),
- ))
-
- queries_and_expected_outputs.append(_degree_select_nodes_query_expected_pair(
- f"degree: {{ direction: {direction}, where: {{ isIn: {{ list: [{{u64: {threshold}}}, {{u64: {threshold + 1}}}] }} }} }}",
- _expected_degree_select_names(graph, direction, lambda d: d in [threshold, threshold + 1]),
- ))
- queries_and_expected_outputs.append(_degree_filter_nodes_query_expected_pair(
- f"degree: {{ direction: {direction}, where: {{ isIn: {{ list: [{{u64: {threshold}}}, {{u64: {threshold + 1}}}] }} }} }}",
- _expected_degree_names(graph, direction, lambda d: d in [threshold, threshold + 1]),
- ))
-
- queries_and_expected_outputs.append(_degree_select_nodes_query_expected_pair(
- f"degree: {{ direction: {direction}, where: {{ isNotIn: {{ list: [{{u64: {threshold}}}, {{u64: {threshold + 1}}}] }} }} }}",
- _expected_degree_select_names(graph, direction, lambda d: d not in [threshold, threshold + 1]),
- ))
- queries_and_expected_outputs.append(_degree_filter_nodes_query_expected_pair(
- f"degree: {{ direction: {direction}, where: {{ isNotIn: {{ list: [{{u64: {threshold}}}, {{u64: {threshold + 1}}}] }} }} }}",
- _expected_degree_names(graph, direction, lambda d: d not in [threshold, threshold + 1]),
- ))
-
- run_group_graphql_test(queries_and_expected_outputs, graph, sort_output=True)
+ threshold = 3
+ upper = threshold + 5
+ queries_and_expected_outputs = []
+
+ for direction in ["BOTH", "IN", "OUT"]:
+ queries_and_expected_outputs.append(
+ _degree_select_nodes_query_expected_pair(
+ "and: ["
+ f"{{ degree: {{ direction: {direction}, where: {{ gt: {{ u64: {threshold} }} }} }} }},"
+ f"{{ degree: {{ direction: {direction}, where: {{ lt: {{ u64: {upper} }} }} }} }}"
+ "]",
+ _expected_degree_select_names(
+ graph, direction, lambda d: d > threshold and d < upper
+ ),
+ )
+ )
+ queries_and_expected_outputs.append(
+ _degree_filter_nodes_query_expected_pair(
+ "and: ["
+ f"{{ degree: {{ direction: {direction}, where: {{ gt: {{ u64: {threshold} }} }} }} }},"
+ f"{{ degree: {{ direction: {direction}, where: {{ lt: {{ u64: {upper} }} }} }} }}"
+ "]",
+ _expected_degree_names(
+ graph, direction, lambda d: d > threshold and d < upper
+ ),
+ )
+ )
+
+ queries_and_expected_outputs.append(
+ _degree_select_nodes_query_expected_pair(
+ "or: ["
+ f"{{ degree: {{ direction: {direction}, where: {{ lt: {{ u64: {threshold} }} }} }} }},"
+ f"{{ degree: {{ direction: {direction}, where: {{ gt: {{ u64: {upper} }} }} }} }}"
+ "]",
+ _expected_degree_select_names(
+ graph, direction, lambda d: d < threshold or d > upper
+ ),
+ )
+ )
+ queries_and_expected_outputs.append(
+ _degree_filter_nodes_query_expected_pair(
+ "or: ["
+ f"{{ degree: {{ direction: {direction}, where: {{ lt: {{ u64: {threshold} }} }} }} }},"
+ f"{{ degree: {{ direction: {direction}, where: {{ gt: {{ u64: {upper} }} }} }} }}"
+ "]",
+ _expected_degree_names(
+ graph, direction, lambda d: d < threshold or d > upper
+ ),
+ )
+ )
+
+ queries_and_expected_outputs.append(
+ _degree_select_nodes_query_expected_pair(
+ "or: ["
+ f"{{ degree: {{ direction: {direction}, where: {{ lt: {{ u64: {threshold} }} }} }} }},"
+ "{ not: "
+ f"{{ degree: {{ direction: {direction}, where: {{ gt: {{ u64: {upper} }} }} }} }}"
+ " }"
+ "]",
+ _expected_degree_select_names(
+ graph, direction, lambda d: d < threshold or d <= upper
+ ),
+ )
+ )
+ queries_and_expected_outputs.append(
+ _degree_filter_nodes_query_expected_pair(
+ "or: ["
+ f"{{ degree: {{ direction: {direction}, where: {{ lt: {{ u64: {threshold} }} }} }} }},"
+ "{ not: "
+ f"{{ degree: {{ direction: {direction}, where: {{ gt: {{ u64: {upper} }} }} }} }}"
+ " }"
+ "]",
+ _expected_degree_names(
+ graph, direction, lambda d: d < threshold or d <= upper
+ ),
+ )
+ )
+
+ queries_and_expected_outputs.append(
+ _degree_select_nodes_query_expected_pair(
+ f"degree: {{ direction: {direction}, where: {{ isIn: {{ list: [{{u64: {threshold}}}, {{u64: {threshold + 1}}}] }} }} }}",
+ _expected_degree_select_names(
+ graph, direction, lambda d: d in [threshold, threshold + 1]
+ ),
+ )
+ )
+ queries_and_expected_outputs.append(
+ _degree_filter_nodes_query_expected_pair(
+ f"degree: {{ direction: {direction}, where: {{ isIn: {{ list: [{{u64: {threshold}}}, {{u64: {threshold + 1}}}] }} }} }}",
+ _expected_degree_names(
+ graph, direction, lambda d: d in [threshold, threshold + 1]
+ ),
+ )
+ )
+
+ queries_and_expected_outputs.append(
+ _degree_select_nodes_query_expected_pair(
+ f"degree: {{ direction: {direction}, where: {{ isNotIn: {{ list: [{{u64: {threshold}}}, {{u64: {threshold + 1}}}] }} }} }}",
+ _expected_degree_select_names(
+ graph, direction, lambda d: d not in [threshold, threshold + 1]
+ ),
+ )
+ )
+ queries_and_expected_outputs.append(
+ _degree_filter_nodes_query_expected_pair(
+ f"degree: {{ direction: {direction}, where: {{ isNotIn: {{ list: [{{u64: {threshold}}}, {{u64: {threshold + 1}}}] }} }} }}",
+ _expected_degree_names(
+ graph, direction, lambda d: d not in [threshold, threshold + 1]
+ ),
+ )
+ )
+
+ run_group_graphql_test(queries_and_expected_outputs, graph, sort_output=True)
@pytest.mark.parametrize("graph", [EVENT_GRAPH, PERSISTENT_GRAPH])
def test_filter_nodes_degree_numeric_coercion_gql(graph):
- threshold_str = "4"
- threshold_float = 4.5
- queries_and_expected_outputs = []
-
- for direction in ["BOTH", "IN", "OUT"]:
- queries_and_expected_outputs.append(_degree_select_nodes_query_expected_pair(
- f'degree: {{ direction: {direction}, where: {{ eq: {{ str: "{threshold_str}" }} }} }}',
- _expected_degree_select_names(graph, direction, lambda d: d == int(threshold_str)),
- ))
- queries_and_expected_outputs.append(_degree_filter_nodes_query_expected_pair(
- f'degree: {{ direction: {direction}, where: {{ eq: {{ str: "{threshold_str}" }} }} }}',
- _expected_degree_names(graph, direction, lambda d: d == int(threshold_str)),
- ))
-
- queries_and_expected_outputs.append(_degree_select_nodes_query_expected_pair(
- f"degree: {{ direction: {direction}, where: {{ ge: {{ f64: {threshold_float} }} }} }}",
- _expected_degree_select_names(graph, direction, lambda d: d >= int(threshold_float)),
- ))
- queries_and_expected_outputs.append(_degree_filter_nodes_query_expected_pair(
- f"degree: {{ direction: {direction}, where: {{ ge: {{ f64: {threshold_float} }} }} }}",
- _expected_degree_names(graph, direction, lambda d: d >= int(threshold_float)),
- ))
-
- queries_and_expected_outputs.append(_degree_select_nodes_query_expected_pair(
- f"degree: {{ direction: {direction}, where: {{ isIn: {{ list: [{{str: \"3\"}}, {{f64: 4.9}}] }} }} }}",
- _expected_degree_select_names(graph, direction, lambda d: d in [3, 4]),
- ))
- queries_and_expected_outputs.append(_degree_filter_nodes_query_expected_pair(
- f"degree: {{ direction: {direction}, where: {{ isIn: {{ list: [{{str: \"3\"}}, {{f64: 4.9}}] }} }} }}",
- _expected_degree_names(graph, direction, lambda d: d in [3, 4]),
- ))
-
- run_group_graphql_test(queries_and_expected_outputs, graph, sort_output=True)
+ threshold_str = "4"
+ threshold_float = 4.5
+ queries_and_expected_outputs = []
+
+ for direction in ["BOTH", "IN", "OUT"]:
+ queries_and_expected_outputs.append(
+ _degree_select_nodes_query_expected_pair(
+ f'degree: {{ direction: {direction}, where: {{ eq: {{ str: "{threshold_str}" }} }} }}',
+ _expected_degree_select_names(
+ graph, direction, lambda d: d == int(threshold_str)
+ ),
+ )
+ )
+ queries_and_expected_outputs.append(
+ _degree_filter_nodes_query_expected_pair(
+ f'degree: {{ direction: {direction}, where: {{ eq: {{ str: "{threshold_str}" }} }} }}',
+ _expected_degree_names(
+ graph, direction, lambda d: d == int(threshold_str)
+ ),
+ )
+ )
+
+ queries_and_expected_outputs.append(
+ _degree_select_nodes_query_expected_pair(
+ f"degree: {{ direction: {direction}, where: {{ ge: {{ f64: {threshold_float} }} }} }}",
+ _expected_degree_select_names(
+ graph, direction, lambda d: d >= int(threshold_float)
+ ),
+ )
+ )
+ queries_and_expected_outputs.append(
+ _degree_filter_nodes_query_expected_pair(
+ f"degree: {{ direction: {direction}, where: {{ ge: {{ f64: {threshold_float} }} }} }}",
+ _expected_degree_names(
+ graph, direction, lambda d: d >= int(threshold_float)
+ ),
+ )
+ )
+
+ queries_and_expected_outputs.append(
+ _degree_select_nodes_query_expected_pair(
+ f'degree: {{ direction: {direction}, where: {{ isIn: {{ list: [{{str: "3"}}, {{f64: 4.9}}] }} }} }}',
+ _expected_degree_select_names(graph, direction, lambda d: d in [3, 4]),
+ )
+ )
+ queries_and_expected_outputs.append(
+ _degree_filter_nodes_query_expected_pair(
+ f'degree: {{ direction: {direction}, where: {{ isIn: {{ list: [{{str: "3"}}, {{f64: 4.9}}] }} }} }}',
+ _expected_degree_names(graph, direction, lambda d: d in [3, 4]),
+ )
+ )
+
+ run_group_graphql_test(queries_and_expected_outputs, graph, sort_output=True)
@pytest.mark.parametrize("graph", [EVENT_GRAPH, PERSISTENT_GRAPH])
def test_filter_nodes_degree_invalid_non_numeric_string_values_gql(graph):
- invalid_exprs = [
- 'degree: { direction: BOTH, where: { lt: { str: "foo" } } }',
- 'degree: { direction: IN, where: { eq: { str: "bar" } } }',
- 'degree: { direction: OUT, where: { isIn: { list: [{str: "a"}, {str: "b"}] } } }',
- 'degree: { direction: BOTH, where: { isNotIn: { list: [{str: "x"}, {str: "y"}] } } }',
- ]
-
- for expr in invalid_exprs:
- filter_nodes_query = f"""
+ invalid_exprs = [
+ 'degree: { direction: BOTH, where: { lt: { str: "foo" } } }',
+ 'degree: { direction: IN, where: { eq: { str: "bar" } } }',
+ 'degree: { direction: OUT, where: { isIn: { list: [{str: "a"}, {str: "b"}] } } }',
+ 'degree: { direction: BOTH, where: { isNotIn: { list: [{str: "x"}, {str: "y"}] } } }',
+ ]
+
+ for expr in invalid_exprs:
+ filter_nodes_query = f"""
query {{
graph(path: "g") {{
filterNodes(expr: {{ {expr} }}) {{
@@ -428,7 +539,7 @@ def test_filter_nodes_degree_invalid_non_numeric_string_values_gql(graph):
}}
"""
- select_nodes_query = f"""
+ select_nodes_query = f"""
query {{
graph(path: "g") {{
nodes {{
@@ -440,30 +551,30 @@ def test_filter_nodes_degree_invalid_non_numeric_string_values_gql(graph):
}}
"""
- run_graphql_error_test_contains(filter_nodes_query, ["Invalid filter"], graph)
- run_graphql_error_test_contains(select_nodes_query, ["Invalid filter"], graph)
+ run_graphql_error_test_contains(filter_nodes_query, ["Invalid filter"], graph)
+ run_graphql_error_test_contains(select_nodes_query, ["Invalid filter"], graph)
@pytest.mark.parametrize("graph", [EVENT_GRAPH, PERSISTENT_GRAPH])
def test_filter_nodes_degree_invalid_expressions_gql(graph):
- invalid_exprs = [
- "degree: { direction: BOTH, where: { isNone: true } }",
- "degree: { direction: IN, where: { isSome: true } }",
- 'degree: { direction: OUT, where: { startsWith: { str: "1" } } }',
- 'degree: { direction: BOTH, where: { endsWith: { str: "1" } } }',
- 'degree: { direction: IN, where: { contains: { str: "1" } } }',
- 'degree: { direction: OUT, where: { notContains: { str: "1" } } }',
- "degree: { direction: BOTH, where: { any: { eq: { u64: 1 } } } }",
- "degree: { direction: IN, where: { all: { eq: { u64: 1 } } } }",
- "degree: { direction: OUT, where: { len: { gt: { u64: 0 } } } }",
- "degree: { direction: BOTH, where: { sum: { eq: { u64: 1 } } } }",
- "degree: { direction: IN, where: { avg: { eq: { u64: 1 } } } }",
- "degree: { direction: OUT, where: { first: { eq: { u64: 1 } } } }",
- "degree: { direction: BOTH, where: { last: { eq: { u64: 1 } } } }",
- ]
-
- for expr in invalid_exprs:
- filter_nodes_query = f"""
+ invalid_exprs = [
+ "degree: { direction: BOTH, where: { isNone: true } }",
+ "degree: { direction: IN, where: { isSome: true } }",
+ 'degree: { direction: OUT, where: { startsWith: { str: "1" } } }',
+ 'degree: { direction: BOTH, where: { endsWith: { str: "1" } } }',
+ 'degree: { direction: IN, where: { contains: { str: "1" } } }',
+ 'degree: { direction: OUT, where: { notContains: { str: "1" } } }',
+ "degree: { direction: BOTH, where: { any: { eq: { u64: 1 } } } }",
+ "degree: { direction: IN, where: { all: { eq: { u64: 1 } } } }",
+ "degree: { direction: OUT, where: { len: { gt: { u64: 0 } } } }",
+ "degree: { direction: BOTH, where: { sum: { eq: { u64: 1 } } } }",
+ "degree: { direction: IN, where: { avg: { eq: { u64: 1 } } } }",
+ "degree: { direction: OUT, where: { first: { eq: { u64: 1 } } } }",
+ "degree: { direction: BOTH, where: { last: { eq: { u64: 1 } } } }",
+ ]
+
+ for expr in invalid_exprs:
+ filter_nodes_query = f"""
query {{
graph(path: "g") {{
filterNodes(expr: {{ {expr} }}) {{
@@ -475,7 +586,7 @@ def test_filter_nodes_degree_invalid_expressions_gql(graph):
}}
"""
- select_nodes_query = f"""
+ select_nodes_query = f"""
query {{
graph(path: "g") {{
nodes {{
@@ -487,11 +598,5 @@ def test_filter_nodes_degree_invalid_expressions_gql(graph):
}}
"""
- run_graphql_error_test_contains(filter_nodes_query, ["Invalid filter"], graph)
- run_graphql_error_test_contains(select_nodes_query, ["Invalid filter"], graph)
-
-
-
-
-
-
+ run_graphql_error_test_contains(filter_nodes_query, ["Invalid filter"], graph)
+ run_graphql_error_test_contains(select_nodes_query, ["Invalid filter"], graph)
diff --git a/raphtory-graphql/schema.graphql b/raphtory-graphql/schema.graphql
index ac83a98743..dfaf911edc 100644
--- a/raphtory-graphql/schema.graphql
+++ b/raphtory-graphql/schema.graphql
@@ -130,6 +130,32 @@ type CollectionOfNamespacedItem {
count: Int!
}
+"""
+Filters nodes by computed degree with a directional scope.
+
+`DegreeFilterNew` lets callers filter on:
+- inbound degree (`IN`),
+- outbound degree (`OUT`),
+- or total degree (`BOTH`).
+
+The selected degree is compared using the `where` condition.
+
+Example (GraphQL):
+```graphql
+{ Degree: { direction: BOTH, where: { Gt: 10 } } }
+```
+"""
+enum DegreeDirection {
+ IN
+ OUT
+ BOTH
+}
+
+input DegreeFilterNew {
+ direction: DegreeDirection!
+ where: PropCondition!
+}
+
"""
Document in a vector graph
"""
@@ -3623,6 +3649,10 @@ input NodeFilter @oneOf {
"""
property: PropertyFilterNew
"""
+ Filters a node's degree (in, out, or total) by a condition.
+ """
+ degree: DegreeFilterNew
+ """
Filters a node metadata field by name and condition.
Metadata is shared across all temporal versions of a node.
diff --git a/raphtory-graphql/src/lib.rs b/raphtory-graphql/src/lib.rs
index 184f6a0049..1a3f2acfde 100644
--- a/raphtory-graphql/src/lib.rs
+++ b/raphtory-graphql/src/lib.rs
@@ -536,7 +536,6 @@ mod graphql_test {
graph
}
-
fn degree_graph_with_add_edge_only() -> Graph {
let graph = Graph::new();
@@ -646,8 +645,6 @@ mod graphql_test {
);
}
-
-
#[tokio::test]
async fn test_unique_temporal_properties() {
let g = Graph::new();
diff --git a/raphtory-graphql/src/model/graph/filtering.rs b/raphtory-graphql/src/model/graph/filtering.rs
index 3033016e1b..2ab6872c9c 100644
--- a/raphtory-graphql/src/model/graph/filtering.rs
+++ b/raphtory-graphql/src/model/graph/filtering.rs
@@ -1,4 +1,7 @@
-use crate::model::{graph::{node_id::GqlNodeId, property::Value, timeindex::GqlTimeInput}, plugins::operation};
+use crate::model::{
+ graph::{node_id::GqlNodeId, property::Value, timeindex::GqlTimeInput},
+ plugins::operation,
+};
use async_graphql::dynamic::ValueAccessor;
use dynamic_graphql::{
internal::{
@@ -7,16 +10,35 @@ use dynamic_graphql::{
Enum, InputObject, OneOfInput,
};
use raphtory::{
- db::{api::{state::ops::Degree, view::internal::filtered_edge}, graph::views::filter::model::{
- ComposableFilter, DynFilter, DynView, NoFilter, ViewWrapOps, degree_filter::DegreeFilter, edge_filter::{CompositeEdgeFilter, EdgeFilter}, filter::{Filter, FilterValue}, filter_operator::FilterOperator, graph_filter::GraphFilter, is_active_edge_filter::IsActiveEdge, is_active_node_filter::IsActiveNode, is_deleted_filter::IsDeletedEdge, is_self_loop_filter::IsSelfLoopEdge, is_valid_filter::IsValidEdge, latest_filter::Latest as LatestWrap, layered_filter::Layered, node_filter::{CompositeNodeFilter, NodeFilter}, property_filter::{Op, PropertyFilter, PropertyFilterValue, PropertyRef}, snapshot_filter::{SnapshotAt as SnapshotAtWrap, SnapshotLatest as SnapshotLatestWrap}, windowed_filter::Windowed
- }},
+ db::{
+ api::{state::ops::Degree, view::internal::filtered_edge},
+ graph::views::filter::model::{
+ degree_filter::DegreeFilter,
+ edge_filter::{CompositeEdgeFilter, EdgeFilter},
+ filter::{Filter, FilterValue},
+ filter_operator::FilterOperator,
+ graph_filter::GraphFilter,
+ is_active_edge_filter::IsActiveEdge,
+ is_active_node_filter::IsActiveNode,
+ is_deleted_filter::IsDeletedEdge,
+ is_self_loop_filter::IsSelfLoopEdge,
+ is_valid_filter::IsValidEdge,
+ latest_filter::Latest as LatestWrap,
+ layered_filter::Layered,
+ node_filter::{CompositeNodeFilter, NodeFilter},
+ property_filter::{Op, PropertyFilter, PropertyFilterValue, PropertyRef},
+ snapshot_filter::{SnapshotAt as SnapshotAtWrap, SnapshotLatest as SnapshotLatestWrap},
+ windowed_filter::Windowed,
+ ComposableFilter, DynFilter, DynView, NoFilter, ViewWrapOps,
+ },
+ },
errors::GraphError,
};
-use raphtory_api::core::Direction;
use raphtory_api::core::{
entities::{properties::prop::Prop, Layer, GID},
storage::timeindex::{AsTime, EventTime},
utils::time::IntoTime,
+ Direction,
};
use serde::{Deserialize, Serialize};
use std::{
@@ -304,7 +326,6 @@ pub struct PropertyFilterNew {
pub where_: PropCondition,
}
-
/// Filters nodes by computed degree with a directional scope.
///
/// `DegreeFilterNew` lets callers filter on:
@@ -330,8 +351,8 @@ pub enum DegreeDirection {
impl From for Direction {
fn from(d: DegreeDirection) -> Self {
match d {
- DegreeDirection::In => Direction::IN,
- DegreeDirection::Out => Direction::OUT,
+ DegreeDirection::In => Direction::IN,
+ DegreeDirection::Out => Direction::OUT,
DegreeDirection::Both => Direction::BOTH,
}
}
@@ -342,7 +363,7 @@ impl From for String {
match d {
DegreeDirection::In => "in_degree".to_string(),
DegreeDirection::Out => "out_degree".to_string(),
- DegreeDirection::Both => "degree".to_string(),
+ DegreeDirection::Both => "degree".to_string(),
}
}
}
@@ -1440,8 +1461,8 @@ impl TryFrom for CompositeNodeFilter {
direction: core_direction,
operator,
value,
- ops
- }))
+ ops,
+ }))
}
GqlNodeFilter::Property(prop) => {
let prop_ref = PropertyRef::Property(prop.name.clone());
diff --git a/raphtory-tests/tests/cached_view.rs b/raphtory-tests/tests/cached_view.rs
deleted file mode 100644
index e9c132490a..0000000000
--- a/raphtory-tests/tests/cached_view.rs
+++ /dev/null
@@ -1,369 +0,0 @@
-use itertools::Itertools;
-use proptest::prelude::*;
-use raphtory::{
- algorithms::motifs::triangle_count::triangle_count, db::graph::graph::assert_graph_equal,
- prelude::*,
-};
-use raphtory_api::core::storage::timeindex::AsTime;
-use raphtory_tests::test_storage;
-
-#[test]
-fn empty_graph() {
- let graph = Graph::new();
- test_storage!(&graph, |graph| {
- let sg = graph.cache_view();
- assert_graph_equal(&sg, &graph);
- });
-}
-
-#[test]
-fn empty_window() {
- let graph = Graph::new();
- graph.add_edge(1, 1, 1, NO_PROPS, None).unwrap();
- test_storage!(&graph, |graph| {
- let window = graph.window(2, 3);
- let sg = window.cache_view();
- assert_graph_equal(&window, &sg);
- });
-}
-
-#[test]
-fn test_materialize_no_edges() {
- let graph = Graph::new();
-
- graph.add_node(1, 1, NO_PROPS, None, None).unwrap();
- graph.add_node(2, 2, NO_PROPS, None, None).unwrap();
-
- test_storage!(&graph, |graph| {
- let sg = graph.cache_view();
-
- let actual = sg.materialize().unwrap().into_events().unwrap();
- assert_graph_equal(&actual, &sg);
- });
-}
-
-#[test]
-fn test_mask_the_window_50pc() {
- let graph = Graph::new();
- let edges = vec![
- (1, 2, 1),
- (1, 3, 2),
- (1, 4, 3),
- (3, 1, 4),
- (3, 4, 5),
- (3, 5, 6),
- (4, 5, 7),
- (5, 6, 8),
- (5, 8, 9),
- (7, 5, 10),
- (8, 5, 11),
- (1, 9, 12),
- (9, 1, 13),
- (6, 3, 14),
- (4, 8, 15),
- (8, 3, 16),
- (5, 10, 17),
- (10, 5, 18),
- (10, 8, 19),
- (1, 11, 20),
- (11, 1, 21),
- (9, 11, 22),
- (11, 9, 23),
- ];
- for (src, dst, ts) in edges {
- graph.add_edge(ts, src, dst, NO_PROPS, None).unwrap();
- }
- test_storage!(&graph, |graph| {
- let window = graph.window(12, 24);
- let mask = window.cache_view();
- let ts = triangle_count(&mask, None);
- let tg = triangle_count(&window, None);
- assert_eq!(ts, tg);
- });
-}
-
-#[test]
-fn masked_always_equals_proptest() {
- fn check(edge_list: &[(u8, u8, i16, u8)]) {
- let graph = Graph::new();
- for (src, dst, ts, layer) in edge_list {
- graph
- .add_edge(
- *ts as i64,
- *src as u64,
- *dst as u64,
- NO_PROPS,
- Some(&layer.to_string()),
- )
- .unwrap();
- }
-
- test_storage!(&graph, |graph| {
- let layers = graph
- .unique_layers()
- .take(graph.unique_layers().count() / 2)
- .collect_vec();
-
- let earliest = graph.earliest_time().unwrap().t();
- let latest = graph.latest_time().unwrap().t();
- let middle = earliest + (latest - earliest) / 2;
-
- if !layers.is_empty() && earliest < middle && middle < latest {
- let subgraph = graph.layers(layers).unwrap().window(earliest, middle);
- let masked = subgraph.cache_view();
- assert_graph_equal(&subgraph, &masked);
- }
- });
- }
-
- proptest!(|(edge_list in any::>().prop_filter("greater than 3",|v| !v.is_empty() ))| {
- check(&edge_list);
- })
-}
-
-mod test_filters_cached_view {
- use raphtory::{
- db::{
- api::view::StaticGraphViewOps,
- graph::views::{cached_view::CachedView, window_graph::WindowedGraph},
- },
- prelude::{GraphViewOps, TimeOps},
- };
- use raphtory_tests::assertions::GraphTransformer;
- use std::ops::Range;
-
- struct CachedGraphTransformer;
-
- impl GraphTransformer for CachedGraphTransformer {
- type Return = CachedView;
- fn apply(&self, graph: G) -> Self::Return {
- graph.cache_view()
- }
- }
-
- struct WindowedCachedGraphTransformer(Range);
-
- impl GraphTransformer for WindowedCachedGraphTransformer {
- type Return = WindowedGraph>;
- fn apply(&self, graph: G) -> Self::Return {
- graph.cache_view().window(self.0.start, self.0.end)
- }
- }
-
- mod test_nodes_filters_cached_view_graph {
- use raphtory::{
- db::{
- api::view::StaticGraphViewOps,
- graph::views::filter::model::{
- node_filter::NodeFilter, property_filter::ops::PropertyFilterOps,
- PropertyFilterFactory,
- },
- },
- prelude::AdditionOps,
- };
- use raphtory_api::core::entities::properties::prop::Prop;
- use raphtory_tests::assertions::{
- assert_filter_nodes_results, assert_search_nodes_results, TestGraphVariants,
- TestVariants,
- };
-
- use crate::test_filters_cached_view::{
- CachedGraphTransformer, WindowedCachedGraphTransformer,
- };
-
- fn init_graph(graph: G) -> G {
- let node_data = vec![
- (6, "N1", 2u64, "air_nomad"),
- (7, "N1", 1u64, "air_nomad"),
- (6, "N2", 1u64, "water_tribe"),
- (7, "N2", 2u64, "water_tribe"),
- (8, "N3", 1u64, "air_nomad"),
- (9, "N4", 1u64, "air_nomad"),
- (5, "N5", 1u64, "air_nomad"),
- (6, "N5", 2u64, "air_nomad"),
- (5, "N6", 1u64, "fire_nation"),
- (6, "N6", 1u64, "fire_nation"),
- (3, "N7", 1u64, "air_nomad"),
- (5, "N7", 1u64, "air_nomad"),
- (3, "N8", 1u64, "fire_nation"),
- (4, "N8", 2u64, "fire_nation"),
- ];
-
- for (ts, name, value, kind) in node_data {
- graph
- .add_node(ts, name, [("p1", Prop::U64(value))], Some(kind), None)
- .unwrap();
- }
-
- graph
- }
-
- #[test]
- fn test_nodes_filters() {
- let filter = NodeFilter.property("p1").eq(1u64);
- let expected_results = vec!["N1", "N3", "N4", "N6", "N7"];
- assert_filter_nodes_results(
- init_graph,
- CachedGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_nodes_results(
- init_graph,
- CachedGraphTransformer,
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
- }
-
- #[test]
- fn test_nodes_filters_w() {
- // TODO: Enable event_disk_graph for filter_nodes once bug fixed: https://github.com/Pometry/Raphtory/issues/2098
- let filter = NodeFilter.property("p1").eq(1u64);
- let expected_results = vec!["N1", "N3", "N6"];
- assert_filter_nodes_results(
- init_graph,
- WindowedCachedGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowedCachedGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
- }
-
- #[test]
- fn test_nodes_filters_pg_w() {
- let filter = NodeFilter.property("p1").ge(2u64);
- let expected_results = vec!["N2", "N5", "N8"];
- assert_filter_nodes_results(
- init_graph,
- WindowedCachedGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowedCachedGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
- }
-
- mod test_edges_filter_cached_view_graph {
- use raphtory::{
- db::api::view::StaticGraphViewOps,
- prelude::{AdditionOps, EdgeFilter},
- };
- use raphtory_api::core::entities::properties::prop::Prop;
- use raphtory_tests::assertions::{
- assert_filter_edges_results, assert_search_edges_results, TestVariants,
- };
-
- use crate::test_filters_cached_view::{
- CachedGraphTransformer, WindowedCachedGraphTransformer,
- };
- use raphtory::db::graph::views::filter::model::{
- property_filter::ops::PropertyFilterOps, PropertyFilterFactory,
- };
-
- fn init_graph(graph: G) -> G {
- let edge_data = vec![
- (6, "N1", "N2", 2u64),
- (7, "N1", "N2", 1u64),
- (6, "N2", "N3", 1u64),
- (7, "N2", "N3", 2u64),
- (8, "N3", "N4", 1u64),
- (9, "N4", "N5", 1u64),
- (5, "N5", "N6", 1u64),
- (6, "N5", "N6", 2u64),
- (5, "N6", "N7", 1u64),
- (6, "N6", "N7", 1u64),
- (3, "N7", "N8", 1u64),
- (5, "N7", "N8", 1u64),
- (3, "N8", "N1", 1u64),
- (4, "N8", "N1", 2u64),
- ];
-
- for (ts, src, dst, p1_val) in edge_data {
- graph
- .add_edge(ts, src, dst, [("p1", Prop::U64(p1_val))], None)
- .unwrap();
- }
-
- graph
- }
-
- #[test]
- fn test_edges_filters() {
- // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
- let filter = EdgeFilter.property("p1").eq(1u64);
- let expected_results = vec!["N1->N2", "N3->N4", "N4->N5", "N6->N7", "N7->N8"];
- assert_filter_edges_results(
- init_graph,
- CachedGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- CachedGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_edges_filter_w() {
- let filter = EdgeFilter.property("p1").eq(1u64);
- let expected_results = vec!["N1->N2", "N3->N4", "N6->N7"];
- assert_filter_edges_results(
- init_graph,
- WindowedCachedGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowedCachedGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
- }
-
- #[test]
- fn test_edges_filters_pg_w() {
- // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
- let filter = EdgeFilter.property("p1").ge(2u64);
- let expected_results = vec!["N2->N3", "N5->N6", "N8->N1"];
- assert_filter_edges_results(
- init_graph,
- WindowedCachedGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![],
- );
- assert_search_edges_results(
- init_graph,
- WindowedCachedGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
- }
-}
diff --git a/raphtory-tests/tests/deletion_graph.rs b/raphtory-tests/tests/deletion_graph.rs
deleted file mode 100644
index 8b13789179..0000000000
--- a/raphtory-tests/tests/deletion_graph.rs
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/raphtory-tests/tests/filter_tests/cached_view.rs b/raphtory-tests/tests/filter_tests/cached_view.rs
new file mode 100644
index 0000000000..e77440ea5d
--- /dev/null
+++ b/raphtory-tests/tests/filter_tests/cached_view.rs
@@ -0,0 +1,193 @@
+use raphtory::{
+ db::{
+ api::view::StaticGraphViewOps,
+ graph::views::{cached_view::CachedView, window_graph::WindowedGraph},
+ },
+ prelude::{GraphViewOps, TimeOps},
+};
+use raphtory_tests::assertions::GraphTransformer;
+use std::ops::Range;
+
+struct CachedGraphTransformer;
+
+impl GraphTransformer for CachedGraphTransformer {
+ type Return = CachedView;
+ fn apply(&self, graph: G) -> Self::Return {
+ graph.cache_view()
+ }
+}
+
+struct WindowedCachedGraphTransformer(Range);
+
+impl GraphTransformer for WindowedCachedGraphTransformer {
+ type Return = WindowedGraph>;
+ fn apply(&self, graph: G) -> Self::Return {
+ graph.cache_view().window(self.0.start, self.0.end)
+ }
+}
+
+mod test_nodes_filters_cached_view_graph {
+ use raphtory::{
+ db::{
+ api::view::StaticGraphViewOps,
+ graph::views::filter::model::{
+ node_filter::NodeFilter, property_filter::ops::PropertyFilterOps,
+ PropertyFilterFactory,
+ },
+ },
+ prelude::AdditionOps,
+ };
+ use raphtory_api::core::entities::properties::prop::Prop;
+ use raphtory_tests::assertions::{
+ assert_filter_nodes_results, assert_search_nodes_results, TestGraphVariants, TestVariants,
+ };
+
+ use crate::filter_tests::cached_view::{
+ CachedGraphTransformer, WindowedCachedGraphTransformer,
+ };
+
+ use crate::filter_tests::{init_graph, Edges, Nodes};
+
+ #[test]
+ fn test_nodes_filters() {
+ let filter = NodeFilter.property("p1").eq(1u64);
+ let expected_results = vec!["N1", "N3", "N4", "N6", "N7"];
+ assert_filter_nodes_results(
+ |graph| init_graph(graph, Nodes::Typed, Edges::None),
+ CachedGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_nodes_results(
+ |graph| init_graph(graph, Nodes::Typed, Edges::None),
+ CachedGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ }
+
+ #[test]
+ fn test_nodes_filters_w() {
+ // TODO: Enable event_disk_graph for filter_nodes once bug fixed: https://github.com/Pometry/Raphtory/issues/2098
+ let filter = NodeFilter.property("p1").eq(1u64);
+ let expected_results = vec!["N1", "N3", "N6"];
+ assert_filter_nodes_results(
+ |graph| init_graph(graph, Nodes::Typed, Edges::None),
+ WindowedCachedGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ |graph| init_graph(graph, Nodes::Typed, Edges::None),
+ WindowedCachedGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ }
+
+ #[test]
+ fn test_nodes_filters_pg_w() {
+ let filter = NodeFilter.property("p1").ge(2u64);
+ let expected_results = vec!["N2", "N5", "N8"];
+ assert_filter_nodes_results(
+ |graph| init_graph(graph, Nodes::Typed, Edges::None),
+ WindowedCachedGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ |graph| init_graph(graph, Nodes::Typed, Edges::None),
+ WindowedCachedGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+}
+
+mod test_edges_filter_cached_view_graph {
+ use raphtory::{
+ db::api::view::StaticGraphViewOps,
+ prelude::{AdditionOps, EdgeFilter},
+ };
+ use raphtory_api::core::entities::properties::prop::Prop;
+ use raphtory_tests::assertions::{
+ assert_filter_edges_results, assert_search_edges_results, TestVariants,
+ };
+
+ use crate::filter_tests::cached_view::{
+ CachedGraphTransformer, WindowedCachedGraphTransformer,
+ };
+ use raphtory::db::graph::views::filter::model::{
+ property_filter::ops::PropertyFilterOps, PropertyFilterFactory,
+ };
+
+ use crate::filter_tests::{init_graph, Edges, Nodes};
+
+ #[test]
+ fn test_edges_filters() {
+ // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
+ let filter = EdgeFilter.property("p1").eq(1u64);
+ let expected_results = vec!["N1->N2", "N3->N4", "N4->N5", "N6->N7", "N7->N8"];
+ assert_filter_edges_results(
+ |graph| init_graph(graph, Nodes::None, Edges::Unlayered),
+ CachedGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ |graph| init_graph(graph, Nodes::None, Edges::Unlayered),
+ CachedGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_edges_filter_w() {
+ let filter = EdgeFilter.property("p1").eq(1u64);
+ let expected_results = vec!["N1->N2", "N3->N4", "N6->N7"];
+ assert_filter_edges_results(
+ |graph| init_graph(graph, Nodes::None, Edges::Unlayered),
+ WindowedCachedGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ |graph| init_graph(graph, Nodes::None, Edges::Unlayered),
+ WindowedCachedGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ }
+
+ #[test]
+ fn test_edges_filters_pg_w() {
+ // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
+ let filter = EdgeFilter.property("p1").ge(2u64);
+ let expected_results = vec!["N2->N3", "N5->N6", "N8->N1"];
+ assert_filter_edges_results(
+ |graph| init_graph(graph, Nodes::None, Edges::Unlayered),
+ WindowedCachedGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![],
+ );
+ assert_search_edges_results(
+ |graph| init_graph(graph, Nodes::None, Edges::Unlayered),
+ WindowedCachedGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+}
diff --git a/raphtory-tests/tests/edge_property_filter.rs b/raphtory-tests/tests/filter_tests/edge_property_filter.rs
similarity index 100%
rename from raphtory-tests/tests/edge_property_filter.rs
rename to raphtory-tests/tests/filter_tests/edge_property_filter.rs
diff --git a/raphtory-tests/tests/exploded_edge_property_filter.rs b/raphtory-tests/tests/filter_tests/exploded_edge_property_filter.rs
similarity index 100%
rename from raphtory-tests/tests/exploded_edge_property_filter.rs
rename to raphtory-tests/tests/filter_tests/exploded_edge_property_filter.rs
diff --git a/raphtory-tests/tests/filter_tests/mod.rs b/raphtory-tests/tests/filter_tests/mod.rs
new file mode 100644
index 0000000000..34d697ad40
--- /dev/null
+++ b/raphtory-tests/tests/filter_tests/mod.rs
@@ -0,0 +1,89 @@
+use raphtory::{db::api::view::StaticGraphViewOps, prelude::*};
+
+mod cached_view;
+mod edge_property_filter;
+mod node_property_filter;
+mod subgraph_tests;
+mod test_filters;
+mod test_layers;
+mod tests_node_type_filtered_subgraph;
+mod views_test;
+
+/// Whether [`init_graph`] adds nodes, and whether they carry a node type.
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub enum Nodes {
+ /// Don't add any nodes.
+ None,
+ /// Add nodes without a node type.
+ Untyped,
+ /// Add nodes with their node type (`air_nomad` / `water_tribe` / `fire_nation`).
+ Typed,
+}
+
+/// Whether [`init_graph`] adds edges, and whether they carry a layer.
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub enum Edges {
+ /// Don't add any edges.
+ None,
+ /// Add edges without a layer.
+ Unlayered,
+ /// Add edges with their layer (`layer1` / `layer2`).
+ Layered,
+}
+
+/// Builds the filter-test graph in the variations the different filter test modules use
+pub fn init_graph(graph: G, nodes: Nodes, edges: Edges) -> G {
+ if edges != Edges::None {
+ let edge_data = [
+ (6, "N1", "N2", 2u64, "layer1"),
+ (7, "N1", "N2", 1u64, "layer2"),
+ (6, "N2", "N3", 1u64, "layer1"),
+ (7, "N2", "N3", 2u64, "layer2"),
+ (8, "N3", "N4", 1u64, "layer1"),
+ (9, "N4", "N5", 1u64, "layer1"),
+ (5, "N5", "N6", 1u64, "layer1"),
+ (6, "N5", "N6", 2u64, "layer2"),
+ (5, "N6", "N7", 1u64, "layer1"),
+ (6, "N6", "N7", 1u64, "layer2"),
+ (3, "N7", "N8", 1u64, "layer1"),
+ (5, "N7", "N8", 1u64, "layer2"),
+ (3, "N8", "N1", 1u64, "layer1"),
+ (4, "N8", "N1", 2u64, "layer2"),
+ ];
+
+ for (ts, src, dst, p1, layer) in edge_data {
+ let layer = (edges == Edges::Layered).then_some(layer);
+ graph
+ .add_edge(ts, src, dst, [("p1", Prop::U64(p1))], layer)
+ .unwrap();
+ }
+ }
+
+ if nodes != Nodes::None {
+ let node_data = [
+ (6, "N1", 2u64, "air_nomad"),
+ (7, "N1", 1u64, "air_nomad"),
+ (6, "N2", 1u64, "water_tribe"),
+ (7, "N2", 2u64, "water_tribe"),
+ (8, "N3", 1u64, "air_nomad"),
+ (9, "N4", 1u64, "air_nomad"),
+ (5, "N5", 1u64, "air_nomad"),
+ (6, "N5", 2u64, "air_nomad"),
+ (5, "N6", 1u64, "fire_nation"),
+ (6, "N6", 1u64, "fire_nation"),
+ (3, "N7", 1u64, "air_nomad"),
+ (5, "N7", 1u64, "air_nomad"),
+ (3, "N8", 1u64, "fire_nation"),
+ (4, "N8", 2u64, "fire_nation"),
+ ];
+
+ for (ts, name, p1, node_type) in node_data {
+ let node_type = (nodes == Nodes::Typed).then_some(node_type);
+ graph
+ .add_node(ts, name, [("p1", Prop::U64(p1))], node_type, None)
+ .unwrap();
+ }
+ }
+
+ graph
+}
diff --git a/raphtory-tests/tests/node_property_filter.rs b/raphtory-tests/tests/filter_tests/node_property_filter.rs
similarity index 100%
rename from raphtory-tests/tests/node_property_filter.rs
rename to raphtory-tests/tests/filter_tests/node_property_filter.rs
diff --git a/raphtory-tests/tests/filter_tests/subgraph_tests.rs b/raphtory-tests/tests/filter_tests/subgraph_tests.rs
new file mode 100644
index 0000000000..edd1dfa9e5
--- /dev/null
+++ b/raphtory-tests/tests/filter_tests/subgraph_tests.rs
@@ -0,0 +1,320 @@
+use raphtory::{
+ db::{
+ api::view::StaticGraphViewOps,
+ graph::views::{node_subgraph::NodeSubgraph, window_graph::WindowedGraph},
+ },
+ prelude::{GraphViewOps, NodeViewOps, TimeOps},
+};
+use raphtory_tests::assertions::GraphTransformer;
+use std::ops::Range;
+
+struct NodeSubgraphTransformer(Option>);
+
+impl GraphTransformer for NodeSubgraphTransformer {
+ type Return = NodeSubgraph;
+ fn apply(&self, graph: G) -> Self::Return {
+ let node_names: Vec = self
+ .0
+ .clone()
+ .unwrap_or_else(|| graph.nodes().name().collect::>());
+ graph.subgraph(node_names)
+ }
+}
+
+struct WindowedNodeSubgraphTransformer(Option>, Range);
+
+impl GraphTransformer for WindowedNodeSubgraphTransformer {
+ type Return = NodeSubgraph>;
+ fn apply(&self, graph: G) -> Self::Return {
+ let graph = graph.window(self.1.start, self.1.end);
+ let node_names: Vec = self
+ .0
+ .clone()
+ .unwrap_or_else(|| graph.nodes().name().collect::>());
+ graph.subgraph(node_names)
+ }
+}
+
+mod test_nodes_filters_node_subgraph {
+ use crate::filter_tests::subgraph_tests::{
+ NodeSubgraphTransformer, WindowedNodeSubgraphTransformer,
+ };
+ use raphtory::{
+ db::{
+ api::view::StaticGraphViewOps,
+ graph::views::filter::model::{
+ property_filter::ops::PropertyFilterOps, PropertyFilterFactory,
+ },
+ },
+ prelude::{AdditionOps, NodeFilter},
+ };
+ use raphtory_api::core::entities::properties::prop::Prop;
+ use raphtory_tests::assertions::{
+ assert_filter_nodes_results, assert_search_nodes_results, TestGraphVariants, TestVariants,
+ };
+
+ use crate::filter_tests::{init_graph, Edges, Nodes};
+
+ #[test]
+ fn test_search_nodes_subgraph() {
+ let filter = NodeFilter.property("p1").eq(1u64);
+ let expected_results = ["N1", "N3", "N4", "N6", "N7"];
+ assert_filter_nodes_results(
+ |graph| init_graph(graph, Nodes::Untyped, Edges::None),
+ NodeSubgraphTransformer(None),
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ |graph| init_graph(graph, Nodes::Untyped, Edges::None),
+ NodeSubgraphTransformer(None),
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let node_names: Option> =
+ Some(vec!["N2".into(), "N3".into(), "N4".into(), "N5".into()]);
+ let filter = NodeFilter.property("p1").le(1u64);
+ let expected_results = vec!["N3", "N4"];
+ assert_filter_nodes_results(
+ |graph| init_graph(graph, Nodes::Untyped, Edges::None),
+ NodeSubgraphTransformer(node_names.clone()),
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ |graph| init_graph(graph, Nodes::Untyped, Edges::None),
+ NodeSubgraphTransformer(node_names),
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_search_nodes_subgraph_w() {
+ // TODO: Enable event_disk_graph for filter_nodes once bug fixed: https://github.com/Pometry/Raphtory/issues/2098
+ let filter = NodeFilter.property("p1").eq(1u64);
+ let expected_results = vec!["N1", "N3", "N6"];
+ assert_filter_nodes_results(
+ |graph| init_graph(graph, Nodes::Untyped, Edges::None),
+ WindowedNodeSubgraphTransformer(None, 6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ |graph| init_graph(graph, Nodes::Untyped, Edges::None),
+ WindowedNodeSubgraphTransformer(None, 6..9),
+ filter,
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+
+ let node_names: Option> = Some(vec!["N3".into()]);
+ let filter = NodeFilter.property("p1").gt(0u64);
+ let expected_results = vec!["N3"];
+ assert_filter_nodes_results(
+ |graph| init_graph(graph, Nodes::Untyped, Edges::None),
+ WindowedNodeSubgraphTransformer(node_names.clone(), 6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ |graph| init_graph(graph, Nodes::Untyped, Edges::None),
+ WindowedNodeSubgraphTransformer(node_names, 6..9),
+ filter,
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ }
+
+ #[test]
+ fn test_search_nodes_pg_w() {
+ let filter = NodeFilter.property("p1").eq(1u64);
+ let expected_results = vec!["N1", "N3", "N6", "N7"];
+ assert_filter_nodes_results(
+ |graph| init_graph(graph, Nodes::Untyped, Edges::None),
+ WindowedNodeSubgraphTransformer(None, 6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ |graph| init_graph(graph, Nodes::Untyped, Edges::None),
+ WindowedNodeSubgraphTransformer(None, 6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let node_names: Option> =
+ Some(vec!["N2".into(), "N3".into(), "N4".into(), "N5".into()]);
+ let filter = NodeFilter.property("p1").ge(1u64);
+ let expected_results = vec!["N2", "N3", "N5"];
+ assert_filter_nodes_results(
+ |graph| init_graph(graph, Nodes::Untyped, Edges::None),
+ WindowedNodeSubgraphTransformer(node_names.clone(), 6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ |graph| init_graph(graph, Nodes::Untyped, Edges::None),
+ WindowedNodeSubgraphTransformer(node_names, 6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+}
+
+mod test_edges_filters_node_subgraph {
+ use raphtory::{
+ db::{
+ api::view::StaticGraphViewOps,
+ graph::views::filter::model::{
+ property_filter::ops::PropertyFilterOps, PropertyFilterFactory,
+ },
+ },
+ prelude::{AdditionOps, EdgeFilter},
+ };
+ use raphtory_api::core::entities::properties::prop::Prop;
+ use raphtory_tests::assertions::{
+ assert_filter_edges_results, assert_search_edges_results, TestVariants,
+ };
+
+ use crate::filter_tests::subgraph_tests::{
+ NodeSubgraphTransformer, WindowedNodeSubgraphTransformer,
+ };
+
+ use crate::filter_tests::{init_graph, Edges, Nodes};
+
+ #[test]
+ fn test_edges_filters() {
+ // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph.
+ let filter = EdgeFilter.property("p1").eq(1u64);
+ let expected_results = vec!["N1->N2", "N3->N4", "N4->N5", "N6->N7", "N7->N8"];
+ assert_filter_edges_results(
+ |graph| init_graph(graph, Nodes::None, Edges::Unlayered),
+ NodeSubgraphTransformer(None),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ |graph| init_graph(graph, Nodes::None, Edges::Unlayered),
+ NodeSubgraphTransformer(None),
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let node_names: Option> =
+ Some(vec!["N2".into(), "N3".into(), "N4".into(), "N5".into()]);
+ let filter = EdgeFilter.property("p1").le(1u64);
+ let expected_results = vec!["N3->N4", "N4->N5"];
+ assert_filter_edges_results(
+ |graph| init_graph(graph, Nodes::None, Edges::Unlayered),
+ NodeSubgraphTransformer(node_names.clone()),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ |graph| init_graph(graph, Nodes::None, Edges::Unlayered),
+ NodeSubgraphTransformer(node_names),
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_edges_filters_w() {
+ let filter = EdgeFilter.property("p1").eq(1u64);
+ let expected_results = vec!["N1->N2", "N3->N4", "N6->N7"];
+ assert_filter_edges_results(
+ |graph| init_graph(graph, Nodes::None, Edges::Unlayered),
+ WindowedNodeSubgraphTransformer(None, 6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ |graph| init_graph(graph, Nodes::None, Edges::Unlayered),
+ WindowedNodeSubgraphTransformer(None, 6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ let node_names: Option> =
+ Some(vec!["N2".into(), "N3".into(), "N4".into(), "N5".into()]);
+ let filter = EdgeFilter.property("p1").ge(1u64);
+ let expected_results = vec!["N2->N3", "N3->N4"];
+ assert_filter_edges_results(
+ |graph| init_graph(graph, Nodes::None, Edges::Unlayered),
+ WindowedNodeSubgraphTransformer(node_names.clone(), 6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ |graph| init_graph(graph, Nodes::None, Edges::Unlayered),
+ WindowedNodeSubgraphTransformer(node_names, 6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ }
+
+ #[test]
+ fn test_edges_filters_pg_w() {
+ // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph.
+ let filter = EdgeFilter.property("p1").eq(1u64);
+ let expected_results = vec!["N1->N2", "N3->N4", "N6->N7", "N7->N8"];
+ assert_filter_edges_results(
+ |graph| init_graph(graph, Nodes::None, Edges::Unlayered),
+ WindowedNodeSubgraphTransformer(None, 6..9),
+ filter.clone(),
+ &expected_results,
+ vec![],
+ );
+ assert_search_edges_results(
+ |graph| init_graph(graph, Nodes::None, Edges::Unlayered),
+ WindowedNodeSubgraphTransformer(None, 6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let node_names: Option> = Some(vec![
+ "N2".into(),
+ "N3".into(),
+ "N4".into(),
+ "N5".into(),
+ "N6".into(),
+ ]);
+ let filter = EdgeFilter.property("p1").lt(2u64);
+ let expected_results = vec!["N3->N4"];
+ assert_filter_edges_results(
+ |graph| init_graph(graph, Nodes::None, Edges::Unlayered),
+ WindowedNodeSubgraphTransformer(node_names.clone(), 6..9),
+ filter.clone(),
+ &expected_results,
+ vec![],
+ );
+ assert_search_edges_results(
+ |graph| init_graph(graph, Nodes::None, Edges::Unlayered),
+ WindowedNodeSubgraphTransformer(node_names, 6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+}
diff --git a/raphtory-tests/tests/filter_tests/test_filters.rs b/raphtory-tests/tests/filter_tests/test_filters.rs
new file mode 100644
index 0000000000..78d9bd8adf
--- /dev/null
+++ b/raphtory-tests/tests/filter_tests/test_filters.rs
@@ -0,0 +1,13031 @@
+use raphtory::{db::api::view::StaticGraphViewOps, prelude::*};
+
+mod test_composite_filters {
+ use raphtory::{
+ db::graph::views::filter::model::{
+ edge_filter::EdgeFilter, filter::Filter, node_filter::NodeFilter,
+ property_filter::ops::PropertyFilterOps, PropertyFilterFactory,
+ },
+ prelude::IntoProp,
+ };
+ use raphtory_api::core::{entities::properties::prop::Prop, storage::arc_str::ArcStr};
+
+ #[test]
+ fn test_fuzzy_search() {
+ let filter = Filter::fuzzy_search("name", "pomet", 2, false);
+ assert!(filter.matches(Some("pometry")));
+
+ let filter = Filter::fuzzy_search("name", "shivam_kapoor", 2, false);
+ assert!(filter.matches(Some("shivam_kapoor2")));
+
+ let filter = Filter::fuzzy_search("name", "shivam kapoor", 2, false);
+ assert!(filter.matches(Some("shivam_kapoor2")));
+
+ let filter = Filter::fuzzy_search("name", "shivam kapoor", 2, false);
+ assert!(filter.matches(Some("shivam_kapoor2")));
+
+ let filter = Filter::fuzzy_search("name", "shivam kapoor", 2, false);
+ assert!(!filter.matches(Some("shivam1_kapoor2")));
+
+ let filter = Filter::fuzzy_search("name", "khivam sapoor", 2, false);
+ assert!(!filter.matches(Some("shivam1_kapoor2")));
+ }
+
+ #[test]
+ fn test_fuzzy_search_prefix_match() {
+ let filter = Filter::fuzzy_search("name", "pome", 2, false);
+ assert!(!filter.matches(Some("pometry")));
+
+ let filter = Filter::fuzzy_search("name", "pome", 2, true);
+ assert!(filter.matches(Some("pometry")));
+ }
+
+ #[test]
+ fn test_fuzzy_search_property() {
+ let filter = NodeFilter.property("prop").fuzzy_search("pomet", 2, false);
+ assert!(filter.matches(Some(&Prop::Str(ArcStr::from("pometry")))));
+ }
+
+ #[test]
+ fn test_fuzzy_search_property_prefix_match() {
+ let filter = EdgeFilter.property("prop").fuzzy_search("pome", 2, false);
+ assert!(!filter.matches(Some(&Prop::Str(ArcStr::from("pometry")))));
+
+ let filter = EdgeFilter.property("prop").fuzzy_search("pome", 2, true);
+ assert!(filter.matches(Some(&Prop::Str(ArcStr::from("pometry")))));
+ }
+
+ #[test]
+ fn test_contains_match() {
+ let filter = EdgeFilter.property("prop").contains("shivam");
+ let res = filter.matches(Some(&Prop::Str(ArcStr::from("shivam_kapoor"))));
+ assert!(res);
+ let res = filter.matches(None);
+ assert!(!res);
+
+ let filter = EdgeFilter.property("prop").contains("am_ka");
+ let res = filter.matches(Some(&Prop::Str(ArcStr::from("shivam_kapoor"))));
+ assert!(res);
+ }
+
+ #[test]
+ fn test_contains_not_match() {
+ let filter = NodeFilter.property("prop").not_contains("shivam");
+ let res = filter.matches(Some(&Prop::Str(ArcStr::from("shivam_kapoor"))));
+ assert!(!res);
+ let res = filter.matches(None);
+ assert!(!res);
+ }
+
+ #[test]
+ fn test_is_in_match() {
+ let filter = NodeFilter
+ .property("prop")
+ .is_in(vec!["shivam".into_prop()]);
+ let res = filter.matches(Some(&Prop::Str(ArcStr::from("shivam"))));
+ assert!(res);
+ let res = filter.matches(None);
+ assert!(!res);
+ }
+
+ #[test]
+ fn test_is_not_in_match() {
+ let filter = EdgeFilter
+ .property("prop")
+ .is_not_in(vec!["shivam".into_prop()]);
+ let res = filter.matches(Some(&Prop::Str(ArcStr::from("shivam"))));
+ assert!(!res);
+ let res = filter.matches(None);
+ assert!(!res);
+ }
+}
+
+use raphtory_api::core::entities::properties::prop::IntoProp;
+use raphtory_storage::mutation::{
+ addition_ops::InternalAdditionOps, property_addition_ops::InternalPropertyAdditionOps,
+};
+use raphtory_tests::assertions::GraphTransformer;
+
+struct IdentityGraphTransformer;
+
+impl GraphTransformer for IdentityGraphTransformer {
+ type Return = G;
+ fn apply(&self, graph: G) -> Self::Return {
+ graph
+ }
+}
+
+mod test_property_semantics {
+ mod test_node_property_filter_semantics {
+ use crate::filter_tests::test_filters::IdentityGraphTransformer;
+ use raphtory::{
+ db::{
+ api::view::{filter_ops::Filter, StaticGraphViewOps},
+ graph::views::filter::model::{
+ node_filter::NodeFilter, property_filter::ops::PropertyFilterOps,
+ PropertyFilterFactory, TemporalPropertyFilterFactory,
+ },
+ },
+ errors::GraphError,
+ prelude::*,
+ };
+ use raphtory_api::core::entities::properties::prop::Prop;
+ use raphtory_storage::mutation::{
+ addition_ops::InternalAdditionOps, property_addition_ops::InternalPropertyAdditionOps,
+ };
+ use raphtory_tests::assertions::{
+ assert_filter_nodes_results, assert_search_nodes_results, TestVariants,
+ };
+
+ fn init_graph(graph: G) -> G {
+ let nodes = [
+ (6, "N1", vec![("p1", Prop::U64(2u64))]),
+ (7, "N1", vec![("p1", Prop::U64(1u64))]),
+ (6, "N2", vec![("p1", Prop::U64(1u64))]),
+ (7, "N2", vec![("p1", Prop::U64(2u64))]),
+ (8, "N3", vec![("p1", Prop::U64(1u64))]),
+ (9, "N4", vec![("p1", Prop::U64(1u64))]),
+ (5, "N5", vec![("p1", Prop::U64(1u64))]),
+ (6, "N5", vec![("p1", Prop::U64(2u64))]),
+ (5, "N6", vec![("p1", Prop::U64(1u64))]),
+ (6, "N6", vec![("p1", Prop::U64(1u64))]),
+ (3, "N7", vec![("p1", Prop::U64(1u64))]),
+ (5, "N7", vec![("p1", Prop::U64(1u64))]),
+ (3, "N8", vec![("p1", Prop::U64(1u64))]),
+ (4, "N8", vec![("p1", Prop::U64(2u64))]),
+ (2, "N9", vec![("p1", Prop::U64(2u64))]),
+ (2, "N10", vec![("q1", Prop::U64(0u64))]),
+ (2, "N10", vec![("p1", Prop::U64(3u64))]),
+ (2, "N11", vec![("p1", Prop::U64(3u64))]),
+ (2, "N11", vec![("q1", Prop::U64(0u64))]),
+ (2, "N12", vec![("q1", Prop::U64(0u64))]),
+ (3, "N12", vec![("p1", Prop::U64(3u64))]),
+ (2, "N13", vec![("q1", Prop::U64(0u64))]),
+ (3, "N13", vec![("p1", Prop::U64(3u64))]),
+ (2, "N14", vec![("q1", Prop::U64(0u64))]),
+ (2, "N15", vec![]),
+ ];
+
+ for (id, label, props) in nodes.iter() {
+ graph
+ .add_node(*id, label, props.clone(), None, None)
+ .unwrap();
+ }
+
+ let metadata = [
+ ("N1", [("p1", Prop::U64(1u64))]),
+ ("N4", [("p1", Prop::U64(2u64))]),
+ ("N9", [("p1", Prop::U64(1u64))]),
+ ("N10", [("p1", Prop::U64(1u64))]),
+ ("N11", [("p1", Prop::U64(1u64))]),
+ ("N12", [("p1", Prop::U64(1u64))]),
+ ("N13", [("p1", Prop::U64(1u64))]),
+ ("N14", [("p1", Prop::U64(1u64))]),
+ ("N15", [("p1", Prop::U64(1u64))]),
+ ];
+
+ for (node, props) in metadata.iter() {
+ graph
+ .node(node)
+ .unwrap()
+ .add_metadata(props.clone())
+ .unwrap();
+ }
+
+ graph
+ }
+
+ fn init_graph_for_event_ids<
+ G: StaticGraphViewOps
+ + AdditionOps
+ + InternalAdditionOps
+ + InternalPropertyAdditionOps
+ + PropertyAdditionOps,
+ >(
+ graph: G,
+ ) -> G {
+ let graph: G = init_graph(graph);
+ let nodes = [
+ (1, "N16", vec![("p1", Prop::U64(2u64))]),
+ (1, "N16", vec![("p1", Prop::U64(1u64))]),
+ (1, "N17", vec![("p1", Prop::U64(1u64))]),
+ (1, "N17", vec![("p1", Prop::U64(2u64))]),
+ ];
+
+ for (id, label, props) in nodes.iter() {
+ graph
+ .add_node(*id, label, props.clone(), None, None)
+ .unwrap();
+ }
+
+ graph
+ }
+
+ #[test]
+ fn test_metadata_semantics() {
+ let filter = NodeFilter.metadata("p1").eq(1u64);
+ let expected_results = vec!["N1", "N10", "N11", "N12", "N13", "N14", "N15", "N9"];
+ assert_filter_nodes_results(
+ init_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_temporal_any_semantics() {
+ let filter = NodeFilter.property("p1").temporal().any().eq(1u64);
+ let expected_results = vec!["N1", "N2", "N3", "N4", "N5", "N6", "N7", "N8"];
+ assert_filter_nodes_results(
+ init_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_temporal_any_semantics_for_event_ids() {
+ let filter = NodeFilter.property("p1").temporal().any().eq(1u64);
+ let expected_results =
+ vec!["N1", "N16", "N17", "N2", "N3", "N4", "N5", "N6", "N7", "N8"];
+ assert_filter_nodes_results(
+ init_graph_for_event_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_graph_for_event_ids,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_temporal_latest_semantics() {
+ let filter = NodeFilter.property("p1").temporal().last().eq(1u64);
+ let expected_results = vec!["N1", "N3", "N4", "N6", "N7"];
+ assert_filter_nodes_results(
+ init_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_temporal_latest_semantics_for_event_ids() {
+ let filter = NodeFilter.property("p1").temporal().last().eq(1u64);
+ let expected_results = vec!["N1", "N16", "N3", "N4", "N6", "N7"];
+ assert_filter_nodes_results(
+ init_graph_for_event_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_graph_for_event_ids,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_property_semantics() {
+ // TODO: Const properties not supported for disk_graph.
+ let filter = NodeFilter.property("p1").eq(1u64);
+ let expected_results = vec!["N1", "N3", "N4", "N6", "N7"];
+ assert_filter_nodes_results(
+ init_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_property_semantics_for_event_ids() {
+ let filter = NodeFilter.property("p1").eq(1u64);
+ let expected_results = vec!["N1", "N16", "N3", "N4", "N6", "N7"];
+ assert_filter_nodes_results(
+ init_graph_for_event_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_graph_for_event_ids,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_property_semantics_only_metadata() {
+ // For this graph there won't be any temporal property index for property name "p1".
+ fn init_graph<
+ G: StaticGraphViewOps
+ + AdditionOps
+ + InternalAdditionOps
+ + InternalPropertyAdditionOps
+ + PropertyAdditionOps,
+ >(
+ graph: G,
+ ) -> G {
+ let nodes = [(2, "N1", vec![("q1", Prop::U64(0u64))]), (2, "N2", vec![])];
+
+ for (id, label, props) in nodes.iter() {
+ graph
+ .add_node(*id, label, props.clone(), None, None)
+ .unwrap();
+ }
+
+ let metadata = [
+ ("N1", [("p1", Prop::U64(1u64))]),
+ ("N2", [("p1", Prop::U64(1u64))]),
+ ];
+
+ for (node, props) in metadata.iter() {
+ graph
+ .node(node)
+ .unwrap()
+ .add_metadata(props.clone())
+ .unwrap();
+ }
+
+ graph
+ }
+
+ let filter = NodeFilter.property("p1").ge(1u64);
+ let graph = init_graph(Graph::new());
+ assert!(matches!(
+ graph.filter(filter.clone()).unwrap_err(),
+ GraphError::PropertyMissingError(ref name) if name == "p1"
+ ));
+ assert!(matches!(
+ graph.persistent_graph().filter(filter).unwrap_err(),
+ GraphError::PropertyMissingError(ref name) if name == "p1"
+ ));
+ }
+
+ #[test]
+ fn test_property_semantics_only_temporal() {
+ // For this graph there won't be any metadata index for property name "p1".
+ fn init_graph<
+ G: StaticGraphViewOps
+ + AdditionOps
+ + InternalAdditionOps
+ + InternalPropertyAdditionOps
+ + PropertyAdditionOps,
+ >(
+ graph: G,
+ ) -> G {
+ let nodes = [
+ (1, "N1", vec![("p1", Prop::U64(1u64))]),
+ (2, "N2", vec![("p1", Prop::U64(1u64))]),
+ (3, "N2", vec![("p1", Prop::U64(2u64))]),
+ (2, "N3", vec![("p1", Prop::U64(2u64))]),
+ (3, "N3", vec![("p1", Prop::U64(1u64))]),
+ (3, "N4", vec![]),
+ ];
+
+ for (id, label, props) in nodes.iter() {
+ graph
+ .add_node(*id, label, props.clone(), None, None)
+ .unwrap();
+ }
+
+ graph
+ }
+
+ let filter = NodeFilter.property("p1").le(1u64);
+ let expected_results = vec!["N1", "N3"];
+ assert_filter_nodes_results(
+ init_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+ }
+
+ mod test_edge_property_filter_semantics {
+ use crate::filter_tests::test_filters::IdentityGraphTransformer;
+ use raphtory::{
+ db::{
+ api::view::{filter_ops::Filter, EdgeViewOps, StaticGraphViewOps},
+ graph::views::filter::{
+ model::{
+ edge_filter::EdgeFilter, property_filter::ops::PropertyFilterOps,
+ PropertyFilterFactory, TemporalPropertyFilterFactory,
+ },
+ CreateFilter,
+ },
+ },
+ errors::GraphError,
+ prelude::*,
+ };
+ use raphtory_api::core::entities::properties::prop::Prop;
+ use raphtory_storage::mutation::{
+ addition_ops::InternalAdditionOps, property_addition_ops::InternalPropertyAdditionOps,
+ };
+ use raphtory_tests::assertions::{
+ assert_filter_edges_results, assert_search_edges_results, TestGraphVariants,
+ TestVariants, WindowGraphTransformer,
+ };
+
+ fn init_graph<
+ G: StaticGraphViewOps
+ + AdditionOps
+ + InternalAdditionOps
+ + InternalPropertyAdditionOps
+ + PropertyAdditionOps,
+ >(
+ graph: G,
+ ) -> G {
+ let edges = [
+ (6, "N1", "N2", vec![("p1", Prop::U64(2u64))]),
+ (7, "N1", "N2", vec![("p1", Prop::U64(1u64))]),
+ (6, "N2", "N3", vec![("p1", Prop::U64(1u64))]),
+ (7, "N2", "N3", vec![("p1", Prop::U64(2u64))]),
+ (8, "N3", "N4", vec![("p1", Prop::U64(1u64))]),
+ (9, "N4", "N5", vec![("p1", Prop::U64(1u64))]),
+ (5, "N5", "N6", vec![("p1", Prop::U64(1u64))]),
+ (6, "N5", "N6", vec![("p1", Prop::U64(2u64))]),
+ (5, "N6", "N7", vec![("p1", Prop::U64(1u64))]),
+ (6, "N6", "N7", vec![("p1", Prop::U64(1u64))]),
+ (3, "N7", "N8", vec![("p1", Prop::U64(1u64))]),
+ (5, "N7", "N8", vec![("p1", Prop::U64(1u64))]),
+ (3, "N8", "N9", vec![("p1", Prop::U64(1u64))]),
+ (4, "N8", "N9", vec![("p1", Prop::U64(2u64))]),
+ (2, "N9", "N10", vec![("p1", Prop::U64(2u64))]),
+ (2, "N10", "N11", vec![("q1", Prop::U64(0u64))]),
+ (2, "N10", "N11", vec![("p1", Prop::U64(3u64))]),
+ (2, "N11", "N12", vec![("p1", Prop::U64(3u64))]),
+ (2, "N11", "N12", vec![("q1", Prop::U64(0u64))]),
+ (2, "N12", "N13", vec![("q1", Prop::U64(0u64))]),
+ (3, "N12", "N13", vec![("p1", Prop::U64(3u64))]),
+ (2, "N13", "N14", vec![("q1", Prop::U64(0u64))]),
+ (3, "N13", "N14", vec![("p1", Prop::U64(3u64))]),
+ (2, "N14", "N15", vec![("q1", Prop::U64(0u64))]),
+ (2, "N15", "N1", vec![]),
+ ];
+
+ for (time, src, dst, props) in edges {
+ graph.add_edge(time, src, dst, props, None).unwrap();
+ }
+
+ let metadata_edges = [
+ ("N1", "N2", vec![("p1", Prop::U64(1u64))]),
+ ("N4", "N5", vec![("p1", Prop::U64(2u64))]),
+ ("N9", "N10", vec![("p1", Prop::U64(1u64))]),
+ ("N10", "N11", vec![("p1", Prop::U64(1u64))]),
+ ("N11", "N12", vec![("p1", Prop::U64(1u64))]),
+ ("N12", "N13", vec![("p1", Prop::U64(1u64))]),
+ ("N13", "N14", vec![("p1", Prop::U64(1u64))]),
+ ("N14", "N15", vec![("p1", Prop::U64(1u64))]),
+ ("N15", "N1", vec![("p1", Prop::U64(1u64))]),
+ ];
+
+ for (src, dst, props) in metadata_edges {
+ graph
+ .edge(src, dst)
+ .unwrap()
+ .add_metadata(props.clone(), None)
+ .unwrap();
+ }
+
+ graph
+ }
+
+ fn init_graph_for_event_ids<
+ G: StaticGraphViewOps
+ + AdditionOps
+ + InternalAdditionOps
+ + InternalPropertyAdditionOps
+ + PropertyAdditionOps,
+ >(
+ graph: G,
+ ) -> G {
+ let graph: G = init_graph(graph);
+ let edge_data = [
+ (1, "N16", "N15", vec![("p1", Prop::U64(2u64))]),
+ (1, "N16", "N15", vec![("p1", Prop::U64(1u64))]),
+ (1, "N17", "N16", vec![("p1", Prop::U64(1u64))]),
+ (1, "N17", "N16", vec![("p1", Prop::U64(2u64))]),
+ ];
+
+ for (time, src, dst, props) in edge_data {
+ graph.add_edge(time, src, dst, props, None).unwrap();
+ }
+
+ graph
+ }
+
+ #[test]
+ fn test_persistent_graph_first_window() {
+ fn init_graph<
+ G: StaticGraphViewOps
+ + AdditionOps
+ + InternalAdditionOps
+ + InternalPropertyAdditionOps
+ + PropertyAdditionOps,
+ >(
+ graph: G,
+ ) -> G {
+ graph
+ .add_edge(0, 1, 2, [("p1", Prop::U64(1u64))], None)
+ .unwrap();
+ graph
+ .add_edge(2, 1, 2, [("p1", Prop::U64(2u64))], None)
+ .unwrap();
+ graph
+ .add_edge(5, 1, 2, [("p1", Prop::U64(5u64))], None)
+ .unwrap();
+ graph
+ .add_edge(10, 1, 2, [("p1", Prop::U64(10u64))], None)
+ .unwrap();
+ graph
+ }
+
+ let filter = EdgeFilter.property("p1").temporal().first().eq(2u64);
+
+ // No window; means the first update is at time 0 and the value of p1 is expected to be 1u64.
+ let expected_empty = [];
+ let expected_found = ["1->2"];
+
+ assert_filter_edges_results(
+ init_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_empty,
+ vec![TestGraphVariants::PersistentGraph],
+ );
+ assert_search_edges_results(
+ init_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_empty,
+ TestVariants::PersistentOnly,
+ );
+
+ // Window(1,10); Expected emtpy because the first update is at time 0 and the value of p1 is expected to be 1u64.
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(1..10),
+ filter.clone(),
+ &expected_empty,
+ vec![TestGraphVariants::PersistentGraph],
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(1..10),
+ filter.clone(),
+ &expected_empty,
+ TestVariants::PersistentOnly,
+ );
+
+ // Window(2,10); Expected update at time 2 and the value of p1 is expected to be 2u64.
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(2..10),
+ filter.clone(),
+ &expected_found,
+ vec![TestGraphVariants::PersistentGraph],
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(2..10),
+ filter.clone(),
+ &expected_found,
+ TestVariants::PersistentOnly,
+ );
+
+ // Window(3,10); Expected update at time 2 (even if it is outside the window) and the value of p1 is expected to be 2u64.
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(3..10),
+ filter.clone(),
+ &expected_found,
+ vec![TestGraphVariants::PersistentGraph],
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(3..10),
+ filter.clone(),
+ &expected_found,
+ TestVariants::PersistentOnly,
+ );
+
+ // Window(4,10); Expected update at time 2 (even if it is outside the window) and the value of p1 is expected to be 2u64.
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(4..10),
+ filter.clone(),
+ &expected_found,
+ vec![TestGraphVariants::PersistentGraph],
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(4..10),
+ filter.clone(),
+ &expected_found,
+ TestVariants::PersistentOnly,
+ );
+
+ // Window(5,10); Expected update at time 5 (even if it is outside the window) and the value of p1 is expected to be 5u64.
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(5..10),
+ filter.clone(),
+ &expected_empty,
+ vec![TestGraphVariants::PersistentGraph],
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(5..10),
+ filter.clone(),
+ &expected_empty,
+ TestVariants::PersistentOnly,
+ );
+ }
+
+ #[test]
+ fn test_metadata_semantics() {
+ // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
+ // TODO: Const properties not supported for disk_graph.
+ let filter = EdgeFilter.metadata("p1").eq(1u64);
+ let expected_results = vec![
+ "N1->N2", "N10->N11", "N11->N12", "N12->N13", "N13->N14", "N14->N15", "N15->N1",
+ "N9->N10",
+ ];
+ assert_filter_edges_results(
+ init_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_edges_results(
+ init_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_metadata_semantics2() {
+ fn filter_edges(graph: &Graph, filter: impl CreateFilter) -> Vec {
+ let mut results = graph
+ .filter(filter)
+ .unwrap()
+ .edges()
+ .iter()
+ .map(|e| format!("{}->{}", e.src().name(), e.dst().name()))
+ .collect::>();
+ results.sort();
+ results
+ }
+
+ let graph = init_graph(Graph::new());
+
+ let filter = EdgeFilter.metadata("p1").eq(1u64);
+ assert_eq!(
+ filter_edges(&graph, filter.clone()),
+ vec![
+ "N1->N2", "N10->N11", "N11->N12", "N12->N13", "N13->N14", "N14->N15",
+ "N15->N1", "N9->N10"
+ ]
+ );
+
+ let edge = graph
+ .add_edge(1, "shivam", "kapoor", [("p1", 100u64)], Some("fire_nation"))
+ .unwrap();
+ edge.add_metadata([("z", true)], Some("fire_nation"))
+ .unwrap();
+ let prop = graph.edge("shivam", "kapoor").unwrap().metadata().get("z");
+ assert_eq!(prop, Some(Prop::map([("fire_nation", true)])));
+
+ let filter2 = EdgeFilter
+ .metadata("z")
+ .eq(Prop::map([("fire_nation", true)]));
+ assert_eq!(filter_edges(&graph, filter2), vec!["shivam->kapoor"]);
+
+ let filter = EdgeFilter
+ .metadata("p1")
+ .eq(Prop::map([("_default", 1u64)]));
+ assert_eq!(
+ filter_edges(&graph, filter),
+ vec![
+ "N1->N2", "N10->N11", "N11->N12", "N12->N13", "N13->N14", "N14->N15",
+ "N15->N1", "N9->N10"
+ ]
+ );
+ }
+
+ #[test]
+ fn test_temporal_any_semantics() {
+ // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
+ let filter = EdgeFilter.property("p1").temporal().any().eq(1u64);
+ let expected_results = vec![
+ "N1->N2", "N2->N3", "N3->N4", "N4->N5", "N5->N6", "N6->N7", "N7->N8", "N8->N9",
+ ];
+ assert_filter_edges_results(
+ init_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_temporal_any_semantics_for_event_ids() {
+ // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
+ let filter = EdgeFilter.property("p1").temporal().any().lt(2u64);
+ let expected_results = vec![
+ "N1->N2", "N16->N15", "N17->N16", "N2->N3", "N3->N4", "N4->N5", "N5->N6", "N6->N7",
+ "N7->N8", "N8->N9",
+ ];
+ assert_filter_edges_results(
+ init_graph_for_event_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph_for_event_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_temporal_latest_semantics() {
+ // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
+ let filter = EdgeFilter.property("p1").temporal().last().eq(1u64);
+ let expected_results = vec!["N1->N2", "N3->N4", "N4->N5", "N6->N7", "N7->N8"];
+ assert_filter_edges_results(
+ init_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_temporal_latest_semantics_for_event_ids() {
+ // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
+ let filter = EdgeFilter.property("p1").temporal().last().eq(1u64);
+ let expected_results =
+ vec!["N1->N2", "N16->N15", "N3->N4", "N4->N5", "N6->N7", "N7->N8"];
+ assert_filter_edges_results(
+ init_graph_for_event_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph_for_event_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_property_semantics() {
+ // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
+ let filter = EdgeFilter.property("p1").ge(2u64);
+ let expected_results = vec![
+ "N10->N11", "N11->N12", "N12->N13", "N13->N14", "N2->N3", "N5->N6", "N8->N9",
+ "N9->N10",
+ ];
+ assert_filter_edges_results(
+ init_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_property_semantics_for_event_ids() {
+ // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
+ // TODO: Const properties not supported for disk_graph.
+ let filter = EdgeFilter.property("p1").eq(1u64);
+ let expected_results =
+ vec!["N1->N2", "N16->N15", "N3->N4", "N4->N5", "N6->N7", "N7->N8"];
+ assert_filter_edges_results(
+ init_graph_for_event_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_edges_results(
+ init_graph_for_event_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_property_semantics_only_metadata() {
+ // For this graph there won't be any temporal property index for property name "p1".
+ fn init_graph<
+ G: StaticGraphViewOps
+ + AdditionOps
+ + InternalAdditionOps
+ + InternalPropertyAdditionOps
+ + PropertyAdditionOps,
+ >(
+ graph: G,
+ ) -> G {
+ let edges = [
+ (2, "N1", "N2", vec![("q1", Prop::U64(0u64))]),
+ (2, "N2", "N3", vec![]),
+ ];
+
+ for (time, src, dst, props) in edges {
+ graph.add_edge(time, src, dst, props, None).unwrap();
+ }
+
+ let metadata_edges = [
+ ("N1", "N2", vec![("p1", Prop::U64(1u64))]),
+ ("N2", "N3", vec![("p1", Prop::U64(1u64))]),
+ ];
+
+ for (src, dst, props) in metadata_edges {
+ graph
+ .edge(src, dst)
+ .unwrap()
+ .add_metadata(props.clone(), None)
+ .unwrap();
+ }
+
+ graph
+ }
+
+ let filter = EdgeFilter.property("p1").eq(1u64);
+ let graph = init_graph(Graph::new());
+ assert!(matches!(
+ graph.filter(filter.clone()).unwrap_err(),
+ GraphError::PropertyMissingError(ref name) if name == "p1"
+ ));
+ assert!(matches!(
+ graph.persistent_graph().filter(filter).unwrap_err(),
+ GraphError::PropertyMissingError(ref name) if name == "p1"
+ ));
+ }
+
+ #[test]
+ fn test_property_semantics_only_temporal() {
+ // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
+ // For this graph there won't be any metadata index for property name "p1".
+ fn init_graph<
+ G: StaticGraphViewOps
+ + AdditionOps
+ + InternalAdditionOps
+ + InternalPropertyAdditionOps
+ + PropertyAdditionOps,
+ >(
+ graph: G,
+ ) -> G {
+ let edges = [
+ (1, "N1", "N2", vec![("p1", Prop::U64(1u64))]),
+ (2, "N2", "N3", vec![("p1", Prop::U64(1u64))]),
+ (3, "N2", "N3", vec![("p1", Prop::U64(2u64))]),
+ (2, "N3", "N4", vec![("p1", Prop::U64(2u64))]),
+ (3, "N3", "N4", vec![("p1", Prop::U64(1u64))]),
+ (2, "N4", "N5", vec![]),
+ ];
+
+ for (time, src, dst, props) in edges {
+ graph.add_edge(time, src, dst, props, None).unwrap();
+ }
+
+ graph
+ }
+
+ let filter = EdgeFilter.property("p1").eq(1u64);
+ let expected_results = vec!["N1->N2", "N3->N4"];
+ assert_filter_edges_results(
+ init_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+ }
+}
+
+fn init_nodes_graph<
+ G: StaticGraphViewOps
+ + AdditionOps
+ + InternalAdditionOps
+ + InternalPropertyAdditionOps
+ + PropertyAdditionOps,
+>(
+ graph: G,
+) -> G {
+ let nodes = [
+ (
+ 1,
+ "1",
+ vec![
+ ("p1", "shivam_kapoor".into_prop()),
+ ("p9", 5u64.into_prop()),
+ ("p10", "Paper_airplane".into_prop()),
+ ("p20", "Gold_ship".into_prop()),
+ ("p30", "Gold_ship".into_prop()),
+ ("p40", 5u64.into_prop()),
+ ],
+ Some("fire_nation"),
+ ),
+ (
+ 2,
+ "2",
+ vec![
+ ("p1", "prop12".into_prop()),
+ ("p2", 2u64.into_prop()),
+ ("p10", "Paper_ship".into_prop()),
+ ("p20", "Gold_boat".into_prop()),
+ ("p30", "Old_boat".into_prop()),
+ ("p40", 10u64.into_prop()),
+ ],
+ Some("air_nomads"),
+ ),
+ (
+ 3,
+ "2",
+ vec![
+ ("p20", "Gold_ship".into_prop()),
+ ("p30", "Gold_ship".into_prop()),
+ ("p40", 15u64.into_prop()),
+ ],
+ Some("air_nomads"),
+ ),
+ (
+ 4,
+ "2",
+ vec![
+ ("p20", "Gold_ship".into_prop()),
+ ("p30", "Gold_ship".into_prop()),
+ ("p40", 20u64.into_prop()),
+ ],
+ Some("air_nomads"),
+ ),
+ (
+ 3,
+ "1",
+ vec![
+ ("p1", "shivam_kapoor".into_prop()),
+ ("p9", 5u64.into_prop()),
+ ("p20", "Gold_ship".into_prop()),
+ ("p30", "Gold_ship".into_prop()),
+ ("p40", 10u64.into_prop()),
+ ],
+ Some("fire_nation"),
+ ),
+ (
+ 3,
+ "3",
+ vec![
+ ("p2", 6u64.into_prop()),
+ ("p3", 1u64.into_prop()),
+ ("p10", "Paper_airplane".into_prop()),
+ ],
+ Some("fire_nation"),
+ ),
+ (
+ 4,
+ "1",
+ vec![
+ ("p1", "shivam_kapoor".into_prop()),
+ ("p9", 5u64.into_prop()),
+ ("p20", "Gold_ship".into_prop()),
+ ("p30", "Gold_ship".into_prop()),
+ ("p40", 15u64.into_prop()),
+ ],
+ Some("fire_nation"),
+ ),
+ (
+ 3,
+ "4",
+ vec![
+ ("p4", "pometry".into_prop()),
+ ("p20", "Gold_ship".into_prop()),
+ ("p30", "Gold_ship".into_prop()),
+ ],
+ None,
+ ),
+ (
+ 4,
+ "4",
+ vec![
+ ("p5", 12u64.into_prop()),
+ ("p20", "Gold_boat".into_prop()),
+ ("p30", "Old_ship".into_prop()),
+ ],
+ None,
+ ),
+ ];
+
+ for (time, id, props, node_type) in nodes {
+ graph.add_node(time, id, props, node_type, None).unwrap();
+ }
+
+ let metadata = [
+ (
+ "1",
+ vec![
+ ("m1", "pometry".into_prop()),
+ ("m2", "raphtory".into_prop()),
+ ],
+ ),
+ ("2", vec![("m1", "raphtory".into_prop())]),
+ (
+ "3",
+ vec![
+ ("m2", "pometry".into_prop()),
+ ("m3", "raphtory".into_prop()),
+ ],
+ ),
+ (
+ "4",
+ vec![
+ ("m3", "pometry".into_prop()),
+ ("m4", "raphtory".into_prop()),
+ ],
+ ),
+ ];
+
+ for (node_id, md) in metadata {
+ graph.node(node_id).unwrap().add_metadata(md).unwrap();
+ }
+
+ graph
+}
+
+fn init_nodes_graph_with_num_ids<
+ G: StaticGraphViewOps
+ + AdditionOps
+ + InternalAdditionOps
+ + InternalPropertyAdditionOps
+ + PropertyAdditionOps,
+>(
+ graph: G,
+) -> G {
+ let nodes = [
+ (
+ 1,
+ 1,
+ vec![
+ ("p1", "shivam_kapoor".into_prop()),
+ ("p9", 5u64.into_prop()),
+ ("p10", "Paper_airplane".into_prop()),
+ ("p20", "Gold_ship".into_prop()),
+ ("p30", "Gold_ship".into_prop()),
+ ("p40", 5u64.into_prop()),
+ ],
+ Some("fire_nation"),
+ ),
+ (
+ 2,
+ 2,
+ vec![
+ ("p1", "prop12".into_prop()),
+ ("p2", 2u64.into_prop()),
+ ("p10", "Paper_ship".into_prop()),
+ ("p20", "Gold_boat".into_prop()),
+ ("p30", "Old_boat".into_prop()),
+ ("p40", 10u64.into_prop()),
+ ],
+ Some("air_nomads"),
+ ),
+ (
+ 3,
+ 2,
+ vec![
+ ("p20", "Gold_ship".into_prop()),
+ ("p30", "Gold_ship".into_prop()),
+ ("p40", 15u64.into_prop()),
+ ],
+ Some("air_nomads"),
+ ),
+ (
+ 4,
+ 2,
+ vec![
+ ("p20", "Gold_ship".into_prop()),
+ ("p30", "Gold_ship".into_prop()),
+ ("p40", 20u64.into_prop()),
+ ],
+ Some("air_nomads"),
+ ),
+ (
+ 3,
+ 1,
+ vec![
+ ("p1", "shivam_kapoor".into_prop()),
+ ("p9", 5u64.into_prop()),
+ ("p20", "Gold_ship".into_prop()),
+ ("p30", "Gold_ship".into_prop()),
+ ("p40", 10u64.into_prop()),
+ ],
+ Some("fire_nation"),
+ ),
+ (
+ 3,
+ 3,
+ vec![
+ ("p2", 6u64.into_prop()),
+ ("p3", 1u64.into_prop()),
+ ("p10", "Paper_airplane".into_prop()),
+ ],
+ Some("fire_nation"),
+ ),
+ (
+ 4,
+ 1,
+ vec![
+ ("p1", "shivam_kapoor".into_prop()),
+ ("p9", 5u64.into_prop()),
+ ("p20", "Gold_ship".into_prop()),
+ ("p30", "Gold_ship".into_prop()),
+ ("p40", 15u64.into_prop()),
+ ],
+ Some("fire_nation"),
+ ),
+ (
+ 3,
+ 4,
+ vec![
+ ("p4", "pometry".into_prop()),
+ ("p20", "Gold_ship".into_prop()),
+ ("p30", "Gold_ship".into_prop()),
+ ],
+ None,
+ ),
+ (
+ 4,
+ 4,
+ vec![
+ ("p5", 12u64.into_prop()),
+ ("p20", "Gold_boat".into_prop()),
+ ("p30", "Old_ship".into_prop()),
+ ],
+ None,
+ ),
+ ];
+
+ for (time, id, props, node_type) in nodes {
+ graph.add_node(time, id, props, node_type, None).unwrap();
+ }
+
+ graph
+}
+
+fn init_nodes_graph_with_str_ids<
+ G: StaticGraphViewOps
+ + AdditionOps
+ + InternalAdditionOps
+ + InternalPropertyAdditionOps
+ + PropertyAdditionOps,
+>(
+ graph: G,
+) -> G {
+ let nodes = [
+ (1, "London", Some("fire_nation")),
+ (2, "Two", Some("air_nomads")),
+ (3, "Two", Some("air_nomads")),
+ (4, "Two", Some("air_nomads")),
+ (3, "London", Some("fire_nation")),
+ (3, "Tokyo", Some("fire_nation")),
+ (4, "London", Some("fire_nation")),
+ (3, "France Paris", None),
+ (4, "France Paris", None),
+ ];
+
+ for (time, id, node_type) in nodes {
+ graph.add_node(time, id, NO_PROPS, node_type, None).unwrap();
+ }
+
+ graph
+}
+
+fn init_edges_graph<
+ G: StaticGraphViewOps
+ + AdditionOps
+ + InternalAdditionOps
+ + InternalPropertyAdditionOps
+ + PropertyAdditionOps,
+>(
+ graph: G,
+) -> G {
+ let edges = [
+ (
+ 1,
+ "1",
+ "2",
+ vec![
+ ("p1", "shivam_kapoor".into_prop()),
+ ("p10", "Paper_airplane".into_prop()),
+ ("p20", "Gold_ship".into_prop()),
+ ("p30", "Gold_ship".into_prop()),
+ ],
+ Some("fire_nation"),
+ ),
+ (
+ 2,
+ "1",
+ "2",
+ vec![
+ ("p1", "shivam_kapoor".into_prop()),
+ ("p2", 4u64.into_prop()),
+ ("p20", "Gold_ship".into_prop()),
+ ("p30", "Gold_ship".into_prop()),
+ ],
+ Some("fire_nation"),
+ ),
+ (
+ 2,
+ "2",
+ "3",
+ vec![
+ ("p1", "prop12".into_prop()),
+ ("p2", 2u64.into_prop()),
+ ("p10", "Paper_ship".into_prop()),
+ ("p20", "Gold_boat".into_prop()),
+ ("p30", "Old_boat".into_prop()),
+ ],
+ Some("air_nomads"),
+ ),
+ (
+ 3,
+ "2",
+ "3",
+ vec![
+ ("p20", "Gold_ship".into_prop()),
+ ("p30", "Gold_boat".into_prop()),
+ ],
+ Some("air_nomads"),
+ ),
+ (
+ 3,
+ "3",
+ "1",
+ vec![("p2", 6u64.into_prop()), ("p3", 1u64.into_prop())],
+ Some("fire_nation"),
+ ),
+ (
+ 3,
+ "2",
+ "1",
+ vec![
+ ("p2", 6u64.into_prop()),
+ ("p3", 1u64.into_prop()),
+ ("p10", "Paper_airplane".into_prop()),
+ ],
+ None,
+ ),
+ (
+ 4,
+ "David Gilmour",
+ "John Mayer",
+ vec![("p2", 6u64.into_prop()), ("p3", 1u64.into_prop())],
+ None,
+ ),
+ (
+ 4,
+ "John Mayer",
+ "Jimmy Page",
+ vec![("p2", 6u64.into_prop()), ("p3", 1u64.into_prop())],
+ None,
+ ),
+ ];
+
+ for (time, src, dst, props, edge_type) in edges {
+ graph.add_edge(time, src, dst, props, edge_type).unwrap();
+ }
+
+ graph
+}
+
+fn init_edges_graph2<
+ G: StaticGraphViewOps
+ + AdditionOps
+ + InternalAdditionOps
+ + InternalPropertyAdditionOps
+ + PropertyAdditionOps,
+>(
+ graph: G,
+) -> G {
+ let edges = [
+ (
+ 1,
+ "1",
+ "2",
+ vec![
+ ("p1", "shivam_kapoor".into_prop()),
+ ("p2", 6u64.into_prop()),
+ ("p10", "Paper_airplane".into_prop()),
+ ("p20", "Gold_ship".into_prop()),
+ ],
+ Some("fire_nation"),
+ ),
+ (
+ 2,
+ "1",
+ "2",
+ vec![
+ ("p1", "shivam_kapoor".into_prop()),
+ ("p2", 7u64.into_prop()),
+ ("p10", "Gold_ship".into_prop()),
+ ("p20", "Gold_ship".into_prop()),
+ ],
+ Some("fire_nation"),
+ ),
+ (
+ 2,
+ "1",
+ "2",
+ vec![
+ ("p1", "shivam_kapoor".into_prop()),
+ ("p2", 4u64.into_prop()),
+ ("p20", "Gold_ship".into_prop()),
+ ],
+ Some("air_nomads"),
+ ),
+ (
+ 2,
+ "2",
+ "3",
+ vec![
+ ("p1", "prop12".into_prop()),
+ ("p2", 2u64.into_prop()),
+ ("p10", "Paper_ship".into_prop()),
+ ("p20", "Gold_boat".into_prop()),
+ ],
+ Some("air_nomads"),
+ ),
+ (
+ 3,
+ "2",
+ "3",
+ vec![
+ ("p20", "Gold_ship".into_prop()),
+ ("p30", "Gold_boat".into_prop()),
+ ],
+ Some("air_nomads"),
+ ),
+ (
+ 3,
+ "3",
+ "1",
+ vec![("p2", 6u64.into_prop()), ("p3", 1u64.into_prop())],
+ Some("air_nomads"),
+ ),
+ (
+ 3,
+ "2",
+ "1",
+ vec![
+ ("p2", 6u64.into_prop()),
+ ("p3", 1u64.into_prop()),
+ ("p10", "Paper_airplane".into_prop()),
+ ],
+ None,
+ ),
+ ];
+
+ for (time, src, dst, props, edge_type) in edges {
+ graph.add_edge(time, src, dst, props, edge_type).unwrap();
+ }
+
+ graph
+}
+
+fn init_edges_graph_with_num_ids<
+ G: StaticGraphViewOps
+ + AdditionOps
+ + InternalAdditionOps
+ + InternalPropertyAdditionOps
+ + PropertyAdditionOps,
+>(
+ graph: G,
+) -> G {
+ let edges = [
+ (
+ 1,
+ 1,
+ 2,
+ vec![
+ ("p1", "shivam_kapoor".into_prop()),
+ ("p10", "Paper_airplane".into_prop()),
+ ("p20", "Gold_ship".into_prop()),
+ ("p30", "Gold_ship".into_prop()),
+ ],
+ Some("fire_nation"),
+ ),
+ (
+ 2,
+ 1,
+ 2,
+ vec![
+ ("p1", "shivam_kapoor".into_prop()),
+ ("p2", 4u64.into_prop()),
+ ("p20", "Gold_ship".into_prop()),
+ ("p30", "Gold_ship".into_prop()),
+ ],
+ Some("fire_nation"),
+ ),
+ (
+ 2,
+ 2,
+ 3,
+ vec![
+ ("p1", "prop12".into_prop()),
+ ("p2", 2u64.into_prop()),
+ ("p10", "Paper_ship".into_prop()),
+ ("p20", "Gold_boat".into_prop()),
+ ("p30", "Old_boat".into_prop()),
+ ],
+ Some("air_nomads"),
+ ),
+ (
+ 3,
+ 2,
+ 3,
+ vec![
+ ("p20", "Gold_ship".into_prop()),
+ ("p30", "Gold_boat".into_prop()),
+ ],
+ Some("air_nomads"),
+ ),
+ (
+ 3,
+ 3,
+ 1,
+ vec![("p2", 6u64.into_prop()), ("p3", 1u64.into_prop())],
+ Some("fire_nation"),
+ ),
+ (
+ 3,
+ 2,
+ 1,
+ vec![
+ ("p2", 6u64.into_prop()),
+ ("p3", 1u64.into_prop()),
+ ("p10", "Paper_airplane".into_prop()),
+ ],
+ None,
+ ),
+ ];
+
+ for (time, src, dst, props, edge_type) in edges {
+ graph.add_edge(time, src, dst, props, edge_type).unwrap();
+ }
+
+ graph
+}
+
+fn init_edges_graph_with_str_ids<
+ G: StaticGraphViewOps
+ + AdditionOps
+ + InternalAdditionOps
+ + InternalPropertyAdditionOps
+ + PropertyAdditionOps,
+>(
+ graph: G,
+) -> G {
+ let edges = [
+ (1, "London", "Paris", Some("fire_nation")),
+ (2, "London", "Paris", Some("fire_nation")),
+ (2, "Two", "Three", Some("air_nomads")),
+ (3, "Two", "Three", Some("air_nomads")),
+ (3, "Three", "One", Some("fire_nation")),
+ (3, "Two", "One", None),
+ (4, "David Gilmour", "John Mayer", None),
+ (4, "John Mayer", "Jimmy Page", None),
+ ];
+
+ for (time, src, dst, edge_type) in edges {
+ graph.add_edge(time, src, dst, NO_PROPS, edge_type).unwrap();
+ }
+
+ graph
+}
+
+fn init_edges_graph_with_str_ids_del<
+ G: StaticGraphViewOps
+ + AdditionOps
+ + DeletionOps
+ + InternalAdditionOps
+ + InternalPropertyAdditionOps
+ + PropertyAdditionOps,
+>(
+ graph: G,
+) -> G {
+ let edges = [
+ (1, "London", "Paris", Some("fire_nation")),
+ (2, "London", "Paris", Some("fire_nation")),
+ (2, "Two", "Three", Some("air_nomads")),
+ (3, "Two", "Three", Some("air_nomads")),
+ (3, "Three", "One", Some("fire_nation")),
+ (3, "Two", "One", None),
+ (4, "David Gilmour", "John Mayer", None),
+ (4, "John Mayer", "Jimmy Page", None),
+ ];
+
+ for (time, src, dst, edge_type) in edges {
+ graph.add_edge(time, src, dst, NO_PROPS, edge_type).unwrap();
+ }
+
+ graph
+ .delete_edge(3, "London", "Paris", Some("fire_nation"))
+ .unwrap();
+
+ graph
+ .add_edge(5, "Bangalore", "Bangalore", NO_PROPS, None)
+ .unwrap();
+
+ graph
+}
+
+mod test_node_filter {
+ use crate::filter_tests::test_filters::{
+ init_nodes_graph, init_nodes_graph_with_num_ids, init_nodes_graph_with_str_ids,
+ IdentityGraphTransformer,
+ };
+ use proptest::proptest;
+ use raphtory::{
+ algorithms::alternating_mask::alternating_mask,
+ core::entities::VID,
+ db::{
+ api::view::{filter_ops::NodeSelect, Filter},
+ graph::views::filter::{
+ model::{
+ degree_filter::DegreeFilterFactory,
+ node_filter::ops::{NodeFilterOps, NodeIdFilterOps},
+ property_filter::ops::{ElemQualifierOps, ListAggOps, PropertyFilterOps},
+ ComposableFilter, CompositeNodeFilter, NodeViewFilterOps,
+ PropertyFilterFactory, TryAsCompositeFilter, ViewWrapOps,
+ },
+ CreateFilter,
+ },
+ },
+ errors::GraphError,
+ prelude::{
+ AdditionOps, Graph, GraphViewOps, IntoProp, NodeFilter, NodeStateOps, NodeViewOps,
+ TimeOps, NO_PROPS,
+ },
+ };
+ use raphtory_api::core::{entities::properties::prop::Prop, Direction};
+ use raphtory_tests::assertions::{
+ assert_filter_nodes_results, assert_search_nodes_results, assert_select_nodes_results,
+ TestVariants,
+ };
+
+ fn sort_vids(mut vids: Vec) -> Vec {
+ vids.sort();
+ vids
+ }
+
+ fn candidates_with_history_after_filtering<'a, G: GraphViewOps<'a>>(
+ graph: &G,
+ candidate_nodes: Vec,
+ ) -> Vec {
+ let subgraph = graph.subgraph(candidate_nodes);
+ sort_vids(
+ subgraph
+ .nodes()
+ .into_iter()
+ .filter(|n| !n.history().is_empty())
+ .map(|n| n.node)
+ .collect(),
+ )
+ }
+
+ fn assert_filter(
+ graph: &Graph,
+ filter: CF,
+ metric: Direction,
+ manual_expr: F,
+ context: &str,
+ ) where
+ CF: CreateFilter + TryAsCompositeFilter + Clone,
+ F: Fn(usize) -> bool + Copy,
+ {
+ let expected_select_nodes = graph
+ .nodes()
+ .into_iter()
+ .filter(|n| {
+ manual_expr(match metric {
+ Direction::BOTH => n.degree(),
+ Direction::IN => n.in_degree(),
+ Direction::OUT => n.out_degree(),
+ })
+ })
+ .map(|n| n.node)
+ .collect::>();
+
+ let expected_filter_nodes =
+ candidates_with_history_after_filtering(graph, expected_select_nodes.clone());
+
+ let filtered_event_graph = graph.filter(filter.clone()).unwrap();
+ let filtered_event_nodes = sort_vids(
+ filtered_event_graph
+ .nodes()
+ .into_iter()
+ .map(|n| n.node)
+ .collect(),
+ );
+ assert_eq!(
+ filtered_event_nodes, expected_filter_nodes,
+ "{} failed for event graph",
+ context
+ );
+
+ let selected_event_nodes = sort_vids(
+ graph
+ .nodes()
+ .select(filter.clone())
+ .unwrap()
+ .into_iter()
+ .map(|n| n.node)
+ .collect(),
+ );
+ assert_eq!(
+ selected_event_nodes, expected_select_nodes,
+ "{} failed for event graph select",
+ context
+ );
+
+ let filtered_persistent_graph = graph.persistent_graph().filter(filter.clone()).unwrap();
+ let filtered_persistent_nodes = sort_vids(
+ filtered_persistent_graph
+ .nodes()
+ .into_iter()
+ .map(|n| n.node)
+ .collect(),
+ );
+ assert_eq!(
+ filtered_persistent_nodes, expected_filter_nodes,
+ "{} failed for persistent graph",
+ context
+ );
+
+ let selected_persistent_nodes = sort_vids(
+ graph
+ .persistent_graph()
+ .nodes()
+ .select(filter)
+ .unwrap()
+ .into_iter()
+ .map(|n| n.node)
+ .collect(),
+ );
+ assert_eq!(
+ selected_persistent_nodes, expected_select_nodes,
+ "{} failed for persistent graph select",
+ context
+ );
+ }
+
+ fn degree_graph_with_add_node_and_add_edge() -> Graph {
+ let graph = degree_graph_with_add_edge_only();
+ let add_nodes = [
+ (0, "1", Some("layer_a")),
+ (0, "7", None),
+ (0, "8", None),
+ (3, "9", Some("layer_a")),
+ (4, "9", Some("layer_c")),
+ (5, "10", Some("layer_b")),
+ (6, "10", Some("layer_e")),
+ (7, "11", Some("layer_d")),
+ (8, "12", Some("layer_f")),
+ (9, "12", Some("layer_c")),
+ ];
+ for (t, id, layer) in add_nodes {
+ graph.add_node(t, id, NO_PROPS, None, layer).unwrap();
+ }
+ graph
+ }
+
+ fn degree_graph_with_add_edge_only() -> Graph {
+ let graph = Graph::new();
+
+ let edges = [
+ (1, "1", "2", "layer_a"),
+ (1, "1", "3", "layer_b"),
+ (1, "1", "4", "layer_a"),
+ (1, "1", "5", "layer_b"),
+ (1, "1", "6", "layer_a"),
+ (2, "2", "1", "layer_b"),
+ (2, "2", "3", "layer_a"),
+ (2, "2", "4", "layer_b"),
+ (2, "2", "5", "layer_a"),
+ (3, "3", "1", "layer_a"),
+ (3, "3", "4", "layer_b"),
+ (3, "3", "5", "layer_a"),
+ (4, "4", "1", "layer_b"),
+ (4, "4", "2", "layer_a"),
+ (5, "5", "1", "layer_b"),
+ (6, "6", "1", "layer_a"),
+ (6, "4", "3", "layer_b"),
+ (6, "5", "2", "layer_a"),
+ (6, "6", "2", "layer_b"),
+ (6, "5", "3", "layer_a"),
+ (7, "2", "6", "layer_c"),
+ (7, "3", "6", "layer_d"),
+ (7, "6", "4", "layer_e"),
+ (7, "1", "5", "layer_f"),
+ (8, "3", "2", "layer_c"),
+ (8, "4", "6", "layer_d"),
+ (8, "2", "5", "layer_e"),
+ (8, "6", "3", "layer_f"),
+ (9, "5", "4", "layer_c"),
+ (9, "4", "5", "layer_d"),
+ (9, "2", "4", "layer_e"),
+ (9, "3", "1", "layer_f"),
+ ];
+ for (t, src, dst, layer) in edges {
+ graph.add_edge(t, src, dst, NO_PROPS, Some(layer)).unwrap();
+ }
+
+ graph
+ }
+
+ // Property-based tests for degree filtering
+ proptest! {
+ #[test]
+ fn prop_degree_filter_both_direction_comparison(threshold in 0u64..15) {
+ let graph = degree_graph_with_add_node_and_add_edge();
+
+ assert_filter(
+ &graph,
+ NodeFilter.degree().lt(threshold),
+ Direction::BOTH,
+ |d| d < threshold as usize,
+ &format!("BOTH < {}", threshold),
+ );
+
+ assert_filter(
+ &graph,
+ NodeFilter.degree().le(threshold),
+ Direction::BOTH,
+ |d| d <= threshold as usize,
+ &format!("BOTH <= {}", threshold),
+ );
+
+ assert_filter(
+ &graph,
+ NodeFilter.degree().eq(threshold),
+ Direction::BOTH,
+ |d| d == threshold as usize,
+ &format!("BOTH == {}", threshold),
+ );
+
+ assert_filter(
+ &graph,
+ NodeFilter.degree().ne(threshold),
+ Direction::BOTH,
+ |d| d != threshold as usize,
+ &format!("BOTH != {}", threshold),
+ );
+
+ assert_filter(
+ &graph,
+ NodeFilter.degree().ge(threshold),
+ Direction::BOTH,
+ |d| d >= threshold as usize,
+ &format!("BOTH >= {}", threshold),
+ );
+
+ assert_filter(
+ &graph,
+ NodeFilter.degree().gt(threshold),
+ Direction::BOTH,
+ |d| d > threshold as usize,
+ &format!("BOTH > {}", threshold),
+ );
+ }
+
+ #[test]
+ fn prop_degree_filter_in_direction_comparison(threshold in 0u64..15) {
+ let graph = degree_graph_with_add_node_and_add_edge();
+
+ assert_filter(
+ &graph,
+ NodeFilter.in_degree().lt(threshold),
+ Direction::IN,
+ |d| d < threshold as usize,
+ &format!("IN < {}", threshold),
+ );
+
+ assert_filter(
+ &graph,
+ NodeFilter.in_degree().le(threshold),
+ Direction::IN,
+ |d| d <= threshold as usize,
+ &format!("IN <= {}", threshold),
+ );
+
+ assert_filter(
+ &graph,
+ NodeFilter.in_degree().eq(threshold),
+ Direction::IN,
+ |d| d == threshold as usize,
+ &format!("IN == {}", threshold),
+ );
+
+ assert_filter(
+ &graph,
+ NodeFilter.in_degree().ne(threshold),
+ Direction::IN,
+ |d| d != threshold as usize,
+ &format!("IN != {}", threshold),
+ );
+
+ assert_filter(
+ &graph,
+ NodeFilter.in_degree().ge(threshold),
+ Direction::IN,
+ |d| d >= threshold as usize,
+ &format!("IN >= {}", threshold),
+ );
+
+ assert_filter(
+ &graph,
+ NodeFilter.in_degree().gt(threshold),
+ Direction::IN,
+ |d| d > threshold as usize,
+ &format!("IN > {}", threshold),
+ );
+ }
+
+ #[test]
+ fn prop_degree_filter_out_direction_comparison(threshold in 0u64..15) {
+ let graph = degree_graph_with_add_node_and_add_edge();
+
+ assert_filter(
+ &graph,
+ NodeFilter.out_degree().lt(threshold),
+ Direction::OUT,
+ |d| d < threshold as usize,
+ &format!("OUT < {}", threshold),
+ );
+
+ assert_filter(
+ &graph,
+ NodeFilter.out_degree().le(threshold),
+ Direction::OUT,
+ |d| d <= threshold as usize,
+ &format!("OUT <= {}", threshold),
+ );
+
+ assert_filter(
+ &graph,
+ NodeFilter.out_degree().eq(threshold),
+ Direction::OUT,
+ |d| d == threshold as usize,
+ &format!("OUT == {}", threshold),
+ );
+
+ assert_filter(
+ &graph,
+ NodeFilter.out_degree().ne(threshold),
+ Direction::OUT,
+ |d| d != threshold as usize,
+ &format!("OUT != {}", threshold),
+ );
+
+ assert_filter(
+ &graph,
+ NodeFilter.out_degree().ge(threshold),
+ Direction::OUT,
+ |d| d >= threshold as usize,
+ &format!("OUT >= {}", threshold),
+ );
+
+ assert_filter(
+ &graph,
+ NodeFilter.out_degree().gt(threshold),
+ Direction::OUT,
+ |d| d > threshold as usize,
+ &format!("OUT > {}", threshold),
+ );
+ }
+
+ #[test]
+ fn prop_degree_filter_and(threshold in 0u64..15) {
+ let graph = degree_graph_with_add_node_and_add_edge();
+
+ assert_filter(
+ &graph,
+ NodeFilter.degree().gt(threshold).and(NodeFilter.degree().lt(threshold + 5)),
+ Direction::BOTH,
+ |d| d > threshold as usize && d < (threshold + 5) as usize,
+ &format!("BOTH > {} AND BOTH < {}", threshold, threshold + 5),
+ );
+
+ assert_filter(
+ &graph,
+ NodeFilter.in_degree().gt(threshold).and(NodeFilter.in_degree().lt(threshold + 5)),
+ Direction::IN,
+ |d| d > threshold as usize && d < (threshold + 5) as usize,
+ &format!("IN > {} AND IN < {}", threshold, threshold + 5),
+ );
+
+ assert_filter(
+ &graph,
+ NodeFilter.out_degree().gt(threshold).and(NodeFilter.out_degree().lt(threshold + 5)),
+ Direction::OUT,
+ |d| d > threshold as usize && d < (threshold + 5) as usize,
+ &format!("OUT > {} AND OUT < {}", threshold, threshold + 5),
+ );
+ }
+
+ #[test]
+ fn prop_degree_filter_or(threshold in 0u64..15) {
+ let graph = degree_graph_with_add_node_and_add_edge();
+
+ assert_filter(
+ &graph,
+ NodeFilter.degree().lt(threshold).or(NodeFilter.degree().gt(threshold + 5)),
+ Direction::BOTH,
+ |d| d < threshold as usize || d > (threshold + 5) as usize,
+ &format!("BOTH < {} OR BOTH > {}", threshold, threshold + 5),
+ );
+
+ assert_filter(
+ &graph,
+ NodeFilter.in_degree().lt(threshold).or(NodeFilter.in_degree().gt(threshold + 5)),
+ Direction::IN,
+ |d| d < threshold as usize || d > (threshold + 5) as usize,
+ &format!("IN < {} OR IN > {}", threshold, threshold + 5),
+ );
+
+ assert_filter(
+ &graph,
+ NodeFilter.out_degree().lt(threshold).or(NodeFilter.out_degree().gt(threshold + 5)),
+ Direction::OUT,
+ |d| d < threshold as usize || d > (threshold + 5) as usize,
+ &format!("OUT < {} OR OUT > {}", threshold, threshold + 5),
+ );
+ }
+
+ #[test]
+ fn prop_degree_filter_not(threshold in 0u64..15) {
+ let graph = degree_graph_with_add_node_and_add_edge();
+
+ assert_filter(
+ &graph,
+ NodeFilter.degree().lt(threshold).or(NodeFilter.degree().gt(threshold + 5).not()),
+ Direction::BOTH,
+ |d| d < threshold as usize || d <= (threshold + 5) as usize,
+ &format!("BOTH < {} OR BOTH > {}", threshold, threshold + 5),
+ );
+
+ assert_filter(
+ &graph,
+ NodeFilter.in_degree().lt(threshold).or(NodeFilter.in_degree().gt(threshold + 5).not()),
+ Direction::IN,
+ |d| d < threshold as usize || d <= (threshold + 5) as usize,
+ &format!("IN < {} OR IN > {}", threshold, threshold + 5),
+ );
+
+ assert_filter(
+ &graph,
+ NodeFilter.out_degree().lt(threshold).or(NodeFilter.out_degree().gt(threshold + 5).not()),
+ Direction::OUT,
+ |d| d < threshold as usize || d <= (threshold + 5) as usize,
+ &format!("OUT < {} OR OUT > {}", threshold, threshold + 5),
+ );
+ }
+
+ #[test]
+ fn prop_degree_filter_is_in(val1 in 0u64..15, val2 in 0u64..15) {
+ let graph = degree_graph_with_add_node_and_add_edge();
+ let set = [val1, val2];
+
+ assert_filter(
+ &graph,
+ NodeFilter.degree().is_in(vec![Prop::U64(val1), Prop::U64(val2)]),
+ Direction::BOTH,
+ |d| set.contains(&(d as u64)),
+ &format!("BOTH is_in({}, {})", val1, val2),
+ );
+
+ assert_filter(
+ &graph,
+ NodeFilter.in_degree().is_in(vec![Prop::U64(val1), Prop::U64(val2)]),
+ Direction::IN,
+ |d| set.contains(&(d as u64)),
+ &format!("IN is_in({}, {})", val1, val2),
+ );
+
+ assert_filter(
+ &graph,
+ NodeFilter.out_degree().is_in(vec![Prop::U64(val1), Prop::U64(val2)]),
+ Direction::OUT,
+ |d| set.contains(&(d as u64)),
+ &format!("OUT is_in({}, {})", val1, val2),
+ );
+ }
+
+ #[test]
+ fn prop_degree_filter_is_not_in(val1 in 0u64..15, val2 in 0u64..15) {
+ let graph = degree_graph_with_add_node_and_add_edge();
+ let set = [val1, val2];
+
+ assert_filter(
+ &graph,
+ NodeFilter
+ .degree()
+ .is_not_in(vec![Prop::U64(val1), Prop::U64(val2)]),
+ Direction::BOTH,
+ |d| !set.contains(&(d as u64)),
+ &format!("BOTH is_not_in({}, {})", val1, val2),
+ );
+
+ assert_filter(
+ &graph,
+ NodeFilter
+ .in_degree()
+ .is_not_in(vec![Prop::U64(val1), Prop::U64(val2)]),
+ Direction::IN,
+ |d| !set.contains(&(d as u64)),
+ &format!("IN is_not_in({}, {})", val1, val2),
+ );
+
+ assert_filter(
+ &graph,
+ NodeFilter
+ .out_degree()
+ .is_not_in(vec![Prop::U64(val1), Prop::U64(val2)]),
+ Direction::OUT,
+ |d| !set.contains(&(d as u64)),
+ &format!("OUT is_not_in({}, {})", val1, val2),
+ );
+ }
+ }
+
+ #[test]
+ fn test_degree_filter_with_invalid_expressions() {
+ let graph = degree_graph_with_add_node_and_add_edge();
+ let invalid_filters = vec![
+ NodeFilter.degree().is_none(),
+ NodeFilter.degree().is_some(),
+ NodeFilter.degree().starts_with("1"),
+ NodeFilter.degree().ends_with("1"),
+ NodeFilter.degree().contains("1"),
+ NodeFilter.degree().not_contains("1"),
+ NodeFilter.degree().fuzzy_search("1", 1, false),
+ NodeFilter.in_degree().is_none(),
+ NodeFilter.in_degree().is_some(),
+ NodeFilter.in_degree().starts_with("1"),
+ NodeFilter.in_degree().ends_with("1"),
+ NodeFilter.in_degree().contains("1"),
+ NodeFilter.in_degree().not_contains("1"),
+ NodeFilter.in_degree().fuzzy_search("1", 1, false),
+ NodeFilter.out_degree().is_none(),
+ NodeFilter.out_degree().is_some(),
+ NodeFilter.out_degree().starts_with("1"),
+ NodeFilter.out_degree().ends_with("1"),
+ NodeFilter.out_degree().contains("1"),
+ NodeFilter.out_degree().not_contains("1"),
+ NodeFilter.out_degree().fuzzy_search("1", 1, false),
+ NodeFilter.degree().any().eq(1u64),
+ NodeFilter.degree().all().eq(1u64),
+ NodeFilter.degree().len().gt(0u64),
+ NodeFilter.degree().sum().eq(1u64),
+ NodeFilter.degree().avg().eq(1u64),
+ NodeFilter.degree().min().eq(1u64),
+ NodeFilter.degree().max().eq(1u64),
+ NodeFilter.degree().first().eq(1u64),
+ NodeFilter.degree().last().eq(1u64),
+ NodeFilter.in_degree().any().eq(1u64),
+ NodeFilter.in_degree().all().eq(1u64),
+ NodeFilter.in_degree().len().gt(0u64),
+ NodeFilter.in_degree().sum().eq(1u64),
+ NodeFilter.in_degree().avg().eq(1u64),
+ NodeFilter.in_degree().min().eq(1u64),
+ NodeFilter.in_degree().max().eq(1u64),
+ NodeFilter.in_degree().first().eq(1u64),
+ NodeFilter.in_degree().last().eq(1u64),
+ NodeFilter.out_degree().any().eq(1u64),
+ NodeFilter.out_degree().all().eq(1u64),
+ NodeFilter.out_degree().len().gt(0u64),
+ NodeFilter.out_degree().sum().eq(1u64),
+ NodeFilter.out_degree().avg().eq(1u64),
+ NodeFilter.out_degree().min().eq(1u64),
+ NodeFilter.out_degree().max().eq(1u64),
+ NodeFilter.out_degree().first().eq(1u64),
+ NodeFilter.out_degree().last().eq(1u64),
+ ];
+
+ for filter in invalid_filters {
+ assert!(
+ matches!(graph.filter(filter), Err(GraphError::InvalidFilter(_))),
+ "expected InvalidFilter for unsupported degree filter operation"
+ );
+ }
+ }
+
+ proptest! {
+ #[test]
+ fn prop_degree_filter_with_string_threshold(threshold in 0u64..15) {
+ let graph = degree_graph_with_add_node_and_add_edge();
+ let threshold_str = threshold.to_string();
+ let parsed_str = threshold_str.parse::().unwrap();
+
+ assert_filter(&graph, NodeFilter.degree().lt(threshold_str.clone()), Direction::BOTH, |d| d < parsed_str as usize, "BOTH < string threshold parsed to u64");
+ assert_filter(&graph, NodeFilter.degree().le(threshold_str.clone()), Direction::BOTH, |d| d <= parsed_str as usize, "BOTH <= string threshold parsed to u64");
+ assert_filter(&graph, NodeFilter.degree().eq(threshold_str.clone()), Direction::BOTH, |d| d == parsed_str as usize, "BOTH == string threshold parsed to u64");
+ assert_filter(&graph, NodeFilter.degree().ne(threshold_str.clone()), Direction::BOTH, |d| d != parsed_str as usize, "BOTH != string threshold parsed to u64");
+ assert_filter(&graph, NodeFilter.degree().ge(threshold_str.clone()), Direction::BOTH, |d| d >= parsed_str as usize, "BOTH >= string threshold parsed to u64");
+ assert_filter(&graph, NodeFilter.degree().gt(threshold_str.clone()), Direction::BOTH, |d| d > parsed_str as usize, "BOTH > string threshold parsed to u64");
+
+ assert_filter(&graph, NodeFilter.in_degree().lt(threshold_str.clone()), Direction::IN, |d| d < parsed_str as usize, "IN < string threshold parsed to u64");
+ assert_filter(&graph, NodeFilter.in_degree().le(threshold_str.clone()), Direction::IN, |d| d <= parsed_str as usize, "IN <= string threshold parsed to u64");
+ assert_filter(&graph, NodeFilter.in_degree().eq(threshold_str.clone()), Direction::IN, |d| d == parsed_str as usize, "IN == string threshold parsed to u64");
+ assert_filter(&graph, NodeFilter.in_degree().ne(threshold_str.clone()), Direction::IN, |d| d != parsed_str as usize, "IN != string threshold parsed to u64");
+ assert_filter(&graph, NodeFilter.in_degree().ge(threshold_str.clone()), Direction::IN, |d| d >= parsed_str as usize, "IN >= string threshold parsed to u64");
+ assert_filter(&graph, NodeFilter.in_degree().gt(threshold_str.clone()), Direction::IN, |d| d > parsed_str as usize, "IN > string threshold parsed to u64");
+
+ assert_filter(&graph, NodeFilter.out_degree().lt(threshold_str.clone()), Direction::OUT, |d| d < parsed_str as usize, "OUT < string threshold parsed to u64");
+ assert_filter(&graph, NodeFilter.out_degree().le(threshold_str.clone()), Direction::OUT, |d| d <= parsed_str as usize, "OUT <= string threshold parsed to u64");
+ assert_filter(&graph, NodeFilter.out_degree().eq(threshold_str.clone()), Direction::OUT, |d| d == parsed_str as usize, "OUT == string threshold parsed to u64");
+ assert_filter(&graph, NodeFilter.out_degree().ne(threshold_str.clone()), Direction::OUT, |d| d != parsed_str as usize, "OUT != string threshold parsed to u64");
+ assert_filter(&graph, NodeFilter.out_degree().ge(threshold_str.clone()), Direction::OUT, |d| d >= parsed_str as usize, "OUT >= string threshold parsed to u64");
+ assert_filter(&graph, NodeFilter.out_degree().gt(threshold_str), Direction::OUT, |d| d > parsed_str as usize, "OUT > string threshold parsed to u64");
+ }
+
+ #[test]
+ fn prop_degree_filter_with_float_threshold(threshold in 0u64..15) {
+ let graph = degree_graph_with_add_node_and_add_edge();
+ let threshold_float = threshold as f64;
+ let parsed_float = threshold_float as u64;
+
+ assert_filter(&graph, NodeFilter.degree().lt(threshold_float), Direction::BOTH, |d| d < parsed_float as usize, "BOTH < float threshold cast to u64");
+ assert_filter(&graph, NodeFilter.degree().le(threshold_float), Direction::BOTH, |d| d <= parsed_float as usize, "BOTH <= float threshold cast to u64");
+ assert_filter(&graph, NodeFilter.degree().eq(threshold_float), Direction::BOTH, |d| d == parsed_float as usize, "BOTH == float threshold cast to u64");
+ assert_filter(&graph, NodeFilter.degree().ne(threshold_float), Direction::BOTH, |d| d != parsed_float as usize, "BOTH != float threshold cast to u64");
+ assert_filter(&graph, NodeFilter.degree().ge(threshold_float), Direction::BOTH, |d| d >= parsed_float as usize, "BOTH >= float threshold cast to u64");
+ assert_filter(&graph, NodeFilter.degree().gt(threshold_float), Direction::BOTH, |d| d > parsed_float as usize, "BOTH > float threshold cast to u64");
+
+ assert_filter(&graph, NodeFilter.in_degree().lt(threshold_float), Direction::IN, |d| d < parsed_float as usize, "IN < float threshold cast to u64");
+ assert_filter(&graph, NodeFilter.in_degree().le(threshold_float), Direction::IN, |d| d <= parsed_float as usize, "IN <= float threshold cast to u64");
+ assert_filter(&graph, NodeFilter.in_degree().eq(threshold_float), Direction::IN, |d| d == parsed_float as usize, "IN == float threshold cast to u64");
+ assert_filter(&graph, NodeFilter.in_degree().ne(threshold_float), Direction::IN, |d| d != parsed_float as usize, "IN != float threshold cast to u64");
+ assert_filter(&graph, NodeFilter.in_degree().ge(threshold_float), Direction::IN, |d| d >= parsed_float as usize, "IN >= float threshold cast to u64");
+ assert_filter(&graph, NodeFilter.in_degree().gt(threshold_float), Direction::IN, |d| d > parsed_float as usize, "IN > float threshold cast to u64");
+
+ assert_filter(&graph, NodeFilter.out_degree().lt(threshold_float), Direction::OUT, |d| d < parsed_float as usize, "OUT < float threshold cast to u64");
+ assert_filter(&graph, NodeFilter.out_degree().le(threshold_float), Direction::OUT, |d| d <= parsed_float as usize, "OUT <= float threshold cast to u64");
+ assert_filter(&graph, NodeFilter.out_degree().eq(threshold_float), Direction::OUT, |d| d == parsed_float as usize, "OUT == float threshold cast to u64");
+ assert_filter(&graph, NodeFilter.out_degree().ne(threshold_float), Direction::OUT, |d| d != parsed_float as usize, "OUT != float threshold cast to u64");
+ assert_filter(&graph, NodeFilter.out_degree().ge(threshold_float), Direction::OUT, |d| d >= parsed_float as usize, "OUT >= float threshold cast to u64");
+ assert_filter(&graph, NodeFilter.out_degree().gt(threshold_float), Direction::OUT, |d| d > parsed_float as usize, "OUT > float threshold cast to u64");
+ }
+
+ #[test]
+ fn prop_degree_filter_with_string_is_in(threshold_a in 0u64..15, threshold_b in 0u64..15) {
+ let graph = degree_graph_with_add_node_and_add_edge();
+ let threshold_a_str = threshold_a.to_string();
+ let threshold_b_str = threshold_b.to_string();
+ let parsed_a = threshold_a_str.parse::().unwrap();
+ let parsed_b = threshold_b_str.parse::().unwrap();
+ let set = [parsed_a, parsed_b];
+
+ assert_filter(&graph, NodeFilter.degree().is_in(vec![threshold_a_str.clone().into_prop(), threshold_b_str.clone().into_prop()]), Direction::BOTH, |d| set.contains(&(d as u64)), "BOTH is_in(string thresholds parsed to u64)");
+ assert_filter(&graph, NodeFilter.in_degree().is_in(vec![threshold_a_str.clone().into_prop(), threshold_b_str.clone().into_prop()]), Direction::IN, |d| set.contains(&(d as u64)), "IN is_in(string thresholds parsed to u64)");
+ assert_filter(&graph, NodeFilter.out_degree().is_in(vec![threshold_a_str.into_prop(), threshold_b_str.into_prop()]), Direction::OUT, |d| set.contains(&(d as u64)), "OUT is_in(string thresholds parsed to u64)");
+ }
+
+ #[test]
+ fn prop_degree_filter_with_string_is_not_in(threshold_a in 0u64..15, threshold_b in 0u64..15) {
+ let graph = degree_graph_with_add_node_and_add_edge();
+ let threshold_a_str = threshold_a.to_string();
+ let threshold_b_str = threshold_b.to_string();
+ let parsed_a = threshold_a_str.parse::().unwrap();
+ let parsed_b = threshold_b_str.parse::().unwrap();
+ let set = [parsed_a, parsed_b];
+
+ assert_filter(&graph, NodeFilter.degree().is_not_in(vec![threshold_a_str.clone().into_prop(), threshold_b_str.clone().into_prop()]), Direction::BOTH, |d| !set.contains(&(d as u64)), "BOTH is_not_in(string thresholds parsed to u64)");
+ assert_filter(&graph, NodeFilter.in_degree().is_not_in(vec![threshold_a_str.clone().into_prop(), threshold_b_str.clone().into_prop()]), Direction::IN, |d| !set.contains(&(d as u64)), "IN is_not_in(string thresholds parsed to u64)");
+ assert_filter(&graph, NodeFilter.out_degree().is_not_in(vec![threshold_a_str.into_prop(), threshold_b_str.into_prop()]), Direction::OUT, |d| !set.contains(&(d as u64)), "OUT is_not_in(string thresholds parsed to u64)");
+ }
+
+ #[test]
+ fn prop_degree_filter_with_float_is_in(threshold_a in 0u64..15, threshold_b in 0u64..15) {
+ let graph = degree_graph_with_add_node_and_add_edge();
+ let threshold_a_float = threshold_a as f64;
+ let threshold_b_float = threshold_b as f64;
+ let parsed_a = threshold_a_float as u64;
+ let parsed_b = threshold_b_float as u64;
+ let set = [parsed_a, parsed_b];
+
+ assert_filter(&graph, NodeFilter.degree().is_in(vec![threshold_a_float.into_prop(), threshold_b_float.into_prop()]), Direction::BOTH, |d| set.contains(&(d as u64)), "BOTH is_in(float thresholds cast to u64)");
+ assert_filter(&graph, NodeFilter.in_degree().is_in(vec![threshold_a_float.into_prop(), threshold_b_float.into_prop()]), Direction::IN, |d| set.contains(&(d as u64)), "IN is_in(float thresholds cast to u64)");
+ assert_filter(&graph, NodeFilter.out_degree().is_in(vec![threshold_a_float.into_prop(), threshold_b_float.into_prop()]), Direction::OUT, |d| set.contains(&(d as u64)), "OUT is_in(float thresholds cast to u64)");
+ }
+
+ #[test]
+ fn prop_degree_filter_with_float_is_not_in(threshold_a in 0u64..15, threshold_b in 0u64..15) {
+ let graph = degree_graph_with_add_node_and_add_edge();
+ let threshold_a_float = threshold_a as f64;
+ let threshold_b_float = threshold_b as f64;
+ let parsed_a = threshold_a_float as u64;
+ let parsed_b = threshold_b_float as u64;
+ let set = [parsed_a, parsed_b];
+
+ assert_filter(&graph, NodeFilter.degree().is_not_in(vec![threshold_a_float.into_prop(), threshold_b_float.into_prop()]), Direction::BOTH, |d| !set.contains(&(d as u64)), "BOTH is_not_in(float thresholds cast to u64)");
+ assert_filter(&graph, NodeFilter.in_degree().is_not_in(vec![threshold_a_float.into_prop(), threshold_b_float.into_prop()]), Direction::IN, |d| !set.contains(&(d as u64)), "IN is_not_in(float thresholds cast to u64)");
+ assert_filter(&graph, NodeFilter.out_degree().is_not_in(vec![threshold_a_float.into_prop(), threshold_b_float.into_prop()]), Direction::OUT, |d| !set.contains(&(d as u64)), "OUT is_not_in(float thresholds cast to u64)");
+ }
+
+ #[test]
+ fn prop_degree_filter_invalid_non_numeric_string_values(value_a in "[a-zA-Z]{1,8}", value_b in "[a-zA-Z]{1,8}") {
+ let graph = degree_graph_with_add_node_and_add_edge();
+
+ let invalid_filters = vec![
+ NodeFilter.degree().lt(value_a.clone()),
+ NodeFilter.degree().le(value_a.clone()),
+ NodeFilter.degree().eq(value_a.clone()),
+ NodeFilter.degree().ne(value_a.clone()),
+ NodeFilter.degree().ge(value_a.clone()),
+ NodeFilter.degree().gt(value_a.clone()),
+ NodeFilter.in_degree().lt(value_a.clone()),
+ NodeFilter.in_degree().le(value_a.clone()),
+ NodeFilter.in_degree().eq(value_a.clone()),
+ NodeFilter.in_degree().ne(value_a.clone()),
+ NodeFilter.in_degree().ge(value_a.clone()),
+ NodeFilter.in_degree().gt(value_a.clone()),
+ NodeFilter.out_degree().lt(value_a.clone()),
+ NodeFilter.out_degree().le(value_a.clone()),
+ NodeFilter.out_degree().eq(value_a.clone()),
+ NodeFilter.out_degree().ne(value_a.clone()),
+ NodeFilter.out_degree().ge(value_a.clone()),
+ NodeFilter.out_degree().gt(value_a.clone()),
+ NodeFilter.degree().is_in(vec![value_a.clone().into_prop(), value_b.clone().into_prop()]),
+ NodeFilter.degree().is_not_in(vec![value_a.clone().into_prop(), value_b.clone().into_prop()]),
+ NodeFilter.in_degree().is_in(vec![value_a.clone().into_prop(), value_b.clone().into_prop()]),
+ NodeFilter.in_degree().is_not_in(vec![value_a.clone().into_prop(), value_b.clone().into_prop()]),
+ NodeFilter.out_degree().is_in(vec![value_a.clone().into_prop(), value_b.clone().into_prop()]),
+ NodeFilter.out_degree().is_not_in(vec![value_a.clone().into_prop(), value_b.clone().into_prop()]),
+ ];
+
+ for filter in invalid_filters {
+ assert!(
+ matches!(graph.filter(filter), Err(GraphError::InvalidFilter(_))),
+ "expected InvalidFilter for non-numeric string values"
+ );
+ }
+ }
+ }
+
+ #[test]
+ fn test_node_list_is_preserved() {
+ let graph = init_nodes_graph(Graph::new());
+ let nodes = graph
+ .nodes()
+ .after(5)
+ .select(NodeFilter::node_type().contains("x"))
+ .unwrap();
+ let degrees = nodes.degree();
+ let degrees_collected = degrees.compute();
+ assert_eq!(degrees, degrees_collected);
+ }
+
+ #[test]
+ fn test_filter_nodes_for_node_name_eq() {
+ let filter = NodeFilter::name().eq("3");
+ let expected_results = vec!["3"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_node_name_ne() {
+ let filter = NodeFilter::name().ne("2");
+ let expected_results = vec!["1", "3", "4"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_node_name_in() {
+ let filter = NodeFilter::name().is_in(vec!["1"]);
+ let expected_results = vec!["1"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter::name().is_in(vec![""]);
+ let expected_results = Vec::<&str>::new();
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter::name().is_in(vec!["2", "3"]);
+ let expected_results = vec!["2", "3"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_node_name_not_in() {
+ let filter = NodeFilter::name().is_not_in(vec!["1"]);
+ let expected_results = vec!["2", "3", "4"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter::name().is_not_in(vec![""]);
+ let expected_results = vec!["1", "2", "3", "4"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_node_type_eq() {
+ let filter = NodeFilter::node_type().eq("fire_nation");
+ let expected_results = vec!["1", "3"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_node_type_ne() {
+ let filter = NodeFilter::node_type().ne("fire_nation");
+ let expected_results = vec!["2", "4"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_node_type_in() {
+ let filter = NodeFilter::node_type().is_in(vec!["fire_nation"]);
+ let expected_results = vec!["1", "3"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter::node_type().is_in(vec!["fire_nation", "air_nomads"]);
+ let expected_results = vec!["1", "2", "3"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_node_type_not_in() {
+ let filter = NodeFilter::node_type().is_not_in(vec!["fire_nation"]);
+ let expected_results = vec!["2", "4"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_node_type_starts_with() {
+ let filter = NodeFilter::node_type().starts_with("fire");
+ let expected_results = vec!["1", "3"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter::node_type().starts_with("rocket");
+ let expected_results = vec![];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_node_type_ends_with() {
+ let filter = NodeFilter::node_type().ends_with("nomads");
+ let expected_results = vec!["2"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter::node_type().ends_with("circle");
+ let expected_results = vec![];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_node_type_contains() {
+ let filter = NodeFilter::node_type().contains("fire");
+ let expected_results = vec!["1", "3"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_node_type_contains_not() {
+ let filter = NodeFilter::node_type().not_contains("fire");
+ let expected_results = vec!["2", "4"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_fuzzy_search() {
+ let filter = NodeFilter::node_type().fuzzy_search("fire", 2, true);
+ let expected_results: Vec<&str> = vec!["1", "3"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter::node_type().fuzzy_search("fire", 2, false);
+ let expected_results: Vec<&str> = vec![];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter::node_type().fuzzy_search("air_noma", 2, false);
+ let expected_results: Vec<&str> = vec!["2"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_not_node_type() {
+ let filter = NodeFilter::node_type().is_not_in(vec!["fire_nation"]).not();
+ let expected_results = vec!["1", "3"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_eq_node_id() {
+ let filter = NodeFilter::id().eq("1");
+ let expected_results = vec!["1"];
+
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter::id().eq(1);
+ let expected_results = vec!["1"];
+
+ assert_filter_nodes_results(
+ init_nodes_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_filter_nodes_results(
+ init_nodes_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_ne_node_id() {
+ let filter = NodeFilter::id().ne("1");
+ let expected_results = vec!["2", "3", "4"];
+
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter::id().ne(1);
+ let expected_results = vec!["2", "3", "4"];
+
+ assert_filter_nodes_results(
+ init_nodes_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_is_in_node_id() {
+ let filter = NodeFilter::id().is_in(vec!["1", "3", "6"]);
+ let expected_results = vec!["1", "3"];
+
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter::id().is_in(vec![1, 3, 6]);
+ let expected_results = vec!["1", "3"];
+
+ assert_filter_nodes_results(
+ init_nodes_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_is_not_in_node_id() {
+ let filter = NodeFilter::id().is_not_in(vec!["1", "3", "6"]);
+ let expected_results = vec!["2", "4"];
+
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter::id().is_not_in(vec![1, 3, 6]);
+ let expected_results = vec!["2", "4"];
+
+ assert_filter_nodes_results(
+ init_nodes_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_lt_node_id() {
+ let filter = NodeFilter::id().lt(2);
+ let expected_results = vec!["1"];
+
+ assert_filter_nodes_results(
+ init_nodes_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_le_node_id() {
+ let filter = NodeFilter::id().le(3);
+ let expected_results = vec!["1", "2", "3"];
+
+ assert_filter_nodes_results(
+ init_nodes_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_gt_node_id() {
+ let filter = NodeFilter::id().gt(2);
+ let expected_results = vec!["3", "4"];
+
+ assert_filter_nodes_results(
+ init_nodes_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_ge_node_id() {
+ let filter = NodeFilter::id().ge(2);
+ let expected_results = vec!["2", "3", "4"];
+
+ assert_filter_nodes_results(
+ init_nodes_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_starts_with_node_id() {
+ let filter = NodeFilter::id().starts_with("France");
+ let expected_results = vec!["France Paris"];
+ assert_filter_nodes_results(
+ init_nodes_graph_with_str_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_ends_with_node_id() {
+ let filter = NodeFilter::id().ends_with("wo");
+ let expected_results = vec!["Two"];
+ assert_filter_nodes_results(
+ init_nodes_graph_with_str_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph_with_str_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_contains_node_id() {
+ let filter = NodeFilter::id().contains("o");
+ let expected_results = vec!["London", "Tokyo", "Two"];
+ assert_filter_nodes_results(
+ init_nodes_graph_with_str_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_not_contains_node_id() {
+ let filter = NodeFilter::id().not_contains("o");
+ let expected_results = vec!["France Paris"];
+ assert_filter_nodes_results(
+ init_nodes_graph_with_str_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_is_in_node_id_str() {
+ let filter = NodeFilter::id().is_in(vec!["London", "Tokyo"]);
+ let expected_results = vec!["London", "Tokyo"];
+ assert_filter_nodes_results(
+ init_nodes_graph_with_str_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph_with_str_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_is_not_in_node_id_str() {
+ let filter = NodeFilter::id().is_not_in(vec!["London", "Tokyo"]);
+ let expected_results = vec!["France Paris", "Two"];
+ assert_filter_nodes_results(
+ init_nodes_graph_with_str_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph_with_str_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_is_active_node_window() {
+ let filter = NodeFilter.window(1, 10).is_active();
+ let expected_results = vec!["1", "2", "3", "4"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+
+ #[test]
+ fn test_is_active_node_window_not() {
+ let filter = NodeFilter
+ .window(1, 10)
+ .is_active()
+ .try_as_composite_node_filter()
+ .unwrap();
+ let filter = CompositeNodeFilter::Not(Box::new(filter));
+ let expected_results = vec![];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+
+ #[test]
+ fn test_is_active_node_latest() {
+ let filter = NodeFilter.latest().is_active();
+ let expected_results = vec!["1", "2", "4"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+
+ #[test]
+ fn test_filter_by_column() {
+ let graph = Graph::new();
+ graph.add_node(1, 1, NO_PROPS, None, None).unwrap();
+ graph.add_node(1, 2, NO_PROPS, None, None).unwrap();
+ graph.add_node(1, 3, NO_PROPS, None, None).unwrap();
+ graph.add_node(1, 4, NO_PROPS, None, None).unwrap();
+ graph.add_node(1, 5, NO_PROPS, None, None).unwrap();
+
+ let mask = alternating_mask(&graph);
+ let expected_nodes: Vec<_> = graph
+ .nodes()
+ .name()
+ .iter_values()
+ .skip(1)
+ .step_by(2)
+ .collect();
+
+ let filtered = graph
+ .filter(NodeFilter::by_column(&mask, "bool_col").unwrap())
+ .unwrap();
+
+ let names = filtered
+ .nodes()
+ .iter()
+ .map(|n| n.id().to_string())
+ .collect::>();
+
+ assert_eq!(names, expected_nodes);
+
+ let filtered = graph
+ .nodes()
+ .select(NodeFilter::by_column(&mask, "bool_col").unwrap())
+ .unwrap();
+
+ let names = filtered
+ .iter()
+ .map(|n| n.id().to_string())
+ .collect::>();
+
+ assert_eq!(names, expected_nodes);
+ }
+
+ #[test]
+ fn test_is_active_node_snapshot_at() {
+ let filter = NodeFilter.snapshot_at(2).is_active();
+ let expected_results = vec!["2"];
+ assert_select_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+}
+
+mod test_node_property_filter {
+ use crate::filter_tests::test_filters::{init_nodes_graph, IdentityGraphTransformer};
+ use raphtory::db::graph::views::filter::model::{
+ graph_filter::GraphFilter,
+ node_filter::NodeFilter,
+ not_filter::NotFilter,
+ property_filter::ops::{ElemQualifierOps, ListAggOps, PropertyFilterOps},
+ windowed_filter::Windowed,
+ ComposableFilter, PropertyFilterFactory, TemporalPropertyFilterFactory, ViewWrapOps,
+ };
+ use raphtory_api::core::entities::properties::prop::Prop;
+ use raphtory_tests::assertions::{
+ assert_filter_nodes_results, assert_search_nodes_results, TestVariants,
+ };
+ use std::vec;
+
+ #[test]
+ fn test_exact_match() {
+ // let filter = NodeFilter.degree > 5
+ let filter = NodeFilter.property("p10").eq("Paper_airplane");
+ let expected_results = vec!["1", "3"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter.property("p10").eq("");
+ let expected_results = Vec::<&str>::new();
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_not_exact_match() {
+ let filter = NodeFilter.property("p10").eq("Paper");
+ let expected_results: Vec<&str> = vec![];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_property_eq() {
+ let filter = NodeFilter.property("p2").eq(2u64);
+ let expected_results = vec!["2"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter.property("p30").temporal().first().eq("Old_boat");
+ let expected_results = vec!["2"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter.property("p20").temporal().all().eq("Gold_ship");
+ let expected_results = vec!["1"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_property_ne() {
+ let filter = NodeFilter.property("p2").ne(2u64);
+ let expected_results = vec!["3"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter.property("p30").temporal().first().ne("Old_boat");
+ let expected_results = vec!["1", "4"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter.property("p1").temporal().all().ne("Gold_ship");
+ let expected_results = vec!["1"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_property_lt() {
+ let filter = NodeFilter.property("p2").lt(10u64);
+ let expected_results = vec!["2", "3"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter.property("p40").temporal().first().lt(10u64);
+ let expected_results = vec!["1"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter.property("p9").temporal().all().lt(10u64);
+ let expected_results = vec!["1"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_property_le() {
+ let filter = NodeFilter.property("p2").le(6u64);
+ let expected_results = vec!["2", "3"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter.property("p9").temporal().first().le(10u64);
+ let expected_results = vec!["1"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter.property("p2").temporal().all().le(10u64);
+ let expected_results = vec!["3"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_property_gt() {
+ let filter = NodeFilter.property("p2").gt(2u64);
+ let expected_results = vec!["3"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter.property("p40").temporal().first().gt(5u64);
+ let expected_results = vec!["2"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter.property("p9").temporal().all().gt(1u64);
+ let expected_results = vec!["1"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_property_ge() {
+ let filter = NodeFilter.property("p2").ge(2u64);
+ let expected_results = vec!["2", "3"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter.property("p40").temporal().first().ge(5u64);
+ let expected_results = vec!["1", "2"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter.property("p40").temporal().all().ge(5u64);
+ let expected_results = vec!["1", "2"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_property_in() {
+ let filter = NodeFilter.property("p2").is_in(vec![Prop::U64(6)]);
+ let expected_results = vec!["3"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter
+ .property("p2")
+ .is_in(vec![Prop::U64(2), Prop::U64(6)]);
+ let expected_results = vec!["2", "3"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter
+ .property("p40")
+ .temporal()
+ .first()
+ .is_in(vec![Prop::U64(5)]);
+ let expected_results = vec!["1"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter
+ .property("p2")
+ .temporal()
+ .any()
+ .is_in(vec![Prop::U64(2)]);
+ let expected_results = vec!["2"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_property_not_in() {
+ let filter = NodeFilter.property("p2").is_not_in(vec![Prop::U64(6)]);
+ let expected_results = vec!["2"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter.property("p40").is_not_in(vec![Prop::U64(6)]);
+ let expected_results = vec!["1", "2"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter
+ .property("p2")
+ .temporal()
+ .all()
+ .is_not_in(vec![Prop::U64(2)]);
+ let expected_results = vec!["3"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_property_is_some() {
+ let filter = NodeFilter.property("p2").is_some();
+ let expected_results = vec!["2", "3"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter.property("p40").is_some();
+ let expected_results = vec!["1", "2"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_property_is_none() {
+ let filter = NodeFilter.property("p2").is_none();
+ let expected_results = vec!["1", "4"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter.property("p40").is_none();
+ let expected_results = vec!["3", "4"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_property_starts_with() {
+ let filter = NodeFilter.property("p10").starts_with("Pa");
+ let expected_results: Vec<&str> = vec!["1", "2", "3"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter
+ .property("p10")
+ .temporal()
+ .any()
+ .starts_with("Pap");
+ let expected_results: Vec<&str> = vec!["1", "2", "3"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter
+ .property("p10")
+ .temporal()
+ .last()
+ .starts_with("Pape");
+ let expected_results: Vec<&str> = vec!["1", "2", "3"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter
+ .property("p10")
+ .temporal()
+ .last()
+ .starts_with("Yohan");
+ let expected_results: Vec<&str> = vec![];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter
+ .property("p30")
+ .temporal()
+ .first()
+ .starts_with("Gold");
+ let expected_results: Vec<&str> = vec!["1", "4"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter
+ .property("p20")
+ .temporal()
+ .all()
+ .starts_with("Gold");
+ let expected_results: Vec<&str> = vec!["1", "2", "4"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_property_ends_with() {
+ let filter = NodeFilter.property("p10").ends_with("lane");
+ let expected_results: Vec<&str> = vec!["1", "3"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter
+ .property("p10")
+ .temporal()
+ .any()
+ .ends_with("ship");
+ let expected_results: Vec<&str> = vec!["2"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter
+ .property("p10")
+ .temporal()
+ .last()
+ .ends_with("ane");
+ let expected_results: Vec<&str> = vec!["1", "3"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter
+ .property("p10")
+ .temporal()
+ .last()
+ .ends_with("Jerry");
+ let expected_results: Vec<&str> = vec![];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter
+ .property("p20")
+ .temporal()
+ .first()
+ .ends_with("boat");
+ let expected_results: Vec<&str> = vec!["2"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter
+ .property("p20")
+ .temporal()
+ .all()
+ .ends_with("ship");
+ let expected_results: Vec<&str> = vec!["1"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_property_contains() {
+ let filter = NodeFilter.property("p10").contains("Paper");
+ let expected_results: Vec<&str> = vec!["1", "2", "3"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter
+ .property("p10")
+ .temporal()
+ .any()
+ .contains("Paper");
+ let expected_results: Vec<&str> = vec!["1", "2", "3"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter
+ .property("p10")
+ .temporal()
+ .last()
+ .contains("Paper");
+ let expected_results: Vec<&str> = vec!["1", "2", "3"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter
+ .property("p30")
+ .temporal()
+ .first()
+ .contains("Old");
+ let expected_results: Vec<&str> = vec!["2"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter.property("p30").temporal().all().contains("Gold");
+ let expected_results: Vec<&str> = vec!["1"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_property_contains_not() {
+ let filter = NodeFilter.property("p10").not_contains("ship");
+ let expected_results: Vec<&str> = vec!["1", "3"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter
+ .property("p10")
+ .temporal()
+ .any()
+ .not_contains("ship");
+ let expected_results: Vec<&str> = vec!["1", "3"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter
+ .property("p10")
+ .temporal()
+ .last()
+ .not_contains("ship");
+ let expected_results: Vec<&str> = vec!["1", "3"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter
+ .property("p30")
+ .temporal()
+ .first()
+ .not_contains("Old");
+ let expected_results: Vec<&str> = vec!["1", "4"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter
+ .property("p30")
+ .temporal()
+ .all()
+ .not_contains("boat");
+ let expected_results: Vec<&str> = vec!["1", "4"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_not_property() {
+ let filter = NotFilter(NodeFilter.property("p10").contains("Paper"));
+ let expected_results: Vec<&str> = vec!["4"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter.property("p10").contains("Paper").not();
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_temporal_property_sum() {
+ let filter = NodeFilter.property("p9").temporal().sum().eq(15u64);
+ let expected_results: Vec<&str> = vec!["1"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_temporal_property_avg() {
+ let filter = NodeFilter.property("p2").temporal().avg().le(10f64);
+ let expected_results: Vec<&str> = vec!["2", "3"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_temporal_property_min() {
+ let filter = NodeFilter.property("p40").temporal().min().is_in(vec![
+ Prop::U64(5),
+ Prop::U64(10),
+ Prop::U64(20),
+ ]);
+ let expected_results: Vec<&str> = vec!["1", "2"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_temporal_property_max() {
+ let filter = NodeFilter.property("p3").temporal().max().is_not_in(vec![
+ Prop::U64(5),
+ Prop::U64(10),
+ Prop::U64(20),
+ ]);
+ let expected_results: Vec<&str> = vec!["3"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_nodes_for_temporal_property_len() {
+ let filter = NodeFilter.property("p2").temporal().len().le(5u64);
+ let expected_results: Vec<&str> = vec!["1", "2", "3", "4"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_nodes_window_filter() {
+ let filter = NodeFilter
+ .window(1, 3)
+ .property("p2")
+ .temporal()
+ .sum()
+ .ge(2u64);
+
+ let expected_results = vec!["2"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ // Wider window includes node 3
+ let filter = NodeFilter
+ .window(1, 5)
+ .property("p2")
+ .temporal()
+ .sum()
+ .ge(2u64);
+
+ let expected_results = vec!["2", "3"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_nodes_window_filter_on_non_temporal_property() {
+ let filter1 = NodeFilter.window(1, 2).property("p1").eq("shivam_kapoor");
+ let filter2 = NodeFilter
+ .window(100, 200)
+ .property("p1")
+ .eq("shivam_kapoor");
+
+ let expected_results = vec!["1"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter1.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter1.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let expected_results = vec![];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter2.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter2.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ let filter = NodeFilter
+ .window(100, 200)
+ .property("p1")
+ .eq("shivam_kapoor");
+
+ let expected_results = vec!["1"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+
+ #[test]
+ fn test_nodes_window_filter_any_all_over_window() {
+ let filter = NodeFilter
+ .window(3, 5)
+ .property("p20")
+ .temporal()
+ .any()
+ .eq("Gold_boat");
+
+ let expected_results = vec!["4"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter
+ .window(3, 5)
+ .property("p20")
+ .temporal()
+ .all()
+ .eq("Gold_boat");
+
+ let expected_results = vec![];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_nodes_window_filter_and() {
+ // Filters both node 1 and 3
+ let filter1 = NodeFilter
+ .window(1, 4)
+ .property("p10")
+ .temporal()
+ .any()
+ .eq("Paper_airplane");
+
+ // Filters only node 3
+ let filter2 = NodeFilter
+ .window(3, 6)
+ .property("p2")
+ .temporal()
+ .sum()
+ .eq(6u64);
+
+ let filter = filter1.and(filter2);
+
+ let expected_results = vec!["3"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_nodes_at_filter() {
+ // Only time=2 contributes; node 2 has p2=2 at t=2
+ let filter = NodeFilter.at(2).property("p2").temporal().sum().eq(2u64);
+
+ let expected_results = vec!["2"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ // Only time=3 contributes; node 3 has p2=6 at t=3
+ let filter = NodeFilter.at(3).property("p2").temporal().sum().eq(6u64);
+
+ let expected_results = vec!["3"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_nodes_after_filter() {
+ // after(2) means t >= 3
+ let filter = NodeFilter.after(2).property("p2").temporal().sum().ge(6u64);
+
+ let expected_results = vec!["3"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_nodes_before_filter() {
+ // before(3) means t <= 2
+ let filter = NodeFilter
+ .before(3)
+ .property("p2")
+ .temporal()
+ .sum()
+ .eq(2u64);
+
+ let expected_results = vec!["2"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ // And node 3 shouldn't match, because its p2=6 lives at t=3.
+ let filter = NodeFilter
+ .before(3)
+ .property("p2")
+ .temporal()
+ .sum()
+ .eq(6u64);
+
+ let expected_results = vec![];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_nodes_latest_filter() {
+ // At latest time (currently t=4), only node 4 has p5=12
+ let filter = NodeFilter.latest().property("p5").eq(12u64);
+
+ let expected_results = vec!["4"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_nodes_snapshot_at_semantics_event_graph() {
+ let t = 2;
+
+ let filter_snapshot = NodeFilter.snapshot_at(t).property("p2").eq(2u64);
+
+ let filter_before = NodeFilter.before(t + 1).property("p2").eq(2u64);
+
+ let expected_results = vec!["2"];
+
+ // snapshot_at
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter_snapshot.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter_snapshot,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ // before(t+1)
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter_before.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter_before,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ }
+
+ #[test]
+ fn test_nodes_snapshot_at_semantics_persistent_graph() {
+ let t = 2;
+
+ let filter_snapshot = NodeFilter.snapshot_at(t).property("p2").eq(2u64);
+
+ let filter_at = NodeFilter.at(t).property("p2").eq(2u64);
+
+ let expected_results = vec!["2"];
+
+ // snapshot_at
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter_snapshot.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter_snapshot,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ // at(t)
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter_at.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter_at,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+
+ #[test]
+ fn test_nodes_snapshot_latest_semantics_event_graph() {
+ let filter_snapshot_latest = NodeFilter
+ .snapshot_latest()
+ .property("p2")
+ .temporal()
+ .sum()
+ .ge(2u64);
+
+ let filter_noop = NodeFilter.property("p2").temporal().sum().ge(2u64);
+
+ // From your earlier window test, "2" and "3" are the ones with p2 values across time.
+ // If your underlying dataset changes, adjust this accordingly.
+ let expected_results = vec!["2", "3"];
+
+ // snapshot_latest
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter_snapshot_latest.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter_snapshot_latest,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ // no-op baseline
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter_noop.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter_noop,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ }
+
+ #[test]
+ fn test_nodes_snapshot_latest_semantics_persistent_graph() {
+ let filter_snapshot_latest = NodeFilter
+ .snapshot_latest()
+ .property("p1")
+ .eq("shivam_kapoor");
+
+ let filter_latest = NodeFilter.latest().property("p1").eq("shivam_kapoor");
+
+ let expected_results = vec!["1"];
+
+ // snapshot_latest
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter_snapshot_latest.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter_snapshot_latest,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ // latest
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter_latest.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter_latest,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+
+ #[test]
+ #[ignore] // TODO: Enable this when node layer is supported
+ fn test_nodes_layer_filter() {
+ let filter = NodeFilter
+ .layer("_default")
+ .property("p2")
+ .temporal()
+ .sum()
+ .ge(2u64);
+
+ let expected_results = vec!["2"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ #[ignore] // TODO: Enable this when node layer is supported
+ fn test_nodes_layer_then_window_ordering() {
+ // In layer "fire_nation" within window [1,4), node "1" matches p1 == "shivam_kapoor".
+ let filter = NodeFilter
+ .layer("fire_nation")
+ .window(1, 4)
+ .property("p1")
+ .eq("shivam_kapoor");
+
+ let expected_results = vec!["1"];
+
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ #[ignore] // TODO: Enable this when node layer is supported
+ fn test_nodes_window_then_layer_ordering() {
+ // Same semantics as above, but reversed chaining order.
+ let filter = NodeFilter
+ .window(1, 4)
+ .layer("fire_nation")
+ .property("p1")
+ .eq("shivam_kapoor");
+
+ let expected_results = vec!["1"];
+
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_graph_filter_window() {
+ let filter: Windowed = GraphFilter.window(1, 2);
+ let expected_results = vec!["1"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = GraphFilter.window(1, 3);
+ let expected_results = vec!["1", "2"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = GraphFilter.window(4, 6);
+ let expected_results = vec!["1", "2", "4"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ let filter = GraphFilter.window(4, 6);
+ let expected_results = vec!["1", "2", "3", "4"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+
+ #[test]
+ #[ignore] // TODO: Enable this when node layer is supported
+ fn test_graph_filter_layer() {
+ let filter = GraphFilter.layer("fire_nation");
+ let expected_results = vec!["1", "3"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = GraphFilter.layer("air_nomads");
+ let expected_results = vec!["2"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ #[ignore] // TODO: Enable this when node layer is supported
+ fn test_graph_filter_window_then_layer() {
+ let filter = GraphFilter.window(1, 3).layer("fire_nation");
+ let expected_results = vec!["1", "3"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = GraphFilter.window(4, 4).layer("air_nomads");
+ let expected_results = vec!["2"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ #[ignore] // TODO: Enable this when node layer is supported
+ fn test_graph_filter_layer_then_window() {
+ let filter = GraphFilter.layer("fire_nation").window(1, 3);
+ let expected_results = vec!["1", "3"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_graph_filter_at() {
+ let filter = GraphFilter.at(1);
+ let expected_results = vec!["1"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = GraphFilter.at(2);
+ let expected_results = vec!["2"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ let filter = GraphFilter.at(2);
+ let expected_results = vec!["1", "2"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = GraphFilter.at(3);
+ let expected_results = vec!["1", "2", "3", "4"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_graph_filter_after() {
+ let filter = GraphFilter.after(3);
+ let expected_results = vec!["1", "2", "4"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ let filter = GraphFilter.after(3);
+ let expected_results = vec!["1", "2", "3", "4"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+
+ #[test]
+ fn test_graph_filter_before() {
+ let filter = GraphFilter.before(2);
+ let expected_results = vec!["1"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = GraphFilter.before(3);
+ let expected_results = vec!["1", "2"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_graph_filter_snapshot_at() {
+ let filter = GraphFilter.snapshot_at(1);
+ let expected_results = vec!["1"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = GraphFilter.snapshot_at(3);
+ let expected_results = vec!["1", "2", "3", "4"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = GraphFilter.snapshot_at(4);
+ let expected_results = vec!["1", "2", "3", "4"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_graph_filter_snapshot_latest() {
+ let filter = GraphFilter.snapshot_latest();
+ let expected_results = vec!["1", "2", "3", "4"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_graph_filter_latest() {
+ let filter = GraphFilter.latest();
+ let expected_results = vec!["1", "2", "4"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ let filter = GraphFilter.latest();
+ let expected_results = vec!["1", "2", "3", "4"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+}
+
+mod test_node_composite_filter {
+ use raphtory_api::core::Direction;
+
+ use crate::filter_tests::test_filters::{
+ init_edges_graph, init_nodes_graph, IdentityGraphTransformer,
+ };
+ use raphtory::{
+ db::graph::views::filter::model::{
+ node_filter::ops::NodeFilterOps, property_filter::ops::PropertyFilterOps,
+ ComposableFilter, PropertyFilterFactory, TryAsCompositeFilter,
+ },
+ prelude::NodeFilter,
+ };
+ use raphtory_tests::assertions::{
+ assert_filter_neighbours_results, assert_filter_nodes_results, assert_search_nodes_results,
+ TestVariants,
+ };
+
+ #[test]
+ fn test_filter_nodes_by_props_added_at_different_times() {
+ let filter = NodeFilter
+ .property("p4")
+ .eq("pometry")
+ .and(NodeFilter.property("p5").eq(12u64));
+ let expected_results = vec!["4"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_unique_results_from_composite_filters() {
+ let filter = NodeFilter
+ .property("p2")
+ .ge(2u64)
+ .and(NodeFilter.property("p2").ge(1u64));
+ let expected_results = vec!["2", "3"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter
+ .property("p2")
+ .ge(2u64)
+ .or(NodeFilter.property("p2").ge(5u64));
+ let expected_results = vec!["2", "3"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_composite_filter_nodes() {
+ let filter = NodeFilter
+ .property("p2")
+ .eq(2u64)
+ .and(NodeFilter.property("p1").eq("kapoor"));
+ let expected_results = Vec::<&str>::new();
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ let filter = filter.try_as_composite_node_filter().unwrap();
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter
+ .property("p2")
+ .eq(2u64)
+ .or(NodeFilter.property("p1").eq("shivam_kapoor"));
+ let expected_results = vec!["1", "2"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ let filter = filter.try_as_composite_node_filter().unwrap();
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter.property("p1").eq("pometry").or(NodeFilter
+ .property("p2")
+ .eq(6u64)
+ .and(NodeFilter.property("p3").eq(1u64)));
+ let expected_results = vec!["3"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ let filter = filter.try_as_composite_node_filter().unwrap();
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter::node_type()
+ .eq("fire_nation")
+ .and(NodeFilter.property("p1").eq("prop1"));
+ let expected_results = Vec::<&str>::new();
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ let filter = filter.try_as_composite_node_filter().unwrap();
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter
+ .property("p9")
+ .eq(5u64)
+ .and(NodeFilter.property("p1").eq("shivam_kapoor"));
+ let expected_results = vec!["1"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ let filter = filter.try_as_composite_node_filter().unwrap();
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter::node_type()
+ .eq("fire_nation")
+ .and(NodeFilter.property("p1").eq("shivam_kapoor"));
+ let expected_results = vec!["1"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ let filter = filter.try_as_composite_node_filter().unwrap();
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter::name()
+ .eq("2")
+ .and(NodeFilter.property("p2").eq(2u64));
+ let expected_results = vec!["2"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ let filter = filter.try_as_composite_node_filter().unwrap();
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter::name()
+ .eq("2")
+ .and(NodeFilter.property("p2").eq(2u64))
+ .or(NodeFilter.property("p9").eq(5u64));
+ let expected_results = vec!["1", "2"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ let filter = filter.try_as_composite_node_filter().unwrap();
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_not_composite_filter_nodes() {
+ let filter = NodeFilter::name()
+ .eq("2")
+ .and(NodeFilter.property("p2").eq(2u64))
+ .or(NodeFilter.property("p9").eq(5u64))
+ .not();
+ let expected_results = vec!["3", "4"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = NodeFilter::name()
+ .eq("2")
+ .not()
+ .and(NodeFilter.property("p2").eq(2u64))
+ .or(NodeFilter.property("p9").eq(5u64));
+ let expected_results = vec!["1"];
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_out_neighbours_filter() {
+ let filter = NodeFilter::name()
+ .eq("2")
+ .and(NodeFilter.property("p2").eq(2u64));
+ let expected_results = vec!["2"];
+ assert_filter_neighbours_results(
+ |graph| init_edges_graph(init_nodes_graph(graph)),
+ IdentityGraphTransformer,
+ "1",
+ Direction::OUT,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_in_neighbours_filter() {
+ let filter = NodeFilter.property("p9").ge(1u64);
+ let expected_results = vec!["1"];
+ assert_filter_neighbours_results(
+ |graph| init_edges_graph(init_nodes_graph(graph)),
+ IdentityGraphTransformer,
+ "2",
+ Direction::IN,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_neighbours_filter() {
+ let filter = NodeFilter.property("p10").contains("Paper");
+ let expected_results = vec!["1", "3"];
+ assert_filter_neighbours_results(
+ |graph| init_edges_graph(init_nodes_graph(graph)),
+ IdentityGraphTransformer,
+ "2",
+ Direction::BOTH,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+}
+
+mod test_node_property_filter_agg {
+ use crate::filter_tests::test_filters::IdentityGraphTransformer;
+ use raphtory::{
+ db::{
+ api::view::StaticGraphViewOps,
+ graph::views::filter::{
+ model::{
+ node_filter::NodeFilter,
+ property_filter::ops::{ElemQualifierOps, ListAggOps, PropertyFilterOps},
+ PropertyFilterFactory, TemporalPropertyFilterFactory, TryAsCompositeFilter,
+ },
+ CreateFilter,
+ },
+ },
+ prelude::{AdditionOps, GraphViewOps, PropertyAdditionOps},
+ };
+ use raphtory_api::core::{
+ entities::properties::prop::{IntoProp, Prop},
+ storage::arc_str::ArcStr,
+ };
+ use raphtory_storage::mutation::{
+ addition_ops::InternalAdditionOps, property_addition_ops::InternalPropertyAdditionOps,
+ };
+ use raphtory_tests::assertions::{
+ assert_filter_nodes_err, assert_filter_nodes_results, assert_search_nodes_results,
+ TestVariants::All,
+ };
+
+ fn list_u8(xs: &[u8]) -> Prop {
+ Prop::list(xs.iter().copied().map(Prop::U8))
+ }
+ fn list_u16(xs: &[u16]) -> Prop {
+ Prop::list(xs.iter().copied().map(Prop::U16))
+ }
+ fn list_u32(xs: &[u32]) -> Prop {
+ Prop::list(xs.iter().copied().map(Prop::U32))
+ }
+ fn list_u64(xs: &[u64]) -> Prop {
+ Prop::list(xs.iter().copied().map(Prop::U64))
+ }
+ fn list_i32(xs: &[i32]) -> Prop {
+ Prop::list(xs.iter().copied().map(Prop::I32))
+ }
+ fn list_i64(xs: &[i64]) -> Prop {
+ Prop::list(xs.iter().copied().map(Prop::I64))
+ }
+ fn list_f32(xs: &[f32]) -> Prop {
+ Prop::list(xs.iter().copied().map(Prop::F32))
+ }
+ fn list_f64(xs: &[f64]) -> Prop {
+ Prop::list(xs.iter().copied().map(Prop::F64))
+ }
+ fn list_str(xs: &[&str]) -> Prop {
+ Prop::list(xs.iter().map(|s| Prop::Str(ArcStr::from(*s))))
+ }
+ fn list_bool(xs: &[bool]) -> Prop {
+ Prop::list(xs.iter().copied().map(Prop::Bool))
+ }
+
+ #[inline]
+ fn list(v: Vec) -> Prop {
+ Prop::List(v.into())
+ }
+
+ /// Writes a set of node temporal properties and node metadata to the given graph.
+ pub fn init_nodes_graph<
+ G: StaticGraphViewOps
+ + AdditionOps
+ + InternalAdditionOps
+ + InternalPropertyAdditionOps
+ + PropertyAdditionOps,
+ >(
+ graph: G,
+ ) -> G {
+ // Each tuple represents (timestamp, node_name, properties).
+ let nodes: [(i64, &str, Vec<(&str, Prop)>); 12] = [
+ (
+ 1,
+ "n1",
+ vec![
+ ("p_strs", list_str(&["a", "b", "c"])), // min: None, max: None, sum: None, avg: None, len: 3
+ ("p_bools", list_bool(&[true, false])), // min: None, max: None, sum: None, avg: None, len: 2
+ ("p_u8s", list_u8(&[1, 2, 3])), // min: 1, max: 3, sum: 6, avg: 2.0, len: 3
+ ("p_u8s_max", list_u8(&[u8::MAX, u8::MAX])), // min: u8::MAX, max: u8::MAX, sum: 510
+ ("p_u16s", list_u16(&[1, 2, 3])), // min: 1, max: 3, sum: 6, avg: 2.0, len: 3
+ ("p_u16s_max", list_u16(&[u16::MAX, u16::MAX])), // min: u16::MAX, max: u16::MAX, sum: 131070
+ ("p_u32s", list_u32(&[1, 2, 3])), // min: 1, max: 3, sum: 6, avg: 2.0, len: 3
+ ("p_u32s_max", list_u32(&[u32::MAX, u32::MAX])), // min: 1, max: 3, sum: 8589934590
+ ("p_u64s", list_u64(&[1, 2, 3])), // min: 1, max: 3, sum: 6, avg: 2.0, len: 3
+ ("p_u64s_max", list_u64(&[u64::MAX, u64::MAX])), // min: 1, max: 3, sum: OVERFLOW
+ ("p_i32s", list_i32(&[1, 2, 3])), // min: 1, max: 3, sum: 6, avg: 2.0, len: 3
+ ("p_i64s", list_i64(&[1, 2, 3])), // min: 1, max: 3, sum: 6, avg: 2.0, len: 3
+ ("p_f32s", list_f32(&[1.0, 2.0, 3.5])), // min: 1.0, max: 3.5, sum: 6.5, avg: 2.1666666666666665, len: 3
+ ("p_f64s", list_f64(&[50.0, 40.0])), // min: 40.0, max: 50.0, sum: 90.0, avg: 45.0, len: 2
+ (
+ "nested_list",
+ list(vec![
+ list(vec![
+ list(vec![
+ list(vec![50.0.into_prop(), 40.0.into_prop()]),
+ list(vec![60.0.into_prop()]),
+ ]),
+ list(vec![list(vec![46.0.into_prop()])]),
+ ]),
+ list(vec![list(vec![list(vec![90.0.into_prop()])])]),
+ ]),
+ ),
+ ],
+ ),
+ (
+ 2,
+ "n1",
+ vec![
+ ("p_strs", list_str(&["a", "b", "c", "d"])), // min: None, max: None, sum: None, avg: None, len: 4
+ ("p_bools", list_bool(&[true, true])), // min: None, max: None, sum: None, avg: None, len: 2
+ ("p_u8s", list_u8(&[1, 2, 3, 4])), // min: 1, max: 4, sum: 10, avg: 2.5, len: 4
+ ("p_u16s", list_u16(&[1, 2, 3, 4])), // min: 1, max: 4, sum: 10, avg: 2.5, len: 4
+ ("p_u32s", list_u32(&[1, 2, 3, 4])), // min: 1, max: 4, sum: 10, avg: 2.5, len: 4
+ ("p_u64s", list_u64(&[1, 2, 3, 4])), // min: 1, max: 4, sum: 10, avg: 2.5, len: 4
+ ("p_i32s", list_i32(&[1, 2, 3, 4])), // min: 1, max: 4, sum: 10, avg: 2.5, len: 4
+ ("p_i64s", list_i64(&[1, 2, 3, 4])), // min: 1, max: 4, sum: 10, avg: 2.5, len: 4
+ ("p_f32s", list_f32(&[1.0, 2.0, 3.5, 4.5])), // min: 1.0, max: 4.5, sum: 11.0, avg: 2.75, len: 4
+ ("p_f64s", list_f64(&[30.0, 50.0, 40.0])), // min: 30.0, max: 50.0, sum: 120.0, avg: 40.0, len: 3
+ ],
+ ),
+ (
+ 1,
+ "n2",
+ vec![
+ ("p_strs", list_str(&["a", "b", "c", "d"])), // min: None, max: None, sum: None, avg: None, len: 4
+ ("p_u64s", list_u64(&[1, 2, 3, 4])), // min: 1, max: 4, sum: 10, avg: 2.5, len: 4
+ ("p_f64s", list_f64(&[30.0, 50.0, 40.0])), // min: 30.0, max: 50.0, sum: 120.0, avg: 40.0, len: 3
+ ("p_bools", list_bool(&[false, false])),
+ ],
+ ),
+ (
+ 2,
+ "n2",
+ vec![
+ ("p_strs", list_str(&["a", "b", "c", "d"])), // min: None, max: None, sum: None, avg: None, len: 4
+ ("p_u64s", list_u64(&[1, 2, 3, 4])), // min: 1, max: 4, sum: 10, avg: 2.5, len: 4
+ ("p_f64s", list_f64(&[30.0, 50.0, 40.0])), // min: 30.0, max: 50.0, sum: 120.0, avg: 40.0, len: 3
+ ],
+ ),
+ (
+ 1,
+ "n3",
+ vec![
+ ("p_strs", list_str(&["a", "b", "c"])), // min: None, max: None, sum: None, avg: None, len: 3
+ ("p_bools", list_bool(&[true, false])), // min: None, max: None, sum: None, avg: None, len: 2
+ ("p_u8s", list_u8(&[1, 1, 4])), // min: 1, max: 4, sum: 6, avg: 2.0, len: 3
+ ("p_u16s", list_u16(&[1, 0, 5])), // min: 0, max: 5, sum: 6, avg: 2.0, len: 3
+ ("p_u32s", list_u32(&[2, 2, 2])), // min: 2, max: 2, sum: 6, avg: 2.0, len: 3
+ ("p_u64s", list_u64(&[0, 3, 3])), // min: 0, max: 3, sum: 6, avg: 2.0, len: 3
+ ("p_i32s", list_i32(&[-1, 4, 3])), // min: -1, max: 4, sum: 6, avg: 2.0, len: 3
+ ("p_i64s", list_i64(&[0, 3, -3])), // min: -3, max: 3, sum: 0, avg: 0.0, len: 3
+ ("p_f32s", list_f32(&[1.0, 2.5, 3.0])), // min: 1.0, max: 3.0, sum: 6.5, avg: 2.1666666666666665, len: 3
+ ("p_f64s", list_f64(&[30.0, 60.0])), // min: 30.0, max: 60.0, sum: 90.0, avg: 45.0, len: 2
+ (
+ "nested_list",
+ list(vec![
+ list(vec![
+ list(vec![
+ list(vec![50.0.into_prop(), 40.0.into_prop()]),
+ list(vec![60.0.into_prop()]),
+ ]),
+ list(vec![list(vec![46.0.into_prop()])]),
+ ]),
+ list(vec![list(vec![list(vec![90.0.into_prop()])])]),
+ ]),
+ ),
+ ],
+ ),
+ (
+ 2,
+ "n3",
+ vec![
+ ("p_strs", list_str(&["a", "b", "c"])), // min: None, max: None, sum: None, avg: None, len: 3
+ ("p_bools", list_bool(&[true, false])), // min: None, max: None, sum: None, avg: None, len: 2
+ ("p_u8s", list_u8(&[1, 2, 3])), // min: 1, max: 3, sum: 6, avg: 2.0, len: 3
+ ("p_u16s", list_u16(&[1, 2, 3])), // min: 1, max: 3, sum: 6, avg: 2.0, len: 3
+ ("p_u32s", list_u32(&[1, 2, 3])), // min: 1, max: 3, sum: 6, avg: 2.0, len: 3
+ ("p_u64s", list_u64(&[1, 2, 3])), // min: 1, max: 3, sum: 6, avg: 2.0, len: 3
+ ("p_i32s", list_i32(&[1, 2, 3])), // min: 1, max: 3, sum: 6, avg: 2.0, len: 3
+ ("p_i64s", list_i64(&[1, 2, -3])), // min: -3, max: 2, sum: 0, avg: 0.0, len: 3
+ ("p_f32s", list_f32(&[1.0, 2.0, 3.5])), // min: 1.0, max: 3.5, sum: 6.5, avg: 2.1666666666666665, len: 3
+ ("p_f64s", list_f64(&[50.0, 40.0])), // min: 40.0, max: 50.0, sum: 90.0, avg: 45.0, len: 2
+ (
+ "nested_list",
+ list(vec![
+ list(vec![
+ list(vec![
+ list(vec![50.0.into_prop(), 40.0.into_prop()]),
+ list(vec![60.0.into_prop()]),
+ ]),
+ list(vec![list(vec![46.0.into_prop()])]),
+ ]),
+ list(vec![list(vec![list(vec![90.0.into_prop()])])]),
+ ]),
+ ),
+ ],
+ ),
+ (
+ 1,
+ "n4",
+ vec![
+ ("p_strs", list_str(&["a", "b", "c"])), // min: None, max: None, sum: None, avg: None, len: 3
+ ("p_bools", list_bool(&[true, false])), // min: None, max: None, sum: None, avg: None, len: 2
+ ("p_u64s", list_u64(&[1, 2, 3])), // min: 1, max: 3, sum: 6, avg: 2.0, len: 3
+ ("p_i32s", list_i32(&[1, 2, 3])), // min: 1, max: 3, sum: 6, avg: 2.0, len: 3
+ ("p_f32s", list_f32(&[1.0, 2.0, 3.5])), // min: 1.0, max: 3.5, sum: 6.5, avg: 2.1666666666666665, len: 3
+ ("p_bools_all", list_bool(&[true, true])),
+ ],
+ ),
+ (
+ 2,
+ "n4",
+ vec![
+ ("p_strs", list_str(&["x", "y", "z"])), // min: None, max: None, sum: None, avg: None, len: 3
+ ("p_bools", list_bool(&[false, false])), // min: None, max: None, sum: None, avg: None, len: 2
+ ("p_u64s", list_u64(&[10, 20, 30])), // min: 10, max: 30, sum: 60, avg: 20.0, len: 3
+ ("p_i32s", list_i32(&[10, 20, 30])), // min: 10, max: 30, sum: 60, avg: 20.0, len: 3
+ ("p_f32s", list_f32(&[10.0, 20.0, 30.0])), // min: 10.0, max: 30.0, sum: 60.0, avg: 20.0, len: 3
+ ("p_bools_all", list_bool(&[true, true])),
+ ],
+ ),
+ (
+ 2,
+ "n5",
+ vec![
+ ("p_u64s", list_u64(&[u64::MAX, 1])), // min: 1, max: u64::MAX, sum: None (overflow), avg: 9223372036854775808.0, len: 2
+ ("p_u64s_max", list_u64(&[u64::MAX, 1])), // min: 1, max: u64::MAX, sum: None (overflow), avg: 9223372036854775808.0, len: 2
+ ("p_u64s_min", list_u64(&[u64::MIN, 1])), // min: 1, max: u64::MAX, sum: None (overflow), avg: 9223372036854775808.0, len: 2
+ ("p_i64s", list_i64(&[i64::MAX, 1])), // min: 1, max: i64::MAX, sum: None (overflow), avg: 4611686018427387904.0, len: 2
+ ("p_i64s_max", list_i64(&[i64::MAX, 1])), // min: 1, max: i64::MAX, sum: None (overflow), avg: 4611686018427387904.0, len: 2
+ ("p_i64s_min", list_i64(&[i64::MIN, 1])), // min: 1, max: i64::MAX, sum: None (overflow), avg: 4611686018427387904.0, len: 2
+ ],
+ ),
+ (
+ 2,
+ "n6",
+ vec![
+ ("p_i32s", list_i32(&[-2, 1, 3])), // min: -2, max: 3, sum: 2, avg: 0.6666666666666666, len: 3
+ ],
+ ),
+ (
+ 1,
+ "n7",
+ vec![
+ ("p_u64s", list_u64(&[])), // min: None, max: None, sum: None, avg: None, len: 0
+ ],
+ ),
+ (
+ 2,
+ "n10",
+ vec![
+ ("p_strs", list_str(&["a", "b", "c"])), // min: None, max: None, sum: None, avg: None, len: 3
+ ("p_bools", list_bool(&[true, false])), // min: None, max: None, sum: None, avg: None, len: 2
+ ("p_u8s", list_u8(&[1, 2, 3])), // min: 1, max: 3, sum: 6, avg: 2.0, len: 3
+ ("p_u16s", list_u16(&[1, 2, 3])), // min: 1, max: 3, sum: 6, avg: 2.0, len: 3
+ ("p_u32s", list_u32(&[1, 2, 3])), // min: 1, max: 3, sum: 6, avg: 2.0, len: 3
+ ("p_u64s", list_u64(&[1, 2, 3])), // min: 1, max: 3, sum: 6, avg: 2.0, len: 3
+ ("p_i32s", list_i32(&[1, 2, 3])), // min: 1, max: 3, sum: 6, avg: 2.0, len: 3
+ ("p_i64s", list_i64(&[1, 2, -3])), // min: -3, max: 2, sum: 0, avg: 0.0, len: 3
+ ("p_f32s", list_f32(&[1.0, 2.0, 3.5])), // min: 1.0, max: 3.5, sum: 6.5, avg: 2.1666666666666665, len: 3
+ ("p_f64s", list_f64(&[50.0, 40.0])), // min: 40.0, max: 50.0, sum: 90.0, avg: 45.0, len: 2
+ ("p_bools_all", list_bool(&[true, true])),
+ ],
+ ),
+ ];
+
+ for (t, id, props) in nodes {
+ graph.add_node(t, id, props, None, None).unwrap();
+ }
+
+ // Each tuple represents (node_name, properties).
+ let metadata: [(&str, Vec<(&str, Prop)>); 8] = [
+ (
+ "n1",
+ vec![
+ ("p_u8s", list_u8(&[2, 9])), // min: 2, max: 9, sum: 11, avg: 5.5, len: 2
+ ("p_u16s", list_u16(&[3, 5])), // min: 3, max: 5, sum: 8, avg: 4.0, len: 2
+ ("p_u32s", list_u32(&[4, 9])), // min: 4, max: 9, sum: 13, avg: 6.5, len: 2
+ ],
+ ),
+ (
+ "n2",
+ vec![
+ ("p_u64s", list_u64(&[2, 3, 7])), // min: 2, max: 7, sum: 12, avg: 4.0, len: 3
+ ],
+ ),
+ (
+ "n3",
+ vec![
+ ("p_i32s", list_i32(&[10, 2, -3])), // min: -3, max: 10, sum: 9, avg: 3.0, len: 3
+ ("p_i64s", list_i64(&[1, 12, 3, 4])), // min: 1, max: 12, sum: 20, avg: 5.0, len: 4
+ ],
+ ),
+ (
+ "n4",
+ vec![
+ ("p_f32s", list_f32(&[1.5, 2.5])), // min: 1.5, max: 2.5, sum: 4.0, avg: 2.0, len: 2
+ ("p_f64s", list_f64(&[0.5, 1.5])), // min: 0.5, max: 1.5, sum: 2.0, avg: 1.0, len: 2
+ ],
+ ),
+ (
+ "n5",
+ vec![
+ ("p_strs", list_str(&["m1", "m2", "m3"])), // min: None, max: None, sum: None, avg: None, len: 3
+ ],
+ ),
+ (
+ "n6",
+ vec![
+ ("p_u64s", list_u64(&[])), // min: None, max: None, sum: None, avg: None, len: 0
+ ("p_strs", list_str(&["a", "a"])),
+ ],
+ ),
+ (
+ "n7",
+ vec![
+ ("p_u64s", list_u64(&[u64::MAX, 1])), // min: 1, max: u64::MAX, sum: None (overflow), avg: ~9.22e18, len: 2
+ ("p_strs", list_str(&["a"])),
+ ],
+ ),
+ (
+ "n10",
+ vec![
+ ("p_u64s", list_u64(&[1, 2, 3])), // min: 1, max: 3, sum: 6, avg: 2.0, len: 3
+ ("p_strs", list_str(&["a", "b", "c"])), // min: None, max: None, sum: None, avg: None, len: 3
+ ],
+ ),
+ ];
+
+ for (node_id, md) in metadata {
+ graph.node(node_id).unwrap().add_metadata(md).unwrap();
+ }
+
+ graph
+ }
+
+ fn apply_assertion(
+ filter: impl TryAsCompositeFilter + CreateFilter + Clone,
+ expected: &[&str],
+ ) {
+ assert_filter_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected,
+ All,
+ );
+
+ assert_search_nodes_results(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected,
+ All,
+ );
+ }
+
+ fn apply_assertion_err(
+ filter: impl TryAsCompositeFilter + CreateFilter + Clone,
+ expected: &str,
+ ) {
+ assert_filter_nodes_err(
+ init_nodes_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected,
+ All,
+ );
+
+ // assert_search_nodes_err(
+ // init_nodes_graph,
+ // IdentityGraphTransformer,
+ // filter,
+ // expected,
+ // All,
+ // );
+ }
+
+ // ------ Property: SUM ----
+ #[test]
+ fn test_node_property_sum_u8s() {
+ let filter = NodeFilter.property("p_u8s").sum().eq(Prop::U64(10));
+ let expected = vec!["n1"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_sum_u16s() {
+ let filter = NodeFilter.property("p_u16s").sum().eq(Prop::U64(6));
+ let expected = vec!["n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_sum_u32s() {
+ let filter = NodeFilter.property("p_u32s").sum().eq(Prop::U64(10));
+ let expected = vec!["n1"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_sum_u64s() {
+ let filter = NodeFilter.property("p_u64s").sum().eq(Prop::U64(6));
+ let expected = vec!["n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_sum_i32s() {
+ let filter = NodeFilter.property("p_i32s").sum().eq(Prop::I64(2));
+ let expected = vec!["n6"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_sum_i64s() {
+ let filter = NodeFilter.property("p_i64s").sum().eq(Prop::I64(0));
+ let expected = vec!["n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_sum_f32s() {
+ let filter = NodeFilter.property("p_f32s").sum().eq(Prop::F64(6.5));
+ let expected = vec!["n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_sum_f64s() {
+ let filter = NodeFilter.property("p_f64s").sum().eq(Prop::F64(120.0));
+ let expected = vec!["n1", "n2"];
+ apply_assertion(filter, &expected);
+ }
+
+ // ------ Property: AVG ----
+ #[test]
+ fn test_node_property_avg_u8s() {
+ let filter = NodeFilter.property("p_u8s").avg().eq(Prop::F64(2.5));
+ let expected = vec!["n1"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_avg_u16s() {
+ let filter = NodeFilter.property("p_u16s").avg().eq(Prop::F64(2.0));
+ let expected = vec!["n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_avg_u32s() {
+ let filter = NodeFilter.property("p_u32s").avg().eq(Prop::F64(2.5));
+ let expected = vec!["n1"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_avg_u64s() {
+ let filter = NodeFilter.property("p_u64s").avg().eq(Prop::F64(2.0));
+ let expected = vec!["n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_avg_i32s() {
+ let filter = NodeFilter
+ .property("p_i32s")
+ .avg()
+ .eq(Prop::F64(0.6666666666666666));
+ let expected = vec!["n6"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_avg_i64s() {
+ let filter = NodeFilter.property("p_i64s").avg().eq(Prop::F64(0.0));
+ let expected = vec!["n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_avg_f32s() {
+ let filter = NodeFilter
+ .property("p_f32s")
+ .avg()
+ .eq(Prop::F64(2.1666666666666665));
+ let expected = vec!["n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_avg_f64s() {
+ let filter = NodeFilter.property("p_f64s").avg().eq(Prop::F64(40.0));
+ let expected = vec!["n1", "n2"];
+ apply_assertion(filter, &expected);
+ }
+
+ // ------ Property: LEN ------
+ #[test]
+ fn test_node_property_len_u8s() {
+ let filter = NodeFilter.property("p_u8s").len().eq(Prop::U64(4));
+ let expected = vec!["n1"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_len_u16s() {
+ let filter = NodeFilter.property("p_u16s").len().eq(Prop::U64(3));
+ let expected = vec!["n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_len_u32s() {
+ let filter = NodeFilter.property("p_u32s").len().eq(Prop::U64(4));
+ let expected = vec!["n1"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_len_u64s() {
+ let filter = NodeFilter.property("p_u64s").len().eq(Prop::U64(3));
+ let expected = vec!["n10", "n3", "n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_len_i32s() {
+ let filter = NodeFilter.property("p_i32s").len().eq(Prop::U64(3));
+ let expected = vec!["n10", "n3", "n4", "n6"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_len_i64s() {
+ let filter = NodeFilter.property("p_i64s").len().eq(Prop::U64(3));
+ let expected = vec!["n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_len_f32s() {
+ let filter = NodeFilter.property("p_f32s").len().eq(Prop::U64(3));
+ let expected = vec!["n10", "n3", "n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_len_f64s() {
+ let filter = NodeFilter.property("p_f64s").len().eq(Prop::U64(3));
+ let expected = vec!["n1", "n2"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_len_strs() {
+ let filter = NodeFilter.property("p_strs").len().eq(Prop::U64(3));
+ let expected = vec!["n10", "n3", "n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ // ------ Property: MIN ------
+ #[test]
+ fn test_node_property_min_u8s() {
+ let filter = NodeFilter.property("p_u8s").min().eq(Prop::U8(1));
+ let expected = vec!["n1", "n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_min_u16s() {
+ let filter = NodeFilter.property("p_u16s").min().eq(Prop::U16(1));
+ let expected = vec!["n1", "n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_min_u32s() {
+ let filter = NodeFilter.property("p_u32s").min().eq(Prop::U32(1));
+ let expected = vec!["n1", "n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_min_u64s() {
+ let filter = NodeFilter.property("p_u64s").min().eq(Prop::U64(1));
+ let expected = vec!["n1", "n10", "n2", "n3", "n5"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_min_i32s() {
+ let filter = NodeFilter.property("p_i32s").min().eq(Prop::I32(-2));
+ let expected = vec!["n6"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_min_i64s() {
+ let filter = NodeFilter.property("p_i64s").min().eq(Prop::I64(-3));
+ let expected = vec!["n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_min_f32s() {
+ let filter = NodeFilter.property("p_f32s").min().eq(Prop::F32(10.0));
+ let expected = vec!["n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_min_f64s() {
+ let filter = NodeFilter.property("p_f64s").min().eq(Prop::F64(40.0));
+ let expected = vec!["n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ // ------ Property: MAX ------
+ #[test]
+ fn test_node_property_max_u8s() {
+ let filter = NodeFilter.property("p_u8s").max().eq(Prop::U8(4));
+ let expected = vec!["n1"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_max_u16s() {
+ let filter = NodeFilter.property("p_u16s").max().eq(Prop::U16(3));
+ let expected = vec!["n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_max_u32s() {
+ let filter = NodeFilter.property("p_u32s").max().eq(Prop::U32(4));
+ let expected = vec!["n1"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_max_u64s() {
+ let filter = NodeFilter.property("p_u64s").max().eq(Prop::U64(3));
+ let expected = vec!["n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_max_i32s() {
+ let filter = NodeFilter.property("p_i32s").max().eq(Prop::I32(3));
+ let expected = vec!["n10", "n3", "n6"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_max_i64s() {
+ let filter = NodeFilter.property("p_i64s").max().eq(Prop::I64(2));
+ let expected = vec!["n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_max_f32s() {
+ let filter = NodeFilter.property("p_f32s").max().eq(Prop::F32(30.0));
+ let expected = vec!["n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_max_f64s() {
+ let filter = NodeFilter.property("p_f64s").max().eq(Prop::F64(50.0));
+ let expected = vec!["n1", "n10", "n2", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ // ------ Metadata: SUM ------
+ #[test]
+ fn test_node_property_metadata_sum_u8s() {
+ let filter = NodeFilter.metadata("p_u8s").sum().eq(Prop::U64(11));
+ let expected = vec!["n1"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_metadata_sum_u16s() {
+ let filter = NodeFilter.metadata("p_u16s").sum().eq(Prop::U64(8));
+ let expected = vec!["n1"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_metadata_sum_u32s() {
+ let filter = NodeFilter.metadata("p_u32s").sum().eq(Prop::U64(13));
+ let expected = vec!["n1"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_metadata_sum_u64s() {
+ let filter = NodeFilter.metadata("p_u64s").sum().eq(Prop::U64(12));
+ let expected = vec!["n2"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_metadata_sum_i32s() {
+ let filter = NodeFilter.metadata("p_i32s").sum().eq(Prop::I64(9));
+ let expected = vec!["n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_metadata_sum_i64s() {
+ let filter = NodeFilter.metadata("p_i64s").sum().eq(Prop::I64(20));
+ let expected = vec!["n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_metadata_sum_f32s() {
+ let filter = NodeFilter.metadata("p_f32s").sum().eq(Prop::F64(4.0));
+ let expected = vec!["n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_metadata_sum_f64s() {
+ let filter = NodeFilter.metadata("p_f64s").sum().eq(Prop::F64(2.0));
+ let expected = vec!["n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ // ------ Metadata: AVG ------
+ #[test]
+ fn test_node_property_metadata_avg_u8s() {
+ let filter = NodeFilter.metadata("p_u8s").avg().eq(Prop::F64(5.5));
+ let expected = vec!["n1"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_metadata_avg_u16s() {
+ let filter = NodeFilter.metadata("p_u16s").avg().eq(Prop::F64(4.0));
+ let expected = vec!["n1"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_metadata_avg_u32s() {
+ let filter = NodeFilter.metadata("p_u32s").avg().eq(Prop::F64(6.5));
+ let expected = vec!["n1"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_metadata_avg_u64s() {
+ let filter = NodeFilter.metadata("p_u64s").avg().eq(Prop::F64(4.0));
+ let expected = vec!["n2"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_metadata_avg_i32s() {
+ let filter = NodeFilter.metadata("p_i32s").avg().eq(Prop::F64(3.0));
+ let expected = vec!["n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_metadata_avg_i64s() {
+ let filter = NodeFilter.metadata("p_i64s").avg().eq(Prop::F64(5.0));
+ let expected = vec!["n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_metadata_avg_f32s() {
+ let filter = NodeFilter.metadata("p_f32s").avg().eq(Prop::F64(2.0));
+ let expected = vec!["n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_metadata_avg_f64s() {
+ let filter = NodeFilter.metadata("p_f64s").avg().eq(Prop::F64(1.0));
+ let expected = vec!["n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ // ------ Metadata: MIN ------
+ #[test]
+ fn test_node_property_metadata_min_u8s() {
+ let filter = NodeFilter.metadata("p_u8s").min().eq(Prop::U8(2));
+ let expected = vec!["n1"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_metadata_min_u16s() {
+ let filter = NodeFilter.metadata("p_u16s").min().eq(Prop::U16(3));
+ let expected = vec!["n1"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_metadata_min_u32s() {
+ let filter = NodeFilter.metadata("p_u32s").min().eq(Prop::U32(4));
+ let expected = vec!["n1"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_metadata_min_u64s() {
+ let filter = NodeFilter.metadata("p_u64s").min().eq(Prop::U64(2));
+ let expected = vec!["n2"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_metadata_min_i32s() {
+ let filter = NodeFilter.metadata("p_i32s").min().eq(Prop::I32(-3));
+ let expected = vec!["n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_metadata_min_i64s() {
+ let filter = NodeFilter.metadata("p_i64s").min().eq(Prop::I64(1));
+ let expected = vec!["n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_metadata_min_f32s() {
+ let filter = NodeFilter.metadata("p_f32s").min().eq(Prop::F32(1.5));
+ let expected = vec!["n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_metadata_min_f64s() {
+ let filter = NodeFilter.metadata("p_f64s").min().eq(Prop::F64(0.5));
+ let expected = vec!["n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ // ------ Metadata: MAX ------
+ #[test]
+ fn test_node_property_metadata_max_u8s() {
+ let filter = NodeFilter.metadata("p_u8s").max().eq(Prop::U8(9));
+ let expected = vec!["n1"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_metadata_max_u16s() {
+ let filter = NodeFilter.metadata("p_u16s").max().eq(Prop::U16(5));
+ let expected = vec!["n1"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_metadata_max_u32s() {
+ let filter = NodeFilter.metadata("p_u32s").max().eq(Prop::U32(9));
+ let expected = vec!["n1"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_metadata_max_u64s() {
+ let filter = NodeFilter.metadata("p_u64s").max().eq(Prop::U64(7));
+ let expected = vec!["n2"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_metadata_max_i32s() {
+ let filter = NodeFilter.metadata("p_i32s").max().eq(Prop::I32(10));
+ let expected = vec!["n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_metadata_max_i64s() {
+ let filter = NodeFilter.metadata("p_i64s").max().eq(Prop::I64(12));
+ let expected = vec!["n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_metadata_max_f32s() {
+ let filter = NodeFilter.metadata("p_f32s").max().eq(Prop::F32(2.5));
+ let expected = vec!["n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_metadata_max_f64s() {
+ let filter = NodeFilter.metadata("p_f64s").max().eq(Prop::F64(1.5));
+ let expected = vec!["n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ // ------ Metadata: Len ------
+ #[test]
+ fn test_node_property_metadata_len_u8s() {
+ let filter = NodeFilter.metadata("p_u8s").len().eq(Prop::U64(2));
+ let expected = vec!["n1"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_metadata_len_u16s() {
+ let filter = NodeFilter.metadata("p_u16s").len().eq(Prop::U64(2));
+ let expected = vec!["n1"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_metadata_len_u32s() {
+ let filter = NodeFilter.metadata("p_u32s").len().eq(Prop::U64(2));
+ let expected = vec!["n1"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_metadata_len_u64s() {
+ let filter = NodeFilter.metadata("p_u64s").len().eq(Prop::U64(3));
+ let expected = vec!["n10", "n2"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_metadata_len_i32s() {
+ let filter = NodeFilter.metadata("p_i32s").len().eq(Prop::U64(3));
+ let expected = vec!["n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_metadata_len_i64s() {
+ let filter = NodeFilter.metadata("p_i64s").len().eq(Prop::U64(4));
+ let expected = vec!["n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_metadata_len_f32s() {
+ let filter = NodeFilter.metadata("p_f32s").len().eq(Prop::U64(2));
+ let expected = vec!["n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_metadata_len_f64s() {
+ let filter = NodeFilter.metadata("p_f64s").len().eq(Prop::U64(2));
+ let expected = vec!["n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_metadata_len_strs() {
+ let filter = NodeFilter.metadata("p_strs").len().eq(Prop::U64(3));
+ let expected = vec!["n10", "n5"];
+ apply_assertion(filter, &expected);
+ }
+
+ // ------ Temporal last: SUM ------
+ #[test]
+ fn test_node_property_temporal_last_sum_u8s() {
+ let filter = NodeFilter
+ .property("p_u8s")
+ .temporal()
+ .last()
+ .sum()
+ .eq(Prop::U64(10));
+ let expected = vec!["n1"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_last_sum_u16s() {
+ let filter = NodeFilter
+ .property("p_u16s")
+ .temporal()
+ .last()
+ .sum()
+ .eq(Prop::U64(6));
+ let expected = vec!["n3", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_last_sum_u32s() {
+ let filter = NodeFilter
+ .property("p_u32s")
+ .temporal()
+ .last()
+ .sum()
+ .eq(Prop::U64(10));
+ let expected = vec!["n1"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_last_sum_u64s() {
+ let filter = NodeFilter
+ .property("p_u64s")
+ .temporal()
+ .last()
+ .sum()
+ .eq(Prop::U64(60));
+ let expected = vec!["n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_last_sum_i32s() {
+ let filter = NodeFilter
+ .property("p_i32s")
+ .temporal()
+ .last()
+ .sum()
+ .eq(Prop::I64(60));
+ let expected = vec!["n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_last_sum_i64s() {
+ let filter = NodeFilter
+ .property("p_i64s")
+ .temporal()
+ .last()
+ .sum()
+ .eq(Prop::I64(0));
+ let expected = vec!["n3", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_last_sum_f32s() {
+ let filter = NodeFilter
+ .property("p_f32s")
+ .temporal()
+ .last()
+ .sum()
+ .eq(Prop::F64(6.5));
+ let expected = vec!["n3", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_last_sum_f64s() {
+ let filter = NodeFilter
+ .property("p_f64s")
+ .temporal()
+ .last()
+ .sum()
+ .eq(Prop::F64(90.0));
+ let expected = vec!["n3", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ // ------ Temporal last: AVG ------
+ #[test]
+ fn test_node_property_temporal_last_avg_u8s() {
+ let filter = NodeFilter
+ .property("p_u8s")
+ .temporal()
+ .last()
+ .avg()
+ .eq(Prop::F64(2.5));
+ let expected = vec!["n1"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_last_avg_u16s() {
+ let filter = NodeFilter
+ .property("p_u16s")
+ .temporal()
+ .last()
+ .avg()
+ .eq(Prop::F64(2.0));
+ let expected = vec!["n3", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_last_avg_u32s() {
+ let filter = NodeFilter
+ .property("p_u32s")
+ .temporal()
+ .last()
+ .avg()
+ .eq(Prop::F64(2.5));
+ let expected = vec!["n1"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_last_avg_u64s() {
+ let filter = NodeFilter
+ .property("p_u64s")
+ .temporal()
+ .last()
+ .avg()
+ .eq(Prop::F64(20.0));
+ let expected = vec!["n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_last_avg_i32s() {
+ let filter = NodeFilter
+ .property("p_i32s")
+ .temporal()
+ .last()
+ .avg()
+ .eq(Prop::F64(0.6666666666666666));
+ let expected = vec!["n6"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_last_avg_i64s() {
+ let filter = NodeFilter
+ .property("p_i64s")
+ .temporal()
+ .last()
+ .avg()
+ .eq(Prop::F64(0.0));
+ let expected = vec!["n3", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_last_avg_f32s() {
+ let filter = NodeFilter
+ .property("p_f32s")
+ .temporal()
+ .last()
+ .avg()
+ .eq(Prop::F64(20.0));
+ let expected = vec!["n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_last_avg_f64s() {
+ let filter = NodeFilter
+ .property("p_f64s")
+ .temporal()
+ .last()
+ .avg()
+ .eq(Prop::F64(45.0));
+ let expected = vec!["n3", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ // ------ Temporal last: MIN ------
+ #[test]
+ fn test_node_property_temporal_last_min_u8s() {
+ let filter = NodeFilter
+ .property("p_u8s")
+ .temporal()
+ .last()
+ .min()
+ .eq(Prop::U8(1));
+ let expected = vec!["n1", "n3", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_last_min_u16s() {
+ let filter = NodeFilter
+ .property("p_u16s")
+ .temporal()
+ .last()
+ .min()
+ .eq(Prop::U16(1));
+ let expected = vec!["n1", "n3", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_last_min_u32s() {
+ let filter = NodeFilter
+ .property("p_u32s")
+ .temporal()
+ .last()
+ .min()
+ .eq(Prop::U32(1));
+ let expected = vec!["n1", "n3", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_last_min_u64s() {
+ let filter = NodeFilter
+ .property("p_u64s")
+ .temporal()
+ .last()
+ .min()
+ .eq(Prop::U64(10));
+ let expected = vec!["n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_last_min_i32s() {
+ let filter = NodeFilter
+ .property("p_i32s")
+ .temporal()
+ .last()
+ .min()
+ .eq(Prop::I32(-2));
+ let expected = vec!["n6"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_last_min_i64s() {
+ let filter = NodeFilter
+ .property("p_i64s")
+ .temporal()
+ .last()
+ .min()
+ .eq(Prop::I64(-3));
+ let expected = vec!["n3", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_last_min_f32s() {
+ let filter = NodeFilter
+ .property("p_f32s")
+ .temporal()
+ .last()
+ .min()
+ .eq(Prop::F32(10.0));
+ let expected = vec!["n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_last_min_f64s() {
+ let filter = NodeFilter
+ .property("p_f64s")
+ .temporal()
+ .last()
+ .min()
+ .eq(Prop::F64(40.0));
+ let expected = vec!["n3", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ // ------ Temporal last: MAX ------
+ #[test]
+ fn test_node_property_temporal_last_max_u8s() {
+ let filter = NodeFilter
+ .property("p_u8s")
+ .temporal()
+ .last()
+ .max()
+ .eq(Prop::U8(4));
+ let expected = vec!["n1"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_last_max_u16s() {
+ let filter = NodeFilter
+ .property("p_u16s")
+ .temporal()
+ .last()
+ .max()
+ .eq(Prop::U16(3));
+ let expected = vec!["n3", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_last_max_u32s() {
+ let filter = NodeFilter
+ .property("p_u32s")
+ .temporal()
+ .last()
+ .max()
+ .eq(Prop::U32(4));
+ let expected = vec!["n1"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_last_max_u64s() {
+ let filter = NodeFilter
+ .property("p_u64s")
+ .temporal()
+ .last()
+ .max()
+ .eq(Prop::U64(30));
+ let expected = vec!["n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_last_max_i32s() {
+ let filter = NodeFilter
+ .property("p_i32s")
+ .temporal()
+ .last()
+ .max()
+ .eq(Prop::I32(3));
+ let expected = vec!["n3", "n6", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_last_max_i64s() {
+ let filter = NodeFilter
+ .property("p_i64s")
+ .temporal()
+ .last()
+ .max()
+ .eq(Prop::I64(2));
+ let expected = vec!["n3", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_last_max_f32s() {
+ let filter = NodeFilter
+ .property("p_f32s")
+ .temporal()
+ .last()
+ .max()
+ .eq(Prop::F32(3.5));
+ let expected = vec!["n3", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_last_max_f64s() {
+ let filter = NodeFilter
+ .property("p_f64s")
+ .temporal()
+ .last()
+ .max()
+ .eq(Prop::F64(50.0));
+ let expected = vec!["n1", "n2", "n3", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ // ------ Temporal last: LEN ------
+ #[test]
+ fn test_node_property_temporal_last_len_u8s() {
+ let filter = NodeFilter
+ .property("p_u8s")
+ .temporal()
+ .last()
+ .len()
+ .eq(Prop::U64(3));
+ let expected = vec!["n3", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_last_len_u16s() {
+ let filter = NodeFilter
+ .property("p_u16s")
+ .temporal()
+ .last()
+ .len()
+ .eq(Prop::U64(3));
+ let expected = vec!["n3", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_last_len_u32s() {
+ let filter = NodeFilter
+ .property("p_u32s")
+ .temporal()
+ .last()
+ .len()
+ .eq(Prop::U64(3));
+ let expected = vec!["n3", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_last_len_u64s() {
+ let filter = NodeFilter
+ .property("p_u64s")
+ .temporal()
+ .last()
+ .len()
+ .eq(Prop::U64(3));
+ let expected = vec!["n3", "n4", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_last_len_i32s() {
+ let filter = NodeFilter
+ .property("p_i32s")
+ .temporal()
+ .last()
+ .len()
+ .eq(Prop::U64(3));
+ let expected = vec!["n3", "n4", "n6", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_last_len_i64s() {
+ let filter = NodeFilter
+ .property("p_i64s")
+ .temporal()
+ .last()
+ .len()
+ .eq(Prop::U64(3));
+ let expected = vec!["n3", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_last_len_f32s() {
+ let filter = NodeFilter
+ .property("p_f32s")
+ .temporal()
+ .last()
+ .len()
+ .eq(Prop::U64(3));
+ let expected = vec!["n3", "n4", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_last_len_f64s() {
+ let filter = NodeFilter
+ .property("p_f64s")
+ .temporal()
+ .last()
+ .len()
+ .eq(Prop::U64(2));
+ let expected = vec!["n3", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ // ------ Temporal all: SUM ------
+ #[test]
+ fn test_node_property_temporal_all_sum_u8s() {
+ let filter = NodeFilter
+ .property("p_u8s")
+ .temporal()
+ .all()
+ .sum()
+ .eq(Prop::U64(6));
+ let expected = vec!["n3", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_all_sum_u16s() {
+ let filter = NodeFilter
+ .property("p_u16s")
+ .temporal()
+ .all()
+ .sum()
+ .eq(Prop::U64(6));
+ let expected = vec!["n3", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_all_sum_u32s() {
+ let filter = NodeFilter
+ .property("p_u32s")
+ .temporal()
+ .all()
+ .sum()
+ .eq(Prop::U64(6));
+ let expected = vec!["n3", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_all_sum_u64s() {
+ let filter = NodeFilter
+ .property("p_u64s")
+ .temporal()
+ .all()
+ .sum()
+ .eq(Prop::U64(6));
+ let expected = vec!["n3", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_all_sum_i32s() {
+ let filter = NodeFilter
+ .property("p_i32s")
+ .temporal()
+ .all()
+ .sum()
+ .eq(Prop::I64(6));
+ let expected = vec!["n3", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_all_sum_i64s() {
+ let filter = NodeFilter
+ .property("p_i64s")
+ .temporal()
+ .all()
+ .sum()
+ .eq(Prop::I64(0));
+ let expected = vec!["n3", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_all_sum_f32s() {
+ let filter = NodeFilter
+ .property("p_f32s")
+ .temporal()
+ .all()
+ .sum()
+ .eq(Prop::F64(6.5));
+ let expected = vec!["n3", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_all_sum_f64s() {
+ let filter = NodeFilter
+ .property("p_f64s")
+ .temporal()
+ .all()
+ .sum()
+ .eq(Prop::F64(90.0));
+ let expected = vec!["n3", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ // ------ Temporal all: AVG ------
+ #[test]
+ fn test_node_property_temporal_all_avg_u8s() {
+ let filter = NodeFilter
+ .property("p_u8s")
+ .temporal()
+ .all()
+ .avg()
+ .eq(Prop::F64(2.0));
+ let expected = vec!["n3", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_all_avg_u16s() {
+ let filter = NodeFilter
+ .property("p_u16s")
+ .temporal()
+ .all()
+ .avg()
+ .eq(Prop::F64(2.0));
+ let expected = vec!["n3", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_all_avg_u32s() {
+ let filter = NodeFilter
+ .property("p_u32s")
+ .temporal()
+ .all()
+ .avg()
+ .eq(Prop::F64(2.0));
+ let expected = vec!["n3", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_all_avg_u64s() {
+ let filter = NodeFilter
+ .property("p_u64s")
+ .temporal()
+ .all()
+ .avg()
+ .eq(Prop::F64(2.0));
+ let expected = vec!["n3", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_all_avg_i32s() {
+ let filter = NodeFilter
+ .property("p_i32s")
+ .temporal()
+ .all()
+ .avg()
+ .eq(Prop::F64(2.0));
+ let expected = vec!["n3", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_all_avg_i64s() {
+ let filter = NodeFilter
+ .property("p_i64s")
+ .temporal()
+ .all()
+ .avg()
+ .eq(Prop::F64(0.0));
+ let expected = vec!["n3", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_all_avg_f32s() {
+ let filter = NodeFilter
+ .property("p_f32s")
+ .temporal()
+ .all()
+ .avg()
+ .eq(Prop::F64(2.1666666666666665));
+ let expected = vec!["n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_all_avg_f64s() {
+ let filter = NodeFilter
+ .property("p_f64s")
+ .temporal()
+ .all()
+ .avg()
+ .eq(Prop::F64(45.0));
+ let expected = vec!["n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ // ------ Temporal all: MIN ------
+ #[test]
+ fn test_node_property_temporal_all_min_u8s() {
+ let filter = NodeFilter
+ .property("p_u8s")
+ .temporal()
+ .all()
+ .min()
+ .eq(Prop::U8(1));
+ let expected = vec!["n1", "n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_all_min_u16s() {
+ let filter = NodeFilter
+ .property("p_u16s")
+ .temporal()
+ .all()
+ .min()
+ .eq(Prop::U16(1));
+ let expected = vec!["n1", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_all_min_u32s() {
+ let filter = NodeFilter
+ .property("p_u32s")
+ .temporal()
+ .all()
+ .min()
+ .eq(Prop::U32(1));
+ let expected = vec!["n1", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_all_min_u64s() {
+ let filter = NodeFilter
+ .property("p_u64s")
+ .temporal()
+ .all()
+ .min()
+ .eq(Prop::U64(1));
+ let expected = vec!["n1", "n10", "n2", "n5"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_all_min_i32s() {
+ let filter = NodeFilter
+ .property("p_i32s")
+ .temporal()
+ .all()
+ .min()
+ .eq(Prop::I32(-2));
+ let expected = vec!["n6"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_all_min_i64s() {
+ let filter = NodeFilter
+ .property("p_i64s")
+ .temporal()
+ .all()
+ .min()
+ .eq(Prop::I64(-3));
+ let expected = vec!["n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_all_min_f32s() {
+ let filter = NodeFilter
+ .property("p_f32s")
+ .temporal()
+ .all()
+ .min()
+ .eq(Prop::F32(1.0));
+ let expected = vec!["n1", "n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_all_min_f64s() {
+ let filter = NodeFilter
+ .property("p_f64s")
+ .temporal()
+ .all()
+ .min()
+ .eq(Prop::F64(30.0));
+ let expected = vec!["n2"];
+ apply_assertion(filter, &expected);
+ }
+
+ // ------ Temporal all: MAX ------
+ #[test]
+ fn test_node_property_temporal_all_max_u8s() {
+ let filter = NodeFilter
+ .property("p_u8s")
+ .temporal()
+ .all()
+ .max()
+ .eq(Prop::U8(3));
+ let expected = vec!["n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_all_max_u16s() {
+ let filter = NodeFilter
+ .property("p_u16s")
+ .temporal()
+ .all()
+ .max()
+ .eq(Prop::U16(3));
+ let expected = vec!["n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_all_max_u32s() {
+ let filter = NodeFilter
+ .property("p_u32s")
+ .temporal()
+ .all()
+ .max()
+ .eq(Prop::U32(3));
+ let expected = vec!["n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_all_max_u64s() {
+ let filter = NodeFilter
+ .property("p_u64s")
+ .temporal()
+ .all()
+ .max()
+ .eq(Prop::U64(4));
+ let expected = vec!["n2"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_all_max_i32s() {
+ let filter = NodeFilter
+ .property("p_i32s")
+ .temporal()
+ .all()
+ .max()
+ .eq(Prop::I32(3));
+ let expected = vec!["n10", "n6"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_all_max_i64s() {
+ let filter = NodeFilter
+ .property("p_i64s")
+ .temporal()
+ .all()
+ .max()
+ .eq(Prop::I64(2));
+ let expected = vec!["n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_all_max_f32s() {
+ let filter = NodeFilter
+ .property("p_f32s")
+ .temporal()
+ .all()
+ .max()
+ .eq(Prop::F32(3.5));
+ let expected = vec!["n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_all_max_f64s() {
+ let filter = NodeFilter
+ .property("p_f64s")
+ .temporal()
+ .all()
+ .max()
+ .eq(Prop::F64(50.0));
+ let expected = vec!["n1", "n10", "n2"];
+ apply_assertion(filter, &expected);
+ }
+
+ // ------ Temporal all: LEN ------
+ #[test]
+ fn test_node_property_temporal_all_len_u8s() {
+ let filter = NodeFilter
+ .property("p_u8s")
+ .temporal()
+ .all()
+ .len()
+ .eq(Prop::U64(3));
+ let expected = vec!["n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_all_len_u16s() {
+ let filter = NodeFilter
+ .property("p_u16s")
+ .temporal()
+ .all()
+ .len()
+ .eq(Prop::U64(3));
+ let expected = vec!["n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_all_len_u32s() {
+ let filter = NodeFilter
+ .property("p_u32s")
+ .temporal()
+ .all()
+ .len()
+ .eq(Prop::U64(3));
+ let expected = vec!["n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_all_len_u64s() {
+ let filter = NodeFilter
+ .property("p_u64s")
+ .temporal()
+ .all()
+ .len()
+ .eq(Prop::U64(4));
+ let expected = vec!["n2"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_all_len_i32s() {
+ let filter = NodeFilter
+ .property("p_i32s")
+ .temporal()
+ .all()
+ .len()
+ .eq(Prop::U64(3));
+ let expected = vec!["n10", "n3", "n4", "n6"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_all_len_i64s() {
+ let filter = NodeFilter
+ .property("p_i64s")
+ .temporal()
+ .all()
+ .len()
+ .eq(Prop::U64(2));
+ let expected = vec!["n5"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_all_len_f32s() {
+ let filter = NodeFilter
+ .property("p_f32s")
+ .temporal()
+ .all()
+ .len()
+ .eq(Prop::U64(3));
+ let expected = vec!["n10", "n3", "n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_all_len_f64s() {
+ let filter = NodeFilter
+ .property("p_f64s")
+ .temporal()
+ .all()
+ .len()
+ .eq(Prop::U64(2));
+ let expected = vec!["n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ // ------ Temporal first: SUM ------
+ #[test]
+ fn test_node_property_temporal_first_sum_u8s() {
+ let filter = NodeFilter
+ .property("p_u8s")
+ .temporal()
+ .first()
+ .sum()
+ .eq(Prop::U64(6));
+ let expected = vec!["n1", "n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_first_sum_u16s() {
+ let filter = NodeFilter
+ .property("p_u16s")
+ .temporal()
+ .first()
+ .sum()
+ .eq(Prop::U64(6));
+ let expected = vec!["n1", "n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_first_sum_u32s() {
+ let filter = NodeFilter
+ .property("p_u32s")
+ .temporal()
+ .first()
+ .sum()
+ .eq(Prop::U64(6));
+ let expected = vec!["n1", "n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_first_sum_u64s() {
+ let filter = NodeFilter
+ .property("p_u64s")
+ .temporal()
+ .first()
+ .sum()
+ .eq(Prop::U64(6));
+ let expected = vec!["n1", "n10", "n3", "n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_first_sum_i32s() {
+ let filter = NodeFilter
+ .property("p_i32s")
+ .temporal()
+ .first()
+ .sum()
+ .eq(Prop::I64(6));
+ let expected = vec!["n1", "n10", "n3", "n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_first_sum_i64s() {
+ let filter = NodeFilter
+ .property("p_i64s")
+ .temporal()
+ .first()
+ .sum()
+ .eq(Prop::I64(0));
+ let expected = vec!["n3", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_first_sum_f32s() {
+ let filter = NodeFilter
+ .property("p_f32s")
+ .temporal()
+ .first()
+ .sum()
+ .eq(Prop::F64(6.5));
+ let expected = vec!["n1", "n10", "n3", "n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_first_sum_f64s() {
+ let filter = NodeFilter
+ .property("p_f64s")
+ .temporal()
+ .first()
+ .sum()
+ .eq(Prop::F64(90.0));
+ let expected = vec!["n1", "n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ // ------ Temporal first: AVG ------
+ #[test]
+ fn test_node_property_temporal_first_avg_u8s() {
+ let filter = NodeFilter
+ .property("p_u8s")
+ .temporal()
+ .first()
+ .avg()
+ .eq(Prop::F64(2.0));
+ let expected = vec!["n1", "n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_first_avg_u16s() {
+ let filter = NodeFilter
+ .property("p_u16s")
+ .temporal()
+ .first()
+ .avg()
+ .eq(Prop::F64(2.0));
+ let expected = vec!["n1", "n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_first_avg_u32s() {
+ let filter = NodeFilter
+ .property("p_u32s")
+ .temporal()
+ .first()
+ .avg()
+ .eq(Prop::F64(2.0));
+ let expected = vec!["n1", "n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_first_avg_u64s() {
+ let filter = NodeFilter
+ .property("p_u64s")
+ .temporal()
+ .first()
+ .avg()
+ .eq(Prop::F64(2.0));
+ let expected = vec!["n1", "n10", "n3", "n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_first_avg_i32s() {
+ let filter = NodeFilter
+ .property("p_i32s")
+ .temporal()
+ .first()
+ .avg()
+ .eq(Prop::F64(2.0));
+ let expected = vec!["n1", "n10", "n3", "n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_first_avg_i64s() {
+ let filter = NodeFilter
+ .property("p_i64s")
+ .temporal()
+ .first()
+ .avg()
+ .eq(Prop::F64(0.0));
+ let expected = vec!["n3", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_first_avg_f32s() {
+ let filter = NodeFilter
+ .property("p_f32s")
+ .temporal()
+ .first()
+ .avg()
+ .eq(Prop::F64(2.1666666666666665));
+ let expected = vec!["n1", "n10", "n3", "n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_first_avg_f64s() {
+ let filter = NodeFilter
+ .property("p_f64s")
+ .temporal()
+ .first()
+ .avg()
+ .eq(Prop::F64(45.0));
+ let expected = vec!["n1", "n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ // ------ Temporal first: MIN ------
+ #[test]
+ fn test_node_property_temporal_first_min_u8s() {
+ let filter = NodeFilter
+ .property("p_u8s")
+ .temporal()
+ .first()
+ .min()
+ .eq(Prop::U8(1));
+ let expected = vec!["n1", "n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_first_min_u16s() {
+ let filter = NodeFilter
+ .property("p_u16s")
+ .temporal()
+ .first()
+ .min()
+ .eq(Prop::U16(1));
+ let expected = vec!["n1", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_first_min_u32s() {
+ let filter = NodeFilter
+ .property("p_u32s")
+ .temporal()
+ .first()
+ .min()
+ .eq(Prop::U32(1));
+ let expected = vec!["n1", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_first_min_u64s() {
+ let filter = NodeFilter
+ .property("p_u64s")
+ .temporal()
+ .first()
+ .min()
+ .eq(Prop::U64(1));
+ let expected = vec!["n1", "n10", "n2", "n4", "n5"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_first_min_i32s() {
+ let filter = NodeFilter
+ .property("p_i32s")
+ .temporal()
+ .first()
+ .min()
+ .eq(Prop::I32(-2));
+ let expected = vec!["n6"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_first_min_i64s() {
+ let filter = NodeFilter
+ .property("p_i64s")
+ .temporal()
+ .first()
+ .min()
+ .eq(Prop::I64(-3));
+ let expected = vec!["n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_first_min_f32s() {
+ let filter = NodeFilter
+ .property("p_f32s")
+ .temporal()
+ .first()
+ .min()
+ .eq(Prop::F32(1.0));
+ let expected = vec!["n1", "n10", "n3", "n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_first_min_f64s() {
+ let filter = NodeFilter
+ .property("p_f64s")
+ .temporal()
+ .first()
+ .min()
+ .eq(Prop::F64(30.0));
+ let expected = vec!["n2", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ // ------ Temporal first: MAX ------
+ #[test]
+ fn test_node_property_temporal_first_max_u8s() {
+ let filter = NodeFilter
+ .property("p_u8s")
+ .temporal()
+ .first()
+ .max()
+ .eq(Prop::U8(3));
+ let expected = vec!["n1", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_first_max_u16s() {
+ let filter = NodeFilter
+ .property("p_u16s")
+ .temporal()
+ .first()
+ .max()
+ .eq(Prop::U16(3));
+ let expected = vec!["n1", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_first_max_u32s() {
+ let filter = NodeFilter
+ .property("p_u32s")
+ .temporal()
+ .first()
+ .max()
+ .eq(Prop::U32(3));
+ let expected = vec!["n1", "n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_first_max_u64s() {
+ let filter = NodeFilter
+ .property("p_u64s")
+ .temporal()
+ .first()
+ .max()
+ .eq(Prop::U64(4));
+ let expected = vec!["n2"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_first_max_i32s() {
+ let filter = NodeFilter
+ .property("p_i32s")
+ .temporal()
+ .first()
+ .max()
+ .eq(Prop::I32(3));
+ let expected = vec!["n1", "n10", "n4", "n6"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_first_max_i64s() {
+ let filter = NodeFilter
+ .property("p_i64s")
+ .temporal()
+ .first()
+ .max()
+ .eq(Prop::I64(2));
+ let expected = vec!["n10"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_first_max_f32s() {
+ let filter = NodeFilter
+ .property("p_f32s")
+ .temporal()
+ .first()
+ .max()
+ .eq(Prop::F32(3.5));
+ let expected = vec!["n1", "n10", "n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_first_max_f64s() {
+ let filter = NodeFilter
+ .property("p_f64s")
+ .temporal()
+ .first()
+ .max()
+ .eq(Prop::F64(50.0));
+ let expected = vec!["n1", "n10", "n2"];
+ apply_assertion(filter, &expected);
+ }
+
+ // ------ Temporal first: LEN ------
+ #[test]
+ fn test_node_property_temporal_first_len_u8s() {
+ let filter = NodeFilter
+ .property("p_u8s")
+ .temporal()
+ .first()
+ .len()
+ .eq(Prop::U64(3));
+ let expected = vec!["n1", "n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_first_len_u16s() {
+ let filter = NodeFilter
+ .property("p_u16s")
+ .temporal()
+ .first()
+ .len()
+ .eq(Prop::U64(3));
+ let expected = vec!["n1", "n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_first_len_u32s() {
+ let filter = NodeFilter
+ .property("p_u32s")
+ .temporal()
+ .first()
+ .len()
+ .eq(Prop::U64(3));
+ let expected = vec!["n1", "n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_first_len_u64s() {
+ let filter = NodeFilter
+ .property("p_u64s")
+ .temporal()
+ .first()
+ .len()
+ .eq(Prop::U64(4));
+ let expected = vec!["n2"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_first_len_i32s() {
+ let filter = NodeFilter
+ .property("p_i32s")
+ .temporal()
+ .first()
+ .len()
+ .eq(Prop::U64(3));
+ let expected = vec!["n1", "n10", "n3", "n4", "n6"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_first_len_i64s() {
+ let filter = NodeFilter
+ .property("p_i64s")
+ .temporal()
+ .first()
+ .len()
+ .eq(Prop::U64(2));
+ let expected = vec!["n5"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_first_len_f32s() {
+ let filter = NodeFilter
+ .property("p_f32s")
+ .temporal()
+ .first()
+ .len()
+ .eq(Prop::U64(3));
+ let expected = vec!["n1", "n10", "n3", "n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_first_len_f64s() {
+ let filter = NodeFilter
+ .property("p_f64s")
+ .temporal()
+ .first()
+ .len()
+ .eq(Prop::U64(2));
+ let expected = vec!["n1", "n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ // ------ Temporal any: SUM ------
+ #[test]
+ fn test_node_property_temporal_any_sum_u8s() {
+ let filter = NodeFilter
+ .property("p_u8s")
+ .temporal()
+ .any()
+ .sum()
+ .eq(Prop::U64(6));
+ let expected = vec!["n1", "n10", "n3"];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter
+ .property("p_u8s")
+ .temporal()
+ .any()
+ .sum()
+ .eq(Prop::U64(10));
+ let expected = vec!["n1"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_any_sum_u16s() {
+ let filter = NodeFilter
+ .property("p_u16s")
+ .temporal()
+ .any()
+ .sum()
+ .eq(Prop::U64(6));
+ let expected = vec!["n1", "n10", "n3"];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter
+ .property("p_u16s")
+ .temporal()
+ .any()
+ .sum()
+ .eq(Prop::U64(10));
+ let expected = vec!["n1"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_any_sum_u32s() {
+ let filter = NodeFilter
+ .property("p_u32s")
+ .temporal()
+ .any()
+ .sum()
+ .eq(Prop::U64(6));
+ let expected = vec!["n1", "n10", "n3"];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter
+ .property("p_u32s")
+ .temporal()
+ .any()
+ .sum()
+ .eq(Prop::U64(10));
+ let expected = vec!["n1"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_any_sum_u64s() {
+ let filter = NodeFilter
+ .property("p_u64s")
+ .temporal()
+ .any()
+ .sum()
+ .eq(Prop::U64(6));
+ let expected = vec!["n1", "n10", "n3", "n4"];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter
+ .property("p_u64s")
+ .temporal()
+ .any()
+ .sum()
+ .eq(Prop::U64(10));
+ let expected = vec!["n1", "n2"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_any_sum_i32s() {
+ let filter = NodeFilter
+ .property("p_i32s")
+ .temporal()
+ .any()
+ .sum()
+ .eq(Prop::I64(6));
+ let expected = vec!["n1", "n10", "n3", "n4"];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter
+ .property("p_i32s")
+ .temporal()
+ .any()
+ .sum()
+ .eq(Prop::I64(60));
+ let expected = vec!["n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_any_sum_i64s() {
+ let filter = NodeFilter
+ .property("p_i64s")
+ .temporal()
+ .any()
+ .sum()
+ .eq(Prop::I64(0));
+ let expected = vec!["n3", "n10"];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter
+ .property("p_i64s")
+ .temporal()
+ .any()
+ .sum()
+ .eq(Prop::I64(10));
+ let expected = vec!["n1"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_any_sum_f32s() {
+ let filter = NodeFilter
+ .property("p_f32s")
+ .temporal()
+ .any()
+ .sum()
+ .eq(Prop::F64(6.5));
+ let expected = vec!["n1", "n10", "n3", "n4"];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter
+ .property("p_f32s")
+ .temporal()
+ .any()
+ .sum()
+ .eq(Prop::F64(60.0));
+ let expected = vec!["n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_any_sum_f64s() {
+ let filter = NodeFilter
+ .property("p_f64s")
+ .temporal()
+ .any()
+ .sum()
+ .eq(Prop::F64(90.0));
+ let expected = vec!["n1", "n10", "n3"];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter
+ .property("p_f64s")
+ .temporal()
+ .any()
+ .sum()
+ .eq(Prop::F64(120.0));
+ let expected = vec!["n1", "n2"];
+ apply_assertion(filter, &expected);
+ }
+
+ // ------ Temporal any: AVG ------
+ #[test]
+ fn test_node_property_temporal_any_avg_u8s() {
+ let filter = NodeFilter
+ .property("p_u8s")
+ .temporal()
+ .any()
+ .avg()
+ .eq(Prop::F64(2.0));
+ let expected = vec!["n1", "n10", "n3"];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter
+ .property("p_u8s")
+ .temporal()
+ .any()
+ .avg()
+ .eq(Prop::F64(2.5));
+ let expected = vec!["n1"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_any_avg_u16s() {
+ let filter = NodeFilter
+ .property("p_u16s")
+ .temporal()
+ .any()
+ .avg()
+ .eq(Prop::F64(2.0));
+ let expected = vec!["n1", "n10", "n3"];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter
+ .property("p_u16s")
+ .temporal()
+ .any()
+ .avg()
+ .eq(Prop::F64(2.5));
+ let expected = vec!["n1"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_any_avg_u32s() {
+ let filter = NodeFilter
+ .property("p_u32s")
+ .temporal()
+ .any()
+ .avg()
+ .eq(Prop::F64(2.0));
+ let expected = vec!["n1", "n10", "n3"];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter
+ .property("p_u32s")
+ .temporal()
+ .any()
+ .avg()
+ .eq(Prop::F64(2.5));
+ let expected = vec!["n1"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_any_avg_u64s() {
+ let filter = NodeFilter
+ .property("p_u64s")
+ .temporal()
+ .any()
+ .avg()
+ .eq(Prop::F64(2.0));
+ let expected = vec!["n1", "n10", "n3", "n4"];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter
+ .property("p_u64s")
+ .temporal()
+ .any()
+ .avg()
+ .eq(Prop::F64(2.5));
+ let expected = vec!["n1", "n2"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_any_avg_i32s() {
+ let filter = NodeFilter
+ .property("p_i32s")
+ .temporal()
+ .any()
+ .avg()
+ .eq(Prop::F64(2.0));
+ let expected = vec!["n1", "n10", "n3", "n4"];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter
+ .property("p_i32s")
+ .temporal()
+ .any()
+ .avg()
+ .eq(Prop::F64(2.5));
+ let expected = vec!["n1"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_any_avg_i64s() {
+ let filter = NodeFilter
+ .property("p_i64s")
+ .temporal()
+ .any()
+ .avg()
+ .eq(Prop::F64(0.0));
+ let expected = vec!["n3", "n10"];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter
+ .property("p_i64s")
+ .temporal()
+ .any()
+ .avg()
+ .eq(Prop::F64(2.5));
+ let expected = vec!["n1"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_any_avg_f32s() {
+ let filter = NodeFilter
+ .property("p_f32s")
+ .temporal()
+ .any()
+ .avg()
+ .eq(Prop::F64(2.1666666666666665));
+ let expected = vec!["n1", "n10", "n3", "n4"];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter
+ .property("p_f32s")
+ .temporal()
+ .any()
+ .avg()
+ .eq(Prop::F64(20.0));
+ let expected = vec!["n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_any_avg_f64s() {
+ let filter = NodeFilter
+ .property("p_f64s")
+ .temporal()
+ .any()
+ .avg()
+ .eq(Prop::F64(45.0));
+ let expected = vec!["n1", "n10", "n3"];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter
+ .property("p_f64s")
+ .temporal()
+ .any()
+ .avg()
+ .eq(Prop::F64(40.0));
+ let expected = vec!["n1", "n2"];
+ apply_assertion(filter, &expected);
+ }
+
+ // ------ Temporal any: MIN ------
+ #[test]
+ fn test_node_property_temporal_any_min_u8s() {
+ let filter = NodeFilter
+ .property("p_u8s")
+ .temporal()
+ .any()
+ .min()
+ .eq(Prop::U8(1));
+ let expected = vec!["n1", "n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_any_min_u16s() {
+ let filter = NodeFilter
+ .property("p_u16s")
+ .temporal()
+ .any()
+ .min()
+ .eq(Prop::U16(1));
+ let expected = vec!["n1", "n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_any_min_u32s() {
+ let filter = NodeFilter
+ .property("p_u32s")
+ .temporal()
+ .any()
+ .min()
+ .eq(Prop::U32(1));
+ let expected = vec!["n1", "n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_any_min_u64s() {
+ let filter = NodeFilter
+ .property("p_u64s")
+ .temporal()
+ .any()
+ .min()
+ .eq(Prop::U64(1));
+ let expected = vec!["n1", "n10", "n2", "n3", "n4", "n5"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_any_min_i32s() {
+ let filter = NodeFilter
+ .property("p_i32s")
+ .temporal()
+ .any()
+ .min()
+ .eq(Prop::I32(-2));
+ let expected = vec!["n6"];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter
+ .property("p_i32s")
+ .temporal()
+ .any()
+ .min()
+ .eq(Prop::I32(10));
+ let expected = vec!["n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_any_min_i64s() {
+ let filter = NodeFilter
+ .property("p_i64s")
+ .temporal()
+ .any()
+ .min()
+ .eq(Prop::I64(-3));
+ let expected = vec!["n10", "n3"];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter
+ .property("p_i64s")
+ .temporal()
+ .any()
+ .min()
+ .eq(Prop::I64(1));
+ let expected = vec!["n1", "n5"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_any_min_f32s() {
+ let filter = NodeFilter
+ .property("p_f32s")
+ .temporal()
+ .any()
+ .min()
+ .eq(Prop::F32(1.0));
+ let expected = vec!["n1", "n10", "n3", "n4"];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter
+ .property("p_f32s")
+ .temporal()
+ .any()
+ .min()
+ .eq(Prop::F32(10.0));
+ let expected = vec!["n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_any_min_f64s() {
+ let filter = NodeFilter
+ .property("p_f64s")
+ .temporal()
+ .any()
+ .min()
+ .eq(Prop::F64(30.0));
+ let expected = vec!["n1", "n2", "n3"];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter
+ .property("p_f64s")
+ .temporal()
+ .any()
+ .min()
+ .eq(Prop::F64(40.0));
+ let expected = vec!["n1", "n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ // ------ Temporal any: MAX ------
+ #[test]
+ fn test_node_property_temporal_any_max_u8s() {
+ let filter = NodeFilter
+ .property("p_u8s")
+ .temporal()
+ .any()
+ .max()
+ .eq(Prop::U8(3));
+ let expected = vec!["n1", "n10", "n3"];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter
+ .property("p_u8s")
+ .temporal()
+ .any()
+ .max()
+ .eq(Prop::U8(4));
+ let expected = vec!["n1", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_any_max_u16s() {
+ let filter = NodeFilter
+ .property("p_u16s")
+ .temporal()
+ .any()
+ .max()
+ .eq(Prop::U16(3));
+ let expected = vec!["n1", "n10", "n3"];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter
+ .property("p_u16s")
+ .temporal()
+ .any()
+ .max()
+ .eq(Prop::U16(4));
+ let expected = vec!["n1"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_any_max_u32s() {
+ let filter = NodeFilter
+ .property("p_u32s")
+ .temporal()
+ .any()
+ .max()
+ .eq(Prop::U32(3));
+ let expected = vec!["n1", "n10", "n3"];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter
+ .property("p_u32s")
+ .temporal()
+ .any()
+ .max()
+ .eq(Prop::U32(4));
+ let expected = vec!["n1"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_any_max_u64s() {
+ let filter = NodeFilter
+ .property("p_u64s")
+ .temporal()
+ .any()
+ .max()
+ .eq(Prop::U64(4));
+ let expected = vec!["n1", "n2"];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter
+ .property("p_u64s")
+ .temporal()
+ .any()
+ .max()
+ .eq(Prop::U64(3));
+ let expected = vec!["n1", "n10", "n3", "n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_any_max_i32s() {
+ let filter = NodeFilter
+ .property("p_i32s")
+ .temporal()
+ .any()
+ .max()
+ .eq(Prop::I32(3));
+ let expected = vec!["n1", "n10", "n3", "n4", "n6"];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter
+ .property("p_i32s")
+ .temporal()
+ .any()
+ .max()
+ .eq(Prop::I32(30));
+ let expected = vec!["n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_any_max_i64s() {
+ let filter = NodeFilter
+ .property("p_i64s")
+ .temporal()
+ .any()
+ .max()
+ .eq(Prop::I64(2));
+ let expected = vec!["n10", "n3"];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter
+ .property("p_i64s")
+ .temporal()
+ .any()
+ .max()
+ .eq(Prop::I64(2));
+ let expected = vec!["n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_any_max_f32s() {
+ let filter = NodeFilter
+ .property("p_f32s")
+ .temporal()
+ .any()
+ .max()
+ .eq(Prop::F32(3.5));
+ let expected = vec!["n1", "n10", "n3", "n4"];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter
+ .property("p_f32s")
+ .temporal()
+ .any()
+ .max()
+ .eq(Prop::F32(30.0));
+ let expected = vec!["n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_any_max_f64s() {
+ let filter = NodeFilter
+ .property("p_f64s")
+ .temporal()
+ .any()
+ .max()
+ .eq(Prop::F64(50.0));
+ let expected = vec!["n1", "n10", "n2", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ // ------ Temporal any: LEN ------
+ #[test]
+ fn test_node_property_temporal_any_len_u8s() {
+ let filter = NodeFilter
+ .property("p_u8s")
+ .temporal()
+ .any()
+ .len()
+ .is_in(vec![Prop::U64(3)]);
+ let expected = vec!["n1", "n10", "n3"];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter
+ .property("p_u8s")
+ .temporal()
+ .any()
+ .len()
+ .eq(Prop::U64(4));
+ let expected = vec!["n1"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_any_len_u16s() {
+ let filter = NodeFilter
+ .property("p_u16s")
+ .temporal()
+ .any()
+ .len()
+ .eq(Prop::U64(3));
+ let expected = vec!["n1", "n10", "n3"];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter
+ .property("p_u16s")
+ .temporal()
+ .any()
+ .len()
+ .eq(Prop::U64(4));
+ let expected = vec!["n1"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_any_len_u32s() {
+ let filter = NodeFilter
+ .property("p_u32s")
+ .temporal()
+ .any()
+ .len()
+ .eq(Prop::U64(3));
+ let expected = vec!["n1", "n10", "n3"];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter
+ .property("p_u32s")
+ .temporal()
+ .any()
+ .len()
+ .eq(Prop::U64(4));
+ let expected = vec!["n1"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_any_len_u64s() {
+ let filter = NodeFilter
+ .property("p_u64s")
+ .temporal()
+ .any()
+ .len()
+ .eq(Prop::U64(4));
+ let expected = vec!["n1", "n2"];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter
+ .property("p_u64s")
+ .temporal()
+ .any()
+ .len()
+ .eq(Prop::U64(3));
+ let expected = vec!["n1", "n10", "n3", "n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_any_len_i32s() {
+ let filter = NodeFilter
+ .property("p_i32s")
+ .temporal()
+ .any()
+ .len()
+ .eq(Prop::U64(3));
+ let expected = vec!["n1", "n10", "n3", "n4", "n6"];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter
+ .property("p_i32s")
+ .temporal()
+ .any()
+ .len()
+ .eq(Prop::U64(4));
+ let expected = vec!["n1"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_any_len_i64s() {
+ let filter = NodeFilter
+ .property("p_i64s")
+ .temporal()
+ .any()
+ .len()
+ .eq(Prop::U64(2));
+ let expected = vec!["n5"];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter
+ .property("p_i64s")
+ .temporal()
+ .any()
+ .len()
+ .eq(Prop::U64(4));
+ let expected = vec!["n1"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_any_len_f32s() {
+ let filter = NodeFilter
+ .property("p_f32s")
+ .temporal()
+ .any()
+ .len()
+ .eq(Prop::U64(3));
+ let expected = vec!["n1", "n10", "n3", "n4"];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter
+ .property("p_f32s")
+ .temporal()
+ .any()
+ .len()
+ .eq(Prop::U64(4));
+ let expected = vec!["n1"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_property_temporal_any_len_f64s() {
+ let filter = NodeFilter
+ .property("p_f64s")
+ .temporal()
+ .any()
+ .len()
+ .eq(Prop::U64(2));
+ let expected = vec!["n1", "n10", "n3"];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter
+ .property("p_f64s")
+ .temporal()
+ .any()
+ .len()
+ .eq(Prop::U64(3));
+ let expected = vec!["n1", "n2"];
+ apply_assertion(filter, &expected);
+ }
+
+ // ------ EMPTY LISTS ------
+ #[test]
+ fn test_empty_list_agg() {
+ let filter = NodeFilter.property("p_u64s").sum().eq(Prop::U64(0));
+ let expected: Vec<&str> = vec![];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter.property("p_u64s").avg().eq(Prop::F64(0.0));
+ let expected: Vec<&str> = vec![];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter
+ .property("p_u64s")
+ .temporal()
+ .last()
+ .min()
+ .eq(Prop::U64(0));
+ let expected: Vec<&str> = vec![];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter
+ .property("p_u64s")
+ .temporal()
+ .first()
+ .max()
+ .eq(Prop::U64(0));
+ let expected: Vec<&str> = vec![];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter.property("p_u64s").len().eq(Prop::U64(0));
+ let expected: Vec<&str> = vec!["n7"];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter.metadata("p_u64s").len().eq(Prop::U64(0));
+ let expected: Vec<&str> = vec!["n6"];
+ apply_assertion(filter, &expected);
+ }
+
+ // ------ Unsupported filter operations ------
+ #[test]
+ fn test_unsupported_filter_ops_agg() {
+ let filter = NodeFilter.property("p_u64s").sum().starts_with("abc");
+ let expected: &str = "Operator STARTS_WITH is not supported with list aggregation";
+ apply_assertion_err(filter, expected);
+
+ let filter = NodeFilter.property("p_u64s").avg().ends_with("abc");
+ let expected: &str = "Operator ENDS_WITH is not supported with list aggregation";
+ apply_assertion_err(filter, expected);
+
+ let filter = NodeFilter.property("p_u64s").min().is_none();
+ let expected: &str = "Operator IS_NONE is not supported with list aggregation";
+ apply_assertion_err(filter, expected);
+
+ let filter = NodeFilter.property("p_u64s").max().is_some();
+ let expected: &str = "Operator IS_SOME is not supported with list aggregation";
+ apply_assertion_err(filter, expected);
+
+ let filter = NodeFilter.property("p_u64s").len().contains("abc");
+ let expected: &str = "Operator CONTAINS is not supported with list aggregation";
+ apply_assertion_err(filter, expected);
+
+ let filter = NodeFilter.property("p_u64s").sum().not_contains("abc");
+ let expected: &str = "Operator NOT_CONTAINS is not supported with list aggregation";
+ apply_assertion_err(filter, expected);
+ }
+
+ // --------------- OVERFLOW ---------------
+ #[test]
+ fn test_max_value_agg() {
+ let filter = NodeFilter
+ .property("p_u64s_max")
+ .max()
+ .eq(Prop::U64(u64::MAX));
+ let expected: Vec<&str> = vec!["n5", "n1"];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter
+ .property("p_u64s_min")
+ .min()
+ .eq(Prop::U64(u64::MIN));
+ let expected: Vec<&str> = vec!["n5"];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter.property("p_u8s_max").sum().eq(Prop::U64(510));
+ let expected: Vec<&str> = vec!["n1"];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter
+ .property("p_u16s_max")
+ .sum()
+ .eq(Prop::U64(131070));
+ let expected: Vec<&str> = vec!["n1"];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter
+ .property("p_u32s_max")
+ .sum()
+ .eq(Prop::U64(8589934590));
+ let expected: Vec<&str> = vec!["n1"];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter.property("p_u64s_max").sum().gt(Prop::U64(0));
+ let expected: Vec<&str> = vec![];
+ apply_assertion(filter, &expected);
+
+ // AVG is computed in f64 even if SUM overflowed.
+ let avg = (u64::MAX as f64 + 1.0) / 2.0;
+ let filter = NodeFilter.property("p_u64s_max").avg().eq(avg);
+ let expected = vec!["n5"];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter.property("p_i64s_max").sum().gt(Prop::I64(0));
+ let expected: Vec<&str> = vec![];
+ apply_assertion(filter, &expected);
+
+ // AVG is computed in f64 even if SUM overflowed.
+ let avg = (i64::MAX as f64 + 1.0) / 2.0;
+ let filter = NodeFilter.property("p_i64s_max").avg().eq(avg);
+ let expected = vec!["n5"];
+ apply_assertion(filter, &expected);
+ }
+
+ // ------ Property: any ------
+ #[test]
+ fn test_node_property_any() {
+ let filter = NodeFilter.property("p_u8s").any().eq(Prop::U8(3));
+ let expected = vec!["n1", "n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ // ------ Property: all ------
+ #[test]
+ fn test_node_property_all() {
+ let filter = NodeFilter
+ .property("p_bools_all")
+ .all()
+ .eq(Prop::Bool(true));
+ let expected = vec!["n10", "n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ // ------ Metadata: any ------
+ #[test]
+ fn test_node_metadata_any() {
+ let filter = NodeFilter.metadata("p_u64s").any().eq(Prop::U64(1));
+ let expected = vec!["n10", "n7"];
+ apply_assertion(filter, &expected);
+ }
+
+ // ------ Metadata: all ------
+ #[test]
+ fn test_node_metadata_all() {
+ let filter = NodeFilter.metadata("p_strs").all().eq("a");
+ let expected = vec!["n6", "n7"];
+ apply_assertion(filter, &expected);
+ }
+
+ // ------ Temporal First: any ------
+ #[test]
+ fn test_node_temporal_property_first_any() {
+ let filter = NodeFilter
+ .property("p_bools")
+ .temporal()
+ .first()
+ .any()
+ .eq(false);
+ let expected = vec!["n1", "n10", "n2", "n3", "n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ // ------ Temporal First: all ------
+ #[test]
+ fn test_node_temporal_property_first_all() {
+ let filter = NodeFilter
+ .property("p_bools_all")
+ .temporal()
+ .first()
+ .all()
+ .eq(true);
+ let expected = vec!["n10", "n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ // ------ Temporal last: any ------
+ #[test]
+ fn test_node_temporal_property_last_any() {
+ let filter = NodeFilter
+ .property("p_f32s")
+ .temporal()
+ .last()
+ .any()
+ .eq(Prop::F32(3.5));
+ let expected = vec!["n1", "n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ // ------ Temporal last: all ------
+ #[test]
+ fn test_node_temporal_property_last_all() {
+ let filter = NodeFilter
+ .property("p_bools_all")
+ .temporal()
+ .last()
+ .all()
+ .eq(true);
+ let expected = vec!["n10", "n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ // ------ Temporal Any: any ------
+ #[test]
+ fn test_node_temporal_property_any_any() {
+ let filter = NodeFilter
+ .property("p_f32s")
+ .temporal()
+ .any()
+ .any()
+ .eq(Prop::F32(3.5));
+ let expected = vec!["n1", "n10", "n3", "n4"];
+ apply_assertion(filter, &expected);
+
+ let filter = NodeFilter
+ .property("p_f32s")
+ .temporal()
+ .any()
+ .any()
+ .eq(Prop::F32(30.0));
+ let expected = vec!["n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ // ------ Temporal Any: all ------
+ #[test]
+ fn test_node_temporal_property_any_all() {
+ let filter = NodeFilter
+ .property("p_bools")
+ .temporal()
+ .any()
+ .all()
+ .eq(false);
+ let expected = vec!["n2", "n4"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_nested_list_property_all_all_all_any() {
+ let filter = NodeFilter
+ .property("nested_list")
+ .all()
+ .all()
+ .all()
+ .any()
+ .gt(45.0);
+
+ let expected = vec!["n1", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ #[test]
+ fn test_node_nested_list_temporal_property_all_all_all_all_any() {
+ let filter = NodeFilter
+ .property("nested_list")
+ .temporal()
+ .all()
+ .all()
+ .all()
+ .all()
+ .any()
+ .gt(45.0);
+
+ let expected = vec!["n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ // ------ Temporal All: any ------
+ #[test]
+ fn test_node_temporal_property_all_any() {
+ let filter = NodeFilter
+ .property("p_bools")
+ .temporal()
+ .all()
+ .any()
+ .eq(true);
+ let expected = vec!["n1", "n10", "n3"];
+ apply_assertion(filter, &expected);
+ }
+
+ // ------ Temporal All: all ------
+ #[test]
+ fn test_node_temporal_property_all_all() {
+ let filter = NodeFilter
+ .property("p_bools_all")
+ .temporal()
+ .all()
+ .all()
+ .eq(true);
+ let expected = vec!["n4", "n10"];
+ apply_assertion(filter, &expected);
+ }
+}
+
+mod test_edge_filter {
+ use crate::filter_tests::test_filters::{
+ init_edges_graph, init_edges_graph_with_num_ids, init_edges_graph_with_str_ids,
+ init_edges_graph_with_str_ids_del, init_nodes_graph, IdentityGraphTransformer,
+ };
+ use raphtory::db::graph::views::filter::model::{
+ edge_filter::EdgeFilter,
+ node_filter::ops::{NodeFilterOps, NodeIdFilterOps},
+ property_filter::ops::{ListAggOps, PropertyFilterOps},
+ ComposableFilter, EdgeViewFilterOps, PropertyFilterFactory, TemporalPropertyFilterFactory,
+ ViewWrapOps,
+ };
+ use raphtory_tests::assertions::{
+ assert_filter_edges_results, assert_search_edges_results, assert_select_edges_results,
+ TestGraphVariants, TestVariants,
+ };
+
+ #[test]
+ fn test_filter_edges_src_property_eq() {
+ let filter = EdgeFilter::src().property("p10").eq("Paper_airplane");
+ let expected_results = vec!["1->2", "3->1"];
+ let g = |g| init_edges_graph(init_nodes_graph(g));
+ assert_filter_edges_results(
+ g,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ g,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_src_property_temporal_eq() {
+ let filter = EdgeFilter::src()
+ .property("p30")
+ .temporal()
+ .first()
+ .eq("Old_boat");
+ let expected_results = vec!["2->1", "2->3"];
+ let g = |g| init_edges_graph(init_nodes_graph(g));
+ assert_filter_edges_results(
+ g,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ g,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_src_metadata_eq() {
+ let filter = EdgeFilter::src().metadata("m1").eq("pometry");
+ let expected_results = vec!["1->2"];
+ let g = |g| init_edges_graph(init_nodes_graph(g));
+ assert_filter_edges_results(
+ g,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ g,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_src_eq() {
+ let filter = EdgeFilter::src().name().eq("3");
+ let expected_results = vec!["3->1"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_src_ne() {
+ let filter = EdgeFilter::src().name().ne("1");
+ let expected_results = vec![
+ "2->1",
+ "2->3",
+ "3->1",
+ "David Gilmour->John Mayer",
+ "John Mayer->Jimmy Page",
+ ];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_src_in() {
+ let filter = EdgeFilter::src().name().is_in(vec!["1"]);
+ let expected_results = vec!["1->2"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter::src().name().is_in(vec!["1", "2"]);
+ let expected_results = vec!["1->2", "2->1", "2->3"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_src_not_in() {
+ let filter = EdgeFilter::src().name().is_not_in(vec!["1"]);
+ let expected_results = vec![
+ "2->1",
+ "2->3",
+ "3->1",
+ "David Gilmour->John Mayer",
+ "John Mayer->Jimmy Page",
+ ];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_dst_eq() {
+ let filter = EdgeFilter::dst().name().eq("2");
+ let expected_results = vec!["1->2"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_dst_ne() {
+ let filter = EdgeFilter::dst().name().ne("2");
+ let expected_results = vec![
+ "2->1",
+ "2->3",
+ "3->1",
+ "David Gilmour->John Mayer",
+ "John Mayer->Jimmy Page",
+ ];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_dst_in() {
+ let filter = EdgeFilter::dst().name().is_in(vec!["2"]);
+ let expected_results = vec!["1->2"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter::dst().name().is_in(vec!["2", "3"]);
+ let expected_results = vec!["1->2", "2->3"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_dst_not_in() {
+ let filter = EdgeFilter::dst().name().is_not_in(vec!["1"]);
+ let expected_results = vec![
+ "1->2",
+ "2->3",
+ "David Gilmour->John Mayer",
+ "John Mayer->Jimmy Page",
+ ];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_src_dst_starts_with() {
+ let filter = EdgeFilter::src().name().starts_with("Joh");
+ let expected_results: Vec<&str> = vec!["John Mayer->Jimmy Page"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter::src().name().starts_with("Joker");
+ let expected_results: Vec<&str> = vec![];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter::dst().name().starts_with("Jimmy");
+ let expected_results: Vec<&str> = vec!["John Mayer->Jimmy Page"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter::dst().name().starts_with("Tango");
+ let expected_results: Vec<&str> = vec![];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_src_dst_ends_with() {
+ let filter = EdgeFilter::src().name().ends_with("Mayer");
+ let expected_results: Vec<&str> = vec!["John Mayer->Jimmy Page"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter::src().name().ends_with("Cruise");
+ let expected_results: Vec<&str> = vec![];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter::dst().name().ends_with("Page");
+ let expected_results: Vec<&str> = vec!["John Mayer->Jimmy Page"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter::dst().name().ends_with("Cruise");
+ let expected_results: Vec<&str> = vec![];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_src_contains() {
+ let filter = EdgeFilter::src().name().contains("Mayer");
+ let expected_results: Vec<&str> = vec!["John Mayer->Jimmy Page"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_src_contains_not() {
+ let filter = EdgeFilter::src().name().not_contains("Mayer");
+ let expected_results: Vec<&str> =
+ vec!["1->2", "2->1", "2->3", "3->1", "David Gilmour->John Mayer"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_fuzzy_search() {
+ let filter = EdgeFilter::src().name().fuzzy_search("John", 2, true);
+ let expected_results: Vec<&str> = vec!["John Mayer->Jimmy Page"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter::src().name().fuzzy_search("John", 2, false);
+ let expected_results: Vec<&str> = vec![];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter::src().name().fuzzy_search("John May", 2, false);
+ let expected_results: Vec<&str> = vec!["John Mayer->Jimmy Page"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_not_src() {
+ let filter = EdgeFilter::src().name().is_not_in(vec!["1"]).not();
+ let expected_results = vec!["1->2"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_src_id_eq() {
+ let filter = EdgeFilter::src().id().eq("3");
+ let expected_results = vec!["3->1"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter::src().id().eq(3);
+ let expected_results = vec!["3->1"];
+ assert_filter_edges_results(
+ init_edges_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_dst_id_eq() {
+ let filter = EdgeFilter::dst().id().eq("3");
+ let expected_results = vec!["2->3"];
+ // assert_filter_edges_results(
+ // init_edges_graph,
+ // IdentityGraphTransformer,
+ // filter.clone(),
+ // &expected_results,
+ // TestVariants::All,
+ // );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter::dst().id().eq(3);
+ let expected_results = vec!["2->3"];
+ assert_filter_edges_results(
+ init_edges_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_src_id_ne() {
+ let filter = EdgeFilter::src().id().ne("3");
+ let expected_results = vec![
+ "1->2",
+ "2->1",
+ "2->3",
+ "David Gilmour->John Mayer",
+ "John Mayer->Jimmy Page",
+ ];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter::src().id().ne(3);
+ let expected_results = vec!["1->2", "2->1", "2->3"];
+ assert_filter_edges_results(
+ init_edges_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_dst_id_ne() {
+ let filter = EdgeFilter::dst().id().ne("3");
+ let expected_results = vec![
+ "1->2",
+ "2->1",
+ "3->1",
+ "David Gilmour->John Mayer",
+ "John Mayer->Jimmy Page",
+ ];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter::dst().id().ne(3);
+ let expected_results = vec!["1->2", "2->1", "3->1"];
+ assert_filter_edges_results(
+ init_edges_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_id_src_is_in() {
+ let filter = EdgeFilter::src().id().is_in(vec!["3"]);
+ let expected_results = vec!["3->1"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter::src().id().is_in(vec![3]);
+ let expected_results = vec!["3->1"];
+ assert_filter_edges_results(
+ init_edges_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_id_dst_is_in() {
+ let filter = EdgeFilter::dst().id().is_in(vec!["3"]);
+ let expected_results = vec!["2->3"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter::dst().id().is_in(vec![3]);
+ let expected_results = vec!["2->3"];
+ assert_filter_edges_results(
+ init_edges_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_id_src_is_not_in() {
+ let filter = EdgeFilter::src().id().is_not_in(vec!["3"]);
+ let expected_results = vec![
+ "1->2",
+ "2->1",
+ "2->3",
+ "David Gilmour->John Mayer",
+ "John Mayer->Jimmy Page",
+ ];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter::src().id().is_not_in(vec![3]);
+ let expected_results = vec!["1->2", "2->1", "2->3"];
+ assert_filter_edges_results(
+ init_edges_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_id_dst_is_not_in() {
+ let filter = EdgeFilter::dst().id().is_not_in(vec!["3"]);
+ let expected_results = vec![
+ "1->2",
+ "2->1",
+ "3->1",
+ "David Gilmour->John Mayer",
+ "John Mayer->Jimmy Page",
+ ];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter::dst().id().is_not_in(vec![3]);
+ let expected_results = vec!["1->2", "2->1", "3->1"];
+ assert_filter_edges_results(
+ init_edges_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_src_id_lt() {
+ let filter = EdgeFilter::src().id().lt(3);
+ let expected_results = vec!["1->2", "2->1", "2->3"];
+ assert_filter_edges_results(
+ init_edges_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_dst_id_lt() {
+ let filter = EdgeFilter::dst().id().lt(3);
+ let expected_results = vec!["1->2", "2->1", "3->1"];
+ assert_filter_edges_results(
+ init_edges_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_src_id_le() {
+ let filter = EdgeFilter::src().id().le(3);
+ let expected_results = vec!["1->2", "2->1", "2->3", "3->1"];
+ assert_filter_edges_results(
+ init_edges_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_dst_id_le() {
+ let filter = EdgeFilter::dst().id().le(3);
+ let expected_results = vec!["1->2", "2->1", "2->3", "3->1"];
+ assert_filter_edges_results(
+ init_edges_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_src_id_gt() {
+ let filter = EdgeFilter::src().id().gt(1);
+ let expected_results = vec!["2->1", "2->3", "3->1"];
+ assert_filter_edges_results(
+ init_edges_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_dst_id_gt() {
+ let filter = EdgeFilter::dst().id().gt(1);
+ let expected_results = vec!["1->2", "2->3"];
+ assert_filter_edges_results(
+ init_edges_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_src_id_ge() {
+ let filter = EdgeFilter::src().id().ge(1);
+ let expected_results = vec!["1->2", "2->1", "2->3", "3->1"];
+ assert_filter_edges_results(
+ init_edges_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_dst_id_ge() {
+ let filter = EdgeFilter::dst().id().ge(1);
+ let expected_results = vec!["1->2", "2->1", "2->3", "3->1"];
+ assert_filter_edges_results(
+ init_edges_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph_with_num_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_src_name_starts_with() {
+ let filter = EdgeFilter::src().name().starts_with("Tw");
+ let expected_results = vec!["Two->One", "Two->Three"];
+ assert_filter_edges_results(
+ init_edges_graph_with_str_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph_with_str_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_src_id_ends_with() {
+ let filter = EdgeFilter::src().id().ends_with("don");
+ let expected_results = vec!["London->Paris"];
+ assert_filter_edges_results(
+ init_edges_graph_with_str_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph_with_str_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_src_id_contains() {
+ let filter = EdgeFilter::src().id().contains("don");
+ let expected_results = vec!["London->Paris"];
+ assert_filter_edges_results(
+ init_edges_graph_with_str_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_dst_id_contains() {
+ let filter = EdgeFilter::dst().id().contains("Par");
+ let expected_results = vec!["London->Paris"];
+ assert_filter_edges_results(
+ init_edges_graph_with_str_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_dst_name_not_contains() {
+ let filter = EdgeFilter::dst().name().not_contains("Par");
+ let expected_results = vec![
+ "David Gilmour->John Mayer",
+ "John Mayer->Jimmy Page",
+ "Three->One",
+ "Two->One",
+ "Two->Three",
+ ];
+ assert_filter_edges_results(
+ init_edges_graph_with_str_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph_with_str_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_src_id_is_in() {
+ let filter = EdgeFilter::src().id().is_in(["Two"]);
+ let expected_results = vec!["Two->One", "Two->Three"];
+ assert_filter_edges_results(
+ init_edges_graph_with_str_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph_with_str_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_dst_id_is_not_in() {
+ let filter = EdgeFilter::dst().id().is_not_in(["One"]);
+ let expected_results = vec![
+ "David Gilmour->John Mayer",
+ "John Mayer->Jimmy Page",
+ "London->Paris",
+ "Two->Three",
+ ];
+ assert_filter_edges_results(
+ init_edges_graph_with_str_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph_with_str_ids,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_is_active_edge_window() {
+ let filter = EdgeFilter.window(1, 3).is_active();
+ let expected_results = vec!["London->Paris", "Two->Three"];
+ assert_filter_edges_results(
+ init_edges_graph_with_str_ids_del,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph_with_str_ids_del,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_is_active_edge_after() {
+ let filter = EdgeFilter.after(3).is_active();
+ let expected_results = vec![
+ "Bangalore->Bangalore",
+ "David Gilmour->John Mayer",
+ "John Mayer->Jimmy Page",
+ ];
+ assert_filter_edges_results(
+ init_edges_graph_with_str_ids_del,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph_with_str_ids_del,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_is_active_edge_before() {
+ let filter = EdgeFilter.before(3).is_active();
+ let expected_results = vec!["London->Paris", "Two->Three"];
+ assert_filter_edges_results(
+ init_edges_graph_with_str_ids_del,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph_with_str_ids_del,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_is_active_edge_snapshot_latest() {
+ let filter = EdgeFilter.snapshot_latest().is_active();
+ let expected_results = vec!["Bangalore->Bangalore"];
+ assert_filter_edges_results(
+ init_edges_graph_with_str_ids_del,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph_with_str_ids_del,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+
+ #[test]
+ fn test_is_valid_edge_window() {
+ let filter = EdgeFilter.window(1, 3).is_valid();
+ let expected_results = vec!["London->Paris", "Two->Three"];
+ assert_filter_edges_results(
+ init_edges_graph_with_str_ids_del,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestGraphVariants::PersistentGraph,
+ );
+ assert_select_edges_results(
+ init_edges_graph_with_str_ids_del,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestGraphVariants::PersistentGraph,
+ );
+ assert_search_edges_results(
+ init_edges_graph_with_str_ids_del,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestGraphVariants::PersistentGraph,
+ );
+
+ let filter = EdgeFilter.window(1, 4).is_valid();
+ let expected_results = vec!["Three->One", "Two->One", "Two->Three"];
+ assert_filter_edges_results(
+ init_edges_graph_with_str_ids_del,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestGraphVariants::PersistentGraph,
+ );
+ assert_select_edges_results(
+ init_edges_graph_with_str_ids_del,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestGraphVariants::PersistentGraph,
+ );
+ assert_search_edges_results(
+ init_edges_graph_with_str_ids_del,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestGraphVariants::PersistentGraph,
+ );
+ }
+
+ #[test]
+ fn test_is_valid_edge_snapshot_at() {
+ let filter = EdgeFilter.snapshot_at(2).is_valid();
+ let expected_results = vec!["London->Paris", "Two->Three"];
+ assert_filter_edges_results(
+ init_edges_graph_with_str_ids_del,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestGraphVariants::PersistentGraph,
+ );
+ assert_select_edges_results(
+ init_edges_graph_with_str_ids_del,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestGraphVariants::PersistentGraph,
+ );
+ assert_search_edges_results(
+ init_edges_graph_with_str_ids_del,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestGraphVariants::PersistentGraph,
+ );
+
+ let filter = EdgeFilter.snapshot_at(3).is_valid();
+ let expected_results = vec!["Three->One", "Two->One", "Two->Three"];
+ assert_filter_edges_results(
+ init_edges_graph_with_str_ids_del,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestGraphVariants::PersistentGraph,
+ );
+ assert_select_edges_results(
+ init_edges_graph_with_str_ids_del,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestGraphVariants::PersistentGraph,
+ );
+ assert_search_edges_results(
+ init_edges_graph_with_str_ids_del,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestGraphVariants::PersistentGraph,
+ );
+ }
+
+ #[test]
+ fn test_is_valid_edge_snapshot_latest() {
+ let filter = EdgeFilter.snapshot_latest().is_valid();
+ let expected_results = vec![
+ "Bangalore->Bangalore",
+ "David Gilmour->John Mayer",
+ "John Mayer->Jimmy Page",
+ "Three->One",
+ "Two->One",
+ "Two->Three",
+ ];
+ assert_filter_edges_results(
+ init_edges_graph_with_str_ids_del,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestGraphVariants::PersistentGraph,
+ );
+ assert_select_edges_results(
+ init_edges_graph_with_str_ids_del,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestGraphVariants::PersistentGraph,
+ );
+ assert_search_edges_results(
+ init_edges_graph_with_str_ids_del,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestGraphVariants::PersistentGraph,
+ );
+ }
+
+ // Disk graph doesn't support deletions
+ #[test]
+ fn test_is_deleted_edge_after() {
+ let filter = EdgeFilter.after(1).is_deleted();
+ let expected_results = vec!["London->Paris"];
+ assert_filter_edges_results(
+ init_edges_graph_with_str_ids_del,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_select_edges_results(
+ init_edges_graph_with_str_ids_del,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph_with_str_ids_del,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ // Disk graph doesn't support deletions
+ #[test]
+ fn test_is_deleted_edge_before() {
+ let filter = EdgeFilter.before(4).is_deleted();
+ let expected_results = vec!["London->Paris"];
+ assert_filter_edges_results(
+ init_edges_graph_with_str_ids_del,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_select_edges_results(
+ init_edges_graph_with_str_ids_del,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph_with_str_ids_del,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_is_self_loop_edge_window() {
+ let filter = EdgeFilter.window(1, 3).is_self_loop();
+ let expected_results = vec![];
+ assert_filter_edges_results(
+ init_edges_graph_with_str_ids_del,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_select_edges_results(
+ init_edges_graph_with_str_ids_del,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph_with_str_ids_del,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter.window(1, 6).is_self_loop();
+ let expected_results = vec!["Bangalore->Bangalore"];
+ assert_filter_edges_results(
+ init_edges_graph_with_str_ids_del,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_select_edges_results(
+ init_edges_graph_with_str_ids_del,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph_with_str_ids_del,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+}
+
+mod test_edge_property_filter {
+ use crate::filter_tests::test_filters::{
+ init_edges_graph, init_edges_graph2, IdentityGraphTransformer,
+ };
+ use raphtory::db::graph::views::filter::model::{
+ edge_filter::EdgeFilter,
+ property_filter::ops::{ElemQualifierOps, ListAggOps, PropertyFilterOps},
+ ComposableFilter, PropertyFilterFactory, TemporalPropertyFilterFactory, ViewWrapOps,
+ };
+
+ use raphtory_api::core::entities::properties::prop::Prop;
+ use raphtory_tests::assertions::{
+ assert_filter_edges_results, assert_search_edges_results, TestGraphVariants, TestVariants,
+ };
+
+ #[test]
+ fn test_filter_edges_for_property_eq() {
+ // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
+ let filter = EdgeFilter.property("p2").eq(2u64);
+ let expected_results = vec!["2->3"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter.property("p30").temporal().first().eq("Old_boat");
+ let expected_results = vec!["2->3"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter.property("p20").temporal().all().eq("Gold_ship");
+ let expected_results = vec!["1->2"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_property_ne() {
+ // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
+ let filter = EdgeFilter.property("p2").ne(2u64);
+ let expected_results = vec![
+ "1->2",
+ "2->1",
+ "3->1",
+ "David Gilmour->John Mayer",
+ "John Mayer->Jimmy Page",
+ ];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter.property("p30").temporal().first().ne("Old_boat");
+ let expected_results = vec!["1->2"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter.property("p30").temporal().all().ne("Classic");
+ let expected_results = vec!["1->2", "2->3"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_property_lt() {
+ // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
+ let filter = EdgeFilter.property("p2").lt(10u64);
+ let expected_results = vec![
+ "1->2",
+ "2->1",
+ "2->3",
+ "3->1",
+ "David Gilmour->John Mayer",
+ "John Mayer->Jimmy Page",
+ ];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter.property("p2").temporal().first().lt(5u64);
+ let expected_results = vec!["1->2", "2->3"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter.property("p2").temporal().all().lt(10u64);
+ let expected_results = vec![
+ "1->2",
+ "2->1",
+ "2->3",
+ "3->1",
+ "David Gilmour->John Mayer",
+ "John Mayer->Jimmy Page",
+ ];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_property_le() {
+ // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
+ let filter = EdgeFilter.property("p2").le(6u64);
+ let expected_results = vec![
+ "1->2",
+ "2->1",
+ "2->3",
+ "3->1",
+ "David Gilmour->John Mayer",
+ "John Mayer->Jimmy Page",
+ ];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter.property("p2").temporal().first().le(3u64);
+ let expected_results = vec!["2->3"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter.property("p2").temporal().all().le(5u64);
+ let expected_results = vec!["1->2", "2->3"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_property_gt() {
+ // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
+ let filter = EdgeFilter.property("p2").gt(2u64);
+ let expected_results = vec![
+ "1->2",
+ "2->1",
+ "3->1",
+ "David Gilmour->John Mayer",
+ "John Mayer->Jimmy Page",
+ ];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter.property("p2").temporal().first().gt(5u64);
+ let expected_results = vec![
+ "2->1",
+ "3->1",
+ "David Gilmour->John Mayer",
+ "John Mayer->Jimmy Page",
+ ];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter.property("p2").temporal().all().gt(5u64);
+ let expected_results = vec![
+ "2->1",
+ "3->1",
+ "David Gilmour->John Mayer",
+ "John Mayer->Jimmy Page",
+ ];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_property_ge() {
+ // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
+ let filter = EdgeFilter.property("p2").ge(2u64);
+ let expected_results = vec![
+ "1->2",
+ "2->1",
+ "2->3",
+ "3->1",
+ "David Gilmour->John Mayer",
+ "John Mayer->Jimmy Page",
+ ];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter.property("p2").temporal().first().ge(6u64);
+ let expected_results = vec![
+ "2->1",
+ "3->1",
+ "David Gilmour->John Mayer",
+ "John Mayer->Jimmy Page",
+ ];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter.property("p2").temporal().all().ge(6u64);
+ let expected_results = vec![
+ "2->1",
+ "3->1",
+ "David Gilmour->John Mayer",
+ "John Mayer->Jimmy Page",
+ ];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_property_in() {
+ // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
+ let filter = EdgeFilter.property("p2").is_in(vec![Prop::U64(6)]);
+ let expected_results = vec![
+ "2->1",
+ "3->1",
+ "David Gilmour->John Mayer",
+ "John Mayer->Jimmy Page",
+ ];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter
+ .property("p2")
+ .is_in(vec![Prop::U64(2), Prop::U64(6)]);
+ let expected_results = vec![
+ "2->1",
+ "2->3",
+ "3->1",
+ "David Gilmour->John Mayer",
+ "John Mayer->Jimmy Page",
+ ];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter
+ .property("p2")
+ .temporal()
+ .first()
+ .is_in(vec![Prop::U64(6)]);
+ let expected_results = vec![
+ "2->1",
+ "3->1",
+ "David Gilmour->John Mayer",
+ "John Mayer->Jimmy Page",
+ ];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter
+ .property("p2")
+ .temporal()
+ .all()
+ .is_in(vec![Prop::U64(6)]);
+ let expected_results = vec![
+ "2->1",
+ "3->1",
+ "David Gilmour->John Mayer",
+ "John Mayer->Jimmy Page",
+ ];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_property_not_in() {
+ // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
+ let filter = EdgeFilter.property("p2").is_not_in(vec![Prop::U64(6)]);
+ let expected_results = vec!["1->2", "2->3"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter
+ .property("p2")
+ .temporal()
+ .first()
+ .is_not_in(vec![Prop::U64(6)]);
+ let expected_results = vec!["1->2", "2->3"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter
+ .property("p2")
+ .temporal()
+ .all()
+ .is_not_in(vec![Prop::U64(6)]);
+ let expected_results = vec!["1->2", "2->3"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_property_is_some() {
+ // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
+ let filter = EdgeFilter.property("p2").is_some();
+ let expected_results = vec![
+ "1->2",
+ "2->1",
+ "2->3",
+ "3->1",
+ "David Gilmour->John Mayer",
+ "John Mayer->Jimmy Page",
+ ];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter.property("p2").temporal().first().is_some();
+ let expected_results = vec![
+ "1->2",
+ "2->1",
+ "2->3",
+ "3->1",
+ "David Gilmour->John Mayer",
+ "John Mayer->Jimmy Page",
+ ];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_property_is_none() {
+ // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for both filter_edges and search_edges. Search API uses filter API internally for this filter.
+ let filter = EdgeFilter.property("p2").is_none();
+ let expected_results = Vec::<&str>::new();
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ let filter = EdgeFilter.property("p2").temporal().first().is_none();
+ let expected_results = vec![];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_property_starts_with() {
+ // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
+ let filter = EdgeFilter.property("p10").starts_with("Pa");
+ let expected_results: Vec<&str> = vec!["1->2", "2->1", "2->3"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter
+ .property("p10")
+ .temporal()
+ .any()
+ .starts_with("Pape");
+ let expected_results: Vec<&str> = vec!["1->2", "2->1", "2->3"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter
+ .property("p10")
+ .temporal()
+ .last()
+ .starts_with("Paper");
+ let expected_results: Vec<&str> = vec!["1->2", "2->1", "2->3"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter
+ .property("p10")
+ .temporal()
+ .last()
+ .starts_with("Traffic");
+ let expected_results: Vec<&str> = vec![];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter
+ .property("p30")
+ .temporal()
+ .first()
+ .starts_with("Old");
+ let expected_results: Vec<&str> = vec!["2->3"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter
+ .property("p20")
+ .temporal()
+ .all()
+ .starts_with("Gold");
+ let expected_results: Vec<&str> = vec!["1->2", "2->3"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_property_ends_with() {
+ // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
+ let filter = EdgeFilter.property("p10").ends_with("lane");
+ let expected_results: Vec<&str> = vec!["1->2", "2->1"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter
+ .property("p10")
+ .temporal()
+ .any()
+ .ends_with("ship");
+ let expected_results: Vec<&str> = vec!["2->3"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter
+ .property("p10")
+ .temporal()
+ .last()
+ .ends_with("ane");
+ let expected_results: Vec<&str> = vec!["1->2", "2->1"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter
+ .property("p10")
+ .temporal()
+ .last()
+ .ends_with("marcus");
+ let expected_results: Vec<&str> = vec![];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter
+ .property("p20")
+ .temporal()
+ .first()
+ .ends_with("boat");
+ let expected_results: Vec<&str> = vec!["2->3"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter
+ .property("p20")
+ .temporal()
+ .all()
+ .ends_with("ship");
+ let expected_results: Vec<&str> = vec!["1->2"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_property_contains() {
+ // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
+ let filter = EdgeFilter.property("p10").contains("Paper");
+ let expected_results: Vec<&str> = vec!["1->2", "2->1", "2->3"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter
+ .property("p10")
+ .temporal()
+ .any()
+ .contains("Paper");
+ let expected_results: Vec<&str> = vec!["1->2", "2->1", "2->3"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter
+ .property("p10")
+ .temporal()
+ .last()
+ .contains("Paper");
+ let expected_results: Vec<&str> = vec!["1->2", "2->1", "2->3"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter
+ .property("p20")
+ .temporal()
+ .first()
+ .contains("boat");
+ let expected_results: Vec<&str> = vec!["2->3"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter.property("p20").temporal().all().contains("ship");
+ let expected_results: Vec<&str> = vec!["1->2"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_property_contains_not() {
+ // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
+ let filter = EdgeFilter.property("p10").not_contains("ship");
+ let expected_results: Vec<&str> = vec!["1->2", "2->1"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter
+ .property("p10")
+ .temporal()
+ .any()
+ .not_contains("ship");
+ let expected_results: Vec<&str> = vec!["1->2", "2->1"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter
+ .property("p10")
+ .temporal()
+ .last()
+ .not_contains("ship");
+ let expected_results: Vec<&str> = vec!["1->2", "2->1"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter
+ .property("p20")
+ .temporal()
+ .first()
+ .not_contains("boat");
+ let expected_results: Vec<&str> = vec!["1->2"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter
+ .property("p30")
+ .temporal()
+ .all()
+ .not_contains("ship");
+ let expected_results: Vec<&str> = vec!["2->3"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_by_fuzzy_search() {
+ // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for both filter_edges and search_edges.
+ // TODO: Enable these test for event_disk_graph, persistent_disk_graph once string property is fixed.
+ let filter = EdgeFilter.property("p1").fuzzy_search("shiv", 2, true);
+ let expected_results: Vec<&str> = vec!["1->2"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+
+ let filter = EdgeFilter.property("p1").fuzzy_search("ShiV", 2, true);
+ let expected_results: Vec<&str> = vec!["1->2"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+
+ let filter = EdgeFilter.property("p1").fuzzy_search("shiv", 2, false);
+ let expected_results: Vec<&str> = vec![];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ }
+
+ #[test]
+ fn test_filter_edges_for_not_property() {
+ // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for both filter_edges and search_edges. Search API uses filter API internally for this filter.
+ let filter = EdgeFilter.property("p2").ne(2u64).not();
+ let expected_results = vec!["2->3"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ }
+
+ #[test]
+ fn test_edges_window_filter() {
+ let filter = EdgeFilter
+ .window(1, 3)
+ .property("p2")
+ .temporal()
+ .sum()
+ .ge(2u64);
+
+ let expected_results = vec!["1->2", "2->3"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter
+ .window(1, 5)
+ .property("p2")
+ .temporal()
+ .sum()
+ .ge(2u64);
+
+ let expected_results = vec![
+ "1->2",
+ "2->3",
+ "3->1",
+ "2->1",
+ "David Gilmour->John Mayer",
+ "John Mayer->Jimmy Page",
+ ];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_edges_window_filter_on_non_temporal_property() {
+ let filter1 = EdgeFilter.window(1, 2).property("p1").eq("shivam_kapoor");
+ let filter2 = EdgeFilter
+ .window(100, 200)
+ .property("p1")
+ .eq("shivam_kapoor");
+
+ let expected_results = vec!["1->2"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter1.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter1.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let expected_results = vec![];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter2.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter2.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ let filter2 = EdgeFilter
+ .window(100, 200)
+ .property("p1")
+ .eq("shivam_kapoor");
+ let expected_results = vec!["1->2"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter2.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter2.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+
+ #[test]
+ fn test_edges_window_filter_any_all_over_window() {
+ let filter_any = EdgeFilter
+ .window(2, 4)
+ .property("p20")
+ .temporal()
+ .any()
+ .eq("Gold_boat");
+
+ let expected_any = vec!["2->3"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter_any.clone(),
+ &expected_any,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter_any.clone(),
+ &expected_any,
+ TestVariants::All,
+ );
+
+ let filter_all = EdgeFilter
+ .window(2, 4)
+ .property("p20")
+ .temporal()
+ .all()
+ .eq("Gold_boat");
+
+ let expected_all: Vec<&str> = vec![];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter_all.clone(),
+ &expected_all,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter_all.clone(),
+ &expected_all,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_edges_window_filter_and() {
+ let filter1 = EdgeFilter
+ .window(3, 6)
+ .property("p10")
+ .temporal()
+ .any()
+ .eq("Paper_airplane");
+
+ let filter2 = EdgeFilter
+ .window(3, 6)
+ .property("p2")
+ .temporal()
+ .sum()
+ .eq(6u64);
+
+ let filter = filter1.and(filter2);
+
+ let expected_results = vec!["2->1"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_edges_layer_filter() {
+ let filter = EdgeFilter
+ .layer("fire_nation")
+ .property("p2")
+ .temporal()
+ .sum()
+ .ge(2u64);
+
+ let expected_results = vec!["1->2", "3->1"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_edges_at_filter() {
+ // Only time=2 contributes; edge 2->3 has p2=2 at t=2
+ let filter = EdgeFilter.at(2).property("p2").temporal().sum().eq(2u64);
+
+ let expected_results = vec!["2->3"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ // Only time=3 contributes; edge 3->1 has p2=6 at t=3
+ let filter = EdgeFilter.at(3).property("p2").temporal().sum().eq(6u64);
+
+ let expected_results = vec!["3->1", "2->1"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_edges_after_filter() {
+ // after(2) means t >= 3
+ let filter = EdgeFilter.after(2).property("p2").temporal().sum().ge(6u64);
+
+ // At t=3: 3->1 and 2->1 have p2=6
+ // At t=4: David->John and John->Jimmy have p2=6
+ let expected_results = vec![
+ "3->1",
+ "2->1",
+ "David Gilmour->John Mayer",
+ "John Mayer->Jimmy Page",
+ ];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_edges_before_filter() {
+ // before(3) means t <= 2
+ let filter = EdgeFilter
+ .before(3)
+ .property("p2")
+ .temporal()
+ .sum()
+ .eq(2u64);
+
+ // Only t=2 contributes for p2=2 -> 2->3
+ let expected_results = vec!["2->3"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ // And p2=6 edges shouldn't match, because their p2=6 lives at t=3+.
+ let filter = EdgeFilter
+ .before(3)
+ .property("p2")
+ .temporal()
+ .sum()
+ .eq(6u64);
+
+ let expected_results = vec![];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_edges_latest_filter() {
+ // At latest time (currently t=4), only the t=4 edges exist in the Event graph.
+ // Use EventOnly so the expectation is stable and matches node-style.
+ let filter = EdgeFilter.latest().property("p2").eq(6u64);
+
+ let expected_results = vec!["David Gilmour->John Mayer", "John Mayer->Jimmy Page"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ }
+
+ #[test]
+ fn test_edges_snapshot_at_semantics_event_graph() {
+ let t = 2;
+
+ let filter_snapshot = EdgeFilter
+ .snapshot_at(t)
+ .property("p2")
+ .temporal()
+ .sum()
+ .eq(2u64);
+
+ let filter_before = EdgeFilter
+ .before(t + 1)
+ .property("p2")
+ .temporal()
+ .sum()
+ .eq(2u64);
+
+ let expected_results = vec!["2->3"];
+
+ // snapshot_at
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter_snapshot.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter_snapshot,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ // before(t+1)
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter_before.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter_before,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ }
+
+ #[test]
+ fn test_edges_snapshot_at_semantics_persistent_graph() {
+ let t = 2;
+
+ let filter_snapshot = EdgeFilter
+ .snapshot_at(t)
+ .property("p2")
+ .temporal()
+ .sum()
+ .eq(2u64);
+
+ let filter_at = EdgeFilter.at(t).property("p2").temporal().sum().eq(2u64);
+
+ let expected_results = vec!["2->3"];
+
+ // snapshot_at
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter_snapshot.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter_snapshot,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ // at(t)
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter_at.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter_at,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+
+ #[test]
+ fn test_edges_snapshot_latest_semantics_event_graph() {
+ let filter_snapshot_latest = EdgeFilter
+ .snapshot_latest()
+ .property("p2")
+ .temporal()
+ .sum()
+ .ge(6u64);
+
+ let filter_noop = EdgeFilter.property("p2").temporal().sum().ge(6u64);
+
+ // Across the whole event history, p2=6 appears at t=3 and t=4.
+ let expected_results = vec![
+ "3->1",
+ "2->1",
+ "David Gilmour->John Mayer",
+ "John Mayer->Jimmy Page",
+ ];
+
+ // snapshot_latest
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter_snapshot_latest.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter_snapshot_latest,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ // no-op baseline
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter_noop.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter_noop,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ }
+
+ #[test]
+ fn test_edges_snapshot_latest_semantics_persistent_graph() {
+ let filter_snapshot_latest = EdgeFilter.snapshot_latest().property("p2").eq(6u64);
+
+ let filter_latest = EdgeFilter.latest().property("p2").eq(6u64);
+
+ // In persistent latest state at t=4, these edges have p2=6:
+ // - t=3 edges: 3->1, 2->1
+ // - t=4 edges: David->John, John->Jimmy
+ let expected_results = vec![
+ "3->1",
+ "2->1",
+ "David Gilmour->John Mayer",
+ "John Mayer->Jimmy Page",
+ ];
+
+ // snapshot_latest
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter_snapshot_latest.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter_snapshot_latest,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ // latest
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter_latest.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter_latest,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+
+ #[test]
+ fn test_edges_layer_then_window_ordering() {
+ // In layer "fire_nation" within window [1,3), edge 1->2 matches p1 == "shivam_kapoor".
+ let filter = EdgeFilter
+ .layer("fire_nation")
+ .window(1, 3)
+ .property("p1")
+ .eq("shivam_kapoor");
+
+ let expected_results = vec!["1->2"];
+
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_edges_window_then_layer_ordering() {
+ // Same semantics, reversed chaining order.
+ let filter = EdgeFilter
+ .window(1, 3)
+ .layer("fire_nation")
+ .property("p1")
+ .eq("shivam_kapoor");
+
+ let expected_results = vec!["1->2"];
+
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_edges_latest_layer() {
+ let filter = EdgeFilter
+ .latest()
+ .layer("fire_nation")
+ .property("p2")
+ .temporal()
+ .last()
+ .eq(7u64);
+
+ let expected_results = vec![];
+
+ assert_filter_edges_results(
+ init_edges_graph2,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ }
+
+ #[test]
+ fn test_edges_layer_latest() {
+ let filter = EdgeFilter
+ .layer("fire_nation")
+ .latest()
+ .property("p2")
+ .temporal()
+ .last()
+ .eq(7u64);
+
+ let expected_results = vec!["1->2"];
+
+ assert_filter_edges_results(
+ init_edges_graph2,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ }
+}
+
+mod test_edge_composite_filter {
+ use raphtory::db::graph::views::filter::model::{
+ edge_filter::EdgeFilter, node_filter::ops::NodeFilterOps,
+ property_filter::ops::PropertyFilterOps, ComposableFilter, PropertyFilterFactory,
+ TryAsCompositeFilter,
+ };
+ use raphtory_tests::assertions::{
+ assert_filter_edges_results, assert_search_edges_results, TestGraphVariants, TestVariants,
+ };
+
+ use crate::filter_tests::test_filters::{init_edges_graph, IdentityGraphTransformer};
+
+ #[test]
+ fn test_filter_edge_for_src_dst() {
+ // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
+ let filter = EdgeFilter::src()
+ .name()
+ .eq("3")
+ .and(EdgeFilter::dst().name().eq("1"));
+ let expected_results = vec!["3->1"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_unique_results_from_composite_filters() {
+ // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
+ let filter = EdgeFilter
+ .property("p2")
+ .ge(2u64)
+ .and(EdgeFilter.property("p2").ge(1u64));
+ let expected_results = vec![
+ "1->2",
+ "2->1",
+ "2->3",
+ "3->1",
+ "David Gilmour->John Mayer",
+ "John Mayer->Jimmy Page",
+ ];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ let filter = EdgeFilter
+ .property("p2")
+ .ge(2u64)
+ .or(EdgeFilter.property("p2").ge(5u64));
+ let expected_results = vec![
+ "1->2",
+ "2->1",
+ "2->3",
+ "3->1",
+ "David Gilmour->John Mayer",
+ "John Mayer->Jimmy Page",
+ ];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ }
+
+ #[test]
+ fn test_composite_filter_edges() {
+ // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for both filter_edges and search_edges.
+ // TODO: Enable these test for event_disk_graph, persistent_disk_graph once string property is fixed.
+ let filter = EdgeFilter
+ .property("p2")
+ .eq(2u64)
+ .and(EdgeFilter.property("p1").eq("kapoor"));
+ let expected_results = Vec::<&str>::new();
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ let filter = filter.try_as_composite_edge_filter().unwrap();
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter
+ .property("p2")
+ .eq(2u64)
+ .or(EdgeFilter.property("p1").eq("shivam_kapoor"));
+ let expected_results = vec!["1->2", "2->3"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ let filter = filter.try_as_composite_edge_filter().unwrap();
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter.property("p1").eq("pometry").or(EdgeFilter
+ .property("p2")
+ .eq(6u64)
+ .and(EdgeFilter.property("p3").eq(1u64)));
+ let expected_results = vec![
+ "2->1",
+ "3->1",
+ "David Gilmour->John Mayer",
+ "John Mayer->Jimmy Page",
+ ];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ let filter = filter.try_as_composite_edge_filter().unwrap();
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter::src()
+ .name()
+ .eq("13")
+ .and(EdgeFilter.property("p1").eq("prop1"));
+ let expected_results = Vec::<&str>::new();
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ let filter = filter.try_as_composite_edge_filter().unwrap();
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter
+ .property("p2")
+ .eq(4u64)
+ .and(EdgeFilter.property("p1").eq("shivam_kapoor"));
+ let expected_results = vec!["1->2"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ let filter = filter.try_as_composite_edge_filter().unwrap();
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter::src()
+ .name()
+ .eq("1")
+ .and(EdgeFilter.property("p1").eq("shivam_kapoor"));
+ let expected_results = vec!["1->2"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ let filter = filter.try_as_composite_edge_filter().unwrap();
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter::dst()
+ .name()
+ .eq("1")
+ .and(EdgeFilter.property("p2").eq(6u64));
+ let expected_results = vec!["2->1", "3->1"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ let filter = filter.try_as_composite_edge_filter().unwrap();
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = EdgeFilter::src()
+ .name()
+ .eq("1")
+ .and(EdgeFilter.property("p1").eq("shivam_kapoor"))
+ .or(EdgeFilter.property("p3").eq(5u64));
+ let expected_results = vec!["1->2"];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let filter = filter.try_as_composite_edge_filter().unwrap();
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_not_composite_filter_edges() {
+ // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for both filter_edges and search_edges. Search API uses filter API internally for this filter.
+ let filter = EdgeFilter::src()
+ .name()
+ .eq("13")
+ .and(EdgeFilter.property("p1").eq("prop1"))
+ .not();
+ let expected_results = vec![
+ "1->2",
+ "2->1",
+ "2->3",
+ "3->1",
+ "David Gilmour->John Mayer",
+ "John Mayer->Jimmy Page",
+ ];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ let filter = EdgeFilter::src()
+ .name()
+ .eq("13")
+ .and(EdgeFilter.property("p1").eq("prop1").not())
+ .not();
+ let expected_results = vec![
+ "1->2",
+ "2->1",
+ "2->3",
+ "3->1",
+ "David Gilmour->John Mayer",
+ "John Mayer->Jimmy Page",
+ ];
+ assert_filter_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ assert_search_edges_results(
+ init_edges_graph,
+ IdentityGraphTransformer,
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ }
+}
diff --git a/raphtory-tests/tests/filter_tests/test_layers.rs b/raphtory-tests/tests/filter_tests/test_layers.rs
new file mode 100644
index 0000000000..c0edccb61c
--- /dev/null
+++ b/raphtory-tests/tests/filter_tests/test_layers.rs
@@ -0,0 +1,514 @@
+use raphtory::{
+ db::{
+ api::view::StaticGraphViewOps,
+ graph::views::{layer_graph::LayeredGraph, window_graph::WindowedGraph},
+ },
+ prelude::{LayerOps, TimeOps},
+};
+use raphtory_tests::assertions::GraphTransformer;
+use std::ops::Range;
+
+struct LayeredGraphTransformer(Vec);
+
+impl GraphTransformer for LayeredGraphTransformer {
+ type Return = LayeredGraph;
+ fn apply(&self, graph: G) -> Self::Return {
+ graph.layers(self.0.clone()).unwrap()
+ }
+}
+
+struct LayeredGraphWindowTransformer(Vec, Range);
+
+impl GraphTransformer for LayeredGraphWindowTransformer {
+ type Return = WindowedGraph>;
+ fn apply(&self, graph: G) -> Self::Return {
+ graph
+ .layers(self.0.clone())
+ .unwrap()
+ .window(self.1.start, self.1.end)
+ }
+}
+
+pub mod test_nodes_filters_layer_graph {
+ use raphtory::{
+ db::{
+ api::view::StaticGraphViewOps,
+ graph::views::filter::model::property_filter::ops::PropertyFilterOps,
+ },
+ prelude::AdditionOps,
+ };
+ use raphtory_api::core::entities::properties::prop::Prop;
+
+ use crate::filter_tests::test_layers::{
+ LayeredGraphTransformer, LayeredGraphWindowTransformer,
+ };
+ use raphtory::{db::graph::views::filter::model::PropertyFilterFactory, prelude::NodeFilter};
+
+ use crate::filter_tests::{init_graph, Edges, Nodes};
+ use raphtory_tests::assertions::{
+ assert_filter_nodes_results, assert_search_nodes_results, TestGraphVariants, TestVariants,
+ };
+
+ // Layers don't have any effect on the number of nodes in a graph.
+ // In other words, it is as good as applying no layer filters.
+ #[test]
+ fn test_nodes_filters() {
+ let layers: Vec = vec!["layer1".into(), "layer2".into()];
+ let filter = NodeFilter.property("p1").eq(1u64);
+ let expected_results = vec!["N1", "N3", "N4", "N6", "N7"];
+ assert_filter_nodes_results(
+ |graph| init_graph(graph, Nodes::Typed, Edges::Layered),
+ LayeredGraphTransformer(layers.clone()),
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ |graph| init_graph(graph, Nodes::Typed, Edges::Layered),
+ LayeredGraphTransformer(layers),
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let layers: Vec = vec!["layer1".into()];
+ let filter = NodeFilter.property("p1").ge(2u64);
+ let expected_results = vec!["N2", "N5", "N8"];
+ assert_filter_nodes_results(
+ |graph| init_graph(graph, Nodes::Typed, Edges::Layered),
+ LayeredGraphTransformer(layers.clone()),
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ |graph| init_graph(graph, Nodes::Typed, Edges::Layered),
+ LayeredGraphTransformer(layers),
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let layers: Vec = vec!["layer2".into()];
+ let filter = NodeFilter.property("p1").le(1u64);
+ let expected_results = vec!["N1", "N3", "N4", "N6", "N7"];
+ assert_filter_nodes_results(
+ |graph| init_graph(graph, Nodes::Typed, Edges::Layered),
+ LayeredGraphTransformer(layers.clone()),
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ |graph| init_graph(graph, Nodes::Typed, Edges::Layered),
+ LayeredGraphTransformer(layers),
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let layers: Vec = vec!["layer1".into()];
+ let filter = NodeFilter.property("p1").lt(2u64);
+ let expected_results = vec!["N1", "N3", "N4", "N6", "N7"];
+ assert_filter_nodes_results(
+ |graph| init_graph(graph, Nodes::Typed, Edges::Layered),
+ LayeredGraphTransformer(layers.clone()),
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ |graph| init_graph(graph, Nodes::Typed, Edges::Layered),
+ LayeredGraphTransformer(layers),
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let layers: Vec = vec!["layer2".into()];
+ let filter = NodeFilter.property("p1").gt(1u64);
+ let expected_results = vec!["N2", "N5", "N8"];
+ assert_filter_nodes_results(
+ |graph| init_graph(graph, Nodes::Typed, Edges::Layered),
+ LayeredGraphTransformer(layers.clone()),
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_nodes_results(
+ |graph| init_graph(graph, Nodes::Typed, Edges::Layered),
+ LayeredGraphTransformer(layers),
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_nodes_filters_w() {
+ // TODO: Enable event_disk_graph for filter_nodes once bug fixed: https://github.com/Pometry/Raphtory/issues/2098
+ let layers: Vec = vec!["layer1".into(), "layer2".into()];
+ let filter = NodeFilter.property("p1").eq(1u64);
+ let expected_results = vec!["N1", "N3", "N6"];
+ assert_filter_nodes_results(
+ |graph| init_graph(graph, Nodes::Typed, Edges::Layered),
+ LayeredGraphWindowTransformer(layers.clone(), 6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ |graph| init_graph(graph, Nodes::Typed, Edges::Layered),
+ LayeredGraphWindowTransformer(layers.clone(), 6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ let layers: Vec = vec!["layer1".into()];
+ let filter = NodeFilter.property("p1").ge(2u64);
+ let expected_results = vec!["N2", "N5"];
+ assert_filter_nodes_results(
+ |graph| init_graph(graph, Nodes::Typed, Edges::Layered),
+ LayeredGraphWindowTransformer(layers.clone(), 6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ |graph| init_graph(graph, Nodes::Typed, Edges::Layered),
+ LayeredGraphWindowTransformer(layers.clone(), 6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ let layers: Vec = vec!["layer2".into()];
+ let filter = NodeFilter.property("p1").lt(2u64);
+ let expected_results = vec!["N1", "N3", "N6"];
+ assert_filter_nodes_results(
+ |graph| init_graph(graph, Nodes::Typed, Edges::Layered),
+ LayeredGraphWindowTransformer(layers.clone(), 6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ |graph| init_graph(graph, Nodes::Typed, Edges::Layered),
+ LayeredGraphWindowTransformer(layers.clone(), 6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ }
+
+ #[test]
+ fn test_nodes_filters_pg_w() {
+ let layers: Vec = vec!["layer1".into(), "layer2".into()];
+ let filter = NodeFilter.property("p1").eq(1u64);
+ let expected_results = vec!["N1", "N3", "N6", "N7"];
+ assert_filter_nodes_results(
+ |graph| init_graph(graph, Nodes::Typed, Edges::Layered),
+ LayeredGraphWindowTransformer(layers.clone(), 6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ |graph| init_graph(graph, Nodes::Typed, Edges::Layered),
+ LayeredGraphWindowTransformer(layers.clone(), 6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let layers: Vec = vec!["layer1".into()];
+ let filter = NodeFilter.property("p1").lt(2u64);
+ let expected_results = vec!["N1", "N3", "N6", "N7"];
+ assert_filter_nodes_results(
+ |graph| init_graph(graph, Nodes::Typed, Edges::Layered),
+ LayeredGraphWindowTransformer(layers.clone(), 6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ |graph| init_graph(graph, Nodes::Typed, Edges::Layered),
+ LayeredGraphWindowTransformer(layers.clone(), 6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let layers: Vec = vec!["layer2".into()];
+ let filter = NodeFilter.property("p1").gt(1u64);
+ let expected_results = vec!["N2", "N5", "N8"];
+ assert_filter_nodes_results(
+ |graph| init_graph(graph, Nodes::Typed, Edges::Layered),
+ LayeredGraphWindowTransformer(layers.clone(), 6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ |graph| init_graph(graph, Nodes::Typed, Edges::Layered),
+ LayeredGraphWindowTransformer(layers.clone(), 6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+}
+
+mod test_edges_filters_layer_graph {
+ use raphtory::{
+ db::{
+ api::view::StaticGraphViewOps,
+ graph::views::filter::model::{
+ property_filter::ops::PropertyFilterOps, PropertyFilterFactory,
+ },
+ },
+ prelude::{AdditionOps, EdgeFilter},
+ };
+ use raphtory_api::core::entities::properties::prop::Prop;
+ use raphtory_tests::assertions::{
+ assert_filter_edges_results, assert_search_edges_results, TestGraphVariants, TestVariants,
+ };
+
+ use crate::filter_tests::test_layers::{
+ LayeredGraphTransformer, LayeredGraphWindowTransformer,
+ };
+
+ use crate::filter_tests::{init_graph, Edges, Nodes};
+
+ #[test]
+ fn test_edges_filters() {
+ // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph.
+ let layers: Vec = vec!["layer1".into(), "layer2".into()];
+ let filter = EdgeFilter.property("p1").eq(1u64);
+ let expected_results = vec!["N1->N2", "N3->N4", "N4->N5", "N6->N7", "N7->N8"];
+ assert_filter_edges_results(
+ |graph| init_graph(graph, Nodes::None, Edges::Layered),
+ LayeredGraphTransformer(layers.clone()),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ |graph| init_graph(graph, Nodes::None, Edges::Layered),
+ LayeredGraphTransformer(layers),
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let layers: Vec = vec!["layer1".into()];
+ let filter = EdgeFilter.property("p1").le(1u64);
+ let expected_results = vec![
+ "N2->N3", "N3->N4", "N4->N5", "N5->N6", "N6->N7", "N7->N8", "N8->N1",
+ ];
+ assert_filter_edges_results(
+ |graph| init_graph(graph, Nodes::None, Edges::Layered),
+ LayeredGraphTransformer(layers.clone()),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ |graph| init_graph(graph, Nodes::None, Edges::Layered),
+ LayeredGraphTransformer(layers),
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let layers: Vec = vec!["layer2".into()];
+ let filter = EdgeFilter.property("p1").ge(2u64);
+ let expected_results = vec!["N2->N3", "N5->N6", "N8->N1"];
+ assert_filter_edges_results(
+ |graph| init_graph(graph, Nodes::None, Edges::Layered),
+ LayeredGraphTransformer(layers.clone()),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ |graph| init_graph(graph, Nodes::None, Edges::Layered),
+ LayeredGraphTransformer(layers),
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let layers: Vec = vec!["layer1".into()];
+ let filter = EdgeFilter.property("p1").lt(2u64);
+ let expected_results = vec![
+ "N2->N3", "N3->N4", "N4->N5", "N5->N6", "N6->N7", "N7->N8", "N8->N1",
+ ];
+ assert_filter_edges_results(
+ |graph| init_graph(graph, Nodes::None, Edges::Layered),
+ LayeredGraphTransformer(layers.clone()),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ |graph| init_graph(graph, Nodes::None, Edges::Layered),
+ LayeredGraphTransformer(layers),
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+
+ let layers: Vec = vec!["layer2".into()];
+ let filter = EdgeFilter.property("p1").gt(1u64);
+ let expected_results = vec!["N2->N3", "N5->N6", "N8->N1"];
+ assert_filter_edges_results(
+ |graph| init_graph(graph, Nodes::None, Edges::Layered),
+ LayeredGraphTransformer(layers.clone()),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ |graph| init_graph(graph, Nodes::None, Edges::Layered),
+ LayeredGraphTransformer(layers),
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_edges_filter_w() {
+ // Edge Property Semantics:
+ // 1. All property updates to an edge belong to a layer (or _default if no layer specified)
+ // 2. However, when asked for a value of a particular property for an edge, the latest update
+ // across all specified layers (or all layers if no layers specified) is returned!
+ let layers: Vec = vec!["layer1".into(), "layer2".into()];
+ let filter = EdgeFilter.property("p1").eq(1u64);
+ let expected_results = vec!["N1->N2", "N3->N4", "N6->N7"];
+ assert_filter_edges_results(
+ |graph| init_graph(graph, Nodes::None, Edges::Layered),
+ LayeredGraphWindowTransformer(layers.clone(), 6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ |graph| init_graph(graph, Nodes::None, Edges::Layered),
+ LayeredGraphWindowTransformer(layers, 6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ // Edge Property Semantics:
+ // When filtering by specific layer, filter criteria (p1==1) and latest semantics is applicable
+ // only to that specific layer.
+ let layers: Vec = vec!["layer1".into()];
+ let filter = EdgeFilter.property("p1").lt(2u64);
+ let expected_results = vec!["N2->N3", "N3->N4"];
+ assert_filter_edges_results(
+ |graph| init_graph(graph, Nodes::None, Edges::Layered),
+ LayeredGraphWindowTransformer(layers.clone(), 6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ |graph| init_graph(graph, Nodes::None, Edges::Layered),
+ LayeredGraphWindowTransformer(layers, 6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ let layers: Vec = vec!["layer2".into()];
+ let filter = EdgeFilter.property("p1").gt(1u64);
+ let expected_results = vec!["N2->N3", "N5->N6"];
+ assert_filter_edges_results(
+ |graph| init_graph(graph, Nodes::None, Edges::Layered),
+ LayeredGraphWindowTransformer(layers.clone(), 6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ |graph| init_graph(graph, Nodes::None, Edges::Layered),
+ LayeredGraphWindowTransformer(layers, 6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ }
+
+ #[test]
+ fn test_edges_filters_pg_w() {
+ // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph.
+ let layers: Vec = vec!["layer1".into(), "layer2".into()];
+ let filter = EdgeFilter.property("p1").eq(1u64);
+
+ // Why is the edge N8 -> N1 included in the results?
+ // The reason edge N8 -> N1 is included as part of the results because of following two semantic reasons:
+ // .add_edge(3, "N8", "N1", [("p1", Prop::U64(1u64))], Some("layer1"))
+ // .add_edge(4, "N8", "N1", [("p1", Prop::U64(2u64))], Some("layer2"))
+ // 1. As per layer graph semantics, every edge update belongs to a particular layer (or '_default' if no layer specified).
+ // This means the last_before is computed per layer and not across layers. In other words, when computing
+ // last_before for (N8->N1, layer1) and window(6, 9), t = 3 is the correct last before edge update timestamp and not t = 4
+ // because t=4 edge update is in layer2.
+ // 2. Since the search is conducted across both the layers i.e., layer1 and layer2, the results are union of
+ // results from both layer1 and layer2.
+ let expected_results = vec!["N1->N2", "N3->N4", "N6->N7", "N7->N8"];
+ assert_filter_edges_results(
+ |graph| init_graph(graph, Nodes::None, Edges::Layered),
+ LayeredGraphWindowTransformer(layers.clone(), 6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::PersistentGraph],
+ );
+ assert_search_edges_results(
+ |graph| init_graph(graph, Nodes::None, Edges::Layered),
+ LayeredGraphWindowTransformer(layers, 6..9),
+ filter,
+ &expected_results,
+ vec![TestGraphVariants::PersistentGraph],
+ );
+
+ let layers: Vec = vec!["layer1".into()];
+ let filter = EdgeFilter.property("p1").le(1u64);
+ let expected_results = vec!["N2->N3", "N3->N4", "N5->N6", "N6->N7", "N7->N8", "N8->N1"];
+ assert_filter_edges_results(
+ |graph| init_graph(graph, Nodes::None, Edges::Layered),
+ LayeredGraphWindowTransformer(layers.clone(), 6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::PersistentGraph],
+ );
+ assert_search_edges_results(
+ |graph| init_graph(graph, Nodes::None, Edges::Layered),
+ LayeredGraphWindowTransformer(layers, 6..9),
+ filter,
+ &expected_results,
+ vec![TestGraphVariants::PersistentGraph],
+ );
+
+ let layers: Vec = vec!["layer2".into()];
+ let filter = EdgeFilter.property("p1").ge(2u64);
+ let expected_results = vec!["N2->N3", "N5->N6", "N8->N1"];
+ assert_filter_edges_results(
+ |graph| init_graph(graph, Nodes::None, Edges::Layered),
+ LayeredGraphWindowTransformer(layers.clone(), 6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::PersistentGraph],
+ );
+ assert_search_edges_results(
+ |graph| init_graph(graph, Nodes::None, Edges::Layered),
+ LayeredGraphWindowTransformer(layers, 6..9),
+ filter,
+ &expected_results,
+ vec![TestGraphVariants::PersistentGraph],
+ );
+ }
+}
diff --git a/raphtory-tests/tests/tests_node_type_filtered_subgraph.rs b/raphtory-tests/tests/filter_tests/tests_node_type_filtered_subgraph.rs
similarity index 92%
rename from raphtory-tests/tests/tests_node_type_filtered_subgraph.rs
rename to raphtory-tests/tests/filter_tests/tests_node_type_filtered_subgraph.rs
index fb8190bb59..4bf7e5d878 100644
--- a/raphtory-tests/tests/tests_node_type_filtered_subgraph.rs
+++ b/raphtory-tests/tests/filter_tests/tests_node_type_filtered_subgraph.rs
@@ -219,35 +219,9 @@ mod test_filters_node_type_filtered_subgraph {
};
use raphtory_api::core::entities::properties::prop::Prop;
- fn init_graph(graph: G) -> G {
- let nodes = vec![
- (6, "N1", vec![("p1", Prop::U64(2u64))], Some("air_nomad")),
- (7, "N1", vec![("p1", Prop::U64(1u64))], Some("air_nomad")),
- (6, "N2", vec![("p1", Prop::U64(1u64))], Some("water_tribe")),
- (7, "N2", vec![("p1", Prop::U64(2u64))], Some("water_tribe")),
- (8, "N3", vec![("p1", Prop::U64(1u64))], Some("air_nomad")),
- (9, "N4", vec![("p1", Prop::U64(1u64))], Some("air_nomad")),
- (5, "N5", vec![("p1", Prop::U64(1u64))], Some("air_nomad")),
- (6, "N5", vec![("p1", Prop::U64(2u64))], Some("air_nomad")),
- (5, "N6", vec![("p1", Prop::U64(1u64))], Some("fire_nation")),
- (6, "N6", vec![("p1", Prop::U64(1u64))], Some("fire_nation")),
- (3, "N7", vec![("p1", Prop::U64(1u64))], Some("air_nomad")),
- (5, "N7", vec![("p1", Prop::U64(1u64))], Some("air_nomad")),
- (3, "N8", vec![("p1", Prop::U64(1u64))], Some("fire_nation")),
- (4, "N8", vec![("p1", Prop::U64(2u64))], Some("fire_nation")),
- ];
-
- // Add nodes to the graph
- for (id, name, props, layer) in &nodes {
- graph
- .add_node(*id, name, props.clone(), *layer, None)
- .unwrap();
- }
-
- graph
- }
+ use crate::filter_tests::{init_graph, Edges, Nodes};
- use crate::test_filters_node_type_filtered_subgraph::{
+ use crate::filter_tests::tests_node_type_filtered_subgraph::test_filters_node_type_filtered_subgraph::{
NodeTypeGraphTransformer, WindowedNodeTypeGraphTransformer,
};
use raphtory::{
@@ -262,14 +236,14 @@ mod test_filters_node_type_filtered_subgraph {
let filter = NodeFilter.property("p1").eq(1u64);
let expected_results = vec!["N1", "N3", "N4", "N6", "N7"];
assert_filter_nodes_results(
- init_graph,
+ |graph| init_graph(graph, Nodes::Typed, Edges::None),
NodeTypeGraphTransformer(None),
filter.clone(),
&expected_results,
TestVariants::All,
);
assert_search_nodes_results(
- init_graph,
+ |graph| init_graph(graph, Nodes::Typed, Edges::None),
NodeTypeGraphTransformer(None),
filter,
&expected_results,
@@ -281,14 +255,14 @@ mod test_filters_node_type_filtered_subgraph {
let filter = NodeFilter.property("p1").eq(1u64);
let expected_results = vec!["N1", "N3", "N4", "N7"];
assert_filter_nodes_results(
- init_graph,
+ |graph| init_graph(graph, Nodes::Typed, Edges::None),
NodeTypeGraphTransformer(node_types.clone()),
filter.clone(),
&expected_results,
TestVariants::All,
);
assert_search_nodes_results(
- init_graph,
+ |graph| init_graph(graph, Nodes::Typed, Edges::None),
NodeTypeGraphTransformer(node_types),
filter,
&expected_results,
@@ -302,14 +276,14 @@ mod test_filters_node_type_filtered_subgraph {
let filter = NodeFilter.property("p1").eq(1u64);
let expected_results = vec!["N1", "N3", "N6"];
assert_filter_nodes_results(
- init_graph,
+ |graph| init_graph(graph, Nodes::Typed, Edges::None),
WindowedNodeTypeGraphTransformer(None, 6..9),
filter.clone(),
&expected_results,
vec![TestGraphVariants::Graph],
);
assert_search_nodes_results(
- init_graph,
+ |graph| init_graph(graph, Nodes::Typed, Edges::None),
WindowedNodeTypeGraphTransformer(None, 6..9),
filter,
&expected_results,
@@ -321,14 +295,14 @@ mod test_filters_node_type_filtered_subgraph {
let filter = NodeFilter.property("p1").eq(1u64);
let expected_results = vec!["N1", "N3"];
assert_filter_nodes_results(
- init_graph,
+ |graph| init_graph(graph, Nodes::Typed, Edges::None),
WindowedNodeTypeGraphTransformer(node_types.clone(), 6..9),
filter.clone(),
&expected_results,
vec![TestGraphVariants::Graph],
);
assert_search_nodes_results(
- init_graph,
+ |graph| init_graph(graph, Nodes::Typed, Edges::None),
WindowedNodeTypeGraphTransformer(node_types, 6..9),
filter,
&expected_results,
@@ -341,14 +315,14 @@ mod test_filters_node_type_filtered_subgraph {
let filter = NodeFilter.property("p1").eq(1u64);
let expected_results = vec!["N1", "N3", "N6", "N7"];
assert_filter_nodes_results(
- init_graph,
+ |graph| init_graph(graph, Nodes::Typed, Edges::None),
WindowedNodeTypeGraphTransformer(None, 6..9),
filter.clone(),
&expected_results,
TestVariants::PersistentOnly,
);
assert_search_nodes_results(
- init_graph,
+ |graph| init_graph(graph, Nodes::Typed, Edges::None),
WindowedNodeTypeGraphTransformer(None, 6..9),
filter,
&expected_results,
@@ -360,14 +334,14 @@ mod test_filters_node_type_filtered_subgraph {
let filter = NodeFilter.property("p1").eq(1u64);
let expected_results = vec!["N1", "N3", "N7"];
assert_filter_nodes_results(
- init_graph,
+ |graph| init_graph(graph, Nodes::Typed, Edges::None),
WindowedNodeTypeGraphTransformer(node_types.clone(), 6..9),
filter.clone(),
&expected_results,
TestVariants::PersistentOnly,
);
assert_search_nodes_results(
- init_graph,
+ |graph| init_graph(graph, Nodes::Typed, Edges::None),
WindowedNodeTypeGraphTransformer(node_types, 6..9),
filter,
&expected_results,
@@ -490,7 +464,7 @@ mod test_filters_node_type_filtered_subgraph {
graph
}
- use crate::test_filters_node_type_filtered_subgraph::{
+ use crate::filter_tests::tests_node_type_filtered_subgraph::test_filters_node_type_filtered_subgraph::{
LayeredNodeTypeGraphTransformer, LayeredWindowedNodeTypeGraphTransformer,
NodeTypeGraphTransformer, WindowedNodeTypeGraphTransformer,
};
diff --git a/raphtory-tests/tests/filter_tests/views_test.rs b/raphtory-tests/tests/filter_tests/views_test.rs
new file mode 100644
index 0000000000..64e8c07b20
--- /dev/null
+++ b/raphtory-tests/tests/filter_tests/views_test.rs
@@ -0,0 +1,4032 @@
+mod test_nodes_filters_window_graph {
+ use raphtory::{
+ db::{api::view::StaticGraphViewOps, graph::views::filter::model::ComposableFilter},
+ prelude::{AdditionOps, PropertyAdditionOps},
+ };
+ use raphtory_api::core::{entities::properties::prop::Prop, storage::arc_str::ArcStr};
+ use raphtory_storage::mutation::{
+ addition_ops::InternalAdditionOps, property_addition_ops::InternalPropertyAdditionOps,
+ };
+ use raphtory_tests::assertions::{
+ assert_filter_nodes_results, assert_search_nodes_results, TestGraphVariants, TestVariants,
+ };
+
+ use raphtory::{
+ db::{
+ api::view::filter_ops::Filter,
+ graph::views::filter::model::{
+ node_filter::{ops::NodeFilterOps, NodeFilter},
+ property_filter::ops::PropertyFilterOps,
+ PropertyFilterFactory,
+ },
+ },
+ errors::GraphError,
+ prelude::{Graph, GraphViewOps, TimeOps},
+ };
+ use raphtory_tests::assertions::WindowGraphTransformer;
+
+ fn init_graph(graph: G) -> G {
+ let nodes = vec![
+ (
+ 6,
+ "N1",
+ vec![
+ ("p1", Prop::U64(2u64)),
+ ("k1", Prop::I64(2i64)),
+ ("k2", Prop::Str(ArcStr::from("Paper_Airplane"))),
+ ("k3", Prop::Bool(true)),
+ ("k4", Prop::F64(6.0f64)),
+ ],
+ Some("air_nomad"),
+ ),
+ (
+ 7,
+ "N1",
+ vec![
+ ("p1", Prop::U64(1u64)),
+ ("k1", Prop::I64(5i64)),
+ ("k3", Prop::Bool(false)),
+ ],
+ Some("air_nomad"),
+ ),
+ (
+ 6,
+ "N2",
+ vec![("p1", Prop::U64(1u64)), ("k4", Prop::F64(6.0f64))],
+ Some("water_tribe"),
+ ),
+ (
+ 7,
+ "N2",
+ vec![
+ ("p1", Prop::U64(2u64)),
+ ("k1", Prop::I64(2i64)),
+ ("k2", Prop::Str(ArcStr::from("Paper_Ship"))),
+ ("k3", Prop::Bool(true)),
+ ("k4", Prop::F64(10.0f64)),
+ ],
+ Some("water_tribe"),
+ ),
+ (8, "N3", vec![("p1", Prop::U64(1u64))], Some("air_nomad")),
+ (9, "N4", vec![("p1", Prop::U64(1u64))], Some("air_nomad")),
+ (
+ 5,
+ "N5",
+ vec![
+ ("p1", Prop::U64(1u64)),
+ ("k1", Prop::I64(2i64)),
+ ("k2", Prop::Str(ArcStr::from("Paper_Airplane"))),
+ ("k3", Prop::Bool(true)),
+ ("k4", Prop::F64(6.0f64)),
+ ],
+ Some("air_nomad"),
+ ),
+ (
+ 6,
+ "N5",
+ vec![
+ ("p1", Prop::U64(2u64)),
+ ("k2", Prop::Str(ArcStr::from("Pometry"))),
+ ("k4", Prop::F64(1.0f64)),
+ ],
+ Some("air_nomad"),
+ ),
+ (5, "N6", vec![("p1", Prop::U64(1u64))], Some("fire_nation")),
+ (
+ 6,
+ "N6",
+ vec![("p1", Prop::U64(1u64)), ("k4", Prop::F64(1.0f64))],
+ Some("fire_nation"),
+ ),
+ (
+ 3,
+ "N7",
+ vec![
+ ("p1", Prop::U64(1u64)),
+ ("k1", Prop::I64(2i64)),
+ ("k2", Prop::Str(ArcStr::from("Paper_Ship"))),
+ ("k3", Prop::Bool(true)),
+ ("k4", Prop::F64(10.0f64)),
+ ],
+ Some("air_nomad"),
+ ),
+ (5, "N7", vec![("p1", Prop::U64(1u64))], Some("air_nomad")),
+ (3, "N8", vec![("p1", Prop::U64(1u64))], Some("fire_nation")),
+ (
+ 4,
+ "N8",
+ vec![
+ ("p1", Prop::U64(2u64)),
+ ("k1", Prop::I64(2i64)),
+ ("k2", Prop::Str(ArcStr::from("Sand_Clown"))),
+ ("k3", Prop::Bool(true)),
+ ("k4", Prop::F64(10.0f64)),
+ ],
+ Some("fire_nation"),
+ ),
+ (2, "N9", vec![("p1", Prop::U64(2u64))], None),
+ (2, "N10", vec![("q1", Prop::U64(0u64))], None),
+ (2, "N10", vec![("p1", Prop::U64(3u64))], None),
+ (2, "N11", vec![("p1", Prop::U64(3u64))], None),
+ (2, "N11", vec![("q1", Prop::U64(0u64))], None),
+ (2, "N12", vec![("q1", Prop::U64(0u64))], None),
+ (
+ 3,
+ "N12",
+ vec![
+ ("p1", Prop::U64(3u64)),
+ ("k1", Prop::I64(2i64)),
+ ("k2", Prop::Str(ArcStr::from("Sand_Clown"))),
+ ("k3", Prop::Bool(true)),
+ ("k4", Prop::F64(10.0f64)),
+ ],
+ None,
+ ),
+ (2, "N13", vec![("q1", Prop::U64(0u64))], None),
+ (3, "N13", vec![("p1", Prop::U64(3u64))], None),
+ (2, "N14", vec![("q1", Prop::U64(0u64))], None),
+ (2, "N15", vec![], None),
+ ];
+
+ // Add nodes to the graph
+ for (id, name, props, layer) in &nodes {
+ graph
+ .add_node(*id, name, props.clone(), *layer, None)
+ .unwrap();
+ }
+
+ // Metadata property assignments
+ let metadata = vec![
+ (
+ "N1",
+ vec![
+ ("p1", Prop::U64(1u64)),
+ ("k1", Prop::I64(3i64)),
+ ("k2", Prop::Str(ArcStr::from("Paper_Airplane"))),
+ ("k3", Prop::Bool(true)),
+ ("k4", Prop::F64(6.0f64)),
+ ],
+ ),
+ ("N4", vec![("p1", Prop::U64(2u64))]),
+ ("N9", vec![("p1", Prop::U64(1u64))]),
+ ("N10", vec![("p1", Prop::U64(1u64))]),
+ ("N11", vec![("p1", Prop::U64(1u64))]),
+ ("N12", vec![("p1", Prop::U64(1u64))]),
+ (
+ "N13",
+ vec![
+ ("p1", Prop::U64(1u64)),
+ ("k1", Prop::I64(2i64)),
+ ("k2", Prop::Str(ArcStr::from("Sand_Clown"))),
+ ("k3", Prop::Bool(true)),
+ ("k4", Prop::F64(10.0f64)),
+ ],
+ ),
+ ("N14", vec![("p1", Prop::U64(1u64))]),
+ ("N15", vec![("p1", Prop::U64(1u64))]),
+ ];
+
+ // Apply metadata
+ for (node, props) in metadata {
+ graph.node(node).unwrap().add_metadata(props).unwrap();
+ }
+
+ graph
+ }
+
+ fn init_graph2<
+ G: StaticGraphViewOps
+ + AdditionOps
+ + InternalAdditionOps
+ + InternalPropertyAdditionOps
+ + PropertyAdditionOps,
+ >(
+ graph: G,
+ ) -> G {
+ let nodes = vec![(
+ 2,
+ "N14",
+ vec![
+ ("q1", Prop::U64(0u64)),
+ (
+ "x",
+ Prop::list(vec![Prop::U64(1), Prop::U64(6), Prop::U64(9)]),
+ ),
+ ],
+ None,
+ )];
+
+ // Add nodes to the graph
+ for (id, name, props, layer) in &nodes {
+ graph
+ .add_node(*id, name, props.clone(), *layer, None)
+ .unwrap();
+ }
+
+ graph
+ }
+
+ #[test]
+ fn test_nodes_filters_for_node_name_eq() {
+ // TODO: Enable event_disk_graph once bug fixed: https://github.com/Pometry/Raphtory/issues/2098
+ let filter = NodeFilter::name().eq("N2");
+ let expected_results = vec!["N2"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ }
+
+ #[test]
+ fn test_nodes_filters_pg_for_node_name_eq() {
+ let filter = NodeFilter::name().eq("N2");
+ let expected_results = vec!["N2"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+
+ #[test]
+ fn test_nodes_filters_for_node_name_ne() {
+ // TODO: Enable event_disk_graph once bug fixed: https://github.com/Pometry/Raphtory/issues/2098
+ let filter = NodeFilter::name().ne("N2");
+ let expected_results = vec!["N1", "N3", "N5", "N6"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ }
+
+ #[test]
+ fn test_nodes_filters_pg_for_node_name_ne() {
+ let filter = NodeFilter::name().ne("N2");
+ let expected_results = vec![
+ "N1", "N10", "N11", "N12", "N13", "N14", "N15", "N3", "N5", "N6", "N7", "N8", "N9",
+ ];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+
+ #[test]
+ fn test_nodes_filters_for_node_name_in() {
+ // TODO: Enable event_disk_graph once bug fixed: https://github.com/Pometry/Raphtory/issues/2098
+ let filter = NodeFilter::name().is_in(vec!["N2"]);
+ let expected_results = vec!["N2"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ let filter = NodeFilter::name().is_in(vec!["N2", "N5"]);
+ let expected_results = vec!["N2", "N5"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ }
+
+ #[test]
+ fn test_nodes_filters_pg_for_node_name_in() {
+ let filter = NodeFilter::name().is_in(vec!["N2"]);
+ let expected_results = vec!["N2"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = NodeFilter::name().is_in(vec!["N2", "N5"]);
+ let expected_results = vec!["N2", "N5"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+
+ #[test]
+ fn test_nodes_filters_for_node_name_not_in() {
+ // TODO: Enable event_disk_graph once bug fixed: https://github.com/Pometry/Raphtory/issues/2098
+ let filter = NodeFilter::name().is_not_in(vec!["N5"]);
+ let expected_results = vec!["N1", "N2", "N3", "N6"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ }
+
+ #[test]
+ fn test_nodes_filters_pg_for_node_name_not_in() {
+ let filter = NodeFilter::name().is_not_in(vec!["N5"]);
+ let expected_results = vec![
+ "N1", "N10", "N11", "N12", "N13", "N14", "N15", "N2", "N3", "N6", "N7", "N8", "N9",
+ ];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+
+ #[test]
+ fn test_nodes_filters_for_node_type_eq() {
+ // TODO: Enable event_disk_graph once bug fixed: https://github.com/Pometry/Raphtory/issues/2098
+ let filter = NodeFilter::node_type().eq("fire_nation");
+ let expected_results = vec!["N6"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ }
+
+ #[test]
+ fn test_nodes_filters_pg_for_node_type_eq() {
+ let filter = NodeFilter::node_type().eq("fire_nation");
+ let expected_results = vec!["N6", "N8"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+
+ #[test]
+ fn test_nodes_filters_for_node_type_ne() {
+ // TODO: Enable event_disk_graph once bug fixed: https://github.com/Pometry/Raphtory/issues/2098
+ let filter = NodeFilter::node_type().ne("fire_nation");
+ let expected_results = vec!["N1", "N2", "N3", "N5"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ }
+
+ #[test]
+ fn test_nodes_filters_pg_for_node_type_ne() {
+ let filter = NodeFilter::node_type().ne("fire_nation");
+ let expected_results = vec![
+ "N1", "N10", "N11", "N12", "N13", "N14", "N15", "N2", "N3", "N5", "N7", "N9",
+ ];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+
+ #[test]
+ fn test_nodes_filters_for_node_type_in() {
+ // TODO: Enable event_disk_graph once bug fixed: https://github.com/Pometry/Raphtory/issues/2098
+ let filter = NodeFilter::node_type().is_in(vec!["fire_nation"]);
+ let expected_results = vec!["N6"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+
+ let filter = NodeFilter::node_type().is_in(vec!["fire_nation", "air_nomad"]);
+ let expected_results = vec!["N1", "N3", "N5", "N6"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ }
+
+ #[test]
+ fn test_nodes_filters_pg_for_node_type_in() {
+ let filter = NodeFilter::node_type().is_in(vec!["fire_nation"]);
+ let expected_results = vec!["N6", "N8"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = NodeFilter::node_type().is_in(vec!["fire_nation", "air_nomad"]);
+ let expected_results = vec!["N1", "N3", "N5", "N6", "N7", "N8"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+
+ #[test]
+ fn test_nodes_filters_for_node_type_not_in() {
+ // TODO: Enable event_disk_graph once bug fixed: https://github.com/Pometry/Raphtory/issues/2098
+ let filter = NodeFilter::node_type().is_not_in(vec!["fire_nation"]);
+ let expected_results = vec!["N1", "N2", "N3", "N5"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ }
+
+ #[test]
+ fn test_nodes_filters_pg_for_node_type_not_in() {
+ let filter = NodeFilter::node_type().is_not_in(vec!["fire_nation"]);
+ let expected_results = vec![
+ "N1", "N10", "N11", "N12", "N13", "N14", "N15", "N2", "N3", "N5", "N7", "N9",
+ ];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+
+ #[test]
+ fn test_nodes_filters_for_property_eq() {
+ // TODO: Enable event_disk_graph once bug fixed: https://github.com/Pometry/Raphtory/issues/2098
+ let filter = NodeFilter.property("p1").eq(1u64);
+ let expected_results = vec!["N1", "N3", "N6"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+
+ let filter = NodeFilter.property("k1").eq(2i64);
+ let expected_results = vec!["N2"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+
+ let filter = NodeFilter.property("k2").eq("Paper_Airplane");
+ let expected_results = vec!["N1"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ let filter = NodeFilter.property("k3").eq(true);
+ let expected_results = vec!["N2"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ let filter = NodeFilter.property("k4").eq(6.0f64);
+ let expected_results = vec!["N1"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ let filter =
+ NodeFilter
+ .property("x")
+ .eq(Prop::list(vec![Prop::U64(1), Prop::U64(6), Prop::U64(9)]));
+ let expected_results = vec!["N14"];
+ // TODO: List(U64) not supported as disk_graph property
+ // assert_filter_nodes_results_w!(
+ // init_graph2,
+ // filter,
+ // 1..9,
+ // expected_results,
+ // variants = [graph]
+ // );
+ assert_filter_nodes_results(
+ init_graph2,
+ WindowGraphTransformer(1..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ // TODO: Search APIs don't support list yet
+ // assert_search_nodes_results(
+ // init_graph,
+ // WindowGraphTransformer(6..9),
+ // filter,
+ // &expected_results,
+ // TestVariants::EventOnly,
+ // );
+ }
+
+ #[test]
+ fn test_nodes_filters_pg_for_property_eq() {
+ let filter = NodeFilter.property("p1").eq(1u64);
+ let expected_results = vec!["N1", "N3", "N6", "N7"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = NodeFilter.property("k1").eq(2i64);
+ let expected_results = vec!["N12", "N2", "N5", "N7", "N8"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = NodeFilter.property("k2").eq("Paper_Airplane");
+ let expected_results = vec!["N1"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ // TODO: Const properties not supported for disk_graph.
+ let filter = NodeFilter.property("k3").eq(true);
+ let expected_results = vec!["N12", "N2", "N5", "N7", "N8"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = NodeFilter.property("k4").eq(6.0f64);
+ let expected_results = vec!["N1"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter =
+ NodeFilter
+ .property("x")
+ .eq(Prop::list(vec![Prop::U64(1), Prop::U64(6), Prop::U64(9)]));
+ let expected_results = vec!["N14"];
+ // TODO: List(U64) not supported as disk_graph property
+ // assert_filter_nodes_results_pg_w!(
+ // init_graph2,
+ // filter,
+ // 1..9,
+ // expected_results,
+ // variants = [persistent_graph]
+ // );
+ assert_filter_nodes_results(
+ init_graph2,
+ WindowGraphTransformer(1..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::PersistentGraph],
+ );
+ // TODO: Search APIs don't support list yet
+ // assert_search_nodes_results(
+ // init_graph,
+ // WindowGraphTransformer(6..9),
+ // filter,
+ // &expected_results,
+ // vec![TestGraphVariants::PersistentGraph],
+ // );
+ }
+
+ #[test]
+ fn test_nodes_filters_for_property_ne() {
+ // TODO: Enable event_disk_graph once bug fixed: https://github.com/Pometry/Raphtory/issues/2098
+ let filter = NodeFilter.property("p1").ne(1u64);
+ let expected_results = vec!["N2", "N5"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+
+ let filter = NodeFilter.property("k1").ne(2i64);
+ let expected_results = vec!["N1"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+
+ let filter = NodeFilter.property("k2").ne("Paper_Airplane");
+ let expected_results = vec!["N2", "N5"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+
+ let filter = NodeFilter.property("k3").ne(true);
+ let expected_results = vec!["N1"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+
+ let filter = NodeFilter.property("k4").ne(6.0f64);
+ let expected_results = vec!["N2", "N5", "N6"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ }
+
+ #[test]
+ fn test_nodes_filters_pg_for_property_ne() {
+ let filter = NodeFilter.property("p1").ne(1u64);
+ let expected_results = vec!["N10", "N11", "N12", "N13", "N2", "N5", "N8", "N9"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = NodeFilter.property("k1").ne(2i64);
+ let expected_results = vec!["N1"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = NodeFilter.property("k2").ne("Paper_Airplane");
+ let expected_results = vec!["N12", "N2", "N5", "N7", "N8"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = NodeFilter.property("k3").ne(true);
+ let expected_results = vec!["N1"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = NodeFilter.property("k4").ne(6.0f64);
+ let expected_results = vec!["N12", "N2", "N5", "N6", "N7", "N8"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+
+ #[test]
+ fn test_nodes_filters_for_property_lt() {
+ // TODO: Enable event_disk_graph once bug fixed: https://github.com/Pometry/Raphtory/issues/2098
+ let filter = NodeFilter.property("p1").lt(3u64);
+ let expected_results = vec!["N1", "N2", "N3", "N5", "N6"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+
+ let filter = NodeFilter.property("k1").lt(3i64);
+ let expected_results = vec!["N2"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+
+ let filter = NodeFilter.property("k4").lt(10.0f64);
+ let expected_results = vec!["N1", "N5", "N6"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ }
+
+ #[test]
+ fn test_nodes_filters_pg_for_property_lt() {
+ let filter = NodeFilter.property("p1").lt(3u64);
+ let expected_results = vec!["N1", "N2", "N3", "N5", "N6", "N7", "N8", "N9"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = NodeFilter.property("k1").lt(3i64);
+ let expected_results = vec!["N12", "N2", "N5", "N7", "N8"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = NodeFilter.property("k4").lt(10.0f64);
+ let expected_results = vec!["N1", "N5", "N6"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+
+ #[test]
+ fn test_nodes_filters_for_property_le() {
+ // TODO: Enable event_disk_graph once bug fixed: https://github.com/Pometry/Raphtory/issues/2098
+ let filter = NodeFilter.property("p1").le(1u64);
+ let expected_results = vec!["N1", "N3", "N6"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+
+ let filter = NodeFilter.property("k1").le(2i64);
+ let expected_results = vec!["N2"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+
+ let filter = NodeFilter.property("k4").le(6.0f64);
+ let expected_results = vec!["N1", "N5", "N6"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ }
+
+ #[test]
+ fn test_nodes_filters_pg_for_property_le() {
+ let filter = NodeFilter.property("p1").le(1u64);
+ let expected_results = vec!["N1", "N3", "N6", "N7"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = NodeFilter.property("k1").le(2i64);
+ let expected_results = vec!["N12", "N2", "N5", "N7", "N8"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = NodeFilter.property("k4").le(6.0f64);
+ let expected_results = vec!["N1", "N5", "N6"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+
+ #[test]
+ fn test_nodes_filters_for_property_gt() {
+ // TODO: Enable event_disk_graph once bug fixed: https://github.com/Pometry/Raphtory/issues/2098
+ let filter = NodeFilter.property("p1").gt(1u64);
+ let expected_results = vec!["N2", "N5"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+
+ let filter = NodeFilter.property("k1").gt(2i64);
+ let expected_results = vec!["N1"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+
+ let filter = NodeFilter.property("k4").gt(6.0f64);
+ let expected_results = vec!["N2"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+
+ let filter = NodeFilter.property("x").gt(Prop::List(
+ vec![Prop::U64(1), Prop::U64(6), Prop::U64(9)].into(),
+ ));
+ let graph = init_graph(Graph::new());
+ assert!(matches!(
+ graph.window(1, 9).filter(filter.clone()).unwrap_err(),
+ GraphError::PropertyMissingError(ref name) if name == "x"
+ ));
+ assert!(matches!(
+ graph.persistent_graph().window(1, 9).filter(filter).unwrap_err(),
+ GraphError::PropertyMissingError(ref name) if name == "x"
+ ));
+ }
+
+ #[test]
+ fn test_nodes_filters_pg_for_property_gt() {
+ let filter = NodeFilter.property("p1").gt(1u64);
+ let expected_results = vec!["N10", "N11", "N12", "N13", "N2", "N5", "N8", "N9"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = NodeFilter.property("k1").gt(2i64);
+ let expected_results = vec!["N1"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = NodeFilter.property("k4").gt(6.0f64);
+ let expected_results = vec!["N12", "N2", "N7", "N8"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+
+ #[test]
+ fn test_nodes_filters_for_property_ge() {
+ // TODO: Enable event_disk_graph once bug fixed: https://github.com/Pometry/Raphtory/issues/2098
+ let filter = NodeFilter.property("p1").ge(1u64);
+ let expected_results = vec!["N1", "N2", "N3", "N5", "N6"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+
+ let filter = NodeFilter.property("k1").ge(2i64);
+ let expected_results = vec!["N1", "N2"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+
+ let filter = NodeFilter.property("k4").ge(6.0f64);
+ let expected_results = vec!["N1", "N2"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ }
+
+ #[test]
+ fn test_nodes_filters_pg_for_property_ge() {
+ let filter = NodeFilter.property("p1").ge(1u64);
+ let expected_results = vec![
+ "N1", "N10", "N11", "N12", "N13", "N2", "N3", "N5", "N6", "N7", "N8", "N9",
+ ];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = NodeFilter.property("k1").ge(2i64);
+ let expected_results = vec!["N1", "N12", "N2", "N5", "N7", "N8"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = NodeFilter.property("k4").ge(6.0f64);
+ let expected_results = vec!["N1", "N12", "N2", "N7", "N8"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+
+ #[test]
+ fn test_nodes_filters_for_property_in() {
+ // TODO: Enable event_disk_graph once bug fixed: https://github.com/Pometry/Raphtory/issues/2098
+ let filter = NodeFilter.property("p1").is_in(vec![2u64.into()]);
+ let expected_results = vec!["N2", "N5"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+
+ let filter = NodeFilter.property("k1").is_in(vec![2i64.into()]);
+ let expected_results = vec!["N2"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+
+ let filter = NodeFilter
+ .property("k2")
+ .is_in(vec!["Paper_Airplane".into()]);
+ let expected_results = vec!["N1"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+
+ let filter = NodeFilter.property("k3").is_in(vec![true.into()]);
+ let expected_results = vec!["N2"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+
+ let filter = NodeFilter.property("k4").is_in(vec![6.0f64.into()]);
+ let expected_results = vec!["N1"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ }
+
+ #[test]
+ fn test_nodes_filters_pg_for_property_in() {
+ let filter = NodeFilter.property("p1").is_in(vec![2u64.into()]);
+ let expected_results = vec!["N2", "N5", "N8", "N9"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = NodeFilter.property("k1").is_in(vec![2i64.into()]);
+ let expected_results = vec!["N12", "N2", "N5", "N7", "N8"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = NodeFilter
+ .property("k2")
+ .is_in(vec!["Paper_Airplane".into()]);
+ let expected_results = vec!["N1"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ // TODO: Const properties not supported for disk_graph.
+ let filter = NodeFilter.property("k3").is_in(vec![true.into()]);
+ let expected_results = vec!["N12", "N2", "N5", "N7", "N8"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = NodeFilter.property("k4").is_in(vec![6.0f64.into()]);
+ let expected_results = vec!["N1"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+
+ #[test]
+ fn test_nodes_filters_for_property_not_in() {
+ // TODO: Enable event_disk_graph once bug fixed: https://github.com/Pometry/Raphtory/issues/2098
+ let filter = NodeFilter.property("p1").is_not_in(vec![1u64.into()]);
+ let expected_results = vec!["N2", "N5"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+
+ let filter = NodeFilter.property("k1").is_not_in(vec![2i64.into()]);
+ let expected_results = vec!["N1"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+
+ let filter = NodeFilter
+ .property("k2")
+ .is_not_in(vec!["Paper_Airplane".into()]);
+ let expected_results = vec!["N2", "N5"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+
+ let filter = NodeFilter.property("k3").is_not_in(vec![true.into()]);
+ let expected_results = vec!["N1"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+
+ let filter = NodeFilter.property("k4").is_not_in(vec![6.0f64.into()]);
+ let expected_results = vec!["N2", "N5", "N6"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ }
+
+ #[test]
+ fn test_nodes_filters_pg_for_property_not_in() {
+ let filter = NodeFilter.property("p1").is_not_in(vec![1u64.into()]);
+ let expected_results = vec!["N10", "N11", "N12", "N13", "N2", "N5", "N8", "N9"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = NodeFilter.property("k1").is_not_in(vec![2i64.into()]);
+ let expected_results = vec!["N1"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = NodeFilter
+ .property("k2")
+ .is_not_in(vec!["Paper_Airplane".into()]);
+ let expected_results = vec!["N12", "N2", "N5", "N7", "N8"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = NodeFilter.property("k3").is_not_in(vec![true.into()]);
+ let expected_results = vec!["N1"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = NodeFilter.property("k4").is_not_in(vec![6.0f64.into()]);
+ let expected_results = vec!["N12", "N2", "N5", "N6", "N7", "N8"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+
+ #[test]
+ fn test_nodes_filters_for_property_is_some() {
+ // TODO: Enable event_disk_graph once bug fixed: https://github.com/Pometry/Raphtory/issues/2098
+ let filter = NodeFilter.property("p1").is_some();
+ let expected_results = vec!["N1", "N2", "N3", "N5", "N6"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+
+ let expected_results = Vec::<&str>::new();
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(1..2),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(1..2),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(10..12),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(10..12),
+ filter,
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ }
+
+ #[test]
+ fn test_nodes_filters_pg_for_property_is_some() {
+ let filter = NodeFilter.property("p1").is_some();
+ let expected_results = vec![
+ "N1", "N10", "N11", "N12", "N13", "N2", "N3", "N5", "N6", "N7", "N8", "N9",
+ ];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let expected_results = Vec::<&str>::new();
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(1..2),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(1..2),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let expected_results = vec![
+ "N1", "N10", "N11", "N12", "N13", "N2", "N3", "N4", "N5", "N6", "N7", "N8", "N9",
+ ];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(10..12),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(10..12),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+
+ #[test]
+ fn test_nodes_filters_for_props_added_at_different_times() {
+ let filter = NodeFilter
+ .property("q1")
+ .eq(0u64)
+ .and(NodeFilter.property("p1").eq(3u64));
+ let expected_results = vec!["N10", "N11", "N12", "N13"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(1..4),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(1..4),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ }
+
+ #[test]
+ fn test_nodes_filters_pg_for_props_added_at_different_times() {
+ let filter = NodeFilter
+ .property("q1")
+ .eq(0u64)
+ .and(NodeFilter.property("p1").eq(3u64));
+ let expected_results = vec!["N10", "N11", "N12", "N13"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+
+ #[test]
+ fn test_nodes_filters_fuzzy_search() {
+ // TODO: Enable event_disk_graph once bug fixed: https://github.com/Pometry/Raphtory/issues/2098
+ let filter = NodeFilter
+ .property("k2")
+ .fuzzy_search("Paper_Airpla", 2, false);
+ let expected_results = vec!["N1"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ }
+
+ #[test]
+ fn test_nodes_filters_pg_fuzzy_search() {
+ let filter = NodeFilter
+ .property("k2")
+ .fuzzy_search("Paper_Air", 5, false);
+ let expected_results = vec!["N1", "N2", "N7"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+
+ #[test]
+ fn test_nodes_filters_fuzzy_search_prefix_match() {
+ // TODO: Enable event_disk_graph once bug fixed: https://github.com/Pometry/Raphtory/issues/2098
+ let filter = NodeFilter.property("k2").fuzzy_search("Pa", 2, true);
+ let expected_results = vec!["N1", "N2"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+
+ let filter = NodeFilter.property("k2").fuzzy_search("Pa", 2, false);
+ let expected_results = Vec::<&str>::new();
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ }
+
+ #[test]
+ fn test_nodes_filters_pg_fuzzy_search_prefix_match() {
+ let filter = NodeFilter.property("k2").fuzzy_search("Pa", 2, true);
+ let expected_results = vec!["N1", "N2", "N7"];
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = NodeFilter.property("k2").fuzzy_search("Pa", 2, false);
+ let expected_results = Vec::<&str>::new();
+ assert_filter_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_nodes_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+}
+
+mod test_edges_filters_window_graph {
+ use raphtory::{
+ db::{
+ api::view::{filter_ops::Filter, StaticGraphViewOps},
+ graph::views::filter::model::{
+ edge_filter::EdgeFilter, node_filter::ops::NodeFilterOps,
+ property_filter::ops::PropertyFilterOps, ComposableFilter, PropertyFilterFactory,
+ },
+ },
+ errors::GraphError,
+ prelude::{AdditionOps, Graph, GraphViewOps, PropertyAdditionOps, TimeOps, NO_PROPS},
+ };
+ use raphtory_api::core::{entities::properties::prop::Prop, storage::arc_str::ArcStr};
+ use raphtory_tests::assertions::{
+ assert_filter_edges_results, assert_search_edges_results, TestGraphVariants, TestVariants,
+ WindowGraphTransformer,
+ };
+
+ fn init_graph(graph: G) -> G {
+ let edges = vec![
+ (
+ 6,
+ "N1",
+ "N2",
+ vec![
+ ("p1", Prop::U64(2u64)),
+ ("k1", Prop::I64(2i64)),
+ ("k2", Prop::Str(ArcStr::from("Paper_Airplane"))),
+ ("k3", Prop::Bool(true)),
+ ("k4", Prop::F64(6.0f64)),
+ ],
+ Some("air_nomad"),
+ ),
+ (
+ 7,
+ "N1",
+ "N2",
+ vec![
+ ("p1", Prop::U64(1u64)),
+ ("k1", Prop::I64(5i64)),
+ ("k3", Prop::Bool(false)),
+ ],
+ Some("air_nomad"),
+ ),
+ (
+ 6,
+ "N2",
+ "N3",
+ vec![("p1", Prop::U64(1u64)), ("k4", Prop::F64(6.0f64))],
+ Some("water_tribe"),
+ ),
+ (
+ 7,
+ "N2",
+ "N3",
+ vec![
+ ("p1", Prop::U64(2u64)),
+ ("k1", Prop::I64(2i64)),
+ ("k2", Prop::Str(ArcStr::from("Paper_Ship"))),
+ ("k3", Prop::Bool(true)),
+ ("k4", Prop::F64(10.0f64)),
+ ],
+ Some("water_tribe"),
+ ),
+ (
+ 8,
+ "N3",
+ "N4",
+ vec![("p1", Prop::U64(1u64))],
+ Some("air_nomad"),
+ ),
+ (
+ 9,
+ "N4",
+ "N5",
+ vec![("p1", Prop::U64(1u64))],
+ Some("air_nomad"),
+ ),
+ (
+ 5,
+ "N5",
+ "N6",
+ vec![
+ ("p1", Prop::U64(1u64)),
+ ("k1", Prop::I64(2i64)),
+ ("k2", Prop::Str(ArcStr::from("Paper_Airplane"))),
+ ("k3", Prop::Bool(true)),
+ ("k4", Prop::F64(6.0f64)),
+ ],
+ Some("air_nomad"),
+ ),
+ (
+ 6,
+ "N5",
+ "N6",
+ vec![
+ ("p1", Prop::U64(2u64)),
+ ("k2", Prop::Str(ArcStr::from("Pometry"))),
+ ("k4", Prop::F64(1.0f64)),
+ ],
+ Some("air_nomad"),
+ ),
+ (
+ 5,
+ "N6",
+ "N7",
+ vec![("p1", Prop::U64(1u64))],
+ Some("fire_nation"),
+ ),
+ (
+ 6,
+ "N6",
+ "N7",
+ vec![("p1", Prop::U64(1u64)), ("k4", Prop::F64(1.0f64))],
+ Some("fire_nation"),
+ ),
+ (
+ 3,
+ "N7",
+ "N8",
+ vec![
+ ("p1", Prop::U64(1u64)),
+ ("k1", Prop::I64(2i64)),
+ ("k2", Prop::Str(ArcStr::from("Paper_Ship"))),
+ ("k3", Prop::Bool(true)),
+ ("k4", Prop::F64(10.0f64)),
+ ],
+ Some("air_nomad"),
+ ),
+ (
+ 5,
+ "N7",
+ "N8",
+ vec![("p1", Prop::U64(1u64))],
+ Some("air_nomad"),
+ ),
+ (
+ 3,
+ "N8",
+ "N9",
+ vec![("p1", Prop::U64(1u64))],
+ Some("fire_nation"),
+ ),
+ (
+ 4,
+ "N8",
+ "N9",
+ vec![
+ ("p1", Prop::U64(2u64)),
+ ("k1", Prop::I64(2i64)),
+ ("k2", Prop::Str(ArcStr::from("Sand_Clown"))),
+ ("k3", Prop::Bool(true)),
+ ("k4", Prop::F64(10.0f64)),
+ ],
+ Some("fire_nation"),
+ ),
+ (2, "N9", "N10", vec![("p1", Prop::U64(2u64))], None),
+ (2, "N10", "N11", vec![("q1", Prop::U64(0u64))], None),
+ (2, "N10", "N11", vec![("p1", Prop::U64(3u64))], None),
+ (2, "N11", "N12", vec![("p1", Prop::U64(3u64))], None),
+ (2, "N11", "N12", vec![("q1", Prop::U64(0u64))], None),
+ (2, "N12", "N13", vec![("q1", Prop::U64(0u64))], None),
+ (
+ 3,
+ "N12",
+ "N13",
+ vec![
+ ("p1", Prop::U64(3u64)),
+ ("k1", Prop::I64(2i64)),
+ ("k2", Prop::Str(ArcStr::from("Sand_Clown"))),
+ ("k3", Prop::Bool(true)),
+ ("k4", Prop::F64(10.0f64)),
+ ],
+ None,
+ ),
+ (2, "N13", "N14", vec![("q1", Prop::U64(0u64))], None),
+ (3, "N13", "N14", vec![("p1", Prop::U64(3u64))], None),
+ (2, "N14", "N15", vec![("q1", Prop::U64(0u64))], None),
+ (2, "N15", "N1", vec![], None),
+ ];
+
+ for (id, src, dst, props, layer) in &edges {
+ graph
+ .add_edge(*id, src, dst, props.clone(), *layer)
+ .unwrap();
+ }
+
+ // Metadata property assignments
+ let metadata = vec![
+ (
+ "N1",
+ "N2",
+ vec![
+ ("p1", Prop::U64(1u64)),
+ ("k1", Prop::I64(3i64)),
+ ("k2", Prop::Str(ArcStr::from("Paper_Airplane"))),
+ ("k3", Prop::Bool(true)),
+ ("k4", Prop::F64(6.0f64)),
+ ],
+ Some("air_nomad"),
+ ),
+ ("N4", "N5", vec![("p1", Prop::U64(2u64))], Some("air_nomad")),
+ ("N9", "N10", vec![("p1", Prop::U64(1u64))], None),
+ ("N10", "N11", vec![("p1", Prop::U64(1u64))], None),
+ ("N11", "N12", vec![("p1", Prop::U64(1u64))], None),
+ ("N12", "N13", vec![("p1", Prop::U64(1u64))], None),
+ (
+ "N13",
+ "N14",
+ vec![
+ ("p1", Prop::U64(1u64)),
+ ("k1", Prop::I64(2i64)),
+ ("k2", Prop::Str(ArcStr::from("Sand_Clown"))),
+ ("k3", Prop::Bool(true)),
+ ("k4", Prop::F64(10.0f64)),
+ ],
+ None,
+ ),
+ ("N14", "N15", vec![("p1", Prop::U64(1u64))], None),
+ ("N15", "N1", vec![("p1", Prop::U64(1u64))], None),
+ ];
+
+ for (src, dst, props, layer) in metadata {
+ graph
+ .edge(src, dst)
+ .unwrap()
+ .add_metadata(props, layer)
+ .unwrap();
+ }
+
+ graph.add_node(1, "N1", NO_PROPS, None, None).unwrap();
+ graph.add_node(2, "N2", NO_PROPS, None, None).unwrap();
+ graph.add_node(3, "N3", NO_PROPS, None, None).unwrap();
+
+ graph
+ }
+
+ fn init_graph2(graph: G) -> G {
+ let edges = vec![(
+ 2,
+ "N14",
+ "N15",
+ vec![
+ ("q1", Prop::U64(0u64)),
+ (
+ "x",
+ Prop::list(vec![Prop::U64(1), Prop::U64(6), Prop::U64(9)]),
+ ),
+ ],
+ None,
+ )];
+
+ for (id, src, dst, props, layer) in &edges {
+ graph
+ .add_edge(*id, src, dst, props.clone(), *layer)
+ .unwrap();
+ }
+
+ graph
+ }
+
+ #[test]
+ fn test_edges_filters_for_src_eq() {
+ let filter = EdgeFilter::src().name().eq("N2");
+ let expected_results = vec!["N2->N3"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ }
+
+ #[test]
+ fn test_edges_filters_pg_for_src_eq() {
+ let filter = EdgeFilter::src().name().eq("N2");
+ let expected_results = vec!["N2->N3"];
+ // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![],
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+
+ #[test]
+ fn test_edges_filters_for_src_ne() {
+ let filter = EdgeFilter::src().name().ne("N2");
+ let expected_results = vec!["N1->N2", "N3->N4", "N5->N6", "N6->N7"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ }
+
+ #[test]
+ fn test_edges_filters_pg_for_src_ne() {
+ let filter = EdgeFilter::src().name().ne("N2");
+ let expected_results = vec![
+ "N1->N2", "N10->N11", "N11->N12", "N12->N13", "N13->N14", "N14->N15", "N15->N1",
+ "N3->N4", "N5->N6", "N6->N7", "N7->N8", "N8->N9", "N9->N10",
+ ];
+ // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![],
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ vec![TestGraphVariants::PersistentGraph],
+ );
+ }
+
+ #[test]
+ fn test_edges_filters_for_dst_in() {
+ let filter = EdgeFilter::dst().name().is_in(vec!["N2"]);
+ let expected_results = vec!["N1->N2"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ let filter = EdgeFilter::dst().name().is_in(vec!["N2", "N5"]);
+ let expected_results = vec!["N1->N2"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ }
+
+ #[test]
+ fn test_edges_filters_pg_for_dst_in() {
+ // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
+ let filter = EdgeFilter::dst().name().is_in(vec!["N2"]);
+ let expected_results = vec!["N1->N2"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![],
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = EdgeFilter::dst().name().is_in(vec!["N2", "N5"]);
+ let expected_results = vec!["N1->N2"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![],
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+
+ #[test]
+ fn test_edges_filters_for_dst_not_in() {
+ let filter = EdgeFilter::dst().name().is_not_in(vec!["N5"]);
+ let expected_results = vec!["N1->N2", "N2->N3", "N3->N4", "N5->N6", "N6->N7"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ }
+
+ #[test]
+ fn test_edges_filters_pg_for_dst_not_in() {
+ let filter = EdgeFilter::dst().name().is_not_in(vec!["N5"]);
+ let expected_results = vec![
+ "N1->N2", "N10->N11", "N11->N12", "N12->N13", "N13->N14", "N14->N15", "N15->N1",
+ "N2->N3", "N3->N4", "N5->N6", "N6->N7", "N7->N8", "N8->N9", "N9->N10",
+ ];
+ // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ vec![],
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+
+ #[test]
+ fn test_edges_filters_for_property_eq() {
+ let filter = EdgeFilter.property("p1").eq(1u64);
+ let expected_results = vec!["N1->N2", "N3->N4", "N6->N7"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ let filter = EdgeFilter.property("k1").eq(2i64);
+ let expected_results = vec!["N2->N3"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ let filter = EdgeFilter.property("k2").eq("Paper_Airplane");
+ let expected_results = vec!["N1->N2"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ let filter = EdgeFilter.property("k3").eq(true);
+ let expected_results = vec!["N2->N3"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ let filter = EdgeFilter.property("k4").eq(6.0f64);
+ let expected_results = vec!["N1->N2"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ let filter =
+ EdgeFilter
+ .property("x")
+ .eq(Prop::list(vec![Prop::U64(1), Prop::U64(6), Prop::U64(9)]));
+ let expected_results = vec!["N14->N15"];
+ // TODO: List(U64) not supported as disk_graph property
+ // assert_filter_edges_results_w!(
+ // init_graph2,
+ // filter,
+ // 1..9,
+ // expected_results,
+ // variants = [graph]
+ // );
+ assert_filter_edges_results(
+ init_graph2,
+ WindowGraphTransformer(1..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::Graph],
+ );
+ // TODO: Search APIs don't support list yet
+ // assert_search_edges_results(
+ // init_graph2,
+ // WindowGraphTransformer(6..9),
+ // filter,
+ // &expected_results,
+ // TestVariants::PersistentOnly,
+ // );
+ }
+
+ #[test]
+ fn test_edges_filters_pg_for_property_eq() {
+ // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
+ // TODO: Const properties not supported for disk_graph.
+ let filter = EdgeFilter.property("p1").eq(1u64);
+ let expected_results = vec!["N1->N2", "N3->N4", "N6->N7", "N7->N8"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = EdgeFilter.property("k1").eq(2i64);
+
+ let expected_results = vec!["N12->N13", "N2->N3", "N5->N6", "N7->N8", "N8->N9"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = EdgeFilter.property("k2").eq("Paper_Airplane");
+ let expected_results = vec!["N1->N2"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = EdgeFilter.property("k3").eq(true);
+ let expected_results = vec!["N12->N13", "N2->N3", "N5->N6", "N7->N8", "N8->N9"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = EdgeFilter.property("k4").eq(6.0f64);
+ let expected_results = vec!["N1->N2"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter =
+ EdgeFilter
+ .property("x")
+ .eq(Prop::list(vec![Prop::U64(1), Prop::U64(6), Prop::U64(9)]));
+ let expected_results = vec!["N14->N15"];
+ // TODO: List(U64) not supported as disk_graph property
+ // assert_filter_edges_results_pg_w!(
+ // init_graph2,
+ // filter,
+ // 1..9,
+ // expected_results,
+ // variants = []
+ // );
+ assert_filter_edges_results(
+ init_graph2,
+ WindowGraphTransformer(1..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::PersistentGraph],
+ );
+ // TODO: Search APIs don't support list yet
+ // assert_search_edges_results(
+ // init_graph2,
+ // WindowGraphTransformer(1..9),
+ // filter.clone(),
+ // &expected_results,
+ // vec![TestGraphVariants::PersistentGraph],
+ // );
+ }
+
+ #[test]
+ fn test_edges_filters_for_property_ne() {
+ let filter = EdgeFilter.property("p1").ne(1u64);
+ let expected_results = vec!["N2->N3", "N5->N6"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ let filter = EdgeFilter.property("k1").ne(2i64);
+ let expected_results = vec!["N1->N2"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ let filter = EdgeFilter.property("k2").ne("Paper_Airplane");
+ let expected_results = vec!["N2->N3", "N5->N6"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ let filter = EdgeFilter.property("k3").ne(true);
+ let expected_results = vec!["N1->N2"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ let filter = EdgeFilter.property("k4").ne(6.0f64);
+ let expected_results = vec!["N2->N3", "N5->N6", "N6->N7"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ }
+
+ #[test]
+ fn test_edges_filters_pg_for_property_ne() {
+ // TODO: Const properties not supported for disk_graph.
+ let filter = EdgeFilter.property("p1").ne(1u64);
+ let expected_results = vec![
+ "N10->N11", "N11->N12", "N12->N13", "N13->N14", "N2->N3", "N5->N6", "N8->N9", "N9->N10",
+ ];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = EdgeFilter.property("k1").ne(2i64);
+ let expected_results = vec!["N1->N2"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = EdgeFilter.property("k2").ne("Paper_Airplane");
+ let expected_results = vec!["N12->N13", "N2->N3", "N5->N6", "N7->N8", "N8->N9"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = EdgeFilter.property("k3").ne(true);
+ let expected_results = vec!["N1->N2"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = EdgeFilter.property("k4").ne(6.0f64);
+ let expected_results = vec!["N12->N13", "N2->N3", "N5->N6", "N6->N7", "N7->N8", "N8->N9"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter =
+ EdgeFilter
+ .property("x")
+ .ne(Prop::list(vec![Prop::U64(1), Prop::U64(6), Prop::U64(9)]));
+ let expected_results = Vec::<&str>::new();
+ assert_filter_edges_results(
+ init_graph2,
+ WindowGraphTransformer(1..9),
+ filter.clone(),
+ &expected_results,
+ vec![TestGraphVariants::PersistentGraph],
+ );
+ // TODO: Search APIs don't support list yet
+ // assert_search_edges_results(
+ // init_graph2,
+ // WindowGraphTransformer(1..9),
+ // filter.clone(),
+ // &expected_results,
+ // TestVariants::PersistentOnly,
+ // );
+ }
+
+ #[test]
+ fn test_edges_filters_for_property_lt() {
+ let filter = EdgeFilter.property("p1").lt(3u64);
+ let expected_results = vec!["N1->N2", "N2->N3", "N3->N4", "N5->N6", "N6->N7"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ let filter = EdgeFilter.property("k1").lt(3i64);
+ let expected_results = vec!["N2->N3"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ let filter = EdgeFilter.property("k4").lt(10.0f64);
+ let expected_results = vec!["N1->N2", "N5->N6", "N6->N7"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ }
+
+ #[test]
+ fn test_edges_filters_pg_for_property_lt() {
+ // TODO: Const properties not supported for disk_graph.
+ let filter = EdgeFilter.property("p1").lt(3u64);
+ let expected_results = vec![
+ "N1->N2", "N2->N3", "N3->N4", "N5->N6", "N6->N7", "N7->N8", "N8->N9", "N9->N10",
+ ];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = EdgeFilter.property("k1").lt(3i64);
+ let expected_results = vec!["N12->N13", "N2->N3", "N5->N6", "N7->N8", "N8->N9"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = EdgeFilter.property("k4").lt(10.0f64);
+ let expected_results = vec!["N1->N2", "N5->N6", "N6->N7"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+
+ #[test]
+ fn test_edges_filters_for_property_le() {
+ let filter = EdgeFilter.property("p1").le(1u64);
+ let expected_results = vec!["N1->N2", "N3->N4", "N6->N7"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ let filter = EdgeFilter.property("k1").le(2i64);
+ let expected_results = vec!["N2->N3"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ let filter = EdgeFilter.property("k4").le(6.0f64);
+ let expected_results = vec!["N1->N2", "N5->N6", "N6->N7"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ }
+
+ #[test]
+ fn test_edges_filters_pg_for_property_le() {
+ // TODO: Const properties not supported for disk_graph.
+ let filter = EdgeFilter.property("p1").le(1u64);
+ let expected_results = vec!["N1->N2", "N3->N4", "N6->N7", "N7->N8"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = EdgeFilter.property("k1").le(2i64);
+ let expected_results = vec!["N12->N13", "N2->N3", "N5->N6", "N7->N8", "N8->N9"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = EdgeFilter.property("k4").le(6.0f64);
+ let expected_results = vec!["N1->N2", "N5->N6", "N6->N7"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+
+ #[test]
+ fn test_edges_filters_for_property_gt() {
+ let filter = EdgeFilter.property("p1").gt(1u64);
+ let expected_results = vec!["N2->N3", "N5->N6"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ let filter = EdgeFilter.property("k1").gt(2i64);
+ let expected_results = vec!["N1->N2"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ let filter = EdgeFilter.property("k4").gt(6.0f64);
+ let expected_results = vec!["N2->N3"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ let filter = EdgeFilter.property("x").gt(Prop::List(
+ vec![Prop::U64(1), Prop::U64(6), Prop::U64(9)].into(),
+ ));
+ let graph = init_graph(Graph::new());
+ assert!(matches!(
+ graph.window(1, 9).filter(filter.clone()).unwrap_err(),
+ GraphError::PropertyMissingError(ref name) if name == "x"
+ ));
+ assert!(matches!(
+ graph.persistent_graph().window(1, 9).filter(filter).unwrap_err(),
+ GraphError::PropertyMissingError(ref name) if name == "x"
+ ));
+ }
+
+ #[test]
+ fn test_edges_filters_pg_for_property_gt() {
+ // TODO: Const properties not supported for disk_graph.
+ let filter = EdgeFilter.property("p1").gt(1u64);
+ let expected_results = vec![
+ "N10->N11", "N11->N12", "N12->N13", "N13->N14", "N2->N3", "N5->N6", "N8->N9", "N9->N10",
+ ];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = EdgeFilter.property("k1").gt(2i64);
+ let expected_results = vec!["N1->N2"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = EdgeFilter.property("k4").gt(6.0f64);
+ let expected_results = vec!["N12->N13", "N2->N3", "N7->N8", "N8->N9"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+
+ #[test]
+ fn test_edges_filters_for_property_ge() {
+ let filter = EdgeFilter.property("p1").ge(1u64);
+ let expected_results = vec!["N1->N2", "N2->N3", "N3->N4", "N5->N6", "N6->N7"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ let filter = EdgeFilter.property("k1").ge(2i64);
+ let expected_results = vec!["N1->N2", "N2->N3"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ let filter = EdgeFilter.property("k4").ge(6.0f64);
+ let expected_results = vec!["N1->N2", "N2->N3"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ }
+
+ #[test]
+ fn test_edges_filters_pg_for_property_ge() {
+ // TODO: Const properties not supported for disk_graph.
+ let filter = EdgeFilter.property("p1").ge(1u64);
+ let expected_results = vec![
+ "N1->N2", "N10->N11", "N11->N12", "N12->N13", "N13->N14", "N2->N3", "N3->N4", "N5->N6",
+ "N6->N7", "N7->N8", "N8->N9", "N9->N10",
+ ];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = EdgeFilter.property("k1").ge(2i64);
+ let expected_results = vec!["N1->N2", "N12->N13", "N2->N3", "N5->N6", "N7->N8", "N8->N9"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = EdgeFilter.property("k4").ge(6.0f64);
+ let expected_results = vec!["N1->N2", "N12->N13", "N2->N3", "N7->N8", "N8->N9"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+
+ #[test]
+ fn test_edges_filters_for_property_in() {
+ let filter = EdgeFilter.property("p1").is_in(vec![2u64.into()]);
+ let expected_results = vec!["N2->N3", "N5->N6"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ let filter = EdgeFilter.property("k1").is_in(vec![2i64.into()]);
+ let expected_results = vec!["N2->N3"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ let filter = EdgeFilter
+ .property("k2")
+ .is_in(vec!["Paper_Airplane".into()]);
+ let expected_results = vec!["N1->N2"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ let filter = EdgeFilter.property("k3").is_in(vec![true.into()]);
+ let expected_results = vec!["N2->N3"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ let filter = EdgeFilter.property("k4").is_in(vec![6.0f64.into()]);
+ let expected_results = vec!["N1->N2"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ }
+
+ #[test]
+ fn test_edges_filters_pg_for_property_in() {
+ // TODO: Const properties not supported for disk_graph.
+ let filter = EdgeFilter.property("p1").is_in(vec![2u64.into()]);
+ let expected_results = vec!["N2->N3", "N5->N6", "N8->N9", "N9->N10"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = EdgeFilter.property("k1").is_in(vec![2i64.into()]);
+ let expected_results = vec!["N12->N13", "N2->N3", "N5->N6", "N7->N8", "N8->N9"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = EdgeFilter
+ .property("k2")
+ .is_in(vec!["Paper_Airplane".into()]);
+ let expected_results = vec!["N1->N2"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = EdgeFilter.property("k3").is_in(vec![true.into()]);
+ let expected_results = vec!["N12->N13", "N2->N3", "N5->N6", "N7->N8", "N8->N9"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = EdgeFilter.property("k4").is_in(vec![6.0f64.into()]);
+ let expected_results = vec!["N1->N2"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+
+ #[test]
+ fn test_edges_filters_for_property_not_in() {
+ let filter = EdgeFilter.property("p1").is_not_in(vec![1u64.into()]);
+ let expected_results = vec!["N2->N3", "N5->N6"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ let filter = EdgeFilter.property("k1").is_not_in(vec![2i64.into()]);
+ let expected_results = vec!["N1->N2"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ let filter = EdgeFilter
+ .property("k2")
+ .is_not_in(vec!["Paper_Airplane".into()]);
+ let expected_results = vec!["N2->N3", "N5->N6"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ let filter = EdgeFilter.property("k3").is_not_in(vec![true.into()]);
+ let expected_results = vec!["N1->N2"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ let filter = EdgeFilter.property("k4").is_not_in(vec![6.0f64.into()]);
+ let expected_results = vec!["N2->N3", "N5->N6", "N6->N7"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ }
+
+ #[test]
+ fn test_edges_filters_pg_for_property_not_in() {
+ // TODO: Const properties not supported for disk_graph.
+ let filter = EdgeFilter.property("p1").is_not_in(vec![1u64.into()]);
+ let expected_results = vec![
+ "N10->N11", "N11->N12", "N12->N13", "N13->N14", "N2->N3", "N5->N6", "N8->N9", "N9->N10",
+ ];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = EdgeFilter.property("k1").is_not_in(vec![2i64.into()]);
+ let expected_results = vec!["N1->N2"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = EdgeFilter
+ .property("k2")
+ .is_not_in(vec!["Paper_Airplane".into()]);
+ let expected_results = vec!["N12->N13", "N2->N3", "N5->N6", "N7->N8", "N8->N9"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = EdgeFilter.property("k3").is_not_in(vec![true.into()]);
+ let expected_results = vec!["N1->N2"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = EdgeFilter.property("k4").is_not_in(vec![6.0f64.into()]);
+ let expected_results = vec!["N12->N13", "N2->N3", "N5->N6", "N6->N7", "N7->N8", "N8->N9"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+
+ #[test]
+ fn test_edges_filters_for_property_is_some() {
+ let filter = EdgeFilter.property("p1").is_some();
+ let expected_results = vec!["N1->N2", "N2->N3", "N3->N4", "N5->N6", "N6->N7"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ }
+
+ #[test]
+ fn test_edges_filters_pg_for_property_is_some() {
+ // TODO: Const properties not supported for disk_graph.
+ let filter = EdgeFilter.property("p1").is_some();
+ let expected_results = vec![
+ "N1->N2", "N10->N11", "N11->N12", "N12->N13", "N13->N14", "N2->N3", "N3->N4", "N5->N6",
+ "N6->N7", "N7->N8", "N8->N9", "N9->N10",
+ ];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+
+ #[test]
+ fn test_edges_filters_for_src_dst() {
+ let filter = EdgeFilter::src()
+ .name()
+ .eq("N1")
+ .and(EdgeFilter::dst().name().eq("N2"));
+ let expected_results = vec!["N1->N2"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::All,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::All,
+ );
+ }
+
+ #[test]
+ fn test_edges_filters_fuzzy_search() {
+ let filter = EdgeFilter
+ .property("k2")
+ .fuzzy_search("Paper_Airpla", 2, false);
+ let expected_results = vec!["N1->N2"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ }
+
+ #[test]
+ #[ignore]
+ fn test_edges_filters_pg_fuzzy_search() {
+ // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
+ let filter = EdgeFilter.property("k2").fuzzy_search("Paper_", 2, false);
+ let expected_results = vec!["N1->N2", "N2->N3", "N7->N8"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+
+ #[test]
+ fn test_edges_filters_fuzzy_search_prefix_match() {
+ let filter = EdgeFilter.property("k2").fuzzy_search("Pa", 2, true);
+ let expected_results = vec!["N1->N2", "N2->N3"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+
+ let filter = EdgeFilter.property("k2").fuzzy_search("Pa", 2, true);
+ let expected_results = vec!["N1->N2", "N2->N3"];
+ assert_filter_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter.clone(),
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::EventOnly,
+ );
+ }
+
+ #[test]
+ #[ignore]
+ fn test_edges_filters_pg_fuzzy_search_prefix_match() {
+ // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
+ let filter = EdgeFilter.property("k2").fuzzy_search("Pa", 2, true);
+ let expected_results = vec![
+ "N1->N2", "N12->N13", "N13->N14", "N2->N3", "N5->N6", "N7->N8", "N8->N9",
+ ];
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+
+ let filter = EdgeFilter.property("k2").fuzzy_search("Pa", 2, false);
+ let expected_results = Vec::<&str>::new();
+ assert_search_edges_results(
+ init_graph,
+ WindowGraphTransformer(6..9),
+ filter,
+ &expected_results,
+ TestVariants::PersistentOnly,
+ );
+ }
+}
diff --git a/raphtory-tests/tests/db_tests.rs b/raphtory-tests/tests/graph_tests/db_tests.rs
similarity index 100%
rename from raphtory-tests/tests/db_tests.rs
rename to raphtory-tests/tests/graph_tests/db_tests.rs
diff --git a/raphtory-tests/tests/graph_index.rs b/raphtory-tests/tests/graph_tests/graph_index.rs
similarity index 100%
rename from raphtory-tests/tests/graph_index.rs
rename to raphtory-tests/tests/graph_tests/graph_index.rs
diff --git a/raphtory-tests/tests/graph_tests/mod.rs b/raphtory-tests/tests/graph_tests/mod.rs
new file mode 100644
index 0000000000..1d4c3fe498
--- /dev/null
+++ b/raphtory-tests/tests/graph_tests/mod.rs
@@ -0,0 +1,6 @@
+mod db_tests;
+mod graph_index;
+mod test_deletions;
+mod test_history;
+mod test_materialize;
+mod valid_graph;
diff --git a/raphtory-tests/tests/test_deletions.rs b/raphtory-tests/tests/graph_tests/test_deletions.rs
similarity index 100%
rename from raphtory-tests/tests/test_deletions.rs
rename to raphtory-tests/tests/graph_tests/test_deletions.rs
diff --git a/raphtory-tests/tests/test_history.rs b/raphtory-tests/tests/graph_tests/test_history.rs
similarity index 100%
rename from raphtory-tests/tests/test_history.rs
rename to raphtory-tests/tests/graph_tests/test_history.rs
diff --git a/raphtory-tests/tests/test_materialize.rs b/raphtory-tests/tests/graph_tests/test_materialize.rs
similarity index 100%
rename from raphtory-tests/tests/test_materialize.rs
rename to raphtory-tests/tests/graph_tests/test_materialize.rs
diff --git a/raphtory-tests/tests/valid_graph.rs b/raphtory-tests/tests/graph_tests/valid_graph.rs
similarity index 100%
rename from raphtory-tests/tests/valid_graph.rs
rename to raphtory-tests/tests/graph_tests/valid_graph.rs
diff --git a/raphtory-tests/tests/df_loaders.rs b/raphtory-tests/tests/io_tests/df_loaders.rs
similarity index 100%
rename from raphtory-tests/tests/df_loaders.rs
rename to raphtory-tests/tests/io_tests/df_loaders.rs
diff --git a/raphtory-tests/tests/io_tests/mod.rs b/raphtory-tests/tests/io_tests/mod.rs
new file mode 100644
index 0000000000..2c43147925
--- /dev/null
+++ b/raphtory-tests/tests/io_tests/mod.rs
@@ -0,0 +1,4 @@
+mod df_loaders;
+mod serialise_test;
+mod test_materialize_sf10;
+mod test_saved_graphs;
diff --git a/raphtory-tests/tests/serialise_test.rs b/raphtory-tests/tests/io_tests/serialise_test.rs
similarity index 100%
rename from raphtory-tests/tests/serialise_test.rs
rename to raphtory-tests/tests/io_tests/serialise_test.rs
diff --git a/raphtory-tests/tests/test_materialize_sf10.rs b/raphtory-tests/tests/io_tests/test_materialize_sf10.rs
similarity index 100%
rename from raphtory-tests/tests/test_materialize_sf10.rs
rename to raphtory-tests/tests/io_tests/test_materialize_sf10.rs
diff --git a/raphtory-tests/tests/test_saved_graphs.rs b/raphtory-tests/tests/io_tests/test_saved_graphs.rs
similarity index 100%
rename from raphtory-tests/tests/test_saved_graphs.rs
rename to raphtory-tests/tests/io_tests/test_saved_graphs.rs
diff --git a/raphtory-tests/tests/node_edge_tests/mod.rs b/raphtory-tests/tests/node_edge_tests/mod.rs
new file mode 100644
index 0000000000..9a6815fc81
--- /dev/null
+++ b/raphtory-tests/tests/node_edge_tests/mod.rs
@@ -0,0 +1,4 @@
+mod node_test;
+mod test_edge;
+mod test_edge_view;
+mod test_exploded_edges;
diff --git a/raphtory-tests/tests/node_test.rs b/raphtory-tests/tests/node_edge_tests/node_test.rs
similarity index 100%
rename from raphtory-tests/tests/node_test.rs
rename to raphtory-tests/tests/node_edge_tests/node_test.rs
diff --git a/raphtory-tests/tests/test_edge.rs b/raphtory-tests/tests/node_edge_tests/test_edge.rs
similarity index 100%
rename from raphtory-tests/tests/test_edge.rs
rename to raphtory-tests/tests/node_edge_tests/test_edge.rs
diff --git a/raphtory-tests/tests/test_edge_view.rs b/raphtory-tests/tests/node_edge_tests/test_edge_view.rs
similarity index 100%
rename from raphtory-tests/tests/test_edge_view.rs
rename to raphtory-tests/tests/node_edge_tests/test_edge_view.rs
diff --git a/raphtory-tests/tests/test_exploded_edges.rs b/raphtory-tests/tests/node_edge_tests/test_exploded_edges.rs
similarity index 100%
rename from raphtory-tests/tests/test_exploded_edges.rs
rename to raphtory-tests/tests/node_edge_tests/test_exploded_edges.rs
diff --git a/raphtory-tests/tests/subgraph_tests.rs b/raphtory-tests/tests/subgraph_tests.rs
deleted file mode 100644
index 18ec426856..0000000000
--- a/raphtory-tests/tests/subgraph_tests.rs
+++ /dev/null
@@ -1,559 +0,0 @@
-use ahash::HashSet;
-use itertools::Itertools;
-use proptest::{proptest, sample::subsequence};
-use raphtory::{
- algorithms::{components::weakly_connected_components, motifs::triangle_count::triangle_count},
- db::graph::{graph::assert_graph_equal, views::deletion_graph::PersistentGraph},
- prelude::*,
-};
-use raphtory_storage::mutation::addition_ops::InternalAdditionOps;
-use raphtory_tests::{
- test_storage,
- utils::{build_graph, build_graph_strat},
-};
-use serde_json::json;
-use std::collections::BTreeSet;
-
-#[test]
-fn test_materialize_no_edges() {
- let graph = Graph::new();
-
- graph.add_node(1, 1, NO_PROPS, None, None).unwrap();
- graph.add_node(2, 2, NO_PROPS, None, None).unwrap();
-
- test_storage!(&graph, |graph| {
- let sg = graph.subgraph([1, 2, 1]); // <- duplicated nodes should have no effect
-
- let actual = sg.materialize().unwrap().into_events().unwrap();
- assert_graph_equal(&actual, &sg);
- });
-}
-
-#[test]
-fn test_remove_degree1_triangle_count() {
- let graph = Graph::new();
- let edges = vec![
- (1, 2, 1),
- (1, 3, 2),
- (1, 4, 3),
- (3, 1, 4),
- (3, 4, 5),
- (3, 5, 6),
- (4, 5, 7),
- (5, 6, 8),
- (5, 8, 9),
- (7, 5, 10),
- (8, 5, 11),
- (1, 9, 12),
- (9, 1, 13),
- (6, 3, 14),
- (4, 8, 15),
- (8, 3, 16),
- (5, 10, 17),
- (10, 5, 18),
- (10, 8, 19),
- (1, 11, 20),
- (11, 1, 21),
- (9, 11, 22),
- (11, 9, 23),
- ];
- for (src, dst, ts) in edges {
- graph.add_edge(ts, src, dst, NO_PROPS, None).unwrap();
- }
- test_storage!(&graph, |graph| {
- let subgraph = graph.subgraph(graph.nodes().into_iter().filter(|v| v.degree() > 1));
- let ts = triangle_count(&subgraph, None);
- let tg = triangle_count(graph, None);
- assert_eq!(ts, tg)
- });
-}
-
-#[test]
-fn layer_materialize() {
- let graph = Graph::new();
- graph.add_edge(0, 1, 2, NO_PROPS, Some("1")).unwrap();
- graph.add_edge(0, 3, 4, NO_PROPS, Some("2")).unwrap();
-
- test_storage!(&graph, |graph| {
- let sg = graph.subgraph([1, 2]);
- let sgm = sg.materialize().unwrap();
- assert_eq!(
- sg.unique_layers().collect_vec(),
- sgm.unique_layers().collect_vec()
- );
- });
-}
-
-#[test]
-fn test_cc() {
- let graph = Graph::new();
- graph.add_node(0, 0, NO_PROPS, None, None).unwrap();
- graph.add_node(0, 3, NO_PROPS, None, None).unwrap();
- graph.add_node(1, 2, NO_PROPS, None, None).unwrap();
- graph.add_node(1, 4, NO_PROPS, None, None).unwrap();
- graph.add_edge(0, 0, 1, NO_PROPS, Some("1")).unwrap();
- graph.add_edge(1, 3, 4, NO_PROPS, Some("1")).unwrap();
- let sg = graph.subgraph([0, 1, 3, 4]);
- let cc = weakly_connected_components(&sg);
- let groups = cc.groups();
- let group_sets = groups
- .iter()
- .map(|(_, g)| {
- g.iter()
- .map(|node| node.id())
- .sorted()
- .collect::>()
- })
- .collect::>();
- assert_eq!(
- group_sets,
- HashSet::from_iter([
- BTreeSet::from([GID::U64(0), GID::U64(1)]),
- BTreeSet::from([GID::U64(3), GID::U64(4)])
- ])
- );
-}
-
-#[test]
-fn test_layer_edges() {
- let graph = Graph::new();
- graph.add_edge(0, 0, 1, NO_PROPS, Some("1")).unwrap();
- graph.add_edge(1, 0, 1, NO_PROPS, Some("2")).unwrap();
-
- assert_eq!(
- graph.subgraph([0, 1]).edges().id().collect_vec(),
- [(GID::U64(0), GID::U64(1))]
- );
- assert_eq!(
- graph
- .subgraph([0, 1])
- .valid_layers("1")
- .edges()
- .id()
- .collect_vec(),
- [(GID::U64(0), GID::U64(1))]
- );
-}
-
-pub mod test_filters_node_subgraph {
- use raphtory::{
- db::{
- api::view::StaticGraphViewOps,
- graph::views::{node_subgraph::NodeSubgraph, window_graph::WindowedGraph},
- },
- prelude::{GraphViewOps, NodeViewOps, TimeOps},
- };
- use raphtory_tests::assertions::GraphTransformer;
- use std::ops::Range;
-
- struct NodeSubgraphTransformer(Option>);
-
- impl GraphTransformer for NodeSubgraphTransformer {
- type Return = NodeSubgraph;
- fn apply(&self, graph: G) -> Self::Return {
- let node_names: Vec = self
- .0
- .clone()
- .unwrap_or_else(|| graph.nodes().name().collect::>());
- graph.subgraph(node_names)
- }
- }
-
- struct WindowedNodeSubgraphTransformer(Option>, Range);
-
- impl GraphTransformer for WindowedNodeSubgraphTransformer {
- type Return = NodeSubgraph>;
- fn apply(&self, graph: G) -> Self::Return {
- let graph = graph.window(self.1.start, self.1.end);
- let node_names: Vec = self
- .0
- .clone()
- .unwrap_or_else(|| graph.nodes().name().collect::>());
- graph.subgraph(node_names)
- }
- }
-
- mod test_nodes_filters_node_subgraph {
- use crate::test_filters_node_subgraph::{
- NodeSubgraphTransformer, WindowedNodeSubgraphTransformer,
- };
- use raphtory::{
- db::{
- api::view::StaticGraphViewOps,
- graph::views::filter::model::{
- property_filter::ops::PropertyFilterOps, PropertyFilterFactory,
- },
- },
- prelude::{AdditionOps, NodeFilter},
- };
- use raphtory_api::core::entities::properties::prop::Prop;
- use raphtory_tests::assertions::{
- assert_filter_nodes_results, assert_search_nodes_results, TestGraphVariants,
- TestVariants,
- };
-
- fn init_graph(graph: G) -> G {
- let nodes = vec![
- (6, "N1", vec![("p1", Prop::U64(2u64))]),
- (7, "N1", vec![("p1", Prop::U64(1u64))]),
- (6, "N2", vec![("p1", Prop::U64(1u64))]),
- (7, "N2", vec![("p1", Prop::U64(2u64))]),
- (8, "N3", vec![("p1", Prop::U64(1u64))]),
- (9, "N4", vec![("p1", Prop::U64(1u64))]),
- (5, "N5", vec![("p1", Prop::U64(1u64))]),
- (6, "N5", vec![("p1", Prop::U64(2u64))]),
- (5, "N6", vec![("p1", Prop::U64(1u64))]),
- (6, "N6", vec![("p1", Prop::U64(1u64))]),
- (3, "N7", vec![("p1", Prop::U64(1u64))]),
- (5, "N7", vec![("p1", Prop::U64(1u64))]),
- (3, "N8", vec![("p1", Prop::U64(1u64))]),
- (4, "N8", vec![("p1", Prop::U64(2u64))]),
- ];
-
- for (id, name, props) in &nodes {
- graph
- .add_node(*id, name, props.clone(), None, None)
- .unwrap();
- }
-
- graph
- }
-
- #[test]
- fn test_search_nodes_subgraph() {
- let filter = NodeFilter.property("p1").eq(1u64);
- let expected_results = ["N1", "N3", "N4", "N6", "N7"];
- assert_filter_nodes_results(
- init_graph,
- NodeSubgraphTransformer(None),
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_graph,
- NodeSubgraphTransformer(None),
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let node_names: Option> =
- Some(vec!["N2".into(), "N3".into(), "N4".into(), "N5".into()]);
- let filter = NodeFilter.property("p1").le(1u64);
- let expected_results = vec!["N3", "N4"];
- assert_filter_nodes_results(
- init_graph,
- NodeSubgraphTransformer(node_names.clone()),
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_graph,
- NodeSubgraphTransformer(node_names),
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_search_nodes_subgraph_w() {
- // TODO: Enable event_disk_graph for filter_nodes once bug fixed: https://github.com/Pometry/Raphtory/issues/2098
- let filter = NodeFilter.property("p1").eq(1u64);
- let expected_results = vec!["N1", "N3", "N6"];
- assert_filter_nodes_results(
- init_graph,
- WindowedNodeSubgraphTransformer(None, 6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowedNodeSubgraphTransformer(None, 6..9),
- filter,
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
-
- let node_names: Option> = Some(vec!["N3".into()]);
- let filter = NodeFilter.property("p1").gt(0u64);
- let expected_results = vec!["N3"];
- assert_filter_nodes_results(
- init_graph,
- WindowedNodeSubgraphTransformer(node_names.clone(), 6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowedNodeSubgraphTransformer(node_names, 6..9),
- filter,
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- }
-
- #[test]
- fn test_search_nodes_pg_w() {
- let filter = NodeFilter.property("p1").eq(1u64);
- let expected_results = vec!["N1", "N3", "N6", "N7"];
- assert_filter_nodes_results(
- init_graph,
- WindowedNodeSubgraphTransformer(None, 6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowedNodeSubgraphTransformer(None, 6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let node_names: Option> =
- Some(vec!["N2".into(), "N3".into(), "N4".into(), "N5".into()]);
- let filter = NodeFilter.property("p1").ge(1u64);
- let expected_results = vec!["N2", "N3", "N5"];
- assert_filter_nodes_results(
- init_graph,
- WindowedNodeSubgraphTransformer(node_names.clone(), 6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowedNodeSubgraphTransformer(node_names, 6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
- }
-
- mod test_edges_filters_node_subgraph {
- use raphtory::{
- db::{
- api::view::StaticGraphViewOps,
- graph::views::filter::model::{
- property_filter::ops::PropertyFilterOps, PropertyFilterFactory,
- },
- },
- prelude::{AdditionOps, EdgeFilter},
- };
- use raphtory_api::core::entities::properties::prop::Prop;
- use raphtory_tests::assertions::{
- assert_filter_edges_results, assert_search_edges_results, TestVariants,
- };
-
- use crate::test_filters_node_subgraph::{
- NodeSubgraphTransformer, WindowedNodeSubgraphTransformer,
- };
-
- fn init_graph(graph: G) -> G {
- let edges = vec![
- (6, "N1", "N2", vec![("p1", Prop::U64(2u64))]),
- (7, "N1", "N2", vec![("p1", Prop::U64(1u64))]),
- (6, "N2", "N3", vec![("p1", Prop::U64(1u64))]),
- (7, "N2", "N3", vec![("p1", Prop::U64(2u64))]),
- (8, "N3", "N4", vec![("p1", Prop::U64(1u64))]),
- (9, "N4", "N5", vec![("p1", Prop::U64(1u64))]),
- (5, "N5", "N6", vec![("p1", Prop::U64(1u64))]),
- (6, "N5", "N6", vec![("p1", Prop::U64(2u64))]),
- (5, "N6", "N7", vec![("p1", Prop::U64(1u64))]),
- (6, "N6", "N7", vec![("p1", Prop::U64(1u64))]),
- (3, "N7", "N8", vec![("p1", Prop::U64(1u64))]),
- (5, "N7", "N8", vec![("p1", Prop::U64(1u64))]),
- (3, "N8", "N1", vec![("p1", Prop::U64(1u64))]),
- (4, "N8", "N1", vec![("p1", Prop::U64(2u64))]),
- ];
-
- for (id, src, tgt, props) in &edges {
- graph.add_edge(*id, src, tgt, props.clone(), None).unwrap();
- }
-
- graph
- }
-
- #[test]
- fn test_edges_filters() {
- // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph.
- let filter = EdgeFilter.property("p1").eq(1u64);
- let expected_results = vec!["N1->N2", "N3->N4", "N4->N5", "N6->N7", "N7->N8"];
- assert_filter_edges_results(
- init_graph,
- NodeSubgraphTransformer(None),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- NodeSubgraphTransformer(None),
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let node_names: Option> =
- Some(vec!["N2".into(), "N3".into(), "N4".into(), "N5".into()]);
- let filter = EdgeFilter.property("p1").le(1u64);
- let expected_results = vec!["N3->N4", "N4->N5"];
- assert_filter_edges_results(
- init_graph,
- NodeSubgraphTransformer(node_names.clone()),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- NodeSubgraphTransformer(node_names),
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_edges_filters_w() {
- let filter = EdgeFilter.property("p1").eq(1u64);
- let expected_results = vec!["N1->N2", "N3->N4", "N6->N7"];
- assert_filter_edges_results(
- init_graph,
- WindowedNodeSubgraphTransformer(None, 6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowedNodeSubgraphTransformer(None, 6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
-
- let node_names: Option> =
- Some(vec!["N2".into(), "N3".into(), "N4".into(), "N5".into()]);
- let filter = EdgeFilter.property("p1").ge(1u64);
- let expected_results = vec!["N2->N3", "N3->N4"];
- assert_filter_edges_results(
- init_graph,
- WindowedNodeSubgraphTransformer(node_names.clone(), 6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowedNodeSubgraphTransformer(node_names, 6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
- }
-
- #[test]
- fn test_edges_filters_pg_w() {
- // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph.
- let filter = EdgeFilter.property("p1").eq(1u64);
- let expected_results = vec!["N1->N2", "N3->N4", "N6->N7", "N7->N8"];
- assert_filter_edges_results(
- init_graph,
- WindowedNodeSubgraphTransformer(None, 6..9),
- filter.clone(),
- &expected_results,
- vec![],
- );
- assert_search_edges_results(
- init_graph,
- WindowedNodeSubgraphTransformer(None, 6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let node_names: Option> = Some(vec![
- "N2".into(),
- "N3".into(),
- "N4".into(),
- "N5".into(),
- "N6".into(),
- ]);
- let filter = EdgeFilter.property("p1").lt(2u64);
- let expected_results = vec!["N3->N4"];
- assert_filter_edges_results(
- init_graph,
- WindowedNodeSubgraphTransformer(node_names.clone(), 6..9),
- filter.clone(),
- &expected_results,
- vec![],
- );
- assert_search_edges_results(
- init_graph,
- WindowedNodeSubgraphTransformer(node_names, 6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
- }
-}
-
-#[test]
-fn nodes_without_updates_are_filtered() {
- let g = Graph::new();
- g.add_edge(0, 0, 1, NO_PROPS, None).unwrap();
- let expected = Graph::new();
- expected.resolve_layer(None).unwrap();
- let subgraph = g.subgraph([0]);
- assert_graph_equal(&subgraph, &expected);
-}
-
-#[test]
-fn materialize_proptest() {
- proptest!(|(graph in build_graph_strat(10, 10, 10, 10, false), nodes in subsequence((0..10).collect::>(), 0..10))| {
- let graph = Graph::from(build_graph(&graph));
- let subgraph = graph.subgraph(nodes);
- assert_graph_equal(&subgraph, &subgraph.materialize().unwrap());
- })
-}
-
-#[test]
-fn materialize_proptest_failure() {
- let graph_f = serde_json::from_value(json!({"nodes":{},"edges":[[[1,1,"a"],{"props":{"t_props":[[0,[]]],"c_props":[]},"deletions":[]}],[[0,0,null],{"props":{"t_props":[[0,[]]],"c_props":[]},"deletions":[]}]]})).unwrap();
- let graph = Graph::from(build_graph(&graph_f));
- let subgraph = graph.subgraph([1]);
- let nodes = subgraph.default_layer().nodes().id().collect_vec();
- dbg!(nodes);
- assert_eq!(subgraph.default_layer().count_nodes(), 0);
- assert_eq!(subgraph.count_edges(), 1);
- let materialised = subgraph.materialize().unwrap();
- assert_graph_equal(&subgraph, &materialised);
-}
-
-#[test]
-fn materialize_persistent_proptest() {
- proptest!(|(graph in build_graph_strat(10, 10, 10, 10, true), nodes in subsequence((0..10).collect::>(), 0..10))| {
- let graph = PersistentGraph::from(build_graph(&graph));
- let subgraph = graph.subgraph(nodes);
- assert_graph_equal(&subgraph, &subgraph.materialize().unwrap());
- })
-}
-
-#[test]
-fn test_subgraph_only_deletion() {
- let g = PersistentGraph::new();
- g.delete_edge(0, 0, 1, None).unwrap();
- let sg = g.subgraph([0]);
- let expected = PersistentGraph::new();
- expected.resolve_layer(None).unwrap();
- assert_graph_equal(&sg, &expected);
-}
diff --git a/raphtory-tests/tests/test_filters.rs b/raphtory-tests/tests/test_filters.rs
index a4bc92771c..328a67e88a 100644
--- a/raphtory-tests/tests/test_filters.rs
+++ b/raphtory-tests/tests/test_filters.rs
@@ -1,13024 +1 @@
-use raphtory::{db::api::view::StaticGraphViewOps, prelude::*};
-
-mod test_composite_filters {
- use raphtory::{
- db::graph::views::filter::model::{
- edge_filter::EdgeFilter, filter::Filter, node_filter::NodeFilter,
- property_filter::ops::PropertyFilterOps, PropertyFilterFactory,
- },
- prelude::IntoProp,
- };
- use raphtory_api::core::{entities::properties::prop::Prop, storage::arc_str::ArcStr};
-
- #[test]
- fn test_fuzzy_search() {
- let filter = Filter::fuzzy_search("name", "pomet", 2, false);
- assert!(filter.matches(Some("pometry")));
-
- let filter = Filter::fuzzy_search("name", "shivam_kapoor", 2, false);
- assert!(filter.matches(Some("shivam_kapoor2")));
-
- let filter = Filter::fuzzy_search("name", "shivam kapoor", 2, false);
- assert!(filter.matches(Some("shivam_kapoor2")));
-
- let filter = Filter::fuzzy_search("name", "shivam kapoor", 2, false);
- assert!(filter.matches(Some("shivam_kapoor2")));
-
- let filter = Filter::fuzzy_search("name", "shivam kapoor", 2, false);
- assert!(!filter.matches(Some("shivam1_kapoor2")));
-
- let filter = Filter::fuzzy_search("name", "khivam sapoor", 2, false);
- assert!(!filter.matches(Some("shivam1_kapoor2")));
- }
-
- #[test]
- fn test_fuzzy_search_prefix_match() {
- let filter = Filter::fuzzy_search("name", "pome", 2, false);
- assert!(!filter.matches(Some("pometry")));
-
- let filter = Filter::fuzzy_search("name", "pome", 2, true);
- assert!(filter.matches(Some("pometry")));
- }
-
- #[test]
- fn test_fuzzy_search_property() {
- let filter = NodeFilter.property("prop").fuzzy_search("pomet", 2, false);
- assert!(filter.matches(Some(&Prop::Str(ArcStr::from("pometry")))));
- }
-
- #[test]
- fn test_fuzzy_search_property_prefix_match() {
- let filter = EdgeFilter.property("prop").fuzzy_search("pome", 2, false);
- assert!(!filter.matches(Some(&Prop::Str(ArcStr::from("pometry")))));
-
- let filter = EdgeFilter.property("prop").fuzzy_search("pome", 2, true);
- assert!(filter.matches(Some(&Prop::Str(ArcStr::from("pometry")))));
- }
-
- #[test]
- fn test_contains_match() {
- let filter = EdgeFilter.property("prop").contains("shivam");
- let res = filter.matches(Some(&Prop::Str(ArcStr::from("shivam_kapoor"))));
- assert!(res);
- let res = filter.matches(None);
- assert!(!res);
-
- let filter = EdgeFilter.property("prop").contains("am_ka");
- let res = filter.matches(Some(&Prop::Str(ArcStr::from("shivam_kapoor"))));
- assert!(res);
- }
-
- #[test]
- fn test_contains_not_match() {
- let filter = NodeFilter.property("prop").not_contains("shivam");
- let res = filter.matches(Some(&Prop::Str(ArcStr::from("shivam_kapoor"))));
- assert!(!res);
- let res = filter.matches(None);
- assert!(!res);
- }
-
- #[test]
- fn test_is_in_match() {
- let filter = NodeFilter
- .property("prop")
- .is_in(vec!["shivam".into_prop()]);
- let res = filter.matches(Some(&Prop::Str(ArcStr::from("shivam"))));
- assert!(res);
- let res = filter.matches(None);
- assert!(!res);
- }
-
- #[test]
- fn test_is_not_in_match() {
- let filter = EdgeFilter
- .property("prop")
- .is_not_in(vec!["shivam".into_prop()]);
- let res = filter.matches(Some(&Prop::Str(ArcStr::from("shivam"))));
- assert!(!res);
- let res = filter.matches(None);
- assert!(!res);
- }
-}
-
-use raphtory_api::core::entities::properties::prop::IntoProp;
-use raphtory_storage::mutation::{
- addition_ops::InternalAdditionOps, property_addition_ops::InternalPropertyAdditionOps,
-};
-use raphtory_tests::assertions::GraphTransformer;
-
-struct IdentityGraphTransformer;
-
-impl GraphTransformer for IdentityGraphTransformer {
- type Return = G;
- fn apply(&self, graph: G) -> Self::Return {
- graph
- }
-}
-
-mod test_property_semantics {
- mod test_node_property_filter_semantics {
- use crate::IdentityGraphTransformer;
- use raphtory::{
- db::{
- api::view::{filter_ops::Filter, StaticGraphViewOps},
- graph::views::filter::model::{
- node_filter::NodeFilter, property_filter::ops::PropertyFilterOps,
- PropertyFilterFactory, TemporalPropertyFilterFactory,
- },
- },
- errors::GraphError,
- prelude::*,
- };
- use raphtory_api::core::entities::properties::prop::Prop;
- use raphtory_storage::mutation::{
- addition_ops::InternalAdditionOps, property_addition_ops::InternalPropertyAdditionOps,
- };
- use raphtory_tests::assertions::{
- assert_filter_nodes_results, assert_search_nodes_results, TestVariants,
- };
-
- fn init_graph(graph: G) -> G {
- let nodes = [
- (6, "N1", vec![("p1", Prop::U64(2u64))]),
- (7, "N1", vec![("p1", Prop::U64(1u64))]),
- (6, "N2", vec![("p1", Prop::U64(1u64))]),
- (7, "N2", vec![("p1", Prop::U64(2u64))]),
- (8, "N3", vec![("p1", Prop::U64(1u64))]),
- (9, "N4", vec![("p1", Prop::U64(1u64))]),
- (5, "N5", vec![("p1", Prop::U64(1u64))]),
- (6, "N5", vec![("p1", Prop::U64(2u64))]),
- (5, "N6", vec![("p1", Prop::U64(1u64))]),
- (6, "N6", vec![("p1", Prop::U64(1u64))]),
- (3, "N7", vec![("p1", Prop::U64(1u64))]),
- (5, "N7", vec![("p1", Prop::U64(1u64))]),
- (3, "N8", vec![("p1", Prop::U64(1u64))]),
- (4, "N8", vec![("p1", Prop::U64(2u64))]),
- (2, "N9", vec![("p1", Prop::U64(2u64))]),
- (2, "N10", vec![("q1", Prop::U64(0u64))]),
- (2, "N10", vec![("p1", Prop::U64(3u64))]),
- (2, "N11", vec![("p1", Prop::U64(3u64))]),
- (2, "N11", vec![("q1", Prop::U64(0u64))]),
- (2, "N12", vec![("q1", Prop::U64(0u64))]),
- (3, "N12", vec![("p1", Prop::U64(3u64))]),
- (2, "N13", vec![("q1", Prop::U64(0u64))]),
- (3, "N13", vec![("p1", Prop::U64(3u64))]),
- (2, "N14", vec![("q1", Prop::U64(0u64))]),
- (2, "N15", vec![]),
- ];
-
- for (id, label, props) in nodes.iter() {
- graph
- .add_node(*id, label, props.clone(), None, None)
- .unwrap();
- }
-
- let metadata = [
- ("N1", [("p1", Prop::U64(1u64))]),
- ("N4", [("p1", Prop::U64(2u64))]),
- ("N9", [("p1", Prop::U64(1u64))]),
- ("N10", [("p1", Prop::U64(1u64))]),
- ("N11", [("p1", Prop::U64(1u64))]),
- ("N12", [("p1", Prop::U64(1u64))]),
- ("N13", [("p1", Prop::U64(1u64))]),
- ("N14", [("p1", Prop::U64(1u64))]),
- ("N15", [("p1", Prop::U64(1u64))]),
- ];
-
- for (node, props) in metadata.iter() {
- graph
- .node(node)
- .unwrap()
- .add_metadata(props.clone())
- .unwrap();
- }
-
- graph
- }
-
- fn init_graph_for_event_ids<
- G: StaticGraphViewOps
- + AdditionOps
- + InternalAdditionOps
- + InternalPropertyAdditionOps
- + PropertyAdditionOps,
- >(
- graph: G,
- ) -> G {
- let graph: G = init_graph(graph);
- let nodes = [
- (1, "N16", vec![("p1", Prop::U64(2u64))]),
- (1, "N16", vec![("p1", Prop::U64(1u64))]),
- (1, "N17", vec![("p1", Prop::U64(1u64))]),
- (1, "N17", vec![("p1", Prop::U64(2u64))]),
- ];
-
- for (id, label, props) in nodes.iter() {
- graph
- .add_node(*id, label, props.clone(), None, None)
- .unwrap();
- }
-
- graph
- }
-
- #[test]
- fn test_metadata_semantics() {
- let filter = NodeFilter.metadata("p1").eq(1u64);
- let expected_results = vec!["N1", "N10", "N11", "N12", "N13", "N14", "N15", "N9"];
- assert_filter_nodes_results(
- init_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_temporal_any_semantics() {
- let filter = NodeFilter.property("p1").temporal().any().eq(1u64);
- let expected_results = vec!["N1", "N2", "N3", "N4", "N5", "N6", "N7", "N8"];
- assert_filter_nodes_results(
- init_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_temporal_any_semantics_for_event_ids() {
- let filter = NodeFilter.property("p1").temporal().any().eq(1u64);
- let expected_results =
- vec!["N1", "N16", "N17", "N2", "N3", "N4", "N5", "N6", "N7", "N8"];
- assert_filter_nodes_results(
- init_graph_for_event_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_graph_for_event_ids,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_temporal_latest_semantics() {
- let filter = NodeFilter.property("p1").temporal().last().eq(1u64);
- let expected_results = vec!["N1", "N3", "N4", "N6", "N7"];
- assert_filter_nodes_results(
- init_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_temporal_latest_semantics_for_event_ids() {
- let filter = NodeFilter.property("p1").temporal().last().eq(1u64);
- let expected_results = vec!["N1", "N16", "N3", "N4", "N6", "N7"];
- assert_filter_nodes_results(
- init_graph_for_event_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_graph_for_event_ids,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_property_semantics() {
- // TODO: Const properties not supported for disk_graph.
- let filter = NodeFilter.property("p1").eq(1u64);
- let expected_results = vec!["N1", "N3", "N4", "N6", "N7"];
- assert_filter_nodes_results(
- init_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_property_semantics_for_event_ids() {
- let filter = NodeFilter.property("p1").eq(1u64);
- let expected_results = vec!["N1", "N16", "N3", "N4", "N6", "N7"];
- assert_filter_nodes_results(
- init_graph_for_event_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_graph_for_event_ids,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_property_semantics_only_metadata() {
- // For this graph there won't be any temporal property index for property name "p1".
- fn init_graph<
- G: StaticGraphViewOps
- + AdditionOps
- + InternalAdditionOps
- + InternalPropertyAdditionOps
- + PropertyAdditionOps,
- >(
- graph: G,
- ) -> G {
- let nodes = [(2, "N1", vec![("q1", Prop::U64(0u64))]), (2, "N2", vec![])];
-
- for (id, label, props) in nodes.iter() {
- graph
- .add_node(*id, label, props.clone(), None, None)
- .unwrap();
- }
-
- let metadata = [
- ("N1", [("p1", Prop::U64(1u64))]),
- ("N2", [("p1", Prop::U64(1u64))]),
- ];
-
- for (node, props) in metadata.iter() {
- graph
- .node(node)
- .unwrap()
- .add_metadata(props.clone())
- .unwrap();
- }
-
- graph
- }
-
- let filter = NodeFilter.property("p1").ge(1u64);
- let graph = init_graph(Graph::new());
- assert!(matches!(
- graph.filter(filter.clone()).unwrap_err(),
- GraphError::PropertyMissingError(ref name) if name == "p1"
- ));
- assert!(matches!(
- graph.persistent_graph().filter(filter).unwrap_err(),
- GraphError::PropertyMissingError(ref name) if name == "p1"
- ));
- }
-
- #[test]
- fn test_property_semantics_only_temporal() {
- // For this graph there won't be any metadata index for property name "p1".
- fn init_graph<
- G: StaticGraphViewOps
- + AdditionOps
- + InternalAdditionOps
- + InternalPropertyAdditionOps
- + PropertyAdditionOps,
- >(
- graph: G,
- ) -> G {
- let nodes = [
- (1, "N1", vec![("p1", Prop::U64(1u64))]),
- (2, "N2", vec![("p1", Prop::U64(1u64))]),
- (3, "N2", vec![("p1", Prop::U64(2u64))]),
- (2, "N3", vec![("p1", Prop::U64(2u64))]),
- (3, "N3", vec![("p1", Prop::U64(1u64))]),
- (3, "N4", vec![]),
- ];
-
- for (id, label, props) in nodes.iter() {
- graph
- .add_node(*id, label, props.clone(), None, None)
- .unwrap();
- }
-
- graph
- }
-
- let filter = NodeFilter.property("p1").le(1u64);
- let expected_results = vec!["N1", "N3"];
- assert_filter_nodes_results(
- init_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
- }
-
- mod test_edge_property_filter_semantics {
- use crate::IdentityGraphTransformer;
- use raphtory::{
- db::{
- api::view::{filter_ops::Filter, EdgeViewOps, StaticGraphViewOps},
- graph::views::filter::{
- model::{
- edge_filter::EdgeFilter, property_filter::ops::PropertyFilterOps,
- PropertyFilterFactory, TemporalPropertyFilterFactory,
- },
- CreateFilter,
- },
- },
- errors::GraphError,
- prelude::*,
- };
- use raphtory_api::core::entities::properties::prop::Prop;
- use raphtory_storage::mutation::{
- addition_ops::InternalAdditionOps, property_addition_ops::InternalPropertyAdditionOps,
- };
- use raphtory_tests::assertions::{
- assert_filter_edges_results, assert_search_edges_results, TestGraphVariants,
- TestVariants, WindowGraphTransformer,
- };
-
- fn init_graph<
- G: StaticGraphViewOps
- + AdditionOps
- + InternalAdditionOps
- + InternalPropertyAdditionOps
- + PropertyAdditionOps,
- >(
- graph: G,
- ) -> G {
- let edges = [
- (6, "N1", "N2", vec![("p1", Prop::U64(2u64))]),
- (7, "N1", "N2", vec![("p1", Prop::U64(1u64))]),
- (6, "N2", "N3", vec![("p1", Prop::U64(1u64))]),
- (7, "N2", "N3", vec![("p1", Prop::U64(2u64))]),
- (8, "N3", "N4", vec![("p1", Prop::U64(1u64))]),
- (9, "N4", "N5", vec![("p1", Prop::U64(1u64))]),
- (5, "N5", "N6", vec![("p1", Prop::U64(1u64))]),
- (6, "N5", "N6", vec![("p1", Prop::U64(2u64))]),
- (5, "N6", "N7", vec![("p1", Prop::U64(1u64))]),
- (6, "N6", "N7", vec![("p1", Prop::U64(1u64))]),
- (3, "N7", "N8", vec![("p1", Prop::U64(1u64))]),
- (5, "N7", "N8", vec![("p1", Prop::U64(1u64))]),
- (3, "N8", "N9", vec![("p1", Prop::U64(1u64))]),
- (4, "N8", "N9", vec![("p1", Prop::U64(2u64))]),
- (2, "N9", "N10", vec![("p1", Prop::U64(2u64))]),
- (2, "N10", "N11", vec![("q1", Prop::U64(0u64))]),
- (2, "N10", "N11", vec![("p1", Prop::U64(3u64))]),
- (2, "N11", "N12", vec![("p1", Prop::U64(3u64))]),
- (2, "N11", "N12", vec![("q1", Prop::U64(0u64))]),
- (2, "N12", "N13", vec![("q1", Prop::U64(0u64))]),
- (3, "N12", "N13", vec![("p1", Prop::U64(3u64))]),
- (2, "N13", "N14", vec![("q1", Prop::U64(0u64))]),
- (3, "N13", "N14", vec![("p1", Prop::U64(3u64))]),
- (2, "N14", "N15", vec![("q1", Prop::U64(0u64))]),
- (2, "N15", "N1", vec![]),
- ];
-
- for (time, src, dst, props) in edges {
- graph.add_edge(time, src, dst, props, None).unwrap();
- }
-
- let metadata_edges = [
- ("N1", "N2", vec![("p1", Prop::U64(1u64))]),
- ("N4", "N5", vec![("p1", Prop::U64(2u64))]),
- ("N9", "N10", vec![("p1", Prop::U64(1u64))]),
- ("N10", "N11", vec![("p1", Prop::U64(1u64))]),
- ("N11", "N12", vec![("p1", Prop::U64(1u64))]),
- ("N12", "N13", vec![("p1", Prop::U64(1u64))]),
- ("N13", "N14", vec![("p1", Prop::U64(1u64))]),
- ("N14", "N15", vec![("p1", Prop::U64(1u64))]),
- ("N15", "N1", vec![("p1", Prop::U64(1u64))]),
- ];
-
- for (src, dst, props) in metadata_edges {
- graph
- .edge(src, dst)
- .unwrap()
- .add_metadata(props.clone(), None)
- .unwrap();
- }
-
- graph
- }
-
- fn init_graph_for_event_ids<
- G: StaticGraphViewOps
- + AdditionOps
- + InternalAdditionOps
- + InternalPropertyAdditionOps
- + PropertyAdditionOps,
- >(
- graph: G,
- ) -> G {
- let graph: G = init_graph(graph);
- let edge_data = [
- (1, "N16", "N15", vec![("p1", Prop::U64(2u64))]),
- (1, "N16", "N15", vec![("p1", Prop::U64(1u64))]),
- (1, "N17", "N16", vec![("p1", Prop::U64(1u64))]),
- (1, "N17", "N16", vec![("p1", Prop::U64(2u64))]),
- ];
-
- for (time, src, dst, props) in edge_data {
- graph.add_edge(time, src, dst, props, None).unwrap();
- }
-
- graph
- }
-
- #[test]
- fn test_persistent_graph_first_window() {
- fn init_graph<
- G: StaticGraphViewOps
- + AdditionOps
- + InternalAdditionOps
- + InternalPropertyAdditionOps
- + PropertyAdditionOps,
- >(
- graph: G,
- ) -> G {
- graph
- .add_edge(0, 1, 2, [("p1", Prop::U64(1u64))], None)
- .unwrap();
- graph
- .add_edge(2, 1, 2, [("p1", Prop::U64(2u64))], None)
- .unwrap();
- graph
- .add_edge(5, 1, 2, [("p1", Prop::U64(5u64))], None)
- .unwrap();
- graph
- .add_edge(10, 1, 2, [("p1", Prop::U64(10u64))], None)
- .unwrap();
- graph
- }
-
- let filter = EdgeFilter.property("p1").temporal().first().eq(2u64);
-
- // No window; means the first update is at time 0 and the value of p1 is expected to be 1u64.
- let expected_empty = [];
- let expected_found = ["1->2"];
-
- assert_filter_edges_results(
- init_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_empty,
- vec![TestGraphVariants::PersistentGraph],
- );
- assert_search_edges_results(
- init_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_empty,
- TestVariants::PersistentOnly,
- );
-
- // Window(1,10); Expected emtpy because the first update is at time 0 and the value of p1 is expected to be 1u64.
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(1..10),
- filter.clone(),
- &expected_empty,
- vec![TestGraphVariants::PersistentGraph],
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(1..10),
- filter.clone(),
- &expected_empty,
- TestVariants::PersistentOnly,
- );
-
- // Window(2,10); Expected update at time 2 and the value of p1 is expected to be 2u64.
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(2..10),
- filter.clone(),
- &expected_found,
- vec![TestGraphVariants::PersistentGraph],
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(2..10),
- filter.clone(),
- &expected_found,
- TestVariants::PersistentOnly,
- );
-
- // Window(3,10); Expected update at time 2 (even if it is outside the window) and the value of p1 is expected to be 2u64.
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(3..10),
- filter.clone(),
- &expected_found,
- vec![TestGraphVariants::PersistentGraph],
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(3..10),
- filter.clone(),
- &expected_found,
- TestVariants::PersistentOnly,
- );
-
- // Window(4,10); Expected update at time 2 (even if it is outside the window) and the value of p1 is expected to be 2u64.
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(4..10),
- filter.clone(),
- &expected_found,
- vec![TestGraphVariants::PersistentGraph],
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(4..10),
- filter.clone(),
- &expected_found,
- TestVariants::PersistentOnly,
- );
-
- // Window(5,10); Expected update at time 5 (even if it is outside the window) and the value of p1 is expected to be 5u64.
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(5..10),
- filter.clone(),
- &expected_empty,
- vec![TestGraphVariants::PersistentGraph],
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(5..10),
- filter.clone(),
- &expected_empty,
- TestVariants::PersistentOnly,
- );
- }
-
- #[test]
- fn test_metadata_semantics() {
- // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
- // TODO: Const properties not supported for disk_graph.
- let filter = EdgeFilter.metadata("p1").eq(1u64);
- let expected_results = vec![
- "N1->N2", "N10->N11", "N11->N12", "N12->N13", "N13->N14", "N14->N15", "N15->N1",
- "N9->N10",
- ];
- assert_filter_edges_results(
- init_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_edges_results(
- init_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_metadata_semantics2() {
- fn filter_edges(graph: &Graph, filter: impl CreateFilter) -> Vec {
- let mut results = graph
- .filter(filter)
- .unwrap()
- .edges()
- .iter()
- .map(|e| format!("{}->{}", e.src().name(), e.dst().name()))
- .collect::>();
- results.sort();
- results
- }
-
- let graph = init_graph(Graph::new());
-
- let filter = EdgeFilter.metadata("p1").eq(1u64);
- assert_eq!(
- filter_edges(&graph, filter.clone()),
- vec![
- "N1->N2", "N10->N11", "N11->N12", "N12->N13", "N13->N14", "N14->N15",
- "N15->N1", "N9->N10"
- ]
- );
-
- let edge = graph
- .add_edge(1, "shivam", "kapoor", [("p1", 100u64)], Some("fire_nation"))
- .unwrap();
- edge.add_metadata([("z", true)], Some("fire_nation"))
- .unwrap();
- let prop = graph.edge("shivam", "kapoor").unwrap().metadata().get("z");
- assert_eq!(prop, Some(Prop::map([("fire_nation", true)])));
-
- let filter2 = EdgeFilter
- .metadata("z")
- .eq(Prop::map([("fire_nation", true)]));
- assert_eq!(filter_edges(&graph, filter2), vec!["shivam->kapoor"]);
-
- let filter = EdgeFilter
- .metadata("p1")
- .eq(Prop::map([("_default", 1u64)]));
- assert_eq!(
- filter_edges(&graph, filter),
- vec![
- "N1->N2", "N10->N11", "N11->N12", "N12->N13", "N13->N14", "N14->N15",
- "N15->N1", "N9->N10"
- ]
- );
- }
-
- #[test]
- fn test_temporal_any_semantics() {
- // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
- let filter = EdgeFilter.property("p1").temporal().any().eq(1u64);
- let expected_results = vec![
- "N1->N2", "N2->N3", "N3->N4", "N4->N5", "N5->N6", "N6->N7", "N7->N8", "N8->N9",
- ];
- assert_filter_edges_results(
- init_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_temporal_any_semantics_for_event_ids() {
- // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
- let filter = EdgeFilter.property("p1").temporal().any().lt(2u64);
- let expected_results = vec![
- "N1->N2", "N16->N15", "N17->N16", "N2->N3", "N3->N4", "N4->N5", "N5->N6", "N6->N7",
- "N7->N8", "N8->N9",
- ];
- assert_filter_edges_results(
- init_graph_for_event_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph_for_event_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_temporal_latest_semantics() {
- // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
- let filter = EdgeFilter.property("p1").temporal().last().eq(1u64);
- let expected_results = vec!["N1->N2", "N3->N4", "N4->N5", "N6->N7", "N7->N8"];
- assert_filter_edges_results(
- init_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_temporal_latest_semantics_for_event_ids() {
- // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
- let filter = EdgeFilter.property("p1").temporal().last().eq(1u64);
- let expected_results =
- vec!["N1->N2", "N16->N15", "N3->N4", "N4->N5", "N6->N7", "N7->N8"];
- assert_filter_edges_results(
- init_graph_for_event_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph_for_event_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_property_semantics() {
- // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
- let filter = EdgeFilter.property("p1").ge(2u64);
- let expected_results = vec![
- "N10->N11", "N11->N12", "N12->N13", "N13->N14", "N2->N3", "N5->N6", "N8->N9",
- "N9->N10",
- ];
- assert_filter_edges_results(
- init_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_property_semantics_for_event_ids() {
- // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
- // TODO: Const properties not supported for disk_graph.
- let filter = EdgeFilter.property("p1").eq(1u64);
- let expected_results =
- vec!["N1->N2", "N16->N15", "N3->N4", "N4->N5", "N6->N7", "N7->N8"];
- assert_filter_edges_results(
- init_graph_for_event_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_edges_results(
- init_graph_for_event_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_property_semantics_only_metadata() {
- // For this graph there won't be any temporal property index for property name "p1".
- fn init_graph<
- G: StaticGraphViewOps
- + AdditionOps
- + InternalAdditionOps
- + InternalPropertyAdditionOps
- + PropertyAdditionOps,
- >(
- graph: G,
- ) -> G {
- let edges = [
- (2, "N1", "N2", vec![("q1", Prop::U64(0u64))]),
- (2, "N2", "N3", vec![]),
- ];
-
- for (time, src, dst, props) in edges {
- graph.add_edge(time, src, dst, props, None).unwrap();
- }
-
- let metadata_edges = [
- ("N1", "N2", vec![("p1", Prop::U64(1u64))]),
- ("N2", "N3", vec![("p1", Prop::U64(1u64))]),
- ];
-
- for (src, dst, props) in metadata_edges {
- graph
- .edge(src, dst)
- .unwrap()
- .add_metadata(props.clone(), None)
- .unwrap();
- }
-
- graph
- }
-
- let filter = EdgeFilter.property("p1").eq(1u64);
- let graph = init_graph(Graph::new());
- assert!(matches!(
- graph.filter(filter.clone()).unwrap_err(),
- GraphError::PropertyMissingError(ref name) if name == "p1"
- ));
- assert!(matches!(
- graph.persistent_graph().filter(filter).unwrap_err(),
- GraphError::PropertyMissingError(ref name) if name == "p1"
- ));
- }
-
- #[test]
- fn test_property_semantics_only_temporal() {
- // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
- // For this graph there won't be any metadata index for property name "p1".
- fn init_graph<
- G: StaticGraphViewOps
- + AdditionOps
- + InternalAdditionOps
- + InternalPropertyAdditionOps
- + PropertyAdditionOps,
- >(
- graph: G,
- ) -> G {
- let edges = [
- (1, "N1", "N2", vec![("p1", Prop::U64(1u64))]),
- (2, "N2", "N3", vec![("p1", Prop::U64(1u64))]),
- (3, "N2", "N3", vec![("p1", Prop::U64(2u64))]),
- (2, "N3", "N4", vec![("p1", Prop::U64(2u64))]),
- (3, "N3", "N4", vec![("p1", Prop::U64(1u64))]),
- (2, "N4", "N5", vec![]),
- ];
-
- for (time, src, dst, props) in edges {
- graph.add_edge(time, src, dst, props, None).unwrap();
- }
-
- graph
- }
-
- let filter = EdgeFilter.property("p1").eq(1u64);
- let expected_results = vec!["N1->N2", "N3->N4"];
- assert_filter_edges_results(
- init_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
- }
-}
-
-fn init_nodes_graph<
- G: StaticGraphViewOps
- + AdditionOps
- + InternalAdditionOps
- + InternalPropertyAdditionOps
- + PropertyAdditionOps,
->(
- graph: G,
-) -> G {
- let nodes = [
- (
- 1,
- "1",
- vec![
- ("p1", "shivam_kapoor".into_prop()),
- ("p9", 5u64.into_prop()),
- ("p10", "Paper_airplane".into_prop()),
- ("p20", "Gold_ship".into_prop()),
- ("p30", "Gold_ship".into_prop()),
- ("p40", 5u64.into_prop()),
- ],
- Some("fire_nation"),
- ),
- (
- 2,
- "2",
- vec![
- ("p1", "prop12".into_prop()),
- ("p2", 2u64.into_prop()),
- ("p10", "Paper_ship".into_prop()),
- ("p20", "Gold_boat".into_prop()),
- ("p30", "Old_boat".into_prop()),
- ("p40", 10u64.into_prop()),
- ],
- Some("air_nomads"),
- ),
- (
- 3,
- "2",
- vec![
- ("p20", "Gold_ship".into_prop()),
- ("p30", "Gold_ship".into_prop()),
- ("p40", 15u64.into_prop()),
- ],
- Some("air_nomads"),
- ),
- (
- 4,
- "2",
- vec![
- ("p20", "Gold_ship".into_prop()),
- ("p30", "Gold_ship".into_prop()),
- ("p40", 20u64.into_prop()),
- ],
- Some("air_nomads"),
- ),
- (
- 3,
- "1",
- vec![
- ("p1", "shivam_kapoor".into_prop()),
- ("p9", 5u64.into_prop()),
- ("p20", "Gold_ship".into_prop()),
- ("p30", "Gold_ship".into_prop()),
- ("p40", 10u64.into_prop()),
- ],
- Some("fire_nation"),
- ),
- (
- 3,
- "3",
- vec![
- ("p2", 6u64.into_prop()),
- ("p3", 1u64.into_prop()),
- ("p10", "Paper_airplane".into_prop()),
- ],
- Some("fire_nation"),
- ),
- (
- 4,
- "1",
- vec![
- ("p1", "shivam_kapoor".into_prop()),
- ("p9", 5u64.into_prop()),
- ("p20", "Gold_ship".into_prop()),
- ("p30", "Gold_ship".into_prop()),
- ("p40", 15u64.into_prop()),
- ],
- Some("fire_nation"),
- ),
- (
- 3,
- "4",
- vec![
- ("p4", "pometry".into_prop()),
- ("p20", "Gold_ship".into_prop()),
- ("p30", "Gold_ship".into_prop()),
- ],
- None,
- ),
- (
- 4,
- "4",
- vec![
- ("p5", 12u64.into_prop()),
- ("p20", "Gold_boat".into_prop()),
- ("p30", "Old_ship".into_prop()),
- ],
- None,
- ),
- ];
-
- for (time, id, props, node_type) in nodes {
- graph.add_node(time, id, props, node_type, None).unwrap();
- }
-
- let metadata = [
- (
- "1",
- vec![
- ("m1", "pometry".into_prop()),
- ("m2", "raphtory".into_prop()),
- ],
- ),
- ("2", vec![("m1", "raphtory".into_prop())]),
- (
- "3",
- vec![
- ("m2", "pometry".into_prop()),
- ("m3", "raphtory".into_prop()),
- ],
- ),
- (
- "4",
- vec![
- ("m3", "pometry".into_prop()),
- ("m4", "raphtory".into_prop()),
- ],
- ),
- ];
-
- for (node_id, md) in metadata {
- graph.node(node_id).unwrap().add_metadata(md).unwrap();
- }
-
- graph
-}
-
-fn init_nodes_graph_with_num_ids<
- G: StaticGraphViewOps
- + AdditionOps
- + InternalAdditionOps
- + InternalPropertyAdditionOps
- + PropertyAdditionOps,
->(
- graph: G,
-) -> G {
- let nodes = [
- (
- 1,
- 1,
- vec![
- ("p1", "shivam_kapoor".into_prop()),
- ("p9", 5u64.into_prop()),
- ("p10", "Paper_airplane".into_prop()),
- ("p20", "Gold_ship".into_prop()),
- ("p30", "Gold_ship".into_prop()),
- ("p40", 5u64.into_prop()),
- ],
- Some("fire_nation"),
- ),
- (
- 2,
- 2,
- vec![
- ("p1", "prop12".into_prop()),
- ("p2", 2u64.into_prop()),
- ("p10", "Paper_ship".into_prop()),
- ("p20", "Gold_boat".into_prop()),
- ("p30", "Old_boat".into_prop()),
- ("p40", 10u64.into_prop()),
- ],
- Some("air_nomads"),
- ),
- (
- 3,
- 2,
- vec![
- ("p20", "Gold_ship".into_prop()),
- ("p30", "Gold_ship".into_prop()),
- ("p40", 15u64.into_prop()),
- ],
- Some("air_nomads"),
- ),
- (
- 4,
- 2,
- vec![
- ("p20", "Gold_ship".into_prop()),
- ("p30", "Gold_ship".into_prop()),
- ("p40", 20u64.into_prop()),
- ],
- Some("air_nomads"),
- ),
- (
- 3,
- 1,
- vec![
- ("p1", "shivam_kapoor".into_prop()),
- ("p9", 5u64.into_prop()),
- ("p20", "Gold_ship".into_prop()),
- ("p30", "Gold_ship".into_prop()),
- ("p40", 10u64.into_prop()),
- ],
- Some("fire_nation"),
- ),
- (
- 3,
- 3,
- vec![
- ("p2", 6u64.into_prop()),
- ("p3", 1u64.into_prop()),
- ("p10", "Paper_airplane".into_prop()),
- ],
- Some("fire_nation"),
- ),
- (
- 4,
- 1,
- vec![
- ("p1", "shivam_kapoor".into_prop()),
- ("p9", 5u64.into_prop()),
- ("p20", "Gold_ship".into_prop()),
- ("p30", "Gold_ship".into_prop()),
- ("p40", 15u64.into_prop()),
- ],
- Some("fire_nation"),
- ),
- (
- 3,
- 4,
- vec![
- ("p4", "pometry".into_prop()),
- ("p20", "Gold_ship".into_prop()),
- ("p30", "Gold_ship".into_prop()),
- ],
- None,
- ),
- (
- 4,
- 4,
- vec![
- ("p5", 12u64.into_prop()),
- ("p20", "Gold_boat".into_prop()),
- ("p30", "Old_ship".into_prop()),
- ],
- None,
- ),
- ];
-
- for (time, id, props, node_type) in nodes {
- graph.add_node(time, id, props, node_type, None).unwrap();
- }
-
- graph
-}
-
-fn init_nodes_graph_with_str_ids<
- G: StaticGraphViewOps
- + AdditionOps
- + InternalAdditionOps
- + InternalPropertyAdditionOps
- + PropertyAdditionOps,
->(
- graph: G,
-) -> G {
- let nodes = [
- (1, "London", Some("fire_nation")),
- (2, "Two", Some("air_nomads")),
- (3, "Two", Some("air_nomads")),
- (4, "Two", Some("air_nomads")),
- (3, "London", Some("fire_nation")),
- (3, "Tokyo", Some("fire_nation")),
- (4, "London", Some("fire_nation")),
- (3, "France Paris", None),
- (4, "France Paris", None),
- ];
-
- for (time, id, node_type) in nodes {
- graph.add_node(time, id, NO_PROPS, node_type, None).unwrap();
- }
-
- graph
-}
-
-fn init_edges_graph<
- G: StaticGraphViewOps
- + AdditionOps
- + InternalAdditionOps
- + InternalPropertyAdditionOps
- + PropertyAdditionOps,
->(
- graph: G,
-) -> G {
- let edges = [
- (
- 1,
- "1",
- "2",
- vec![
- ("p1", "shivam_kapoor".into_prop()),
- ("p10", "Paper_airplane".into_prop()),
- ("p20", "Gold_ship".into_prop()),
- ("p30", "Gold_ship".into_prop()),
- ],
- Some("fire_nation"),
- ),
- (
- 2,
- "1",
- "2",
- vec![
- ("p1", "shivam_kapoor".into_prop()),
- ("p2", 4u64.into_prop()),
- ("p20", "Gold_ship".into_prop()),
- ("p30", "Gold_ship".into_prop()),
- ],
- Some("fire_nation"),
- ),
- (
- 2,
- "2",
- "3",
- vec![
- ("p1", "prop12".into_prop()),
- ("p2", 2u64.into_prop()),
- ("p10", "Paper_ship".into_prop()),
- ("p20", "Gold_boat".into_prop()),
- ("p30", "Old_boat".into_prop()),
- ],
- Some("air_nomads"),
- ),
- (
- 3,
- "2",
- "3",
- vec![
- ("p20", "Gold_ship".into_prop()),
- ("p30", "Gold_boat".into_prop()),
- ],
- Some("air_nomads"),
- ),
- (
- 3,
- "3",
- "1",
- vec![("p2", 6u64.into_prop()), ("p3", 1u64.into_prop())],
- Some("fire_nation"),
- ),
- (
- 3,
- "2",
- "1",
- vec![
- ("p2", 6u64.into_prop()),
- ("p3", 1u64.into_prop()),
- ("p10", "Paper_airplane".into_prop()),
- ],
- None,
- ),
- (
- 4,
- "David Gilmour",
- "John Mayer",
- vec![("p2", 6u64.into_prop()), ("p3", 1u64.into_prop())],
- None,
- ),
- (
- 4,
- "John Mayer",
- "Jimmy Page",
- vec![("p2", 6u64.into_prop()), ("p3", 1u64.into_prop())],
- None,
- ),
- ];
-
- for (time, src, dst, props, edge_type) in edges {
- graph.add_edge(time, src, dst, props, edge_type).unwrap();
- }
-
- graph
-}
-
-fn init_edges_graph2<
- G: StaticGraphViewOps
- + AdditionOps
- + InternalAdditionOps
- + InternalPropertyAdditionOps
- + PropertyAdditionOps,
->(
- graph: G,
-) -> G {
- let edges = [
- (
- 1,
- "1",
- "2",
- vec![
- ("p1", "shivam_kapoor".into_prop()),
- ("p2", 6u64.into_prop()),
- ("p10", "Paper_airplane".into_prop()),
- ("p20", "Gold_ship".into_prop()),
- ],
- Some("fire_nation"),
- ),
- (
- 2,
- "1",
- "2",
- vec![
- ("p1", "shivam_kapoor".into_prop()),
- ("p2", 7u64.into_prop()),
- ("p10", "Gold_ship".into_prop()),
- ("p20", "Gold_ship".into_prop()),
- ],
- Some("fire_nation"),
- ),
- (
- 2,
- "1",
- "2",
- vec![
- ("p1", "shivam_kapoor".into_prop()),
- ("p2", 4u64.into_prop()),
- ("p20", "Gold_ship".into_prop()),
- ],
- Some("air_nomads"),
- ),
- (
- 2,
- "2",
- "3",
- vec![
- ("p1", "prop12".into_prop()),
- ("p2", 2u64.into_prop()),
- ("p10", "Paper_ship".into_prop()),
- ("p20", "Gold_boat".into_prop()),
- ],
- Some("air_nomads"),
- ),
- (
- 3,
- "2",
- "3",
- vec![
- ("p20", "Gold_ship".into_prop()),
- ("p30", "Gold_boat".into_prop()),
- ],
- Some("air_nomads"),
- ),
- (
- 3,
- "3",
- "1",
- vec![("p2", 6u64.into_prop()), ("p3", 1u64.into_prop())],
- Some("air_nomads"),
- ),
- (
- 3,
- "2",
- "1",
- vec![
- ("p2", 6u64.into_prop()),
- ("p3", 1u64.into_prop()),
- ("p10", "Paper_airplane".into_prop()),
- ],
- None,
- ),
- ];
-
- for (time, src, dst, props, edge_type) in edges {
- graph.add_edge(time, src, dst, props, edge_type).unwrap();
- }
-
- graph
-}
-
-fn init_edges_graph_with_num_ids<
- G: StaticGraphViewOps
- + AdditionOps
- + InternalAdditionOps
- + InternalPropertyAdditionOps
- + PropertyAdditionOps,
->(
- graph: G,
-) -> G {
- let edges = [
- (
- 1,
- 1,
- 2,
- vec![
- ("p1", "shivam_kapoor".into_prop()),
- ("p10", "Paper_airplane".into_prop()),
- ("p20", "Gold_ship".into_prop()),
- ("p30", "Gold_ship".into_prop()),
- ],
- Some("fire_nation"),
- ),
- (
- 2,
- 1,
- 2,
- vec![
- ("p1", "shivam_kapoor".into_prop()),
- ("p2", 4u64.into_prop()),
- ("p20", "Gold_ship".into_prop()),
- ("p30", "Gold_ship".into_prop()),
- ],
- Some("fire_nation"),
- ),
- (
- 2,
- 2,
- 3,
- vec![
- ("p1", "prop12".into_prop()),
- ("p2", 2u64.into_prop()),
- ("p10", "Paper_ship".into_prop()),
- ("p20", "Gold_boat".into_prop()),
- ("p30", "Old_boat".into_prop()),
- ],
- Some("air_nomads"),
- ),
- (
- 3,
- 2,
- 3,
- vec![
- ("p20", "Gold_ship".into_prop()),
- ("p30", "Gold_boat".into_prop()),
- ],
- Some("air_nomads"),
- ),
- (
- 3,
- 3,
- 1,
- vec![("p2", 6u64.into_prop()), ("p3", 1u64.into_prop())],
- Some("fire_nation"),
- ),
- (
- 3,
- 2,
- 1,
- vec![
- ("p2", 6u64.into_prop()),
- ("p3", 1u64.into_prop()),
- ("p10", "Paper_airplane".into_prop()),
- ],
- None,
- ),
- ];
-
- for (time, src, dst, props, edge_type) in edges {
- graph.add_edge(time, src, dst, props, edge_type).unwrap();
- }
-
- graph
-}
-
-fn init_edges_graph_with_str_ids<
- G: StaticGraphViewOps
- + AdditionOps
- + InternalAdditionOps
- + InternalPropertyAdditionOps
- + PropertyAdditionOps,
->(
- graph: G,
-) -> G {
- let edges = [
- (1, "London", "Paris", Some("fire_nation")),
- (2, "London", "Paris", Some("fire_nation")),
- (2, "Two", "Three", Some("air_nomads")),
- (3, "Two", "Three", Some("air_nomads")),
- (3, "Three", "One", Some("fire_nation")),
- (3, "Two", "One", None),
- (4, "David Gilmour", "John Mayer", None),
- (4, "John Mayer", "Jimmy Page", None),
- ];
-
- for (time, src, dst, edge_type) in edges {
- graph.add_edge(time, src, dst, NO_PROPS, edge_type).unwrap();
- }
-
- graph
-}
-
-fn init_edges_graph_with_str_ids_del<
- G: StaticGraphViewOps
- + AdditionOps
- + DeletionOps
- + InternalAdditionOps
- + InternalPropertyAdditionOps
- + PropertyAdditionOps,
->(
- graph: G,
-) -> G {
- let edges = [
- (1, "London", "Paris", Some("fire_nation")),
- (2, "London", "Paris", Some("fire_nation")),
- (2, "Two", "Three", Some("air_nomads")),
- (3, "Two", "Three", Some("air_nomads")),
- (3, "Three", "One", Some("fire_nation")),
- (3, "Two", "One", None),
- (4, "David Gilmour", "John Mayer", None),
- (4, "John Mayer", "Jimmy Page", None),
- ];
-
- for (time, src, dst, edge_type) in edges {
- graph.add_edge(time, src, dst, NO_PROPS, edge_type).unwrap();
- }
-
- graph
- .delete_edge(3, "London", "Paris", Some("fire_nation"))
- .unwrap();
-
- graph
- .add_edge(5, "Bangalore", "Bangalore", NO_PROPS, None)
- .unwrap();
-
- graph
-}
-
-mod test_node_filter {
-
-use crate::{
- init_nodes_graph, init_nodes_graph_with_num_ids, init_nodes_graph_with_str_ids,
- IdentityGraphTransformer,
- };
- use raphtory::{
- algorithms::alternating_mask::alternating_mask, core::entities::VID, db::{
- api::view::{Filter, filter_ops::NodeSelect},
- graph::{
- views::filter::{
- CreateFilter, model::{
- ComposableFilter, CompositeNodeFilter, NodeViewFilterOps, PropertyFilterFactory, TryAsCompositeFilter, ViewWrapOps, degree_filter::DegreeFilterFactory, node_filter::ops::{NodeFilterOps, NodeIdFilterOps}, property_filter::ops::{ListAggOps, PropertyFilterOps}
- }
- },
- },
- }, errors::GraphError, prelude::{
- AdditionOps, Graph, GraphViewOps, NO_PROPS, NodeFilter, NodeStateOps, NodeViewOps, TimeOps
- }
- };
- use raphtory_tests::assertions::{
- assert_filter_nodes_results, assert_search_nodes_results, assert_select_nodes_results,
- TestVariants,
- };
- use raphtory_api::core::{Direction, entities::properties::prop::Prop};
- use raphtory::prelude::IntoProp;
- use raphtory::db::graph::views::filter::model::property_filter::ops::ElemQualifierOps;
- use proptest::proptest;
-
- fn sort_vids(mut vids: Vec) -> Vec {
- vids.sort();
- vids
- }
-
- fn candidates_with_history_after_filtering<'a, G: GraphViewOps<'a>>(
- graph: &G,
- candidate_nodes: Vec,
- ) -> Vec {
- let subgraph = graph.subgraph(candidate_nodes);
- sort_vids(
- subgraph
- .nodes()
- .into_iter()
- .filter(|n| !n.history().is_empty())
- .map(|n| n.node)
- .collect(),
- )
- }
-
- fn assert_filter(
- graph: &Graph,
- filter: CF,
- metric: Direction,
- manual_expr: F,
- context: &str,
- ) where
- CF: CreateFilter + TryAsCompositeFilter + Clone,
- F: Fn(usize) -> bool + Copy,
- {
- let expected_select_nodes = graph
- .nodes()
- .into_iter()
- .filter(|n| {
- manual_expr(match metric {
- Direction::BOTH => n.degree(),
- Direction::IN => n.in_degree(),
- Direction::OUT => n.out_degree(),
- })
- })
- .map(|n| n.node)
- .collect::>();
-
- let expected_filter_nodes = candidates_with_history_after_filtering(graph, expected_select_nodes.clone());
-
- let filtered_event_graph = graph.filter(filter.clone()).unwrap();
- let filtered_event_nodes = sort_vids(
- filtered_event_graph
- .nodes()
- .into_iter()
- .map(|n| n.node)
- .collect(),
- );
- assert_eq!(
- filtered_event_nodes, expected_filter_nodes,
- "{} failed for event graph",
- context
- );
-
- let selected_event_nodes = sort_vids(
- graph
- .nodes()
- .select(filter.clone())
- .unwrap()
- .into_iter()
- .map(|n| n.node)
- .collect(),
- );
- assert_eq!(
- selected_event_nodes, expected_select_nodes,
- "{} failed for event graph select",
- context
- );
-
- let filtered_persistent_graph = graph.persistent_graph().filter(filter.clone()).unwrap();
- let filtered_persistent_nodes = sort_vids(
- filtered_persistent_graph
- .nodes()
- .into_iter()
- .map(|n| n.node)
- .collect(),
- );
- assert_eq!(
- filtered_persistent_nodes, expected_filter_nodes,
- "{} failed for persistent graph",
- context
- );
-
- let selected_persistent_nodes = sort_vids(
- graph
- .persistent_graph()
- .nodes()
- .select(filter)
- .unwrap()
- .into_iter()
- .map(|n| n.node)
- .collect(),
- );
- assert_eq!(
- selected_persistent_nodes, expected_select_nodes,
- "{} failed for persistent graph select",
- context
- );
- }
-
- fn degree_graph_with_add_node_and_add_edge() -> Graph {
- let graph = degree_graph_with_add_edge_only();
- let add_nodes = [
- (0, "1", Some("layer_a")),
- (0, "7", None),
- (0, "8", None),
- (3, "9", Some("layer_a")),
- (4, "9", Some("layer_c")),
- (5, "10", Some("layer_b")),
- (6, "10", Some("layer_e")),
- (7, "11", Some("layer_d")),
- (8, "12", Some("layer_f")),
- (9, "12", Some("layer_c")),
- ];
- for (t, id, layer) in add_nodes {
- graph.add_node(t, id, NO_PROPS, None, layer).unwrap();
- }
- graph
- }
-
-
- fn degree_graph_with_add_edge_only() -> Graph {
- let graph = Graph::new();
-
- let edges = [
- (1, "1", "2", "layer_a"),
- (1, "1", "3", "layer_b"),
- (1, "1", "4", "layer_a"),
- (1, "1", "5", "layer_b"),
- (1, "1", "6", "layer_a"),
- (2, "2", "1", "layer_b"),
- (2, "2", "3", "layer_a"),
- (2, "2", "4", "layer_b"),
- (2, "2", "5", "layer_a"),
- (3, "3", "1", "layer_a"),
- (3, "3", "4", "layer_b"),
- (3, "3", "5", "layer_a"),
- (4, "4", "1", "layer_b"),
- (4, "4", "2", "layer_a"),
- (5, "5", "1", "layer_b"),
- (6, "6", "1", "layer_a"),
- (6, "4", "3", "layer_b"),
- (6, "5", "2", "layer_a"),
- (6, "6", "2", "layer_b"),
- (6, "5", "3", "layer_a"),
- (7, "2", "6", "layer_c"),
- (7, "3", "6", "layer_d"),
- (7, "6", "4", "layer_e"),
- (7, "1", "5", "layer_f"),
- (8, "3", "2", "layer_c"),
- (8, "4", "6", "layer_d"),
- (8, "2", "5", "layer_e"),
- (8, "6", "3", "layer_f"),
- (9, "5", "4", "layer_c"),
- (9, "4", "5", "layer_d"),
- (9, "2", "4", "layer_e"),
- (9, "3", "1", "layer_f"),
- ];
- for (t, src, dst, layer) in edges {
- graph.add_edge(t, src, dst, NO_PROPS, Some(layer)).unwrap();
- }
-
- graph
- }
-
-
- // Property-based tests for degree filtering
- proptest! {
- #[test]
- fn prop_degree_filter_both_direction_comparison(threshold in 0u64..15) {
- let graph = degree_graph_with_add_node_and_add_edge();
-
- assert_filter(
- &graph,
- NodeFilter.degree().lt(threshold),
- Direction::BOTH,
- |d| d < threshold as usize,
- &format!("BOTH < {}", threshold),
- );
-
- assert_filter(
- &graph,
- NodeFilter.degree().le(threshold),
- Direction::BOTH,
- |d| d <= threshold as usize,
- &format!("BOTH <= {}", threshold),
- );
-
- assert_filter(
- &graph,
- NodeFilter.degree().eq(threshold),
- Direction::BOTH,
- |d| d == threshold as usize,
- &format!("BOTH == {}", threshold),
- );
-
- assert_filter(
- &graph,
- NodeFilter.degree().ne(threshold),
- Direction::BOTH,
- |d| d != threshold as usize,
- &format!("BOTH != {}", threshold),
- );
-
- assert_filter(
- &graph,
- NodeFilter.degree().ge(threshold),
- Direction::BOTH,
- |d| d >= threshold as usize,
- &format!("BOTH >= {}", threshold),
- );
-
- assert_filter(
- &graph,
- NodeFilter.degree().gt(threshold),
- Direction::BOTH,
- |d| d > threshold as usize,
- &format!("BOTH > {}", threshold),
- );
- }
-
- #[test]
- fn prop_degree_filter_in_direction_comparison(threshold in 0u64..15) {
- let graph = degree_graph_with_add_node_and_add_edge();
-
- assert_filter(
- &graph,
- NodeFilter.in_degree().lt(threshold),
- Direction::IN,
- |d| d < threshold as usize,
- &format!("IN < {}", threshold),
- );
-
- assert_filter(
- &graph,
- NodeFilter.in_degree().le(threshold),
- Direction::IN,
- |d| d <= threshold as usize,
- &format!("IN <= {}", threshold),
- );
-
- assert_filter(
- &graph,
- NodeFilter.in_degree().eq(threshold),
- Direction::IN,
- |d| d == threshold as usize,
- &format!("IN == {}", threshold),
- );
-
- assert_filter(
- &graph,
- NodeFilter.in_degree().ne(threshold),
- Direction::IN,
- |d| d != threshold as usize,
- &format!("IN != {}", threshold),
- );
-
- assert_filter(
- &graph,
- NodeFilter.in_degree().ge(threshold),
- Direction::IN,
- |d| d >= threshold as usize,
- &format!("IN >= {}", threshold),
- );
-
- assert_filter(
- &graph,
- NodeFilter.in_degree().gt(threshold),
- Direction::IN,
- |d| d > threshold as usize,
- &format!("IN > {}", threshold),
- );
- }
-
- #[test]
- fn prop_degree_filter_out_direction_comparison(threshold in 0u64..15) {
- let graph = degree_graph_with_add_node_and_add_edge();
-
- assert_filter(
- &graph,
- NodeFilter.out_degree().lt(threshold),
- Direction::OUT,
- |d| d < threshold as usize,
- &format!("OUT < {}", threshold),
- );
-
- assert_filter(
- &graph,
- NodeFilter.out_degree().le(threshold),
- Direction::OUT,
- |d| d <= threshold as usize,
- &format!("OUT <= {}", threshold),
- );
-
- assert_filter(
- &graph,
- NodeFilter.out_degree().eq(threshold),
- Direction::OUT,
- |d| d == threshold as usize,
- &format!("OUT == {}", threshold),
- );
-
- assert_filter(
- &graph,
- NodeFilter.out_degree().ne(threshold),
- Direction::OUT,
- |d| d != threshold as usize,
- &format!("OUT != {}", threshold),
- );
-
- assert_filter(
- &graph,
- NodeFilter.out_degree().ge(threshold),
- Direction::OUT,
- |d| d >= threshold as usize,
- &format!("OUT >= {}", threshold),
- );
-
- assert_filter(
- &graph,
- NodeFilter.out_degree().gt(threshold),
- Direction::OUT,
- |d| d > threshold as usize,
- &format!("OUT > {}", threshold),
- );
- }
-
- #[test]
- fn prop_degree_filter_and(threshold in 0u64..15) {
- let graph = degree_graph_with_add_node_and_add_edge();
-
- assert_filter(
- &graph,
- NodeFilter.degree().gt(threshold).and(NodeFilter.degree().lt(threshold + 5)),
- Direction::BOTH,
- |d| d > threshold as usize && d < (threshold + 5) as usize,
- &format!("BOTH > {} AND BOTH < {}", threshold, threshold + 5),
- );
-
- assert_filter(
- &graph,
- NodeFilter.in_degree().gt(threshold).and(NodeFilter.in_degree().lt(threshold + 5)),
- Direction::IN,
- |d| d > threshold as usize && d < (threshold + 5) as usize,
- &format!("IN > {} AND IN < {}", threshold, threshold + 5),
- );
-
- assert_filter(
- &graph,
- NodeFilter.out_degree().gt(threshold).and(NodeFilter.out_degree().lt(threshold + 5)),
- Direction::OUT,
- |d| d > threshold as usize && d < (threshold + 5) as usize,
- &format!("OUT > {} AND OUT < {}", threshold, threshold + 5),
- );
- }
-
- #[test]
- fn prop_degree_filter_or(threshold in 0u64..15) {
- let graph = degree_graph_with_add_node_and_add_edge();
-
- assert_filter(
- &graph,
- NodeFilter.degree().lt(threshold).or(NodeFilter.degree().gt(threshold + 5)),
- Direction::BOTH,
- |d| d < threshold as usize || d > (threshold + 5) as usize,
- &format!("BOTH < {} OR BOTH > {}", threshold, threshold + 5),
- );
-
- assert_filter(
- &graph,
- NodeFilter.in_degree().lt(threshold).or(NodeFilter.in_degree().gt(threshold + 5)),
- Direction::IN,
- |d| d < threshold as usize || d > (threshold + 5) as usize,
- &format!("IN < {} OR IN > {}", threshold, threshold + 5),
- );
-
- assert_filter(
- &graph,
- NodeFilter.out_degree().lt(threshold).or(NodeFilter.out_degree().gt(threshold + 5)),
- Direction::OUT,
- |d| d < threshold as usize || d > (threshold + 5) as usize,
- &format!("OUT < {} OR OUT > {}", threshold, threshold + 5),
- );
- }
-
- #[test]
- fn prop_degree_filter_not(threshold in 0u64..15) {
- let graph = degree_graph_with_add_node_and_add_edge();
-
- assert_filter(
- &graph,
- NodeFilter.degree().lt(threshold).or(NodeFilter.degree().gt(threshold + 5).not()),
- Direction::BOTH,
- |d| d < threshold as usize || d <= (threshold + 5) as usize,
- &format!("BOTH < {} OR BOTH > {}", threshold, threshold + 5),
- );
-
- assert_filter(
- &graph,
- NodeFilter.in_degree().lt(threshold).or(NodeFilter.in_degree().gt(threshold + 5).not()),
- Direction::IN,
- |d| d < threshold as usize || d <= (threshold + 5) as usize,
- &format!("IN < {} OR IN > {}", threshold, threshold + 5),
- );
-
- assert_filter(
- &graph,
- NodeFilter.out_degree().lt(threshold).or(NodeFilter.out_degree().gt(threshold + 5).not()),
- Direction::OUT,
- |d| d < threshold as usize || d <= (threshold + 5) as usize,
- &format!("OUT < {} OR OUT > {}", threshold, threshold + 5),
- );
- }
-
- #[test]
- fn prop_degree_filter_is_in(val1 in 0u64..15, val2 in 0u64..15) {
- let graph = degree_graph_with_add_node_and_add_edge();
- let set = [val1, val2];
-
- assert_filter(
- &graph,
- NodeFilter.degree().is_in(vec![Prop::U64(val1), Prop::U64(val2)]),
- Direction::BOTH,
- |d| set.contains(&(d as u64)),
- &format!("BOTH is_in({}, {})", val1, val2),
- );
-
- assert_filter(
- &graph,
- NodeFilter.in_degree().is_in(vec![Prop::U64(val1), Prop::U64(val2)]),
- Direction::IN,
- |d| set.contains(&(d as u64)),
- &format!("IN is_in({}, {})", val1, val2),
- );
-
- assert_filter(
- &graph,
- NodeFilter.out_degree().is_in(vec![Prop::U64(val1), Prop::U64(val2)]),
- Direction::OUT,
- |d| set.contains(&(d as u64)),
- &format!("OUT is_in({}, {})", val1, val2),
- );
- }
-
- #[test]
- fn prop_degree_filter_is_not_in(val1 in 0u64..15, val2 in 0u64..15) {
- let graph = degree_graph_with_add_node_and_add_edge();
- let set = [val1, val2];
-
- assert_filter(
- &graph,
- NodeFilter
- .degree()
- .is_not_in(vec![Prop::U64(val1), Prop::U64(val2)]),
- Direction::BOTH,
- |d| !set.contains(&(d as u64)),
- &format!("BOTH is_not_in({}, {})", val1, val2),
- );
-
- assert_filter(
- &graph,
- NodeFilter
- .in_degree()
- .is_not_in(vec![Prop::U64(val1), Prop::U64(val2)]),
- Direction::IN,
- |d| !set.contains(&(d as u64)),
- &format!("IN is_not_in({}, {})", val1, val2),
- );
-
- assert_filter(
- &graph,
- NodeFilter
- .out_degree()
- .is_not_in(vec![Prop::U64(val1), Prop::U64(val2)]),
- Direction::OUT,
- |d| !set.contains(&(d as u64)),
- &format!("OUT is_not_in({}, {})", val1, val2),
- );
- }
- }
-
- #[test]
- fn test_degree_filter_with_invalid_expressions() {
- let graph = degree_graph_with_add_node_and_add_edge();
- let invalid_filters = vec![
- NodeFilter.degree().is_none(),
- NodeFilter.degree().is_some(),
- NodeFilter.degree().starts_with("1"),
- NodeFilter.degree().ends_with("1"),
- NodeFilter.degree().contains("1"),
- NodeFilter.degree().not_contains("1"),
- NodeFilter.degree().fuzzy_search("1", 1, false),
- NodeFilter.in_degree().is_none(),
- NodeFilter.in_degree().is_some(),
- NodeFilter.in_degree().starts_with("1"),
- NodeFilter.in_degree().ends_with("1"),
- NodeFilter.in_degree().contains("1"),
- NodeFilter.in_degree().not_contains("1"),
- NodeFilter.in_degree().fuzzy_search("1", 1, false),
- NodeFilter.out_degree().is_none(),
- NodeFilter.out_degree().is_some(),
- NodeFilter.out_degree().starts_with("1"),
- NodeFilter.out_degree().ends_with("1"),
- NodeFilter.out_degree().contains("1"),
- NodeFilter.out_degree().not_contains("1"),
- NodeFilter.out_degree().fuzzy_search("1", 1, false),
- NodeFilter.degree().any().eq(1u64),
- NodeFilter.degree().all().eq(1u64),
- NodeFilter.degree().len().gt(0u64),
- NodeFilter.degree().sum().eq(1u64),
- NodeFilter.degree().avg().eq(1u64),
- NodeFilter.degree().min().eq(1u64),
- NodeFilter.degree().max().eq(1u64),
- NodeFilter.degree().first().eq(1u64),
- NodeFilter.degree().last().eq(1u64),
- NodeFilter.in_degree().any().eq(1u64),
- NodeFilter.in_degree().all().eq(1u64),
- NodeFilter.in_degree().len().gt(0u64),
- NodeFilter.in_degree().sum().eq(1u64),
- NodeFilter.in_degree().avg().eq(1u64),
- NodeFilter.in_degree().min().eq(1u64),
- NodeFilter.in_degree().max().eq(1u64),
- NodeFilter.in_degree().first().eq(1u64),
- NodeFilter.in_degree().last().eq(1u64),
- NodeFilter.out_degree().any().eq(1u64),
- NodeFilter.out_degree().all().eq(1u64),
- NodeFilter.out_degree().len().gt(0u64),
- NodeFilter.out_degree().sum().eq(1u64),
- NodeFilter.out_degree().avg().eq(1u64),
- NodeFilter.out_degree().min().eq(1u64),
- NodeFilter.out_degree().max().eq(1u64),
- NodeFilter.out_degree().first().eq(1u64),
- NodeFilter.out_degree().last().eq(1u64),
- ];
-
- for filter in invalid_filters {
- assert!(
- matches!(graph.filter(filter), Err(GraphError::InvalidFilter(_))),
- "expected InvalidFilter for unsupported degree filter operation"
- );
- }
- }
-
- proptest! {
- #[test]
- fn prop_degree_filter_with_string_threshold(threshold in 0u64..15) {
- let graph = degree_graph_with_add_node_and_add_edge();
- let threshold_str = threshold.to_string();
- let parsed_str = threshold_str.parse::().unwrap();
-
- assert_filter(&graph, NodeFilter.degree().lt(threshold_str.clone()), Direction::BOTH, |d| d < parsed_str as usize, "BOTH < string threshold parsed to u64");
- assert_filter(&graph, NodeFilter.degree().le(threshold_str.clone()), Direction::BOTH, |d| d <= parsed_str as usize, "BOTH <= string threshold parsed to u64");
- assert_filter(&graph, NodeFilter.degree().eq(threshold_str.clone()), Direction::BOTH, |d| d == parsed_str as usize, "BOTH == string threshold parsed to u64");
- assert_filter(&graph, NodeFilter.degree().ne(threshold_str.clone()), Direction::BOTH, |d| d != parsed_str as usize, "BOTH != string threshold parsed to u64");
- assert_filter(&graph, NodeFilter.degree().ge(threshold_str.clone()), Direction::BOTH, |d| d >= parsed_str as usize, "BOTH >= string threshold parsed to u64");
- assert_filter(&graph, NodeFilter.degree().gt(threshold_str.clone()), Direction::BOTH, |d| d > parsed_str as usize, "BOTH > string threshold parsed to u64");
-
- assert_filter(&graph, NodeFilter.in_degree().lt(threshold_str.clone()), Direction::IN, |d| d < parsed_str as usize, "IN < string threshold parsed to u64");
- assert_filter(&graph, NodeFilter.in_degree().le(threshold_str.clone()), Direction::IN, |d| d <= parsed_str as usize, "IN <= string threshold parsed to u64");
- assert_filter(&graph, NodeFilter.in_degree().eq(threshold_str.clone()), Direction::IN, |d| d == parsed_str as usize, "IN == string threshold parsed to u64");
- assert_filter(&graph, NodeFilter.in_degree().ne(threshold_str.clone()), Direction::IN, |d| d != parsed_str as usize, "IN != string threshold parsed to u64");
- assert_filter(&graph, NodeFilter.in_degree().ge(threshold_str.clone()), Direction::IN, |d| d >= parsed_str as usize, "IN >= string threshold parsed to u64");
- assert_filter(&graph, NodeFilter.in_degree().gt(threshold_str.clone()), Direction::IN, |d| d > parsed_str as usize, "IN > string threshold parsed to u64");
-
- assert_filter(&graph, NodeFilter.out_degree().lt(threshold_str.clone()), Direction::OUT, |d| d < parsed_str as usize, "OUT < string threshold parsed to u64");
- assert_filter(&graph, NodeFilter.out_degree().le(threshold_str.clone()), Direction::OUT, |d| d <= parsed_str as usize, "OUT <= string threshold parsed to u64");
- assert_filter(&graph, NodeFilter.out_degree().eq(threshold_str.clone()), Direction::OUT, |d| d == parsed_str as usize, "OUT == string threshold parsed to u64");
- assert_filter(&graph, NodeFilter.out_degree().ne(threshold_str.clone()), Direction::OUT, |d| d != parsed_str as usize, "OUT != string threshold parsed to u64");
- assert_filter(&graph, NodeFilter.out_degree().ge(threshold_str.clone()), Direction::OUT, |d| d >= parsed_str as usize, "OUT >= string threshold parsed to u64");
- assert_filter(&graph, NodeFilter.out_degree().gt(threshold_str), Direction::OUT, |d| d > parsed_str as usize, "OUT > string threshold parsed to u64");
- }
-
- #[test]
- fn prop_degree_filter_with_float_threshold(threshold in 0u64..15) {
- let graph = degree_graph_with_add_node_and_add_edge();
- let threshold_float = threshold as f64;
- let parsed_float = threshold_float as u64;
-
- assert_filter(&graph, NodeFilter.degree().lt(threshold_float), Direction::BOTH, |d| d < parsed_float as usize, "BOTH < float threshold cast to u64");
- assert_filter(&graph, NodeFilter.degree().le(threshold_float), Direction::BOTH, |d| d <= parsed_float as usize, "BOTH <= float threshold cast to u64");
- assert_filter(&graph, NodeFilter.degree().eq(threshold_float), Direction::BOTH, |d| d == parsed_float as usize, "BOTH == float threshold cast to u64");
- assert_filter(&graph, NodeFilter.degree().ne(threshold_float), Direction::BOTH, |d| d != parsed_float as usize, "BOTH != float threshold cast to u64");
- assert_filter(&graph, NodeFilter.degree().ge(threshold_float), Direction::BOTH, |d| d >= parsed_float as usize, "BOTH >= float threshold cast to u64");
- assert_filter(&graph, NodeFilter.degree().gt(threshold_float), Direction::BOTH, |d| d > parsed_float as usize, "BOTH > float threshold cast to u64");
-
- assert_filter(&graph, NodeFilter.in_degree().lt(threshold_float), Direction::IN, |d| d < parsed_float as usize, "IN < float threshold cast to u64");
- assert_filter(&graph, NodeFilter.in_degree().le(threshold_float), Direction::IN, |d| d <= parsed_float as usize, "IN <= float threshold cast to u64");
- assert_filter(&graph, NodeFilter.in_degree().eq(threshold_float), Direction::IN, |d| d == parsed_float as usize, "IN == float threshold cast to u64");
- assert_filter(&graph, NodeFilter.in_degree().ne(threshold_float), Direction::IN, |d| d != parsed_float as usize, "IN != float threshold cast to u64");
- assert_filter(&graph, NodeFilter.in_degree().ge(threshold_float), Direction::IN, |d| d >= parsed_float as usize, "IN >= float threshold cast to u64");
- assert_filter(&graph, NodeFilter.in_degree().gt(threshold_float), Direction::IN, |d| d > parsed_float as usize, "IN > float threshold cast to u64");
-
- assert_filter(&graph, NodeFilter.out_degree().lt(threshold_float), Direction::OUT, |d| d < parsed_float as usize, "OUT < float threshold cast to u64");
- assert_filter(&graph, NodeFilter.out_degree().le(threshold_float), Direction::OUT, |d| d <= parsed_float as usize, "OUT <= float threshold cast to u64");
- assert_filter(&graph, NodeFilter.out_degree().eq(threshold_float), Direction::OUT, |d| d == parsed_float as usize, "OUT == float threshold cast to u64");
- assert_filter(&graph, NodeFilter.out_degree().ne(threshold_float), Direction::OUT, |d| d != parsed_float as usize, "OUT != float threshold cast to u64");
- assert_filter(&graph, NodeFilter.out_degree().ge(threshold_float), Direction::OUT, |d| d >= parsed_float as usize, "OUT >= float threshold cast to u64");
- assert_filter(&graph, NodeFilter.out_degree().gt(threshold_float), Direction::OUT, |d| d > parsed_float as usize, "OUT > float threshold cast to u64");
- }
-
- #[test]
- fn prop_degree_filter_with_string_is_in(threshold_a in 0u64..15, threshold_b in 0u64..15) {
- let graph = degree_graph_with_add_node_and_add_edge();
- let threshold_a_str = threshold_a.to_string();
- let threshold_b_str = threshold_b.to_string();
- let parsed_a = threshold_a_str.parse::().unwrap();
- let parsed_b = threshold_b_str.parse::().unwrap();
- let set = [parsed_a, parsed_b];
-
- assert_filter(&graph, NodeFilter.degree().is_in(vec![threshold_a_str.clone().into_prop(), threshold_b_str.clone().into_prop()]), Direction::BOTH, |d| set.contains(&(d as u64)), "BOTH is_in(string thresholds parsed to u64)");
- assert_filter(&graph, NodeFilter.in_degree().is_in(vec![threshold_a_str.clone().into_prop(), threshold_b_str.clone().into_prop()]), Direction::IN, |d| set.contains(&(d as u64)), "IN is_in(string thresholds parsed to u64)");
- assert_filter(&graph, NodeFilter.out_degree().is_in(vec![threshold_a_str.into_prop(), threshold_b_str.into_prop()]), Direction::OUT, |d| set.contains(&(d as u64)), "OUT is_in(string thresholds parsed to u64)");
- }
-
- #[test]
- fn prop_degree_filter_with_string_is_not_in(threshold_a in 0u64..15, threshold_b in 0u64..15) {
- let graph = degree_graph_with_add_node_and_add_edge();
- let threshold_a_str = threshold_a.to_string();
- let threshold_b_str = threshold_b.to_string();
- let parsed_a = threshold_a_str.parse::().unwrap();
- let parsed_b = threshold_b_str.parse::().unwrap();
- let set = [parsed_a, parsed_b];
-
- assert_filter(&graph, NodeFilter.degree().is_not_in(vec![threshold_a_str.clone().into_prop(), threshold_b_str.clone().into_prop()]), Direction::BOTH, |d| !set.contains(&(d as u64)), "BOTH is_not_in(string thresholds parsed to u64)");
- assert_filter(&graph, NodeFilter.in_degree().is_not_in(vec![threshold_a_str.clone().into_prop(), threshold_b_str.clone().into_prop()]), Direction::IN, |d| !set.contains(&(d as u64)), "IN is_not_in(string thresholds parsed to u64)");
- assert_filter(&graph, NodeFilter.out_degree().is_not_in(vec![threshold_a_str.into_prop(), threshold_b_str.into_prop()]), Direction::OUT, |d| !set.contains(&(d as u64)), "OUT is_not_in(string thresholds parsed to u64)");
- }
-
- #[test]
- fn prop_degree_filter_with_float_is_in(threshold_a in 0u64..15, threshold_b in 0u64..15) {
- let graph = degree_graph_with_add_node_and_add_edge();
- let threshold_a_float = threshold_a as f64;
- let threshold_b_float = threshold_b as f64;
- let parsed_a = threshold_a_float as u64;
- let parsed_b = threshold_b_float as u64;
- let set = [parsed_a, parsed_b];
-
- assert_filter(&graph, NodeFilter.degree().is_in(vec![threshold_a_float.into_prop(), threshold_b_float.into_prop()]), Direction::BOTH, |d| set.contains(&(d as u64)), "BOTH is_in(float thresholds cast to u64)");
- assert_filter(&graph, NodeFilter.in_degree().is_in(vec![threshold_a_float.into_prop(), threshold_b_float.into_prop()]), Direction::IN, |d| set.contains(&(d as u64)), "IN is_in(float thresholds cast to u64)");
- assert_filter(&graph, NodeFilter.out_degree().is_in(vec![threshold_a_float.into_prop(), threshold_b_float.into_prop()]), Direction::OUT, |d| set.contains(&(d as u64)), "OUT is_in(float thresholds cast to u64)");
- }
-
- #[test]
- fn prop_degree_filter_with_float_is_not_in(threshold_a in 0u64..15, threshold_b in 0u64..15) {
- let graph = degree_graph_with_add_node_and_add_edge();
- let threshold_a_float = threshold_a as f64;
- let threshold_b_float = threshold_b as f64;
- let parsed_a = threshold_a_float as u64;
- let parsed_b = threshold_b_float as u64;
- let set = [parsed_a, parsed_b];
-
- assert_filter(&graph, NodeFilter.degree().is_not_in(vec![threshold_a_float.into_prop(), threshold_b_float.into_prop()]), Direction::BOTH, |d| !set.contains(&(d as u64)), "BOTH is_not_in(float thresholds cast to u64)");
- assert_filter(&graph, NodeFilter.in_degree().is_not_in(vec![threshold_a_float.into_prop(), threshold_b_float.into_prop()]), Direction::IN, |d| !set.contains(&(d as u64)), "IN is_not_in(float thresholds cast to u64)");
- assert_filter(&graph, NodeFilter.out_degree().is_not_in(vec![threshold_a_float.into_prop(), threshold_b_float.into_prop()]), Direction::OUT, |d| !set.contains(&(d as u64)), "OUT is_not_in(float thresholds cast to u64)");
- }
-
- #[test]
- fn prop_degree_filter_invalid_non_numeric_string_values(value_a in "[a-zA-Z]{1,8}", value_b in "[a-zA-Z]{1,8}") {
- let graph = degree_graph_with_add_node_and_add_edge();
-
- let invalid_filters = vec![
- NodeFilter.degree().lt(value_a.clone()),
- NodeFilter.degree().le(value_a.clone()),
- NodeFilter.degree().eq(value_a.clone()),
- NodeFilter.degree().ne(value_a.clone()),
- NodeFilter.degree().ge(value_a.clone()),
- NodeFilter.degree().gt(value_a.clone()),
- NodeFilter.in_degree().lt(value_a.clone()),
- NodeFilter.in_degree().le(value_a.clone()),
- NodeFilter.in_degree().eq(value_a.clone()),
- NodeFilter.in_degree().ne(value_a.clone()),
- NodeFilter.in_degree().ge(value_a.clone()),
- NodeFilter.in_degree().gt(value_a.clone()),
- NodeFilter.out_degree().lt(value_a.clone()),
- NodeFilter.out_degree().le(value_a.clone()),
- NodeFilter.out_degree().eq(value_a.clone()),
- NodeFilter.out_degree().ne(value_a.clone()),
- NodeFilter.out_degree().ge(value_a.clone()),
- NodeFilter.out_degree().gt(value_a.clone()),
- NodeFilter.degree().is_in(vec![value_a.clone().into_prop(), value_b.clone().into_prop()]),
- NodeFilter.degree().is_not_in(vec![value_a.clone().into_prop(), value_b.clone().into_prop()]),
- NodeFilter.in_degree().is_in(vec![value_a.clone().into_prop(), value_b.clone().into_prop()]),
- NodeFilter.in_degree().is_not_in(vec![value_a.clone().into_prop(), value_b.clone().into_prop()]),
- NodeFilter.out_degree().is_in(vec![value_a.clone().into_prop(), value_b.clone().into_prop()]),
- NodeFilter.out_degree().is_not_in(vec![value_a.clone().into_prop(), value_b.clone().into_prop()]),
- ];
-
- for filter in invalid_filters {
- assert!(
- matches!(graph.filter(filter), Err(GraphError::InvalidFilter(_))),
- "expected InvalidFilter for non-numeric string values"
- );
- }
- }
- }
-
- #[test]
- fn test_node_list_is_preserved() {
- let graph = init_nodes_graph(Graph::new());
- let nodes = graph
- .nodes()
- .after(5)
- .select(NodeFilter::node_type().contains("x"))
- .unwrap();
- let degrees = nodes.degree();
- let degrees_collected = degrees.compute();
- assert_eq!(degrees, degrees_collected);
- }
-
- #[test]
- fn test_filter_nodes_for_node_name_eq() {
- let filter = NodeFilter::name().eq("3");
- let expected_results = vec!["3"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_node_name_ne() {
- let filter = NodeFilter::name().ne("2");
- let expected_results = vec!["1", "3", "4"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_node_name_in() {
- let filter = NodeFilter::name().is_in(vec!["1"]);
- let expected_results = vec!["1"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter::name().is_in(vec![""]);
- let expected_results = Vec::<&str>::new();
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter::name().is_in(vec!["2", "3"]);
- let expected_results = vec!["2", "3"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_node_name_not_in() {
- let filter = NodeFilter::name().is_not_in(vec!["1"]);
- let expected_results = vec!["2", "3", "4"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter::name().is_not_in(vec![""]);
- let expected_results = vec!["1", "2", "3", "4"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_node_type_eq() {
- let filter = NodeFilter::node_type().eq("fire_nation");
- let expected_results = vec!["1", "3"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_node_type_ne() {
- let filter = NodeFilter::node_type().ne("fire_nation");
- let expected_results = vec!["2", "4"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_node_type_in() {
- let filter = NodeFilter::node_type().is_in(vec!["fire_nation"]);
- let expected_results = vec!["1", "3"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter::node_type().is_in(vec!["fire_nation", "air_nomads"]);
- let expected_results = vec!["1", "2", "3"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_node_type_not_in() {
- let filter = NodeFilter::node_type().is_not_in(vec!["fire_nation"]);
- let expected_results = vec!["2", "4"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_node_type_starts_with() {
- let filter = NodeFilter::node_type().starts_with("fire");
- let expected_results = vec!["1", "3"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter::node_type().starts_with("rocket");
- let expected_results = vec![];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_node_type_ends_with() {
- let filter = NodeFilter::node_type().ends_with("nomads");
- let expected_results = vec!["2"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter::node_type().ends_with("circle");
- let expected_results = vec![];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_node_type_contains() {
- let filter = NodeFilter::node_type().contains("fire");
- let expected_results = vec!["1", "3"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_node_type_contains_not() {
- let filter = NodeFilter::node_type().not_contains("fire");
- let expected_results = vec!["2", "4"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_fuzzy_search() {
- let filter = NodeFilter::node_type().fuzzy_search("fire", 2, true);
- let expected_results: Vec<&str> = vec!["1", "3"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter::node_type().fuzzy_search("fire", 2, false);
- let expected_results: Vec<&str> = vec![];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter::node_type().fuzzy_search("air_noma", 2, false);
- let expected_results: Vec<&str> = vec!["2"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_not_node_type() {
- let filter = NodeFilter::node_type().is_not_in(vec!["fire_nation"]).not();
- let expected_results = vec!["1", "3"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_eq_node_id() {
- let filter = NodeFilter::id().eq("1");
- let expected_results = vec!["1"];
-
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter::id().eq(1);
- let expected_results = vec!["1"];
-
- assert_filter_nodes_results(
- init_nodes_graph_with_num_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_filter_nodes_results(
- init_nodes_graph_with_num_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_ne_node_id() {
- let filter = NodeFilter::id().ne("1");
- let expected_results = vec!["2", "3", "4"];
-
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter::id().ne(1);
- let expected_results = vec!["2", "3", "4"];
-
- assert_filter_nodes_results(
- init_nodes_graph_with_num_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph_with_num_ids,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_is_in_node_id() {
- let filter = NodeFilter::id().is_in(vec!["1", "3", "6"]);
- let expected_results = vec!["1", "3"];
-
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter::id().is_in(vec![1, 3, 6]);
- let expected_results = vec!["1", "3"];
-
- assert_filter_nodes_results(
- init_nodes_graph_with_num_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph_with_num_ids,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_is_not_in_node_id() {
- let filter = NodeFilter::id().is_not_in(vec!["1", "3", "6"]);
- let expected_results = vec!["2", "4"];
-
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter::id().is_not_in(vec![1, 3, 6]);
- let expected_results = vec!["2", "4"];
-
- assert_filter_nodes_results(
- init_nodes_graph_with_num_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph_with_num_ids,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_lt_node_id() {
- let filter = NodeFilter::id().lt(2);
- let expected_results = vec!["1"];
-
- assert_filter_nodes_results(
- init_nodes_graph_with_num_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph_with_num_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_le_node_id() {
- let filter = NodeFilter::id().le(3);
- let expected_results = vec!["1", "2", "3"];
-
- assert_filter_nodes_results(
- init_nodes_graph_with_num_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph_with_num_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_gt_node_id() {
- let filter = NodeFilter::id().gt(2);
- let expected_results = vec!["3", "4"];
-
- assert_filter_nodes_results(
- init_nodes_graph_with_num_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph_with_num_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_ge_node_id() {
- let filter = NodeFilter::id().ge(2);
- let expected_results = vec!["2", "3", "4"];
-
- assert_filter_nodes_results(
- init_nodes_graph_with_num_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph_with_num_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_starts_with_node_id() {
- let filter = NodeFilter::id().starts_with("France");
- let expected_results = vec!["France Paris"];
- assert_filter_nodes_results(
- init_nodes_graph_with_str_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_ends_with_node_id() {
- let filter = NodeFilter::id().ends_with("wo");
- let expected_results = vec!["Two"];
- assert_filter_nodes_results(
- init_nodes_graph_with_str_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph_with_str_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_contains_node_id() {
- let filter = NodeFilter::id().contains("o");
- let expected_results = vec!["London", "Tokyo", "Two"];
- assert_filter_nodes_results(
- init_nodes_graph_with_str_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_not_contains_node_id() {
- let filter = NodeFilter::id().not_contains("o");
- let expected_results = vec!["France Paris"];
- assert_filter_nodes_results(
- init_nodes_graph_with_str_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_is_in_node_id_str() {
- let filter = NodeFilter::id().is_in(vec!["London", "Tokyo"]);
- let expected_results = vec!["London", "Tokyo"];
- assert_filter_nodes_results(
- init_nodes_graph_with_str_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph_with_str_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_is_not_in_node_id_str() {
- let filter = NodeFilter::id().is_not_in(vec!["London", "Tokyo"]);
- let expected_results = vec!["France Paris", "Two"];
- assert_filter_nodes_results(
- init_nodes_graph_with_str_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph_with_str_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_is_active_node_window() {
- let filter = NodeFilter.window(1, 10).is_active();
- let expected_results = vec!["1", "2", "3", "4"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
-
- #[test]
- fn test_is_active_node_window_not() {
- let filter = NodeFilter
- .window(1, 10)
- .is_active()
- .try_as_composite_node_filter()
- .unwrap();
- let filter = CompositeNodeFilter::Not(Box::new(filter));
- let expected_results = vec![];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
-
- #[test]
- fn test_is_active_node_latest() {
- let filter = NodeFilter.latest().is_active();
- let expected_results = vec!["1", "2", "4"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
-
- #[test]
- fn test_filter_by_column() {
- let graph = Graph::new();
- graph.add_node(1, 1, NO_PROPS, None, None).unwrap();
- graph.add_node(1, 2, NO_PROPS, None, None).unwrap();
- graph.add_node(1, 3, NO_PROPS, None, None).unwrap();
- graph.add_node(1, 4, NO_PROPS, None, None).unwrap();
- graph.add_node(1, 5, NO_PROPS, None, None).unwrap();
-
- let mask = alternating_mask(&graph);
- let expected_nodes: Vec<_> = graph
- .nodes()
- .name()
- .iter_values()
- .skip(1)
- .step_by(2)
- .collect();
-
- let filtered = graph
- .filter(NodeFilter::by_column(&mask, "bool_col").unwrap())
- .unwrap();
-
- let names = filtered
- .nodes()
- .iter()
- .map(|n| n.id().to_string())
- .collect::>();
-
- assert_eq!(names, expected_nodes);
-
- let filtered = graph
- .nodes()
- .select(NodeFilter::by_column(&mask, "bool_col").unwrap())
- .unwrap();
-
- let names = filtered
- .iter()
- .map(|n| n.id().to_string())
- .collect::>();
-
- assert_eq!(names, expected_nodes);
- }
-
- #[test]
- fn test_is_active_node_snapshot_at() {
- let filter = NodeFilter.snapshot_at(2).is_active();
- let expected_results = vec!["2"];
- assert_select_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
-}
-
-mod test_node_property_filter {
- use crate::{init_nodes_graph, IdentityGraphTransformer};
- use raphtory::db::graph::views::filter::model::{
- graph_filter::GraphFilter,
- node_filter::NodeFilter,
- not_filter::NotFilter,
- property_filter::ops::{ElemQualifierOps, ListAggOps, PropertyFilterOps},
- windowed_filter::Windowed,
- ComposableFilter, PropertyFilterFactory, TemporalPropertyFilterFactory, ViewWrapOps,
- };
- use raphtory_api::core::entities::properties::prop::Prop;
- use raphtory_tests::assertions::{
- assert_filter_nodes_results, assert_search_nodes_results, TestVariants,
- };
- use std::vec;
-
- #[test]
- fn test_exact_match() {
- // let filter = NodeFilter.degree > 5
- let filter = NodeFilter.property("p10").eq("Paper_airplane");
- let expected_results = vec!["1", "3"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter.property("p10").eq("");
- let expected_results = Vec::<&str>::new();
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_not_exact_match() {
- let filter = NodeFilter.property("p10").eq("Paper");
- let expected_results: Vec<&str> = vec![];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_property_eq() {
- let filter = NodeFilter.property("p2").eq(2u64);
- let expected_results = vec!["2"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter.property("p30").temporal().first().eq("Old_boat");
- let expected_results = vec!["2"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter.property("p20").temporal().all().eq("Gold_ship");
- let expected_results = vec!["1"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_property_ne() {
- let filter = NodeFilter.property("p2").ne(2u64);
- let expected_results = vec!["3"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter.property("p30").temporal().first().ne("Old_boat");
- let expected_results = vec!["1", "4"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter.property("p1").temporal().all().ne("Gold_ship");
- let expected_results = vec!["1"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_property_lt() {
- let filter = NodeFilter.property("p2").lt(10u64);
- let expected_results = vec!["2", "3"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter.property("p40").temporal().first().lt(10u64);
- let expected_results = vec!["1"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter.property("p9").temporal().all().lt(10u64);
- let expected_results = vec!["1"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_property_le() {
- let filter = NodeFilter.property("p2").le(6u64);
- let expected_results = vec!["2", "3"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter.property("p9").temporal().first().le(10u64);
- let expected_results = vec!["1"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter.property("p2").temporal().all().le(10u64);
- let expected_results = vec!["3"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_property_gt() {
- let filter = NodeFilter.property("p2").gt(2u64);
- let expected_results = vec!["3"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter.property("p40").temporal().first().gt(5u64);
- let expected_results = vec!["2"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter.property("p9").temporal().all().gt(1u64);
- let expected_results = vec!["1"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_property_ge() {
- let filter = NodeFilter.property("p2").ge(2u64);
- let expected_results = vec!["2", "3"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter.property("p40").temporal().first().ge(5u64);
- let expected_results = vec!["1", "2"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter.property("p40").temporal().all().ge(5u64);
- let expected_results = vec!["1", "2"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_property_in() {
- let filter = NodeFilter.property("p2").is_in(vec![Prop::U64(6)]);
- let expected_results = vec!["3"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter
- .property("p2")
- .is_in(vec![Prop::U64(2), Prop::U64(6)]);
- let expected_results = vec!["2", "3"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter
- .property("p40")
- .temporal()
- .first()
- .is_in(vec![Prop::U64(5)]);
- let expected_results = vec!["1"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter
- .property("p2")
- .temporal()
- .any()
- .is_in(vec![Prop::U64(2)]);
- let expected_results = vec!["2"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_property_not_in() {
- let filter = NodeFilter.property("p2").is_not_in(vec![Prop::U64(6)]);
- let expected_results = vec!["2"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter.property("p40").is_not_in(vec![Prop::U64(6)]);
- let expected_results = vec!["1", "2"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter
- .property("p2")
- .temporal()
- .all()
- .is_not_in(vec![Prop::U64(2)]);
- let expected_results = vec!["3"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_property_is_some() {
- let filter = NodeFilter.property("p2").is_some();
- let expected_results = vec!["2", "3"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter.property("p40").is_some();
- let expected_results = vec!["1", "2"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_property_is_none() {
- let filter = NodeFilter.property("p2").is_none();
- let expected_results = vec!["1", "4"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter.property("p40").is_none();
- let expected_results = vec!["3", "4"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_property_starts_with() {
- let filter = NodeFilter.property("p10").starts_with("Pa");
- let expected_results: Vec<&str> = vec!["1", "2", "3"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter
- .property("p10")
- .temporal()
- .any()
- .starts_with("Pap");
- let expected_results: Vec<&str> = vec!["1", "2", "3"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter
- .property("p10")
- .temporal()
- .last()
- .starts_with("Pape");
- let expected_results: Vec<&str> = vec!["1", "2", "3"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter
- .property("p10")
- .temporal()
- .last()
- .starts_with("Yohan");
- let expected_results: Vec<&str> = vec![];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter
- .property("p30")
- .temporal()
- .first()
- .starts_with("Gold");
- let expected_results: Vec<&str> = vec!["1", "4"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter
- .property("p20")
- .temporal()
- .all()
- .starts_with("Gold");
- let expected_results: Vec<&str> = vec!["1", "2", "4"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_property_ends_with() {
- let filter = NodeFilter.property("p10").ends_with("lane");
- let expected_results: Vec<&str> = vec!["1", "3"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter
- .property("p10")
- .temporal()
- .any()
- .ends_with("ship");
- let expected_results: Vec<&str> = vec!["2"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter
- .property("p10")
- .temporal()
- .last()
- .ends_with("ane");
- let expected_results: Vec<&str> = vec!["1", "3"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter
- .property("p10")
- .temporal()
- .last()
- .ends_with("Jerry");
- let expected_results: Vec<&str> = vec![];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter
- .property("p20")
- .temporal()
- .first()
- .ends_with("boat");
- let expected_results: Vec<&str> = vec!["2"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter
- .property("p20")
- .temporal()
- .all()
- .ends_with("ship");
- let expected_results: Vec<&str> = vec!["1"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_property_contains() {
- let filter = NodeFilter.property("p10").contains("Paper");
- let expected_results: Vec<&str> = vec!["1", "2", "3"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter
- .property("p10")
- .temporal()
- .any()
- .contains("Paper");
- let expected_results: Vec<&str> = vec!["1", "2", "3"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter
- .property("p10")
- .temporal()
- .last()
- .contains("Paper");
- let expected_results: Vec<&str> = vec!["1", "2", "3"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter
- .property("p30")
- .temporal()
- .first()
- .contains("Old");
- let expected_results: Vec<&str> = vec!["2"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter.property("p30").temporal().all().contains("Gold");
- let expected_results: Vec<&str> = vec!["1"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_property_contains_not() {
- let filter = NodeFilter.property("p10").not_contains("ship");
- let expected_results: Vec<&str> = vec!["1", "3"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter
- .property("p10")
- .temporal()
- .any()
- .not_contains("ship");
- let expected_results: Vec<&str> = vec!["1", "3"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter
- .property("p10")
- .temporal()
- .last()
- .not_contains("ship");
- let expected_results: Vec<&str> = vec!["1", "3"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter
- .property("p30")
- .temporal()
- .first()
- .not_contains("Old");
- let expected_results: Vec<&str> = vec!["1", "4"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter
- .property("p30")
- .temporal()
- .all()
- .not_contains("boat");
- let expected_results: Vec<&str> = vec!["1", "4"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_not_property() {
- let filter = NotFilter(NodeFilter.property("p10").contains("Paper"));
- let expected_results: Vec<&str> = vec!["4"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter.property("p10").contains("Paper").not();
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_temporal_property_sum() {
- let filter = NodeFilter.property("p9").temporal().sum().eq(15u64);
- let expected_results: Vec<&str> = vec!["1"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_temporal_property_avg() {
- let filter = NodeFilter.property("p2").temporal().avg().le(10f64);
- let expected_results: Vec<&str> = vec!["2", "3"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_temporal_property_min() {
- let filter = NodeFilter.property("p40").temporal().min().is_in(vec![
- Prop::U64(5),
- Prop::U64(10),
- Prop::U64(20),
- ]);
- let expected_results: Vec<&str> = vec!["1", "2"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_temporal_property_max() {
- let filter = NodeFilter.property("p3").temporal().max().is_not_in(vec![
- Prop::U64(5),
- Prop::U64(10),
- Prop::U64(20),
- ]);
- let expected_results: Vec<&str> = vec!["3"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_nodes_for_temporal_property_len() {
- let filter = NodeFilter.property("p2").temporal().len().le(5u64);
- let expected_results: Vec<&str> = vec!["1", "2", "3", "4"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_nodes_window_filter() {
- let filter = NodeFilter
- .window(1, 3)
- .property("p2")
- .temporal()
- .sum()
- .ge(2u64);
-
- let expected_results = vec!["2"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- // Wider window includes node 3
- let filter = NodeFilter
- .window(1, 5)
- .property("p2")
- .temporal()
- .sum()
- .ge(2u64);
-
- let expected_results = vec!["2", "3"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_nodes_window_filter_on_non_temporal_property() {
- let filter1 = NodeFilter.window(1, 2).property("p1").eq("shivam_kapoor");
- let filter2 = NodeFilter
- .window(100, 200)
- .property("p1")
- .eq("shivam_kapoor");
-
- let expected_results = vec!["1"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter1.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter1.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let expected_results = vec![];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter2.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter2.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
-
- let filter = NodeFilter
- .window(100, 200)
- .property("p1")
- .eq("shivam_kapoor");
-
- let expected_results = vec!["1"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
-
- #[test]
- fn test_nodes_window_filter_any_all_over_window() {
- let filter = NodeFilter
- .window(3, 5)
- .property("p20")
- .temporal()
- .any()
- .eq("Gold_boat");
-
- let expected_results = vec!["4"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter
- .window(3, 5)
- .property("p20")
- .temporal()
- .all()
- .eq("Gold_boat");
-
- let expected_results = vec![];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_nodes_window_filter_and() {
- // Filters both node 1 and 3
- let filter1 = NodeFilter
- .window(1, 4)
- .property("p10")
- .temporal()
- .any()
- .eq("Paper_airplane");
-
- // Filters only node 3
- let filter2 = NodeFilter
- .window(3, 6)
- .property("p2")
- .temporal()
- .sum()
- .eq(6u64);
-
- let filter = filter1.and(filter2);
-
- let expected_results = vec!["3"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_nodes_at_filter() {
- // Only time=2 contributes; node 2 has p2=2 at t=2
- let filter = NodeFilter.at(2).property("p2").temporal().sum().eq(2u64);
-
- let expected_results = vec!["2"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- // Only time=3 contributes; node 3 has p2=6 at t=3
- let filter = NodeFilter.at(3).property("p2").temporal().sum().eq(6u64);
-
- let expected_results = vec!["3"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_nodes_after_filter() {
- // after(2) means t >= 3
- let filter = NodeFilter.after(2).property("p2").temporal().sum().ge(6u64);
-
- let expected_results = vec!["3"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_nodes_before_filter() {
- // before(3) means t <= 2
- let filter = NodeFilter
- .before(3)
- .property("p2")
- .temporal()
- .sum()
- .eq(2u64);
-
- let expected_results = vec!["2"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- // And node 3 shouldn't match, because its p2=6 lives at t=3.
- let filter = NodeFilter
- .before(3)
- .property("p2")
- .temporal()
- .sum()
- .eq(6u64);
-
- let expected_results = vec![];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_nodes_latest_filter() {
- // At latest time (currently t=4), only node 4 has p5=12
- let filter = NodeFilter.latest().property("p5").eq(12u64);
-
- let expected_results = vec!["4"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_nodes_snapshot_at_semantics_event_graph() {
- let t = 2;
-
- let filter_snapshot = NodeFilter.snapshot_at(t).property("p2").eq(2u64);
-
- let filter_before = NodeFilter.before(t + 1).property("p2").eq(2u64);
-
- let expected_results = vec!["2"];
-
- // snapshot_at
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter_snapshot.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter_snapshot,
- &expected_results,
- TestVariants::EventOnly,
- );
-
- // before(t+1)
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter_before.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter_before,
- &expected_results,
- TestVariants::EventOnly,
- );
- }
-
- #[test]
- fn test_nodes_snapshot_at_semantics_persistent_graph() {
- let t = 2;
-
- let filter_snapshot = NodeFilter.snapshot_at(t).property("p2").eq(2u64);
-
- let filter_at = NodeFilter.at(t).property("p2").eq(2u64);
-
- let expected_results = vec!["2"];
-
- // snapshot_at
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter_snapshot.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter_snapshot,
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- // at(t)
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter_at.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter_at,
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
-
- #[test]
- fn test_nodes_snapshot_latest_semantics_event_graph() {
- let filter_snapshot_latest = NodeFilter
- .snapshot_latest()
- .property("p2")
- .temporal()
- .sum()
- .ge(2u64);
-
- let filter_noop = NodeFilter.property("p2").temporal().sum().ge(2u64);
-
- // From your earlier window test, "2" and "3" are the ones with p2 values across time.
- // If your underlying dataset changes, adjust this accordingly.
- let expected_results = vec!["2", "3"];
-
- // snapshot_latest
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter_snapshot_latest.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter_snapshot_latest,
- &expected_results,
- TestVariants::EventOnly,
- );
-
- // no-op baseline
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter_noop.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter_noop,
- &expected_results,
- TestVariants::EventOnly,
- );
- }
-
- #[test]
- fn test_nodes_snapshot_latest_semantics_persistent_graph() {
- let filter_snapshot_latest = NodeFilter
- .snapshot_latest()
- .property("p1")
- .eq("shivam_kapoor");
-
- let filter_latest = NodeFilter.latest().property("p1").eq("shivam_kapoor");
-
- let expected_results = vec!["1"];
-
- // snapshot_latest
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter_snapshot_latest.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter_snapshot_latest,
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- // latest
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter_latest.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter_latest,
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
-
- #[test]
- #[ignore] // TODO: Enable this when node layer is supported
- fn test_nodes_layer_filter() {
- let filter = NodeFilter
- .layer("_default")
- .property("p2")
- .temporal()
- .sum()
- .ge(2u64);
-
- let expected_results = vec!["2"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- #[ignore] // TODO: Enable this when node layer is supported
- fn test_nodes_layer_then_window_ordering() {
- // In layer "fire_nation" within window [1,4), node "1" matches p1 == "shivam_kapoor".
- let filter = NodeFilter
- .layer("fire_nation")
- .window(1, 4)
- .property("p1")
- .eq("shivam_kapoor");
-
- let expected_results = vec!["1"];
-
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- #[ignore] // TODO: Enable this when node layer is supported
- fn test_nodes_window_then_layer_ordering() {
- // Same semantics as above, but reversed chaining order.
- let filter = NodeFilter
- .window(1, 4)
- .layer("fire_nation")
- .property("p1")
- .eq("shivam_kapoor");
-
- let expected_results = vec!["1"];
-
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_graph_filter_window() {
- let filter: Windowed = GraphFilter.window(1, 2);
- let expected_results = vec!["1"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = GraphFilter.window(1, 3);
- let expected_results = vec!["1", "2"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = GraphFilter.window(4, 6);
- let expected_results = vec!["1", "2", "4"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
-
- let filter = GraphFilter.window(4, 6);
- let expected_results = vec!["1", "2", "3", "4"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
-
- #[test]
- #[ignore] // TODO: Enable this when node layer is supported
- fn test_graph_filter_layer() {
- let filter = GraphFilter.layer("fire_nation");
- let expected_results = vec!["1", "3"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = GraphFilter.layer("air_nomads");
- let expected_results = vec!["2"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- #[ignore] // TODO: Enable this when node layer is supported
- fn test_graph_filter_window_then_layer() {
- let filter = GraphFilter.window(1, 3).layer("fire_nation");
- let expected_results = vec!["1", "3"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = GraphFilter.window(4, 4).layer("air_nomads");
- let expected_results = vec!["2"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- #[ignore] // TODO: Enable this when node layer is supported
- fn test_graph_filter_layer_then_window() {
- let filter = GraphFilter.layer("fire_nation").window(1, 3);
- let expected_results = vec!["1", "3"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_graph_filter_at() {
- let filter = GraphFilter.at(1);
- let expected_results = vec!["1"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = GraphFilter.at(2);
- let expected_results = vec!["2"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
-
- let filter = GraphFilter.at(2);
- let expected_results = vec!["1", "2"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = GraphFilter.at(3);
- let expected_results = vec!["1", "2", "3", "4"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_graph_filter_after() {
- let filter = GraphFilter.after(3);
- let expected_results = vec!["1", "2", "4"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
-
- let filter = GraphFilter.after(3);
- let expected_results = vec!["1", "2", "3", "4"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
-
- #[test]
- fn test_graph_filter_before() {
- let filter = GraphFilter.before(2);
- let expected_results = vec!["1"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = GraphFilter.before(3);
- let expected_results = vec!["1", "2"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_graph_filter_snapshot_at() {
- let filter = GraphFilter.snapshot_at(1);
- let expected_results = vec!["1"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = GraphFilter.snapshot_at(3);
- let expected_results = vec!["1", "2", "3", "4"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = GraphFilter.snapshot_at(4);
- let expected_results = vec!["1", "2", "3", "4"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_graph_filter_snapshot_latest() {
- let filter = GraphFilter.snapshot_latest();
- let expected_results = vec!["1", "2", "3", "4"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_graph_filter_latest() {
- let filter = GraphFilter.latest();
- let expected_results = vec!["1", "2", "4"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
-
- let filter = GraphFilter.latest();
- let expected_results = vec!["1", "2", "3", "4"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
-}
-
-mod test_node_composite_filter {
- use raphtory_api::core::Direction;
-
- use crate::{init_edges_graph, init_nodes_graph, IdentityGraphTransformer};
- use raphtory::{
- db::graph::views::filter::model::{
- node_filter::ops::NodeFilterOps, property_filter::ops::PropertyFilterOps,
- ComposableFilter, PropertyFilterFactory, TryAsCompositeFilter,
- },
- prelude::NodeFilter,
- };
- use raphtory_tests::assertions::{
- assert_filter_neighbours_results, assert_filter_nodes_results, assert_search_nodes_results,
- TestVariants,
- };
-
- #[test]
- fn test_filter_nodes_by_props_added_at_different_times() {
- let filter = NodeFilter
- .property("p4")
- .eq("pometry")
- .and(NodeFilter.property("p5").eq(12u64));
- let expected_results = vec!["4"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_unique_results_from_composite_filters() {
- let filter = NodeFilter
- .property("p2")
- .ge(2u64)
- .and(NodeFilter.property("p2").ge(1u64));
- let expected_results = vec!["2", "3"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter
- .property("p2")
- .ge(2u64)
- .or(NodeFilter.property("p2").ge(5u64));
- let expected_results = vec!["2", "3"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_composite_filter_nodes() {
- let filter = NodeFilter
- .property("p2")
- .eq(2u64)
- .and(NodeFilter.property("p1").eq("kapoor"));
- let expected_results = Vec::<&str>::new();
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- let filter = filter.try_as_composite_node_filter().unwrap();
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter
- .property("p2")
- .eq(2u64)
- .or(NodeFilter.property("p1").eq("shivam_kapoor"));
- let expected_results = vec!["1", "2"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- let filter = filter.try_as_composite_node_filter().unwrap();
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter.property("p1").eq("pometry").or(NodeFilter
- .property("p2")
- .eq(6u64)
- .and(NodeFilter.property("p3").eq(1u64)));
- let expected_results = vec!["3"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- let filter = filter.try_as_composite_node_filter().unwrap();
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter::node_type()
- .eq("fire_nation")
- .and(NodeFilter.property("p1").eq("prop1"));
- let expected_results = Vec::<&str>::new();
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- let filter = filter.try_as_composite_node_filter().unwrap();
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter
- .property("p9")
- .eq(5u64)
- .and(NodeFilter.property("p1").eq("shivam_kapoor"));
- let expected_results = vec!["1"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- let filter = filter.try_as_composite_node_filter().unwrap();
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter::node_type()
- .eq("fire_nation")
- .and(NodeFilter.property("p1").eq("shivam_kapoor"));
- let expected_results = vec!["1"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- let filter = filter.try_as_composite_node_filter().unwrap();
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter::name()
- .eq("2")
- .and(NodeFilter.property("p2").eq(2u64));
- let expected_results = vec!["2"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- let filter = filter.try_as_composite_node_filter().unwrap();
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter::name()
- .eq("2")
- .and(NodeFilter.property("p2").eq(2u64))
- .or(NodeFilter.property("p9").eq(5u64));
- let expected_results = vec!["1", "2"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- let filter = filter.try_as_composite_node_filter().unwrap();
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_not_composite_filter_nodes() {
- let filter = NodeFilter::name()
- .eq("2")
- .and(NodeFilter.property("p2").eq(2u64))
- .or(NodeFilter.property("p9").eq(5u64))
- .not();
- let expected_results = vec!["3", "4"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = NodeFilter::name()
- .eq("2")
- .not()
- .and(NodeFilter.property("p2").eq(2u64))
- .or(NodeFilter.property("p9").eq(5u64));
- let expected_results = vec!["1"];
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_out_neighbours_filter() {
- let filter = NodeFilter::name()
- .eq("2")
- .and(NodeFilter.property("p2").eq(2u64));
- let expected_results = vec!["2"];
- assert_filter_neighbours_results(
- |graph| init_edges_graph(init_nodes_graph(graph)),
- IdentityGraphTransformer,
- "1",
- Direction::OUT,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_in_neighbours_filter() {
- let filter = NodeFilter.property("p9").ge(1u64);
- let expected_results = vec!["1"];
- assert_filter_neighbours_results(
- |graph| init_edges_graph(init_nodes_graph(graph)),
- IdentityGraphTransformer,
- "2",
- Direction::IN,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_neighbours_filter() {
- let filter = NodeFilter.property("p10").contains("Paper");
- let expected_results = vec!["1", "3"];
- assert_filter_neighbours_results(
- |graph| init_edges_graph(init_nodes_graph(graph)),
- IdentityGraphTransformer,
- "2",
- Direction::BOTH,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-}
-
-mod test_node_property_filter_agg {
- use crate::IdentityGraphTransformer;
- use raphtory::{
- db::{
- api::view::StaticGraphViewOps,
- graph::views::filter::{
- model::{
- node_filter::NodeFilter,
- property_filter::ops::{ElemQualifierOps, ListAggOps, PropertyFilterOps},
- PropertyFilterFactory, TemporalPropertyFilterFactory, TryAsCompositeFilter,
- },
- CreateFilter,
- },
- },
- prelude::{AdditionOps, GraphViewOps, PropertyAdditionOps},
- };
- use raphtory_api::core::{
- entities::properties::prop::{IntoProp, Prop},
- storage::arc_str::ArcStr,
- };
- use raphtory_storage::mutation::{
- addition_ops::InternalAdditionOps, property_addition_ops::InternalPropertyAdditionOps,
- };
- use raphtory_tests::assertions::{
- assert_filter_nodes_err, assert_filter_nodes_results, assert_search_nodes_results,
- TestVariants::All,
- };
-
- fn list_u8(xs: &[u8]) -> Prop {
- Prop::list(xs.iter().copied().map(Prop::U8))
- }
- fn list_u16(xs: &[u16]) -> Prop {
- Prop::list(xs.iter().copied().map(Prop::U16))
- }
- fn list_u32(xs: &[u32]) -> Prop {
- Prop::list(xs.iter().copied().map(Prop::U32))
- }
- fn list_u64(xs: &[u64]) -> Prop {
- Prop::list(xs.iter().copied().map(Prop::U64))
- }
- fn list_i32(xs: &[i32]) -> Prop {
- Prop::list(xs.iter().copied().map(Prop::I32))
- }
- fn list_i64(xs: &[i64]) -> Prop {
- Prop::list(xs.iter().copied().map(Prop::I64))
- }
- fn list_f32(xs: &[f32]) -> Prop {
- Prop::list(xs.iter().copied().map(Prop::F32))
- }
- fn list_f64(xs: &[f64]) -> Prop {
- Prop::list(xs.iter().copied().map(Prop::F64))
- }
- fn list_str(xs: &[&str]) -> Prop {
- Prop::list(xs.iter().map(|s| Prop::Str(ArcStr::from(*s))))
- }
- fn list_bool(xs: &[bool]) -> Prop {
- Prop::list(xs.iter().copied().map(Prop::Bool))
- }
-
- #[inline]
- fn list(v: Vec) -> Prop {
- Prop::List(v.into())
- }
-
- /// Writes a set of node temporal properties and node metadata to the given graph.
- pub fn init_nodes_graph<
- G: StaticGraphViewOps
- + AdditionOps
- + InternalAdditionOps
- + InternalPropertyAdditionOps
- + PropertyAdditionOps,
- >(
- graph: G,
- ) -> G {
- // Each tuple represents (timestamp, node_name, properties).
- let nodes: [(i64, &str, Vec<(&str, Prop)>); 12] = [
- (
- 1,
- "n1",
- vec![
- ("p_strs", list_str(&["a", "b", "c"])), // min: None, max: None, sum: None, avg: None, len: 3
- ("p_bools", list_bool(&[true, false])), // min: None, max: None, sum: None, avg: None, len: 2
- ("p_u8s", list_u8(&[1, 2, 3])), // min: 1, max: 3, sum: 6, avg: 2.0, len: 3
- ("p_u8s_max", list_u8(&[u8::MAX, u8::MAX])), // min: u8::MAX, max: u8::MAX, sum: 510
- ("p_u16s", list_u16(&[1, 2, 3])), // min: 1, max: 3, sum: 6, avg: 2.0, len: 3
- ("p_u16s_max", list_u16(&[u16::MAX, u16::MAX])), // min: u16::MAX, max: u16::MAX, sum: 131070
- ("p_u32s", list_u32(&[1, 2, 3])), // min: 1, max: 3, sum: 6, avg: 2.0, len: 3
- ("p_u32s_max", list_u32(&[u32::MAX, u32::MAX])), // min: 1, max: 3, sum: 8589934590
- ("p_u64s", list_u64(&[1, 2, 3])), // min: 1, max: 3, sum: 6, avg: 2.0, len: 3
- ("p_u64s_max", list_u64(&[u64::MAX, u64::MAX])), // min: 1, max: 3, sum: OVERFLOW
- ("p_i32s", list_i32(&[1, 2, 3])), // min: 1, max: 3, sum: 6, avg: 2.0, len: 3
- ("p_i64s", list_i64(&[1, 2, 3])), // min: 1, max: 3, sum: 6, avg: 2.0, len: 3
- ("p_f32s", list_f32(&[1.0, 2.0, 3.5])), // min: 1.0, max: 3.5, sum: 6.5, avg: 2.1666666666666665, len: 3
- ("p_f64s", list_f64(&[50.0, 40.0])), // min: 40.0, max: 50.0, sum: 90.0, avg: 45.0, len: 2
- (
- "nested_list",
- list(vec![
- list(vec![
- list(vec![
- list(vec![50.0.into_prop(), 40.0.into_prop()]),
- list(vec![60.0.into_prop()]),
- ]),
- list(vec![list(vec![46.0.into_prop()])]),
- ]),
- list(vec![list(vec![list(vec![90.0.into_prop()])])]),
- ]),
- ),
- ],
- ),
- (
- 2,
- "n1",
- vec![
- ("p_strs", list_str(&["a", "b", "c", "d"])), // min: None, max: None, sum: None, avg: None, len: 4
- ("p_bools", list_bool(&[true, true])), // min: None, max: None, sum: None, avg: None, len: 2
- ("p_u8s", list_u8(&[1, 2, 3, 4])), // min: 1, max: 4, sum: 10, avg: 2.5, len: 4
- ("p_u16s", list_u16(&[1, 2, 3, 4])), // min: 1, max: 4, sum: 10, avg: 2.5, len: 4
- ("p_u32s", list_u32(&[1, 2, 3, 4])), // min: 1, max: 4, sum: 10, avg: 2.5, len: 4
- ("p_u64s", list_u64(&[1, 2, 3, 4])), // min: 1, max: 4, sum: 10, avg: 2.5, len: 4
- ("p_i32s", list_i32(&[1, 2, 3, 4])), // min: 1, max: 4, sum: 10, avg: 2.5, len: 4
- ("p_i64s", list_i64(&[1, 2, 3, 4])), // min: 1, max: 4, sum: 10, avg: 2.5, len: 4
- ("p_f32s", list_f32(&[1.0, 2.0, 3.5, 4.5])), // min: 1.0, max: 4.5, sum: 11.0, avg: 2.75, len: 4
- ("p_f64s", list_f64(&[30.0, 50.0, 40.0])), // min: 30.0, max: 50.0, sum: 120.0, avg: 40.0, len: 3
- ],
- ),
- (
- 1,
- "n2",
- vec![
- ("p_strs", list_str(&["a", "b", "c", "d"])), // min: None, max: None, sum: None, avg: None, len: 4
- ("p_u64s", list_u64(&[1, 2, 3, 4])), // min: 1, max: 4, sum: 10, avg: 2.5, len: 4
- ("p_f64s", list_f64(&[30.0, 50.0, 40.0])), // min: 30.0, max: 50.0, sum: 120.0, avg: 40.0, len: 3
- ("p_bools", list_bool(&[false, false])),
- ],
- ),
- (
- 2,
- "n2",
- vec![
- ("p_strs", list_str(&["a", "b", "c", "d"])), // min: None, max: None, sum: None, avg: None, len: 4
- ("p_u64s", list_u64(&[1, 2, 3, 4])), // min: 1, max: 4, sum: 10, avg: 2.5, len: 4
- ("p_f64s", list_f64(&[30.0, 50.0, 40.0])), // min: 30.0, max: 50.0, sum: 120.0, avg: 40.0, len: 3
- ],
- ),
- (
- 1,
- "n3",
- vec![
- ("p_strs", list_str(&["a", "b", "c"])), // min: None, max: None, sum: None, avg: None, len: 3
- ("p_bools", list_bool(&[true, false])), // min: None, max: None, sum: None, avg: None, len: 2
- ("p_u8s", list_u8(&[1, 1, 4])), // min: 1, max: 4, sum: 6, avg: 2.0, len: 3
- ("p_u16s", list_u16(&[1, 0, 5])), // min: 0, max: 5, sum: 6, avg: 2.0, len: 3
- ("p_u32s", list_u32(&[2, 2, 2])), // min: 2, max: 2, sum: 6, avg: 2.0, len: 3
- ("p_u64s", list_u64(&[0, 3, 3])), // min: 0, max: 3, sum: 6, avg: 2.0, len: 3
- ("p_i32s", list_i32(&[-1, 4, 3])), // min: -1, max: 4, sum: 6, avg: 2.0, len: 3
- ("p_i64s", list_i64(&[0, 3, -3])), // min: -3, max: 3, sum: 0, avg: 0.0, len: 3
- ("p_f32s", list_f32(&[1.0, 2.5, 3.0])), // min: 1.0, max: 3.0, sum: 6.5, avg: 2.1666666666666665, len: 3
- ("p_f64s", list_f64(&[30.0, 60.0])), // min: 30.0, max: 60.0, sum: 90.0, avg: 45.0, len: 2
- (
- "nested_list",
- list(vec![
- list(vec![
- list(vec![
- list(vec![50.0.into_prop(), 40.0.into_prop()]),
- list(vec![60.0.into_prop()]),
- ]),
- list(vec![list(vec![46.0.into_prop()])]),
- ]),
- list(vec![list(vec![list(vec![90.0.into_prop()])])]),
- ]),
- ),
- ],
- ),
- (
- 2,
- "n3",
- vec![
- ("p_strs", list_str(&["a", "b", "c"])), // min: None, max: None, sum: None, avg: None, len: 3
- ("p_bools", list_bool(&[true, false])), // min: None, max: None, sum: None, avg: None, len: 2
- ("p_u8s", list_u8(&[1, 2, 3])), // min: 1, max: 3, sum: 6, avg: 2.0, len: 3
- ("p_u16s", list_u16(&[1, 2, 3])), // min: 1, max: 3, sum: 6, avg: 2.0, len: 3
- ("p_u32s", list_u32(&[1, 2, 3])), // min: 1, max: 3, sum: 6, avg: 2.0, len: 3
- ("p_u64s", list_u64(&[1, 2, 3])), // min: 1, max: 3, sum: 6, avg: 2.0, len: 3
- ("p_i32s", list_i32(&[1, 2, 3])), // min: 1, max: 3, sum: 6, avg: 2.0, len: 3
- ("p_i64s", list_i64(&[1, 2, -3])), // min: -3, max: 2, sum: 0, avg: 0.0, len: 3
- ("p_f32s", list_f32(&[1.0, 2.0, 3.5])), // min: 1.0, max: 3.5, sum: 6.5, avg: 2.1666666666666665, len: 3
- ("p_f64s", list_f64(&[50.0, 40.0])), // min: 40.0, max: 50.0, sum: 90.0, avg: 45.0, len: 2
- (
- "nested_list",
- list(vec![
- list(vec![
- list(vec![
- list(vec![50.0.into_prop(), 40.0.into_prop()]),
- list(vec![60.0.into_prop()]),
- ]),
- list(vec![list(vec![46.0.into_prop()])]),
- ]),
- list(vec![list(vec![list(vec![90.0.into_prop()])])]),
- ]),
- ),
- ],
- ),
- (
- 1,
- "n4",
- vec![
- ("p_strs", list_str(&["a", "b", "c"])), // min: None, max: None, sum: None, avg: None, len: 3
- ("p_bools", list_bool(&[true, false])), // min: None, max: None, sum: None, avg: None, len: 2
- ("p_u64s", list_u64(&[1, 2, 3])), // min: 1, max: 3, sum: 6, avg: 2.0, len: 3
- ("p_i32s", list_i32(&[1, 2, 3])), // min: 1, max: 3, sum: 6, avg: 2.0, len: 3
- ("p_f32s", list_f32(&[1.0, 2.0, 3.5])), // min: 1.0, max: 3.5, sum: 6.5, avg: 2.1666666666666665, len: 3
- ("p_bools_all", list_bool(&[true, true])),
- ],
- ),
- (
- 2,
- "n4",
- vec![
- ("p_strs", list_str(&["x", "y", "z"])), // min: None, max: None, sum: None, avg: None, len: 3
- ("p_bools", list_bool(&[false, false])), // min: None, max: None, sum: None, avg: None, len: 2
- ("p_u64s", list_u64(&[10, 20, 30])), // min: 10, max: 30, sum: 60, avg: 20.0, len: 3
- ("p_i32s", list_i32(&[10, 20, 30])), // min: 10, max: 30, sum: 60, avg: 20.0, len: 3
- ("p_f32s", list_f32(&[10.0, 20.0, 30.0])), // min: 10.0, max: 30.0, sum: 60.0, avg: 20.0, len: 3
- ("p_bools_all", list_bool(&[true, true])),
- ],
- ),
- (
- 2,
- "n5",
- vec![
- ("p_u64s", list_u64(&[u64::MAX, 1])), // min: 1, max: u64::MAX, sum: None (overflow), avg: 9223372036854775808.0, len: 2
- ("p_u64s_max", list_u64(&[u64::MAX, 1])), // min: 1, max: u64::MAX, sum: None (overflow), avg: 9223372036854775808.0, len: 2
- ("p_u64s_min", list_u64(&[u64::MIN, 1])), // min: 1, max: u64::MAX, sum: None (overflow), avg: 9223372036854775808.0, len: 2
- ("p_i64s", list_i64(&[i64::MAX, 1])), // min: 1, max: i64::MAX, sum: None (overflow), avg: 4611686018427387904.0, len: 2
- ("p_i64s_max", list_i64(&[i64::MAX, 1])), // min: 1, max: i64::MAX, sum: None (overflow), avg: 4611686018427387904.0, len: 2
- ("p_i64s_min", list_i64(&[i64::MIN, 1])), // min: 1, max: i64::MAX, sum: None (overflow), avg: 4611686018427387904.0, len: 2
- ],
- ),
- (
- 2,
- "n6",
- vec![
- ("p_i32s", list_i32(&[-2, 1, 3])), // min: -2, max: 3, sum: 2, avg: 0.6666666666666666, len: 3
- ],
- ),
- (
- 1,
- "n7",
- vec![
- ("p_u64s", list_u64(&[])), // min: None, max: None, sum: None, avg: None, len: 0
- ],
- ),
- (
- 2,
- "n10",
- vec![
- ("p_strs", list_str(&["a", "b", "c"])), // min: None, max: None, sum: None, avg: None, len: 3
- ("p_bools", list_bool(&[true, false])), // min: None, max: None, sum: None, avg: None, len: 2
- ("p_u8s", list_u8(&[1, 2, 3])), // min: 1, max: 3, sum: 6, avg: 2.0, len: 3
- ("p_u16s", list_u16(&[1, 2, 3])), // min: 1, max: 3, sum: 6, avg: 2.0, len: 3
- ("p_u32s", list_u32(&[1, 2, 3])), // min: 1, max: 3, sum: 6, avg: 2.0, len: 3
- ("p_u64s", list_u64(&[1, 2, 3])), // min: 1, max: 3, sum: 6, avg: 2.0, len: 3
- ("p_i32s", list_i32(&[1, 2, 3])), // min: 1, max: 3, sum: 6, avg: 2.0, len: 3
- ("p_i64s", list_i64(&[1, 2, -3])), // min: -3, max: 2, sum: 0, avg: 0.0, len: 3
- ("p_f32s", list_f32(&[1.0, 2.0, 3.5])), // min: 1.0, max: 3.5, sum: 6.5, avg: 2.1666666666666665, len: 3
- ("p_f64s", list_f64(&[50.0, 40.0])), // min: 40.0, max: 50.0, sum: 90.0, avg: 45.0, len: 2
- ("p_bools_all", list_bool(&[true, true])),
- ],
- ),
- ];
-
- for (t, id, props) in nodes {
- graph.add_node(t, id, props, None, None).unwrap();
- }
-
- // Each tuple represents (node_name, properties).
- let metadata: [(&str, Vec<(&str, Prop)>); 8] = [
- (
- "n1",
- vec![
- ("p_u8s", list_u8(&[2, 9])), // min: 2, max: 9, sum: 11, avg: 5.5, len: 2
- ("p_u16s", list_u16(&[3, 5])), // min: 3, max: 5, sum: 8, avg: 4.0, len: 2
- ("p_u32s", list_u32(&[4, 9])), // min: 4, max: 9, sum: 13, avg: 6.5, len: 2
- ],
- ),
- (
- "n2",
- vec![
- ("p_u64s", list_u64(&[2, 3, 7])), // min: 2, max: 7, sum: 12, avg: 4.0, len: 3
- ],
- ),
- (
- "n3",
- vec![
- ("p_i32s", list_i32(&[10, 2, -3])), // min: -3, max: 10, sum: 9, avg: 3.0, len: 3
- ("p_i64s", list_i64(&[1, 12, 3, 4])), // min: 1, max: 12, sum: 20, avg: 5.0, len: 4
- ],
- ),
- (
- "n4",
- vec![
- ("p_f32s", list_f32(&[1.5, 2.5])), // min: 1.5, max: 2.5, sum: 4.0, avg: 2.0, len: 2
- ("p_f64s", list_f64(&[0.5, 1.5])), // min: 0.5, max: 1.5, sum: 2.0, avg: 1.0, len: 2
- ],
- ),
- (
- "n5",
- vec![
- ("p_strs", list_str(&["m1", "m2", "m3"])), // min: None, max: None, sum: None, avg: None, len: 3
- ],
- ),
- (
- "n6",
- vec![
- ("p_u64s", list_u64(&[])), // min: None, max: None, sum: None, avg: None, len: 0
- ("p_strs", list_str(&["a", "a"])),
- ],
- ),
- (
- "n7",
- vec![
- ("p_u64s", list_u64(&[u64::MAX, 1])), // min: 1, max: u64::MAX, sum: None (overflow), avg: ~9.22e18, len: 2
- ("p_strs", list_str(&["a"])),
- ],
- ),
- (
- "n10",
- vec![
- ("p_u64s", list_u64(&[1, 2, 3])), // min: 1, max: 3, sum: 6, avg: 2.0, len: 3
- ("p_strs", list_str(&["a", "b", "c"])), // min: None, max: None, sum: None, avg: None, len: 3
- ],
- ),
- ];
-
- for (node_id, md) in metadata {
- graph.node(node_id).unwrap().add_metadata(md).unwrap();
- }
-
- graph
- }
-
- fn apply_assertion(
- filter: impl TryAsCompositeFilter + CreateFilter + Clone,
- expected: &[&str],
- ) {
- assert_filter_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected,
- All,
- );
-
- assert_search_nodes_results(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter,
- &expected,
- All,
- );
- }
-
- fn apply_assertion_err(
- filter: impl TryAsCompositeFilter + CreateFilter + Clone,
- expected: &str,
- ) {
- assert_filter_nodes_err(
- init_nodes_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected,
- All,
- );
-
- // assert_search_nodes_err(
- // init_nodes_graph,
- // IdentityGraphTransformer,
- // filter,
- // expected,
- // All,
- // );
- }
-
- // ------ Property: SUM ----
- #[test]
- fn test_node_property_sum_u8s() {
- let filter = NodeFilter.property("p_u8s").sum().eq(Prop::U64(10));
- let expected = vec!["n1"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_sum_u16s() {
- let filter = NodeFilter.property("p_u16s").sum().eq(Prop::U64(6));
- let expected = vec!["n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_sum_u32s() {
- let filter = NodeFilter.property("p_u32s").sum().eq(Prop::U64(10));
- let expected = vec!["n1"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_sum_u64s() {
- let filter = NodeFilter.property("p_u64s").sum().eq(Prop::U64(6));
- let expected = vec!["n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_sum_i32s() {
- let filter = NodeFilter.property("p_i32s").sum().eq(Prop::I64(2));
- let expected = vec!["n6"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_sum_i64s() {
- let filter = NodeFilter.property("p_i64s").sum().eq(Prop::I64(0));
- let expected = vec!["n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_sum_f32s() {
- let filter = NodeFilter.property("p_f32s").sum().eq(Prop::F64(6.5));
- let expected = vec!["n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_sum_f64s() {
- let filter = NodeFilter.property("p_f64s").sum().eq(Prop::F64(120.0));
- let expected = vec!["n1", "n2"];
- apply_assertion(filter, &expected);
- }
-
- // ------ Property: AVG ----
- #[test]
- fn test_node_property_avg_u8s() {
- let filter = NodeFilter.property("p_u8s").avg().eq(Prop::F64(2.5));
- let expected = vec!["n1"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_avg_u16s() {
- let filter = NodeFilter.property("p_u16s").avg().eq(Prop::F64(2.0));
- let expected = vec!["n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_avg_u32s() {
- let filter = NodeFilter.property("p_u32s").avg().eq(Prop::F64(2.5));
- let expected = vec!["n1"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_avg_u64s() {
- let filter = NodeFilter.property("p_u64s").avg().eq(Prop::F64(2.0));
- let expected = vec!["n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_avg_i32s() {
- let filter = NodeFilter
- .property("p_i32s")
- .avg()
- .eq(Prop::F64(0.6666666666666666));
- let expected = vec!["n6"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_avg_i64s() {
- let filter = NodeFilter.property("p_i64s").avg().eq(Prop::F64(0.0));
- let expected = vec!["n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_avg_f32s() {
- let filter = NodeFilter
- .property("p_f32s")
- .avg()
- .eq(Prop::F64(2.1666666666666665));
- let expected = vec!["n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_avg_f64s() {
- let filter = NodeFilter.property("p_f64s").avg().eq(Prop::F64(40.0));
- let expected = vec!["n1", "n2"];
- apply_assertion(filter, &expected);
- }
-
- // ------ Property: LEN ------
- #[test]
- fn test_node_property_len_u8s() {
- let filter = NodeFilter.property("p_u8s").len().eq(Prop::U64(4));
- let expected = vec!["n1"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_len_u16s() {
- let filter = NodeFilter.property("p_u16s").len().eq(Prop::U64(3));
- let expected = vec!["n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_len_u32s() {
- let filter = NodeFilter.property("p_u32s").len().eq(Prop::U64(4));
- let expected = vec!["n1"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_len_u64s() {
- let filter = NodeFilter.property("p_u64s").len().eq(Prop::U64(3));
- let expected = vec!["n10", "n3", "n4"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_len_i32s() {
- let filter = NodeFilter.property("p_i32s").len().eq(Prop::U64(3));
- let expected = vec!["n10", "n3", "n4", "n6"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_len_i64s() {
- let filter = NodeFilter.property("p_i64s").len().eq(Prop::U64(3));
- let expected = vec!["n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_len_f32s() {
- let filter = NodeFilter.property("p_f32s").len().eq(Prop::U64(3));
- let expected = vec!["n10", "n3", "n4"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_len_f64s() {
- let filter = NodeFilter.property("p_f64s").len().eq(Prop::U64(3));
- let expected = vec!["n1", "n2"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_len_strs() {
- let filter = NodeFilter.property("p_strs").len().eq(Prop::U64(3));
- let expected = vec!["n10", "n3", "n4"];
- apply_assertion(filter, &expected);
- }
-
- // ------ Property: MIN ------
- #[test]
- fn test_node_property_min_u8s() {
- let filter = NodeFilter.property("p_u8s").min().eq(Prop::U8(1));
- let expected = vec!["n1", "n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_min_u16s() {
- let filter = NodeFilter.property("p_u16s").min().eq(Prop::U16(1));
- let expected = vec!["n1", "n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_min_u32s() {
- let filter = NodeFilter.property("p_u32s").min().eq(Prop::U32(1));
- let expected = vec!["n1", "n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_min_u64s() {
- let filter = NodeFilter.property("p_u64s").min().eq(Prop::U64(1));
- let expected = vec!["n1", "n10", "n2", "n3", "n5"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_min_i32s() {
- let filter = NodeFilter.property("p_i32s").min().eq(Prop::I32(-2));
- let expected = vec!["n6"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_min_i64s() {
- let filter = NodeFilter.property("p_i64s").min().eq(Prop::I64(-3));
- let expected = vec!["n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_min_f32s() {
- let filter = NodeFilter.property("p_f32s").min().eq(Prop::F32(10.0));
- let expected = vec!["n4"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_min_f64s() {
- let filter = NodeFilter.property("p_f64s").min().eq(Prop::F64(40.0));
- let expected = vec!["n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- // ------ Property: MAX ------
- #[test]
- fn test_node_property_max_u8s() {
- let filter = NodeFilter.property("p_u8s").max().eq(Prop::U8(4));
- let expected = vec!["n1"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_max_u16s() {
- let filter = NodeFilter.property("p_u16s").max().eq(Prop::U16(3));
- let expected = vec!["n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_max_u32s() {
- let filter = NodeFilter.property("p_u32s").max().eq(Prop::U32(4));
- let expected = vec!["n1"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_max_u64s() {
- let filter = NodeFilter.property("p_u64s").max().eq(Prop::U64(3));
- let expected = vec!["n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_max_i32s() {
- let filter = NodeFilter.property("p_i32s").max().eq(Prop::I32(3));
- let expected = vec!["n10", "n3", "n6"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_max_i64s() {
- let filter = NodeFilter.property("p_i64s").max().eq(Prop::I64(2));
- let expected = vec!["n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_max_f32s() {
- let filter = NodeFilter.property("p_f32s").max().eq(Prop::F32(30.0));
- let expected = vec!["n4"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_max_f64s() {
- let filter = NodeFilter.property("p_f64s").max().eq(Prop::F64(50.0));
- let expected = vec!["n1", "n10", "n2", "n3"];
- apply_assertion(filter, &expected);
- }
-
- // ------ Metadata: SUM ------
- #[test]
- fn test_node_property_metadata_sum_u8s() {
- let filter = NodeFilter.metadata("p_u8s").sum().eq(Prop::U64(11));
- let expected = vec!["n1"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_metadata_sum_u16s() {
- let filter = NodeFilter.metadata("p_u16s").sum().eq(Prop::U64(8));
- let expected = vec!["n1"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_metadata_sum_u32s() {
- let filter = NodeFilter.metadata("p_u32s").sum().eq(Prop::U64(13));
- let expected = vec!["n1"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_metadata_sum_u64s() {
- let filter = NodeFilter.metadata("p_u64s").sum().eq(Prop::U64(12));
- let expected = vec!["n2"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_metadata_sum_i32s() {
- let filter = NodeFilter.metadata("p_i32s").sum().eq(Prop::I64(9));
- let expected = vec!["n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_metadata_sum_i64s() {
- let filter = NodeFilter.metadata("p_i64s").sum().eq(Prop::I64(20));
- let expected = vec!["n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_metadata_sum_f32s() {
- let filter = NodeFilter.metadata("p_f32s").sum().eq(Prop::F64(4.0));
- let expected = vec!["n4"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_metadata_sum_f64s() {
- let filter = NodeFilter.metadata("p_f64s").sum().eq(Prop::F64(2.0));
- let expected = vec!["n4"];
- apply_assertion(filter, &expected);
- }
-
- // ------ Metadata: AVG ------
- #[test]
- fn test_node_property_metadata_avg_u8s() {
- let filter = NodeFilter.metadata("p_u8s").avg().eq(Prop::F64(5.5));
- let expected = vec!["n1"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_metadata_avg_u16s() {
- let filter = NodeFilter.metadata("p_u16s").avg().eq(Prop::F64(4.0));
- let expected = vec!["n1"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_metadata_avg_u32s() {
- let filter = NodeFilter.metadata("p_u32s").avg().eq(Prop::F64(6.5));
- let expected = vec!["n1"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_metadata_avg_u64s() {
- let filter = NodeFilter.metadata("p_u64s").avg().eq(Prop::F64(4.0));
- let expected = vec!["n2"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_metadata_avg_i32s() {
- let filter = NodeFilter.metadata("p_i32s").avg().eq(Prop::F64(3.0));
- let expected = vec!["n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_metadata_avg_i64s() {
- let filter = NodeFilter.metadata("p_i64s").avg().eq(Prop::F64(5.0));
- let expected = vec!["n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_metadata_avg_f32s() {
- let filter = NodeFilter.metadata("p_f32s").avg().eq(Prop::F64(2.0));
- let expected = vec!["n4"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_metadata_avg_f64s() {
- let filter = NodeFilter.metadata("p_f64s").avg().eq(Prop::F64(1.0));
- let expected = vec!["n4"];
- apply_assertion(filter, &expected);
- }
-
- // ------ Metadata: MIN ------
- #[test]
- fn test_node_property_metadata_min_u8s() {
- let filter = NodeFilter.metadata("p_u8s").min().eq(Prop::U8(2));
- let expected = vec!["n1"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_metadata_min_u16s() {
- let filter = NodeFilter.metadata("p_u16s").min().eq(Prop::U16(3));
- let expected = vec!["n1"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_metadata_min_u32s() {
- let filter = NodeFilter.metadata("p_u32s").min().eq(Prop::U32(4));
- let expected = vec!["n1"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_metadata_min_u64s() {
- let filter = NodeFilter.metadata("p_u64s").min().eq(Prop::U64(2));
- let expected = vec!["n2"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_metadata_min_i32s() {
- let filter = NodeFilter.metadata("p_i32s").min().eq(Prop::I32(-3));
- let expected = vec!["n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_metadata_min_i64s() {
- let filter = NodeFilter.metadata("p_i64s").min().eq(Prop::I64(1));
- let expected = vec!["n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_metadata_min_f32s() {
- let filter = NodeFilter.metadata("p_f32s").min().eq(Prop::F32(1.5));
- let expected = vec!["n4"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_metadata_min_f64s() {
- let filter = NodeFilter.metadata("p_f64s").min().eq(Prop::F64(0.5));
- let expected = vec!["n4"];
- apply_assertion(filter, &expected);
- }
-
- // ------ Metadata: MAX ------
- #[test]
- fn test_node_property_metadata_max_u8s() {
- let filter = NodeFilter.metadata("p_u8s").max().eq(Prop::U8(9));
- let expected = vec!["n1"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_metadata_max_u16s() {
- let filter = NodeFilter.metadata("p_u16s").max().eq(Prop::U16(5));
- let expected = vec!["n1"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_metadata_max_u32s() {
- let filter = NodeFilter.metadata("p_u32s").max().eq(Prop::U32(9));
- let expected = vec!["n1"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_metadata_max_u64s() {
- let filter = NodeFilter.metadata("p_u64s").max().eq(Prop::U64(7));
- let expected = vec!["n2"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_metadata_max_i32s() {
- let filter = NodeFilter.metadata("p_i32s").max().eq(Prop::I32(10));
- let expected = vec!["n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_metadata_max_i64s() {
- let filter = NodeFilter.metadata("p_i64s").max().eq(Prop::I64(12));
- let expected = vec!["n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_metadata_max_f32s() {
- let filter = NodeFilter.metadata("p_f32s").max().eq(Prop::F32(2.5));
- let expected = vec!["n4"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_metadata_max_f64s() {
- let filter = NodeFilter.metadata("p_f64s").max().eq(Prop::F64(1.5));
- let expected = vec!["n4"];
- apply_assertion(filter, &expected);
- }
-
- // ------ Metadata: Len ------
- #[test]
- fn test_node_property_metadata_len_u8s() {
- let filter = NodeFilter.metadata("p_u8s").len().eq(Prop::U64(2));
- let expected = vec!["n1"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_metadata_len_u16s() {
- let filter = NodeFilter.metadata("p_u16s").len().eq(Prop::U64(2));
- let expected = vec!["n1"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_metadata_len_u32s() {
- let filter = NodeFilter.metadata("p_u32s").len().eq(Prop::U64(2));
- let expected = vec!["n1"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_metadata_len_u64s() {
- let filter = NodeFilter.metadata("p_u64s").len().eq(Prop::U64(3));
- let expected = vec!["n10", "n2"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_metadata_len_i32s() {
- let filter = NodeFilter.metadata("p_i32s").len().eq(Prop::U64(3));
- let expected = vec!["n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_metadata_len_i64s() {
- let filter = NodeFilter.metadata("p_i64s").len().eq(Prop::U64(4));
- let expected = vec!["n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_metadata_len_f32s() {
- let filter = NodeFilter.metadata("p_f32s").len().eq(Prop::U64(2));
- let expected = vec!["n4"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_metadata_len_f64s() {
- let filter = NodeFilter.metadata("p_f64s").len().eq(Prop::U64(2));
- let expected = vec!["n4"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_metadata_len_strs() {
- let filter = NodeFilter.metadata("p_strs").len().eq(Prop::U64(3));
- let expected = vec!["n10", "n5"];
- apply_assertion(filter, &expected);
- }
-
- // ------ Temporal last: SUM ------
- #[test]
- fn test_node_property_temporal_last_sum_u8s() {
- let filter = NodeFilter
- .property("p_u8s")
- .temporal()
- .last()
- .sum()
- .eq(Prop::U64(10));
- let expected = vec!["n1"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_last_sum_u16s() {
- let filter = NodeFilter
- .property("p_u16s")
- .temporal()
- .last()
- .sum()
- .eq(Prop::U64(6));
- let expected = vec!["n3", "n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_last_sum_u32s() {
- let filter = NodeFilter
- .property("p_u32s")
- .temporal()
- .last()
- .sum()
- .eq(Prop::U64(10));
- let expected = vec!["n1"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_last_sum_u64s() {
- let filter = NodeFilter
- .property("p_u64s")
- .temporal()
- .last()
- .sum()
- .eq(Prop::U64(60));
- let expected = vec!["n4"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_last_sum_i32s() {
- let filter = NodeFilter
- .property("p_i32s")
- .temporal()
- .last()
- .sum()
- .eq(Prop::I64(60));
- let expected = vec!["n4"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_last_sum_i64s() {
- let filter = NodeFilter
- .property("p_i64s")
- .temporal()
- .last()
- .sum()
- .eq(Prop::I64(0));
- let expected = vec!["n3", "n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_last_sum_f32s() {
- let filter = NodeFilter
- .property("p_f32s")
- .temporal()
- .last()
- .sum()
- .eq(Prop::F64(6.5));
- let expected = vec!["n3", "n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_last_sum_f64s() {
- let filter = NodeFilter
- .property("p_f64s")
- .temporal()
- .last()
- .sum()
- .eq(Prop::F64(90.0));
- let expected = vec!["n3", "n10"];
- apply_assertion(filter, &expected);
- }
-
- // ------ Temporal last: AVG ------
- #[test]
- fn test_node_property_temporal_last_avg_u8s() {
- let filter = NodeFilter
- .property("p_u8s")
- .temporal()
- .last()
- .avg()
- .eq(Prop::F64(2.5));
- let expected = vec!["n1"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_last_avg_u16s() {
- let filter = NodeFilter
- .property("p_u16s")
- .temporal()
- .last()
- .avg()
- .eq(Prop::F64(2.0));
- let expected = vec!["n3", "n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_last_avg_u32s() {
- let filter = NodeFilter
- .property("p_u32s")
- .temporal()
- .last()
- .avg()
- .eq(Prop::F64(2.5));
- let expected = vec!["n1"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_last_avg_u64s() {
- let filter = NodeFilter
- .property("p_u64s")
- .temporal()
- .last()
- .avg()
- .eq(Prop::F64(20.0));
- let expected = vec!["n4"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_last_avg_i32s() {
- let filter = NodeFilter
- .property("p_i32s")
- .temporal()
- .last()
- .avg()
- .eq(Prop::F64(0.6666666666666666));
- let expected = vec!["n6"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_last_avg_i64s() {
- let filter = NodeFilter
- .property("p_i64s")
- .temporal()
- .last()
- .avg()
- .eq(Prop::F64(0.0));
- let expected = vec!["n3", "n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_last_avg_f32s() {
- let filter = NodeFilter
- .property("p_f32s")
- .temporal()
- .last()
- .avg()
- .eq(Prop::F64(20.0));
- let expected = vec!["n4"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_last_avg_f64s() {
- let filter = NodeFilter
- .property("p_f64s")
- .temporal()
- .last()
- .avg()
- .eq(Prop::F64(45.0));
- let expected = vec!["n3", "n10"];
- apply_assertion(filter, &expected);
- }
-
- // ------ Temporal last: MIN ------
- #[test]
- fn test_node_property_temporal_last_min_u8s() {
- let filter = NodeFilter
- .property("p_u8s")
- .temporal()
- .last()
- .min()
- .eq(Prop::U8(1));
- let expected = vec!["n1", "n3", "n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_last_min_u16s() {
- let filter = NodeFilter
- .property("p_u16s")
- .temporal()
- .last()
- .min()
- .eq(Prop::U16(1));
- let expected = vec!["n1", "n3", "n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_last_min_u32s() {
- let filter = NodeFilter
- .property("p_u32s")
- .temporal()
- .last()
- .min()
- .eq(Prop::U32(1));
- let expected = vec!["n1", "n3", "n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_last_min_u64s() {
- let filter = NodeFilter
- .property("p_u64s")
- .temporal()
- .last()
- .min()
- .eq(Prop::U64(10));
- let expected = vec!["n4"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_last_min_i32s() {
- let filter = NodeFilter
- .property("p_i32s")
- .temporal()
- .last()
- .min()
- .eq(Prop::I32(-2));
- let expected = vec!["n6"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_last_min_i64s() {
- let filter = NodeFilter
- .property("p_i64s")
- .temporal()
- .last()
- .min()
- .eq(Prop::I64(-3));
- let expected = vec!["n3", "n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_last_min_f32s() {
- let filter = NodeFilter
- .property("p_f32s")
- .temporal()
- .last()
- .min()
- .eq(Prop::F32(10.0));
- let expected = vec!["n4"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_last_min_f64s() {
- let filter = NodeFilter
- .property("p_f64s")
- .temporal()
- .last()
- .min()
- .eq(Prop::F64(40.0));
- let expected = vec!["n3", "n10"];
- apply_assertion(filter, &expected);
- }
-
- // ------ Temporal last: MAX ------
- #[test]
- fn test_node_property_temporal_last_max_u8s() {
- let filter = NodeFilter
- .property("p_u8s")
- .temporal()
- .last()
- .max()
- .eq(Prop::U8(4));
- let expected = vec!["n1"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_last_max_u16s() {
- let filter = NodeFilter
- .property("p_u16s")
- .temporal()
- .last()
- .max()
- .eq(Prop::U16(3));
- let expected = vec!["n3", "n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_last_max_u32s() {
- let filter = NodeFilter
- .property("p_u32s")
- .temporal()
- .last()
- .max()
- .eq(Prop::U32(4));
- let expected = vec!["n1"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_last_max_u64s() {
- let filter = NodeFilter
- .property("p_u64s")
- .temporal()
- .last()
- .max()
- .eq(Prop::U64(30));
- let expected = vec!["n4"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_last_max_i32s() {
- let filter = NodeFilter
- .property("p_i32s")
- .temporal()
- .last()
- .max()
- .eq(Prop::I32(3));
- let expected = vec!["n3", "n6", "n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_last_max_i64s() {
- let filter = NodeFilter
- .property("p_i64s")
- .temporal()
- .last()
- .max()
- .eq(Prop::I64(2));
- let expected = vec!["n3", "n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_last_max_f32s() {
- let filter = NodeFilter
- .property("p_f32s")
- .temporal()
- .last()
- .max()
- .eq(Prop::F32(3.5));
- let expected = vec!["n3", "n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_last_max_f64s() {
- let filter = NodeFilter
- .property("p_f64s")
- .temporal()
- .last()
- .max()
- .eq(Prop::F64(50.0));
- let expected = vec!["n1", "n2", "n3", "n10"];
- apply_assertion(filter, &expected);
- }
-
- // ------ Temporal last: LEN ------
- #[test]
- fn test_node_property_temporal_last_len_u8s() {
- let filter = NodeFilter
- .property("p_u8s")
- .temporal()
- .last()
- .len()
- .eq(Prop::U64(3));
- let expected = vec!["n3", "n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_last_len_u16s() {
- let filter = NodeFilter
- .property("p_u16s")
- .temporal()
- .last()
- .len()
- .eq(Prop::U64(3));
- let expected = vec!["n3", "n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_last_len_u32s() {
- let filter = NodeFilter
- .property("p_u32s")
- .temporal()
- .last()
- .len()
- .eq(Prop::U64(3));
- let expected = vec!["n3", "n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_last_len_u64s() {
- let filter = NodeFilter
- .property("p_u64s")
- .temporal()
- .last()
- .len()
- .eq(Prop::U64(3));
- let expected = vec!["n3", "n4", "n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_last_len_i32s() {
- let filter = NodeFilter
- .property("p_i32s")
- .temporal()
- .last()
- .len()
- .eq(Prop::U64(3));
- let expected = vec!["n3", "n4", "n6", "n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_last_len_i64s() {
- let filter = NodeFilter
- .property("p_i64s")
- .temporal()
- .last()
- .len()
- .eq(Prop::U64(3));
- let expected = vec!["n3", "n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_last_len_f32s() {
- let filter = NodeFilter
- .property("p_f32s")
- .temporal()
- .last()
- .len()
- .eq(Prop::U64(3));
- let expected = vec!["n3", "n4", "n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_last_len_f64s() {
- let filter = NodeFilter
- .property("p_f64s")
- .temporal()
- .last()
- .len()
- .eq(Prop::U64(2));
- let expected = vec!["n3", "n10"];
- apply_assertion(filter, &expected);
- }
-
- // ------ Temporal all: SUM ------
- #[test]
- fn test_node_property_temporal_all_sum_u8s() {
- let filter = NodeFilter
- .property("p_u8s")
- .temporal()
- .all()
- .sum()
- .eq(Prop::U64(6));
- let expected = vec!["n3", "n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_all_sum_u16s() {
- let filter = NodeFilter
- .property("p_u16s")
- .temporal()
- .all()
- .sum()
- .eq(Prop::U64(6));
- let expected = vec!["n3", "n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_all_sum_u32s() {
- let filter = NodeFilter
- .property("p_u32s")
- .temporal()
- .all()
- .sum()
- .eq(Prop::U64(6));
- let expected = vec!["n3", "n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_all_sum_u64s() {
- let filter = NodeFilter
- .property("p_u64s")
- .temporal()
- .all()
- .sum()
- .eq(Prop::U64(6));
- let expected = vec!["n3", "n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_all_sum_i32s() {
- let filter = NodeFilter
- .property("p_i32s")
- .temporal()
- .all()
- .sum()
- .eq(Prop::I64(6));
- let expected = vec!["n3", "n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_all_sum_i64s() {
- let filter = NodeFilter
- .property("p_i64s")
- .temporal()
- .all()
- .sum()
- .eq(Prop::I64(0));
- let expected = vec!["n3", "n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_all_sum_f32s() {
- let filter = NodeFilter
- .property("p_f32s")
- .temporal()
- .all()
- .sum()
- .eq(Prop::F64(6.5));
- let expected = vec!["n3", "n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_all_sum_f64s() {
- let filter = NodeFilter
- .property("p_f64s")
- .temporal()
- .all()
- .sum()
- .eq(Prop::F64(90.0));
- let expected = vec!["n3", "n10"];
- apply_assertion(filter, &expected);
- }
-
- // ------ Temporal all: AVG ------
- #[test]
- fn test_node_property_temporal_all_avg_u8s() {
- let filter = NodeFilter
- .property("p_u8s")
- .temporal()
- .all()
- .avg()
- .eq(Prop::F64(2.0));
- let expected = vec!["n3", "n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_all_avg_u16s() {
- let filter = NodeFilter
- .property("p_u16s")
- .temporal()
- .all()
- .avg()
- .eq(Prop::F64(2.0));
- let expected = vec!["n3", "n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_all_avg_u32s() {
- let filter = NodeFilter
- .property("p_u32s")
- .temporal()
- .all()
- .avg()
- .eq(Prop::F64(2.0));
- let expected = vec!["n3", "n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_all_avg_u64s() {
- let filter = NodeFilter
- .property("p_u64s")
- .temporal()
- .all()
- .avg()
- .eq(Prop::F64(2.0));
- let expected = vec!["n3", "n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_all_avg_i32s() {
- let filter = NodeFilter
- .property("p_i32s")
- .temporal()
- .all()
- .avg()
- .eq(Prop::F64(2.0));
- let expected = vec!["n3", "n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_all_avg_i64s() {
- let filter = NodeFilter
- .property("p_i64s")
- .temporal()
- .all()
- .avg()
- .eq(Prop::F64(0.0));
- let expected = vec!["n3", "n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_all_avg_f32s() {
- let filter = NodeFilter
- .property("p_f32s")
- .temporal()
- .all()
- .avg()
- .eq(Prop::F64(2.1666666666666665));
- let expected = vec!["n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_all_avg_f64s() {
- let filter = NodeFilter
- .property("p_f64s")
- .temporal()
- .all()
- .avg()
- .eq(Prop::F64(45.0));
- let expected = vec!["n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- // ------ Temporal all: MIN ------
- #[test]
- fn test_node_property_temporal_all_min_u8s() {
- let filter = NodeFilter
- .property("p_u8s")
- .temporal()
- .all()
- .min()
- .eq(Prop::U8(1));
- let expected = vec!["n1", "n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_all_min_u16s() {
- let filter = NodeFilter
- .property("p_u16s")
- .temporal()
- .all()
- .min()
- .eq(Prop::U16(1));
- let expected = vec!["n1", "n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_all_min_u32s() {
- let filter = NodeFilter
- .property("p_u32s")
- .temporal()
- .all()
- .min()
- .eq(Prop::U32(1));
- let expected = vec!["n1", "n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_all_min_u64s() {
- let filter = NodeFilter
- .property("p_u64s")
- .temporal()
- .all()
- .min()
- .eq(Prop::U64(1));
- let expected = vec!["n1", "n10", "n2", "n5"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_all_min_i32s() {
- let filter = NodeFilter
- .property("p_i32s")
- .temporal()
- .all()
- .min()
- .eq(Prop::I32(-2));
- let expected = vec!["n6"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_all_min_i64s() {
- let filter = NodeFilter
- .property("p_i64s")
- .temporal()
- .all()
- .min()
- .eq(Prop::I64(-3));
- let expected = vec!["n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_all_min_f32s() {
- let filter = NodeFilter
- .property("p_f32s")
- .temporal()
- .all()
- .min()
- .eq(Prop::F32(1.0));
- let expected = vec!["n1", "n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_all_min_f64s() {
- let filter = NodeFilter
- .property("p_f64s")
- .temporal()
- .all()
- .min()
- .eq(Prop::F64(30.0));
- let expected = vec!["n2"];
- apply_assertion(filter, &expected);
- }
-
- // ------ Temporal all: MAX ------
- #[test]
- fn test_node_property_temporal_all_max_u8s() {
- let filter = NodeFilter
- .property("p_u8s")
- .temporal()
- .all()
- .max()
- .eq(Prop::U8(3));
- let expected = vec!["n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_all_max_u16s() {
- let filter = NodeFilter
- .property("p_u16s")
- .temporal()
- .all()
- .max()
- .eq(Prop::U16(3));
- let expected = vec!["n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_all_max_u32s() {
- let filter = NodeFilter
- .property("p_u32s")
- .temporal()
- .all()
- .max()
- .eq(Prop::U32(3));
- let expected = vec!["n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_all_max_u64s() {
- let filter = NodeFilter
- .property("p_u64s")
- .temporal()
- .all()
- .max()
- .eq(Prop::U64(4));
- let expected = vec!["n2"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_all_max_i32s() {
- let filter = NodeFilter
- .property("p_i32s")
- .temporal()
- .all()
- .max()
- .eq(Prop::I32(3));
- let expected = vec!["n10", "n6"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_all_max_i64s() {
- let filter = NodeFilter
- .property("p_i64s")
- .temporal()
- .all()
- .max()
- .eq(Prop::I64(2));
- let expected = vec!["n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_all_max_f32s() {
- let filter = NodeFilter
- .property("p_f32s")
- .temporal()
- .all()
- .max()
- .eq(Prop::F32(3.5));
- let expected = vec!["n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_all_max_f64s() {
- let filter = NodeFilter
- .property("p_f64s")
- .temporal()
- .all()
- .max()
- .eq(Prop::F64(50.0));
- let expected = vec!["n1", "n10", "n2"];
- apply_assertion(filter, &expected);
- }
-
- // ------ Temporal all: LEN ------
- #[test]
- fn test_node_property_temporal_all_len_u8s() {
- let filter = NodeFilter
- .property("p_u8s")
- .temporal()
- .all()
- .len()
- .eq(Prop::U64(3));
- let expected = vec!["n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_all_len_u16s() {
- let filter = NodeFilter
- .property("p_u16s")
- .temporal()
- .all()
- .len()
- .eq(Prop::U64(3));
- let expected = vec!["n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_all_len_u32s() {
- let filter = NodeFilter
- .property("p_u32s")
- .temporal()
- .all()
- .len()
- .eq(Prop::U64(3));
- let expected = vec!["n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_all_len_u64s() {
- let filter = NodeFilter
- .property("p_u64s")
- .temporal()
- .all()
- .len()
- .eq(Prop::U64(4));
- let expected = vec!["n2"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_all_len_i32s() {
- let filter = NodeFilter
- .property("p_i32s")
- .temporal()
- .all()
- .len()
- .eq(Prop::U64(3));
- let expected = vec!["n10", "n3", "n4", "n6"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_all_len_i64s() {
- let filter = NodeFilter
- .property("p_i64s")
- .temporal()
- .all()
- .len()
- .eq(Prop::U64(2));
- let expected = vec!["n5"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_all_len_f32s() {
- let filter = NodeFilter
- .property("p_f32s")
- .temporal()
- .all()
- .len()
- .eq(Prop::U64(3));
- let expected = vec!["n10", "n3", "n4"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_all_len_f64s() {
- let filter = NodeFilter
- .property("p_f64s")
- .temporal()
- .all()
- .len()
- .eq(Prop::U64(2));
- let expected = vec!["n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- // ------ Temporal first: SUM ------
- #[test]
- fn test_node_property_temporal_first_sum_u8s() {
- let filter = NodeFilter
- .property("p_u8s")
- .temporal()
- .first()
- .sum()
- .eq(Prop::U64(6));
- let expected = vec!["n1", "n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_first_sum_u16s() {
- let filter = NodeFilter
- .property("p_u16s")
- .temporal()
- .first()
- .sum()
- .eq(Prop::U64(6));
- let expected = vec!["n1", "n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_first_sum_u32s() {
- let filter = NodeFilter
- .property("p_u32s")
- .temporal()
- .first()
- .sum()
- .eq(Prop::U64(6));
- let expected = vec!["n1", "n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_first_sum_u64s() {
- let filter = NodeFilter
- .property("p_u64s")
- .temporal()
- .first()
- .sum()
- .eq(Prop::U64(6));
- let expected = vec!["n1", "n10", "n3", "n4"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_first_sum_i32s() {
- let filter = NodeFilter
- .property("p_i32s")
- .temporal()
- .first()
- .sum()
- .eq(Prop::I64(6));
- let expected = vec!["n1", "n10", "n3", "n4"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_first_sum_i64s() {
- let filter = NodeFilter
- .property("p_i64s")
- .temporal()
- .first()
- .sum()
- .eq(Prop::I64(0));
- let expected = vec!["n3", "n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_first_sum_f32s() {
- let filter = NodeFilter
- .property("p_f32s")
- .temporal()
- .first()
- .sum()
- .eq(Prop::F64(6.5));
- let expected = vec!["n1", "n10", "n3", "n4"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_first_sum_f64s() {
- let filter = NodeFilter
- .property("p_f64s")
- .temporal()
- .first()
- .sum()
- .eq(Prop::F64(90.0));
- let expected = vec!["n1", "n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- // ------ Temporal first: AVG ------
- #[test]
- fn test_node_property_temporal_first_avg_u8s() {
- let filter = NodeFilter
- .property("p_u8s")
- .temporal()
- .first()
- .avg()
- .eq(Prop::F64(2.0));
- let expected = vec!["n1", "n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_first_avg_u16s() {
- let filter = NodeFilter
- .property("p_u16s")
- .temporal()
- .first()
- .avg()
- .eq(Prop::F64(2.0));
- let expected = vec!["n1", "n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_first_avg_u32s() {
- let filter = NodeFilter
- .property("p_u32s")
- .temporal()
- .first()
- .avg()
- .eq(Prop::F64(2.0));
- let expected = vec!["n1", "n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_first_avg_u64s() {
- let filter = NodeFilter
- .property("p_u64s")
- .temporal()
- .first()
- .avg()
- .eq(Prop::F64(2.0));
- let expected = vec!["n1", "n10", "n3", "n4"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_first_avg_i32s() {
- let filter = NodeFilter
- .property("p_i32s")
- .temporal()
- .first()
- .avg()
- .eq(Prop::F64(2.0));
- let expected = vec!["n1", "n10", "n3", "n4"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_first_avg_i64s() {
- let filter = NodeFilter
- .property("p_i64s")
- .temporal()
- .first()
- .avg()
- .eq(Prop::F64(0.0));
- let expected = vec!["n3", "n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_first_avg_f32s() {
- let filter = NodeFilter
- .property("p_f32s")
- .temporal()
- .first()
- .avg()
- .eq(Prop::F64(2.1666666666666665));
- let expected = vec!["n1", "n10", "n3", "n4"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_first_avg_f64s() {
- let filter = NodeFilter
- .property("p_f64s")
- .temporal()
- .first()
- .avg()
- .eq(Prop::F64(45.0));
- let expected = vec!["n1", "n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- // ------ Temporal first: MIN ------
- #[test]
- fn test_node_property_temporal_first_min_u8s() {
- let filter = NodeFilter
- .property("p_u8s")
- .temporal()
- .first()
- .min()
- .eq(Prop::U8(1));
- let expected = vec!["n1", "n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_first_min_u16s() {
- let filter = NodeFilter
- .property("p_u16s")
- .temporal()
- .first()
- .min()
- .eq(Prop::U16(1));
- let expected = vec!["n1", "n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_first_min_u32s() {
- let filter = NodeFilter
- .property("p_u32s")
- .temporal()
- .first()
- .min()
- .eq(Prop::U32(1));
- let expected = vec!["n1", "n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_first_min_u64s() {
- let filter = NodeFilter
- .property("p_u64s")
- .temporal()
- .first()
- .min()
- .eq(Prop::U64(1));
- let expected = vec!["n1", "n10", "n2", "n4", "n5"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_first_min_i32s() {
- let filter = NodeFilter
- .property("p_i32s")
- .temporal()
- .first()
- .min()
- .eq(Prop::I32(-2));
- let expected = vec!["n6"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_first_min_i64s() {
- let filter = NodeFilter
- .property("p_i64s")
- .temporal()
- .first()
- .min()
- .eq(Prop::I64(-3));
- let expected = vec!["n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_first_min_f32s() {
- let filter = NodeFilter
- .property("p_f32s")
- .temporal()
- .first()
- .min()
- .eq(Prop::F32(1.0));
- let expected = vec!["n1", "n10", "n3", "n4"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_first_min_f64s() {
- let filter = NodeFilter
- .property("p_f64s")
- .temporal()
- .first()
- .min()
- .eq(Prop::F64(30.0));
- let expected = vec!["n2", "n3"];
- apply_assertion(filter, &expected);
- }
-
- // ------ Temporal first: MAX ------
- #[test]
- fn test_node_property_temporal_first_max_u8s() {
- let filter = NodeFilter
- .property("p_u8s")
- .temporal()
- .first()
- .max()
- .eq(Prop::U8(3));
- let expected = vec!["n1", "n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_first_max_u16s() {
- let filter = NodeFilter
- .property("p_u16s")
- .temporal()
- .first()
- .max()
- .eq(Prop::U16(3));
- let expected = vec!["n1", "n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_first_max_u32s() {
- let filter = NodeFilter
- .property("p_u32s")
- .temporal()
- .first()
- .max()
- .eq(Prop::U32(3));
- let expected = vec!["n1", "n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_first_max_u64s() {
- let filter = NodeFilter
- .property("p_u64s")
- .temporal()
- .first()
- .max()
- .eq(Prop::U64(4));
- let expected = vec!["n2"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_first_max_i32s() {
- let filter = NodeFilter
- .property("p_i32s")
- .temporal()
- .first()
- .max()
- .eq(Prop::I32(3));
- let expected = vec!["n1", "n10", "n4", "n6"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_first_max_i64s() {
- let filter = NodeFilter
- .property("p_i64s")
- .temporal()
- .first()
- .max()
- .eq(Prop::I64(2));
- let expected = vec!["n10"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_first_max_f32s() {
- let filter = NodeFilter
- .property("p_f32s")
- .temporal()
- .first()
- .max()
- .eq(Prop::F32(3.5));
- let expected = vec!["n1", "n10", "n4"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_first_max_f64s() {
- let filter = NodeFilter
- .property("p_f64s")
- .temporal()
- .first()
- .max()
- .eq(Prop::F64(50.0));
- let expected = vec!["n1", "n10", "n2"];
- apply_assertion(filter, &expected);
- }
-
- // ------ Temporal first: LEN ------
- #[test]
- fn test_node_property_temporal_first_len_u8s() {
- let filter = NodeFilter
- .property("p_u8s")
- .temporal()
- .first()
- .len()
- .eq(Prop::U64(3));
- let expected = vec!["n1", "n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_first_len_u16s() {
- let filter = NodeFilter
- .property("p_u16s")
- .temporal()
- .first()
- .len()
- .eq(Prop::U64(3));
- let expected = vec!["n1", "n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_first_len_u32s() {
- let filter = NodeFilter
- .property("p_u32s")
- .temporal()
- .first()
- .len()
- .eq(Prop::U64(3));
- let expected = vec!["n1", "n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_first_len_u64s() {
- let filter = NodeFilter
- .property("p_u64s")
- .temporal()
- .first()
- .len()
- .eq(Prop::U64(4));
- let expected = vec!["n2"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_first_len_i32s() {
- let filter = NodeFilter
- .property("p_i32s")
- .temporal()
- .first()
- .len()
- .eq(Prop::U64(3));
- let expected = vec!["n1", "n10", "n3", "n4", "n6"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_first_len_i64s() {
- let filter = NodeFilter
- .property("p_i64s")
- .temporal()
- .first()
- .len()
- .eq(Prop::U64(2));
- let expected = vec!["n5"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_first_len_f32s() {
- let filter = NodeFilter
- .property("p_f32s")
- .temporal()
- .first()
- .len()
- .eq(Prop::U64(3));
- let expected = vec!["n1", "n10", "n3", "n4"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_first_len_f64s() {
- let filter = NodeFilter
- .property("p_f64s")
- .temporal()
- .first()
- .len()
- .eq(Prop::U64(2));
- let expected = vec!["n1", "n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- // ------ Temporal any: SUM ------
- #[test]
- fn test_node_property_temporal_any_sum_u8s() {
- let filter = NodeFilter
- .property("p_u8s")
- .temporal()
- .any()
- .sum()
- .eq(Prop::U64(6));
- let expected = vec!["n1", "n10", "n3"];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter
- .property("p_u8s")
- .temporal()
- .any()
- .sum()
- .eq(Prop::U64(10));
- let expected = vec!["n1"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_any_sum_u16s() {
- let filter = NodeFilter
- .property("p_u16s")
- .temporal()
- .any()
- .sum()
- .eq(Prop::U64(6));
- let expected = vec!["n1", "n10", "n3"];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter
- .property("p_u16s")
- .temporal()
- .any()
- .sum()
- .eq(Prop::U64(10));
- let expected = vec!["n1"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_any_sum_u32s() {
- let filter = NodeFilter
- .property("p_u32s")
- .temporal()
- .any()
- .sum()
- .eq(Prop::U64(6));
- let expected = vec!["n1", "n10", "n3"];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter
- .property("p_u32s")
- .temporal()
- .any()
- .sum()
- .eq(Prop::U64(10));
- let expected = vec!["n1"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_any_sum_u64s() {
- let filter = NodeFilter
- .property("p_u64s")
- .temporal()
- .any()
- .sum()
- .eq(Prop::U64(6));
- let expected = vec!["n1", "n10", "n3", "n4"];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter
- .property("p_u64s")
- .temporal()
- .any()
- .sum()
- .eq(Prop::U64(10));
- let expected = vec!["n1", "n2"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_any_sum_i32s() {
- let filter = NodeFilter
- .property("p_i32s")
- .temporal()
- .any()
- .sum()
- .eq(Prop::I64(6));
- let expected = vec!["n1", "n10", "n3", "n4"];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter
- .property("p_i32s")
- .temporal()
- .any()
- .sum()
- .eq(Prop::I64(60));
- let expected = vec!["n4"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_any_sum_i64s() {
- let filter = NodeFilter
- .property("p_i64s")
- .temporal()
- .any()
- .sum()
- .eq(Prop::I64(0));
- let expected = vec!["n3", "n10"];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter
- .property("p_i64s")
- .temporal()
- .any()
- .sum()
- .eq(Prop::I64(10));
- let expected = vec!["n1"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_any_sum_f32s() {
- let filter = NodeFilter
- .property("p_f32s")
- .temporal()
- .any()
- .sum()
- .eq(Prop::F64(6.5));
- let expected = vec!["n1", "n10", "n3", "n4"];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter
- .property("p_f32s")
- .temporal()
- .any()
- .sum()
- .eq(Prop::F64(60.0));
- let expected = vec!["n4"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_any_sum_f64s() {
- let filter = NodeFilter
- .property("p_f64s")
- .temporal()
- .any()
- .sum()
- .eq(Prop::F64(90.0));
- let expected = vec!["n1", "n10", "n3"];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter
- .property("p_f64s")
- .temporal()
- .any()
- .sum()
- .eq(Prop::F64(120.0));
- let expected = vec!["n1", "n2"];
- apply_assertion(filter, &expected);
- }
-
- // ------ Temporal any: AVG ------
- #[test]
- fn test_node_property_temporal_any_avg_u8s() {
- let filter = NodeFilter
- .property("p_u8s")
- .temporal()
- .any()
- .avg()
- .eq(Prop::F64(2.0));
- let expected = vec!["n1", "n10", "n3"];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter
- .property("p_u8s")
- .temporal()
- .any()
- .avg()
- .eq(Prop::F64(2.5));
- let expected = vec!["n1"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_any_avg_u16s() {
- let filter = NodeFilter
- .property("p_u16s")
- .temporal()
- .any()
- .avg()
- .eq(Prop::F64(2.0));
- let expected = vec!["n1", "n10", "n3"];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter
- .property("p_u16s")
- .temporal()
- .any()
- .avg()
- .eq(Prop::F64(2.5));
- let expected = vec!["n1"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_any_avg_u32s() {
- let filter = NodeFilter
- .property("p_u32s")
- .temporal()
- .any()
- .avg()
- .eq(Prop::F64(2.0));
- let expected = vec!["n1", "n10", "n3"];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter
- .property("p_u32s")
- .temporal()
- .any()
- .avg()
- .eq(Prop::F64(2.5));
- let expected = vec!["n1"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_any_avg_u64s() {
- let filter = NodeFilter
- .property("p_u64s")
- .temporal()
- .any()
- .avg()
- .eq(Prop::F64(2.0));
- let expected = vec!["n1", "n10", "n3", "n4"];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter
- .property("p_u64s")
- .temporal()
- .any()
- .avg()
- .eq(Prop::F64(2.5));
- let expected = vec!["n1", "n2"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_any_avg_i32s() {
- let filter = NodeFilter
- .property("p_i32s")
- .temporal()
- .any()
- .avg()
- .eq(Prop::F64(2.0));
- let expected = vec!["n1", "n10", "n3", "n4"];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter
- .property("p_i32s")
- .temporal()
- .any()
- .avg()
- .eq(Prop::F64(2.5));
- let expected = vec!["n1"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_any_avg_i64s() {
- let filter = NodeFilter
- .property("p_i64s")
- .temporal()
- .any()
- .avg()
- .eq(Prop::F64(0.0));
- let expected = vec!["n3", "n10"];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter
- .property("p_i64s")
- .temporal()
- .any()
- .avg()
- .eq(Prop::F64(2.5));
- let expected = vec!["n1"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_any_avg_f32s() {
- let filter = NodeFilter
- .property("p_f32s")
- .temporal()
- .any()
- .avg()
- .eq(Prop::F64(2.1666666666666665));
- let expected = vec!["n1", "n10", "n3", "n4"];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter
- .property("p_f32s")
- .temporal()
- .any()
- .avg()
- .eq(Prop::F64(20.0));
- let expected = vec!["n4"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_any_avg_f64s() {
- let filter = NodeFilter
- .property("p_f64s")
- .temporal()
- .any()
- .avg()
- .eq(Prop::F64(45.0));
- let expected = vec!["n1", "n10", "n3"];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter
- .property("p_f64s")
- .temporal()
- .any()
- .avg()
- .eq(Prop::F64(40.0));
- let expected = vec!["n1", "n2"];
- apply_assertion(filter, &expected);
- }
-
- // ------ Temporal any: MIN ------
- #[test]
- fn test_node_property_temporal_any_min_u8s() {
- let filter = NodeFilter
- .property("p_u8s")
- .temporal()
- .any()
- .min()
- .eq(Prop::U8(1));
- let expected = vec!["n1", "n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_any_min_u16s() {
- let filter = NodeFilter
- .property("p_u16s")
- .temporal()
- .any()
- .min()
- .eq(Prop::U16(1));
- let expected = vec!["n1", "n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_any_min_u32s() {
- let filter = NodeFilter
- .property("p_u32s")
- .temporal()
- .any()
- .min()
- .eq(Prop::U32(1));
- let expected = vec!["n1", "n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_any_min_u64s() {
- let filter = NodeFilter
- .property("p_u64s")
- .temporal()
- .any()
- .min()
- .eq(Prop::U64(1));
- let expected = vec!["n1", "n10", "n2", "n3", "n4", "n5"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_any_min_i32s() {
- let filter = NodeFilter
- .property("p_i32s")
- .temporal()
- .any()
- .min()
- .eq(Prop::I32(-2));
- let expected = vec!["n6"];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter
- .property("p_i32s")
- .temporal()
- .any()
- .min()
- .eq(Prop::I32(10));
- let expected = vec!["n4"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_any_min_i64s() {
- let filter = NodeFilter
- .property("p_i64s")
- .temporal()
- .any()
- .min()
- .eq(Prop::I64(-3));
- let expected = vec!["n10", "n3"];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter
- .property("p_i64s")
- .temporal()
- .any()
- .min()
- .eq(Prop::I64(1));
- let expected = vec!["n1", "n5"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_any_min_f32s() {
- let filter = NodeFilter
- .property("p_f32s")
- .temporal()
- .any()
- .min()
- .eq(Prop::F32(1.0));
- let expected = vec!["n1", "n10", "n3", "n4"];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter
- .property("p_f32s")
- .temporal()
- .any()
- .min()
- .eq(Prop::F32(10.0));
- let expected = vec!["n4"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_any_min_f64s() {
- let filter = NodeFilter
- .property("p_f64s")
- .temporal()
- .any()
- .min()
- .eq(Prop::F64(30.0));
- let expected = vec!["n1", "n2", "n3"];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter
- .property("p_f64s")
- .temporal()
- .any()
- .min()
- .eq(Prop::F64(40.0));
- let expected = vec!["n1", "n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- // ------ Temporal any: MAX ------
- #[test]
- fn test_node_property_temporal_any_max_u8s() {
- let filter = NodeFilter
- .property("p_u8s")
- .temporal()
- .any()
- .max()
- .eq(Prop::U8(3));
- let expected = vec!["n1", "n10", "n3"];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter
- .property("p_u8s")
- .temporal()
- .any()
- .max()
- .eq(Prop::U8(4));
- let expected = vec!["n1", "n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_any_max_u16s() {
- let filter = NodeFilter
- .property("p_u16s")
- .temporal()
- .any()
- .max()
- .eq(Prop::U16(3));
- let expected = vec!["n1", "n10", "n3"];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter
- .property("p_u16s")
- .temporal()
- .any()
- .max()
- .eq(Prop::U16(4));
- let expected = vec!["n1"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_any_max_u32s() {
- let filter = NodeFilter
- .property("p_u32s")
- .temporal()
- .any()
- .max()
- .eq(Prop::U32(3));
- let expected = vec!["n1", "n10", "n3"];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter
- .property("p_u32s")
- .temporal()
- .any()
- .max()
- .eq(Prop::U32(4));
- let expected = vec!["n1"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_any_max_u64s() {
- let filter = NodeFilter
- .property("p_u64s")
- .temporal()
- .any()
- .max()
- .eq(Prop::U64(4));
- let expected = vec!["n1", "n2"];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter
- .property("p_u64s")
- .temporal()
- .any()
- .max()
- .eq(Prop::U64(3));
- let expected = vec!["n1", "n10", "n3", "n4"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_any_max_i32s() {
- let filter = NodeFilter
- .property("p_i32s")
- .temporal()
- .any()
- .max()
- .eq(Prop::I32(3));
- let expected = vec!["n1", "n10", "n3", "n4", "n6"];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter
- .property("p_i32s")
- .temporal()
- .any()
- .max()
- .eq(Prop::I32(30));
- let expected = vec!["n4"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_any_max_i64s() {
- let filter = NodeFilter
- .property("p_i64s")
- .temporal()
- .any()
- .max()
- .eq(Prop::I64(2));
- let expected = vec!["n10", "n3"];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter
- .property("p_i64s")
- .temporal()
- .any()
- .max()
- .eq(Prop::I64(2));
- let expected = vec!["n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_any_max_f32s() {
- let filter = NodeFilter
- .property("p_f32s")
- .temporal()
- .any()
- .max()
- .eq(Prop::F32(3.5));
- let expected = vec!["n1", "n10", "n3", "n4"];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter
- .property("p_f32s")
- .temporal()
- .any()
- .max()
- .eq(Prop::F32(30.0));
- let expected = vec!["n4"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_any_max_f64s() {
- let filter = NodeFilter
- .property("p_f64s")
- .temporal()
- .any()
- .max()
- .eq(Prop::F64(50.0));
- let expected = vec!["n1", "n10", "n2", "n3"];
- apply_assertion(filter, &expected);
- }
-
- // ------ Temporal any: LEN ------
- #[test]
- fn test_node_property_temporal_any_len_u8s() {
- let filter = NodeFilter
- .property("p_u8s")
- .temporal()
- .any()
- .len()
- .is_in(vec![Prop::U64(3)]);
- let expected = vec!["n1", "n10", "n3"];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter
- .property("p_u8s")
- .temporal()
- .any()
- .len()
- .eq(Prop::U64(4));
- let expected = vec!["n1"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_any_len_u16s() {
- let filter = NodeFilter
- .property("p_u16s")
- .temporal()
- .any()
- .len()
- .eq(Prop::U64(3));
- let expected = vec!["n1", "n10", "n3"];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter
- .property("p_u16s")
- .temporal()
- .any()
- .len()
- .eq(Prop::U64(4));
- let expected = vec!["n1"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_any_len_u32s() {
- let filter = NodeFilter
- .property("p_u32s")
- .temporal()
- .any()
- .len()
- .eq(Prop::U64(3));
- let expected = vec!["n1", "n10", "n3"];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter
- .property("p_u32s")
- .temporal()
- .any()
- .len()
- .eq(Prop::U64(4));
- let expected = vec!["n1"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_any_len_u64s() {
- let filter = NodeFilter
- .property("p_u64s")
- .temporal()
- .any()
- .len()
- .eq(Prop::U64(4));
- let expected = vec!["n1", "n2"];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter
- .property("p_u64s")
- .temporal()
- .any()
- .len()
- .eq(Prop::U64(3));
- let expected = vec!["n1", "n10", "n3", "n4"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_any_len_i32s() {
- let filter = NodeFilter
- .property("p_i32s")
- .temporal()
- .any()
- .len()
- .eq(Prop::U64(3));
- let expected = vec!["n1", "n10", "n3", "n4", "n6"];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter
- .property("p_i32s")
- .temporal()
- .any()
- .len()
- .eq(Prop::U64(4));
- let expected = vec!["n1"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_any_len_i64s() {
- let filter = NodeFilter
- .property("p_i64s")
- .temporal()
- .any()
- .len()
- .eq(Prop::U64(2));
- let expected = vec!["n5"];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter
- .property("p_i64s")
- .temporal()
- .any()
- .len()
- .eq(Prop::U64(4));
- let expected = vec!["n1"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_any_len_f32s() {
- let filter = NodeFilter
- .property("p_f32s")
- .temporal()
- .any()
- .len()
- .eq(Prop::U64(3));
- let expected = vec!["n1", "n10", "n3", "n4"];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter
- .property("p_f32s")
- .temporal()
- .any()
- .len()
- .eq(Prop::U64(4));
- let expected = vec!["n1"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_property_temporal_any_len_f64s() {
- let filter = NodeFilter
- .property("p_f64s")
- .temporal()
- .any()
- .len()
- .eq(Prop::U64(2));
- let expected = vec!["n1", "n10", "n3"];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter
- .property("p_f64s")
- .temporal()
- .any()
- .len()
- .eq(Prop::U64(3));
- let expected = vec!["n1", "n2"];
- apply_assertion(filter, &expected);
- }
-
- // ------ EMPTY LISTS ------
- #[test]
- fn test_empty_list_agg() {
- let filter = NodeFilter.property("p_u64s").sum().eq(Prop::U64(0));
- let expected: Vec<&str> = vec![];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter.property("p_u64s").avg().eq(Prop::F64(0.0));
- let expected: Vec<&str> = vec![];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter
- .property("p_u64s")
- .temporal()
- .last()
- .min()
- .eq(Prop::U64(0));
- let expected: Vec<&str> = vec![];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter
- .property("p_u64s")
- .temporal()
- .first()
- .max()
- .eq(Prop::U64(0));
- let expected: Vec<&str> = vec![];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter.property("p_u64s").len().eq(Prop::U64(0));
- let expected: Vec<&str> = vec!["n7"];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter.metadata("p_u64s").len().eq(Prop::U64(0));
- let expected: Vec<&str> = vec!["n6"];
- apply_assertion(filter, &expected);
- }
-
- // ------ Unsupported filter operations ------
- #[test]
- fn test_unsupported_filter_ops_agg() {
- let filter = NodeFilter.property("p_u64s").sum().starts_with("abc");
- let expected: &str = "Operator STARTS_WITH is not supported with list aggregation";
- apply_assertion_err(filter, expected);
-
- let filter = NodeFilter.property("p_u64s").avg().ends_with("abc");
- let expected: &str = "Operator ENDS_WITH is not supported with list aggregation";
- apply_assertion_err(filter, expected);
-
- let filter = NodeFilter.property("p_u64s").min().is_none();
- let expected: &str = "Operator IS_NONE is not supported with list aggregation";
- apply_assertion_err(filter, expected);
-
- let filter = NodeFilter.property("p_u64s").max().is_some();
- let expected: &str = "Operator IS_SOME is not supported with list aggregation";
- apply_assertion_err(filter, expected);
-
- let filter = NodeFilter.property("p_u64s").len().contains("abc");
- let expected: &str = "Operator CONTAINS is not supported with list aggregation";
- apply_assertion_err(filter, expected);
-
- let filter = NodeFilter.property("p_u64s").sum().not_contains("abc");
- let expected: &str = "Operator NOT_CONTAINS is not supported with list aggregation";
- apply_assertion_err(filter, expected);
- }
-
- // --------------- OVERFLOW ---------------
- #[test]
- fn test_max_value_agg() {
- let filter = NodeFilter
- .property("p_u64s_max")
- .max()
- .eq(Prop::U64(u64::MAX));
- let expected: Vec<&str> = vec!["n5", "n1"];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter
- .property("p_u64s_min")
- .min()
- .eq(Prop::U64(u64::MIN));
- let expected: Vec<&str> = vec!["n5"];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter.property("p_u8s_max").sum().eq(Prop::U64(510));
- let expected: Vec<&str> = vec!["n1"];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter
- .property("p_u16s_max")
- .sum()
- .eq(Prop::U64(131070));
- let expected: Vec<&str> = vec!["n1"];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter
- .property("p_u32s_max")
- .sum()
- .eq(Prop::U64(8589934590));
- let expected: Vec<&str> = vec!["n1"];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter.property("p_u64s_max").sum().gt(Prop::U64(0));
- let expected: Vec<&str> = vec![];
- apply_assertion(filter, &expected);
-
- // AVG is computed in f64 even if SUM overflowed.
- let avg = (u64::MAX as f64 + 1.0) / 2.0;
- let filter = NodeFilter.property("p_u64s_max").avg().eq(avg);
- let expected = vec!["n5"];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter.property("p_i64s_max").sum().gt(Prop::I64(0));
- let expected: Vec<&str> = vec![];
- apply_assertion(filter, &expected);
-
- // AVG is computed in f64 even if SUM overflowed.
- let avg = (i64::MAX as f64 + 1.0) / 2.0;
- let filter = NodeFilter.property("p_i64s_max").avg().eq(avg);
- let expected = vec!["n5"];
- apply_assertion(filter, &expected);
- }
-
- // ------ Property: any ------
- #[test]
- fn test_node_property_any() {
- let filter = NodeFilter.property("p_u8s").any().eq(Prop::U8(3));
- let expected = vec!["n1", "n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- // ------ Property: all ------
- #[test]
- fn test_node_property_all() {
- let filter = NodeFilter
- .property("p_bools_all")
- .all()
- .eq(Prop::Bool(true));
- let expected = vec!["n10", "n4"];
- apply_assertion(filter, &expected);
- }
-
- // ------ Metadata: any ------
- #[test]
- fn test_node_metadata_any() {
- let filter = NodeFilter.metadata("p_u64s").any().eq(Prop::U64(1));
- let expected = vec!["n10", "n7"];
- apply_assertion(filter, &expected);
- }
-
- // ------ Metadata: all ------
- #[test]
- fn test_node_metadata_all() {
- let filter = NodeFilter.metadata("p_strs").all().eq("a");
- let expected = vec!["n6", "n7"];
- apply_assertion(filter, &expected);
- }
-
- // ------ Temporal First: any ------
- #[test]
- fn test_node_temporal_property_first_any() {
- let filter = NodeFilter
- .property("p_bools")
- .temporal()
- .first()
- .any()
- .eq(false);
- let expected = vec!["n1", "n10", "n2", "n3", "n4"];
- apply_assertion(filter, &expected);
- }
-
- // ------ Temporal First: all ------
- #[test]
- fn test_node_temporal_property_first_all() {
- let filter = NodeFilter
- .property("p_bools_all")
- .temporal()
- .first()
- .all()
- .eq(true);
- let expected = vec!["n10", "n4"];
- apply_assertion(filter, &expected);
- }
-
- // ------ Temporal last: any ------
- #[test]
- fn test_node_temporal_property_last_any() {
- let filter = NodeFilter
- .property("p_f32s")
- .temporal()
- .last()
- .any()
- .eq(Prop::F32(3.5));
- let expected = vec!["n1", "n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- // ------ Temporal last: all ------
- #[test]
- fn test_node_temporal_property_last_all() {
- let filter = NodeFilter
- .property("p_bools_all")
- .temporal()
- .last()
- .all()
- .eq(true);
- let expected = vec!["n10", "n4"];
- apply_assertion(filter, &expected);
- }
-
- // ------ Temporal Any: any ------
- #[test]
- fn test_node_temporal_property_any_any() {
- let filter = NodeFilter
- .property("p_f32s")
- .temporal()
- .any()
- .any()
- .eq(Prop::F32(3.5));
- let expected = vec!["n1", "n10", "n3", "n4"];
- apply_assertion(filter, &expected);
-
- let filter = NodeFilter
- .property("p_f32s")
- .temporal()
- .any()
- .any()
- .eq(Prop::F32(30.0));
- let expected = vec!["n4"];
- apply_assertion(filter, &expected);
- }
-
- // ------ Temporal Any: all ------
- #[test]
- fn test_node_temporal_property_any_all() {
- let filter = NodeFilter
- .property("p_bools")
- .temporal()
- .any()
- .all()
- .eq(false);
- let expected = vec!["n2", "n4"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_nested_list_property_all_all_all_any() {
- let filter = NodeFilter
- .property("nested_list")
- .all()
- .all()
- .all()
- .any()
- .gt(45.0);
-
- let expected = vec!["n1", "n3"];
- apply_assertion(filter, &expected);
- }
-
- #[test]
- fn test_node_nested_list_temporal_property_all_all_all_all_any() {
- let filter = NodeFilter
- .property("nested_list")
- .temporal()
- .all()
- .all()
- .all()
- .all()
- .any()
- .gt(45.0);
-
- let expected = vec!["n3"];
- apply_assertion(filter, &expected);
- }
-
- // ------ Temporal All: any ------
- #[test]
- fn test_node_temporal_property_all_any() {
- let filter = NodeFilter
- .property("p_bools")
- .temporal()
- .all()
- .any()
- .eq(true);
- let expected = vec!["n1", "n10", "n3"];
- apply_assertion(filter, &expected);
- }
-
- // ------ Temporal All: all ------
- #[test]
- fn test_node_temporal_property_all_all() {
- let filter = NodeFilter
- .property("p_bools_all")
- .temporal()
- .all()
- .all()
- .eq(true);
- let expected = vec!["n4", "n10"];
- apply_assertion(filter, &expected);
- }
-}
-
-mod test_edge_filter {
- use crate::{
- init_edges_graph, init_edges_graph_with_num_ids, init_edges_graph_with_str_ids,
- init_edges_graph_with_str_ids_del, init_nodes_graph, IdentityGraphTransformer,
- };
- use raphtory::db::graph::views::filter::model::{
- edge_filter::EdgeFilter,
- node_filter::ops::{NodeFilterOps, NodeIdFilterOps},
- property_filter::ops::{ListAggOps, PropertyFilterOps},
- ComposableFilter, EdgeViewFilterOps, PropertyFilterFactory, TemporalPropertyFilterFactory,
- ViewWrapOps,
- };
- use raphtory_tests::assertions::{
- assert_filter_edges_results, assert_search_edges_results, assert_select_edges_results,
- TestGraphVariants, TestVariants,
- };
-
- #[test]
- fn test_filter_edges_src_property_eq() {
- let filter = EdgeFilter::src().property("p10").eq("Paper_airplane");
- let expected_results = vec!["1->2", "3->1"];
- let g = |g| init_edges_graph(init_nodes_graph(g));
- assert_filter_edges_results(
- g,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- g,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_src_property_temporal_eq() {
- let filter = EdgeFilter::src()
- .property("p30")
- .temporal()
- .first()
- .eq("Old_boat");
- let expected_results = vec!["2->1", "2->3"];
- let g = |g| init_edges_graph(init_nodes_graph(g));
- assert_filter_edges_results(
- g,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- g,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_src_metadata_eq() {
- let filter = EdgeFilter::src().metadata("m1").eq("pometry");
- let expected_results = vec!["1->2"];
- let g = |g| init_edges_graph(init_nodes_graph(g));
- assert_filter_edges_results(
- g,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- g,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_src_eq() {
- let filter = EdgeFilter::src().name().eq("3");
- let expected_results = vec!["3->1"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_src_ne() {
- let filter = EdgeFilter::src().name().ne("1");
- let expected_results = vec![
- "2->1",
- "2->3",
- "3->1",
- "David Gilmour->John Mayer",
- "John Mayer->Jimmy Page",
- ];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_src_in() {
- let filter = EdgeFilter::src().name().is_in(vec!["1"]);
- let expected_results = vec!["1->2"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter::src().name().is_in(vec!["1", "2"]);
- let expected_results = vec!["1->2", "2->1", "2->3"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_src_not_in() {
- let filter = EdgeFilter::src().name().is_not_in(vec!["1"]);
- let expected_results = vec![
- "2->1",
- "2->3",
- "3->1",
- "David Gilmour->John Mayer",
- "John Mayer->Jimmy Page",
- ];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_dst_eq() {
- let filter = EdgeFilter::dst().name().eq("2");
- let expected_results = vec!["1->2"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_dst_ne() {
- let filter = EdgeFilter::dst().name().ne("2");
- let expected_results = vec![
- "2->1",
- "2->3",
- "3->1",
- "David Gilmour->John Mayer",
- "John Mayer->Jimmy Page",
- ];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_dst_in() {
- let filter = EdgeFilter::dst().name().is_in(vec!["2"]);
- let expected_results = vec!["1->2"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter::dst().name().is_in(vec!["2", "3"]);
- let expected_results = vec!["1->2", "2->3"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_dst_not_in() {
- let filter = EdgeFilter::dst().name().is_not_in(vec!["1"]);
- let expected_results = vec![
- "1->2",
- "2->3",
- "David Gilmour->John Mayer",
- "John Mayer->Jimmy Page",
- ];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_src_dst_starts_with() {
- let filter = EdgeFilter::src().name().starts_with("Joh");
- let expected_results: Vec<&str> = vec!["John Mayer->Jimmy Page"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter::src().name().starts_with("Joker");
- let expected_results: Vec<&str> = vec![];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter::dst().name().starts_with("Jimmy");
- let expected_results: Vec<&str> = vec!["John Mayer->Jimmy Page"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter::dst().name().starts_with("Tango");
- let expected_results: Vec<&str> = vec![];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_src_dst_ends_with() {
- let filter = EdgeFilter::src().name().ends_with("Mayer");
- let expected_results: Vec<&str> = vec!["John Mayer->Jimmy Page"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter::src().name().ends_with("Cruise");
- let expected_results: Vec<&str> = vec![];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter::dst().name().ends_with("Page");
- let expected_results: Vec<&str> = vec!["John Mayer->Jimmy Page"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter::dst().name().ends_with("Cruise");
- let expected_results: Vec<&str> = vec![];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_src_contains() {
- let filter = EdgeFilter::src().name().contains("Mayer");
- let expected_results: Vec<&str> = vec!["John Mayer->Jimmy Page"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_src_contains_not() {
- let filter = EdgeFilter::src().name().not_contains("Mayer");
- let expected_results: Vec<&str> =
- vec!["1->2", "2->1", "2->3", "3->1", "David Gilmour->John Mayer"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_fuzzy_search() {
- let filter = EdgeFilter::src().name().fuzzy_search("John", 2, true);
- let expected_results: Vec<&str> = vec!["John Mayer->Jimmy Page"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter::src().name().fuzzy_search("John", 2, false);
- let expected_results: Vec<&str> = vec![];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter::src().name().fuzzy_search("John May", 2, false);
- let expected_results: Vec<&str> = vec!["John Mayer->Jimmy Page"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_not_src() {
- let filter = EdgeFilter::src().name().is_not_in(vec!["1"]).not();
- let expected_results = vec!["1->2"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_src_id_eq() {
- let filter = EdgeFilter::src().id().eq("3");
- let expected_results = vec!["3->1"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter::src().id().eq(3);
- let expected_results = vec!["3->1"];
- assert_filter_edges_results(
- init_edges_graph_with_num_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph_with_num_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_dst_id_eq() {
- let filter = EdgeFilter::dst().id().eq("3");
- let expected_results = vec!["2->3"];
- // assert_filter_edges_results(
- // init_edges_graph,
- // IdentityGraphTransformer,
- // filter.clone(),
- // &expected_results,
- // TestVariants::All,
- // );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter::dst().id().eq(3);
- let expected_results = vec!["2->3"];
- assert_filter_edges_results(
- init_edges_graph_with_num_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph_with_num_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_src_id_ne() {
- let filter = EdgeFilter::src().id().ne("3");
- let expected_results = vec![
- "1->2",
- "2->1",
- "2->3",
- "David Gilmour->John Mayer",
- "John Mayer->Jimmy Page",
- ];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter::src().id().ne(3);
- let expected_results = vec!["1->2", "2->1", "2->3"];
- assert_filter_edges_results(
- init_edges_graph_with_num_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph_with_num_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_dst_id_ne() {
- let filter = EdgeFilter::dst().id().ne("3");
- let expected_results = vec![
- "1->2",
- "2->1",
- "3->1",
- "David Gilmour->John Mayer",
- "John Mayer->Jimmy Page",
- ];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter::dst().id().ne(3);
- let expected_results = vec!["1->2", "2->1", "3->1"];
- assert_filter_edges_results(
- init_edges_graph_with_num_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph_with_num_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_id_src_is_in() {
- let filter = EdgeFilter::src().id().is_in(vec!["3"]);
- let expected_results = vec!["3->1"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter::src().id().is_in(vec![3]);
- let expected_results = vec!["3->1"];
- assert_filter_edges_results(
- init_edges_graph_with_num_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph_with_num_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_id_dst_is_in() {
- let filter = EdgeFilter::dst().id().is_in(vec!["3"]);
- let expected_results = vec!["2->3"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter::dst().id().is_in(vec![3]);
- let expected_results = vec!["2->3"];
- assert_filter_edges_results(
- init_edges_graph_with_num_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph_with_num_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_id_src_is_not_in() {
- let filter = EdgeFilter::src().id().is_not_in(vec!["3"]);
- let expected_results = vec![
- "1->2",
- "2->1",
- "2->3",
- "David Gilmour->John Mayer",
- "John Mayer->Jimmy Page",
- ];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter::src().id().is_not_in(vec![3]);
- let expected_results = vec!["1->2", "2->1", "2->3"];
- assert_filter_edges_results(
- init_edges_graph_with_num_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph_with_num_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_id_dst_is_not_in() {
- let filter = EdgeFilter::dst().id().is_not_in(vec!["3"]);
- let expected_results = vec![
- "1->2",
- "2->1",
- "3->1",
- "David Gilmour->John Mayer",
- "John Mayer->Jimmy Page",
- ];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter::dst().id().is_not_in(vec![3]);
- let expected_results = vec!["1->2", "2->1", "3->1"];
- assert_filter_edges_results(
- init_edges_graph_with_num_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph_with_num_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_src_id_lt() {
- let filter = EdgeFilter::src().id().lt(3);
- let expected_results = vec!["1->2", "2->1", "2->3"];
- assert_filter_edges_results(
- init_edges_graph_with_num_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph_with_num_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_dst_id_lt() {
- let filter = EdgeFilter::dst().id().lt(3);
- let expected_results = vec!["1->2", "2->1", "3->1"];
- assert_filter_edges_results(
- init_edges_graph_with_num_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph_with_num_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_src_id_le() {
- let filter = EdgeFilter::src().id().le(3);
- let expected_results = vec!["1->2", "2->1", "2->3", "3->1"];
- assert_filter_edges_results(
- init_edges_graph_with_num_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph_with_num_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_dst_id_le() {
- let filter = EdgeFilter::dst().id().le(3);
- let expected_results = vec!["1->2", "2->1", "2->3", "3->1"];
- assert_filter_edges_results(
- init_edges_graph_with_num_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph_with_num_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_src_id_gt() {
- let filter = EdgeFilter::src().id().gt(1);
- let expected_results = vec!["2->1", "2->3", "3->1"];
- assert_filter_edges_results(
- init_edges_graph_with_num_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph_with_num_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_dst_id_gt() {
- let filter = EdgeFilter::dst().id().gt(1);
- let expected_results = vec!["1->2", "2->3"];
- assert_filter_edges_results(
- init_edges_graph_with_num_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph_with_num_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_src_id_ge() {
- let filter = EdgeFilter::src().id().ge(1);
- let expected_results = vec!["1->2", "2->1", "2->3", "3->1"];
- assert_filter_edges_results(
- init_edges_graph_with_num_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph_with_num_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_dst_id_ge() {
- let filter = EdgeFilter::dst().id().ge(1);
- let expected_results = vec!["1->2", "2->1", "2->3", "3->1"];
- assert_filter_edges_results(
- init_edges_graph_with_num_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph_with_num_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_src_name_starts_with() {
- let filter = EdgeFilter::src().name().starts_with("Tw");
- let expected_results = vec!["Two->One", "Two->Three"];
- assert_filter_edges_results(
- init_edges_graph_with_str_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph_with_str_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_src_id_ends_with() {
- let filter = EdgeFilter::src().id().ends_with("don");
- let expected_results = vec!["London->Paris"];
- assert_filter_edges_results(
- init_edges_graph_with_str_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph_with_str_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_src_id_contains() {
- let filter = EdgeFilter::src().id().contains("don");
- let expected_results = vec!["London->Paris"];
- assert_filter_edges_results(
- init_edges_graph_with_str_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_dst_id_contains() {
- let filter = EdgeFilter::dst().id().contains("Par");
- let expected_results = vec!["London->Paris"];
- assert_filter_edges_results(
- init_edges_graph_with_str_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_dst_name_not_contains() {
- let filter = EdgeFilter::dst().name().not_contains("Par");
- let expected_results = vec![
- "David Gilmour->John Mayer",
- "John Mayer->Jimmy Page",
- "Three->One",
- "Two->One",
- "Two->Three",
- ];
- assert_filter_edges_results(
- init_edges_graph_with_str_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph_with_str_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_src_id_is_in() {
- let filter = EdgeFilter::src().id().is_in(["Two"]);
- let expected_results = vec!["Two->One", "Two->Three"];
- assert_filter_edges_results(
- init_edges_graph_with_str_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph_with_str_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_dst_id_is_not_in() {
- let filter = EdgeFilter::dst().id().is_not_in(["One"]);
- let expected_results = vec![
- "David Gilmour->John Mayer",
- "John Mayer->Jimmy Page",
- "London->Paris",
- "Two->Three",
- ];
- assert_filter_edges_results(
- init_edges_graph_with_str_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph_with_str_ids,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_is_active_edge_window() {
- let filter = EdgeFilter.window(1, 3).is_active();
- let expected_results = vec!["London->Paris", "Two->Three"];
- assert_filter_edges_results(
- init_edges_graph_with_str_ids_del,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph_with_str_ids_del,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_is_active_edge_after() {
- let filter = EdgeFilter.after(3).is_active();
- let expected_results = vec![
- "Bangalore->Bangalore",
- "David Gilmour->John Mayer",
- "John Mayer->Jimmy Page",
- ];
- assert_filter_edges_results(
- init_edges_graph_with_str_ids_del,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph_with_str_ids_del,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_is_active_edge_before() {
- let filter = EdgeFilter.before(3).is_active();
- let expected_results = vec!["London->Paris", "Two->Three"];
- assert_filter_edges_results(
- init_edges_graph_with_str_ids_del,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph_with_str_ids_del,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_is_active_edge_snapshot_latest() {
- let filter = EdgeFilter.snapshot_latest().is_active();
- let expected_results = vec!["Bangalore->Bangalore"];
- assert_filter_edges_results(
- init_edges_graph_with_str_ids_del,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_edges_results(
- init_edges_graph_with_str_ids_del,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
-
- #[test]
- fn test_is_valid_edge_window() {
- let filter = EdgeFilter.window(1, 3).is_valid();
- let expected_results = vec!["London->Paris", "Two->Three"];
- assert_filter_edges_results(
- init_edges_graph_with_str_ids_del,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestGraphVariants::PersistentGraph,
- );
- assert_select_edges_results(
- init_edges_graph_with_str_ids_del,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestGraphVariants::PersistentGraph,
- );
- assert_search_edges_results(
- init_edges_graph_with_str_ids_del,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestGraphVariants::PersistentGraph,
- );
-
- let filter = EdgeFilter.window(1, 4).is_valid();
- let expected_results = vec!["Three->One", "Two->One", "Two->Three"];
- assert_filter_edges_results(
- init_edges_graph_with_str_ids_del,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestGraphVariants::PersistentGraph,
- );
- assert_select_edges_results(
- init_edges_graph_with_str_ids_del,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestGraphVariants::PersistentGraph,
- );
- assert_search_edges_results(
- init_edges_graph_with_str_ids_del,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestGraphVariants::PersistentGraph,
- );
- }
-
- #[test]
- fn test_is_valid_edge_snapshot_at() {
- let filter = EdgeFilter.snapshot_at(2).is_valid();
- let expected_results = vec!["London->Paris", "Two->Three"];
- assert_filter_edges_results(
- init_edges_graph_with_str_ids_del,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestGraphVariants::PersistentGraph,
- );
- assert_select_edges_results(
- init_edges_graph_with_str_ids_del,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestGraphVariants::PersistentGraph,
- );
- assert_search_edges_results(
- init_edges_graph_with_str_ids_del,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestGraphVariants::PersistentGraph,
- );
-
- let filter = EdgeFilter.snapshot_at(3).is_valid();
- let expected_results = vec!["Three->One", "Two->One", "Two->Three"];
- assert_filter_edges_results(
- init_edges_graph_with_str_ids_del,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestGraphVariants::PersistentGraph,
- );
- assert_select_edges_results(
- init_edges_graph_with_str_ids_del,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestGraphVariants::PersistentGraph,
- );
- assert_search_edges_results(
- init_edges_graph_with_str_ids_del,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestGraphVariants::PersistentGraph,
- );
- }
-
- #[test]
- fn test_is_valid_edge_snapshot_latest() {
- let filter = EdgeFilter.snapshot_latest().is_valid();
- let expected_results = vec![
- "Bangalore->Bangalore",
- "David Gilmour->John Mayer",
- "John Mayer->Jimmy Page",
- "Three->One",
- "Two->One",
- "Two->Three",
- ];
- assert_filter_edges_results(
- init_edges_graph_with_str_ids_del,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestGraphVariants::PersistentGraph,
- );
- assert_select_edges_results(
- init_edges_graph_with_str_ids_del,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestGraphVariants::PersistentGraph,
- );
- assert_search_edges_results(
- init_edges_graph_with_str_ids_del,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestGraphVariants::PersistentGraph,
- );
- }
-
- // Disk graph doesn't support deletions
- #[test]
- fn test_is_deleted_edge_after() {
- let filter = EdgeFilter.after(1).is_deleted();
- let expected_results = vec!["London->Paris"];
- assert_filter_edges_results(
- init_edges_graph_with_str_ids_del,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_select_edges_results(
- init_edges_graph_with_str_ids_del,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph_with_str_ids_del,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- // Disk graph doesn't support deletions
- #[test]
- fn test_is_deleted_edge_before() {
- let filter = EdgeFilter.before(4).is_deleted();
- let expected_results = vec!["London->Paris"];
- assert_filter_edges_results(
- init_edges_graph_with_str_ids_del,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_select_edges_results(
- init_edges_graph_with_str_ids_del,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph_with_str_ids_del,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_is_self_loop_edge_window() {
- let filter = EdgeFilter.window(1, 3).is_self_loop();
- let expected_results = vec![];
- assert_filter_edges_results(
- init_edges_graph_with_str_ids_del,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_select_edges_results(
- init_edges_graph_with_str_ids_del,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph_with_str_ids_del,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter.window(1, 6).is_self_loop();
- let expected_results = vec!["Bangalore->Bangalore"];
- assert_filter_edges_results(
- init_edges_graph_with_str_ids_del,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_select_edges_results(
- init_edges_graph_with_str_ids_del,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph_with_str_ids_del,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-}
-
-mod test_edge_property_filter {
- use crate::{init_edges_graph, init_edges_graph2, IdentityGraphTransformer};
- use raphtory::db::graph::views::filter::model::{
- edge_filter::EdgeFilter,
- property_filter::ops::{ElemQualifierOps, ListAggOps, PropertyFilterOps},
- ComposableFilter, PropertyFilterFactory, TemporalPropertyFilterFactory, ViewWrapOps,
- };
-
- use raphtory_api::core::entities::properties::prop::Prop;
- use raphtory_tests::assertions::{
- assert_filter_edges_results, assert_search_edges_results, TestGraphVariants, TestVariants,
- };
-
- #[test]
- fn test_filter_edges_for_property_eq() {
- // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
- let filter = EdgeFilter.property("p2").eq(2u64);
- let expected_results = vec!["2->3"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter.property("p30").temporal().first().eq("Old_boat");
- let expected_results = vec!["2->3"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter.property("p20").temporal().all().eq("Gold_ship");
- let expected_results = vec!["1->2"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_property_ne() {
- // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
- let filter = EdgeFilter.property("p2").ne(2u64);
- let expected_results = vec![
- "1->2",
- "2->1",
- "3->1",
- "David Gilmour->John Mayer",
- "John Mayer->Jimmy Page",
- ];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter.property("p30").temporal().first().ne("Old_boat");
- let expected_results = vec!["1->2"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter.property("p30").temporal().all().ne("Classic");
- let expected_results = vec!["1->2", "2->3"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_property_lt() {
- // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
- let filter = EdgeFilter.property("p2").lt(10u64);
- let expected_results = vec![
- "1->2",
- "2->1",
- "2->3",
- "3->1",
- "David Gilmour->John Mayer",
- "John Mayer->Jimmy Page",
- ];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter.property("p2").temporal().first().lt(5u64);
- let expected_results = vec!["1->2", "2->3"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter.property("p2").temporal().all().lt(10u64);
- let expected_results = vec![
- "1->2",
- "2->1",
- "2->3",
- "3->1",
- "David Gilmour->John Mayer",
- "John Mayer->Jimmy Page",
- ];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_property_le() {
- // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
- let filter = EdgeFilter.property("p2").le(6u64);
- let expected_results = vec![
- "1->2",
- "2->1",
- "2->3",
- "3->1",
- "David Gilmour->John Mayer",
- "John Mayer->Jimmy Page",
- ];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter.property("p2").temporal().first().le(3u64);
- let expected_results = vec!["2->3"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter.property("p2").temporal().all().le(5u64);
- let expected_results = vec!["1->2", "2->3"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_property_gt() {
- // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
- let filter = EdgeFilter.property("p2").gt(2u64);
- let expected_results = vec![
- "1->2",
- "2->1",
- "3->1",
- "David Gilmour->John Mayer",
- "John Mayer->Jimmy Page",
- ];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter.property("p2").temporal().first().gt(5u64);
- let expected_results = vec![
- "2->1",
- "3->1",
- "David Gilmour->John Mayer",
- "John Mayer->Jimmy Page",
- ];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter.property("p2").temporal().all().gt(5u64);
- let expected_results = vec![
- "2->1",
- "3->1",
- "David Gilmour->John Mayer",
- "John Mayer->Jimmy Page",
- ];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_property_ge() {
- // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
- let filter = EdgeFilter.property("p2").ge(2u64);
- let expected_results = vec![
- "1->2",
- "2->1",
- "2->3",
- "3->1",
- "David Gilmour->John Mayer",
- "John Mayer->Jimmy Page",
- ];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter.property("p2").temporal().first().ge(6u64);
- let expected_results = vec![
- "2->1",
- "3->1",
- "David Gilmour->John Mayer",
- "John Mayer->Jimmy Page",
- ];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter.property("p2").temporal().all().ge(6u64);
- let expected_results = vec![
- "2->1",
- "3->1",
- "David Gilmour->John Mayer",
- "John Mayer->Jimmy Page",
- ];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_property_in() {
- // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
- let filter = EdgeFilter.property("p2").is_in(vec![Prop::U64(6)]);
- let expected_results = vec![
- "2->1",
- "3->1",
- "David Gilmour->John Mayer",
- "John Mayer->Jimmy Page",
- ];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter
- .property("p2")
- .is_in(vec![Prop::U64(2), Prop::U64(6)]);
- let expected_results = vec![
- "2->1",
- "2->3",
- "3->1",
- "David Gilmour->John Mayer",
- "John Mayer->Jimmy Page",
- ];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter
- .property("p2")
- .temporal()
- .first()
- .is_in(vec![Prop::U64(6)]);
- let expected_results = vec![
- "2->1",
- "3->1",
- "David Gilmour->John Mayer",
- "John Mayer->Jimmy Page",
- ];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter
- .property("p2")
- .temporal()
- .all()
- .is_in(vec![Prop::U64(6)]);
- let expected_results = vec![
- "2->1",
- "3->1",
- "David Gilmour->John Mayer",
- "John Mayer->Jimmy Page",
- ];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_property_not_in() {
- // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
- let filter = EdgeFilter.property("p2").is_not_in(vec![Prop::U64(6)]);
- let expected_results = vec!["1->2", "2->3"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter
- .property("p2")
- .temporal()
- .first()
- .is_not_in(vec![Prop::U64(6)]);
- let expected_results = vec!["1->2", "2->3"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter
- .property("p2")
- .temporal()
- .all()
- .is_not_in(vec![Prop::U64(6)]);
- let expected_results = vec!["1->2", "2->3"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_property_is_some() {
- // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
- let filter = EdgeFilter.property("p2").is_some();
- let expected_results = vec![
- "1->2",
- "2->1",
- "2->3",
- "3->1",
- "David Gilmour->John Mayer",
- "John Mayer->Jimmy Page",
- ];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter.property("p2").temporal().first().is_some();
- let expected_results = vec![
- "1->2",
- "2->1",
- "2->3",
- "3->1",
- "David Gilmour->John Mayer",
- "John Mayer->Jimmy Page",
- ];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_property_is_none() {
- // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for both filter_edges and search_edges. Search API uses filter API internally for this filter.
- let filter = EdgeFilter.property("p2").is_none();
- let expected_results = Vec::<&str>::new();
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
-
- let filter = EdgeFilter.property("p2").temporal().first().is_none();
- let expected_results = vec![];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_property_starts_with() {
- // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
- let filter = EdgeFilter.property("p10").starts_with("Pa");
- let expected_results: Vec<&str> = vec!["1->2", "2->1", "2->3"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter
- .property("p10")
- .temporal()
- .any()
- .starts_with("Pape");
- let expected_results: Vec<&str> = vec!["1->2", "2->1", "2->3"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter
- .property("p10")
- .temporal()
- .last()
- .starts_with("Paper");
- let expected_results: Vec<&str> = vec!["1->2", "2->1", "2->3"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter
- .property("p10")
- .temporal()
- .last()
- .starts_with("Traffic");
- let expected_results: Vec<&str> = vec![];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter
- .property("p30")
- .temporal()
- .first()
- .starts_with("Old");
- let expected_results: Vec<&str> = vec!["2->3"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter
- .property("p20")
- .temporal()
- .all()
- .starts_with("Gold");
- let expected_results: Vec<&str> = vec!["1->2", "2->3"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_property_ends_with() {
- // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
- let filter = EdgeFilter.property("p10").ends_with("lane");
- let expected_results: Vec<&str> = vec!["1->2", "2->1"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter
- .property("p10")
- .temporal()
- .any()
- .ends_with("ship");
- let expected_results: Vec<&str> = vec!["2->3"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter
- .property("p10")
- .temporal()
- .last()
- .ends_with("ane");
- let expected_results: Vec<&str> = vec!["1->2", "2->1"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter
- .property("p10")
- .temporal()
- .last()
- .ends_with("marcus");
- let expected_results: Vec<&str> = vec![];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter
- .property("p20")
- .temporal()
- .first()
- .ends_with("boat");
- let expected_results: Vec<&str> = vec!["2->3"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter
- .property("p20")
- .temporal()
- .all()
- .ends_with("ship");
- let expected_results: Vec<&str> = vec!["1->2"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_property_contains() {
- // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
- let filter = EdgeFilter.property("p10").contains("Paper");
- let expected_results: Vec<&str> = vec!["1->2", "2->1", "2->3"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter
- .property("p10")
- .temporal()
- .any()
- .contains("Paper");
- let expected_results: Vec<&str> = vec!["1->2", "2->1", "2->3"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter
- .property("p10")
- .temporal()
- .last()
- .contains("Paper");
- let expected_results: Vec<&str> = vec!["1->2", "2->1", "2->3"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter
- .property("p20")
- .temporal()
- .first()
- .contains("boat");
- let expected_results: Vec<&str> = vec!["2->3"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter.property("p20").temporal().all().contains("ship");
- let expected_results: Vec<&str> = vec!["1->2"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_for_property_contains_not() {
- // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
- let filter = EdgeFilter.property("p10").not_contains("ship");
- let expected_results: Vec<&str> = vec!["1->2", "2->1"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter
- .property("p10")
- .temporal()
- .any()
- .not_contains("ship");
- let expected_results: Vec<&str> = vec!["1->2", "2->1"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter
- .property("p10")
- .temporal()
- .last()
- .not_contains("ship");
- let expected_results: Vec<&str> = vec!["1->2", "2->1"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter
- .property("p20")
- .temporal()
- .first()
- .not_contains("boat");
- let expected_results: Vec<&str> = vec!["1->2"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter
- .property("p30")
- .temporal()
- .all()
- .not_contains("ship");
- let expected_results: Vec<&str> = vec!["2->3"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_filter_edges_by_fuzzy_search() {
- // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for both filter_edges and search_edges.
- // TODO: Enable these test for event_disk_graph, persistent_disk_graph once string property is fixed.
- let filter = EdgeFilter.property("p1").fuzzy_search("shiv", 2, true);
- let expected_results: Vec<&str> = vec!["1->2"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
-
- let filter = EdgeFilter.property("p1").fuzzy_search("ShiV", 2, true);
- let expected_results: Vec<&str> = vec!["1->2"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
-
- let filter = EdgeFilter.property("p1").fuzzy_search("shiv", 2, false);
- let expected_results: Vec<&str> = vec![];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- }
-
- #[test]
- fn test_filter_edges_for_not_property() {
- // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for both filter_edges and search_edges. Search API uses filter API internally for this filter.
- let filter = EdgeFilter.property("p2").ne(2u64).not();
- let expected_results = vec!["2->3"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- }
-
- #[test]
- fn test_edges_window_filter() {
- let filter = EdgeFilter
- .window(1, 3)
- .property("p2")
- .temporal()
- .sum()
- .ge(2u64);
-
- let expected_results = vec!["1->2", "2->3"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter
- .window(1, 5)
- .property("p2")
- .temporal()
- .sum()
- .ge(2u64);
-
- let expected_results = vec![
- "1->2",
- "2->3",
- "3->1",
- "2->1",
- "David Gilmour->John Mayer",
- "John Mayer->Jimmy Page",
- ];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_edges_window_filter_on_non_temporal_property() {
- let filter1 = EdgeFilter.window(1, 2).property("p1").eq("shivam_kapoor");
- let filter2 = EdgeFilter
- .window(100, 200)
- .property("p1")
- .eq("shivam_kapoor");
-
- let expected_results = vec!["1->2"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter1.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter1.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let expected_results = vec![];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter2.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter2.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
-
- let filter2 = EdgeFilter
- .window(100, 200)
- .property("p1")
- .eq("shivam_kapoor");
- let expected_results = vec!["1->2"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter2.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter2.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
-
- #[test]
- fn test_edges_window_filter_any_all_over_window() {
- let filter_any = EdgeFilter
- .window(2, 4)
- .property("p20")
- .temporal()
- .any()
- .eq("Gold_boat");
-
- let expected_any = vec!["2->3"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter_any.clone(),
- &expected_any,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter_any.clone(),
- &expected_any,
- TestVariants::All,
- );
-
- let filter_all = EdgeFilter
- .window(2, 4)
- .property("p20")
- .temporal()
- .all()
- .eq("Gold_boat");
-
- let expected_all: Vec<&str> = vec![];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter_all.clone(),
- &expected_all,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter_all.clone(),
- &expected_all,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_edges_window_filter_and() {
- let filter1 = EdgeFilter
- .window(3, 6)
- .property("p10")
- .temporal()
- .any()
- .eq("Paper_airplane");
-
- let filter2 = EdgeFilter
- .window(3, 6)
- .property("p2")
- .temporal()
- .sum()
- .eq(6u64);
-
- let filter = filter1.and(filter2);
-
- let expected_results = vec!["2->1"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_edges_layer_filter() {
- let filter = EdgeFilter
- .layer("fire_nation")
- .property("p2")
- .temporal()
- .sum()
- .ge(2u64);
-
- let expected_results = vec!["1->2", "3->1"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_edges_at_filter() {
- // Only time=2 contributes; edge 2->3 has p2=2 at t=2
- let filter = EdgeFilter.at(2).property("p2").temporal().sum().eq(2u64);
-
- let expected_results = vec!["2->3"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- // Only time=3 contributes; edge 3->1 has p2=6 at t=3
- let filter = EdgeFilter.at(3).property("p2").temporal().sum().eq(6u64);
-
- let expected_results = vec!["3->1", "2->1"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_edges_after_filter() {
- // after(2) means t >= 3
- let filter = EdgeFilter.after(2).property("p2").temporal().sum().ge(6u64);
-
- // At t=3: 3->1 and 2->1 have p2=6
- // At t=4: David->John and John->Jimmy have p2=6
- let expected_results = vec![
- "3->1",
- "2->1",
- "David Gilmour->John Mayer",
- "John Mayer->Jimmy Page",
- ];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_edges_before_filter() {
- // before(3) means t <= 2
- let filter = EdgeFilter
- .before(3)
- .property("p2")
- .temporal()
- .sum()
- .eq(2u64);
-
- // Only t=2 contributes for p2=2 -> 2->3
- let expected_results = vec!["2->3"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- // And p2=6 edges shouldn't match, because their p2=6 lives at t=3+.
- let filter = EdgeFilter
- .before(3)
- .property("p2")
- .temporal()
- .sum()
- .eq(6u64);
-
- let expected_results = vec![];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_edges_latest_filter() {
- // At latest time (currently t=4), only the t=4 edges exist in the Event graph.
- // Use EventOnly so the expectation is stable and matches node-style.
- let filter = EdgeFilter.latest().property("p2").eq(6u64);
-
- let expected_results = vec!["David Gilmour->John Mayer", "John Mayer->Jimmy Page"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
- }
-
- #[test]
- fn test_edges_snapshot_at_semantics_event_graph() {
- let t = 2;
-
- let filter_snapshot = EdgeFilter
- .snapshot_at(t)
- .property("p2")
- .temporal()
- .sum()
- .eq(2u64);
-
- let filter_before = EdgeFilter
- .before(t + 1)
- .property("p2")
- .temporal()
- .sum()
- .eq(2u64);
-
- let expected_results = vec!["2->3"];
-
- // snapshot_at
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter_snapshot.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter_snapshot,
- &expected_results,
- TestVariants::EventOnly,
- );
-
- // before(t+1)
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter_before.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter_before,
- &expected_results,
- TestVariants::EventOnly,
- );
- }
-
- #[test]
- fn test_edges_snapshot_at_semantics_persistent_graph() {
- let t = 2;
-
- let filter_snapshot = EdgeFilter
- .snapshot_at(t)
- .property("p2")
- .temporal()
- .sum()
- .eq(2u64);
-
- let filter_at = EdgeFilter.at(t).property("p2").temporal().sum().eq(2u64);
-
- let expected_results = vec!["2->3"];
-
- // snapshot_at
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter_snapshot.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter_snapshot,
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- // at(t)
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter_at.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter_at,
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
-
- #[test]
- fn test_edges_snapshot_latest_semantics_event_graph() {
- let filter_snapshot_latest = EdgeFilter
- .snapshot_latest()
- .property("p2")
- .temporal()
- .sum()
- .ge(6u64);
-
- let filter_noop = EdgeFilter.property("p2").temporal().sum().ge(6u64);
-
- // Across the whole event history, p2=6 appears at t=3 and t=4.
- let expected_results = vec![
- "3->1",
- "2->1",
- "David Gilmour->John Mayer",
- "John Mayer->Jimmy Page",
- ];
-
- // snapshot_latest
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter_snapshot_latest.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter_snapshot_latest,
- &expected_results,
- TestVariants::EventOnly,
- );
-
- // no-op baseline
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter_noop.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter_noop,
- &expected_results,
- TestVariants::EventOnly,
- );
- }
-
- #[test]
- fn test_edges_snapshot_latest_semantics_persistent_graph() {
- let filter_snapshot_latest = EdgeFilter.snapshot_latest().property("p2").eq(6u64);
-
- let filter_latest = EdgeFilter.latest().property("p2").eq(6u64);
-
- // In persistent latest state at t=4, these edges have p2=6:
- // - t=3 edges: 3->1, 2->1
- // - t=4 edges: David->John, John->Jimmy
- let expected_results = vec![
- "3->1",
- "2->1",
- "David Gilmour->John Mayer",
- "John Mayer->Jimmy Page",
- ];
-
- // snapshot_latest
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter_snapshot_latest.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter_snapshot_latest,
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- // latest
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter_latest.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter_latest,
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
-
- #[test]
- fn test_edges_layer_then_window_ordering() {
- // In layer "fire_nation" within window [1,3), edge 1->2 matches p1 == "shivam_kapoor".
- let filter = EdgeFilter
- .layer("fire_nation")
- .window(1, 3)
- .property("p1")
- .eq("shivam_kapoor");
-
- let expected_results = vec!["1->2"];
-
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_edges_window_then_layer_ordering() {
- // Same semantics, reversed chaining order.
- let filter = EdgeFilter
- .window(1, 3)
- .layer("fire_nation")
- .property("p1")
- .eq("shivam_kapoor");
-
- let expected_results = vec!["1->2"];
-
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_edges_latest_layer() {
- let filter = EdgeFilter
- .latest()
- .layer("fire_nation")
- .property("p2")
- .temporal()
- .last()
- .eq(7u64);
-
- let expected_results = vec![];
-
- assert_filter_edges_results(
- init_edges_graph2,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- }
-
- #[test]
- fn test_edges_layer_latest() {
- let filter = EdgeFilter
- .layer("fire_nation")
- .latest()
- .property("p2")
- .temporal()
- .last()
- .eq(7u64);
-
- let expected_results = vec!["1->2"];
-
- assert_filter_edges_results(
- init_edges_graph2,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- }
-}
-
-mod test_edge_composite_filter {
- use raphtory::db::graph::views::filter::model::{
- edge_filter::EdgeFilter, node_filter::ops::NodeFilterOps,
- property_filter::ops::PropertyFilterOps, ComposableFilter, PropertyFilterFactory,
- TryAsCompositeFilter,
- };
- use raphtory_tests::assertions::{
- assert_filter_edges_results, assert_search_edges_results, TestGraphVariants, TestVariants,
- };
-
- use crate::{init_edges_graph, IdentityGraphTransformer};
-
- #[test]
- fn test_filter_edge_for_src_dst() {
- // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
- let filter = EdgeFilter::src()
- .name()
- .eq("3")
- .and(EdgeFilter::dst().name().eq("1"));
- let expected_results = vec!["3->1"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_unique_results_from_composite_filters() {
- // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
- let filter = EdgeFilter
- .property("p2")
- .ge(2u64)
- .and(EdgeFilter.property("p2").ge(1u64));
- let expected_results = vec![
- "1->2",
- "2->1",
- "2->3",
- "3->1",
- "David Gilmour->John Mayer",
- "John Mayer->Jimmy Page",
- ];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
-
- let filter = EdgeFilter
- .property("p2")
- .ge(2u64)
- .or(EdgeFilter.property("p2").ge(5u64));
- let expected_results = vec![
- "1->2",
- "2->1",
- "2->3",
- "3->1",
- "David Gilmour->John Mayer",
- "John Mayer->Jimmy Page",
- ];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- }
-
- #[test]
- fn test_composite_filter_edges() {
- // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for both filter_edges and search_edges.
- // TODO: Enable these test for event_disk_graph, persistent_disk_graph once string property is fixed.
- let filter = EdgeFilter
- .property("p2")
- .eq(2u64)
- .and(EdgeFilter.property("p1").eq("kapoor"));
- let expected_results = Vec::<&str>::new();
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- let filter = filter.try_as_composite_edge_filter().unwrap();
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter
- .property("p2")
- .eq(2u64)
- .or(EdgeFilter.property("p1").eq("shivam_kapoor"));
- let expected_results = vec!["1->2", "2->3"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- let filter = filter.try_as_composite_edge_filter().unwrap();
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter.property("p1").eq("pometry").or(EdgeFilter
- .property("p2")
- .eq(6u64)
- .and(EdgeFilter.property("p3").eq(1u64)));
- let expected_results = vec![
- "2->1",
- "3->1",
- "David Gilmour->John Mayer",
- "John Mayer->Jimmy Page",
- ];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- let filter = filter.try_as_composite_edge_filter().unwrap();
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter::src()
- .name()
- .eq("13")
- .and(EdgeFilter.property("p1").eq("prop1"));
- let expected_results = Vec::<&str>::new();
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- let filter = filter.try_as_composite_edge_filter().unwrap();
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter
- .property("p2")
- .eq(4u64)
- .and(EdgeFilter.property("p1").eq("shivam_kapoor"));
- let expected_results = vec!["1->2"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- let filter = filter.try_as_composite_edge_filter().unwrap();
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter::src()
- .name()
- .eq("1")
- .and(EdgeFilter.property("p1").eq("shivam_kapoor"));
- let expected_results = vec!["1->2"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- let filter = filter.try_as_composite_edge_filter().unwrap();
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter::dst()
- .name()
- .eq("1")
- .and(EdgeFilter.property("p2").eq(6u64));
- let expected_results = vec!["2->1", "3->1"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- let filter = filter.try_as_composite_edge_filter().unwrap();
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = EdgeFilter::src()
- .name()
- .eq("1")
- .and(EdgeFilter.property("p1").eq("shivam_kapoor"))
- .or(EdgeFilter.property("p3").eq(5u64));
- let expected_results = vec!["1->2"];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
-
- let filter = filter.try_as_composite_edge_filter().unwrap();
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_not_composite_filter_edges() {
- // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for both filter_edges and search_edges. Search API uses filter API internally for this filter.
- let filter = EdgeFilter::src()
- .name()
- .eq("13")
- .and(EdgeFilter.property("p1").eq("prop1"))
- .not();
- let expected_results = vec![
- "1->2",
- "2->1",
- "2->3",
- "3->1",
- "David Gilmour->John Mayer",
- "John Mayer->Jimmy Page",
- ];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
-
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
-
- let filter = EdgeFilter::src()
- .name()
- .eq("13")
- .and(EdgeFilter.property("p1").eq("prop1").not())
- .not();
- let expected_results = vec![
- "1->2",
- "2->1",
- "2->3",
- "3->1",
- "David Gilmour->John Mayer",
- "John Mayer->Jimmy Page",
- ];
- assert_filter_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
-
- assert_search_edges_results(
- init_edges_graph,
- IdentityGraphTransformer,
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- }
-}
-
+pub mod filter_tests;
diff --git a/raphtory-tests/tests/test_graphs.rs b/raphtory-tests/tests/test_graphs.rs
new file mode 100644
index 0000000000..8f1ba52c1f
--- /dev/null
+++ b/raphtory-tests/tests/test_graphs.rs
@@ -0,0 +1 @@
+pub mod graph_tests;
diff --git a/raphtory-tests/tests/test_io.rs b/raphtory-tests/tests/test_io.rs
new file mode 100644
index 0000000000..265b89e50a
--- /dev/null
+++ b/raphtory-tests/tests/test_io.rs
@@ -0,0 +1 @@
+pub mod io_tests;
diff --git a/raphtory-tests/tests/test_layers.rs b/raphtory-tests/tests/test_layers.rs
deleted file mode 100644
index 78b07db14b..0000000000
--- a/raphtory-tests/tests/test_layers.rs
+++ /dev/null
@@ -1,799 +0,0 @@
-use itertools::Itertools;
-use proptest::proptest;
-use raphtory::{
- db::graph::{graph::assert_graph_equal, views::deletion_graph::PersistentGraph},
- prelude::*,
-};
-use raphtory_api::core::entities::GID;
-use raphtory_tests::{
- test_storage,
- utils::{build_graph, build_graph_layer, build_graph_strat, GraphFixture},
-};
-use serde_json::json;
-
-#[test]
-fn proptest_layering() {
- proptest!(|(graph_f in build_graph_strat(10, 10, 10, 10, false), layer in proptest::sample::subsequence(&["_default", "a", "b"], 0..3))| {
- let g_layer_expected = Graph::from(build_graph_layer(&graph_f, &layer));
- let g = Graph::from(build_graph(&graph_f));
- let g_layer = g.valid_layers(layer.clone());
- assert_graph_equal(&g_layer, &g_layer_expected);
- })
-}
-
-#[test]
-fn test_node_explicit_node_additions() {
- let graph_f: GraphFixture = serde_json::from_value(json!({"nodes":{"10":{"props":{"t_props":[[0,[]]],"c_props":[]},"node_type":null}},"edges":[]})).unwrap();
- let layer = [];
- let g_layer_expected = Graph::from(build_graph_layer(&graph_f, &layer));
- let g = Graph::from(build_graph(&graph_f));
- let g_layer = g.valid_layers(layer.clone());
-
- assert_graph_equal(&g_layer, &g_layer_expected);
-}
-
-#[test]
-fn test_failure() {
- let graph_f: GraphFixture = serde_json::from_value(json!({"nodes":{},"edges":[[[0,0,"a"],{"props":{"t_props":[[0,[]]],"c_props":[]},"deletions":[]}],[[3,9,"b"],{"props":{"t_props":[[0,[]]],"c_props":[]},"deletions":[]}],[[9,3,"b"],{"props":{"t_props":[[0,[]]],"c_props":[]},"deletions":[]}],[[0,0,null],{"props":{"t_props":[[0,[]]],"c_props":[]},"deletions":[]}]]})).unwrap();
- let layer = ["_default", "b"];
- let g_layer_expected = Graph::from(build_graph_layer(&graph_f, &layer));
- let g = Graph::from(build_graph(&graph_f));
- let g_layer = g.valid_layers(layer.clone());
-
- assert_graph_equal(&g_layer, &g_layer_expected);
-}
-
-#[test]
-fn test_failure2() {
- let graph_f: GraphFixture = serde_json::from_value(json!({"nodes":{},"edges":[[[0,0,null],{"props":{"t_props":[[0,[]]],"c_props":[]},"deletions":[]}],[[0,0,"a"],{"props":{"t_props":[[0,[]]],"c_props":[]},"deletions":[]}],[[0,0,"b"],{"props":{"t_props":[[0,[]]],"c_props":[]},"deletions":[]}]]})).unwrap();
- let layer = ["_default", "b"];
- let g_layer_expected = Graph::from(build_graph_layer(&graph_f, &layer));
- let g = Graph::from(build_graph(&graph_f));
- let g_layer = g.valid_layers(layer.clone());
-
- assert_graph_equal(&g_layer, &g_layer_expected);
-}
-
-#[test]
-fn test_failure3() {
- let graph_f: GraphFixture = serde_json::from_value(json!({"nodes":{},"edges":[[[0,0,null],{"props":{"t_props":[[0,[]]],"c_props":[]},"deletions":[]}],[[0,0,"b"],{"props":{"t_props":[[0,[]]],"c_props":[]},"deletions":[]}],[[0,1,"a"],{"props":{"t_props":[[0,[]]],"c_props":[]},"deletions":[]}]]})).unwrap();
- let layer = ["_default", "b"];
- let g_layer_expected = Graph::from(build_graph_layer(&graph_f, &layer));
- let g = Graph::from(build_graph(&graph_f));
- let g_layer = g.valid_layers(layer.clone());
-
- assert_graph_equal(&g_layer, &g_layer_expected);
-}
-
-// Regression for the build_graph_layer node-layer filter
-#[test]
-fn test_node_layer_visibility_under_valid_layers() {
- let graph_f: GraphFixture = serde_json::from_value(json!({
- "nodes": {
- "1": {"props":{"t_props":[[0,[]]],"c_props":[]}, "node_type": null, "node_layer": null},
- "2": {"props":{"t_props":[[0,[]]],"c_props":[]}, "node_type": null, "node_layer": "a"},
- "3": {"props":{"t_props":[[0,[]]],"c_props":[]}, "node_type": null, "node_layer": "b"}
- },
- "edges": []
- }))
- .unwrap();
-
- let layer = ["b"];
- let g_layer_expected = Graph::from(build_graph_layer(&graph_f, &layer));
- let g = Graph::from(build_graph(&graph_f));
- let g_layer = g.valid_layers(layer.clone());
-
- assert_graph_equal(&g_layer, &g_layer_expected);
-}
-
-#[test]
-fn proptest_layering_persistent_graph() {
- proptest!(|(graph_f in build_graph_strat(10, 10, 10, 10, true), layer in proptest::sample::subsequence(&["_default", "a", "b"], 0..3))| {
- let g_layer_expected = PersistentGraph::from(build_graph_layer(&graph_f, &layer));
- let g = PersistentGraph::from(build_graph(&graph_f));
- let g_layer = g.valid_layers(layer);
- assert_graph_equal(&g_layer, &g_layer_expected);
- })
-}
-
-#[test]
-fn test_layer_node() {
- let graph = Graph::new();
-
- graph.add_edge(0, 1, 2, NO_PROPS, Some("layer1")).unwrap();
- graph.add_edge(0, 2, 3, NO_PROPS, Some("layer2")).unwrap();
- graph.add_edge(3, 2, 4, NO_PROPS, Some("layer1")).unwrap();
- graph.add_edge(1, 4, 1, NO_PROPS, Some("layer3")).unwrap();
-
- test_storage!(&graph, |graph| {
- let neighbours = graph
- .layers(vec!["layer1", "layer2"])
- .unwrap()
- .node(1)
- .unwrap()
- .neighbours()
- .into_iter()
- .collect_vec();
- assert_eq!(
- neighbours[0]
- .layers("layer2")
- .unwrap()
- .edges()
- .id()
- .collect_vec(),
- vec![(GID::U64(2), GID::U64(3))]
- );
- assert_eq!(
- graph
- .layers("layer2")
- .unwrap()
- .node(neighbours[0].name())
- .unwrap()
- .edges()
- .id()
- .collect_vec(),
- vec![(GID::U64(2), GID::U64(3))]
- );
- let mut edges = graph
- .layers("layer1")
- .unwrap()
- .node(neighbours[0].name())
- .unwrap()
- .edges()
- .id()
- .filter_map(|(a, b)| a.to_u64().zip(b.to_u64()))
- .collect_vec();
- edges.sort();
- assert_eq!(edges, vec![(1, 2), (2, 4)]);
- let mut edges = graph
- .layers("layer1")
- .unwrap()
- .edges()
- .id()
- .filter_map(|(a, b)| a.to_u64().zip(b.to_u64()))
- .collect_vec();
- edges.sort();
- assert_eq!(edges, vec![(1, 2), (2, 4)]);
- let mut edges = graph
- .layers(vec!["layer1", "layer2"])
- .unwrap()
- .edges()
- .id()
- .filter_map(|(a, b)| a.to_u64().zip(b.to_u64()))
- .collect_vec();
- edges.sort();
- assert_eq!(edges, vec![(1, 2), (2, 3), (2, 4)]);
-
- let mut edges = graph
- .layers(["layer1", "layer3"])
- .unwrap()
- .window(0, 2)
- .edges()
- .id()
- .filter_map(|(a, b)| a.to_u64().zip(b.to_u64()))
- .collect_vec();
- edges.sort();
- assert_eq!(edges, vec![(1, 2), (4, 1)]);
- });
-}
-
-#[test]
-fn layering_tests() {
- let graph = Graph::new();
- let e1 = graph.add_edge(0, 1, 2, NO_PROPS, Some("1")).unwrap();
- graph.add_edge(1, 1, 2, NO_PROPS, Some("2")).unwrap();
-
- println!("edge: {e1:?}");
- // FIXME: this is weird, see issue #1458
- assert!(e1.has_layer("2"));
- let history = e1.layers("2").unwrap().history();
- println!("history: {:?}", history);
- assert!(e1.layers("2").unwrap().history().is_empty());
-
- test_storage!(&graph, |graph| {
- let e = graph.edge(1, 2).unwrap();
- // layers with non-existing layers errors
- assert!(e.layers(["1", "3"]).is_err());
- // valid_layers ignores non-existing layers
- assert_eq!(e.valid_layers(["1", "3"]).layer_names(), ["1"]);
- assert!(e.has_layer("1"));
- assert!(e.has_layer("2"));
- assert!(!e.has_layer("3"));
- assert!(e.valid_layers("1").has_layer("1"));
- assert!(!e.valid_layers("1").has_layer("2"));
- });
-}
-
-pub mod test_filters_layer_graph {
- use raphtory::{
- db::{
- api::view::StaticGraphViewOps,
- graph::views::{layer_graph::LayeredGraph, window_graph::WindowedGraph},
- },
- prelude::{LayerOps, TimeOps},
- };
- use raphtory_tests::assertions::GraphTransformer;
- use std::ops::Range;
-
- struct LayeredGraphTransformer(Vec);
-
- impl GraphTransformer for LayeredGraphTransformer {
- type Return = LayeredGraph;
- fn apply(&self, graph: G) -> Self::Return {
- graph.layers(self.0.clone()).unwrap()
- }
- }
-
- struct LayeredGraphWindowTransformer(Vec, Range);
-
- impl GraphTransformer for LayeredGraphWindowTransformer {
- type Return = WindowedGraph>;
- fn apply(&self, graph: G) -> Self::Return {
- graph
- .layers(self.0.clone())
- .unwrap()
- .window(self.1.start, self.1.end)
- }
- }
-
- pub mod test_nodes_filters_layer_graph {
- use raphtory::{
- db::{
- api::view::StaticGraphViewOps,
- graph::views::filter::model::property_filter::ops::PropertyFilterOps,
- },
- prelude::AdditionOps,
- };
- use raphtory_api::core::entities::properties::prop::Prop;
-
- use crate::test_filters_layer_graph::{
- LayeredGraphTransformer, LayeredGraphWindowTransformer,
- };
- use raphtory::{
- db::graph::views::filter::model::PropertyFilterFactory, prelude::NodeFilter,
- };
-
- use raphtory_tests::assertions::{
- assert_filter_nodes_results, assert_search_nodes_results, TestGraphVariants,
- TestVariants,
- };
- fn init_graph(graph: G) -> G {
- let edges = vec![
- (6, "N1", "N2", vec![("p1", Prop::U64(2u64))], Some("layer1")),
- (7, "N1", "N2", vec![("p1", Prop::U64(1u64))], Some("layer2")),
- (6, "N2", "N3", vec![("p1", Prop::U64(1u64))], Some("layer1")),
- (7, "N2", "N3", vec![("p1", Prop::U64(2u64))], Some("layer2")),
- (8, "N3", "N4", vec![("p1", Prop::U64(1u64))], Some("layer1")),
- (9, "N4", "N5", vec![("p1", Prop::U64(1u64))], Some("layer1")),
- (5, "N5", "N6", vec![("p1", Prop::U64(1u64))], Some("layer1")),
- (6, "N5", "N6", vec![("p1", Prop::U64(2u64))], Some("layer2")),
- (5, "N6", "N7", vec![("p1", Prop::U64(1u64))], Some("layer1")),
- (6, "N6", "N7", vec![("p1", Prop::U64(1u64))], Some("layer2")),
- (3, "N7", "N8", vec![("p1", Prop::U64(1u64))], Some("layer1")),
- (5, "N7", "N8", vec![("p1", Prop::U64(1u64))], Some("layer2")),
- (3, "N8", "N1", vec![("p1", Prop::U64(1u64))], Some("layer1")),
- (4, "N8", "N1", vec![("p1", Prop::U64(2u64))], Some("layer2")),
- ];
-
- for (id, src, tgt, props, layer) in &edges {
- graph
- .add_edge(*id, src, tgt, props.clone(), *layer)
- .unwrap();
- }
-
- let nodes = vec![
- (6, "N1", vec![("p1", Prop::U64(2u64))], Some("air_nomad")),
- (7, "N1", vec![("p1", Prop::U64(1u64))], Some("air_nomad")),
- (6, "N2", vec![("p1", Prop::U64(1u64))], Some("water_tribe")),
- (7, "N2", vec![("p1", Prop::U64(2u64))], Some("water_tribe")),
- (8, "N3", vec![("p1", Prop::U64(1u64))], Some("air_nomad")),
- (9, "N4", vec![("p1", Prop::U64(1u64))], Some("air_nomad")),
- (5, "N5", vec![("p1", Prop::U64(1u64))], Some("air_nomad")),
- (6, "N5", vec![("p1", Prop::U64(2u64))], Some("air_nomad")),
- (5, "N6", vec![("p1", Prop::U64(1u64))], Some("fire_nation")),
- (6, "N6", vec![("p1", Prop::U64(1u64))], Some("fire_nation")),
- (3, "N7", vec![("p1", Prop::U64(1u64))], Some("air_nomad")),
- (5, "N7", vec![("p1", Prop::U64(1u64))], Some("air_nomad")),
- (3, "N8", vec![("p1", Prop::U64(1u64))], Some("fire_nation")),
- (4, "N8", vec![("p1", Prop::U64(2u64))], Some("fire_nation")),
- ];
-
- for (id, name, props, label) in &nodes {
- graph
- .add_node(*id, name, props.clone(), *label, None)
- .unwrap();
- }
-
- graph
- }
-
- // Layers don't have any effect on the number of nodes in a graph.
- // In other words, it is as good as applying no layer filters.
- #[test]
- fn test_nodes_filters() {
- let layers: Vec = vec!["layer1".into(), "layer2".into()];
- let filter = NodeFilter.property("p1").eq(1u64);
- let expected_results = vec!["N1", "N3", "N4", "N6", "N7"];
- assert_filter_nodes_results(
- init_graph,
- LayeredGraphTransformer(layers.clone()),
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_graph,
- LayeredGraphTransformer(layers),
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let layers: Vec = vec!["layer1".into()];
- let filter = NodeFilter.property("p1").ge(2u64);
- let expected_results = vec!["N2", "N5", "N8"];
- assert_filter_nodes_results(
- init_graph,
- LayeredGraphTransformer(layers.clone()),
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_graph,
- LayeredGraphTransformer(layers),
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let layers: Vec = vec!["layer2".into()];
- let filter = NodeFilter.property("p1").le(1u64);
- let expected_results = vec!["N1", "N3", "N4", "N6", "N7"];
- assert_filter_nodes_results(
- init_graph,
- LayeredGraphTransformer(layers.clone()),
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_graph,
- LayeredGraphTransformer(layers),
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let layers: Vec = vec!["layer1".into()];
- let filter = NodeFilter.property("p1").lt(2u64);
- let expected_results = vec!["N1", "N3", "N4", "N6", "N7"];
- assert_filter_nodes_results(
- init_graph,
- LayeredGraphTransformer(layers.clone()),
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_graph,
- LayeredGraphTransformer(layers),
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let layers: Vec = vec!["layer2".into()];
- let filter = NodeFilter.property("p1").gt(1u64);
- let expected_results = vec!["N2", "N5", "N8"];
- assert_filter_nodes_results(
- init_graph,
- LayeredGraphTransformer(layers.clone()),
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_nodes_results(
- init_graph,
- LayeredGraphTransformer(layers),
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_nodes_filters_w() {
- // TODO: Enable event_disk_graph for filter_nodes once bug fixed: https://github.com/Pometry/Raphtory/issues/2098
- let layers: Vec = vec!["layer1".into(), "layer2".into()];
- let filter = NodeFilter.property("p1").eq(1u64);
- let expected_results = vec!["N1", "N3", "N6"];
- assert_filter_nodes_results(
- init_graph,
- LayeredGraphWindowTransformer(layers.clone(), 6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- LayeredGraphWindowTransformer(layers.clone(), 6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
-
- let layers: Vec = vec!["layer1".into()];
- let filter = NodeFilter.property("p1").ge(2u64);
- let expected_results = vec!["N2", "N5"];
- assert_filter_nodes_results(
- init_graph,
- LayeredGraphWindowTransformer(layers.clone(), 6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- LayeredGraphWindowTransformer(layers.clone(), 6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
-
- let layers: Vec = vec!["layer2".into()];
- let filter = NodeFilter.property("p1").lt(2u64);
- let expected_results = vec!["N1", "N3", "N6"];
- assert_filter_nodes_results(
- init_graph,
- LayeredGraphWindowTransformer(layers.clone(), 6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- LayeredGraphWindowTransformer(layers.clone(), 6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
- }
-
- #[test]
- fn test_nodes_filters_pg_w() {
- let layers: Vec = vec!["layer1".into(), "layer2".into()];
- let filter = NodeFilter.property("p1").eq(1u64);
- let expected_results = vec!["N1", "N3", "N6", "N7"];
- assert_filter_nodes_results(
- init_graph,
- LayeredGraphWindowTransformer(layers.clone(), 6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- LayeredGraphWindowTransformer(layers.clone(), 6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let layers: Vec = vec!["layer1".into()];
- let filter = NodeFilter.property("p1").lt(2u64);
- let expected_results = vec!["N1", "N3", "N6", "N7"];
- assert_filter_nodes_results(
- init_graph,
- LayeredGraphWindowTransformer(layers.clone(), 6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- LayeredGraphWindowTransformer(layers.clone(), 6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let layers: Vec = vec!["layer2".into()];
- let filter = NodeFilter.property("p1").gt(1u64);
- let expected_results = vec!["N2", "N5", "N8"];
- assert_filter_nodes_results(
- init_graph,
- LayeredGraphWindowTransformer(layers.clone(), 6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- LayeredGraphWindowTransformer(layers.clone(), 6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
- }
-
- mod test_edges_filters_layer_graph {
- use raphtory::{
- db::{
- api::view::StaticGraphViewOps,
- graph::views::filter::model::{
- property_filter::ops::PropertyFilterOps, PropertyFilterFactory,
- },
- },
- prelude::{AdditionOps, EdgeFilter},
- };
- use raphtory_api::core::entities::properties::prop::Prop;
- use raphtory_tests::assertions::{
- assert_filter_edges_results, assert_search_edges_results, TestGraphVariants,
- TestVariants,
- };
-
- use crate::test_filters_layer_graph::{
- LayeredGraphTransformer, LayeredGraphWindowTransformer,
- };
-
- fn init_graph(graph: G) -> G {
- let edges = vec![
- (6, "N1", "N2", 2u64, "layer1"),
- (7, "N1", "N2", 1u64, "layer2"),
- (6, "N2", "N3", 1u64, "layer1"),
- (7, "N2", "N3", 2u64, "layer2"),
- (8, "N3", "N4", 1u64, "layer1"),
- (9, "N4", "N5", 1u64, "layer1"),
- (5, "N5", "N6", 1u64, "layer1"),
- (6, "N5", "N6", 2u64, "layer2"),
- (5, "N6", "N7", 1u64, "layer1"),
- (6, "N6", "N7", 1u64, "layer2"),
- (3, "N7", "N8", 1u64, "layer1"),
- (5, "N7", "N8", 1u64, "layer2"),
- (3, "N8", "N1", 1u64, "layer1"),
- (4, "N8", "N1", 2u64, "layer2"),
- ];
-
- for (ts, src, dst, p1_val, layer) in edges {
- graph
- .add_edge(ts, src, dst, [("p1", Prop::U64(p1_val))], Some(layer))
- .unwrap();
- }
-
- graph
- }
-
- #[test]
- fn test_edges_filters() {
- // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph.
- let layers: Vec = vec!["layer1".into(), "layer2".into()];
- let filter = EdgeFilter.property("p1").eq(1u64);
- let expected_results = vec!["N1->N2", "N3->N4", "N4->N5", "N6->N7", "N7->N8"];
- assert_filter_edges_results(
- init_graph,
- LayeredGraphTransformer(layers.clone()),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- LayeredGraphTransformer(layers),
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let layers: Vec = vec!["layer1".into()];
- let filter = EdgeFilter.property("p1").le(1u64);
- let expected_results = vec![
- "N2->N3", "N3->N4", "N4->N5", "N5->N6", "N6->N7", "N7->N8", "N8->N1",
- ];
- assert_filter_edges_results(
- init_graph,
- LayeredGraphTransformer(layers.clone()),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- LayeredGraphTransformer(layers),
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let layers: Vec = vec!["layer2".into()];
- let filter = EdgeFilter.property("p1").ge(2u64);
- let expected_results = vec!["N2->N3", "N5->N6", "N8->N1"];
- assert_filter_edges_results(
- init_graph,
- LayeredGraphTransformer(layers.clone()),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- LayeredGraphTransformer(layers),
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let layers: Vec = vec!["layer1".into()];
- let filter = EdgeFilter.property("p1").lt(2u64);
- let expected_results = vec![
- "N2->N3", "N3->N4", "N4->N5", "N5->N6", "N6->N7", "N7->N8", "N8->N1",
- ];
- assert_filter_edges_results(
- init_graph,
- LayeredGraphTransformer(layers.clone()),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- LayeredGraphTransformer(layers),
- filter,
- &expected_results,
- TestVariants::All,
- );
-
- let layers: Vec = vec!["layer2".into()];
- let filter = EdgeFilter.property("p1").gt(1u64);
- let expected_results = vec!["N2->N3", "N5->N6", "N8->N1"];
- assert_filter_edges_results(
- init_graph,
- LayeredGraphTransformer(layers.clone()),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- LayeredGraphTransformer(layers),
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_edges_filter_w() {
- // Edge Property Semantics:
- // 1. All property updates to an edge belong to a layer (or _default if no layer specified)
- // 2. However, when asked for a value of a particular property for an edge, the latest update
- // across all specified layers (or all layers if no layers specified) is returned!
- let layers: Vec = vec!["layer1".into(), "layer2".into()];
- let filter = EdgeFilter.property("p1").eq(1u64);
- let expected_results = vec!["N1->N2", "N3->N4", "N6->N7"];
- assert_filter_edges_results(
- init_graph,
- LayeredGraphWindowTransformer(layers.clone(), 6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- LayeredGraphWindowTransformer(layers, 6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
-
- // Edge Property Semantics:
- // When filtering by specific layer, filter criteria (p1==1) and latest semantics is applicable
- // only to that specific layer.
- let layers: Vec = vec!["layer1".into()];
- let filter = EdgeFilter.property("p1").lt(2u64);
- let expected_results = vec!["N2->N3", "N3->N4"];
- assert_filter_edges_results(
- init_graph,
- LayeredGraphWindowTransformer(layers.clone(), 6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- LayeredGraphWindowTransformer(layers, 6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
-
- let layers: Vec = vec!["layer2".into()];
- let filter = EdgeFilter.property("p1").gt(1u64);
- let expected_results = vec!["N2->N3", "N5->N6"];
- assert_filter_edges_results(
- init_graph,
- LayeredGraphWindowTransformer(layers.clone(), 6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- LayeredGraphWindowTransformer(layers, 6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
- }
-
- #[test]
- fn test_edges_filters_pg_w() {
- // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph.
- let layers: Vec = vec!["layer1".into(), "layer2".into()];
- let filter = EdgeFilter.property("p1").eq(1u64);
-
- // Why is the edge N8 -> N1 included in the results?
- // The reason edge N8 -> N1 is included as part of the results because of following two semantic reasons:
- // .add_edge(3, "N8", "N1", [("p1", Prop::U64(1u64))], Some("layer1"))
- // .add_edge(4, "N8", "N1", [("p1", Prop::U64(2u64))], Some("layer2"))
- // 1. As per layer graph semantics, every edge update belongs to a particular layer (or '_default' if no layer specified).
- // This means the last_before is computed per layer and not across layers. In other words, when computing
- // last_before for (N8->N1, layer1) and window(6, 9), t = 3 is the correct last before edge update timestamp and not t = 4
- // because t=4 edge update is in layer2.
- // 2. Since the search is conducted across both the layers i.e., layer1 and layer2, the results are union of
- // results from both layer1 and layer2.
- let expected_results = vec!["N1->N2", "N3->N4", "N6->N7", "N7->N8"];
- assert_filter_edges_results(
- init_graph,
- LayeredGraphWindowTransformer(layers.clone(), 6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::PersistentGraph],
- );
- assert_search_edges_results(
- init_graph,
- LayeredGraphWindowTransformer(layers, 6..9),
- filter,
- &expected_results,
- vec![TestGraphVariants::PersistentGraph],
- );
-
- let layers: Vec = vec!["layer1".into()];
- let filter = EdgeFilter.property("p1").le(1u64);
- let expected_results = vec!["N2->N3", "N3->N4", "N5->N6", "N6->N7", "N7->N8", "N8->N1"];
- assert_filter_edges_results(
- init_graph,
- LayeredGraphWindowTransformer(layers.clone(), 6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::PersistentGraph],
- );
- assert_search_edges_results(
- init_graph,
- LayeredGraphWindowTransformer(layers, 6..9),
- filter,
- &expected_results,
- vec![TestGraphVariants::PersistentGraph],
- );
-
- let layers: Vec = vec!["layer2".into()];
- let filter = EdgeFilter.property("p1").ge(2u64);
- let expected_results = vec!["N2->N3", "N5->N6", "N8->N1"];
- assert_filter_edges_results(
- init_graph,
- LayeredGraphWindowTransformer(layers.clone(), 6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::PersistentGraph],
- );
- assert_search_edges_results(
- init_graph,
- LayeredGraphWindowTransformer(layers, 6..9),
- filter,
- &expected_results,
- vec![TestGraphVariants::PersistentGraph],
- );
- }
- }
-}
diff --git a/raphtory-tests/tests/test_nodes_edges.rs b/raphtory-tests/tests/test_nodes_edges.rs
new file mode 100644
index 0000000000..bc73567639
--- /dev/null
+++ b/raphtory-tests/tests/test_nodes_edges.rs
@@ -0,0 +1 @@
+pub mod node_edge_tests;
diff --git a/raphtory-tests/tests/test_views.rs b/raphtory-tests/tests/test_views.rs
new file mode 100644
index 0000000000..610211aa15
--- /dev/null
+++ b/raphtory-tests/tests/test_views.rs
@@ -0,0 +1 @@
+pub mod view_tests;
diff --git a/raphtory-tests/tests/view_tests/cached_view.rs b/raphtory-tests/tests/view_tests/cached_view.rs
new file mode 100644
index 0000000000..dab69c3817
--- /dev/null
+++ b/raphtory-tests/tests/view_tests/cached_view.rs
@@ -0,0 +1,122 @@
+use itertools::Itertools;
+use proptest::prelude::*;
+use raphtory::{
+ algorithms::motifs::triangle_count::triangle_count, db::graph::graph::assert_graph_equal,
+ prelude::*,
+};
+use raphtory_api::core::storage::timeindex::AsTime;
+use raphtory_tests::test_storage;
+
+#[test]
+fn empty_graph() {
+ let graph = Graph::new();
+ test_storage!(&graph, |graph| {
+ let sg = graph.cache_view();
+ assert_graph_equal(&sg, &graph);
+ });
+}
+
+#[test]
+fn empty_window() {
+ let graph = Graph::new();
+ graph.add_edge(1, 1, 1, NO_PROPS, None).unwrap();
+ test_storage!(&graph, |graph| {
+ let window = graph.window(2, 3);
+ let sg = window.cache_view();
+ assert_graph_equal(&window, &sg);
+ });
+}
+
+#[test]
+fn test_materialize_no_edges() {
+ let graph = Graph::new();
+
+ graph.add_node(1, 1, NO_PROPS, None, None).unwrap();
+ graph.add_node(2, 2, NO_PROPS, None, None).unwrap();
+
+ test_storage!(&graph, |graph| {
+ let sg = graph.cache_view();
+
+ let actual = sg.materialize().unwrap().into_events().unwrap();
+ assert_graph_equal(&actual, &sg);
+ });
+}
+
+#[test]
+fn test_mask_the_window_50pc() {
+ let graph = Graph::new();
+ let edges = vec![
+ (1, 2, 1),
+ (1, 3, 2),
+ (1, 4, 3),
+ (3, 1, 4),
+ (3, 4, 5),
+ (3, 5, 6),
+ (4, 5, 7),
+ (5, 6, 8),
+ (5, 8, 9),
+ (7, 5, 10),
+ (8, 5, 11),
+ (1, 9, 12),
+ (9, 1, 13),
+ (6, 3, 14),
+ (4, 8, 15),
+ (8, 3, 16),
+ (5, 10, 17),
+ (10, 5, 18),
+ (10, 8, 19),
+ (1, 11, 20),
+ (11, 1, 21),
+ (9, 11, 22),
+ (11, 9, 23),
+ ];
+ for (src, dst, ts) in edges {
+ graph.add_edge(ts, src, dst, NO_PROPS, None).unwrap();
+ }
+ test_storage!(&graph, |graph| {
+ let window = graph.window(12, 24);
+ let mask = window.cache_view();
+ let ts = triangle_count(&mask, None);
+ let tg = triangle_count(&window, None);
+ assert_eq!(ts, tg);
+ });
+}
+
+#[test]
+fn masked_always_equals_proptest() {
+ fn check(edge_list: &[(u8, u8, i16, u8)]) {
+ let graph = Graph::new();
+ for (src, dst, ts, layer) in edge_list {
+ graph
+ .add_edge(
+ *ts as i64,
+ *src as u64,
+ *dst as u64,
+ NO_PROPS,
+ Some(&layer.to_string()),
+ )
+ .unwrap();
+ }
+
+ test_storage!(&graph, |graph| {
+ let layers = graph
+ .unique_layers()
+ .take(graph.unique_layers().count() / 2)
+ .collect_vec();
+
+ let earliest = graph.earliest_time().unwrap().t();
+ let latest = graph.latest_time().unwrap().t();
+ let middle = earliest + (latest - earliest) / 2;
+
+ if !layers.is_empty() && earliest < middle && middle < latest {
+ let subgraph = graph.layers(layers).unwrap().window(earliest, middle);
+ let masked = subgraph.cache_view();
+ assert_graph_equal(&subgraph, &masked);
+ }
+ });
+ }
+
+ proptest!(|(edge_list in any::>().prop_filter("greater than 3",|v| !v.is_empty() ))| {
+ check(&edge_list);
+ })
+}
diff --git a/raphtory-tests/tests/view_tests/mod.rs b/raphtory-tests/tests/view_tests/mod.rs
new file mode 100644
index 0000000000..91154462b9
--- /dev/null
+++ b/raphtory-tests/tests/view_tests/mod.rs
@@ -0,0 +1,5 @@
+mod cached_view;
+mod subgraph_tests;
+mod test_layers;
+mod time_tests;
+mod views_test;
diff --git a/raphtory-tests/tests/view_tests/subgraph_tests.rs b/raphtory-tests/tests/view_tests/subgraph_tests.rs
new file mode 100644
index 0000000000..1b75a8c162
--- /dev/null
+++ b/raphtory-tests/tests/view_tests/subgraph_tests.rs
@@ -0,0 +1,187 @@
+use ahash::HashSet;
+use itertools::Itertools;
+use proptest::{proptest, sample::subsequence};
+use raphtory::{
+ algorithms::{components::weakly_connected_components, motifs::triangle_count::triangle_count},
+ db::graph::{graph::assert_graph_equal, views::deletion_graph::PersistentGraph},
+ prelude::*,
+};
+use raphtory_storage::mutation::addition_ops::InternalAdditionOps;
+use raphtory_tests::{
+ test_storage,
+ utils::{build_graph, build_graph_strat},
+};
+use serde_json::json;
+use std::collections::BTreeSet;
+
+#[test]
+fn test_materialize_no_edges() {
+ let graph = Graph::new();
+
+ graph.add_node(1, 1, NO_PROPS, None, None).unwrap();
+ graph.add_node(2, 2, NO_PROPS, None, None).unwrap();
+
+ test_storage!(&graph, |graph| {
+ let sg = graph.subgraph([1, 2, 1]); // <- duplicated nodes should have no effect
+
+ let actual = sg.materialize().unwrap().into_events().unwrap();
+ assert_graph_equal(&actual, &sg);
+ });
+}
+
+#[test]
+fn test_remove_degree1_triangle_count() {
+ let graph = Graph::new();
+ let edges = vec![
+ (1, 2, 1),
+ (1, 3, 2),
+ (1, 4, 3),
+ (3, 1, 4),
+ (3, 4, 5),
+ (3, 5, 6),
+ (4, 5, 7),
+ (5, 6, 8),
+ (5, 8, 9),
+ (7, 5, 10),
+ (8, 5, 11),
+ (1, 9, 12),
+ (9, 1, 13),
+ (6, 3, 14),
+ (4, 8, 15),
+ (8, 3, 16),
+ (5, 10, 17),
+ (10, 5, 18),
+ (10, 8, 19),
+ (1, 11, 20),
+ (11, 1, 21),
+ (9, 11, 22),
+ (11, 9, 23),
+ ];
+ for (src, dst, ts) in edges {
+ graph.add_edge(ts, src, dst, NO_PROPS, None).unwrap();
+ }
+ test_storage!(&graph, |graph| {
+ let subgraph = graph.subgraph(graph.nodes().into_iter().filter(|v| v.degree() > 1));
+ let ts = triangle_count(&subgraph, None);
+ let tg = triangle_count(graph, None);
+ assert_eq!(ts, tg)
+ });
+}
+
+#[test]
+fn layer_materialize() {
+ let graph = Graph::new();
+ graph.add_edge(0, 1, 2, NO_PROPS, Some("1")).unwrap();
+ graph.add_edge(0, 3, 4, NO_PROPS, Some("2")).unwrap();
+
+ test_storage!(&graph, |graph| {
+ let sg = graph.subgraph([1, 2]);
+ let sgm = sg.materialize().unwrap();
+ assert_eq!(
+ sg.unique_layers().collect_vec(),
+ sgm.unique_layers().collect_vec()
+ );
+ });
+}
+
+#[test]
+fn test_cc() {
+ let graph = Graph::new();
+ graph.add_node(0, 0, NO_PROPS, None, None).unwrap();
+ graph.add_node(0, 3, NO_PROPS, None, None).unwrap();
+ graph.add_node(1, 2, NO_PROPS, None, None).unwrap();
+ graph.add_node(1, 4, NO_PROPS, None, None).unwrap();
+ graph.add_edge(0, 0, 1, NO_PROPS, Some("1")).unwrap();
+ graph.add_edge(1, 3, 4, NO_PROPS, Some("1")).unwrap();
+ let sg = graph.subgraph([0, 1, 3, 4]);
+ let cc = weakly_connected_components(&sg);
+ let groups = cc.groups();
+ let group_sets = groups
+ .iter()
+ .map(|(_, g)| {
+ g.iter()
+ .map(|node| node.id())
+ .sorted()
+ .collect::>()
+ })
+ .collect::>();
+ assert_eq!(
+ group_sets,
+ HashSet::from_iter([
+ BTreeSet::from([GID::U64(0), GID::U64(1)]),
+ BTreeSet::from([GID::U64(3), GID::U64(4)])
+ ])
+ );
+}
+
+#[test]
+fn test_layer_edges() {
+ let graph = Graph::new();
+ graph.add_edge(0, 0, 1, NO_PROPS, Some("1")).unwrap();
+ graph.add_edge(1, 0, 1, NO_PROPS, Some("2")).unwrap();
+
+ assert_eq!(
+ graph.subgraph([0, 1]).edges().id().collect_vec(),
+ [(GID::U64(0), GID::U64(1))]
+ );
+ assert_eq!(
+ graph
+ .subgraph([0, 1])
+ .valid_layers("1")
+ .edges()
+ .id()
+ .collect_vec(),
+ [(GID::U64(0), GID::U64(1))]
+ );
+}
+
+#[test]
+fn nodes_without_updates_are_filtered() {
+ let g = Graph::new();
+ g.add_edge(0, 0, 1, NO_PROPS, None).unwrap();
+ let expected = Graph::new();
+ expected.resolve_layer(None).unwrap();
+ let subgraph = g.subgraph([0]);
+ assert_graph_equal(&subgraph, &expected);
+}
+
+#[test]
+fn materialize_proptest() {
+ proptest!(|(graph in build_graph_strat(10, 10, 10, 10, false), nodes in subsequence((0..10).collect::>(), 0..10))| {
+ let graph = Graph::from(build_graph(&graph));
+ let subgraph = graph.subgraph(nodes);
+ assert_graph_equal(&subgraph, &subgraph.materialize().unwrap());
+ })
+}
+
+#[test]
+fn materialize_proptest_failure() {
+ let graph_f = serde_json::from_value(json!({"nodes":{},"edges":[[[1,1,"a"],{"props":{"t_props":[[0,[]]],"c_props":[]},"deletions":[]}],[[0,0,null],{"props":{"t_props":[[0,[]]],"c_props":[]},"deletions":[]}]]})).unwrap();
+ let graph = Graph::from(build_graph(&graph_f));
+ let subgraph = graph.subgraph([1]);
+ let nodes = subgraph.default_layer().nodes().id().collect_vec();
+ dbg!(nodes);
+ assert_eq!(subgraph.default_layer().count_nodes(), 0);
+ assert_eq!(subgraph.count_edges(), 1);
+ let materialised = subgraph.materialize().unwrap();
+ assert_graph_equal(&subgraph, &materialised);
+}
+
+#[test]
+fn materialize_persistent_proptest() {
+ proptest!(|(graph in build_graph_strat(10, 10, 10, 10, true), nodes in subsequence((0..10).collect::>(), 0..10))| {
+ let graph = PersistentGraph::from(build_graph(&graph));
+ let subgraph = graph.subgraph(nodes);
+ assert_graph_equal(&subgraph, &subgraph.materialize().unwrap());
+ })
+}
+
+#[test]
+fn test_subgraph_only_deletion() {
+ let g = PersistentGraph::new();
+ g.delete_edge(0, 0, 1, None).unwrap();
+ let sg = g.subgraph([0]);
+ let expected = PersistentGraph::new();
+ expected.resolve_layer(None).unwrap();
+ assert_graph_equal(&sg, &expected);
+}
diff --git a/raphtory-tests/tests/view_tests/test_layers.rs b/raphtory-tests/tests/view_tests/test_layers.rs
new file mode 100644
index 0000000000..a34ae2e8b5
--- /dev/null
+++ b/raphtory-tests/tests/view_tests/test_layers.rs
@@ -0,0 +1,205 @@
+use itertools::Itertools;
+use proptest::proptest;
+use raphtory::{
+ db::graph::{graph::assert_graph_equal, views::deletion_graph::PersistentGraph},
+ prelude::*,
+};
+use raphtory_api::core::entities::GID;
+use raphtory_tests::{
+ test_storage,
+ utils::{build_graph, build_graph_layer, build_graph_strat, GraphFixture},
+};
+use serde_json::json;
+
+#[test]
+fn proptest_layering() {
+ proptest!(|(graph_f in build_graph_strat(10, 10, 10, 10, false), layer in proptest::sample::subsequence(&["_default", "a", "b"], 0..3))| {
+ let g_layer_expected = Graph::from(build_graph_layer(&graph_f, &layer));
+ let g = Graph::from(build_graph(&graph_f));
+ let g_layer = g.valid_layers(layer.clone());
+ assert_graph_equal(&g_layer, &g_layer_expected);
+ })
+}
+
+#[test]
+fn test_node_explicit_node_additions() {
+ let graph_f: GraphFixture = serde_json::from_value(json!({"nodes":{"10":{"props":{"t_props":[[0,[]]],"c_props":[]},"node_type":null}},"edges":[]})).unwrap();
+ let layer = [];
+ let g_layer_expected = Graph::from(build_graph_layer(&graph_f, &layer));
+ let g = Graph::from(build_graph(&graph_f));
+ let g_layer = g.valid_layers(layer.clone());
+
+ assert_graph_equal(&g_layer, &g_layer_expected);
+}
+
+#[test]
+fn test_failure() {
+ let graph_f: GraphFixture = serde_json::from_value(json!({"nodes":{},"edges":[[[0,0,"a"],{"props":{"t_props":[[0,[]]],"c_props":[]},"deletions":[]}],[[3,9,"b"],{"props":{"t_props":[[0,[]]],"c_props":[]},"deletions":[]}],[[9,3,"b"],{"props":{"t_props":[[0,[]]],"c_props":[]},"deletions":[]}],[[0,0,null],{"props":{"t_props":[[0,[]]],"c_props":[]},"deletions":[]}]]})).unwrap();
+ let layer = ["_default", "b"];
+ let g_layer_expected = Graph::from(build_graph_layer(&graph_f, &layer));
+ let g = Graph::from(build_graph(&graph_f));
+ let g_layer = g.valid_layers(layer.clone());
+
+ assert_graph_equal(&g_layer, &g_layer_expected);
+}
+
+#[test]
+fn test_failure2() {
+ let graph_f: GraphFixture = serde_json::from_value(json!({"nodes":{},"edges":[[[0,0,null],{"props":{"t_props":[[0,[]]],"c_props":[]},"deletions":[]}],[[0,0,"a"],{"props":{"t_props":[[0,[]]],"c_props":[]},"deletions":[]}],[[0,0,"b"],{"props":{"t_props":[[0,[]]],"c_props":[]},"deletions":[]}]]})).unwrap();
+ let layer = ["_default", "b"];
+ let g_layer_expected = Graph::from(build_graph_layer(&graph_f, &layer));
+ let g = Graph::from(build_graph(&graph_f));
+ let g_layer = g.valid_layers(layer.clone());
+
+ assert_graph_equal(&g_layer, &g_layer_expected);
+}
+
+#[test]
+fn test_failure3() {
+ let graph_f: GraphFixture = serde_json::from_value(json!({"nodes":{},"edges":[[[0,0,null],{"props":{"t_props":[[0,[]]],"c_props":[]},"deletions":[]}],[[0,0,"b"],{"props":{"t_props":[[0,[]]],"c_props":[]},"deletions":[]}],[[0,1,"a"],{"props":{"t_props":[[0,[]]],"c_props":[]},"deletions":[]}]]})).unwrap();
+ let layer = ["_default", "b"];
+ let g_layer_expected = Graph::from(build_graph_layer(&graph_f, &layer));
+ let g = Graph::from(build_graph(&graph_f));
+ let g_layer = g.valid_layers(layer.clone());
+
+ assert_graph_equal(&g_layer, &g_layer_expected);
+}
+
+// Regression for the build_graph_layer node-layer filter
+#[test]
+fn test_node_layer_visibility_under_valid_layers() {
+ let graph_f: GraphFixture = serde_json::from_value(json!({
+ "nodes": {
+ "1": {"props":{"t_props":[[0,[]]],"c_props":[]}, "node_type": null, "node_layer": null},
+ "2": {"props":{"t_props":[[0,[]]],"c_props":[]}, "node_type": null, "node_layer": "a"},
+ "3": {"props":{"t_props":[[0,[]]],"c_props":[]}, "node_type": null, "node_layer": "b"}
+ },
+ "edges": []
+ }))
+ .unwrap();
+
+ let layer = ["b"];
+ let g_layer_expected = Graph::from(build_graph_layer(&graph_f, &layer));
+ let g = Graph::from(build_graph(&graph_f));
+ let g_layer = g.valid_layers(layer.clone());
+
+ assert_graph_equal(&g_layer, &g_layer_expected);
+}
+
+#[test]
+fn proptest_layering_persistent_graph() {
+ proptest!(|(graph_f in build_graph_strat(10, 10, 10, 10, true), layer in proptest::sample::subsequence(&["_default", "a", "b"], 0..3))| {
+ let g_layer_expected = PersistentGraph::from(build_graph_layer(&graph_f, &layer));
+ let g = PersistentGraph::from(build_graph(&graph_f));
+ let g_layer = g.valid_layers(layer);
+ assert_graph_equal(&g_layer, &g_layer_expected);
+ })
+}
+
+#[test]
+fn test_layer_node() {
+ let graph = Graph::new();
+
+ graph.add_edge(0, 1, 2, NO_PROPS, Some("layer1")).unwrap();
+ graph.add_edge(0, 2, 3, NO_PROPS, Some("layer2")).unwrap();
+ graph.add_edge(3, 2, 4, NO_PROPS, Some("layer1")).unwrap();
+ graph.add_edge(1, 4, 1, NO_PROPS, Some("layer3")).unwrap();
+
+ test_storage!(&graph, |graph| {
+ let neighbours = graph
+ .layers(vec!["layer1", "layer2"])
+ .unwrap()
+ .node(1)
+ .unwrap()
+ .neighbours()
+ .into_iter()
+ .collect_vec();
+ assert_eq!(
+ neighbours[0]
+ .layers("layer2")
+ .unwrap()
+ .edges()
+ .id()
+ .collect_vec(),
+ vec![(GID::U64(2), GID::U64(3))]
+ );
+ assert_eq!(
+ graph
+ .layers("layer2")
+ .unwrap()
+ .node(neighbours[0].name())
+ .unwrap()
+ .edges()
+ .id()
+ .collect_vec(),
+ vec![(GID::U64(2), GID::U64(3))]
+ );
+ let mut edges = graph
+ .layers("layer1")
+ .unwrap()
+ .node(neighbours[0].name())
+ .unwrap()
+ .edges()
+ .id()
+ .filter_map(|(a, b)| a.to_u64().zip(b.to_u64()))
+ .collect_vec();
+ edges.sort();
+ assert_eq!(edges, vec![(1, 2), (2, 4)]);
+ let mut edges = graph
+ .layers("layer1")
+ .unwrap()
+ .edges()
+ .id()
+ .filter_map(|(a, b)| a.to_u64().zip(b.to_u64()))
+ .collect_vec();
+ edges.sort();
+ assert_eq!(edges, vec![(1, 2), (2, 4)]);
+ let mut edges = graph
+ .layers(vec!["layer1", "layer2"])
+ .unwrap()
+ .edges()
+ .id()
+ .filter_map(|(a, b)| a.to_u64().zip(b.to_u64()))
+ .collect_vec();
+ edges.sort();
+ assert_eq!(edges, vec![(1, 2), (2, 3), (2, 4)]);
+
+ let mut edges = graph
+ .layers(["layer1", "layer3"])
+ .unwrap()
+ .window(0, 2)
+ .edges()
+ .id()
+ .filter_map(|(a, b)| a.to_u64().zip(b.to_u64()))
+ .collect_vec();
+ edges.sort();
+ assert_eq!(edges, vec![(1, 2), (4, 1)]);
+ });
+}
+
+#[test]
+fn layering_tests() {
+ let graph = Graph::new();
+ let e1 = graph.add_edge(0, 1, 2, NO_PROPS, Some("1")).unwrap();
+ graph.add_edge(1, 1, 2, NO_PROPS, Some("2")).unwrap();
+
+ println!("edge: {e1:?}");
+ // FIXME: this is weird, see issue #1458
+ assert!(e1.has_layer("2"));
+ let history = e1.layers("2").unwrap().history();
+ println!("history: {:?}", history);
+ assert!(e1.layers("2").unwrap().history().is_empty());
+
+ test_storage!(&graph, |graph| {
+ let e = graph.edge(1, 2).unwrap();
+ // layers with non-existing layers errors
+ assert!(e.layers(["1", "3"]).is_err());
+ // valid_layers ignores non-existing layers
+ assert_eq!(e.valid_layers(["1", "3"]).layer_names(), ["1"]);
+ assert!(e.has_layer("1"));
+ assert!(e.has_layer("2"));
+ assert!(!e.has_layer("3"));
+ assert!(e.valid_layers("1").has_layer("1"));
+ assert!(!e.valid_layers("1").has_layer("2"));
+ });
+}
diff --git a/raphtory-tests/tests/time_tests.rs b/raphtory-tests/tests/view_tests/time_tests.rs
similarity index 100%
rename from raphtory-tests/tests/time_tests.rs
rename to raphtory-tests/tests/view_tests/time_tests.rs
diff --git a/raphtory-tests/tests/view_tests/views_test.rs b/raphtory-tests/tests/view_tests/views_test.rs
new file mode 100644
index 0000000000..f5c167373d
--- /dev/null
+++ b/raphtory-tests/tests/view_tests/views_test.rs
@@ -0,0 +1,532 @@
+use itertools::Itertools;
+use proptest::{prop_assert, prop_assert_eq, prop_assume, proptest};
+use rand::{prelude::*, rng};
+use raphtory::{
+ algorithms::centrality::degree_centrality::degree_centrality,
+ db::graph::{graph::assert_graph_equal, views::window_graph::WindowedGraph},
+ prelude::*,
+};
+use raphtory_api::core::{
+ entities::GID,
+ storage::timeindex::AsTime,
+ utils::{logging::global_info_logger, time::IntoTime},
+};
+use raphtory_tests::{test_storage, utils::test_graph};
+use rayon::prelude::*;
+use std::ops::Range;
+use tracing::{error, info};
+
+#[test]
+fn test_non_restricted_window() {
+ let g = Graph::new();
+ g.add_edge(0, 0, 1, NO_PROPS, None).unwrap();
+
+ for n in g.window(0, 1).nodes() {
+ assert!(g.has_node(n));
+ }
+
+ assert_graph_equal(&g.window(0, 1), &g)
+}
+
+#[test]
+fn windowed_graph_nodes_degree() {
+ let vs = vec![
+ (1, 1, 2),
+ (2, 1, 3),
+ (-1, 2, 1),
+ (0, 1, 1),
+ (7, 3, 2),
+ (1, 1, 1),
+ ];
+
+ let graph = Graph::new();
+
+ for (t, src, dst) in &vs {
+ graph.add_edge(*t, *src, *dst, NO_PROPS, None).unwrap();
+ }
+ test_storage!(&graph, |graph| {
+ let wg = graph.window(-1, 1);
+
+ let actual = wg
+ .nodes()
+ .iter()
+ .map(|v| (v.id(), v.degree()))
+ .collect::>();
+
+ let expected = vec![(GID::U64(1), 2), (GID::U64(2), 1)];
+
+ assert_eq!(actual, expected);
+ });
+}
+
+#[test]
+fn windowed_graph_edge() {
+ let vs = vec![
+ (1, 1, 2),
+ (2, 1, 3),
+ (-1, 2, 1),
+ (0, 1, 1),
+ (7, 3, 2),
+ (1, 1, 1),
+ ];
+
+ let graph = Graph::new();
+
+ for (t, src, dst) in vs {
+ graph.add_edge(t, src, dst, NO_PROPS, None).unwrap();
+ }
+ test_storage!(&graph, |graph| {
+ let wg = graph.window(i64::MIN, i64::MAX);
+ assert_eq!(wg.edge(1, 3).unwrap().src().id(), GID::U64(1));
+ assert_eq!(wg.edge(1, 3).unwrap().dst().id(), GID::U64(3));
+ });
+}
+
+#[test]
+fn windowed_graph_node_edges() {
+ let vs = vec![
+ (1, 1, 2),
+ (2, 1, 3),
+ (-1, 2, 1),
+ (0, 1, 1),
+ (7, 3, 2),
+ (1, 1, 1),
+ ];
+
+ let graph = Graph::new();
+
+ for (t, src, dst) in &vs {
+ graph.add_edge(*t, *src, *dst, NO_PROPS, None).unwrap();
+ }
+ test_storage!(&graph, |graph| {
+ let wg = graph.window(-1, 1);
+
+ assert_eq!(wg.node(1).unwrap().id(), GID::U64(1));
+ });
+}
+
+#[test]
+fn graph_has_node_check_fail() {
+ let vs: Vec<(i64, u64)> = vec![
+ (1, 0),
+ (-100, 262),
+ // (327226439, 108748364996394682),
+ (1, 9135428456135679950),
+ // (0, 1),
+ // (2, 2),
+ ];
+ let graph = Graph::new();
+
+ for (t, v) in &vs {
+ graph.add_node(*t, *v, NO_PROPS, None, None).unwrap();
+ }
+
+ // FIXME: Issue #46: arrow_test(&graph, test)
+ test_graph(&graph, |graph| {
+ let wg = graph.window(1, 2);
+ assert!(!wg.has_node(262))
+ });
+}
+
+#[test]
+fn windowed_graph_has_node_proptest() {
+ proptest!(|(mut vs: Vec<(i64, u64)>)| {
+ global_info_logger();
+ prop_assume!(!vs.is_empty());
+
+ vs.sort_by_key(|v| v.1); // Sorted by node
+ vs.dedup_by_key(|v| v.1); // Have each node only once to avoid headaches
+ vs.sort_by_key(|v| v.0); // Sorted by time
+
+ let rand_start_index = rng().random_range(0..vs.len());
+ let rand_end_index = rng().random_range(rand_start_index..vs.len());
+
+ let g = Graph::new();
+
+ for (t, v) in &vs {
+ g.add_node(*t, *v, NO_PROPS, None, None)
+ .map_err(|err| error!("{:?}", err))
+ .ok();
+ }
+
+ let start = vs.get(rand_start_index).expect("start index in range").0;
+ let end = vs.get(rand_end_index).expect("end index in range").0;
+
+ let wg = g.window(start, end);
+
+ let rand_test_index: usize = rng().random_range(0..vs.len());
+
+ let (i, v) = vs.get(rand_test_index).expect("test index in range");
+ if (start..end).contains(i) {
+ prop_assert!(wg.has_node(*v), "Node {:?} was not in window {:?}", (i, v), start..end);
+ } else {
+ prop_assert!(!wg.has_node(*v), "Node {:?} was in window {:?}", (i, v), start..end);
+ }
+ });
+}
+
+#[test]
+fn windowed_graph_has_edge_proptest() {
+ proptest!(|(mut edges: Vec<(i64, (u64, u64))>)| {
+ prop_assume!(!edges.is_empty());
+
+ edges.sort_by_key(|e| e.1); // Sorted by edge
+ edges.dedup_by_key(|e| e.1); // Have each edge only once to avoid headaches
+ edges.sort_by_key(|e| e.0); // Sorted by time
+
+ let rand_start_index = rng().random_range(0..edges.len());
+ let rand_end_index = rng().random_range(rand_start_index..edges.len());
+
+ let g = Graph::new();
+
+ for (t, e) in &edges {
+ g.add_edge(*t, e.0, e.1, NO_PROPS, None).unwrap();
+ }
+
+ let start = edges.get(rand_start_index).expect("start index in range").0;
+ let end = edges.get(rand_end_index).expect("end index in range").0;
+
+ let wg = g.window(start, end);
+
+ let rand_test_index: usize = rng().random_range(0..edges.len());
+
+ let (i, e) = edges.get(rand_test_index).expect("test index in range");
+ if (start..end).contains(i) {
+ prop_assert!(wg.has_edge(e.0, e.1), "Edge {:?} was not in window {:?}", (i, e), start..end);
+ } else {
+ prop_assert!(!wg.has_edge(e.0, e.1), "Edge {:?} was in window {:?}", (i, e), start..end);
+ }
+ });
+}
+
+#[test]
+fn windowed_graph_edge_count_proptest() {
+ proptest!(|(mut edges: Vec<(i64, (u64, u64))>, window: Range)| {
+ global_info_logger();
+ prop_assume!(window.end >= window.start);
+
+ edges.sort_by_key(|e| e.1); // Sorted by edge
+ edges.dedup_by_key(|e| e.1); // Have each edge only once to avoid headaches
+
+ let true_edge_count = edges.iter().filter(|e| window.contains(&e.0)).count();
+
+ let g = Graph::new();
+
+ for (t, e) in &edges {
+ g.add_edge(*t, e.0, e.1, [("test".to_owned(), Prop::Bool(true))], None)
+ .unwrap();
+ }
+
+ let wg = g.window(window.start, window.end);
+ if wg.count_edges() != true_edge_count {
+ info!(
+ "failed, g.num_edges() = {}, true count = {}",
+ wg.count_edges(),
+ true_edge_count
+ );
+ info!("g.edges() = {:?}", wg.edges().iter().collect_vec());
+ }
+ prop_assert_eq!(wg.count_edges(), true_edge_count);
+ });
+}
+
+#[test]
+fn trivial_window_has_all_edges_proptest() {
+ proptest!(|(edges: Vec<(i64, u64, u64)>)| {
+ let g = Graph::new();
+ edges
+ .into_par_iter()
+ .filter(|e| e.0 < i64::MAX)
+ .for_each(|(t, src, dst)| {
+ g.add_edge(t, src, dst, [("test".to_owned(), Prop::Bool(true))], None)
+ .unwrap();
+ });
+ let w = g.window(i64::MIN, i64::MAX);
+ prop_assert!(g.edges()
+ .iter()
+ .all(|e| w.has_edge(e.src().id(), e.dst().id())));
+ });
+}
+
+#[test]
+fn large_node_in_window_proptest() {
+ proptest!(|(dsts: Vec)| {
+ let dsts: Vec = dsts.into_iter().unique().collect();
+ let n = dsts.len();
+ let g = Graph::new();
+
+ for dst in dsts {
+ let t = 1;
+ g.add_edge(t, 0, dst, NO_PROPS, None).unwrap();
+ }
+ let w = g.window(i64::MIN, i64::MAX);
+ prop_assert_eq!(w.count_edges(), n);
+ });
+}
+
+#[test]
+fn windowed_graph_node_ids() {
+ let vs = vec![(1, 1, 2), (3, 3, 4), (5, 5, 6), (7, 7, 1)];
+
+ let args = [(i64::MIN, 8), (i64::MIN, 2), (i64::MIN, 4), (3, 6)];
+
+ let expected = vec![
+ vec![1, 2, 3, 4, 5, 6, 7],
+ vec![1, 2],
+ vec![1, 2, 3, 4],
+ vec![3, 4, 5, 6],
+ ];
+
+ let graph = Graph::new();
+
+ for (t, src, dst) in &vs {
+ graph.add_edge(*t, *src, *dst, NO_PROPS, None).unwrap();
+ }
+
+ test_storage!(&graph, |graph| {
+ let res: Vec<_> = (0..=3)
+ .map(|i| {
+ let wg = graph.window(args[i].0, args[i].1);
+ let mut e = wg
+ .nodes()
+ .id()
+ .iter_values()
+ .filter_map(|id| id.to_u64())
+ .collect::>();
+ e.sort();
+ e
+ })
+ .collect_vec();
+
+ assert_eq!(res, expected);
+ });
+
+ let graph = Graph::new();
+ for (src, dst, t) in &vs {
+ graph.add_edge(*src, *dst, *t, NO_PROPS, None).unwrap();
+ }
+ test_storage!(&graph, |graph| {
+ let res: Vec<_> = (0..=3)
+ .map(|i| {
+ let wg = graph.window(args[i].0, args[i].1);
+ let mut e = wg
+ .nodes()
+ .id()
+ .iter_values()
+ .filter_map(|id| id.to_u64())
+ .collect::>();
+ e.sort();
+ e
+ })
+ .collect_vec();
+ assert_eq!(res, expected);
+ });
+}
+
+#[test]
+fn windowed_graph_nodes() {
+ let vs = vec![
+ (1, 1, 2),
+ (2, 1, 3),
+ (-1, 2, 1),
+ (0, 1, 1),
+ (7, 3, 2),
+ (1, 1, 1),
+ ];
+
+ let graph = Graph::new();
+
+ graph
+ .add_node(
+ 0,
+ 1,
+ [("type", "wallet".into_prop()), ("cost", 99.5.into_prop())],
+ None,
+ None,
+ )
+ .unwrap();
+
+ graph
+ .add_node(
+ -1,
+ 2,
+ [("type", "wallet".into_prop()), ("cost", 10.0.into_prop())],
+ None,
+ None,
+ )
+ .unwrap();
+
+ graph
+ .add_node(
+ 6,
+ 3,
+ [("type", "wallet".into_prop()), ("cost", 76.2.into_prop())],
+ None,
+ None,
+ )
+ .unwrap();
+
+ for (t, src, dst) in &vs {
+ graph
+ .add_edge(*t, *src, *dst, [("eprop", "commons")], None)
+ .unwrap();
+ }
+ test_storage!(&graph, |graph| {
+ let wg = graph.window(-2, 0);
+
+ let actual = wg
+ .nodes()
+ .id()
+ .iter_values()
+ .filter_map(|id| id.to_u64())
+ .collect::>();
+
+ let expected = vec![1, 2];
+
+ assert_eq!(actual, expected);
+ });
+}
+
+#[test]
+fn test_reference() {
+ let graph = Graph::new();
+ graph.add_edge(0, 1, 2, NO_PROPS, None).unwrap();
+
+ test_storage!(&graph, |graph| {
+ let mut w = WindowedGraph::new(&graph, Some(0.into_time()), Some(1.into_time()));
+ assert_eq!(w, graph);
+ w = WindowedGraph::new(&graph, Some(1.into_time()), Some(2.into_time()));
+ assert_eq!(w, Graph::new());
+ });
+}
+
+#[test]
+fn test_algorithm_on_windowed_graph() {
+ global_info_logger();
+ let graph = Graph::new();
+ graph.add_edge(0, 1, 2, NO_PROPS, None).unwrap();
+ test_storage!(&graph, |graph| {
+ let w = graph.window(0, 1);
+ let _ = degree_centrality(&w);
+ });
+}
+
+#[test]
+fn test_view_resetting() {
+ let graph = Graph::new();
+ for t in 0..10 {
+ let t1 = t * 3;
+ let t2 = t * 3 + 1;
+ let t3 = t * 3 + 2;
+ graph.add_edge(t1, 1, 2, NO_PROPS, None).unwrap();
+ graph.add_edge(t2, 2, 3, NO_PROPS, None).unwrap();
+ graph.add_edge(t3, 3, 1, NO_PROPS, None).unwrap();
+ }
+
+ test_storage!(&graph, |graph| {
+ assert_graph_equal(&graph.before(9).after(2), &graph.window(3, 9));
+ let res = graph
+ .window(3, 9)
+ .nodes()
+ .before(6)
+ .edges()
+ .window(1, 9)
+ .earliest_time()
+ .map(|it| it.map(|t_opt| t_opt.map(|t| t.t())).collect_vec())
+ .collect_vec();
+ assert_eq!(
+ res,
+ [[Some(3), Some(5)], [Some(3), Some(4)], [Some(5), Some(4)]]
+ );
+ });
+}
+
+#[test]
+fn test_entity_history() {
+ let graph = Graph::new();
+ graph.add_node(0, 0, NO_PROPS, None, None).unwrap();
+ graph.add_node(1, 0, NO_PROPS, None, None).unwrap();
+ graph.add_node(2, 0, NO_PROPS, None, None).unwrap();
+ graph.add_node(3, 0, NO_PROPS, None, None).unwrap();
+ graph.add_edge(0, 1, 2, NO_PROPS, None).unwrap();
+ graph.add_edge(1, 1, 2, NO_PROPS, None).unwrap();
+ graph.add_edge(2, 1, 2, NO_PROPS, None).unwrap();
+ graph.add_edge(3, 1, 2, NO_PROPS, None).unwrap();
+ graph.add_edge(4, 1, 3, NO_PROPS, None).unwrap();
+ graph.add_edge(5, 1, 3, NO_PROPS, None).unwrap();
+ graph.add_edge(6, 1, 3, NO_PROPS, None).unwrap();
+ graph.add_edge(7, 1, 3, NO_PROPS, None).unwrap();
+
+ // FIXME: Issue #46
+ test_graph(&graph, |graph| {
+ let e = graph.edge(1, 2).unwrap();
+ let v = graph.node(0).unwrap();
+ let full_history_1 = vec![0i64, 1, 2, 3];
+
+ let full_history_2 = vec![4i64, 5, 6, 7];
+
+ let windowed_history = vec![0i64, 1];
+
+ assert_eq!(v.history(), full_history_1);
+
+ assert_eq!(v.window(0, 2).history(), windowed_history);
+ assert_eq!(e.history(), full_history_1);
+ assert_eq!(e.window(0, 2).history(), windowed_history);
+
+ assert_eq!(
+ graph.edges().history().collect_vec(),
+ [full_history_1.clone(), full_history_2.clone()]
+ );
+ assert_eq!(
+ graph
+ .nodes()
+ .in_edges()
+ .history()
+ .map(|it| it.collect_vec())
+ .collect_vec(),
+ [vec![], vec![], vec![full_history_1], vec![full_history_2],]
+ );
+
+ assert_eq!(
+ graph
+ .nodes()
+ .earliest_time()
+ .iter_values()
+ .flatten()
+ .collect_vec(),
+ [0, 0, 0, 4,]
+ );
+
+ assert_eq!(
+ graph
+ .nodes()
+ .latest_time()
+ .iter_values()
+ .flatten()
+ .collect_vec(),
+ [3, 7, 3, 7]
+ );
+
+ assert_eq!(
+ graph
+ .nodes()
+ .neighbours()
+ .latest_time()
+ .sorted_by_key(|(n, _)| n.id())
+ .map(|(_, it)| it.flatten().collect_vec())
+ .collect_vec(),
+ [vec![], vec![3, 7], vec![7], vec![7],]
+ );
+
+ assert_eq!(
+ graph
+ .nodes()
+ .neighbours()
+ .earliest_time()
+ .sorted_by_key(|(n, _)| n.id())
+ .map(|(_, it)| it.flatten().collect_vec())
+ .collect_vec(),
+ [vec![], vec![0, 4], vec![0], vec![0],]
+ );
+ });
+}
diff --git a/raphtory-tests/tests/views_test.rs b/raphtory-tests/tests/views_test.rs
deleted file mode 100644
index 435df284a8..0000000000
--- a/raphtory-tests/tests/views_test.rs
+++ /dev/null
@@ -1,4581 +0,0 @@
-use itertools::Itertools;
-use proptest::{prop_assert, prop_assert_eq, prop_assume, proptest};
-use rand::{prelude::*, rng};
-use raphtory::{
- algorithms::centrality::degree_centrality::degree_centrality,
- db::graph::{graph::assert_graph_equal, views::window_graph::WindowedGraph},
- prelude::*,
-};
-use raphtory_api::core::{
- entities::GID,
- storage::timeindex::AsTime,
- utils::{logging::global_info_logger, time::IntoTime},
-};
-use raphtory_tests::{test_storage, utils::test_graph};
-use rayon::prelude::*;
-use std::ops::Range;
-use tracing::{error, info};
-
-#[test]
-fn test_non_restricted_window() {
- let g = Graph::new();
- g.add_edge(0, 0, 1, NO_PROPS, None).unwrap();
-
- for n in g.window(0, 1).nodes() {
- assert!(g.has_node(n));
- }
-
- assert_graph_equal(&g.window(0, 1), &g)
-}
-
-#[test]
-fn windowed_graph_nodes_degree() {
- let vs = vec![
- (1, 1, 2),
- (2, 1, 3),
- (-1, 2, 1),
- (0, 1, 1),
- (7, 3, 2),
- (1, 1, 1),
- ];
-
- let graph = Graph::new();
-
- for (t, src, dst) in &vs {
- graph.add_edge(*t, *src, *dst, NO_PROPS, None).unwrap();
- }
- test_storage!(&graph, |graph| {
- let wg = graph.window(-1, 1);
-
- let actual = wg
- .nodes()
- .iter()
- .map(|v| (v.id(), v.degree()))
- .collect::>();
-
- let expected = vec![(GID::U64(1), 2), (GID::U64(2), 1)];
-
- assert_eq!(actual, expected);
- });
-}
-
-#[test]
-fn windowed_graph_edge() {
- let vs = vec![
- (1, 1, 2),
- (2, 1, 3),
- (-1, 2, 1),
- (0, 1, 1),
- (7, 3, 2),
- (1, 1, 1),
- ];
-
- let graph = Graph::new();
-
- for (t, src, dst) in vs {
- graph.add_edge(t, src, dst, NO_PROPS, None).unwrap();
- }
- test_storage!(&graph, |graph| {
- let wg = graph.window(i64::MIN, i64::MAX);
- assert_eq!(wg.edge(1, 3).unwrap().src().id(), GID::U64(1));
- assert_eq!(wg.edge(1, 3).unwrap().dst().id(), GID::U64(3));
- });
-}
-
-#[test]
-fn windowed_graph_node_edges() {
- let vs = vec![
- (1, 1, 2),
- (2, 1, 3),
- (-1, 2, 1),
- (0, 1, 1),
- (7, 3, 2),
- (1, 1, 1),
- ];
-
- let graph = Graph::new();
-
- for (t, src, dst) in &vs {
- graph.add_edge(*t, *src, *dst, NO_PROPS, None).unwrap();
- }
- test_storage!(&graph, |graph| {
- let wg = graph.window(-1, 1);
-
- assert_eq!(wg.node(1).unwrap().id(), GID::U64(1));
- });
-}
-
-#[test]
-fn graph_has_node_check_fail() {
- let vs: Vec<(i64, u64)> = vec![
- (1, 0),
- (-100, 262),
- // (327226439, 108748364996394682),
- (1, 9135428456135679950),
- // (0, 1),
- // (2, 2),
- ];
- let graph = Graph::new();
-
- for (t, v) in &vs {
- graph.add_node(*t, *v, NO_PROPS, None, None).unwrap();
- }
-
- // FIXME: Issue #46: arrow_test(&graph, test)
- test_graph(&graph, |graph| {
- let wg = graph.window(1, 2);
- assert!(!wg.has_node(262))
- });
-}
-
-#[test]
-fn windowed_graph_has_node_proptest() {
- proptest!(|(mut vs: Vec<(i64, u64)>)| {
- global_info_logger();
- prop_assume!(!vs.is_empty());
-
- vs.sort_by_key(|v| v.1); // Sorted by node
- vs.dedup_by_key(|v| v.1); // Have each node only once to avoid headaches
- vs.sort_by_key(|v| v.0); // Sorted by time
-
- let rand_start_index = rng().random_range(0..vs.len());
- let rand_end_index = rng().random_range(rand_start_index..vs.len());
-
- let g = Graph::new();
-
- for (t, v) in &vs {
- g.add_node(*t, *v, NO_PROPS, None, None)
- .map_err(|err| error!("{:?}", err))
- .ok();
- }
-
- let start = vs.get(rand_start_index).expect("start index in range").0;
- let end = vs.get(rand_end_index).expect("end index in range").0;
-
- let wg = g.window(start, end);
-
- let rand_test_index: usize = rng().random_range(0..vs.len());
-
- let (i, v) = vs.get(rand_test_index).expect("test index in range");
- if (start..end).contains(i) {
- prop_assert!(wg.has_node(*v), "Node {:?} was not in window {:?}", (i, v), start..end);
- } else {
- prop_assert!(!wg.has_node(*v), "Node {:?} was in window {:?}", (i, v), start..end);
- }
- });
-}
-
-#[test]
-fn windowed_graph_has_edge_proptest() {
- proptest!(|(mut edges: Vec<(i64, (u64, u64))>)| {
- prop_assume!(!edges.is_empty());
-
- edges.sort_by_key(|e| e.1); // Sorted by edge
- edges.dedup_by_key(|e| e.1); // Have each edge only once to avoid headaches
- edges.sort_by_key(|e| e.0); // Sorted by time
-
- let rand_start_index = rng().random_range(0..edges.len());
- let rand_end_index = rng().random_range(rand_start_index..edges.len());
-
- let g = Graph::new();
-
- for (t, e) in &edges {
- g.add_edge(*t, e.0, e.1, NO_PROPS, None).unwrap();
- }
-
- let start = edges.get(rand_start_index).expect("start index in range").0;
- let end = edges.get(rand_end_index).expect("end index in range").0;
-
- let wg = g.window(start, end);
-
- let rand_test_index: usize = rng().random_range(0..edges.len());
-
- let (i, e) = edges.get(rand_test_index).expect("test index in range");
- if (start..end).contains(i) {
- prop_assert!(wg.has_edge(e.0, e.1), "Edge {:?} was not in window {:?}", (i, e), start..end);
- } else {
- prop_assert!(!wg.has_edge(e.0, e.1), "Edge {:?} was in window {:?}", (i, e), start..end);
- }
- });
-}
-
-#[test]
-fn windowed_graph_edge_count_proptest() {
- proptest!(|(mut edges: Vec<(i64, (u64, u64))>, window: Range)| {
- global_info_logger();
- prop_assume!(window.end >= window.start);
-
- edges.sort_by_key(|e| e.1); // Sorted by edge
- edges.dedup_by_key(|e| e.1); // Have each edge only once to avoid headaches
-
- let true_edge_count = edges.iter().filter(|e| window.contains(&e.0)).count();
-
- let g = Graph::new();
-
- for (t, e) in &edges {
- g.add_edge(*t, e.0, e.1, [("test".to_owned(), Prop::Bool(true))], None)
- .unwrap();
- }
-
- let wg = g.window(window.start, window.end);
- if wg.count_edges() != true_edge_count {
- info!(
- "failed, g.num_edges() = {}, true count = {}",
- wg.count_edges(),
- true_edge_count
- );
- info!("g.edges() = {:?}", wg.edges().iter().collect_vec());
- }
- prop_assert_eq!(wg.count_edges(), true_edge_count);
- });
-}
-
-#[test]
-fn trivial_window_has_all_edges_proptest() {
- proptest!(|(edges: Vec<(i64, u64, u64)>)| {
- let g = Graph::new();
- edges
- .into_par_iter()
- .filter(|e| e.0 < i64::MAX)
- .for_each(|(t, src, dst)| {
- g.add_edge(t, src, dst, [("test".to_owned(), Prop::Bool(true))], None)
- .unwrap();
- });
- let w = g.window(i64::MIN, i64::MAX);
- prop_assert!(g.edges()
- .iter()
- .all(|e| w.has_edge(e.src().id(), e.dst().id())));
- });
-}
-
-#[test]
-fn large_node_in_window_proptest() {
- proptest!(|(dsts: Vec)| {
- let dsts: Vec = dsts.into_iter().unique().collect();
- let n = dsts.len();
- let g = Graph::new();
-
- for dst in dsts {
- let t = 1;
- g.add_edge(t, 0, dst, NO_PROPS, None).unwrap();
- }
- let w = g.window(i64::MIN, i64::MAX);
- prop_assert_eq!(w.count_edges(), n);
- });
-}
-
-#[test]
-fn windowed_graph_node_ids() {
- let vs = vec![(1, 1, 2), (3, 3, 4), (5, 5, 6), (7, 7, 1)];
-
- let args = [(i64::MIN, 8), (i64::MIN, 2), (i64::MIN, 4), (3, 6)];
-
- let expected = vec![
- vec![1, 2, 3, 4, 5, 6, 7],
- vec![1, 2],
- vec![1, 2, 3, 4],
- vec![3, 4, 5, 6],
- ];
-
- let graph = Graph::new();
-
- for (t, src, dst) in &vs {
- graph.add_edge(*t, *src, *dst, NO_PROPS, None).unwrap();
- }
-
- test_storage!(&graph, |graph| {
- let res: Vec<_> = (0..=3)
- .map(|i| {
- let wg = graph.window(args[i].0, args[i].1);
- let mut e = wg
- .nodes()
- .id()
- .iter_values()
- .filter_map(|id| id.to_u64())
- .collect::>();
- e.sort();
- e
- })
- .collect_vec();
-
- assert_eq!(res, expected);
- });
-
- let graph = Graph::new();
- for (src, dst, t) in &vs {
- graph.add_edge(*src, *dst, *t, NO_PROPS, None).unwrap();
- }
- test_storage!(&graph, |graph| {
- let res: Vec<_> = (0..=3)
- .map(|i| {
- let wg = graph.window(args[i].0, args[i].1);
- let mut e = wg
- .nodes()
- .id()
- .iter_values()
- .filter_map(|id| id.to_u64())
- .collect::>();
- e.sort();
- e
- })
- .collect_vec();
- assert_eq!(res, expected);
- });
-}
-
-#[test]
-fn windowed_graph_nodes() {
- let vs = vec![
- (1, 1, 2),
- (2, 1, 3),
- (-1, 2, 1),
- (0, 1, 1),
- (7, 3, 2),
- (1, 1, 1),
- ];
-
- let graph = Graph::new();
-
- graph
- .add_node(
- 0,
- 1,
- [("type", "wallet".into_prop()), ("cost", 99.5.into_prop())],
- None,
- None,
- )
- .unwrap();
-
- graph
- .add_node(
- -1,
- 2,
- [("type", "wallet".into_prop()), ("cost", 10.0.into_prop())],
- None,
- None,
- )
- .unwrap();
-
- graph
- .add_node(
- 6,
- 3,
- [("type", "wallet".into_prop()), ("cost", 76.2.into_prop())],
- None,
- None,
- )
- .unwrap();
-
- for (t, src, dst) in &vs {
- graph
- .add_edge(*t, *src, *dst, [("eprop", "commons")], None)
- .unwrap();
- }
- test_storage!(&graph, |graph| {
- let wg = graph.window(-2, 0);
-
- let actual = wg
- .nodes()
- .id()
- .iter_values()
- .filter_map(|id| id.to_u64())
- .collect::>();
-
- let expected = vec![1, 2];
-
- assert_eq!(actual, expected);
- });
-}
-
-#[test]
-fn test_reference() {
- let graph = Graph::new();
- graph.add_edge(0, 1, 2, NO_PROPS, None).unwrap();
-
- test_storage!(&graph, |graph| {
- let mut w = WindowedGraph::new(&graph, Some(0.into_time()), Some(1.into_time()));
- assert_eq!(w, graph);
- w = WindowedGraph::new(&graph, Some(1.into_time()), Some(2.into_time()));
- assert_eq!(w, Graph::new());
- });
-}
-
-#[test]
-fn test_algorithm_on_windowed_graph() {
- global_info_logger();
- let graph = Graph::new();
- graph.add_edge(0, 1, 2, NO_PROPS, None).unwrap();
- test_storage!(&graph, |graph| {
- let w = graph.window(0, 1);
- let _ = degree_centrality(&w);
- });
-}
-
-#[test]
-fn test_view_resetting() {
- let graph = Graph::new();
- for t in 0..10 {
- let t1 = t * 3;
- let t2 = t * 3 + 1;
- let t3 = t * 3 + 2;
- graph.add_edge(t1, 1, 2, NO_PROPS, None).unwrap();
- graph.add_edge(t2, 2, 3, NO_PROPS, None).unwrap();
- graph.add_edge(t3, 3, 1, NO_PROPS, None).unwrap();
- }
-
- test_storage!(&graph, |graph| {
- assert_graph_equal(&graph.before(9).after(2), &graph.window(3, 9));
- let res = graph
- .window(3, 9)
- .nodes()
- .before(6)
- .edges()
- .window(1, 9)
- .earliest_time()
- .map(|it| it.map(|t_opt| t_opt.map(|t| t.t())).collect_vec())
- .collect_vec();
- assert_eq!(
- res,
- [[Some(3), Some(5)], [Some(3), Some(4)], [Some(5), Some(4)]]
- );
- });
-}
-
-#[test]
-fn test_entity_history() {
- let graph = Graph::new();
- graph.add_node(0, 0, NO_PROPS, None, None).unwrap();
- graph.add_node(1, 0, NO_PROPS, None, None).unwrap();
- graph.add_node(2, 0, NO_PROPS, None, None).unwrap();
- graph.add_node(3, 0, NO_PROPS, None, None).unwrap();
- graph.add_edge(0, 1, 2, NO_PROPS, None).unwrap();
- graph.add_edge(1, 1, 2, NO_PROPS, None).unwrap();
- graph.add_edge(2, 1, 2, NO_PROPS, None).unwrap();
- graph.add_edge(3, 1, 2, NO_PROPS, None).unwrap();
- graph.add_edge(4, 1, 3, NO_PROPS, None).unwrap();
- graph.add_edge(5, 1, 3, NO_PROPS, None).unwrap();
- graph.add_edge(6, 1, 3, NO_PROPS, None).unwrap();
- graph.add_edge(7, 1, 3, NO_PROPS, None).unwrap();
-
- // FIXME: Issue #46
- test_graph(&graph, |graph| {
- let e = graph.edge(1, 2).unwrap();
- let v = graph.node(0).unwrap();
- let full_history_1 = vec![0i64, 1, 2, 3];
-
- let full_history_2 = vec![4i64, 5, 6, 7];
-
- let windowed_history = vec![0i64, 1];
-
- assert_eq!(v.history(), full_history_1);
-
- assert_eq!(v.window(0, 2).history(), windowed_history);
- assert_eq!(e.history(), full_history_1);
- assert_eq!(e.window(0, 2).history(), windowed_history);
-
- assert_eq!(
- graph.edges().history().collect_vec(),
- [full_history_1.clone(), full_history_2.clone()]
- );
- assert_eq!(
- graph
- .nodes()
- .in_edges()
- .history()
- .map(|it| it.collect_vec())
- .collect_vec(),
- [vec![], vec![], vec![full_history_1], vec![full_history_2],]
- );
-
- assert_eq!(
- graph
- .nodes()
- .earliest_time()
- .iter_values()
- .flatten()
- .collect_vec(),
- [0, 0, 0, 4,]
- );
-
- assert_eq!(
- graph
- .nodes()
- .latest_time()
- .iter_values()
- .flatten()
- .collect_vec(),
- [3, 7, 3, 7]
- );
-
- assert_eq!(
- graph
- .nodes()
- .neighbours()
- .latest_time()
- .sorted_by_key(|(n, _)| n.id())
- .map(|(_, it)| it.flatten().collect_vec())
- .collect_vec(),
- [vec![], vec![3, 7], vec![7], vec![7],]
- );
-
- assert_eq!(
- graph
- .nodes()
- .neighbours()
- .earliest_time()
- .sorted_by_key(|(n, _)| n.id())
- .map(|(_, it)| it.flatten().collect_vec())
- .collect_vec(),
- [vec![], vec![0, 4], vec![0], vec![0],]
- );
- });
-}
-
-mod test_filters_window_graph {
-
- mod test_nodes_filters_window_graph {
- use raphtory::{
- db::{api::view::StaticGraphViewOps, graph::views::filter::model::ComposableFilter},
- prelude::{AdditionOps, PropertyAdditionOps},
- };
- use raphtory_api::core::{entities::properties::prop::Prop, storage::arc_str::ArcStr};
- use raphtory_storage::mutation::{
- addition_ops::InternalAdditionOps, property_addition_ops::InternalPropertyAdditionOps,
- };
- use raphtory_tests::assertions::{
- assert_filter_nodes_results, assert_search_nodes_results, TestGraphVariants,
- TestVariants,
- };
-
- use raphtory::{
- db::{
- api::view::filter_ops::Filter,
- graph::views::filter::model::{
- node_filter::{ops::NodeFilterOps, NodeFilter},
- property_filter::ops::PropertyFilterOps,
- PropertyFilterFactory,
- },
- },
- errors::GraphError,
- prelude::{Graph, GraphViewOps, TimeOps},
- };
- use raphtory_tests::assertions::WindowGraphTransformer;
-
- fn init_graph(graph: G) -> G {
- let nodes = vec![
- (
- 6,
- "N1",
- vec![
- ("p1", Prop::U64(2u64)),
- ("k1", Prop::I64(2i64)),
- ("k2", Prop::Str(ArcStr::from("Paper_Airplane"))),
- ("k3", Prop::Bool(true)),
- ("k4", Prop::F64(6.0f64)),
- ],
- Some("air_nomad"),
- ),
- (
- 7,
- "N1",
- vec![
- ("p1", Prop::U64(1u64)),
- ("k1", Prop::I64(5i64)),
- ("k3", Prop::Bool(false)),
- ],
- Some("air_nomad"),
- ),
- (
- 6,
- "N2",
- vec![("p1", Prop::U64(1u64)), ("k4", Prop::F64(6.0f64))],
- Some("water_tribe"),
- ),
- (
- 7,
- "N2",
- vec![
- ("p1", Prop::U64(2u64)),
- ("k1", Prop::I64(2i64)),
- ("k2", Prop::Str(ArcStr::from("Paper_Ship"))),
- ("k3", Prop::Bool(true)),
- ("k4", Prop::F64(10.0f64)),
- ],
- Some("water_tribe"),
- ),
- (8, "N3", vec![("p1", Prop::U64(1u64))], Some("air_nomad")),
- (9, "N4", vec![("p1", Prop::U64(1u64))], Some("air_nomad")),
- (
- 5,
- "N5",
- vec![
- ("p1", Prop::U64(1u64)),
- ("k1", Prop::I64(2i64)),
- ("k2", Prop::Str(ArcStr::from("Paper_Airplane"))),
- ("k3", Prop::Bool(true)),
- ("k4", Prop::F64(6.0f64)),
- ],
- Some("air_nomad"),
- ),
- (
- 6,
- "N5",
- vec![
- ("p1", Prop::U64(2u64)),
- ("k2", Prop::Str(ArcStr::from("Pometry"))),
- ("k4", Prop::F64(1.0f64)),
- ],
- Some("air_nomad"),
- ),
- (5, "N6", vec![("p1", Prop::U64(1u64))], Some("fire_nation")),
- (
- 6,
- "N6",
- vec![("p1", Prop::U64(1u64)), ("k4", Prop::F64(1.0f64))],
- Some("fire_nation"),
- ),
- (
- 3,
- "N7",
- vec![
- ("p1", Prop::U64(1u64)),
- ("k1", Prop::I64(2i64)),
- ("k2", Prop::Str(ArcStr::from("Paper_Ship"))),
- ("k3", Prop::Bool(true)),
- ("k4", Prop::F64(10.0f64)),
- ],
- Some("air_nomad"),
- ),
- (5, "N7", vec![("p1", Prop::U64(1u64))], Some("air_nomad")),
- (3, "N8", vec![("p1", Prop::U64(1u64))], Some("fire_nation")),
- (
- 4,
- "N8",
- vec![
- ("p1", Prop::U64(2u64)),
- ("k1", Prop::I64(2i64)),
- ("k2", Prop::Str(ArcStr::from("Sand_Clown"))),
- ("k3", Prop::Bool(true)),
- ("k4", Prop::F64(10.0f64)),
- ],
- Some("fire_nation"),
- ),
- (2, "N9", vec![("p1", Prop::U64(2u64))], None),
- (2, "N10", vec![("q1", Prop::U64(0u64))], None),
- (2, "N10", vec![("p1", Prop::U64(3u64))], None),
- (2, "N11", vec![("p1", Prop::U64(3u64))], None),
- (2, "N11", vec![("q1", Prop::U64(0u64))], None),
- (2, "N12", vec![("q1", Prop::U64(0u64))], None),
- (
- 3,
- "N12",
- vec![
- ("p1", Prop::U64(3u64)),
- ("k1", Prop::I64(2i64)),
- ("k2", Prop::Str(ArcStr::from("Sand_Clown"))),
- ("k3", Prop::Bool(true)),
- ("k4", Prop::F64(10.0f64)),
- ],
- None,
- ),
- (2, "N13", vec![("q1", Prop::U64(0u64))], None),
- (3, "N13", vec![("p1", Prop::U64(3u64))], None),
- (2, "N14", vec![("q1", Prop::U64(0u64))], None),
- (2, "N15", vec![], None),
- ];
-
- // Add nodes to the graph
- for (id, name, props, layer) in &nodes {
- graph
- .add_node(*id, name, props.clone(), *layer, None)
- .unwrap();
- }
-
- // Metadata property assignments
- let metadata = vec![
- (
- "N1",
- vec![
- ("p1", Prop::U64(1u64)),
- ("k1", Prop::I64(3i64)),
- ("k2", Prop::Str(ArcStr::from("Paper_Airplane"))),
- ("k3", Prop::Bool(true)),
- ("k4", Prop::F64(6.0f64)),
- ],
- ),
- ("N4", vec![("p1", Prop::U64(2u64))]),
- ("N9", vec![("p1", Prop::U64(1u64))]),
- ("N10", vec![("p1", Prop::U64(1u64))]),
- ("N11", vec![("p1", Prop::U64(1u64))]),
- ("N12", vec![("p1", Prop::U64(1u64))]),
- (
- "N13",
- vec![
- ("p1", Prop::U64(1u64)),
- ("k1", Prop::I64(2i64)),
- ("k2", Prop::Str(ArcStr::from("Sand_Clown"))),
- ("k3", Prop::Bool(true)),
- ("k4", Prop::F64(10.0f64)),
- ],
- ),
- ("N14", vec![("p1", Prop::U64(1u64))]),
- ("N15", vec![("p1", Prop::U64(1u64))]),
- ];
-
- // Apply metadata
- for (node, props) in metadata {
- graph.node(node).unwrap().add_metadata(props).unwrap();
- }
-
- graph
- }
-
- fn init_graph2<
- G: StaticGraphViewOps
- + AdditionOps
- + InternalAdditionOps
- + InternalPropertyAdditionOps
- + PropertyAdditionOps,
- >(
- graph: G,
- ) -> G {
- let nodes = vec![(
- 2,
- "N14",
- vec![
- ("q1", Prop::U64(0u64)),
- (
- "x",
- Prop::list(vec![Prop::U64(1), Prop::U64(6), Prop::U64(9)]),
- ),
- ],
- None,
- )];
-
- // Add nodes to the graph
- for (id, name, props, layer) in &nodes {
- graph
- .add_node(*id, name, props.clone(), *layer, None)
- .unwrap();
- }
-
- graph
- }
-
- #[test]
- fn test_nodes_filters_for_node_name_eq() {
- // TODO: Enable event_disk_graph once bug fixed: https://github.com/Pometry/Raphtory/issues/2098
- let filter = NodeFilter::name().eq("N2");
- let expected_results = vec!["N2"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
- }
-
- #[test]
- fn test_nodes_filters_pg_for_node_name_eq() {
- let filter = NodeFilter::name().eq("N2");
- let expected_results = vec!["N2"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
-
- #[test]
- fn test_nodes_filters_for_node_name_ne() {
- // TODO: Enable event_disk_graph once bug fixed: https://github.com/Pometry/Raphtory/issues/2098
- let filter = NodeFilter::name().ne("N2");
- let expected_results = vec!["N1", "N3", "N5", "N6"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- }
-
- #[test]
- fn test_nodes_filters_pg_for_node_name_ne() {
- let filter = NodeFilter::name().ne("N2");
- let expected_results = vec![
- "N1", "N10", "N11", "N12", "N13", "N14", "N15", "N3", "N5", "N6", "N7", "N8", "N9",
- ];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
-
- #[test]
- fn test_nodes_filters_for_node_name_in() {
- // TODO: Enable event_disk_graph once bug fixed: https://github.com/Pometry/Raphtory/issues/2098
- let filter = NodeFilter::name().is_in(vec!["N2"]);
- let expected_results = vec!["N2"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
-
- let filter = NodeFilter::name().is_in(vec!["N2", "N5"]);
- let expected_results = vec!["N2", "N5"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
- }
-
- #[test]
- fn test_nodes_filters_pg_for_node_name_in() {
- let filter = NodeFilter::name().is_in(vec!["N2"]);
- let expected_results = vec!["N2"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = NodeFilter::name().is_in(vec!["N2", "N5"]);
- let expected_results = vec!["N2", "N5"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
-
- #[test]
- fn test_nodes_filters_for_node_name_not_in() {
- // TODO: Enable event_disk_graph once bug fixed: https://github.com/Pometry/Raphtory/issues/2098
- let filter = NodeFilter::name().is_not_in(vec!["N5"]);
- let expected_results = vec!["N1", "N2", "N3", "N6"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- }
-
- #[test]
- fn test_nodes_filters_pg_for_node_name_not_in() {
- let filter = NodeFilter::name().is_not_in(vec!["N5"]);
- let expected_results = vec![
- "N1", "N10", "N11", "N12", "N13", "N14", "N15", "N2", "N3", "N6", "N7", "N8", "N9",
- ];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
-
- #[test]
- fn test_nodes_filters_for_node_type_eq() {
- // TODO: Enable event_disk_graph once bug fixed: https://github.com/Pometry/Raphtory/issues/2098
- let filter = NodeFilter::node_type().eq("fire_nation");
- let expected_results = vec!["N6"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- }
-
- #[test]
- fn test_nodes_filters_pg_for_node_type_eq() {
- let filter = NodeFilter::node_type().eq("fire_nation");
- let expected_results = vec!["N6", "N8"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
-
- #[test]
- fn test_nodes_filters_for_node_type_ne() {
- // TODO: Enable event_disk_graph once bug fixed: https://github.com/Pometry/Raphtory/issues/2098
- let filter = NodeFilter::node_type().ne("fire_nation");
- let expected_results = vec!["N1", "N2", "N3", "N5"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- }
-
- #[test]
- fn test_nodes_filters_pg_for_node_type_ne() {
- let filter = NodeFilter::node_type().ne("fire_nation");
- let expected_results = vec![
- "N1", "N10", "N11", "N12", "N13", "N14", "N15", "N2", "N3", "N5", "N7", "N9",
- ];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
-
- #[test]
- fn test_nodes_filters_for_node_type_in() {
- // TODO: Enable event_disk_graph once bug fixed: https://github.com/Pometry/Raphtory/issues/2098
- let filter = NodeFilter::node_type().is_in(vec!["fire_nation"]);
- let expected_results = vec!["N6"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
-
- let filter = NodeFilter::node_type().is_in(vec!["fire_nation", "air_nomad"]);
- let expected_results = vec!["N1", "N3", "N5", "N6"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- }
-
- #[test]
- fn test_nodes_filters_pg_for_node_type_in() {
- let filter = NodeFilter::node_type().is_in(vec!["fire_nation"]);
- let expected_results = vec!["N6", "N8"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = NodeFilter::node_type().is_in(vec!["fire_nation", "air_nomad"]);
- let expected_results = vec!["N1", "N3", "N5", "N6", "N7", "N8"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
-
- #[test]
- fn test_nodes_filters_for_node_type_not_in() {
- // TODO: Enable event_disk_graph once bug fixed: https://github.com/Pometry/Raphtory/issues/2098
- let filter = NodeFilter::node_type().is_not_in(vec!["fire_nation"]);
- let expected_results = vec!["N1", "N2", "N3", "N5"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- }
-
- #[test]
- fn test_nodes_filters_pg_for_node_type_not_in() {
- let filter = NodeFilter::node_type().is_not_in(vec!["fire_nation"]);
- let expected_results = vec![
- "N1", "N10", "N11", "N12", "N13", "N14", "N15", "N2", "N3", "N5", "N7", "N9",
- ];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
-
- #[test]
- fn test_nodes_filters_for_property_eq() {
- // TODO: Enable event_disk_graph once bug fixed: https://github.com/Pometry/Raphtory/issues/2098
- let filter = NodeFilter.property("p1").eq(1u64);
- let expected_results = vec!["N1", "N3", "N6"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
-
- let filter = NodeFilter.property("k1").eq(2i64);
- let expected_results = vec!["N2"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
-
- let filter = NodeFilter.property("k2").eq("Paper_Airplane");
- let expected_results = vec!["N1"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
-
- let filter = NodeFilter.property("k3").eq(true);
- let expected_results = vec!["N2"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
-
- let filter = NodeFilter.property("k4").eq(6.0f64);
- let expected_results = vec!["N1"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
-
- let filter = NodeFilter.property("x").eq(Prop::list(vec![
- Prop::U64(1),
- Prop::U64(6),
- Prop::U64(9),
- ]));
- let expected_results = vec!["N14"];
- // TODO: List(U64) not supported as disk_graph property
- // assert_filter_nodes_results_w!(
- // init_graph2,
- // filter,
- // 1..9,
- // expected_results,
- // variants = [graph]
- // );
- assert_filter_nodes_results(
- init_graph2,
- WindowGraphTransformer(1..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- // TODO: Search APIs don't support list yet
- // assert_search_nodes_results(
- // init_graph,
- // WindowGraphTransformer(6..9),
- // filter,
- // &expected_results,
- // TestVariants::EventOnly,
- // );
- }
-
- #[test]
- fn test_nodes_filters_pg_for_property_eq() {
- let filter = NodeFilter.property("p1").eq(1u64);
- let expected_results = vec!["N1", "N3", "N6", "N7"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = NodeFilter.property("k1").eq(2i64);
- let expected_results = vec!["N12", "N2", "N5", "N7", "N8"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = NodeFilter.property("k2").eq("Paper_Airplane");
- let expected_results = vec!["N1"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- // TODO: Const properties not supported for disk_graph.
- let filter = NodeFilter.property("k3").eq(true);
- let expected_results = vec!["N12", "N2", "N5", "N7", "N8"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = NodeFilter.property("k4").eq(6.0f64);
- let expected_results = vec!["N1"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = NodeFilter.property("x").eq(Prop::list(vec![
- Prop::U64(1),
- Prop::U64(6),
- Prop::U64(9),
- ]));
- let expected_results = vec!["N14"];
- // TODO: List(U64) not supported as disk_graph property
- // assert_filter_nodes_results_pg_w!(
- // init_graph2,
- // filter,
- // 1..9,
- // expected_results,
- // variants = [persistent_graph]
- // );
- assert_filter_nodes_results(
- init_graph2,
- WindowGraphTransformer(1..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::PersistentGraph],
- );
- // TODO: Search APIs don't support list yet
- // assert_search_nodes_results(
- // init_graph,
- // WindowGraphTransformer(6..9),
- // filter,
- // &expected_results,
- // vec![TestGraphVariants::PersistentGraph],
- // );
- }
-
- #[test]
- fn test_nodes_filters_for_property_ne() {
- // TODO: Enable event_disk_graph once bug fixed: https://github.com/Pometry/Raphtory/issues/2098
- let filter = NodeFilter.property("p1").ne(1u64);
- let expected_results = vec!["N2", "N5"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
-
- let filter = NodeFilter.property("k1").ne(2i64);
- let expected_results = vec!["N1"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
-
- let filter = NodeFilter.property("k2").ne("Paper_Airplane");
- let expected_results = vec!["N2", "N5"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
-
- let filter = NodeFilter.property("k3").ne(true);
- let expected_results = vec!["N1"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
-
- let filter = NodeFilter.property("k4").ne(6.0f64);
- let expected_results = vec!["N2", "N5", "N6"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- }
-
- #[test]
- fn test_nodes_filters_pg_for_property_ne() {
- let filter = NodeFilter.property("p1").ne(1u64);
- let expected_results = vec!["N10", "N11", "N12", "N13", "N2", "N5", "N8", "N9"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = NodeFilter.property("k1").ne(2i64);
- let expected_results = vec!["N1"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = NodeFilter.property("k2").ne("Paper_Airplane");
- let expected_results = vec!["N12", "N2", "N5", "N7", "N8"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = NodeFilter.property("k3").ne(true);
- let expected_results = vec!["N1"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = NodeFilter.property("k4").ne(6.0f64);
- let expected_results = vec!["N12", "N2", "N5", "N6", "N7", "N8"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
-
- #[test]
- fn test_nodes_filters_for_property_lt() {
- // TODO: Enable event_disk_graph once bug fixed: https://github.com/Pometry/Raphtory/issues/2098
- let filter = NodeFilter.property("p1").lt(3u64);
- let expected_results = vec!["N1", "N2", "N3", "N5", "N6"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
-
- let filter = NodeFilter.property("k1").lt(3i64);
- let expected_results = vec!["N2"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
-
- let filter = NodeFilter.property("k4").lt(10.0f64);
- let expected_results = vec!["N1", "N5", "N6"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- }
-
- #[test]
- fn test_nodes_filters_pg_for_property_lt() {
- let filter = NodeFilter.property("p1").lt(3u64);
- let expected_results = vec!["N1", "N2", "N3", "N5", "N6", "N7", "N8", "N9"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = NodeFilter.property("k1").lt(3i64);
- let expected_results = vec!["N12", "N2", "N5", "N7", "N8"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = NodeFilter.property("k4").lt(10.0f64);
- let expected_results = vec!["N1", "N5", "N6"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
-
- #[test]
- fn test_nodes_filters_for_property_le() {
- // TODO: Enable event_disk_graph once bug fixed: https://github.com/Pometry/Raphtory/issues/2098
- let filter = NodeFilter.property("p1").le(1u64);
- let expected_results = vec!["N1", "N3", "N6"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
-
- let filter = NodeFilter.property("k1").le(2i64);
- let expected_results = vec!["N2"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
-
- let filter = NodeFilter.property("k4").le(6.0f64);
- let expected_results = vec!["N1", "N5", "N6"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- }
-
- #[test]
- fn test_nodes_filters_pg_for_property_le() {
- let filter = NodeFilter.property("p1").le(1u64);
- let expected_results = vec!["N1", "N3", "N6", "N7"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = NodeFilter.property("k1").le(2i64);
- let expected_results = vec!["N12", "N2", "N5", "N7", "N8"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = NodeFilter.property("k4").le(6.0f64);
- let expected_results = vec!["N1", "N5", "N6"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
-
- #[test]
- fn test_nodes_filters_for_property_gt() {
- // TODO: Enable event_disk_graph once bug fixed: https://github.com/Pometry/Raphtory/issues/2098
- let filter = NodeFilter.property("p1").gt(1u64);
- let expected_results = vec!["N2", "N5"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
-
- let filter = NodeFilter.property("k1").gt(2i64);
- let expected_results = vec!["N1"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
-
- let filter = NodeFilter.property("k4").gt(6.0f64);
- let expected_results = vec!["N2"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
-
- let filter = NodeFilter.property("x").gt(Prop::List(
- vec![Prop::U64(1), Prop::U64(6), Prop::U64(9)].into(),
- ));
- let graph = init_graph(Graph::new());
- assert!(matches!(
- graph.window(1, 9).filter(filter.clone()).unwrap_err(),
- GraphError::PropertyMissingError(ref name) if name == "x"
- ));
- assert!(matches!(
- graph.persistent_graph().window(1, 9).filter(filter).unwrap_err(),
- GraphError::PropertyMissingError(ref name) if name == "x"
- ));
- }
-
- #[test]
- fn test_nodes_filters_pg_for_property_gt() {
- let filter = NodeFilter.property("p1").gt(1u64);
- let expected_results = vec!["N10", "N11", "N12", "N13", "N2", "N5", "N8", "N9"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = NodeFilter.property("k1").gt(2i64);
- let expected_results = vec!["N1"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = NodeFilter.property("k4").gt(6.0f64);
- let expected_results = vec!["N12", "N2", "N7", "N8"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
-
- #[test]
- fn test_nodes_filters_for_property_ge() {
- // TODO: Enable event_disk_graph once bug fixed: https://github.com/Pometry/Raphtory/issues/2098
- let filter = NodeFilter.property("p1").ge(1u64);
- let expected_results = vec!["N1", "N2", "N3", "N5", "N6"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
-
- let filter = NodeFilter.property("k1").ge(2i64);
- let expected_results = vec!["N1", "N2"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
-
- let filter = NodeFilter.property("k4").ge(6.0f64);
- let expected_results = vec!["N1", "N2"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- }
-
- #[test]
- fn test_nodes_filters_pg_for_property_ge() {
- let filter = NodeFilter.property("p1").ge(1u64);
- let expected_results = vec![
- "N1", "N10", "N11", "N12", "N13", "N2", "N3", "N5", "N6", "N7", "N8", "N9",
- ];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = NodeFilter.property("k1").ge(2i64);
- let expected_results = vec!["N1", "N12", "N2", "N5", "N7", "N8"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = NodeFilter.property("k4").ge(6.0f64);
- let expected_results = vec!["N1", "N12", "N2", "N7", "N8"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
-
- #[test]
- fn test_nodes_filters_for_property_in() {
- // TODO: Enable event_disk_graph once bug fixed: https://github.com/Pometry/Raphtory/issues/2098
- let filter = NodeFilter.property("p1").is_in(vec![2u64.into()]);
- let expected_results = vec!["N2", "N5"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
-
- let filter = NodeFilter.property("k1").is_in(vec![2i64.into()]);
- let expected_results = vec!["N2"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
-
- let filter = NodeFilter
- .property("k2")
- .is_in(vec!["Paper_Airplane".into()]);
- let expected_results = vec!["N1"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
-
- let filter = NodeFilter.property("k3").is_in(vec![true.into()]);
- let expected_results = vec!["N2"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
-
- let filter = NodeFilter.property("k4").is_in(vec![6.0f64.into()]);
- let expected_results = vec!["N1"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- }
-
- #[test]
- fn test_nodes_filters_pg_for_property_in() {
- let filter = NodeFilter.property("p1").is_in(vec![2u64.into()]);
- let expected_results = vec!["N2", "N5", "N8", "N9"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = NodeFilter.property("k1").is_in(vec![2i64.into()]);
- let expected_results = vec!["N12", "N2", "N5", "N7", "N8"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = NodeFilter
- .property("k2")
- .is_in(vec!["Paper_Airplane".into()]);
- let expected_results = vec!["N1"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- // TODO: Const properties not supported for disk_graph.
- let filter = NodeFilter.property("k3").is_in(vec![true.into()]);
- let expected_results = vec!["N12", "N2", "N5", "N7", "N8"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = NodeFilter.property("k4").is_in(vec![6.0f64.into()]);
- let expected_results = vec!["N1"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
-
- #[test]
- fn test_nodes_filters_for_property_not_in() {
- // TODO: Enable event_disk_graph once bug fixed: https://github.com/Pometry/Raphtory/issues/2098
- let filter = NodeFilter.property("p1").is_not_in(vec![1u64.into()]);
- let expected_results = vec!["N2", "N5"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
-
- let filter = NodeFilter.property("k1").is_not_in(vec![2i64.into()]);
- let expected_results = vec!["N1"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
-
- let filter = NodeFilter
- .property("k2")
- .is_not_in(vec!["Paper_Airplane".into()]);
- let expected_results = vec!["N2", "N5"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
-
- let filter = NodeFilter.property("k3").is_not_in(vec![true.into()]);
- let expected_results = vec!["N1"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
-
- let filter = NodeFilter.property("k4").is_not_in(vec![6.0f64.into()]);
- let expected_results = vec!["N2", "N5", "N6"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- }
-
- #[test]
- fn test_nodes_filters_pg_for_property_not_in() {
- let filter = NodeFilter.property("p1").is_not_in(vec![1u64.into()]);
- let expected_results = vec!["N10", "N11", "N12", "N13", "N2", "N5", "N8", "N9"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = NodeFilter.property("k1").is_not_in(vec![2i64.into()]);
- let expected_results = vec!["N1"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = NodeFilter
- .property("k2")
- .is_not_in(vec!["Paper_Airplane".into()]);
- let expected_results = vec!["N12", "N2", "N5", "N7", "N8"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = NodeFilter.property("k3").is_not_in(vec![true.into()]);
- let expected_results = vec!["N1"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = NodeFilter.property("k4").is_not_in(vec![6.0f64.into()]);
- let expected_results = vec!["N12", "N2", "N5", "N6", "N7", "N8"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
-
- #[test]
- fn test_nodes_filters_for_property_is_some() {
- // TODO: Enable event_disk_graph once bug fixed: https://github.com/Pometry/Raphtory/issues/2098
- let filter = NodeFilter.property("p1").is_some();
- let expected_results = vec!["N1", "N2", "N3", "N5", "N6"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
-
- let expected_results = Vec::<&str>::new();
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(1..2),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(1..2),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
-
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(10..12),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(10..12),
- filter,
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- }
-
- #[test]
- fn test_nodes_filters_pg_for_property_is_some() {
- let filter = NodeFilter.property("p1").is_some();
- let expected_results = vec![
- "N1", "N10", "N11", "N12", "N13", "N2", "N3", "N5", "N6", "N7", "N8", "N9",
- ];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let expected_results = Vec::<&str>::new();
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(1..2),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(1..2),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let expected_results = vec![
- "N1", "N10", "N11", "N12", "N13", "N2", "N3", "N4", "N5", "N6", "N7", "N8", "N9",
- ];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(10..12),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(10..12),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
-
- #[test]
- fn test_nodes_filters_for_props_added_at_different_times() {
- let filter = NodeFilter
- .property("q1")
- .eq(0u64)
- .and(NodeFilter.property("p1").eq(3u64));
- let expected_results = vec!["N10", "N11", "N12", "N13"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(1..4),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(1..4),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
- }
-
- #[test]
- fn test_nodes_filters_pg_for_props_added_at_different_times() {
- let filter = NodeFilter
- .property("q1")
- .eq(0u64)
- .and(NodeFilter.property("p1").eq(3u64));
- let expected_results = vec!["N10", "N11", "N12", "N13"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
-
- #[test]
- fn test_nodes_filters_fuzzy_search() {
- // TODO: Enable event_disk_graph once bug fixed: https://github.com/Pometry/Raphtory/issues/2098
- let filter = NodeFilter
- .property("k2")
- .fuzzy_search("Paper_Airpla", 2, false);
- let expected_results = vec!["N1"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- }
-
- #[test]
- fn test_nodes_filters_pg_fuzzy_search() {
- let filter = NodeFilter
- .property("k2")
- .fuzzy_search("Paper_Air", 5, false);
- let expected_results = vec!["N1", "N2", "N7"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
-
- #[test]
- fn test_nodes_filters_fuzzy_search_prefix_match() {
- // TODO: Enable event_disk_graph once bug fixed: https://github.com/Pometry/Raphtory/issues/2098
- let filter = NodeFilter.property("k2").fuzzy_search("Pa", 2, true);
- let expected_results = vec!["N1", "N2"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
-
- let filter = NodeFilter.property("k2").fuzzy_search("Pa", 2, false);
- let expected_results = Vec::<&str>::new();
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- }
-
- #[test]
- fn test_nodes_filters_pg_fuzzy_search_prefix_match() {
- let filter = NodeFilter.property("k2").fuzzy_search("Pa", 2, true);
- let expected_results = vec!["N1", "N2", "N7"];
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = NodeFilter.property("k2").fuzzy_search("Pa", 2, false);
- let expected_results = Vec::<&str>::new();
- assert_filter_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_nodes_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
- }
-
- mod test_edges_filters_window_graph {
- use raphtory::{
- db::{
- api::view::{filter_ops::Filter, StaticGraphViewOps},
- graph::views::filter::model::{
- edge_filter::EdgeFilter, node_filter::ops::NodeFilterOps,
- property_filter::ops::PropertyFilterOps, ComposableFilter,
- PropertyFilterFactory,
- },
- },
- errors::GraphError,
- prelude::{AdditionOps, Graph, GraphViewOps, PropertyAdditionOps, TimeOps, NO_PROPS},
- };
- use raphtory_api::core::{entities::properties::prop::Prop, storage::arc_str::ArcStr};
- use raphtory_tests::assertions::{
- assert_filter_edges_results, assert_search_edges_results, TestGraphVariants,
- TestVariants, WindowGraphTransformer,
- };
-
- fn init_graph(graph: G) -> G {
- let edges = vec![
- (
- 6,
- "N1",
- "N2",
- vec![
- ("p1", Prop::U64(2u64)),
- ("k1", Prop::I64(2i64)),
- ("k2", Prop::Str(ArcStr::from("Paper_Airplane"))),
- ("k3", Prop::Bool(true)),
- ("k4", Prop::F64(6.0f64)),
- ],
- Some("air_nomad"),
- ),
- (
- 7,
- "N1",
- "N2",
- vec![
- ("p1", Prop::U64(1u64)),
- ("k1", Prop::I64(5i64)),
- ("k3", Prop::Bool(false)),
- ],
- Some("air_nomad"),
- ),
- (
- 6,
- "N2",
- "N3",
- vec![("p1", Prop::U64(1u64)), ("k4", Prop::F64(6.0f64))],
- Some("water_tribe"),
- ),
- (
- 7,
- "N2",
- "N3",
- vec![
- ("p1", Prop::U64(2u64)),
- ("k1", Prop::I64(2i64)),
- ("k2", Prop::Str(ArcStr::from("Paper_Ship"))),
- ("k3", Prop::Bool(true)),
- ("k4", Prop::F64(10.0f64)),
- ],
- Some("water_tribe"),
- ),
- (
- 8,
- "N3",
- "N4",
- vec![("p1", Prop::U64(1u64))],
- Some("air_nomad"),
- ),
- (
- 9,
- "N4",
- "N5",
- vec![("p1", Prop::U64(1u64))],
- Some("air_nomad"),
- ),
- (
- 5,
- "N5",
- "N6",
- vec![
- ("p1", Prop::U64(1u64)),
- ("k1", Prop::I64(2i64)),
- ("k2", Prop::Str(ArcStr::from("Paper_Airplane"))),
- ("k3", Prop::Bool(true)),
- ("k4", Prop::F64(6.0f64)),
- ],
- Some("air_nomad"),
- ),
- (
- 6,
- "N5",
- "N6",
- vec![
- ("p1", Prop::U64(2u64)),
- ("k2", Prop::Str(ArcStr::from("Pometry"))),
- ("k4", Prop::F64(1.0f64)),
- ],
- Some("air_nomad"),
- ),
- (
- 5,
- "N6",
- "N7",
- vec![("p1", Prop::U64(1u64))],
- Some("fire_nation"),
- ),
- (
- 6,
- "N6",
- "N7",
- vec![("p1", Prop::U64(1u64)), ("k4", Prop::F64(1.0f64))],
- Some("fire_nation"),
- ),
- (
- 3,
- "N7",
- "N8",
- vec![
- ("p1", Prop::U64(1u64)),
- ("k1", Prop::I64(2i64)),
- ("k2", Prop::Str(ArcStr::from("Paper_Ship"))),
- ("k3", Prop::Bool(true)),
- ("k4", Prop::F64(10.0f64)),
- ],
- Some("air_nomad"),
- ),
- (
- 5,
- "N7",
- "N8",
- vec![("p1", Prop::U64(1u64))],
- Some("air_nomad"),
- ),
- (
- 3,
- "N8",
- "N9",
- vec![("p1", Prop::U64(1u64))],
- Some("fire_nation"),
- ),
- (
- 4,
- "N8",
- "N9",
- vec![
- ("p1", Prop::U64(2u64)),
- ("k1", Prop::I64(2i64)),
- ("k2", Prop::Str(ArcStr::from("Sand_Clown"))),
- ("k3", Prop::Bool(true)),
- ("k4", Prop::F64(10.0f64)),
- ],
- Some("fire_nation"),
- ),
- (2, "N9", "N10", vec![("p1", Prop::U64(2u64))], None),
- (2, "N10", "N11", vec![("q1", Prop::U64(0u64))], None),
- (2, "N10", "N11", vec![("p1", Prop::U64(3u64))], None),
- (2, "N11", "N12", vec![("p1", Prop::U64(3u64))], None),
- (2, "N11", "N12", vec![("q1", Prop::U64(0u64))], None),
- (2, "N12", "N13", vec![("q1", Prop::U64(0u64))], None),
- (
- 3,
- "N12",
- "N13",
- vec![
- ("p1", Prop::U64(3u64)),
- ("k1", Prop::I64(2i64)),
- ("k2", Prop::Str(ArcStr::from("Sand_Clown"))),
- ("k3", Prop::Bool(true)),
- ("k4", Prop::F64(10.0f64)),
- ],
- None,
- ),
- (2, "N13", "N14", vec![("q1", Prop::U64(0u64))], None),
- (3, "N13", "N14", vec![("p1", Prop::U64(3u64))], None),
- (2, "N14", "N15", vec![("q1", Prop::U64(0u64))], None),
- (2, "N15", "N1", vec![], None),
- ];
-
- for (id, src, dst, props, layer) in &edges {
- graph
- .add_edge(*id, src, dst, props.clone(), *layer)
- .unwrap();
- }
-
- // Metadata property assignments
- let metadata = vec![
- (
- "N1",
- "N2",
- vec![
- ("p1", Prop::U64(1u64)),
- ("k1", Prop::I64(3i64)),
- ("k2", Prop::Str(ArcStr::from("Paper_Airplane"))),
- ("k3", Prop::Bool(true)),
- ("k4", Prop::F64(6.0f64)),
- ],
- Some("air_nomad"),
- ),
- ("N4", "N5", vec![("p1", Prop::U64(2u64))], Some("air_nomad")),
- ("N9", "N10", vec![("p1", Prop::U64(1u64))], None),
- ("N10", "N11", vec![("p1", Prop::U64(1u64))], None),
- ("N11", "N12", vec![("p1", Prop::U64(1u64))], None),
- ("N12", "N13", vec![("p1", Prop::U64(1u64))], None),
- (
- "N13",
- "N14",
- vec![
- ("p1", Prop::U64(1u64)),
- ("k1", Prop::I64(2i64)),
- ("k2", Prop::Str(ArcStr::from("Sand_Clown"))),
- ("k3", Prop::Bool(true)),
- ("k4", Prop::F64(10.0f64)),
- ],
- None,
- ),
- ("N14", "N15", vec![("p1", Prop::U64(1u64))], None),
- ("N15", "N1", vec![("p1", Prop::U64(1u64))], None),
- ];
-
- for (src, dst, props, layer) in metadata {
- graph
- .edge(src, dst)
- .unwrap()
- .add_metadata(props, layer)
- .unwrap();
- }
-
- graph.add_node(1, "N1", NO_PROPS, None, None).unwrap();
- graph.add_node(2, "N2", NO_PROPS, None, None).unwrap();
- graph.add_node(3, "N3", NO_PROPS, None, None).unwrap();
-
- graph
- }
-
- fn init_graph2(graph: G) -> G {
- let edges = vec![(
- 2,
- "N14",
- "N15",
- vec![
- ("q1", Prop::U64(0u64)),
- (
- "x",
- Prop::list(vec![Prop::U64(1), Prop::U64(6), Prop::U64(9)]),
- ),
- ],
- None,
- )];
-
- for (id, src, dst, props, layer) in &edges {
- graph
- .add_edge(*id, src, dst, props.clone(), *layer)
- .unwrap();
- }
-
- graph
- }
-
- #[test]
- fn test_edges_filters_for_src_eq() {
- let filter = EdgeFilter::src().name().eq("N2");
- let expected_results = vec!["N2->N3"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
- }
-
- #[test]
- fn test_edges_filters_pg_for_src_eq() {
- let filter = EdgeFilter::src().name().eq("N2");
- let expected_results = vec!["N2->N3"];
- // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![],
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
-
- #[test]
- fn test_edges_filters_for_src_ne() {
- let filter = EdgeFilter::src().name().ne("N2");
- let expected_results = vec!["N1->N2", "N3->N4", "N5->N6", "N6->N7"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
- }
-
- #[test]
- fn test_edges_filters_pg_for_src_ne() {
- let filter = EdgeFilter::src().name().ne("N2");
- let expected_results = vec![
- "N1->N2", "N10->N11", "N11->N12", "N12->N13", "N13->N14", "N14->N15", "N15->N1",
- "N3->N4", "N5->N6", "N6->N7", "N7->N8", "N8->N9", "N9->N10",
- ];
- // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![],
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- vec![TestGraphVariants::PersistentGraph],
- );
- }
-
- #[test]
- fn test_edges_filters_for_dst_in() {
- let filter = EdgeFilter::dst().name().is_in(vec!["N2"]);
- let expected_results = vec!["N1->N2"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
-
- let filter = EdgeFilter::dst().name().is_in(vec!["N2", "N5"]);
- let expected_results = vec!["N1->N2"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
- }
-
- #[test]
- fn test_edges_filters_pg_for_dst_in() {
- // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
- let filter = EdgeFilter::dst().name().is_in(vec!["N2"]);
- let expected_results = vec!["N1->N2"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![],
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = EdgeFilter::dst().name().is_in(vec!["N2", "N5"]);
- let expected_results = vec!["N1->N2"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![],
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
-
- #[test]
- fn test_edges_filters_for_dst_not_in() {
- let filter = EdgeFilter::dst().name().is_not_in(vec!["N5"]);
- let expected_results = vec!["N1->N2", "N2->N3", "N3->N4", "N5->N6", "N6->N7"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
- }
-
- #[test]
- fn test_edges_filters_pg_for_dst_not_in() {
- let filter = EdgeFilter::dst().name().is_not_in(vec!["N5"]);
- let expected_results = vec![
- "N1->N2", "N10->N11", "N11->N12", "N12->N13", "N13->N14", "N14->N15", "N15->N1",
- "N2->N3", "N3->N4", "N5->N6", "N6->N7", "N7->N8", "N8->N9", "N9->N10",
- ];
- // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- vec![],
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
-
- #[test]
- fn test_edges_filters_for_property_eq() {
- let filter = EdgeFilter.property("p1").eq(1u64);
- let expected_results = vec!["N1->N2", "N3->N4", "N6->N7"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
-
- let filter = EdgeFilter.property("k1").eq(2i64);
- let expected_results = vec!["N2->N3"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
-
- let filter = EdgeFilter.property("k2").eq("Paper_Airplane");
- let expected_results = vec!["N1->N2"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
-
- let filter = EdgeFilter.property("k3").eq(true);
- let expected_results = vec!["N2->N3"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
-
- let filter = EdgeFilter.property("k4").eq(6.0f64);
- let expected_results = vec!["N1->N2"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
-
- let filter = EdgeFilter.property("x").eq(Prop::list(vec![
- Prop::U64(1),
- Prop::U64(6),
- Prop::U64(9),
- ]));
- let expected_results = vec!["N14->N15"];
- // TODO: List(U64) not supported as disk_graph property
- // assert_filter_edges_results_w!(
- // init_graph2,
- // filter,
- // 1..9,
- // expected_results,
- // variants = [graph]
- // );
- assert_filter_edges_results(
- init_graph2,
- WindowGraphTransformer(1..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::Graph],
- );
- // TODO: Search APIs don't support list yet
- // assert_search_edges_results(
- // init_graph2,
- // WindowGraphTransformer(6..9),
- // filter,
- // &expected_results,
- // TestVariants::PersistentOnly,
- // );
- }
-
- #[test]
- fn test_edges_filters_pg_for_property_eq() {
- // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
- // TODO: Const properties not supported for disk_graph.
- let filter = EdgeFilter.property("p1").eq(1u64);
- let expected_results = vec!["N1->N2", "N3->N4", "N6->N7", "N7->N8"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = EdgeFilter.property("k1").eq(2i64);
-
- let expected_results = vec!["N12->N13", "N2->N3", "N5->N6", "N7->N8", "N8->N9"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = EdgeFilter.property("k2").eq("Paper_Airplane");
- let expected_results = vec!["N1->N2"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = EdgeFilter.property("k3").eq(true);
- let expected_results = vec!["N12->N13", "N2->N3", "N5->N6", "N7->N8", "N8->N9"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = EdgeFilter.property("k4").eq(6.0f64);
- let expected_results = vec!["N1->N2"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = EdgeFilter.property("x").eq(Prop::list(vec![
- Prop::U64(1),
- Prop::U64(6),
- Prop::U64(9),
- ]));
- let expected_results = vec!["N14->N15"];
- // TODO: List(U64) not supported as disk_graph property
- // assert_filter_edges_results_pg_w!(
- // init_graph2,
- // filter,
- // 1..9,
- // expected_results,
- // variants = []
- // );
- assert_filter_edges_results(
- init_graph2,
- WindowGraphTransformer(1..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::PersistentGraph],
- );
- // TODO: Search APIs don't support list yet
- // assert_search_edges_results(
- // init_graph2,
- // WindowGraphTransformer(1..9),
- // filter.clone(),
- // &expected_results,
- // vec![TestGraphVariants::PersistentGraph],
- // );
- }
-
- #[test]
- fn test_edges_filters_for_property_ne() {
- let filter = EdgeFilter.property("p1").ne(1u64);
- let expected_results = vec!["N2->N3", "N5->N6"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
-
- let filter = EdgeFilter.property("k1").ne(2i64);
- let expected_results = vec!["N1->N2"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
-
- let filter = EdgeFilter.property("k2").ne("Paper_Airplane");
- let expected_results = vec!["N2->N3", "N5->N6"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
-
- let filter = EdgeFilter.property("k3").ne(true);
- let expected_results = vec!["N1->N2"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
-
- let filter = EdgeFilter.property("k4").ne(6.0f64);
- let expected_results = vec!["N2->N3", "N5->N6", "N6->N7"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- }
-
- #[test]
- fn test_edges_filters_pg_for_property_ne() {
- // TODO: Const properties not supported for disk_graph.
- let filter = EdgeFilter.property("p1").ne(1u64);
- let expected_results = vec![
- "N10->N11", "N11->N12", "N12->N13", "N13->N14", "N2->N3", "N5->N6", "N8->N9",
- "N9->N10",
- ];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = EdgeFilter.property("k1").ne(2i64);
- let expected_results = vec!["N1->N2"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = EdgeFilter.property("k2").ne("Paper_Airplane");
- let expected_results = vec!["N12->N13", "N2->N3", "N5->N6", "N7->N8", "N8->N9"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = EdgeFilter.property("k3").ne(true);
- let expected_results = vec!["N1->N2"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = EdgeFilter.property("k4").ne(6.0f64);
- let expected_results =
- vec!["N12->N13", "N2->N3", "N5->N6", "N6->N7", "N7->N8", "N8->N9"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = EdgeFilter.property("x").ne(Prop::list(vec![
- Prop::U64(1),
- Prop::U64(6),
- Prop::U64(9),
- ]));
- let expected_results = Vec::<&str>::new();
- assert_filter_edges_results(
- init_graph2,
- WindowGraphTransformer(1..9),
- filter.clone(),
- &expected_results,
- vec![TestGraphVariants::PersistentGraph],
- );
- // TODO: Search APIs don't support list yet
- // assert_search_edges_results(
- // init_graph2,
- // WindowGraphTransformer(1..9),
- // filter.clone(),
- // &expected_results,
- // TestVariants::PersistentOnly,
- // );
- }
-
- #[test]
- fn test_edges_filters_for_property_lt() {
- let filter = EdgeFilter.property("p1").lt(3u64);
- let expected_results = vec!["N1->N2", "N2->N3", "N3->N4", "N5->N6", "N6->N7"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
-
- let filter = EdgeFilter.property("k1").lt(3i64);
- let expected_results = vec!["N2->N3"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
-
- let filter = EdgeFilter.property("k4").lt(10.0f64);
- let expected_results = vec!["N1->N2", "N5->N6", "N6->N7"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
- }
-
- #[test]
- fn test_edges_filters_pg_for_property_lt() {
- // TODO: Const properties not supported for disk_graph.
- let filter = EdgeFilter.property("p1").lt(3u64);
- let expected_results = vec![
- "N1->N2", "N2->N3", "N3->N4", "N5->N6", "N6->N7", "N7->N8", "N8->N9", "N9->N10",
- ];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = EdgeFilter.property("k1").lt(3i64);
- let expected_results = vec!["N12->N13", "N2->N3", "N5->N6", "N7->N8", "N8->N9"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = EdgeFilter.property("k4").lt(10.0f64);
- let expected_results = vec!["N1->N2", "N5->N6", "N6->N7"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
-
- #[test]
- fn test_edges_filters_for_property_le() {
- let filter = EdgeFilter.property("p1").le(1u64);
- let expected_results = vec!["N1->N2", "N3->N4", "N6->N7"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
-
- let filter = EdgeFilter.property("k1").le(2i64);
- let expected_results = vec!["N2->N3"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
-
- let filter = EdgeFilter.property("k4").le(6.0f64);
- let expected_results = vec!["N1->N2", "N5->N6", "N6->N7"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
- }
-
- #[test]
- fn test_edges_filters_pg_for_property_le() {
- // TODO: Const properties not supported for disk_graph.
- let filter = EdgeFilter.property("p1").le(1u64);
- let expected_results = vec!["N1->N2", "N3->N4", "N6->N7", "N7->N8"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = EdgeFilter.property("k1").le(2i64);
- let expected_results = vec!["N12->N13", "N2->N3", "N5->N6", "N7->N8", "N8->N9"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = EdgeFilter.property("k4").le(6.0f64);
- let expected_results = vec!["N1->N2", "N5->N6", "N6->N7"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
-
- #[test]
- fn test_edges_filters_for_property_gt() {
- let filter = EdgeFilter.property("p1").gt(1u64);
- let expected_results = vec!["N2->N3", "N5->N6"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
-
- let filter = EdgeFilter.property("k1").gt(2i64);
- let expected_results = vec!["N1->N2"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
-
- let filter = EdgeFilter.property("k4").gt(6.0f64);
- let expected_results = vec!["N2->N3"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
-
- let filter = EdgeFilter.property("x").gt(Prop::List(
- vec![Prop::U64(1), Prop::U64(6), Prop::U64(9)].into(),
- ));
- let graph = init_graph(Graph::new());
- assert!(matches!(
- graph.window(1, 9).filter(filter.clone()).unwrap_err(),
- GraphError::PropertyMissingError(ref name) if name == "x"
- ));
- assert!(matches!(
- graph.persistent_graph().window(1, 9).filter(filter).unwrap_err(),
- GraphError::PropertyMissingError(ref name) if name == "x"
- ));
- }
-
- #[test]
- fn test_edges_filters_pg_for_property_gt() {
- // TODO: Const properties not supported for disk_graph.
- let filter = EdgeFilter.property("p1").gt(1u64);
- let expected_results = vec![
- "N10->N11", "N11->N12", "N12->N13", "N13->N14", "N2->N3", "N5->N6", "N8->N9",
- "N9->N10",
- ];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = EdgeFilter.property("k1").gt(2i64);
- let expected_results = vec!["N1->N2"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = EdgeFilter.property("k4").gt(6.0f64);
- let expected_results = vec!["N12->N13", "N2->N3", "N7->N8", "N8->N9"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
-
- #[test]
- fn test_edges_filters_for_property_ge() {
- let filter = EdgeFilter.property("p1").ge(1u64);
- let expected_results = vec!["N1->N2", "N2->N3", "N3->N4", "N5->N6", "N6->N7"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
-
- let filter = EdgeFilter.property("k1").ge(2i64);
- let expected_results = vec!["N1->N2", "N2->N3"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
-
- let filter = EdgeFilter.property("k4").ge(6.0f64);
- let expected_results = vec!["N1->N2", "N2->N3"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
- }
-
- #[test]
- fn test_edges_filters_pg_for_property_ge() {
- // TODO: Const properties not supported for disk_graph.
- let filter = EdgeFilter.property("p1").ge(1u64);
- let expected_results = vec![
- "N1->N2", "N10->N11", "N11->N12", "N12->N13", "N13->N14", "N2->N3", "N3->N4",
- "N5->N6", "N6->N7", "N7->N8", "N8->N9", "N9->N10",
- ];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = EdgeFilter.property("k1").ge(2i64);
- let expected_results =
- vec!["N1->N2", "N12->N13", "N2->N3", "N5->N6", "N7->N8", "N8->N9"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = EdgeFilter.property("k4").ge(6.0f64);
- let expected_results = vec!["N1->N2", "N12->N13", "N2->N3", "N7->N8", "N8->N9"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
-
- #[test]
- fn test_edges_filters_for_property_in() {
- let filter = EdgeFilter.property("p1").is_in(vec![2u64.into()]);
- let expected_results = vec!["N2->N3", "N5->N6"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
-
- let filter = EdgeFilter.property("k1").is_in(vec![2i64.into()]);
- let expected_results = vec!["N2->N3"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
-
- let filter = EdgeFilter
- .property("k2")
- .is_in(vec!["Paper_Airplane".into()]);
- let expected_results = vec!["N1->N2"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
-
- let filter = EdgeFilter.property("k3").is_in(vec![true.into()]);
- let expected_results = vec!["N2->N3"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
-
- let filter = EdgeFilter.property("k4").is_in(vec![6.0f64.into()]);
- let expected_results = vec!["N1->N2"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
- }
-
- #[test]
- fn test_edges_filters_pg_for_property_in() {
- // TODO: Const properties not supported for disk_graph.
- let filter = EdgeFilter.property("p1").is_in(vec![2u64.into()]);
- let expected_results = vec!["N2->N3", "N5->N6", "N8->N9", "N9->N10"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = EdgeFilter.property("k1").is_in(vec![2i64.into()]);
- let expected_results = vec!["N12->N13", "N2->N3", "N5->N6", "N7->N8", "N8->N9"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = EdgeFilter
- .property("k2")
- .is_in(vec!["Paper_Airplane".into()]);
- let expected_results = vec!["N1->N2"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = EdgeFilter.property("k3").is_in(vec![true.into()]);
- let expected_results = vec!["N12->N13", "N2->N3", "N5->N6", "N7->N8", "N8->N9"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = EdgeFilter.property("k4").is_in(vec![6.0f64.into()]);
- let expected_results = vec!["N1->N2"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
-
- #[test]
- fn test_edges_filters_for_property_not_in() {
- let filter = EdgeFilter.property("p1").is_not_in(vec![1u64.into()]);
- let expected_results = vec!["N2->N3", "N5->N6"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
-
- let filter = EdgeFilter.property("k1").is_not_in(vec![2i64.into()]);
- let expected_results = vec!["N1->N2"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
-
- let filter = EdgeFilter
- .property("k2")
- .is_not_in(vec!["Paper_Airplane".into()]);
- let expected_results = vec!["N2->N3", "N5->N6"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
-
- let filter = EdgeFilter.property("k3").is_not_in(vec![true.into()]);
- let expected_results = vec!["N1->N2"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
-
- let filter = EdgeFilter.property("k4").is_not_in(vec![6.0f64.into()]);
- let expected_results = vec!["N2->N3", "N5->N6", "N6->N7"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
- }
-
- #[test]
- fn test_edges_filters_pg_for_property_not_in() {
- // TODO: Const properties not supported for disk_graph.
- let filter = EdgeFilter.property("p1").is_not_in(vec![1u64.into()]);
- let expected_results = vec![
- "N10->N11", "N11->N12", "N12->N13", "N13->N14", "N2->N3", "N5->N6", "N8->N9",
- "N9->N10",
- ];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = EdgeFilter.property("k1").is_not_in(vec![2i64.into()]);
- let expected_results = vec!["N1->N2"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = EdgeFilter
- .property("k2")
- .is_not_in(vec!["Paper_Airplane".into()]);
- let expected_results = vec!["N12->N13", "N2->N3", "N5->N6", "N7->N8", "N8->N9"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = EdgeFilter.property("k3").is_not_in(vec![true.into()]);
- let expected_results = vec!["N1->N2"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = EdgeFilter.property("k4").is_not_in(vec![6.0f64.into()]);
- let expected_results =
- vec!["N12->N13", "N2->N3", "N5->N6", "N6->N7", "N7->N8", "N8->N9"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
-
- #[test]
- fn test_edges_filters_for_property_is_some() {
- let filter = EdgeFilter.property("p1").is_some();
- let expected_results = vec!["N1->N2", "N2->N3", "N3->N4", "N5->N6", "N6->N7"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
- }
-
- #[test]
- fn test_edges_filters_pg_for_property_is_some() {
- // TODO: Const properties not supported for disk_graph.
- let filter = EdgeFilter.property("p1").is_some();
- let expected_results = vec![
- "N1->N2", "N10->N11", "N11->N12", "N12->N13", "N13->N14", "N2->N3", "N3->N4",
- "N5->N6", "N6->N7", "N7->N8", "N8->N9", "N9->N10",
- ];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
-
- #[test]
- fn test_edges_filters_for_src_dst() {
- let filter = EdgeFilter::src()
- .name()
- .eq("N1")
- .and(EdgeFilter::dst().name().eq("N2"));
- let expected_results = vec!["N1->N2"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::All,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::All,
- );
- }
-
- #[test]
- fn test_edges_filters_fuzzy_search() {
- let filter = EdgeFilter
- .property("k2")
- .fuzzy_search("Paper_Airpla", 2, false);
- let expected_results = vec!["N1->N2"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
- }
-
- #[test]
- #[ignore]
- fn test_edges_filters_pg_fuzzy_search() {
- // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
- let filter = EdgeFilter.property("k2").fuzzy_search("Paper_", 2, false);
- let expected_results = vec!["N1->N2", "N2->N3", "N7->N8"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
-
- #[test]
- fn test_edges_filters_fuzzy_search_prefix_match() {
- let filter = EdgeFilter.property("k2").fuzzy_search("Pa", 2, true);
- let expected_results = vec!["N1->N2", "N2->N3"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
-
- let filter = EdgeFilter.property("k2").fuzzy_search("Pa", 2, true);
- let expected_results = vec!["N1->N2", "N2->N3"];
- assert_filter_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter.clone(),
- &expected_results,
- TestVariants::EventOnly,
- );
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::EventOnly,
- );
- }
-
- #[test]
- #[ignore]
- fn test_edges_filters_pg_fuzzy_search_prefix_match() {
- // TODO: PropertyFilteringNotImplemented for variants persistent_graph, persistent_disk_graph for filter_edges.
- let filter = EdgeFilter.property("k2").fuzzy_search("Pa", 2, true);
- let expected_results = vec![
- "N1->N2", "N12->N13", "N13->N14", "N2->N3", "N5->N6", "N7->N8", "N8->N9",
- ];
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
-
- let filter = EdgeFilter.property("k2").fuzzy_search("Pa", 2, false);
- let expected_results = Vec::<&str>::new();
- assert_search_edges_results(
- init_graph,
- WindowGraphTransformer(6..9),
- filter,
- &expected_results,
- TestVariants::PersistentOnly,
- );
- }
- }
-}
diff --git a/raphtory/src/db/api/state/ops/filter.rs b/raphtory/src/db/api/state/ops/filter.rs
index 11c5a90747..25e4b70d47 100644
--- a/raphtory/src/db/api/state/ops/filter.rs
+++ b/raphtory/src/db/api/state/ops/filter.rs
@@ -2,18 +2,25 @@ use crate::{
db::{
api::{
state::{
- Index, ops::{Const, Degree, IntoDynNodeOp, NodeOp, TypeId}
+ ops::{Const, Degree, IntoDynNodeOp, NodeOp, TypeId},
+ Index,
},
view::internal::{GraphView, NodeList},
},
graph::{
create_node_type_filter,
- views::filter::model::{FilterOperator, degree_filter::DegreeFilter, filter::{Filter, FilterValue}, node_filter::NodeFilter, property_filter::PropertyFilterValue},
+ views::filter::model::{
+ degree_filter::DegreeFilter,
+ filter::{Filter, FilterValue},
+ node_filter::NodeFilter,
+ property_filter::PropertyFilterValue,
+ FilterOperator,
+ },
},
},
prelude::{GraphViewOps, PropertyFilter},
};
-use raphtory_api::core::entities::{VID, properties::prop::Prop};
+use raphtory_api::core::entities::{properties::prop::Prop, VID};
use raphtory_core::entities::nodes::node_ref::AsNodeRef;
use raphtory_storage::graph::{graph::GraphStorage, nodes::node_storage_ops::NodeStorageOps};
use std::sync::Arc;
@@ -225,19 +232,19 @@ impl NodeOp for NodePropertyFilterOp {
pub struct NodeDegreeFilterOp {
degree: Degree,
operator: FilterOperator,
- value: PropertyFilterValue
+ value: PropertyFilterValue,
}
impl NodeDegreeFilterOp {
pub(crate) fn new(graph: G, filter: DegreeFilter) -> Self {
let degree = Degree {
dir: filter.direction,
- view: graph
+ view: graph,
};
Self {
degree,
operator: filter.operator,
- value: filter.value
+ value: filter.value,
}
}
}
@@ -248,7 +255,8 @@ impl NodeOp for NodeDegreeFilterOp {
fn apply(&self, storage: &GraphStorage, node: VID) -> Self::Output {
let node_degree = self.degree.apply(storage, node);
let node_degree_prop = Prop::U64(node_degree as u64);
- self.operator.apply_to_property(&self.value, Some(&node_degree_prop))
+ self.operator
+ .apply_to_property(&self.value, Some(&node_degree_prop))
}
}
diff --git a/raphtory/src/db/graph/views/filter/model/degree_filter.rs b/raphtory/src/db/graph/views/filter/model/degree_filter.rs
index 18e5f3d463..ef6bc5c56f 100644
--- a/raphtory/src/db/graph/views/filter/model/degree_filter.rs
+++ b/raphtory/src/db/graph/views/filter/model/degree_filter.rs
@@ -1,24 +1,35 @@
-use std::collections::HashSet;
-use std::sync::Arc;
-
-use raphtory_api::core::entities::properties::prop::PropType;
-use raphtory_api::core::{Direction, entities::properties::prop::Prop};
-use raphtory_core::entities::{VID};
+use std::{collections::HashSet, sync::Arc};
+
+use crate::{
+ db::{
+ api::{
+ state::ops::{filter::NodeDegreeFilterOp, GraphView},
+ view::{GraphViewOps, NodeViewOps},
+ },
+ graph::views::filter::{
+ model,
+ model::{
+ property_filter::{
+ builders::{PropertyExprBuilder, PropertyExprBuilderInput},
+ Op, PropertyFilter, PropertyFilterInput, PropertyFilterValue, PropertyRef,
+ },
+ CombinedFilter, ComposableFilter, CompositeNodeFilter, EntityMarker,
+ FilterOperator, InternalPropertyFilterBuilder, NodeFilter, TryAsCompositeFilter,
+ },
+ node_filtered_graph::NodeFilteredGraph,
+ CreateFilter,
+ },
+ },
+ errors::GraphError,
+};
+use raphtory_api::core::{
+ entities::properties::prop::{Prop, PropType},
+ Direction,
+};
+use raphtory_core::entities::VID;
use raphtory_storage::graph::nodes::{node_ref::NodeStorageRef, node_storage_ops::NodeStorageOps};
-use crate::db::api::state::ops::GraphView;
-use crate::db::api::state::ops::filter::NodeDegreeFilterOp;
-use crate::db::graph::views::filter::CreateFilter;
-use crate::db::graph::views::filter::model::{ComposableFilter, CompositeNodeFilter, NodeFilter};
-use crate::db::graph::views::filter::model::property_filter::{Op, PropertyFilterInput, PropertyRef, PropertyFilter};
-use crate::db::graph::views::filter::model::property_filter::builders::{PropertyExprBuilder, PropertyExprBuilderInput};
-use crate::db::graph::views::filter::model::{CombinedFilter, EntityMarker, InternalPropertyFilterBuilder, TryAsCompositeFilter};
-use crate::db::graph::views::filter::model;
-use crate::db::graph::views::filter::node_filtered_graph::NodeFilteredGraph;
-use crate::db::{api::view::{GraphViewOps, NodeViewOps}, graph::views::filter::model::{FilterOperator, property_filter::PropertyFilterValue}};
-use crate::errors::GraphError;
use std::{fmt, fmt::Display};
-
#[derive(Clone)]
pub struct DegreeFilterBuilder {
direction: Direction,
@@ -42,7 +53,6 @@ pub struct DegreeFilter {
pub ops: Vec,
}
-
impl CreateFilter for DegreeFilter {
type EntityFiltered<'graph, G: GraphViewOps<'graph>> =
NodeFilteredGraph>;
@@ -73,22 +83,30 @@ impl CreateFilter for DegreeFilter {
));
}
match self.operator {
- FilterOperator::Eq | FilterOperator::Ne| FilterOperator::Gt | FilterOperator::Ge | FilterOperator::Lt | FilterOperator::Le | FilterOperator::IsIn | FilterOperator::IsNotIn => {},
+ FilterOperator::Eq
+ | FilterOperator::Ne
+ | FilterOperator::Gt
+ | FilterOperator::Ge
+ | FilterOperator::Lt
+ | FilterOperator::Le
+ | FilterOperator::IsIn
+ | FilterOperator::IsNotIn => {}
_ => {
- return Err(GraphError::InvalidFilter(
- format!("degree filter does not support operator {:?}", self.operator)
- ));
+ return Err(GraphError::InvalidFilter(format!(
+ "degree filter does not support operator {:?}",
+ self.operator
+ )));
}
}
let value = match self.value {
PropertyFilterValue::Single(ref prop_val) => {
let casted_val = prop_val.clone().try_cast(PropType::U64).ok_or_else(|| {
GraphError::InvalidFilter(format!(
- "degree filter expects an integer value, got {}",
+ "degree filter expects an integer value, got {}",
prop_val.to_string()
))
})?;
-
+
PropertyFilterValue::Single(casted_val)
}
PropertyFilterValue::Set(ref prop_vals) => {
@@ -97,7 +115,7 @@ impl CreateFilter for DegreeFilter {
.map(|val| {
val.clone().try_cast(PropType::U64).ok_or_else(|| {
GraphError::InvalidFilter(format!(
- "degree filter expects an integer value, got {}",
+ "degree filter expects an integer value, got {}",
val.to_string()
))
})
@@ -108,11 +126,11 @@ impl CreateFilter for DegreeFilter {
}
PropertyFilterValue::None => {
return Err(GraphError::InvalidFilter(
- "degree filter requires a value".to_string()
+ "degree filter requires a value".to_string(),
));
}
- };
- let mut filter = self.clone();
+ };
+ let mut filter = self.clone();
filter.value = value;
Ok(NodeDegreeFilterOp::new(graph, filter))
}
@@ -126,19 +144,20 @@ impl CreateFilter for DegreeFilter {
}
impl TryAsCompositeFilter for DegreeFilter {
- fn try_as_composite_edge_filter(&self) -> Result {
- Err(GraphError::NotSupported)
+ fn try_as_composite_edge_filter(
+ &self,
+ ) -> Result {
+ Err(GraphError::NotSupported)
}
fn try_as_composite_exploded_edge_filter(
&self,
- ) -> Result
- {
- Err(GraphError::NotSupported)
- }
+ ) -> Result {
+ Err(GraphError::NotSupported)
+ }
fn try_as_composite_node_filter(&self) -> Result {
Ok(CompositeNodeFilter::Degree(self.clone()))
}
-}
+}
fn property_ref(direction: &Direction) -> PropertyRef {
match direction {
@@ -150,7 +169,7 @@ fn property_ref(direction: &Direction) -> PropertyRef {
impl InternalPropertyFilterBuilder for DegreeFilterBuilder
where
- DegreeFilter: CombinedFilter
+ DegreeFilter: CombinedFilter,
{
type Filter = DegreeFilter;
type ExprBuilder = DegreeFilterBuilder;
@@ -170,10 +189,10 @@ where
fn filter(&self, filter: PropertyFilterInput) -> Self::Filter {
DegreeFilter {
- value: filter.prop_value,
- direction: self.direction,
- operator: filter.operator,
- ops: filter.ops,
+ value: filter.prop_value,
+ direction: self.direction,
+ operator: filter.operator,
+ ops: filter.ops,
}
}
@@ -187,7 +206,7 @@ where
impl ComposableFilter for DegreeFilter {}
pub trait DegreeFilterFactory {
- fn in_degree(&self) -> DegreeFilterBuilder;
+ fn in_degree(&self) -> DegreeFilterBuilder;
fn out_degree(&self) -> DegreeFilterBuilder;
fn degree(&self) -> DegreeFilterBuilder;
}
@@ -203,4 +222,4 @@ impl Display for DegreeFilter {
};
property_filter.fmt(f)
}
-}
+}
diff --git a/raphtory/src/db/graph/views/filter/model/mod.rs b/raphtory/src/db/graph/views/filter/model/mod.rs
index ef20e4609e..b95369693f 100644
--- a/raphtory/src/db/graph/views/filter/model/mod.rs
+++ b/raphtory/src/db/graph/views/filter/model/mod.rs
@@ -56,6 +56,7 @@ use raphtory_api::core::{
use std::{ops::Deref, sync::Arc};
pub mod and_filter;
+pub mod degree_filter;
pub mod edge_filter;
pub mod exploded_edge_filter;
pub mod filter;
@@ -75,8 +76,6 @@ pub mod or_filter;
pub mod property_filter;
pub mod snapshot_filter;
pub mod windowed_filter;
-pub mod degree_filter;
-
#[derive(Debug, Copy, Clone)]
pub struct NoFilter;
diff --git a/raphtory/src/db/graph/views/filter/model/node_filter/mod.rs b/raphtory/src/db/graph/views/filter/model/node_filter/mod.rs
index 4dd4cc38fd..85bf52f82e 100644
--- a/raphtory/src/db/graph/views/filter/model/node_filter/mod.rs
+++ b/raphtory/src/db/graph/views/filter/model/node_filter/mod.rs
@@ -1,31 +1,47 @@
use crate::{
+ api::core::Direction,
db::{
api::{
state::{
- NodeStateValue, TypedNodeState, ops::{
- NodeOp, TypeId, filter::{
+ ops::{
+ filter::{
AndOp, MaskOp, NodeIdFilterOp, NodeNameFilterOp, NodeTypeFilterOp, NotOp,
OrOp,
- }
- }
+ },
+ NodeOp, TypeId,
+ },
+ NodeStateValue, TypedNodeState,
},
- view::{BoxableGraphView, internal::GraphView},
+ view::{internal::GraphView, BoxableGraphView},
},
graph::views::filter::{
- CreateFilter, model::{
- AndFilter, CombinedFilter, ComposableFilter, CompositeExplodedEdgeFilter, EntityMarker, InternalPropertyFilterFactory, InternalViewWrapOps, NodeViewFilterOps, NotFilter, OrFilter, TryAsCompositeFilter, Wrap, degree_filter::{DegreeFilter, DegreeFilterBuilder}, edge_filter::CompositeEdgeFilter, filter::Filter, is_active_node_filter::IsActiveNode, latest_filter::Latest, layered_filter::Layered, node_filter::{
+ model::{
+ degree_filter::{DegreeFilter, DegreeFilterBuilder, DegreeFilterFactory},
+ edge_filter::CompositeEdgeFilter,
+ filter::Filter,
+ is_active_node_filter::IsActiveNode,
+ latest_filter::Latest,
+ layered_filter::Layered,
+ node_filter::{
builders::{NodeIdFilterBuilder, NodeNameFilterBuilder, NodeTypeFilterBuilder},
validate::validate,
- }, node_state_filter::NodeStateBoolColOp, property_filter::builders::{MetadataFilterBuilder, PropertyFilterBuilder}, snapshot_filter::{SnapshotAt, SnapshotLatest}, windowed_filter::Windowed
- }, node_filtered_graph::NodeFilteredGraph
+ },
+ node_state_filter::NodeStateBoolColOp,
+ property_filter::builders::{MetadataFilterBuilder, PropertyFilterBuilder},
+ snapshot_filter::{SnapshotAt, SnapshotLatest},
+ windowed_filter::Windowed,
+ AndFilter, CombinedFilter, ComposableFilter, CompositeExplodedEdgeFilter,
+ EntityMarker, InternalPropertyFilterFactory, InternalViewWrapOps,
+ NodeViewFilterOps, NotFilter, OrFilter, TryAsCompositeFilter, Wrap,
+ },
+ node_filtered_graph::NodeFilteredGraph,
+ CreateFilter,
},
},
errors::GraphError,
prelude::{GraphViewOps, PropertyFilter},
};
use raphtory_api::core::storage::timeindex::EventTime;
-use crate::api::core::Direction;
-use crate::db::graph::views::filter::model::degree_filter::DegreeFilterFactory;
use std::{fmt, fmt::Display, sync::Arc};
pub mod builders;
@@ -106,19 +122,18 @@ impl InternalPropertyFilterFactory for NodeFilter {
impl DegreeFilterFactory for NodeFilter {
fn degree(&self) -> DegreeFilterBuilder {
- DegreeFilterBuilder::new(Direction::BOTH)
+ DegreeFilterBuilder::new(Direction::BOTH)
}
fn in_degree(&self) -> DegreeFilterBuilder {
- DegreeFilterBuilder::new(Direction::IN)
+ DegreeFilterBuilder::new(Direction::IN)
}
fn out_degree(&self) -> DegreeFilterBuilder {
- DegreeFilterBuilder::new(Direction::OUT)
+ DegreeFilterBuilder::new(Direction::OUT)
}
}
-
impl NodeViewFilterOps for NodeFilter {
type Output = T;
diff --git a/raphtory/src/python/filter/node_filter_builders.rs b/raphtory/src/python/filter/node_filter_builders.rs
index 84317343c8..1fd4147f11 100644
--- a/raphtory/src/python/filter/node_filter_builders.rs
+++ b/raphtory/src/python/filter/node_filter_builders.rs
@@ -1,8 +1,14 @@
use crate::{
db::graph::views::filter::model::{
- NodeViewFilterOps, PropertyFilterFactory, ViewWrapOps, degree_filter::DegreeFilterFactory, node_filter::{
- NodeFilter, builders::{NodeIdFilterBuilder, NodeNameFilterBuilder, NodeTypeFilterBuilder}, ops::{NodeFilterOps, NodeIdFilterOps}
- }, node_state_filter::NodeStateBoolColOp, property_filter::builders::{MetadataFilterBuilder, PropertyFilterBuilder}
+ degree_filter::DegreeFilterFactory,
+ node_filter::{
+ builders::{NodeIdFilterBuilder, NodeNameFilterBuilder, NodeTypeFilterBuilder},
+ ops::{NodeFilterOps, NodeIdFilterOps},
+ NodeFilter,
+ },
+ node_state_filter::NodeStateBoolColOp,
+ property_filter::builders::{MetadataFilterBuilder, PropertyFilterBuilder},
+ NodeViewFilterOps, PropertyFilterFactory, ViewWrapOps,
},
python::{
filter::{