Class: ActiveRecord::ConnectionAdapters::ElasticsearchAdapter

Constant Summary collapse

ADAPTER_NAME =

defines the Elasticsearch adapter name.

Returns:

  • (String)
"Elasticsearch".freeze
METADATA_FIELDS =

defines the Elasticsearch 'base' structure, which is always included but cannot be resolved through mappings ...

Returns:

  • (Hash)
[
  { 'name' => '_id', 'type' => 'keyword', 'meta' => { 'primary_key' => 'true' } },
  { 'name' => '_index', 'type' => 'keyword', 'virtual' => true },
  { 'name' => '_score', 'type' => 'float', 'virtual' => true },
  { 'name' => '_type', 'type' => 'keyword', 'virtual' => true },
  { 'name' => '_ignored', 'type' => 'boolean', 'virtual' => true }
].freeze
TYPE_MAP =

-- TYPE MAP -- DO NOT insert before this line (initialize_type_map needs to be rewritten) reinitialize the constant with new types

ActiveRecord::Type::HashLookupTypeMap.new.tap { |m| initialize_type_map(m) }
NATIVE_DATABASE_TYPES =

define native types - which will be used for schema-dumping

Returns:

  • (Hash)
{
  primary_key: { name: 'long' }, # maybe this hae to changed to 'keyword'
  string:   { name: 'keyword' },
  blob:     { name: 'binary' },
  datetime: { name: 'date' },
  bigint:   { name: 'long' },
  json:     { name: 'object' },

  **TYPE_MAP.keys.map { |key| [key.to_sym, { name: key }] }.to_h
}.freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeElasticsearchAdapter

Returns a new instance of ElasticsearchAdapter.



152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/active_record/connection_adapters/elasticsearch_adapter.rb', line 152

def initialize(...)
  super

  # transform provided config
  config         = @config.dup

  # move 'username' to 'user'
  config[:user]  = config.delete(:username) if config[:username]

  # append 'port' to 'host'
  config[:host]  += ":#{config.delete(:port)}" if config[:port] && config[:host]

  # move 'host' to 'hosts'
  config[:hosts] = config.delete(:host) if config[:host]

  @connection_parameters = config
end

Class Method Details

.metadata_keysObject



60
61
62
63
# File 'lib/active_record/connection_adapters/elasticsearch_adapter.rb', line 60

def 
  # using a class_variable to not reinitialize for descendants
  @@metadata_keys ||= METADATA_FIELDS.map { |struct| struct['name'] }.freeze
end

.new_client(config) ⇒ Object



65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/active_record/connection_adapters/elasticsearch_adapter.rb', line 65

def new_client(config)
  # IMPORTANT: remove +adapter+ from config - otherwise we mess up with Faraday::AdapterRegistry
  client_config          = config.except(:adapter)
  # add rails logger manually, if +:log+ is true
  client_config[:logger] = logger if client_config.delete(:log)

  # build and return new client
  ::Elasticsearch::Client.new(client_config)
rescue ::Elastic::Transport::Transport::Errors::Unauthorized
  raise ::ActiveRecord::DatabaseConnectionError.username_error(config[:user])
rescue ::Elastic::Transport::Transport::ServerError => error
  raise ::ActiveRecord::ConnectionNotEstablished, error.message
end

Instance Method Details

#active?Boolean

Returns:

  • (Boolean)


304
305
306
# File 'lib/active_record/connection_adapters/elasticsearch_adapter.rb', line 304

def active?
  !!@raw_connection&.ping
end

#api(gate, arguments = {}, name = 'API', async: false, allow_retry: false, materialize_transactions: false) ⇒ Elasticsearch::API::Response, Object

calls the elasticsearch-api endpoints by provided gate and returns a response object.

Parameters:

  • gate (Symbol, String)
    • the API namespace & action gate (e.g. 'indices.get','cluster.health', :bulk, ...)
  • arguments (Hash) (defaults to: {})
    • gate arguments
  • name (String (frozen)) (defaults to: 'API')
    • the logging name
  • async (Boolean) (defaults to: false)
    • send async (default: false) - NOT supported!
  • allow_retry (Boolean) (defaults to: false)
    • allows to retry a possible failing query (default: false)
  • materialize_transactions (Boolean) (defaults to: false)
    • materializes transactions (default: false) - NOT supported!

