elasticsearch_record 1.0.2 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +4 -0
  3. data/Gemfile.lock +10 -14
  4. data/README.md +180 -27
  5. data/docs/CHANGELOG.md +36 -18
  6. data/docs/LICENSE.txt +1 -1
  7. data/elasticsearch_record.gemspec +42 -0
  8. data/lib/active_record/connection_adapters/elasticsearch/column.rb +20 -6
  9. data/lib/active_record/connection_adapters/elasticsearch/database_statements.rb +142 -125
  10. data/lib/active_record/connection_adapters/elasticsearch/quoting.rb +2 -23
  11. data/lib/active_record/connection_adapters/elasticsearch/schema_creation.rb +30 -0
  12. data/lib/active_record/connection_adapters/elasticsearch/schema_definitions/attribute_methods.rb +103 -0
  13. data/lib/active_record/connection_adapters/elasticsearch/schema_definitions/column_methods.rb +42 -0
  14. data/lib/active_record/connection_adapters/elasticsearch/schema_definitions/create_table_definition.rb +158 -0
  15. data/lib/active_record/connection_adapters/elasticsearch/schema_definitions/table_alias_definition.rb +32 -0
  16. data/lib/active_record/connection_adapters/elasticsearch/schema_definitions/table_definition.rb +132 -0
  17. data/lib/active_record/connection_adapters/elasticsearch/schema_definitions/table_mapping_definition.rb +110 -0
  18. data/lib/active_record/connection_adapters/elasticsearch/schema_definitions/table_setting_definition.rb +136 -0
  19. data/lib/active_record/connection_adapters/elasticsearch/schema_definitions/update_table_definition.rb +174 -0
  20. data/lib/active_record/connection_adapters/elasticsearch/schema_definitions.rb +37 -0
  21. data/lib/active_record/connection_adapters/elasticsearch/schema_dumper.rb +110 -0
  22. data/lib/active_record/connection_adapters/elasticsearch/schema_statements.rb +398 -174
  23. data/lib/active_record/connection_adapters/elasticsearch/table_statements.rb +232 -0
  24. data/lib/active_record/connection_adapters/elasticsearch/type/multicast_value.rb +2 -0
  25. data/lib/active_record/connection_adapters/elasticsearch/unsupported_implementation.rb +32 -0
  26. data/lib/active_record/connection_adapters/elasticsearch_adapter.rb +112 -19
  27. data/lib/arel/collectors/elasticsearch_query.rb +0 -1
  28. data/lib/arel/visitors/elasticsearch.rb +7 -579
  29. data/lib/arel/visitors/elasticsearch_base.rb +234 -0
  30. data/lib/arel/visitors/elasticsearch_query.rb +463 -0
  31. data/lib/arel/visitors/elasticsearch_schema.rb +124 -0
  32. data/lib/elasticsearch_record/core.rb +44 -10
  33. data/lib/elasticsearch_record/errors.rb +13 -0
  34. data/lib/elasticsearch_record/gem_version.rb +6 -2
  35. data/lib/elasticsearch_record/instrumentation/log_subscriber.rb +27 -9
  36. data/lib/elasticsearch_record/model_schema.rb +5 -0
  37. data/lib/elasticsearch_record/persistence.rb +31 -26
  38. data/lib/elasticsearch_record/query.rb +56 -17
  39. data/lib/elasticsearch_record/querying.rb +17 -0
  40. data/lib/elasticsearch_record/relation/calculation_methods.rb +3 -0
  41. data/lib/elasticsearch_record/relation/core_methods.rb +57 -17
  42. data/lib/elasticsearch_record/relation/query_clause_tree.rb +38 -1
  43. data/lib/elasticsearch_record/relation/query_methods.rb +6 -0
  44. data/lib/elasticsearch_record/relation/result_methods.rb +15 -9
  45. data/lib/elasticsearch_record/result.rb +32 -5
  46. data/lib/elasticsearch_record/statement_cache.rb +2 -1
  47. data/lib/elasticsearch_record.rb +2 -2
  48. metadata +29 -11
  49. data/.ruby-version +0 -1
  50. data/lib/elasticsearch_record/schema_migration.rb +0 -30
