esse 0.2.0 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/lib/esse/backend/index/aliases.rb +8 -8
  3. data/lib/esse/backend/index/close.rb +3 -3
  4. data/lib/esse/backend/index/create.rb +4 -4
  5. data/lib/esse/backend/index/delete.rb +4 -4
  6. data/lib/esse/backend/index/documents.rb +253 -6
  7. data/lib/esse/backend/index/existance.rb +3 -3
  8. data/lib/esse/backend/index/open.rb +3 -3
  9. data/lib/esse/backend/index/refresh.rb +7 -5
  10. data/lib/esse/backend/index/reset.rb +4 -4
  11. data/lib/esse/backend/index/update.rb +7 -7
  12. data/lib/esse/backend/index.rb +16 -14
  13. data/lib/esse/backend/repository_backend.rb +105 -0
  14. data/lib/esse/cli/event_listener.rb +14 -0
  15. data/lib/esse/cli/generate.rb +53 -12
  16. data/lib/esse/cli/index/base_operation.rb +5 -13
  17. data/lib/esse/cli/index/import.rb +6 -2
  18. data/lib/esse/cli/index/update_mapping.rb +3 -4
  19. data/lib/esse/cli/index.rb +2 -0
  20. data/lib/esse/cli/templates/{type_collection.rb.erb → collection.rb.erb} +6 -18
  21. data/lib/esse/cli/templates/config.rb.erb +13 -3
  22. data/lib/esse/cli/templates/index.rb.erb +53 -109
  23. data/lib/esse/cli/templates/mappings.json +27 -0
  24. data/lib/esse/cli/templates/serializer.rb.erb +34 -0
  25. data/lib/esse/cli/templates/settings.json +62 -0
  26. data/lib/esse/client_proxy/search.rb +44 -0
  27. data/lib/esse/client_proxy.rb +32 -0
  28. data/lib/esse/cluster.rb +64 -9
  29. data/lib/esse/cluster_engine.rb +42 -0
  30. data/lib/esse/collection.rb +18 -0
  31. data/lib/esse/config.rb +14 -2
  32. data/lib/esse/core.rb +23 -6
  33. data/lib/esse/deprecations/cluster.rb +27 -0
  34. data/lib/esse/deprecations/index.rb +19 -0
  35. data/lib/esse/deprecations/repository.rb +19 -0
  36. data/lib/esse/deprecations.rb +3 -0
  37. data/lib/esse/dynamic_template.rb +39 -0
  38. data/lib/esse/errors.rb +53 -2
  39. data/lib/esse/events/event.rb +4 -19
  40. data/lib/esse/events.rb +3 -0
  41. data/lib/esse/hash_document.rb +38 -0
  42. data/lib/esse/import/bulk.rb +96 -0
  43. data/lib/esse/import/request_body.rb +60 -0
  44. data/lib/esse/index/attributes.rb +98 -0
  45. data/lib/esse/index/base.rb +1 -1
  46. data/lib/esse/index/inheritance.rb +30 -0
  47. data/lib/esse/index/mappings.rb +6 -19
  48. data/lib/esse/index/object_document_mapper.rb +95 -0
  49. data/lib/esse/index/plugins.rb +42 -0
  50. data/lib/esse/index/search.rb +27 -0
  51. data/lib/esse/index/settings.rb +2 -2
  52. data/lib/esse/index/type.rb +52 -11
  53. data/lib/esse/index.rb +10 -6
  54. data/lib/esse/index_mapping.rb +10 -2
  55. data/lib/esse/index_setting.rb +3 -1
  56. data/lib/esse/null_document.rb +35 -0
  57. data/lib/esse/plugins.rb +12 -0
  58. data/lib/esse/primitives/hstring.rb +1 -1
  59. data/lib/esse/{index_type → repository}/actions.rb +1 -1
  60. data/lib/esse/{index_type → repository}/backend.rb +2 -2
  61. data/lib/esse/repository/object_document_mapper.rb +157 -0
  62. data/lib/esse/repository.rb +18 -0
  63. data/lib/esse/search/query.rb +105 -0
  64. data/lib/esse/search/response.rb +46 -0
  65. data/lib/esse/serializer.rb +76 -0
  66. data/lib/esse/version.rb +1 -1
  67. data/lib/esse.rb +20 -5
  68. metadata +35 -30
  69. data/lib/esse/backend/index_type/documents.rb +0 -214
  70. data/lib/esse/backend/index_type.rb +0 -37
  71. data/lib/esse/cli/templates/type_mappings.json +0 -6
  72. data/lib/esse/cli/templates/type_serializer.rb.erb +0 -23
  73. data/lib/esse/index/naming.rb +0 -64
  74. data/lib/esse/index_type/mappings.rb +0 -42
  75. data/lib/esse/index_type.rb +0 -15
  76. data/lib/esse/object_document_mapper.rb +0 -110
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a31d2a1c181dccd9c2acd7256d958010e7c636016b1d5a267597f7aec9ed3334
4
- data.tar.gz: cdb390a10b0492833a9360d4fd39df0c18df114a44b37554cba1dd39d229f75b
3
+ metadata.gz: 1a9a18ea9cc75f6e98edecd0c151fe3077dc362529dc562e380855ec651b898e
4
+ data.tar.gz: 3d1a96c3ba0a088e2a88b5e7aa3c1440662877d6ab2dc3e1edbd7276fe39611e
5
5
  SHA512:
