esse 0.0.5 → 0.1.1

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 (75) hide show
  1. checksums.yaml +4 -4
  2. data/exec/esse +3 -1
  3. data/lib/esse/backend/index/aliases.rb +7 -3
  4. data/lib/esse/backend/index/close.rb +6 -3
  5. data/lib/esse/backend/index/create.rb +19 -8
  6. data/lib/esse/backend/index/delete.rb +13 -8
  7. data/lib/esse/backend/index/documents.rb +2 -2
  8. data/lib/esse/backend/index/existance.rb +1 -1
  9. data/lib/esse/backend/index/open.rb +6 -3
  10. data/lib/esse/backend/index/refresh.rb +2 -2
  11. data/lib/esse/backend/index/reset.rb +2 -4
  12. data/lib/esse/backend/index/update.rb +37 -12
  13. data/lib/esse/backend/index.rb +5 -1
  14. data/lib/esse/backend/index_type/documents.rb +7 -7
  15. data/lib/esse/cli/event_listener.rb +87 -0
  16. data/lib/esse/cli/generate.rb +7 -3
  17. data/lib/esse/cli/index/base_operation.rb +76 -0
  18. data/lib/esse/cli/index/close.rb +26 -0
  19. data/lib/esse/cli/index/create.rb +26 -0
  20. data/lib/esse/cli/index/delete.rb +26 -0
  21. data/lib/esse/cli/index/open.rb +26 -0
  22. data/lib/esse/cli/index/reset.rb +26 -0
  23. data/lib/esse/cli/index/update_aliases.rb +32 -0
  24. data/lib/esse/cli/index/update_mapping.rb +33 -0
  25. data/lib/esse/cli/index/update_settings.rb +26 -0
  26. data/lib/esse/cli/index.rb +70 -2
  27. data/lib/esse/cli/templates/config.rb.erb +20 -0
  28. data/lib/esse/cli/templates/index.rb.erb +74 -9
  29. data/lib/esse/cli/templates/type_collection.rb.erb +41 -0
  30. data/lib/esse/cli/templates/{mappings.json → type_mappings.json} +0 -0
  31. data/lib/esse/cli/templates/{serializer.rb.erb → type_serializer.rb.erb} +9 -4
  32. data/lib/esse/cli.rb +75 -3
  33. data/lib/esse/cluster.rb +18 -2
  34. data/lib/esse/config.rb +39 -5
  35. data/lib/esse/core.rb +15 -33
  36. data/lib/esse/errors.rb +47 -0
  37. data/lib/esse/events/bus.rb +103 -0
  38. data/lib/esse/events/event.rb +64 -0
  39. data/lib/esse/events/publisher.rb +119 -0
  40. data/lib/esse/events.rb +49 -0
  41. data/lib/esse/index/backend.rb +2 -1
  42. data/lib/esse/index/base.rb +4 -6
  43. data/lib/esse/index/mappings.rb +2 -3
  44. data/lib/esse/index/settings.rb +7 -8
  45. data/lib/esse/index.rb +2 -1
  46. data/lib/esse/index_mapping.rb +2 -2
  47. data/lib/esse/index_setting.rb +8 -4
  48. data/lib/esse/index_type/actions.rb +2 -1
  49. data/lib/esse/index_type/backend.rb +2 -1
  50. data/lib/esse/index_type/mappings.rb +2 -2
  51. data/lib/esse/index_type.rb +6 -1
  52. data/lib/esse/logging.rb +19 -0
  53. data/lib/esse/object_document_mapper.rb +96 -0
  54. data/lib/esse/primitives/hash_utils.rb +29 -0
  55. data/lib/esse/primitives/hstring.rb +4 -3
  56. data/lib/esse/primitives/output.rb +64 -0
  57. data/lib/esse/primitives.rb +1 -0
  58. data/lib/esse/template_loader.rb +1 -1
  59. data/lib/esse/version.rb +1 -1
  60. data/lib/esse.rb +12 -3
  61. metadata +106 -22
  62. data/.gitignore +0 -12
  63. data/.rubocop.yml +0 -128
  64. data/.tool-versions +0 -1
  65. data/.yardopts +0 -2
  66. data/CHANGELOG.md +0 -0
  67. data/Gemfile +0 -7
  68. data/Gemfile.lock +0 -62
  69. data/LICENSE.txt +0 -21
  70. data/README.md +0 -52
  71. data/Rakefile +0 -4
  72. data/bin/console +0 -22
  73. data/bin/setup +0 -8
  74. data/esse.gemspec +0 -40
  75. data/lib/esse/index_type/serializer.rb +0 -87
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5c1da621c23c6e5ed445c51dc56d789e117874b545dd647e377ca69202d60a3c
4
- data.tar.gz: 60c5e597a2ed96b98af47cb90b7e29e4959b3d7dad0d842ea9858d2308a44e75
3
+ metadata.gz: 74a999f5083a3e258834ca27ac444c63e8f10e20940106f1415331d8a5e772b7
4
+ data.tar.gz: e7e2853b5fe1296795e6a5d306d12e2ac5c91e88cba671e2cd980ee1b1edfb2e
5
5
  SHA512:
