neomirror 0.0.1 → 0.0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ab74e8c31f0b8ea8c07d4fdb8b454f7f1823c37b
4
- data.tar.gz: 465c276d4c825cf27d2bf38decb2955287958669
3
+ metadata.gz: 91d4c19efa74a09c812dfbffc777ebb884f3289c
4
+ data.tar.gz: 06e831911c25f4022c41038d5af73d1ca20085e6
5
5
  SHA512:
6
- metadata.gz: 3d952da8b37fd49abd4cf9207992319a39c30f428cda953749e5d1c4cde0d5ece314edb849c39f472a44276c079b260221198ce501b472d8e5578165820a1034
7
- data.tar.gz: 0e96b273a81c88048c053e8d450dd40b949845e306b5e31779b37f869bc2863337c3932776ec9e2d974087bb789ac84a866b7237cc58a6f941e42a80d25bd0b8
6
+ metadata.gz: 171520bb5e991c0605a03d5adb5d8774e16cf31bc494c8f8e4beb635505af69038be2881831a84d78bd2b7b1610897d7d61a7f8956c1b05e0caeb59f9118fd2b
7
+ data.tar.gz: 13de4c46626309fd61fc6046156a405909e9805a67039ae0a7f8804fe43d1d063338f9b50b904e2b5846e1bd93cf1738ad3b30dde3dcf8c3cecf8e6bf1dce8c9
data/README.md CHANGED
@@ -163,7 +163,20 @@ class Staff < ActiveRecord::Base
163
163
  end
