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.
- 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
|