@@ -3,202 +3,426 @@
3
3
  module ActiveRecord
4
4
  module ConnectionAdapters
5
5
  module Elasticsearch
6
- module SchemaStatements # :nodoc:
6
+ # extend adapter with schema-related statements
7
+ #
8
+ # *ORIGINAL* methods untouched:
9
+ # - internal_string_options_for_primary_key
10
+ # - options_include_default?
11
+ # - fetch_type_metadata
12
+ # - column_exists?
13
+ #
14
+ # *SUPPORTED* but not used:
15
+ # - strip_table_name_prefix_and_suffix
16
+ #
17
+ # *UNSUPPORTED* methods that will be +ignored+:
18
+ # - native_database_types
19
+ # - table_options
20
+ # - table_comment
21
+ # - table_alias_for
22
+ # - columns_for_distinct
23
+ # - extract_new_default_value
24
+ # - insert_versions_sql
25
+ # - data_source_sql
26
+ # - quoted_scope
27
+ # - add_column_for_alter
28
+ # - rename_column_sql
29
+ # - remove_column_for_alter
30
+ # - remove_columns_for_alter
31
+ # - add_timestamps_for_alter
32
+ # - remove_timestamps_for_alter
33
+ # - foreign_key_name
34
+ # - foreign_key_for
35
+ # - foreign_key_for!
36
+ # - extract_foreign_key_action
37
+ # - check_constraint_name
38
+ # - check_constraint_for
39
+ # - check_constraint_for!
40
+ # - validate_index_length!
41
+ # - can_remove_index_by_name?
42
+ # - index_column_names
43
+ # - index_name_options
44
+ # - add_index_sort_order
45
+ # - options_for_index_columns
46
+ # - add_options_for_index_columns
47
+ # - index_name_for_remove
48
+ # - add_index_options
49
+ # - index_algorithm
50
+ # - quoted_columns_for_index
51
+ # - check_constraint_options
52
+ # - check_constraints
53
+ # - foreign_key_exists?
54
+ # - foreign_key_column_for
55
+ # - foreign_key_options
56
+ # - foreign_keys
57
+ # - index_name_exists?
58
+ # - indexes
59
+ # - index_name
60
+ # - index_exists?
61
+ #
62
+ # *UNSUPPORTED* methods that will +fail+:
63
+ # - views
64
+ # - view_exists?
65
+ # - add_index
66
+ # - remove_index
67
+ # - rename_index
68
+ # - add_reference
69
+ # - remove_reference
70
+ # - add_foreign_key
71
+ # - remove_foreign_key
72
+ # - add_check_constraint
73
+ # - remove_check_constraint
74
+ # - rename_table_indexes
75
+ # - rename_column_indexes
76
+ # - create_alter_table
77
+ # - insert_fixture
78
+ # - insert_fixtures_set
79
+ # - bulk_change_table
80
+ # - dump_schema_information
81
+ #
82
+ # OVERWRITTEN methods for Elasticsearch:
83
+ # ...
84
+ module SchemaStatements
85
+ extend ActiveSupport::Concern
7
86
 
8
- # temporary workaround
9
- # toDo: fixme
10
- def create_table(*args)
11
- $stdout.puts "\n>>> 'create_table' elasticsearch is not supported - the following message is insignificant!"
12
- end
87
+ included do
88
+ define_unsupported_method :views, :view_exists?, :add_index, :remove_index, :rename_index, :add_reference,
89
+ :remove_reference, :add_foreign_key, :remove_foreign_key, :add_check_constraint,
90
+ :remove_check_constraint, :rename_table_indexes, :rename_column_indexes,
91
+ :create_alter_table, :insert_fixture, :insert_fixtures_set, :bulk_change_table,
92
+ :dump_schema_information
13
93
 
