query_filter 0.1.5 → 0.2.2

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: 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