query_filter 0.1.5 → 0.2.2

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
- SHA1:
3
- metadata.gz: 3be0d7ad318960b8718eb59befce928685961643
4
- data.tar.gz: a78a2e95239421f221293bd64539c2b7112e1dbb
2
+ SHA256:
3
+ metadata.gz: 6fe7cf9e804b940444eefcf3fbced4b24099d52d32f71d896bcb401fcb1e9e43
4
+ data.tar.gz: e61f5e207c0a6c7fccae4d44a6a5990cde48f2432d0f520ea47767a417323504
5
5
  SHA512:
6
- metadata.gz: f0a67510e6629f6f188c388ecdcdb70adf8527f2f43a14a23d4c364e6805dfc9a9d6f9a7092e98008c1c1df6b188aedd2e0a6a3fd006fd90f69d0387ce0e032d
7
- data.tar.gz: 929fdde8fb5003292a4eb85d3af88d3eb361ba9628abcdfc89e27d75cb8658a39bf96639cdce79727b53a89718d7a5b2c8cae3c7316c2986c73419302ebf786c
6
+ metadata.gz: caa899332d0b1034baf784a418c1788d70220380d783069edf8b653729d47bdacd67016828546dfe41a078e0000e72b54379b5f60a67f5bf1e4823f4e8e72862
7
+ data.tar.gz: 931eed522f0e6d00cab63631967f70729f5d22067016d12a89220d34ee38513213c47ced8090c1062e10f9d0001490dffdc9913b9cc3a0dc84c4395e3bd4e2b0
data/.gitignore CHANGED
@@ -1,2 +1,3 @@
1
1
  .DS_Store
2
2
  .rspec_status
3
+ pkg
@@ -0,0 +1 @@
1
+ 2.5.5
@@ -1,5 +1,5 @@
1
1
  sudo: false
2
2
  language: ruby
3
3
  rvm:
4
- - 2.3.4
4
+ - 2.5.5
5
5
  before_install: gem install bundler -v 1.15.1
@@ -1,84 +1,47 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- query_filter (0.1.5)
4
+ query_filter (0.2.2)
5
5
  activesupport (>= 4.0)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- activemodel (5.1.2)
11
- activesupport (= 5.1.2)
12
- activerecord (5.1.2)
13
- activemodel (= 5.1.2)
14
- activesupport (= 5.1.2)
15
- arel (~> 8.0)
16
- activesupport (5.1.2)
10
+ activemodel (6.0.3.2)
11
+ activesupport (= 6.0.3.2)
12
+ activerecord (6.0.3.2)
13
+ activemodel (= 6.0.3.2)
14
+ activesupport (= 6.0.3.2)
15
+ activesupport (6.0.3.2)
17
16
  concurrent-ruby (~> 1.0, >= 1.0.2)
18
- i18n (~> 0.7)
17
+ i18n (>= 0.7, < 2)
19
18
  minitest (~> 5.1)
20
19
  tzinfo (~> 1.1)
21
- arel (8.0.0)
22
- coderay (1.1.1)
23
- concurrent-ruby (1.0.5)
24
- diff-lcs (1.3)
25
- ffi (1.9.18)
26
- formatador (0.2.5)
27
- guard (2.14.1)
28
- formatador (>= 0.2.4)
29
- listen (>= 2.7, < 4.0)
30
- lumberjack (~> 1.0)
31
- nenv (~> 0.1)
32
- notiffany (~> 0.0)
33
- pry (>= 0.9.12)
34
- shellany (~> 0.0)
35
- thor (>= 0.18.1)
36
- guard-compat (1.2.1)
37
- guard-rspec (4.7.3)
38
- guard (~> 2.1)
39
- guard-compat (~> 1.1)
40
- rspec (>= 2.99.0, < 4.0)
41
- i18n (0.8.4)
42
- listen (3.1.5)
43
- rb-fsevent (~> 0.9, >= 0.9.4)
44
- rb-inotify (~> 0.9, >= 0.9.7)
45
- ruby_dep (~> 1.2)
46
- lumberjack (1.0.12)
47
- method_source (0.8.2)
48
- minitest (5.10.2)
49
- nenv (0.3.0)
50
- notiffany (0.1.1)
51
- nenv (~> 0.1)
52
- shellany (~> 0.0)
53
- pry (0.10.4)
54
- coderay (~> 1.1.0)
55
- method_source (~> 0.8.1)
56
- slop (~> 3.4)
57
- rake (10.5.0)
58
- rb-fsevent (0.9.8)
59
- rb-inotify (0.9.10)
60
- ffi (>= 0.5.0, < 2)
61
- rspec (3.6.0)
62
- rspec-core (~> 3.6.0)
63
- rspec-expectations (~> 3.6.0)
64
- rspec-mocks (~> 3.6.0)
65
- rspec-core (3.6.0)
66
- rspec-support (~> 3.6.0)
67
- rspec-expectations (3.6.0)
20
+ zeitwerk (~> 2.2, >= 2.2.2)
21
+ concurrent-ruby (1.1.6)
22
+ diff-lcs (1.4.2)
23
+ i18n (1.8.3)
24
+ concurrent-ruby (~> 1.0)
25
+ minitest (5.14.1)
26
+ rake (13.0.1)
27
+ rspec (3.9.0)
28
+ rspec-core (~> 3.9.0)
29
+ rspec-expectations (~> 3.9.0)
30
+ rspec-mocks (~> 3.9.0)
31
+ rspec-core (3.9.2)
32
+ rspec-support (~> 3.9.3)
33
+ rspec-expectations (3.9.2)
68
34
  diff-lcs (>= 1.2.0, < 2.0)
