neo4j 3.0.3 → 3.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4d902cb2867667c62e30b5a4c0ca2aa5341b06cc
4
- data.tar.gz: 95ce7ebf16a229a510ab76aeb1e40b69275e1dc3
3
+ metadata.gz: bf2546cbe829d338babc703fcecdeff5650e8fd5
4
+ data.tar.gz: 094b2019bb62cb8e9f5e510eb54cf00f51c6131f
5
5
  SHA512:
6
- metadata.gz: 265e6724e37c3a89d7af59dcc2484915cd0d39b60e1cf642bd22ed1f0a6d997aa09163186148e78803f7cec552be2c07f0ce9eb503f572208c116313da6db764
7
- data.tar.gz: c84429373e502d634d4b29c6a0ab864af15e4def869260693bfba8789c4a610c2406f2dd611d6d84317ca2a55199c267d642342f1610966d5a210a351ae873eb
6
+ metadata.gz: b7552de25d876bd2b98038637c517ae77c47c04ae5d3fbd0a14852710998a3549d1ce981a9c35eea94e84cf1dcc04f469497ae7c7eb9be45a76b77f813900bd8
7
+ data.tar.gz: ba45f543a6cbce758ccfba472789cfb41ba78ce8ee6fe70db8e187371a1a638e83c86a6dae316a4ff786046a61b2ab3a984001993d4150b30e9eee57c4b89fcd
data/Gemfile CHANGED
@@ -2,7 +2,7 @@ source 'http://rubygems.org'
2
2
 
3
3
  gemspec
4
4
 
5
- gem 'neo4j-core', github: 'neo4jrb/neo4j-core' if ENV["TRAVIS"]
5
+ #gem 'neo4j-core', github: 'neo4jrb/neo4j-core', branch: 'master'
6
6
  #gem 'neo4j-core', git: 'https://github.com/neo4jrb/neo4j-core'
7
7
  #gem 'orm_adapter', :path => '../orm_adapter'
8
8
 
@@ -27,25 +27,21 @@ module Neo4j::ActiveNode
27
27
 
28
28
  module TypeMethods
29
29
  def define_id_methods(clazz, name, conf)
30
- validate_conf(conf)
30
+ raise "Expected a Hash, got #{conf.class} (#{conf.to_s}) for id_property" unless conf.is_a?(Hash)
31
31
  if conf[:on]
32
32
  define_custom_method(clazz, name, conf[:on])
33
33
  elsif conf[:auto]
34
34
  raise "only :uuid auto id_property allowed, got #{conf[:auto]}" unless conf[:auto] == :uuid
35
35
  define_uuid_method(clazz, name)
36
- else conf.empty?
36
+ elsif conf.empty?
37
37
  define_property_method(clazz, name)
38
+ else
39
+ raise "Illegal value #{conf.inspect} for id_property, expected :on or :auto"
38
40
  end
39
41
  end
40
42
 
41
43
  private
42
44
 
43
- def validate_conf(conf)
44
- return if conf.empty?
45
- raise "Expected a Hash, got #{conf.class} (#{conf.to_s}) for id_property" unless conf.is_a?(Hash)
46
- raise "Illegal value #{conf.inspect} for id_property, expected :on or :auto" unless conf.include?(:auto) || conf.include?(:on)
47
- end
48
-
49
45
  def define_property_method(clazz, name)
50
46
  clear_methods(clazz, name)
51
47
 
@@ -1,4 +1,5 @@
1
1
  class Neo4j::Node
2
+ # The wrapping process is what transforms a raw CypherNode or EmbeddedNode from Neo4j::Core into a healthy ActiveNode (or ActiveRel) object.
2
3
  module Wrapper
3
4
 
4
5
  # this is a plugin in the neo4j-core so that the Ruby wrapper will be wrapped around the Neo4j::Node objects
@@ -23,6 +24,7 @@ class Neo4j::Node
23
24
  end
24
25
  end
25
26
 
27
+ # Makes the determination of whether to use <tt>_classname</tt> (or whatever is defined by config) or the node's labels.
26
28
  def sorted_wrapper_classes
27
29
  if self.props.is_a?(Hash) && self.props.has_key?(Neo4j::Config.class_name_property)
28
30
  self.props[Neo4j::Config.class_name_property].constantize