14
- # temporary workaround
15
- # toDo: fixme
16
- def assume_migrated_upto_version(version)
17
- $stdout.puts "\n>>> 'assume_migrated_upto_version' elasticsearch is not supported - the following message is insignificant!"
18
- end
94
+ def assume_migrated_upto_version(version)
95
+ version = version.to_i
96
+ migrated = migration_context.get_all_versions
97
+ versions = migration_context.migrations.map(&:version)
19
98
 
99
+ unless migrated.include?(version)
100
+ # use a ActiveRecord syntax to create a new version
101
+ schema_migration.create(version: version)
102
+ end
20
103
 
104
+ inserting = (versions - migrated).select { |v| v < version }
105
+ if inserting.any?
106
+ if (duplicate = inserting.detect { |v| inserting.count(v) > 1 })
107
+ raise "Duplicate migration #{duplicate}. Please renumber your migrations to resolve the conflict."
108
+ end
21
109
 
110
+ # use a ActiveRecord syntax to create new versions
111
+ inserting.each {|iversion| schema_migration.create(version: iversion) }
112
+ end
22
113
 
114
+ true
115
+ end
23
116
 
24
- # Returns the relation names usable to back Active Record models.
25
- # For Elasticsearch this means all indices - which also includes system +dot+ '.' indices.
26
- # @see ActiveRecord::ConnectionAdapters::SchemaStatements#data_sources
27
- # @return [Array<String>]
28
- def data_sources
29
- api(:indices, :get_settings, { index: :_all }, 'SCHEMA').keys
30
- end
117
+ # Returns the relation names usable to back Active Record models.
118
+ # For Elasticsearch this means all indices - which also includes system +dot+ '.' indices.
119
+ # @see ActiveRecord::ConnectionAdapters::SchemaStatements#data_sources
120
+ # @return [Array<String>]
121
+ def data_sources
122
+ api(:indices, :get, { index: :_all, expand_wildcards: [:open, :closed] }, 'SCHEMA').keys
123
+ end
31
124
 
32
- # returns a hash of all mappings by provided index_name
33
- # @param [String] index_name
34
- # @return [Hash]
35
- def mappings(index_name)
36
- api(:indices, :get_mapping, { index: index_name }, 'SCHEMA').dig(index_name, 'mappings')
37
- end
125
+ # Returns an array of table names defined in the database.
126
+ # For Elasticsearch this means all normal indices (no system +dot+ '.' indices)
127
+ # @see ActiveRecord::ConnectionAdapters::SchemaStatements#tables
128
+ # @return [Array<String>]
129
+ def tables
130
+ data_sources.reject { |key| key[0] == '.' }
131
+ end
38
132
 
39
- # returns a hash of all settings by provided index_name
40
- # @param [String] index_name
41
- # @return [Hash]
42
- def settings(index_name)
43
- api(:indices, :get_settings, { index: index_name }, 'SCHEMA').dig(index_name, 'settings', 'index')
44
- end
133
+ # returns a hash of all mappings by provided table_name (index)
134
+ # @param [String] table_name
135
+ # @return [Hash]
136
+ def table_mappings(table_name)
137
+ api(:indices, :get_mapping, { index: table_name, expand_wildcards: [:open, :closed] }, 'SCHEMA').dig(table_name, 'mappings')
138
+ end
45
139
 
