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
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Esse
4
+ class ClientProxy
5
+ module InstanceMethods
6
+ # Returns results matching a query.
7
+ def search(index:, **options)
8
+ definition = options.merge(
9
+ index: index,
10
+ )
11
+
12
+ Esse::Events.instrument('elasticsearch.search') do |payload|
13
+ payload[:request] = definition
14
+ payload[:response] = coerce_exception { client.search(definition) }
15
+ end
16
+ end
17
+
18
+ # Allows to retrieve a large numbers of results from a single search request.
19
+ #
20
+ # @param [Time] :scroll Specify how long a consistent view of the index should be maintained for scrolled search
21
+ # @param [Boolean] :rest_total_hits_as_int Indicates whether hits.total should be rendered as an integer or an object in the rest search response
22
+ # @param [Hash] :body The scroll ID
23
+ def scroll(scroll:, **definition)
24
+ unless definition[:body]
25
+ raise ArgumentError, 'scroll search must have a :body with the :scroll_id'
26
+ end
27
+ Esse::Events.instrument('elasticsearch.search') do |payload|
28
+ payload[:request] = definition
29
+ payload[:response] = coerce_exception { client.scroll(scroll: scroll, **definition) }
30
+ end
31
+ end
32
+
33
+ # Explicitly clears the search context for a scroll.
34
+ #
35
+ # @param [Hash] :body Body with the "scroll_id" (string or array of strings) Scroll IDs to clear.
36
+ # To clear all scroll IDs, use _all.
37
+ def clear_scroll(body:, **options)
38
+ coerce_exception { client.clear_scroll(body: body, **options) }
39
+ end
40
+ end
41
+
42
+ include InstanceMethods
43
+ end
44
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Esse
4
+ class ClientProxy
5
+ require_relative './client_proxy/search'
6
+
7
+ extend Forwardable
8
+
9
+ def_delegators :@cluster, :client
10
+
11
+ attr_reader :cluster
12
+
13
+ def initialize(cluster)
14
+ @cluster = cluster
15
+ end
16
+
17
+ # Elasticsearch::Transport was renamed to Elastic::Transport in 8.0
18
+ # This lib should support both versions that's why we are wrapping up the transport
19
+ # errors to local errors.
20
+ def coerce_exception
21
+ yield
22
+ rescue => exception
23
+ name = Hstring.new(exception.class.name)
24
+ if /^(Elasticsearch|Elastic|OpenSearch)?::Transport::Transport::Errors/.match?(name.value) && \
25
+ (exception_class = Esse::Backend::ERRORS[name.demodulize.value])
26
+ raise exception_class.new(exception.message)
27
+ else
28
+ raise exception
29
+ end
30
+ end
31
+ end
32
+ end
data/lib/esse/cluster.rb CHANGED
@@ -1,16 +1,23 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'cluster_engine'
4
+ require_relative 'client_proxy'
5
+
3
6
  module Esse
4
7
  class Cluster
5
- ATTRIBUTES = %i[index_prefix index_settings client wait_for_status].freeze
8
+ ATTRIBUTES = %i[index_prefix settings mappings client wait_for_status].freeze
6
9
  WAIT_FOR_STATUSES = %w[green yellow red].freeze
7
10
 
8
11
  # The index prefix. For example an index named UsersIndex.
9
12
  # With `index_prefix = 'app1'`. Final index/alias is: 'app1_users'
10
13
  attr_accessor :index_prefix
11
14
 
12
- # This settings will be passed through all indices during the mapping
13
- attr_accessor :index_settings
15
+ # This global settings will be passed through all indices
16
+ attr_accessor :settings
17
+
18
+ # This global mappings will be applied to all indices
19
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping.html
20
+ attr_accessor :mappings
14
21
 
15
22
  # if this option set, actions such as creating or deleting index,
16
23
  # importing data will wait for the status specified. Extremely useful
@@ -25,7 +32,8 @@ module Esse
25
32
 
26
33
  def initialize(id:, **options)
27
34
  @id = id.to_sym
28
- @index_settings = {}
35
+ @settings = {}
36
+ @mappings = {}
29
37
  assign(options)
30
38
  end
31
39
 
@@ -41,16 +49,28 @@ module Esse
41
49
  end
42
50
 
43
51
  def client