69
- rspec-support (~> 3.6.0)
70
- rspec-mocks (3.6.0)
35
+ rspec-support (~> 3.9.0)
36
+ rspec-mocks (3.9.1)
71
37
  diff-lcs (>= 1.2.0, < 2.0)
72
- rspec-support (~> 3.6.0)
73
- rspec-support (3.6.0)
74
- ruby_dep (1.5.0)
75
- shellany (0.0.1)
76
- slop (3.6.0)
77
- sqlite3 (1.3.13)
78
- thor (0.19.4)
38
+ rspec-support (~> 3.9.0)
39
+ rspec-support (3.9.3)
40
+ sqlite3 (1.4.2)
79
41
  thread_safe (0.3.6)
80
- tzinfo (1.2.3)
42
+ tzinfo (1.2.7)
81
43
  thread_safe (~> 0.1)
44
+ zeitwerk (2.3.0)
82
45
 
83
46
  PLATFORMS
84
47
  ruby
@@ -86,12 +49,10 @@ PLATFORMS
86
49
  DEPENDENCIES
87
50
  activerecord (>= 4.0)
88
51
  bundler (~> 1.15)
89
- guard-rspec (~> 4.7, >= 4.7.3)
90
52
  query_filter!
91
- rake (~> 10.0)
92
- rb-fsevent (= 0.9.8)
53
+ rake (>= 12.3.3)
93
54
  rspec (~> 3.0)
94
55
  sqlite3 (~> 1.3, >= 1.3.13)
95
56
 
96
57
  BUNDLED WITH
97
- 1.15.1
58
+ 1.17.3
data/README.md CHANGED
@@ -26,6 +26,37 @@ class Order < ActiveRecord::Base
26
26
  end
27
27
  ```
28
28
 
29
+ Where OrderFilter class looks like:
30
+
31
+ ```ruby
32
+ # app/filters/order_filter.rb
33
+ #
34
+ class OrderFilter < QueryFilter::Base
35
+ scope :customer_id
36
+ scope :service
37
+
38
+ range :total
39
+
40
+ date_range :completed_at
41
+
42
+ def scope_customer_id(value)
43
+ query.where(customer_id: value)
44
+ end
45
+
46
+ def scope_service(value)
47
+ query.where(service_id: value.to_i)
48
+ end
49
+
50
+ def range_total(range)
51
+ query.where(range.query('orders.total'))
52
+ end
53
+
54
+ def date_range_completed_at(period)
55
+ query.where(completed_at: period.range_original)
56
+ end
57
+ end
58
+ ```
59
+
29
60
  ## Installation
30
61
 
31
62
  Add this line to your application's Gemfile:
@@ -94,6 +125,23 @@ This gem support next types of filter params:
94
125
  orders.created_at BETWEEN '2017-06-24 04:00:00.000000' AND '2017-07-01 03:59:59.999999'
95
126
  ```
96
127
 
128
+ When we have date with custom time:
129
+ ```ruby
130
+ date_range :range, format: '%m/%d/%Y %H:%M'
131
+
132
+ def date_range_range(period)
133
+ query.where(created_at: period.range)
134
+ end
135
+ ```
136
+
137
+ `period.range` will ignore time and always return time start_of_day and end_of_day, but the method `period.range_original` will return dates without time modification
138
+
139
+ ```ruby
140
+ def date_range_range(period)
141
+ query.where(created_at: period.range_original)
142
+ end
143
+ ```
144
+
97
145
  * order by
98
146
  ```ruby
99
147
  order_by :sort_column, via: :sort_mode
@@ -188,6 +236,62 @@ QueryFilter.setup do |config|
188
236
  end
189
237
  ```
