active_node 0.2 → 2.0.0

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