6
- metadata.gz: c8e3de9e3f05a9f404eaf80ce334d3d9afb06f33040ef6240db1d3535ec657e32107c25df35c8eede19551c7e4fb162c92e0fb775baea4a743aab64768d3f1b0
7
- data.tar.gz: 5863ce26c2aaa3617fa665de6f85309866613f827a1b2a27490808aeb2c9a68e85b0fee7a0e59b0c3353140d5e7cc5062ced0e225728b9ea06048a4e4a2b556b
6
+ metadata.gz: 04a5efa492606d9385b07d8f076966b85bf825ffb49d37c9e35edd8fa5be5c4d283ac193097733f16583f920472aa83e2f1c05a00188649932c2c63ce6f14e53
7
+ data.tar.gz: 34b4426c3014edfcfe2c1320da019ba6b5c2566842baeb78e14e73df1df173f7a3a7298505b94128180a094aa953ee83dbf09a0e48791d65aa70f04f9e2c5fd9
data/exec/esse CHANGED
@@ -6,4 +6,6 @@ $LOAD_PATH.unshift File.expand_path('../lib', __dir__)
6
6
  require 'esse'
7
7
  require 'esse/cli'
8
8
 
9
- Esse::CLI.start(ARGV)
9
+ Esse::CLI.with_friendly_errors do
10
+ Esse::CLI.start(ARGV)
11
+ end
@@ -47,7 +47,11 @@ module Esse
47
47
  { add: {index: build_real_index_name(suffix), alias: index_name } }
48
48
  ],
49
49
  }
50
- client.indices.update_aliases(options)
50
+
51
+ Esse::Events.instrument('elasticsearch.update_aliases') do |payload|
52
+ payload[:request] = options
53
+ payload[:response] = client.indices.update_aliases(options)
54
+ end
51
55
  end
52
56
 
53
57
  # Replaces all existing aliases by the respective suffixed index from argument.
@@ -55,11 +59,11 @@ module Esse
55
59
  # @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
56
60
  # @option [String] :suffix The suffix of the index used for versioning.
57
61
  # @raise [Elasticsearch::Transport::Transport::Errors::NotFound] in case of failure
58
- # @return [Hash, false] the elasticsearch response, or false in case of failure
62
+ # @return [Hash] the elasticsearch response, or an hash with 'errors' as true in case of failure
59
63
  def update_aliases(suffix:, **options)
60
64
  update_aliases!(suffix: suffix, **options)
61
65
  rescue Elasticsearch::Transport::Transport::Errors::NotFound
62
- false
66
+ { 'errors' => true }
63
67
  end
64
68
  end
65
69
 
@@ -21,7 +21,10 @@ module Esse
21
21
  #
22
22
  # @see https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-open-close.html
23
23
  def close!(suffix: index_version, **options)
24
- client.indices.close(options.merge(index: index_name(suffix: suffix)))
24
+ Esse::Events.instrument('elasticsearch.close') do |payload|
25
+ payload[:request] = attributes = options.merge(index: index_name(suffix: suffix))
26
+ payload[:response] = client.indices.close(**attributes)
27
+ end
25
28
  end
26
29
 
