active_node 2.2.3 → 2.2.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f1e0b745f51b5a1c58f9053bb5fe9b0d94b24bec
4
- data.tar.gz: f83ca71aed4249ee3f7eff3f9a69b00b5b6ad7e5
3
+ metadata.gz: f099f7600aea945cfd5006b737360b8d5403909c
4
+ data.tar.gz: b2505371bcbc5ed36a5692fc6720aab6bff55985
5
5
  SHA512:
6
- metadata.gz: ced0ba488ef4173804f1dbd6cc96ba567ef76f796ed7e3b093e901df80b0228309ba1dfbfb3da6fb58f9ccd73303f002642c693b353542f2f6085a64f58ae271
7
- data.tar.gz: 20b2b8337a2fc1577fa9f943a5dc1ab4476138b1e3bb87255ed67963085252cf2d505e5bcd68bf9f57584ea706e1e8da9c1a47c84b83f56ecea8f2e77689f319
6
+ metadata.gz: 52822ad900508188e43d78788179768eb0dcde8cbbb4e543fc28c63cb1d259913dbbaeb0f50a3e6af29e4977fb063f5b8f4f57864d00778e2d0ea94cf981314a
7
+ data.tar.gz: aa4ca077908e7d79375059bfe776291bb4d3267d1b088e80515c6127ca8293e86c94c49945c55a39e216a40543ac5e22d9fae22da335c8b06d8447b19ca164d2
@@ -1,5 +1,14 @@
1
1
  module ActiveNode
2
2
  class Graph
3
+ MULTI_VALUE_METHODS = [:includes, :eager_load, :preload, :select, :group,
4
+ :order, :joins, :where, :having, :bind, :references,
5
+ :extending, :unscope]
6
+
7
+ SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :from, :reordering,
8
+ :reverse_order, :distinct, :create_with, :uniq]
9
+
10
+ VALUE_METHODS = MULTI_VALUE_METHODS + SINGLE_VALUE_METHODS
11
+
3
12
  include Neography::Rest::Helpers
4
13
  include FinderMethods, QueryMethods, Delegation
5
14
 
@@ -15,6 +24,7 @@ module ActiveNode
15
24
  @loaded_assoc_cache = {}
16
25
  @where = {}
17
26
  @includes = includes
27
+ @values = {}
18
28
  @offsets = {}
19
29
  end
20
30
 
@@ -36,11 +46,6 @@ module ActiveNode
36
46
  self
37
47
  end
38
48
 
39
- def limit count
40
- @limit = count
41
- self
42
- end
43
-
44
49
  def build *objects
45
50
  find objects.map { |o| o.is_a?(ActiveNode::Base) ? o.id.tap { |id| @object_cache[id]=o } : extract_id(o) }
46
51
  end
@@ -138,7 +143,11 @@ module ActiveNode
138
143
  end
139
144
 
140
145
  def limit_cond
141
- "limit #{@limit}" if @limit
146
+ "limit #{limit_value}" if limit_value
147
+ end
148
+
149
+ def skip_cond
150
+ "skip #{offset_value}" if offset_value
142
151
  end
143
152
 
144
153
  def initial_match
@@ -154,7 +163,7 @@ module ActiveNode
154
163
  end
155
164
 
156
165
  def to_cypher
157
- [initial_match, conditions, "with n0", limit_cond, query, 'return', list_with_rel(@reflections.size), 'order by', created_at_list(@reflections.size)].compact.join ' '
166
+ [initial_match, conditions, "with n0", order_list, skip_cond, limit_cond, query, 'return', list_with_rel(@reflections.size), order_list_with_defaults].compact.join ' '
158
167
  end
159
168
 
160
169
  def parse_results results
@@ -229,15 +238,23 @@ module ActiveNode
229
238
  end
230
239
 
231
240
  def list_with_rel num
232
- comma_sep_list(num) { |i| [("r#{i}" if i>0), "n#{i}"] }
241
+ comma_sep_list(0, num) { |i| [("r#{i}" if i>0), "n#{i}"] }
233
242
  end
234
243
 
235
- def comma_sep_list num, &block
244
+ def comma_sep_list start, num, &block
236
245
  (0..num).map(&block).flatten.compact.join(', ')
237
246
  end
238
247
 
239
- def created_at_list num
240
- comma_sep_list(num) { |i| "n#{i}.created_at" }
248
+ def order_list_with_defaults
249
+ "#{order_list}, #{comma_sep_list(1, @reflections.size) { |i| "n#{i}.created_at" }}"
250
+ end
251
+
252
+ def order_list
253
+ if order_values.empty?
254
+ order(:created_at) if @klass.respond_to? :created_at
255
+ order(:id)
256
+ end
257
+ "order by #{build_order(:n0)}"
241
258
  end
242
259
 
243
260
  def extract_id(id)
@@ -250,5 +267,7 @@ module ActiveNode
250
267
  get_id(id).to_i
251
268
  end
252
269
  end
270
+
271
+
253
272
  end
254
273
  end
