esse 0.2.0 → 0.2.2

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.
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