pursuit 0.3.1 → 0.4.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
2
  SHA256:
3
- metadata.gz: c5d86e6be4355b96bdaf0d8c02ea680e5cf0f6c3c9f5fdcd3d8e9a20785aad8b
4
- data.tar.gz: 310009d659879f97ae8bc9947594533fdb0c11f20702b2bf10e1003c072b4425
3
+ metadata.gz: 33d8d69593b2a4d0958be760e1fb12b1bcfe6f6fef61cb76ab81f29c57849fe9
4
+ data.tar.gz: 04a6f91a0a5d0ed66390fdb389c64344ab15c32547755fa8b1b54c33449479d8
5
5
  SHA512:
6
- metadata.gz: 49991dd50ed278c76d9dbc7f0dd8f48a7f41fa7905f284964a27df9bc90a55ad6833a5911b86ed159d4d4c88fc2aac736ac5feb2c1b8469fb9adbf02abca3f49
7
- data.tar.gz: 6663dc11f0f6e6adc08f87834d303ed59e0269415132d7c0fdb54d96ee7ca926be69097dd26dd58d0bc836b9a9bf7f8ccfc35fd3e8f9c6976340e52b0719c5b1
6
+ metadata.gz: 205bf48c72a98dcf57a95483d25722bee933a23e570c00e7dfa1aabeb4cb6e8cf78e59e87526052357fd42590955c7b9a18f867abf0e6bb8f95d009faf0f1820
7
+ data.tar.gz: fa909dbe9e34a411c6131e74c22bdf005dd664fef89d6fb3b63b3a8853b5c92080a8f358b081c1ff589235ffd358a9b31fd50b4f7a027750b8bf3ce4709461b6
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 3.0.2
1
+ 3.1.0
data/Gemfile.lock CHANGED
@@ -1,50 +1,49 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- pursuit (0.3.0)
5
- activerecord (>= 5.2.0, < 6.2.0)
6
- activesupport (>= 5.2.0, < 6.2.0)
4
+ pursuit (0.4.2)
5
+ activerecord (>= 5.2.0, < 7.1.0)
6
+ activesupport (>= 5.2.0, < 7.1.0)
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
10
10
  specs:
11
- actionpack (6.0.4.1)
12
- actionview (= 6.0.4.1)
13
- activesupport (= 6.0.4.1)
14
- rack (~> 2.0, >= 2.0.8)
11
+ actionpack (7.0.1)
12
+ actionview (= 7.0.1)
13
+ activesupport (= 7.0.1)
14
+ rack (~> 2.0, >= 2.2.0)
15
15
  rack-test (>= 0.6.3)
16
16
  rails-dom-testing (~> 2.0)
17
17
  rails-html-sanitizer (~> 1.0, >= 1.2.0)
18
- actionview (6.0.4.1)
19
- activesupport (= 6.0.4.1)
18
+ actionview (7.0.1)
19
+ activesupport (= 7.0.1)
20
20
  builder (~> 3.1)
21
21
  erubi (~> 1.4)
22
22
  rails-dom-testing (~> 2.0)
23
23
  rails-html-sanitizer (~> 1.1, >= 1.2.0)
24
- activemodel (6.0.4.1)
25
- activesupport (= 6.0.4.1)
26
- activerecord (6.0.4.1)
27
- activemodel (= 6.0.4.1)
28
- activesupport (= 6.0.4.1)
29
- activesupport (6.0.4.1)
24
+ activemodel (7.0.1)
25
+ activesupport (= 7.0.1)
26
+ activerecord (7.0.1)
27
+ activemodel (= 7.0.1)
28
+ activesupport (= 7.0.1)
29
+ activesupport (7.0.1)
30
30
  concurrent-ruby (~> 1.0, >= 1.0.2)
31
- i18n (>= 0.7, < 2)
32
- minitest (~> 5.1)
33
- tzinfo (~> 1.1)
34
- zeitwerk (~> 2.2, >= 2.2.2)
31
+ i18n (>= 1.6, < 2)
32
+ minitest (>= 5.1)
33
+ tzinfo (~> 2.0)
35
34
  ast (2.4.2)
36
35
  builder (3.2.4)
37
36
  coderay (1.1.3)
38
- combustion (1.3.3)
37
+ combustion (1.3.5)
39
38
  activesupport (>= 3.0.0)
40
39
  railties (>= 3.0.0)
41
40
  thor (>= 0.14.6)
42
41
  concurrent-ruby (1.1.9)
43
42
  crass (1.0.6)
44
- diff-lcs (1.4.4)
43
+ diff-lcs (1.5.0)
45
44
  erubi (1.10.0)
46
- ffi (1.15.4)
47
- formatador (0.3.0)
45
+ ffi (1.15.5)
46
+ formatador (1.1.0)
48
47
  guard (2.18.0)
49
48
  formatador (>= 0.2.4)
50
49
  listen (>= 2.7, < 4.0)
@@ -59,26 +58,25 @@ GEM
59
58
  guard (~> 2.1)
60
59
  guard-compat (~> 1.1)
61
60
  rspec (>= 2.99.0, < 4.0)
62
- i18n (1.8.11)
61
+ i18n (1.9.1)
63
62
  concurrent-ruby (~> 1.0)
64
- jaro_winkler (1.5.4)
65
- listen (3.7.0)
63
+ listen (3.7.1)
66
64
  rb-fsevent (~> 0.10, >= 0.10.3)
67
65
  rb-inotify (~> 0.9, >= 0.9.10)
