searchable-by 0.5.0 → 0.5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '008edf75bb0e4b27410f7e889cbfd26eda27d0391dd7e70be3e984a962ddd756'
4
- data.tar.gz: 9b2fbbc4cc13b2cfe6e23998616ec48e49617bfb67db3143f800c5d35134b2df
3
+ metadata.gz: 8c1c5cfdea465a6a9ff73159a062558c5475889d27e0119e81212bb8bb37bbc1
4
+ data.tar.gz: c77c158c890b37b67d1243c93b4d5c982731b55fb48d284ecc404de58142da26
5
5
  SHA512:
6
- metadata.gz: 0fa58611207ecef62a12c698be927aa34659e0b19f5c5a4ce6c8c2c87b77df49349fb72a4356683f406a80110727442e854448f4b1dc20bc04527e1981af03a2
7
- data.tar.gz: b9dbbde8350310301567ed1ba6cf8a45d80813e7f99415a6e0a6dc6d1a69b4dbd0f340a39851b8db4e291b503f21c2f4f9e8d74311cdaa5fe705a3a06a9201e1
6
+ metadata.gz: 1ba79022ae7056fc1cd6f6ef7af109ed6e0a7228601241ac2bc8f501818b6f487a6fd929f77bc3ce0dba9956b879def3dc705159c3696246d4653e3197f3d71f
7
+ data.tar.gz: c023dff5eb1bb4685dcfe7d10b7164242a090a930189ccc1b336c6de3437ab05d1de0dc90d13f52412e8e15b16a0a1386d5dacb289b208e00eefca5eab0cc2f7
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- searchable-by (0.5.0)
4
+ searchable-by (0.5.1)
5
5
  activerecord
6
6
  activesupport
7
7
 
data/lib/searchable_by.rb CHANGED
@@ -3,24 +3,42 @@ require 'shellwords'
3
3
 
4
4
  module ActiveRecord
5
5
  module SearchableBy
6
- class Config < Hash
6
+ class Column
7
+ attr_reader :attr, :type
8
+ attr_accessor :node
9
+
10
+ def initialize(attr, type: :string)
11
+ @attr = attr
12
+ @type = type.to_sym
13
+ end
14
+ end
15
+
16
+ class Config
17
+ attr_reader :columns, :scoping
18
+ attr_accessor :max_terms
19
+
7
20
  def initialize
8
- update columns: [], max_terms: 5
21
+ @columns = []
22
+ @max_terms = 5
9
23
  scope { all }
10
24
  end
11
25
 
26
+ def initialize_copy(other)
27
+ @columns = other.columns.dup
28
+ super
29
+ end
30
+
12
31
  def column(*attrs, &block)
13
32
  opts = attrs.extract_options!
14
- cols = self[:columns]
15
33
  attrs.each do |attr|
16
- cols.push(opts.merge(column: attr))
34
+ columns.push Column.new(attr, opts)
17
35
  end
18
- cols.push(opts.merge(column: block)) if block
19
- cols
36
+ columns.push Column.new(block, opts) if block
37
+ columns
20
38
  end
21
39
 
22
40
  def scope(&block)
23
- self[:scope] = block
41
+ @scoping = block
24
42
  end
25
43
  end
26
44
 
@@ -32,27 +50,30 @@ module ActiveRecord
32
50
  values
33
51
  end
34
52
 
35
- def self.build_clauses(relations, values)
53
+ def self.build_clauses(columns, values)
36
54
  clauses = values.map do |value|
37
55
  negate = value[0] == '-'
38
56
  value.slice!(0) if negate || value[0] == '+'
39
57
 
40
- c0, *cn = relations.map do |opts|
41
- build_condition(opts, value)
42
- end.compact
43
- next unless c0
58
+ grouping = columns.map do |column|
59
+ build_condition(column, value)
60
+ end
61
+ grouping.compact!
62
+ next if grouping.empty?
44
63
 
45
- [cn.inject(c0) {|x, part| x.or(part) }, negate]
64
+ clause = grouping.inject(&:or)
65
+ clause = clause.not if negate
66
+ clause
46
67
  end
