redgraph 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +8 -0
- data/CHANGELOG.md +26 -1
- data/Gemfile +2 -0
- data/Gemfile.lock +22 -1
- data/README.md +70 -8
- data/lib/redgraph.rb +11 -0
- data/lib/redgraph/edge.rb +17 -4
- data/lib/redgraph/graph.rb +44 -79
- data/lib/redgraph/graph/edge_methods.rb +105 -0
- data/lib/redgraph/graph/node_methods.rb +104 -0
- data/lib/redgraph/node.rb +11 -3
- data/lib/redgraph/node_model.rb +123 -0
- data/lib/redgraph/node_model/class_methods.rb +76 -0
- data/lib/redgraph/query_response.rb +82 -5
- data/lib/redgraph/util.rb +21 -0
- data/lib/redgraph/version.rb +1 -1
- data/redgraph.gemspec +2 -1
- data/test/graph_edge_methods_test.rb +100 -0
- data/test/graph_manipulation_test.rb +59 -0
- data/test/graph_node_methods_test.rb +112 -0
- data/test/graph_queries_test.rb +22 -35
- data/test/graph_test.rb +26 -0
- data/test/node_model_class_methods_test.rb +66 -0
- data/test/node_model_labels_test.rb +57 -0
- data/test/node_model_test.rb +126 -0
- data/test/test_helper.rb +21 -0
- metadata +27 -3
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: a5a64b5cffa36368ac0664e813ab61f0329a055237b7e4acd473820d9c73409d
         | 
| 4 | 
            +
              data.tar.gz: 371cde906c0a80370e39763a9b3ba9f3fcb83cdd2c19e97f635bfea6e35c5540
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: ac0481573ed2d41bb20de03ab1dc36d6781f5a121a865358e296654dc09abe168868104df92deeb623594b6d68363a0c9333268a059c7b8caf362504039e1431
         | 
| 7 | 
            +
              data.tar.gz: dcb4c293c0a1003926d8776930123c81a5d35981a0896d447a03cc8ee1082f837ce1d73a1f7ca664478980fb485eefb39dad120f703b4584d40ffd6a3ff509c2
         | 
    
        data/.github/workflows/main.yml
    CHANGED
    
    | @@ -5,6 +5,12 @@ on: [push,pull_request] | |
| 5 5 | 
             
            jobs:
         | 
| 6 6 | 
             
              build:
         | 
| 7 7 | 
             
                runs-on: ubuntu-latest
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                services:
         | 
| 10 | 
            +
                  redis:
         | 
| 11 | 
            +
                    image: redislabs/redisgraph
         | 
| 12 | 
            +
                    ports: ["6379:6379"]
         | 
| 13 | 
            +
             | 
| 8 14 | 
             
                steps:
         | 
| 9 15 | 
             
                - uses: actions/checkout@v2
         | 
| 10 16 | 
             
                - name: Set up Ruby
         | 
| @@ -12,6 +18,8 @@ jobs: | |
| 12 18 | 
             
                  with:
         | 
| 13 19 | 
             
                    ruby-version: 3.0.0
         | 
| 14 20 | 
             
                - name: Run the default task
         | 
| 21 | 
            +
                  env:
         | 
| 22 | 
            +
                    TEST_REDIS_URL: redis://localhost:6379/0
         | 
| 15 23 | 
             
                  run: |
         | 
| 16 24 | 
             
                    gem install bundler -v 2.2.15
         | 
| 17 25 | 
             
                    bundle install
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -1,4 +1,29 @@ | |
| 1 | 
            -
            ## [ | 
| 1 | 
            +
            ## [0.2.0]
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            - revamp the NodeModel mixin, the Node to model mapping is now handled by the `_type` property
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            ## [0.1.4]
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            - add NodeModel mixin for a basic ActiveRecord-like syntax
         | 
| 8 | 
            +
            - add Graph#merge_node and Graph#merge_edge 
         | 
