architect4r 0.3.2

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.
Files changed (110) hide show
  1. data/.gitignore +4 -0
  2. data/Gemfile +4 -0
  3. data/Gemfile.lock +53 -0
  4. data/Guardfile +10 -0
  5. data/License +20 -0
  6. data/README.md +62 -0
  7. data/Rakefile +40 -0
  8. data/ReleaseNotes.md +33 -0
  9. data/Roadmap.md +31 -0
  10. data/Specs.md +21 -0
  11. data/architect4r.gemspec +31 -0
  12. data/lib/architect4r.rb +66 -0
  13. data/lib/architect4r/adapters/carrier_wave.rb +64 -0
  14. data/lib/architect4r/core/configuration.rb +148 -0
  15. data/lib/architect4r/core/cypher_methods.rb +47 -0
  16. data/lib/architect4r/core/management_methods.rb +129 -0
  17. data/lib/architect4r/core/node_methods.rb +73 -0
  18. data/lib/architect4r/core/relationship_methods.rb +82 -0
  19. data/lib/architect4r/generic_node.rb +7 -0
  20. data/lib/architect4r/has_node.rb +80 -0
  21. data/lib/architect4r/instance_manager.rb +47 -0
  22. data/lib/architect4r/model/callbacks.rb +19 -0
  23. data/lib/architect4r/model/connection.rb +29 -0
  24. data/lib/architect4r/model/links_query_interface.rb +23 -0
  25. data/lib/architect4r/model/node.rb +117 -0
  26. data/lib/architect4r/model/persistency.rb +95 -0
  27. data/lib/architect4r/model/properties.rb +166 -0
  28. data/lib/architect4r/model/queries.rb +38 -0
  29. data/lib/architect4r/model/relationship.rb +105 -0
  30. data/lib/architect4r/model/relationships.rb +16 -0
  31. data/lib/architect4r/model/validations.rb +11 -0
  32. data/lib/architect4r/server.rb +96 -0
  33. data/lib/architect4r/version.rb +3 -0
  34. data/spec/architect4r_spec.rb +9 -0
  35. data/spec/core/configuration_spec.rb +54 -0
  36. data/spec/core/cypher_methods_spec.rb +29 -0
  37. data/spec/core/node_methods_spec.rb +47 -0
  38. data/spec/core/relationship_methods_spec.rb +92 -0
  39. data/spec/fixtures/architect4r.yml +21 -0
  40. data/spec/fixtures/graph.db.default/active_tx_log +1 -0
  41. data/spec/fixtures/graph.db.default/index/lucene-store.db +0 -0
  42. data/spec/fixtures/graph.db.default/index/lucene.log.1 +0 -0
  43. data/spec/fixtures/graph.db.default/index/lucene.log.active +0 -0
  44. data/spec/fixtures/graph.db.default/index/lucene.log.v0 +0 -0
  45. data/spec/fixtures/graph.db.default/index/lucene.log.v1 +0 -0
  46. data/spec/fixtures/graph.db.default/index/lucene.log.v2 +0 -0
  47. data/spec/fixtures/graph.db.default/lock +0 -0
  48. data/spec/fixtures/graph.db.default/messages.log +183 -0
  49. data/spec/fixtures/graph.db.default/neostore +0 -0
  50. data/spec/fixtures/graph.db.default/neostore.id +0 -0
  51. data/spec/fixtures/graph.db.default/neostore.nodestore.db +0 -0
  52. data/spec/fixtures/graph.db.default/neostore.nodestore.db.id +0 -0
  53. data/spec/fixtures/graph.db.default/neostore.propertystore.db +0 -0
  54. data/spec/fixtures/graph.db.default/neostore.propertystore.db.arrays +0 -0
  55. data/spec/fixtures/graph.db.default/neostore.propertystore.db.arrays.id +0 -0
  56. data/spec/fixtures/graph.db.default/neostore.propertystore.db.id +0 -0
  57. data/spec/fixtures/graph.db.default/neostore.propertystore.db.index +0 -0
  58. data/spec/fixtures/graph.db.default/neostore.propertystore.db.index.id +0 -0
  59. data/spec/fixtures/graph.db.default/neostore.propertystore.db.index.keys +0 -0
  60. data/spec/fixtures/graph.db.default/neostore.propertystore.db.index.keys.id +0 -0
  61. data/spec/fixtures/graph.db.default/neostore.propertystore.db.strings +0 -0
  62. data/spec/fixtures/graph.db.default/neostore.propertystore.db.strings.id +0 -0
  63. data/spec/fixtures/graph.db.default/neostore.relationshipstore.db +0 -0
  64. data/spec/fixtures/graph.db.default/neostore.relationshipstore.db.id +0 -0
  65. data/spec/fixtures/graph.db.default/neostore.relationshiptypestore.db +0 -0
  66. data/spec/fixtures/graph.db.default/neostore.relationshiptypestore.db.id +0 -0
  67. data/spec/fixtures/graph.db.default/neostore.relationshiptypestore.db.names +0 -0
  68. data/spec/fixtures/graph.db.default/neostore.relationshiptypestore.db.names.id +0 -0
  69. data/spec/fixtures/graph.db.default/nioneo_logical.log.1 +0 -0
  70. data/spec/fixtures/graph.db.default/nioneo_logical.log.active +0 -0
  71. data/spec/fixtures/graph.db.default/tm_tx_log.1 +0 -0
  72. data/spec/fixtures/graph.db.default/upgrade_backup/active_tx_log +1 -0
  73. data/spec/fixtures/graph.db.default/upgrade_backup/messages.log +142 -0
  74. data/spec/fixtures/graph.db.default/upgrade_backup/neostore +0 -0
  75. data/spec/fixtures/graph.db.default/upgrade_backup/neostore.id +0 -0
  76. data/spec/fixtures/graph.db.default/upgrade_backup/neostore.nodestore.db +0 -0
  77. data/spec/fixtures/graph.db.default/upgrade_backup/neostore.nodestore.db.id +0 -0
  78. data/spec/fixtures/graph.db.default/upgrade_backup/neostore.propertystore.db +0 -0
  79. data/spec/fixtures/graph.db.default/upgrade_backup/neostore.propertystore.db.arrays +0 -0
  80. data/spec/fixtures/graph.db.default/upgrade_backup/neostore.propertystore.db.arrays.id +0 -0
  81. data/spec/fixtures/graph.db.default/upgrade_backup/neostore.propertystore.db.id +0 -0
  82. data/spec/fixtures/graph.db.default/upgrade_backup/neostore.propertystore.db.index +0 -0
  83. data/spec/fixtures/graph.db.default/upgrade_backup/neostore.propertystore.db.index.id +0 -0
  84. data/spec/fixtures/graph.db.default/upgrade_backup/neostore.propertystore.db.index.keys +0 -0
  85. data/spec/fixtures/graph.db.default/upgrade_backup/neostore.propertystore.db.index.keys.id +0 -0
  86. data/spec/fixtures/graph.db.default/upgrade_backup/neostore.propertystore.db.strings +0 -0
  87. data/spec/fixtures/graph.db.default/upgrade_backup/neostore.propertystore.db.strings.id +0 -0
  88. data/spec/fixtures/graph.db.default/upgrade_backup/neostore.relationshipstore.db +0 -0
  89. data/spec/fixtures/graph.db.default/upgrade_backup/neostore.relationshipstore.db.id +0 -0
  90. data/spec/fixtures/graph.db.default/upgrade_backup/neostore.relationshiptypestore.db +0 -0
  91. data/spec/fixtures/graph.db.default/upgrade_backup/neostore.relationshiptypestore.db.id +0 -0
  92. data/spec/fixtures/graph.db.default/upgrade_backup/neostore.relationshiptypestore.db.names +0 -0
  93. data/spec/fixtures/graph.db.default/upgrade_backup/neostore.relationshiptypestore.db.names.id +0 -0
  94. data/spec/fixtures/graph.db.default/upgrade_backup/nioneo_logical.log.active +0 -0
  95. data/spec/fixtures/graph.db.default/upgrade_backup/nioneo_logical.log.v0 +0 -0
  96. data/spec/fixtures/graph.db.default/upgrade_backup/nioneo_logical.log.v1 +0 -0
  97. data/spec/fixtures/graph.db.default/upgrade_backup/nioneo_logical.log.v2 +0 -0
  98. data/spec/fixtures/graph.db.default/upgrade_backup/tm_tx_log.1 +0 -0
  99. data/spec/has_node_spec.rb +87 -0
  100. data/spec/model/links_query_interface_spec.rb +22 -0
  101. data/spec/model/links_spec.rb +26 -0
  102. data/spec/model/node_spec.rb +48 -0
  103. data/spec/model/persistency_spec.rb +98 -0
  104. data/spec/model/properties_spec.rb +165 -0
  105. data/spec/model/queries_spec.rb +50 -0
  106. data/spec/model/relationship_spec.rb +63 -0
  107. data/spec/model/validations_spec.rb +31 -0
  108. data/spec/server_spec.rb +33 -0
  109. data/spec/spec_helper.rb +115 -0
  110. 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,16 @@
1
+ module Architect4r
2
+ module Model
3
+ module Relationships
4
+ extend ActiveSupport::Concern
5
+
6
+ module InstanceMethods
7
+
8
+ def links
9
+ @links_query_interface = LinksQueryInterface.new(self)
10
+ end
11
+
12
+ end
13
+
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,11 @@
1
+ module Architect4r
2
+ module Model
3
+ module Validations
4
+ extend ActiveSupport::Concern
5
+ include ActiveModel::Validations
6
+
7
+ # just in case that we want to add some more sugar
8
+
9
+ end
10
+ end
11
+ 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,3 @@
1
+ module Architect4r
2
+ VERSION = "0.3.2"
3
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ describe Architect4r do
4
+
5
+ it 'should return correct version string' do
6
+ Architect4r.version.should == "Architect4r version #{Architect4r::VERSION}"
7
+ end
8
+
9
+ 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