elastic_search_framework 2.1.0 → 2.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9bb31cdcff7f6e3f40501c7dcadba923be7582ff8d91daec8e52d7dd8689e8da
4
- data.tar.gz: b5c57937085a1719aae84d24fb10a93fbb582ec12ebe6f6b8c15f3aa987c053e
3
+ metadata.gz: 843e0d64a790e34d0cca88a47eb6824530b366a3f2f5732d09e8e7bae8437151
4
+ data.tar.gz: 914a7d0b4730df74b4cd8851d019f9cca83335951ba808b3b2a942d3398a0d8a
5
5
  SHA512:
6
- metadata.gz: 214b8d927d48733fc52a98c7667621529efb9d68e331d8f4b3e4e70c76a2b72fd2e5d56f749cd5d0b2a6002316fd56bc77d9b68bf8091fe0402ea7c7f994db61
7
- data.tar.gz: 8151848be2786d442eea281aa10e89338d06109b20bde72de2df87fd2f0b31a8a2279a9d560a035f66af92333657890cd5a34ed22dbb828a25e9d3003886d459
6
+ metadata.gz: 69b9c1c1e39841ad54cc1daf0b9895664ca4af635786dfc703c4ac8aa313af6146be873d26ca6358143f2bb1be11c453a28913a10437202524f8dbc4a75d93d9
7
+ data.tar.gz: e2c9a9d2ad91996c24837e2c7982b1e5a5f4a9a2d01c191e22a268f90fb9e8cbb63c2560b2cb5c105c9ac3c17dd930041bdda605512e389815e43747146f5677
@@ -8,6 +8,8 @@ require_relative 'elastic_search_framework/logger'
8
8
  require_relative 'elastic_search_framework/exceptions'
9
9
  require_relative 'elastic_search_framework/repository'
10
10
  require_relative 'elastic_search_framework/index'
11
+ require_relative 'elastic_search_framework/index_alias'
12
+ require_relative 'elastic_search_framework/sharded_index'
11
13
  require_relative 'elastic_search_framework/query'
12
14
 
13
15
  module ElasticSearchFramework
@@ -2,14 +2,23 @@ module ElasticSearchFramework
2
2
  module Index
3
3
  attr_accessor :index_settings
4
4
 
5
- def index(name:)
5
+ def index(name:, version: nil)
6
6
  unless instance_variable_defined?(:@elastic_search_index_def)
7
- instance_variable_set(:@elastic_search_index_def, name: "#{name}")
7
+ instance_variable_set(:@elastic_search_index_def, name: "#{name}#{version}")
8
+ instance_variable_set(:@elastic_search_index_version, version: version) unless version.nil?
8
9
  else
9
10
  raise ElasticSearchFramework::Exceptions::IndexError.new("[#{self.class}] - Duplicate index description. Name: #{name}.")
10
11
  end
11
12
  end
12
13
 
14
+ def version
15
+ instance_variable_defined?(:@elastic_search_index_version) ? instance_variable_get(:@elastic_search_index_version) : 0
16
+ end
17
+
18
+ def routing_enabled?
19
+ false
20
+ end
21
+
13
22
  def id(field)
14
23
  unless instance_variable_defined?(:@elastic_search_index_id)
15
24
  instance_variable_set(:@elastic_search_index_id, field)
@@ -160,19 +169,28 @@ module ElasticSearchFramework
160
169
  end
161
170
 
162
171
  def repository
163
- ElasticSearchFramework::Repository.new
172
+ @repository ||= ElasticSearchFramework::Repository.new
164
173
  end
165
174
 
166
- def get_item(id:, type: 'default')
167
- repository.get(index: self, id: id, type: type)
175
+ def get_item(id:, type: 'default', routing_key: nil)
176
+ options = { index: self, id: id, type: type }
177
+ options[:routing_key] = routing_key if routing_enabled? && routing_key
178
+
179
+ repository.get(options)
168
180
  end
169
181
 
170
- def put_item(type: 'default', item:)
171
- repository.set(entity: item, index: self, type: type)
182
+ def put_item(type: 'default', item:, op_type: 'index', routing_key: nil)
183
+ options = { entity: item, index: self, type: type, op_type: op_type }
184
+ options[:routing_key] = routing_key if routing_enabled? && routing_key
185
+
186
+ repository.set(options)
172
187
  end
173
188
 
174
- def delete_item(id:, type: 'default')
175
- repository.drop(index: self, id: id, type: type)
189
+ def delete_item(id:, type: 'default', routing_key: nil)
190
+ options = { index: self, id: id, type: type }
191
+ options[:routing_key] = routing_key if routing_enabled? && routing_key
192
+
193
+ repository.drop(options)
176
194
  end
177
195
 
178
196
  def query
