active_node 2.0.4 → 2.1.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 +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
|
+
- [](https://rubygems.org/gems/active_node)
|
5
|
+
- [](https://travis-ci.org/klobuczek/active_node)
|
6
|
+
- [](https://codeclimate.com/github/klobuczek/active_node)
|
7
|
+
- [](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
|