190
238
 
239
+ ## Testing
240
+
241
+ query_filter gem defines some custom RSpec matchers. Include them to your project:
242
+
243
+ ```ruby
244
+ # spec/support/query_filter.rb
245
+
246
+ require "query_filter/rspec_matchers"
247
+
248
+ RSpec.configure do |config|
249
+ config.include QueryFilter::RSpecMatchers, type: :query_filter
250
+ end
251
+ ```
252
+
253
+ Custom matchers will be available to use in specs:
254
+
255
+ ```ruby
256
+ # spec/filters/order_filter_spec.rb
257
+
258
+ describe OrderFilter, type: :query_filter do
259
+ context "scope deleted" do
260
+ it "performs query" do
261
+ expect { filter(deleted: true) }.to perform_query(deleted: true)
262
+ end
263
+
264
+ it "doesn't perform query with wrong params" do
265
+ expect { filter(deleted: "invalid_param") }.to_not perform_query
266
+ end
267
+ end
268
+
269
+ it "performs query by state" do
270
+ expect(relation).to receive(:with_state).with(:pending)
271
+ filter(state: :pending)
272
+ end
273
+
274
+ it "reorders by sort_column" do
275
+ expect { filter(sort_column: :id, sort_mode: :desc) }
276
+ .to reorder.by("orders.id DESC NULLS LAST")
277
+ end
278
+
279
+ context "query against the database" do
280
+ let(:order) { create(:order, state: :pending) }
281
+
282
+ # relation is a double by default, but can be redefined to an actual ActiveRecord::Relation:
283
+ before do
284
+ relation Order.all
285
+ end
286
+
287
+ it "finds the order" do
288
+ expect(filter(state: :pending)).to contain_exactly(order)
289
+ expect(filter(state: :invalid_state)).to be_empty
290
+ end
291
+ end
292
+ end
293
+ ```
294
+
191
295
  ## Development
192
296
 
193
297
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -17,6 +17,7 @@ module QueryFilter
17
17
  end
18
18
 
19
19
  module Utils
20
+ autoload :DateNormalizer, 'query_filter/utils/date_normalizer'
20
21
  autoload :DatePeriod, 'query_filter/utils/date_period'
21
22
  autoload :ScopeRange, 'query_filter/utils/scope_range'
22
23
  autoload :UserConditions, 'query_filter/utils/user_conditions'
@@ -30,6 +31,18 @@ module QueryFilter
30
31
  mattr_accessor :date_period_splitter
31
32
  self.date_period_splitter = 'to'
32
33
 
34
+ mattr_accessor :date_display_format
35
+ self.date_display_format = '%Y-%m-%d %H:%M'
36
+
37
+ mattr_accessor :datetime_formats
38
+ self.datetime_formats = %w[
39
+ %Y-%m-%dT%H:%M:%S.%L%z
40
+ %Y-%m-%dT%H:%M:%S%z
41
+ %Y-%m-%d %H:%M:%S
42
+ %Y-%m-%d %H:%M
43
+ %Y-%m-%d
44
+ ]
45
+
33
46
  # Default way to setup QueryFilter
34
47
  # @example
35
48
  # QueryFilter.setup do |config|
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Build select query based on params hash
2
4
  #
3
5
  module QueryFilter
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.configure do |config|
4
+ module QueryFilter::RSpecMatchers
5
+ extend RSpec::Matchers::DSL
6
+
7
+ def relation(override = nil)
8
+ @relation ||= override || double('ActiveRecord::Relation')
9
+ end
10
+
11
+ def filter(params)
12
+ described_class.new(relation, params).to_query
13
+ end
14
+
15
+ # Usage:
16
+ #
17
+ # expect { filter(username: "joe") }.to perform_query(users: { username: "joe" })
18
+ # expect { filter(field: :invalid_value) }.to_not perform_query
19
+ #
20
+ matcher :perform_query do |*params_for_where|
21
+ def supports_block_expectations?
22
+ true
23
+ end
24
+
25
+ match do |block|
26
+ expect(relation).to receive(:where).with(*params_for_where)
27
+ block.call
28
+ end
29
+
30
+ match_when_negated do |block|
31
+ expect(relation).to_not receive(:where)
32
+ block.call
33
+ end
34
+ end
35
+
36
+ # Usage:
37
+ #
38
+ # expect { filter(sort: :asc) }.to reorder.by("users.created_at" => "asc")
39
+ # expect { filter(sort: :invalid_value) }.to_not reorder
40
+ #
41
+ matcher :reorder do
42
+ def supports_block_expectations?
43
+ true
44
+ end
45
+
46
+ match do |block|
47
+ expect(relation).to receive(:reorder).with(@params_for_reorder)
48
+ block.call
49
+ end
50
+
51
+ match_when_negated do |block|
52
+ expect(relation).to_not receive(:reorder)
53
+ block.call
54
+ end
55
+
56
+ chain :by do |conditions|
57
+ @params_for_reorder = conditions
58
+ end
59
+ end
60
+ end
61
+
62
+ config.after do
63
+ @relation = nil
64
+ end
65
+ end
@@ -1,42 +1,47 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Parse date range params
2
4
  #
