redis / node-redis

Redis Node.js client

Home Page:https://redis.js.org/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Graph: Compability with non-compact relationship property names

jonaskello opened this issue · comments

Motivation

If you return a relationship using GRAPH.QUERY in non-compact mode the properties of the relationship object are named id, type, src_node, dest_node, properties :

127.0.0.1:16380> GRAPH.QUERY MotoGP "MATCH (a)-[r]->(b) RETURN r"
1) 1) "r"
2) 1) 1) 1) 1) "id"
            2) (integer) 0
         2) 1) "type"
            2) "rides"
         3) 1) "src_node"
            2) (integer) 0
         4) 1) "dest_node"
            2) (integer) 1
         5) 1) "properties"
            2) (empty list or set)
...
3) 1) "Cached execution: 0"
   2) "Query internal execution time: 0.246391 milliseconds"

So this translates to an JSON object like this:

{
    "id": 53,
    "type": "rides",
    "src_node": 0,
    "dest_node": 1,
    "properties": {}
}

However using the graph package in this repo (which uses compact mode) we get this object for a relationship:

{
    "id": 53,
    "relationshipType": "rides",
    "sourceId": 0,
    "destinationId": 1,
    "properties": {}
}

So the property names of the relationship object are different (eg. relationshipType vs type). Our code currently assumes the names we got in non-compact mode. It would be very nice if the graph package could have some option to use the same names as in non-compact mode because then we would not have to rewrite all our code to the use new names.

Basic Code Example

Se above.

I think that this and #2403 can be fixed by adding an option to override some of the parser functions, something like:

const graph = new Graph(client, 'key', {
  parser: {
    [GraphValueTypes.EDGE]: (rawValue) => {
      return {
        // ...
      };
    };
  }
});

but it won't be easy to integrate that with TypeScript..

What do you think?

To be honest the best API for us would be to instead of the Graph class simply have two functions to call. One function to transform the arguments and one to transform the reply. The one transforming the reply would then return a tuple of the result and the state that needs to be cached for the reply parsing (the result of db.labels() etc.). One reason for this API would be that it is possible to combine with lua scripting. For example today we have a lua script that only executes some GRAPH.QUERY if a key exists. I'm not sure how to implement that with the Graph class.

So bascially what we'd really want is something like this:

export function transformArguments(
    graph: RedisCommandArgument,
    query: RedisCommandArgument,
    options?: QueryOptionsBackwardCompatible,
    compact?: boolean
): RedisCommandArguments

export async function transformReply(
    reply: QueryRawReply, 
    cacheState: CacheState
): Promise<[ParsedQueryReply, CacheState]> 

We currently keep a LRU cache of Graph objects in order to avoid extra calls to db.labels() etc. so it would be no problem to keep the same kind of cache just for the state that the transformReply function uses. The transformReply could take addional options for the key names to use for relationship type etc.

I realise that is quite different than the current class based API but I just wanted to mention it. For the class based API I guess just passing more options like you suggest is the way to go.