@@ -11,6 +11,27 @@ module Neo4j
11
11
  # Will be nil when using QueryProxy chains on class methods.
12
12
  attr_reader :caller
13
13
 
14
+ # QueryProxy is ActiveNode's Cypher DSL. While the name might imply that it creates queries in a general sense,
15
+ # it is actually referring to <tt>Neo4j::Core::Query</tt>, which is a pure Ruby Cypher DSL provided by the <tt>neo4j-core</tt> gem.
16
+ # QueryProxy provides ActiveRecord-like methods for common patterns. When it's not handling CRUD for relationships and queries, it
17
+ # provides ActiveNode's association chaining (`student.lessons.teachers.where(age: 30).hobbies`) and enjoys long walks on the
18
+ # beach.
19
+ #
20
+ # It should not ever be necessary to instantiate a new QueryProxy object directly, it always happens as a result of
21
+ # calling a method that makes use of it.
22
+ #
23
+ # @param [Constant] model The class which included ActiveNode (typically a model, hence the name) from which the query
24
+ # originated.
25
+ # @param [Neo4j::ActiveNode::HasN::Association] association The ActiveNode association (an object created by a <tt>has_one</tt> or
26
+ # <tt>has_many</tt>) that created this object.
27
+ # @param [Hash] options Additional options pertaining to the QueryProxy object. These may include:
28
+ # * node_var: A string or symbol to be used by Cypher within its query string as an identifier
29
+ # * rel_var: Same as above but pertaining to a relationship identifier
30
+ # * session: The session to be used for this query
31
+ # * caller: The node instance at the start of the QueryProxy chain
32
+ # * query_proxy: An existing QueryProxy chain upon which this new object should be built
33
+ #
34
+ # QueryProxy objects are evaluated lazily.
14
35
  def initialize(model, association = nil, options = {})
15
36
  @model = model
16
37
  @association = association
@@ -24,10 +45,21 @@ module Neo4j
24
45
  @params = options[:query_proxy] ? options[:query_proxy].instance_variable_get('@params') : {}
25
46
  end
26
47
 
48
+ # The current node identifier on deck, so to speak. It is the object that will be returned by calling `each` and the last node link
49
+ # in the QueryProxy chain.
27
50
  def identity
28
51
  @node_var || :result
29
52
  end
30
53
 
54
+ # The relationship identifier most recently used by the QueryProxy chain.
55
+ def rel_identity
56
+ @rel_var
57
+ end
58
+
59
+ # Executes the query against the database if the results are not already present in a node's association cache. This method is
60
+ # shared by <tt>each</tt>, <tt>each_rel</tt>, and <tt>each_with_rel</tt>.
61
+ # @param [String,Symbol] node The string or symbol of the node to return from the database.
62
+ # @param [String,Symbol] rel The string or symbol of a relationship to return from the database.
31
63
  def enumerable_query(node, rel = nil)
32
64
  pluck_this = rel.nil? ? [node] : [node, rel]
33
65
  return self.pluck(*pluck_this) if @association.nil? || caller.nil?
@@ -40,6 +72,10 @@ module Neo4j
40
72
  association_collection
41
73
  end
42
74
 
75
+ # Just like every other <tt>each</tt> but it allows for optional params to support the versions that also return relationships.
76
+ # The <tt>node</tt> and <tt>rel</tt> params are typically used by those other methods but there's nothing stopping you from
77
+ # using `your_node.each(true, true)` instead of `your_node.each_with_rel`.
78
+ # @return [Enumerable] An enumerable containing some combination of nodes and rels.
43
79
  def each(node = true, rel = nil, &block)
44
80
  if node && rel
45
81
  enumerable_query(identity, @rel_var).each { |obj, rel| yield obj, rel }
@@ -49,14 +85,23 @@ module Neo4j
49
85
  end
50
86
  end
51
87
 
88
+ # When called at the end of a QueryProxy chain, it will return the resultant relationship objects intead of nodes.
89
+ # For example, to return the relationship between a given student and their lessons:
90
+ # student.lessons.each_rel do |rel|
91
+ # @return [Enumerable] An enumerable containing any number of applicable relationship objects.
52
92
  def each_rel(&block)
53
93
  block_given? ? each(false, true, &block) : to_enum(:each, false, true)
54
94
  end
55
95
 