44
- @client ||= Elasticsearch::Client.new
52
+ @client ||= if defined? Elasticsearch::Client
53
+ Elasticsearch::Client.new
54
+ elsif defined? OpenSearch::Client
55
+ OpenSearch::Client.new
56
+ else
57
+ raise Esse::Error, <<~ERROR
58
+ Elasticsearch::Client or OpenSearch::Client is not defined.
59
+ Please install elasticsearch or opensearch-ruby gem.
60
+ ERROR
61
+ end
45
62
  end
46
63
 
47
- # Define the elasticsearch client connectio
48
- # @param es_client [Elasticsearch::Client, Hash] an instance of elasticsearch/api client or an hash
49
- # with the settings that will be used to initialize Elasticsearch::Client
64
+ # Define the elasticsearch client connection
65
+ # @param es_client [Elasticsearch::Client, OpenSearch::Client, Hash] an instance of elasticsearch/api client or an hash
66
+ # with the settings that will be used to initialize the Client
50
67
  def client=(es_client)
51
- @client = if es_client.is_a?(Hash)
68
+ @client = if es_client.is_a?(Hash) && defined?(Elasticsearch::Client)
52
69
  settings = es_client.each_with_object({}) { |(k, v), r| r[k.to_sym] = v }
53
70
  Elasticsearch::Client.new(settings)
71
+ elsif es_client.is_a?(Hash) && defined?(OpenSearch::Client)
72
+ settings = es_client.each_with_object({}) { |(k, v), r| r[k.to_sym] = v }
73
+ OpenSearch::Client.new(settings)
54
74
  else
55
75
  es_client
56
76
  end
@@ -70,5 +90,40 @@ module Esse
70
90
 
71
91
  client.cluster.health(wait_for_status: status.to_s)
72
92
  end
93
+
94
+ # @idea Change this to use the response from `GET /`
95
+ def document_type?
96
+ defined?(OpenSearch::VERSION) || \
97
+ (defined?(Elasticsearch::VERSION) && Elasticsearch::VERSION < '7')
98
+ end
99
+
100
+ def info
101
+ @info ||= begin
102
+ resp = client.info
103
+ {
104
+ distribution: (resp.dig('version', 'distribution') || 'elasticsearch'),
105
+ version: resp.dig('version', 'number'),
106
+ }
107
+ end
108
+ end
109
+
110
+ def engine
111
+ ClusterEngine.new(**info)
112
+ end
113
+
114
+ # Build a search query for the given indices
115
+ #
116
+ # @param indices [Array<Esse::Index, String>] The indices class or the index name
117
+ # @return [Esse::Search::Query] The search query instance
118
+ def search(*indices, **kwargs, &block)
119
+ Esse::Search::Query.new(api, *indices, **kwargs, &block)
120
+ end
121
+
122
+ # Return the proxy object used to perform low level actions on the elasticsearch cluster through the official api client
123
+ #
124
+ # @return [Esse::ClientProxy] The cluster api instance
125
+ def api
126
+ Esse::ClientProxy.new(self)
127
+ end
73
128
  end
74
129
  end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Esse
4
+ class ClusterEngine
5
+ OPENSEARCH_FORK_VERSION = '7.10.2'
6
+
7
+ attr_reader :version, :distribution
8
+
9
+ def initialize(distribution:, version:)
10
+ @distribution = distribution
11
+ @version = version
12
+ end
13
+
14
+ def engine_version
15
+ return @version unless opensearch?
16
+
17
+ OPENSEARCH_FORK_VERSION
18
+ end
19
+
20
+ def opensearch?
21
+ distribution == 'opensearch'
22
+ end
23
+
24
+ def elasticsearch?
25
+ distribution == 'elasticsearch'
26
+ end
27
+
28
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/7.17/removal-of-types.html
29
+ def mapping_single_type?
30
+ engine_version >= '6'
31
+ end
32
+
33
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/6.3/mapping.html
34
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/6.4/mapping.html
35
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/7.1/mapping.html
36
+ def mapping_default_type
37
+ return unless engine_version.to_i == 6
38
+
39
+ engine_version >= '6.4' ? :_doc : :doc
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Esse
4
+ class Collection
5
+ include Enumerable
6
+ attr_reader :options
7
+
8
+ def initialize(**options)
9
+ @options = options
10
+ end
11
+
12
+ # @yield [<Array, Hash>] A batch of documents to be serialized and indexed.
13
+ # @abstract Override this method to yield each chunk of documents with optional metadata
14
+ def each
15
+ raise NotImplementedError, 'Override this method to iterate over the collection'
16
+ end
17
+ end
18
+ end
data/lib/esse/config.rb CHANGED
@@ -9,10 +9,14 @@ module Esse
9
9
  # conf.cluster(:v1) do |cluster|
10
10
  # cluster.index_prefix = 'backend'
11
11
  # cluster.client = Elasticsearch::Client.new
12
- # cluster.index_settings = {
12
+ # cluster.settings = {
13
13
  # number_of_shards: 2,
14
14
  # number_of_replicas: 0
15
15
  # }
16
+ # cluster.mappings = {
17
+ # dynamic_templates: [...]
18
+ # properties: { ... }
19
+ # }
16
20
  # end
17
21
  # end
18
22
  #
@@ -36,13 +40,17 @@ module Esse
36
40
  # end
37
41
  class Config
38
42
  DEFAULT_CLUSTER_ID = :default
39
- ATTRIBUTES = %i[indices_directory].freeze
43
+ ATTRIBUTES = %i[indices_directory bulk_wait_interval].freeze
40
44
 
41
45
  # The location of the indices. Defaults to the `app/indices`
42
46
  attr_reader :indices_directory
43
47
 
48
+ # wait a given period between posting pages to give Elasticsearch time to catch up.
49
+ attr_reader :bulk_wait_interval
50
+
44
51
  def initialize
45
52
  self.indices_directory = 'app/indices'
53
+ self.bulk_wait_interval = 0.1
46
54
  @clusters = {}
47
55
  cluster(DEFAULT_CLUSTER_ID) # initialize the :default client
48
56
  end
@@ -66,6 +74,10 @@ module Esse
66
74
  @indices_directory = value.is_a?(Pathname) ? value : Pathname.new(value)
67
75
  end
68
76
 
77
+ def bulk_wait_interval=(value)
78
+ @bulk_wait_interval = value.to_f
79
+ end
80
+
69
81
  def load(arg)
70
82
  case arg
71
83
  when Hash
data/lib/esse/core.rb CHANGED
@@ -1,22 +1,28 @@
1
1
  # frozen_string_literal: true
2
2
 
3
-
4
- require 'multi_json'
5
- require 'elasticsearch'
6
-
7
3
  module Esse
8
4
  require_relative 'config'
9
5
  require_relative 'cluster'
10
6
  require_relative 'primitives'
11
- require_relative 'index_type'
7
+ require_relative 'collection'
8
+ require_relative 'serializer'
9
+ require_relative 'hash_document'
10
+ require_relative 'null_document'
11
+ require_relative 'repository'
12
12
  require_relative 'index_setting'
13
+ require_relative 'dynamic_template'
13
14
  require_relative 'index_mapping'
14
15
  require_relative 'template_loader'
16
+ require_relative 'import/request_body'
17
+ require_relative 'import/bulk'
15
18
  require_relative 'backend/index'
16
- require_relative 'backend/index_type'
19
+ require_relative 'backend/repository_backend'
17
20
  require_relative 'version'
18
21
  require_relative 'logging'
19
22
  require_relative 'events'
23
+ require_relative 'search/query'
24
+ require_relative 'search/response'
25
+ require_relative 'deprecations' # Should be last
20
26
  include Logging
21
27
 
22
28
  @single_threaded = false
@@ -68,4 +74,15 @@ module Esse
68
74
  end
69
75
  [id, modified]
70
76
  end
77
+
78
+ def self.eager_load_indices!
79
+ return false unless Esse.config.indices_directory.exist?
80
+
81
+ Dir[Esse.config.indices_directory.join('**/*_index.rb')].map { |path| Pathname.new(path) }.each do |path|
82
+ next unless path.extname == '.rb'
83
+
84
+ require(path.expand_path.to_s)
85
+ end
86
+ true
87
+ end
71
88
  end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Esse
