Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
4ae827a
filter expr impl
shivamka1 Jun 4, 2026
4460d19
split NodePropOp into NodePropOp and NodeMetaOp, remove is_metadata flag
shivamka1 Jun 4, 2026
9d4691c
remove NodeTypeStringOp, use ArcStr directly for node type comparisons
shivamka1 Jun 4, 2026
793b0e6
ref
shivamka1 Jun 5, 2026
c3c3da7
split CompositeNodeFilter::Node into typed Id/Name/Type variants, rem…
shivamka1 Jun 5, 2026
9889d5f
replace NodeIdFilterBuilder/InternalNodeIdFilterBuilder/NodeIdFilterO…
shivamka1 Jun 5, 2026
454e3d1
implement InternalNodeFilterBuilder on Name and Type directly, replac…
shivamka1 Jun 5, 2026
142699f
implement InternalNodeFilterBuilder on Name and Type directly, replac…
shivamka1 Jun 5, 2026
af438c1
add comment
shivamka1 Jun 5, 2026
18eaec7
some experiments
ljeub-pometry Jun 5, 2026
4659ba2
add temporal property NodeExpr with any/all quantifiers and aggregato…
shivamka1 Jun 8, 2026
6e853bb
Merge branch 'filter_expr' of github.com:Pometry/Raphtory into filter…
shivamka1 Jun 8, 2026
16e6304
split QuantifiedNodeOp into AnyNodeOp/AllNodeOp, fix post-merge build…
shivamka1 Jun 8, 2026
b09096a
start reworking some bits
ljeub-pometry Jun 8, 2026
9a1381f
break more things
ljeub-pometry Jun 9, 2026
e5ff97d
make things
shivamka1 Jun 9, 2026
fd45acf
start introducing prop_type for handling validation
ljeub-pometry Jun 9, 2026
fedf488
reorganise node_expr into exprs/ops/filters, drop NoWrap, document th…
shivamka1 Jun 10, 2026
d2cbd57
add is_true() / is_false() convenience filters for boolean properties
shivamka1 Jun 10, 2026
66ef4d1
rename TemporalPropContext/QuantifiedContextBuilder/NodeExprContextBu…
shivamka1 Jun 10, 2026
d74efe2
add NodeFilter::name/id/node_type associated fns and export NodeExprF…
shivamka1 Jun 11, 2026
4c02e77
implement InternalPropertyFilterBuilder for PropertyExpr/MetadataExpr…
shivamka1 Jun 11, 2026
54747e5
remove TemporalNodeExprBuilderOps and temporal_property shortcut — us…
shivamka1 Jun 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ async-graphql = { version = "7.2.1", features = ["dynamic-schema"] }
async-graphql-poem = "7.2.1"
dynamic-graphql = "0.10.2"
derive_more = "2.1.1"
tikv-jemallocator = "0.6.1"
tikv-jemallocator = "0.7.0"
reqwest = { version = "0.13.3", default-features = false, features = [
"multipart",
"json",
Expand Down
1 change: 0 additions & 1 deletion raphtory-api/src/core/entities/properties/prop/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ mod serde;
mod template;

pub use arrow::*;

pub use prop_array::*;
pub use prop_enum::*;
pub use prop_ref_enum::*;
Expand Down
1 change: 0 additions & 1 deletion raphtory-graphql/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -5614,4 +5614,3 @@ schema {
query: QueryRoot
mutation: MutRoot
}

86 changes: 47 additions & 39 deletions raphtory-graphql/src/model/graph/filtering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use dynamic_graphql::{
use raphtory::{
db::graph::views::filter::model::{
edge_filter::{CompositeEdgeFilter, EdgeFilter},
filter::{Filter, FilterValue},
filter::{FieldFilterValue, Filter},
filter_operator::FilterOperator,
graph_filter::GraphFilter,
is_active_edge_filter::IsActiveEdge,
Expand Down Expand Up @@ -1028,17 +1028,17 @@ fn require_u64_value(op: &str, v: &Value) -> Result<u64, GraphError> {
}
}

fn parse_node_id_scalar(op: &str, v: &Value) -> Result<FilterValue, GraphError> {
fn parse_node_id_scalar(op: &str, v: &Value) -> Result<FieldFilterValue, GraphError> {
match v {
Value::U64(i) => Ok(FilterValue::ID(GID::U64(*i))),
Value::Str(s) => Ok(FilterValue::ID(GID::Str(s.clone()))),
Value::U64(i) => Ok(FieldFilterValue::ID(GID::U64(*i))),
Value::Str(s) => Ok(FieldFilterValue::ID(GID::Str(s.clone()))),
other => Err(GraphError::InvalidGqlFilter(format!(
"{op} requires int or str, got {other}"
))),
}
}

fn parse_node_id_list(op: &str, v: &Value) -> Result<FilterValue, GraphError> {
fn parse_node_id_list(op: &str, v: &Value) -> Result<FieldFilterValue, GraphError> {
let Value::List(vs) = v else {
return Err(GraphError::InvalidGqlFilter(format!(
"{op} requires a list value, got {v}"
Expand Down Expand Up @@ -1067,10 +1067,10 @@ fn parse_node_id_list(op: &str, v: &Value) -> Result<FilterValue, GraphError> {
}
}
}
Ok(FilterValue::IDSet(Arc::new(set)))
Ok(FieldFilterValue::IDSet(Arc::new(set)))
}

fn parse_string_list(op: &str, v: &Value) -> Result<FilterValue, GraphError> {
fn parse_string_list(op: &str, v: &Value) -> Result<FieldFilterValue, GraphError> {
let Value::List(vs) = v else {
return Err(GraphError::InvalidGqlFilter(format!(
"{op} requires a list value, got {v}"
Expand All @@ -1090,13 +1090,15 @@ fn parse_string_list(op: &str, v: &Value) -> Result<FilterValue, GraphError> {
})
.collect::<Result<Vec<_>, _>>()?;

Ok(FilterValue::Set(Arc::new(strings.into_iter().collect())))
Ok(FieldFilterValue::Set(Arc::new(
strings.into_iter().collect(),
)))
}

fn translate_node_field_where(
field: NodeField,
cond: &NodeFieldCondition,
) -> Result<(String, FilterValue, FilterOperator), GraphError> {
) -> Result<(String, FieldFilterValue, FilterOperator), GraphError> {
use FilterOperator as FO;
use NodeField::*;
use NodeFieldCondition::*;
Expand All @@ -1109,43 +1111,43 @@ fn translate_node_field_where(
(NodeId, Ne(v)) => (field_name, parse_node_id_scalar(op, v)?, FO::Ne),
(NodeId, Gt(v)) => (
field_name,
FilterValue::ID(GID::U64(require_u64_value(op, v)?)),
FieldFilterValue::ID(GID::U64(require_u64_value(op, v)?)),
FO::Gt,
),
(NodeId, Ge(v)) => (
field_name,
FilterValue::ID(GID::U64(require_u64_value(op, v)?)),
FieldFilterValue::ID(GID::U64(require_u64_value(op, v)?)),
FO::Ge,
),
(NodeId, Lt(v)) => (
field_name,
FilterValue::ID(GID::U64(require_u64_value(op, v)?)),
FieldFilterValue::ID(GID::U64(require_u64_value(op, v)?)),
FO::Lt,
),
(NodeId, Le(v)) => (
field_name,
FilterValue::ID(GID::U64(require_u64_value(op, v)?)),
FieldFilterValue::ID(GID::U64(require_u64_value(op, v)?)),
FO::Le,
),

(NodeId, StartsWith(v)) => (
field_name,
FilterValue::ID(GID::Str(require_string_value(op, v)?)),
FieldFilterValue::ID(GID::Str(require_string_value(op, v)?)),
FO::StartsWith,
),
(NodeId, EndsWith(v)) => (
field_name,
FilterValue::ID(GID::Str(require_string_value(op, v)?)),
FieldFilterValue::ID(GID::Str(require_string_value(op, v)?)),
FO::EndsWith,
),
(NodeId, Contains(v)) => (
field_name,
FilterValue::ID(GID::Str(require_string_value(op, v)?)),
FieldFilterValue::ID(GID::Str(require_string_value(op, v)?)),
FO::Contains,
),
(NodeId, NotContains(v)) => (
field_name,
FilterValue::ID(GID::Str(require_string_value(op, v)?)),
FieldFilterValue::ID(GID::Str(require_string_value(op, v)?)),
FO::NotContains,
),

Expand All @@ -1154,53 +1156,53 @@ fn translate_node_field_where(

(NodeName, Eq(v)) => (
field_name,
FilterValue::Single(require_string_value(op, v)?),
FieldFilterValue::Single(require_string_value(op, v)?),
FO::Eq,
),
(NodeName, Ne(v)) => (
field_name,
FilterValue::Single(require_string_value(op, v)?),
FieldFilterValue::Single(require_string_value(op, v)?),
FO::Ne,
),
(NodeName, Gt(v)) => (
field_name,
FilterValue::Single(require_string_value(op, v)?),
FieldFilterValue::Single(require_string_value(op, v)?),
FO::Gt,
),
(NodeName, Ge(v)) => (
field_name,
FilterValue::Single(require_string_value(op, v)?),
FieldFilterValue::Single(require_string_value(op, v)?),
FO::Ge,
),
(NodeName, Lt(v)) => (
field_name,
FilterValue::Single(require_string_value(op, v)?),
FieldFilterValue::Single(require_string_value(op, v)?),
FO::Lt,
),
(NodeName, Le(v)) => (
field_name,
FilterValue::Single(require_string_value(op, v)?),
FieldFilterValue::Single(require_string_value(op, v)?),
FO::Le,
),

(NodeName, StartsWith(v)) => (
field_name,
FilterValue::Single(require_string_value(op, v)?),
FieldFilterValue::Single(require_string_value(op, v)?),
FO::StartsWith,
),
(NodeName, EndsWith(v)) => (
field_name,
FilterValue::Single(require_string_value(op, v)?),
FieldFilterValue::Single(require_string_value(op, v)?),
FO::EndsWith,
),
(NodeName, Contains(v)) => (
field_name,
FilterValue::Single(require_string_value(op, v)?),
FieldFilterValue::Single(require_string_value(op, v)?),
FO::Contains,
),
(NodeName, NotContains(v)) => (
field_name,
FilterValue::Single(require_string_value(op, v)?),
FieldFilterValue::Single(require_string_value(op, v)?),
FO::NotContains,
),

Expand All @@ -1209,53 +1211,53 @@ fn translate_node_field_where(

(NodeType, Eq(v)) => (
field_name,
FilterValue::Single(require_string_value(op, v)?),
FieldFilterValue::Single(require_string_value(op, v)?),
FO::Eq,
),
(NodeType, Ne(v)) => (
field_name,
FilterValue::Single(require_string_value(op, v)?),
FieldFilterValue::Single(require_string_value(op, v)?),
FO::Ne,
),
(NodeType, Gt(v)) => (
field_name,
FilterValue::Single(require_string_value(op, v)?),
FieldFilterValue::Single(require_string_value(op, v)?),
FO::Gt,
),
(NodeType, Ge(v)) => (
field_name,
FilterValue::Single(require_string_value(op, v)?),
FieldFilterValue::Single(require_string_value(op, v)?),
FO::Ge,
),
(NodeType, Lt(v)) => (
field_name,
FilterValue::Single(require_string_value(op, v)?),
FieldFilterValue::Single(require_string_value(op, v)?),
FO::Lt,
),
(NodeType, Le(v)) => (
field_name,
FilterValue::Single(require_string_value(op, v)?),
FieldFilterValue::Single(require_string_value(op, v)?),
FO::Le,
),

(NodeType, StartsWith(v)) => (
field_name,
FilterValue::Single(require_string_value(op, v)?),
FieldFilterValue::Single(require_string_value(op, v)?),
FO::StartsWith,
),
(NodeType, EndsWith(v)) => (
field_name,
FilterValue::Single(require_string_value(op, v)?),
FieldFilterValue::Single(require_string_value(op, v)?),
FO::EndsWith,
),
(NodeType, Contains(v)) => (
field_name,
FilterValue::Single(require_string_value(op, v)?),
FieldFilterValue::Single(require_string_value(op, v)?),
FO::Contains,
),
(NodeType, NotContains(v)) => (
field_name,
FilterValue::Single(require_string_value(op, v)?),
FieldFilterValue::Single(require_string_value(op, v)?),
FO::NotContains,
),

Expand Down Expand Up @@ -1380,13 +1382,19 @@ impl TryFrom<GqlNodeFilter> for CompositeNodeFilter {
fn try_from(filter: GqlNodeFilter) -> Result<Self, Self::Error> {
match filter {
GqlNodeFilter::Node(node) => {
let field = node.field;
let (field_name, field_value, operator) =
translate_node_field_where(node.field, &node.where_)?;
Ok(CompositeNodeFilter::Node(Filter {
let filter = Filter {
field_name,
field_value,
operator,
}))
};
Ok(match field {
NodeField::NodeId => CompositeNodeFilter::Id(filter),
NodeField::NodeName => CompositeNodeFilter::Name(filter),
NodeField::NodeType => CompositeNodeFilter::Type(filter),
})
}
GqlNodeFilter::Property(prop) => {
let prop_ref = PropertyRef::Property(prop.name.clone());
Expand Down
5 changes: 3 additions & 2 deletions raphtory-tests/tests/node_property_filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use raphtory::{
graph::{
graph::assert_edges_equal,
views::filter::model::{
node_filter::{ops::NodeFilterOps, NodeFilter},
node_filter::{ops::NodeFilterOps, NodeFilter, NodeFilterFactory},
property_filter::ops::PropertyFilterOps,
ComposableFilter, PropertyFilterFactory,
},
Expand Down Expand Up @@ -34,7 +34,8 @@ fn test_node_filter_on_nodes() {
g.add_node(2, "David", [("band", "Pink Floyd")], None, None)
.unwrap();

let filter_expr = NodeFilter::name()
let filter_expr = NodeFilter
.name()
.eq("John")
.and(NodeFilter.property("band").eq("Dead & Company"));
let filtered_nodes = g.nodes().filter(filter_expr).unwrap();
Expand Down
2 changes: 1 addition & 1 deletion raphtory/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ proptest.workspace = true
proptest-derive.workspace = true

[target.'cfg(target_os = "macos")'.dependencies]
tikv-jemallocator = "0.6.1"
tikv-jemallocator = "0.7.0"

[features]
default = [] # we can't depend on ourselves but we want to share test-utils
Expand Down
10 changes: 5 additions & 5 deletions raphtory/src/db/api/state/ops/filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::{
graph::{
create_node_type_filter,
views::filter::model::{
filter::{Filter, FilterValue},
filter::{FieldFilterValue, Filter},
node_filter::NodeFilter,
FilterOperator,
},
Expand Down Expand Up @@ -96,7 +96,7 @@ impl NodeOp for NodeIdFilterOp {
let op = &self.filter.operator;
match op {
FilterOperator::Eq => match &self.filter.field_value {
FilterValue::ID(id) => {
FieldFilterValue::ID(id) => {
let vid = storage.internalise_node(id.as_node_ref());
NodeList::List {
elems: vid.into_iter().collect(),
Expand All @@ -105,7 +105,7 @@ impl NodeOp for NodeIdFilterOp {
_ => unreachable!(),
},
FilterOperator::IsIn => match &self.filter.field_value {
FilterValue::IDSet(ids) => NodeList::List {
FieldFilterValue::IDSet(ids) => NodeList::List {
elems: ids
.iter()
.filter_map(|id| storage.internalise_node(id.as_node_ref()))
Expand Down Expand Up @@ -153,7 +153,7 @@ impl NodeOp for NodeNameFilterOp {
let op = &self.filter.operator;
match op {
FilterOperator::Eq => match &self.filter.field_value {
FilterValue::Single(name) => {
FieldFilterValue::Single(name) => {
let vid = storage.internalise_node(name.as_node_ref());
NodeList::List {
elems: vid.into_iter().collect(),
Expand All @@ -162,7 +162,7 @@ impl NodeOp for NodeNameFilterOp {
_ => unreachable!(),
},
FilterOperator::IsIn => match &self.filter.field_value {
FilterValue::Set(names) => NodeList::List {
FieldFilterValue::Set(names) => NodeList::List {
elems: names
.iter()
.filter_map(|name| storage.internalise_node(name.as_node_ref()))
Expand Down
Loading