active_node 0.2 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 009873db2285d63fc20017f441525c2356dec8b9
4
- data.tar.gz: 59aab9d43e21d1fb9376ddde89feecfdfe9c82f9
3
+ metadata.gz: 2d31741bd5a8017c8fbc4a49a3494d5d4622e6b0
4
+ data.tar.gz: 4fe415aecee9215b53ab04a5e5f031c94fcca1b8
5
5
  SHA512:
6
- metadata.gz: 506c0696d7db079e83d2e36ddf00be5dc3e0e1088c037755f6d3ad0205faf50a89a6def731093dbf66df5dc3ddfa13b853eb5e4bfe748c2f99550465e445942b
7
- data.tar.gz: 5594c6ce98652b3549369628bd6fb33e3f7eab56199e69e7a4c23d6b0bab9f7a421db842c1fe313593f97352653c7cab8ea08298fc2db1be63c83d6ba3f255b8
6
+ metadata.gz: 740435b0a5eceb85a52c8c98a0a2068b26c1e17cfb5dde3341bb6075c9f6717478a811e564c48cf1ae2460f7131bea2ef34c8bf2713b3e5a9eb04fbe28255304
7
+ data.tar.gz: ec10984057ef8c34ccfd19e4a1b83359db40b121e02e5d5b400618c78ff565c6f198b67ce8329c1f9f9a2f673dc6969bbedd82f373f3a69cf7a452cf73c44f1d
data/.travis.yml CHANGED
@@ -1,4 +1,4 @@
1
- script: "bundle exec rake neo4j:install['enterprise','1.9.3'] neo4j:start spec --trace"
1
+ script: "bundle exec rake neo4j:install['enterprise','2.0.0'] neo4j:start spec --trace"
2
2
  language: ruby
3
3
  rvm:
4
4
  - 1.9.3
data/lib/active_node.rb CHANGED
@@ -9,6 +9,7 @@ module ActiveNode
9
9
  autoload :Validations
10
10
  autoload :Reflection
11
11
  autoload :VERSION
12
+ autoload :Neo
12
13
 
13
14
  eager_autoload do
14
15
  autoload :ActiveNodeError, 'active_node/errors'
@@ -58,13 +58,14 @@ module ActiveNode
58
58
  def save
59
59
  return unless @dirty
60
60
  #delete all relations missing in new target
61
- owner.node.rels(reflection.type).send(reflection.direction).each do |rel|
62
- rel.del unless ids_reader.include? rel.other_node(owner.node).neo_id.to_i
61
+ node = Neography::Node.load(owner.id)
62
+ node.rels(reflection.type).send(reflection.direction).each do |rel|
63
+ rel.del unless ids_reader.include? rel.other_node(node).neo_id.to_i
63
64
  end
64
- original_target = owner.node.send(reflection.direction, reflection.type)
65
+ original_target = node.send(reflection.direction, reflection.type)
65
66
  original_target_ids = original_target.map(&:neo_id).map(&:to_i)
66
67
  #add relations missing in old target
67
- target_each { |n| original_target << n.node unless original_target_ids.include? n.id }
68
+ target_each { |n| original_target << n.id unless original_target_ids.include? n.id }
68
69
  end
69
70
  end
70
71
  end
@@ -6,7 +6,7 @@ module ActiveNode
6
6
  end
7
7
 
8
8
  def target_each
9
- yield target
9
+ yield target if target.present?
10
10
  end
11
11
 
12
12
  def ids_reader
@@ -18,7 +18,7 @@ module ActiveNode
18
18
  end
19
19
 
20
20
  def id_writer(id)
21
- writer(klass.find(id.to_i))
21
+ writer(id.blank? ? nil : klass.find(id.to_i))
22
22
  end
23
23
  end
24
24
  end
@@ -10,5 +10,9 @@ module ActiveNode
10
10
  include Associations
11
11
  include Reflection
12
12
  include Core
13
+
14
+ def self.subclass(klass_name)
15
+ Class.new(super_class=self) { define_singleton_method(:label) { klass_name } }
16
+ end
13
17
  end
14
18
  end
@@ -2,9 +2,9 @@ module ActiveNode
2
2
  module Core
3
3
  extend ActiveSupport::Concern
4
4
 