@@ -1,28 +1,218 @@
1
1
  module ActiveNode
2
2
  module QueryMethods
3
- def order(*args)
3
+ Graph::MULTI_VALUE_METHODS.each do |name|
4
+ class_eval <<-CODE, __FILE__, __LINE__ + 1
5
+ def #{name}_values # def select_values
6
+ @values[:#{name}] || [] # @values[:select] || []
7
+ end # end
8
+ #
9
+ def #{name}_values=(values) # def select_values=(values)
10
+ raise ImmutableGraph if @loaded # raise ImmutableGraph if @loaded
11
+ @values[:#{name}] = values # @values[:select] = values
12
+ end # end
13
+ CODE
14
+ end
15
+
16
+ (Graph::SINGLE_VALUE_METHODS - [:create_with]).each do |name|
17
+ class_eval <<-CODE, __FILE__, __LINE__ + 1
18
+ def #{name}_value # def readonly_value
19
+ @values[:#{name}] # @values[:readonly]
20
+ end # end
21
+ CODE
22
+ end
23
+
24
+ Graph::SINGLE_VALUE_METHODS.each do |name|
25
+ class_eval <<-CODE, __FILE__, __LINE__ + 1
26
+ def #{name}_value=(value) # def readonly_value=(value)
27
+ raise ImmutableGraph if @loaded # raise ImmutableGraph if @loaded
28
+ @values[:#{name}] = value # @values[:readonly] = value
29
+ end # end
30
+ CODE
31
+ end
32
+
33
+ # Specifies a limit for the number of records to retrieve.
34
+ #
35
+ # User.limit(10) # generated SQL has 'LIMIT 10'
36
+ #
37
+ # User.limit(10).limit(20) # generated SQL has 'LIMIT 20'
38
+ def limit(value)
39
+ spawn.limit!(value)
40
+ end
41
+
42
+ def limit!(value) # :nodoc:
43
+ self.limit_value = value
4
44
  self
5
45
  end
6
46
 
47
+ # Specifies the number of rows to skip before returning rows.
48
+ #
49
+ # User.offset(10) # generated SQL has "OFFSET 10"
50
+ #
51
+ # Should be used with order.
52
+ #
53
+ # User.offset(10).order("name ASC")
7
54
  def offset(value)
55
+ spawn.offset!(value)
56
+ end
57
+
58
+ def offset!(value) # :nodoc:
59
+ self.offset_value = value
60
+ self
61
+ end
62
+
63
+
64
+ # Allows to specify an order attribute:
65
+ #
66
+ # User.order('name')
67
+ # => SELECT "users".* FROM "users" ORDER BY name
68
+ #
69
+ # User.order('name DESC')
70
+ # => SELECT "users".* FROM "users" ORDER BY name DESC
71
+ #
72
+ # User.order('name DESC, email')
73
+ # => SELECT "users".* FROM "users" ORDER BY name DESC, email
74
+ #
75
+ # User.order(:name)
76
+ # => SELECT "users".* FROM "users" ORDER BY "users"."name" ASC
77
+ #
78
+ # User.order(email: :desc)
79
+ # => SELECT "users".* FROM "users" ORDER BY "users"."email" DESC
80
+ #
81
+ # User.order(:name, email: :desc)
82
+ # => SELECT "users".* FROM "users" ORDER BY "users"."name" ASC, "users"."email" DESC
83
+ def order(*args)
84
+ check_if_method_has_arguments!(:order, args)
85
+ spawn.order!(*args)
86
+ end
87
+
88
+ def order!(*args) # :nodoc:
89
+ preprocess_order_args(args)
90
+
91
+ self.order_values += args
92
+ self
93
+ end
94
+
95
+ # Replaces any existing order defined on the relation with the specified order.
96
+ #
97
+ # User.order('email DESC').reorder('id ASC') # generated SQL has 'ORDER BY id ASC'
98
+ #
99
+ # Subsequent calls to order on the same relation will be appended. For example:
100
+ #
101
+ # User.order('email DESC').reorder('id ASC').order('name ASC')
102
+ #
103
+ # generates a query with 'ORDER BY id ASC, name ASC'.
104
+ def reorder(*args)
105
+ check_if_method_has_arguments!(:reorder, args)
106
+ spawn.reorder!(*args)
107
+ end
108
+
109
+ def reorder!(*args) # :nodoc:
110
+ preprocess_order_args(args)
111
+
112
+ self.reordering_value = true
113
+ self.order_values = args
8
114
  self
9
115
  end
10
116
 
117
+ # Reverse the existing order clause on the relation.
118
+ #
119
+ # User.order('name ASC').reverse_order # generated SQL has 'ORDER BY name DESC'
11
120
  def reverse_order
121
+ spawn.reverse_order!
122
+ end
123
+
124
+ def reverse_order! # :nodoc:
125
+ self.reverse_order_value = !reverse_order_value
12
126
  self
13
127
  end
14
128
 
15
- #TODO temporary stubbing
16
- def offset_value
17
- 0
129
+ private
130
+
131
+ def build_order(prefix)
132
+ orders = order_values.uniq
133
+ orders.reject!(&:blank?)
134
+ orders = reverse_sql_order(orders) if reverse_order_value
135
+
136
+ orders.map {|o| "#{prefix}.#{o}"}.join(', ')
137
+ end
138
+
139
+ def reverse_sql_order(order_query)
140
+ # order_query = ["#{quoted_table_name}.#{quoted_primary_key} ASC"] if order_query.empty?
141
+
142
+ order_query.flat_map do |o|
143
+ case o
144
+ when String
145
+ split_order(o).map! do |s|
146
+ s.gsub!(/\sasc\Z/i, ' DESC') || s.gsub!(/\sdesc\Z/i, ' ASC') || s.concat(' DESC')
147
+ end
148
+ else
149
+ o
150
+ end
151
+ end
152
+ end
153
+
154
+ def spawn
155
+ clone
156
+ end
157
+
158
+ def split_order s
159
+ s.to_s.split(',').map! &:strip
160
+ end
161
+
162
+ def preprocess_order_args(order_args)
163
+ order_args.flatten!
164
+ validate_order_args(order_args)
165
+
166
+ # references = order_args.grep(String)
167
+ # references.map! { |arg| arg =~ /^([a-zA-Z]\w*)\.(\w+)/ && $1 }.compact!
168
+ # references!(references) if references.any?
169
+
170
+ order_args.map! do |arg|
171
+ case arg
172
+ when Symbol
173
+ arg = klass.attribute_alias(arg) if klass.try :attribute_alias?, arg
174
+ arg.to_s
175
+ when Hash
176
+ arg.map { |field, dir|
177
+ field = klass.attribute_alias(field) if klass.try :attribute_alias?, arg
178
+ "#{field} #{dir}"
179
+ }
180
+ when String
181
+ split_order(arg)
182
+ else
183
+ arg
184
+ end
185
+ end.flatten!
18
186
  end
19
187
 
20
- def order_values
21
- []
188
+ # Checks to make sure that the arguments are not blank. Note that if some
189
+ # blank-like object were initially passed into the query method, then this
190
+ # method will not raise an error.
191
+ #
192
+ # Example:
193
+ #
194
+ # Post.references() # => raises an error
195
+ # Post.references([]) # => does not raise an error
196
+ #
197
+ # This particular method should be called with a method_name and the args
198
+ # passed into that method as an input. For example:
199
+ #
200
+ # def references(*args)
201
+ # check_if_method_has_arguments!("references", args)
202
+ # ...
203
+ # end
204
+ def check_if_method_has_arguments!(method_name, args)
205
+ if args.blank?
206
+ raise ArgumentError, "The method .#{method_name}() must contain arguments."
207
+ end
22
208
  end
23
209
 
24
- def limit_value
25
- nil
210
+ def validate_order_args(args)
211
+ args.grep(Hash) do |h|
212
+ unless (h.values - [:asc, :desc]).empty?
213
+ raise ArgumentError, 'Direction should be :asc or :desc'
214
+ end
215
+ end
26
216
  end
27
217
  end
28
- end
218
+ end
@@ -1,3 +1,3 @@
1
1
  module ActiveNode
2
- VERSION = "2.2.3"
2
+ VERSION = "2.2.4"
3
3
  end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActiveNode::QueryMethods do
4
+ describe "#order" do
5
+ it "should order" do
6
+ p1=Person.create!(name: 'abc')
7
+ p2=Person.create!(name: 'def')
8
+ Person.order(:name).should == [p1, p2]
9
+ Person.order(name: :desc).should == [p2, p1]
10
+ Person.order('name asc').reverse_order.should == [p2, p1]
11
+ end
12
+ end
13
+
14
+ describe "#limit" do
15
+ it "should limt" do
16
+ p1=Person.create!(name: 'abc')
17
+ p2=Person.create!(name: 'def')
18
+ Person.limit(1).should == [p1]
19
+ end
20
+ end
21
+ end
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.2.3
4
+ version: 2.2.4
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-05-13 00:00:00.000000000 Z
11
+ date: 2014-05-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: active_attr
@@ -182,6 +182,7 @@ files:
182
182
  - lib/active_node/version.rb
183
183
  - spec/functional/associations_spec.rb
184
184
  - spec/functional/base_spec.rb
185
+ - spec/functional/graph/query_methods_spec.rb
185
186
  - spec/functional/graph_spec.rb
186
187
  - spec/functional/persistence_spec.rb
187
188
  - spec/functional/validations_spec.rb
@@ -218,6 +219,7 @@ summary: ActiveRecord style Object Graph Mapping for neo4j
218
219
  test_files:
219
220
  - spec/functional/associations_spec.rb
220
221
  - spec/functional/base_spec.rb
222
+ - spec/functional/graph/query_methods_spec.rb
221
223
  - spec/functional/graph_spec.rb
222
224
  - spec/functional/persistence_spec.rb
223
225
  - spec/functional/validations_spec.rb