68
- loofah (2.12.0)
66
+ loofah (2.13.0)
69
67
  crass (~> 1.0.2)
70
68
  nokogiri (>= 1.5.9)
71
69
  lumberjack (1.2.8)
72
70
  method_source (1.0.0)
73
- minitest (5.14.4)
71
+ minitest (5.15.0)
74
72
  nenv (0.3.0)
75
- nokogiri (1.12.5-x86_64-darwin)
73
+ nokogiri (1.13.1-x86_64-darwin)
76
74
  racc (~> 1.4)
77
75
  notiffany (0.1.3)
78
76
  nenv (~> 0.1)
79
77
  shellany (~> 0.0)
80
78
  parallel (1.21.0)
81
- parser (3.0.2.0)
79
+ parser (3.1.0.0)
82
80
  ast (~> 2.4.1)
83
81
  pry (0.14.1)
84
82
  coderay (~> 1.1)
@@ -92,70 +90,78 @@ GEM
92
90
  nokogiri (>= 1.6)
93
91
  rails-html-sanitizer (1.4.2)
94
92
  loofah (~> 2.3)
95
- railties (6.0.4.1)
96
- actionpack (= 6.0.4.1)
97
- activesupport (= 6.0.4.1)
93
+ railties (7.0.1)
94
+ actionpack (= 7.0.1)
95
+ activesupport (= 7.0.1)
98
96
  method_source
99
- rake (>= 0.8.7)
100
- thor (>= 0.20.3, < 2.0)
101
- rainbow (3.0.0)
97
+ rake (>= 12.2)
98
+ thor (~> 1.0)
99
+ zeitwerk (~> 2.5)
100
+ rainbow (3.1.1)
102
101
  rake (13.0.6)
103
102
  rb-fsevent (0.11.0)
104
103
  rb-inotify (0.10.1)
105
104
  ffi (~> 1.0)
106
- rspec (3.9.0)
107
- rspec-core (~> 3.9.0)
108
- rspec-expectations (~> 3.9.0)
109
- rspec-mocks (~> 3.9.0)
110
- rspec-core (3.9.3)
111
- rspec-support (~> 3.9.3)
112
- rspec-expectations (3.9.4)
105
+ regexp_parser (2.2.0)
106
+ rexml (3.2.5)
107
+ rspec (3.10.0)
108
+ rspec-core (~> 3.10.0)
109
+ rspec-expectations (~> 3.10.0)
110
+ rspec-mocks (~> 3.10.0)
111
+ rspec-core (3.10.2)
112
+ rspec-support (~> 3.10.0)
113
+ rspec-expectations (3.10.2)
113
114
  diff-lcs (>= 1.2.0, < 2.0)
114
- rspec-support (~> 3.9.0)
115
- rspec-mocks (3.9.1)
115
+ rspec-support (~> 3.10.0)
116
+ rspec-mocks (3.10.3)
116
117
  diff-lcs (>= 1.2.0, < 2.0)
117
- rspec-support (~> 3.9.0)
118
- rspec-rails (3.9.1)
119
- actionpack (>= 3.0)
120
- activesupport (>= 3.0)
121
- railties (>= 3.0)
122
- rspec-core (~> 3.9.0)
123
- rspec-expectations (~> 3.9.0)
124
- rspec-mocks (~> 3.9.0)
125
- rspec-support (~> 3.9.0)
126
- rspec-support (3.9.4)
127
- rubocop (0.77.0)
128
- jaro_winkler (~> 1.5.1)
118
+ rspec-support (~> 3.10.0)
119
+ rspec-rails (5.1.0)
120
+ actionpack (>= 5.2)
121
+ activesupport (>= 5.2)
122
+ railties (>= 5.2)
123
+ rspec-core (~> 3.10)
124
+ rspec-expectations (~> 3.10)
125
+ rspec-mocks (~> 3.10)
126
+ rspec-support (~> 3.10)
127
+ rspec-support (3.10.3)
128
+ rubocop (1.25.0)
129
129
  parallel (~> 1.10)
130
- parser (>= 2.6)
130
+ parser (>= 3.1.0.0)
131
131
  rainbow (>= 2.2.2, < 4.0)
132
+ regexp_parser (>= 1.8, < 3.0)
133
+ rexml
134
+ rubocop-ast (>= 1.15.1, < 2.0)
132
135
  ruby-progressbar (~> 1.7)
133
- unicode-display_width (>= 1.4.0, < 1.7)
136
+ unicode-display_width (>= 1.4.0, < 3.0)
137
+ rubocop-ast (1.15.1)
138
+ parser (>= 3.0.1.1)
134
139
  ruby-progressbar (1.11.0)
135
140
  shellany (0.0.1)
136
141
  sqlite3 (1.4.2)
137
- thor (1.1.0)
138
- thread_safe (0.3.6)
139
- tzinfo (1.2.9)
140
- thread_safe (~> 0.1)
141
- unicode-display_width (1.6.1)
142
- yard (0.9.26)
143
- zeitwerk (2.5.1)
142
+ thor (1.2.1)
143
+ tzinfo (2.0.4)
144
+ concurrent-ruby (~> 1.0)
145
+ unicode-display_width (2.1.0)
146
+ webrick (1.7.0)
147
+ yard (0.9.27)
148
+ webrick (~> 1.7.0)
149
+ zeitwerk (2.5.4)
144
150
 
145
151
  PLATFORMS
146
152
  x86_64-darwin-21
147
153
 
148
154
  DEPENDENCIES
