pursuit 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2b49ae3ec2734b8b67fef2fb0686b85af3a694745db4654de863942d4a598d53
4
- data.tar.gz: 8d8a6e71f23b31d0ebf33a1c2554a9875c0c189786954574c3d5f58ced5fe304
3
+ metadata.gz: 9584065901bd2b27fce1df13ee13586151c96be3e04f222b81c6ee93d8f078a4
4
+ data.tar.gz: 81f233b5d39526129b8bdf7c7bba997e9a5b964b9bd5024bc3e3351f1105c927
5
5
  SHA512:
6
- metadata.gz: faebb7031e643b0fe4011cee2fda71a916dd12aa2819845a26bf79ef6ca0f0411bcd3e8b5ea1f092624909933639d97d0e59cc2b80ba38ea10f2dcbf0254c154
7
- data.tar.gz: 0c06093eb83369d20f5e64a843483e98a019a5facb594f75b845949cfdcc0b7027da78ccb8be92d6a739cc76720e1d28165019aaaf7220718deb550c2816440a
6
+ metadata.gz: 83fcec1d5657de087a5a5fdf71b131e34632fc02328cd66d2a551c438201f9125fd8d0861d239a96a4b6b36c6ac3bde342efaa4b610a1689646540229fe456bd
7
+ data.tar.gz: 47d981997a463f5203b3316410d6f5e2395fc1aa448329a86a625a732c2751a3e281b4581973cb9893f3c76d68f6999f38a0fbe0020c56ecc608f99b968101b0
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- pursuit (0.2.0)
4
+ pursuit (0.3.0)
5
5
  activerecord (>= 5.2.0, < 6.2.0)
6
6
  activesupport (>= 5.2.0, < 6.2.0)
7
7
 
data/README.md CHANGED
@@ -23,19 +23,18 @@ class Product < ActiveRecord::Base
23
23
  searchable do |o|
24
24
  o.relation :variations, :title, :stock_status
25
25
 
26
- o.keyed :title
27
- o.keyed :description
28
- o.keyed :rating
26
+ # Attributes can be used for both keyed and unkeyed searching by default, but you can pass either `keyed: false` or
27
+ # `unkeyed: false` to restrict when the attribute is searched.
28
+ o.attribute :title
29
+ o.attribute :description
30
+ o.attribute :rating, unkeyed: false
29
31
 
30
32
  # You can also create virtual attributes to search by passing in a block that returns an arel node.
31
- o.keyed :title_length do
33
+ o.attribute :title_length, unkeyed: false do
32
34
  Arel::Nodes::NamedFunction.new('LENGTH', [
33
35
  arel_table[:title]
34
36
  ])
35
37
  end
36
-
37
- o.unkeyed :title
38
- o.unkeyed :description
39
38
  end
40
39
  end