3
5
  # date_range :created_at, keys: [:start_date, :end_date]
4
6
  #
5
7
  # date_range :last_login_date
6
8
  #
7
- module QueryFilter::Rules
8
- class DateRange < Scope
9
- def name
10
- 'date_range'.freeze
11
- end
9
+ module QueryFilter
10
+ module Rules
11
+ class DateRange < Scope
12
+ def name
13
+ 'date_range'
14
+ end
12
15
 
13
- def valid?(values)
14
- period = build_period_from_params(values)
15
- !(period.nil? || period.default?)
16
- end
16
+ def valid?(values)
17
+ period = build_period_from_params(values)
18
+ !(period.nil? || period.default?)
19
+ end
17
20
 
18
- def normalize_params(values)
19
- build_period_from_params(values)
20
- end
21
+ def normalize_params(values)
22
+ build_period_from_params(values)
23
+ end
21
24
 
22
- protected
25
+ protected
23
26
 
24
- def build_period_from_params(params)
25
- if params[key].present?
26
- QueryFilter::Utils::DatePeriod.parse_from_string(params[key], @options[:format])
27
- elsif keys_start_end_dates_exists?(params)
28
- QueryFilter::Utils::DatePeriod.new(*values_start_end_dates(params))
27
+ def build_period_from_params(params)
28
+ if params[key].present?
29
+ QueryFilter::Utils::DatePeriod.parse_from_string(params[key], @options[:format])
30
+ elsif keys_start_end_dates_exists?(params)
31
+ QueryFilter::Utils::DatePeriod.new(*values_start_end_dates(params), @options[:format])
32
+ end
29
33
  end
30
- end
31
34
 
32
- def keys_start_end_dates_exists?(params)
33
- values = values_start_end_dates(params)
34
- !values.nil? && values.size == 2
35
- end
35
+ def keys_start_end_dates_exists?(params)
36
+ values = values_start_end_dates(params)
37
+ !values.nil? && values.size == 2
38
+ end
39
+
40
+ def values_start_end_dates(params)
41
+ return unless @options[:keys]
36
42
 
37
- def values_start_end_dates(params)
38
- return if @options[:keys].nil?
39
- params.values_at(*@options[:keys])
43
+ params.values_at(*@options[:keys])
44
+ end
40
45
  end
41
46
  end
42
47
  end
@@ -1,23 +1,27 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Define order by filter rule
2
4
  #
3
- module QueryFilter::Rules
4
- class OrderBy < Scope
5
- DIRECTIONS = %w[asc desc].freeze
5
+ module QueryFilter
6
+ module Rules
7
+ class OrderBy < Scope
8
+ DIRECTIONS = %w[asc desc].freeze
6
9
 
7
- def name
8
- 'order_by'.freeze
9
- end
10
+ def name
11
+ 'order_by'
12
+ end
10
13
 
11
- def valid?(params)
12
- params[key].present? && DIRECTIONS.include?(params[direction_key].try(:downcase))
13
- end
14
+ def valid?(params)
15
+ params[key].present? && DIRECTIONS.include?(params[direction_key].try(:downcase))
16
+ end
14
17
 
15
- def direction_key
16
- @direction_key ||= (@options[:via] || 'sort_direction').to_sym
17
- end
18
+ def direction_key
19
+ @direction_key ||= (@options[:via] || 'sort_direction').to_sym
20
+ end
18
21
 
19
- def normalize_params(values)
20
- [values[key], values[direction_key]]
22
+ def normalize_params(values)
23
+ [values[key], values[direction_key]]
24
+ end
21
25
  end
22
26
  end
23
27
  end
@@ -1,38 +1,42 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Define range filter rule
2
4
  #
3
- module QueryFilter::Rules
4
- class Range < Scope
5
- def initialize(keys, options = {})
6
- @key = Array(keys).first
7
- @keys = [key_from, key_to]
8
- @options = options
9
- end
5
+ module QueryFilter
6
+ module Rules
7
+ class Range < Scope
8
+ def initialize(keys, options = {})
9
+ @key = Array(keys).first
10
+ @keys = [key_from, key_to]
11
+ @options = options
12
+ end
10
13
 