6
- metadata.gz: 59ae5dcafd8998c69e5705910b119f5f9d1333899a4320b8f7afa4c5782aa435d820dde222726de111cee00c6d3b4bbed9d6fdd18dac6a6f740cf64138b70d53
7
- data.tar.gz: 84b876eaec5b090718e2d265dd5d9456c5dfaeedafdae6e9361ac790de91eab0ba46b9ceabee3c5e8a891c5027ff3ac8443217554219f8dce5f52c853912989c
6
+ metadata.gz: a70c285401ed1f1d3c43ebb73970339d9c48344d1872a8f5c8391ead77c75a3aeabbc8391acd88971e8bdfcc370abafdab726884deb86d713aabe75bf553c3da
7
+ data.tar.gz: 6ca5282a53d4e7b29bbe29e149fd5405c9a25a6bd561bc803969e173955f83625c33a6f5b1116280f5a327b54ad4ec5923b58844543da63c51ff029e805e64ec
@@ -11,12 +11,12 @@ module Esse
11
11
  #
12
12
  # @see https://www.elastic.co/guide/en/elasticsearch/reference/7.5/indices-aliases.html
13
13
  def aliases(**options)
14
- response = client.indices.get_alias({ index: index_name, name: '*' }.merge(options))
14
+ response = coerce_exception { client.indices.get_alias({ index: index_name, name: '*' }.merge(options)) }
15
15
  idx_name = response.keys.find { |idx| idx.start_with?(index_name) }
16
16
  return [] unless idx_name
17
17
 
18
18
  response.dig(idx_name, 'aliases')&.keys || []
19
- rescue Elasticsearch::Transport::Transport::Errors::NotFound
19
+ rescue NotFoundError
20
20
  []
21
21
  end
22
22
 
@@ -25,8 +25,8 @@ module Esse
25
25
  # @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
26
26
  # @return [Array] list of indices that match with `index_name`.
27
27
  def indices(**options)
28
- client.indices.get_alias({ name: index_name }.merge(options)).keys
29
- rescue Elasticsearch::Transport::Transport::Errors::NotFound
28
+ coerce_exception { client.indices.get_alias({ name: index_name }.merge(options)).keys }
29
+ rescue NotFoundError
30
30
  []
31
31
  end
32
32
 
@@ -34,7 +34,7 @@ module Esse
34
34
  #
35
35
  # @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
36
36
  # @option [String] :suffix The suffix of the index used for versioning.
37
- # @raise [Elasticsearch::Transport::Transport::Errors::NotFound] in case of failure
37
+ # @raise [Esse::Backend::NotFoundError] in case of failure
38
38
  # @return [Hash] the elasticsearch response
39
39
  def update_aliases!(suffix:, **options)
40
40
  raise(ArgumentError, 'index suffix cannot be nil') if suffix.nil?
@@ -50,7 +50,7 @@ module Esse
50
50
 
51
51
  Esse::Events.instrument('elasticsearch.update_aliases') do |payload|
52
52
  payload[:request] = options
53
- payload[:response] = client.indices.update_aliases(options)
53
+ payload[:response] = coerce_exception { client.indices.update_aliases(options)}
54
54
  end
55
55
  end
56
56
 
@@ -58,11 +58,11 @@ module Esse
58
58
  #
59
59
  # @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
60
60
  # @option [String] :suffix The suffix of the index used for versioning.
61
- # @raise [Elasticsearch::Transport::Transport::Errors::NotFound] in case of failure
61
+ # @raise [Esse::Backend::NotFoundError] in case of failure
62
62
  # @return [Hash] the elasticsearch response, or an hash with 'errors' as true in case of failure
63
63
  def update_aliases(suffix:, **options)
64
64
  update_aliases!(suffix: suffix, **options)
65
- rescue Elasticsearch::Transport::Transport::Errors::NotFound
65
+ rescue NotFoundError
66
66
  { 'errors' => true }
