elasticsearch_autocomplete 0.1.4 → 0.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 +4 -4
- data/.gitignore +2 -0
- data/.travis.yml +2 -5
- data/README.md +6 -5
- data/lib/elasticsearch_autocomplete.rb +25 -11
- data/lib/elasticsearch_autocomplete/analyzers.rb +34 -34
- data/lib/elasticsearch_autocomplete/model_addition.rb +29 -26
- data/lib/elasticsearch_autocomplete/version.rb +1 -1
- data/spec/elasticsearch_autocomplete/base_spec.rb +39 -21
- data/spec/elasticsearch_autocomplete/full_mode_spec.rb +8 -8
- data/spec/elasticsearch_autocomplete/localized_spec.rb +6 -6
- data/spec/elasticsearch_autocomplete/phrase_mode_spec.rb +4 -4
- data/spec/elasticsearch_autocomplete/search_filters_spec.rb +14 -14
- data/spec/elasticsearch_autocomplete/word_mode_spec.rb +5 -5
- data/spec/spec_helper.rb +1 -1
- metadata +17 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 033b837130dd4581eb9dbefe8b6424a5012f179c
|
4
|
+
data.tar.gz: 517d306c4a96ba7da1693bf6591a662133028a06
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 141d423cb8d784bf259f4b4ef7026fce9804116bf7552525f9856638bb8cb44a8f78f870539322be926b55c1f6758d946ac0560c3783c822918faa167a9871cc
|
7
|
+
data.tar.gz: be4c0e832e7a27c0f41243902c37d8531a3c42361af68e4eb50e732512cc51693086a0691ab9cadfa5442e84c86784bfb7bb3b3f33c25c424c035e9f1aa0e640
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
# ElasticsearchAutocomplete
|
2
2
|
|
3
|
-
Simple autocomplete for rails models using awesome [Elasticsearch](http://www.elasticsearch.org/) and [tire](https://github.com/karmi/tire) gem
|
4
|
-
|
5
3
|
[](https://travis-ci.org/leschenko/elasticsearch_autocomplete)
|
4
|
+
[](https://gemnasium.com/leschenko/elasticsearch_autocomplete)
|
5
|
+
|
6
|
+
Simple autocomplete for rails models using awesome [Elasticsearch](http://www.elasticsearch.org/).
|
6
7
|
|
7
8
|
## Example app
|
8
9
|
|
@@ -51,7 +52,7 @@ You can specify fields for suggestions search:
|
|
51
52
|
|
52
53
|
```ruby
|
53
54
|
class User < ActiveRecord::Base
|
54
|
-
ac_field :full_name, :
|
55
|
+
ac_field :full_name, search_fields: [:full_name, :email]
|
55
56
|
end
|
56
57
|
```
|
57
58
|
|
@@ -59,7 +60,7 @@ For search on localized fields such as `name_en`, `name_ru`:
|
|
59
60
|
|
60
61
|
```ruby
|
61
62
|
class Product < ActiveRecord::Base
|
62
|
-
ac_field :name, :
|
63
|
+
ac_field :name, localized: true
|
63
64
|
end
|
64
65
|
```
|
65
66
|
|
@@ -67,7 +68,7 @@ If you want to define settings and mapping for elasticsearch index yourselves:
|
|
67
68
|
|
68
69
|
```ruby
|
69
70
|
class Product < ActiveRecord::Base
|
70
|
-
ac_field :name, :
|
71
|
+
ac_field :name, skip_settings: true
|
71
72
|
end
|
72
73
|
```
|
73
74
|
|
@@ -6,25 +6,39 @@ require 'elasticsearch_autocomplete/railtie' if Object.const_defined?(:Rails)
|
|
6
6
|
|
7
7
|
module ElasticsearchAutocomplete
|
8
8
|
mattr_accessor :defaults
|
9
|
+
mattr_accessor :enable_indexing
|
10
|
+
self.enable_indexing = true
|
9
11
|
|
10
12
|
def self.default_index_prefix
|
11
13
|
Object.const_defined?(:Rails) ? ::Rails.application.class.name.split('::').first.downcase : nil
|
12
14
|
end
|
13
15
|
|
14
|
-
self.defaults = {:
|
16
|
+
self.defaults = {attr: :name, localized: false, mode: :word, index_prefix: default_index_prefix}
|
15
17
|
|
16
18
|
MODES = {
|
17
|
-
:
|
18
|
-
:
|
19
|
-
:
|
19
|
+
word: {base: 'ac', word: 'ac_word'},
|
20
|
+
phrase: {base: 'ac'},
|
21
|
+
full: {base: 'ac', full: 'ac_full'}
|
20
22
|
}
|
21
23
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
24
|
+
class << self
|
25
|
+
def val_to_terms(val, zero=false)
|
26
|
+
return [] unless val
|
27
|
+
return val if val.is_a?(Array)
|
28
|
+
return [true] if val == 'true'
|
29
|
+
return [false] if val == 'false'
|
30
|
+
a = val.to_s.split(',').map(&:to_i)
|
31
|
+
zero ? a : a.reject(&:zero?)
|
32
|
+
end
|
33
|
+
|
34
|
+
def without_indexing
|
35
|
+
original_setting = enable_indexing
|
36
|
+
self.enable_indexing = false
|
37
|
+
begin
|
38
|
+
yield
|
39
|
+
ensure
|
40
|
+
self.enable_indexing = original_setting
|
41
|
+
end
|
42
|
+
end
|
29
43
|
end
|
30
44
|
end
|
@@ -2,56 +2,56 @@ module ElasticsearchAutocomplete
|
|
2
2
|
module Analyzers
|
3
3
|
|
4
4
|
AC_TOKENIZERS = {
|
5
|
-
:
|
6
|
-
:
|
7
|
-
:
|
8
|
-
:
|
9
|
-
:
|
5
|
+
ac_edge_ngram: {
|
6
|
+
type: 'edgeNGram',
|
7
|
+
min_gram: 1,
|
8
|
+
max_gram: 50,
|
9
|
+
side: 'front'
|
10
10
|
},
|
11
|
-
:
|
12
|
-
:
|
13
|
-
:
|
14
|
-
:
|
11
|
+
ac_edge_ngram_full: {
|
12
|
+
type: 'nGram',
|
13
|
+
min_gram: 1,
|
14
|
+
max_gram: 50
|
15
15
|
}
|
16
16
|
}
|
17
17
|
|
18
18
|
AC_FILTERS = {
|
19
|
-
:
|
20
|
-
:
|
21
|
-
:
|
22
|
-
:
|
23
|
-
:
|
19
|
+
ac_edge_ngram: {
|
20
|
+
type: 'edgeNGram',
|
21
|
+
min_gram: 1,
|
22
|
+
max_gram: 50,
|
23
|
+
side: 'front'
|
24
24
|
}
|
25
25
|
}
|
26
26
|
|
27
27
|
AC_ANALYZERS = {
|
28
|
-
:
|
29
|
-
:
|
30
|
-
:
|
31
|
-
:
|
28
|
+
ac_edge_ngram: {
|
29
|
+
type: 'custom',
|
30
|
+
tokenizer: 'ac_edge_ngram',
|
31
|
+
filter: %w(lowercase asciifolding)
|
32
32
|
},
|
33
|
-
:
|
34
|
-
:
|
35
|
-
:
|
36
|
-
:
|
33
|
+
ac_edge_ngram_full: {
|
34
|
+
type: 'custom',
|
35
|
+
tokenizer: 'ac_edge_ngram_full',
|
36
|
+
filter: %w(lowercase asciifolding)
|
37
37
|
},
|
38
|
-
:
|
39
|
-
:
|
40
|
-
:
|
41
|
-
:
|
38
|
+
ac_edge_ngram_word: {
|
39
|
+
type: 'custom',
|
40
|
+
tokenizer: 'standard',
|
41
|
+
filter: %w(lowercase asciifolding ac_edge_ngram)
|
42
42
|
},
|
43
|
-
:
|
44
|
-
:
|
45
|
-
:
|
46
|
-
:
|
43
|
+
ac_search: {
|
44
|
+
type: 'custom',
|
45
|
+
tokenizer: 'keyword',
|
46
|
+
filter: %w(lowercase asciifolding)
|
47
47
|
}
|
48
48
|
}
|
49
49
|
|
50
50
|
AC_BASE = {
|
51
|
-
:
|
52
|
-
:
|
53
|
-
:
|
54
|
-
:
|
51
|
+
analysis: {
|
52
|
+
analyzer: AC_ANALYZERS,
|
53
|
+
tokenizer: AC_TOKENIZERS,
|
54
|
+
filter: AC_FILTERS
|
55
55
|
}
|
56
56
|
}
|
57
57
|
|
@@ -5,24 +5,23 @@ module ElasticsearchAutocomplete
|
|
5
5
|
end
|
6
6
|
|
7
7
|
module SingletonMethods
|
8
|
-
def
|
8
|
+
def ac_setup_tire
|
9
|
+
include InstanceMethods
|
9
10
|
include Tire::Model::Search
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
|
12
|
+
after_save :ac_update_index
|
13
|
+
after_destroy :ac_update_index
|
14
|
+
|
14
15
|
index_prefix ElasticsearchAutocomplete.defaults[:index_prefix] if ElasticsearchAutocomplete.defaults[:index_prefix]
|
15
16
|
end
|
16
17
|
|
17
|
-
def ac_field(*args
|
18
|
-
options = args.extract_options!
|
19
|
-
|
20
|
-
include InstanceMethods
|
18
|
+
def ac_field(*args)
|
21
19
|
extend ClassMethods
|
22
20
|
|
23
|
-
|
21
|
+
ac_setup_tire
|
24
22
|
|
25
|
-
class_attribute :ac_opts, :ac_attr, :ac_search_attrs, :ac_search_fields, :ac_mode_config, :
|
23
|
+
class_attribute :ac_opts, :ac_attr, :ac_search_attrs, :ac_search_fields, :ac_mode_config, instance_writer: false
|
24
|
+
options = args.extract_options!
|
26
25
|
self.ac_opts = options.reverse_merge(ElasticsearchAutocomplete.defaults)
|
27
26
|
self.ac_attr = args.first || ElasticsearchAutocomplete.defaults[:attr]
|
28
27
|
|
@@ -31,16 +30,15 @@ module ElasticsearchAutocomplete
|
|
31
30
|
self.ac_search_attrs = ac_opts[:search_fields] || (ac_opts[:localized] ? I18n.available_locales.map { |l| "#{ac_attr}_#{l}" } : [ac_attr])
|
32
31
|
self.ac_search_fields = ac_search_attrs.map { |attr| ac_mode_config.values.map { |prefix| "#{prefix}_#{attr}" } }.flatten
|
33
32
|
|
34
|
-
|
35
33
|
define_ac_index(ac_opts[:mode]) unless options[:skip_settings]
|
36
34
|
end
|
37
35
|
end
|
38
36
|
|
39
37
|
module ClassMethods
|
40
38
|
def ac_search(query, options={})
|
41
|
-
options.reverse_merge!({:
|
39
|
+
options.reverse_merge!({per_page: 50, search_fields: ac_search_fields, load: false})
|
42
40
|
|
43
|
-
tire.search :
|
41
|
+
tire.search per_page: options[:per_page], page: options[:page], load: options[:load] do
|
44
42
|
query do
|
45
43
|
if query.size.zero?
|
46
44
|
all
|
@@ -58,10 +56,10 @@ module ElasticsearchAutocomplete
|
|
58
56
|
by(options[:order], options[:sort_mode] || 'asc') if options[:order].present?
|
59
57
|
end
|
60
58
|
|
61
|
-
filter(:and, :
|
59
|
+
filter(:and, filters: options[:with].map { |k, v| {terms: {k => ElasticsearchAutocomplete.val_to_terms(v)}} }) if options[:with].present?
|
62
60
|
if options[:without].present?
|
63
61
|
options[:without].each do |k, v|
|
64
|
-
filter(:not, {:
|
62
|
+
filter(:not, {terms: {k => ElasticsearchAutocomplete.val_to_terms(v, true)}})
|
65
63
|
end
|
66
64
|
end
|
67
65
|
end
|
@@ -79,27 +77,27 @@ module ElasticsearchAutocomplete
|
|
79
77
|
end
|
80
78
|
|
81
79
|
def ac_index_config(attr, mode=:word)
|
82
|
-
defaults = {:
|
80
|
+
defaults = {type: 'string', search_analyzer: 'ac_search', include_in_all: false}
|
83
81
|
fields = case mode
|
84
82
|
when :word
|
85
83
|
{
|
86
|
-
attr => {:
|
87
|
-
"#{ac_mode_config[:base]}_#{attr}" => defaults.merge(:
|
88
|
-
"#{ac_mode_config[:word]}_#{attr}" => defaults.merge(:
|
84
|
+
attr => {type: 'string'},
|
85
|
+
"#{ac_mode_config[:base]}_#{attr}" => defaults.merge(index_analyzer: 'ac_edge_ngram'),
|
86
|
+
"#{ac_mode_config[:word]}_#{attr}" => defaults.merge(index_analyzer: 'ac_edge_ngram_word')
|
89
87
|
}
|
90
88
|
when :phrase
|
91
89
|
{
|
92
|
-
attr => {:
|
93
|
-
"#{ac_mode_config[:base]}_#{attr}" => defaults.merge(:
|
90
|
+
attr => {type: 'string'},
|
91
|
+
"#{ac_mode_config[:base]}_#{attr}" => defaults.merge(index_analyzer: 'ac_edge_ngram')
|
94
92
|
}
|
95
93
|
when :full
|
96
94
|
{
|
97
|
-
attr => {:
|
98
|
-
"#{ac_mode_config[:base]}_#{attr}" => defaults.merge(:
|
99
|
-
"#{ac_mode_config[:full]}_#{attr}" => defaults.merge(:
|
95
|
+
attr => {type: 'string'},
|
96
|
+
"#{ac_mode_config[:base]}_#{attr}" => defaults.merge(index_analyzer: 'ac_edge_ngram', boost: 3),
|
97
|
+
"#{ac_mode_config[:full]}_#{attr}" => defaults.merge(index_analyzer: 'ac_edge_ngram_full')
|
100
98
|
}
|
101
99
|
end
|
102
|
-
{:
|
100
|
+
{type: 'multi_field', fields: fields}
|
103
101
|
end
|
104
102
|
end
|
105
103
|
|
@@ -112,6 +110,11 @@ module ElasticsearchAutocomplete
|
|
112
110
|
end
|
113
111
|
MultiJson.encode(for_json)
|
114
112
|
end
|
113
|
+
|
114
|
+
def ac_update_index
|
115
|
+
return true unless ElasticsearchAutocomplete.enable_indexing
|
116
|
+
tire.update_index
|
117
|
+
end
|
115
118
|
end
|
116
119
|
end
|
117
120
|
end
|
@@ -9,7 +9,7 @@ class ActiveModelUser < StubModelBase
|
|
9
9
|
|
10
10
|
def self.populate
|
11
11
|
test_data.each_with_index do |name, id|
|
12
|
-
u = new(:
|
12
|
+
u = new(full_name: name)
|
13
13
|
u.id = id
|
14
14
|
u.save
|
15
15
|
end
|
@@ -19,7 +19,7 @@ class ActiveModelUser < StubModelBase
|
|
19
19
|
def self.find(ids)
|
20
20
|
ids.map do |id|
|
21
21
|
id = id.to_i
|
22
|
-
u = new(:
|
22
|
+
u = new(full_name: test_data[id])
|
23
23
|
u.id = id
|
24
24
|
u
|
25
25
|
end
|
@@ -33,11 +33,15 @@ describe ElasticsearchAutocomplete do
|
|
33
33
|
end
|
34
34
|
|
35
35
|
it 'add ac_search method' do
|
36
|
-
|
36
|
+
expect(subject).to respond_to(:ac_search)
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'indexing enabled by default' do
|
40
|
+
expect(ElasticsearchAutocomplete.enable_indexing).to be_truthy
|
37
41
|
end
|
38
42
|
|
39
43
|
it 'define to_indexed_json method' do
|
40
|
-
ActiveModelUser.new(:
|
44
|
+
expect(ActiveModelUser.new(full_name: 'test').to_indexed_json).to eq '{"id":null,"created_at":null,"full_name":"test"}'
|
41
45
|
end
|
42
46
|
|
43
47
|
describe 'default settings' do
|
@@ -48,70 +52,84 @@ describe ElasticsearchAutocomplete do
|
|
48
52
|
end
|
49
53
|
|
50
54
|
it 'allow to change default settings' do
|
51
|
-
ElasticsearchAutocomplete.defaults = {:
|
52
|
-
ElasticsearchAutocomplete.defaults.
|
55
|
+
ElasticsearchAutocomplete.defaults = {attr: :test, localized: true, mode: :phrase, index_prefix: 'test'}
|
56
|
+
expect(ElasticsearchAutocomplete.defaults).to eq ({attr: :test, localized: true, mode: :phrase, index_prefix: 'test'})
|
53
57
|
end
|
54
58
|
end
|
55
59
|
|
56
60
|
describe 'eager loading' do
|
57
61
|
it 'does not eager load the records from ac_search by default' do
|
58
62
|
results = ActiveModelUser.ac_search('Test User')
|
59
|
-
results.to_a.
|
60
|
-
results.map{|x| x.is_a?(ActiveModelUser).
|
63
|
+
expect(results.to_a).not_to be_empty
|
64
|
+
results.map{|x| expect(x.is_a?(ActiveModelUser)).to eq false }
|
61
65
|
end
|
62
66
|
|
63
67
|
it 'eager loads the records from ac_search' do
|
64
|
-
results = ActiveModelUser.ac_search('Test User', :
|
65
|
-
results.to_a.
|
66
|
-
results.map{|x| x.is_a?(ActiveModelUser).
|
68
|
+
results = ActiveModelUser.ac_search('Test User', load: true)
|
69
|
+
expect(results.to_a).not_to be_empty
|
70
|
+
results.map{|x| expect(x.is_a?(ActiveModelUser)).to eq true }
|
67
71
|
end
|
68
72
|
end
|
69
73
|
|
70
74
|
describe '#val_to_terms' do
|
71
75
|
it 'empty array if argument is blank' do
|
72
|
-
ElasticsearchAutocomplete.val_to_terms(nil).
|
76
|
+
expect(ElasticsearchAutocomplete.val_to_terms(nil)).to eq []
|
73
77
|
end
|
74
78
|
|
75
79
|
it 'array if argument is array' do
|
76
|
-
ElasticsearchAutocomplete.val_to_terms([1, 2]).
|
80
|
+
expect(ElasticsearchAutocomplete.val_to_terms([1, 2])).to eq [1, 2]
|
77
81
|
end
|
78
82
|
|
79
83
|
it 'comma separated values' do
|
80
|
-
ElasticsearchAutocomplete.val_to_terms('1,2').
|
84
|
+
expect(ElasticsearchAutocomplete.val_to_terms('1,2')).to eq [1, 2]
|
81
85
|
end
|
82
86
|
|
83
87
|
context 'skip zero' do
|
84
88
|
it 'skip zero by default' do
|
85
|
-
ElasticsearchAutocomplete.val_to_terms('0,1,2').
|
89
|
+
expect(ElasticsearchAutocomplete.val_to_terms('0,1,2')).to eq [1, 2]
|
86
90
|
end
|
87
91
|
|
88
92
|
it 'include zero' do
|
89
|
-
ElasticsearchAutocomplete.val_to_terms('0,1,2', true).
|
93
|
+
expect(ElasticsearchAutocomplete.val_to_terms('0,1,2', true)).to eq [0, 1, 2]
|
90
94
|
end
|
91
95
|
end
|
92
96
|
|
93
97
|
context 'boolean' do
|
94
98
|
it 'true value' do
|
95
|
-
ElasticsearchAutocomplete.val_to_terms('true').
|
99
|
+
expect(ElasticsearchAutocomplete.val_to_terms('true')).to eq [true]
|
96
100
|
end
|
97
101
|
|
98
102
|
it 'false value' do
|
99
|
-
ElasticsearchAutocomplete.val_to_terms('false').
|
103
|
+
expect(ElasticsearchAutocomplete.val_to_terms('false')).to eq [false]
|
100
104
|
end
|
101
105
|
end
|
102
106
|
end
|
107
|
+
|
108
|
+
describe 'indexing' do
|
109
|
+
it 'enabled by default' do
|
110
|
+
record = ActiveModelUser.new(full_name: 'test')
|
111
|
+
expect(record).to receive(:tire).and_return(double('tire').as_null_object)
|
112
|
+
record.save
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'disabled' do
|
116
|
+
record = ActiveModelUser.new(full_name: 'test')
|
117
|
+
expect(record).not_to receive(:tire)
|
118
|
+
ElasticsearchAutocomplete.without_indexing { record.save }
|
119
|
+
end
|
120
|
+
end
|
103
121
|
end
|
104
122
|
|
105
123
|
shared_examples 'basic autocomplete' do |model|
|
106
124
|
it 'suggest for beginning of the source' do
|
107
|
-
model.ac_search('Joyce Flores').to_a.
|
125
|
+
expect(model.ac_search('Joyce Flores').to_a).not_to be_empty
|
108
126
|
end
|
109
127
|
|
110
128
|
it 'suggest for for full match' do
|
111
|
-
model.ac_search('Lau').to_a.
|
129
|
+
expect(model.ac_search('Lau').to_a).not_to be_empty
|
112
130
|
end
|
113
131
|
|
114
132
|
it 'don\'t suggest for unmatched term' do
|
115
|
-
model.ac_search('Lai').to_a.
|
133
|
+
expect(model.ac_search('Lai').to_a).to be_empty
|
116
134
|
end
|
117
135
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
class ActiveModelProductFull < StubModelBase
|
4
|
-
ac_field :sku, :
|
4
|
+
ac_field :sku, mode: :full
|
5
5
|
|
6
6
|
def self.test_data
|
7
7
|
['SAMARA', 'A.3103', 'b A.3611', 'kac12 dk/sm']
|
@@ -9,7 +9,7 @@ class ActiveModelProductFull < StubModelBase
|
|
9
9
|
|
10
10
|
def self.populate
|
11
11
|
test_data.each_with_index do |name, id|
|
12
|
-
u = new(:
|
12
|
+
u = new(sku: name)
|
13
13
|
u.id = id
|
14
14
|
u.save
|
15
15
|
end
|
@@ -23,26 +23,26 @@ describe ':full mode autocomplete' do
|
|
23
23
|
end
|
24
24
|
|
25
25
|
it 'have :full mode' do
|
26
|
-
@model.ac_opts[:mode].
|
26
|
+
expect(@model.ac_opts[:mode]).to eq :full
|
27
27
|
end
|
28
28
|
|
29
29
|
it 'suggest for beginning of the source' do
|
30
|
-
@model.ac_search('A.31').to_a.
|
30
|
+
expect(@model.ac_search('A.31').to_a).not_to be_empty
|
31
31
|
end
|
32
32
|
|
33
33
|
it 'suggest for for full match' do
|
34
|
-
@model.ac_search('SAMARA').to_a.
|
34
|
+
expect(@model.ac_search('SAMARA').to_a).not_to be_empty
|
35
35
|
end
|
36
36
|
|
37
37
|
it 'don\'t suggest for unmatched term' do
|
38
|
-
@model.ac_search('kac3').to_a.
|
38
|
+
expect(@model.ac_search('kac3').to_a).to be_empty
|
39
39
|
end
|
40
40
|
|
41
41
|
it 'suggest from the middle of the word' do
|
42
|
-
@model.ac_search('/sm').to_a.
|
42
|
+
expect(@model.ac_search('/sm').to_a).not_to be_empty
|
43
43
|
end
|
44
44
|
|
45
45
|
it 'suggest with relevance order' do
|
46
|
-
@model.ac_search('A.3').map(&:sku).
|
46
|
+
expect(@model.ac_search('A.3').map(&:sku)).to eq ['A.3103', 'b A.3611']
|
47
47
|
end
|
48
48
|
end
|
@@ -1,12 +1,12 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
class ActiveModelProductLocalized < StubModelBase
|
4
|
-
ac_field :name, :
|
4
|
+
ac_field :name, localized: true
|
5
5
|
|
6
6
|
def self.test_data
|
7
7
|
[
|
8
|
-
{:
|
9
|
-
{:
|
8
|
+
{name_ru: 'name_ru first', name_en: 'name_en first'},
|
9
|
+
{name_ru: 'name_ru second', name_en: 'name_en second'}
|
10
10
|
]
|
11
11
|
end
|
12
12
|
|
@@ -26,8 +26,8 @@ describe 'suggestions for localized attributes' do
|
|
26
26
|
end
|
27
27
|
|
28
28
|
it 'don\'t suggest from all locales' do
|
29
|
-
@model.ac_search('name_en first').to_a.
|
30
|
-
@model.ac_search('name_ru first').to_a.
|
31
|
-
@model.ac_search('name_ru').to_a.
|
29
|
+
expect(@model.ac_search('name_en first').to_a.length).to eq 1
|
30
|
+
expect(@model.ac_search('name_ru first').to_a.length).to eq 1
|
31
|
+
expect(@model.ac_search('name_ru').to_a.length).to eq 2
|
32
32
|
end
|
33
33
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
class ActiveModelUserPhrase < StubModelBase
|
4
|
-
ac_field :full_name, :
|
4
|
+
ac_field :full_name, mode: :phrase
|
5
5
|
end
|
6
6
|
|
7
7
|
describe ':phrase mode autocomplete' do
|
@@ -12,16 +12,16 @@ describe ':phrase mode autocomplete' do
|
|
12
12
|
end
|
13
13
|
|
14
14
|
it 'have :phrase mode' do
|
15
|
-
@model.ac_opts[:mode].
|
15
|
+
expect(@model.ac_opts[:mode]).to eq :phrase
|
16
16
|
end
|
17
17
|
|
18
18
|
it_behaves_like 'basic autocomplete', ActiveModelUserPhrase
|
19
19
|
|
20
20
|
it 'don\'t suggest from the middle of the word' do
|
21
|
-
@model.ac_search('becca').to_a.
|
21
|
+
expect(@model.ac_search('becca').to_a).to be_empty
|
22
22
|
end
|
23
23
|
|
24
24
|
it 'don\'t for each word of the source' do
|
25
|
-
@model.ac_search('Flores').map(&:full_name).
|
25
|
+
expect(@model.ac_search('Flores').map(&:full_name)).to be_empty
|
26
26
|
end
|
27
27
|
end
|
@@ -5,9 +5,9 @@ class ActiveModelUserFilter < StubModelBase
|
|
5
5
|
|
6
6
|
def self.test_data
|
7
7
|
[
|
8
|
-
{:
|
9
|
-
{:
|
10
|
-
{:
|
8
|
+
{full_name: 'Laura Nelson', interest_ids: [1, 2]},
|
9
|
+
{full_name: 'Laura Flores', interest_ids: [2, 3]},
|
10
|
+
{full_name: 'Laura Larson', interest_ids: [3, 4]}
|
11
11
|
]
|
12
12
|
end
|
13
13
|
|
@@ -36,34 +36,34 @@ describe 'search filters' do
|
|
36
36
|
end
|
37
37
|
|
38
38
|
it 'filter suggestions with terms' do
|
39
|
-
@model.ac_search('Laura', :
|
39
|
+
expect(@model.ac_search('Laura', with: {interest_ids: [2]}).map(&:full_name)).to match_array ['Laura Nelson', 'Laura Flores']
|
40
40
|
end
|
41
41
|
|
42
42
|
it 'accept coma separated string for filter' do
|
43
|
-
@model.ac_search('Laura', :
|
43
|
+
expect(@model.ac_search('Laura', with: {interest_ids: '1,4'}).map(&:full_name)).to match_array ['Laura Nelson', 'Laura Larson']
|
44
44
|
end
|
45
45
|
|
46
46
|
it 'filter suggestions without terms' do
|
47
|
-
@model.ac_search('Laura', :
|
47
|
+
expect(@model.ac_search('Laura', without: {interest_ids: [2]}).map(&:full_name)).to match_array ['Laura Larson']
|
48
48
|
end
|
49
49
|
|
50
50
|
it 'can order suggestions desc' do
|
51
|
-
res = @model.ac_search('Laura', :
|
52
|
-
res.
|
51
|
+
res = @model.ac_search('Laura', order: :id, sort_mode: 'desc').map(&:id)
|
52
|
+
expect(res).to eq res.sort.reverse
|
53
53
|
end
|
54
54
|
|
55
55
|
it 'can order suggestions asc' do
|
56
|
-
res = @model.ac_search('Laura', :
|
57
|
-
res.
|
56
|
+
res = @model.ac_search('Laura', order: :id, sort_mode: 'asc').map(&:id)
|
57
|
+
expect(res).to eq res.sort
|
58
58
|
end
|
59
59
|
|
60
60
|
it 'limit suggestions collection size' do
|
61
|
-
@model.ac_search('Laura', :
|
61
|
+
expect(@model.ac_search('Laura', per_page: 1).to_a.length).to eq 1
|
62
62
|
end
|
63
63
|
|
64
64
|
it 'paginate suggestions' do
|
65
|
-
res = @model.ac_search('Laura', :
|
66
|
-
res.
|
67
|
-
res.first.full_name.
|
65
|
+
res = @model.ac_search('Laura', per_page: 1, page: 2).to_a
|
66
|
+
expect(res.length).to eq 1
|
67
|
+
expect(res.first.full_name).to eq 'Laura Flores'
|
68
68
|
end
|
69
69
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
class ActiveModelUserWord < StubModelBase
|
4
|
-
ac_field :full_name, :
|
4
|
+
ac_field :full_name, mode: :word
|
5
5
|
end
|
6
6
|
|
7
7
|
describe ':word mode autocomplete' do
|
@@ -11,20 +11,20 @@ describe ':word mode autocomplete' do
|
|
11
11
|
end
|
12
12
|
|
13
13
|
it 'have :word mode' do
|
14
|
-
@model.ac_opts[:mode].
|
14
|
+
expect(@model.ac_opts[:mode]).to eq :word
|
15
15
|
end
|
16
16
|
|
17
17
|
it_behaves_like 'basic autocomplete', ActiveModelUserWord
|
18
18
|
|
19
19
|
it 'don\'t suggest from the middle of the word' do
|
20
|
-
@model.ac_search('becca').to_a.
|
20
|
+
expect(@model.ac_search('becca').to_a).to be_empty
|
21
21
|
end
|
22
22
|
|
23
23
|
it 'suggest for each word of the source' do
|
24
|
-
@model.ac_search('Flores').map(&:full_name).
|
24
|
+
expect(@model.ac_search('Flores').map(&:full_name)).to eq ['Joyce Flores']
|
25
25
|
end
|
26
26
|
|
27
27
|
it 'suggest with relevance order' do
|
28
|
-
@model.ac_search('Lau').map(&:full_name).
|
28
|
+
expect(@model.ac_search('Lau').map(&:full_name)).to eq ['Laura Larson', 'Larson Laura']
|
29
29
|
end
|
30
30
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,83 +1,83 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: elasticsearch_autocomplete
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alex Leschenko
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2014-12-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: tire
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - ~>
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: 0.6.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - ~>
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 0.6.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: oj
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- -
|
59
|
+
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '0'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- -
|
66
|
+
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: activerecord
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- -
|
73
|
+
- - ">="
|
74
74
|
- !ruby/object:Gem::Version
|
75
75
|
version: '3.2'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- -
|
80
|
+
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '3.2'
|
83
83
|
description: Simple autocomplete for your models using awesome elasticsearch and tire
|
@@ -88,8 +88,8 @@ executables: []
|
|
88
88
|
extensions: []
|
89
89
|
extra_rdoc_files: []
|
90
90
|
files:
|
91
|
-
- .gitignore
|
92
|
-
- .travis.yml
|
91
|
+
- ".gitignore"
|
92
|
+
- ".travis.yml"
|
93
93
|
- Gemfile
|
94
94
|
- LICENSE.txt
|
95
95
|
- README.md
|
@@ -116,17 +116,17 @@ require_paths:
|
|
116
116
|
- lib
|
117
117
|
required_ruby_version: !ruby/object:Gem::Requirement
|
118
118
|
requirements:
|
119
|
-
- -
|
119
|
+
- - ">="
|
120
120
|
- !ruby/object:Gem::Version
|
121
121
|
version: '0'
|
122
122
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
123
123
|
requirements:
|
124
|
-
- -
|
124
|
+
- - ">="
|
125
125
|
- !ruby/object:Gem::Version
|
126
126
|
version: '0'
|
127
127
|
requirements: []
|
128
128
|
rubyforge_project:
|
129
|
-
rubygems_version: 2.
|
129
|
+
rubygems_version: 2.4.3
|
130
130
|
signing_key:
|
131
131
|
specification_version: 4
|
132
132
|
summary: Elasticsearch autocomplete for models
|