neo4j 5.0.15 → 5.1.0.rc.1
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.md +60 -5
- data/Gemfile +1 -1
- data/README.md +8 -0
- data/lib/neo4j.rb +4 -0
- data/lib/neo4j/active_node.rb +3 -1
- data/lib/neo4j/active_node/dependent/association_methods.rb +4 -2
- data/lib/neo4j/active_node/dependent/query_proxy_methods.rb +3 -3
- data/lib/neo4j/active_node/has_n.rb +103 -36
- data/lib/neo4j/active_node/has_n/association.rb +10 -33
- data/lib/neo4j/active_node/has_n/association_cypher_methods.rb +108 -0
- data/lib/neo4j/active_node/id_property.rb +19 -11
- data/lib/neo4j/active_node/id_property/accessor.rb +62 -0
- data/lib/neo4j/active_node/labels.rb +13 -2
- data/lib/neo4j/active_node/persistence.rb +19 -4
- data/lib/neo4j/active_node/property.rb +4 -3
- data/lib/neo4j/active_node/query/query_proxy.rb +29 -13
- data/lib/neo4j/active_node/query/query_proxy_eager_loading.rb +8 -0
- data/lib/neo4j/active_node/query/query_proxy_enumerable.rb +7 -0
- data/lib/neo4j/active_node/query/query_proxy_link.rb +16 -6
- data/lib/neo4j/active_node/query/query_proxy_methods.rb +4 -0
- data/lib/neo4j/active_node/query/query_proxy_unpersisted.rb +17 -0
- data/lib/neo4j/active_node/unpersisted.rb +49 -0
- data/lib/neo4j/active_node/validations.rb +1 -1
- data/lib/neo4j/active_rel.rb +17 -0
- data/lib/neo4j/active_rel/persistence.rb +10 -5
- data/lib/neo4j/active_rel/property.rb +17 -5
- data/lib/neo4j/railtie.rb +2 -1
- data/lib/neo4j/shared/declared_property_manager.rb +10 -0
- data/lib/neo4j/shared/initialize.rb +3 -3
- data/lib/neo4j/shared/property.rb +7 -51
- data/lib/neo4j/shared/property/default_property.rb +0 -0
- data/lib/neo4j/shared/type_converters.rb +49 -6
- data/lib/neo4j/shared/typecaster.rb +22 -18
- data/lib/neo4j/shared/validations.rb +1 -1
- data/lib/neo4j/version.rb +1 -1
- data/neo4j.gemspec +1 -1
- metadata +12 -7
@@ -6,6 +6,7 @@ module Neo4j
|
|
6
6
|
class Association
|
7
7
|
include Neo4j::Shared::RelTypeConverters
|
8
8
|
include Neo4j::ActiveNode::Dependent::AssociationMethods
|
9
|
+
include Neo4j::ActiveNode::HasN::AssociationCypherMethods
|
9
10
|
|
10
11
|
attr_reader :type, :name, :relationship, :direction, :dependent, :model_class
|
11
12
|
|
@@ -29,7 +30,9 @@ module Neo4j
|
|
29
30
|
|
30
31
|
def refresh_model_class!
|
31
32
|
@pending_model_refresh = @target_classes_or_nil = nil
|
32
|
-
|
33
|
+
|
34
|
+
# Using #to_s on purpose here to take care of classes/strings/symbols
|
35
|
+
@model_class = @model_class.to_s.constantize if @model_class
|
33
36
|
end
|
34
37
|
|
35
38
|
def queue_model_refresh!
|
@@ -49,12 +52,6 @@ module Neo4j
|
|
49
52
|
end
|
50
53
|
end
|
51
54
|
|
52
|
-
# Return cypher partial query string for the relationship part of a MATCH (arrow / relationship definition)
|
53
|
-
def arrow_cypher(var = nil, properties = {}, create = false, reverse = false)
|
54
|
-
validate_origin!
|
55
|
-
direction_cypher(get_relationship_cypher(var, properties, create), create, reverse)
|
56
|
-
end
|
57
|
-
|
58
55
|
def pending_model_refresh?
|
59
56
|
!!@pending_model_refresh
|
60
57
|
end
|
@@ -110,9 +107,12 @@ module Neo4j
|
|
110
107
|
|
111
108
|
def relationship_type(create = false)
|
112
109
|
case
|
113
|
-
when relationship_class
|
114
|
-
|
115
|
-
when @
|
110
|
+
when relationship_class
|
111
|
+
relationship_class_type
|
112
|
+
when @relationship_type
|
113
|
+
@relationship_type
|
114
|
+
when @origin
|
115
|
+
origin_type
|
116
116
|
else
|
117
117
|
(create || exceptional_target_class?) && decorated_rel_type(@name)
|
118
118
|
end
|
@@ -148,14 +148,6 @@ module Neo4j
|
|
148
148
|
Neo4j::Config.association_model_namespace_string
|
149
149
|
end
|
150
150
|
|
151
|
-
def direction_cypher(relationship_cypher, create, reverse = false)
|
152
|
-
case get_direction(create, reverse)
|
153
|
-
when :out then "-#{relationship_cypher}->"
|
154
|
-
when :in then "<-#{relationship_cypher}-"
|
155
|
-
when :both then "-#{relationship_cypher}-"
|
156
|
-
end
|
157
|
-
end
|
158
|
-
|
159
151
|
def get_direction(create, reverse = false)
|
160
152
|
dir = (create && @direction == :both) ? :out : @direction
|
161
153
|
if reverse
|
@@ -169,21 +161,6 @@ module Neo4j
|
|
169
161
|
end
|
170
162
|
end
|
171
163
|
|
172
|
-
def get_relationship_cypher(var, properties, create)
|
173
|
-
relationship_type = relationship_type(create)
|
174
|
-
relationship_name_cypher = ":`#{relationship_type}`" if relationship_type
|
175
|
-
properties_string = get_properties_string(properties)
|
176
|
-
|
177
|
-
"[#{var}#{relationship_name_cypher}#{properties_string}]"
|
178
|
-
end
|
179
|
-
|
180
|
-
def get_properties_string(properties)
|
181
|
-
p = properties.map do |key, value|
|
182
|
-
"#{key}: #{value.inspect}"
|
183
|
-
end.join(', ')
|
184
|
-
p.size == 0 ? '' : " {#{p}}"
|
185
|
-
end
|
186
|
-
|
187
164
|
def origin_association
|
188
165
|
target_class.associations[@origin]
|
189
166
|
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
module Neo4j
|
2
|
+
module ActiveNode
|
3
|
+
module HasN
|
4
|
+
module AssociationCypherMethods
|
5
|
+
# Return cypher partial query string for the relationship part of a MATCH (arrow / relationship definition)
|
6
|
+
def arrow_cypher(var = nil, properties = {}, create = false, reverse = false, length = nil)
|
7
|
+
validate_origin!
|
8
|
+
|
9
|
+
if create && length.present?
|
10
|
+
fail(ArgumentError, 'rel_length option cannot be specified when creating a relationship')
|
11
|
+
end
|
12
|
+
|
13
|
+
direction_cypher(get_relationship_cypher(var, properties, create, length), create, reverse)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def direction_cypher(relationship_cypher, create, reverse = false)
|
19
|
+
case get_direction(create, reverse)
|
20
|
+
when :out
|
21
|
+
"-#{relationship_cypher}->"
|
22
|
+
when :in
|
23
|
+
"<-#{relationship_cypher}-"
|
24
|
+
when :both
|
25
|
+
"-#{relationship_cypher}-"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def get_relationship_cypher(var, properties, create, length)
|
30
|
+
relationship_type = relationship_type(create)
|
31
|
+
relationship_name_cypher = ":`#{relationship_type}`" if relationship_type
|
32
|
+
rel_length_cypher = cypher_for_rel_length(length)
|
33
|
+
properties_string = get_properties_string(properties)
|
34
|
+
|
35
|
+
"[#{var}#{relationship_name_cypher}#{rel_length_cypher}#{properties_string}]"
|
36
|
+
end
|
37
|
+
|
38
|
+
def get_properties_string(properties)
|
39
|
+
p = properties.map do |key, value|
|
40
|
+
"#{key}: #{value.inspect}"
|
41
|
+
end.join(', ')
|
42
|
+
p.size == 0 ? '' : " {#{p}}"
|
43
|
+
end
|
44
|
+
|
45
|
+
VALID_REL_LENGTH_SYMBOLS = {
|
46
|
+
any: '*'
|
47
|
+
}
|
48
|
+
|
49
|
+
def cypher_for_rel_length(length)
|
50
|
+
return nil if length.blank?
|
51
|
+
|
52
|
+
validate_rel_length!(length)
|
53
|
+
|
54
|
+
case length
|
55
|
+
when Symbol then VALID_REL_LENGTH_SYMBOLS[length]
|
56
|
+
when Fixnum then "*#{length}"
|
57
|
+
when Range then cypher_for_range_rel_length(length)
|
58
|
+
when Hash then cypher_for_hash_rel_length(length)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def cypher_for_range_rel_length(length)
|
63
|
+
range_end = length.end
|
64
|
+
range_end = nil if range_end == Float::INFINITY
|
65
|
+
"*#{length.begin}..#{range_end}"
|
66
|
+
end
|
67
|
+
|
68
|
+
def cypher_for_hash_rel_length(length)
|
69
|
+
range_end = length[:max]
|
70
|
+
range_end = nil if range_end == Float::INFINITY
|
71
|
+
"*#{length[:min]}..#{range_end}"
|
72
|
+
end
|
73
|
+
|
74
|
+
def validate_rel_length!(length)
|
75
|
+
message = rel_length_error_message(length)
|
76
|
+
fail(ArgumentError, "Invalid value for rel_length (#{length.inspect}): #{message}") if message
|
77
|
+
true
|
78
|
+
end
|
79
|
+
|
80
|
+
def rel_length_error_message(length)
|
81
|
+
case length
|
82
|
+
when Fixnum then 'cannot be negative' if length < 0
|
83
|
+
when Symbol then rel_length_symbol_error_message(length)
|
84
|
+
when Range then rel_length_range_error_message(length)
|
85
|
+
when Hash then rel_length_hash_error_message(length)
|
86
|
+
else 'should be a Symbol, Fixnum, Range or Hash'
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def rel_length_symbol_error_message(length)
|
91
|
+
"expecting one of #{VALID_REL_LENGTH_SYMBOLS.keys.inspect}" if !VALID_REL_LENGTH_SYMBOLS.key?(length)
|
92
|
+
end
|
93
|
+
|
94
|
+
def rel_length_range_error_message(length)
|
95
|
+
if length.begin > length.end
|
96
|
+
'cannot be a decreasing Range'
|
97
|
+
elsif length.begin < 0
|
98
|
+
'cannot include negative values'
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def rel_length_hash_error_message(length)
|
103
|
+
'Hash keys should be a subset of [:min, :max]' if (length.keys & [:min, :max]) != length.keys
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -34,7 +34,7 @@ module Neo4j::ActiveNode
|
|
34
34
|
#
|
35
35
|
module IdProperty
|
36
36
|
extend ActiveSupport::Concern
|
37
|
-
|
37
|
+
include Accessor
|
38
38
|
|
39
39
|
module TypeMethods
|
40
40
|
def define_id_methods(clazz, name, conf)
|
@@ -90,7 +90,7 @@ module Neo4j::ActiveNode
|
|
90
90
|
end
|
91
91
|
|
92
92
|
def #{name}
|
93
|
-
|
93
|
+
default_property_value
|
94
94
|
end
|
95
95
|
|
96
96
|
alias_method :id, :#{name}
|
@@ -102,12 +102,12 @@ module Neo4j::ActiveNode
|
|
102
102
|
|
103
103
|
clazz.module_eval(%{
|
104
104
|
default_property :#{name} do |instance|
|
105
|
-
|
106
|
-
|
105
|
+
raise "Specifying custom id_property #{name} on non-existent method #{on}" unless instance.respond_to?(:#{on})
|
106
|
+
instance.#{on}
|
107
107
|
end
|
108
108
|
|
109
109
|
def #{name}
|
110
|
-
|
110
|
+
default_property_value
|
111
111
|
end
|
112
112
|
|
113
113
|
alias_method :id, :#{name}
|
@@ -124,6 +124,8 @@ module Neo4j::ActiveNode
|
|
124
124
|
|
125
125
|
|
126
126
|
module ClassMethods
|
127
|
+
attr_accessor :manual_id_property
|
128
|
+
|
127
129
|
def find_by_neo_id(id)
|
128
130
|
Neo4j::Node.load(id)
|
129
131
|
end
|
@@ -137,12 +139,14 @@ module Neo4j::ActiveNode
|
|
137
139
|
end
|
138
140
|
|
139
141
|
def id_property(name, conf = {})
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
142
|
+
self.manual_id_property = true
|
143
|
+
Neo4j::Session.on_session_available do |_|
|
144
|
+
@id_property_info = {name: name, type: conf}
|
145
|
+
TypeMethods.define_id_methods(self, name, conf)
|
146
|
+
constraint(name, type: :unique) unless conf[:constraint] == false
|
144
147
|
|
145
|
-
|
148
|
+
self.define_singleton_method(:find_by_id) { |key| self.where(name => key).first }
|
149
|
+
end
|
146
150
|
end
|
147
151
|
|
148
152
|
# rubocop:disable Style/PredicateName
|
@@ -165,6 +169,10 @@ module Neo4j::ActiveNode
|
|
165
169
|
id_property_info[:name]
|
166
170
|
end
|
167
171
|
|
172
|
+
def manual_id_property?
|
173
|
+
!!manual_id_property
|
174
|
+
end
|
175
|
+
|
168
176
|
alias_method :primary_key, :id_property_name
|
169
177
|
|
170
178
|
private
|
@@ -173,7 +181,7 @@ module Neo4j::ActiveNode
|
|
173
181
|
if id_property?
|
174
182
|
unless mapped_label.uniqueness_constraints[:property_keys].include?([name])
|
175
183
|
# Neo4j Embedded throws a crazy error when a constraint can't be dropped
|
176
|
-
drop_constraint(id_property_name, type: :unique)
|
184
|
+
drop_constraint(id_property_name, type: :unique) if constraint?(mapped_label_name, id_property_name)
|
177
185
|
end
|
178
186
|
end
|
179
187
|
rescue Neo4j::Server::CypherResponse::ResponseError, Java::OrgNeo4jCypher::CypherExecutionException
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Neo4j::ActiveNode::IdProperty
|
2
|
+
# Provides get/set of the Id Property values.
|
3
|
+
# Some methods
|
4
|
+
module Accessor
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
attr_reader :default_property_value
|
8
|
+
|
9
|
+
def default_properties=(properties)
|
10
|
+
@default_property_value = properties[default_property_key]
|
11
|
+
end
|
12
|
+
|
13
|
+
def default_property(key)
|
14
|
+
return nil unless key == default_property_key
|
15
|
+
default_property_value
|
16
|
+
end
|
17
|
+
|
18
|
+
def default_property_key
|
19
|
+
self.class.default_property_key
|
20
|
+
end
|
21
|
+
|
22
|
+
def default_properties
|
23
|
+
@default_properties ||= Hash.new(nil)
|
24
|
+
end
|
25
|
+
|
26
|
+
module ClassMethods
|
27
|
+
def default_property_key
|
28
|
+
@default_property_key ||= default_properties_keys.first
|
29
|
+
end
|
30
|
+
|
31
|
+
# TODO: Move this to the DeclaredPropertyManager
|
32
|
+
def default_property(name, &block)
|
33
|
+
reset_default_properties(name) if default_properties.respond_to?(:size)
|
34
|
+
default_properties[name] = block
|
35
|
+
end
|
36
|
+
|
37
|
+
# @return [Hash<Symbol,Proc>]
|
38
|
+
def default_properties
|
39
|
+
@default_property ||= {}
|
40
|
+
end
|
41
|
+
|
42
|
+
def default_properties_keys
|
43
|
+
@default_properties_keys ||= default_properties.keys
|
44
|
+
end
|
45
|
+
|
46
|
+
def reset_default_properties(name_to_keep)
|
47
|
+
default_properties.each_key do |property|
|
48
|
+
@default_properties_keys = nil
|
49
|
+
undef_method(property) unless property == name_to_keep
|
50
|
+
end
|
51
|
+
@default_properties_keys = nil
|
52
|
+
@default_property = {}
|
53
|
+
end
|
54
|
+
|
55
|
+
def default_property_values(instance)
|
56
|
+
default_properties.each_with_object({}) do |(key, block), result|
|
57
|
+
result[key] = block.call(instance)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -103,7 +103,7 @@ module Neo4j
|
|
103
103
|
# Finds the first record matching the specified conditions. There is no implied ordering so if order matters, you should specify it yourself.
|
104
104
|
# @param Hash args of arguments to find
|
105
105
|
def find_by(values)
|
106
|
-
all.
|
106
|
+
all.where(values).limit(1).query_as(:n).pluck(:n).first
|
107
107
|
end
|
108
108
|
|
109
109
|
# Like find_by, except that if no record is found, raises a RecordNotFound error.
|
@@ -147,6 +147,7 @@ module Neo4j
|
|
147
147
|
# end
|
148
148
|
def index(property, conf = {})
|
149
149
|
Neo4j::Session.on_session_available do |_|
|
150
|
+
drop_constraint(property, type: :unique) if Neo4j::Label.constraint?(mapped_label_name, property)
|
150
151
|
_index(property, conf)
|
151
152
|
end
|
152
153
|
indexed_properties.push property unless indexed_properties.include? property
|
@@ -161,12 +162,22 @@ module Neo4j
|
|
161
162
|
Neo4j::Session.on_session_available do |session|
|
162
163
|
unless Neo4j::Label.constraint?(mapped_label_name, property)
|
163
164
|
label = Neo4j::Label.create(mapped_label_name)
|
165
|
+
drop_index(property, label) if index?(property)
|
164
166
|
label.create_constraint(property, constraints, session)
|
165
167
|
end
|
166
168
|
end
|
167
169
|
end
|
168
170
|
|
169
|
-
|
171
|
+
# @param [Symbol] property The name of the property index to be dropped
|
172
|
+
# @param [Neo4j::Label] label An instance of label from Neo4j::Core
|
173
|
+
def drop_index(property, label = nil)
|
174
|
+
label_obj = label || Neo4j::Label.create(mapped_label_name)
|
175
|
+
label_obj.drop_index(property)
|
176
|
+
end
|
177
|
+
|
178
|
+
# @param [Symbol] property The name of the property constraint to be dropped
|
179
|
+
# @param [Hash] constraint The constraint type to be dropped.
|
180
|
+
def drop_constraint(property, constraint = {type: :unique})
|
170
181
|
Neo4j::Session.on_session_available do |session|
|
171
182
|
label = Neo4j::Label.create(mapped_label_name)
|
172
183
|
label.drop_constraint(property, constraint, session)
|
@@ -24,8 +24,10 @@ module Neo4j::ActiveNode
|
|
24
24
|
# If any of the before_* callbacks return false the action is cancelled and save returns false.
|
25
25
|
def save(*)
|
26
26
|
update_magic_properties
|
27
|
-
|
28
|
-
|
27
|
+
cascade_save do
|
28
|
+
association_proxy_cache.clear
|
29
|
+
create_or_update
|
30
|
+
end
|
29
31
|
end
|
30
32
|
|
31
33
|
# Persist the object to the database. Validations and Callbacks are included
|
@@ -53,7 +55,7 @@ module Neo4j::ActiveNode
|
|
53
55
|
node = _create_node(properties)
|
54
56
|
init_on_load(node, node.props)
|
55
57
|
send_props(@relationship_props) if @relationship_props
|
56
|
-
@relationship_props = nil
|
58
|
+
@relationship_props = @deferred_nodes = nil
|
57
59
|
true
|
58
60
|
end
|
59
61
|
|
@@ -66,12 +68,25 @@ module Neo4j::ActiveNode
|
|
66
68
|
session.create_node(props, labels)
|
67
69
|
end
|
68
70
|
|
71
|
+
private
|
72
|
+
|
73
|
+
# The pending associations are cleared during the save process, so it's necessary to
|
74
|
+
# build the processable hash before it begins. If there are nodes and associations that
|
75
|
+
# need to be created after the node is saved, a new transaction is started.
|
76
|
+
def cascade_save
|
77
|
+
deferred_nodes = pending_associations_with_nodes
|
78
|
+
Neo4j::Transaction.run(!deferred_nodes.blank?) do
|
79
|
+
result = yield
|
80
|
+
process_unpersisted_nodes!(deferred_nodes) if deferred_nodes
|
81
|
+
result
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
69
85
|
module ClassMethods
|
70
86
|
# Creates and saves a new node
|
71
87
|
# @param [Hash] props the properties the new node should have
|
72
88
|
def create(props = {})
|
73
89
|
association_props = extract_association_attributes!(props) || {}
|
74
|
-
|
75
90
|
new(props).tap do |obj|
|
76
91
|
yield obj if block_given?
|
77
92
|
obj.save
|
@@ -3,9 +3,9 @@ module Neo4j::ActiveNode
|
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
include Neo4j::Shared::Property
|
5
5
|
|
6
|
-
def initialize(attributes =
|
7
|
-
super(attributes
|
8
|
-
@attributes ||= self.class.attributes_nil_hash
|
6
|
+
def initialize(attributes = nil)
|
7
|
+
super(attributes)
|
8
|
+
@attributes ||= Hash[self.class.attributes_nil_hash]
|
9
9
|
send_props(@relationship_props) if _persisted_obj && !@relationship_props.nil?
|
10
10
|
end
|
11
11
|
|
@@ -22,6 +22,7 @@ module Neo4j::ActiveNode
|
|
22
22
|
private
|
23
23
|
|
24
24
|
def contains_association?(attributes)
|
25
|
+
return false unless attributes
|
25
26
|
attributes.each_key { |key| return true if associations_keys.include?(key) }
|
26
27
|
false
|
27
28
|
end
|
@@ -6,6 +6,7 @@ module Neo4j
|
|
6
6
|
include Neo4j::ActiveNode::Query::QueryProxyMethods
|
7
7
|
include Neo4j::ActiveNode::Query::QueryProxyFindInBatches
|
8
8
|
include Neo4j::ActiveNode::Query::QueryProxyEagerLoading
|
9
|
+
include Neo4j::ActiveNode::Query::QueryProxyUnpersisted
|
9
10
|
include Neo4j::ActiveNode::Dependent::QueryProxyMethods
|
10
11
|
|
11
12
|
# The most recent node to start a QueryProxy chain.
|
@@ -26,11 +27,13 @@ module Neo4j
|
|
26
27
|
# @param [Neo4j::ActiveNode::HasN::Association] association The ActiveNode association (an object created by a <tt>has_one</tt> or
|
27
28
|
# <tt>has_many</tt>) that created this object.
|
28
29
|
# @param [Hash] options Additional options pertaining to the QueryProxy object. These may include:
|
29
|
-
#
|
30
|
-
#
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
30
|
+
# @option options [String, Symbol] :node_var A string or symbol to be used by Cypher within its query string as an identifier
|
31
|
+
# @option options [String, Symbol] :rel_var Same as above but pertaining to a relationship identifier
|
32
|
+
# @option options [Range, Fixnum, Symbol, Hash] :rel_length A Range, a Fixnum, a Hash or a Symbol to indicate the variable-length/fixed-length
|
33
|
+
# qualifier of the relationship. See http://neo4jrb.readthedocs.org/en/latest/Querying.html#variable-length-relationships.
|
34
|
+
# @option options [Neo4j::Session] :session The session to be used for this query
|
35
|
+
# @option options [Neo4j::ActiveNode] :source_object The node instance at the start of the QueryProxy chain
|
36
|
+
# @option options [QueryProxy] :query_proxy An existing QueryProxy chain upon which this new object should be built
|
34
37
|
#
|
35
38
|
# QueryProxy objects are evaluated lazily.
|
36
39
|
def initialize(model, association = nil, options = {})
|
@@ -51,7 +54,7 @@ module Neo4j
|
|
51
54
|
end
|
52
55
|
|
53
56
|
def inspect
|
54
|
-
"
|
57
|
+
"#<QueryProxy #{@context} CYPHER: #{self.to_cypher.inspect}>"
|
55
58
|
end
|
56
59
|
|
57
60
|
attr_reader :start_object, :query_proxy
|
@@ -84,6 +87,9 @@ module Neo4j
|
|
84
87
|
# Build a Neo4j::Core::Query object for the QueryProxy. This is necessary when you want to take an existing QueryProxy chain
|
85
88
|
# and work with it from the more powerful (but less friendly) Neo4j::Core::Query.
|
86
89
|
# @param [String,Symbol] var The identifier to use for node at this link of the QueryProxy chain.
|
90
|
+
#
|
91
|
+
# .. code-block:: ruby
|
92
|
+
#
|
87
93
|
# student.lessons.query_as(:l).with('your cypher here...')
|
88
94
|
def query_as(var, with_labels = true)
|
89
95
|
result_query = @chain.inject(base_query(var, with_labels).params(@params)) do |query, link|
|
@@ -115,6 +121,8 @@ module Neo4j
|
|
115
121
|
|
116
122
|
# Scope all queries to the current scope.
|
117
123
|
#
|
124
|
+
# .. code-block:: ruby
|
125
|
+
#
|
118
126
|
# Comment.where(post_id: 1).scoping do
|
119
127
|
# Comment.first
|
120
128
|
# end
|
@@ -141,8 +149,12 @@ module Neo4j
|
|
141
149
|
alias_method :order_by, :order
|
142
150
|
|
143
151
|
# Cypher string for the QueryProxy's query. This will not include params. For the full output, see <tt>to_cypher_with_params</tt>.
|
144
|
-
def to_cypher
|
145
|
-
query.to_cypher
|
152
|
+
def to_cypher(*args)
|
153
|
+
query.to_cypher(*args)
|
154
|
+
end
|
155
|
+
|
156
|
+
def print_cypher
|
157
|
+
query.print_cypher
|
146
158
|
end
|
147
159
|
|
148
160
|
# Returns a string of the cypher query with return objects and params
|
@@ -155,8 +167,7 @@ module Neo4j
|
|
155
167
|
|
156
168
|
# To add a relationship for the node for the association on this QueryProxy
|
157
169
|
def <<(other_node)
|
158
|
-
create(other_node, {})
|
159
|
-
|
170
|
+
@start_object._persisted_obj ? create(other_node, {}) : defer_create(other_node, {}, :<<)
|
160
171
|
self
|
161
172
|
end
|
162
173
|
|
@@ -278,7 +289,7 @@ module Neo4j
|
|
278
289
|
end
|
279
290
|
|
280
291
|
def _association_arrow(properties = {}, create = false)
|
281
|
-
@association && @association.arrow_cypher(@rel_var, properties, create)
|
292
|
+
@association && @association.arrow_cypher(@rel_var, properties, create, false, @rel_length)
|
282
293
|
end
|
283
294
|
|
284
295
|
def _chain_level
|
@@ -312,8 +323,13 @@ module Neo4j
|
|
312
323
|
private
|
313
324
|
|
314
325
|
def instance_vars_from_options!(options)
|
315
|
-
@node_var, @session, @source_object, @starting_query, @optional,
|
316
|
-
|
326
|
+
@node_var, @session, @source_object, @starting_query, @optional,
|
327
|
+
@start_object, @query_proxy, @chain_level, @association_labels,
|
328
|
+
@rel_length = options.values_at(:node, :session, :source_object,
|
329
|
+
:starting_query, :optional,
|
330
|
+
:start_object, :query_proxy,
|
331
|
+
:chain_level, :association_labels,
|
332
|
+
:rel_length)
|
317
333
|
end
|
318
334
|
|
319
335
|
def build_deeper_query_proxy(method, args)
|