Returns:

  • (Elasticsearch::API::Response, Object)

Raises:

  • (::ArgumentError)


247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
# File 'lib/active_record/connection_adapters/elasticsearch_adapter.rb', line 247

def api(gate, arguments = {}, name = 'API', async: false, allow_retry: false, materialize_transactions: false)
  raise ::ArgumentError, "ElasticsearchRecord API call is now using a single `gate` instead of providing `namespace & action`.\n'core' namespace must not provided (only provide action symbol) - any other must be provided as string (e.g. 'nodes.stats')" if arguments.is_a?(Symbol)
  raise ::StandardError, 'ASYNC api calls are not supported' if async

  # drop 'core.' prefix, if provided
  if gate.is_a?(String) && gate[0..4] == 'core.'
    # add deprecation warning
    ::ActiveRecord.deprecator.warn(<<~MSG)
      Providing the 'core.' namespace prefix in the `gate` parameter is deprecated and will be removed in a future version.
      Please provide only the action symbol (e.g.:bulk) or the full namespace and action as a string (e.g.'nodes.stats')
    MSG

    # IMPORTANT: only strip the *prefix* - a +gsub+ would also replace any later occurrence
    # (e.g. 'core.score.thing' would become :sthing)
    gate = gate.delete_prefix('core.').to_sym
  end

  # PLEASE NOTE: Don't remove the +statistics+ assignment here.
  # - this is required as referenced hash for the instrumentation
  log(gate, arguments, name, async: async, statistics: (statistics = {})) do
    with_raw_connection(allow_retry: allow_retry, materialize_transactions: materialize_transactions) do |conn|
      response = ::ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
        # determinate the correct target from the provided gate
        if gate.is_a?(Symbol) || !gate.include?('.')
          conn.__send__(gate, arguments)
        else
          namespace, action = gate.split('.')
          conn.__send__(namespace).__send__(action, arguments)
        end
      end

      # marks the connection as verified (an AbstractAdapter method, which is used to decide how errors and connections are handled)
      verified!

      if response.is_a?(::Elasticsearch::API::Response)
        # reverse information for the LogSubscriber - shows the 'query-time' in the logs
        # this works, since we use a referenced hash ...
        statistics[:took] = response['took']

        # raise timeouts
        raise(::ActiveRecord::StatementTimeout, "Elasticsearch api request failed due a timeout") if response['timed_out']
      end

      # return response
      response
    end
  end
end

#begin_db_transactionObject Originally defined in module ActiveRecord::ConnectionAdapters::Elasticsearch::Transactions

Begins the transaction (and turns off auto-committing).

#commit_db_transactionObject Originally defined in module ActiveRecord::ConnectionAdapters::Elasticsearch::Transactions

Commits the transaction (and turns on auto-committing).

#create_savepointObject Originally defined in module ActiveRecord::ConnectionAdapters::Elasticsearch::Transactions

#default_prepared_statementsObject

prepared statements are not supported by Elasticsearch. documentation for mysql prepares statements @ https://dev.mysql.com/doc/refman/8.0/en/sql-prepared-statements.html



193
194
195
# File 'lib/active_record/connection_adapters/elasticsearch_adapter.rb', line 193

def default_prepared_statements
  false
end

#disconnect!Object

Disconnects from the database if already connected. Otherwise, this method does nothing.



310
311
312
313
314
315
316
# File 'lib/active_record/connection_adapters/elasticsearch_adapter.rb', line 310

def disconnect!
  @lock.synchronize do
    super
    # no need to 'close' a connection for +::Elasticsearch::Client+ / +::Elastic::Transport+
    @raw_connection = nil
  end
end

#exec_rollback_db_transactionObject Originally defined in module ActiveRecord::ConnectionAdapters::Elasticsearch::Transactions

rollback transaction

#exec_rollback_to_savepointObject Originally defined in module ActiveRecord::ConnectionAdapters::Elasticsearch::Transactions

#migrations_pathsObject

overwrite method to provide a Elasticsearch path



187
188
189
# File 'lib/active_record/connection_adapters/elasticsearch_adapter.rb', line 187

