Coder Social home page Coder Social logo

nredisgraph's Introduction

NRedisGraph

Build Status

Overview

NRedisGraph is a series of extensions methods for the StackExchange.Redis library that will enable you to interact with the Redis module RedisGraph. This is made possible by the Execute and ExecuteAsync methods already present in the StackExchange.Redis library.

The intent of this library is to duplicate the API (as much as possible) of the RedisGraph module support found embedded in the Jedis library.

Installation

PM> Install-Package NRedisGraph -Version 1.9.0

Usage

I'm assuming that you already have the RedisGraph module installed on your Redis server.

You can verify that the module is installed by executing the following command:

MODULE LIST

If RedisGraph is installed you should see output similar to the following:

1) 1) "name"
   2) "graph"
   3) "ver"
   4) (integer) 20811

(The version of the module installed on your server obviously may vary.)

Extras

  • Adds support for the LOLWUT Redis command by introducing extension methods to the IDatabase.

Examples

In this repository there are a suite of integration tests that should be sufficient to serve as examples on how to use all supported RedisGraph commands.

Integration Tests

nredisgraph's People

Contributors

jgeyen avatar jweber avatar rolfwessels avatar tombatron avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

nredisgraph's Issues

Support map as parameter

I am running the following code:

var assignments = new (long ScopeId, long RoleId, long UserId)[]
{
    (123, 234, 345),
    (321, 432, 543),
}
var assignmentMaps = assignments.Select(a => new { scopeId = a.ScopeId, roleId = a.RoleId, userId = a.UserId }).ToArray();

await graph.QueryAsync(AuthGraphKey,
    query: "UNWIND $assignments AS assignment " +
            "MATCH (s:Scope { id: assignment.scopeId }), (r:Role { id: assignment.roleId }) " +
            "CREATE (s)-[:ASSIGNED_TO { user_id: assignment.userId }]->(r)",
    parameters: new Dictionary<string, object> {
            { "assignments", assignmentMaps },
    });

However, I get an exception from RedisGraph:

Exception: StackExchange.Redis.RedisServerException: errMsg: Invalid input 'a': expected ';', ':', a statement option, a query hint, a clause or a schema command line: 1, column: 1, offset: 0 errCtx: assignments=[{ scopeId = 1044, roleId = 1, userId = 12291 }, { scopeId = 1045... errCtxOffset: 0 at NRedisGraph.RedisGraph.QueryAsync(String graphId, String query) at GlobalEditAPI.Authorization.Core.Infrastructure.Data.IO.RedisGraphAdapter.QueryAsync(String graphId, String query, IDictionary2 parameters)`

From its formatting, I assume this is because when you provide a "map" type as a parameter, the utility calls .ToString() instead of serializing as json. We should do that serialization, so we can support map types.

CallProcedure deserialization is not working with Read-Only queries

We are using a Redis graph read-only replica and performing read-only queries. In standard scenarios when the result is a specific value like a string or long there aren't any problems, but in the case when we are expecting nodes, the deserialization is calling inside it a 'GRAPH.QUERY' and the read-only replica which is only accepting 'GRAPH_RO.QUERY' is throwing an exception.

The full path to the method is ResultSet>RecordIterator>DeserializeScalar>DeserializeNode>_graphCache.GetLabel>_labels.GetCachedData>GetProcedureInfo>CallProcedure

Need to support nested Records in the Result Set

In a query like this
MATCH p = (r)-[e]->(d) RETURN { nodes: nodes(p), edges: relationships(p) } LIMIT 2

There doesn't appear to be a way to decode the result.
ToDictionary on the returned RedisResult will give you a set of Key Value pairs, so I assume this is possible.

Obsolete attribute for RedisGraph 2.1

Hello, I noticed the following attribute in the code:

[Obsolete("SchemaType is no longer supported after RedisGraph 2.1 and will always return COLUMN_SCALAR")]

Is there a branch I could use where this is fixed ? It seems the whole deserialization in the ResultSet will not work anymore starting at 2.1.

Production usage

Hi,
For now, I am using a nodejs microservice to communicate with redisgraph from c#, I'm thinking to switch to this library.

  1. Is it production-ready?
  2. Are you planning to continue and maintain it?

Thanks

Library does not lend itself to unit testing

I am attempting to implement unit tests of a repository that uses NRedisGraph to access my Redis data. As one should always do for unit testing, I am mocking/faking al ldependencies, which includes objects from NRedisGraph. However, the library is too hard-coded and makes this impossible:

  1. Because the only way to create the graph object is via a new command (no abstract factory, no interface for dependency injection, etc.), I had to wrap the graph object in an adapter so that it would be unit testable.
  2. My query returns the ResultSet from the graph object's QueryAsync function. However, this object is sealed and internal. However, since it implements IEnumerable<Record>, I could create that enumerable and cast it to ResultSet when needed. Further cumbersome, but at least doable.
  3. The constructors for the Record are all internal, so I cannot instantiate a new one when setting up my mocks in my test. The class is sealed, which means I cannot extend it. It implements no interfaces and isn't abstract, so I can't mock it directly. This means that I cannot, in any way, shape, or form, create a Record object in a unit-test appropriate way. Therefore, all the other earlier work is for naught.

Ideally, we would have interfaces for the RedisGraph object, so it can be mockable at the root. Barring that, there needs to at least be 1 public constructor for the Record object, so they can be instantiated for mocks in a unit test.

Below is an example of my test:

        [Test]
        public async Task GetUserOrganizationPoliciesAsync_SingleScope_ReturnsUserPolicies()
        {
            //Arrange
            var mockGraph = new Mock<IRedisGraphAdapter>();
            _mockRedisGraphFactory.Setup(f => f.BuildAsync(0)).ReturnsAsync(mockGraph.Object);

            var mockRecord = new Mock<Record>();
            var policies = new[] { "my:policy", "my:other:policy" };
            mockRecord.Setup(r => r.GetString("r.policies")).Returns(JsonConvert.SerializeObject(policies));

            IEnumerable<Record> records = new[]
            {
                mockRecord.Object,
            };

            var queries = new Dictionary<string, IDictionary<string, object>>();
            mockGraph
                .Setup(g => g.QueryAsync("auth", It.IsAny<string>(), It.IsAny<Dictionary<string, object>>()))
                .Callback((string d, string q, IDictionary<string, object> p) => queries[q] = p)
                .ReturnsAsync((ResultSet)records);

            //Act
            var result = await _userPolicyCacheRepository.GetUserOrganizationPoliciesAsync(9266, 90210);

            //Assert
            Assert.That(result.ErrorMessage, Is.Null);
            Assert.That(result.Success, Is.True);
            Assert.That(result.Policies, Is.EqualTo(policies));

            mockGraph.Verify(g => g.QueryAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<Dictionary<string, object>>()), Times.Once);
            var policyQuery = "MATCH (r:Role)-[:ASSIGNED_TO { user_id: $userId }]-(s:Scope)-[:INHERITS_FROM*0..3]->(:Scope { id: $scopeId }) " +
                               "RETURN r.policies " +
                               "UNION " +
                               "MATCH (:Scope { id: $scopeId })-[:INHERITS_FROM*0..3]->(s:Scope)-[:ASSIGNED_TO { user_id: $userId }]-(r:Role) " +
                               "RETURN r.policies";

            Assert.That(queries, Has.Count.EqualTo(1)
                .And.ContainKey(policyQuery));
            Assert.That(queries[policyQuery], Has.Count.EqualTo(2)
                .And.ContainKey("scopeId")
                .And.ContainKey("userId"));
            Assert.That(queries[policyQuery]["scopeId"], Is.EqualTo(90210));
            Assert.That(queries[policyQuery]["userId"], Is.EqualTo(9266));
        }

Escaping query parameters

Hi,
I have some odd use-cases that I can't really put my finger on...
I am getting errors about un-escaped parameters, The bellow function received an object and internally convert it to a dictionary.
I have attached a screenshot that previews the dictionary.
ontop of that, I have some other use cases of emojis throwing the same errors, but I can really put my finger on it...

//success
services.RedisGraphClient.Execute("CREATE (a:Test {SomeString: $SomeString})", new { SomeString = "dsfdsfdss\"" });

//fails
services.RedisGraphClient.Execute("CREATE (a:Test {SomeString: $SomeString})", new { SomeString = "ds\" fdsfdss\"" });
//fails
services.RedisGraphClient.Execute("CREATE (a:Test {SomeString: $SomeString})", new { SomeString = "dsfdsfdss\"#" });

Thanks

image

How to specify the password used to connect?

I created a new Redis Graph on https://app.redislabs.com/ and it has a random password that the service created.

I tried to connect to it:

var muxr = ConnectionMultiplexer.Connect("[mydatabase].azure.cloud.redislabs.com:13788");// ("127.0.0.1");

But it throws this Exception:

StackExchange.Redis.RedisConnectionException: 'It was not possible to connect to the redis server(s). There was an authentication failure; check that passwords (or client certificates) are configured correctly. AuthenticationFailure (None, last-recv: 264)

How to specify the password that NRedisGraph uses to connect to the server?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.