46
- # Returns the list of a table's column names, data types, and default values.
47
- # @see ActiveRecord::ConnectionAdapters::SchemaStatements#columns
48
- # @see ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter#column_definitions
49
- # @param [String] table_name
50
- # @return [Array<Hash>]
51
- def column_definitions(table_name)
52
- structure = mappings(table_name)
53
- raise(ActiveRecord::StatementInvalid, "Could not find elasticsearch index '#{table_name}'") if structure.blank? || structure['properties'].blank?
54
-
55
- # since the received mappings do not have the "primary" +_id+-column we manually need to add this here
56
- # The BASE_STRUCTURE will also include some meta keys like '_score', '_type', ...
57
- ActiveRecord::ConnectionAdapters::ElasticsearchAdapter::BASE_STRUCTURE + structure['properties'].map { |key, prop|
58
- # resolve (nested) fields and properties
59
- fields, properties = resolve_fields_and_properties(key, prop, true)
60
-
61
- # fallback for possible empty type
62
- type = prop['type'].presence || (properties.present? ? 'object' : 'nested')
63
-
64
- # return a new hash
65
- prop.merge('name' => key, 'type' => type, 'fields' => fields, 'properties' => properties)
66
- }
67
- end
140
+ # returns a hash of all settings by provided table_name
141
+ # @param [String] table_name
142
+ # @param [Boolean] flat_settings (default: true)
143
+ # @return [Hash]
144
+ def table_settings(table_name, flat_settings = true)
145
+ api(:indices, :get_settings, { index: table_name, expand_wildcards: [:open, :closed], flat_settings: flat_settings }, 'SCHEMA').dig(table_name, 'settings')
146
+ end
68
147
 
69
- # creates a new column object from provided field Hash
70
- # @see ActiveRecord::ConnectionAdapters::SchemaStatements#columns
71
- # @see ActiveRecord::ConnectionAdapters::MySQL::SchemaStatements#new_column_from_field
72
- # @param [String] _table_name
73
- # @param [Hash] field
74
- # @return [ActiveRecord::ConnectionAdapters::Column]
75
- def new_column_from_field(_table_name, field)
76
- ActiveRecord::ConnectionAdapters::Elasticsearch::Column.new(
77
- field["name"],
78
- field["null_value"],
79
- fetch_type_metadata(field["type"]),
80
- field['null'].nil? ? true : field['null'],
81
- nil,
82
- comment: field['meta'] ? field['meta'].map { |k, v| "#{k}: #{v}" }.join(' | ') : nil,
83
- virtual: field['virtual'],
84
- fields: field['fields'],
85
- properties: field['properties']
86
- )
87
- end
148
+ # returns a hash of all aliases by provided table_name (index).
149
+ # @param [String] table_name
150
+ # @return [Hash]
151
+ def table_aliases(table_name)
152
+ api(:indices, :get_alias, { index: table_name, expand_wildcards: [:open, :closed] }, 'SCHEMA').dig(table_name, 'aliases')
153
+ end
88
154
 
89
- # lookups from building the @columns_hash.
90
- # since Elasticsearch has the "feature" to provide multicast values on any type, we need to fetch them ...
91
- # you know, ES can return an integer or an array of integers for any column ...
92
- # @param [ActiveRecord::ConnectionAdapters::Elasticsearch::Column] column
93
- # @return [ActiveRecord::ConnectionAdapters::Elasticsearch::Type::MulticastValue]
94
- def lookup_cast_type_from_column(column)
95
- type_map.lookup(:multicast_value, super)
96
- end
155
+ # returns information about number of primaries and replicas, document counts, disk size, ... by provided table_name (index).
156
+ # @param [String] table_name
157
+ # @return [Hash]
158
+ def table_state(table_name)
159
+ response = api(:cat, :indices, { index: table_name, expand_wildcards: [:open, :closed] }, 'SCHEMA')
97
160
 
