scoped_search 4.1.13 → 4.2.0

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
  SHA256:
3
- metadata.gz: fbd1e857e3b248d6d585ac7c41679b536949dc945f4c7e067b2b16e86ce325b2
4
- data.tar.gz: b4c1dc92102ff1d56b1f23406b16cf0523c6bdc17ab336ee92300993de5fd7f9
3
+ metadata.gz: 958718e625d5bbb80f93ea868abebac96d29a54e712c6c0275f9e6a1e44e07d3
4
+ data.tar.gz: 90f57db3c2009746a0beb9d843bee7a46d55d1b0ef02d796c12490d7b3e7f1b8
5
5
  SHA512:
6
- metadata.gz: 1fe965444b5640251c4ca34c5fc1fca34857f2c8cc96a8f759096165391490ca7deb7f5b3f9d8ed8c9219a5ddfa82716660e2739adb5d7dfdb2d61ca95a968a7
7
- data.tar.gz: f9ce7c87b95ceec5f3f5d1cc46f6401ef121870bf58a8cffe1b07cb7de597b8bcd3bcd1069e98ef52007df2209b26998f3f1c05a9719eefe17351d1f6da1eebf
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
- span = 1.minute if(value =~ /\A\s*\d+\s+\bminutes?\b\s+\bago\b\s*\z/i)
150
- span ||= (timestamp.day_fraction == 0) ? 1.day : 1.hour
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
 
@@ -1,3 +1,3 @@
1
1
  module ScopedSearch
2
- VERSION = "4.1.13"
2
+ VERSION = "4.2.0"
3
3
  end
data/lib/scoped_search.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require 'logger' # a workaround for https://github.com/rails/rails/issues/54263
1
2
  require 'active_record'
2
3
 
3
4
  # ScopedSearch is the base module for the scoped_search plugin. This file
@@ -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.1.13
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: 2024-12-03 00:00:00.000000000 Z
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