47
68
  clauses.compact!
48
69
  clauses
49
70
  end
50
71
 
51
- def self.build_condition(opts, value)
52
- case opts[:type]
72
+ def self.build_condition(column, value)
73
+ case column.type
53
74
  when :int, :integer
54
75
  begin
55
- opts[:rel].eq(Integer(value))
76
+ column.node.eq(Integer(value))
56
77
  rescue ArgumentError
57
78
  nil
58
79
  end
@@ -60,7 +81,7 @@ module ActiveRecord
60
81
  value = value.dup
61
82
  value.gsub!('%', '\%')
62
83
  value.gsub!('_', '\_')
63
- opts[:rel].matches("%#{value}%")
84
+ column.node.matches("%#{value}%")
64
85
  end
65
86
  end
66
87
 
@@ -72,35 +93,35 @@ module ActiveRecord
72
93
  end
73
94
 
74
95
  def inherited(base) # :nodoc:
75
- base._searchable_by_config = _searchable_by_config.deep_dup
96
+ base._searchable_by_config = _searchable_by_config.dup
76
97
  super
77
98
  end
78
99
 
79
100
  def searchable_by(max_terms: 5, &block)
80
101
  _searchable_by_config.instance_eval(&block)
81
- _searchable_by_config[:max_terms] = max_terms if max_terms
102
+ _searchable_by_config.max_terms = max_terms if max_terms
82
103
  end
83
104
 
84
105
  # @param [String] query the search query
85
106
  # @return [ActiveRecord::Relation] the scoped relation
86
107
  def search_by(query)
87
- columns = _searchable_by_config[:columns]
108
+ columns = _searchable_by_config.columns
88
109
  return all if columns.empty?
89
110
 
90
- values = SearchableBy.norm_values(query).first(_searchable_by_config[:max_terms])
111
+ values = SearchableBy.norm_values(query).first(_searchable_by_config.max_terms)
91
112
  return all if values.empty?
92
113
 
93
- relations = columns.map do |opts|
94
- rel = opts[:column].is_a?(Proc) ? opts[:column].call : arel_table[opts[:column]]
95
- opts.merge(rel: rel)
114
+ columns.each do |col|
115
+ col.node ||= col.attr.is_a?(Proc) ? col.attr.call : arel_table[col.attr]
96
116
  end
97
- clauses = SearchableBy.build_clauses(relations, values)
117
+ clauses = SearchableBy.build_clauses(columns, values)
98
118
  return all if clauses.empty?
99
119
 
100
- scope = instance_exec(&_searchable_by_config[:scope])
101
- clauses.inject(scope) do |x, (clause, negate)|
102
- negate ? x.where.not(clause) : x.where(clause)
120
+ scope = instance_exec(&_searchable_by_config.scoping)
121
+ clauses.each do |clause|
122
+ scope = scope.where(clause)
103
123
  end
124
+ scope
104
125
  end
105
126
  end
106
127
  end
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'searchable-by'
3
- s.version = '0.5.0'
3
+ s.version = '0.5.1'
4
4
  s.authors = ['Dimitrij Denissenko']
5
5
  s.email = ['dimitrij@blacksquaremedia.com']
6
6
  s.summary = 'Generate search scopes'
@@ -1,11 +1,17 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe ActiveRecord::SearchableBy do
4
+
4
5
  it 'should ignore bad inputs' do
5
6
  expect(Post.search_by(nil).count).to eq(4)
6
7
  expect(Post.search_by('').count).to eq(4)
7
8
  end
8
9
 
10
+ it 'should configure correctly' do
11
+ expect(AbstractModel._searchable_by_config.columns.size).to eq(1)
12
+ expect(Post._searchable_by_config.columns.size).to eq(4)
13
+ end
14
+
9
15
  it 'should generate SQL' do
10
16
  sql = Post.search_by('123').to_sql
11
17
  expect(sql).to include(%("posts"."id" = 123))
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: searchable-by
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dimitrij Denissenko