esse 0.0.2
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.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.rubocop.yml +128 -0
- data/CHANGELOG.md +0 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +60 -0
- data/LICENSE.txt +21 -0
- data/README.md +50 -0
- data/Rakefile +4 -0
- data/bin/console +22 -0
- data/bin/setup +8 -0
- data/esse.gemspec +39 -0
- data/exec/esse +9 -0
- data/lib/esse.rb +7 -0
- data/lib/esse/backend/index.rb +38 -0
- data/lib/esse/backend/index/aliases.rb +69 -0
- data/lib/esse/backend/index/create.rb +56 -0
- data/lib/esse/backend/index/delete.rb +38 -0
- data/lib/esse/backend/index/documents.rb +23 -0
- data/lib/esse/backend/index/existance.rb +23 -0
- data/lib/esse/backend/index/update.rb +19 -0
- data/lib/esse/backend/index_type.rb +32 -0
- data/lib/esse/backend/index_type/documents.rb +203 -0
- data/lib/esse/cli.rb +29 -0
- data/lib/esse/cli/base.rb +11 -0
- data/lib/esse/cli/generate.rb +51 -0
- data/lib/esse/cli/index.rb +14 -0
- data/lib/esse/cli/templates/index.rb.erb +59 -0
- data/lib/esse/cli/templates/mappings.json +6 -0
- data/lib/esse/cli/templates/serializer.rb.erb +14 -0
- data/lib/esse/cluster.rb +58 -0
- data/lib/esse/config.rb +73 -0
- data/lib/esse/core.rb +89 -0
- data/lib/esse/index.rb +21 -0
- data/lib/esse/index/actions.rb +10 -0
- data/lib/esse/index/backend.rb +13 -0
- data/lib/esse/index/base.rb +118 -0
- data/lib/esse/index/descendants.rb +17 -0
- data/lib/esse/index/inheritance.rb +18 -0
- data/lib/esse/index/mappings.rb +47 -0
- data/lib/esse/index/naming.rb +64 -0
- data/lib/esse/index/settings.rb +48 -0
- data/lib/esse/index/type.rb +31 -0
- data/lib/esse/index_mapping.rb +38 -0
- data/lib/esse/index_setting.rb +41 -0
- data/lib/esse/index_type.rb +10 -0
- data/lib/esse/index_type/actions.rb +11 -0
- data/lib/esse/index_type/backend.rb +13 -0
- data/lib/esse/index_type/mappings.rb +42 -0
- data/lib/esse/index_type/serializer.rb +87 -0
- data/lib/esse/primitives.rb +3 -0
- data/lib/esse/primitives/hstring.rb +85 -0
- data/lib/esse/template_loader.rb +46 -0
- data/lib/esse/types/mapping.rb +0 -0
- data/lib/esse/version.rb +5 -0
- metadata +215 -0
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'thor'
|
4
|
+
require 'ostruct'
|
5
|
+
require_relative 'base'
|
6
|
+
|
7
|
+
module Esse
|
8
|
+
module CLI
|
9
|
+
class Generate < Base
|
10
|
+
NAMESPACE_PATTERN_RE = %r{\:|/|\\}i.freeze
|
11
|
+
|
12
|
+
def self.source_root
|
13
|
+
File.dirname(__FILE__)
|
14
|
+
end
|
15
|
+
|
16
|
+
desc 'index NAME *TYPES', 'Creates a new index'
|
17
|
+
def index(name, *types)
|
18
|
+
ns_path = name.split(NAMESPACE_PATTERN_RE).tap(&:pop)
|
19
|
+
@index_name = Hstring.new(name.to_s).modulize.sub(/Index$/, '') + 'Index'
|
20
|
+
@types = types.map { |type| Hstring.new(type) }
|
21
|
+
@base_class = base_index_class(*ns_path)
|
22
|
+
|
23
|
+
base_dir = Esse.config.indices_directory.join(*ns_path)
|
24
|
+
index_name = Hstring.new(@index_name).demodulize.underscore.to_s
|
25
|
+
template(
|
26
|
+
'templates/index.rb.erb',
|
27
|
+
base_dir.join("#{index_name}.rb"),
|
28
|
+
)
|
29
|
+
@types.each do |type|
|
30
|
+
@type = Hstring.new(type).underscore
|
31
|
+
copy_file(
|
32
|
+
'templates/mappings.json',
|
33
|
+
base_dir.join(index_name, 'templates', "#{@type}_mapping.json"),
|
34
|
+
)
|
35
|
+
template(
|
36
|
+
'templates/serializer.rb.erb',
|
37
|
+
base_dir.join(index_name, 'serializers', "#{@type}_serializer.rb"),
|
38
|
+
)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
protected
|
43
|
+
|
44
|
+
def base_index_class(*ns)
|
45
|
+
return 'ApplicationIndex' if Esse.config.indices_directory.join(*ns, 'application_index.rb').exist?
|
46
|
+
|
47
|
+
'Esse::Index'
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'thor'
|
4
|
+
require_relative 'base'
|
5
|
+
module Esse
|
6
|
+
module CLI
|
7
|
+
class Index < Base
|
8
|
+
desc 'create *INDEX_CLASSES', 'Creates a new index'
|
9
|
+
def create(*index_classes)
|
10
|
+
# Add action here
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class <%= @index_name %> < <%= @base_class %>
|
4
|
+
# plugin :active_record
|
5
|
+
# plugin :sequel
|
6
|
+
<%- @types.each do |type| -%>
|
7
|
+
|
8
|
+
define_type :<%= type %> do
|
9
|
+
# Collection
|
10
|
+
# ==========
|
11
|
+
#
|
12
|
+
# Collection wraps the data into an array of items that should be serialized. The first argument that is
|
13
|
+
# yielded must extends Enumerable.
|
14
|
+
# Useful for eager loading data from database or any other repository. Below is an example of a rails like
|
15
|
+
# application could load using activerecord.
|
16
|
+
#
|
17
|
+
# collection do |conditions|
|
18
|
+
# context = {}
|
19
|
+
# <%= type.camelize %>.where(conditions).find_in_batches(batch_size: 5000) do |batch|
|
20
|
+
# yield batch, context, ...
|
21
|
+
# end
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
#
|
25
|
+
# Serializer
|
26
|
+
# ==========
|
27
|
+
#
|
28
|
+
# The serializer can be any class that respond with the `as_json` class method.
|
29
|
+
# And the result of its as_json is a Hash.
|
30
|
+
#
|
31
|
+
# Here is an example of a simple serializer:
|
32
|
+
# app/serializers/<%= type %>_serializer.rb
|
33
|
+
# class <%= type.camelize %>Serializer
|
34
|
+
# def initialize(<%= type %>, _context)
|
35
|
+
# @<%= type %> = <%= type %>
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# def as_json
|
39
|
+
# { '_id' => @<%= type %>.id, 'name' => @<%= type %>.name }
|
40
|
+
# end
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# And here you specify your serializer classe.
|
44
|
+
# serializer <%= @index_name %>::Serializers::<%= type.camelize %>Serializer
|
45
|
+
#
|
46
|
+
# You can also serialize the collection entry using a block:
|
47
|
+
#
|
48
|
+
# serializer(<%= type %>, context = {}) do
|
49
|
+
# hash = {
|
50
|
+
# name: <%= type %>.name,
|
51
|
+
# }
|
52
|
+
# # Context is just an example here. But it's useful for eager loading data.
|
53
|
+
# # I'll think a better example when implement this idea.
|
54
|
+
# hash[:some_attribute] = <%= type %>.some_attribute if context[:include_some_attribute]
|
55
|
+
# hash
|
56
|
+
# end
|
57
|
+
end
|
58
|
+
<%- end -%>
|
59
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class <%= @index_name %>::Serializers::<%= @type.camelize %>Serializer
|
4
|
+
def initialize(<%= @type %>, *_other)
|
5
|
+
@entity = <%= @type %>
|
6
|
+
end
|
7
|
+
|
8
|
+
def as_json
|
9
|
+
{
|
10
|
+
id: @entity.id, # This field is required
|
11
|
+
name: @entity.name,
|
12
|
+
}
|
13
|
+
end
|
14
|
+
end
|
data/lib/esse/cluster.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Esse
|
4
|
+
class Cluster
|
5
|
+
ATTRIBUTES = %i[index_prefix index_settings client].freeze
|
6
|
+
|
7
|
+
# The index prefix. For example an index named UsersIndex.
|
8
|
+
# With `index_prefix = 'app1'`. Final index/alias is: 'app1_users'
|
9
|
+
attr_accessor :index_prefix
|
10
|
+
|
11
|
+
# This settings will be passed through all indices during the mapping
|
12
|
+
attr_accessor :index_settings
|
13
|
+
|
14
|
+
attr_reader :id
|
15
|
+
|
16
|
+
def initialize(id:, **options)
|
17
|
+
@id = id.to_sym
|
18
|
+
@index_settings = {}
|
19
|
+
assign(options)
|
20
|
+
end
|
21
|
+
|
22
|
+
def assign(hash)
|
23
|
+
return unless hash.is_a?(Hash)
|
24
|
+
|
25
|
+
hash.each do |key, value|
|
26
|
+
method = (ATTRIBUTES & [key.to_s, key.to_sym]).first
|
27
|
+
next unless method
|
28
|
+
|
29
|
+
public_send(:"#{method}=", value)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def client
|
34
|
+
@client ||= Elasticsearch::Client.new
|
35
|
+
end
|
36
|
+
|
37
|
+
# Define the elasticsearch client connectio
|
38
|
+
# @param client [Elasticsearch::Client, Hash] an instance of elasticsearch/api client or an hash
|
39
|
+
# with the settings that will be used to initialize Elasticsearch::Client
|
40
|
+
def client=(val)
|
41
|
+
@client = if val.is_a?(Hash)
|
42
|
+
settings = val.each_with_object({}) { |(k,v), r| r[k.to_sym] = v }
|
43
|
+
Elasticsearch::Client.new(settings)
|
44
|
+
else
|
45
|
+
val
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def inspect
|
50
|
+
attrs = ([:id] + ATTRIBUTES - [:client]).map do |method|
|
51
|
+
value = public_send(method)
|
52
|
+
format('%<k>s=%<v>p', k: method, v: value) if value
|
53
|
+
end.compact
|
54
|
+
attrs << format('client=%p', @client)
|
55
|
+
format('#<Esse::Cluster %<attrs>s>', attrs: attrs.join(' '))
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/lib/esse/config.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'pathname'
|
4
|
+
|
5
|
+
module Esse
|
6
|
+
# Provides all configurations
|
7
|
+
#
|
8
|
+
# Example
|
9
|
+
# Esse.config do |conf|
|
10
|
+
# conf.indices_directory = 'app/indices'
|
11
|
+
# end
|
12
|
+
class Config
|
13
|
+
DEFAULT_CLUSTER_ID = :default
|
14
|
+
ATTRIBUTES = %i[indices_directory].freeze
|
15
|
+
|
16
|
+
# The location of the indices. Defaults to the `app/indices`
|
17
|
+
attr_reader :indices_directory
|
18
|
+
|
19
|
+
def initialize
|
20
|
+
self.indices_directory = 'app/indices'
|
21
|
+
@clusters = {}
|
22
|
+
clusters(DEFAULT_CLUSTER_ID) # initialize the :default client
|
23
|
+
end
|
24
|
+
|
25
|
+
def cluster_ids
|
26
|
+
@clusters.keys
|
27
|
+
end
|
28
|
+
|
29
|
+
def clusters(key = DEFAULT_CLUSTER_ID, **options)
|
30
|
+
return unless key
|
31
|
+
|
32
|
+
id = key.to_sym
|
33
|
+
(@clusters[id] ||= Cluster.new(id: id)).tap do |c|
|
34
|
+
c.assign(options) if options
|
35
|
+
yield c if block_given?
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def indices_directory=(value)
|
40
|
+
@indices_directory = value.is_a?(Pathname) ? value : Pathname.new(value)
|
41
|
+
end
|
42
|
+
|
43
|
+
def load(arg)
|
44
|
+
case arg
|
45
|
+
when Hash
|
46
|
+
assign(arg)
|
47
|
+
when File, Pathname
|
48
|
+
# @TODO Load JSON or YAML
|
49
|
+
when String
|
50
|
+
# @TODO Load JSON or YAML if File.exist?(arg)
|
51
|
+
else
|
52
|
+
raise ArgumentError, printf('could not load configuration using: %p', val)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def assign(hash)
|
59
|
+
hash.each do |key, value|
|
60
|
+
method = (ATTRIBUTES & [key.to_s, key.to_sym]).first
|
61
|
+
next unless method
|
62
|
+
|
63
|
+
public_send("#{method}=", value)
|
64
|
+
end
|
65
|
+
if (connections = hash['clusters'] || hash[:clusters]).is_a?(Hash)
|
66
|
+
connections.each do |key, value|
|
67
|
+
clusters(key).assign(value) if value.is_a?(Hash)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
true
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
data/lib/esse/core.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'multi_json'
|
4
|
+
require 'elasticsearch'
|
5
|
+
|
6
|
+
module Esse
|
7
|
+
@single_threaded = false
|
8
|
+
# Mutex used to protect mutable data structures
|
9
|
+
@data_mutex = Mutex.new
|
10
|
+
|
11
|
+
# Block configurations
|
12
|
+
# Esse.config do |conf|
|
13
|
+
# conf.indices_directory = 'app/indices/directory'
|
14
|
+
# conf.clusters(:v1) do |cluster|
|
15
|
+
# cluster.index_prefix = 'backend'
|
16
|
+
# cluster.client = Elasticsearch::Client.new
|
17
|
+
# cluster.index_settings = {
|
18
|
+
# number_of_shards: 2,
|
19
|
+
# number_of_replicas: 0
|
20
|
+
# }
|
21
|
+
# end
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# Inline configurations
|
25
|
+
# Esse.config.indices_directory = 'app/indices/directory'
|
26
|
+
# Esse.config.clusters(:v1).client = Elasticsearch::Client.new
|
27
|
+
def self.config
|
28
|
+
@config ||= Config.new
|
29
|
+
yield(@config) if block_given?
|
30
|
+
@config
|
31
|
+
end
|
32
|
+
|
33
|
+
# Unless in single threaded mode, protects access to any mutable
|
34
|
+
# global data structure in Esse.
|
35
|
+
# Uses a non-reentrant mutex, so calling code should be careful.
|
36
|
+
# In general, this should only be used around the minimal possible code
|
37
|
+
# such as Hash#[], Hash#[]=, Hash#delete, Array#<<, and Array#delete.
|
38
|
+
def self.synchronize(&block)
|
39
|
+
@single_threaded ? yield : @data_mutex.synchronize(&block)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Generates an unique timestamp to be used as a index suffix.
|
43
|
+
# Time.now.to_i could also do the job. But I think this format
|
44
|
+
# is more readable for humans
|
45
|
+
def self.timestamp
|
46
|
+
Time.now.strftime('%Y%m%d%H%M%S')
|
47
|
+
end
|
48
|
+
|
49
|
+
# Simple helper used to fetch Hash value using Symbol and String keys.
|
50
|
+
#
|
51
|
+
# @param [Hash] the JSON document
|
52
|
+
# @option [Array] :delete Removes the hash key and return its value
|
53
|
+
# @option [Array] :keep Fetch the hash key and return its value
|
54
|
+
# @return [Array([Integer, String, nil], Hash)] return the key value and the modified hash
|
55
|
+
def self.doc_id!(hash, delete: %w[_id], keep: %w[id])
|
56
|
+
return unless hash.is_a?(Hash)
|
57
|
+
|
58
|
+
id = nil
|
59
|
+
modified = nil
|
60
|
+
Array(delete).each do |key|
|
61
|
+
k = key.to_s if hash.key?(key.to_s)
|
62
|
+
k ||= key.to_sym if hash.key?(key.to_sym)
|
63
|
+
next unless k
|
64
|
+
|
65
|
+
modified ||= hash.dup
|
66
|
+
id = modified.delete(k)
|
67
|
+
break if id
|
68
|
+
end
|
69
|
+
return [id, modified] if id
|
70
|
+
|
71
|
+
modified ||= hash
|
72
|
+
Array(keep).each do |key|
|
73
|
+
id = modified[key.to_s] || modified[key.to_sym]
|
74
|
+
break if id
|
75
|
+
end
|
76
|
+
[id, modified]
|
77
|
+
end
|
78
|
+
|
79
|
+
require_relative 'config'
|
80
|
+
require_relative 'cluster'
|
81
|
+
require_relative 'primitives'
|
82
|
+
require_relative 'index_type'
|
83
|
+
require_relative 'index_setting'
|
84
|
+
require_relative 'index_mapping'
|
85
|
+
require_relative 'template_loader'
|
86
|
+
require_relative 'backend/index'
|
87
|
+
require_relative 'backend/index_type'
|
88
|
+
require_relative 'version'
|
89
|
+
end
|
data/lib/esse/index.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'core'
|
4
|
+
|
5
|
+
module Esse
|
6
|
+
class Index
|
7
|
+
require_relative 'index/base'
|
8
|
+
require_relative 'index/inheritance'
|
9
|
+
require_relative 'index/actions'
|
10
|
+
require_relative 'index/naming'
|
11
|
+
require_relative 'index/type'
|
12
|
+
require_relative 'index/settings'
|
13
|
+
require_relative 'index/mappings'
|
14
|
+
require_relative 'index/descendants'
|
15
|
+
require_relative 'index/backend'
|
16
|
+
|
17
|
+
@cluster_id = nil
|
18
|
+
|
19
|
+
def_Index(::Esse)
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Esse
|
4
|
+
class Index
|
5
|
+
module ClassMethods
|
6
|
+
attr_reader :cluster_id
|
7
|
+
|
8
|
+
# Define a Index method on the given module that calls the Index
|
9
|
+
# method on the receiver. This is how the Esse::Index() method is
|
10
|
+
# defined, and allows you to define Index() methods on other modules,
|
11
|
+
# making it easier to have custom index settings for all indexes under
|
12
|
+
# a namespace. Example:
|
13
|
+
#
|
14
|
+
# module V1
|
15
|
+
# EsIndex = Class.new(Esse::Index)
|
16
|
+
# EsIndex.def_Index(self)
|
17
|
+
#
|
18
|
+
# class Bar < EsIndex
|
19
|
+
# # Uses :default elasticsearch client connection
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# class Baz < EsIndex(:v1)
|
23
|
+
# # Uses :v1 elasticsearch client connection
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
def def_Index(index_module) # rubocop:disable Naming/MethodName
|
27
|
+
tap do |model|
|
28
|
+
index_module.define_singleton_method(:Index) do |source|
|
29
|
+
model.Index(source)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Lets you create a Index subclass with its elasticsearch cluster
|
35
|
+
#
|
36
|
+
# Example:
|
37
|
+
# # Using a custom cluster
|
38
|
+
# Esse.config.clusters(:v1).client = Elasticsearch::Client.new
|
39
|
+
# class UsersIndex < Esse::Index(:v1)
|
40
|
+
# end
|
41
|
+
#
|
42
|
+
# # Using :default cluster
|
43
|
+
# class UsersIndex < Esse::Index
|
44
|
+
# end
|
45
|
+
def Index(source) # rubocop:disable Naming/MethodName
|
46
|
+
klass = Class.new(self)
|
47
|
+
|
48
|
+
valid_ids = Esse.config.cluster_ids
|
49
|
+
klass.cluster_id = \
|
50
|
+
case source
|
51
|
+
when Esse::Cluster
|
52
|
+
source.id
|
53
|
+
when String, Symbol
|
54
|
+
id = source.to_sym
|
55
|
+
id if valid_ids.include?(id)
|
56
|
+
end
|
57
|
+
|
58
|
+
msg = <<~MSG
|
59
|
+
We could not resolve the index cluster using the argument %<arg>p. \n
|
60
|
+
It must be previously defined in the `Esse.config' settings. \n
|
61
|
+
Here is the list of cluster ids we have configured: %<ids>s\n
|
62
|
+
|
63
|
+
You can ignore this cluster id entirely. That way the :default id will be used.\n
|
64
|
+
Example: \n
|
65
|
+
class UsersIndex < Esse::Index\n
|
66
|
+
end\n
|
67
|
+
MSG
|
68
|
+
unless klass.cluster_id
|
69
|
+
raise ArgumentError.new, format(msg, arg: source, ids: valid_ids.map(&:inspect).join(', '))
|
70
|
+
end
|
71
|
+
|
72
|
+
klass.type_hash = {}
|
73
|
+
klass
|
74
|
+
end
|
75
|
+
|
76
|
+
# Sets the client_id associated with the Index class.
|
77
|
+
# This can be used directly on Esse::Index to set the :default es cluster
|
78
|
+
# to be used by subclasses, or to override the es client used for specific indices:
|
79
|
+
# Esse::Index.cluster_id = :v1
|
80
|
+
# ArtistIndex = Class.new(Esse::Index)
|
81
|
+
# ArtistIndex.cluster_id = :v2
|
82
|
+
def cluster_id=(cluster_id)
|
83
|
+
@cluster_id = cluster_id
|
84
|
+
end
|
85
|
+
|
86
|
+
# @return [Symbol] reads the @cluster_id instance variable or :default
|
87
|
+
def cluster_id
|
88
|
+
@cluster_id || Config::DEFAULT_CLUSTER_ID
|
89
|
+
end
|
90
|
+
|
91
|
+
# @return [Esse::Cluster] an instance of cluster based on its cluster_id
|
92
|
+
def cluster
|
93
|
+
unless Esse.config.cluster_ids.include?(cluster_id)
|
94
|
+
raise NotImplementedError, <<~MSG
|
95
|
+
There is no cluster configured for this index. Use `Esse.config.clusters(cluster_id) { ... }' define the elasticsearch
|
96
|
+
client connection.
|
97
|
+
MSG
|
98
|
+
end
|
99
|
+
|
100
|
+
Esse.synchronize { Esse.config.clusters(cluster_id) }
|
101
|
+
end
|
102
|
+
|
103
|
+
def inspect
|
104
|
+
if self == Index
|
105
|
+
super
|
106
|
+
elsif abstract_class?
|
107
|
+
"#{super}(abstract)"
|
108
|
+
elsif index_name?
|
109
|
+
"#{super}(Index: #{index_name})"
|
110
|
+
else
|
111
|
+
"#{super}(Index is not defined)"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
extend ClassMethods
|
117
|
+
end
|
118
|
+
end
|