esse 0.2.0 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
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,171 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Esse
4
+ class Index
5
+ module ClassMethods
6
+ CREATE_INDEX_RESERVED_KEYWORDS = {
7
+ alias: true,
8
+ }.freeze
9
+
10
+ # Creates index and applies mappings and settings.
11
+ #
12
+ # UsersIndex.create_index # creates index named `<cluster.index_prefix>users<index_suffix>`
13
+ #
14
+ # @param options [Hash] Options hash
15
+ # @option options [Boolean] :alias Update `index_name` alias along with the new index
16
+ # @option options [String] :suffix The index suffix. Defaults to the `IndexClass#index_suffix` or
17
+ # `Esse.timestamp`. Suffixed index names might be used for zero-downtime mapping change.
18
+ # @option arguments [String] :wait_for_active_shards Set the number of active shards
19
+ # to wait for before the operation returns.
20
+ # @option arguments [Time] :timeout Explicit operation timeout
21
+ # @option arguments [Time] :master_timeout Specify timeout for connection to master
22
+ # @option arguments [Hash] :headers Custom HTTP headers
23
+ # @option arguments [Hash] :body The configuration for the index (`settings` and `mappings`)
24
+ # @raise [Esse::Transport::NotFoundError] when index already exists
25
+ # @return [Hash] the elasticsearch response
26
+ #
27
+ # @see http://www.elasticsearch.org/blog/changing-mapping-with-zero-downtime/
28
+ # @see Esse::Transport#create_index
29
+ def create_index(suffix: nil, **options)
30
+ options = CREATE_INDEX_RESERVED_KEYWORDS.merge(options)
31
+ name = build_real_index_name(suffix)
32
+ definition = [settings_hash, mappings_hash].reduce(&:merge)
33
+
34
+ if options.delete(:alias) && name != index_name
35
+ definition[:aliases] = { index_name => {} }
36
+ end
37
+
38
+ cluster.api.create_index(index: name, body: definition, **options)
39
+ end
40
+
41
+ # Deletes, creates and imports data to the index. Performs zero-downtime index resetting.
42
+ #
43
+ # @option options [String, nil] :suffix The index suffix. Defaults to the index_suffix.
44
+ # A uniq index name will be generated if one index already exist with the given alias.
45
+ # @option options [Time] :timeout Explicit operation timeout
46
+ # @raise [Esse::Transport::ServerError]
47
+ # in case of failure
48
+ # @return [Hash] the elasticsearch response
49
+ #
50
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-open-close.html
51
+ def reset_index(suffix: index_suffix, import: true, reindex: false, **options)
52
+ cluster.throw_error_when_readonly!
53
+ existing = []
54
+ suffix ||= Esse.timestamp
55
+ suffix = Esse.timestamp while index_exist?(suffix: suffix).tap { |exist| existing << suffix if exist }
56
+
57
+ create_index(**options, suffix: suffix, alias: false)
58
+ if index_exist? && aliases.none?
59
+ cluster.api.delete_index(index: index_name)
60
+ end
61
+ if import
62
+ import(**options, suffix: suffix)
63
+ elsif reindex && (_from = indices_pointing_to_alias).any?
64
+ # @TODO: Reindex using the reindex API
65
+ end
66
+ update_aliases(suffix: suffix)
67
+ existing.each { |_s| delete_index!(**options, suffix: suffix) }
68
+ true
69
+ end
70
+
71
+ # Checks the index existance. Returns true or false
72
+ #
73
+ # UsersIndex.index_exist? #=> true
74
+ #
75
+ # @param options [Hash] Options hash
76
+ # @option options [String, nil] :suffix The index suffix
77
+ # @see Esse::Transport#index_exist?
78
+ def index_exist?(suffix: nil)
79
+ cluster.api.index_exist?(index: index_name(suffix: suffix))
80
+ end
81
+
82
+ # Deletes an existing index.
83
+ #
84
+ # UsersIndex.delete_index # deletes `<cluster.index_prefix>users<index_suffix>` index
85
+ #
86
+ # @param suffix [String, nil] The index suffix Use nil if you want to delete the current index.
87
+ # @raise [Esse::Transport::NotFoundError] when index does not exists
88
+ # @return [Hash] elasticsearch response
89
+ def delete_index(suffix: nil, **options)
90
+ index = suffix ? index_name(suffix: suffix) : indices_pointing_to_alias.first
91
+ index ||= index_name
92
+ cluster.api.delete_index(**options, index: index)
93
+ end
94
+
95
+ # Open a previously closed index
96
+ #
97
+ # @option options [String, nil] :suffix The index suffix
98
+ # @see Esse::Transport#open
99
+ def open(suffix: nil, **options)
100
+ cluster.api.open(index: index_name(suffix: suffix), **options)
101
+ end
102
+
103
+ # Close an index (keep the data on disk, but deny operations with the index).
104
+ #
105
+ # @option options [String, nil] :suffix The index suffix
106
+ # @see Esse::Transport#close
107
+ def close(suffix: nil, **options)
108
+ cluster.api.close(index: index_name(suffix: suffix), **options)
109
+ end
110
+
111
+ # Performs the refresh operation in one or more indices.
112
+ #
113
+ # @note The refresh operation can adversely affect indexing throughput when used too frequently.
114
+ # @param :suffix [String, nil] :suffix The index suffix
115
+ # @see Esse::Transport#refresh
116
+ def refresh(suffix: nil, **options)
117
+ cluster.api.refresh(index: index_name(suffix: suffix), **options)
118
+ end
119
+
120
+ # Updates index mappings
121
+ #
122
+ # @param :suffix [String, nil] :suffix The index suffix
123
+ # @see Esse::Transport#update_mapping
124
+ def update_mapping(suffix: nil, **options)
125
+ body = mappings_hash.fetch(Esse::MAPPING_ROOT_KEY)
126
+ if (type = options[:type])
127
+ # Elasticsearch <= 5.x should submit request with type both in the path and in the body
128
+ # Elasticsearch 6.x should submit request with type in the path but not in the body
129
+ # Elasticsearch >= 7.x does not support type in the mapping
130
+ body = body[type.to_s] || body[type.to_sym] || body
131
+ end
132
+ cluster.api.update_mapping(index: index_name(suffix: suffix), body: body, **options)
133
+ end
134
+
135
+ # Updates index settings
136
+ #
137
+ # @param :suffix [String, nil] :suffix The index suffix
138
+ # @see Esse::Transport#update_settings
139
+ def update_settings(suffix: nil, **options)
140
+ response = nil
141
+
142
+ settings = HashUtils.deep_transform_keys(settings_hash.fetch(Esse::SETTING_ROOT_KEY), &:to_s)
143
+ if options[:body]
144
+ settings = settings.merge(HashUtils.deep_transform_keys(options.delete(:body), &:to_s))
145
+ end
146
+ settings.delete('number_of_shards') # Can't change number of shards for an index
147
+ settings['index']&.delete('number_of_shards')
148
+ analysis = settings.delete('analysis')
149
+
150
+ if settings.any?
151
+ response = cluster.api.update_settings(index: index_name(suffix: suffix), body: settings, **options)
152
+ end
153
+
154
+ if analysis
155
+ # It is also possible to define new analyzers for the index. But it is required to close the
156
+ # index first and open it after the changes are made.
157
+ close(suffix: suffix)
158
+ begin
159
+ response = cluster.api.update_settings(index: index_name(suffix: suffix), body: { analysis: analysis }, **options)
160
+ ensure
161
+ self.open(suffix: suffix)
162
+ end
163
+ end
164
+
165
+ response
166
+ end
167
+ end
168
+
169
+ extend ClassMethods
170
+ end
171
+ end
@@ -11,6 +11,36 @@ module Esse
11
11
 
12
12
  !index_name?
13
13
  end
14
+
15
+ def inherited(subclass)
16
+ super
17
+
18
+ inherited_instance_variables.each do |variable_name, should_duplicate|
19
+ if (variable_value = instance_variable_get(variable_name)) && should_duplicate
20
+ value = case variable_value
21
+ when Hash
22
+ h = {}
23
+ variable_value.each { |k, v| h[k] = v.dup }
24
+ h
25
+ else
26
+ variable_value.dup
27
+ end
28
+ end
29
+ subclass.instance_variable_set(variable_name, value)
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def inherited_instance_variables
36
+ {
37
+ :@repo_hash => nil,
38
+ :@setting => nil,
39
+ :@mapping => nil,
40
+ :@cluster_id => :dup,
41
+ :@plugins => :dup,
42
+ }
43
+ end
14
44
  end
15
45
 
16
46
  extend ClassMethods
@@ -7,36 +7,23 @@
7
7
  module Esse
8
8
  class Index
9
9
  module ClassMethods
10
- # This is the actually content that will be passed through the ES api
11
- def mappings_hash
12
- { Esse::MAPPING_ROOT_KEY => (index_mapping || type_mapping) }
13
- end
14
-
15
10
  # This method is only used to define mapping
16
11
  def mappings(hash = {}, &block)