11
- def name
12
- 'range'.freeze
13
- end
14
+ def name
15
+ 'range'
16
+ end
14
17
 
15
- def valid?(values)
16
- filter = build_range_from_params(values)
17
- filter.valid?
18
- end
18
+ def valid?(values)
19
+ filter = build_range_from_params(values)
20
+ filter.valid?
21
+ end
19
22
 
20
- def normalize_params(values)
21
- build_range_from_params(values)
22
- end
23
+ def normalize_params(values)
24
+ build_range_from_params(values)
25
+ end
23
26
 
24
- protected
27
+ protected
25
28
 
26
- def build_range_from_params(params)
27
- QueryFilter::Utils::ScopeRange.new(key, params)
28
- end
29
+ def build_range_from_params(params)
30
+ QueryFilter::Utils::ScopeRange.new(key, params)
31
+ end
29
32
 
30
- def key_from
31
- @key_from ||= "#{key}_from".to_sym
32
- end
33
+ def key_from
34
+ @key_from ||= "#{key}_from".to_sym
35
+ end
33
36
 
34
- def key_to
35
- @key_to ||= "#{key}_to".to_sym
37
+ def key_to
38
+ @key_to ||= "#{key}_to".to_sym
39
+ end
36
40
  end
37
41
  end
38
42
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Define filter rules
2
4
  #
3
5
  module QueryFilter
@@ -33,7 +35,7 @@ module QueryFilter
33
35
  end
34
36
 
35
37
  def name
36
- 'scope'.freeze
38
+ 'scope'
37
39
  end
38
40
 
39
41
  def key
@@ -1,44 +1,49 @@
1
- module QueryFilter::Rules
2
- class SplitterRange < Scope
3
- class RangeParam
4
- SPLITTER = /[;-]/
1
+ # frozen_string_literal: true
5
2
 
6
- def initialize(value)
7
- @value = value
8
- end
3
+ module QueryFilter
4
+ module Rules
5
+ class SplitterRange < Scope
6
+ class RangeParam
7
+ SPLITTER = /[;-]/.freeze
9
8
 
10
- def valid?
11
- @value.present? && items.size == 2
12
- end
9
+ def initialize(value)
10
+ @value = value
11
+ end
12
+
13
+ def valid?
14
+ @value.present? && items.size == 2
15
+ end
13
16
 
14
- def range
15
- ::Range.new(*items)
17
+ def range
18
+ ::Range.new(*items)
19
+ end
20
+
21
+ def items
22
+ @items ||= @value.split(SPLITTER).map(&:strip).map(&:to_i)
23
+ end
16
24
  end
17
25
 
18
- def items
19
- @items ||= @value.split(SPLITTER).map(&:strip).map(&:to_i)
26
+ def name
27
+ 'splitter_range'
20
28
  end
21
- end
22
29
 
23
- def name
24
- 'splitter_range'.freeze
25
- end
30
+ def valid?(values)
31
+ period = build_period_from_params(values)
32
+ !period.nil?
33
+ end
26
34
 
27
- def valid?(values)
28
- period = build_period_from_params(values)
29
- !period.nil?
30
- end
35
+ def normalize_params(values)
36
+ build_period_from_params(values)
37
+ end
31
38
 
32
- def normalize_params(values)
33
- build_period_from_params(values)
34
- end
39
+ protected
35
40
 
36
- protected
41
+ def build_period_from_params(values)
42
+ param = RangeParam.new(values[key])
43
+ return unless param.valid?
37
44
 
38
- def build_period_from_params(values)
39
- param = RangeParam.new(values[key])
40
- return unless param.valid?
41
- param
45
+ param
46
+ end
42
47
  end
43
48
  end
44
49
  end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module QueryFilter
