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 +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +6 -7
- data/lib/pursuit/constants.rb +1 -1
- data/lib/pursuit/search_options.rb +33 -26
- data/spec/internal/app/models/product.rb +4 -8
- data/spec/pursuit/search_options_spec.rb +80 -15
- data/spec/pursuit/search_spec.rb +4 -8
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9584065901bd2b27fce1df13ee13586151c96be3e04f222b81c6ee93d8f078a4
|
4
|
+
data.tar.gz: 81f233b5d39526129b8bdf7c7bba997e9a5b964b9bd5024bc3e3351f1105c927
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 83fcec1d5657de087a5a5fdf71b131e34632fc02328cd66d2a551c438201f9125fd8d0861d239a96a4b6b36c6ac3bde342efaa4b610a1689646540229fe456bd
|
7
|
+
data.tar.gz: 47d981997a463f5203b3316410d6f5e2395fc1aa448329a86a625a732c2751a3e281b4581973cb9893f3c76d68f6999f38a0fbe0020c56ecc608f99b968101b0
|
data/Gemfile.lock
CHANGED
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
|
-
|
27
|
-
|
28
|
-
o.
|
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.
|
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
|
```
|
data/lib/pursuit/constants.rb
CHANGED
@@ -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
|
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,
|
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 :
|
19
|
+
attr_reader :attributes
|
20
20
|
|
21
|
-
# Create a new `SearchOptions`
|
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
|
24
|
+
# @params block [Proc]
|
25
25
|
#
|
26
26
|
def initialize(record_class, &block)
|
27
27
|
@record_class = record_class
|
28
28
|
@relations = {}
|
29
|
-
@
|
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 +
|
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
|
55
|
-
# @param
|
56
|
-
#
|
57
|
-
|
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
|
68
|
-
|
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.
|
12
|
-
o.
|
13
|
-
o.
|
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(:
|
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[:
|
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
|
data/spec/pursuit/search_spec.rb
CHANGED
@@ -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.
|
11
|
-
o.
|
12
|
-
o.
|
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.
|
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-
|
11
|
+
date: 2021-11-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|