149
155
  bundler (~> 2.0)
150
- combustion (~> 1.1)
156
+ combustion (~> 1.3)
151
157
  guard-rspec (~> 4.7)
152
158
  pursuit!
153
159
  rake (~> 13.0)
154
- rspec (~> 3.8)
155
- rspec-rails (~> 3.8)
156
- rubocop (~> 0.77.0)
160
+ rspec (~> 3.10)
161
+ rspec-rails (~> 5.0)
162
+ rubocop (~> 1.25)
157
163
  sqlite3 (~> 1.4)
158
- yard (~> 0.9.20)
164
+ yard (~> 0.9)
159
165
 
160
166
  BUNDLED WITH
161
- 2.2.22
167
+ 2.3.3
data/README.md CHANGED
@@ -26,12 +26,13 @@ class Product < ActiveRecord::Base
26
26
  # Attributes can be used for both keyed and unkeyed searching by default, but you can pass either `keyed: false` or
27
27
  # `unkeyed: false` to restrict when the attribute is searched.
28
28
  o.attribute :title
29
+ o.attribute :description
29
30
  o.attribute :rating, unkeyed: false
30
31
 
31
32
  # You can shorten the search keyword by passing the desired search term first, and then the real attribute name
32
33
  # as the second argument.
33
- # => "desc*=foo"
34
- o.attribute :desc, :description
34
+ # => "category*=shirts"
35
+ o.attribute :category, :category_id
35
36
 
36
37
  # It's also possible to query entirely custom Arel nodes by passing a block which returns the Arel node to query.
37
38
  # You could use this to query a person's full name by concatenating their first and last name columns, for example.
@@ -3,5 +3,5 @@
3
3
  module Pursuit
4
4
  # @return [String] The gem's semantic version number.
5
5
  #
6
- VERSION = '0.3.1'
6
+ VERSION = '0.4.2'
7
7
  end
@@ -51,12 +51,13 @@ module Pursuit
51
51
  return nil if terms.blank?
52
52
 
53
53
  terms.reduce(nil) do |chain, term|
54
- reflection = options.record_class.reflections[term.key]
54
+ attribute_name = term.key.to_sym
55
+ reflection = options.relations.key?(attribute_name) ? options.record_class.reflections[term.key] : nil
55
56
  node = if reflection.present?
56
- attribute_names = options.relations[term.key.to_sym]
57
+ attribute_names = options.relations[attribute_name]
57
58
  build_arel_for_reflection(reflection, attribute_names, term.operator, term.value)
58
59
  else
59
- node_builder = options.keyed_attributes[term.key.to_sym]
60
+ node_builder = options.keyed_attributes[attribute_name]
60
61
  build_arel_for_node(node_builder.call, term.operator, term.value)
61
62
  end
62
63
 
@@ -89,7 +90,7 @@ module Pursuit
89
90
 
90
91
  def build_arel_for_reflection(reflection, attribute_names, operator, value)
91
92
  nodes = build_arel_for_reflection_join(reflection)
92
- count_nodes = build_arel_for_relation_count(nodes, operator, value)
93
+ count_nodes = build_arel_for_relation_count(nodes, operator, value) unless reflection.belongs_to?
93
94
  return count_nodes if count_nodes.present?
94
95
 
95
96
  match_nodes = attribute_names.reduce(nil) do |chain, attribute_name|
@@ -103,6 +104,23 @@ module Pursuit
103
104
  end
104
105
 
105
106
  def build_arel_for_reflection_join(reflection)
107
+ if reflection.belongs_to?
108
+ build_arel_for_belongs_to_reflection_join(reflection)
109
+ else
110
+ build_arel_for_has_reflection_join(reflection)
111
+ end
112
+ end
113
+
114
+ def build_arel_for_belongs_to_reflection_join(reflection)
115
+ reflection_table = reflection.klass.arel_table
116
+ reflection_table.where(
117
+ reflection_table[reflection.join_primary_key].eq(
118
+ options.record_class.arel_table[reflection.join_foreign_key]
119
+ )
120
+ )
121
+ end
122
+
123
+ def build_arel_for_has_reflection_join(reflection)
106
124
  reflection_table = reflection.klass.arel_table
107
125
  reflection_through = reflection.through_reflection
108
126
 
data/pursuit.gemspec CHANGED
@@ -21,16 +21,16 @@ Gem::Specification.new do |spec|
21
21
 
22
22
  spec.metadata['yard.run'] = 'yri'
23
23
 
24
- spec.add_runtime_dependency 'activerecord', '>= 5.2.0', '< 6.2.0'
25
- spec.add_runtime_dependency 'activesupport', '>= 5.2.0', '< 6.2.0'
24
+ spec.add_runtime_dependency 'activerecord', '>= 5.2.0', '< 7.1.0'
25
+ spec.add_runtime_dependency 'activesupport', '>= 5.2.0', '< 7.1.0'
26
26
 
27
27
  spec.add_development_dependency 'bundler', '~> 2.0'
28
- spec.add_development_dependency 'combustion', '~> 1.1'
28
+ spec.add_development_dependency 'combustion', '~> 1.3'
29
29
  spec.add_development_dependency 'guard-rspec', '~> 4.7'
30
30
  spec.add_development_dependency 'rake', '~> 13.0'
31
- spec.add_development_dependency 'rspec', '~> 3.8'
32
- spec.add_development_dependency 'rspec-rails', '~> 3.8'
33
- spec.add_development_dependency 'rubocop', '~> 0.77.0'
34
- spec.add_development_dependency 'yard', '~> 0.9.20'
31
+ spec.add_development_dependency 'rspec', '~> 3.10'
32
+ spec.add_development_dependency 'rspec-rails', '~> 5.0'
33
+ spec.add_development_dependency 'rubocop', '~> 1.25'
34
+ spec.add_development_dependency 'yard', '~> 0.9'
35
35
  spec.add_development_dependency 'sqlite3', '~> 1.4'
36
36
  end
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Product < ActiveRecord::Base
4
+ belongs_to :category, class_name: 'ProductCategory', inverse_of: :products, optional: true
5
+
4
6
  has_many :variations, class_name: 'ProductVariation', inverse_of: :product
5
7
 
6
8
  validates :title, presence: true
@@ -16,5 +18,7 @@ class Product < ActiveRecord::Base
16
18
  arel_table[:title]
17
19
  ])
18
20
  end
21
+
22
+ o.attribute :category, :category_id
19
23
  end
20
24
  end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ProductCategory < ActiveRecord::Base
4
+ has_many :products, class_name: 'Product', foreign_key: :category_id, inverse_of: :category, dependent: :nullify
5
+
6
+ validates :name, presence: true
7
+ end
@@ -1,7 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  ActiveRecord::Schema.define do
4
+ create_table :product_categories, id: :string, force: true do |t|
5
+ t.string :name, null: false
6
+
7
+ t.timestamps null: false
8
+ end
9
+
4
10
  create_table :products, force: true do |t|
11
+ t.belongs_to :category, type: :string, foreign_key: { to_table: 'product_categories' }
12
+
5
13
  t.string :title, null: false
6
14
 
7
15
  t.text :description
@@ -5,6 +5,7 @@ RSpec.describe Pursuit::Search do
5
5
 
6
6
  let(:search_options) do
7
7
  Pursuit::SearchOptions.new(Product) do |o|
8
+ o.relation :category, :name
8
9
  o.relation :variations, :title, :stock_status
9
10
 
10
11
  o.attribute :title
@@ -15,6 +16,8 @@ RSpec.describe Pursuit::Search do
15
16
  Product.arel_table[:title]
16
17
  ])
17
18
  end
19
+
20
+ o.attribute :cat, :category_id
18
21
  end
19
22
  end
20
23
 
@@ -251,115 +254,20 @@ RSpec.describe Pursuit::Search do
251
254
  end
252
255
  end
253
256
 
254
- context 'when passed a `match` relationship search query' do
255
- let(:query) { 'variations*=green' }
256
-
257
- let(:product_a) { Product.create!(title: 'Plain Shirt') }
258
- let(:product_b) { Product.create!(title: 'Funky Shirt') }
259
-
260
- let(:product_variation_a) { ProductVariation.create!(product: product_a, title: 'Red') }
261
- let(:product_variation_b) { ProductVariation.create!(product: product_b, title: 'Green') }
262
- let(:product_variation_c) { ProductVariation.create!(product: product_b, title: 'Blue') }
263
-
264
- before do
265
- product_a
266
- product_b
267
-
268
- product_variation_a
269
- product_variation_b
270
- product_variation_c
271
- end
272
-
273
- it 'is expected to contain the matching records' do
274
- expect(perform).to contain_exactly(product_b)
275
- end
276
- end
277
-
278
- context 'when passed an `equal to` relationship count query' do
279
- let(:query) { 'variations==1' }
280
-
281
- let(:product_a) { Product.create!(title: 'Plain Shirt') }
282
- let(:product_b) { Product.create!(title: 'Funky Shirt') }
283
- let(:product_c) { Product.create!(title: 'Socks') }
284
-
285
- let(:product_variation_a) { ProductVariation.create!(product: product_b, title: 'Red') }
286
- let(:product_variation_b) { ProductVariation.create!(product: product_b, title: 'Green') }
287
- let(:product_variation_c) { ProductVariation.create!(product: product_b, title: 'Blue') }
288
- let(:product_variation_d) { ProductVariation.create!(product: product_c, title: 'White') }
289
-
290
- before do
291
- product_a
292
- product_b
293
- product_c
294
-
295
- product_variation_a
296
- product_variation_b
297
- product_variation_c
298
- product_variation_d
299
- end
300
-
301
- it 'is expected to contain the matching records' do
302
- expect(perform).to contain_exactly(product_c)
303
- end
304
- end
305
-
306
- context 'when passed a `greater than` relationship count query' do
307
- let(:query) { 'variations>1' }
308
-
309
- let(:product_a) { Product.create!(title: 'Plain Shirt') }
310
- let(:product_b) { Product.create!(title: 'Funky Shirt') }
311
- let(:product_c) { Product.create!(title: 'Socks') }
312
-
313
- let(:product_variation_a) { ProductVariation.create!(product: product_b, title: 'Red') }
314
- let(:product_variation_b) { ProductVariation.create!(product: product_b, title: 'Green') }
315
- let(:product_variation_c) { ProductVariation.create!(product: product_b, title: 'Blue') }
316
- let(:product_variation_d) { ProductVariation.create!(product: product_c, title: 'White') }
317
- let(:product_variation_e) { ProductVariation.create!(product: product_a, title: 'Black') }
318
- let(:product_variation_f) { ProductVariation.create!(product: product_a, title: 'Gray') }
319
-
320
- before do
321
- product_a
322
- product_b
323
- product_c
324
-
325
- product_variation_a
326
- product_variation_b
327
- product_variation_c
328
- product_variation_d
329
- product_variation_e
330
- product_variation_f
331
- end
332
-
333
- it 'is expected to contain the matching records' do
334
- expect(perform).to contain_exactly(product_a, product_b)
335
- end
336
- end
337
-
338
- context 'when passed a `greater than or equal to` relationship count query' do
339
- let(:query) { 'variations>=2' }
257
+ context 'when querying a custom attribute whose name matches a reflection' do
258
+ let(:query) { 'cat==shirts' }
340
259
 
