scoped_search 4.1.7 → 4.1.8

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
- SHA1:
3
- metadata.gz: 4d5d5ddd90a25434d39644b46bf7ff531a4c3b9f
4
- data.tar.gz: c6f84e3fa52f86b25d03b0ec6a0cb61fb0be79e9
2
+ SHA256:
3
+ metadata.gz: 76592b4cfe81be4cef968ea35cd9659957af349738fb799ce5e34608247b320a
4
+ data.tar.gz: 43e889676986012a6827d6904c616e66e73eecd7a4381ed4e4eb573da270f3f1
5
5
  SHA512:
6
- metadata.gz: e798cdc07468120499ae613122e4a96d6e300998cf3868af27e4df65204af23a28aed861cb3144a7b7bdf44097b5024684b91d0db1a9becdb0397c73d0e39cc6
7
- data.tar.gz: 0da17cd812a2ca5f2802e3cff5835317117426530707d6af6dc1d1d093a9efac13378d1d781b8a1512fd86ca6ab969ef6fe10be6ac6e30356ec988a040cd49d4
6
+ metadata.gz: 6d0d6000ce3a827d33c24591548fcbc6c477c0a9d878dfa39c4a92c5eaaa9bdfe619a5df6c410b2469ebfff4c88a41aef7669afeb591e5d5d6e9a47704bf873c
7
+ data.tar.gz: d9a20afd3c5328f2195b694a3c305a4f00e4a104680fcf8292afb2b1e7cd838da86ce07c03648312d670d010ec7cda38684bc5be24e9841ffbc445dfc5e9e6d8
@@ -1,6 +1,9 @@
1
1
  language: ruby
2
2
  cache: bundler
3
3
  sudo: false
4
+ services:
5
+ - postgresql
6
+ - mysql
4
7
 
5
8
  install:
6
9
  - bundle install
@@ -16,7 +19,7 @@ rvm:
16
19
  - "2.2.2"
17
20
  - "2.3.7"
18
21
  - "2.4.0"
19
- - "2.5.0"
22
+ - "2.5.1"
20
23
  - "2.6.0"
21
24
  - ruby-head
22
25
  - jruby-19mode
@@ -28,6 +31,8 @@ gemfile:
28
31
  - Gemfile.activerecord51
29
32
  - Gemfile.activerecord52
30
33
  - Gemfile.activerecord52_with_activesupport52
34
+ - Gemfile.activerecord60
35
+ - Gemfile.activerecord60_with_activesupport60
31
36
 
32
37
  matrix:
33
38
  allow_failures:
@@ -51,4 +56,23 @@ matrix:
51
56
  gemfile: Gemfile.activerecord52_with_activesupport52
52
57
  - rvm: "2.1"
53
58
  gemfile: Gemfile.activerecord52_with_activesupport52
54
-
59
+ - rvm: "2.0"
60
+ gemfile: Gemfile.activerecord60
61
+ - rvm: "2.1"
62
+ gemfile: Gemfile.activerecord60
63
+ - rvm: "2.2.2"
64
+ gemfile: Gemfile.activerecord60
65
+ - rvm: "2.3.7"
66
+ gemfile: Gemfile.activerecord60
67
+ - rvm: "2.4.0"
68
+ gemfile: Gemfile.activerecord60
69
+ - rvm: "2.0"
70
+ gemfile: Gemfile.activerecord60_with_activesupport60
71
+ - rvm: "2.1"
72
+ gemfile: Gemfile.activerecord60_with_activesupport60
73
+ - rvm: "2.2.2"
74
+ gemfile: Gemfile.activerecord60_with_activesupport60
75
+ - rvm: "2.3.7"
76
+ gemfile: Gemfile.activerecord60_with_activesupport60
77
+ - rvm: "2.4.0"
78
+ gemfile: Gemfile.activerecord60_with_activesupport60
@@ -8,6 +8,11 @@ Please add an entry to the "Unreleased changes" section in your pull requests.
8
8
 
9
9
  - Nothing yet
10
10
 
11
+ === Version 4.1.8
12
+
13
+ - Fix querying in associations by set, datetime or IN searches
14
+ - Add support for ActiveRecord 6.0 and Rails 6.1
15
+
11
16
  === Version 4.1.7
12
17
 
13
18
  - When Active Support is available, we parse time respecting current time zone