98
- # Returns a array of tables primary keys.
99
- # PLEASE NOTE: Elasticsearch does not have a concept of primary key.
100
- # The only thing that uniquely identifies a document is the index together with the +_id+.
101
- # To not break the "ConnectionAdapters" concept we simulate this through the BASE_STRUCTURE.
102
- # We know, we can just return '_id' here ...
103
- # @see ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter#primary_keys
104
- # @param [String] _table_name
105
- def primary_keys(_table_name)
106
- ActiveRecord::ConnectionAdapters::ElasticsearchAdapter::BASE_STRUCTURE
107
- .select { |f| f["primary"] }
108
- .map { |f| f["name"] }
109
- end
161
+ [:health, :status, :name, :uuid, :pri, :rep, :docs_count, :docs_deleted, :store_size, :pri_store_size].zip(
162
+ response.body.split(' ')
163
+ ).to_h
164
+ end
110
165
 
111
- # Checks to see if the data source +name+ exists on the database.
112
- #
113
- # data_source_exists?(:ebooks)
114
- # @see ActiveRecord::ConnectionAdapters::SchemaStatements#data_source_exists?
115
- # @param [String, Symbol] name
116
- # @return [Boolean]
117
- def data_source_exists?(name)
118
- # response returns boolean
119
- api(:indices, :exists?, { index: name }, 'SCHEMA')
120
- end
166
+ # returns a hash of the full definition of the provided table_name (index).
167
+ # (includes settings, mappings & aliases)
168
+ # @param [String] table_name
169
+ # @param [Array, Symbol] features
170
+ # @return [Hash]
171
+ def table_schema(table_name, features = [:aliases, :mappings, :settings])
172
+ if cluster_info[:version] >= '8.5.0'
173
+ response = api(:indices, :get, { index: table_name, expand_wildcards: [:open, :closed], features: features, flat_settings: true }, 'SCHEMA')
174
+ else
175
+ response = api(:indices, :get, { index: table_name, expand_wildcards: [:open, :closed], flat_settings: true }, 'SCHEMA')
176
+ end
121
177
 
122
- # Returns an array of table names defined in the database.
123
- # For Elasticsearch this means all normal indices (no system +dot+ '.' indices)
124
- # @see ActiveRecord::ConnectionAdapters::SchemaStatements#tables
125
- # @return [Array<String>]
126
- def tables
127
- data_sources.reject { |key| key[0] == '.' }
128
- end
178
+ {
179
+ settings: response.dig(table_name, 'settings'),
180
+ mappings: response.dig(table_name, 'mappings'),
181
+ aliases: response.dig(table_name, 'aliases')
182
+ }
183
+ end
129
184
 
130
- # Checks to see if the table +table_name+ exists on the database.
131
- #
132
- # table_exists?(:developers)
133
- #
134
- # @see ActiveRecord::ConnectionAdapters::SchemaStatements#table_exists?
135
- # @param [String, Symbol] table_name
136
- # @return [Boolean]
137
- def table_exists?(table_name)
138
- # just reference to the data sources
139
- data_source_exists?(table_name)
140
- end
185
+ # Returns the list of a table's column names, data types, and default values.
186
+ # @see ActiveRecord::ConnectionAdapters::SchemaStatements#columns
187
+ # @see ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter#column_definitions
188
+ # @param [String] table_name
189
+ # @return [Array<Hash>]
190
+ def column_definitions(table_name)
191
+ mappings = table_mappings(table_name)
141
192
 