27
30
  # Close an index (keep the data on disk, but deny operations with the index).
@@ -35,13 +38,13 @@ module Esse
35
38
  # @option options [Boolean] :ignore_unavailable Whether specified concrete indices should be ignored when
36
39
  # unavailable (missing, closed, etc)
37
40
  # @option options [Time] :timeout Explicit operation timeout
38
- # @return [Hash, false] the elasticsearch response, or false in case of failure
41
+ # @return [Hash] the elasticsearch response, or an hash with 'errors' as true in case of failure
39
42
  #
40
43
  # @see https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-open-close.html
41
44
  def close(suffix: index_version, **options)
42
45
  close!(suffix: suffix, **options)
43
46
  rescue Elasticsearch::Transport::Transport::ServerError
44
- false
47
+ { 'errors' => true }
45
48
  end
46
49
  end
47
50
 
@@ -10,43 +10,54 @@ module Esse
10
10
 
11
11
  # Creates index and applies mappings and settings.
12
12
  #
13
- # UsersIndex.backend.create_index # creates index named `<prefix_>users_<suffix|index_version|timestamp>`
13
+ # UsersIndex.elasticsearch.create_index # creates index named `<prefix_>users_<suffix|index_version|timestamp>`
14
14
  #
15
15
  # @param options [Hash] Options hash
16
16
  # @option options [Boolean] :alias Update `index_name` alias along with the new index
17
17
  # @option options [String] :suffix The index suffix. Defaults to the `IndexClass#index_version` or
18
18
  # `Esse.timestamp`. Suffixed index names might be used for zero-downtime mapping change.
19
- # @return [Hash, false] the elasticsearch response or false in case of unsuccessful creation.
19
+ # @return [Hash] the elasticsearch response, or an hash with 'errors' as true in case of failure
20
20
  #
21
21
  # @see http://www.elasticsearch.org/blog/changing-mapping-with-zero-downtime/
22
- def create_index(suffix: nil, **options)
22
+ def create_index(suffix: index_version, **options)
23
23
  create_index!(suffix: suffix, **options)
24
24
  rescue Elasticsearch::Transport::Transport::Errors::BadRequest
25
- false
25
+ { 'errors' => true }
26
26
  end
27
27
 
28
28
  # Creates index and applies mappings and settings.
29
29
  #
30
- # UsersIndex.backend.create_index! # creates index named `<prefix_>users_<suffix|index_version|timestamp>`
30
+ # UsersIndex.elasticsearch.create_index! # creates index named `<prefix_>users_<suffix|index_version|timestamp>`
31
31
  #
32
32
  # @param options [Hash] Options hash
33
33
  # @option options [Boolean] :alias Update `index_name` alias along with the new index
34
34
  # @option options [String] :suffix The index suffix. Defaults to the `IndexClass#index_version` or
35
35
  # `Esse.timestamp`. Suffixed index names might be used for zero-downtime mapping change.
36
+ # @option arguments [String] :wait_for_active_shards Set the number of active shards
37
+ # to wait for before the operation returns.
38
+ # @option arguments [Time] :timeout Explicit operation timeout
39
+ # @option arguments [Time] :master_timeout Specify timeout for connection to master
40
+ # @option arguments [Hash] :headers Custom HTTP headers
41
+ # @option arguments [Hash] :body The configuration for the index (`settings` and `mappings`)
36
42
  # @raise [Elasticsearch::Transport::Transport::Errors::NotFound] when index already exists
37
43
  # @return [Hash] the elasticsearch response
38
44
  #
39
45
  # @see http://www.elasticsearch.org/blog/changing-mapping-with-zero-downtime/
40
- def create_index!(suffix: nil, **options)
46
+ def create_index!(suffix: index_version, **options)
41
47
  options = DEFAULT_OPTIONS.merge(options)
42
48
  name = build_real_index_name(suffix)
43
49
  definition = [settings_hash, mappings_hash].reduce(&:merge)
44
50
 
45
- if options[:alias] && name != index_name
51
+ if options.delete(:alias) && name != index_name
46
52
  definition[:aliases] = { index_name => {} }
47
53
  end
48
54
 
