neo4j 3.0.1 → 3.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +10 -0
- data/README.md +4 -3
- data/lib/neo4j/active_node/has_n/association.rb +13 -5
- data/lib/neo4j/active_node/id_property.rb +4 -0
- data/lib/neo4j/active_node/labels.rb +11 -4
- data/lib/neo4j/active_node/node_wrapper.rb +1 -0
- data/lib/neo4j/active_node/query.rb +1 -9
- data/lib/neo4j/active_node/query/query_proxy.rb +2 -2
- data/lib/neo4j/active_node/query/query_proxy_methods.rb +2 -2
- data/lib/neo4j/active_node/query_methods.rb +2 -7
- data/lib/neo4j/active_node/validations.rb +3 -4
- data/lib/neo4j/active_rel/persistence.rb +16 -2
- data/lib/neo4j/active_rel/query.rb +1 -1
- data/lib/neo4j/active_rel/related_node.rb +18 -0
- data/lib/neo4j/migration.rb +12 -4
- data/lib/neo4j/tasks/migration.rake +3 -2
- data/lib/neo4j/version.rb +1 -1
- data/neo4j.gemspec +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 75e9394211348d0302d6f68dac0f87653eb95f28
|
4
|
+
data.tar.gz: 289355ac0ac9c885ae57eb12395046a1b612b5ae
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6d85f48c40cb8d3af253ae0eae9ed40d10b351eb0dc993d962987426d54f395495b7a1940f970c8c25b4847693d658fa22a5e6c003ea85cdb36fc04da51b2e04
|
7
|
+
data.tar.gz: 8cd671cfc2c868f184388c4b37df8490b7d07b7dcc0421e3bce21ea1ee0caee1626e0b3800128e736f8002497a0868996e2517880b69f076d63d5664d9487096
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
== 3.0.2
|
2
|
+
* "Model#all" now evaluates lazily, models no longer include Enumerable
|
3
|
+
* Faster, more efficient uniqueness validations
|
4
|
+
* Adjusted many common queries to use params, will improve performance
|
5
|
+
* ActiveRel fixes: create uses Core Query instead of Core's `rels` method, `{ classname: #{_classname} }` no longer inserted into every query, find related node IDs without loading the nodes
|
6
|
+
* Allow inheritance when checking model class on a relation (Andrew Jones)
|
7
|
+
* Provided migrations will use Rake.original_dir instead of Rails.env to provide better compatibility with frameworks other than Rails
|
8
|
+
* rel_class option in ActiveNode models will now accept string of a model name
|
9
|
+
* Additional bug fixes
|
10
|
+
|
1
11
|
== 3.0.1
|
2
12
|
* Removed reference to neo4j-core from Gemfile and set neo4j.gemspec to use neo4j-core ~>3.0.0
|
3
13
|
|
data/README.md
CHANGED
@@ -2,19 +2,20 @@
|
|
2
2
|
|
3
3
|
Neo4j.rb is an Active Model compliant Ruby/JRuby wrapper for [the Neo4j graph database](http://www.neo4j.org/). It uses the [neo4j-core](https://github.com/neo4jrb/neo4j-core) and [active_attr](https://github.com/cgriego/active_attr) gems.
|
4
4
|
|
5
|
-
##
|
5
|
+
## Modern (3.X) Documentation
|
6
6
|
|
7
7
|
* [Wiki](https://github.com/neo4jrb/neo4j/wiki/Neo4j.rb-v3-Introduction)
|
8
8
|
|
9
|
-
##
|
9
|
+
## Legacy (2.x) Documentation
|
10
10
|
|
11
11
|
* [README](https://github.com/neo4jrb/neo4j/tree/2.x)
|
12
12
|
* [Wiki](https://github.com/neo4jrb/neo4j/wiki/Neo4j%3A%3ARails-Introduction)
|
13
13
|
|
14
14
|
## Support
|
15
15
|
|
16
|
+
* Open an [issue](https://github.com/neo4jrb/neo4j/issues), post to [Stack Overflow](http://stackoverflow.com/questions/tagged/neo4j+ruby), or contact one of the developers.
|
16
17
|
* [Neo4j.rb mailing list](https://groups.google.com/forum/#!forum/neo4jrb)
|
17
|
-
* Consulting support
|
18
|
+
* Consulting support? Ask any of the developers, info below.
|
18
19
|
|
19
20
|
## Developers
|
20
21
|
|
@@ -23,7 +23,6 @@ module Neo4j
|
|
23
23
|
# Return cypher partial query string for the relationship part of a MATCH (arrow / relationship definition)
|
24
24
|
def arrow_cypher(var = nil, properties = {}, create = false)
|
25
25
|
validate_origin!
|
26
|
-
|
27
26
|
relationship_type = relationship_type(create)
|
28
27
|
relationship_name_cypher = ":`#{relationship_type}`" if relationship_type
|
29
28
|
properties_string = get_properties_string(properties)
|
@@ -55,7 +54,7 @@ module Neo4j
|
|
55
54
|
def relationship_type(create = false)
|
56
55
|
case
|
57
56
|
when @relationship_class
|
58
|
-
|
57
|
+
relationship_class_type
|
59
58
|
when @relationship_type
|
60
59
|
@relationship_type
|
61
60
|
when @origin
|
@@ -69,6 +68,16 @@ module Neo4j
|
|
69
68
|
@relationship_class
|
70
69
|
end
|
71
70
|
|
71
|
+
def relationship_class_type
|
72
|
+
@relationship_class = @relationship_class.constantize if @relationship_class.class == String || @relationship_class == Symbol
|
73
|
+
@relationship_class._type
|
74
|
+
end
|
75
|
+
|
76
|
+
def inject_classname(properties)
|
77
|
+
properties[Neo4j::Config.class_name_property] = @relationship_class.name if @relationship_class
|
78
|
+
properties
|
79
|
+
end
|
80
|
+
|
72
81
|
private
|
73
82
|
|
74
83
|
def get_direction(relationship_cypher, create)
|
@@ -88,7 +97,6 @@ module Neo4j
|
|
88
97
|
end
|
89
98
|
|
90
99
|
def get_properties_string(properties)
|
91
|
-
properties[Neo4j::Config.class_name_property] = @relationship_class.name if @relationship_class
|
92
100
|
p = properties.map do |key, value|
|
93
101
|
"#{key}: #{value.inspect}"
|
94
102
|
end.join(', ')
|
@@ -124,8 +132,8 @@ module Neo4j
|
|
124
132
|
|
125
133
|
def validate_option_combinations(options)
|
126
134
|
raise ArgumentError, "Cannot specify both :type and :origin (#{base_declaration})" if options[:type] && options[:origin]
|
127
|
-
raise ArgumentError, "Cannot specify both :type and :rel_class (#{base_declaration})" if options[:type] && options[:rel_class]
|
128
|
-
raise ArgumentError, "Cannot specify both :origin and :rel_class (#{base_declaration}" if options[:origin] && options[:rel_class]
|
135
|
+
# raise ArgumentError, "Cannot specify both :type and :rel_class (#{base_declaration})" if options[:type] && options[:rel_class] see issue #494
|
136
|
+
# raise ArgumentError, "Cannot specify both :origin and :rel_class (#{base_declaration}" if options[:origin] && options[:rel_class]
|
129
137
|
end
|
130
138
|
|
131
139
|
# Determine if model class as derived from the association name would be different than the one specified via the model_class key
|
@@ -13,7 +13,16 @@ module Neo4j
|
|
13
13
|
# @return the labels
|
14
14
|
# @see Neo4j-core
|
15
15
|
def labels
|
16
|
-
@_persisted_obj.labels
|
16
|
+
if @_persisted_obj.labels.nil?
|
17
|
+
r = queried_labels
|
18
|
+
@_persisted_obj.labels = r
|
19
|
+
else
|
20
|
+
@_persisted_obj.labels
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def queried_labels
|
25
|
+
self.class.query_as(:result).where("ID(result)" => self.neo_id).return("LABELS(result) as result_labels").first.result_labels.map(&:to_sym)
|
17
26
|
end
|
18
27
|
|
19
28
|
# adds one or more labels
|
@@ -63,11 +72,9 @@ module Neo4j
|
|
63
72
|
|
64
73
|
# Find all nodes/objects of this class
|
65
74
|
def all
|
66
|
-
self.
|
75
|
+
self.as(:n)
|
67
76
|
end
|
68
77
|
|
69
|
-
|
70
|
-
|
71
78
|
# Returns the object with the specified neo4j id.
|
72
79
|
# @param [String,Fixnum] id of node to find
|
73
80
|
def find(id)
|
@@ -3,6 +3,7 @@ class Neo4j::Node
|
|
3
3
|
|
4
4
|
# this is a plugin in the neo4j-core so that the Ruby wrapper will be wrapped around the Neo4j::Node objects
|
5
5
|
def wrapper
|
6
|
+
self.props.symbolize_keys!
|
6
7
|
most_concrete_class = sorted_wrapper_classes
|
7
8
|
return self unless most_concrete_class
|
8
9
|
wrapped_node = most_concrete_class.new
|
@@ -17,18 +17,10 @@ module Neo4j
|
|
17
17
|
# @param var [Symbol, String] The variable name to specify in the query
|
18
18
|
# @return [Neo4j::Core::Query]
|
19
19
|
def query_as(var)
|
20
|
-
self.class.query_as(var).where("ID(#{var})
|
20
|
+
self.class.query_as(var).where("ID(#{var})" => self.neo_id)
|
21
21
|
end
|
22
22
|
|
23
23
|
module ClassMethods
|
24
|
-
include Enumerable
|
25
|
-
|
26
|
-
#attr_writer :query_proxy
|
27
|
-
|
28
|
-
def each
|
29
|
-
self.query_as(:n).pluck(:n).each {|o| yield o }
|
30
|
-
end
|
31
|
-
|
32
24
|
# Returns a Query object with all nodes for the model matched as the specified variable name
|
33
25
|
#
|
34
26
|
# @example Return the registration number of all cars owned by a person over the age of 30
|
@@ -135,7 +135,7 @@ module Neo4j
|
|
135
135
|
def create(other_nodes, properties)
|
136
136
|
raise "Can only create associations on associations" unless @association
|
137
137
|
other_nodes = [other_nodes].flatten
|
138
|
-
|
138
|
+
properties = @association.inject_classname(properties)
|
139
139
|
other_nodes = other_nodes.map do |other_node|
|
140
140
|
case other_node
|
141
141
|
when Integer, String
|
@@ -145,7 +145,7 @@ module Neo4j
|
|
145
145
|
end
|
146
146
|
end.compact
|
147
147
|
|
148
|
-
raise ArgumentError, "Node must be of the association's class when model is specified" if @model && other_nodes.any? {|other_node| other_node.
|
148
|
+
raise ArgumentError, "Node must be of the association's class when model is specified" if @model && other_nodes.any? {|other_node| !other_node.is_a?(@model) }
|
149
149
|
other_nodes.each do |other_node|
|
150
150
|
#Neo4j::Transaction.run do
|
151
151
|
other_node.save if not other_node.persisted?
|
@@ -37,7 +37,7 @@ module Neo4j
|
|
37
37
|
def include?(other, target=nil)
|
38
38
|
raise(InvalidParameterError, ':include? only accepts nodes') unless other.respond_to?(:neo_id)
|
39
39
|
query_with_target(target) do |target|
|
40
|
-
self.where("#{target}
|
40
|
+
self.where("ID(#{target}) = {other_node_id}").params(other_node_id: other.neo_id).query.return("count(#{target}) as count").first.count > 0
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
@@ -59,7 +59,7 @@ module Neo4j
|
|
59
59
|
def exists_query_start(origin, condition, target)
|
60
60
|
case
|
61
61
|
when condition.class == Fixnum
|
62
|
-
self.where("ID(#{target}) =
|
62
|
+
self.where("ID(#{target}) = {exists_condition}").params(exists_condition: condition)
|
63
63
|
when condition.class == Hash
|
64
64
|
self.where(condition.keys.first => condition.values.first)
|
65
65
|
else
|
@@ -31,22 +31,17 @@ module Neo4j
|
|
31
31
|
alias_method :length, :count
|
32
32
|
|
33
33
|
def empty?
|
34
|
-
!self.exists?
|
34
|
+
!self.all.exists?
|
35
35
|
end
|
36
36
|
|
37
37
|
alias_method :blank?, :empty?
|
38
38
|
|
39
|
-
def include?(other)
|
40
|
-
raise(InvalidParameterError, ':include? only accepts nodes') unless other.respond_to?(:neo_id)
|
41
|
-
self.query_as(:n).where(n: {primary_key => other.id}).return("count(n) AS count").first.count > 0
|
42
|
-
end
|
43
|
-
|
44
39
|
private
|
45
40
|
|
46
41
|
def exists_query_start(node_condition)
|
47
42
|
case node_condition
|
48
43
|
when Fixnum
|
49
|
-
self.query_as(:n).where("ID(n)
|
44
|
+
self.query_as(:n).where("ID(n)" => node_condition)
|
50
45
|
when Hash
|
51
46
|
self.where(node_condition.keys.first => node_condition.values.first)
|
52
47
|
else
|
@@ -33,10 +33,9 @@ module Neo4j
|
|
33
33
|
|
34
34
|
conditions[attribute] = options[:case_sensitive] ? value : /^#{Regexp.escape(value.to_s)}$/i
|
35
35
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
record.errors.add(attribute, :taken, options.except(:case_sensitive, :scope).merge(:value => value)) if found.count > 0
|
36
|
+
found = record.class.as(:result).where(conditions)
|
37
|
+
found = found.where("NOT ID(result) = {record_neo_id}").params(record_neo_id: record.neo_id) if record.persisted?
|
38
|
+
record.errors.add(attribute, :taken, options.except(:case_sensitive, :scope).merge(:value => value)) if found.exists?
|
40
39
|
end
|
41
40
|
|
42
41
|
def message(instance)
|
@@ -24,7 +24,7 @@ module Neo4j::ActiveRel
|
|
24
24
|
set_timestamps
|
25
25
|
properties = convert_properties_to :db, props
|
26
26
|
rel = _create_rel(from_node, to_node, properties)
|
27
|
-
init_on_load(rel, from_node, to_node, @rel_type)
|
27
|
+
init_on_load(rel._persisted_obj, from_node, to_node, @rel_type)
|
28
28
|
true
|
29
29
|
end
|
30
30
|
|
@@ -62,7 +62,7 @@ module Neo4j::ActiveRel
|
|
62
62
|
props = self.class.default_property_values(self)
|
63
63
|
props.merge!(args[0]) if args[0].is_a?(Hash)
|
64
64
|
set_classname(props)
|
65
|
-
from_node
|
65
|
+
_rel_creation_query(from_node, to_node, props)
|
66
66
|
end
|
67
67
|
|
68
68
|
def class_as_constant(type)
|
@@ -80,5 +80,19 @@ module Neo4j::ActiveRel
|
|
80
80
|
def allows_any_class?(type)
|
81
81
|
self.class.send(type) == :any || self.class.send(type) == false
|
82
82
|
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
def _rel_creation_query(from_node, to_node, props)
|
87
|
+
from_class = from_node.class
|
88
|
+
to_class = to_node.class
|
89
|
+
Neo4j::Session.query.match(n1: from_class.mapped_label_name, n2: to_class.mapped_label_name)
|
90
|
+
.where("n1.#{from_class.primary_key} = {from_node_id}")
|
91
|
+
.where("n2.#{to_class.primary_key} = {to_node_id}")
|
92
|
+
.params(from_node_id: from_node.id, to_node_id: to_node.id)
|
93
|
+
.create("(n1)-[r:`#{type}`]->(n2)")
|
94
|
+
.with('r').set(r: props).return(:r).first.r
|
95
|
+
end
|
96
|
+
|
83
97
|
end
|
84
98
|
end
|
@@ -14,7 +14,7 @@ module Neo4j::ActiveRel
|
|
14
14
|
|
15
15
|
# Loads the relationship using its neo_id.
|
16
16
|
def find_by_id(key, session = Neo4j::Session.current!)
|
17
|
-
|
17
|
+
session.query.match("()-[r]-()").where("ID(r)" => key.to_i).limit(1).return(:r).first.r
|
18
18
|
end
|
19
19
|
|
20
20
|
# Performs a very basic match on the relationship.
|
@@ -1,22 +1,40 @@
|
|
1
1
|
module Neo4j::ActiveRel
|
2
2
|
# A container for ActiveRel's :inbound and :outbound methods. It provides lazy loading of nodes.
|
3
|
+
# It's important (or maybe not really IMPORTANT, but at least worth mentioning) that calling method_missing
|
4
|
+
# will result in a query to load the node if the node is not already loaded.
|
3
5
|
class RelatedNode
|
4
6
|
|
5
7
|
class InvalidParameterError < StandardError; end
|
6
8
|
|
9
|
+
# ActiveRel's related nodes can be initialized with nothing, an integer, or a fully wrapped node.
|
10
|
+
#
|
11
|
+
# Initialization with nothing happens when a new, non-persisted ActiveRel object is first initialized.
|
12
|
+
#
|
13
|
+
# Initialization with an integer happens when a relationship is loaded from the database. It loads using the ID
|
14
|
+
# because that is provided by the Cypher response and does not require an extra query.
|
15
|
+
#
|
16
|
+
# Initialization with a node doesn't appear to happen in the code. TODO: maybe find out why this is an option.
|
7
17
|
def initialize(node = nil)
|
8
18
|
@node = valid_node_param?(node) ? node : (raise InvalidParameterError, 'RelatedNode must be initialized with either a node ID or node' )
|
9
19
|
end
|
10
20
|
|
21
|
+
# Loads the node if needed, then conducts comparison.
|
11
22
|
def == (obj)
|
12
23
|
loaded if @node.is_a?(Fixnum)
|
13
24
|
@node == obj
|
14
25
|
end
|
15
26
|
|
27
|
+
# Returns the neo_id of a given node without loading.
|
28
|
+
def neo_id
|
29
|
+
loaded? ? @node.neo_id : @node
|
30
|
+
end
|
31
|
+
|
32
|
+
# Loads a node from the database or returns the node if already laoded
|
16
33
|
def loaded
|
17
34
|
@node = @node.respond_to?(:neo_id) ? @node : Neo4j::Node.load(@node)
|
18
35
|
end
|
19
36
|
|
37
|
+
# @return [Boolean] indicates whether a node has or has not been fully loaded from the database
|
20
38
|
def loaded?
|
21
39
|
@node.respond_to?(:neo_id)
|
22
40
|
end
|
data/lib/neo4j/migration.rb
CHANGED
@@ -13,11 +13,19 @@ module Neo4j
|
|
13
13
|
print string unless !!ENV['silenced']
|
14
14
|
end
|
15
15
|
|
16
|
+
def default_path
|
17
|
+
Rails.root if defined? Rails
|
18
|
+
end
|
19
|
+
|
20
|
+
def joined_path(path)
|
21
|
+
File.join(path, 'db', 'neo4j-migrate')
|
22
|
+
end
|
23
|
+
|
16
24
|
class AddIdProperty < Neo4j::Migration
|
17
25
|
attr_reader :models_filename
|
18
26
|
|
19
|
-
def initialize
|
20
|
-
@models_filename = File.join(
|
27
|
+
def initialize(path = default_path)
|
28
|
+
@models_filename = File.join(joined_path(path), 'add_id_property.yml')
|
21
29
|
end
|
22
30
|
|
23
31
|
def migrate
|
@@ -109,9 +117,9 @@ module Neo4j
|
|
109
117
|
|
110
118
|
class AddClassnames < Neo4j::Migration
|
111
119
|
|
112
|
-
def initialize
|
120
|
+
def initialize(path = default_path)
|
113
121
|
@classnames_filename = 'add_classnames.yml'
|
114
|
-
@classnames_filepath = File.join(
|
122
|
+
@classnames_filepath = File.join(joined_path(path), classnames_filename)
|
115
123
|
end
|
116
124
|
|
117
125
|
def migrate
|
@@ -3,15 +3,16 @@ require 'neo4j/migration'
|
|
3
3
|
namespace :neo4j do
|
4
4
|
desc "Run a script against the database to perform system-wide changes"
|
5
5
|
task :migrate, [:task_name, :subtask] => :environment do |_, args|
|
6
|
+
path = Rake.original_dir
|
6
7
|
migration_task = args[:task_name]
|
7
8
|
task_name_constant = migration_task.split('_').map { |word| word.capitalize }.join('')
|
8
9
|
begin
|
9
10
|
migration_class = "Neo4j::Migration::#{task_name_constant}".constantize
|
10
11
|
rescue NameError
|
11
|
-
load File.join(
|
12
|
+
load File.join(path, 'db', 'neo4j-migrate', "#{migration_task}.rb")
|
12
13
|
migration_class = "#{task_name_constant}".constantize
|
13
14
|
end
|
14
|
-
migration = migration_class.new
|
15
|
+
migration = migration_class.new(path)
|
15
16
|
|
16
17
|
subtask = args[:subtask]
|
17
18
|
if subtask
|
data/lib/neo4j/version.rb
CHANGED
data/neo4j.gemspec
CHANGED
@@ -31,7 +31,7 @@ A Neo4j OGM (Object-Graph-Mapper) for use in Ruby on Rails and Rack frameworks,
|
|
31
31
|
s.add_dependency("activesupport", "~> 4")
|
32
32
|
s.add_dependency("railties", "~> 4")
|
33
33
|
s.add_dependency('active_attr', "~> 0.8")
|
34
|
-
s.add_dependency("neo4j-core", "~> 3.0.
|
34
|
+
s.add_dependency("neo4j-core", "~> 3.0.2")
|
35
35
|
|
36
36
|
if RUBY_PLATFORM =~ /java/
|
37
37
|
s.add_dependency("neo4j-community", '~> 2.0')
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: neo4j
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.0.
|
4
|
+
version: 3.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andreas Ronge
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-10-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: orm_adapter
|
@@ -86,14 +86,14 @@ dependencies:
|
|
86
86
|
requirements:
|
87
87
|
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: 3.0.
|
89
|
+
version: 3.0.2
|
90
90
|
type: :runtime
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: 3.0.
|
96
|
+
version: 3.0.2
|
97
97
|
description: |
|
98
98
|
A Neo4j OGM (Object-Graph-Mapper) for use in Ruby on Rails and Rack frameworks, intended as a complete replacement for ActiveRecord.
|
99
99
|
email: andreas.ronge@gmail.com
|