142
- # returns the maximum allowed size for queries.
143
- # The query will raise an ActiveRecord::StatementInvalid if the requested limit is above this value.
144
- # @return [Integer]
145
- def max_result_window
146
- 10000
147
- end
193
+ # prevent exceptions on missing mappings, to provide the possibility to create them
194
+ # otherwise loading the table (index) will always fail!
195
+ mappings = { 'properties' => {} } if mappings.blank? || mappings['properties'].blank?
196
+ # raise(ActiveRecord::StatementInvalid, "Could not find valid mappings for '#{table_name}'") if mappings.blank? || mappings['properties'].blank?
197
+
198
+ # since the received mappings do not have the "primary" +_id+-column we manually need to add this here
199
+ # The BASE_STRUCTURE will also include some meta keys like '_score', '_type', ...
200
+ ActiveRecord::ConnectionAdapters::ElasticsearchAdapter::BASE_STRUCTURE + mappings['properties'].map { |key, prop|
201
+ # resolve (nested) fields and properties
202
+ fields, properties = resolve_fields_and_properties(key, prop, true)
203
+
204
+ # fallback for possible empty type
205
+ type = prop['type'].presence || (properties.present? ? 'object' : 'nested')
206
+
207
+ # return a new hash
208
+ prop.merge('name' => key, 'type' => type, 'fields' => fields, 'properties' => properties)
209
+ }
210
+ end
211
+
212
+ # creates a new column object from provided field Hash
213
+ # @see ActiveRecord::ConnectionAdapters::SchemaStatements#columns
214
+ # @see ActiveRecord::ConnectionAdapters::MySQL::SchemaStatements#new_column_from_field
215
+ # @param [String] _table_name
216
+ # @param [Hash] field
217
+ # @return [ActiveRecord::ConnectionAdapters::Column]
218
+ def new_column_from_field(_table_name, field)
219
+ ActiveRecord::ConnectionAdapters::Elasticsearch::Column.new(
220
+ field["name"],
221
+ field["null_value"],
222
+ fetch_type_metadata(field["type"]),
223
+ meta: field['meta'],
224
+ virtual: field['virtual'],
225
+ fields: field['fields'],
226
+ properties: field['properties']
227
+ )
228
+ end
229
+
230
+ # lookups from building the @columns_hash.
231
+ # since Elasticsearch has the "feature" to provide multicast values on any type, we need to fetch them ...
232
+ # you know, ES can return an integer or an array of integers for any column ...
233
+ # @param [ActiveRecord::ConnectionAdapters::Elasticsearch::Column] column
234
+ # @return [ActiveRecord::ConnectionAdapters::Elasticsearch::Type::MulticastValue]
235
+ def lookup_cast_type_from_column(column)
236
+ type_map.lookup(:multicast_value, super)
237
+ end
238
+
239
+ # Returns a array of tables primary keys.
240
+ # PLEASE NOTE: Elasticsearch does not have a concept of primary key.
241
+ # The only thing that uniquely identifies a document is the index together with the +_id+.
242
+ # To not break the "ConnectionAdapters" concept we simulate this through the +meta+ attribute.
243
+ # @see ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter#primary_keys
244
+ # @param [String] table_name
245
+ def primary_keys(table_name)
246
+ column_definitions(table_name)
247
+ # ActiveRecord::ConnectionAdapters::ElasticsearchAdapter::BASE_STRUCTURE
248
+ .select { |f| f['meta'] && f['meta']['primary_key'] == 'true' }
249
+ # only take the last found primary key (if no custom primary_key was provided this will return +_id+ )
250
+ .map { |f| f["name"] }[-1..-1]
251
+ end
252
+
253
+ # Checks to see if the data source +name+ exists on the database.
254
+ #
255
+ # data_source_exists?(:ebooks)
256
+ # @see ActiveRecord::ConnectionAdapters::SchemaStatements#data_source_exists?
257
+ # @param [String, Symbol] name
258
+ # @return [Boolean]
259
+ def data_source_exists?(name)
260
+ # response returns boolean
261
+ api(:indices, :exists?, { index: name, expand_wildcards: [:open, :closed] }, 'SCHEMA')
262
+ end
263
+
264
+ # Checks to see if the table +table_name+ exists on the database.
265
+ #
266
+ # table_exists?(:developers)
267
+ #
268
+ # @see ActiveRecord::ConnectionAdapters::SchemaStatements#table_exists?
269
+ # @param [String, Symbol] table_name
270
+ # @return [Boolean]
271
+ def table_exists?(table_name)
272
+ # just reference to the data sources
273
+ data_source_exists?(table_name)
274
+ end
275
+
276
+ # Checks to see if a alias +alias_name+ within a table +table_name+ exists on the database.
277
+ #
278
+ # alias_exists?(:developers, 'my-alias')
279
+ #
280
+ # @param [String] table_name
281
+ # @param [String, Symbol] alias_name
282
+ # @return [Boolean]
283
+ def alias_exists?(table_name, alias_name)
284
+ table_aliases(table_name).keys.include?(alias_name.to_s)
285
+ end
286
+
287
+ # Checks to see if a setting +setting_name+ within a table +table_name+ exists on the database.
288
+ # The provided +setting_name+ must be flat!
289
+ #
290
+ # setting_exists?(:developers, 'index.number_of_replicas')
291
+ #
292
+ # @param [String] table_name
293
+ # @param [String,Symbol] setting_name
294
+ # @return [Boolean]
295
+ def setting_exists?(table_name, setting_name)
296
+ table_settings(table_name).keys.include?(setting_name.to_s)
297
+ end
298
+
299
+ # Checks to see if a mapping +mapping_name+ within a table +table_name+ exists on the database.
300
+ #
301
+ # mapping_exists?(:developers, :status, :integer)
302
+ #
303
+ # @param [String, Symbol] table_name
304
+ # @param [String, Symbol] mapping_name
305
+ # @return [Boolean]
306
+ def mapping_exists?(table_name, mapping_name, type = nil)
307
+ column_exists?(table_name, mapping_name, type)
308
+ end
309
+
310
+ # overwrite original methods to provide a elasticsearch version
311
+ def create_schema_dumper(options)
312
+ ActiveRecord::ConnectionAdapters::Elasticsearch::SchemaDumper.create(self, options)
313
+ end
314
+
315
+ # overwrite original methods to provide a elasticsearch version
316
+ def create_table_definition(name, **options)
317
+ ::ActiveRecord::ConnectionAdapters::Elasticsearch::CreateTableDefinition.new(self, name, **options)
318
+ end
319
+
320
+ # overwrite original methods to provide a elasticsearch version
321
+ def update_table_definition(name, base = self, **options)
322
+ # :nodoc:
323
+ ::ActiveRecord::ConnectionAdapters::Elasticsearch::UpdateTableDefinition.new(base, name, **options)
324
+ end
148
325
 