67
67
  end
68
68
  end
@@ -15,7 +15,7 @@ module Esse
15
15
  # @option options [Boolean] :ignore_unavailable Whether specified concrete indices should be ignored when
16
16
  # unavailable (missing, closed, etc)
17
17
  # @option options [Time] :timeout Explicit operation timeout
18
- # @raise [Elasticsearch::Transport::Transport::Errors::BadRequest, Elasticsearch::Transport::Transport::Errors::NotFound]
18
+ # @raise [Esse::Backend::ServerError]
19
19
  # in case of failure
20
20
  # @return [Hash] the elasticsearch response
21
21
  #
@@ -23,7 +23,7 @@ module Esse
23
23
  def close!(suffix: index_version, **options)
24
24
  Esse::Events.instrument('elasticsearch.close') do |payload|
25
25
  payload[:request] = attributes = options.merge(index: index_name(suffix: suffix))
26
- payload[:response] = client.indices.close(**attributes)
26
+ payload[:response] = coerce_exception { client.indices.close(**attributes) }
27
27
  end
28
28
  end
29
29
 
@@ -43,7 +43,7 @@ module Esse
43
43
  # @see https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-open-close.html
44
44
  def close(suffix: index_version, **options)
45
45
  close!(suffix: suffix, **options)
46
- rescue Elasticsearch::Transport::Transport::ServerError
46
+ rescue ServerError
47
47
  { 'errors' => true }
48
48
  end
49
49
  end
@@ -21,7 +21,7 @@ module Esse
21
21
  # @see http://www.elasticsearch.org/blog/changing-mapping-with-zero-downtime/
22
22
  def create_index(suffix: index_version, **options)
23
23
  create_index!(suffix: suffix, **options)
24
- rescue Elasticsearch::Transport::Transport::Errors::BadRequest
24
+ rescue ServerError
25
25
  { 'errors' => true }
26
26
  end
27
27
 
@@ -39,7 +39,7 @@ module Esse
39
39
  # @option arguments [Time] :master_timeout Specify timeout for connection to master
40
40
  # @option arguments [Hash] :headers Custom HTTP headers
41
41
  # @option arguments [Hash] :body The configuration for the index (`settings` and `mappings`)
42
- # @raise [Elasticsearch::Transport::Transport::Errors::NotFound] when index already exists
42
+ # @raise [Esse::Backend::NotFoundError] when index already exists
43
43
  # @return [Hash] the elasticsearch response
44
44
  #
45
45
  # @see http://www.elasticsearch.org/blog/changing-mapping-with-zero-downtime/
@@ -54,8 +54,8 @@ module Esse
54
54
 
55
55
  Esse::Events.instrument('elasticsearch.create_index') do |payload|
56
56
  payload[:request] = opts = options.merge(index: name, body: definition)
57
- payload[:response] = response = client.indices.create(**opts)
58
- cluster.wait_for_status! if response
57
+ payload[:response] = response = coerce_exception { client.indices.create(**opts) }
58
+ coerce_exception { cluster.wait_for_status! } if response
59
59
  response
60
60
  end
61
61
  end
@@ -9,13 +9,13 @@ module Esse
9
9
  # UsersIndex.elasticsearch.delete_index! # deletes `<prefix_>users<_suffix|_index_version|_timestamp>` index
10
10
  #
11
11
  # @param suffix [String, nil] The index suffix Use nil if you want to delete the current index.
12
- # @raise [Elasticsearch::Transport::Transport::Errors::NotFound] when index does not exists
12
+ # @raise [Esse::Backend::NotFoundError] when index does not exists
13
13
  # @return [Hash] elasticsearch response
14
14
  def delete_index!(suffix: index_version, **options)
15
15
  Esse::Events.instrument('elasticsearch.delete_index') do |payload|
16
16
  payload[:request] = opts = options.merge(index: index_name(suffix: suffix))
17
- payload[:response] = response = client.indices.delete(**opts)
18
- cluster.wait_for_status! if response
17
+ payload[:response] = response = coerce_exception { client.indices.delete(**opts) }
18
+ coerce_exception { cluster.wait_for_status! } if response
19
19
  response
20
20
  end
21
21
  end
@@ -28,7 +28,7 @@ module Esse
28
28
  # @return [Hash] the elasticsearch response, or an hash with 'errors' as true in case of failure
29
29
  def delete_index(suffix: index_version, **options)
30
30
  delete_index!(suffix: suffix, **options)
31
- rescue Elasticsearch::Transport::Transport::Errors::NotFound
31
+ rescue ServerError
32
32
  { 'errors' => true }
33
33
  end