4
+ class Cluster
5
+ extend Gem::Deprecate
6
+
7
+ def index_settings
8
+ settings
9
+ end
10
+ deprecate :index_settings, :settings, 2022, 10
11
+
12
+ def index_settings=(value)
13
+ self.settings = value
14
+ end
15
+ deprecate :index_settings=, :settings=, 2022, 10
16
+
17
+ def index_mappings
18
+ mappings
19
+ end
20
+ deprecate :index_mappings, :mappings, 2022, 10
21
+
22
+ def index_mappings=(value)
23
+ self.mappings = value
24
+ end
25
+ deprecate :index_mappings=, :mappings=, 2022, 10
26
+ end
27
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Esse
4
+ class Index
5
+ class << self
6
+ extend Gem::Deprecate
7
+
8
+ def define_type(name, *args, **kwargs, &block)
9
+ repository(name, *args, **kwargs, &block)
10
+ end
11
+ deprecate :define_type, :repository, 2022, 8
12
+
13
+ def type_hash
14
+ repo_hash
15
+ end
16
+ deprecate :type_hash, :repo_hash, 2022, 8
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Esse
4
+ class Repository
5
+ class << self
6
+ extend Gem::Deprecate
7
+
8
+ def type_name
9
+ document_type
10
+ end
11
+ deprecate :type_name, :document_type, 2022, 10
12
+
13
+ def mappings(*args, &block)
14
+ index.mappings(*args, &block)
15
+ end
16
+ deprecate :mappings, "Esse::Index.mappings", 2022, 10
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,3 @@
1
+ require_relative 'deprecations/index'
2
+ require_relative 'deprecations/cluster'
3
+ require_relative 'deprecations/repository'
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Esse
4
+ class DynamicTemplate
5
+ # @param [Array, Hash] value The list of dynamic_templates for mapping
6
+ def initialize(value)
7
+ @hash = normalize(value)
8
+ end
9
+
10
+ def merge!(value)
11
+ @hash = HashUtils.deep_merge(@hash, normalize(value))
12
+ end
13
+
14
+ def to_a
15
+ @hash.map do |name, value|
16
+ { name => value }
17
+ end
18
+ end
19
+
20
+ def any?
21
+ @hash.any?
22
+ end
23
+
24
+ def dup
25
+ self.class.new(@hash.dup)
26
+ end
27
+
28
+ private
29
+
30
+ def normalize(value)
31
+ case value
32
+ when Array
33
+ value.map { |v| normalize(v) }.reduce(&:merge)
34
+ when Hash
35
+ HashUtils.deep_transform_keys(value, &:to_sym)
36
+ end || {}
37
+ end
38
+ end
39
+ end
data/lib/esse/errors.rb CHANGED
@@ -4,6 +4,59 @@ module Esse
4
4
  class Error < StandardError
5
5
  end
6
6
 
7
+ # @todo Rename this
8
+ module Backend
9
+ class ServerError < ::Esse::Error; end
10
+
11
+ ES_TRANSPORT_ERRORS = {
12
+ 'MultipleChoices' => 'MultipleChoicesError', # 300
13
+ 'MovedPermanently' => 'MovedPermanentlyError', # 301
14
+ 'Found' => 'FoundError', # 302
15
+ 'SeeOther' => 'SeeOtherError', # 303
16
+ 'NotModified' => 'NotModifiedError', # 304
17
+ 'UseProxy' => 'UseProxyError', # 305
18
+ 'TemporaryRedirect' => 'TemporaryRedirectError', # 307
19
+ 'PermanentRedirect' => 'PermanentRedirectError', # 308
20
+ 'BadRequest' => 'BadRequestError', # 400
21
+ 'Unauthorized' => 'UnauthorizedError', # 401
22
+ 'PaymentRequired' => 'PaymentRequiredError', # 402
23
+ 'Forbidden' => 'ForbiddenError', # 403
24
+ 'NotFound' => 'NotFoundError', # 404
25
+ 'MethodNotAllowed' => 'MethodNotAllowedError', # 405
26
+ 'NotAcceptable' => 'NotAcceptableError', # 406
27
+ 'ProxyAuthenticationRequired' => 'ProxyAuthenticationRequiredError', # 407
28
+ 'RequestTimeout' => 'RequestTimeoutError', # 408
29
+ 'Conflict' => 'ConflictError', # 409
30
+ 'Gone' => 'GoneError', # 410
31
+ 'LengthRequired' => 'LengthRequiredError', # 411
32
+ 'PreconditionFailed' => 'PreconditionFailedError', # 412
33
+ 'RequestEntityTooLarge' => 'RequestEntityTooLargeError', # 413
34
+ 'RequestURITooLong' => 'RequestURITooLongError', # 414
35
+ 'UnsupportedMediaType' => 'UnsupportedMediaTypeError', # 415
36
+ 'RequestedRangeNotSatisfiable' => 'RequestedRangeNotSatisfiableError', # 416
37
+ 'ExpectationFailed' => 'ExpectationFailedError', # 417
38
+ 'ImATeapot' => 'ImATeapotError', # 418
39
+ 'TooManyConnectionsFromThisIP' => 'TooManyConnectionsFromThisIPError', # 421
40
+ 'UpgradeRequired' => 'UpgradeRequiredError', # 426
41
+ 'BlockedByWindowsParentalControls' => 'BlockedByWindowsParentalControlsError', # 450
42
+ 'RequestHeaderTooLarge' => 'RequestHeaderTooLargeError', # 494
43
+ 'HTTPToHTTPS' => 'HTTPToHTTPSError', # 497
44
+ 'ClientClosedRequest' => 'ClientClosedRequestError', # 499
45
+ 'InternalServerError' => 'InternalServerError', # 500
46
+ 'NotImplemented' => 'NotImplementedError', # 501
47
+ 'BadGateway' => 'BadGatewayError', # 502
48
+ 'ServiceUnavailable' => 'ServiceUnavailableError', # 503
49
+ 'GatewayTimeout' => 'GatewayTimeoutError', # 504
50
+ 'HTTPVersionNotSupported' => 'HTTPVersionNotSupportedError', # 505
51
+ 'VariantAlsoNegotiates' => 'VariantAlsoNegotiatesError', # 506
52
+ 'NotExtended' => 'NotExtendedError', # 510
53
+ }
54
+
55
+ ERRORS = ES_TRANSPORT_ERRORS.each_with_object({}) do |(transport_name, esse_name), memo|
56
+ memo[transport_name] = const_set esse_name, Class.new(ServerError)
57
+ end
58
+ end
59
+
7
60
  module Events
