esse 0.2.0 → 0.2.3

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 (98) hide show
  1. checksums.yaml +4 -4
  2. data/lib/esse/cli/event_listener.rb +13 -0
  3. data/lib/esse/cli/generate.rb +53 -14
  4. data/lib/esse/cli/index/base_operation.rb +5 -13
  5. data/lib/esse/cli/index/close.rb +1 -1
  6. data/lib/esse/cli/index/create.rb +1 -1
  7. data/lib/esse/cli/index/delete.rb +1 -1
  8. data/lib/esse/cli/index/import.rb +6 -2
  9. data/lib/esse/cli/index/open.rb +1 -1
  10. data/lib/esse/cli/index/reset.rb +1 -1
  11. data/lib/esse/cli/index/update_aliases.rb +2 -2
  12. data/lib/esse/cli/index/update_mapping.rb +9 -5
  13. data/lib/esse/cli/index/update_settings.rb +1 -1
  14. data/lib/esse/cli/index.rb +11 -4
  15. data/lib/esse/cli/templates/collection.rb.erb +29 -0
  16. data/lib/esse/cli/templates/config.rb.erb +13 -3
  17. data/lib/esse/cli/templates/document.rb.erb +34 -0
  18. data/lib/esse/cli/templates/index.rb.erb +63 -114
  19. data/lib/esse/cli/templates/mappings.json +27 -0
  20. data/lib/esse/cli/templates/settings.json +62 -0
  21. data/lib/esse/cli.rb +5 -0
  22. data/lib/esse/cluster.rb +93 -12
  23. data/lib/esse/cluster_engine.rb +42 -0
  24. data/lib/esse/collection.rb +18 -0
  25. data/lib/esse/config.rb +14 -2
  26. data/lib/esse/core.rb +28 -7
  27. data/lib/esse/deprecations/cluster.rb +27 -0
  28. data/lib/esse/deprecations/deprecate.rb +29 -0
  29. data/lib/esse/deprecations/index.rb +37 -0
  30. data/lib/esse/deprecations/index_backend_delegator.rb +217 -0
  31. data/lib/esse/deprecations/repository.rb +34 -0
  32. data/lib/esse/deprecations/repository_backend_delegator.rb +110 -0
  33. data/lib/esse/deprecations/serializer.rb +14 -0
  34. data/lib/esse/deprecations.rb +7 -0
  35. data/lib/esse/document.rb +91 -0
  36. data/lib/esse/dynamic_template.rb +43 -0
  37. data/lib/esse/errors.rb +60 -2
  38. data/lib/esse/events/event.rb +4 -19
  39. data/lib/esse/events.rb +13 -2
  40. data/lib/esse/hash_document.rb +38 -0
  41. data/lib/esse/import/bulk.rb +106 -0
  42. data/lib/esse/import/request_body.rb +60 -0
  43. data/lib/esse/index/aliases.rb +50 -0
  44. data/lib/esse/index/attributes.rb +107 -0
  45. data/lib/esse/index/base.rb +17 -53
  46. data/lib/esse/index/documents.rb +236 -0
  47. data/lib/esse/index/indices.rb +171 -0
  48. data/lib/esse/index/inheritance.rb +30 -0
  49. data/lib/esse/index/mappings.rb +6 -19
  50. data/lib/esse/index/object_document_mapper.rb +36 -0
  51. data/lib/esse/index/plugins.rb +42 -0
  52. data/lib/esse/index/search.rb +27 -0
  53. data/lib/esse/index/settings.rb +2 -2
  54. data/lib/esse/index/type.rb +51 -11
  55. data/lib/esse/index.rb +14 -9
  56. data/lib/esse/index_mapping.rb +10 -2
  57. data/lib/esse/index_setting.rb +3 -1
  58. data/lib/esse/null_document.rb +35 -0
  59. data/lib/esse/plugins.rb +12 -0
  60. data/lib/esse/primitives/hstring.rb +1 -1
  61. data/lib/esse/{index_type → repository}/actions.rb +1 -1
  62. data/lib/esse/repository/documents.rb +13 -0
  63. data/lib/esse/repository/object_document_mapper.rb +157 -0
  64. data/lib/esse/repository.rb +17 -0
  65. data/lib/esse/search/query.rb +105 -0
  66. data/lib/esse/search/response.rb +46 -0
  67. data/lib/esse/template_loader.rb +1 -1
  68. data/lib/esse/transport/aliases.rb +36 -0
  69. data/lib/esse/transport/documents.rb +199 -0
  70. data/lib/esse/transport/health.rb +30 -0
  71. data/lib/esse/transport/indices.rb +192 -0
  72. data/lib/esse/transport/search.rb +48 -0
  73. data/lib/esse/transport.rb +44 -0
  74. data/lib/esse/version.rb +1 -1
  75. data/lib/esse.rb +20 -5
  76. metadata +55 -50
  77. data/lib/esse/backend/index/aliases.rb +0 -73
  78. data/lib/esse/backend/index/close.rb +0 -54
  79. data/lib/esse/backend/index/create.rb +0 -67
  80. data/lib/esse/backend/index/delete.rb +0 -39
  81. data/lib/esse/backend/index/documents.rb +0 -23
  82. data/lib/esse/backend/index/existance.rb +0 -22
  83. data/lib/esse/backend/index/open.rb +0 -54
  84. data/lib/esse/backend/index/refresh.rb +0 -43
  85. data/lib/esse/backend/index/reset.rb +0 -33
  86. data/lib/esse/backend/index/update.rb +0 -143
  87. data/lib/esse/backend/index.rb +0 -54
  88. data/lib/esse/backend/index_type/documents.rb +0 -214
  89. data/lib/esse/backend/index_type.rb +0 -37
  90. data/lib/esse/cli/templates/type_collection.rb.erb +0 -41
  91. data/lib/esse/cli/templates/type_mappings.json +0 -6
  92. data/lib/esse/cli/templates/type_serializer.rb.erb +0 -23
  93. data/lib/esse/index/backend.rb +0 -14
  94. data/lib/esse/index/naming.rb +0 -64
  95. data/lib/esse/index_type/backend.rb +0 -14
  96. data/lib/esse/index_type/mappings.rb +0 -42
  97. data/lib/esse/index_type.rb +0 -15
  98. data/lib/esse/object_document_mapper.rb +0 -110
