elasticsearch_record 1.1.0 → 1.2.0
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 +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +22 -8
- data/docs/CHANGELOG.md +20 -1
- data/lib/active_record/connection_adapters/elasticsearch/column.rb +9 -2
- data/lib/active_record/connection_adapters/elasticsearch/schema_definitions/clone_table_definition.rb +88 -0
- data/lib/active_record/connection_adapters/elasticsearch/schema_definitions/column_methods.rb +1 -1
- data/lib/active_record/connection_adapters/elasticsearch/schema_definitions/create_table_definition.rb +29 -27
- data/lib/active_record/connection_adapters/elasticsearch/schema_definitions/table_definition.rb +67 -12
- data/lib/active_record/connection_adapters/elasticsearch/schema_definitions/table_mapping_definition.rb +48 -13
- data/lib/active_record/connection_adapters/elasticsearch/schema_definitions/table_meta_definition.rb +24 -0
- data/lib/active_record/connection_adapters/elasticsearch/schema_definitions/table_setting_definition.rb +9 -4
- data/lib/active_record/connection_adapters/elasticsearch/schema_definitions/update_table_definition.rb +38 -13
- data/lib/active_record/connection_adapters/elasticsearch/schema_definitions.rb +3 -0
- data/lib/active_record/connection_adapters/elasticsearch/schema_dumper.rb +41 -0
- data/lib/active_record/connection_adapters/elasticsearch/schema_statements.rb +36 -10
- data/lib/active_record/connection_adapters/elasticsearch/table_statements.rb +102 -8
- data/lib/active_record/connection_adapters/elasticsearch_adapter.rb +17 -2
- data/lib/arel/collectors/elasticsearch_query.rb +3 -0
- data/lib/arel/visitors/elasticsearch_query.rb +1 -0
- data/lib/arel/visitors/elasticsearch_schema.rb +48 -7
- data/lib/elasticsearch_record/core.rb +24 -8
- data/lib/elasticsearch_record/gem_version.rb +1 -1
- data/lib/elasticsearch_record/model_schema.rb +26 -2
- data/lib/elasticsearch_record/persistence.rb +45 -34
- data/lib/elasticsearch_record/query.rb +4 -1
- data/lib/elasticsearch_record/schema_migration.rb +49 -0
- data/lib/elasticsearch_record/tasks/elasticsearch_database_tasks.rb +15 -5
- data/lib/elasticsearch_record.rb +1 -0
- metadata +6 -3
@@ -10,7 +10,7 @@ module ActiveRecord
|
|
10
10
|
include ActiveModel::Validations
|
11
11
|
|
12
12
|
# exclude settings, that are provided through the API but are not part of the index-settings API
|
13
|
-
IGNORE_NAMES = ['provided_name', 'creation_date', 'uuid', 'version'].freeze
|
13
|
+
IGNORE_NAMES = ['provided_name', 'creation_date', 'uuid', 'version','routing.allocation.initial_recovery','resize'].freeze
|
14
14
|
|
15
15
|
# available setting names
|
16
16
|
# - see @ https://www.elastic.co/guide/en/elasticsearch/reference/current/index-modules.html#index-modules-settings
|
@@ -33,7 +33,8 @@ module ActiveRecord
|
|
33
33
|
'max_docvalue_fields_search', 'max_script_fields', 'max_ngram_diff', 'max_shingle_diff',
|
34
34
|
'max_refresh_listeners', 'analyze.max_token_count', 'highlight.max_analyzed_offset',
|
35
35
|
'max_terms_count', 'max_regex_length', 'query.default_field', 'routing.allocation.enable',
|
36
|
-
'routing.rebalance.enable', 'gc_deletes', 'default_pipeline', 'final_pipeline',
|
36
|
+
'routing.rebalance.enable', 'gc_deletes', 'default_pipeline', 'final_pipeline',
|
37
|
+
'hidden', 'blocks'].freeze
|
37
38
|
|
38
39
|
VALID_NAMES = (FINAL_NAMES + STATIC_NAMES + DYNAMIC_NAMES).freeze
|
39
40
|
|
@@ -43,6 +44,9 @@ module ActiveRecord
|
|
43
44
|
|
44
45
|
# validations
|
45
46
|
validates_presence_of :name
|
47
|
+
|
48
|
+
# disable validation for name - maybe future updates of Elasticsearch have other names.
|
49
|
+
# To not be hooked on those possible changes we disable the validation
|
46
50
|
validate :_validate_name
|
47
51
|
validate :_validate_final_name
|
48
52
|
validate :_validate_static_name
|
@@ -78,7 +82,8 @@ module ActiveRecord
|
|
78
82
|
end
|
79
83
|
|
80
84
|
def static?
|
81
|
-
|
85
|
+
@static = flat_names.all? { |flat_name| self.class.match_static_names?(flat_name) } if @static.nil?
|
86
|
+
@static
|
82
87
|
end
|
83
88
|
|
84
89
|
def dynamic?
|
@@ -100,7 +105,7 @@ module ActiveRecord
|
|
100
105
|
end
|
101
106
|
|
102
107
|
def _validate_static_name
|
103
|
-
return true
|
108
|
+
return true unless static?
|
104
109
|
return true if ['missing', 'close'].include?(_table_status)
|
105
110
|
|
106
111
|
invalid!("is static - this setting can only be changed on a closed index!", :name)
|
@@ -14,7 +14,7 @@ module ActiveRecord
|
|
14
14
|
COMPOSITE_DEFINITIONS = [
|
15
15
|
AddMappingDefinition,
|
16
16
|
ChangeMappingDefinition,
|
17
|
-
|
17
|
+
ChangeMetaDefinition,
|
18
18
|
AddSettingDefinition,
|
19
19
|
DeleteAliasDefinition
|
20
20
|
].freeze
|
@@ -29,10 +29,29 @@ module ActiveRecord
|
|
29
29
|
alias :mapping :add_mapping
|
30
30
|
alias :column :add_mapping
|
31
31
|
|
32
|
+
def change_meta(name, value, **options)
|
33
|
+
load_meta_definition!
|
34
|
+
|
35
|
+
define! ChangeMetaDefinition, new_meta_definition(name, value, **options)
|
36
|
+
end
|
37
|
+
|
38
|
+
def delete_meta(name, **options)
|
39
|
+
load_meta_definition!
|
40
|
+
|
41
|
+
define! ChangeMetaDefinition, new_meta_definition(name, nil, **options)
|
42
|
+
end
|
43
|
+
|
32
44
|
def change_mapping(name, type, if_exists: false, **options, &block)
|
33
45
|
return if if_exists && !mapping_exists?(self.name, name, type)
|
34
46
|
|
35
|
-
|
47
|
+
mapping = new_mapping_definition(name, type, **options, &block)
|
48
|
+
define! ChangeMappingDefinition, mapping
|
49
|
+
|
50
|
+
# check if the mapping is assigned as primary_key
|
51
|
+
if mapping.primary_key?
|
52
|
+
change_meta :primary_key, mapping.name
|
53
|
+
change_meta(:auto_increment, mapping.auto_increment) if mapping.auto_increment?
|
54
|
+
end
|
36
55
|
end
|
37
56
|
|
38
57
|
alias :change_column :change_mapping
|
@@ -56,6 +75,7 @@ module ActiveRecord
|
|
56
75
|
|
57
76
|
define! ChangeMappingDefinition, new_mapping_definition(name, mapping['type'], **options, &block)
|
58
77
|
end
|
78
|
+
|
59
79
|
alias :change_mapping_attribute :change_mapping_attributes
|
60
80
|
|
61
81
|
def add_setting(name, value, if_not_exists: false, **options, &block)
|
@@ -105,6 +125,17 @@ module ActiveRecord
|
|
105
125
|
|
106
126
|
private
|
107
127
|
|
128
|
+
# loads existing meta definitions from table_mappings
|
129
|
+
def load_meta_definition!
|
130
|
+
return if @load_meta_definition
|
131
|
+
@load_meta_definition = true
|
132
|
+
|
133
|
+
|
134
|
+
table_metas(self.name).each do |name, value|
|
135
|
+
define! ChangeMetaDefinition, new_meta_definition(name, value)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
108
139
|
def define!(klass, item)
|
109
140
|
@definitions ||= {}
|
110
141
|
@definitions[klass] ||= []
|
@@ -119,11 +150,6 @@ module ActiveRecord
|
|
119
150
|
clear_state!
|
120
151
|
end
|
121
152
|
|
122
|
-
def _after_assign
|
123
|
-
# run the same content as +_after_exec+, but only if the assignment failed
|
124
|
-
_after_exec if failed?
|
125
|
-
end
|
126
|
-
|
127
153
|
def _after_exec
|
128
154
|
# reopen the table again
|
129
155
|
open_table(self.name) if _toggle_table_status?
|
@@ -131,6 +157,8 @@ module ActiveRecord
|
|
131
157
|
# reset table state
|
132
158
|
clear_state!
|
133
159
|
end
|
160
|
+
alias :_rescue_assign :_after_exec
|
161
|
+
alias :_rescue_exec :_after_exec
|
134
162
|
|
135
163
|
def _toggle_table_status?
|
136
164
|
@toggle_table_status = (force? && state[:status] == 'open') if @toggle_table_status.nil?
|
@@ -141,9 +169,6 @@ module ActiveRecord
|
|
141
169
|
def _exec
|
142
170
|
return unless definitions.any?
|
143
171
|
|
144
|
-
# check, if the table should be closed before executing the queries
|
145
|
-
close_table(self.name) if opts[:close] == true
|
146
|
-
|
147
172
|
definitions.each do |klass, items|
|
148
173
|
# check if the provided definition klass is a composite definition
|
149
174
|
executable_definitions = if COMPOSITE_DEFINITIONS.include?(klass)
|
@@ -159,10 +184,10 @@ module ActiveRecord
|
|
159
184
|
end
|
160
185
|
end
|
161
186
|
|
162
|
-
|
163
|
-
|
164
|
-
# cleanup definitions
|
187
|
+
# cleanup executed definitions
|
165
188
|
@definitions = {}
|
189
|
+
|
190
|
+
true
|
166
191
|
end
|
167
192
|
|
168
193
|
def _to_composite_log(klass)
|
@@ -9,6 +9,7 @@ module ActiveRecord
|
|
9
9
|
# mapping definitions
|
10
10
|
AddMappingDefinition = Struct.new(:items) # composite
|
11
11
|
ChangeMappingDefinition = Struct.new(:items) # composite
|
12
|
+
ChangeMetaDefinition = Struct.new(:items) # composite
|
12
13
|
|
13
14
|
# setting definitions
|
14
15
|
AddSettingDefinition = Struct.new(:items) # composite
|
@@ -30,8 +31,10 @@ require 'active_record/connection_adapters/elasticsearch/schema_definitions/colu
|
|
30
31
|
|
31
32
|
require 'active_record/connection_adapters/elasticsearch/schema_definitions/table_alias_definition'
|
32
33
|
require 'active_record/connection_adapters/elasticsearch/schema_definitions/table_mapping_definition'
|
34
|
+
require 'active_record/connection_adapters/elasticsearch/schema_definitions/table_meta_definition'
|
33
35
|
require 'active_record/connection_adapters/elasticsearch/schema_definitions/table_setting_definition'
|
34
36
|
|
35
37
|
require 'active_record/connection_adapters/elasticsearch/schema_definitions/table_definition'
|
36
38
|
require 'active_record/connection_adapters/elasticsearch/schema_definitions/create_table_definition'
|
37
39
|
require 'active_record/connection_adapters/elasticsearch/schema_definitions/update_table_definition'
|
40
|
+
require 'active_record/connection_adapters/elasticsearch/schema_definitions/clone_table_definition'
|
@@ -6,8 +6,40 @@ module ActiveRecord
|
|
6
6
|
module ConnectionAdapters
|
7
7
|
module Elasticsearch
|
8
8
|
class SchemaDumper < ActiveRecord::ConnectionAdapters::SchemaDumper # :nodoc:
|
9
|
+
|
10
|
+
def initialize(connection, options = {})
|
11
|
+
super
|
12
|
+
|
13
|
+
_expand_options!
|
14
|
+
end
|
15
|
+
|
9
16
|
private
|
10
17
|
|
18
|
+
def _expand_options!
|
19
|
+
@options[:table_name_prefix] = @connection.table_name_prefix if @options[:table_name_prefix].blank?
|
20
|
+
@options[:table_name_suffix] = @connection.table_name_suffix if @options[:table_name_suffix].blank?
|
21
|
+
end
|
22
|
+
|
23
|
+
# overwrite the method to 'fix' a possible ActiveRecord bug:
|
24
|
+
# If a +table_name_prefix+ or +table_name_suffix+ was provided we also only want to dump those tables,
|
25
|
+
# which matches the prefix/suffix. So possible, environment-related tables will be ignored
|
26
|
+
# (e.g. if a '-development' as +table_name_suffix+ was provided ... )
|
27
|
+
def ignored?(table_name)
|
28
|
+
super(table_name) || ignored_table?(table_name)
|
29
|
+
end
|
30
|
+
|
31
|
+
# returns true if the provided table name does not match possible provided
|
32
|
+
# options +table_name_prefix+ or +table_name_suffix+.
|
33
|
+
def ignored_table?(table_name)
|
34
|
+
# if the table starts NOT with +prefix+ it must be ignored
|
35
|
+
return true if @options[:table_name_prefix].present? && !table_name.start_with?(@options[:table_name_prefix].to_s)
|
36
|
+
|
37
|
+
# if the table ends NOT with +suffix+ it must be ignored
|
38
|
+
return true if @options[:table_name_suffix].present? && !table_name.end_with?(@options[:table_name_suffix].to_s)
|
39
|
+
|
40
|
+
false
|
41
|
+
end
|
42
|
+
|
11
43
|
def table(table, stream, nested_blocks: false, **)
|
12
44
|
begin
|
13
45
|
self.table_name = table
|
@@ -21,6 +53,15 @@ module ActiveRecord
|
|
21
53
|
tbl.print " create_table #{remove_prefix_and_suffix(table).inspect}"
|
22
54
|
tbl.print ", force: true do |t|"
|
23
55
|
|
56
|
+
# META
|
57
|
+
if (metas = definition.metas).present?
|
58
|
+
tbl.puts
|
59
|
+
|
60
|
+
metas.each do |meta|
|
61
|
+
tbl.puts " t.meta #{meta.name.inspect}, #{format_attribute(meta.value)}"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
24
65
|
# ALIASES
|
25
66
|
if (aliases = definition.aliases).present?
|
26
67
|
tbl.puts
|
@@ -92,7 +92,7 @@ module ActiveRecord
|
|
92
92
|
:dump_schema_information
|
93
93
|
|
94
94
|
def assume_migrated_upto_version(version)
|
95
|
-
version
|
95
|
+
version = version.to_i
|
96
96
|
migrated = migration_context.get_all_versions
|
97
97
|
versions = migration_context.migrations.map(&:version)
|
98
98
|
|
@@ -108,7 +108,7 @@ module ActiveRecord
|
|
108
108
|
end
|
109
109
|
|
110
110
|
# use a ActiveRecord syntax to create new versions
|
111
|
-
inserting.each {|iversion| schema_migration.create(version: iversion) }
|
111
|
+
inserting.each { |iversion| schema_migration.create(version: iversion) }
|
112
112
|
end
|
113
113
|
|
114
114
|
true
|
@@ -137,6 +137,14 @@ module ActiveRecord
|
|
137
137
|
api(:indices, :get_mapping, { index: table_name, expand_wildcards: [:open, :closed] }, 'SCHEMA').dig(table_name, 'mappings')
|
138
138
|
end
|
139
139
|
|
140
|
+
# returns a hash of all meta data by provided table_name (index).
|
141
|
+
# HINT: +_meta+ is resolved from the table mappings
|
142
|
+
# @param [String] table_name
|
143
|
+
# @return [Hash]
|
144
|
+
def table_metas(table_name)
|
145
|
+
table_mappings(table_name).dig('_meta').presence || {}
|
146
|
+
end
|
147
|
+
|
140
148
|
# returns a hash of all settings by provided table_name
|
141
149
|
# @param [String] table_name
|
142
150
|
# @param [Boolean] flat_settings (default: true)
|
@@ -223,7 +231,8 @@ module ActiveRecord
|
|
223
231
|
meta: field['meta'],
|
224
232
|
virtual: field['virtual'],
|
225
233
|
fields: field['fields'],
|
226
|
-
properties: field['properties']
|
234
|
+
properties: field['properties'],
|
235
|
+
enabled: field['enabled']
|
227
236
|
)
|
228
237
|
end
|
229
238
|
|
@@ -239,15 +248,18 @@ module ActiveRecord
|
|
239
248
|
# Returns a array of tables primary keys.
|
240
249
|
# PLEASE NOTE: Elasticsearch does not have a concept of primary key.
|
241
250
|
# The only thing that uniquely identifies a document is the index together with the +_id+.
|
242
|
-
# To
|
251
|
+
# To support this concept we simulate this through the +_meta+ field (from the index).
|
252
|
+
#
|
253
|
+
# As a alternative, the primary_key can also be provided through the mappings +meta+ field.
|
254
|
+
#
|
255
|
+
# see @ https://www.elastic.co/guide/en/elasticsearch/reference/8.5/mapping-meta-field.html
|
243
256
|
# @see ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter#primary_keys
|
244
257
|
# @param [String] table_name
|
245
258
|
def primary_keys(table_name)
|
246
|
-
column_definitions(table_name)
|
247
|
-
|
248
|
-
.select { |f| f['meta'] && f['meta']['primary_key'] == 'true' }
|
259
|
+
table_metas(table_name).dig('primary_key').presence || column_definitions(table_name).
|
260
|
+
select { |f| f['meta'] && f['meta']['primary_key'] == 'true' }.
|
249
261
|
# only take the last found primary key (if no custom primary_key was provided this will return +_id+ )
|
250
|
-
|
262
|
+
map { |f| f["name"] }[-1..-1]
|
251
263
|
end
|
252
264
|
|
253
265
|
# Checks to see if the data source +name+ exists on the database.
|
@@ -307,6 +319,17 @@ module ActiveRecord
|
|
307
319
|
column_exists?(table_name, mapping_name, type)
|
308
320
|
end
|
309
321
|
|
322
|
+
# Checks to see if a meta +meta_name+ within a table +table_name+ exists on the database.
|
323
|
+
#
|
324
|
+
# meta_exists?(:developers, 'class')
|
325
|
+
#
|
326
|
+
# @param [String] table_name
|
327
|
+
# @param [String,Symbol] meta_name
|
328
|
+
# @return [Boolean]
|
329
|
+
def meta_exists?(table_name, meta_name)
|
330
|
+
table_metas(table_name).keys.include?(meta_name.to_s)
|
331
|
+
end
|
332
|
+
|
310
333
|
# overwrite original methods to provide a elasticsearch version
|
311
334
|
def create_schema_dumper(options)
|
312
335
|
ActiveRecord::ConnectionAdapters::Elasticsearch::SchemaDumper.create(self, options)
|
@@ -318,11 +341,14 @@ module ActiveRecord
|
|
318
341
|
end
|
319
342
|
|
320
343
|
# overwrite original methods to provide a elasticsearch version
|
321
|
-
def update_table_definition(name, base = self, **options)
|
322
|
-
# :nodoc:
|
344
|
+
def update_table_definition(name, base = self, **options) # :nodoc:
|
323
345
|
::ActiveRecord::ConnectionAdapters::Elasticsearch::UpdateTableDefinition.new(base, name, **options)
|
324
346
|
end
|
325
347
|
|
348
|
+
def clone_table_definition(name, target, **options)
|
349
|
+
::ActiveRecord::ConnectionAdapters::Elasticsearch::CloneTableDefinition.new(self, name, target, **options)
|
350
|
+
end
|
351
|
+
|
326
352
|
# overwrite original methods to provide a elasticsearch version
|
327
353
|
def schema_creation
|
328
354
|
::ActiveRecord::ConnectionAdapters::Elasticsearch::SchemaCreation.new(self)
|
@@ -31,13 +31,17 @@ module ActiveRecord
|
|
31
31
|
# - refresh
|
32
32
|
# - rename_table
|
33
33
|
|
34
|
-
define_unsupported_method :
|
34
|
+
define_unsupported_method :create_join_table, :drop_join_table, :create_alter_table,
|
35
|
+
:change_column_default, :change_column_null, :rename_column, :rename_table
|
35
36
|
|
36
37
|
# Opens a closed index.
|
37
38
|
# @param [String] table_name
|
38
39
|
# @return [Boolean] acknowledged status
|
39
40
|
def open_table(table_name)
|
40
|
-
|
41
|
+
# IMPORTANT: compute will add possible configured prefix & suffix
|
42
|
+
table_name = _compute_table_name(table_name)
|
43
|
+
|
44
|
+
schema_cache.clear_data_source_cache!(table_name)
|
41
45
|
api(:indices, :open, { index: table_name }, 'OPEN TABLE').dig('acknowledged')
|
42
46
|
end
|
43
47
|
|
@@ -55,7 +59,10 @@ module ActiveRecord
|
|
55
59
|
# @param [String] table_name
|
56
60
|
# @return [Boolean] acknowledged status
|
57
61
|
def close_table(table_name)
|
58
|
-
|
62
|
+
# IMPORTANT: compute will add possible configured prefix & suffix
|
63
|
+
table_name = _compute_table_name(table_name)
|
64
|
+
|
65
|
+
schema_cache.clear_data_source_cache!(table_name)
|
59
66
|
api(:indices, :close, { index: table_name }, 'CLOSE TABLE').dig('acknowledged')
|
60
67
|
end
|
61
68
|
|
@@ -77,6 +84,9 @@ module ActiveRecord
|
|
77
84
|
# @param [String] table_name
|
78
85
|
# @return [Boolean] acknowledged status
|
79
86
|
def truncate_table(table_name)
|
87
|
+
# IMPORTANT: compute will add possible configured prefix & suffix
|
88
|
+
table_name = _compute_table_name(table_name)
|
89
|
+
|
80
90
|
# force: automatically drops an existing index
|
81
91
|
create_table(table_name, force: true, **table_schema(table_name))
|
82
92
|
end
|
@@ -98,11 +108,71 @@ module ActiveRecord
|
|
98
108
|
# Set to +true+ to only drop the table if it exists.
|
99
109
|
# Defaults to false.
|
100
110
|
# @param [String] table_name
|
111
|
+
# @param [Boolean] if_exists
|
112
|
+
# @return [Array] acknowledged status
|
113
|
+
def drop_table(table_name, if_exists: false, **)
|
114
|
+
# IMPORTANT: compute will add possible configured prefix & suffix
|
115
|
+
table_name = _compute_table_name(table_name)
|
116
|
+
|
117
|
+
schema_cache.clear_data_source_cache!(table_name)
|
118
|
+
api(:indices, :delete, { index: table_name, ignore: (if_exists ? 404 : nil) }, 'DROP TABLE').dig('acknowledged')
|
119
|
+
end
|
120
|
+
|
121
|
+
# blocks access to the provided table (index) and +block+ name.
|
122
|
+
# @param [String] table_name
|
123
|
+
# @param [Symbol] block_name The block to add (one of :read, :write, :read_only or :metadata)
|
124
|
+
# @return [Boolean] acknowledged status
|
125
|
+
def block_table(table_name, block_name = :write)
|
126
|
+
# IMPORTANT: compute will add possible configured prefix & suffix
|
127
|
+
table_name = _compute_table_name(table_name)
|
128
|
+
|
129
|
+
api(:indices, :add_block, { index: table_name, block: block_name }, "BLOCK #{block_name.to_s.upcase} TABLE").dig('acknowledged')
|
130
|
+
end
|
131
|
+
|
132
|
+
# unblocks access to the provided table (index) and +block+ name.
|
133
|
+
# provide a nil-value to unblock all blocks, otherwise provide the blocked name.
|
134
|
+
# @param [String] table_name
|
135
|
+
# @param [Symbol] block_name The block to add (one of :read, :write, :read_only or :metadata)
|
136
|
+
# @return [Boolean] acknowledged status
|
137
|
+
def unblock_table(table_name, block_name = nil)
|
138
|
+
# IMPORTANT: compute will add possible configured prefix & suffix
|
139
|
+
table_name = _compute_table_name(table_name)
|
140
|
+
|
141
|
+
if block_name.nil?
|
142
|
+
change_table(table_name) do |t|
|
143
|
+
t.change_setting('index.blocks.read', false)
|
144
|
+
t.change_setting('index.blocks.write', false)
|
145
|
+
t.change_setting('index.blocks.read_only', false)
|
146
|
+
t.change_setting('index.blocks.metadata', false)
|
147
|
+
end
|
148
|
+
else
|
149
|
+
change_setting(table_name, "index.blocks.#{block_name}", false)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
# clones an entire table to the provided +target_name+.
|
154
|
+
# During cloning, the table will be automatically 'write'-blocked.
|
155
|
+
# @param [String] table_name
|
156
|
+
# @param [String] target_name
|
101
157
|
# @param [Hash] options
|
102
|
-
# @
|
103
|
-
def
|
104
|
-
|
105
|
-
|
158
|
+
# @param [Proc] block
|
159
|
+
def clone_table(table_name, target_name, **options, &block)
|
160
|
+
# IMPORTANT: compute will add possible configured prefix & suffix
|
161
|
+
table_name = _compute_table_name(table_name)
|
162
|
+
target_name = _compute_table_name(target_name)
|
163
|
+
|
164
|
+
# create new definition
|
165
|
+
definition = clone_table_definition(table_name, target_name, **extract_table_options!(options), &block)
|
166
|
+
|
167
|
+
# yield optional block
|
168
|
+
if block_given?
|
169
|
+
definition.assign do |d|
|
170
|
+
yield d
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
# execute definition query(ies)
|
175
|
+
definition.exec!
|
106
176
|
end
|
107
177
|
|
108
178
|
# creates a new table (index).
|
@@ -120,6 +190,9 @@ module ActiveRecord
|
|
120
190
|
# @param [Hash] options
|
121
191
|
# @return [Boolean] acknowledged status
|
122
192
|
def create_table(table_name, force: false, copy_from: nil, if_not_exists: false, **options)
|
193
|
+
# IMPORTANT: compute will add possible configured prefix & suffix
|
194
|
+
table_name = _compute_table_name(table_name)
|
195
|
+
|
123
196
|
return if if_not_exists && table_exists?(table_name)
|
124
197
|
|
125
198
|
# copy schema from existing table
|
@@ -154,6 +227,9 @@ module ActiveRecord
|
|
154
227
|
# # Other column alterations here
|
155
228
|
# end
|
156
229
|
def change_table(table_name, **options)
|
230
|
+
# IMPORTANT: compute will add possible configured prefix & suffix
|
231
|
+
table_name = _compute_table_name(table_name)
|
232
|
+
|
157
233
|
definition = update_table_definition(table_name, self, **options)
|
158
234
|
|
159
235
|
# yield optional block
|
@@ -185,11 +261,20 @@ module ActiveRecord
|
|
185
261
|
_exec_change_table_with(:change_mapping_meta, table_name, name, **options)
|
186
262
|
end
|
187
263
|
|
188
|
-
def change_mapping_attributes(table_name, name, **options
|
264
|
+
def change_mapping_attributes(table_name, name, **options, &block)
|
189
265
|
_exec_change_table_with(:change_mapping_attributes, table_name, name, **options, &block)
|
190
266
|
end
|
267
|
+
|
191
268
|
alias :change_mapping_attribute :change_mapping_attributes
|
192
269
|
|
270
|
+
def change_meta(table_name, name, value, **options)
|
271
|
+
_exec_change_table_with(:change_meta, table_name, name, value, **options)
|
272
|
+
end
|
273
|
+
|
274
|
+
def delete_meta(table_name, name, **options)
|
275
|
+
_exec_change_table_with(:delete_meta, table_name, name, **options)
|
276
|
+
end
|
277
|
+
|
193
278
|
# -- setting -------------------------------------------------------------------------------------------------
|
194
279
|
|
195
280
|
def add_setting(table_name, name, value, **options, &block)
|
@@ -220,6 +305,15 @@ module ActiveRecord
|
|
220
305
|
|
221
306
|
private
|
222
307
|
|
308
|
+
def _compute_table_name(table_name)
|
309
|
+
# HINT: +"" creates a new +unfrozen+ string!
|
310
|
+
str = +""
|
311
|
+
str << table_name_prefix unless table_name.to_s.start_with?(table_name_prefix)
|
312
|
+
str << table_name
|
313
|
+
str << table_name_suffix unless table_name.to_s.end_with?(table_name_suffix)
|
314
|
+
str
|
315
|
+
end
|
316
|
+
|
223
317
|
def _exec_change_table_with(method, table_name, *args, **kwargs, &block)
|
224
318
|
change_table(table_name) do |t|
|
225
319
|
t.send(method, *args, **kwargs, &block)
|
@@ -45,10 +45,11 @@ module ActiveRecord # :nodoc:
|
|
45
45
|
|
46
46
|
# defines the Elasticsearch 'base' structure, which is always included but cannot be resolved through mappings ...
|
47
47
|
BASE_STRUCTURE = [
|
48
|
-
{ 'name' => '_id', 'type' => 'keyword', 'virtual' => true, 'meta' => { 'primary_key' => 'true' } },
|
48
|
+
{ 'name' => '_id', 'type' => 'keyword', 'virtual' => true, 'enabled' => true, 'meta' => { 'primary_key' => 'true' } },
|
49
49
|
{ 'name' => '_index', 'type' => 'keyword', 'virtual' => true },
|
50
50
|
{ 'name' => '_score', 'type' => 'float', 'virtual' => true },
|
51
|
-
{ 'name' => '_type', 'type' => 'keyword', 'virtual' => true }
|
51
|
+
{ 'name' => '_type', 'type' => 'keyword', 'virtual' => true },
|
52
|
+
{ 'name' => '_ignored', 'type' => 'boolean', 'virtual' => true }
|
52
53
|
].freeze
|
53
54
|
|
54
55
|
include Elasticsearch::UnsupportedImplementation
|
@@ -152,6 +153,20 @@ module ActiveRecord # :nodoc:
|
|
152
153
|
@prepared_statements = false
|
153
154
|
end
|
154
155
|
|
156
|
+
def schema_migration # :nodoc:
|
157
|
+
@schema_migration ||= ElasticsearchRecord::SchemaMigration
|
158
|
+
end
|
159
|
+
|
160
|
+
# provide a table_name_prefix from the configuration to create & restrict schema creation
|
161
|
+
def table_name_prefix
|
162
|
+
@config.fetch(:table_name_prefix, '')
|
163
|
+
end
|
164
|
+
|
165
|
+
# provide a table_name_suffix from the configuration to create & restrict schema creation
|
166
|
+
def table_name_suffix
|
167
|
+
@config.fetch(:table_name_suffix, '')
|
168
|
+
end
|
169
|
+
|
155
170
|
# overwrite method to provide a Elasticsearch path
|
156
171
|
def migrations_paths
|
157
172
|
@config[:migrations_paths] || ['db/migrate_elasticsearch']
|
@@ -23,11 +23,35 @@ module Arel # :nodoc: all
|
|
23
23
|
# set the name of the index
|
24
24
|
claim(:index, visit(o.name))
|
25
25
|
|
26
|
+
if o.metas.present? || o.mappings.present?
|
27
|
+
assign(:mappings, {}) do
|
28
|
+
# sets metas
|
29
|
+
resolve(o, :visit_TableMetas) if o.metas.present?
|
30
|
+
|
31
|
+
# sets mappings
|
32
|
+
resolve(o, :visit_TableMappings) if o.mappings.present?
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
26
36
|
# sets settings
|
27
37
|
resolve(o, :visit_TableSettings) if o.settings.present?
|
28
38
|
|
29
|
-
# sets
|
30
|
-
resolve(o, :
|
39
|
+
# sets aliases
|
40
|
+
resolve(o, :visit_TableAliases) if o.aliases.present?
|
41
|
+
end
|
42
|
+
|
43
|
+
def visit_CloneTableDefinition(o)
|
44
|
+
# prepare query
|
45
|
+
claim(:type, ::ElasticsearchRecord::Query::TYPE_INDEX_CLONE)
|
46
|
+
|
47
|
+
# set the name of the index
|
48
|
+
claim(:index, visit(o.name))
|
49
|
+
|
50
|
+
# set the name of the target
|
51
|
+
claim(:argument, :target, visit(o.target))
|
52
|
+
|
53
|
+
# sets settings
|
54
|
+
resolve(o, :visit_TableSettings) if o.settings.present?
|
31
55
|
|
32
56
|
# sets aliases
|
33
57
|
resolve(o, :visit_TableAliases) if o.aliases.present?
|
@@ -41,6 +65,15 @@ module Arel # :nodoc: all
|
|
41
65
|
visit(o.definition)
|
42
66
|
end
|
43
67
|
|
68
|
+
def visit_ChangeMetaDefinition(o)
|
69
|
+
# prepare query
|
70
|
+
claim(:type, ::ElasticsearchRecord::Query::TYPE_INDEX_UPDATE_MAPPING)
|
71
|
+
|
72
|
+
assign(:_meta, {}) do
|
73
|
+
resolve(o.items, :visit_TableMetaDefinition)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
44
77
|
def visit_ChangeMappingDefinition(o)
|
45
78
|
# prepare query
|
46
79
|
claim(:type, ::ElasticsearchRecord::Query::TYPE_INDEX_UPDATE_MAPPING)
|
@@ -95,10 +128,14 @@ module Arel # :nodoc: all
|
|
95
128
|
end
|
96
129
|
|
97
130
|
def visit_TableMappings(o)
|
98
|
-
assign(:
|
99
|
-
|
100
|
-
|
101
|
-
|
131
|
+
assign(:properties, {}) do
|
132
|
+
resolve(o.mappings, :visit_TableMappingDefinition)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def visit_TableMetas(o)
|
137
|
+
assign(:_meta, {}) do
|
138
|
+
resolve(o.metas, :visit_TableMetaDefinition)
|
102
139
|
end
|
103
140
|
end
|
104
141
|
|
@@ -112,8 +149,12 @@ module Arel # :nodoc: all
|
|
112
149
|
assign(o.name, o.value, :__force__)
|
113
150
|
end
|
114
151
|
|
152
|
+
def visit_TableMetaDefinition(o)
|
153
|
+
assign(o.name, o.value)
|
154
|
+
end
|
155
|
+
|
115
156
|
def visit_TableMappingDefinition(o)
|
116
|
-
assign(o.name, o.attributes.merge({type: type_to_sql(o.type)}))
|
157
|
+
assign(o.name, o.attributes.merge({ type: type_to_sql(o.type) }))
|
117
158
|
end
|
118
159
|
|
119
160
|
def visit_TableAliasDefinition(o)
|