34
34
  end
@@ -4,17 +4,264 @@ module Esse
4
4
  module Backend
5
5
  class Index
6
6
  module InstanceMethods
7
- def import!(**options)
8
- type_hash.each_value do |type|
9
- type.elasticsearch.import!(**options)
7
+ # Resolve collection and index data
8
+ #
9
+ # @param types [Array<String>] List of document types. Defaults to all types.
10
+ # @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
11
+ # @option [String, nil] :suffix The index suffix. Defaults to the nil.
12
+ # @option [Hash] :context The collection context. This value will be passed as argument to the collection
13
+ # May be SQL condition or any other filter you have defined on the collection.
14
+ # @return [Numeric] The number of documents imported
15
+ def import(*types, context: {}, suffix: nil, **options)
16
+ types = repo_hash.keys if types.empty?
17
+ count = 0
18
+ types.each do |type|
19
+ each_serialized_batch(type, **(context || {})) do |batch|
20
+ bulk(type: type, index: batch, suffix: suffix, **options)
21
+ count += batch.size
22
+ end
10
23
  end
24
+ count
11
25
  end
26
+ alias_method :import!, :import
12
27
 
13
- def import(**options)
14
- type_hash.each_value do |type|
15
- type.elasticsearch.import(**options)
28
+ # Performs multiple indexing or delete operations in a single API call.
29
+ # This reduces overhead and can greatly increase indexing speed.
30
+ #
31
+ # @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
32
+ # @option [String, nil] :suffix The index suffix. Defaults to the nil.
33
+ # @option [Array] :index list of serialized documents to be indexed(Optional)
34
+ # @option [Array] :delete list of serialized documents to be deleted(Optional)
35
+ # @option [Array] :create list of serialized documents to be created(Optional)
36
+ # @option [String, NilClass] :type The type of the document (Optional for elasticsearch >= 7)
37
+ # @return [Hash, nil] the elasticsearch response or nil if there is no data.
38
+ #
39
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/7.5/docs-bulk.html
40
+ # @see https://github.com/elastic/elasticsearch-ruby/blob/main/elasticsearch-api/lib/elasticsearch/api/utils.rb
41
+ # @see https://github.com/elastic/elasticsearch-ruby/blob/main/elasticsearch-api/lib/elasticsearch/api/actions/bulk.rb
42
+ def bulk(index: nil, delete: nil, create: nil, type: nil, suffix: nil, **options)
43
+ definition = {
44
+ index: index_name(suffix: suffix),
45
+ }.merge(options)
46
+ definition[:type] = type if document_type?
47
+
48
+ Esse::Import::Bulk.new(
49
+ index: index,
50
+ delete: delete,
51
+ create: create,
52
+ ).each_request do |request_body|
53
+ Esse::Events.instrument('elasticsearch.bulk') do |payload|
54
+ payload[:request] = definition.merge(body_stats: request_body.stats)
55
+ payload[:response] = resp = coerce_exception { client.bulk(**definition, body: request_body.body) }
56
+ # @todo move it to a BulkRequest class
57
+ if resp&.[]('errors')
58
+ payload[:error] = resp['errors']
59
+ raise resp&.fetch('items', [])&.select { |item| item.values.first['error'] }.join("\n")
60
+ end
61
+ if bulk_wait_interval > 0
62
+ payload[:wait_interval] = bulk_wait_interval
63
+ sleep(bulk_wait_interval)
64
+ else
65
+ payload[:wait_interval] = 0.0
66
+ end
67
+ resp
68
+ end
16
69
  end
17
70
  end