341
- let(:product_a) { Product.create!(title: 'Plain Shirt') }
342
- let(:product_b) { Product.create!(title: 'Funky Shirt') }
343
- let(:product_c) { Product.create!(title: 'Socks') }
260
+ let(:shirts_category) { ProductCategory.create!(id: 'shirts', name: 'The Shirt Collection') }
261
+ let(:socks_category) { ProductCategory.create!(id: 'socks', name: 'The Sock Collection') }
344
262
 
345
- let(:product_variation_a) { ProductVariation.create!(product: product_b, title: 'Red') }
346
- let(:product_variation_b) { ProductVariation.create!(product: product_b, title: 'Green') }
347
- let(:product_variation_c) { ProductVariation.create!(product: product_b, title: 'Blue') }
348
- let(:product_variation_d) { ProductVariation.create!(product: product_c, title: 'White') }
349
- let(:product_variation_e) { ProductVariation.create!(product: product_a, title: 'Black') }
350
- let(:product_variation_f) { ProductVariation.create!(product: product_a, title: 'Gray') }
263
+ let(:product_a) { Product.create!(title: 'Plain Shirt', category: shirts_category) }
264
+ let(:product_b) { Product.create!(title: 'Funky Shirt', category: shirts_category) }
265
+ let(:product_c) { Product.create!(title: 'Socks - Pack of 4', category: socks_category) }
351
266
 
352
267
  before do
353
268
  product_a
354
269
  product_b
355
270
  product_c
356
-
357
- product_variation_a
358
- product_variation_b
359
- product_variation_c
360
- product_variation_d
361
- product_variation_e
362
- product_variation_f
363
271
  end
364
272
 
365
273
  it 'is expected to contain the matching records' do
@@ -367,99 +275,243 @@ RSpec.describe Pursuit::Search do
367
275
  end
368
276
  end
369
277
 
370
- context 'when passed a `less than` relationship count query' do
371
- let(:query) { 'variations<3' }
372
-
373
- let(:product_a) { Product.create!(title: 'Plain Shirt') }
374
- let(:product_b) { Product.create!(title: 'Funky Shirt') }
375
- let(:product_c) { Product.create!(title: 'Socks') }
376
-
377
- let(:product_variation_a) { ProductVariation.create!(product: product_b, title: 'Red') }
378
- let(:product_variation_b) { ProductVariation.create!(product: product_b, title: 'Green') }
379
- let(:product_variation_c) { ProductVariation.create!(product: product_b, title: 'Blue') }
380
- let(:product_variation_d) { ProductVariation.create!(product: product_c, title: 'White') }
381
- let(:product_variation_e) { ProductVariation.create!(product: product_a, title: 'Black') }
382
- let(:product_variation_f) { ProductVariation.create!(product: product_a, title: 'Gray') }
278
+ context 'when searching a #has_many relationship' do
279
+ context 'when passed a `match` relationship search query' do
280
+ let(:query) { 'variations*=green' }
383
281
 
384
- before do
385
- product_a
386
- product_b
387
- product_c
282
+ let(:product_a) { Product.create!(title: 'Plain Shirt') }
283
+ let(:product_b) { Product.create!(title: 'Funky Shirt') }
284
+
285
+ let(:product_variation_a) { ProductVariation.create!(product: product_a, title: 'Red') }
286
+ let(:product_variation_b) { ProductVariation.create!(product: product_b, title: 'Green') }
287
+ let(:product_variation_c) { ProductVariation.create!(product: product_b, title: 'Blue') }
288
+
289
+ before do
290
+ product_a
291
+ product_b
292
+
293
+ product_variation_a
294
+ product_variation_b
295
+ product_variation_c
296
+ end
388
297
 
389
- product_variation_a
390
- product_variation_b
391
- product_variation_c
392
- product_variation_d
393
- product_variation_e
394
- product_variation_f
298
+ it 'is expected to contain the matching records' do
299
+ expect(perform).to contain_exactly(product_b)
300
+ end
395
301
  end
396
302
 
