active_node 2.0.4 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +2 -2
- data/README.md +87 -53
- data/active_node.gemspec +1 -1
- data/lib/active_node.rb +1 -0
- data/lib/active_node/associations/association.rb +5 -3
- data/lib/active_node/graph.rb +7 -0
- data/lib/active_node/graph/builder.rb +119 -0
- data/lib/active_node/persistence.rb +8 -44
- data/lib/active_node/version.rb +1 -1
- data/spec/functional/base_spec.rb +1 -1
- data/spec/functional/graph/builder_spec.rb +34 -0
- data/spec/functional/persistence_spec.rb +15 -2
- data/spec/functional/validations_spec.rb +6 -0
- data/spec/models/house.rb +5 -0
- data/spec/spec_helper.rb +4 -2
- metadata +22 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2b740f77651e77a06827ae6f01ab6a6592c3f8ad
|
4
|
+
data.tar.gz: 03ecfa69835cae01a75c82fb869d263020fbc5d9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 189c5d2da767a7ea045aa5973bfac329177863280490f30d8e380255c4afed57f763726845a878778f6c742931d6d0f26945d763467dd82eda5d66208608332b
|
7
|
+
data.tar.gz: 74300a45a8374d76f946cc77fd0f59dd606aa5b2c437053d40813bf0f6475eee9cf84a5eaf38d3eb22a43a23aea6f4f5aa04de9d91414877853cb0381a6da9cb
|
data/.travis.yml
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
script: "bundle exec rake neo4j:install['enterprise','2.0.
|
1
|
+
script: "CODECLIMATE_REPO_TOKEN=88fa9b8eb0bfc48e8c5077253d829e94af9f76aca60df9e75ae0e50a4c7cd9f0 bundle exec rake neo4j:install['enterprise','2.0.2'] neo4j:start spec --trace"
|
2
2
|
language: ruby
|
3
3
|
rvm:
|
4
|
-
-
|
4
|
+
- 2.0.0
|
data/README.md
CHANGED
@@ -1,73 +1,107 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
ActiveNode
|
2
|
+
==========
|
3
3
|
|
4
|
-
|
4
|
+
- [![Gem Version](https://badge.fury.io/rb/active_node.png)](https://rubygems.org/gems/active_node)
|
5
|
+
- [![Build Status](https://travis-ci.org/klobuczek/active_node.png?branch=master)](https://travis-ci.org/klobuczek/active_node)
|
6
|
+
- [![Code Climate](https://codeclimate.com/github/klobuczek/active_node.png)](https://codeclimate.com/github/klobuczek/active_node)
|
7
|
+
- [![Coverage Status](https://coveralls.io/repos/klobuczek/active_node/badge.png?branch=master)](https://coveralls.io/r/klobuczek/active_node?branch=master)
|
5
8
|
|
6
9
|
|
7
|
-
|
10
|
+
ActiveNode is object graph mapping layer for neo4j deployed as standalone server. It is implemented on top of [neography](http://github.com/maxdemarzi/neography) by Max De Marzi.
|
8
11
|
|
12
|
+
If you use neo4j in embedded mode with JRuby please refer to the Neo4j.rb gem at https://github.com/andreasronge/neo4j by Andreas Ronge.
|
13
|
+
|
14
|
+
## Installation
|
15
|
+
|
16
|
+
### Gemfile
|
17
|
+
|
18
|
+
Add `active_node` to your Gemfile:
|
9
19
|
|
10
20
|
```ruby
|
11
|
-
|
12
|
-
|
13
|
-
require 'neography'
|
14
|
-
|
15
|
-
Neography.configure do |config|
|
16
|
-
config.protocol = "http://"
|
17
|
-
config.server = "localhost"
|
18
|
-
config.port = 7474
|
19
|
-
config.directory = "" # prefix this path with '/'
|
20
|
-
config.cypher_path = "/cypher"
|
21
|
-
config.gremlin_path = "/ext/GremlinPlugin/graphdb/execute_script"
|
22
|
-
config.log_file = "neography.log"
|
23
|
-
config.log_enabled = false
|
24
|
-
config.slow_log_threshold = 0 # time in ms for query logging
|
25
|
-
config.max_threads = 20
|
26
|
-
config.authentication = nil # 'basic' or 'digest'
|
27
|
-
config.username = nil
|
28
|
-
config.password = nil
|
29
|
-
config.parser = MultiJsonParser
|
30
|
-
end
|
21
|
+
gem 'active_node'
|
22
|
+
```
|
31
23
|
|
32
|
-
|
33
|
-
attribute :name, type: String
|
34
|
-
has_many :clients
|
35
|
-
validates :name, presence: true
|
24
|
+
In case of default neo4j installation no further configuration is required. Otherwise refer to https://github.com/maxdemarzi/neography for further configuration options.
|
36
25
|
|
37
|
-
|
38
|
-
'User'
|
39
|
-
end
|
40
|
-
end
|
26
|
+
## Usage
|
41
27
|
|
42
|
-
|
43
|
-
attribute :name, type: String
|
28
|
+
ActiveNode is inspired by ActiveRecord, but it implements only some of its features and if necessary provides some extensions to work with a graph database.
|
44
29
|
|
45
|
-
|
46
|
-
has_one :address
|
30
|
+
### Creating and Retrieving Nodes
|
47
31
|
|
48
|
-
|
32
|
+
```ruby
|
33
|
+
class Client < ActiveNode::Base
|
49
34
|
end
|
50
35
|
|
51
|
-
|
52
|
-
|
36
|
+
client = Client.create! name: 'Abc' # Creates a neo4j node with label Client and property 'name' == 'Abc'
|
37
|
+
client = Client.find client.id
|
38
|
+
client[:name] # 'Abc'
|
39
|
+
client[:name] = 'Abc Inc.'
|
40
|
+
client.save
|
53
41
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
timestamps
|
42
|
+
Client.all # returns array of all clients
|
43
|
+
Client.find_by_cypher('match (c:Client) where c.name = {name}', name: 'Abc') # array of all Clients meeting given criteria
|
44
|
+
```
|
58
45
|
|
59
|
-
|
60
|
-
has_many :children, class_name: "Person"
|
61
|
-
#has_many :sons, class_name: "Person"
|
62
|
-
has_one :father, type: :child, direction: :incoming, class_name: "Person"
|
63
|
-
has_one :address
|
46
|
+
### Declared Attrribues
|
64
47
|
|
65
|
-
|
48
|
+
```ruby
|
49
|
+
class Client < ActiveNode::Base
|
50
|
+
attribute :name, type: String #typed
|
51
|
+
attribute :code #untyped
|
52
|
+
attribute :keywords # leave array attributes untyped
|
53
|
+
timestamps # will automatically add and maintain created_at and updated_at
|
66
54
|
end
|
67
55
|
|
56
|
+
client.name = 'Abc'
|
57
|
+
client.keywords = ['finance', 'investment']
|
68
58
|
|
69
|
-
user = NeoUser.new(name: 'Heinrich')
|
70
|
-
user.save
|
71
|
-
client = Client.new(name: 'a', users: [user])
|
72
|
-
client.save
|
73
59
|
```
|
60
|
+
|
61
|
+
### Validation
|
62
|
+
Validation is similar to ActiveModel e.g.
|
63
|
+
|
64
|
+
```ruby
|
65
|
+
validates :name, presence: true
|
66
|
+
```
|
67
|
+
|
68
|
+
### Association
|
69
|
+
|
70
|
+
There are 2 types of associations: has_many and has_one. With additional options they can cover all possible relationships between nodes.
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
# label, class name, relationship type are derived from the association name, direction is by default outgoing
|
74
|
+
has_one :user # node with label User connected with outgoing relationship of type 'user'
|
75
|
+
has_many :users # multiple nodes with label User connected with outgoing relationship of type 'user'
|
76
|
+
# all option customized
|
77
|
+
has_one :father, type: :child, direction: :incoming, class_name: "Person"
|
78
|
+
```
|
79
|
+
|
80
|
+
The association declarations generate readers and writers.
|
81
|
+
```ruby
|
82
|
+
Client.create!(name: 'Abc', users: [User.create!, User.create!])
|
83
|
+
Client.create!(name: 'Abc', user_id: User.create!.id)
|
84
|
+
...
|
85
|
+
client.user_ids = [user1.id, user2.id]
|
86
|
+
save
|
87
|
+
client.users # [user1, user2]
|
88
|
+
```
|
89
|
+
### Custom Label
|
90
|
+
|
91
|
+
```ruby
|
92
|
+
class Client < ActiveNode::Base
|
93
|
+
def label
|
94
|
+
'Company'
|
95
|
+
end
|
96
|
+
end
|
97
|
+
```
|
98
|
+
|
99
|
+
Instances of Client will correspond to nodes with label Company.
|
100
|
+
|
101
|
+
## More
|
102
|
+
|
103
|
+
ActiveNode works nicely with [neography](http://github.com/maxdemarzi/neography). If at any point you need more control or want to leverage some advanced features of the neo4j REST API you can easily take advantage of the lower layer calls.
|
104
|
+
|
105
|
+
Please create a [new issue](https://github.com/klobuczek/active_node/issues) if you are missing any important feature in active_node.
|
106
|
+
|
107
|
+
In case of any questions don't hesitate to contact me at heinrich@mail.com
|
data/active_node.gemspec
CHANGED
data/lib/active_node.rb
CHANGED
@@ -17,7 +17,7 @@ module ActiveNode
|
|
17
17
|
# HasManyAssociation
|
18
18
|
# HasManyThroughAssociation + ThroughAssociation
|
19
19
|
class Association #:nodoc:
|
20
|
-
attr_reader :owner, :target, :reflection
|
20
|
+
attr_reader :owner, :target, :rel_target, :reflection
|
21
21
|
|
22
22
|
delegate :options, :to => :reflection
|
23
23
|
|
@@ -51,6 +51,7 @@ module ActiveNode
|
|
51
51
|
@rel_target = nil
|
52
52
|
@target = records
|
53
53
|
end
|
54
|
+
|
54
55
|
alias :super_writer :writer
|
55
56
|
|
56
57
|
# Implements the ids writer method, e.g. foo.item_ids= for Foo.has_many :items
|
@@ -71,7 +72,8 @@ module ActiveNode
|
|
71
72
|
|
72
73
|
|
73
74
|
def rels_reader(*args)
|
74
|
-
|
75
|
+
rel(*args) unless @rel_target
|
76
|
+
@rel_target ||= []
|
75
77
|
end
|
76
78
|
|
77
79
|
def rels_writer(rels)
|
@@ -83,7 +85,7 @@ module ActiveNode
|
|
83
85
|
def save(fresh=false)
|
84
86
|
#return unless @dirty
|
85
87
|
#delete all relations missing in new target
|
86
|
-
original_rels = fresh ? [] :
|
88
|
+
original_rels = fresh ? [] : ActiveNode::Graph::Builder.new(owner.class, reflection.name).build(owner.id).first.association(reflection.name).rels_reader
|
87
89
|
original_rels.each do |r|
|
88
90
|
unless ids_reader.include? r.other.id
|
89
91
|
Neo.db.delete_relationship(r.id)
|
@@ -0,0 +1,119 @@
|
|
1
|
+
module ActiveNode
|
2
|
+
module Graph
|
3
|
+
class Builder
|
4
|
+
include Neography::Rest::Helpers
|
5
|
+
|
6
|
+
attr_reader :reflections, :matches, :klass
|
7
|
+
|
8
|
+
def initialize klass, *includes
|
9
|
+
@klass = klass if klass < ActiveNode::Base
|
10
|
+
@matches = []
|
11
|
+
@reflections =[]
|
12
|
+
@object_cache = {}
|
13
|
+
@relationship_cache = {}
|
14
|
+
@loaded_assoc_cache = {}
|
15
|
+
parse_paths(:n0, klass, includes)
|
16
|
+
end
|
17
|
+
|
18
|
+
def build *objects
|
19
|
+
ids = objects.map { |o| o.is_a?(ActiveNode::Base) ? o.id.tap { |id| @object_cache[id]=o } : o }
|
20
|
+
parse_results execute(ids.compact)
|
21
|
+
@object_cache.slice(*ids).values
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
def query
|
26
|
+
@matches.join " "
|
27
|
+
end
|
28
|
+
|
29
|
+
def execute(ids)
|
30
|
+
q="start n0=node({ids}) #{query}#{"where n0#{label @klass}" if @klass} return #{list_with_rel(@reflections.size)} order by #{created_at_list(@reflections.size)}"
|
31
|
+
Neo.db.execute_query(q, ids: ids)
|
32
|
+
end
|
33
|
+
|
34
|
+
def parse_results results
|
35
|
+
results['data'].each do |record|
|
36
|
+
wrap(record.first, @klass)
|
37
|
+
@reflections.each_with_index do |reflection, index|
|
38
|
+
node_rel = record[2*index+1]
|
39
|
+
node_rel = node_rel.last if node_rel.is_a? Array
|
40
|
+
next unless node_rel
|
41
|
+
owner = @object_cache[owner_id node_rel, reflection.direction]
|
42
|
+
node = wrap record[2*index + 2], reflection.klass
|
43
|
+
rel = reflection.klass.create_rel node_rel, node
|
44
|
+
assoc = owner.association(reflection.name)
|
45
|
+
assoc.rels_writer((assoc.rel_target || []) << rel) unless previously_loaded?(assoc)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def previously_loaded?(assoc)
|
51
|
+
@loaded_assoc_cache[assoc] = assoc.rel_target unless @loaded_assoc_cache.key? assoc
|
52
|
+
@loaded_assoc_cache[assoc]
|
53
|
+
end
|
54
|
+
|
55
|
+
def wrap(record, klass)
|
56
|
+
@object_cache[extract_id record] ||= ActiveNode::Base.wrap(record, klass)
|
57
|
+
end
|
58
|
+
|
59
|
+
def owner_id relationship, direction
|
60
|
+
extract_id relationship[direction == :incoming ? 'end' : 'start']
|
61
|
+
end
|
62
|
+
|
63
|
+
def parse_paths as, klass, includes
|
64
|
+
if includes.is_a?(Hash)
|
65
|
+
includes.each do |key, value|
|
66
|
+
if (value.is_a?(String) || value.is_a?(Numeric))
|
67
|
+
add_match(as, klass, key, value)
|
68
|
+
else
|
69
|
+
parse_paths(as, klass, key)
|
70
|
+
parse_paths(latest_alias, @reflections.last.klass, value)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
elsif includes.is_a?(Array)
|
74
|
+
includes.each { |inc| parse_paths(as, klass, inc) }
|
75
|
+
else
|
76
|
+
add_match(as, klass, includes)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def add_match from, klass, key, multiplicity=nil
|
81
|
+
reflection = klass.reflect_on_association(key)
|
82
|
+
@reflections << reflection
|
83
|
+
matches << match(from, reflection, multiplicity)
|
84
|
+
end
|
85
|
+
|
86
|
+
def latest_alias
|
87
|
+
"n#{@reflections.size}"
|
88
|
+
end
|
89
|
+
|
90
|
+
def match(start_var, reflection, multiplicity)
|
91
|
+
"optional match (#{start_var})#{'<' if reflection.direction == :incoming}-[r#{@reflections.size}:#{reflection.type}#{multiplicity(multiplicity)}]-#{'>' if reflection.direction == :outgoing}(#{latest_alias}#{label reflection.klass})"
|
92
|
+
end
|
93
|
+
|
94
|
+
def label klass
|
95
|
+
":#{klass.label}" if klass
|
96
|
+
end
|
97
|
+
|
98
|
+
def multiplicity multiplicity
|
99
|
+
multiplicity.is_a?(Numeric) ? "*1..#{multiplicity}" : multiplicity
|
100
|
+
end
|
101
|
+
|
102
|
+
def list_with_rel num
|
103
|
+
comma_sep_list(num) { |i| [("r#{i}" if i>0), "n#{i}"] }
|
104
|
+
end
|
105
|
+
|
106
|
+
def comma_sep_list num, &block
|
107
|
+
(0..num).map(&block).flatten.compact.join(', ')
|
108
|
+
end
|
109
|
+
|
110
|
+
def created_at_list num
|
111
|
+
comma_sep_list(num) { |i| "n#{i}.created_at" }
|
112
|
+
end
|
113
|
+
|
114
|
+
def extract_id(id)
|
115
|
+
get_id(id).to_i
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -16,8 +16,8 @@ module ActiveNode
|
|
16
16
|
attribute :updated_at, type: String
|
17
17
|
end
|
18
18
|
|
19
|
-
def find ids
|
20
|
-
array =
|
19
|
+
def find ids, options={}
|
20
|
+
array = ActiveNode::Graph::Builder.new(self, *options[:include]).build(*ids)
|
21
21
|
ids.is_a?(Array) ? array : array.first
|
22
22
|
end
|
23
23
|
|
@@ -38,7 +38,11 @@ module ActiveNode
|
|
38
38
|
end
|
39
39
|
|
40
40
|
def wrap_rel rel, node, klass
|
41
|
-
|
41
|
+
create_rel rel, wrap(node, klass)
|
42
|
+
end
|
43
|
+
|
44
|
+
def create_rel rel, node
|
45
|
+
ActiveNode::Relationship.new node, rel['data'].merge(id: get_id(rel).to_i)
|
42
46
|
end
|
43
47
|
|
44
48
|
def active_node_class(class_name, default_klass=nil)
|
@@ -126,50 +130,10 @@ module ActiveNode
|
|
126
130
|
end
|
127
131
|
|
128
132
|
def relationships(reflection, *associations)
|
129
|
-
|
130
|
-
Neo.db.execute_query(
|
131
|
-
"start n=node({id}) match #{match reflection}#{optional_match reflection, associations} return #{list_with_rel reflection.name, *associations} order by #{created_at_list reflection.name, *associations}",
|
132
|
-
{id: id})['data'].map { |rel_node| self.class.wrap_rel rel_node[0], rel_node[1], reflection.klass } :
|
133
|
-
[]
|
133
|
+
ActiveNode::Graph::Builder.new(self.class, reflection.name => associations).build(self)
|
134
134
|
end
|
135
135
|
|
136
136
|
private
|
137
|
-
def parse_result klass, result, associations
|
138
|
-
node_map = {}
|
139
|
-
result.each do |record|
|
140
|
-
(node_map[extract_id(record[1])] ||= wrap_rel(record[0], record[1], klass))
|
141
|
-
end
|
142
|
-
end
|
143
|
-
|
144
|
-
def extract_id(id)
|
145
|
-
get_id(id).to_i
|
146
|
-
end
|
147
|
-
|
148
|
-
def match(reflection, start_var='n')
|
149
|
-
"(#{start_var})#{'<' if reflection.direction == :incoming}-[#{reflection.name}_rel:#{reflection.type}]-#{'>' if reflection.direction == :outgoing}(#{reflection.name}#{label reflection.klass})"
|
150
|
-
end
|
151
|
-
|
152
|
-
def optional_match reflection, associations
|
153
|
-
return if associations.empty?
|
154
|
-
" optional match " + comma_sep_list(associations.map { |association| match(reflection.klass.reflect_on_association(association), association) })
|
155
|
-
end
|
156
|
-
|
157
|
-
def label klass
|
158
|
-
":#{klass.label}" if klass
|
159
|
-
end
|
160
|
-
|
161
|
-
def list_with_rel *names
|
162
|
-
comma_sep_list names.map { |name| ["#{name}_rel", name] }.flatten
|
163
|
-
end
|
164
|
-
|
165
|
-
def comma_sep_list *items
|
166
|
-
items.join(', ')
|
167
|
-
end
|
168
|
-
|
169
|
-
def created_at_list *names
|
170
|
-
comma_sep_list names.map { |name| "#{name}.created_at" }
|
171
|
-
end
|
172
|
-
|
173
137
|
def split_hash hash, method, split_by
|
174
138
|
hash.try(method) { |k, _| send split_by, k }
|
175
139
|
end
|
data/lib/active_node/version.rb
CHANGED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ActiveNode::Graph::Builder do
|
4
|
+
describe "#path" do
|
5
|
+
it "should parse includes" do
|
6
|
+
ActiveNode::Graph::Builder.new(Person, :father).send(:query).should == "optional match (n0)<-[r1:child]-(n1:Person)"
|
7
|
+
ActiveNode::Graph::Builder.new(Person, :father, :children).send(:query).should == "optional match (n0)<-[r1:child]-(n1:Person) optional match (n0)-[r2:child]->(n2:Person)"
|
8
|
+
ActiveNode::Graph::Builder.new(Person, children: 2).send(:query).should == "optional match (n0)-[r1:child*1..2]->(n1:Person)"
|
9
|
+
ActiveNode::Graph::Builder.new(Person, {children: :address}, :address).send(:query).should == "optional match (n0)-[r1:child]->(n1:Person) optional match (n1)-[r2:address]->(n2:Address) optional match (n0)-[r3:address]->(n3:Address)"
|
10
|
+
ActiveNode::Graph::Builder.new(Person, children: [:address, :father]).send(:query).should == "optional match (n0)-[r1:child]->(n1:Person) optional match (n1)-[r2:address]->(n2:Address) optional match (n1)<-[r3:child]-(n3:Person)"
|
11
|
+
ActiveNode::Graph::Builder.new(Person, {children: 2} => [:address, :father]).send(:query).should == "optional match (n0)-[r1:child*1..2]->(n1:Person) optional match (n1)-[r2:address]->(n2:Address) optional match (n1)<-[r3:child]-(n3:Person)"
|
12
|
+
ActiveNode::Graph::Builder.new(Person, {children: '*'} => [:address, :father]).send(:query).should == "optional match (n0)-[r1:child*]->(n1:Person) optional match (n1)-[r2:address]->(n2:Address) optional match (n1)<-[r3:child]-(n3:Person)"
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should build graph" do
|
16
|
+
person = Person.create! children: [c1=Person.create!, c2=Person.create!(address: a=Address.create!)]
|
17
|
+
g_person = ActiveNode::Graph::Builder.new(Person, {children: '*'} => [:address, :father]).build(person).first
|
18
|
+
g_person.should == person
|
19
|
+
g_person.object_id.should == person.object_id
|
20
|
+
ActiveNode::Neo.should_not_receive(:db)
|
21
|
+
g_person.children.last.address.should == a
|
22
|
+
g_person.children.first.father = person
|
23
|
+
g_person.children.should == [c1, c2]
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should not query db twice" do
|
27
|
+
pending
|
28
|
+
person = Person.create!
|
29
|
+
ActiveNode::Graph::Builder.new(Person, :children).build(person)
|
30
|
+
ActiveNode::Neo.should_not_receive(:db)
|
31
|
+
person.children
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -89,9 +89,22 @@ describe ActiveNode::Persistence do
|
|
89
89
|
person = Person.create!(multi: [1, 2, 3])
|
90
90
|
Person.find(person.id).multi.should == [1, 2, 3]
|
91
91
|
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe "#find" do
|
95
|
+
it 'should find an object by id' do
|
96
|
+
person = Person.create!
|
97
|
+
Person.find(person.id).should == person
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'should find objects passing multiple ids' do
|
101
|
+
person1 = Person.create!
|
102
|
+
person2 = Person.create!
|
103
|
+
Person.find([person1.id, person2.id]).should == [person1, person2]
|
104
|
+
end
|
92
105
|
|
93
|
-
it 'should find an object with id of
|
94
|
-
|
106
|
+
it 'should find an object with id of an unknown model' do
|
107
|
+
ActiveNode::Base.find(Person.create!.id).class.should == Person
|
95
108
|
end
|
96
109
|
end
|
97
110
|
|
@@ -22,5 +22,11 @@ describe ActiveNode::Validations do
|
|
22
22
|
person.should be_valid
|
23
23
|
end
|
24
24
|
end
|
25
|
+
|
26
|
+
it "should validate presence on has_one" do
|
27
|
+
House.new.should_not be_valid
|
28
|
+
house = House.create! address_id: Address.create!.id
|
29
|
+
House.find(house.id).should be_valid
|
30
|
+
end
|
25
31
|
end
|
26
32
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require "codeclimate-test-reporter"
|
2
|
+
CodeClimate::TestReporter.start
|
1
3
|
#require 'rubygems'
|
2
4
|
#require 'bundler/setup'
|
3
5
|
require 'active_node'
|
@@ -41,8 +43,8 @@ RSpec.configure do |c|
|
|
41
43
|
c.before(:each) do
|
42
44
|
@neo=Neography::Rest.new
|
43
45
|
@neo.execute_query("MATCH (n) OPTIONAL MATCH (n)-[r]-() DELETE n,r")
|
44
|
-
|
45
|
-
|
46
|
+
#@neo.set_node_auto_index_status(true)
|
47
|
+
#@neo.add_node_auto_index_property('type')
|
46
48
|
end
|
47
49
|
end
|
48
50
|
|
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: 2.0
|
4
|
+
version: 2.1.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-04-
|
11
|
+
date: 2014-04-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: active_attr
|
@@ -122,6 +122,20 @@ dependencies:
|
|
122
122
|
- - '>='
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: codeclimate-test-reporter
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - '>='
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - '>='
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
125
139
|
description: ActiveRecord style Object Graph Mapping for neo4j
|
126
140
|
email:
|
127
141
|
- heinrich@mail.com
|
@@ -152,6 +166,8 @@ files:
|
|
152
166
|
- lib/active_node/callbacks.rb
|
153
167
|
- lib/active_node/core.rb
|
154
168
|
- lib/active_node/errors.rb
|
169
|
+
- lib/active_node/graph.rb
|
170
|
+
- lib/active_node/graph/builder.rb
|
155
171
|
- lib/active_node/neo.rb
|
156
172
|
- lib/active_node/persistence.rb
|
157
173
|
- lib/active_node/reflection.rb
|
@@ -161,10 +177,12 @@ files:
|
|
161
177
|
- lib/active_node/version.rb
|
162
178
|
- spec/functional/associations_spec.rb
|
163
179
|
- spec/functional/base_spec.rb
|
180
|
+
- spec/functional/graph/builder_spec.rb
|
164
181
|
- spec/functional/persistence_spec.rb
|
165
182
|
- spec/functional/validations_spec.rb
|
166
183
|
- spec/models/address.rb
|
167
184
|
- spec/models/client.rb
|
185
|
+
- spec/models/house.rb
|
168
186
|
- spec/models/neo_user.rb
|
169
187
|
- spec/models/person.rb
|
170
188
|
- spec/spec_helper.rb
|
@@ -195,10 +213,12 @@ summary: ActiveRecord style Object Graph Mapping for neo4j
|
|
195
213
|
test_files:
|
196
214
|
- spec/functional/associations_spec.rb
|
197
215
|
- spec/functional/base_spec.rb
|
216
|
+
- spec/functional/graph/builder_spec.rb
|
198
217
|
- spec/functional/persistence_spec.rb
|
199
218
|
- spec/functional/validations_spec.rb
|
200
219
|
- spec/models/address.rb
|
201
220
|
- spec/models/client.rb
|
221
|
+
- spec/models/house.rb
|
202
222
|
- spec/models/neo_user.rb
|
203
223
|
- spec/models/person.rb
|
204
224
|
- spec/spec_helper.rb
|