71
+ alias_method :bulk!, :bulk
72
+
73
+ # Adds a JSON document to the specified index and makes it searchable. If the document
74
+ # already exists, updates the document and increments its version.
75
+ #
76
+ # UsersIndex::User.index(id: 1, body: { name: 'name' }) # { '_id' => 1, ...}
77
+ #
78
+ # @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
79
+ # @option [String, Integer] :id The `_id` of the elasticsearch document
80
+ # @option [Hash] :body The JSON document that will be indexed (Required)
81
+ # @option [String, NilClass] :type The type of the document (Optional for elasticsearch >= 7)
82
+ # @option [String, nil] :suffix The index suffix. Defaults to the nil.
83
+ # @return [Hash] the elasticsearch response Hash
84
+ #
85
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/7.5/docs-index_.html
86
+ # @todo update to allow serialized document as parameter
87
+ def index(id:, body:, type: nil, suffix: nil, **options)
88
+ params = {
89
+ index: index_name(suffix: suffix),
90
+ id: id,
91
+ body: body,
92
+ }
93
+ params[:type] = type if document_type?
94
+ coerce_exception { client.index(**options, **params) }
95
+ end
96
+ alias_method :index!, :index
97
+
98
+ # Updates a document using the specified script.
99
+ #
100
+ # UsersIndex::User.update!(id: 1, body: { doc: { ... } }) # { '_id' => 1, ...}
101
+ #
102
+ # @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
103
+ # @option [String, Integer] :id The `_id` of the elasticsearch document
104
+ # @option [Hash] :body the body of the request
105
+ # @option [String, NilClass] :type The type of the document (Optional for elasticsearch >= 7)
106
+ # @option [String, nil] :suffix The index suffix. Defaults to the nil.
107
+ # @raise [Esse::Backend::NotFoundError] when the doc does not exist
108
+ # @return [Hash] elasticsearch response hash
109
+ #
110
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/7.5/docs-update.html
111
+ # @todo update to allow serialized document as parameter
112
+ def update!(id:, body:, type: nil, suffix: nil, **options)
113
+ params = {
114
+ index: index_name(suffix: suffix),
115
+ id: id,
116
+ body: body,
117
+ }
118
+ params[:type] = type if document_type?
119
+ coerce_exception { client.update(**options, **params) }
120
+ end
121
+
122
+ # Updates a document using the specified script.
123
+ #
124
+ # UsersIndex::User.update(id: 1, body: { doc: { ... } }) # { '_id' => 1, ...}
125
+ #
126
+ # @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
127
+ # @option [String, Integer] :id The `_id` of the elasticsearch document
128
+ # @option [String, NilClass] :type The type of the document (Optional for elasticsearch >= 7)
129
+ # @option [Hash] :body the body of the request
130
+ # @option [String, nil] :suffix The index suffix. Defaults to the nil.
131
+ # @return [Hash] the elasticsearch response, or an hash with 'errors' as true in case of failure
132
+ #
133
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/7.5/docs-update.html
134
+ # @todo update to allow serialized document as parameter
135
+ def update(id:, body:, suffix: nil, **options)
136
+ update!(id: id, body: body, suffix: suffix, **options)
137
+ rescue NotFoundError
138
+ { 'errors' => true }
139
+ end
140
+
141
+ # Removes a JSON document from the specified index.
142
+ #
143
+ # UsersIndex::User.delete!(id: 1) # true
144
+ # UsersIndex::User.delete!(id: 'missing') # raise Esse::Backend::NotFoundError
145
+ #
146
+ # @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
147
+ # @option [String, Integer] :id The `_id` of the elasticsearch document
148
+ # @option [String, NilClass] :type The type of the document (Optional for elasticsearch >= 7)
149
+ # @option [String, nil] :suffix The index suffix. Defaults to the nil.
150
+ # @raise [Esse::Backend::NotFoundError] when the doc does not exist
151
+ # @return [Boolean] true when the operation is successfully completed
152
+ #
153
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/7.5/docs-delete.html
154
+ # @todo update to allow serialized document as parameter
155
+ def delete!(id:, type: nil, suffix: nil, **options)
156
+ params = {
157
+ index: index_name(suffix: suffix),
158
+ id: id,
159
+ }
160
+ params[:type] = type if document_type?
161
+ coerce_exception { client.delete(**options, **params) }
162
+ end
163
+
164
+ # Removes a JSON document from the specified index.
165
+ #
166
+ # UsersIndex::User.delete(id: 1) # true
167
+ # UsersIndex::User.delete(id: 'missing') # false
168
+ #
169
+ # @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
170
+ # @option [String, Integer] :id The `_id` of the elasticsearch document
171
+ # @option [String, NilClass] :type The type of the document (Optional for elasticsearch >= 7)
172
+ # @option [String, nil] :suffix The index suffix. Defaults to the nil.
173
+ # @raise [Esse::Backend::NotFoundError] when the doc does not exist
174
+ # @return [Boolean] true when the operation is successfully completed
175
+ #
176
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/7.5/docs-delete.html
177
+ # @todo update to allow serialized document as parameter
178
+ def delete(id:, type: nil, suffix: nil, **options)
179
+ delete!(id: id, type: type, suffix: suffix, **options)
180
+ rescue NotFoundError
181
+ false
182
+ end
183
+
184
+ # Gets the number of matches for a search query.
185
+ #
186
+ # UsersIndex::User.count # 999
187
+ # UsersIndex::User.count(body: { ... }) # 32
188
+ #
189
+ # @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
190
+ # @option [Hash] :body A query to restrict the results specified with the Query DSL (optional)
191
+ # @option [String, NilClass] :type The type of the document (Optional for elasticsearch >= 7)
192
+ # @option [String, nil] :suffix The index suffix. Defaults to the nil.
193
+ # @return [Integer] amount of documents found
194
+ #
195
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/7.5/search-count.html
196
+ def count(type: nil, suffix: nil, **options)
197
+ params = {
198
+ index: index_name(suffix: suffix),
199
+ }
200
+ params[:type] = type if document_type?
201
+ response = coerce_exception { client.count(**options, **params) }
202
+ response['count']
203
+ rescue NotFoundError
204
+ 0
205
+ end
206
+
207
+ # Check if a JSON document exists
208
+ #
209
+ # UsersIndex::User.elasticsearch.exist?(id: 1) # true
210
+ # UsersIndex::User.elasticsearch.exist?(id: 'missing') # false
211
+ #
212
+ # @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
213
+ # @option [String, Integer] :id The `_id` of the elasticsearch document
214
+ # @option [String, NilClass] :type The type of the document (Optional for elasticsearch >= 7)
215
+ # @option [String, nil] :suffix The index suffix. Defaults to the nil.
216
+ # @return [Boolean] true if the document exists
217
+ def exist?(id:, type: nil, suffix: nil, **options)
218
+ params = {
219
+ index: index_name(suffix: suffix),
220
+ id: id,
221
+ }
222
+ params[:type] = type if document_type?
223
+ coerce_exception { client.exists(**options, **params) }
224
+ end
225
+
226
+ # Retrieves the specified JSON document from an index.
227
+ #
228
+ # UsersIndex::User.find!(id: 1) # { '_id' => 1, ... }
229
+ # UsersIndex::User.find!(id: 'missing') # raise Esse::Backend::NotFoundError
230
+ #
231
+ # @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
232
+ # @option [String, Integer] :id The `_id` of the elasticsearch document
233
+ # @option [String, NilClass] :type The type of the document (Optional for elasticsearch >= 7)
234
+ # @option [String, nil] :suffix The index suffix. Defaults to the nil.
235
+ # @raise [Esse::Backend::NotFoundError] when the doc does not exist
236
+ # @return [Hash] The elasticsearch document.
237
+ #
238
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/7.5/docs-get.html
239
+ def find!(id:, type: nil, suffix: nil, **options)
240
+ params = {
241
+ index: index_name(suffix: suffix),
242
+ id: id,
243
+ }
244
+ params[:type] = type if document_type?
245
+ coerce_exception { client.get(**options, **params) }
246
+ end
247
+
248
+ # Retrieves the specified JSON document from an index.
249
+ #
250
+ # UsersIndex::User.find(id: 1) # { '_id' => 1, ... }
251
+ # UsersIndex::User.find(id: 'missing') # nil
252
+ #
253
+ # @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
254
+ # @option [String, Integer] :id The `_id` of the elasticsearch document
255
+ # @option [String, NilClass] :type The type of the document (Optional for elasticsearch >= 7)
256
+ # @option [String, nil] :suffix The index suffix. Defaults to the nil.
257
+ # @return [Hash, nil] The elasticsearch document
258
+ #
259
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/7.5/docs-get.html
260
+ def find(id:, suffix: nil, **options)
261
+ find!(id: id, suffix: suffix, **options)
262
+ rescue NotFoundError
263
+ nil
264
+ end
18
265
  end
