Skip to content

ArrayProperty includes filters operator #820

@wbenbihi

Description

@wbenbihi

Feature description

I am currently reaching a limitation in neomodel properties/relationship filtering regarding ArrayProperty.
While #379 and #784 seem to be related, to my understanding it does not filter the NodeSet based on inclusion.

To illustrate this with an example, we define a relationship containing an ArrayProperty, I thought of __includes / __includes_all / __includes_any operators to filter the NodeSet.

from neomodel import StructuredNode
from neomodel import StructuredRel
from neomodel import StringProperty
from neomodel import ArrayProperty
from neomodel import ZeroOrMore
from neomodel import RelationshipTo
from neomodel import RelationshipFrom

class MemberOfRelationship(StructuredRel):
    permissions = ArrayProperty(StringProperty(), required=True)

class User(StructuredNode):
    name = StringProperty(required=True)
    tags = ArrayProperty(StringProperty(), required=True)
    organizations =  RelationshipTo('Organization', "MEMBER_OF", model=MemberOfRelationship, cardinality=ZeroOrMore)

class Organization(StructuredNode):
    name = StringProperty(required=True)
    members =  RelationshipFrom('User', "MEMBER_OF", model=MemberOfRelationship, cardinality=ZeroOrMore)

u = User(name="john", tags=["user", "member", "dummytag"])
o1 = Organization(name="org1")
o2 = Organization(name="org2")

o1.members.connect(u, properties={"permissions": ["read",  "write", "delete"]})
o2.members.connect(u, properties={"permissions": ["read"]})

# How it should behave

User.nodes.filter(tags__includes = "dummytag")
# MATCH (u:User) WHERE "dummytag" IN u.tags RETURN u
> User(name="john", tags=["user", "member", "dummytag"])

User.nodes.filter(tags__includes_any = ["dummytag"])
# MATCH (u:User) WHERE any(x IN ["dummytag"] WHERE x IN u.tags) RETURN u
> User(name="john", tags=["user", "member", "dummytag"])

User.nodes.filter(tags__includes_all = ["dummytag"])
# MATCH (u:User) WHERE all(x IN ["dummytag"] WHERE x IN u.tags) RETURN u
> User(name="john", tags=["user", "member", "dummytag"])

u.organizations.match(permissions__includes = "read")
# MATCH (u:User) WITH u MATCH (u)-[r:MEMBER_OF]->(o:Organization) WHERE "read" IN r.permissions RETURN o
> [Organization(name="org1"), Organization(name="org2")]

u.organizations.match(permissions__includes_all = ["write", "read"])
# MATCH (u:User) WITH u MATCH (u)-[r:MEMBER_OF]->(o:Organization) WHERE all(x IN ["write", "read"] WHERE x IN r.permissions) RETURN o
> [Organization(name="org2")]

u.organizations.match(permissions__includes_any = ["write", "read"])
# MATCH (u:User) WITH u MATCH (u)-[r:MEMBER_OF]->(o:Organization) WHERE any(x IN ["write", "read"] WHERE x IN r.permissions) RETURN o
> [Organization(name="org1"), Organization(name="org2")]

How this feature can improve the project?

While this behavior is achievable with Cypher Queries + Neomodel's class resolution. I think neomodel can benefit from this additional operation to stay consistent with already existing operators.

I can try to open a PR to implement such a feature, but I'd like to know if it is really relevant for neomodel

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions