esse 0.2.0 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. checksums.yaml +4 -4
  2. data/lib/esse/cli/event_listener.rb +13 -0
  3. data/lib/esse/cli/generate.rb +53 -14
  4. data/lib/esse/cli/index/base_operation.rb +5 -13
  5. data/lib/esse/cli/index/close.rb +1 -1
  6. data/lib/esse/cli/index/create.rb +1 -1
  7. data/lib/esse/cli/index/delete.rb +1 -1
  8. data/lib/esse/cli/index/import.rb +6 -2
  9. data/lib/esse/cli/index/open.rb +1 -1
  10. data/lib/esse/cli/index/reset.rb +1 -1
  11. data/lib/esse/cli/index/update_aliases.rb +2 -2
  12. data/lib/esse/cli/index/update_mapping.rb +9 -5
  13. data/lib/esse/cli/index/update_settings.rb +1 -1
  14. data/lib/esse/cli/index.rb +11 -4
  15. data/lib/esse/cli/templates/collection.rb.erb +29 -0
  16. data/lib/esse/cli/templates/config.rb.erb +13 -3
  17. data/lib/esse/cli/templates/document.rb.erb +34 -0
  18. data/lib/esse/cli/templates/index.rb.erb +63 -114
  19. data/lib/esse/cli/templates/mappings.json +27 -0
  20. data/lib/esse/cli/templates/settings.json +62 -0
  21. data/lib/esse/cli.rb +5 -0
  22. data/lib/esse/cluster.rb +93 -12
  23. data/lib/esse/cluster_engine.rb +42 -0
  24. data/lib/esse/collection.rb +18 -0
  25. data/lib/esse/config.rb +14 -2
  26. data/lib/esse/core.rb +28 -7
  27. data/lib/esse/deprecations/cluster.rb +27 -0
  28. data/lib/esse/deprecations/deprecate.rb +29 -0
  29. data/lib/esse/deprecations/index.rb +37 -0
  30. data/lib/esse/deprecations/index_backend_delegator.rb +217 -0
  31. data/lib/esse/deprecations/repository.rb +34 -0
  32. data/lib/esse/deprecations/repository_backend_delegator.rb +110 -0
  33. data/lib/esse/deprecations/serializer.rb +14 -0
  34. data/lib/esse/deprecations.rb +7 -0
  35. data/lib/esse/document.rb +91 -0
  36. data/lib/esse/dynamic_template.rb +43 -0
  37. data/lib/esse/errors.rb +60 -2
  38. data/lib/esse/events/event.rb +4 -19
  39. data/lib/esse/events.rb +13 -2
  40. data/lib/esse/hash_document.rb +38 -0
  41. data/lib/esse/import/bulk.rb +106 -0
  42. data/lib/esse/import/request_body.rb +60 -0
  43. data/lib/esse/index/aliases.rb +50 -0
  44. data/lib/esse/index/attributes.rb +107 -0
  45. data/lib/esse/index/base.rb +17 -53
  46. data/lib/esse/index/documents.rb +236 -0
  47. data/lib/esse/index/indices.rb +171 -0
  48. data/lib/esse/index/inheritance.rb +30 -0
  49. data/lib/esse/index/mappings.rb +6 -19
  50. data/lib/esse/index/object_document_mapper.rb +36 -0
  51. data/lib/esse/index/plugins.rb +42 -0
  52. data/lib/esse/index/search.rb +27 -0
  53. data/lib/esse/index/settings.rb +2 -2
  54. data/lib/esse/index/type.rb +51 -11
  55. data/lib/esse/index.rb +14 -9
  56. data/lib/esse/index_mapping.rb +10 -2
  57. data/lib/esse/index_setting.rb +3 -1
  58. data/lib/esse/null_document.rb +35 -0
  59. data/lib/esse/plugins.rb +12 -0
  60. data/lib/esse/primitives/hstring.rb +1 -1
  61. data/lib/esse/{index_type → repository}/actions.rb +1 -1
  62. data/lib/esse/repository/documents.rb +13 -0
  63. data/lib/esse/repository/object_document_mapper.rb +157 -0
  64. data/lib/esse/repository.rb +17 -0
  65. data/lib/esse/search/query.rb +105 -0
  66. data/lib/esse/search/response.rb +46 -0
  67. data/lib/esse/template_loader.rb +1 -1
  68. data/lib/esse/transport/aliases.rb +36 -0
  69. data/lib/esse/transport/documents.rb +199 -0
  70. data/lib/esse/transport/health.rb +30 -0
  71. data/lib/esse/transport/indices.rb +192 -0
  72. data/lib/esse/transport/search.rb +48 -0
  73. data/lib/esse/transport.rb +44 -0
  74. data/lib/esse/version.rb +1 -1
  75. data/lib/esse.rb +20 -5
  76. metadata +55 -50
  77. data/lib/esse/backend/index/aliases.rb +0 -73
  78. data/lib/esse/backend/index/close.rb +0 -54
  79. data/lib/esse/backend/index/create.rb +0 -67
  80. data/lib/esse/backend/index/delete.rb +0 -39
  81. data/lib/esse/backend/index/documents.rb +0 -23
  82. data/lib/esse/backend/index/existance.rb +0 -22
  83. data/lib/esse/backend/index/open.rb +0 -54
  84. data/lib/esse/backend/index/refresh.rb +0 -43
  85. data/lib/esse/backend/index/reset.rb +0 -33
  86. data/lib/esse/backend/index/update.rb +0 -143
  87. data/lib/esse/backend/index.rb +0 -54
  88. data/lib/esse/backend/index_type/documents.rb +0 -214
  89. data/lib/esse/backend/index_type.rb +0 -37
  90. data/lib/esse/cli/templates/type_collection.rb.erb +0 -41
  91. data/lib/esse/cli/templates/type_mappings.json +0 -6
  92. data/lib/esse/cli/templates/type_serializer.rb.erb +0 -23
  93. data/lib/esse/index/backend.rb +0 -14
  94. data/lib/esse/index/naming.rb +0 -64
  95. data/lib/esse/index_type/backend.rb +0 -14
  96. data/lib/esse/index_type/mappings.rb +0 -42
  97. data/lib/esse/index_type.rb +0 -15
  98. data/lib/esse/object_document_mapper.rb +0 -110
@@ -0,0 +1,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