149
- private
150
-
151
- # returns a multidimensional array with fields & properties from the provided +prop+.
152
- # Nested fields & properties will be also detected.
153
- # .
154
- # resolve_fields_and_properties('user', {...})
155
- # # > [
156
- # # fields
157
- # [0] [
158
- # [0] {
159
- # "name" => "user.name.analyzed",
160
- # "type" => "text"
161
- # }
162
- # ],
163
- # # properties
164
- # [1] [
165
- # [0] {
166
- # "name" => "user.id",
167
- # "type" => "integer"
168
- # },
169
- # [1] {
170
- # "name" => "user.name",
171
- # "type" => "keyword"
172
- # }
173
- # ]
174
- # ]
175
- #
176
- # @param [String] key
177
- # @param [Hash] prop
178
- # @param [Boolean] root - provide true, if this is a top property entry (default: false)
179
- # @return [[Array, Array]]
180
- def resolve_fields_and_properties(key, prop, root = false)
181
- # mappings can have +fields+ - we also want them for 'query-conditions'
182
- fields = (prop['fields'] || {}).map { |field_key, field_def|
183
- { 'name' => "#{key}.#{field_key}", 'type' => field_def['type'] }
184
- }
185
-
186
- # initial empty array
187
- properties = []
188
-
189
- if prop['properties'].present?
190
- prop['properties'].each do |nested_key, nested_prop|
191
- nested_fields, nested_properties = resolve_fields_and_properties("#{key}.#{nested_key}", nested_prop)
192
- fields |= nested_fields
193
- properties |= nested_properties
326
+ # overwrite original methods to provide a elasticsearch version
327
+ def schema_creation
328
+ ::ActiveRecord::ConnectionAdapters::Elasticsearch::SchemaCreation.new(self)
329
+ end
330
+
331
+ # returns the maximum allowed size for queries for the provided +table_name+.
332
+ # The query will raise an ActiveRecord::StatementInvalid if the requested limit is above this value.
333
+ # @return [Integer]
334
+ def max_result_window(table_name)
335
+ table_settings(table_name).dig('index', 'max_result_window').presence || 10000
336
+ end
337
+
338
+ # Returns basic information about the cluster.
339
+ # @return [Hash{Symbol->Unknown}]
340
+ def cluster_info
341
+ @cluster_info ||= begin
342
+ response = api(:core, :info, {}, 'CLUSTER')
343
+
344
+ {
345
+ name: response.dig('name'),
346
+ cluster_name: response.dig('cluster_name'),
347
+ cluster_uuid: response.dig('cluster_uuid'),
348
+ version: Gem::Version.new(response.dig('version', 'number')),
349
+ lucene_version: response.dig('version', 'lucene_version')
350
+ }
351
+ end
352
+ end
353
+
354
+ # transforms provided schema-type to a sql-type
355
+ # @param [String, Symbol] type
356
+ # @param [String]
357
+ def type_to_sql(type, **)
358
+ return '' if type.blank?
359
+
360
+ if (native = native_database_types[type.to_sym])
361
+ (native.is_a?(Hash) ? native[:name] : native).dup
362
+ else
363
+ type.to_s
194
364
  end