41
40
  ```
@@ -3,5 +3,5 @@
3
3
  module Pursuit
4
4
  # @return [String] The gem's semantic version number.
5
5
  #
6
- VERSION = '0.2.0'
6
+ VERSION = '0.3.0'
7
7
  end
@@ -2,40 +2,55 @@
2
2
 
3
3
  module Pursuit
4
4
  class SearchOptions
5
+ # @return [Struct] The structure which holds the search options for a single attribute.
6
+ #
7
+ AttributeOptions = Struct.new(:keyed, :unkeyed, :block)
8
+
5
9
  # @return [Class<ActiveRecord::Base>] The `ActiveRecord::Base` child class to search.
6
10
  #
7
11
  attr_reader :record_class
8
12
 
9
- # @return [Hash<Symbol, Array<Symbol>>] The record's relatives and the attribute names that can be searched.
13
+ # @return [Hash<Symbol, Array<Symbol>>] The attribute names of the record's relatives which can be searched.
10
14
  #
11
15
  attr_reader :relations
12
16
 
13
- # @return [Hash<Symbol, Proc>] The attribute names which can be searched with a keyed term (e.g. 'last_name:*herb').
14
- #
15
- attr_reader :keyed_attributes
16
-
17
- # @return [Hash<Symbol, Proc>] The attribute names which can be searched with an unkeyed term (e.g. 'herb').
17
+ # @return [Hash<Symbol, AttributeOptions>] The attributes which can be searched.
18
18
  #
19
- attr_reader :unkeyed_attributes
19
+ attr_reader :attributes
20
20
 
21
- # Create a new `SearchOptions` ready for adding options.
21
+ # Create a new `SearchOptions` and call the passed block to setup the options.
22
22
  #
23
23
  # @params record_class [Class<ActiveRecord::Base>]
24
- # @params block [Proc]
24
+ # @params block [Proc]
25
25
  #
26
26
  def initialize(record_class, &block)
27
27
  @record_class = record_class
28
28
  @relations = {}
29
- @keyed_attributes = {}
30
- @unkeyed_attributes = {}
29
+ @attributes = {}
31
30
 
32
31
  block.call(self) if block
33
32
  end
34
33
 
34
+ # @return [Hash<Symbol, Proc>] The attributes which can be queried using a keyed term.
35
+ #
36
+ def keyed_attributes
37
+ attributes.each_with_object({}) do |(name, options), keyed_attributes|
38
+ keyed_attributes[name] = options.block if options.keyed
39
+ end
40
+ end
41
+
42
+ # @return [Hash<Symbol, Proc>] The attributes which can be queried using an unkeyed term.
43
+ #
44
+ def unkeyed_attributes
45
+ attributes.each_with_object({}) do |(name, options), unkeyed_attributes|
46
+ unkeyed_attributes[name] = options.block if options.unkeyed
47
+ end
48
+ end
49
+
35
50
  # @return [Array<String>] The collection of all possible attributes which can be used as a keyed term.
36
51
  #
37
52
  def keys
38
- keys = relations.keys + keyed_attributes.keys
53
+ keys = relations.keys + attributes.select { |_, a| a.keyed }.keys
39
54
  keys.map(&:to_s).uniq
40
55
  end
41
56
 
@@ -51,21 +66,13 @@ module Pursuit
51
66
 
52
67
  # Add a keyed attribute to search.
53
68
  #
54
- # @param name [Symbol] The name of the attribute.
55
- # @param block [Proc] A block which returns an arel node to query against instead of a real attribute.
56
- #
57
- def keyed(name, &block)
58
- keyed_attributes[name] = block || -> { record_class.arel_table[name] }
59
- nil
60
- end
61
-
62
- # Add an unkeyed attribute to search.
63
- #
64
- # @param name [Symbol] The name of the attribute.
65
- # @param block [Proc] A block which returns an arel node to query against instead of a real attribute.
69
+ # @param name [Symbol] The name of the attribute.
70
+ # @param keyed [Boolean] `true` when the attribute should be searchable using a keyed term, `false` otherwise.
71
+ # @param unkeyed [Boolean] `true` when the attribute should be searchable using an unkeyed term, `false` otherwise.
72
+ # @param block [Proc] A block which returns an Arel node to query, instead of the matching table column.
66
73
  #
67
- def unkeyed(name, &block)
68
- unkeyed_attributes[name] = block || -> { record_class.arel_table[name] }
74
+ def attribute(name, keyed: true, unkeyed: true, &block)
75
+ attributes[name] = AttributeOptions.new(keyed, unkeyed, block || -> { record_class.arel_table[name] })
69
76
  nil
70
77
  end
71
78
  end
@@ -8,17 +8,13 @@ class Product < ActiveRecord::Base
8
8
  searchable do |o|
9
9
  o.relation :variations, :title, :stock_status
10
10
 
11
- o.keyed :title
12
- o.keyed :description
13
- o.keyed :rating
14
-
15
- o.keyed :title_length do
11
+ o.attribute :title
12
+ o.attribute :description
13
+ o.attribute :rating, unkeyed: false
14
+ o.attribute :title_length, unkeyed: false do
16
15
  Arel::Nodes::NamedFunction.new('LENGTH', [
17
16
  arel_table[:title]
18
17
  ])
19
18
  end
20
-
21
- o.unkeyed :title
22
- o.unkeyed :description
23
19
  end
24
20
  end
@@ -11,19 +11,6 @@ RSpec.describe Pursuit::SearchOptions do
11
11
  end
12
12
  end
13
13
 
14
- before do
15
- search_options.relation :variations, :title, :stock_status
16
-
17
- search_options.keyed :title
18
- search_options.keyed :title_length, &title_length_node_builder
19
- search_options.keyed :description
20
- search_options.keyed :rating
21
-
22
- search_options.unkeyed :title
23
- search_options.unkeyed :title_length, &title_length_node_builder
24
- search_options.unkeyed :description
25
- end
26
-
27
14
  describe '#record_class' do
28
15
  subject(:record_class) { search_options.record_class }
29
16
 
@@ -35,6 +22,10 @@ RSpec.describe Pursuit::SearchOptions do
35
22
  describe '#relations' do
36
23
  subject(:relations) { search_options.relations }
37
24
 
25
+ before do
26
+ search_options.relation :variations, :title, :stock_status
27
+ end
28
+
38
29
  it 'is expected to contain the correct relations' do
39
30
  expect(relations).to eq(variations: %i[title stock_status])
40
31
  end
@@ -43,12 +34,19 @@ RSpec.describe Pursuit::SearchOptions do
43
34
  describe '#keyed_attributes' do
44
35
  subject(:keyed_attributes) { search_options.keyed_attributes }
45
36
 
37
+ before do
38
+ search_options.attribute :title, keyed: false
39
+ search_options.attribute :title_length, &title_length_node_builder
40
+ search_options.attribute :description
41
+ search_options.attribute :rating, unkeyed: false
42
+ end
43
+
46
44
  it 'is expected to contain the correct keyed attributes' do
47
- expect(keyed_attributes.keys).to contain_exactly(:title, :title_length, :description, :rating)
45
+ expect(keyed_attributes.keys).to contain_exactly(:title_length, :description, :rating)
48
46
  end
49
47
 
50
48
  it 'is expected to set a default node builder for attributes declared without a block' do
51
- expect(keyed_attributes[:title].call).to eq(Product.arel_table[:title])
49
+ expect(keyed_attributes[:description].call).to eq(Product.arel_table[:description])
52
50
  end
53
51
 
54
52
  it 'is expected to set a custom node builder for attributes declared with a block' do
@@ -59,6 +57,13 @@ RSpec.describe Pursuit::SearchOptions do
59
57
  describe '#unkeyed_attributes' do
60
58
  subject(:unkeyed_attributes) { search_options.unkeyed_attributes }
61
59
 
60
+ before do
61
+ search_options.attribute :title, keyed: false
62
+ search_options.attribute :title_length, &title_length_node_builder
63
+ search_options.attribute :description
64
+ search_options.attribute :rating, unkeyed: false
65
+ end
66
+
62
67
  it 'is expected to contain the correct unkeyed attributes' do
63
68
  expect(unkeyed_attributes.keys).to contain_exactly(:title, :title_length, :description)
64
69
  end
@@ -71,4 +76,64 @@ RSpec.describe Pursuit::SearchOptions do
71
76
  expect(unkeyed_attributes[:title_length]).to eq(title_length_node_builder)
72
77
  end
73
78
  end
79
+
80
+ describe '#relation' do
81
+ subject(:relation) { search_options.relation(:variations, :title, :stock_status) }
82
+
83
+ it 'is expected to add the relation to #relations' do
84
+ expect { relation }.to change(search_options, :relations).from({}).to(variations: %i[title stock_status])
85
+ end
86
+ end
87
+
88
+ describe '#attribute' do
89
+ subject(:attribute) { search_options.attribute(:description) }
90
+
91
+ it { is_expected.to eq(nil) }
92
+
93
+ it 'is expected to add the attribute to #attributes' do
94
+ expect { attribute }.to change(search_options.attributes, :keys).from([]).to(%i[description])
95
+ end
96
+
97
+ it 'is expected to allow keyed searching by default' do
98
+ attribute
99
+ expect(search_options.attributes[:description].keyed).to eq(true)
100
+ end
101
+
102
+ it 'is expected to allow unkeyed searching by default' do
103
+ attribute
104
+ expect(search_options.attributes[:description].unkeyed).to eq(true)
105
+ end
106
+
107
+ it 'is expected to use the matching table column node builder by default' do
108
+ attribute
109
+ expect(search_options.attributes[:description].block.call).to eq(Product.arel_table[:description])
110
+ end
111
+
112
+ context 'when passing :keyed eq false' do
113
+ subject(:attribute) { search_options.attribute(:description, keyed: false) }
114
+
115
+ it 'is expected to disallow keyed searching' do
116
+ attribute
117
+ expect(search_options.attributes[:description].keyed).to eq(false)
118
+ end
119
+ end
120
+
121
+ context 'when passing :unkeyed eq false' do
122
+ subject(:attribute) { search_options.attribute(:description, unkeyed: false) }
123
+
124
+ it 'is expected to disallow unkeyed searching' do
125
+ attribute
126
+ expect(search_options.attributes[:description].unkeyed).to eq(false)
127
+ end
128
+ end
129
+
130
+ context 'when passing a block' do
131
+ subject(:attribute) { search_options.attribute(:description, &title_length_node_builder) }
132
+
133
+ it 'is expected to use the custom node builder' do
134
+ attribute
135
+ expect(search_options.attributes[:description].block).to eq(title_length_node_builder)
136
+ end
137
+ end
138
+ end
74
139
  end
@@ -7,18 +7,14 @@ RSpec.describe Pursuit::Search do
7
7
  Pursuit::SearchOptions.new(Product) do |o|
8
8
  o.relation :variations, :title, :stock_status
9
9
 
10
- o.keyed :title
11
- o.keyed :description
12
- o.keyed :rating
13
-
14
- o.keyed :title_length do
10
+ o.attribute :title
11
+ o.attribute :description
12
+ o.attribute :rating, unkeyed: false
13
+ o.attribute :title_length, unkeyed: false do
15
14
  Arel::Nodes::NamedFunction.new('LENGTH', [
16
15
  Product.arel_table[:title]
17
16
  ])
18
17
  end
19
-
20
- o.unkeyed :title
21
- o.unkeyed :description
22
18
  end
23
19
  end
24
20
 
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.2.0
4
+ version: 0.3.0
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-18 00:00:00.000000000 Z
11
+ date: 2021-11-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord