scoped_search 4.1.4 → 4.1.5

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
  SHA1:
3
- metadata.gz: cf2c98d3eed66905e04497673572661d98ca832a
4
- data.tar.gz: 5cda23768c0ffef857dc038d74abd2539bf8881c
3
+ metadata.gz: 25198636d3a83a3be37b174722b43786bfb66c40
4
+ data.tar.gz: 2d51410c045dd98edffd782900a960f5111c47f4
5
5
  SHA512:
6
- metadata.gz: 96425ef732825dfb333d977f55a55be95ef3ac9dfda0ba9c4353fc97227d5caebfc4977b8cbdb786eb5929db84885f74435b7ca8795e449dcd2f7b432b0abbf5
7
- data.tar.gz: '068d65cd7fe9e1d4e58b0080d92a22a9216ed879e17275aec5bce2651ce6cced96251803f062113c6ab66135a3ae90e478cf7b90bd2ea7b0437f5f83a96516ce'
6
+ metadata.gz: 467be1c841cb5a0ce8eff10af66df07db0527a8b7423f386ad8a5ea29bea2ab4e3d02edb0b480ff427bfbdc0078ca1ac138690866db4fb67f13c31322334320b
7
+ data.tar.gz: fbc5a32d17479d8e919ca7b9e198416a0acb60bcbf0e1b2b3b7b850ad97af135a7cb5d57b0f93d3fee7a1b27c8ee7b47871367506ebe100e8beb58179041c01d
@@ -6,7 +6,11 @@ Please add an entry to the "Unreleased changes" section in your pull requests.
6
6
 
7
7
  === Unreleased changes
8
8
 