17
- @mapping = Esse::IndexMapping.new(body: hash, paths: template_dirs)
12
+ @mapping = Esse::IndexMapping.new(body: hash, paths: template_dirs, globals: -> { cluster.mappings })
18
13
  return unless block
19
14
 
20
15
  @mapping.define_singleton_method(:to_h, &block)
21
16
  end
22
17
 
23
- private
24
-
25
- def mapping
26
- @mapping ||= Esse::IndexMapping.new(paths: template_dirs)
27
- end
28
-
29
- def index_mapping
30
- return if mapping.empty?
31
-
18
+ def mappings_hash
32
19
  hash = mapping.body
33
- hash.key?(Esse::MAPPING_ROOT_KEY) ? hash[Esse::MAPPING_ROOT_KEY] : hash
20
+ { Esse::MAPPING_ROOT_KEY => (hash.key?(Esse::MAPPING_ROOT_KEY) ? hash[Esse::MAPPING_ROOT_KEY] : hash) }
34
21
  end
35
22
 
36
- def type_mapping
37
- return {} if type_hash.empty?
23
+ private
38
24
 
39
- type_hash.values.map(&:mappings_hash).reduce(&:merge)
25
+ def mapping
26
+ @mapping ||= Esse::IndexMapping.new(paths: template_dirs, globals: -> { cluster.mappings })
40
27
  end
41
28
  end