@@ -0,0 +1,157 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Esse
4
+ # Delegates all the methods to the index ODM by prepending the type name.
5
+ #
6
+ # @see ObjectDocumentMapper
7
+ class Repository
8
+ module ClassMethods
9
+ # Convert ruby object to json. Arguments will be same of passed through the
10
+ # collection. It's allowed a block or a class with the `to_h` instance method.
11
+ # Example with block
12
+ # document do |model, **context|
13
+ # {
14
+ # id: model.id,
15
+ # admin: context[:is_admin],
16
+ # }
17
+ # end
18
+ # Example with document class
19
+ # document UserDocument
20
+ def document(klass = nil, &block)
21
+ if @document_proc
22
+ raise ArgumentError, format('Document for %p already defined', repo_name)
23
+ end
24
+
25
+ if block
26
+ @document_proc = ->(model, **kwargs) { coerce_to_document(block.call(model, **kwargs)) }
27
+ elsif klass.is_a?(Class) && klass <= Esse::Document
28
+ @document_proc = ->(model, **kwargs) { klass.new(model, **kwargs) }
29
+ elsif klass.is_a?(Class) && klass.instance_methods.include?(:to_h)
30
+ @document_proc = ->(model, **kwargs) { coerce_to_document(klass.new(model, **kwargs).to_h) }
31
+ elsif klass.is_a?(Class) && klass.instance_methods.include?(:as_json) # backward compatibility
32
+ @document_proc = ->(model, **kwargs) { coerce_to_document(klass.new(model, **kwargs).as_json) }
33
+ elsif klass.is_a?(Class) && klass.instance_methods.include?(:call)
34
+ @document_proc = ->(model, **kwargs) { coerce_to_document(klass.new(model, **kwargs).call) }
35
+ else
36
+ msg = format("%<arg>p is not a valid document. The document should inherit from Esse::Document or respond to `to_h'", arg: klass)
37
+ raise ArgumentError, msg
38
+ end
39
+ end
40
+
41
+ def coerce_to_document(value)
42
+ case value
43
+ when Esse::Document
44
+ value
45
+ when Hash
46
+ Esse::HashDocument.new(value)
47
+ when NilClass, FalseClass
48
+ Esse::NullDocument.new
49
+ else
50
+ raise ArgumentError, format('%<arg>p is not a valid document. The document should be a hash or an instance of Esse::Document', arg: value)
51
+ end
52
+ end
53
+
54
+ # Convert ruby object to json by using the document of the given document type.
55
+ # @param [Object] model The ruby object
56
+ # @param [Hash] kwargs The context
57
+ # @return [Esse::Document] The serialized document
58
+ def serialize(model, **kwargs)
59
+ if @document_proc.nil?
60
+ raise NotImplementedError, format('there is no %<t>p document defined for the %<k>p index', t: repo_name, k: index.to_s)
61
+ end
62
+
63
+ @document_proc.call(model, **kwargs)
64
+ end
65
+
66
+ # Used to define the source of data. A block is required. And its
67
+ # content should yield an array of each object that should be serialized.
68
+ # The list of arguments will be passed throught the document method.
69
+ #
70
+ # Example:
71
+ # collection AdminStore
72
+ # collection do |**conditions, &block|
73
+ # User.where(conditions).find_in_batches(batch_size: 5000) do |batch|
74
+ # block.call(batch, conditions)
75
+ # end
76
+ # end
77
+ #
78
+ # @param [String] name The identification of the collection.
79
+ # @param [Class] klass The class of the collection. (Optional when block is passed)
80
+ # @param [Proc] block The block that will be used to iterate over the collection. (Optional when using a class)
81
+ # @return [void]
82
+ def collection(collection_klass = nil, **_, &block)
83
+ if collection_klass.nil? && block.nil?
84
+ raise ArgumentError, 'a document type, followed by a collection class or block that stream the data ' \
85
+ 'is required to define the collection'
86
+ end
87
+
88
+ if block.nil? && collection_klass.is_a?(Class) && !collection_klass.include?(Enumerable)
89
+ msg = '%<arg>p is not a valid collection class.' \
90
+ ' Collections should implement the Enumerable interface.'
91
+ raise ArgumentError, format(msg, arg: collection_klass)
92
+ end
93
+
94
+ @collection_proc = collection_klass || block
95
+ end
96
+
97
+ # Used to fetch all batch of data defined on the collection model.
98
+ # Arguments can be anything. They will just be passed through the block.
99
+ # Useful when the collection depends on scope or any other conditions
100
+ #
101
+ # Example:
102
+ # each_batch(active: true) do |data, **_collection_opts|
103
+ # puts data.size
104
+ # end
105
+ #
106
+ # @todo Remove *args. It should only support keyword arguments
107
+ #
108
+ # @param [Hash] kwargs The context
109
+ # @param [Proc] block The block that will be used to iterate over the collection.
110
+ # @return [void]
111
+ def each_batch(*args, **kwargs, &block)
112
+ if @collection_proc.nil?
113
+ raise NotImplementedError, format('there is no %<t>p collection defined for the %<k>p index', t: repo_name, k: index.to_s)
114
+ end
115
+
116
+ case @collection_proc
117
+ when Class
118
+ @collection_proc.new(*args, **kwargs).each(&block)
119
+ else
120
+ @collection_proc.call(*args, **kwargs, &block)
121
+ end
122
+ rescue LocalJumpError
123
+ raise(SyntaxError, 'block must be explicitly declared in the collection definition')
124
+ end
125
+
126
+ # Wrap collection data into serialized batches
127
+ #
128
+ # @param [Hash] kwargs The context
129
+ # @return [Enumerator] The enumerator
130
+ # @yield [Array, **context] serialized collection and the optional context from the collection
131
+ def each_serialized_batch(**kwargs, &block)
132
+ each_batch(**kwargs) do |*args|
133
+ batch, collection_context = args
134
+ collection_context ||= {}
135
+ entries = [*batch].map { |entry| serialize(entry, **collection_context) }.compact
136
+ block.call(entries, **kwargs)
137
+ end
138
+ end
139
+
140
+ # Wrap collection data into serialized documents
141
+ #
142
+ # Example:
143
+ # GeosIndex.documents(id: 1).first
144
+ #
145
+ # @return [Enumerator] All serialized entries
146
+ def documents(**kwargs)
147
+ Enumerator.new do |yielder|
148
+ each_serialized_batch(**kwargs) do |docs, **_collection_kargs|
149
+ docs.each { |document| yielder.yield(document) }
150
+ end
151
+ end
152
+ end
153
+ end
154
+
155
+ extend ClassMethods
156
+ end
157
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Esse
4
+ # Type is actually deprecated. Elasticsearch today uses _doc instead of type
5
+ # And in upcoming release it will be totally removed.
6
+ # But I want to keep compatibility with old versions of es.
7
+ class Repository
8
+ class << self
9
+ # This methods will be defined using meta programming in the index respository definition
10
+ # @see Esse::Index::Type.repository
11
+ attr_reader :index
12
+ end
13
+ require_relative 'repository/actions'
14
+ require_relative 'repository/documents'
15
+ require_relative 'repository/object_document_mapper'
16
+ end
17
+ end
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Esse
4
+ module Search
5
+ class Query
6
+ attr_reader :transport, :definition
7
+
8
+ # @param transport [Esse::Transport] The client proxy to use for the query
9
+ # @param indices [<Array<Esse::Index, String>] The class of the index to search or the index name
10
+ # @param definition [Hash] The options to pass to the search.
11
+ def initialize(transport, *indices, suffix: nil, **definition, &_block)
12
+ @transport = transport
13
+ @definition = definition
14
+ @definition[:index] = indices.map do |index|
15
+ if index.is_a?(Class) && index < Esse::Index
16
+ index.index_name(suffix: suffix)
17
+ elsif index.is_a?(String) || index.is_a?(Symbol)
18
+ [index, suffix].compact.join('_')
19
+ else
20
+ raise ArgumentError, format('Invalid index type: %<index>p. It should be a Esse::Index class or a String index name', index: index)
21
+ end
22
+ end.join(',')
23
+ end
24
+
25
+ def response
26
+ @response ||= execute_search_query!
27
+ end
28
+
29
+ def results
30
+ return paginated_results if respond_to?(:paginated_results, true)
31
+
32
+ response.hits
33
+ end
34
+
35
+ def scroll_hits(batch_size: 1_000, scroll: '1m')
36
+ response = execute_search_query!(size: batch_size, scroll: scroll)
37
+ scroll_id = nil
38
+ fetched = 0
39
+ total = response.total
40
+
41
+ loop do
42
+ fetched += response.hits.size
43
+ yield(response.hits) if response.hits.any?
44
+ break if fetched >= total
45
+ scroll_id = response.raw_response['scroll_id'] || response.raw_response['_scroll_id']
46
+ break unless scroll_id
47
+ response = execute_scroll_query(scroll: scroll, scroll_id: scroll_id)
48
+ end
49
+ ensure
50
+ begin
51
+ transport.clear_scroll(body: {scroll_id: scroll_id}) if scroll_id
52
+ rescue Esse::Transport::NotFoundError
53
+ end
54
+ end
55
+
56
+ private
57
+
58
+ def execute_search_query!(**execution_options)
59
+ resp, err = nil
60
+ Esse::Events.instrument('elasticsearch.execute_search_query') do |payload|
61
+ payload[:query] = self
62
+ begin
63
+ resp = Response.new(self, transport.search(**definition, **execution_options))
64
+ rescue => e
65
+ err = e
66
+ end
67
+ payload[:error] = err if err
68
+ payload[:response] = resp
69
+ end
70
+ raise err if err
71
+
72
+ resp
73
+ end
74
+
75
+ def execute_scroll_query(scroll:, scroll_id:)
76
+ resp, err = nil
77
+ Esse::Events.instrument('elasticsearch.execute_search_query') do |payload|
78
+ payload[:query] = self
79
+ begin
80
+ resp = Response.new(self, transport.scroll(scroll: scroll, body: { scroll_id: scroll_id }))
81
+ rescue => e
82
+ err = e
83
+ end
84
+ payload[:error] = err if err
85
+ payload[:response] = resp
86
+ end
87
+ raise err if err
88
+
89
+ resp
90
+ end
91
+
92
+ def reset!
93
+ @response = nil
94
+ end
95
+
96
+ def raw_limit_value
97
+ definition.dig(:body, :size) || definition.dig(:body, 'size') || definition.dig(:size) || definition.dig('size')
98
+ end
99
+
100
+ def raw_offset_value
101
+ definition.dig(:body, :from) || definition.dig(:body, 'from') || definition.dig(:from) || definition.dig('from')
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Esse
4
+ module Search
5
+ class Response
6
+ include Enumerable
7
+ extend Forwardable
8
+
9
+ def_delegators :hits, :each, :size, :empty?
10
+ attr_reader :query, :raw_response, :options
11
+
12
+ # @param [Esse::Search::Query] query The search query
13
+ # @param [Hash] raw_response The raw response from Elasticsearch
14
+ # @param [Hash] options The options passed to the search
15
+ def initialize(query, raw_response, **options)
16
+ @query = query
17
+ @raw_response = raw_response
18
+ @options = options
19
+ end
20
+
21
+ def shards
22
+ raw_response['_shards']
23
+ end
24
+
25
+ def aggregations
26
+ raw_response['aggregations']
27
+ end
28
+
29
+ def suggestions
30
+ raw_response['suggest']
31
+ end
32
+
33
+ def hits
34
+ raw_response.dig('hits', 'hits') || []
35
+ end
36
+
37
+ def total
38
+ if raw_response.dig('hits', 'total').respond_to?(:keys)
39
+ raw_response.dig('hits', 'total', 'value')
40
+ else
41
+ raw_response.dig('hits', 'total')
42
+ end.to_i
43
+ end
44
+ end
45
+ end
46
+ end
@@ -24,7 +24,7 @@ module Esse
24
24
  path = nil
