lib/redgraph/graph.rb in redgraph-0.1.2 vs lib/redgraph/graph.rb in redgraph-0.1.3

- old
+ new

@@ -1,9 +1,15 @@ # frozen_string_literal: true +require_relative "graph/node_methods" +require_relative "graph/edge_methods" + module Redgraph class Graph + include NodeMethods + include EdgeMethods + attr_accessor :connection, :graph_name def initialize(graph, redis_options = {}) @graph_name = graph @connection = Redis.new(redis_options) @@ -36,144 +42,53 @@ end # Returns an array of existing labels # def labels - result = query("CALL db.labels()") + result = _query("CALL db.labels()") result.resultset.map(&:values).flatten end # Returns an array of existing properties # def properties - result = query("CALL db.propertyKeys()") + result = _query("CALL db.propertyKeys()") result.resultset.map(&:values).flatten end # Returns an array of existing relationship types # def relationship_types - result = query("CALL db.relationshipTypes()") + result = _query("CALL db.relationshipTypes()") result.resultset.map(&:values).flatten end - # Adds a node. If successul it returns the created object, otherwise false - # - def add_node(node) - result = query("CREATE (n:`#{node.label}` #{quote_hash(node.properties)}) RETURN ID(n)") - return false if result.stats[:nodes_created] != 1 - id = result.resultset.first["ID(n)"] - node.id = id - node + # You can run custom cypher queries + def query(cmd) + _query(cmd).rows end - def find_node_by_id(id) - result = query("MATCH (node) WHERE ID(node) = #{id} RETURN node") - return nil if result.resultset.empty? - (node_id, labels, properties) = result.resultset.first["node"] - attrs = {} - - properties.each do |(index, type, value)| - attrs[get_property(index)] = value - end - Node.new(label: get_label(labels.first), properties: attrs).tap do |node| - node.id = node_id - end + def get_label(id) + @labels ||= labels + @labels[id] || (@labels = labels)[id] end - # Returns nodes. Options: - # - # - label: filter by label - # - properties: filter by properties - # - limit: number of items - # - skip: items offset (useful for pagination) - # - def nodes(label: nil, properties: nil, limit: nil, skip: nil) - _label = ":`#{label}`" if label - _props = quote_hash(properties) if properties - _limit = "LIMIT #{limit}" if limit - _skip = "SKIP #{skip}" if skip - - cmd = "MATCH (node#{_label} #{_props}) RETURN node #{_skip} #{_limit}" - result = query(cmd) - - result.resultset.map do |item| - node_from_resultset_item(item["node"]) - end + def get_property(id) + @properties ||= properties + @properties[id] || (@properties = properties)[id] end - # Counts nodes. Options: - # - # - label: filter by label - # - properties: filter by properties - # - def count_nodes(label: nil, properties: nil) - _label = ":`#{label}`" if label - _props = quote_hash(properties) if properties - - cmd = "MATCH (node#{_label} #{_props}) RETURN COUNT(node)" - result = query(cmd) - - result.resultset.first["COUNT(node)"] + def get_relationship_type(id) + @relationship_types ||= relationship_types + @relationship_types[id] || (@relationship_types = relationship_types)[id] end - # Adds an edge. If successul it returns the created object, otherwise false - # - def add_edge(edge) - result = query("MATCH (src), (dest) - WHERE ID(src) = #{edge.src.id} AND ID(dest) = #{edge.dest.id} - CREATE (src)-[e:`#{edge.type}` #{quote_hash(edge.properties)}]->(dest) RETURN ID(e)") - return false if result.stats[:relationships_created] != 1 - id = result.resultset.first["ID(e)"] - edge.id = id - edge - end - - # Finds edges. Options: - # - # - type - # - src - # - dest - # - properties - # - limit - # - skip - # - def edges(type: nil, src: nil, dest: nil, properties: nil, limit: nil, skip: nil) - _type = ":`#{type}`" if type - _props = quote_hash(properties) if properties - _limit = "LIMIT #{limit}" if limit - _skip = "SKIP #{skip}" if skip - - _where = if src || dest - clauses = [ - ("ID(src) = #{src.id}" if src), - ("ID(dest) = #{dest.id}" if dest) - ].compact.join(" AND ") - "WHERE #{clauses}" - end - - cmd = "MATCH (src)-[edge#{_type} #{_props}]->(dest) #{_where} - RETURN src, edge, dest #{_skip} #{_limit}" - result = query(cmd) - - result.resultset.map do |item| - src = node_from_resultset_item(item["src"]) - dest = node_from_resultset_item(item["dest"]) - edge = edge_from_resultset_item(item["edge"]) - - edge.src = src - edge.dest = dest - - edge - end - end - private - def query(cmd) + def _query(cmd) data = @connection.call("GRAPH.QUERY", graph_name, cmd, "--compact") - QueryResponse.new(data) + QueryResponse.new(data, self) end def quote_hash(hash) "{" + hash.map {|k,v| "#{k}:#{escape_value(v)}" }.join(", ") + @@ -187,50 +102,7 @@ else '"' + x.gsub('"', '\"') + '"' end end - def get_label(id) - @labels ||= labels - @labels[id] || (@labels = labels)[id] - end - - def get_property(id) - @properties ||= properties - @properties[id] || (@properties = properties)[id] - end - - def get_relationship_type(id) - @relationship_types ||= relationship_types - @relationship_types[id] || (@relationship_types = relationship_types)[id] - end - - # Builds a Node object from the raw data - # - def node_from_resultset_item(item) - (node_id, labels, props) = item - attrs = {} - - props.each do |(index, type, value)| - attrs[get_property(index)] = value - end - Node.new(label: get_label(labels.first), properties: attrs).tap do |node| - node.id = node_id - end - end - - def edge_from_resultset_item(item) - (edge_id, type_id, _src_id, _dest_id, props) = item - attrs = {} - - props.each do |(index, type, value)| - attrs[get_property(index)] = value - end - - Edge.new.tap do |edge| - edge.id = edge_id - edge.type = get_relationship_type(type_id) - edge.properties = attrs - end - end end end