5
- def initialize(attributes = nil)
5
+ def initialize(attributes = nil, split_by=:respond_to_writer?)
6
6
  @association_cache = {}
7
- super attributes
7
+ super attributes, split_by
8
8
  end
9
9
  end
10
10
  end
@@ -0,0 +1,7 @@
1
+ module ActiveNode
2
+ class Neo
3
+ def self.db
4
+ @db ||= Neography::Rest.new
5
+ end
6
+ end
7
+ end
@@ -1,8 +1,12 @@
1
+ require 'active_support/core_ext/hash/indifferent_access'
2
+
1
3
  module ActiveNode
2
4
  module Persistence
3
5
  extend ActiveSupport::Concern
6
+ include Neography::Rest::Helpers
4
7
 
5
8
  included do
9
+ extend Neography::Rest::Helpers
6
10
  attribute :id
7
11
  end
8
12
 
@@ -13,22 +17,24 @@ module ActiveNode
13
17
  end
14
18
 
15
19
  def find ids
16
- ids.is_a?(Enumerable) ? ids.map { |id| find(id) } : new_instance(Neography::Node.load(ids))
20
+ array = new_instances(Neo.db.get_nodes([ids].flatten))
21
+ ids.is_a?(Array) ? array : array.first
22
+ end
23
+
24
+ def find_by_cypher query, params={}, klass=nil
25
+ wrap(Neo.db.execute_query(query, params)['data'].map(&:first), klass)
17
26
  end
18
27
 
19
28
  def all
20
- result = Neography::Node.find(:node_auto_index, :type, type)
21
- (result.is_a?(Enumerable) ? result : [result]).map { |node| new_instance(node) }.compact
29
+ new_instances(Neo.db.get_nodes_labeled(label), self)
22
30
  end
23
31
 
24
- def type
25
- name.underscore
32
+ def label
33
+ name
26
34
  end
27
35
 
28
36
  def wrap node, klass=nil
29
- node.is_a?(Enumerable) ?
30
- node.map { |n| wrap(n, klass) } :
31
- node.is_a?(Neography::Node) && (active_node_class(node.type.camelize, klass)).try(:new, node) || node
37
+ node.is_a?(Array) ? new_instances(node, klass) : new_instance(node, klass)
32
38
  end
33
39
 
34
40
  def active_node_class(class_name, default_klass=nil)
@@ -36,32 +42,51 @@ module ActiveNode
36
42
  klass && klass < ActiveNode::Base && klass || default_klass
37
43
  end
38
44
 
39
- def filterClass(nodes, klass)
40
- wrap(nodes, klass).select { |model| klass.nil? || model.instance_of?(klass) }
45
+ private
46
+ def new_instance node, klass=nil
47
+ (klass || find_suitable_class(Neo.db.get_node_labels(node))).try(:new, data(node), :declared?)
41
48
  end
42
49
 
43
- private
44
- def new_instance node
45
- new(node) if node.try(:type) == type
50
+ def data hash
51
+ hash['data'].merge(id: get_id(hash).to_i)
52
+ end
53
+
54
+ def new_instances nodes, klass=nil
55
+ nodes.map { |node| new_instance(node, klass) }.compact
46
56
  end
57
+
58
+ def find_suitable_class labels
59
+ labels.include?(label) ? self : labels.map { |l| active_node_class(l) }.compact.first
60
+ end
61
+ end
62
+
63
+ def [](attr)
64
+ declared?(attr) ? send(attr) : @hash[attr]
47
65
  end
48
66
 
49
- attr_reader :node
50
- delegate :neo_id, to: :node, allow_nil: true
67
+ def []=(attr, value)
68
+ if declared? attr
69
+ send "#{attr}=", value
70
+ else
71
+ @hash[attr]=value
72
+ end
73
+ end
51
74
 
52
- alias :[] :send
75
+ def neo_id
76
+ id
77
+ end
53
78
 
54
- def id
55
- neo_id && neo_id.to_i
79
+ def to_param
80
+ id
56
81
  end
57
82
 
58
- alias :to_param :id
59
- alias :persisted? :id
83
+ def persisted?
84
+ id
85
+ end
60
86
 
