Skip to content

Commit

Permalink
Made it possible to use Related together with another database for st…
Browse files Browse the repository at this point in the history
…oring node data. #1
  • Loading branch information
niho committed Feb 10, 2012
1 parent bedaf2a commit d1c411a
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 3 deletions.
31 changes: 31 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,37 @@ relationships on the same machine, making set operations on relationships
a lot faster overall. But with the obvious drawback that the total size of
your graph will be limited by that single machine.

Using Related with another database
-----------------------------------

Related can easily be used together with other databases than Redis to store
Node data. Relationships are always stored in Redis, but node data can often
have characteristics that make Redis unsuitable (like large size).

You can for example use Related together with the Ripple gem to store nodes
in Riak:

```ruby
class CustomNode
include Ripple::Document
include Related::Node::QueryMethods

def query
Related::Node::Query.new(self)
end
end
```

You can then use the `CustomNode` class as an ordinary Related graph Node and
query the graph like usual:

```ruby
node1 = CustomNode.create
node2 = CustomNode.create
Related::Relationship.create(:friend, node1, node2)
node1.shortest_path_to(node2).outgoing(:friend)
```

Development
-----------

Expand Down
10 changes: 7 additions & 3 deletions lib/related/node.rb
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ def map(&block)
def to_a
perform_query unless @result
if @result_type == :nodes
Related::Node.find(@result, @options)
node_class.find(@result, @options)
else
Related::Relationship.find(@result, @options)
end
Expand All @@ -134,7 +134,7 @@ def include?(entity)
if @destination
self.to_a.include?(entity)
else
if entity.is_a?(Related::Node)
if entity.is_a?(node_class)
@result_type = :nodes
Related.redis.sismember(key, entity.to_s)
elsif entity.is_a?(Related::Relationship)
Expand All @@ -147,7 +147,7 @@ def include?(entity)
def find(node)
if @result_type == :nodes
if Related.redis.sismember(key, node.to_s)
Related::Node.find(node.to_s, @options)
node_class.find(node.to_s, @options)
end
else
if id = Related.redis.get(dir_key(node))
Expand Down Expand Up @@ -217,6 +217,10 @@ def to_json(options = {})

protected

def node_class
@node.class
end

def page_start
if @page.nil? || @page.to_i.to_s == @page.to_s
@page && @page.to_i != 1 ? (@page.to_i * @limit.to_i) - @limit.to_i : 0
Expand Down
46 changes: 46 additions & 0 deletions test/custom_node_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
require File.expand_path('test/test_helper')
require 'pp'

class CustomNodeTest < ActiveModel::TestCase

class CustomNode
include Related::Node::QueryMethods
attr_accessor :id
def self.flush
@database = {}
end
def self.create
n = self.new
n.id = Related.generate_id
@database ||= {}
@database[n.id] = n
n
end
def self.find(*ids)
ids.pop if ids.size > 1 && ids.last.is_a?(Hash)
ids.flatten.map do |id|
@database[id]
end
end
def to_s
@id
end
protected
def query
Related::Node::Query.new(self)
end
end

def setup
Related.redis.flushall
CustomNode.flush
end

def test_property_conversion
node1 = CustomNode.create
node2 = CustomNode.create
Related::Relationship.create(:friend, node1, node2)
assert_equal [node2], node1.shortest_path_to(node2).outgoing(:friend).nodes.to_a
end

end

0 comments on commit d1c411a

Please sign in to comment.