architect4r 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +53 -0
- data/Guardfile +10 -0
- data/License +20 -0
- data/README.md +62 -0
- data/Rakefile +40 -0
- data/ReleaseNotes.md +33 -0
- data/Roadmap.md +31 -0
- data/Specs.md +21 -0
- data/architect4r.gemspec +31 -0
- data/lib/architect4r.rb +66 -0
- data/lib/architect4r/adapters/carrier_wave.rb +64 -0
- data/lib/architect4r/core/configuration.rb +148 -0
- data/lib/architect4r/core/cypher_methods.rb +47 -0
- data/lib/architect4r/core/management_methods.rb +129 -0
- data/lib/architect4r/core/node_methods.rb +73 -0
- data/lib/architect4r/core/relationship_methods.rb +82 -0
- data/lib/architect4r/generic_node.rb +7 -0
- data/lib/architect4r/has_node.rb +80 -0
- data/lib/architect4r/instance_manager.rb +47 -0
- data/lib/architect4r/model/callbacks.rb +19 -0
- data/lib/architect4r/model/connection.rb +29 -0
- data/lib/architect4r/model/links_query_interface.rb +23 -0
- data/lib/architect4r/model/node.rb +117 -0
- data/lib/architect4r/model/persistency.rb +95 -0
- data/lib/architect4r/model/properties.rb +166 -0
- data/lib/architect4r/model/queries.rb +38 -0
- data/lib/architect4r/model/relationship.rb +105 -0
- data/lib/architect4r/model/relationships.rb +16 -0
- data/lib/architect4r/model/validations.rb +11 -0
- data/lib/architect4r/server.rb +96 -0
- data/lib/architect4r/version.rb +3 -0
- data/spec/architect4r_spec.rb +9 -0
- data/spec/core/configuration_spec.rb +54 -0
- data/spec/core/cypher_methods_spec.rb +29 -0
- data/spec/core/node_methods_spec.rb +47 -0
- data/spec/core/relationship_methods_spec.rb +92 -0
- data/spec/fixtures/architect4r.yml +21 -0
- data/spec/fixtures/graph.db.default/active_tx_log +1 -0
- data/spec/fixtures/graph.db.default/index/lucene-store.db +0 -0
- data/spec/fixtures/graph.db.default/index/lucene.log.1 +0 -0
- data/spec/fixtures/graph.db.default/index/lucene.log.active +0 -0
- data/spec/fixtures/graph.db.default/index/lucene.log.v0 +0 -0
- data/spec/fixtures/graph.db.default/index/lucene.log.v1 +0 -0
- data/spec/fixtures/graph.db.default/index/lucene.log.v2 +0 -0
- data/spec/fixtures/graph.db.default/lock +0 -0
- data/spec/fixtures/graph.db.default/messages.log +183 -0
- data/spec/fixtures/graph.db.default/neostore +0 -0
- data/spec/fixtures/graph.db.default/neostore.id +0 -0
- data/spec/fixtures/graph.db.default/neostore.nodestore.db +0 -0
- data/spec/fixtures/graph.db.default/neostore.nodestore.db.id +0 -0
- data/spec/fixtures/graph.db.default/neostore.propertystore.db +0 -0
- data/spec/fixtures/graph.db.default/neostore.propertystore.db.arrays +0 -0
- data/spec/fixtures/graph.db.default/neostore.propertystore.db.arrays.id +0 -0
- data/spec/fixtures/graph.db.default/neostore.propertystore.db.id +0 -0
- data/spec/fixtures/graph.db.default/neostore.propertystore.db.index +0 -0
- data/spec/fixtures/graph.db.default/neostore.propertystore.db.index.id +0 -0
- data/spec/fixtures/graph.db.default/neostore.propertystore.db.index.keys +0 -0
- data/spec/fixtures/graph.db.default/neostore.propertystore.db.index.keys.id +0 -0
- data/spec/fixtures/graph.db.default/neostore.propertystore.db.strings +0 -0
- data/spec/fixtures/graph.db.default/neostore.propertystore.db.strings.id +0 -0
- data/spec/fixtures/graph.db.default/neostore.relationshipstore.db +0 -0
- data/spec/fixtures/graph.db.default/neostore.relationshipstore.db.id +0 -0
- data/spec/fixtures/graph.db.default/neostore.relationshiptypestore.db +0 -0
- data/spec/fixtures/graph.db.default/neostore.relationshiptypestore.db.id +0 -0
- data/spec/fixtures/graph.db.default/neostore.relationshiptypestore.db.names +0 -0
- data/spec/fixtures/graph.db.default/neostore.relationshiptypestore.db.names.id +0 -0
- data/spec/fixtures/graph.db.default/nioneo_logical.log.1 +0 -0
- data/spec/fixtures/graph.db.default/nioneo_logical.log.active +0 -0
- data/spec/fixtures/graph.db.default/tm_tx_log.1 +0 -0
- data/spec/fixtures/graph.db.default/upgrade_backup/active_tx_log +1 -0
- data/spec/fixtures/graph.db.default/upgrade_backup/messages.log +142 -0
- data/spec/fixtures/graph.db.default/upgrade_backup/neostore +0 -0
- data/spec/fixtures/graph.db.default/upgrade_backup/neostore.id +0 -0
- data/spec/fixtures/graph.db.default/upgrade_backup/neostore.nodestore.db +0 -0
- data/spec/fixtures/graph.db.default/upgrade_backup/neostore.nodestore.db.id +0 -0
- data/spec/fixtures/graph.db.default/upgrade_backup/neostore.propertystore.db +0 -0
- data/spec/fixtures/graph.db.default/upgrade_backup/neostore.propertystore.db.arrays +0 -0
- data/spec/fixtures/graph.db.default/upgrade_backup/neostore.propertystore.db.arrays.id +0 -0
- data/spec/fixtures/graph.db.default/upgrade_backup/neostore.propertystore.db.id +0 -0
- data/spec/fixtures/graph.db.default/upgrade_backup/neostore.propertystore.db.index +0 -0
- data/spec/fixtures/graph.db.default/upgrade_backup/neostore.propertystore.db.index.id +0 -0
- data/spec/fixtures/graph.db.default/upgrade_backup/neostore.propertystore.db.index.keys +0 -0
- data/spec/fixtures/graph.db.default/upgrade_backup/neostore.propertystore.db.index.keys.id +0 -0
- data/spec/fixtures/graph.db.default/upgrade_backup/neostore.propertystore.db.strings +0 -0
- data/spec/fixtures/graph.db.default/upgrade_backup/neostore.propertystore.db.strings.id +0 -0
- data/spec/fixtures/graph.db.default/upgrade_backup/neostore.relationshipstore.db +0 -0
- data/spec/fixtures/graph.db.default/upgrade_backup/neostore.relationshipstore.db.id +0 -0
- data/spec/fixtures/graph.db.default/upgrade_backup/neostore.relationshiptypestore.db +0 -0
- data/spec/fixtures/graph.db.default/upgrade_backup/neostore.relationshiptypestore.db.id +0 -0
- data/spec/fixtures/graph.db.default/upgrade_backup/neostore.relationshiptypestore.db.names +0 -0
- data/spec/fixtures/graph.db.default/upgrade_backup/neostore.relationshiptypestore.db.names.id +0 -0
- data/spec/fixtures/graph.db.default/upgrade_backup/nioneo_logical.log.active +0 -0
- data/spec/fixtures/graph.db.default/upgrade_backup/nioneo_logical.log.v0 +0 -0
- data/spec/fixtures/graph.db.default/upgrade_backup/nioneo_logical.log.v1 +0 -0
- data/spec/fixtures/graph.db.default/upgrade_backup/nioneo_logical.log.v2 +0 -0
- data/spec/fixtures/graph.db.default/upgrade_backup/tm_tx_log.1 +0 -0
- data/spec/has_node_spec.rb +87 -0
- data/spec/model/links_query_interface_spec.rb +22 -0
- data/spec/model/links_spec.rb +26 -0
- data/spec/model/node_spec.rb +48 -0
- data/spec/model/persistency_spec.rb +98 -0
- data/spec/model/properties_spec.rb +165 -0
- data/spec/model/queries_spec.rb +50 -0
- data/spec/model/relationship_spec.rb +63 -0
- data/spec/model/validations_spec.rb +31 -0
- data/spec/server_spec.rb +33 -0
- data/spec/spec_helper.rb +115 -0
- metadata +377 -0
@@ -0,0 +1,38 @@
|
|
1
|
+
module Architect4r
|
2
|
+
module Model
|
3
|
+
module Queries
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
module InstanceMethods
|
7
|
+
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
|
12
|
+
def count(opts = {}, &block)
|
13
|
+
data = connection.execute_cypher("start s=node(#{self.model_root.id}) match (s)<-[:model_type]-(d) return count(d)")
|
14
|
+
data.first['count(d)']
|
15
|
+
end
|
16
|
+
|
17
|
+
def find_by_id(id)
|
18
|
+
data = connection.execute_cypher("start s=node(#{self.model_root.id}), d=node(#{id.to_i}) match s<-[r:model_type]-d return d")
|
19
|
+
data &&= data.first && data.first['d']
|
20
|
+
self.build_from_database(data)
|
21
|
+
end
|
22
|
+
|
23
|
+
def find_by_id!(id)
|
24
|
+
raise 'not implemented'
|
25
|
+
end
|
26
|
+
|
27
|
+
def find_by_cypher(query, identifier)
|
28
|
+
if data = connection.execute_cypher(query)
|
29
|
+
data.map { |item| build_from_database(item[identifier]) }
|
30
|
+
else
|
31
|
+
nil
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
module Architect4r
|
2
|
+
module Model
|
3
|
+
class Relationship
|
4
|
+
|
5
|
+
#
|
6
|
+
# Architect4r extensions
|
7
|
+
#
|
8
|
+
include Architect4r::Model::Connection
|
9
|
+
include Architect4r::Model::Callbacks
|
10
|
+
include Architect4r::Model::Persistency
|
11
|
+
|
12
|
+
|
13
|
+
def self.inherited(subklass)
|
14
|
+
super
|
15
|
+
subklass.send(:include, ActiveModel::Conversion)
|
16
|
+
subklass.extend ActiveModel::Naming
|
17
|
+
subklass.send(:include, Architect4r::Model::Properties)
|
18
|
+
subklass.send(:include, Architect4r::Model::Validations)
|
19
|
+
|
20
|
+
subklass.class_exec do
|
21
|
+
# Validations
|
22
|
+
validates :source, :presence => true
|
23
|
+
validates :destination, :presence => true
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
#
|
28
|
+
# Virtual attributes
|
29
|
+
#
|
30
|
+
attr_accessor :source, :destination, :raw_data
|
31
|
+
|
32
|
+
#
|
33
|
+
# Instance methods
|
34
|
+
#
|
35
|
+
|
36
|
+
def initialize(*args)
|
37
|
+
# Detect source and destination
|
38
|
+
if s = args[0].is_a?(Architect4r::Model::Node) && args.shift
|
39
|
+
self.source = s
|
40
|
+
|
41
|
+
if d = args[0].is_a?(Architect4r::Model::Node) && args.shift
|
42
|
+
self.destination = d
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Detect properties
|
47
|
+
properties = args[0].is_a?(Hash) && args.shift
|
48
|
+
properties ||= {}
|
49
|
+
parse_properties(properties)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Create the document. Validation is enabled by default and will return
|
53
|
+
# false if the document is not valid. If all goes well, the document will
|
54
|
+
# be returned.
|
55
|
+
def create(options = {})
|
56
|
+
run_callbacks :create do
|
57
|
+
run_callbacks :save do
|
58
|
+
# only create valid records
|
59
|
+
return false unless perform_validations(options)
|
60
|
+
|
61
|
+
# perform creation
|
62
|
+
if result = connection.create_relationship(self.source.id, self.destination.id, self.class.name, self._to_database_hash)
|
63
|
+
self.raw_data = result
|
64
|
+
end
|
65
|
+
|
66
|
+
# if something goes wrong we receive a nil value and return false
|
67
|
+
!result.nil?
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# Trigger the callbacks (before, after, around)
|
73
|
+
# only if the document isn't new
|
74
|
+
def update(options = {})
|
75
|
+
run_callbacks :update do
|
76
|
+
run_callbacks :save do
|
77
|
+
# Check if record can be updated
|
78
|
+
raise "Cannot save a destroyed document!" if destroyed?
|
79
|
+
raise "Calling #{self.class.name}#update on document that has not been created!" if new?
|
80
|
+
|
81
|
+
# Check if we can continue
|
82
|
+
return false unless perform_validations(options)
|
83
|
+
|
84
|
+
# perform update
|
85
|
+
result = connection.update_relationship(self.id, self._to_database_hash)
|
86
|
+
|
87
|
+
# if something goes wrong we receive a nil value and return false
|
88
|
+
!result.nil?
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def destroy
|
94
|
+
run_callbacks :destroy do
|
95
|
+
if result = connection.delete_relationship(self.id)
|
96
|
+
@_destroyed = true
|
97
|
+
self.freeze
|
98
|
+
end
|
99
|
+
result
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'typhoeus'
|
3
|
+
|
4
|
+
module Architect4r
|
5
|
+
|
6
|
+
class Server
|
7
|
+
|
8
|
+
include Architect4r::Core::CypherMethods
|
9
|
+
include Architect4r::Core::NodeMethods
|
10
|
+
include Architect4r::Core::RelationshipMethods
|
11
|
+
|
12
|
+
def initialize(config=nil)
|
13
|
+
@server_config = config
|
14
|
+
end
|
15
|
+
|
16
|
+
def configuration
|
17
|
+
@configuration ||= Core::Configuration.new(@server_config)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Basic rest actions
|
21
|
+
|
22
|
+
def get(url, options = {})
|
23
|
+
response = Typhoeus::Request.get(prepend_base_url(url), :headers => { 'Accept' => 'application/json' })
|
24
|
+
response.success? ? JSON.parse(response.body) : nil
|
25
|
+
end
|
26
|
+
|
27
|
+
def post(url, params = {})
|
28
|
+
response = Typhoeus::Request.post(prepend_base_url(url), :params => params)
|
29
|
+
response.success? ? JSON.parse(response.body) : nil
|
30
|
+
end
|
31
|
+
|
32
|
+
def put(url, params = {})
|
33
|
+
response = Typhoeus::Request.put(prepend_base_url(url), :params => params)
|
34
|
+
response.success? ? JSON.parse(response.body) : nil
|
35
|
+
end
|
36
|
+
|
37
|
+
def delete
|
38
|
+
response = Typhoeus::Request.delete(prepend_base_url(url), :params => params)
|
39
|
+
response.success? ? JSON.parse(response.body) : nil
|
40
|
+
end
|
41
|
+
|
42
|
+
protected
|
43
|
+
|
44
|
+
def prepend_base_url(url)
|
45
|
+
if url[0,4] == "http"
|
46
|
+
url
|
47
|
+
else
|
48
|
+
"http://#{configuration.host}:#{configuration.port}#{configuration.path}/db/data#{url}"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def node_url(url_or_id)
|
53
|
+
if url_or_id.is_a?(Hash)
|
54
|
+
url_or_id['self'].to_s
|
55
|
+
elsif url_or_id.to_s != '0' and url_or_id.to_i == 0
|
56
|
+
url_or_id.to_s
|
57
|
+
else
|
58
|
+
prepend_base_url("/node/#{url_or_id.to_i}")
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def relationship_url(url_or_id)
|
63
|
+
if url_or_id.is_a?(Hash)
|
64
|
+
url_or_id['self'].to_s
|
65
|
+
elsif url_or_id.to_s != '0' and url_or_id.to_i == 0
|
66
|
+
url_or_id.to_s
|
67
|
+
else
|
68
|
+
prepend_base_url("/relationship/#{url_or_id.to_i}")
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def convert_if_possible(data)
|
73
|
+
data
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
=begin
|
83
|
+
|
84
|
+
Example service root response
|
85
|
+
extensions:
|
86
|
+
CypherPlugin:
|
87
|
+
execute_query: http://localhost:7475/db/data/ext/CypherPlugin/graphdb/execute_query
|
88
|
+
GremlinPlugin:
|
89
|
+
execute_script: http://localhost:7475/db/data/ext/GremlinPlugin/graphdb/execute_script
|
90
|
+
relationship_types: http://localhost:7475/db/data/relationship/types
|
91
|
+
relationship_index: http://localhost:7475/db/data/index/relationship
|
92
|
+
reference_node: http://localhost:7475/db/data/node/0
|
93
|
+
node: http://localhost:7475/db/data/node
|
94
|
+
extensions_info: http://localhost:7475/db/data/ext
|
95
|
+
node_index: http://localhost:7475/db/data/index/node
|
96
|
+
=end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Architect4r::Core::Configuration do
|
4
|
+
|
5
|
+
describe "default configuration" do
|
6
|
+
subject { Architect4r::Core::Configuration.new }
|
7
|
+
|
8
|
+
its(:host) { should == 'localhost' }
|
9
|
+
its(:port) { should == 7474 }
|
10
|
+
its(:path) { should == '' }
|
11
|
+
its(:log_level) { should == 'INFO' }
|
12
|
+
|
13
|
+
context "in test environment" do
|
14
|
+
subject { Architect4r::Core::Configuration.new(:environment => :test) }
|
15
|
+
|
16
|
+
its(:host) { should == 'localhost' }
|
17
|
+
its(:port) { should == 7475 }
|
18
|
+
its(:path) { should == '' }
|
19
|
+
its(:log_level) { should == 'OFF' }
|
20
|
+
end
|
21
|
+
|
22
|
+
context "in production environment" do
|
23
|
+
subject { Architect4r::Core::Configuration.new(:environment => :production) }
|
24
|
+
|
25
|
+
its(:host) { should == 'localhost' }
|
26
|
+
its(:port) { should == 7474 }
|
27
|
+
its(:path) { should == '' }
|
28
|
+
its(:log_level) { should == 'WARNING' }
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "provided by hash" do
|
34
|
+
subject { Architect4r::Core::Configuration.new(:environment => :development, :config => { :host => 'neo4j.local', :port => '80', :path => 'dev', :log_level => 'ERROR', :log_file => '/tmp/neo.log' }) }
|
35
|
+
|
36
|
+
its(:host) { should == 'neo4j.local' }
|
37
|
+
its(:port) { should == 80 }
|
38
|
+
its(:path) { should == 'dev' }
|
39
|
+
its(:log_level) { should == 'ERROR' }
|
40
|
+
its(:log_file) { should == '/tmp/neo.log' }
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "provided by a custom config file" do
|
45
|
+
subject { Architect4r::Core::Configuration.new(:environment => :staging, :config => File.join(Dir.pwd, 'spec', 'fixtures', 'architect4r.yml')) }
|
46
|
+
|
47
|
+
its(:host) { should == 'staging.dev' }
|
48
|
+
its(:port) { should == 8080 }
|
49
|
+
its(:path) { should == 'my_neo_instance' }
|
50
|
+
its(:log_level) { should == 'WARNING' }
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Architect4r::Server do
|
4
|
+
|
5
|
+
subject { TEST_SERVER }
|
6
|
+
|
7
|
+
describe :execute_cypher do
|
8
|
+
|
9
|
+
it "should return an array of nodes" do
|
10
|
+
# nodes
|
11
|
+
#results = subject.execute_cypher("start root = (#{subject.root_node.id}) match (root)-[r:model_root]->(x) return r")
|
12
|
+
pending
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should return an array of relationships" do
|
16
|
+
# relations
|
17
|
+
#results = subject.find_by_cypher("start root = (#{subject.root_node.id}) match (root)-[r:model_root]->(x) return r")
|
18
|
+
pending
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should the data unprocessed" do
|
22
|
+
#results = subject.execute_cypher("start node = (0) return node,node.name?")
|
23
|
+
#results.should_not be_empty
|
24
|
+
pending
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Architect4r::Server do
|
4
|
+
|
5
|
+
subject { TEST_SERVER }
|
6
|
+
|
7
|
+
it "should create a node" do
|
8
|
+
result = subject.create_node({ 'name' => 'My test node', 'friends' => 13 })
|
9
|
+
result.should be_a(Hash)
|
10
|
+
result['self'].should be_a(String)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should get a node" do
|
14
|
+
result = subject.get_node(0)
|
15
|
+
result.should be_a(Hash)
|
16
|
+
result['self'].should be_a(String)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should delete a node" do
|
20
|
+
# Create a node which can be deleted
|
21
|
+
node = subject.create_node({ 'test' => 'test' })
|
22
|
+
node.should be_a(Hash)
|
23
|
+
|
24
|
+
# Delete the node
|
25
|
+
subject.delete_node(node['self'])
|
26
|
+
|
27
|
+
# Check if it still exists
|
28
|
+
subject.get_node(node['self']).should be_nil
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should update a nodes properties" do
|
32
|
+
# Create a node which can be deleted
|
33
|
+
original_node = subject.create_node({ 'test1' => 'test', 'test2' => 'hello' })
|
34
|
+
original_node.should be_a(Hash)
|
35
|
+
|
36
|
+
# Update some attributes
|
37
|
+
result = subject.update_node(original_node['self'], { 'test1' => 'world', 'test3' => 'word'})
|
38
|
+
result.should be_true
|
39
|
+
|
40
|
+
# check result
|
41
|
+
changed_node = subject.get_node(original_node['self'])
|
42
|
+
changed_node['data']['test1'].should == 'world'
|
43
|
+
changed_node['data'].has_key?('test2').should be_false
|
44
|
+
changed_node['data']['test3'].should == 'word'
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Architect4r::Server do
|
4
|
+
|
5
|
+
subject { TEST_SERVER }
|
6
|
+
|
7
|
+
before(:all) do
|
8
|
+
# Lets create two nodes we can work with
|
9
|
+
@node1 = subject.create_node({ 'name' => 'first test node' })
|
10
|
+
@node2 = subject.create_node({ 'name' => 'second test node' })
|
11
|
+
end
|
12
|
+
|
13
|
+
after(:all) do
|
14
|
+
# Lets create two nodes we can work with
|
15
|
+
subject.delete_node(@node1)
|
16
|
+
subject.delete_node(@node2)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should create and delete a new relationship" do
|
20
|
+
result = subject.create_relationship(@node1, @node2, 'friendship', { 'reason' => 'Because I really like you!' })
|
21
|
+
result.should be_a(Hash)
|
22
|
+
subject.delete_relationship(result)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should allow creating relationships without properties" do
|
26
|
+
result = subject.create_relationship(@node1, @node2, 'friendship')
|
27
|
+
result.should be_a(Hash)
|
28
|
+
subject.delete_relationship(result)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should allow filtering relationships by direction" do
|
32
|
+
# create test nodes
|
33
|
+
n1 = subject.create_node({ 'name' => 'first test node' })
|
34
|
+
n2 = subject.create_node({ 'name' => 'second test node' })
|
35
|
+
|
36
|
+
# create relationships
|
37
|
+
subject.create_relationship(n1, n2, 'relation')
|
38
|
+
subject.create_relationship(n1, n2, 'relation2')
|
39
|
+
subject.create_relationship(n2, n1, 'relation3')
|
40
|
+
|
41
|
+
# test node direction
|
42
|
+
subject.get_node_relationships(n1).size.should == 3
|
43
|
+
subject.get_node_relationships(n1, :all).size.should == 3
|
44
|
+
subject.get_node_relationships(n1, :outgoing).size.should == 2
|
45
|
+
subject.get_node_relationships(n1, :incoming).size.should == 1
|
46
|
+
|
47
|
+
# test relation type
|
48
|
+
subject.get_node_relationships(n1, :all, 'relation').size.should == 1
|
49
|
+
subject.get_node_relationships(n1, :outgoing, 'relation').size.should == 1
|
50
|
+
subject.get_node_relationships(n1, :incoming, 'relation').size.should == 0
|
51
|
+
subject.get_node_relationships(n1, :all, 'relation', 'relation2').size.should == 2
|
52
|
+
|
53
|
+
# Clean up
|
54
|
+
subject.delete_node(n1)
|
55
|
+
subject.delete_node(n2)
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should retrieve all relationships" do
|
59
|
+
subject.get_node_relationships(0).should be_a(Array)
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should load a relationship" do
|
63
|
+
node = subject.create_node({ 'name' => 'A test node' })
|
64
|
+
rel = subject.create_relationship(node, node, 'test', { 'some' => 'data' })
|
65
|
+
data = subject.get_relationship(rel)
|
66
|
+
data.should be_a(Hash)
|
67
|
+
data['data']['some'].should == 'data'
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should update a nodes properties" do
|
71
|
+
node = subject.create_node({ 'name' => 'A test node' })
|
72
|
+
original_rel = subject.create_relationship(node, node, 'self-reference', { 'note' => 'Some random note', 'obsolete' => '1' })
|
73
|
+
original_rel.should be_a(Hash)
|
74
|
+
|
75
|
+
# Update some attributes
|
76
|
+
result = subject.update_relationship(original_rel, { 'note' => 'Some changed note', 'highlight' => 'note'})
|
77
|
+
result.should be_true
|
78
|
+
|
79
|
+
# check result
|
80
|
+
changed_rel = subject.get_relationship(original_rel)
|
81
|
+
changed_rel['data']['note'].should == 'Some changed note'
|
82
|
+
changed_rel['data'].has_key?('obsolete').should be_false
|
83
|
+
changed_rel['data']['highlight'].should == 'note'
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should know about all relationship types" do
|
87
|
+
node = subject.create_node({ 'name' => 'A test node' })
|
88
|
+
subject.create_relationship(node, node, 'self-reference')
|
89
|
+
subject.get_relationship_types.should include('self-reference')
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|