96
+ # When called at the end of a QueryProxy chain, it will return the nodes and relationships of the last link.
97
+ # For example, to return a lesson and each relationship to a given student:
98
+ # student.lessons.each_with_rel do |lesson, rel|
56
99
  def each_with_rel(&block)
57
100
  block_given? ? each(true, true, &block) : to_enum(:each, true, true)
58
101
  end
59
102
 
103
+ # Does exactly what you would hope. Without it, comparing `bobby.lessons == sandy.lessons` would evaluate to false because it
104
+ # would be comparing the QueryProxy objects, not the lessons themselves.
60
105
  def ==(value)
61
106
  self.to_a == value
62
107
  end
@@ -89,7 +134,10 @@ module Neo4j
89
134
  query_as(identity)
90
135
  end
91
136
 
92
- # Build a Neo4j::Core::Query object for the QueryProxy
137
+ # Build a Neo4j::Core::Query object for the QueryProxy. This is necessary when you want to take an existing QueryProxy chain
138
+ # and work with it from the more powerful (but less friendly) Neo4j::Core::Query.
139
+ # @param [String,Symbol] var The identifier to use for node at this link of the QueryProxy chain.
140
+ # student.lessons.query_as(:l).with('your cypher here...')
93
141
  def query_as(var)
94
142
  var = @node_var if @node_var
95
143
  query = if @association
@@ -106,7 +154,7 @@ module Neo4j
106
154
  end
107
155
  end
108
156
 
109
- # Cypher string for the QueryProxy's query
157
+ # Cypher string for the QueryProxy's query. This will not include params. For the full output, see <tt>to_cypher_with_params</tt>.
110
158
  def to_cypher
111
159
  query.to_cypher
112
160
  end
@@ -49,11 +49,36 @@ module Neo4j
49
49
  end
50
50
  end
51
51
 
52
+ # Deletes a group of nodes and relationships within a QP chain. When identifier is omitted, it will remove the last link in the chain.
53
+ # The optional argument must be a node identifier. A relationship identifier will result in a Cypher Error
54
+ # @param [String,Symbol] the optional identifier of the link in the chain to delete.
55
+ def delete_all(identifier = nil)
56
+ query_with_target(identifier) do |target|
57
+ begin
58
+ self.query.with(target).match("(#{target})-[#{target}_rel]-()").delete("#{target}, #{target}_rel").exec
59
+ rescue Neo4j::Session::CypherError
60
+ self.query.delete(target).exec
61
+ end
62
+ self.caller.clear_association_cache if self.caller.respond_to?(:clear_association_cache)
63
+ end
64
+ end
65
+
66
+ # Shorthand for `MATCH (start)-[r]-(other_node) WHERE ID(other_node) = #{other_node.neo_id}`
67
+ # @return [Neo4j::ActiveNode::Query::QueryProxy] A QueryProxy object upon which you can build.
68
+ def match_to(node)
69
+ self.where(neo_id: node.neo_id)
70
+ end
71
+
72
+ # Gives you the first relationship between the last link of a QueryProxy chain and a given node
73
+ # Shorthand for `MATCH (start)-[r]-(other_node) WHERE ID(other_node) = #{other_node.neo_id} RETURN r`
74
+ def first_rel_to(node)
75
+ self.where(neo_id: node.neo_id).limit(1).pluck(rel_identity).first
76
+ end
77
+
52
78
  private
53
79
 
54
80
  def query_with_target(target, &block)
55
- target = target.nil? ? identity : target
56
- block.yield(target)
81
+ block.yield(target || identity)
57
82
  end
58
83
 
59
84
  def exists_query_start(origin, condition, target)
@@ -36,11 +36,6 @@ module Neo4j
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
  def find_in_batches(options = {})
45
40
  self.query_as(:n).return(:n).find_in_batches(:n, primary_key, options) do |batch|
46
41
  yield batch.map(&:n)
@@ -1,5 +1,5 @@
1
1
  module Neo4j::ActiveNode
2
- # A reflection contains information about an association.
2
+ # A reflection contains information about an association.
3
3
  # They are often used in connection with form builders to determine associated classes.
4
4
  # This module contains methods related to the creation and retrieval of reflections.
5
5
  module Reflection
@@ -4,8 +4,8 @@ module Neo4j::ActiveRel
4
4
  include Neo4j::Shared::Persistence