@@ -0,0 +1,161 @@
1
+ module ElasticSearchFramework
2
+ module IndexAlias
3
+ def index(klass, active:)
4
+ unless instance_variable_defined?(:@elastic_search_indexes)
5
+ instance_variable_set(:@elastic_search_indexes, [])
6
+ end
7
+ indexes = self.instance_variable_get(:@elastic_search_indexes)
8
+ indexes << {klass: klass, active: active}
9
+ instance_variable_set(:@elastic_search_indexes, indexes)
10
+ end
11
+
12
+ def indexes
13
+ self.instance_variable_get(:@elastic_search_indexes)
14
+ end
15
+
16
+ def name(name)
17
+ unless instance_variable_defined?(:@elastic_search_index_alias_name)
18
+ instance_variable_set(:@elastic_search_index_alias_name, "#{name}")
19
+ else
20
+ raise ElasticSearchFramework::Exceptions::IndexError.new("[#{self.class}] - Duplicate index alias name: #{name}.")
21
+ end
22
+ end
23
+
24
+ def valid?
25
+ indexes.select { |i| i[:active] == true }.length == 1
26
+ end
27
+
28
+ def create
29
+ if !valid?
30
+ raise ElasticSearchFramework::Exceptions::IndexError.new("[#{self.class}] - Invalid Index alias.")
31
+ end
32
+
33
+ uri = URI("#{host}/_aliases")
34
+
35
+ payload = {
36
+ actions: [],
37
+ }
38
+
39
+ indexes.each do |index|
40
+ action = nil
41
+ if exists?(index: index[:klass])
42
+ action = "remove" if !index[:active]
43
+ else
44
+ action = "add" if index[:active]
45
+ end
46
+ next if action.nil?
47
+
48
+ payload[:actions] << {action => {index: index[:klass].full_name, alias: self.full_name}}
49
+ end
50
+
51
+ request = Net::HTTP::Post.new(uri.request_uri)
52
+ request.body = JSON.dump(payload)
53
+ request.content_type = "application/json"
54
+
55
+ response = repository.with_client do |client|
56
+ client.request(request)
57
+ end
58
+
59
+ is_valid_response?(response.code) || Integer(response.code) == 404
60
+ end
61
+
62
+ def delete
63
+ uri = URI("#{host}/_all/_aliases/#{full_name}")
64
+
65
+ request = Net::HTTP::Delete.new(uri.request_uri)
66
+
67
+ response = repository.with_client do |client|
68
+ client.request(request)
69
+ end
70
+
71
+ is_valid_response?(response.code) || Integer(response.code) == 404
72
+ end
73
+
74
+ def exists?(index:)
75
+ uri = URI("#{host}/#{index.full_name}/_alias/#{full_name}")
76
+
77
+ request = Net::HTTP::Get.new(uri.request_uri)
78
+
79
+ response = repository.with_client do |client|
80
+ client.request(request)
81
+ end
82
+
83
+ return false if response.code == "404"
84
+
85
+ result = nil
86
+ if is_valid_response?(response.code)
87
+ result = JSON.parse(response.body)
88
+ end
89
+
90
+ return true if !result.nil? && result[index.full_name]["aliases"] != nil
91
+ return false
92
+ end
93
+
94
+ def is_valid_response?(code)
95
+ [200, 201, 202].include?(Integer(code))
96
+ end
97
+
98
+ def full_name
99
+ name = instance_variable_get(:@elastic_search_index_alias_name)
100
+ if ElasticSearchFramework.namespace != nil
101
+ "#{ElasticSearchFramework.namespace}#{ElasticSearchFramework.namespace_delimiter}#{name.downcase}"
102
+ else
103
+ name.downcase
104
+ end
105
+ end
106
+
107
+ def description
108
+ index = indexes.last[:klass]
109
+ hash = index.instance_variable_get(:@elastic_search_index_def)
110
+ if index.instance_variable_defined?(:@elastic_search_index_id)
111
+ hash[:id] = index.instance_variable_get(:@elastic_search_index_id)
112
+ else
113
+ hash[:id] = :id
114
+ end
115
+ hash
116
+ end
117
+
118
+ def host
119
+ "#{ElasticSearchFramework.host}:#{ElasticSearchFramework.port}"
120
+ end
121
+
122
+ def repository
123
+ @repository ||= ElasticSearchFramework::Repository.new
124
+ end
125
+
126
+ def get_item(id:, type: "default", routing_key: nil)
127
+ active_index = indexes.detect { |i| i[:active] == true }[:klass]
128
+
129
+ options = { index: self, id: id, type: type }
130
+ options[:routing_key] = routing_key if active_index.routing_enabled? && routing_key
131
+
132
+ repository.get(options)
133
+ end
134
+
135
+ def put_item(type: "default", item:, op_type: 'index', routing_key: nil)
136
+ indexes.each do |index|
137
+ options = { entity: item, index: index[:klass], type: type, op_type: op_type }
138
+ options[:routing_key] = routing_key if index[:klass].routing_enabled? && routing_key
139
+
140
+ repository.set(options)
141
+ end
142
+ end
143
+
144
+ def delete_item(id:, type: "default", routing_key: nil)
145
+ indexes.each do |index|
146
+ options = { index: index[:klass], id: id, type: type }
147
+ options[:routing_key] = routing_key if index[:klass].routing_enabled? && routing_key
148
+
149
+ repository.drop(options)
150
+ end
151
+ end
152
+
153
+ def query
154
+ ElasticSearchFramework::Query.new(index: self)
155
+ end
156
+
157
+ def routing_enabled?
158
+ indexes.find(active: true).first[:klass].routing_enabled?
159
+ end
160
+ end
161
+ end
@@ -1,8 +1,11 @@
1
1
  module ElasticSearchFramework
2
2
  class Repository
3
3
 
4
- def set(index:, entity:, type: 'default')
5
- uri = URI("#{host}/#{index.full_name}/#{type.downcase}/#{get_id_value(index: index, entity: entity)}")
4
+ def set(index:, entity:, type: 'default', op_type: 'index', routing_key: nil)
5
+ uri_string = "#{host}/#{index.full_name}/#{type.downcase}/#{get_id_value(index: index, entity: entity)}?op_type=#{op_type}"
6
+ uri_string += "&routing=#{routing_key}" if routing_key
7
+
8
+ uri = URI(uri_string)
6
9
  hash = hash_helper.to_hash(entity)
7
10
 
8
11
  request = Net::HTTP::Put.new(uri.request_uri)
@@ -13,16 +16,22 @@ module ElasticSearchFramework
13
16
  client.request(request)
14
17
  end
15
18
 
16
- unless valid_response?(response.code)
19
+ if valid_response?(response.code)
20
+ return true
21
+ elsif op_type == 'create' && Integer(response.code) == 409
22
+ return true
23
+ else
17
24
  raise ElasticSearchFramework::Exceptions::IndexError.new(
18
25
  "An error occurred setting an index document. Response: #{response.body} | Code: #{response.code}"
19
26
  )
20
27
  end
21
- return true
22
28
  end
23
29
 
24
- def get(index:, id:, type: 'default')
25
- uri = URI("#{host}/#{index.full_name}/#{type.downcase}/#{id}/_source")
30
+ def get(index:, id:, type: 'default', routing_key: nil)
31
+ uri_string = "#{host}/#{index.full_name}/#{type.downcase}/#{id}/_source"
32
+ uri_string += "?routing=#{routing_key}" if routing_key
33
+
34
+ uri = URI(uri_string)
26
35
 
27
36
  request = Net::HTTP::Get.new(uri.request_uri)
28
37
 
@@ -43,8 +52,11 @@ module ElasticSearchFramework
43
52
  end
44
53
  end
45
54
 
46
- def drop(index:, id:, type: 'default')
47
- uri = URI("#{host}/#{index.full_name}/#{type.downcase}/#{id}")
55
+ def drop(index:, id:, type: 'default', routing_key: nil)
56
+ uri_string = "#{host}/#{index.full_name}/#{type.downcase}/#{id}"
57
+ uri_string += "?routing=#{routing_key}" if routing_key
58
+
59
+ uri = URI(uri_string)
48
60
 
49
61
  request = Net::HTTP::Delete.new(uri.request_uri)
50
62
 
@@ -61,8 +73,11 @@ module ElasticSearchFramework
61
73
  end
62
74
  end
63
75
 
64
- def query(index:, expression:, type: 'default', limit: 10, count: false)
65
- uri = URI("#{host}/#{index.full_name}/#{type}/_search?q=#{URI.encode(expression)}&size=#{limit}")
76
+ def query(index:, expression:, type: 'default', limit: 10, count: false, routing_key: nil)
77
+ uri_string = "#{host}/#{index.full_name}/#{type}/_search?q=#{URI.encode(expression)}&size=#{limit}"
78
+ uri_string += "&routing=#{routing_key}" if routing_key
79
+
80
+ uri = URI(uri_string)
66
81
 
67
82
  request = Net::HTTP::Get.new(uri.request_uri)
68
83
 
@@ -83,8 +98,11 @@ module ElasticSearchFramework
83
98
  end
84
99
  end
85
100
 