4
+ module Utils
5
+ class DateNormalizer
6
+ PG_MIN_YEAR = -4713
7
+ PG_MAX_YEAR = 294_276
8
+
9
+ attr_reader :date, :format
10
+
11
+ def initialize(date, format = nil)
12
+ @date = date
13
+ @format = format
14
+ end
15
+
16
+ def parsed_value
17
+ @parsed_value ||= parse
18
+ end
19
+
20
+ def normalize
21
+ valid?(parsed_value) ? parsed_value : default_date
22
+ end
23
+
24
+ private
25
+
26
+ def date?
27
+ date.is_a?(Time) || date.is_a?(DateTime)
28
+ end
29
+
30
+ def valid?(value)
31
+ return false unless Date.valid_date?(value.year, value.month, value.day)
32
+
33
+ value.year > PG_MIN_YEAR && value.year < PG_MAX_YEAR
34
+ end
35
+
36
+ def parse
37
+ return date if date?
38
+ return default_date if date.blank?
39
+
40
+ [@format].concat(QueryFilter.datetime_formats).compact.each do |format|
41
+ value = safe_parse_date(date, format)
42
+ return value if value
43
+ end
44
+
45
+ default_date
46
+ end
47
+
48
+ def safe_parse_date(string, format)
49
+ DateTime.strptime(string, format)
50
+ rescue ArgumentError => _e
51
+ nil
52
+ end
53
+
54
+ def default_date
55
+ Time.zone.today
56
+ end
57
+ end
58
+ end
59
+ end
@@ -3,33 +3,48 @@
3
3
  module QueryFilter
4
4
  module Utils
5
5
  class DatePeriod
6
- attr_reader :date_from, :date_to, :format
7
-
8
- TIME_FORMAT = '%Y-%m-%d %H:%M:%S'
6
+ attr_reader :date_from_raw, :date_to_raw
9
7
 
10
8
  def initialize(date_from = nil, date_to = nil, format = nil)
11
- @format = (format.blank? ? QueryFilter.date_period_format : format)
12
9
  @date_from_raw = date_from
13
10
  @date_to_raw = date_to
14
-
15
- @date_from = normalize_date(date_from).beginning_of_day
16
- @date_to = normalize_date(date_to).end_of_day
11
+ @format = format
17
12
  end
18
13
 
19
14
  def range
20
15
  @range ||= date_from..date_to
21
16
  end
22
17
 
18
+ def range_original
19
+ @range_original ||= date_from_original..date_to_original
20
+ end
21
+
22
+ def date_from
23
+ @date_from ||= date_from_original.beginning_of_day
24
+ end
25
+
26
+ def date_to
27
+ @date_to ||= date_to_original.end_of_day
28
+ end
29
+
30
+ def date_from_original
31
+ @date_from_original ||= normalize_date(@date_from_raw)
32
+ end
33
+
34
+ def date_to_original
35
+ @date_to_original ||= normalize_date(@date_to_raw)
36
+ end
37
+
23
38
  def title
24
39
  @title ||= to_human
25
40
  end
26
41
 
27
42
  def datefrom
28
- @datefrom ||= I18n.l(@date_from, format: @format)
43
+ @datefrom ||= I18n.l(date_from, format: date_display_format)
29
44
  end
30
45
 
31
46
  def dateto
32
- @dateto ||= I18n.l(@date_to, format: @format)
47
+ @dateto ||= I18n.l(date_to, format: date_display_format)
33
48
  end
34
49
 
35
50
  def to_param
@@ -55,25 +70,21 @@ module QueryFilter
55
70
  return value if value.is_a?(DatePeriod)
56
71
 
57
72
  if value.blank?
58
- new(nil, nil, format)
73
+ new
59
74
  else
60
75
  dates = value.to_s.split(QueryFilter.date_period_splitter).map(&:strip)
61
- new(dates[0], dates[1], format)
76
+ new(dates[0], dates[1], format || QueryFilter.date_period_format)
62
77
  end
63
78
  end
64
79
 
65
80
  private
66
81
 
82
+ def date_display_format
83
+ @format || QueryFilter.date_display_format
84
+ end
85
+
67
86
  def normalize_date(date)
68
- return date if date.is_a?(Time) || date.is_a?(DateTime)
69
- return Time.zone.today if date.blank?
70
-
71
- begin
72
- time = DateTime.strptime(date, @format)
73
- Time.zone.parse(time.strftime(TIME_FORMAT))
74
- rescue ArgumentError => _e
75
- Time.zone.today
76
- end
87
+ QueryFilter::Utils::DateNormalizer.new(date, @format).normalize
77
88
  end
78
89
  end
79
90
  end
@@ -1,42 +1,46 @@
1
- module QueryFilter::Utils
2
- # Usage:
3
- #
4
- # range = Utils::ScopeRange.new(:orders, { orders_from: 1, orders_to: 44 })
5
- # range.query('orders_count')
6
- #
7
- class ScopeRange
8
- def initialize(name, options = {})
9
- @name = name
10
- @options = options
11
- end
1
+ # frozen_string_literal: true
12
2
 
13
- def name_from
14
- @name_from ||= "#{@name}_from".to_sym
15
- end
3
+ module QueryFilter
4
+ module Utils
5
+ # Usage:
6
+ #
7
+ # range = Utils::ScopeRange.new(:orders, { orders_from: 1, orders_to: 44 })
8
+ # range.query('orders_count')
9
+ #
10
+ class ScopeRange
11
+ def initialize(name, options = {})
12
+ @name = name
13
+ @options = options
14
+ end
16
15
 
17
- def name_to
18
- @name_to ||= "#{@name}_to".to_sym
19
- end
16
+ def name_from
17
+ @name_from ||= "#{@name}_from".to_sym
18
+ end
20
19
 
21
- def value_from
22
- @options[name_from]
23
- end
20
+ def name_to
21
+ @name_to ||= "#{@name}_to".to_sym
22
+ end
24
23
 
25
- def value_to
26
- @options[name_to]
27
- end
24
+ def value_from
25
+ @options[name_from]
26
+ end
28
27
 
29
- def valid?
30
- @options && (value_from.present? || value_to.present?)
31
- end
28
+ def value_to
29
+ @options[name_to]
30
+ end
31
+
32
+ def valid?
33
+ @options && (value_from.present? || value_to.present?)
34
+ end
32
35
 
33
- def query(column)
34
- if value_from.present? && value_to.present?
35
- ["#{column} BETWEEN ? AND ?", value_from, value_to]
36
- elsif value_from.present?
37
- ["#{column} >= ?", value_from]
38
- elsif value_to.present?
39
- ["#{column} <= ?", value_to]
36
+ def query(column)
37
+ if value_from.present? && value_to.present?
38
+ ["#{column} BETWEEN ? AND ?", value_from, value_to]
39
+ elsif value_from.present?
40
+ ["#{column} >= ?", value_from]
41
+ elsif value_to.present?
42
+ ["#{column} <= ?", value_to]
43
+ end
40
44
  end
41
45
  end
42
46
  end
@@ -15,8 +15,8 @@ module QueryFilter
15
15
 
16
16
  def passed?
17
17
  return true if empty?
18
- value = target.params
19
18
 
19
+ value = target.params
20
20
  conditions_lambdas.all? { |c| c.call(target, value) }
21
21
  end
22
22
 
@@ -35,8 +35,8 @@ module QueryFilter
35
35
 
36
36
  private
37
37
 
38
- def invert_lambda(l)
39
- ->(*args, &blk) { !l.call(*args, &blk) }
38
+ def invert_lambda(lblock)
39
+ ->(*args, &blk) { !lblock.call(*args, &blk) }
40
40
  end
41
41
 
42
42
  # Filters support:
@@ -61,6 +61,7 @@ module QueryFilter
61
61
  if filter.arity > 1
62
62
  lambda do |target, _, &block|
63
63
  raise ArgumentError unless block
64
+
64
65
  target.instance_exec(target, block, &filter)
65
66
  end
66
67
  elsif filter.arity <= 0
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module QueryFilter
2
- VERSION = '0.1.5'.freeze
4
+ VERSION = '0.2.2'
3
5
  end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
- # coding: utf-8
3
2
 
4
- lib = File.expand_path('../lib', __FILE__)
3
+ lib = File.expand_path('lib', __dir__)
5
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
6
5
  require 'query_filter/version'
7
6
 
@@ -23,12 +22,10 @@ Gem::Specification.new do |spec|
23
22
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
24
23
  spec.require_paths = ['lib']
25
24
 
25
+ spec.add_development_dependency 'activerecord', '>= 4.0'
26
26
  spec.add_development_dependency 'bundler', '~> 1.15'
27
- spec.add_development_dependency 'rake', '~> 10.0'
27
+ spec.add_development_dependency 'rake', '>= 12.3.3'
28
28
  spec.add_development_dependency 'rspec', '~> 3.0'
29
- spec.add_development_dependency 'guard-rspec', '~> 4.7', '>= 4.7.3'
30
- spec.add_development_dependency 'rb-fsevent', '0.9.8'
31
- spec.add_development_dependency 'activerecord', '>= 4.0'
32
29
  spec.add_development_dependency 'sqlite3', '~> 1.3', '>= 1.3.13'
33
30
 
34
31
  spec.add_dependency 'activesupport', '>= 4.0'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: query_filter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Igor Galeta
@@ -9,98 +9,64 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2017-07-12 00:00:00.000000000 Z
12
+ date: 2020-06-24 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
- name: bundler
16
- requirement: !ruby/object:Gem::Requirement
17
- requirements:
18
- - - "~>"
19
- - !ruby/object:Gem::Version
20
- version: '1.15'
21
- type: :development
22
- prerelease: false
23
- version_requirements: !ruby/object:Gem::Requirement
24
- requirements:
25
- - - "~>"
26
- - !ruby/object:Gem::Version
27
- version: '1.15'
28
- - !ruby/object:Gem::Dependency
29
- name: rake
15
+ name: activerecord
30
16
  requirement: !ruby/object:Gem::Requirement
31
17
  requirements:
32
- - - "~>"
18
+ - - ">="
33
19
  - !ruby/object:Gem::Version
34
- version: '10.0'
20
+ version: '4.0'
35
21
  type: :development
36
22
  prerelease: false
37
23
  version_requirements: !ruby/object:Gem::Requirement
38
24
  requirements:
39
- - - "~>"
25
+ - - ">="
40
26
  - !ruby/object:Gem::Version
41
- version: '10.0'
27
+ version: '4.0'
42
28
  - !ruby/object:Gem::Dependency
43
- name: rspec
29
+ name: bundler
44
30
  requirement: !ruby/object:Gem::Requirement
45
31
  requirements:
46
32
  - - "~>"
47
33
  - !ruby/object:Gem::Version
48
- version: '3.0'
34
+ version: '1.15'
49
35
  type: :development
50
36
  prerelease: false
51
37
  version_requirements: !ruby/object:Gem::Requirement
52
38
  requirements:
53
39
  - - "~>"
54
40
  - !ruby/object:Gem::Version
55
- version: '3.0'
41
+ version: '1.15'
56
42
  - !ruby/object:Gem::Dependency
57
- name: guard-rspec
43
+ name: rake
58
44
  requirement: !ruby/object:Gem::Requirement
59
45
  requirements:
60
- - - "~>"
61
- - !ruby/object:Gem::Version
62
- version: '4.7'
63
46
  - - ">="
64
47
  - !ruby/object:Gem::Version
65
- version: 4.7.3
48
+ version: 12.3.3
66
49
  type: :development
67
50
  prerelease: false
68
51
  version_requirements: !ruby/object:Gem::Requirement
69
52
  requirements:
70
- - - "~>"
71
- - !ruby/object:Gem::Version
72
- version: '4.7'
73
53
  - - ">="
74
54
  - !ruby/object:Gem::Version
75
- version: 4.7.3
76
- - !ruby/object:Gem::Dependency
77
- name: rb-fsevent
78
- requirement: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - '='
81
- - !ruby/object:Gem::Version
82
- version: 0.9.8
83
- type: :development
84
- prerelease: false
85
- version_requirements: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - '='
88
- - !ruby/object:Gem::Version
89
- version: 0.9.8
55
+ version: 12.3.3
90
56
  - !ruby/object:Gem::Dependency
91
- name: activerecord
57
+ name: rspec
92
58
  requirement: !ruby/object:Gem::Requirement
93
59
  requirements:
94
- - - ">="
60
+ - - "~>"
95
61
  - !ruby/object:Gem::Version
96
- version: '4.0'
62
+ version: '3.0'
97
63
  type: :development
98
64
  prerelease: false
99
65
  version_requirements: !ruby/object:Gem::Requirement
100
66
  requirements:
101
- - - ">="
67
+ - - "~>"
102
68
  - !ruby/object:Gem::Version
103
- version: '4.0'
69
+ version: '3.0'
104
70
  - !ruby/object:Gem::Dependency
105
71
  name: sqlite3
106
72
  requirement: !ruby/object:Gem::Requirement
@@ -146,6 +112,7 @@ files:
146
112
  - ".gitignore"
147
113
  - ".rspec"
148
114
  - ".rubocop.yml"
115
+ - ".ruby-version"
149
116
  - ".travis.yml"
150
117
  - Gemfile
151
118
  - Gemfile.lock
@@ -157,11 +124,13 @@ files:
157
124
  - bin/setup
158
125
  - lib/query_filter.rb
159
126
  - lib/query_filter/base.rb
127
+ - lib/query_filter/rspec_matchers.rb
160
128
  - lib/query_filter/rules/date_range.rb
161
129
  - lib/query_filter/rules/order_by.rb
162
130
  - lib/query_filter/rules/range.rb
163
131
  - lib/query_filter/rules/scope.rb
164
132
  - lib/query_filter/rules/splitter_range.rb
133
+ - lib/query_filter/utils/date_normalizer.rb
165
134
  - lib/query_filter/utils/date_period.rb
166
135
  - lib/query_filter/utils/scope_range.rb
167
136
  - lib/query_filter/utils/user_conditions.rb
@@ -187,7 +156,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
187
156
  version: '0'
188
157
  requirements: []
189
158
  rubyforge_project:
190
- rubygems_version: 2.5.2
159
+ rubygems_version: 2.7.6.2
191
160
  signing_key:
192
161
  specification_version: 4
193
162
  summary: ActiveRecord query filter gem