5
5
 
6
6
  class RelInvalidError < RuntimeError; end
7
-
8
7
  class ModelClassInvalidError < RuntimeError; end
8
+ class RelCreateFailedError < RuntimeError; end
9
9
 
10
10
  def clear_association_cache; end
11
11
 
@@ -86,12 +86,16 @@ module Neo4j::ActiveRel
86
86
  def _rel_creation_query(from_node, to_node, props)
87
87
  from_class = from_node.class
88
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
89
+ begin
90
+ Neo4j::Session.query.match(n1: from_class.mapped_label_name, n2: to_class.mapped_label_name)
91
+ .where("n1.#{from_class.primary_key} = {from_node_id}")
92
+ .where("n2.#{to_class.primary_key} = {to_node_id}")
93
+ .params(from_node_id: from_node.id, to_node_id: to_node.id)
94
+ .create("(n1)-[r:`#{type}`]->(n2)")
95
+ .with('r').set(r: props).return(:r).first.r
96
+ rescue NoMethodError
97
+ raise RelCreateFailedError, "Unable to create relationship. from_node: #{from_node}, to_node: #{to_node}"
98
+ end
95
99
  end
96
100
 
97
101
  end
data/lib/neo4j/config.rb CHANGED
@@ -113,7 +113,10 @@ module Neo4j
113
113
  Neo4j::Config[:class_name_property] || :_classname
114
114
  end
115
115
 
116
+ def include_root_in_json
117
+ # we use ternary because a simple || will always evaluate true
118
+ Neo4j::Config[:include_root_in_json].nil? ? true : Neo4j::Config[:include_root_in_json]
119
+ end
116
120
  end
117
121
  end
118
-
119
- end
122
+ end
@@ -8,9 +8,8 @@ module Neo4j
8
8
  end
9
9
 
10
10
  def self.create_from(source, page, per_page, order = nil)
11
- #partial = source.drop((page-1) * per_page).first(per_page)
12
11
  target = source.node_var
13
- partial = source.skip(page-1).limit(per_page)
12
+ partial = source.skip((page - 1) * per_page).limit(per_page)
14
13
  ordered_partial, ordered_source = if order
15
14
  [partial.order_by(order), source.query.with("#{target} as #{target}").pluck("COUNT(#{target})").first]
16
15
  else
data/lib/neo4j/shared.rb CHANGED
@@ -22,7 +22,7 @@ module Neo4j
22
22
  end
23
23
 
24
24
  included do
25
- self.include_root_in_json = true
25
+ self.include_root_in_json = Neo4j::Config.include_root_in_json
26
26
 
27
27
  def self.i18n_scope
28
28
  :neo4j
data/lib/neo4j/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Neo4j
2
- VERSION = "3.0.3"
2
+ VERSION = "3.0.4"
3
3
  end
data/neo4j.gemspec CHANGED
@@ -16,7 +16,7 @@ Gem::Specification.new do |s|
16
16
  s.summary = "A graph database for Ruby"
17
17
  s.license = 'MIT'
18
18
  s.description = <<-EOF
19
- A Neo4j OGM (Object-Graph-Mapper) for use in Ruby on Rails and Rack frameworks, intended as a complete replacement for ActiveRecord.
19
+ A Neo4j OGM (Object-Graph-Mapper) for use in Ruby on Rails and Rack frameworks heavily inspired by ActiveRecord.
20
20
  EOF
21
21
 
22
22
  s.require_path = 'lib'
@@ -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.5")
34
+ s.add_dependency("neo4j-core", "~> 3.0.8")
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.3
4
+ version: 3.0.4
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-03 00:00:00.000000000 Z
11
+ date: 2014-11-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: orm_adapter
@@ -86,16 +86,16 @@ dependencies:
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: 3.0.5
89
+ version: 3.0.8
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.5
96
+ version: 3.0.8
97
97
  description: |
98
- A Neo4j OGM (Object-Graph-Mapper) for use in Ruby on Rails and Rack frameworks, intended as a complete replacement for ActiveRecord.
98
+ A Neo4j OGM (Object-Graph-Mapper) for use in Ruby on Rails and Rack frameworks heavily inspired by ActiveRecord.
99
99
  email: andreas.ronge@gmail.com
100
100
  executables:
101
101
  - neo4j-jars