scoped_search 4.1.7 → 4.1.8
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 +5 -5
- data/.travis.yml +26 -2
- data/CHANGELOG.rdoc +5 -0
- data/Gemfile.activerecord60 +17 -0
- data/Gemfile.activerecord60_with_activesupport60 +18 -0
- data/lib/scoped_search/auto_complete_builder.rb +2 -2
- data/lib/scoped_search/definition.rb +5 -5
- data/lib/scoped_search/query_builder.rb +40 -40
- data/lib/scoped_search/version.rb +1 -1
- data/spec/integration/sti_querying_spec.rb +12 -2
- data/spec/unit/query_builder_spec.rb +2 -0
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 76592b4cfe81be4cef968ea35cd9659957af349738fb799ce5e34608247b320a
|
4
|
+
data.tar.gz: 43e889676986012a6827d6904c616e66e73eecd7a4381ed4e4eb573da270f3f1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6d0d6000ce3a827d33c24591548fcbc6c477c0a9d878dfa39c4a92c5eaaa9bdfe619a5df6c410b2469ebfff4c88a41aef7669afeb591e5d5d6e9a47704bf873c
|
7
|
+
data.tar.gz: d9a20afd3c5328f2195b694a3c305a4f00e4a104680fcf8292afb2b1e7cd838da86ce07c03648312d670d010ec7cda38684bc5be24e9841ffbc445dfc5e9e6d8
|
data/.travis.yml
CHANGED
@@ -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.
|
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
|
data/CHANGELOG.rdoc
CHANGED
@@ -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 =
|
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])
|
330
|
-
search_scope = search_scope.includes(find_options[:include])
|
331
|
-
search_scope = search_scope.joins(find_options[:joins])
|
332
|
-
search_scope = search_scope.reorder(find_options[:order])
|
333
|
-
search_scope = search_scope.references(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
|
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
|
-
#
|
173
|
-
|
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
|
-
|
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
|
226
|
-
|
227
|
-
|
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
|
-
|
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
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
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)
|
@@ -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.
|
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:
|
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
|
-
|
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
|