scoped_search 4.1.13 → 4.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/scoped_search/query_builder.rb +24 -4
- data/lib/scoped_search/version.rb +1 -1
- data/lib/scoped_search.rb +1 -0
- data/scoped_search.gemspec +7 -0
- data/spec/unit/query_builder_spec.rb +61 -0
- metadata +72 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 958718e625d5bbb80f93ea868abebac96d29a54e712c6c0275f9e6a1e44e07d3
|
4
|
+
data.tar.gz: 90f57db3c2009746a0beb9d843bee7a46d55d1b0ef02d796c12490d7b3e7f1b8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2cc38b0ce04452df7b7205465621c0624d1173c9e9a95eb849f50eaa99fdcad9545a7411aec5fae2a3c787f348a3f440244c54e8623a3ed2589d47735110ef8b
|
7
|
+
data.tar.gz: 60ebb019e199a50505e0e934a1e2fd405a03c903350554c8f13ca62f85c5acc472b073a6bf1ebcdb1f44b15c54ec593dc31b9bf474782ff739803a0d94f43e81
|
@@ -146,8 +146,22 @@ module ScopedSearch
|
|
146
146
|
# but the field is of datetime type. Change the comparison to return
|
147
147
|
# more logical results.
|
148
148
|
if field.datetime?
|
149
|
-
|
150
|
-
|
149
|
+
if value =~ time_unit_regex("minutes?|hours?")
|
150
|
+
span = 1.minute
|
151
|
+
elsif value =~ time_unit_regex("days?|weeks?|months?|years?") || value =~ /\b(today|tomorrow|yesterday)\b/i
|
152
|
+
span = 1.day
|
153
|
+
else
|
154
|
+
tokens = DateTime._parse(value)
|
155
|
+
# find the smallest unit of time given in input and determine span for further adjustment of the search query
|
156
|
+
span = {
|
157
|
+
sec: 1.second,
|
158
|
+
min: 1.minute,
|
159
|
+
hour: 1.hour,
|
160
|
+
mday: 1.day,
|
161
|
+
mon: 1.month
|
162
|
+
}.find { |key, _| tokens[key] }&.last || 1.year
|
163
|
+
end
|
164
|
+
|
151
165
|
if [:eq, :ne].include?(operator)
|
152
166
|
# Instead of looking for an exact (non-)match, look for dates that
|
153
167
|
# fall inside/outside the range of timestamps of that day.
|
@@ -155,13 +169,13 @@ module ScopedSearch
|
|
155
169
|
field_sql = field.to_sql(operator, &block)
|
156
170
|
return ["#{negate}(#{field_sql} >= ? AND #{field_sql} < ?)", timestamp, timestamp + span]
|
157
171
|
|
158
|
-
elsif operator == :gt
|
172
|
+
elsif span >= 1.day && operator == :gt
|
159
173
|
# Make sure timestamps on the given date are not included in the results
|
160
174
|
# by moving the date to the next day.
|
161
175
|
timestamp += span
|
162
176
|
operator = :gte
|
163
177
|
|
164
|
-
elsif operator == :lte
|
178
|
+
elsif span >= 1.day && operator == :lte
|
165
179
|
# Make sure the timestamps of the given date are included by moving the
|
166
180
|
# date to the next date.
|
167
181
|
timestamp += span
|
@@ -320,6 +334,12 @@ module ScopedSearch
|
|
320
334
|
definition.reflection_by_name(reflection.klass, as).options[:polymorphic]
|
321
335
|
end
|
322
336
|
|
337
|
+
private
|
338
|
+
|
339
|
+
def time_unit_regex(time_unit)
|
340
|
+
/\A\s*\d+\s+\b(?:#{time_unit})\b\s+\b(ago|from\s+now)\b\s*\z/i
|
341
|
+
end
|
342
|
+
|
323
343
|
# This module gets included into the Field class to add SQL generation.
|
324
344
|
module Field
|
325
345
|
|
data/lib/scoped_search.rb
CHANGED
data/scoped_search.gemspec
CHANGED
@@ -34,6 +34,13 @@ Gem::Specification.new do |gem|
|
|
34
34
|
gem.add_development_dependency('rspec', '~> 3.0')
|
35
35
|
gem.add_development_dependency('rake')
|
36
36
|
|
37
|
+
# Rails require these, but don't explicitly depend on them
|
38
|
+
gem.add_development_dependency('base64')
|
39
|
+
gem.add_development_dependency('benchmark')
|
40
|
+
gem.add_development_dependency('bigdecimal')
|
41
|
+
gem.add_development_dependency('logger')
|
42
|
+
gem.add_development_dependency('mutex_m')
|
43
|
+
|
37
44
|
gem.rdoc_options << '--title' << gem.name << '--main' << 'README.rdoc' << '--line-numbers' << '--inline-source'
|
38
45
|
gem.extra_rdoc_files = ['README.rdoc', 'CHANGELOG.rdoc', 'CONTRIBUTING.rdoc', 'LICENSE']
|
39
46
|
end
|
@@ -155,4 +155,65 @@ describe ScopedSearch::QueryBuilder do
|
|
155
155
|
lambda { ScopedSearch::QueryBuilder.build_query(@definition, 'test_field = test_val') }.should raise_error(ScopedSearch::QueryNotSupported, /failed with error: test/)
|
156
156
|
end
|
157
157
|
end
|
158
|
+
|
159
|
+
context 'datetime_test' do
|
160
|
+
before(:each) do
|
161
|
+
@field = double('field')
|
162
|
+
@query_builder = ScopedSearch::QueryBuilder.new(@definition, nil, nil)
|
163
|
+
|
164
|
+
@field.stub(:datetime?).and_return(true)
|
165
|
+
@field.stub(:date?).and_return(false)
|
166
|
+
@field.stub(:to_sql).and_return('started_at')
|
167
|
+
|
168
|
+
[:virtual?, :set?, :temporal?, :relation, :offset].each { |key| @field.stub(key).and_return(false) }
|
169
|
+
end
|
170
|
+
|
171
|
+
it "should return correct SQL literal for equality operator" do
|
172
|
+
@definition.stub(:parse_temporal).and_return(DateTime.new(2023, 10, 10))
|
173
|
+
result = @query_builder.datetime_test(@field, :eq, '2023-10-10') { |type, value| }
|
174
|
+
result.should eq(["(started_at >= ? AND started_at < ?)", DateTime.new(2023, 10, 10), DateTime.new(2023, 10, 11)])
|
175
|
+
end
|
176
|
+
|
177
|
+
it "should return correct SQL literal for inequality operator" do
|
178
|
+
@definition.stub(:parse_temporal).and_return(DateTime.new(2023, 10, 10))
|
179
|
+
result = @query_builder.datetime_test(@field, :ne, '2023-10-10') { |type, value| }
|
180
|
+
result.should eq(["NOT (started_at >= ? AND started_at < ?)", DateTime.new(2023, 10, 10), DateTime.new(2023, 10, 11)])
|
181
|
+
end
|
182
|
+
|
183
|
+
it "should return correct SQL literal for greater operator" do
|
184
|
+
@definition.stub(:parse_temporal).and_return(DateTime.new(2023, 10, 9))
|
185
|
+
result = @query_builder.datetime_test(@field, :gt, '2023-10-9') { |type, value| }
|
186
|
+
result.should eq(["started_at >= ?", DateTime.new(2023, 10, 10)])
|
187
|
+
end
|
188
|
+
|
189
|
+
it "should return correct SQL literal for less than or equal operator" do
|
190
|
+
@definition.stub(:parse_temporal).and_return(DateTime.new(2023, 10, 10))
|
191
|
+
result = @query_builder.datetime_test(@field, :lte, '2023-10-10') { |type, value| }
|
192
|
+
result.should eq(["started_at < ?", DateTime.new(2023, 10, 11)])
|
193
|
+
end
|
194
|
+
|
195
|
+
it "should return empty array for invalid date" do
|
196
|
+
@definition.stub(:parse_temporal).and_return(nil)
|
197
|
+
result = @query_builder.datetime_test(@field, :eq, 'invalid-date') { |type, value| }
|
198
|
+
result.should eq([])
|
199
|
+
end
|
200
|
+
|
201
|
+
it "should count with 1 month deviation if only year and month is provided" do
|
202
|
+
@definition.stub(:parse_temporal).and_return(DateTime.new(2024, 1, 1))
|
203
|
+
result = @query_builder.datetime_test(@field, :gt, 'January 2024') { |type, value| }
|
204
|
+
result.should eq(["started_at >= ?", DateTime.new(2024, 2, 1)])
|
205
|
+
end
|
206
|
+
|
207
|
+
it "should not count with deviation if minute is the smallest unit provided" do
|
208
|
+
@definition.stub(:parse_temporal).and_return(DateTime.new(2023, 10, 10, 13, 0, 0))
|
209
|
+
result = @query_builder.datetime_test(@field, :gt, '2023-10-10 13:00') { |type, value| }
|
210
|
+
result.should eq(["started_at > ?", DateTime.new(2023, 10, 10, 13, 0, 0)])
|
211
|
+
end
|
212
|
+
|
213
|
+
it "should not count with deviation if second is the smallest unit provided" do
|
214
|
+
@definition.stub(:parse_temporal).and_return(DateTime.new(2023, 10, 10, 13, 0, 0, 1))
|
215
|
+
result = @query_builder.datetime_test(@field, :gt, '2023-10-10 13:00:01') { |type, value| }
|
216
|
+
result.should eq(["started_at > ?", DateTime.new(2023, 10, 10, 13, 0, 0, 1)])
|
217
|
+
end
|
218
|
+
end
|
158
219
|
end
|
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.
|
4
|
+
version: 4.2.0
|
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: 2025-02-18 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activerecord
|
@@ -54,6 +54,76 @@ dependencies:
|
|
54
54
|
- - ">="
|
55
55
|
- !ruby/object:Gem::Version
|
56
56
|
version: '0'
|
57
|
+
- !ruby/object:Gem::Dependency
|
58
|
+
name: base64
|
59
|
+
requirement: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0'
|
64
|
+
type: :development
|
65
|
+
prerelease: false
|
66
|
+
version_requirements: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
- !ruby/object:Gem::Dependency
|
72
|
+
name: benchmark
|
73
|
+
requirement: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
type: :development
|
79
|
+
prerelease: false
|
80
|
+
version_requirements: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
85
|
+
- !ruby/object:Gem::Dependency
|
86
|
+
name: bigdecimal
|
87
|
+
requirement: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - ">="
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '0'
|
92
|
+
type: :development
|
93
|
+
prerelease: false
|
94
|
+
version_requirements: !ruby/object:Gem::Requirement
|
95
|
+
requirements:
|
96
|
+
- - ">="
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
- !ruby/object:Gem::Dependency
|
100
|
+
name: logger
|
101
|
+
requirement: !ruby/object:Gem::Requirement
|
102
|
+
requirements:
|
103
|
+
- - ">="
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '0'
|
106
|
+
type: :development
|
107
|
+
prerelease: false
|
108
|
+
version_requirements: !ruby/object:Gem::Requirement
|
109
|
+
requirements:
|
110
|
+
- - ">="
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: '0'
|
113
|
+
- !ruby/object:Gem::Dependency
|
114
|
+
name: mutex_m
|
115
|
+
requirement: !ruby/object:Gem::Requirement
|
116
|
+
requirements:
|
117
|
+
- - ">="
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: '0'
|
120
|
+
type: :development
|
121
|
+
prerelease: false
|
122
|
+
version_requirements: !ruby/object:Gem::Requirement
|
123
|
+
requirements:
|
124
|
+
- - ">="
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: '0'
|
57
127
|
description: |2
|
58
128
|
Scoped search makes it easy to search your ActiveRecord-based models.
|
59
129
|
|