@@ -0,0 +1,17 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
3
+
4
+ gem 'actionview', '~> 6.0.0'
5
+ gem 'activerecord', '~> 6.0.0'
6
+
7
+ platforms :jruby do
8
+ gem 'activerecord-jdbcsqlite3-adapter'
9
+ gem 'activerecord-jdbcmysql-adapter'
10
+ gem 'activerecord-jdbcpostgresql-adapter'
11
+ end
12
+
13
+ platforms :ruby do
14
+ gem 'sqlite3', '~> 1.4'
15
+ gem 'mysql2', '> 0.5'
16
+ gem 'pg', '>= 0.18', '< 2.0'
17
+ end
@@ -0,0 +1,18 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
3
+
4
+ gem 'actionview', '~> 6.0.0'
5
+ gem 'activerecord', '~> 6.0.0'
6
+ gem 'activesupport', '~> 6.0.0'
7
+
8
+ platforms :jruby do
9
+ gem 'activerecord-jdbcsqlite3-adapter'
10
+ gem 'activerecord-jdbcmysql-adapter'
11
+ gem 'activerecord-jdbcpostgresql-adapter'
12
+ end
13
+
14
+ platforms :ruby do
15
+ gem 'sqlite3', '~> 1.4'
16
+ gem 'mysql2', '> 0.5'
17
+ gem 'pg', '>= 0.18', '< 2.0'
18
+ end
@@ -220,8 +220,8 @@ module ScopedSearch
220
220
 
221
221
  def completer_scope(field)
222
222
  klass = field.klass
223
- scope = klass.respond_to?(:completer_scope) ? klass.completer_scope(@options) : klass
224
- scope.respond_to?(:reorder) ? scope.reorder(field.quoted_field) : scope.scoped(:order => field.quoted_field)
223
+ scope = klass.respond_to?(:completer_scope) ? klass.completer_scope(@options) : klass
224
+ scope.respond_to?(:reorder) ? scope.reorder(Arel.sql(field.quoted_field)) : scope.scoped(:order => field.quoted_field)
225
225
  end
226
226
 
227
227
  # set value completer
@@ -326,11 +326,11 @@ module ScopedSearch
326
326
 
327
327
  search_scope = klass.all
328
328
  find_options = ScopedSearch::QueryBuilder.build_query(definition, query || '', options)
329
- search_scope = search_scope.where(find_options[:conditions]) if find_options[:conditions]
330
- search_scope = search_scope.includes(find_options[:include]) if find_options[:include]
331
- search_scope = search_scope.joins(find_options[:joins]) if find_options[:joins]
332
- search_scope = search_scope.reorder(find_options[:order]) if find_options[:order]
333
- search_scope = search_scope.references(find_options[:include]) if find_options[:include]
329
+ search_scope = search_scope.where(find_options[:conditions]) if find_options[:conditions]
330
+ search_scope = search_scope.includes(find_options[:include]) if find_options[:include]
331
+ search_scope = search_scope.joins(find_options[:joins]) if find_options[:joins]
332
+ search_scope = search_scope.reorder(Arel.sql(find_options[:order])) if find_options[:order]
333
+ search_scope = search_scope.references(find_options[:include]) if find_options[:include]
334
334
 
335
335
  search_scope
336
336
  end
@@ -137,7 +137,7 @@ module ScopedSearch
137
137
 
138
138
  # Parse the value as a date/time and ignore invalid timestamps
139
139
  timestamp = definition.parse_temporal(value)
140
- return nil unless timestamp
140
+ return [] unless timestamp
141
141
 
142
142
  timestamp = timestamp.to_date if field.date?
143
143
  # Check for the case that a date-only value is given as search keyword,
@@ -149,11 +149,9 @@ module ScopedSearch
149
149
  if [:eq, :ne].include?(operator)
150
150
  # Instead of looking for an exact (non-)match, look for dates that
151
151
  # fall inside/outside the range of timestamps of that day.
152
- yield(:parameter, timestamp)
153
- yield(:parameter, timestamp + span)
154
152
  negate = (operator == :ne) ? 'NOT ' : ''
155
153
  field_sql = field.to_sql(operator, &block)
156
- return "#{negate}(#{field_sql} >= ? AND #{field_sql} < ?)"
154
+ return ["#{negate}(#{field_sql} >= ? AND #{field_sql} < ?)", timestamp, timestamp + span]
157
155
 
158
156
  elsif operator == :gt
159
157
  # Make sure timestamps on the given date are not included in the results
@@ -169,9 +167,8 @@ module ScopedSearch
169
167
  end
170
168
  end
171
169
 
172
- # Yield the timestamp and return the SQL test
173
- yield(:parameter, timestamp)
174
- "#{field.to_sql(operator, &block)} #{sql_operator(operator, field)} ?"
170
+ # return the SQL test
171
+ ["#{field.to_sql(operator, &block)} #{sql_operator(operator, field)} ?", timestamp]
175
172
  end
176
173
 
177
174
  # Validate the key name is in the set and translate the value to the set value.
@@ -205,8 +202,7 @@ module ScopedSearch
205
202
  set_value = false
206
203
  end
207
204
  end
208
- yield(:parameter, set_value)
209
- return "#{negate}(#{field.to_sql(operator, &block)} #{self.sql_operator(operator, field)} ?)"
205
+ ["#{negate}(#{field.to_sql(operator, &block)} #{self.sql_operator(operator, field)} ?)", set_value]
210
206
  end
211
207
 
212
208
  # Generates a simple SQL test expression, for a field and value using an operator.
@@ -222,41 +218,45 @@ module ScopedSearch
222
218
 
223
219
  yield(:keyparameter, lhs.sub(/^.*\./,'')) if field.key_field
224
220
 
225
- if [:like, :unlike].include?(operator)
226
- yield(:parameter, (value !~ /^\%|\*/ && value !~ /\%|\*$/) ? "%#{value}%" : value.tr_s('%*', '%'))
227
- return "#{field.to_sql(operator, &block)} #{self.sql_operator(operator, field)} ?"
221
+ condition, *values = if field.temporal?
222
+ datetime_test(field, operator, value, &block)
223
+ elsif field.set?
224
+ set_test(field, operator, value, &block)
225
+ else
226
+ ["#{field.to_sql(operator, &block)} #{self.sql_operator(operator, field)} #{value_placeholders(operator, value)}", value]
227
+ end
228
+ values.each { |value| preprocess_parameters(field, operator, value, &block) }
228
229
 
229
- elsif [:in, :notin].include?(operator)
230
- value.split(',').collect { |v| yield(:parameter, map_value(field, field.set? ? translate_value(field, v) : v.strip)) }
231
- value = value.split(',').collect { "?" }.join(",")
232
- return "#{field.to_sql(operator, &block)} #{self.sql_operator(operator, field)} (#{value})"
233
-
234
- elsif field.temporal?
235
- return datetime_test(field, operator, value, &block)
236
-
237
- elsif field.set?
238
- return set_test(field, operator, value, &block)
239
-
240
- elsif field.relation && definition.reflection_by_name(field.definition.klass, field.relation).macro == :has_many
241
- value = value.to_i if field.offset
242
- value = map_value(field, value)
243
- yield(:parameter, value)
230
+ if field.relation && definition.reflection_by_name(field.definition.klass, field.relation).macro == :has_many
244
231
  connection = field.definition.klass.connection
245
232
  primary_key = "#{connection.quote_table_name(field.definition.klass.table_name)}.#{connection.quote_column_name(field.definition.klass.primary_key)}"
246
- if definition.reflection_by_name(field.definition.klass, field.relation).options.has_key?(:through)
247
- join = has_many_through_join(field)
248
- return "#{primary_key} IN (SELECT #{primary_key} FROM #{join} WHERE #{field.to_sql(operator, &block)} #{self.sql_operator(operator, field)} ? )"
249
- else
250
- foreign_key = connection.quote_column_name(field.reflection_keys(definition.reflection_by_name(field.definition.klass, field.relation))[1])
251
- return "#{primary_key} IN (SELECT #{foreign_key} FROM #{connection.quote_table_name(field.klass.table_name)} WHERE #{field.to_sql(operator, &block)} #{self.sql_operator(operator, field)} ? )"
252
- end
253
-
254
- else
255
- value = value.to_i if field.offset
256
- value = map_value(field, value)
257
- yield(:parameter, value)
258
- return "#{field.to_sql(operator, &block)} #{self.sql_operator(operator, field)} ?"
233
+ key, join_table = if definition.reflection_by_name(field.definition.klass, field.relation).options.has_key?(:through)
234
+ [primary_key, has_many_through_join(field)]
235
+ else
236
+ [connection.quote_column_name(field.reflection_keys(definition.reflection_by_name(field.definition.klass, field.relation))[1]),
237
+ connection.quote_table_name(field.klass.table_name)]
238
+ end
239
+
240
+ condition = "#{primary_key} IN (SELECT #{key} FROM #{join_table} WHERE #{condition} )"
259
241
  end
242
+ condition
243
+ end
244
+
245
+ def preprocess_parameters(field, operator, value, &block)
246
+ values = if [:in, :notin].include?(operator)
247
+ value.split(',').map { |v| map_value(field, field.set? ? translate_value(field, v) : v.strip) }
248
+ elsif [:like, :unlike].include?(operator)
249
+ [(value !~ /^\%|\*/ && value !~ /\%|\*$/) ? "%#{value}%" : value.tr_s('%*', '%')]
250
+ else
251
+ [map_value(field, field.offset ? value.to_i : value)]
252
+ end
253
+ values.each { |value| yield(:parameter, value) }
254
+ end
255
+
256
+ def value_placeholders(operator, value)
257
+ return '?' unless [:in, :notin].include?(operator)
258
+
259
+ '(' + value.split(',').map { '?' }.join(',') + ')'
260
260
  end
261
261
 
262
262
  def find_has_many_through_association(field, through)
@@ -1,3 +1,3 @@
1
1
  module ScopedSearch
2
- VERSION = "4.1.7"
2
+ VERSION = "4.1.8"
3
3
  end
@@ -13,15 +13,18 @@ ScopedSearch::RSpec::Database.test_databases.each do |db|
13
13
 
14
14
  @parent_class = ScopedSearch::RSpec::Database.create_model(int: :integer, type: :string, related_id: :integer) do |klass|
15
15
  klass.scoped_search on: :int
16
+ klass.belongs_to @related_class.table_name.to_sym, foreign_key: :related_id
16
17
  end
17
18
  @subclass1 = ScopedSearch::RSpec::Database.create_sti_model(@parent_class)
18
19
  @subclass2 = ScopedSearch::RSpec::Database.create_sti_model(@parent_class) do |klass|
19
- klass.belongs_to @related_class.table_name.to_sym, foreign_key: :related_id
20
20
  klass.scoped_search on: :int, rename: :other_int
21
21
  klass.scoped_search relation: @related_class.table_name, on: :int, rename: :related_int
22
22
  end
23
23
 
24
- @related_class.has_many @subclass1.table_name.to_sym
24
+ @related_class.has_many @subclass1.table_name.to_sym, :foreign_key => :related_id
25
+ @related_class.has_many @subclass2.table_name.to_sym, :foreign_key => :related_id
26
+ @related_class.scoped_search :relation => @subclass1.table_name.to_sym, :on => :int, :rename => 'subclass1.id'
27
+ @related_class.scoped_search :relation => @subclass2.table_name.to_sym, :on => :int, :rename => 'subclass2.id'
25
28
 
26
29
  @record1 = @subclass1.create!(int: 7)
27
30
  @related_record1 = @related_class.create!(int: 42)
@@ -79,5 +82,12 @@ ScopedSearch::RSpec::Database.test_databases.each do |db|
79
82
  @subclass2.search_for('related_int = 42').should eq([@record2])
80
83
  end
81
84
  end
85
+
86
+ context 'querying related records' do
87
+ it 'shuld find only relevant instances of STI subclasses' do
88
+ @related_class.search_for("subclass1.id ^ (#{@record1.int})").should eq([])
89
+ @related_class.search_for("subclass2.id ^ (#{@record1.int}, #{@record2.int})").should eq([@related_record1])
90
+ end
91
+ end
82
92
  end
83
93
  end
@@ -52,6 +52,8 @@ describe ScopedSearch::QueryBuilder do
52
52
  it "should validate value if validator selected" do
53
53
  field = double('field')
54
54
  field.stub(:virtual?).and_return(false)
55
+ field.stub(:temporal?).and_return(false)
56
+ field.stub(:relation).and_return(nil)
55
57
  field.stub(:only_explicit).and_return(true)
56
58
  field.stub(:field).and_return(:test_field)
57
59
  field.stub(:ext_method).and_return(nil)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: scoped_search
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.7
4
+ version: 4.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Amos Benari
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2019-05-07 00:00:00.000000000 Z
13
+ date: 2020-04-15 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activerecord
@@ -87,6 +87,8 @@ files:
87
87
  - Gemfile.activerecord51
88
88
  - Gemfile.activerecord52
89
89
  - Gemfile.activerecord52_with_activesupport52
90
+ - Gemfile.activerecord60
91
+ - Gemfile.activerecord60_with_activesupport60
90
92
  - LICENSE
91
93
  - README.rdoc
92
94
  - Rakefile
@@ -159,8 +161,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
159
161
  - !ruby/object:Gem::Version
160
162
  version: '0'
161
163
  requirements: []
162
- rubyforge_project:
163
- rubygems_version: 2.6.8
164
+ rubygems_version: 3.0.3
164
165
  signing_key:
165
166
  specification_version: 4
166
167
  summary: Easily search you ActiveRecord models with a simple query language using