pursuit 0.4.5 → 1.0.1
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/.github/workflows/rubygem.yaml +46 -0
- data/Gemfile +14 -13
- data/Gemfile.lock +14 -13
- data/README.md +210 -27
- data/bin/console +10 -0
- data/lib/pursuit/aggregate_modifier_not_found.rb +20 -0
- data/lib/pursuit/aggregate_modifier_required.rb +20 -0
- data/lib/pursuit/aggregate_modifiers_not_available.rb +13 -0
- data/lib/pursuit/attribute_not_found.rb +20 -0
- data/lib/pursuit/constants.rb +1 -1
- data/lib/pursuit/error.rb +7 -0
- data/lib/pursuit/predicate_parser.rb +181 -0
- data/lib/pursuit/predicate_search.rb +83 -0
- data/lib/pursuit/predicate_transform.rb +231 -0
- data/lib/pursuit/query_error.rb +7 -0
- data/lib/pursuit/simple_search.rb +64 -0
- data/lib/pursuit/term_parser.rb +44 -0
- data/lib/pursuit/term_search.rb +69 -0
- data/lib/pursuit/term_transform.rb +35 -0
- data/lib/pursuit.rb +18 -4
- data/pursuit.gemspec +4 -3
- data/spec/internal/app/models/application_record.rb +5 -0
- data/spec/internal/app/models/product.rb +25 -9
- data/spec/internal/app/models/product_category.rb +23 -1
- data/spec/internal/app/models/product_variation.rb +26 -1
- data/spec/lib/pursuit/predicate_parser_spec.rb +1604 -0
- data/spec/lib/pursuit/predicate_search_spec.rb +80 -0
- data/spec/lib/pursuit/predicate_transform_spec.rb +624 -0
- data/spec/lib/pursuit/simple_search_spec.rb +59 -0
- data/spec/lib/pursuit/term_parser_spec.rb +271 -0
- data/spec/lib/pursuit/term_search_spec.rb +71 -0
- data/spec/lib/pursuit/term_transform_spec.rb +105 -0
- metadata +47 -25
- data/.travis.yml +0 -26
- data/lib/pursuit/dsl.rb +0 -28
- data/lib/pursuit/railtie.rb +0 -13
- data/lib/pursuit/search.rb +0 -172
- data/lib/pursuit/search_options.rb +0 -86
- data/lib/pursuit/search_term_parser.rb +0 -46
- data/spec/lib/pursuit/dsl_spec.rb +0 -22
- data/spec/lib/pursuit/search_options_spec.rb +0 -146
- data/spec/lib/pursuit/search_spec.rb +0 -516
- data/spec/lib/pursuit/search_term_parser_spec.rb +0 -34
- data/travis/gemfiles/5.2.gemfile +0 -8
- data/travis/gemfiles/6.0.gemfile +0 -8
- data/travis/gemfiles/6.1.gemfile +0 -8
- data/travis/gemfiles/7.0.gemfile +0 -8
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe Pursuit::SimpleSearch do
|
4
|
+
subject(:simple_search) do
|
5
|
+
described_class.new(
|
6
|
+
Product.left_outer_joins(:variations).group(:id)
|
7
|
+
) do
|
8
|
+
search_attribute :title
|
9
|
+
search_attribute ProductVariation.arel_table[:title]
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '#initialize' do
|
14
|
+
it 'is expected to set #relation eq `relation`' do
|
15
|
+
expect(simple_search).to have_attributes(relation: Product.left_outer_joins(:variations).group(:id))
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'is expected to evaluate the passed block' do
|
19
|
+
expect(simple_search.attributes).to be_present
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '#search_attribute' do
|
24
|
+
subject(:search_attribute) do
|
25
|
+
simple_search.search_attribute(ProductVariation.arel_table[:currency])
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'is expected to add the attribute to #attributes' do
|
29
|
+
search_attribute
|
30
|
+
expect(simple_search.attributes).to include(ProductVariation.arel_table[:currency])
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe '#parse' do
|
35
|
+
subject(:parse) { simple_search.parse('Shirt') }
|
36
|
+
|
37
|
+
it 'is expected to equal the ARel node' do
|
38
|
+
expect(parse).to eq(
|
39
|
+
Product.arel_table[:title].matches('%Shirt%').or(
|
40
|
+
ProductVariation.arel_table[:title].matches('%Shirt%')
|
41
|
+
)
|
42
|
+
)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '#apply' do
|
47
|
+
subject(:apply) { simple_search.apply('Shirt') }
|
48
|
+
|
49
|
+
it 'is expected to equal #relation with clauses applied' do
|
50
|
+
expect(apply).to eq(
|
51
|
+
Product.left_outer_joins(:variations).group(:id).where(
|
52
|
+
Product.arel_table[:title].matches('%Shirt%').or(
|
53
|
+
ProductVariation.arel_table[:title].matches('%Shirt%')
|
54
|
+
)
|
55
|
+
)
|
56
|
+
)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,271 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe Pursuit::TermParser do
|
4
|
+
subject(:parser) { described_class.new }
|
5
|
+
|
6
|
+
describe '#space' do
|
7
|
+
subject(:space) { parser.space }
|
8
|
+
|
9
|
+
context 'when parsing an empty value' do
|
10
|
+
subject(:parse) { space.parse('') }
|
11
|
+
|
12
|
+
it { expect { parse }.to raise_exception(Parslet::ParseFailed) }
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'when parsing one or more spaces' do
|
16
|
+
subject(:parse) { space.parse(value) }
|
17
|
+
|
18
|
+
let(:value) { ' ' * rand(1..10) }
|
19
|
+
|
20
|
+
it 'is expected to eq the parsed spaces' do
|
21
|
+
expect(parse).to eq(value)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#space?' do
|
27
|
+
subject(:space?) { parser.space? }
|
28
|
+
|
29
|
+
context 'when parsing an empty value' do
|
30
|
+
subject(:parse) { space?.parse('') }
|
31
|
+
|
32
|
+
it 'is expected to eq the empty value' do
|
33
|
+
expect(parse).to eq('')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'when parsing one or more spaces' do
|
38
|
+
subject(:parse) { space?.parse(value) }
|
39
|
+
|
40
|
+
let(:value) { ' ' * rand(1..10) }
|
41
|
+
|
42
|
+
it 'is expected to eq the parsed spaces' do
|
43
|
+
expect(parse).to eq(value)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe '#escaped_character' do
|
49
|
+
subject(:escaped_character) { parser.escaped_character }
|
50
|
+
|
51
|
+
context 'when parsing an escaped character' do
|
52
|
+
subject(:parse) { escaped_character.parse('\\"') }
|
53
|
+
|
54
|
+
it 'is expected to eq the escaped character' do
|
55
|
+
expect(parse).to eq('\\"')
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'when parsing an unescaped character' do
|
60
|
+
subject(:parse) { escaped_character.parse('"') }
|
61
|
+
|
62
|
+
it { expect { parse }.to raise_exception(Parslet::ParseFailed) }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe '#string_double_quotes' do
|
67
|
+
subject(:string_double_quotes) { parser.string_double_quotes }
|
68
|
+
|
69
|
+
context 'when parsing a double quoted string' do
|
70
|
+
subject(:parse) { string_double_quotes.parse('"Double \"Quoted\""') }
|
71
|
+
|
72
|
+
it 'is expected to capture the contents of the double quotes as :string_double_quotes' do
|
73
|
+
expect(parse).to eq(string_double_quotes: 'Double \"Quoted\"')
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
context 'when parsing a single quoted string' do
|
78
|
+
subject(:parse) { string_double_quotes.parse("'Single Quoted'") }
|
79
|
+
|
80
|
+
it { expect { parse }.to raise_exception(Parslet::ParseFailed) }
|
81
|
+
end
|
82
|
+
|
83
|
+
context 'when parsing an unquoted string' do
|
84
|
+
subject(:parse) { string_double_quotes.parse('Unquoted') }
|
85
|
+
|
86
|
+
it { expect { parse }.to raise_exception(Parslet::ParseFailed) }
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe '#string_single_quotes' do
|
91
|
+
subject(:string_single_quotes) { parser.string_single_quotes }
|
92
|
+
|
93
|
+
context 'when parsing a single quoted string' do
|
94
|
+
subject(:parse) { string_single_quotes.parse("'Single \\'Quoted\\''") }
|
95
|
+
|
96
|
+
it 'is expected to capture the contents of the single quotes as :string_single_quotes' do
|
97
|
+
expect(parse).to eq(string_single_quotes: "Single \\'Quoted\\'")
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
context 'when parsing a double quoted string' do
|
102
|
+
subject(:parse) { string_single_quotes.parse('"Double Quoted"') }
|
103
|
+
|
104
|
+
it { expect { parse }.to raise_exception(Parslet::ParseFailed) }
|
105
|
+
end
|
106
|
+
|
107
|
+
context 'when parsing an unquoted string' do
|
108
|
+
subject(:parse) { string_single_quotes.parse('Unquoted') }
|
109
|
+
|
110
|
+
it { expect { parse }.to raise_exception(Parslet::ParseFailed) }
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
describe '#string_no_quotes' do
|
115
|
+
subject(:string_no_quotes) { parser.string_no_quotes }
|
116
|
+
|
117
|
+
context 'when parsing an unquoted string with no spaces or symbols' do
|
118
|
+
subject(:parse) { string_no_quotes.parse('Unquoted') }
|
119
|
+
|
120
|
+
it 'is expected to eq the parsed value' do
|
121
|
+
expect(parse).to eq(string_no_quotes: 'Unquoted')
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
context 'when parsing an unquoted string with spaces' do
|
126
|
+
subject(:parse) { string_no_quotes.parse('No Quotes') }
|
127
|
+
|
128
|
+
it { expect { parse }.to raise_exception(Parslet::ParseFailed) }
|
129
|
+
end
|
130
|
+
|
131
|
+
context 'when parsing an unquoted string with symbols' do
|
132
|
+
subject(:parse) { string_no_quotes.parse('No:Quotes') }
|
133
|
+
|
134
|
+
it 'is expected to eq the parsed value' do
|
135
|
+
expect(parse).to eq(string_no_quotes: 'No:Quotes')
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
describe '#string' do
|
141
|
+
subject(:string) { parser.string }
|
142
|
+
|
143
|
+
context 'when parsing a double quoted string' do
|
144
|
+
subject(:parse) { string.parse('"Double \"Quoted\""') }
|
145
|
+
|
146
|
+
it 'is expected to capture the contents of the double quotes as :string_double_quotes' do
|
147
|
+
expect(parse).to eq(string_double_quotes: 'Double \"Quoted\"')
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
context 'when parsing a single quoted string' do
|
152
|
+
subject(:parse) { string.parse("'Single \\'Quoted\\''") }
|
153
|
+
|
154
|
+
it 'is expected to capture the contents of the single quotes as :string_single_quotes' do
|
155
|
+
expect(parse).to eq(string_single_quotes: "Single \\'Quoted\\'")
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
context 'when parsing an unquoted string' do
|
160
|
+
subject(:parse) { string.parse('Unquoted') }
|
161
|
+
|
162
|
+
it 'is expected to eq the parsed value' do
|
163
|
+
expect(parse).to eq(string_no_quotes: 'Unquoted')
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
context 'when parsing an unquoted string with spaces' do
|
168
|
+
subject(:parse) { string.parse('No Quotes') }
|
169
|
+
|
170
|
+
it { expect { parse }.to raise_exception(Parslet::ParseFailed) }
|
171
|
+
end
|
172
|
+
|
173
|
+
context 'when parsing an unquoted string with symbols' do
|
174
|
+
subject(:parse) { string.parse('a@b.c') }
|
175
|
+
|
176
|
+
it 'is expected to eq the parsed value' do
|
177
|
+
expect(parse).to eq(string_no_quotes: 'a@b.c')
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
describe '#term' do
|
183
|
+
subject(:term) { parser.term }
|
184
|
+
|
185
|
+
context 'when parsing a string' do
|
186
|
+
subject(:parse) { term.parse('Hello') }
|
187
|
+
|
188
|
+
it 'is expected to capture the value as :term' do
|
189
|
+
expect(parse).to match(hash_including(term: { string_no_quotes: 'Hello' }))
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
describe '#term_pair' do
|
195
|
+
subject(:term_pair) { parser.term_pair }
|
196
|
+
|
197
|
+
context 'when parsing a term' do
|
198
|
+
subject(:parse) { term_pair.parse('Hello') }
|
199
|
+
|
200
|
+
it { expect { parse }.to raise_exception(Parslet::ParseFailed) }
|
201
|
+
end
|
202
|
+
|
203
|
+
context 'when parsing two terms separated by a space' do
|
204
|
+
subject(:parse) { term_pair.parse('Hello World') }
|
205
|
+
|
206
|
+
it 'is expected to capture the first term as :left' do
|
207
|
+
expect(parse).to match(hash_including(left: { term: { string_no_quotes: 'Hello' } }))
|
208
|
+
end
|
209
|
+
|
210
|
+
it 'is expected to capture the second term as :right' do
|
211
|
+
expect(parse).to match(hash_including(right: { term: { string_no_quotes: 'World' } }))
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
describe '#term_node' do
|
217
|
+
subject(:term_node) { parser.term_node }
|
218
|
+
|
219
|
+
context 'when parsing a term' do
|
220
|
+
subject(:parse) { term_node.parse('Hello') }
|
221
|
+
|
222
|
+
it 'is expected to eq the term result' do
|
223
|
+
expect(parse).to match(hash_including(term: { string_no_quotes: 'Hello' }))
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
context 'when parsing multiple terms' do
|
228
|
+
subject(:parse) { term_node.parse('Hello World') }
|
229
|
+
|
230
|
+
it 'is expected to eq the term list result' do
|
231
|
+
expect(parse).to match(
|
232
|
+
hash_including(
|
233
|
+
left: { term: { string_no_quotes: 'Hello' } },
|
234
|
+
right: { term: { string_no_quotes: 'World' } }
|
235
|
+
)
|
236
|
+
)
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
describe '#terms' do
|
242
|
+
subject(:terms) { parser.terms }
|
243
|
+
|
244
|
+
context 'when parsing a complex list of terms' do
|
245
|
+
subject(:parse) { terms.parse(" FirstTerm \"Second Term\" Third<>Term 'Fourth Term' ") }
|
246
|
+
|
247
|
+
it 'is expected to eq the correct term tree' do
|
248
|
+
expect(parse).to match(
|
249
|
+
hash_including(
|
250
|
+
left: { term: { string_no_quotes: 'FirstTerm' } },
|
251
|
+
right: {
|
252
|
+
left: { term: { string_double_quotes: 'Second Term' } },
|
253
|
+
right: {
|
254
|
+
left: { term: { string_no_quotes: 'Third<>Term' } },
|
255
|
+
right: { term: { string_single_quotes: 'Fourth Term' } }
|
256
|
+
}
|
257
|
+
}
|
258
|
+
)
|
259
|
+
)
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
describe '#root' do
|
265
|
+
subject(:root) { parser.root }
|
266
|
+
|
267
|
+
it 'is expected to eq #terms' do
|
268
|
+
expect(root).to eq(parser.terms)
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe Pursuit::TermSearch do
|
4
|
+
subject(:term_search) do
|
5
|
+
described_class.new(
|
6
|
+
Product.left_outer_joins(:variations).group(:id)
|
7
|
+
) do
|
8
|
+
search_attribute :title
|
9
|
+
search_attribute ProductVariation.arel_table[:title]
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '#initialize' do
|
14
|
+
it 'is expected to set #relation eq `relation`' do
|
15
|
+
expect(term_search).to have_attributes(relation: Product.left_outer_joins(:variations).group(:id))
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'is expected to evaluate the passed block' do
|
19
|
+
expect(term_search.attributes).to be_present
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '#parser' do
|
24
|
+
subject(:parser) { term_search.parser }
|
25
|
+
|
26
|
+
it { is_expected.to be_a(Pursuit::TermParser) }
|
27
|
+
end
|
28
|
+
|
29
|
+
describe '#transform' do
|
30
|
+
subject(:transform) { term_search.transform }
|
31
|
+
|
32
|
+
it { is_expected.to be_a(Pursuit::TermTransform) }
|
33
|
+
end
|
34
|
+
|
35
|
+
describe '#search_attribute' do
|
36
|
+
subject(:search_attribute) do
|
37
|
+
term_search.search_attribute(ProductVariation.arel_table[:currency])
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'is expected to add the attribute to #attributes' do
|
41
|
+
search_attribute
|
42
|
+
expect(term_search.attributes).to include(ProductVariation.arel_table[:currency])
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '#parse' do
|
47
|
+
subject(:parse) { term_search.parse('Shirt') }
|
48
|
+
|
49
|
+
it 'is expected to equal the ARel node' do
|
50
|
+
expect(parse).to eq(
|
51
|
+
Product.arel_table[:title].matches('%Shirt%').or(
|
52
|
+
ProductVariation.arel_table[:title].matches('%Shirt%')
|
53
|
+
)
|
54
|
+
)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe '#apply' do
|
59
|
+
subject(:apply) { term_search.apply('Shirt') }
|
60
|
+
|
61
|
+
it 'is expected to equal #relation with term clauses applied' do
|
62
|
+
expect(apply).to eq(
|
63
|
+
Product.left_outer_joins(:variations).group(:id).where(
|
64
|
+
Product.arel_table[:title].matches('%Shirt%').or(
|
65
|
+
ProductVariation.arel_table[:title].matches('%Shirt%')
|
66
|
+
)
|
67
|
+
)
|
68
|
+
)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe Pursuit::TermTransform do
|
4
|
+
subject(:transform) { described_class.new }
|
5
|
+
|
6
|
+
describe '#apply' do
|
7
|
+
subject(:apply) { transform.apply(tree, attributes: attributes) }
|
8
|
+
|
9
|
+
let(:attributes) do
|
10
|
+
[
|
11
|
+
Product.arel_table[:title],
|
12
|
+
ProductVariation.arel_table[:title]
|
13
|
+
].to_set
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'when passed an empty double quoted string' do
|
17
|
+
let(:tree) do
|
18
|
+
{ string_double_quotes: [] }
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'is expected to equal an empty string' do
|
22
|
+
expect(apply).to eq('')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'when passed a double quoted string' do
|
27
|
+
let(:tree) do
|
28
|
+
{ string_double_quotes: 'Hello \\"World\\"' }
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'is expected to equal the correct string' do
|
32
|
+
expect(apply).to eq('Hello "World"')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'when passed an empty single quoted string' do
|
37
|
+
let(:tree) do
|
38
|
+
{ string_single_quotes: [] }
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'is expected to equal an empty string' do
|
42
|
+
expect(apply).to eq('')
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'when passed a single quoted string' do
|
47
|
+
let(:tree) do
|
48
|
+
{ string_single_quotes: "Hello \\'World\\'" }
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'is expected to equal the correct string' do
|
52
|
+
expect(apply).to eq("Hello 'World'")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'when passed an unquoted string' do
|
57
|
+
let(:tree) do
|
58
|
+
{ string_no_quotes: 'hello_world' }
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'is expected to equal the correct string' do
|
62
|
+
expect(apply).to eq('hello_world')
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
context 'when passed a term' do
|
67
|
+
let(:tree) do
|
68
|
+
{ term: { string_no_quotes: 'Shirt' } }
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'is expected to equal the correct ARel node' do
|
72
|
+
expect(apply).to eq(
|
73
|
+
Product.arel_table[:title].matches('%Shirt%').or(
|
74
|
+
ProductVariation.arel_table[:title].matches('%Shirt%')
|
75
|
+
)
|
76
|
+
)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context 'when passed multiple terms' do
|
81
|
+
let(:tree) do
|
82
|
+
{
|
83
|
+
left: {
|
84
|
+
term: { string_no_quotes: 'Shirt' }
|
85
|
+
},
|
86
|
+
right: {
|
87
|
+
term: { string_no_quotes: 'Green' }
|
88
|
+
}
|
89
|
+
}
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'is expected to equal the correct ARel node' do
|
93
|
+
expect(apply).to eq(
|
94
|
+
Product.arel_table[:title].matches('%Shirt%').or(
|
95
|
+
ProductVariation.arel_table[:title].matches('%Shirt%')
|
96
|
+
).and(
|
97
|
+
Product.arel_table[:title].matches('%Green%').or(
|
98
|
+
ProductVariation.arel_table[:title].matches('%Green%')
|
99
|
+
)
|
100
|
+
)
|
101
|
+
)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
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.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nialto Services
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-11-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -17,9 +17,9 @@ dependencies:
|
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: 5.2.0
|
20
|
-
- - "
|
20
|
+
- - "<="
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version:
|
22
|
+
version: 8.0.0
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -27,9 +27,9 @@ dependencies:
|
|
27
27
|
- - ">="
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: 5.2.0
|
30
|
-
- - "
|
30
|
+
- - "<="
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version:
|
32
|
+
version: 8.0.0
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
34
|
name: activesupport
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -37,9 +37,9 @@ dependencies:
|
|
37
37
|
- - ">="
|
38
38
|
- !ruby/object:Gem::Version
|
39
39
|
version: 5.2.0
|
40
|
-
- - "
|
40
|
+
- - "<="
|
41
41
|
- !ruby/object:Gem::Version
|
42
|
-
version:
|
42
|
+
version: 8.0.0
|
43
43
|
type: :runtime
|
44
44
|
prerelease: false
|
45
45
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -47,9 +47,23 @@ dependencies:
|
|
47
47
|
- - ">="
|
48
48
|
- !ruby/object:Gem::Version
|
49
49
|
version: 5.2.0
|
50
|
-
- - "
|
50
|
+
- - "<="
|
51
51
|
- !ruby/object:Gem::Version
|
52
|
-
version:
|
52
|
+
version: 8.0.0
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: parslet
|
55
|
+
requirement: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - "~>"
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '2.0'
|
60
|
+
type: :runtime
|
61
|
+
prerelease: false
|
62
|
+
version_requirements: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - "~>"
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '2.0'
|
53
67
|
description:
|
54
68
|
email:
|
55
69
|
- support@nialtoservices.co.uk
|
@@ -57,12 +71,12 @@ executables: []
|
|
57
71
|
extensions: []
|
58
72
|
extra_rdoc_files: []
|
59
73
|
files:
|
74
|
+
- ".github/workflows/rubygem.yaml"
|
60
75
|
- ".gitignore"
|
61
76
|
- ".rbenv-gemsets"
|
62
77
|
- ".rspec"
|
63
78
|
- ".rubocop.yml"
|
64
79
|
- ".ruby-version"
|
65
|
-
- ".travis.yml"
|
66
80
|
- Gemfile
|
67
81
|
- Gemfile.lock
|
68
82
|
- Guardfile
|
@@ -73,31 +87,39 @@ files:
|
|
73
87
|
- bin/setup
|
74
88
|
- config.ru
|
75
89
|
- lib/pursuit.rb
|
90
|
+
- lib/pursuit/aggregate_modifier_not_found.rb
|
91
|
+
- lib/pursuit/aggregate_modifier_required.rb
|
92
|
+
- lib/pursuit/aggregate_modifiers_not_available.rb
|
93
|
+
- lib/pursuit/attribute_not_found.rb
|
76
94
|
- lib/pursuit/constants.rb
|
77
|
-
- lib/pursuit/
|
78
|
-
- lib/pursuit/
|
79
|
-
- lib/pursuit/
|
80
|
-
- lib/pursuit/
|
81
|
-
- lib/pursuit/
|
95
|
+
- lib/pursuit/error.rb
|
96
|
+
- lib/pursuit/predicate_parser.rb
|
97
|
+
- lib/pursuit/predicate_search.rb
|
98
|
+
- lib/pursuit/predicate_transform.rb
|
99
|
+
- lib/pursuit/query_error.rb
|
100
|
+
- lib/pursuit/simple_search.rb
|
101
|
+
- lib/pursuit/term_parser.rb
|
102
|
+
- lib/pursuit/term_search.rb
|
103
|
+
- lib/pursuit/term_transform.rb
|
82
104
|
- pursuit.gemspec
|
105
|
+
- spec/internal/app/models/application_record.rb
|
83
106
|
- spec/internal/app/models/product.rb
|
84
107
|
- spec/internal/app/models/product_category.rb
|
85
108
|
- spec/internal/app/models/product_variation.rb
|
86
109
|
- spec/internal/config/database.yml
|
87
110
|
- spec/internal/db/schema.rb
|
88
111
|
- spec/internal/log/.keep
|
89
|
-
- spec/lib/pursuit/
|
90
|
-
- spec/lib/pursuit/
|
91
|
-
- spec/lib/pursuit/
|
92
|
-
- spec/lib/pursuit/
|
112
|
+
- spec/lib/pursuit/predicate_parser_spec.rb
|
113
|
+
- spec/lib/pursuit/predicate_search_spec.rb
|
114
|
+
- spec/lib/pursuit/predicate_transform_spec.rb
|
115
|
+
- spec/lib/pursuit/simple_search_spec.rb
|
116
|
+
- spec/lib/pursuit/term_parser_spec.rb
|
117
|
+
- spec/lib/pursuit/term_search_spec.rb
|
118
|
+
- spec/lib/pursuit/term_transform_spec.rb
|
93
119
|
- spec/lib/pursuit_spec.rb
|
94
120
|
- spec/spec_helper.rb
|
95
|
-
- travis/gemfiles/5.2.gemfile
|
96
|
-
- travis/gemfiles/6.0.gemfile
|
97
|
-
- travis/gemfiles/6.1.gemfile
|
98
|
-
- travis/gemfiles/7.0.gemfile
|
99
121
|
- travis/gemfiles/7.1.gemfile
|
100
|
-
homepage: https://github.com/
|
122
|
+
homepage: https://github.com/NialtoServices/pursuit
|
101
123
|
licenses:
|
102
124
|
- Apache-2.0
|
103
125
|
metadata:
|
data/.travis.yml
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
language: ruby
|
2
|
-
rvm:
|
3
|
-
- 3.2.2
|
4
|
-
gemfile:
|
5
|
-
- travis/gemfiles/5.2.gemfile
|
6
|
-
- travis/gemfiles/6.0.gemfile
|
7
|
-
- travis/gemfiles/6.1.gemfile
|
8
|
-
- travis/gemfiles/7.0.gemfile
|
9
|
-
- travis/gemfiles/7.1.gemfile
|
10
|
-
services:
|
11
|
-
- postgresql
|
12
|
-
before_install:
|
13
|
-
- gem update --system
|
14
|
-
- gem install bundler
|
15
|
-
before_script:
|
16
|
-
- psql -c 'CREATE DATABASE pursuit_test;' -U postgres
|
17
|
-
addons:
|
18
|
-
postgresql: 16
|
19
|
-
apt:
|
20
|
-
packages:
|
21
|
-
- postgresql-16
|
22
|
-
- postgresql-client-16
|
23
|
-
env:
|
24
|
-
global:
|
25
|
-
- DATABASE_URL="postgresql://127.0.0.1:5432/pursuit_test"
|
26
|
-
- RSPEC_DEFAULT_FORMATTER=doc
|
data/lib/pursuit/dsl.rb
DELETED
@@ -1,28 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Pursuit
|
4
|
-
module DSL
|
5
|
-
def self.included(base)
|
6
|
-
base.extend ClassMethods
|
7
|
-
end
|
8
|
-
|
9
|
-
module ClassMethods
|
10
|
-
def searchable(&block)
|
11
|
-
if respond_to?(:search_options) || respond_to?(:search)
|
12
|
-
raise "#{self} already has #search and #search_options defined."
|
13
|
-
end
|
14
|
-
|
15
|
-
options = SearchOptions.new(self, &block)
|
16
|
-
|
17
|
-
define_singleton_method(:search_options) do
|
18
|
-
options
|
19
|
-
end
|
20
|
-
|
21
|
-
define_singleton_method(:search) do |query|
|
22
|
-
search = Pursuit::Search.new(options)
|
23
|
-
search.perform(query)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|