8
61
  class UnregisteredEventError < ::Esse::Error
9
62
  def initialize(object_or_event_id)
@@ -42,6 +95,4 @@ module Esse
42
95
  class InvalidOption < Error
43
96
  end
44
97
  end
45
-
46
- # Elasticsearch::Transport::Transport::Errors::NotFound
47
98
  end
@@ -3,6 +3,10 @@
3
3
  module Esse
4
4
  module Events
5
5
  class Event
6
+ extend Forwardable
7
+ def_delegators :@payload, :[], :fetch, :to_h, :key?
8
+ alias_method :to_hash, :to_h
9
+
6
10
  attr_reader :id
7
11
 
8
12
  # Initialize a new event
@@ -18,25 +22,6 @@ module Esse
18
22
  @payload = payload
19
23
  end
20
24
 
21
- # Get data from the payload
22
- #
23
- # @param [String,Symbol] name
24
- #
25
- # @api public
26
- def [](name)
27
- @payload.fetch(name)
28
- end
29
-
30
- # Coerce an event to a hash
31
- #
32
- # @return [Hash]
33
- #
34
- # @api public
35
- def to_h
36
- @payload
37
- end
38
- alias_method :to_hash, :to_h
39
-
40
25
  # Get or set a payload
41
26
  #
42
27
  # @overload
data/lib/esse/events.rb CHANGED
@@ -45,5 +45,8 @@ module Esse
45
45
  register_event 'elasticsearch.update_mapping'
46
46
  register_event 'elasticsearch.update_settings'
47
47
  register_event 'elasticsearch.update_aliases'
48
+ register_event 'elasticsearch.bulk'
49
+ register_event 'elasticsearch.search'
50
+ register_event 'elasticsearch.execute_search_query'
48
51
  end
49
52
  end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Esse
4
+ class HashDocument < Esse::Serializer
5
+ META_KEYS = %i[_id _type _routing routing].freeze
6
+
7
+ def initialize(object)
8
+ @object = object
9
+ @options = {}
10
+ end
11
+
12
+ # @return [String, Number] the document ID
13
+ def id
14
+ object['_id'] || object[:_id] || object['id'] || object[:id]
15
+ end
16
+
17
+ # @return [String, nil] the document type
18
+ def type
19
+ object['_type'] || object[:_type]
20
+ end
21
+
22
+ # @return [String, nil] the document routing
23
+ def routing
24
+ object['_routing'] || object[:_routing] || object['routing'] || object[:routing]
25
+ end
26
+
27
+ # @return [Hash] the document meta
28
+ def meta
29
+ {}
30
+ end
31
+
32
+ # @return [Hash] the document source
33
+ # @abstract Override this method to return the document source
34
+ def source
35
+ object.reject { |key, _| META_KEYS.include?(key.to_sym) }
36
+ end
37
+ end
38
+ end