49
- client.indices.create(index: name, body: definition)
55
+ Esse::Events.instrument('elasticsearch.create_index') do |payload|
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
59
+ response
60
+ end
50
61
  end
51
62
  end
52
63
 
@@ -6,25 +6,30 @@ module Esse
6
6
  module InstanceMethods
7
7
  # Deletes ES index
8
8
  #
9
- # UsersIndex.backend.delete_index! # deletes `<prefix_>users<_suffix|_index_version|_timestamp>` index
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
12
  # @raise [Elasticsearch::Transport::Transport::Errors::NotFound] when index does not exists
13
13
  # @return [Hash] elasticsearch response
14
- def delete_index!(suffix:)
15
- client.indices.delete(index: index_name(suffix: suffix))
14
+ def delete_index!(suffix: index_version, **options)
15
+ Esse::Events.instrument('elasticsearch.delete_index') do |payload|
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
19
+ response
20
+ end
16
21
  end
17
22
 
18
23
  # Deletes ES index
19
24
  #
20
- # UsersIndex.backend.delete_index # deletes `<prefix_>users<_suffix|_index_version|_timestamp>` index
25
+ # UsersIndex.elasticsearch.delete_index # deletes `<prefix_>users<_suffix|_index_version|_timestamp>` index
21
26
  #
22
27
  # @param suffix [String, nil] The index suffix Use nil if you want to delete the current index.
23
- # @return [Hash, false] elasticsearch response, of false in case of error.
24
- def delete_index(suffix: index_version)
25
- delete_index!(suffix: suffix)
28
+ # @return [Hash] the elasticsearch response, or an hash with 'errors' as true in case of failure
29
+ def delete_index(suffix: index_version, **options)
30
+ delete_index!(suffix: suffix, **options)
26
31
  rescue Elasticsearch::Transport::Transport::Errors::NotFound
27
- false
32
+ { 'errors' => true }
28
33
  end
29
34
  end
30
35
 
@@ -6,13 +6,13 @@ module Esse
6
6
  module InstanceMethods
7
7
  def import!(**options)
8
8
  type_hash.each_value do |type|
9
- type.backend.import!(**options)
9
+ type.elasticsearch.import!(**options)
10
10
  end
11
11
  end
12
12
 
13
13
  def import(**options)
14
14
  type_hash.each_value do |type|
15
- type.backend.import(**options)
15
+ type.elasticsearch.import(**options)
16
16
  end
17
17
  end
18
18
  end
@@ -6,7 +6,7 @@ module Esse
6
6
  module InstanceMethods
7
7
  # Checks the index existance. Returns true or false
8
8
  #
9
- # UsersIndex.backend.exist? #=> true
9
+ # UsersIndex.elasticsearch.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.
@@ -21,7 +21,10 @@ module Esse
21
21
  #
22
22
  # @see https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-open-open.html
23
23
  def open!(suffix: index_version, **options)
24
- client.indices.open(options.merge(index: index_name(suffix: suffix)))
24
+ Esse::Events.instrument('elasticsearch.open') do |payload|
25
+ payload[:request] = attributes = options.merge(index: index_name(suffix: suffix))
26
+ payload[:response] = client.indices.open(**attributes)
27
+ end
25
28
  end
26
29
 
27
30
  # Open a previously closed index
@@ -35,13 +38,13 @@ module Esse
35
38
  # @option options [Boolean] :ignore_unavailable Whether specified concrete indices should be ignored when
36
39
  # unavailable (missing, closed, etc)
37
40
  # @option options [Time] :timeout Explicit operation timeout
38
- # @return [Hash, false] the elasticsearch response, or false in case of failure
41
+ # @return [Hash] the elasticsearch response, or an hash with 'errors' as true in case of failure
39
42
  #
40
43
  # @see https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-open-open.html
41
44
  def open(suffix: index_version, **options)
42
45
  open!(suffix: suffix, **options)
43
46
  rescue Elasticsearch::Transport::Transport::ServerError
44
- false
47
+ { 'errors' => true }
45
48
  end
46
49
  end
47
50
 
@@ -27,13 +27,13 @@ module Esse
27
27
  # @param :suffix [String, nil] :suffix The index suffix. Defaults to the index_version.