164
164
  ```
165
165
 
166
- Even possible reflect model as node (vertex) and relation(s) (edge). But it is probably not needed.
166
+ Even possible reflect model as node (vertex) and relation(s) (edge).
167
+
168
+ ```ruby
169
+ class Group < ActiveRecord::Base
170
+ include Neomirror::Node
171
+ include Neomirror::Relationship
172
+
173
+ belongs_to :parent, class_name: 'Group', foreign_key: :parent_id
174
+
175
+ mirror_neo_node
176
+
177
+ mirror_neo_relationship start_node: :self, end_node: :parent, type: :CHILD_OF
178
+ end
179
+ ```
167
180
 
168
181
  ## Compatibility
169
182
 
@@ -171,12 +184,12 @@ It is possible to use it outside of ActiveRecord (there is no dependency). Just
171
184
 
172
185
  Also specify primary key attribute if it is differ from `id` and class don't `respond_to? :primary_key` method.
173
186
 
174
- ```
187
+ ```ruby
175
188
  class Postcode
176
189
  attr_accessor :code
177
190
  include Neomirror::Node
178
191
 
179
- self.node_primary_key = :code
192
+ self.neo_primary_key = :code
180
193
 
181
194
  mirror_neo_node
182
195
  end
@@ -23,10 +23,10 @@ module Neomirror::Node
23
23
  @neo_mirror
24
24
  end
25
25
 
26
- def node_primary_key
27
- @node_primary_key ||= self.respond_to?(:primary_key) ? self.__send__(:primary_key) : :id
26
+ def neo_primary_key
27
+ @neo_primary_key ||= self.respond_to?(:primary_key) ? self.__send__(:primary_key) : :id
28
28
  end
29
- attr_writer :node_primary_key
29
+ attr_writer :neo_primary_key
30
30
  end
31
31
 
32
32
  def neo_node
@@ -36,20 +36,17 @@ module Neomirror::Node
36
36
  alias_method :node, :neo_node
37
37
 
38
38
  def neo_node_properties
39
- neo_node_properties = ::Hash.new
40
- neo_node_properties[:id] = self.__send__(self.class.node_primary_key)
39
+ hash = { :id => self.__send__(self.class.neo_primary_key) }
41
40
  if self.class.neo_mirror && self.class.neo_mirror[:properties]
42
- self.class.neo_mirror[:properties].each do |property, rule|
43
- neo_node_properties[property] = rule.call(self)
44
- end
41
+ self.class.neo_mirror[:properties].each { |property, rule| hash[property] = rule.call(self) }
45
42
  end
46
- neo_node_properties
43
+ hash
47
44
  end
48
45
 
49
46
  def find_neo_node
50
47
  raise "Couldn't find neo_node declaration" unless self.class.neo_mirror
51
48
  label = self.class.neo_mirror[:label]
52
- id = self.__send__(self.class.node_primary_key)
49
+ id = self.__send__(self.class.neo_primary_key)
53
50
  return nil unless node = ::Neomirror.neo.find_nodes_labeled(label, { :id => id }).first
54
51
  @neo_node = ::Neography::Node.load(node, ::Neomirror.neo)
55
52
  end
@@ -76,8 +73,4 @@ module Neomirror::Node
76
73
  ::Neomirror.neo.delete_node!(@neo_node)
77
74
  true
78
75
  end
79
-
80
- def neo_node_to_cypher
81
- ":#{self.class.neo_mirror[:label]} {id:#{self.__send__(self.class.node_primary_key)}}"
82
- end
83
76
  end
@@ -30,11 +30,19 @@ module Neomirror::Relationship
30
30
  raise ArgumentError, "Options :start_node and :end_node are mandatory" unless m[:start_node] && m[:end_node]
31
31
  m[:start_node] = m[:start_node].to_sym
32
32
  m[:end_node] = m[:end_node].to_sym
33
- m[:type] = (m[:type] ? m[:type] : self.name.gsub(/^.*::/, '').gsub(/([a-z\d])([A-Z])/, '\1_\2').upcase).to_sym
33
+ class_name = self.name.gsub(/^.*::/, '').gsub(/([a-z\d])([A-Z])/, '\1_\2')
34
+ m[:type] = (m[:type] ? m[:type] : class_name.upcase).to_sym
34
35
  m[:properties] = Neomirror::PropertyCollector.new(&block).properties if block_given?
35
36
  m[:if] = m[:if].to_proc if m[:if]
37
+ m[:index_name] = "#{m[:start_node] == :self ? class_name.downcase : m[:start_node]}_#{m[:type]}_#{m[:end_node] == :self ? class_name.downcase : m[:end_node]}"
38
+ ::Neomirror.neo.create_relationship_index(m[:index_name])
36
39
  rel_mirrors << m
37
40
  end
41
+
42
+ def neo_primary_key
43
+ @neo_primary_key ||= self.respond_to?(:primary_key) ? self.__send__(:primary_key) : :id
44
+ end
45
+ attr_writer :neo_primary_key
38
46
  end
39
47
 
40
48
  def neo_relationship(partial_mirror = nil)
@@ -45,7 +53,7 @@ module Neomirror::Relationship
45
53
  def neo_relationship_properties(partial_mirror = nil)
46
54
  raise "Couldn't find neo_relationship declaration" unless rel_mirror = self.class.rel_mirror(partial_mirror)
47
55
  return nil unless rel_mirror[:properties]
48
- rel_mirror[:properties].reduce({}) { |h, (property, rule)| h[property] = rule.call(self); h }
56
+ rel_mirror[:properties].reduce({}) { |hash, (property, rule)| hash[property] = rule.call(self); hash }
49
57
  end
50
58
 
51
59
  def neo_relationship_must_exist?(partial_mirror = nil)
@@ -55,25 +63,30 @@ module Neomirror::Relationship
55
63
 
56
64
  def find_neo_relationship(partial_mirror = nil)
57
65
  raise "Couldn't find neo_relationship declaration" unless rel_mirror = self.class.rel_mirror(partial_mirror)
58
- return nil unless (m1 = self.__send__(rel_mirror[:start_node])) && (m2 = self.__send__(rel_mirror[:end_node])) &&
59
- (rel = ::Neomirror.neo.execute_query("MATCH (#{m1.neo_node_to_cypher})-[r:#{rel_mirror[:type]}]->(#{m2.neo_node_to_cypher}) RETURN r")["data"].first)
66
+ return nil unless rel = ::Neomirror.neo.get_relationship_index(rel_mirror[:index_name], :id, self.__send__(self.class.neo_primary_key))
60
67
  @neo_rel = ::Neography::Relationship.load(rel, ::Neomirror.neo)
61
68
  end
62
69
 
63
70
  def create_neo_relationship(partial_mirror = nil)
64
71
  raise "Couldn't find neo_relationship declaration" unless rel_mirror = self.class.rel_mirror(partial_mirror)
65
- return nil unless self.__send__(rel_mirror[:start_node]) && self.__send__(rel_mirror[:end_node]) &&
72
+ return nil unless (m1 = related_object(rel_mirror[:start_node])) && (m2 = related_object(rel_mirror[:end_node])) &&
66
73
  neo_relationship_must_exist?(rel_mirror)
67
- ::Neography::Relationship.create(rel_mirror[:type], self.__send__(rel_mirror[:start_node]).neo_node,
68
- self.__send__(rel_mirror[:end_node]).neo_node, neo_relationship_properties(rel_mirror))
74
+ @neo_rel = ::Neography::Relationship.create(rel_mirror[:type], m1.neo_node, m2.neo_node, neo_relationship_properties(rel_mirror))
75
+ ::Neomirror.neo.add_relationship_to_index(rel_mirror[:index_name], :id, self.__send__(self.class.neo_primary_key), @neo_rel)
76
+ @neo_rel
77
+ end
78
+
79
+ def related_object(method_name)
80
+ method_name == :self ? self : self.__send__(method_name)
69
81
  end
70
82
 
71
83
  def update_neo_relationship(partial_mirror = nil)
72
84
  raise "Couldn't find neo_relationship declaration" unless rel_mirror = self.class.rel_mirror(partial_mirror)
73
85
  if find_neo_relationship(rel_mirror)
74
- if neo_relationship_must_exist?(rel_mirror)
86
+ if related_object(rel_mirror[:start_node]) && related_object(rel_mirror[:end_node]) && neo_relationship_must_exist?(rel_mirror)
75
87
  ::Neomirror.neo.reset_relationship_properties(@neo_rel, neo_relationship_properties(rel_mirror))
76
88
  else
89
+ ::Neomirror.neo.remove_relationship_from_index(rel_mirror[:index_name], :id, self.__send__(self.class.neo_primary_key), @neo_rel)
77
90
  ::Neomirror.neo.delete_relationship(@neo_rel)
78
91
  end
79
92
  else
@@ -83,7 +96,10 @@ module Neomirror::Relationship
83
96
 
84
97
  def destroy_neo_relationship(partial_mirror = nil)
85
98
  raise "Couldn't find neo_relationship declaration" unless rel_mirror = self.class.rel_mirror(partial_mirror)
86
- ::Neomirror.neo.delete_relationship(@neo_rel) if find_neo_relationship(rel_mirror)
99
+ if find_neo_relationship(rel_mirror)
100
+ ::Neomirror.neo.remove_relationship_from_index(rel_mirror[:index_name], :id, self.__send__(self.class.neo_primary_key), @neo_rel)
101
+ ::Neomirror.neo.delete_relationship(@neo_rel)
102
+ end
87
103
  end
88
104
 
89
105
  def create_neo_relationships
@@ -1,3 +1,3 @@
1
1
  module Neomirror
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -0,0 +1,25 @@
1
+ require "spec_helper"
2
+
3
+ describe Neomirror do
4
+ describe "Reflection of model as node and relation" do
5
+ let(:group) { create(:group) }
6
+ let(:child_group) { create(:group, parent: group) }
7
+
8
+ it "creates neo4j nodes" do
9
+ group.find_neo_node.should be_a Neography::Node
10
+ child_group.find_neo_node.should be_a Neography::Node
11
+ end
12
+
13
+ it "creates neo4j relation with object itself" do
14
+ group.find_neo_relationship.should be_nil
15
+ child_group.find_neo_relationship.should be_a Neography::Relationship
16
+ Neomirror.neo.execute_query("MATCH (:Group {id: #{child_group.id}})-[r:CHILD_OF]->(:Group {id: #{group.id}}) RETURN r")["data"].first.should be_present
17
+ end
18
+
19
+ it "destroys relationship on update if actual relationship disappears (both nodes must be present)" do
20
+ child_group.update(parent_id: nil)
21
+ child_group.find_neo_relationship.should be_nil
22
+ Neomirror.neo.execute_query("MATCH (:Group {id: #{child_group.id}})-[r:CHILD_OF]->(:Group {id: #{group.id}}) RETURN r")["data"].first.should be_nil
23
+ end
24
+ end
25
+ end
@@ -61,7 +61,7 @@ describe Neomirror::Node do
61
61
  end
62
62
  end
63
63
 
64
- describe ".node_primary_key" do
64
+ describe ".neo_primary_key" do
65
65
  let(:postcode) { Postcode.new.tap { |p| p.code = 'ABC' } }
66
66
 
67
67
  it "sets custom primary key" do
@@ -69,10 +69,4 @@ describe Neomirror::Node do
69
69
  postcode.neo_node.id.should == 'ABC'
70
70
  end
71
71
  end
72
-
73
- describe "#neo_node_to_cypher" do
74
- it "represents node as cypher element" do
75
- user.neo_node_to_cypher.should == ":User {id:#{user.id}}"
76
- end
77
- end
78
72
  end
@@ -92,6 +92,13 @@ describe Neomirror::Relationship do
92
92
  staff.find_neo_relationship(type: :VISITOR_OF).should be_nil
93
93
  staff.find_neo_relationship(type: :MANAGER_OF).should be_a Neography::Relationship
94
94
  end
95
+
96
+ it "destroys relationship on update if actual relationship disappears (both nodes must be present)" do
97
+ staff_of_premises
98
+ Neomirror.neo.execute_query("MATCH (:User {id: #{user.id}})-[r:STAFF_OF]->(:Premises {id: #{premises.id}}) RETURN r")["data"].first.should be_present
99
+ staff_of_premises.update(premises_id: nil)
100
+ Neomirror.neo.execute_query("MATCH (:User {id: #{user.id}})-[r:STAFF_OF]->(:Premises {id: #{premises.id}}) RETURN r")["data"].first.should be_nil
101
+ end
95
102
  end
96
103
 
97
104
  describe "#destroy_neo_relationship" do
data/spec/spec_helper.rb CHANGED
@@ -8,7 +8,7 @@ ENV['NEO_URL'] ||= "http://127.0.0.1:7474"
8
8
  Neomirror.connection = Neography::Rest.new(ENV['NEO_URL'])
9
9
 
10
10
  ActiveRecord::Base.connection.execute('CREATE TABLE premises ("id" INTEGER PRIMARY KEY NOT NULL)')
11
- ActiveRecord::Base.connection.execute('CREATE TABLE groups ("id" INTEGER PRIMARY KEY NOT NULL)')
11
+ ActiveRecord::Base.connection.execute('CREATE TABLE groups ("id" INTEGER PRIMARY KEY NOT NULL, "parent_id" INTEGER DEFAULT NULL)')
12
12
  ActiveRecord::Base.connection.execute('CREATE TABLE users ("id" INTEGER PRIMARY KEY NOT NULL, "name" varchar(255) NOT NULL)')
13
13
  ActiveRecord::Base.connection.execute('CREATE TABLE memberships ("id" INTEGER PRIMARY KEY NOT NULL, "premises_id" INTEGER DEFAULT NULL, "group_id" INTEGER DEFAULT NULL)')
14
14
  ActiveRecord::Base.connection.execute('CREATE TABLE staff ("id" INTEGER PRIMARY KEY NOT NULL, "user_id" INTEGER DEFAULT NULL, "premises_id" INTEGER DEFAULT NULL, "group_id" INTEGER DEFAULT NULL, "roles" TEXT)')
@@ -1,9 +1,10 @@
1
1
  class Group < ActiveRecord::Base
2
2
  include Neomirror::Node
3
+ include Neomirror::Relationship
3
4
  has_many :memberships
4
- has_many :premises, through: :memberships
5
5
  has_many :staff
6
- has_many :users, through: :staff
6
+ belongs_to :parent, class_name: 'Group', foreign_key: :parent_id
7
7
 
8
8
  mirror_neo_node
9
+ mirror_neo_relationship start_node: :self, end_node: :parent, type: :CHILD_OF
9
10
  end
@@ -2,7 +2,7 @@ class Postcode
2
2
  attr_accessor :code
3
3
  include Neomirror::Node
4
4
 
5
- self.node_primary_key = :code
5
+ self.neo_primary_key = :code
6
6
 
7
7
  mirror_neo_node
8
8
  end
@@ -1,9 +1,7 @@
1
1
  class Premises < ActiveRecord::Base
2
2
  include Neomirror::Node
3
3
  has_many :memberships
4
- has_many :groups, through: :memberships
5
4
  has_many :staff
6
- has_many :users, through: :staff
7
5
 
8
6
  mirror_neo_node
9
7
  end
data/spec/support/user.rb CHANGED
@@ -1,8 +1,6 @@
1
1
  class User < ActiveRecord::Base
2
2
  include Neomirror::Node
3
3
  has_many :staff
4
- has_many :premises, through: :staff
5
- has_many :groups, through: :staff
6
4
 
7
5
  mirror_neo_node do
8
6
  property :name
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: neomirror
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Avoyants
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-06-30 00:00:00.000000000 Z
11
+ date: 2014-07-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: neography
@@ -162,6 +162,7 @@ files:
162
162
  - spec/factories/premises.rb
163
163
  - spec/factories/staff.rb
164
164
  - spec/factories/user.rb
165
+ - spec/neomirror/neomirror_spec.rb
165
166
  - spec/neomirror/node_spec.rb
166
167
  - spec/neomirror/relationship_spec.rb
167
168
  - spec/spec_helper.rb
@@ -202,6 +203,7 @@ test_files:
202
203
  - spec/factories/premises.rb
203
204
  - spec/factories/staff.rb
204
205
  - spec/factories/user.rb
206
+ - spec/neomirror/neomirror_spec.rb
205
207
  - spec/neomirror/node_spec.rb
206
208
  - spec/neomirror/relationship_spec.rb
207
209
  - spec/spec_helper.rb