397
- it 'is expected to contain the matching records' do
398
- expect(perform).to contain_exactly(product_a, product_c)
303
+ context 'when passed an `equal to` relationship count query' do
304
+ let(:query) { 'variations==1' }
305
+
306
+ let(:product_a) { Product.create!(title: 'Plain Shirt') }
307
+ let(:product_b) { Product.create!(title: 'Funky Shirt') }
308
+ let(:product_c) { Product.create!(title: 'Socks') }
309
+
310
+ let(:product_variation_a) { ProductVariation.create!(product: product_b, title: 'Red') }
311
+ let(:product_variation_b) { ProductVariation.create!(product: product_b, title: 'Green') }
312
+ let(:product_variation_c) { ProductVariation.create!(product: product_b, title: 'Blue') }
313
+ let(:product_variation_d) { ProductVariation.create!(product: product_c, title: 'White') }
314
+
315
+ before do
316
+ product_a
317
+ product_b
318
+ product_c
319
+
320
+ product_variation_a
321
+ product_variation_b
322
+ product_variation_c
323
+ product_variation_d
324
+ end
325
+
326
+ it 'is expected to contain the matching records' do
327
+ expect(perform).to contain_exactly(product_c)
328
+ end
329
+ end
330
+
331
+ context 'when passed a `greater than` relationship count query' do
332
+ let(:query) { 'variations>1' }
333
+
334
+ let(:product_a) { Product.create!(title: 'Plain Shirt') }
335
+ let(:product_b) { Product.create!(title: 'Funky Shirt') }
336
+ let(:product_c) { Product.create!(title: 'Socks') }
337
+
338
+ let(:product_variation_a) { ProductVariation.create!(product: product_b, title: 'Red') }
339
+ let(:product_variation_b) { ProductVariation.create!(product: product_b, title: 'Green') }
340
+ let(:product_variation_c) { ProductVariation.create!(product: product_b, title: 'Blue') }
341
+ let(:product_variation_d) { ProductVariation.create!(product: product_c, title: 'White') }
342
+ let(:product_variation_e) { ProductVariation.create!(product: product_a, title: 'Black') }
343
+ let(:product_variation_f) { ProductVariation.create!(product: product_a, title: 'Gray') }
344
+
345
+ before do
346
+ product_a
347
+ product_b
348
+ product_c
349
+
350
+ product_variation_a
351
+ product_variation_b
352
+ product_variation_c
353
+ product_variation_d
354
+ product_variation_e
355
+ product_variation_f
356
+ end
357
+
358
+ it 'is expected to contain the matching records' do
359
+ expect(perform).to contain_exactly(product_a, product_b)
360
+ end
361
+ end
362
+
363
+ context 'when passed a `greater than or equal to` relationship count query' do
364
+ let(:query) { 'variations>=2' }
365
+
366
+ let(:product_a) { Product.create!(title: 'Plain Shirt') }
367
+ let(:product_b) { Product.create!(title: 'Funky Shirt') }
368
+ let(:product_c) { Product.create!(title: 'Socks') }
369
+
370
+ let(:product_variation_a) { ProductVariation.create!(product: product_b, title: 'Red') }
371
+ let(:product_variation_b) { ProductVariation.create!(product: product_b, title: 'Green') }
372
+ let(:product_variation_c) { ProductVariation.create!(product: product_b, title: 'Blue') }
373
+ let(:product_variation_d) { ProductVariation.create!(product: product_c, title: 'White') }
374
+ let(:product_variation_e) { ProductVariation.create!(product: product_a, title: 'Black') }
375
+ let(:product_variation_f) { ProductVariation.create!(product: product_a, title: 'Gray') }
376
+
377
+ before do
378
+ product_a
379
+ product_b
380
+ product_c
381
+
382
+ product_variation_a
383
+ product_variation_b
384
+ product_variation_c
385
+ product_variation_d
386
+ product_variation_e
387
+ product_variation_f
388
+ end
389
+
390
+ it 'is expected to contain the matching records' do
391
+ expect(perform).to contain_exactly(product_a, product_b)
392
+ end
393
+ end
394
+
395
+ context 'when passed a `less than` relationship count query' do
396
+ let(:query) { 'variations<3' }
397
+
398
+ let(:product_a) { Product.create!(title: 'Plain Shirt') }
399
+ let(:product_b) { Product.create!(title: 'Funky Shirt') }
400
+ let(:product_c) { Product.create!(title: 'Socks') }
401
+
402
+ let(:product_variation_a) { ProductVariation.create!(product: product_b, title: 'Red') }
403
+ let(:product_variation_b) { ProductVariation.create!(product: product_b, title: 'Green') }
404
+ let(:product_variation_c) { ProductVariation.create!(product: product_b, title: 'Blue') }
405
+ let(:product_variation_d) { ProductVariation.create!(product: product_c, title: 'White') }
406
+ let(:product_variation_e) { ProductVariation.create!(product: product_a, title: 'Black') }
407
+ let(:product_variation_f) { ProductVariation.create!(product: product_a, title: 'Gray') }
408
+
409
+ before do
410
+ product_a
411
+ product_b
412
+ product_c
413
+
414
+ product_variation_a
415
+ product_variation_b
416
+ product_variation_c
417
+ product_variation_d
418
+ product_variation_e
419
+ product_variation_f
420
+ end
421
+
422
+ it 'is expected to contain the matching records' do
423
+ expect(perform).to contain_exactly(product_a, product_c)
424
+ end
425
+ end
426
+
427
+ context 'when passed a `less than or equal to` relationship count query' do
428
+ let(:query) { 'variations<=2' }
429
+
430
+ let(:product_a) { Product.create!(title: 'Plain Shirt') }
431
+ let(:product_b) { Product.create!(title: 'Funky Shirt') }
432
+ let(:product_c) { Product.create!(title: 'Socks') }
433
+
434
+ let(:product_variation_a) { ProductVariation.create!(product: product_b, title: 'Red') }
435
+ let(:product_variation_b) { ProductVariation.create!(product: product_b, title: 'Green') }
436
+ let(:product_variation_c) { ProductVariation.create!(product: product_b, title: 'Blue') }
437
+ let(:product_variation_d) { ProductVariation.create!(product: product_c, title: 'White') }
438
+ let(:product_variation_e) { ProductVariation.create!(product: product_a, title: 'Black') }
439
+ let(:product_variation_f) { ProductVariation.create!(product: product_a, title: 'Gray') }
440
+
441
+ before do
442
+ product_a
443
+ product_b
444
+ product_c
445
+
446
+ product_variation_a
447
+ product_variation_b
448
+ product_variation_c
449
+ product_variation_d
450
+ product_variation_e
451
+ product_variation_f
452
+ end
453
+
454
+ it 'is expected to contain the matching records' do
455
+ expect(perform).to contain_exactly(product_a, product_c)
456
+ end
457
+ end
458
+
459
+ context 'when passed a `greater than` and `less than` relationship count query' do
460
+ let(:query) { 'variations>1 variations<3' }
461
+
462
+ let(:product_a) { Product.create!(title: 'Plain Shirt') }
463
+ let(:product_b) { Product.create!(title: 'Funky Shirt') }
464
+ let(:product_c) { Product.create!(title: 'Socks') }
465
+
466
+ let(:product_variation_a) { ProductVariation.create!(product: product_b, title: 'Red') }
467
+ let(:product_variation_b) { ProductVariation.create!(product: product_b, title: 'Green') }
468
+ let(:product_variation_c) { ProductVariation.create!(product: product_b, title: 'Blue') }
469
+ let(:product_variation_d) { ProductVariation.create!(product: product_c, title: 'White') }
470
+ let(:product_variation_e) { ProductVariation.create!(product: product_a, title: 'Black') }
471
+ let(:product_variation_f) { ProductVariation.create!(product: product_a, title: 'Gray') }
472
+
473
+ before do
474
+ product_a
475
+ product_b
476
+ product_c
477
+
478
+ product_variation_a
479
+ product_variation_b
480
+ product_variation_c
481
+ product_variation_d
482
+ product_variation_e
483
+ product_variation_f
484
+ end
485
+
486
+ it 'is expected to contain the matching records' do
487
+ expect(perform).to contain_exactly(product_a)
488
+ end
399
489
  end