28
28
  # A uniq index name will be generated if one index already exist with the given alias.
29
29
  # @param options [Hash] Options hash
30
- # @return [Hash, false] the elasticsearch response, or false in case of failure
30
+ # @return [Hash] the elasticsearch response, or an hash with 'errors' as true in case of failure
31
31
  #
32
32
  # @see https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-refresh.html
33
33
  def refresh(suffix: index_version, **options)
34
34
  refresh!(suffix: suffix, **options)
35
35
  rescue Elasticsearch::Transport::Transport::ServerError
36
- false
36
+ { 'errors' => true }
37
37
  end
38
38
  end
39
39
 
@@ -17,14 +17,12 @@ module Esse
17
17
  def reset_index!(suffix: index_version, **options)
18
18
  existing = []
19
19
  suffix ||= Esse.timestamp
20
- while exist?(suffix: suffix).tap { |exist| existing << suffix if exist }
21
- suffix = Esse.timestamp
22
- end
20
+ suffix = Esse.timestamp while exist?(suffix: suffix).tap { |exist| existing << suffix if exist }
23
21
 
24
22
  create_index!(suffix: suffix, **options)
25
23
  import!(suffix: suffix, **options)
26
24
  update_aliases!(suffix: suffix)
27
- existing.each { |s| delete_index!(suffix: suffix, **options) }
25
+ existing.each { |_s| delete_index!(suffix: suffix, **options) }
28
26
  true
29
27
  end
30
28
  end
@@ -27,7 +27,14 @@ module Esse
27
27
  #
28
28
  # @see http://www.elasticsearch.org/guide/reference/api/admin-indices-put-mapping/
29
29
  def update_mapping!(suffix: index_version, **options)
30
- client.indices.put_mapping(options.merge(index: index_name(suffix: suffix), body: mappings_hash.fetch(Esse::MAPPING_ROOT_KEY)))
30
+ Esse::Events.instrument('elasticsearch.update_mapping') do |payload|
31
+ body = mappings_hash.fetch(Esse::MAPPING_ROOT_KEY)
32
+ if (type = options[:type])
33
+ body = body[type.to_s] || body[type.to_sym]
34
+ end
35
+ payload[:request] = opts = options.merge(index: index_name(suffix: suffix), body: body)
36
+ payload[:response] = client.indices.put_mapping(**opts)
37
+ end
31
38
  end
32
39
 
33
40
  # Create or update a mapping
@@ -47,16 +54,15 @@ module Esse
47
54
  # with the same name across all types
48
55
  # @option options [Time] :timeout Explicit operation timeout
49
56
  # @option options [Boolean] :master_timeout Timeout for connection to master
50
- # @return [Hash, false] the elasticsearch response, or false in case of failure
57
+ # @return [Hash] the elasticsearch response, or an hash with 'errors' as true in case of failure
51
58
  #
52
59
  # @see http://www.elasticsearch.org/guide/reference/api/admin-indices-put-mapping/
53
60
  def update_mapping(suffix: index_version, **options)
54
61
  update_mapping!(suffix: suffix, **options)
55
62
  rescue Elasticsearch::Transport::Transport::ServerError
56
- false
63
+ { 'errors' => true }
57
64
  end
58
65
 
59
-
60
66
  # Closes the index for read/write operations, updates the index settings, and open it again
61
67
  #
62
68
  # @option options [String] :expand_wildcards Whether to expand wildcard expression to concrete indices that
@@ -78,12 +84,31 @@ module Esse
78
84
  def update_settings!(suffix: index_version, **options)
79
85
  response = nil
80
86
 