25
25
  @directories.each do |dir|
26
26
  patterns.find do |pattern|
27
- path = Dir[dir.join("#{pattern}.{#{@extensions.join(",")}}")].first
27
+ path = Dir[dir.join("#{pattern}.{#{@extensions.join(',')}}")].first
28
28
  break if path
29
29
  end
30
30
  break if path
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Esse
4
+ class Transport
5
+ module InstanceMethods
6
+ # Return a list of index aliases.
7
+ #
8
+ # @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
9
+ # @option [String] :index A comma-separated list of index names to filter aliases
10
+ # @option [String] :name A comma-separated list of alias names to return
11
+ # @raise [Esse::Transport::ServerError] in case of failure
12
+ #
13
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/7.5/indices-get-alias.html
14
+ def aliases(**options)
15
+ coerce_exception { client.indices.get_alias(**options) }
16
+ end
17
+
18
+ # Updates index aliases.
19
+ #
20
+ # @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
21
+ # @option [Hash] :body The definition of `actions` to perform
22
+ #
23
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-aliases.html
24
+ def update_aliases(body:, **options)
25
+ throw_error_when_readonly!
26
+
27
+ Esse::Events.instrument('elasticsearch.update_aliases') do |payload|
28
+ payload[:request] = options
29
+ payload[:response] = coerce_exception { client.indices.update_aliases(**options, body: body) }
30
+ end
31
+ end
32
+ end
33
+
34
+ include InstanceMethods
35
+ end
36
+ end
@@ -0,0 +1,199 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Esse
4
+ class Transport
5
+ module InstanceMethods
6
+ # Returns a document.
7
+ #
8
+ # @option [String] :id The document ID
9
+ # @option [String] :index The name of the index
10
+ # @option [Boolean] :force_synthetic_source Should this request force synthetic _source? Use this to test if the mapping supports synthetic _source and to get a sense of the worst case performance. Fetches with this enabled will be slower the enabling synthetic source natively in the index.
11
+ # @option [List] :stored_fields A comma-separated list of stored fields to return in the response
12
+ # @option [String] :preference Specify the node or shard the operation should be performed on (default: random)
13
+ # @option [Boolean] :realtime Specify whether to perform the operation in realtime or search mode
14
+ # @option [Boolean] :refresh Refresh the shard containing the document before performing the operation
15
+ # @option [String] :routing Specific routing value
16
+ # @option [List] :_source True or false to return the _source field or not, or a list of fields to return
17
+ # @option [List] :_source_excludes A list of fields to exclude from the returned _source field
18
+ # @option [List] :_source_includes A list of fields to extract and return from the _source field
19
+ # @option [Number] :version Explicit version number for concurrency control
20
+ # @option [String] :version_type Specific version type (options: internal, external, external_gte)
21
+ # @option [Hash] :headers Custom HTTP headers
22
+ #
23
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-get.html
24
+ #
25
+ def get(id:, index:, **options)
26
+ Esse::Events.instrument('elasticsearch.get') do |payload|
27
+ payload[:request] = opts = options.merge(id: id, index: index)
28
+ payload[:response] = coerce_exception { client.get(**opts) }
29
+ end
30
+ end
31
+
32
+ # Returns information about whether a document exists in an index.
33
+ #
34
+ # @option [String] :id The document ID
35
+ # @option [String] :index The name of the index
36
+ # @option [List] :stored_fields A comma-separated list of stored fields to return in the response
37
+ # @option [String] :preference Specify the node or shard the operation should be performed on (default: random)
38
+ # @option [Boolean] :realtime Specify whether to perform the operation in realtime or search mode
39
+ # @option [Boolean] :refresh Refresh the shard containing the document before performing the operation
40
+ # @option [String] :routing Specific routing value
41
+ # @option [List] :_source True or false to return the _source field or not, or a list of fields to return
42
+ # @option [List] :_source_excludes A list of fields to exclude from the returned _source field
43
+ # @option [List] :_source_includes A list of fields to extract and return from the _source field
44
+ # @option [Number] :version Explicit version number for concurrency control
45
+ # @option [String] :version_type Specific version type (options: internal, external, external_gte)
46
+ # @option [Hash] :headers Custom HTTP headers
47
+ #
48
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-get.html
49
+ #
50
+ def exist?(id:, index:, **options)
51
+ Esse::Events.instrument('elasticsearch.exist') do |payload|
52
+ payload[:request] = opts = options.merge(id: id, index: index)
53
+ payload[:response] = coerce_exception { client.exists(**opts) }
54
+ end
55
+ end
56
+
57
+ # Returns number of documents matching a query.
58
+ #
59
+ # @option [List] :index A comma-separated list of indices to restrict the results
60
+ # @option [Boolean] :ignore_unavailable Whether specified concrete indices should be ignored when unavailable (missing or closed)
61
+ # @option [Boolean] :ignore_throttled Whether specified concrete, expanded or aliased indices should be ignored when throttled
62
+ # @option [Boolean] :allow_no_indices Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified)
63
+ # @option [String] :expand_wildcards Whether to expand wildcard expression to concrete indices that are open, closed or both. (options: open, closed, hidden, none, all)
64
+ # @option [Number] :min_score Include only documents with a specific `_score` value in the result
65
+ # @option [String] :preference Specify the node or shard the operation should be performed on (default: random)
66
+ # @option [List] :routing A comma-separated list of specific routing values
67
+ # @option [String] :q Query in the Lucene query string syntax
68
+ # @option [String] :analyzer The analyzer to use for the query string
69
+ # @option [Boolean] :analyze_wildcard Specify whether wildcard and prefix queries should be analyzed (default: false)
70
+ # @option [String] :default_operator The default operator for query string query (AND or OR) (options: AND, OR)
71
+ # @option [String] :df The field to use as default where no field prefix is given in the query string
72
+ # @option [Boolean] :lenient Specify whether format-based query failures (such as providing text to a numeric field) should be ignored
73
+ # @option [Number] :terminate_after The maximum count for each shard, upon reaching which the query execution will terminate early
74
+ # @option [Hash] :headers Custom HTTP headers
75
+ # @option [Hash] :body A query to restrict the results specified with the Query DSL (optional)
76
+ #
77
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-count.html
78
+ def count(index:, **options)
79
+ Esse::Events.instrument('elasticsearch.count') do |payload|
80
+ payload[:request] = opts = options.merge(index: index)
81
+ payload[:response] = coerce_exception { client.count(**opts) }
82
+ end
83
+ end
84
+
85
+ # Removes a document from the index.
86
+ #
87
+ # @option arguments [String] :id The document ID
88
+ # @option arguments [String] :index The name of the index
89
+ # @option arguments [String] :wait_for_active_shards Sets the number of shard copies that must be active before proceeding with the delete operation. Defaults to 1, meaning the primary shard only. Set to `all` for all shard copies, otherwise set to any non-negative value less than or equal to the total number of copies for the shard (number of replicas + 1)
90
+ # @option arguments [String] :refresh If `true` then refresh the affected shards to make this operation visible to search, if `wait_for` then wait for a refresh to make this operation visible to search, if `false` (the default) then do nothing with refreshes. (options: true, false, wait_for)
91
+ # @option arguments [String] :routing Specific routing value
92
+ # @option arguments [Time] :timeout Explicit operation timeout
93
+ # @option arguments [Number] :if_seq_no only perform the delete operation if the last operation that has changed the document has the specified sequence number
94
+ # @option arguments [Number] :if_primary_term only perform the delete operation if the last operation that has changed the document has the specified primary term
95
+ # @option arguments [Number] :version Explicit version number for concurrency control
96
+ # @option arguments [String] :version_type Specific version type (options: internal, external, external_gte)
97
+ # @option arguments [Hash] :headers Custom HTTP headers
98
+ #
99
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-delete.html
100
+ def delete(id:, index:, **options)
101
+ throw_error_when_readonly!
102
+
103
+ Esse::Events.instrument('elasticsearch.delete') do |payload|
104
+ payload[:request] = opts = options.merge(id: id, index: index)
105
+ payload[:response] = coerce_exception { client.delete(**opts) }
106
+ end
107
+ end
108
+
109
+ # Updates a document with a script or partial document.
110
+ #
111
+ # @option [String] :id Document ID
112
+ # @option [String] :index The name of the index
113
+ # @option [String] :wait_for_active_shards Sets the number of shard copies that must be active before proceeding with the update operation. Defaults to 1, meaning the primary shard only. Set to `all` for all shard copies, otherwise set to any non-negative value less than or equal to the total number of copies for the shard (number of replicas + 1)
114
+ # @option [List] :_source True or false to return the _source field or not, or a list of fields to return
115
+ # @option [List] :_source_excludes A list of fields to exclude from the returned _source field
116
+ # @option [List] :_source_includes A list of fields to extract and return from the _source field
117
+ # @option [String] :lang The script language (default: painless)
118
+ # @option [String] :refresh If `true` then refresh the affected shards to make this operation visible to search, if `wait_for` then wait for a refresh to make this operation visible to search, if `false` (the default) then do nothing with refreshes. (options: true, false, wait_for)
119
+ # @option [Number] :retry_on_conflict Specify how many times should the operation be retried when a conflict occurs (default: 0)
120
+ # @option [String] :routing Specific routing value
121
+ # @option [Time] :timeout Explicit operation timeout
122
+ # @option [Number] :if_seq_no only perform the update operation if the last operation that has changed the document has the specified sequence number
123
+ # @option [Number] :if_primary_term only perform the update operation if the last operation that has changed the document has the specified primary term
124
+ # @option [Boolean] :require_alias When true, requires destination is an alias. Default is false
125
+ # @option [Hash] :headers Custom HTTP headers
126
+ # @option [Hash] :body The request definition requires either `script` or partial `doc` (*Required*)
127
+ #
128
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-update.html
129
+ #
130
+ def update(id:, index:, body:, **options)
131
+ throw_error_when_readonly!
132
+
133
+ Esse::Events.instrument('elasticsearch.update') do |payload|
134
+ payload[:request] = opts = options.merge(id: id, index: index, body: body)
135
+ payload[:response] = coerce_exception { client.update(**opts) }
136
+ end
137
+ end
138
+
139
+ # Creates or updates a document in an index.
140
+ #
141
+ # @option [String] :id Document ID
142
+ # @option [String] :index The name of the index
143
+ # @option [String] :wait_for_active_shards Sets the number of shard copies that must be active before proceeding with the index operation. Defaults to 1, meaning the primary shard only. Set to `all` for all shard copies, otherwise set to any non-negative value less than or equal to the total number of copies for the shard (number of replicas + 1)
144
+ # @option [String] :op_type Explicit operation type. Defaults to `index` for requests with an explicit document ID, and to `create`for requests without an explicit document ID (options: index, create)
145
+ # @option [String] :refresh If `true` then refresh the affected shards to make this operation visible to search, if `wait_for` then wait for a refresh to make this operation visible to search, if `false` (the default) then do nothing with refreshes. (options: true, false, wait_for)
146
+ # @option [String] :routing Specific routing value
147
+ # @option [Time] :timeout Explicit operation timeout
148
+ # @option [Number] :version Explicit version number for concurrency control
149
+ # @option [String] :version_type Specific version type (options: internal, external, external_gte)
150
+ # @option [Number] :if_seq_no only perform the index operation if the last operation that has changed the document has the specified sequence number
151
+ # @option [Number] :if_primary_term only perform the index operation if the last operation that has changed the document has the specified primary term
152
+ # @option [String] :pipeline The pipeline id to preprocess incoming documents with
153
+ # @option [Boolean] :require_alias When true, requires destination to be an alias. Default is false
154
+ # @option [Hash] :headers Custom HTTP headers
155
+ # @option [Hash] :body The document (*Required*)
156
+ #
157
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-index_.html
158
+ def index(id:, index:, body:, **options)
159
+ throw_error_when_readonly!
160
+
161
+ Esse::Events.instrument('elasticsearch.index') do |payload|
162
+ payload[:request] = opts = options.merge(id: id, index: index, body: body)
163
+ payload[:response] = coerce_exception { client.index(**opts) }
164
+ end
165
+ end
166
+
167
+ # Allows to perform multiple index/update/delete operations in a single request.
168
+ #
169
+ # @option arguments [String] :index Default index for items which don't provide one
170
+ # @option arguments [String] :wait_for_active_shards Sets the number of shard copies that must be active before proceeding with the bulk operation. Defaults to 1, meaning the primary shard only. Set to `all` for all shard copies, otherwise set to any non-negative value less than or equal to the total number of copies for the shard (number of replicas + 1)
171
+ # @option arguments [String] :refresh If `true` then refresh the affected shards to make this operation visible to search, if `wait_for` then wait for a refresh to make this operation visible to search, if `false` (the default) then do nothing with refreshes. (options: true, false, wait_for)
172
+ # @option arguments [String] :routing Specific routing value
173
+ # @option arguments [Time] :timeout Explicit operation timeout
174
+ # @option arguments [String] :type Default document type for items which don't provide one
175
+ # @option arguments [List] :_source True or false to return the _source field or not, or default list of fields to return, can be overridden on each sub-request
176
+ # @option arguments [List] :_source_excludes Default list of fields to exclude from the returned _source field, can be overridden on each sub-request
177
+ # @option arguments [List] :_source_includes Default list of fields to extract and return from the _source field, can be overridden on each sub-request
178
+ # @option arguments [String] :pipeline The pipeline id to preprocess incoming documents with
179
+ # @option arguments [Boolean] :require_alias Sets require_alias for all incoming documents. Defaults to unset (false)
180
+ # @option arguments [Hash] :headers Custom HTTP headers
181
+ # @option arguments [String|Array] :body The operation definition and data (action-data pairs), separated by newlines. Array of Strings, Header/Data pairs,
182
+ # or the conveniency "combined" format can be passed, refer to Elasticsearch::API::Utils.__bulkify documentation.
183
+ #
184
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html
185
+ def bulk(body:, **options)
186
+ throw_error_when_readonly!
187
+
188
+ Esse::Events.instrument('elasticsearch.bulk') do |payload|
189
+ payload[:request] = opts = options.merge(body: body)
190
+ payload[:response] = response = coerce_exception { client.bulk(**opts) }
191
+ yield(payload) if block_given? # Allow caller to add data to the payload of event
192
+ response
193
+ end
194
+ end
195
+ end
196
+
197
+ include InstanceMethods
198
+ end
199
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Esse
4
+ class Transport
5
+ module InstanceMethods
6
+ # Returns basic information about the health of the cluster.
7
+ #
8
+ # @option [List] :index Limit the information returned to a specific index
9
+ # @option [String] :expand_wildcards Whether to expand wildcard expression to concrete indices that are open, closed or both. (options: open, closed, hidden, none, all)
10
+ # @option [String] :level Specify the level of detail for returned information (options: cluster, indices, shards)
11
+ # @option [Boolean] :local Return local information, do not retrieve the state from master node (default: false)
12
+ # @option [Time] :master_timeout Explicit operation timeout for connection to master node
13
+ # @option [Time] :timeout Explicit operation timeout
14
+ # @option [String] :wait_for_active_shards Wait until the specified number of shards is active
15
+ # @option [String] :wait_for_nodes Wait until the specified number of nodes is available
16
+ # @option [String] :wait_for_events Wait until all currently queued events with the given priority are processed (options: immediate, urgent, high, normal, low, languid)
17
+ # @option [Boolean] :wait_for_no_relocating_shards Whether to wait until there are no relocating shards in the cluster
18
+ # @option [Boolean] :wait_for_no_initializing_shards Whether to wait until there are no initializing shards in the cluster
19
+ # @option [String] :wait_for_status Wait until cluster is in a specific state (options: green, yellow, red)
20
+ # @option [Hash] :headers Custom HTTP headers
21
+ #
22
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/cluster-health.html
23
+ def health(**options)
24
+ coerce_exception { client.cluster.health(**options) }
25
+ end
26
+ end
27
+
28
+ include InstanceMethods
29
+ end
30
+ end