def migrations_paths
  @config[:migrations_paths] || ['db/migrate_elasticsearch']
end

#native_database_typesHash

returns a hash of 'ActiveRecord types' -> 'Elasticsearch types' (defined @ NATIVE_DATABASE_TYPES)

Returns:

  • (Hash)


235
236
237
# File 'lib/active_record/connection_adapters/elasticsearch_adapter.rb', line 235

def native_database_types # :nodoc:
  NATIVE_DATABASE_TYPES
end

#quoted_falseObject Originally defined in module ActiveRecord::ConnectionAdapters::Elasticsearch::Quoting

#quoted_trueObject Originally defined in module ActiveRecord::ConnectionAdapters::Elasticsearch::Quoting

#reconnectObject



296
297
298
299
300
301
302
# File 'lib/active_record/connection_adapters/elasticsearch_adapter.rb', line 296

def reconnect
  @lock.synchronize do
    # no need to 'close' a connection for +::Elasticsearch::Client+ / +::Elastic::Transport+
    @raw_connection = nil
    connect
  end
end

#release_savepointObject Originally defined in module ActiveRecord::ConnectionAdapters::Elasticsearch::Transactions

#schema_migrationObject

:nodoc:



170
171
172
# File 'lib/active_record/connection_adapters/elasticsearch_adapter.rb', line 170

def schema_migration # :nodoc:
  ElasticsearchRecord::SchemaMigration.new(self)
end

#supports_comments?Boolean

Does this adapter support metadata comments on database objects (tables)? PLEASE NOTE: Elasticsearch does only support comments on mappings as 'meta' information. This method only relies to create comments on tables (indices) and is therefore not supported. see @ ActiveRecord::ConnectionAdapters::SchemaStatements#create_table

Returns:

  • (Boolean)


218
219
220
# File 'lib/active_record/connection_adapters/elasticsearch_adapter.rb', line 218

def supports_comments?
  false
end

#supports_comments_in_create?Boolean

Can comments for tables, columns, and indexes be specified in create/alter table statements? see @ ActiveRecord::ConnectionAdapters::ElasticsearchAdapter#supports_comments?

Returns:

  • (Boolean)


224
225
226
# File 'lib/active_record/connection_adapters/elasticsearch_adapter.rb', line 224

def supports_comments_in_create?
  false
end

#supports_explain?Boolean

Does this adapter support explain?

Returns:

  • (Boolean)


204
205
206
# File 'lib/active_record/connection_adapters/elasticsearch_adapter.rb', line 204

def supports_explain?
  false
end

#supports_indexes_in_create?Boolean

Does this adapter support creating indexes in the same statement as creating the table?

Returns:

  • (Boolean)


210
211
212
# File 'lib/active_record/connection_adapters/elasticsearch_adapter.rb', line 210

def supports_indexes_in_create?
  false
end

#supports_transactions?Boolean

Does this adapter support transactions in general? HINT: This is not an official setting and only introduced to ElasticsearchRecord.

Returns:

  • (Boolean)


199
200
201
# File 'lib/active_record/connection_adapters/elasticsearch_adapter.rb', line 199

def supports_transactions?
  false
end

#table_name_prefixObject

provide a table_name_prefix from the configuration to create & restrict schema creation HINT: This is not an official setting and only introduced to ElasticsearchRecord.



176
177
178
# File 'lib/active_record/connection_adapters/elasticsearch_adapter.rb', line 176

def table_name_prefix
  @config.fetch(:table_name_prefix, '')
end

#table_name_suffixObject

provide a table_name_suffix from the configuration to create & restrict schema creation HINT: This is not an official setting and only introduced to ElasticsearchRecord.



182
183
184
# File 'lib/active_record/connection_adapters/elasticsearch_adapter.rb', line 182

def table_name_suffix
  @config.fetch(:table_name_suffix, '')
end

#transactionObject Originally defined in module ActiveRecord::ConnectionAdapters::Elasticsearch::Transactions

#use_metadata_table?Boolean

disable metadata tables

Returns:

  • (Boolean)


229
230
231
# File 'lib/active_record/connection_adapters/elasticsearch_adapter.rb', line 229

def  # :nodoc:
  false
end