19
266
 
20
267
  include InstanceMethods
@@ -6,13 +6,13 @@ module Esse
6
6
  module InstanceMethods
7
7
  # Checks the index existance. Returns true or false
8
8
  #
9
- # UsersIndex.elasticsearch.exist? #=> true
9
+ # UsersIndex.elasticsearch.index_exist? #=> true
10
10
  #
11
11
  # @param options [Hash] Options hash
12
12
  # @option options [String, nil] :suffix The index suffix. Defaults to the index_version.
13
13
  # Use nil if you want to check existence of the `index_name` index or alias.
14
- def exist?(suffix: index_version)
15
- client.indices.exists(index: index_name(suffix: suffix))
14
+ def index_exist?(suffix: index_version)
15
+ coerce_exception { client.indices.exists(index: index_name(suffix: suffix)) }
16
16
  end
17
17
  end
18
18
 
@@ -15,7 +15,7 @@ module Esse
15
15
  # @option options [Boolean] :ignore_unavailable Whether specified concrete indices should be ignored when
16
16
  # unavailable (missing, closed, etc)
17
17
  # @option options [Time] :timeout Explicit operation timeout
18
- # @raise [Elasticsearch::Transport::Transport::Errors::BadRequest, Elasticsearch::Transport::Transport::Errors::NotFound]
18
+ # @raise [Esse::Backend::ServerError]
19
19
  # in case of failure
