malte-v / redisgraph-rs

A Rust client for RedisGraph.
MIT License
35 stars 6 forks source link

Pipelining (`MULTI/EXEC`) support #8

Open aramperes opened 4 years ago

aramperes commented 4 years ago

RedisGraph has supported MULTI/EXEC to execute queries and mutations atomically for a while. The redis crate supports it through the redis::pipe().atomic() mode. It'd be nice to have implement pipelining on graphs in this crate.

I'm up for implementing this once #7 lands.

malte-v commented 4 years ago

Go ahead. Thank you for your contributions so far!

aramperes commented 4 years ago

One thing to note is that using RedisGraph's --compact mode would be unsafe in pipelines. Right now, this crate will call CALL db.labels() if any of the label IDs in the result set are unknown. However, in pipelines, it's entirely possible that db.labels() no longer matches once the pipeline has completed.

For example, executing the following pipeline:

MULTI
GRAPH.QUERY test "CREATE (:L1 {prop: 1})-[:R1 {prop: 2}]->(:L2 {prop: 3})-[:R2 {prop: 4}]->(:L3 {prop: 5})" --compact
GRAPH.QUERY test "MATCH (x) RETURN x" --compact
GRAPH.DELETE test --compact
EXEC

The MATCH Result Set would have the IDs for L1, L2, L3, which are unknown to the client. Then calling db.labels() would return nothing (since the graph is now empty), and the Result Set converter would enter a perpetual loop:

https://github.com/malte-v/redisgraph-rs/blob/9b3f66b09ea633b9c14d88460f32f20251516e8b/src/graph.rs#L146-L149

This also applies to relationship types and property keys, naturally.

aramperes commented 4 years ago
let mut graph = Graph::open(conn, "test_graph".to_string()).unwrap();

let nodes: Vec<Node> = graph.pipe()
   .atomic() // Maybe make this the default? It isn't the default in `redis-rs` however
   .mutate("CREATE (:L1 {prop: 1})-[:R1 {prop: 2}]->(:L2 {prop: 3})-[:R2 {prop: 4}]->(:L3 {prop: 5})")
   .query("MATCH (x) RETURN x")
   .delete()
   .exec()?;