neo4j 3.0.1 → 3.0.2
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/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
|