esse 0.2.0 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/esse/cli/event_listener.rb +13 -0
- data/lib/esse/cli/generate.rb +53 -14
- data/lib/esse/cli/index/base_operation.rb +5 -13
- data/lib/esse/cli/index/close.rb +1 -1
- data/lib/esse/cli/index/create.rb +1 -1
- data/lib/esse/cli/index/delete.rb +1 -1
- data/lib/esse/cli/index/import.rb +6 -2
- data/lib/esse/cli/index/open.rb +1 -1
- data/lib/esse/cli/index/reset.rb +1 -1
- data/lib/esse/cli/index/update_aliases.rb +2 -2
- data/lib/esse/cli/index/update_mapping.rb +9 -5
- data/lib/esse/cli/index/update_settings.rb +1 -1
- data/lib/esse/cli/index.rb +11 -4
- data/lib/esse/cli/templates/collection.rb.erb +29 -0
- data/lib/esse/cli/templates/config.rb.erb +13 -3
- data/lib/esse/cli/templates/document.rb.erb +34 -0
- data/lib/esse/cli/templates/index.rb.erb +63 -114
- data/lib/esse/cli/templates/mappings.json +27 -0
- data/lib/esse/cli/templates/settings.json +62 -0
- data/lib/esse/cli.rb +5 -0
- data/lib/esse/cluster.rb +93 -12
- data/lib/esse/cluster_engine.rb +42 -0
- data/lib/esse/collection.rb +18 -0
- data/lib/esse/config.rb +14 -2
- data/lib/esse/core.rb +28 -7
- data/lib/esse/deprecations/cluster.rb +27 -0
- data/lib/esse/deprecations/deprecate.rb +29 -0
- data/lib/esse/deprecations/index.rb +37 -0
- data/lib/esse/deprecations/index_backend_delegator.rb +217 -0
- data/lib/esse/deprecations/repository.rb +34 -0
- data/lib/esse/deprecations/repository_backend_delegator.rb +110 -0
- data/lib/esse/deprecations/serializer.rb +14 -0
- data/lib/esse/deprecations.rb +7 -0
- data/lib/esse/document.rb +91 -0
- data/lib/esse/dynamic_template.rb +43 -0
- data/lib/esse/errors.rb +60 -2
- data/lib/esse/events/event.rb +4 -19
- data/lib/esse/events.rb +13 -2
- data/lib/esse/hash_document.rb +38 -0
- data/lib/esse/import/bulk.rb +106 -0
- data/lib/esse/import/request_body.rb +60 -0
- data/lib/esse/index/aliases.rb +50 -0
- data/lib/esse/index/attributes.rb +107 -0
- data/lib/esse/index/base.rb +17 -53
- data/lib/esse/index/documents.rb +236 -0
- data/lib/esse/index/indices.rb +171 -0
- data/lib/esse/index/inheritance.rb +30 -0
- data/lib/esse/index/mappings.rb +6 -19
- data/lib/esse/index/object_document_mapper.rb +36 -0
- data/lib/esse/index/plugins.rb +42 -0
- data/lib/esse/index/search.rb +27 -0
- data/lib/esse/index/settings.rb +2 -2
- data/lib/esse/index/type.rb +51 -11
- data/lib/esse/index.rb +14 -9
- data/lib/esse/index_mapping.rb +10 -2
- data/lib/esse/index_setting.rb +3 -1
- data/lib/esse/null_document.rb +35 -0
- data/lib/esse/plugins.rb +12 -0
- data/lib/esse/primitives/hstring.rb +1 -1
- data/lib/esse/{index_type → repository}/actions.rb +1 -1
- data/lib/esse/repository/documents.rb +13 -0
- data/lib/esse/repository/object_document_mapper.rb +157 -0
- data/lib/esse/repository.rb +17 -0
- data/lib/esse/search/query.rb +105 -0
- data/lib/esse/search/response.rb +46 -0
- data/lib/esse/template_loader.rb +1 -1
- data/lib/esse/transport/aliases.rb +36 -0
- data/lib/esse/transport/documents.rb +199 -0
- data/lib/esse/transport/health.rb +30 -0
- data/lib/esse/transport/indices.rb +192 -0
- data/lib/esse/transport/search.rb +48 -0
- data/lib/esse/transport.rb +44 -0
- data/lib/esse/version.rb +1 -1
- data/lib/esse.rb +20 -5
- metadata +55 -50
- data/lib/esse/backend/index/aliases.rb +0 -73
- data/lib/esse/backend/index/close.rb +0 -54
- data/lib/esse/backend/index/create.rb +0 -67
- data/lib/esse/backend/index/delete.rb +0 -39
- data/lib/esse/backend/index/documents.rb +0 -23
- data/lib/esse/backend/index/existance.rb +0 -22
- data/lib/esse/backend/index/open.rb +0 -54
- data/lib/esse/backend/index/refresh.rb +0 -43
- data/lib/esse/backend/index/reset.rb +0 -33
- data/lib/esse/backend/index/update.rb +0 -143
- data/lib/esse/backend/index.rb +0 -54
- data/lib/esse/backend/index_type/documents.rb +0 -214
- data/lib/esse/backend/index_type.rb +0 -37
- data/lib/esse/cli/templates/type_collection.rb.erb +0 -41
- data/lib/esse/cli/templates/type_mappings.json +0 -6
- data/lib/esse/cli/templates/type_serializer.rb.erb +0 -23
- data/lib/esse/index/backend.rb +0 -14
- data/lib/esse/index/naming.rb +0 -64
- data/lib/esse/index_type/backend.rb +0 -14
- data/lib/esse/index_type/mappings.rb +0 -42
- data/lib/esse/index_type.rb +0 -15
- 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
|
data/lib/esse/index/mappings.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
37
|
-
return {} if type_hash.empty?
|
23
|
+
private
|
38
24
|
|
39
|
-
|
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
|
data/lib/esse/index/settings.rb
CHANGED
@@ -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.
|
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.
|
40
|
+
@setting ||= Esse::IndexSetting.new(paths: template_dirs, globals: -> { cluster.settings })
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
data/lib/esse/index/type.rb
CHANGED
@@ -3,26 +3,66 @@
|
|
3
3
|
module Esse
|
4
4
|
class Index
|
5
5
|
module ClassMethods
|
6
|
-
attr_writer :
|
6
|
+
attr_writer :repo_hash
|
7
7
|
|
8
|
-
def
|
9
|
-
@
|
8
|
+
def repo_hash
|
9
|
+
@repo_hash ||= {}
|
10
10
|
end
|
11
11
|
|
12
|
-
def
|
13
|
-
|
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
|
-
|
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
|
-
|
20
|
-
|
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
|
-
|
60
|
+
elsif block
|
61
|
+
repo_class.class_eval(&block)
|
62
|
+
end
|
23
63
|
|
24
|
-
self.
|
25
|
-
|
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/
|
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/
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
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
|
data/lib/esse/index_mapping.rb
CHANGED
@@ -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
|
-
|
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?
|
data/lib/esse/index_setting.rb
CHANGED
@@ -30,7 +30,9 @@ module Esse
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def body
|
33
|
-
HashUtils.
|
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
|
data/lib/esse/plugins.rb
ADDED
@@ -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)
|