81
- close!(suffix: suffix)
82
- begin
83
- body = settings_hash(cluster_settings: false).fetch(Esse::SETTING_ROOT_KEY)
84
- response = client.indices.put_settings(options.merge(index: index_name(suffix: suffix), body: body))
85
- ensure
86
- open!(suffix: suffix)
87
+ settings = settings_hash.fetch(Esse::SETTING_ROOT_KEY).transform_keys(&:to_s)
88
+ settings.delete('number_of_shards') # Can't change number of shards for an index
89
+ analysis = settings.delete('analysis')
90
+
91
+ if settings.any?
92
+ # When changing the number of replicas the index needs to be open. Changing the number of replicas on a
93
+ # closed index might prevent the index to be opened correctly again.
94
+ Esse::Events.instrument('elasticsearch.update_settings') do |payload|
95
+ payload[:request] = opts = options.merge(index: index_name(suffix: suffix), body: { index: settings })
96
+ payload[:response] = response = client.indices.put_settings(**opts)
97
+ end
98
+ end
99
+
100
+ if analysis
101
+ # It is also possible to define new analyzers for the index. But it is required to close the
102
+ # index first and open it after the changes are made.
103
+ close!(suffix: suffix)
104
+ begin
105
+ Esse::Events.instrument('elasticsearch.update_settings') do |payload|
106
+ payload[:request] = opts = options.merge(index: index_name(suffix: suffix), body: { analysis: analysis })
107
+ payload[:response] = response = client.indices.put_settings(**opts)
108
+ end
109
+ ensure
110
+ open!(suffix: suffix)
111
+ end
87
112
  end
88
113
 
89
114
  response
@@ -102,13 +127,13 @@ module Esse
102
127
  # If set to `true` existing settings on an index remain unchanged, the default is `false`
103
128
  # @option options [Time] :master_timeout Specify timeout for connection to master
104
129
  # @option options [Boolean] :flat_settings Return settings in flat format (default: false)
105
- # @return [Hash, false] the elasticsearch response, false in case of failure
130
+ # @return [Hash] the elasticsearch response, or an hash with 'errors' as true in case of failure
106
131
  #
107
132
  # @see http://www.elasticsearch.org/guide/reference/api/admin-indices-update-settings/
108
133
  def update_settings(suffix: index_version, **options)
109
134
  update_settings!(suffix: suffix, **options)
110
135
  rescue Elasticsearch::Transport::Transport::ServerError
111
- false
136
+ { 'errors' => true }
112
137
  end
113
138
  end
114
139
 
@@ -43,7 +43,11 @@ module Esse
43
43
  end
44
44
 
45
45
  def client
46
- @index.cluster.client
46
+ cluster.client
47
+ end
48
+
49
+ def cluster
50
+ @index.cluster
47
51
  end
48
52
  end
49
53
  end
@@ -15,7 +15,7 @@ module Esse
15
15
  bulk(index: batch, suffix: suffix, **options)
16
16
  end
17
17
  end
18
- alias import! import
18
+ alias_method :import!, :import
19
19
 
20
20
  # Performs multiple indexing or delete operations in a single API call.
21
21
  # This reduces overhead and can greatly increase indexing speed.
@@ -53,7 +53,7 @@ module Esse
53
53
 
54
54
  client.bulk(definition)
55
55
  end
56
- alias bulk! bulk
56
+ alias_method :bulk!, :bulk
57
57
 
58
58
  # Adds a JSON document to the specified index and makes it searchable. If the document
59
59
  # already exists, updates the document and increments its version.
@@ -69,10 +69,10 @@ module Esse
69
69
  # @see https://www.elastic.co/guide/en/elasticsearch/reference/7.5/docs-index_.html
70
70
  def index(id:, body:, suffix: nil, **options)
71
71
  client.index(
72
- options.merge(index: index_name(suffix: suffix), type: type_name, id: id, body: body),
72
+ index: index_name(suffix: suffix), type: type_name, id: id, body: body, **options
73
73
  )
74
74
  end
75
- alias index! index
75
+ alias_method :index!, :index
76
76
 
77
77
  # Updates a document using the specified script.
78
78
  #
@@ -88,7 +88,7 @@ module Esse
88
88
  # @see https://www.elastic.co/guide/en/elasticsearch/reference/7.5/docs-update.html
89
89
  def update!(id:, body:, suffix: nil, **options)
90
90
  client.update(
91
- options.merge(index: index_name(suffix: suffix), type: type_name, id: id, body: body),
91
+ index: index_name(suffix: suffix), type: type_name, id: id, body: body, **options
92
92
  )
93
93
  end
94
94
 