61
- def initialize object={}
62
- hash=object
63
- @node, hash = object, declared_attributes_only(object.send(:table)) if object.is_a? Neography::Node
64
- super hash
87
+ def initialize hash={}, split_by=:respond_to_writer?
88
+ super(split_hash hash, :select, split_by)
89
+ @hash=(split_hash(hash, :reject, split_by) || {}).with_indifferent_access
65
90
  end
66
91
 
67
92
  def new_record?
@@ -76,7 +101,7 @@ module ActiveNode
76
101
 
77
102
  def destroy include_relationships=false
78
103
  destroyable = destroy_associations include_relationships
79
- node.del if destroyable
104
+ Neo.db.delete_node(id) if destroyable
80
105
  @destroyed = destroyable
81
106
  end
82
107
 
@@ -84,32 +109,38 @@ module ActiveNode
84
109
  destroy true
85
110
  end
86
111
 
87
- def incoming(types=nil, klass=nil)
88
- related(:incoming, types, klass)
112
+ def incoming(type=nil, klass=nil)
113
+ related(:incoming, type, klass)
89
114
  end
90
115
 
91
- def outgoing(types=nil, klass=nil)
92
- related(:outgoing, types, klass)
116
+ def outgoing(type=nil, klass=nil)
117
+ related(:outgoing, type, klass)
93
118
  end
94
119
 
95
120
  private
96
- def declared_attributes_only hash
97
- hash.try(:select) { |k, _| self.class.attribute_names.include? k.to_s }
121
+ def split_hash hash, method, split_by
122
+ hash.try(method) { |k, _| send split_by, k }
98
123
  end
99
124
 
100
- def related(direction, types, klass)
101
- node && self.class.filterClass(node.send(direction, types), klass)
125
+ def declared? attr
126
+ self.class.attribute_names.include? attr.to_s
102
127
  end
103
128
 
104
- def destroy_associations include_associations
105
- rels = node.rels
106
- return false unless rels.empty? || include_associations
107
- rels.each { |rel| rel.del }
108
- true
129
+ def respond_to_writer? attr
130
+ respond_to? "#{attr}="
109
131
  end
110
132
 
111
- def nullify_blanks! attrs
112
- attrs.each { |k, v| attrs[k]=nil if v.blank? }
133
+ def related(direction, type, klass)
134
+ id ?
135
+ self.class.find_by_cypher(
136
+ "start n=node({id}) match (n)#{'<' if direction == :incoming}-[:#{type}]-#{'>' if direction == :outgoing}(m#{":#{klass.label}" if klass}) return m",
137
+ {id: id}, klass) :
138
+ []
139
+ end
140
+
141
+ def destroy_associations include_associations
142
+ rels=Neo.db.get_node_relationships(id)
143
+ rels.nil? || rels.empty? || include_associations && rels.each { |rel| Neo.db.delete_relationship(rel) }
113
144
  end
114
145
 
115
146
  def create_or_update
@@ -120,12 +151,25 @@ module ActiveNode
120
151
  def write
121
152
  now = Time.now.utc.iso8601(3)
122
153
  try :updated_at=, now
123
- if @node
124
- nullify_blanks!(self.attributes).each { |k, v| @node[k]=v }
154
+ if persisted?
155
+ write_properties
125
156
  else
126
157
  try :created_at=, now
127
- @node = Neography::Node.create nullify_blanks!(self.attributes).merge!(type: self.class.type)
158
+ create_node_with_label
128
159
  end
129
160
  end
161
+
162
+ def create_node_with_label
163
+ self.id = get_id(Neo.db.create_node(all_attributes)).to_i
164
+ Neo.db.set_label(id, self.class.label)
165
+ end
166
+
167
+ def write_properties
168
+ Neo.db.reset_node_properties(id, all_attributes.select { |_, v| v.present? })
169
+ end
170
+
171
+ def all_attributes
172
+ attributes.merge(@hash)
173
+ end
130
174
  end
131
175
  end
@@ -1,3 +1,3 @@
1
1
  module ActiveNode
2
- VERSION = "0.2"
2
+ VERSION = "2.0.0"
3
3
  end
@@ -104,6 +104,26 @@ describe ActiveNode::Associations do
104
104
  father.children.should == [child]
105
105
  end
106
106
 
