elastic_search_framework 2.1.0 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
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.