@@ -100,13 +100,13 @@ module Esse
100
100
  # @option [String, Integer] :id The `_id` of the elasticsearch document
101
101
  # @option [Hash] :body the body of the request
102
102
  # @option [String, nil] :suffix The index suffix. Defaults to the nil.
103
- # @return [Hash, false] the elasticsearch response hash, or false in case of failure
103
+ # @return [Hash] the elasticsearch response, or an hash with 'errors' as true in case of failure
104
104
  #
105
105
  # @see https://www.elastic.co/guide/en/elasticsearch/reference/7.5/docs-update.html
106
106
  def update(id:, body:, suffix: nil, **options)
107
107
  update!(id: id, body: body, suffix: suffix, **options)
108
108
  rescue Elasticsearch::Transport::Transport::Errors::NotFound
109
- false
109
+ { 'errors' => true }
110
110
  end
111
111
 
112
112
  # Removes a JSON document from the specified index.
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../primitives'
4
+
5
+ module Esse
6
+ module CLI
7
+ module EventListener
8
+ extend Output
9
+
10
+ module_function
11
+
12
+ def [](event_name)
13
+ method_name = Hstring.new(event_name).underscore.to_sym
14
+ return unless respond_to?(method_name)
15
+
16
+ method(method_name)
17
+ end
18
+
19
+ def elasticsearch_create_index(event)
20
+ print_message '[%<runtime>s] Index %<name>s successfuly created',
21
+ name: colorize(event[:request][:index], :bold),
22
+ runtime: formatted_runtime(event[:runtime])
23
+ if (aliases = event.to_h.dig(:request, :body, :aliases)).is_a?(Hash)
24
+ print_message ' --> Aliases: %<aliases>s', aliases: aliases.keys.join(', ')
25
+ end
26
+ end
27
+
28
+ def elasticsearch_delete_index(event)
29
+ print_message '[%<runtime>s] Index %<name>s successfuly deleted',
30
+ name: colorize(event[:request][:index], :bold),
31
+ runtime: formatted_runtime(event[:runtime])
32
+ end
33
+
34
+ def elasticsearch_close(event)
35
+ print_message '[%<runtime>s] Index %<name>s successfuly closed',
36
+ name: colorize(event[:request][:index], :bold),
37
+ runtime: formatted_runtime(event[:runtime])
38
+ end
39
+
40
+ def elasticsearch_open(event)
41
+ print_message '[%<runtime>s] Index %<name>s successfuly opened',
42
+ name: colorize(event[:request][:index], :bold),
43
+ runtime: formatted_runtime(event[:runtime])
44
+ end
45
+
46
+ def elasticsearch_update_mapping(event)
47
+ if event[:request][:type]
48
+ print_message '[%<runtime>s] Index %<name>s mapping for type %<type>s successfuly updated',
49
+ name: colorize(event[:request][:index], :bold),
50
+ type: event[:request][:type],
51
+ runtime: formatted_runtime(event[:runtime])
52
+ else
53
+ print_message '[%<runtime>s] Index %<name>s successfuly updated mapping',
54
+ name: colorize(event[:request][:index], :bold),
55
+ runtime: formatted_runtime(event[:runtime])
56
+ end
57
+ end
58
+
59
+ def elasticsearch_update_settings(event)
60
+ print_message '[%<runtime>s] Index %<name>s successfuly updated settings',
61
+ name: colorize(event[:request][:index], :bold),
62
+ runtime: formatted_runtime(event[:runtime])
63
+ end
64
+
65
+ def elasticsearch_update_aliases(event)
66
+ actions = event[:request][:body][:actions]
67
+ removed = actions.select { |a| a.key?(:remove) }
68
+ added = actions.select { |a| a.key?(:add) }
69
+ print_message '[%<runtime>s] Successfuly updated aliases:',
70
+ runtime: formatted_runtime(event[:runtime])
71
+
72
+ removed.each do |action|
73
+ print_message '%<padding>s-> Index %<name>s removed from alias %<alias>s',
74
+ name: colorize(action[:remove][:index], :bold),
75
+ alias: colorize(action[:remove][:alias], :bold),
76
+ padding: runtime_padding(event[:runtime])
77
+ end
78
+ added.each do |action|
79
+ print_message '%<padding>s-> Index %<name>s added to alias %<alias>s',
80
+ name: colorize(action[:add][:index], :bold),
81
+ alias: colorize(action[:add][:alias], :bold),
82
+ padding: runtime_padding(event[:runtime])
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -7,7 +7,7 @@ require_relative 'base'
7
7
  module Esse
