esse 0.0.5 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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