20
20
  # @return [Hash] the elasticsearch response
21
21
  #
@@ -23,7 +23,7 @@ module Esse
23
23
  def open!(suffix: index_version, **options)
24
24
  Esse::Events.instrument('elasticsearch.open') do |payload|
25
25
  payload[:request] = attributes = options.merge(index: index_name(suffix: suffix))
26
- payload[:response] = client.indices.open(**attributes)
26
+ payload[:response] = coerce_exception { client.indices.open(**attributes) }
27
27
  end
28
28
  end
29
29
 
@@ -43,7 +43,7 @@ module Esse
43
43
  # @see https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-open-open.html
44
44
  def open(suffix: index_version, **options)
45
45
  open!(suffix: suffix, **options)
46
- rescue Elasticsearch::Transport::Transport::ServerError
46
+ rescue ServerError
47
47
  { 'errors' => true }
48
48
  end
49
49
  end
@@ -10,15 +10,17 @@ module Esse
10
10
  # @param :suffix [String, nil] :suffix The index suffix. Defaults to the index_version.
11
11
  # A uniq index name will be generated if one index already exist with the given alias.
12
12
  # @param options [Hash] Options hash
13
- # @raise [Elasticsearch::Transport::Transport::Errors::BadRequest, Elasticsearch::Transport::Transport::Errors::NotFound]
13
+ # @raise [Esse::Backend::ServerError]
14
14
  # in case of failure
15
15
  # @return [Hash] the elasticsearch response
16
16
  #
17
17
  # @see https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-refresh.html
18
18
  def refresh!(suffix: index_version, **options)
19
- client.indices.refresh(
20
- options.merge(index: index_name(suffix: suffix)),
21
- )
19
+ coerce_exception do
20
+ client.indices.refresh(
21
+ options.merge(index: index_name(suffix: suffix)),
22
+ )
23
+ end
22
24
  end
23
25
 
24
26
  # Performs the refresh operation in one or more indices.
@@ -32,7 +34,7 @@ module Esse
32
34
  # @see https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-refresh.html
33
35
  def refresh(suffix: index_version, **options)
34
36
  refresh!(suffix: suffix, **options)
35
- rescue Elasticsearch::Transport::Transport::ServerError
37
+ rescue ServerError
36
38
  { 'errors' => true }
37
39
  end
38
40
  end
@@ -9,18 +9,18 @@ module Esse
9
9
  # @option options [String, nil] :suffix The index suffix. Defaults to the index_version.
10
10
  # A uniq index name will be generated if one index already exist with the given alias.
11
11
  # @option options [Time] :timeout Explicit operation timeout
12
- # @raise [Elasticsearch::Transport::Transport::Errors::BadRequest, Elasticsearch::Transport::Transport::Errors::NotFound]
12
+ # @raise [Esse::Backend::ServerError]
13
13
  # in case of failure
14
14
  # @return [Hash] the elasticsearch response
15
15
  #
16
16
  # @see https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-open-close.html
17
- def reset_index!(suffix: index_version, **options)
17
+ def reset_index!(suffix: index_version, import: true, **options)
18
18
  existing = []
19
19
  suffix ||= Esse.timestamp
20
- suffix = Esse.timestamp while exist?(suffix: suffix).tap { |exist| existing << suffix if exist }
20
+ suffix = Esse.timestamp while index_exist?(suffix: suffix).tap { |exist| existing << suffix if exist }
21
21
 
22
22
  create_index!(**options, suffix: suffix, alias: false)
23
- import!(**options, suffix: suffix)
23
+ import!(**options, suffix: suffix) if import
24
24
  update_aliases!(suffix: suffix)
25
25
  existing.each { |_s| delete_index!(**options, suffix: suffix) }
26
26
  true
@@ -21,7 +21,7 @@ module Esse
21
21
  # with the same name across all types
22
22
  # @option options [Time] :timeout Explicit operation timeout
23
23
  # @option options [Boolean] :master_timeout Timeout for connection to master
24
- # @raise [Elasticsearch::Transport::Transport::Errors::BadRequest, Elasticsearch::Transport::Transport::Errors::NotFound]
24
+ # @raise [Esse::Backend::ServerError]
25
25
  # in case of failure
26
26
  # @return [Hash] the elasticsearch response
27
27
  #
@@ -33,7 +33,7 @@ module Esse
33
33
  body = body[type.to_s] || body[type.to_sym]
34
34
  end
35
35
  payload[:request] = opts = options.merge(index: index_name(suffix: suffix), body: body)
36
- payload[:response] = client.indices.put_mapping(**opts)
36
+ payload[:response] = coerce_exception { client.indices.put_mapping(**opts) }
37
37
  end