8
8
  module CLI
9
9
  class Generate < Base
10
- NAMESPACE_PATTERN_RE = %r{\:|/|\\}i.freeze
10
+ NAMESPACE_PATTERN_RE = %r{:|/|\\}i.freeze
11
11
 
12
12
  def self.source_root
13
13
  File.dirname(__FILE__)
@@ -30,13 +30,17 @@ module Esse
30
30
  @types.each do |type|
31
31
  @type = Hstring.new(type).underscore
32
32
  copy_file(
33
- 'templates/mappings.json',
33
+ 'templates/type_mappings.json',
34
34
  base_dir.join(index_name, 'templates', "#{@type}_mapping.json"),
35
35
  )
36
36
  template(
37
- 'templates/serializer.rb.erb',
37
+ 'templates/type_serializer.rb.erb',
38
38
  base_dir.join(index_name, 'serializers', "#{@type}_serializer.rb"),
39
39
  )
40
+ template(
41
+ 'templates/type_collection.rb.erb',
42
+ base_dir.join(index_name, 'collections', "#{@type}_collection.rb"),
43
+ )
40
44
  end
41
45
  end
42
46
 
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Esse
4
+ module CLI
5
+ class Index::BaseOperation
6
+ include Output
7
+
8
+ def initialize(indices:, **options)
9
+ @indices = Array(indices)
10
+ @options = options
11
+ end
12
+
13
+ # @abstract
14
+ # @void
15
+ def run
16
+ raise NotImplementedError
17
+ end
18
+
19
+ private
20
+
21
+ def validate_indices_option!
22
+ if @indices.empty?
23
+ raise InvalidOption.new(<<~END)
24
+ You must specify at least one index class.
25
+
26
+ Example:
27
+ > esse index create CityIndex
28
+ > esse index create CityIndex, StateIndex
29
+ END
30
+ end
31
+ end
32
+
33
+ def indices
34
+ eager_load_indices!
35
+ @indices.map do |class_name|
36
+ const_exist = begin
37
+ Kernel.const_defined?(class_name)
38
+ rescue NameError
39
+ false
40
+ end
41
+
42
+ raise InvalidOption.new(<<~END, class_name: class_name) unless const_exist
43
+ Unrecognized index class: %<class_name>p. Are you sure you specified the correct index class?
44
+ END
45
+
46
+ klass = Kernel.const_get(class_name)
47
+ unless klass < Esse::Index
48
+ path = Esse.config.indices_directory.join(Hstring.new(class_name).underscore.to_s)
49
+ raise InvalidOption.new(<<~END, class_name: class_name, path: path)
50
+ %<class_name>s must be a subclass of Esse::Index.
51
+
52
+ Example:
53
+ # %<path>s.rb
54
+ class %<class_name>s < Esse::Index
55
+ # the index definition goes here
56
+ end
57
+ END
58
+ end
59
+
60
+ klass
61
+ end
62
+ end
63
+
64
+ def eager_load_indices!
65
+ return false unless Esse.config.indices_directory.exist?
66
+
67
+ Esse.config.indices_directory.each_child do |path|
68
+ next unless path.extname == '.rb'
69
+
70
+ require(path.expand_path.to_s)
71
+ end
72
+ true
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base_operation'
4
+
5
+ module Esse
6
+ module CLI
7
+ class Index::Close < Index::BaseOperation
8
+ def run
9
+ validate_options!
10
+ indices.each do |index|
11
+ index.elasticsearch.close!(**options)
12
+ end
13
+ end
14
+
15
+ private
16
+
17
+ def options
18
+ @options.slice(*@options.keys - CLI_IGNORE_OPTS)
19
+ end
20
+
21
+ def validate_options!
22
+ validate_indices_option!
23
+ end
24
+ end
25
+ end
26
+ end