195
- elsif !root # don't add the root property as sub-property
196
- properties << { 'name' => key, 'type' => prop['type'] }
197
365
  end
198
366
 
199
- [fields, properties]
367
+ private
368
+
369
+ # returns a multidimensional array with fields & properties from the provided +prop+.
370
+ # Nested fields & properties will be also detected.
371
+ # .
372
+ # resolve_fields_and_properties('user', {...})
373
+ # # > [
374
+ # # fields
375
+ # [0] [
376
+ # [0] {
377
+ # "name" => "user.name.analyzed",
378
+ # "type" => "text"
379
+ # }
380
+ # ],
381
+ # # properties
382
+ # [1] [
383
+ # [0] {
384
+ # "name" => "user.id",
385
+ # "type" => "integer"
386
+ # },
387
+ # [1] {
388
+ # "name" => "user.name",
389
+ # "type" => "keyword"
390
+ # }
391
+ # ]
392
+ # ]
393
+ #
394
+ # @param [String] key
395
+ # @param [Hash] prop
396
+ # @param [Boolean] root - provide true, if this is a top property entry (default: false)
397
+ # @return [[Array, Array]]
398
+ def resolve_fields_and_properties(key, prop, root = false)
399
+ # mappings can have +fields+ - we also want them for 'query-conditions'
400
+ fields = (prop['fields'] || {}).map { |field_key, field_def|
401
+ { 'name' => "#{key}.#{field_key}", 'type' => field_def['type'] }
402
+ }
403
+
404
+ # initial empty array
405
+ properties = []
406
+
407
+ if prop['properties'].present?
408
+ prop['properties'].each do |nested_key, nested_prop|
409
+ nested_fields, nested_properties = resolve_fields_and_properties("#{key}.#{nested_key}", nested_prop)
410
+ fields |= nested_fields
411
+ properties |= nested_properties
412
+ end
413
+ elsif !root # don't add the root property as sub-property
414
+ properties << { 'name' => key, 'type' => prop['type'] }
415
+ end
416
+
417
+ [fields, properties]
418
+ end
419
+
420
+ # overwrite original methods to provide a elasticsearch version
421
+ def extract_table_options!(options)
422
+ options.extract!(:settings, :mappings, :aliases, :force, :strict)
423
+ end
200
424
  end
201
425
  end
202
426
  end
203
427
  end
204
- end
428
+ end