86
- def json_query(index_name:, json_query:, type: 'default')
87
- uri = URI("#{host}/#{index_name}/#{type}/_search")
101
+ def json_query(index_name:, json_query:, type: 'default', routing_key: nil)
102
+ uri_string = "#{host}/#{index_name}/#{type}/_search"
103
+ uri_string += "?routing=#{routing_key}" if routing_key
104
+
105
+ uri = URI(uri_string)
88
106
 
89
107
  request = Net::HTTP::Get.new(uri.request_uri)
90
108
  request.content_type = 'application/json'
@@ -0,0 +1,200 @@
1
+ module ElasticSearchFramework
2
+ module ShardedIndex
3
+ attr_accessor :index_settings
4
+
5
+ def index(name:, version: nil)
6
+ unless instance_variable_defined?(:@elastic_search_index_def)
7
+ instance_variable_set(:@elastic_search_index_def, name: "#{name}#{version}")
8
+ instance_variable_set(:@elastic_search_index_version, version: version) unless version.nil?
9
+ else
10
+ raise ElasticSearchFramework::Exceptions::IndexError.new("[#{self.class}] - Duplicate index description. Name: #{name}.")
11
+ end
12
+ end
13
+
14
+ def version
15
+ instance_variable_defined?(:@elastic_search_index_version) ? instance_variable_get(:@elastic_search_index_version) : 0
16
+ end
17
+
18
+ def routing_enabled?
19
+ true
20
+ end
21
+
22
+ def id(field)
23
+ unless instance_variable_defined?(:@elastic_search_index_id)
24
+ instance_variable_set(:@elastic_search_index_id, field)
25
+ else
26
+ raise ElasticSearchFramework::Exceptions::IndexError.new("[#{self.class}] - Duplicate index id. Field: #{field}.")
27
+ end
28
+ end
29
+
30
+ def mapping(name:, field:, **options)
31
+ unless instance_variable_defined?(:@elastic_search_index_mappings)
32
+ instance_variable_set(:@elastic_search_index_mappings, {})
33
+ end
34
+
35
+ mappings = instance_variable_get(:@elastic_search_index_mappings)
36
+
37
+ mappings[name] = {} if mappings[name].nil?
38
+
39
+ mappings[name][field] = options
40
+
41
+ instance_variable_set(:@elastic_search_index_mappings, mappings)
42
+ end
43
+
44
+ def create
45
+ if !valid?
46
+ raise ElasticSearchFramework::Exceptions::IndexError.new("[#{self.class}] - Invalid Index description specified.")
47
+ end
48
+
49
+ if exists?
50
+ ElasticSearchFramework.logger.debug { "[#{self.class}] - Index already exists."}
51
+ return
52
+ end
53
+ payload = create_payload
54
+
55
+ put(payload: payload)
56
+ end
57
+
58
+ def put(payload:)
59
+ uri = URI("#{host}/#{full_name}")
60
+
61
+ request = Net::HTTP::Put.new(uri.request_uri)
62
+ request.body = JSON.dump(payload)
63
+ request.content_type = 'application/json'
64
+
65
+ response = repository.with_client do |client|
66
+ client.request(request)
67
+ end
68
+
69
+ unless is_valid_response?(response.code)
70
+ if JSON.parse(response.body, symbolize_names: true).dig(:error, :root_cause, 0, :type) == 'index_already_exists_exception'
71
+ # We get here because the `exists?` check in #create is non-atomic
72
+ ElasticSearchFramework.logger.warn "[#{self.class}] - Failed to create preexisting index. | Response: #{response.body}"
73
+ else
74
+ raise ElasticSearchFramework::Exceptions::IndexError.new("[#{self}] - Failed to put index. Payload: #{payload} | Response: #{response.body}")
75
+ end
76
+ end
77
+ true
78
+ end
79
+
80
+ def get
81
+ uri = URI("#{host}/#{full_name}")
82
+
83
+ request = Net::HTTP::Get.new(uri.request_uri)
84
+
85
+ response = repository.with_client do |client|
86
+ client.request(request)
87
+ end
88
+
89
+ result = nil
90
+ if is_valid_response?(response.code)
91
+ result = JSON.parse(response.body)
92
+ end
93
+ result
94
+ end
95
+
96
+ def exists?
97
+ get != nil
98
+ end
99
+
100
+ def delete
101
+ uri = URI("#{host}/#{full_name}")
102
+
103
+ request = Net::HTTP::Delete.new(uri.request_uri)
104
+
105
+ response = repository.with_client do |client|
106
+ client.request(request)
107
+ end
108
+
109
+ is_valid_response?(response.code) || Integer(response.code) == 404
110
+ end
111
+
112
+ def settings(name:, type: nil, value:)
113
+ self.index_settings = {} if index_settings.nil?
114
+ index_settings[name] = {} if index_settings[name].nil?
115
+ return index_settings[name][type] = value if type
116
+ index_settings[name] = value
117
+ end
118
+
119
+ def create_payload
120
+ payload = { }
121
+ payload[:settings] = index_settings unless index_settings.nil?
122
+
123
+ unless mappings.keys.empty?
124
+ payload[:mappings] = {}
125
+
126
+ mappings.keys.each do |name|
127
+ payload[:mappings][name] = { properties: {} }
128
+ mappings[name].keys.each do |field|
129
+ payload[:mappings][name][:properties][field] = mappings[name][field]
130
+ end
131
+ end
132
+ end
133
+
134
+ payload
135
+ end
136
+
137
+ def valid?
138
+ self.instance_variable_get(:@elastic_search_index_def) ? true : false
139
+ end
140
+
141
+ def description
142
+ hash = self.instance_variable_get(:@elastic_search_index_def)
143
+ if instance_variable_defined?(:@elastic_search_index_id)
144
+ hash[:id] = self.instance_variable_get(:@elastic_search_index_id)
145
+ else
146
+ hash[:id] = :id
147
+ end
148
+ hash
149
+ end
150
+
151
+ def mappings
152
+ self.instance_variable_defined?(:@elastic_search_index_mappings) ? self.instance_variable_get(:@elastic_search_index_mappings) : {}
153
+ end
154
+
155
+ def is_valid_response?(code)
156
+ [200,201,202].include?(Integer(code))
157
+ end
158
+
159
+ def full_name
160
+ if ElasticSearchFramework.namespace != nil
161
+ "#{ElasticSearchFramework.namespace}#{ElasticSearchFramework.namespace_delimiter}#{description[:name].downcase}"
162
+ else
163
+ description[:name].downcase
164
+ end
165
+ end
166
+
167
+ def host
168
+ "#{ElasticSearchFramework.host}:#{ElasticSearchFramework.port}"
169
+ end
170
+
171
+ def repository
172
+ @repository ||= ElasticSearchFramework::Repository.new
173
+ end
174
+
175
+ def get_item(id:, type: 'default', routing_key: nil)
176
+ options = { index: self, id: id, type: type }
177
+ options[:routing_key] = routing_key if routing_enabled? && routing_key
178
+
179
+ repository.get(options)
180
+ end
181
+
182
+ def put_item(type: 'default', item:, op_type: 'index', routing_key: nil)
183
+ options = { entity: item, index: self, type: type, op_type: op_type }
184
+ options[:routing_key] = routing_key if routing_enabled? && routing_key
185
+
186
+ repository.set(options)
187
+ end
188
+
189
+ def delete_item(id:, type: 'default', routing_key: nil)
190
+ options = { index: self, id: id, type: type }
191
+ options[:routing_key] = routing_key if routing_enabled? && routing_key
192
+
193
+ repository.drop(options)
194
+ end
195
+
196
+ def query
197
+ ElasticSearchFramework::Query.new(index: self)
198
+ end
199
+ end
200
+ end
@@ -1,3 +1,3 @@
1
1
  module ElasticSearchFramework