38
38
  end
39
39
 
@@ -59,7 +59,7 @@ module Esse
59
59
  # @see http://www.elasticsearch.org/guide/reference/api/admin-indices-put-mapping/
60
60
  def update_mapping(suffix: index_version, **options)
61
61
  update_mapping!(suffix: suffix, **options)
62
- rescue Elasticsearch::Transport::Transport::ServerError
62
+ rescue ServerError
63
63
  { 'errors' => true }
64
64
  end
65
65
 
@@ -76,7 +76,7 @@ module Esse
76
76
  # If set to `true` existing settings on an index remain unchanged, the default is `false`
77
77
  # @option options [Time] :master_timeout Specify timeout for connection to master
78
78
  # @option options [Boolean] :flat_settings Return settings in flat format (default: false)
79
- # @raise [Elasticsearch::Transport::Transport::Errors::BadRequest, Elasticsearch::Transport::Transport::Errors::NotFound]
79
+ # @raise [Esse::Backend::ServerError]
80
80
  # in case of failure
81
81
  # @return [Hash] the elasticsearch response
82
82
  #
@@ -93,7 +93,7 @@ module Esse
93
93
  # closed index might prevent the index to be opened correctly again.
94
94
  Esse::Events.instrument('elasticsearch.update_settings') do |payload|
95
95
  payload[:request] = opts = options.merge(index: index_name(suffix: suffix), body: { index: settings })
96
- payload[:response] = response = client.indices.put_settings(**opts)
96
+ payload[:response] = response = coerce_exception { client.indices.put_settings(**opts) }
97
97
  end
98
98
  end
99
99
 
@@ -104,7 +104,7 @@ module Esse
104
104
  begin
105
105
  Esse::Events.instrument('elasticsearch.update_settings') do |payload|
106
106
  payload[:request] = opts = options.merge(index: index_name(suffix: suffix), body: { analysis: analysis })
107
- payload[:response] = response = client.indices.put_settings(**opts)
107
+ payload[:response] = response = coerce_exception { client.indices.put_settings(**opts) }
108
108
  end
109
109
  ensure
110
110
  open!(suffix: suffix)
@@ -132,7 +132,7 @@ module Esse
132
132
  # @see http://www.elasticsearch.org/guide/reference/api/admin-indices-update-settings/
133
133
  def update_settings(suffix: index_version, **options)
134
134
  update_settings!(suffix: suffix, **options)
135
- rescue Elasticsearch::Transport::Transport::ServerError
135
+ rescue ServerError
136
136
  { 'errors' => true }
137
137
  end
138
138
  end
@@ -20,8 +20,10 @@ module Esse
20
20
 
21
21
  NAMING = %i[index_version].freeze
22
22
  DEFINITION = %i[settings_hash mappings_hash].freeze
23
+ DOCUMENTS = %i[each_serialized_batch].freeze
23
24
 
24
- def_delegators :@index, :type_hash, *(NAMING + DEFINITION)
25
+ def_delegators :@index, :index_name, :cluster, :repo_hash, :bulk_wait_interval, *(NAMING + DEFINITION + DOCUMENTS)
26
+ def_delegators :cluster, :document_type?, :client
25
27
 
26
28
  def initialize(index)
27
29
  @index = index
@@ -29,25 +31,25 @@ module Esse
29
31
 
30
32
  protected
31
33
 
32
- def index_name(suffix: nil)
33
- suffix = Hstring.new(suffix).underscore.presence
34
- return @index.index_name unless suffix
35
-
36
- [@index.index_name, suffix].join('_')
37
- end
38
-
39
34
  def build_real_index_name(suffix = nil)
40
35
  suffix = Hstring.new(suffix).underscore.presence || index_version || Esse.timestamp
41
36
 
42
37
  index_name(suffix: suffix)
43
38
  end
44
39
 
45
- def client
46
- cluster.client
47
- end
48
-
49
- def cluster
50
- @index.cluster
40
+ # Elasticsearch::Transport was renamed to Elastic::Transport in 8.0
41
+ # This lib should support both versions that's why we are wrapping up the transport
42
+ # errors to local errors.
43
+ def coerce_exception
44
+ yield
45
+ rescue => exception
46
+ name = Hstring.new(exception.class.name)
47
+ if /^(Elasticsearch|Elastic|OpenSearch)?::Transport::Transport::Errors/.match?(name.value) && \
48
+ (exception_class = ERRORS[name.demodulize.value])
49
+ raise exception_class.new(exception.message)
50
+ else
51
+ raise exception
52
+ end
51
53
  end
52
54
  end
53
55
  end