107
+ it 'can set has_one relationship by id at creation time' do
108
+ father = Person.create!
109
+ child = Person.create! father_id: father.id
110
+ father.children.should == [child]
111
+ end
112
+
113
+ it 'does not set has_one relationship by id if id is blank' do
114
+ father = Person.create!
115
+ child = Person.create! father_id: nil
116
+ father.children.should be_empty
117
+ end
118
+
119
+ it 'can remove has_one relationship' do
120
+ father = Person.create!
121
+ child = Person.create! father: father
122
+ child.father = nil
123
+ child.save
124
+ Person.find(child.id).father.should be_nil
125
+ end
126
+
107
127
  it 'can read has_one relation by id' do
108
128
  father = Person.create!
109
129
  child = Person.create!
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActiveNode::Base do
4
+ describe ".subclass" do
5
+ it "should be ActiveNode::Base" do
6
+ ActiveNode::Base.subclass('Abc').should <= ActiveNode::Base
7
+ end
8
+
9
+ it "should have the right label" do
10
+ ActiveNode::Base.subclass('Abc').label.should == 'Abc'
11
+ end
12
+
13
+ it "should find object via subclass" do
14
+ p = Person.create! name: 'Heinrich'
15
+ ActiveNode::Base.subclass('Person').find(p.id)[:name].should == p.name
16
+ end
17
+ end
18
+ end
@@ -2,6 +2,11 @@ require 'spec_helper'
2
2
 
3
3
  describe ActiveNode::Persistence do
4
4
  describe "#save" do
5
+ it "should save an object" do
6
+ a=Address.create!
7
+ Address.find(a.id).should == a
8
+ end
9
+
5
10
  it "should save not conventionally named object" do
6
11
  NeoUser.new(name: 'Heinrich').save.should be_true
7
12
  NeoUser.all.map(&:name).should == ['Heinrich']
@@ -10,10 +15,10 @@ describe ActiveNode::Persistence do
10
15
  it "should save object with non attribute properties with a name of a relationship" do
11
16
  child = Person.create!
12
17
  person = Person.create! children: [child]
13
- person.node[:children] = "Bob"
14
- person = Person.find person.id
18
+ person[:children] = "Bob"
15
19
  person.save
16
- person.node[:children].should == "Bob"
20
+ person = Person.find person.id
21
+ person[:children].should == "Bob"
17
22
  person.children.should == [child]
18
23
  end
19
24
 
@@ -64,8 +69,8 @@ describe ActiveNode::Persistence do
64
69
  Person.find(person.id).multi.should == [1, 2, 3]
65
70
  end
66
71
 
67
- it 'should not find an object with id of a different model' do
68
- Client.find(Person.create!.id).should be_nil
72
+ it 'should find an object with id of a different model' do
73
+ Client.find(Person.create!.id).class.should == Person
69
74
  end
70
75
  end
71
76
 
@@ -3,7 +3,7 @@ class NeoUser < ActiveNode::Base
3
3
  has_many :clients
4
4
  validates :name, presence: true
5
5
 
6
- def self.type
7
- 'user'
6
+ def self.label
7
+ 'User'
8
8
  end
9
9
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_node
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.2'
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Heinrich Klobuczek
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-01-07 00:00:00.000000000 Z
11
+ date: 2014-01-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: active_attr
@@ -152,11 +152,13 @@ files:
152
152
  - lib/active_node/callbacks.rb
153
153
  - lib/active_node/core.rb
154
154
  - lib/active_node/errors.rb
155
+ - lib/active_node/neo.rb
155
156
  - lib/active_node/persistence.rb
156
157
  - lib/active_node/reflection.rb
157
158
  - lib/active_node/validations.rb
158
159
  - lib/active_node/version.rb
159
160
  - spec/functional/associations_spec.rb
161
+ - spec/functional/base_spec.rb
160
162
  - spec/functional/persistence_spec.rb
161
163
  - spec/functional/validations_spec.rb
162
164
  - spec/models/address.rb
@@ -189,6 +191,7 @@ specification_version: 4
189
191
  summary: ActiveRecord style Object Graph Mapping for neo4j
190
192
  test_files:
191
193
  - spec/functional/associations_spec.rb
194
+ - spec/functional/base_spec.rb
192
195
  - spec/functional/persistence_spec.rb
193
196
  - spec/functional/validations_spec.rb
194
197
  - spec/models/address.rb