400
490
  end
401
491
 
402
- context 'when passed a `less than or equal to` relationship count query' do
403
- let(:query) { 'variations<=2' }
492
+ context 'when searching a #belongs_to relationship' do
493
+ context 'when passed a `match` relationship search query' do
494
+ let(:query) { 'category*=shirt' }
404
495
 
405
- let(:product_a) { Product.create!(title: 'Plain Shirt') }
406
- let(:product_b) { Product.create!(title: 'Funky Shirt') }
407
- let(:product_c) { Product.create!(title: 'Socks') }
496
+ let(:product_category_a) { ProductCategory.create!(id: 'one', name: 'Shirts') }
497
+ let(:product_category_b) { ProductCategory.create!(id: 'two', name: 'Socks') }
408
498
 
409
- let(:product_variation_a) { ProductVariation.create!(product: product_b, title: 'Red') }
410
- let(:product_variation_b) { ProductVariation.create!(product: product_b, title: 'Green') }
411
- let(:product_variation_c) { ProductVariation.create!(product: product_b, title: 'Blue') }
412
- let(:product_variation_d) { ProductVariation.create!(product: product_c, title: 'White') }
413
- let(:product_variation_e) { ProductVariation.create!(product: product_a, title: 'Black') }
414
- let(:product_variation_f) { ProductVariation.create!(product: product_a, title: 'Gray') }
499
+ let(:product_a) { Product.create!(category: product_category_a, title: 'Plain Shirt') }
500
+ let(:product_b) { Product.create!(category: product_category_a, title: 'Funky Shirt') }
501
+ let(:product_c) { Product.create!(category: product_category_b, title: 'White Socks') }
415
502
 
416
- before do
417
- product_a
418
- product_b
419
- product_c
420
-
421
- product_variation_a
422
- product_variation_b
423
- product_variation_c
424
- product_variation_d
425
- product_variation_e
426
- product_variation_f
427
- end
428
-
429
- it 'is expected to contain the matching records' do
430
- expect(perform).to contain_exactly(product_a, product_c)
431
- end
432
- end
503
+ before do
504
+ product_category_a
505
+ product_category_b
433
506
 
434
- context 'when passed a `greater than` and `less than` relationship count query' do
435
- let(:query) { 'variations>1 variations<3' }
507
+ product_a
508
+ product_b
509
+ product_c
510
+ end
436
511
 
437
- let(:product_a) { Product.create!(title: 'Plain Shirt') }
438
- let(:product_b) { Product.create!(title: 'Funky Shirt') }
439
- let(:product_c) { Product.create!(title: 'Socks') }
440
-
441
- let(:product_variation_a) { ProductVariation.create!(product: product_b, title: 'Red') }
442
- let(:product_variation_b) { ProductVariation.create!(product: product_b, title: 'Green') }
443
- let(:product_variation_c) { ProductVariation.create!(product: product_b, title: 'Blue') }
444
- let(:product_variation_d) { ProductVariation.create!(product: product_c, title: 'White') }
445
- let(:product_variation_e) { ProductVariation.create!(product: product_a, title: 'Black') }
446
- let(:product_variation_f) { ProductVariation.create!(product: product_a, title: 'Gray') }
447
-
448
- before do
449
- product_a
450
- product_b
451
- product_c
452
-
453
- product_variation_a
454
- product_variation_b
455
- product_variation_c
456
- product_variation_d
457
- product_variation_e
458
- product_variation_f
459
- end
460
-
461
- it 'is expected to contain the matching records' do
462
- expect(perform).to contain_exactly(product_a)
512
+ it 'is expected to contain the matching records' do
513
+ expect(perform).to contain_exactly(product_a, product_b)
514
+ end
463
515
  end