| 9 | 
            +
            - edge and node properties are now a HashWithIndifferentAccess
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            ## [0.1.3] - 2021-04-13
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            - allow custom queries
         | 
| 14 | 
            +
            - nodes and edges query now allow the `order` option
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            ## [0.1.2] - 2021-04-12
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            - Add Graph#relationship_types
         | 
| 19 | 
            +
            - Add Graph#count_nodes
         | 
| 20 | 
            +
            - Add Graph#edges
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            ## [0.1.1] - 2021-04-11
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            - Graph#nodes:
         | 
| 25 | 
            +
                - filter by properties
         | 
| 26 | 
            +
                - skip and limit options
         | 
| 2 27 |  | 
| 3 28 | 
             
            ## [0.1.0] - 2021-04-08
         | 
| 4 29 |  | 
    
        data/Gemfile
    CHANGED
    
    
    
        data/Gemfile.lock
    CHANGED
    
    | @@ -1,13 +1,24 @@ | |
| 1 1 | 
             
            PATH
         | 
| 2 2 | 
             
              remote: .
         | 
| 3 3 | 
             
              specs:
         | 
| 4 | 
            -
                redgraph (0. | 
| 4 | 
            +
                redgraph (0.2.0)
         | 
| 5 | 
            +
                  activesupport (>= 3.0.0)
         | 
| 5 6 | 
             
                  redis (~> 4)
         | 
| 6 7 |  | 
| 7 8 | 
             
            GEM
         | 
| 8 9 | 
             
              remote: https://rubygems.org/
         | 
| 9 10 | 
             
              specs:
         | 
| 11 | 
            +
                activesupport (6.1.3.1)
         | 
| 12 | 
            +
                  concurrent-ruby (~> 1.0, >= 1.0.2)
         | 
| 13 | 
            +
                  i18n (>= 1.6, < 2)
         | 
| 14 | 
            +
                  minitest (>= 5.1)
         | 
| 15 | 
            +
                  tzinfo (~> 2.0)
         | 
| 16 | 
            +
                  zeitwerk (~> 2.3)
         | 
| 10 17 | 
             
                coderay (1.1.3)
         | 
| 18 | 
            +
                concurrent-ruby (1.1.8)
         | 
| 19 | 
            +
                docile (1.3.5)
         | 
| 20 | 
            +
                i18n (1.8.10)
         | 
| 21 | 
            +
                  concurrent-ruby (~> 1.0)
         | 
| 11 22 | 
             
                method_source (1.0.0)
         | 
| 12 23 | 
             
                minitest (5.14.4)
         | 
| 13 24 | 
             
                pry (0.14.0)
         | 
| @@ -15,6 +26,15 @@ GEM | |
| 15 26 | 
             
                  method_source (~> 1.0)
         | 
| 16 27 | 
             
                rake (13.0.3)
         | 
| 17 28 | 
             
                redis (4.2.5)
         | 
| 29 | 
            +
                simplecov (0.21.2)
         | 
| 30 | 
            +
                  docile (~> 1.1)
         | 
| 31 | 
            +
                  simplecov-html (~> 0.11)
         | 
| 32 | 
            +
                  simplecov_json_formatter (~> 0.1)
         | 
| 33 | 
            +
                simplecov-html (0.12.3)
         | 
| 34 | 
            +
                simplecov_json_formatter (0.1.2)
         | 
| 35 | 
            +
                tzinfo (2.0.4)
         | 
| 36 | 
            +
                  concurrent-ruby (~> 1.0)
         | 
| 37 | 
            +
                zeitwerk (2.4.2)
         | 
| 18 38 |  | 
| 19 39 | 
             
            PLATFORMS
         | 
| 20 40 | 
             
              x86_64-darwin-20
         | 
| @@ -24,6 +44,7 @@ DEPENDENCIES | |
| 24 44 | 
             
              pry (~> 0.14.0)
         | 
| 25 45 | 
             
              rake (~> 13.0)
         | 
| 26 46 | 
             
              redgraph!
         | 
| 47 | 
            +
              simplecov (~> 0.21.2)
         | 
| 27 48 |  | 
| 28 49 | 
             
            BUNDLED WITH
         | 
| 29 50 | 
             
               2.2.15
         | 
    
        data/README.md
    CHANGED
    
    | @@ -20,33 +20,97 @@ Or install it yourself as: | |
| 20 20 |  | 
| 21 21 | 
             
            ## Usage
         | 
| 22 22 |  | 
| 23 | 
            +
            The gem assumes you have a recent version of [RedisGraph](https://oss.redislabs.com/redisgraph/) up and running.
         | 
| 24 | 
            +
             | 
| 23 25 | 
             
            Basic usage:
         | 
| 24 26 |  | 
| 25 27 | 
             
                graph = Redgraph::Graph.new('movies', url: "redis://localhost:6379/1")
         | 
| 28 | 
            +
                => #<Redgraph::Graph:0x00007f8d5c2b7e38 @connection=#<Redis client v4.2.5 for redis://localhost:6379/1>, @graph_name="movies", @module_version=999999>
         | 
| 26 29 |  | 
| 27 30 | 
             
            Create a couple nodes:
         | 
| 28 31 |  | 
| 29 | 
            -
                actor = Redgraph::Node.new(label: 'actor',  | 
| 32 | 
            +
                actor = Redgraph::Node.new(label: 'actor', properties: {name: "Al Pacino"})
         | 
| 33 | 
            +
                => #<Redgraph::Node:0x00007f8d5f95cf88 @label="actor", @properties={:name=>"Al Pacino"}>
         | 
| 30 34 | 
             
                graph.add_node(actor)
         | 
| 31 | 
            -
                 | 
| 35 | 
            +
                => #<Redgraph::Node:0x00007f8d5f95cf88 @id=0, @label="actor", @properties={:name=>"Al Pacino"}>
         | 
| 36 | 
            +
                film = Redgraph::Node.new(label: 'film', properties: {name: "Scarface"})
         | 
| 37 | 
            +
                => #<Redgraph::Node:0x00007f8d5f85ccc8 @label="film", @properties={:name=>"Scarface"}>
         | 
| 32 38 | 
             
                graph.add_node(film)
         | 
| 39 | 
            +
                => #<Redgraph::Node:0x00007f8d5f85ccc8 @id=1, @label="film", @properties={:name=>"Scarface"}>
         | 
| 33 40 |  | 
| 34 41 | 
             
            Create an edge between those nodes:
         | 
| 35 42 |  | 
| 36 43 | 
             
                edge = Redgraph::Edge.new(src: actor, dest: film, type: 'ACTOR_IN', properties: {role: "Tony Montana"})
         | 
| 37 | 
            -
                 | 
| 44 | 
            +
                => #<Redgraph::Edge:0x00007f8d5f9ae3d8 @dest=#<Redgraph::Node:0x00007f8d5f85ccc8 @id=1, @label="film", @properties={:name=>"Scarface"}>, @dest_id=1, @properties={:role=>"Tony Montana"}, @src=#<Redgraph::Node:0x00007f8d5f95cf88 @id=0, @label="actor", @properties={:name=>"Al Pacino"}>, @src_id=0, @type="ACTOR_IN">
         | 
| 45 | 
            +
                @graph.add_edge(edge)
         | 
| 46 | 
            +
                => #<Redgraph::Edge:0x00007f8d5f9ae3d8 @dest=#<Redgraph::Node:0x00007f8d5f85ccc8 @id=1, @label="film", @properties={:name=>"Scarface"}>, @dest_id=1, @id=0, @properties={:role=>"Tony Montana"}, @src=#<Redgraph::Node:0x00007f8d5f95cf88 @id=0, @label="actor", @properties={:name=>"Al Pacino"}>, @src_id=0, @type="ACTOR_IN">
         | 
| 47 | 
            +
             | 
| 48 | 
            +
            You can merge nodes - the node will be created only if there isn't another with the same label and properties:
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                graph.merge_node(film)
         | 
| 51 | 
            +
                => #<Redgraph::Node:0x00007f8d5f85ccc8 @id=1, @label="film", @properties={:name=>"Scarface"}>
         | 
| 52 | 
            +
             | 
| 53 | 
            +
            Same with edges:
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                @graph.merge_edge(edge)
         | 
| 56 | 
            +
                => #<Redgraph::Edge:0x00007f8d5f9ae3d8 @dest=#<Redgraph::Node:0x00007f8d5f85ccc8 @id=1, @label="film", @properties={:name=>"Scarface"}>, @dest_id=1, @id=0, @properties={:role=>"Tony Montana"}, @src=#<Redgraph::Node:0x00007f8d5f95cf88 @id=0, @label="actor", @properties={:name=>"Al Pacino"}>, @src_id=0, @type="ACTOR_IN">
         | 
| 38 57 |  | 
| 39 58 | 
             
            Find a node by id:
         | 
| 40 59 |  | 
| 41 | 
            -
                @graph.find_node_by_id( | 
| 60 | 
            +
                @graph.find_node_by_id(1)
         | 
| 61 | 
            +
                => #<Redgraph::Node:0x00007f8d5c2c6e88 @id=1, @label="film", @properties={"name"=>"Scarface"}>
         | 
| 42 62 |  | 
| 43 63 | 
             
            To get all nodes:
         | 
| 44 64 |  | 
| 45 65 | 
             
                @graph.nodes
         | 
| 66 | 
            +
                => [#<Redgraph::Node:0x00007f8d5c2ee0a0 @id=0, @label="actor", @properties={"name"=>"Al Pacino"}>, #<Redgraph::Node:0x00007f8d5c2edfd8 @id=1, @label="film", @properties={"name"=>"Scarface"}>]
         | 
| 46 67 |  | 
| 47 | 
            -
            Optional filters:
         | 
| 68 | 
            +
            Optional filters that can be combined:
         | 
| 48 69 |  | 
| 49 70 | 
             
                @graph.nodes(label: 'actor')
         | 
| 71 | 
            +
                @graph.nodes(properties: {name: "Al Pacino"})
         | 
| 72 | 
            +
                @graph.nodes(limit: 10, skip: 20)
         | 
| 73 | 
            +
             | 
| 74 | 
            +
            Counting nodes
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                @graph.count_nodes(label: 'actor')
         | 
| 77 | 
            +
                => 1
         | 
| 78 | 
            +
             | 
| 79 | 
            +
            Getting edges:
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                @graph.edges
         | 
| 82 | 
            +
                @graph.edges(src: actor, dest: film)
         | 
| 83 | 
            +
                @graph.edges(kind: 'FRIEND_OF', limit: 10, skip: 20)
         | 
| 84 | 
            +
                @graph.count_edges
         | 
| 85 | 
            +
             | 
| 86 | 
            +
            Running custom queries
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                @graph.query("MATCH (src)-[edge:FRIEND_OF]->(dest) RETURN src, edge")
         | 
| 89 | 
            +
             | 
| 90 | 
            +
            ### NodeModel
         | 
| 91 | 
            +
             | 
| 92 | 
            +
            You can use the `NodeModel` mixin for a limited ActiveRecord-like interface:
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                class Actor
         | 
| 95 | 
            +
                  include Redgraph::NodeModel
         | 
| 96 | 
            +
                  self.graph = Redgraph::Graph.new("movies", url: $REDIS_URL)
         | 
| 97 | 
            +
                  attribute :name
         | 
| 98 | 
            +
                end
         | 
| 99 | 
            +
             | 
| 100 | 
            +
            And this will give you stuff such as
         | 
| 101 | 
            +
             | 
| 102 | 
            +
                Actor.count
         | 
| 103 | 
            +
                john = Actor.new(name: "John Travolta")
         | 
| 104 | 
            +
                john.add_to_graph # Will add the node to the graph
         | 
| 105 | 
            +
                john.add_relation(type: "ACTED_IN", node: film, properties: {role: "Tony Manero"})
         | 
| 106 | 
            +
             | 
| 107 | 
            +
            `NodeModel` models will automatically set a `_type` property to keep track of the object class.
         | 
| 108 | 
            +
             | 
| 109 | 
            +
            You will then be able to run custom queries such as:
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                Actor.query("MATCH (node) RETURN node ORDER BY node.name")
         | 
| 112 | 
            +
             | 
| 113 | 
            +
            And the result rows object will be instances of the classes defined by the `_type` attribute.
         | 
| 50 114 |  | 
| 51 115 | 
             
            ## Development
         | 
| 52 116 |  | 
| @@ -54,7 +118,7 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run | |
| 54 118 |  | 
| 55 119 | 
             
                TEST_REDIS_URL=YOUR-REDIS-URL rake test
         | 
| 56 120 |  | 
| 57 | 
            -
            to run the tests.
         | 
| 121 | 
            +
            to run the tests. Test coverage will be enabled if you set the `COVERAGE` environment variable to any value.
         | 
| 58 122 |  | 
| 59 123 | 
             
            You can use a `TEST_REDIS_URL` such as `redis://localhost:6379/1`. Make sure you're not overwriting important databases.
         | 
| 60 124 |  | 
| @@ -62,8 +126,6 @@ You can also run `bin/console` for an interactive prompt that will allow you to | |
| 62 126 |  | 
| 63 127 | 
             
            To install this gem onto your local machine, run `bundle exec rake install`.
         | 
| 64 128 |  | 
| 65 | 
            -
            Run `bin/console` for an interactive prompt.
         | 
| 66 | 
            -
             | 
| 67 129 | 
             
            ## Contributing
         | 
| 68 130 |  | 
| 69 131 | 
             
            Bug reports and pull requests are welcome on GitHub at https://github.com/pzac/redgraph.
         | 
    
        data/lib/redgraph.rb
    CHANGED
    
    | @@ -1,13 +1,24 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 | 
             
            require "redis"
         | 
| 3 | 
            +
            require "active_support/core_ext/hash/indifferent_access"
         | 
| 4 | 
            +
            require "active_support/core_ext/object/blank"
         | 
| 5 | 
            +
            require "active_support/core_ext/string/inflections"
         | 
| 6 | 
            +
            require "active_support/concern"
         | 
| 3 7 |  | 
| 4 8 | 
             
            require_relative "redgraph/version"
         | 
| 9 | 
            +
            require_relative "redgraph/util"
         | 
| 5 10 | 
             
            require_relative "redgraph/graph"
         | 
| 6 11 | 
             
            require_relative "redgraph/node"
         | 
| 7 12 | 
             
            require_relative "redgraph/edge"
         | 
| 8 13 | 
             
            require_relative "redgraph/query_response"
         | 
| 14 | 
            +
            require_relative "redgraph/node_model"
         | 
| 9 15 |  | 
| 10 16 | 
             
            module Redgraph
         | 
| 11 17 | 
             
              class Error < StandardError; end
         | 
| 12 18 | 
             
              class ServerError < Error; end
         | 
| 19 | 
            +
              class MissingAliasPrefixError < Error
         | 
| 20 | 
            +
                def message
         | 
| 21 | 
            +
                  "The order clause requires the node/edge alias prefix, ie order('node.foo') instead order('foo')"
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
              end
         | 
| 13 24 | 
             
            end
         | 
    
        data/lib/redgraph/edge.rb
    CHANGED
    
    | @@ -2,17 +2,30 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            module Redgraph
         | 
| 4 4 | 
             
              class Edge
         | 
| 5 | 
            -
                 | 
| 5 | 
            +
                include Util
         | 
| 6 6 |  | 
| 7 | 
            -
                 | 
| 7 | 
            +
                attr_accessor :id, :src, :dest, :src_id, :dest_id, :type, :properties
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                def initialize(src: nil, dest: nil, type: nil, properties: {})
         | 
| 8 10 | 
             
                  @src = src
         | 
| 11 | 
            +
                  @src_id = @src.id if @src
         | 
| 9 12 | 
             
                  @dest = dest
         | 
| 13 | 
            +
                  @dest_id = @dest.id if @dest
         | 
| 10 14 | 
             
                  @type = type
         | 
| 11 | 
            -
                  @properties = properties
         | 
| 15 | 
            +
                  @properties = (properties || {}).with_indifferent_access
         | 
| 12 16 | 
             
                end
         | 
| 13 17 |  | 
| 14 18 | 
             
                def persisted?
         | 
| 15 | 
            -
                   | 
| 19 | 
            +
                  id.present?
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                def ==(other)
         | 
| 23 | 
            +
                  super || other.instance_of?(self.class) && !id.nil? && other.id == id
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                def to_query_string(item_alias: 'edge', src_alias: 'src', dest_alias: 'dest')
         | 
| 27 | 
            +
                  _type = ":#{type}" if type
         | 
| 28 | 
            +
                  "(#{src_alias})-[#{item_alias}#{_type} #{properties_to_string(properties)}]->(#{dest_alias})"
         | 
| 16 29 | 
             
                end
         | 
| 17 30 | 
             
              end
         | 
| 18 31 | 
             
            end
         | 
    
        data/lib/redgraph/graph.rb
    CHANGED
    
    | @@ -1,11 +1,21 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            +
            require_relative "graph/node_methods"
         | 
| 4 | 
            +
            require_relative "graph/edge_methods"
         | 
| 5 | 
            +
             | 
| 3 6 | 
             
            module Redgraph
         | 
| 4 7 | 
             
              class Graph
         | 
| 8 | 
            +
                include NodeMethods
         | 
| 9 | 
            +
                include EdgeMethods
         | 
| 10 | 
            +
             | 
| 5 11 | 
             
                attr_accessor :connection, :graph_name
         | 
| 6 12 |  | 
| 7 | 
            -
                 | 
| 8 | 
            -
             | 
| 13 | 
            +
                # @example Graph.new("foobar", url: "redis://localhost:6379/0", logger: Logger.new(STDOUT))
         | 
| 14 | 
            +
                # @param graph_name [String] Name of the graph
         | 
| 15 | 
            +
                # @param redis_options [Hash] Redis client options
         | 
| 16 | 
            +
                #
         | 
| 17 | 
            +
                def initialize(graph_name, redis_options = {})
         | 
| 18 | 
            +
                  @graph_name = graph_name
         | 
| 9 19 | 
             
                  @connection = Redis.new(redis_options)
         | 
| 10 20 | 
             
                  @module_version = module_version
         | 
| 11 21 | 
             
                  raise ServerError unless @module_version
         | 
| @@ -29,112 +39,67 @@ module Redgraph | |
| 29 39 | 
             
                  raise e
         | 
| 30 40 | 
             
                end
         | 
| 31 41 |  | 
| 32 | 
            -
                #  | 
| 42 | 
            +
                # @return [Array] Existing graph names
         | 
| 33 43 | 
             
                #
         | 
| 34 44 | 
             
                def list
         | 
| 35 45 | 
             
                  @connection.call("GRAPH.LIST")
         | 
| 36 46 | 
             
                end
         | 
| 37 47 |  | 
| 38 | 
            -
                #  | 
| 48 | 
            +
                # @return [Array] Existing labels
         | 
| 39 49 | 
             
                #
         | 
| 40 50 | 
             
                def labels
         | 
| 41 | 
            -
                  result =  | 
| 51 | 
            +
                  result = _query("CALL db.labels()")
         | 
| 42 52 | 
             
                  result.resultset.map(&:values).flatten
         | 
| 43 53 | 
             
                end
         | 
| 44 54 |  | 
| 45 | 
            -
                #  | 
| 55 | 
            +
                # @return [Array] Existing properties
         | 
| 46 56 | 
             
                #
         | 
| 47 57 | 
             
                def properties
         | 
| 48 | 
            -
                  result =  | 
| 58 | 
            +
                  result = _query("CALL db.propertyKeys()")
         | 
| 49 59 | 
             
                  result.resultset.map(&:values).flatten
         | 
| 50 60 | 
             
                end
         | 
| 51 61 |  | 
| 52 | 
            -
                #  | 
| 53 | 
            -
                #
         | 
| 54 | 
            -
                def add_node(node)
         | 
| 55 | 
            -
                  result = query("CREATE (n:`#{node.label}` #{quote_hash(node.properties)}) RETURN ID(n)")
         | 
| 56 | 
            -
                  return false if result.stats[:nodes_created] != 1
         | 
| 57 | 
            -
                  id = result.resultset.first["ID(n)"]
         | 
| 58 | 
            -
                  node.id = id
         | 
| 59 | 
            -
                  node
         | 
| 60 | 
            -
                end
         | 
| 61 | 
            -
             | 
| 62 | 
            -
                def find_node_by_id(id)
         | 
| 63 | 
            -
                  result = query("MATCH (node) WHERE ID(node) = #{id} RETURN node")
         | 
| 64 | 
            -
                  return nil if result.resultset.empty?
         | 
| 65 | 
            -
                  (node_id, labels, properties) = result.resultset.first["node"]
         | 
| 66 | 
            -
                  attrs = {}
         | 
| 67 | 
            -
             | 
| 68 | 
            -
                  properties.each do |(index, type, value)|
         | 
| 69 | 
            -
                    attrs[get_property(index)] = value
         | 
| 70 | 
            -
                  end
         | 
| 71 | 
            -
                  Node.new(label: get_label(labels.first), properties: attrs).tap do |node|
         | 
| 72 | 
            -
                    node.id = node_id
         | 
| 73 | 
            -
                  end
         | 
| 74 | 
            -
                end
         | 
| 75 | 
            -
             | 
| 76 | 
            -
                def nodes(label: nil)
         | 
| 77 | 
            -
                  node_or_node_with_label = label ? "node:`#{label}`" : "node"
         | 
| 78 | 
            -
             | 
| 79 | 
            -
                  cmd = "MATCH (#{node_or_node_with_label}) RETURN node"
         | 
| 80 | 
            -
                  result = query(cmd)
         | 
| 81 | 
            -
             | 
| 82 | 
            -
                  result.resultset.map do |item|
         | 
| 83 | 
            -
                    (node_id, labels, properties) = item["node"]
         | 
| 84 | 
            -
                    attrs = {}
         | 
| 85 | 
            -
             | 
| 86 | 
            -
                    properties.each do |(index, type, value)|
         | 
| 87 | 
            -
                      attrs[get_property(index)] = value
         | 
| 88 | 
            -
                    end
         | 
| 89 | 
            -
                    Node.new(label: get_label(labels.first), properties: attrs).tap do |node|
         | 
| 90 | 
            -
                      node.id = node_id
         | 
| 91 | 
            -
                    end
         | 
| 92 | 
            -
                  end
         | 
| 93 | 
            -
                end
         | 
| 94 | 
            -
             | 
| 95 | 
            -
                # Adds an edge. If successul it returns the created object, otherwise false
         | 
| 62 | 
            +
                # @return [Array] Existing relationship types
         | 
| 96 63 | 
             
                #
         | 
| 97 | 
            -
                def  | 
| 98 | 
            -
                  result =  | 
| 99 | 
            -
             | 
| 100 | 
            -
                                  CREATE (src)-[e:`#{edge.type}` #{quote_hash(edge.properties)}]->(dest) RETURN ID(e)")
         | 
| 101 | 
            -
                  return false if result.stats[:relationships_created] != 1
         | 
| 102 | 
            -
                  id = result.resultset.first["ID(e)"]
         | 
| 103 | 
            -
                  edge.id = id
         | 
| 104 | 
            -
                  edge
         | 
| 64 | 
            +
                def relationship_types
         | 
| 65 | 
            +
                  result = _query("CALL db.relationshipTypes()")
         | 
| 66 | 
            +
                  result.resultset.map(&:values).flatten
         | 
| 105 67 | 
             
                end
         | 
| 106 68 |  | 
| 107 | 
            -
                 | 
| 108 | 
            -
             | 
| 69 | 
            +
                # You can run custom cypher queries
         | 
| 109 70 | 
             
                def query(cmd)
         | 
| 110 | 
            -
                   | 
| 111 | 
            -
                  QueryResponse.new(data)
         | 
| 112 | 
            -
                end
         | 
| 113 | 
            -
             | 
| 114 | 
            -
                def quote_hash(hash)
         | 
| 115 | 
            -
                  out = "{"
         | 
| 116 | 
            -
                  hash.each do |k,v|
         | 
| 117 | 
            -
                    out += "#{k}:#{escape_value(v)}"
         | 
| 118 | 
            -
                  end
         | 
| 119 | 
            -
                  out + "}"
         | 
| 120 | 
            -
                end
         | 
| 121 | 
            -
             | 
| 122 | 
            -
                def escape_value(x)
         | 
| 123 | 
            -
                  case x
         | 
| 124 | 
            -
                  when Integer then x
         | 
| 125 | 
            -
                  else
         | 
| 126 | 
            -
                    "'#{x}'"
         | 
| 127 | 
            -
                  end
         | 
| 71 | 
            +
                  _query(cmd).rows
         | 
| 128 72 | 
             
                end
         | 
| 129 73 |  | 
| 74 | 
            +
                # @param id [Integer] label id
         | 
| 75 | 
            +
                # @return [String, nil] label
         | 
| 76 | 
            +
                #
         | 
| 130 77 | 
             
                def get_label(id)
         | 
| 131 78 | 
             
                  @labels ||= labels
         | 
| 132 79 | 
             
                  @labels[id] || (@labels = labels)[id]
         | 
| 133 80 | 
             
                end
         | 
| 134 81 |  | 
| 82 | 
            +
                # @param id [Integer] property id
         | 
| 83 | 
            +
                # @return [String, nil] property
         | 
| 84 | 
            +
                #
         | 
| 135 85 | 
             
                def get_property(id)
         | 
| 136 86 | 
             
                  @properties ||= properties
         | 
| 137 87 | 
             
                  @properties[id] || (@properties = properties)[id]
         | 
| 138 88 | 
             
                end
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                # @param id [Integer] relationship type id
         | 
| 91 | 
            +
                # @return [String, nil] relationship type
         | 
| 92 | 
            +
                #
         | 
| 93 | 
            +
                def get_relationship_type(id)
         | 
| 94 | 
            +
                  @relationship_types ||= relationship_types
         | 
| 95 | 
            +
                  @relationship_types[id] || (@relationship_types = relationship_types)[id]
         | 
| 96 | 
            +
                end
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                private
         | 
| 99 | 
            +
             | 
| 100 | 
            +
                def _query(cmd)
         | 
| 101 | 
            +
                  data = @connection.call("GRAPH.QUERY", graph_name, cmd, "--compact")
         | 
| 102 | 
            +
                  QueryResponse.new(data, self)
         | 
| 103 | 
            +
                end
         | 
| 139 104 | 
             
              end
         | 
| 140 105 | 
             
            end
         |