42
29
 
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Esse
4
+ class Index
5
+ module ObjectDocumentMapper
6
+ # Wrap collection data into serialized batches
7
+ #
8
+ # @param [String, NilClass] repo_name The repository identifier
9
+ # @param [Hash] kwargs The context
10
+ # @return [Enumerator] The enumerator
11
+ # @yield [Array, **context] serialized collection and the optional context from the collection
12
+ def each_serialized_batch(repo_name = nil, **kwargs, &block)
13
+ (repo_name ? [repo(repo_name)] : repo_hash.values).each do |repo|
14
+ repo.each_serialized_batch(**kwargs, &block)
15
+ end
16
+ end
17
+
18
+ # Wrap collection data into serialized documents
19
+ #
20
+ # Example:
21
+ # GeosIndex.documents(id: 1).first
22
+ #
23
+ # @param [String, NilClass] repo_name The repository identifier
24
+ # @return [Enumerator] All serialized entries
25
+ def documents(repo_name = nil, **kwargs)
26
+ Enumerator.new do |yielder|
27
+ each_serialized_batch(repo_name, **kwargs) do |documents, **_collection_kargs|
28
+ documents.each { |document| yielder.yield(document) }
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ extend ObjectDocumentMapper
35
+ end
36
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Esse
4
+ class Index
5
+ module ClassMethods
6
+ attr_reader :plugins
7
+
8
+ def plugin(plugin, **kwargs, &block)
9
+ mod = plugin.is_a?(Module) ? plugin : load_plugin_module(plugin)
10
+
11
+ unless @plugins.include?(mod)
12
+ @plugins << mod
13
+ mod.apply(self, **kwargs, &block) if mod.respond_to?(:apply)
14
+ extend(mod::IndexClassMethods) if mod.const_defined?(:IndexClassMethods, false)
15
+ if mod.const_defined?(:RepositoryClassMethods, false)
16
+ repo_hash.each_value.each { |repo| repository_plugin_extend(repo, mod::RepositoryClassMethods) }
17
+ end
18
+ end
19
+
20
+ mod.configure(self, **kwargs, &block) if mod.respond_to?(:configure)
21
+ end
22
+
23
+ private
24
+
25
+ def repository_plugin_extend(repo_class, mod)
26
+ return if repo_class.singleton_class.included_modules.include?(mod)
27
+
28
+ repo_class.extend(mod)
29
+ end
30
+
31
+ def load_plugin_module(name)
32
+ module_name = Hstring.new(name)
33
+ unless Esse::Plugins.const_defined?(module_name.camelize.to_s, false)
34
+ require "esse/plugins/#{module_name.underscore}"
35
+ end
36
+ Esse::Plugins.const_get(module_name.camelize.to_s)
37
+ end
38
+ end
39
+
40
+ extend ClassMethods
41
+ end
42
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Esse
4
+ class Index
5
+ module ClassMethods
6
+ # @param query_or_payload [String,Hash] The search request definition or query in the Lucene query string syntax
7
+ # @param kwargs [Hash] The options to pass to the search.
8
+ def search(*args, &block)
9
+ query_or_payload = args.shift
10
+ kwargs = args.last.is_a?(Hash) ? args.pop : {}
11
+
12
+ if query_or_payload.respond_to?(:to_hash) && (hash = query_or_payload.to_hash) && (hash.key?(:body) || hash.key?('body') || hash.key?(:q) || hash.key?('q'))
13
+ kwargs.merge!(hash.transform_keys(&:to_sym))
14
+ elsif query_or_payload.respond_to?(:to_hash)
15
+ kwargs[:body] = query_or_payload.to_hash
16
+ elsif query_or_payload.is_a?(String) && query_or_payload =~ /^\s*{/
17
+ kwargs[:body] = MultiJson.load(query_or_payload)
18
+ elsif query_or_payload.is_a?(String)
19
+ kwargs[:q] = query_or_payload
20
+ end
21
+ cluster.search(self, **kwargs, &block)
22
+ end
23
+ end
24
+
25
+ extend ClassMethods
26
+ end
27
+ end
@@ -28,7 +28,7 @@ module Esse
28
28
  # end
29
29
  # end
30
30
  def settings(hash = {}, &block)
31
- @setting = Esse::IndexSetting.new(body: hash, paths: template_dirs, globals: -> { cluster.index_settings })
31
+ @setting = Esse::IndexSetting.new(body: hash, paths: template_dirs, globals: -> { cluster.settings })
32
32
  return unless block
33
33
 
34
34
  @setting.define_singleton_method(:to_h, &block)
@@ -37,7 +37,7 @@ module Esse
37
37
  private
38
38
 
39
39
  def setting
40
- @setting ||= Esse::IndexSetting.new(paths: template_dirs, globals: -> { cluster.index_settings })
40
+ @setting ||= Esse::IndexSetting.new(paths: template_dirs, globals: -> { cluster.settings })
41
41
  end
42
42
  end
43
43
 
@@ -3,26 +3,66 @@
3
3
  module Esse
4
4
  class Index
5
5
  module ClassMethods
6
- attr_writer :type_hash
6
+ attr_writer :repo_hash
7
7
 
8
- def type_hash
9
- @type_hash ||= {}
8
+ def repo_hash
9
+ @repo_hash ||= {}
10
10
  end
11
11
 
12
- def define_type(type_name, &block)
13
- type_class = Class.new(Esse::IndexType)
12
+ def repo(name = nil)
13
+ if name.nil? && repo_hash.size == 1
14
+ name = repo_hash.keys.first
15
+ elsif name.nil? && repo_hash.size > 1
16
+ raise ArgumentError, "You can only call `repo' with a name when there is only one type defined."
17
+ end
18
+ name ||= DEFAULT_REPO_NAME
14
19
 
15
- const_set(Hstring.new(type_name).camelize.demodulize.to_s, type_class)
20
+ repo_hash.fetch(name.to_s)
21
+ rescue KeyError
22
+ raise ArgumentError, <<~MSG
23
+ No repo named "#{name}" found. Use the `repository' method to define one:
24
+
25
+ repository :#{name} do
26
+ # collection ...
27
+ # document ...
28
+ end
29
+ MSG
30
+ end
31
+
32
+ def repo?(name = nil)
33
+ return repo_hash.size > 0 if name.nil?
34
+
35
+ repo_hash.key?(name.to_s)
36
+ end
37
+
38
+ def repository(repo_name, *_args, **kwargs, &block)
39
+ repo_class = Class.new(Esse::Repository)
40
+ kwargs[:const] = true unless kwargs.key?(:const) # TODO Change this to false to avoid collisions with application classes
41
+ kwargs[:lazy_evaluate] ||= false
42
+
43
+ if kwargs[:const]
44
+ const_set(Hstring.new(repo_name).camelize.demodulize.to_s, repo_class)
45
+ end
16
46
 
17
47
  index = self
18
48
 
19
- type_class.send(:define_singleton_method, :index) { index }
20
- type_class.send(:define_singleton_method, :type_name) { type_name.to_s }
49
+ repo_class.send(:define_singleton_method, :index) { index }
50
+ repo_class.send(:define_singleton_method, :repo_name) { repo_name.to_s }
51
+
52
+ plugins.each do |mod|
53
+ next unless mod.const_defined?(:RepositoryClassMethods, false)
54
+
55
+ repository_plugin_extend(repo_class, mod::RepositoryClassMethods)
56
+ end
57
+
58
+ if kwargs[:lazy_evaluate]
21
59
 
22
- type_class.class_eval(&block) if block
60
+ elsif block
61
+ repo_class.class_eval(&block)
62
+ end
23
63
 
24
- self.type_hash = type_hash.merge(type_class.type_name => type_class)
25
- type_class
64
+ self.repo_hash = repo_hash.merge(repo_class.repo_name => repo_class)
65
+ repo_class
26
66
  end
27
67
  end
28
68
 
data/lib/esse/index.rb CHANGED
@@ -1,22 +1,27 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'object_document_mapper'
4
-
5
3
  module Esse
6
4
  class Index
5
+ @repo_hash = {}
6
+ @setting = {}
7
+ @mapping = {}
8
+ @plugins = []
9
+ @cluster_id = nil
10
+
11
+ require_relative 'index/plugins'
7
12
  require_relative 'index/base'
8
13
  require_relative 'index/inheritance'
9
14
  require_relative 'index/actions'
10
- require_relative 'index/naming'
15
+ require_relative 'index/attributes'
11
16
  require_relative 'index/type'
12
17
  require_relative 'index/settings'
13
18
  require_relative 'index/mappings'
14
19
  require_relative 'index/descendants'
15
- require_relative 'index/backend'
16
- extend ObjectDocumentMapper
17
-
18
- @cluster_id = nil
19
-
20
- def_Index(::Esse)
20
+ require_relative 'index/object_document_mapper'
21
+ # Methods that use the cluster API
22
+ require_relative 'index/aliases'
23
+ require_relative 'index/indices'
24
+ require_relative 'index/search'
25
+ require_relative 'index/documents'
21
26
  end
22
27
  end
@@ -4,10 +4,11 @@ module Esse
4
4
  class IndexMapping
5
5
  FILENAMES = %w[mapping mappings].freeze
6
6
 
7
- def initialize(body: {}, paths: [], filenames: FILENAMES)
7
+ def initialize(body: {}, paths: [], filenames: FILENAMES, globals: nil)
8
8
  @paths = Array(paths)
9
9
  @filenames = Array(filenames)
10
10
  @mappings = body
11
+ @globals = globals || -> { {} }
11
12
  end
12
13
 
13
14
  # This method will be overwrited when passing a block during the
@@ -19,7 +20,14 @@ module Esse
19
20
  end
20
21
 
21
22
  def body
22
- to_h
23
+ global = HashUtils.deep_transform_keys(@globals.call, &:to_sym)
24
+ local = HashUtils.deep_transform_keys(to_h.dup, &:to_sym)
25
+ dynamic_template = DynamicTemplate.new(global[:dynamic_templates])
26
+ dynamic_template.merge!(local.delete(:dynamic_templates))
27
+ if dynamic_template.any?
28
+ global[:dynamic_templates] = dynamic_template.to_a
29
+ end
30
+ HashUtils.deep_merge(global, local)
23
31
  end
24
32
 
25
33
  def empty?
@@ -30,7 +30,9 @@ module Esse
30
30
  end
31
31
 
32
32
  def body
33
- HashUtils.deep_merge(@globals.call, to_h)
33
+ global = HashUtils.deep_transform_keys(@globals.call, &:to_sym)
34
+ local = HashUtils.deep_transform_keys(to_h, &:to_sym)
35
+ HashUtils.deep_merge(global, local)
34
36
  end
35
37
 
36
38
  protected
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Esse
4
+ class NullDocument < Esse::Document
5
+ def initialize
6
+ @object = nil
7
+ @options = {}
8
+ end
9
+
10
+ # @return [NilClass] the document ID
11
+ def id
12
+ nil
13
+ end
14
+
15
+ # @return [NilClass] the document type
16
+ def type
17
+ nil
18
+ end
19
+
20
+ # @return [NilClass] the document routing
21
+ def routing
22
+ nil
23
+ end
24
+
25
+ # @return [NilClass] the document meta
26
+ def meta
27
+ {}
28
+ end
29
+
30
+ # @return [NilClass] the document source
31
+ def source
32
+ nil
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Esse
4
+ module Plugins
5
+ def self.inherited_instance_variables(mod, hash)
6
+ mod.send(:define_method, :inherited_instance_variables) do
7
+ super().merge!(hash)
8
+ end
9
+ mod.send(:private, :inherited_instance_variables)
10
+ end
11
+ end
12
+ end
@@ -9,7 +9,7 @@ module Esse
9
9
  class Hstring
10
10
  extend Forwardable
11
11
 
12
- def_delegators :@value, :==, :eq, :to_s, :to_sym, :inspect, :sub, :capitalize
12
+ def_delegators :@value, :==, :eq, :to_s, :to_sym, :inspect, :sub, :capitalize, :tr
13
13
  attr_reader :value
14
14
 
15
15
  def self.def_conventional(bang_method, conv_method = nil)
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Esse
4
- class IndexType
4
+ class Repository
5
5
  module ClassMethods
6
6
  def action(name, options = {}, &block)
7
7
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Esse
4
+ class Repository
5
+ module ClassMethods
6
+ def import(**kwargs)
7
+ index.import(repo_name, **kwargs)
8
+ end
9
+ end
10
+
11
+ extend ClassMethods
12
+ end
13
+ end