2
- VERSION = '2.1.0'
2
+ VERSION = '2.4.0'
3
3
  end
@@ -0,0 +1,174 @@
1
+ RSpec.describe ElasticSearchFramework::Index do
2
+ describe '#full_name' do
3
+ let(:namespace) { 'uat' }
4
+ let(:namespace_delimiter) { '.' }
5
+ before do
6
+ ElasticSearchFramework.namespace = namespace
7
+ ElasticSearchFramework.namespace_delimiter = namespace_delimiter
8
+ end
9
+ it 'should return the full index name including namespace and delimiter' do
10
+ expect(ExampleIndexAlias.full_name).to eq "#{ElasticSearchFramework.namespace}#{ElasticSearchFramework.namespace_delimiter}example"
11
+ end
12
+
13
+ context 'when the namespace is nil' do
14
+ before { ElasticSearchFramework.namespace = nil }
15
+
16
+ it 'returns the description name downcased' do
17
+ expect(ExampleIndexAlias.full_name).to eq 'example'
18
+ end
19
+ end
20
+ end
21
+
22
+ describe '#valid?' do
23
+ context 'for a valid index definition' do
24
+ it 'should return true' do
25
+ expect(ExampleIndexAlias.valid?).to be true
26
+ end
27
+ end
28
+ context 'for an invalid index definition' do
29
+ it 'should return true' do
30
+ expect(InvalidIndexAlias.valid?).to be false
31
+ end
32
+ end
33
+ end
34
+
35
+ describe '#create' do
36
+ context 'when alias is valid and does not exist' do
37
+ before do
38
+ ExampleIndexAlias.delete
39
+ ExampleIndex.delete if ExampleIndex.exists?
40
+ ExampleIndex.create
41
+ end
42
+
43
+ it 'creates an alias for the active index' do
44
+ expect(ExampleIndexAlias.exists?(index: ExampleIndex)).to be false
45
+ ExampleIndexAlias.create
46
+ expect(ExampleIndexAlias.exists?(index: ExampleIndex)).to be true
47
+ end
48
+
49
+ after do
50
+ ExampleIndexAlias.delete
51
+ ExampleIndex.delete
52
+ end
53
+ end
54
+
55
+ context 'when alias is not valid' do
56
+ before { allow(ExampleIndexAlias).to receive(:valid?).and_return(false) }
57
+
58
+ it 'raises an error' do
59
+ expect(ExampleIndexAlias.exists?(index: ExampleIndex)).to be false
60
+ expect { ExampleIndexAlias.create }.to raise_error(
61
+ ElasticSearchFramework::Exceptions::IndexError
62
+ )
63
+ end
64
+ end
65
+
66
+ context 'when alias is valid but already exists' do
67
+ before do
68
+ ExampleIndex.delete if ExampleIndex.exists?
69
+ ExampleIndex.create
70
+ ExampleIndexAlias.create
71
+ end
72
+
73
+ it 'does not try to create a new alias' do
74
+ ExampleIndexAlias.create
75
+ end
76
+
77
+ after do
78
+ ExampleIndexAlias.delete
79
+ ExampleIndex.delete
80
+ end
81
+ end
82
+
83
+ context 'when alias is valid and does not exist and requires updating' do
84
+ before do
85
+ ExampleIndexAlias.delete
86
+ ExampleIndex.delete if ExampleIndex.exists?
87
+ ExampleIndex2.delete if ExampleIndex2.exists?
88
+ ExampleIndex.create
89
+ ExampleIndex2.create
90
+ ExampleIndexAlias.create
91
+ end
92
+
93
+ it 'modifies the alias to the active index' do
94
+ expect(ExampleIndexAlias.exists?(index: ExampleIndex)).to be true
95
+ ExampleIndexAlias2.create
96
+ expect(ExampleIndexAlias.exists?(index: ExampleIndex)).to be false
97
+ expect(ExampleIndexAlias2.exists?(index: ExampleIndex2)).to be true
98
+ end
99
+
100
+ after do
101
+ ExampleIndexAlias.delete
102
+ ExampleIndex.delete
103
+ ExampleIndex2.delete
104
+ end
105
+ end
106
+ end
107
+
108
+ describe '#get_item' do
109
+ let(:id) { 10 }
110
+ let(:type) { 'default' }
111
+ context 'when active index routing_enabled false' do
112
+ it 'should call get on the repository' do
113
+ expect(ExampleIndexAlias.repository).to receive(:get).with(index: ExampleIndexAlias, id: id, type: type).once
114
+ ExampleIndexAlias.get_item(id: id, type: type)
115
+ end
116
+
117
+ it 'should call get on the repository and not pass through routing_key when supplied' do
118
+ expect(ExampleIndexAlias.repository).to receive(:get).with(index: ExampleIndexAlias, id: id, type: type).once
119
+ ExampleIndexAlias.get_item(id: id, type: type, routing_key: 5)
120
+ end
121
+ end
122
+
123
+ context 'when active index routing_enabled true' do
124
+ it 'should call get on the repository' do
125
+ expect(ExampleIndexAlias2.repository).to receive(:get).with(index: ExampleIndexAlias2, id: id, type: type, routing_key: 5).once
126
+ ExampleIndexAlias2.get_item(id: id, type: type, routing_key: 5)
127
+ end
128
+ end
129
+ end
130
+
131
+ describe '#put_item' do
132
+ let(:id) { 10 }
133
+ let(:type) { 'default' }
134
+ let(:item) do
135
+ TestItem.new.tap do |i|
136
+ i.id = id
137
+ i.name = 'abc'
138
+ i.timestamp = Time.now.to_i
139
+ i.number = 5
140
+ end
141
+ end
142
+ context 'without specifying op_type' do
143
+ it 'should call set on the repository for each index of the alias with default op_type (index)' do
144
+ expect(ExampleIndexAlias.repository).to receive(:set).with(entity: item, index: ExampleIndex, type: type, op_type: 'index').once
145
+ expect(ExampleIndexAlias.repository).to receive(:set).with(entity: item, index: ExampleIndex2, type: type, op_type: 'index', routing_key: 5).once
146
+ ExampleIndexAlias.put_item(type: type, item: item, routing_key: 5)
147
+ end
148
+ end
149
+
150
+ context 'with specified op_type' do
151
+ it 'should call set on the repository for each index of the alias with supplied op_type (index)' do
152
+ expect(ExampleIndexAlias.repository).to receive(:set).with(entity: item, index: ExampleIndex, type: type, op_type: 'index').once
153
+ expect(ExampleIndexAlias.repository).to receive(:set).with(entity: item, index: ExampleIndex2, type: type, op_type: 'index', routing_key: 5).once
154
+ ExampleIndexAlias.put_item(type: type, item: item, op_type: 'index', routing_key: 5)
155
+ end
156
+
157
+ it 'should call set on the repository for each index of the alias with supplied op_type (create)' do
158
+ expect(ExampleIndexAlias.repository).to receive(:set).with(entity: item, index: ExampleIndex, type: type, op_type: 'create').once
159
+ expect(ExampleIndexAlias.repository).to receive(:set).with(entity: item, index: ExampleIndex2, type: type, op_type: 'create', routing_key: 5).once
160
+ ExampleIndexAlias.put_item(type: type, item: item, op_type: 'create', routing_key: 5)
161
+ end
162
+ end
163
+ end
164
+
165
+ describe '#delete_item' do
166
+ let(:id) { 10 }
167
+ let(:type) { 'default' }
168
+ it 'should call drop on the repository for each index of the alias' do
169
+ expect(ExampleIndexAlias.repository).to receive(:drop).with(index: ExampleIndex, id: id, type: type).once
170
+ expect(ExampleIndexAlias.repository).to receive(:drop).with(index: ExampleIndex2, id: id, type: type, routing_key: 5).once
171
+ ExampleIndexAlias.delete_item(id: id, type: type, routing_key: 5)
172
+ end
173
+ end
174
+ end
@@ -79,17 +79,18 @@ RSpec.describe ElasticSearchFramework::Index do
79
79
  {
80
80
  'normalizer' => {
81
81
  'custom_normalizer' => {
82
+ 'char_filter' => [],
82
83
  'filter' => ['lowercase'],
83
84
  'type' => 'custom'
84
85
  }
85
86
  },
86
- 'analyzer'=>{
87
- 'custom_analyzer'=>{
88
- 'filter'=>['lowercase'],
89
- 'type'=>'custom',
90
- 'tokenizer'=>'standard'
91
- }
87
+ 'analyzer' => {
88
+ 'custom_analyzer' => {
89
+ 'filter' => ['lowercase'],
90
+ 'type' => 'custom',
91
+ 'tokenizer' => 'standard'
92
92
  }
93
+ }
93
94
  }
94
95
  end
95
96
 
@@ -276,8 +277,8 @@ RSpec.describe ElasticSearchFramework::Index do
276
277
  it 'should return a ElasticSearchFramework::Repository instance' do
277
278
  expect(ExampleIndex.repository).to be_a(ElasticSearchFramework::Repository)
278
279
  end
279
- it 'should return a unique ElasticSearchFramework::Repository instance' do
280
- expect(ExampleIndex.repository).not_to eq ExampleIndex.repository
280
+ it 'should return the same ElasticSearchFramework::Repository instance for multiple calls' do
281
+ expect(ExampleIndex.repository).to eq ExampleIndex.repository
281
282
  end
282
283
  end
283
284
 
@@ -301,9 +302,38 @@ RSpec.describe ElasticSearchFramework::Index do
301
302
  i.number = 5
302
303
  end
303
304
  end
304
- it 'should call set on the repository' do
305
- expect_any_instance_of(ElasticSearchFramework::Repository).to receive(:set).with(entity: item, index: ExampleIndex, type: type)
306
- ExampleIndex.put_item(type: type, item: item)
305
+
306
+ context 'without specifying op_type' do
307
+ it 'should call set on the repository with default op_type (index)' do
308
+ expect_any_instance_of(ElasticSearchFramework::Repository).to receive(:set).with(entity: item, index: ExampleIndex, op_type: 'index', type: type)
309
+ ExampleIndex.put_item(type: type, item: item)
310
+ end
311
+ end
312
+
313
+ context 'with specified op_type' do
314
+ it 'should call set on the repository with supplied op_type (index)' do
315
+ expect_any_instance_of(ElasticSearchFramework::Repository).to receive(:set).with(entity: item, index: ExampleIndex, op_type: 'index', type: type)
316
+ ExampleIndex.put_item(type: type, item: item, op_type: 'index')
317
+ end
318
+
319
+ it 'should call set on the repository with supplied op_type (create)' do
320
+ expect_any_instance_of(ElasticSearchFramework::Repository).to receive(:set).with(entity: item, index: ExampleIndex, op_type: 'create', type: type)
321
+ ExampleIndex.put_item(type: type, item: item, op_type: 'create')
322
+ end
323
+ end
324
+
325
+ context 'without specifying routing_key' do
326
+ it 'should call set on the repository without routing_key' do
327
+ expect_any_instance_of(ElasticSearchFramework::Repository).to receive(:set).with(entity: item, index: ExampleIndex, op_type: 'index', type: type)
328
+ ExampleIndex.put_item(type: type, item: item, op_type: 'index')
329
+ end
330
+ end
331
+
332
+ context 'with specified routing_key' do
333
+ it 'should call set on the repository without routing_key' do
334
+ expect_any_instance_of(ElasticSearchFramework::Repository).to receive(:set).with(entity: item, index: ExampleIndex, op_type: 'index', type: type)
335
+ ExampleIndex.put_item(type: type, item: item, op_type: 'index', routing_key: '6')
336
+ end
307
337
  end
308
338
  end
309
339
 
@@ -63,22 +63,40 @@ RSpec.describe ElasticSearchFramework::Repository do
63
63
  ExampleIndexWithId.create
64
64
  end
65
65
 
66
- it 'should create, read and delete an index document' do
67
- subject.set(index: ExampleIndex, entity: item1)
68
- subject.set(index: ExampleIndex, entity: item2)
69
- subject.set(index: ExampleIndex, entity: item5)
70
- index_item1 = subject.get(index: ExampleIndex, id: item1.id)
71
- expect(index_item1[:id]).to eq item1.id
72
- expect(index_item1[:name]).to eq item1.name
73
- expect(index_item1[:timestamp]).to eq item1.timestamp
74
- expect(index_item1[:number]).to eq item1.number
75
- index_item2 = subject.get(index: ExampleIndex, id: item2.id)
76
- expect(index_item2[:id]).to eq item2.id
77
- expect(index_item2[:name]).to eq item2.name
78
- expect(index_item2[:timestamp]).to eq item2.timestamp
79
- expect(index_item2[:number]).to eq item2.number
80
- subject.drop(index: ExampleIndex, id: item1.id)
81
- expect(subject.get(index: ExampleIndex, id: item1.id)).to be_nil
66
+ context 'PUT with op_type: index' do
67
+ it 'should create, read and delete an index document' do
68
+ subject.set(index: ExampleIndex, entity: item1)
69
+ subject.set(index: ExampleIndex, entity: item1.tap { |i| i.timestamp += 100 })
70
+ subject.set(index: ExampleIndex, entity: item1.tap { |i| i.timestamp += 100 }, op_type: 'index')
71
+ subject.set(index: ExampleIndex, entity: item2)
72
+ subject.set(index: ExampleIndex, entity: item5)
73
+ index_item1 = subject.get(index: ExampleIndex, id: item1.id)
74
+ expect(index_item1[:id]).to eq item1.id
75
+ expect(index_item1[:name]).to eq item1.name
76
+ expect(index_item1[:timestamp]).to eq item1.timestamp
77
+ expect(index_item1[:number]).to eq item1.number
78
+ index_item2 = subject.get(index: ExampleIndex, id: item2.id)
79
+ expect(index_item2[:id]).to eq item2.id
80
+ expect(index_item2[:name]).to eq item2.name
81
+ expect(index_item2[:timestamp]).to eq item2.timestamp
82
+ expect(index_item2[:number]).to eq item2.number
83
+ subject.drop(index: ExampleIndex, id: item1.id)
84
+ expect(subject.get(index: ExampleIndex, id: item1.id)).to be_nil
85
+ end
86
+ end
87
+
88
+ context 'PUT with op_type: create' do
89
+ let!(:original_timestamp) { item1.timestamp }
90
+
91
+ it 'should not update item' do
92
+ subject.set(index: ExampleIndex, entity: item1)
93
+ subject.set(index: ExampleIndex, entity: item1.tap { |i| i.timestamp += 100 }, op_type: 'create')
94
+ index_item1 = subject.get(index: ExampleIndex, id: item1.id)
95
+ expect(index_item1[:id]).to eq item1.id
96
+ expect(index_item1[:name]).to eq item1.name
97
+ expect(index_item1[:timestamp]).to eq original_timestamp
98
+ expect(index_item1[:number]).to eq item1.number
99
+ end
82
100
  end
83
101
 
84
102
  after do
@@ -0,0 +1,348 @@
1
+ RSpec.describe ElasticSearchFramework::ShardedIndex do
2
+ describe '#description' do
3
+ it 'should return the index details' do
4
+ expect(ExampleIndex2.description).to be_a(Hash)
5
+ expect(ExampleIndex2.description[:name]).to eq 'example_index2'
6
+ expect(ExampleIndex2.description[:id]).to eq :id
7
+ expect(ExampleIndexWithId2.description[:id]).to eq :number
8
+ end
9
+ end
10
+
11
+ describe '#index' do
12
+ before { ExampleIndex2.create unless ExampleIndex2.exists? }
13
+ context 'when the instance variable is not defined' do
14
+ before { allow(ExampleIndex2).to receive(:instance_variable_defined?).and_return(true) }
15
+ it 'raises an index error' do
16
+ expect { ExampleIndex2.index(name: 'test') }.to raise_error(
17
+ ElasticSearchFramework::Exceptions::IndexError,
18
+ '[Class] - Duplicate index description. Name: test.'
19
+ )
20
+ end
21
+ end
22
+ end
23
+
24
+ describe '#id' do
25
+ context 'when the instance variable is not defined' do
26
+ before { allow(ExampleIndex2).to receive(:instance_variable_defined?).and_return(true) }
27
+ it 'raises an index error' do
28
+ expect { ExampleIndex2.id('name') }.to raise_error(
29
+ ElasticSearchFramework::Exceptions::IndexError,
30
+ "[Class] - Duplicate index id. Field: name."
31
+ )
32
+ end
33
+ end
34
+ end
35
+
36
+ describe '#full_name' do
37
+ let(:namespace) { 'uat' }
38
+ let(:namespace_delimiter) { '.' }
39
+ before do
40
+ ElasticSearchFramework.namespace = namespace
41
+ ElasticSearchFramework.namespace_delimiter = namespace_delimiter
42
+ end
43
+ it 'should return the full index name including namespace and delimiter' do
44
+ expect(ExampleIndex2.full_name).to eq "#{ElasticSearchFramework.namespace}#{ElasticSearchFramework.namespace_delimiter}#{ExampleIndex2.description[:name]}"
45
+ end
46
+
47
+ context 'when the namespace is nil' do
48
+ before { ElasticSearchFramework.namespace = nil }
49
+
50
+ it 'returns the description name downcased' do
51
+ expect(ExampleIndex2.full_name).to eq 'example_index2'
52
+ end
53
+ end
54
+ end
55
+
56
+ describe '#mapping' do
57
+ it 'should add mapping details to the index definition' do
58
+ mappings = ExampleIndex2.mappings
59
+ expect(mappings).to be_a(Hash)
60
+ expect(mappings.length).to eq 1
61
+ expect(mappings['default'][:name][:type]).to eq :keyword
62
+ expect(mappings['default'][:name][:index]).to eq true
63
+ end
64
+ end
65
+
66
+ describe '#analysis' do
67
+ context 'when analysis is nil' do
68
+ before { ExampleIndex2.delete if ExampleIndex2.exists? }
69
+
70
+ it 'does not add analysis to the index' do
71
+ ExampleIndex2.create
72
+ expect(ExampleIndexWithSettings2.get.dig('example_index2', 'settings', 'index', 'analysis')).to be_nil
73
+ end
74
+ end
75
+
76
+ context 'when analysis is not nil' do
77
+ before { ExampleIndexWithSettings2.delete if ExampleIndexWithSettings2.exists? }
78
+ let(:expected) do
79
+ {
80
+ 'normalizer' => {
81
+ 'custom_normalizer' => {
82
+ 'char_filter' => [],
83
+ 'filter' => ['lowercase'],
84
+ 'type' => 'custom'
85
+ }
86
+ },
87
+ 'analyzer' => {
88
+ 'custom_analyzer' => {
89
+ 'filter' => ['lowercase'],
90
+ 'type' => 'custom',
91
+ 'tokenizer' => 'standard'
92
+ }
93
+ }
94
+ }
95
+ end
96
+
97
+ it 'adds analysis to the index' do
98
+ ExampleIndexWithSettings2.create
99
+ expect(ExampleIndexWithSettings2.get.dig('example_index2', 'settings', 'index', 'number_of_shards')).to eq('1')
100
+ expect(ExampleIndexWithSettings2.get.dig('example_index2', 'settings', 'index', 'analysis')).to eq(expected)
101
+ end
102
+ end
103
+ end
104
+
105
+ describe '#valid?' do
106
+ context 'for a valid index definition' do
107
+ it 'should return true' do
108
+ expect(ExampleIndex2.valid?).to be true
109
+ end
110
+ end
111
+ context 'for an invalid index definition' do
112
+ it 'should return true' do
113
+ expect(InvalidExampleIndex2.valid?).to be false
114
+ end
115
+ end
116
+ end
117
+
118
+ describe '#create' do
119
+ context 'when index is valid and does not exist' do
120
+ before { ExampleIndex2.delete if ExampleIndex2.exists? }
121
+
122
+ it 'should create an index' do
123
+ expect(ExampleIndex2.exists?).to be false
124
+ ExampleIndex2.create
125
+ expect(ExampleIndex2.exists?).to be true
126
+ end
127
+
128
+ after do
129
+ ExampleIndex2.delete
130
+ end
131
+ end
132
+
133
+ context 'when index is not valid' do
134
+ before { allow(ExampleIndex2).to receive(:valid?).and_return(false) }
135
+
136
+ it 'raises an error' do
137
+ expect(ExampleIndex2.exists?).to be false
138
+ expect { ExampleIndex2.create }.to raise_error(
139
+ ElasticSearchFramework::Exceptions::IndexError,
140
+ '[Class] - Invalid Index description specified.'
141
+ )
142
+ end
143
+ end
144
+
145
+ context 'when index is valid but already exists' do
146
+ before { ExampleIndex2.delete if ExampleIndex2.exists? }
147
+
148
+ it 'does not try to create a new index' do
149
+ allow(ExampleIndex2).to receive(:exists?).and_return(true)
150
+ expect(ExampleIndex2).not_to receive(:put)
151
+ ExampleIndex2.create
152
+ end
153
+ end
154
+ end
155
+
156
+ describe '#delete' do
157
+ before do
158
+ unless ExampleIndex2.exists?
159
+ ExampleIndex2.create
160
+ end
161
+ end
162
+ it 'should create an index' do
163
+ expect(ExampleIndex2.exists?).to be true
164
+ ExampleIndex2.delete
165
+ expect(ExampleIndex2.exists?).to be false
166
+ end
167
+ end
168
+
169
+ describe '#exists?' do
170
+ context 'when an index exists' do
171
+ before do
172
+ ExampleIndex2.delete
173
+ ExampleIndex2.create
174
+ end
175
+ it 'should return true' do
176
+ expect(ExampleIndex2.exists?).to be true
177
+ end
178
+ end
179
+ context 'when an index exists' do
180
+ before do
181
+ ExampleIndex2.delete
182
+ end
183
+ it 'should return false' do
184
+ expect(ExampleIndex2.exists?).to be false
185
+ end
186
+ end
187
+ end
188
+
189
+ describe '#put' do
190
+ let(:payload) { {} }
191
+ context 'when there is a valid response' do
192
+ before { allow(ExampleIndex2).to receive(:is_valid_response?).and_return(true) }
193
+
194
+ it 'returns true' do
195
+ ExampleIndex2.create
196
+ expect(ExampleIndex2.put(payload: payload)).to eq true
197
+ end
198
+ end
199
+
200
+ context 'when there is not a valid response' do
201
+ before { allow(ExampleIndex2).to receive(:is_valid_response?).and_return(false) }
202
+
203
+ context 'when the error is "index_already_exists_exception"' do
204
+ let(:response_body) { { error: { root_cause: [{ type: 'index_already_exists_exception' }] } } }
205
+ let(:request) { double }
206
+
207
+ before { ExampleIndex2.delete if ExampleIndex2.exists? }
208
+ it 'returns true' do
209
+ allow(request).to receive(:body).and_return(response_body.to_json)
210
+ allow(request).to receive(:code).and_return(404)
211
+ allow_any_instance_of(Net::HTTP).to receive(:request).and_return(request)
212
+ expect(ExampleIndex2.put(payload: payload)).to eq true
213
+ end
214
+ end
215
+
216
+ context 'when the error is not "index_already_exists_exception"' do
217
+ let(:response_body) { { error: { root_cause: [{ type: 'foo' }] } } }
218
+ let(:request) { double }
219
+ it 'raises an IndexError' do
220
+ allow(request).to receive(:body).and_return(response_body.to_json)
221
+ allow(request).to receive(:code).and_return(404)
222
+ allow_any_instance_of(Net::HTTP).to receive(:request).and_return(request)
223
+ expect { ExampleIndex2.put(payload: payload) }.to raise_error(
224
+ ElasticSearchFramework::Exceptions::IndexError
225
+ )
226
+ end
227
+ end
228
+ end
229
+ end
230
+
231
+ describe '#is_valid_response?' do
232
+ let(:code) { 200 }
233
+ context 'when a 200 response code is returned' do
234
+ it 'should return true' do
235
+ expect(ExampleIndex2.is_valid_response?(code)).to be true
236
+ end
237
+ end
238
+ context 'when a 201 response code is returned' do
239
+ let(:code) { 201 }
240
+ it 'should return true' do
241
+ expect(ExampleIndex2.is_valid_response?(code)).to be true
242
+ end
243
+ end
244
+ context 'when a 202 response code is returned' do
245
+ let(:code) { 202 }
246
+ it 'should return true' do
247
+ expect(ExampleIndex2.is_valid_response?(code)).to be true
248
+ end
249
+ end
250
+ context 'when a 400 response code is returned' do
251
+ let(:code) { 400 }
252
+ it 'should return false' do
253
+ expect(ExampleIndex2.is_valid_response?(code)).to be false
254
+ end
255
+ end
256
+ context 'when a 401 response code is returned' do
257
+ let(:code) { 401 }
258
+ it 'should return false' do
259
+ expect(ExampleIndex2.is_valid_response?(code)).to be false
260
+ end
261
+ end
262
+ context 'when a 500 response code is returned' do
263
+ let(:code) { 500 }
264
+ it 'should return false' do
265
+ expect(ExampleIndex2.is_valid_response?(code)).to be false
266
+ end
267
+ end
268
+ end
269
+
270
+ describe '#host' do
271
+ it 'should return the expected host based on default host & port values' do
272
+ expect(ExampleIndex2.host).to eq "#{ElasticSearchFramework.host}:#{ElasticSearchFramework.port}"
273
+ end
274
+ end
275
+
276
+ describe '#repository' do
277
+ it 'should return a ElasticSearchFramework::Repository instance' do
278
+ expect(ExampleIndex2.repository).to be_a(ElasticSearchFramework::Repository)
279
+ end
280
+ it 'should return the same ElasticSearchFramework::Repository instance for multiple calls' do
281
+ expect(ExampleIndex2.repository).to eq ExampleIndex2.repository
282
+ end
283
+ end
284
+
285
+ describe '#get_item' do
286
+ let(:id) { 10 }
287
+ let(:type) { 'default' }
288
+ it 'should call get on the repository' do
289
+ expect_any_instance_of(ElasticSearchFramework::Repository).to receive(:get).with(index: ExampleIndex2, id: id, type: type)
290
+ ExampleIndex2.get_item(id: id, type: type)
291
+ end
292
+ end
293
+
294
+ describe '#put_item' do
295
+ let(:id) { 10 }
296
+ let(:type) { 'default' }
297
+ let(:item) do
298
+ TestItem.new.tap do |i|
299
+ i.id = id
300
+ i.name = 'abc'
301
+ i.timestamp = Time.now.to_i
302
+ i.number = 5
303
+ end
304
+ end
305
+
306
+ context 'without specifying op_type' do
307
+ it 'should call set on the repository with default op_type (index)' do
308
+ expect_any_instance_of(ElasticSearchFramework::Repository).to receive(:set).with(entity: item, index: ExampleIndex2, op_type: 'index', type: type)
309
+ ExampleIndex2.put_item(type: type, item: item)
310
+ end
311
+ end
312
+
313
+ context 'with specified op_type' do
314
+ it 'should call set on the repository with supplied op_type (index)' do
315
+ expect_any_instance_of(ElasticSearchFramework::Repository).to receive(:set).with(entity: item, index: ExampleIndex2, op_type: 'index', type: type)
316
+ ExampleIndex2.put_item(type: type, item: item, op_type: 'index')
317
+ end
318
+
319
+ it 'should call set on the repository with supplied op_type (create)' do
320
+ expect_any_instance_of(ElasticSearchFramework::Repository).to receive(:set).with(entity: item, index: ExampleIndex2, op_type: 'create', type: type)
321
+ ExampleIndex2.put_item(type: type, item: item, op_type: 'create')
322
+ end
323
+ end
324
+
325
+ context 'without specifying routing_key' do
326
+ it 'should call set on the repository without routing_key' do
327
+ expect_any_instance_of(ElasticSearchFramework::Repository).to receive(:set).with(entity: item, index: ExampleIndex2, op_type: 'index', type: type)
328
+ ExampleIndex2.put_item(type: type, item: item, op_type: 'index')
329
+ end
330
+ end
331
+
332
+ context 'with specified routing_key' do
333
+ it 'should call set on the repository with routing_key' do
334
+ expect_any_instance_of(ElasticSearchFramework::Repository).to receive(:set).with(entity: item, index: ExampleIndex2, op_type: 'index', type: type, routing_key: 6)
335
+ ExampleIndex2.put_item(type: type, item: item, op_type: 'index', routing_key: 6)
336
+ end
337
+ end
338
+ end
339
+
340
+ describe '#delete_item' do
341
+ let(:id) { 10 }
342
+ let(:type) { 'default' }
343
+ it 'should call drop on the repository' do
344
+ expect_any_instance_of(ElasticSearchFramework::Repository).to receive(:drop).with(index: ExampleIndex2, id: id, type: type)
345
+ ExampleIndex2.delete_item(id: id, type: type)
346
+ end
347
+ end
348
+ end
@@ -0,0 +1,35 @@
1
+ class ExampleIndex2
2
+ extend ElasticSearchFramework::ShardedIndex
3
+
4
+ index name: 'example_index', version: 2
5
+
6
+ mapping name: 'default', field: :name, type: :keyword, index: true
7
+ end
8
+
9
+ class ExampleIndexWithId2
10
+ extend ElasticSearchFramework::ShardedIndex
11
+
12
+ index name: 'example_index', version: 2
13
+
14
+ id :number
15
+
16
+ mapping name: 'default', field: :name, type: :keyword, index: true
17
+ end
18
+
19
+ class ExampleIndexWithSettings2
20
+ extend ElasticSearchFramework::ShardedIndex
21
+
22
+ index name: 'example_index', version: 2
23
+
24
+ normalizer_value = { custom_normalizer: { type: 'custom', char_filter: [], filter: ['lowercase'] } }
25
+ analyzer_value = { custom_analyzer: { type: 'custom', tokenizer: 'standard', filter: %w(lowercase) } }
26
+
27
+ settings name: :number_of_shards, value: 1
28
+ settings name: :analysis, type: :normalizer, value: normalizer_value
29
+ settings name: :analysis, type: :analyzer, value: analyzer_value
30
+ mapping name: 'default', field: :name, type: :keyword, index: true
31
+ end
32
+
33
+ class InvalidExampleIndex2
34
+ extend ElasticSearchFramework::ShardedIndex
35
+ end
@@ -0,0 +1,17 @@
1
+ class ExampleIndexAlias
2
+ extend ElasticSearchFramework::IndexAlias
3
+
4
+ index ExampleIndex, active: true
5
+ index ExampleIndex2, active: false
6
+
7
+ name :example
8
+ end
9
+
10
+ class InvalidIndexAlias
11
+ extend ElasticSearchFramework::IndexAlias
12
+
13
+ index ExampleIndex, active: false
14
+ index ExampleIndex2, active: false
15
+
16
+ name :example
17
+ end
@@ -0,0 +1,8 @@
1
+ class ExampleIndexAlias2
2
+ extend ElasticSearchFramework::IndexAlias
3
+
4
+ index ExampleIndex, active: false
5
+ index ExampleIndex2, active: true
6
+
7
+ name :example
8
+ end
data/spec/spec_helper.rb CHANGED
@@ -9,6 +9,9 @@ end
9
9
  require 'elastic_search_framework'
10
10
  require_relative '../spec/test_item.rb'
11
11
  require_relative '../spec/example_index'
12
+ require_relative '../spec/example_index_2'
13
+ require_relative '../spec/example_index_alias'
14
+ require_relative '../spec/example_index_alias_2'
12
15
  require 'pry'
13
16
 
14
17
  RSpec.configure do |config|
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: elastic_search_framework
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
4
+ version: 2.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - vaughanbrittonsage
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-04-17 00:00:00.000000000 Z
11
+ date: 2021-07-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -119,14 +119,21 @@ files:
119
119
  - lib/elastic_search_framework/exceptions.rb
120
120
  - lib/elastic_search_framework/exceptions/index_error.rb
121
121
  - lib/elastic_search_framework/index.rb
122
+ - lib/elastic_search_framework/index_alias.rb
122
123
  - lib/elastic_search_framework/logger.rb
123
124
  - lib/elastic_search_framework/query.rb
124
125
  - lib/elastic_search_framework/repository.rb
126
+ - lib/elastic_search_framework/sharded_index.rb
125
127
  - lib/elastic_search_framework/version.rb
128
+ - spec/elastic_search_framework/index_alias_spec.rb
126
129
  - spec/elastic_search_framework/index_spec.rb
127
130
  - spec/elastic_search_framework/query_spec.rb
128
131
  - spec/elastic_search_framework/repository_spec.rb
132
+ - spec/elastic_search_framework/sharded_index_spec.rb
129
133
  - spec/example_index.rb
134
+ - spec/example_index_2.rb
135
+ - spec/example_index_alias.rb
136
+ - spec/example_index_alias_2.rb
130
137
  - spec/spec_helper.rb
131
138
  - spec/test_item.rb
132
139
  homepage: https://github.com/sage/elastic_search_framework
@@ -148,7 +155,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
148
155
  - !ruby/object:Gem::Version
149
156
  version: '0'
150
157
  requirements: []
151
- rubygems_version: 3.0.3
158
+ rubygems_version: 3.1.2
152
159
  signing_key:
153
160
  specification_version: 4
154
161
  summary: A lightweight framework to for working with elastic search.