9
- *Nothing yet*
9
+ - Nothing yet
10
+
11
+ === Version 4.1.5
12
+
13
+ - Bugfix related to auto-completion of virtual fields (#182)
10
14
 
11
15
  === Version 4.1.4
12
16
 
@@ -270,7 +270,7 @@ module ScopedSearch
270
270
 
271
271
  # This method complete infix operators by field type
272
272
  def complete_operator(node)
273
- definition.operator_by_field_name(node.value)
273
+ definition.operator_by_field_name(node.value).map { |o| o.end_with?(' ') ? o : "#{o} " }
274
274
  end
275
275
  end
276
276
  end
@@ -107,6 +107,11 @@ module ScopedSearch
107
107
  end
108
108
  end
109
109
 
110
+ # Returns true if this is a virtual field.
111
+ def virtual?
112
+ !ext_method.nil?
113
+ end
114
+
110
115
  # Returns the ActiveRecord column definition that corresponds to this field.
111
116
  def column
112
117
  @column ||= begin
@@ -120,15 +125,15 @@ module ScopedSearch
120
125
 
121
126
  # Returns the column type of this field.
122
127
  def type
123
- @type ||= column.type
128
+ @type ||= virtual? ? :virtual : column.type
124
129
  end
125
130
 
126
- # Returns true if this field is a datetime-like column
131
+ # Returns true if this field is a datetime-like column.
127
132
  def datetime?
128
133
  [:datetime, :time, :timestamp].include?(type)
129
134
  end
130
135
 
131
- # Returns true if this field is a date-like column
136
+ # Returns true if this field is a date-like column.
132
137
  def date?
133
138
  type == :date
134
139
  end
@@ -167,7 +172,7 @@ module ScopedSearch
167
172
  return "#{field} #{order}"
168
173
  end
169
174
 
170
- # Return 'table'.'column' with the correct database quotes
175
+ # Return 'table'.'column' with the correct database quotes.
171
176
  def quoted_field
172
177
  c = klass.connection
173
178
  "#{c.quote_table_name(klass.table_name)}.#{c.quote_column_name(field)}"
@@ -231,11 +236,12 @@ module ScopedSearch
231
236
  def operator_by_field_name(name)
232
237
  field = field_by_name(name)
233
238
  return [] if field.nil?
234
- return field.operators if field.operators
235
- return ['= ', '!= '] if field.set?
236
- return ['= ', '> ', '< ', '<= ', '>= ','!= ', '^ ', '!^ '] if field.numerical?
237
- return ['= ', '!= ', '~ ', '!~ ', '^ ', '!^ '] if field.textual?
238
- return ['= ', '> ', '< '] if field.temporal?
239
+ return field.operators if field.operators
240
+ return ['=', '!=', '>', '<', '<=', '>=', '~', '!~', '^', '!^'] if field.virtual?
241
+ return ['=', '!='] if field.set?
242
+ return ['=', '>', '<', '<=', '>=', '!=', '^', '!^'] if field.numerical?
243
+ return ['=', '!=', '~', '!~', '^', '!^'] if field.textual?
244
+ return ['=', '>', '<'] if field.temporal?
239
245
  raise ScopedSearch::QueryNotSupported, "Unsupported type '#{field.type.inspect}')' for field '#{name}'. This can be a result of a search definition problem."
240
246
  end
241
247
 
@@ -245,7 +251,7 @@ module ScopedSearch
245
251
  # Returns a list of appropriate fields to search in given a search keyword and operator.
246
252
  def default_fields_for(value, operator = nil)
247
253
 
248
- column_types = []
254
+ column_types = [:virtual]
249
255
  column_types += [:string, :text] if [nil, :like, :unlike, :ne, :eq].include?(operator)
250
256
  column_types += [:double, :float, :decimal] if value =~ NUMERICAL_REGXP
251
257
  column_types += [:integer] if value =~ INTEGER_REGXP
@@ -113,7 +113,7 @@ module ScopedSearch
113
113
  # By default, it will simply look up the correct SQL operator in the SQL_OPERATORS
114
114
  # hash, but this can be overridden by a database adapter.
115
115
  def sql_operator(operator, field)
116
- raise ScopedSearch::QueryNotSupported, "the operator '#{operator}' is not supported for field type '#{field.type}'" if !field.ext_method and [:like, :unlike].include?(operator) and !field.textual?
116
+ raise ScopedSearch::QueryNotSupported, "the operator '#{operator}' is not supported for field type '#{field.type}'" if !field.virtual? and [:like, :unlike].include?(operator) and !field.textual?
117
117
  SQL_OPERATORS[operator]
118
118
  end
119
119
 
@@ -210,7 +210,7 @@ module ScopedSearch
210
210
  # <tt>operator</tt>:: The operator used for comparison.
211
211
  # <tt>value</tt>:: The value to compare the field with.
212
212
  def sql_test(field, operator, value, lhs, &block) # :yields: finder_option_type, value
213
- return field.to_ext_method_sql(lhs, sql_operator(operator, field), value, &block) if field.ext_method
213
+ return field.to_ext_method_sql(lhs, sql_operator(operator, field), value, &block) if field.virtual?
214
214
 
215
215
  yield(:keyparameter, lhs.sub(/^.*\./,'')) if field.key_field
216
216
 
@@ -403,7 +403,7 @@ module ScopedSearch
403
403
  def to_ext_method_sql(key, operator, value, &block)
404
404
  raise ScopedSearch::QueryNotSupported, "'#{definition.klass}' doesn't respond to '#{ext_method}'" unless definition.klass.respond_to?(ext_method)
405
405
  begin
406
- conditions = definition.klass.send(ext_method.to_sym, key, operator, value)
406
+ conditions = definition.klass.send(ext_method.to_sym, key, operator, value)
407
407
  rescue StandardError => e
408
408
  raise ScopedSearch::QueryNotSupported, "external method '#{ext_method}' failed with error: #{e}"
409
409
  end
@@ -554,7 +554,7 @@ module ScopedSearch
554
554
  # Switches out the default LIKE operator in the default <tt>sql_operator</tt>
555
555
  # method for ILIKE or @@ if full text searching is enabled.
556
556
  def sql_operator(operator, field)
557
- raise ScopedSearch::QueryNotSupported, "the operator '#{operator}' is not supported for field type '#{field.type}'" if !field.ext_method and [:like, :unlike].include?(operator) and !field.textual?
557
+ raise ScopedSearch::QueryNotSupported, "the operator '#{operator}' is not supported for field type '#{field.type}'" if !field.virtual? and [:like, :unlike].include?(operator) and !field.textual?
558
558
  return '@@' if [:like, :unlike].include?(operator) && field.full_text_search
559
559
  case operator
560
560
  when :like then 'ILIKE'
@@ -1,3 +1,3 @@
1
1
  module ScopedSearch
2
- VERSION = "4.1.4"
2
+ VERSION = "4.1.5"
3
3
  end
@@ -2,9 +2,11 @@ require "spec_helper"
2
2
 
3
3
  describe ScopedSearch::AutoCompleteBuilder do
4
4
 
5
+ let(:klass) { Class.new(ActiveRecord::Base) }
6
+
5
7
  before(:each) do
6
8
  @definition = double('ScopedSearch::Definition')
7
- @definition.stub(:klass).and_return(Class.new(ActiveRecord::Base))
9
+ @definition.stub(:klass).and_return(klass)
8
10
  @definition.stub(:profile).and_return(:default)
9
11
  @definition.stub(:profile=).and_return(true)
10
12
  end
@@ -17,4 +19,18 @@ describe ScopedSearch::AutoCompleteBuilder do
17
19
  ScopedSearch::AutoCompleteBuilder.auto_complete(@definition, "").should == []
18
20
  end
19
21
 
22
+ context "with ext_method" do
23
+ before do
24
+ @definition = ScopedSearch::Definition.new(klass)
25
+ @definition.define(:test_field, ext_method: :ext_test)
26
+ @definition.klass.stub(:connection).and_return(double())
27
+ @definition.klass.stub(:columns_hash).and_return({})
28
+ end
29
+
30
+ it "should support operator auto-completion on a virtual field" do
31
+ klass.should_receive(:ext_test).with('', '=', 'test_field').and_return(conditions: '')
32
+ ScopedSearch::AutoCompleteBuilder.auto_complete(@definition, 'test_field ').should eq(["test_field = ", "test_field != ", "test_field > ", "test_field < ", "test_field <= ", "test_field >= ", "test_field ~ ", "test_field !~ ", "test_field ^ ", "test_field !^ "])
33
+ end
34
+ end
35
+
20
36
  end
@@ -38,6 +38,7 @@ describe ScopedSearch::QueryBuilder do
38
38
 
39
39
  it "should validate value if validator selected" do
40
40
  field = double('field')
41
+ field.stub(:virtual?).and_return(false)
41
42
  field.stub(:only_explicit).and_return(true)
42
43
  field.stub(:field).and_return(:test_field)
43
44
  field.stub(:validator).and_return(->(_value) { false })
@@ -49,6 +50,7 @@ describe ScopedSearch::QueryBuilder do
49
50
 
50
51
  it "should validate value if validator selected" do
51
52
  field = double('field')
53
+ field.stub(:virtual?).and_return(false)
52
54
  field.stub(:only_explicit).and_return(true)
53
55
  field.stub(:field).and_return(:test_field)
54
56
  field.stub(:ext_method).and_return(nil)
@@ -65,6 +67,7 @@ describe ScopedSearch::QueryBuilder do
65
67
 
66
68
  it "should display custom error from validator" do
67
69
  field = double('field')
70
+ field.stub(:virtual?).and_return(false)
68
71
  field.stub(:only_explicit).and_return(true)
69
72
  field.stub(:field).and_return(:test_field)
70
73
  field.stub(:validator).and_return(->(_value) { raise ScopedSearch::QueryNotSupported, 'my custom message' })
@@ -90,7 +93,7 @@ describe ScopedSearch::QueryBuilder do
90
93
  ScopedSearch::QueryBuilder.build_query(@definition, 'test_field = test_val').should eq(include: ['test1'], joins: ['test2'])
91
94
  end
92
95
 
93
- it "should support LIKE query even if database field doesn't exist" do
96
+ it "should support LIKE query on a virtual field" do
94
97
  klass.should_receive(:ext_test).with('test_field', 'LIKE', 'test_val').and_return(conditions: 'field LIKE ?', parameter: ['%test_val%'])
95
98
  ScopedSearch::QueryBuilder.build_query(@definition, 'test_field ~ test_val').should eq(conditions: ['(field LIKE ?)', '%test_val%'])
96
99
  end
@@ -100,7 +103,7 @@ describe ScopedSearch::QueryBuilder do
100
103
  lambda { ScopedSearch::QueryBuilder.build_query(@definition, 'test_field = test_val') }.should raise_error(ScopedSearch::QueryNotSupported, /should return hash/)
101
104
  end
102
105
 
103
- it "should raise error when method doesn't exist" do
106
+ it "should raise error when ext_method doesn't exist" do
104
107
  lambda { ScopedSearch::QueryBuilder.build_query(@definition, 'test_field = test_val') }.should raise_error(ScopedSearch::QueryNotSupported, /doesn't respond to 'ext_test'/)
105
108
  end
106
109
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: scoped_search
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.4
4
+ version: 4.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Amos Benari
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2018-09-06 00:00:00.000000000 Z
13
+ date: 2018-09-19 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activerecord
@@ -157,7 +157,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
157
157
  version: '0'
158
158
  requirements: []
159
159
  rubyforge_project:
160
- rubygems_version: 2.6.8
160
+ rubygems_version: 2.6.11
161
161
  signing_key:
162
162
  specification_version: 4
163
163
  summary: Easily search you ActiveRecord models with a simple query language using