464
516
  end
465
517
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pursuit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.4.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nialto Services
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-11-22 00:00:00.000000000 Z
11
+ date: 2022-01-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -19,7 +19,7 @@ dependencies:
19
19
  version: 5.2.0
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
- version: 6.2.0
22
+ version: 7.1.0
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
@@ -29,7 +29,7 @@ dependencies:
29
29
  version: 5.2.0
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
- version: 6.2.0
32
+ version: 7.1.0
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: activesupport
35
35
  requirement: !ruby/object:Gem::Requirement
@@ -39,7 +39,7 @@ dependencies:
39
39
  version: 5.2.0
40
40
  - - "<"
41
41
  - !ruby/object:Gem::Version
42
- version: 6.2.0
42
+ version: 7.1.0
43
43
  type: :runtime
44
44
  prerelease: false
45
45
  version_requirements: !ruby/object:Gem::Requirement
@@ -49,7 +49,7 @@ dependencies:
49
49
  version: 5.2.0
50
50
  - - "<"
51
51
  - !ruby/object:Gem::Version
52
- version: 6.2.0
52
+ version: 7.1.0
53
53
  - !ruby/object:Gem::Dependency
54
54
  name: bundler
55
55
  requirement: !ruby/object:Gem::Requirement
@@ -70,14 +70,14 @@ dependencies:
70
70
  requirements:
71
71
  - - "~>"
72
72
  - !ruby/object:Gem::Version
73
- version: '1.1'
73
+ version: '1.3'
74
74
  type: :development
75
75
  prerelease: false
76
76
  version_requirements: !ruby/object:Gem::Requirement
77
77
  requirements:
78
78
  - - "~>"
79
79
  - !ruby/object:Gem::Version
80
- version: '1.1'
80
+ version: '1.3'
81
81
  - !ruby/object:Gem::Dependency
82
82
  name: guard-rspec
83
83
  requirement: !ruby/object:Gem::Requirement
@@ -112,56 +112,56 @@ dependencies:
112
112
  requirements:
113
113
  - - "~>"
114
114
  - !ruby/object:Gem::Version
115
- version: '3.8'
115
+ version: '3.10'
116
116
  type: :development
117
117
  prerelease: false
118
118
  version_requirements: !ruby/object:Gem::Requirement
119
119
  requirements:
120
120
  - - "~>"
121
121
  - !ruby/object:Gem::Version
122
- version: '3.8'
122
+ version: '3.10'
123
123
  - !ruby/object:Gem::Dependency
124
124
  name: rspec-rails
125
125
  requirement: !ruby/object:Gem::Requirement
126
126
  requirements:
127
127
  - - "~>"
128
128
  - !ruby/object:Gem::Version
129
- version: '3.8'
129
+ version: '5.0'
130
130
  type: :development
131
131
  prerelease: false
132
132
  version_requirements: !ruby/object:Gem::Requirement
133
133
  requirements:
134
134
  - - "~>"
135
135
  - !ruby/object:Gem::Version
136
- version: '3.8'
136
+ version: '5.0'
137
137
  - !ruby/object:Gem::Dependency
138
138
  name: rubocop
139
139
  requirement: !ruby/object:Gem::Requirement
140
140
  requirements:
141
141
  - - "~>"
142
142
  - !ruby/object:Gem::Version
143
- version: 0.77.0
143
+ version: '1.25'
144
144
  type: :development
145
145
  prerelease: false
146
146
  version_requirements: !ruby/object:Gem::Requirement
147
147
  requirements:
148
148
  - - "~>"
149
149
  - !ruby/object:Gem::Version
150
- version: 0.77.0
150
+ version: '1.25'
151
151
  - !ruby/object:Gem::Dependency
152
152
  name: yard
153
153
  requirement: !ruby/object:Gem::Requirement
154
154
  requirements:
155
155
  - - "~>"
156
156
  - !ruby/object:Gem::Version
157
- version: 0.9.20
157
+ version: '0.9'
158
158
  type: :development
159
159
  prerelease: false
160
160
  version_requirements: !ruby/object:Gem::Requirement
161
161
  requirements:
162
162
  - - "~>"
163
163
  - !ruby/object:Gem::Version
164
- version: 0.9.20
164
+ version: '0.9'
165
165
  - !ruby/object:Gem::Dependency
166
166
  name: sqlite3
167
167
  requirement: !ruby/object:Gem::Requirement
@@ -207,6 +207,7 @@ files:
207
207
  - lib/pursuit/search_term_parser.rb
208
208
  - pursuit.gemspec
209
209
  - spec/internal/app/models/product.rb
210
+ - spec/internal/app/models/product_category.rb
210
211
  - spec/internal/app/models/product_variation.rb
211
212
  - spec/internal/config/database.yml
212
213
  - spec/internal/db/schema.rb
@@ -240,12 +241,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
240
241
  - !ruby/object:Gem::Version
241
242
  version: '0'
242
243
  requirements: []
243
- rubygems_version: 3.2.22
244
+ rubygems_version: 3.3.3
244
245
  signing_key:
245
246
  specification_version: 4
246
247
  summary: Advanced key-based searching for ActiveRecord objects.
247
248
  test_files:
248
249
  - spec/internal/app/models/product.rb
250
+ - spec/internal/app/models/product_category.rb
249
251
  - spec/internal/app/models/product_variation.rb
250
252
  - spec/internal/config/database.yml
251
253
  - spec/internal/db/schema.rb