Class: ActiveRecord::ConnectionAdapters::SpannerAdapter

Inherits:
AbstractAdapter
  • Object
show all
Extended by:
TypeMapBuilder
Includes:
ActiveRecord::ConnectionAdapters::Spanner::DatabaseStatements, ActiveRecord::ConnectionAdapters::Spanner::Quoting, ActiveRecord::ConnectionAdapters::Spanner::SchemaStatements, TypeMapBuilder
Defined in:
lib/active_record/connection_adapters/spanner_adapter.rb

Defined Under Namespace

Modules: TypeMapBuilder

Constant Summary collapse

ADAPTER_NAME =
"spanner".freeze
TYPE_MAP =
Type::TypeMap.new.tap { |m| initialize_type_map m }

Constants included from ActiveRecord::ConnectionAdapters::Spanner::SchemaStatements

ActiveRecord::ConnectionAdapters::Spanner::SchemaStatements::VERSION_7_2, ActiveRecord::ConnectionAdapters::Spanner::SchemaStatements::VERSION_8_1

Constants included from ActiveRecord::ConnectionAdapters::Spanner::DatabaseStatements

ActiveRecord::ConnectionAdapters::Spanner::DatabaseStatements::COMMENT_REGEX, ActiveRecord::ConnectionAdapters::Spanner::DatabaseStatements::RequestOptions, ActiveRecord::ConnectionAdapters::Spanner::DatabaseStatements::TransactionMutationLimitExceededError, ActiveRecord::ConnectionAdapters::Spanner::DatabaseStatements::VERSION_7_1_0

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from ActiveRecord::ConnectionAdapters::Spanner::SchemaStatements

#_add_foreign_key, #_remove_columns, #add_column, #add_foreign_key, #add_index, #add_reference, #assume_migrated_upto_version, #change_column, #change_column_default, #change_column_null, #check_constraints, #column_definitions, #create_join_table, #create_schema_dumper, #create_table, #current_database, #data_sources, #drop_table, #extract_schema_qualified_name, #fetch_type_metadata, #foreign_keys, #index_name_exists?, #indexes, #insert_versions_sql, #migration_context, #new_column_from_field, #primary_and_parent_keys, #primary_keys, #quoted_scope, #remove_column, #remove_columns, #remove_foreign_key, #remove_index, #rename_column, #rename_index, #rename_table, #schema_migration, #table_exists?, #type_to_sql

Methods included from ActiveRecord::ConnectionAdapters::Spanner::DatabaseStatements

#_has_pk_binding, #append_request_tag_from_query_logs, #append_request_tag_from_query_logs_with_format, #begin_db_transaction, #begin_isolated_db_transaction, #commit_db_transaction, #exec_mutation, #exec_query, #exec_update, #execute, #execute_ddl, #execute_query_or_dml, #internal_exec_query, #internal_execute, #query, #rollback_db_transaction, #sql_for_insert, #transaction, #transaction_isolation_levels, #truncate, #update, #write_query?

Methods included from ActiveRecord::ConnectionAdapters::Spanner::Quoting

#_type_cast, #quote_column_name, #quote_string, #quote_table_name, #quoted_binary

Constructor Details

#initialize(config_or_deprecated_connection, deprecated_logger = nil, deprecated_connection_options = nil, deprecated_config = nil) ⇒ SpannerAdapter

Returns a new instance of SpannerAdapter.



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/active_record/connection_adapters/spanner_adapter.rb', line 62

def initialize config_or_deprecated_connection, deprecated_logger = nil,
               deprecated_connection_options = nil, deprecated_config = nil
  if config_or_deprecated_connection.is_a? Hash
    @connection = ActiveRecordSpannerAdapter::Connection.new config_or_deprecated_connection
    @connection.connect!
    super config_or_deprecated_connection
    @raw_connection ||= @connection
  else
    @connection = config_or_deprecated_connection
    @connection_options = deprecated_connection_options
    super config_or_deprecated_connection, deprecated_logger, deprecated_config
    @raw_connection ||= config_or_deprecated_connection
  end
  # Spanner does not support unprepared statements
  @prepared_statements = true
  # The default for default_sequence_kind will be changed to BIT_REVERSED_POSITIVE
  # in the next major version. The default value is currently DISABLED to prevent
  # breaking changes to existing code.
  @default_sequence_kind = @config.fetch :default_sequence_kind, "DISABLED"
  @use_auto_increment = @default_sequence_kind&.casecmp? "AUTO_INCREMENT"
  @auto_increment_disabled = @default_sequence_kind&.casecmp? "DISABLED"
  @use_client_side_id_for_mutations = self.class.type_cast_config_to_boolean(
    @config.fetch(:use_client_side_id_for_mutations, false)
  )
end

Instance Attribute Details

#default_sequence_kindObject

Returns the value of attribute default_sequence_kind.



59
60
61
# File 'lib/active_record/connection_adapters/spanner_adapter.rb', line 59

def default_sequence_kind
  @default_sequence_kind
end

#use_client_side_id_for_mutationsObject

Returns the value of attribute use_client_side_id_for_mutations.



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

def use_client_side_id_for_mutations
  @use_client_side_id_for_mutations
end

Class Method Details

.database_exists?(config) ⇒ Boolean

Database

Returns:

  • (Boolean)


112
113
114
115
116
117
118
# File 'lib/active_record/connection_adapters/spanner_adapter.rb', line 112

def self.database_exists? config
  connection = ActiveRecordSpannerAdapter::Connection.new config
  connection.connect!
  true
rescue ActiveRecord::NoDatabaseError
  false
end

.native_database_typesObject



106
107
108
# File 'lib/active_record/connection_adapters/spanner_adapter.rb', line 106

def self.native_database_types
  NATIVE_DATABASE_TYPES
end

Instance Method Details

#active?Boolean

Connection management

Returns:

  • (Boolean)


122
123
124
# File 'lib/active_record/connection_adapters/spanner_adapter.rb', line 122

def active?
  @connection.active?
end

#arel_visitorObject



220
221
222
# File 'lib/active_record/connection_adapters/spanner_adapter.rb', line 220

def arel_visitor
  Arel::Visitors::Spanner.new self
end

#build_insert_sql(insert) ⇒ Object



224
225
226
227
228
229
230
231
232
233
234
235
236
237
# File 'lib/active_record/connection_adapters/spanner_adapter.rb', line 224

def build_insert_sql insert
  if current_spanner_transaction&.isolation == :buffered_mutations
    raise "ActiveRecordSpannerAdapter does not support insert_sql with buffered_mutations transaction."
  end

  values_list, = insert.values_list
  prefix = "INSERT"
  if insert.update_duplicates?
    prefix += " OR UPDATE"
  elsif insert.skip_duplicates?
    prefix += " OR IGNORE"
  end
  "#{prefix} #{insert.into} #{values_list}"
end

#current_spanner_transactionObject



146
147
148
# File 'lib/active_record/connection_adapters/spanner_adapter.rb', line 146

def current_spanner_transaction
  @connection.current_transaction
end

#disconnect!Object



126
127
128
129
# File 'lib/active_record/connection_adapters/spanner_adapter.rb', line 126

def disconnect!
  super
  @connection.disconnect!
end

#log(sql, name = "SQL", binds = [], type_casted_binds = [], statement_name = nil, *args) ⇒ Object



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

def log sql, name = "SQL", binds = [], type_casted_binds = [], async: false, &block
  super
rescue ActiveRecord::StatementInvalid
  raise
rescue StandardError => e
  raise translate_exception_class(e, sql, binds)
end

#max_identifier_lengthObject



98
99
100
# File 'lib/active_record/connection_adapters/spanner_adapter.rb', line 98

def max_identifier_length
  128
end

#native_database_typesObject



102
103
104
# File 'lib/active_record/connection_adapters/spanner_adapter.rb', line 102

def native_database_types
  NATIVE_DATABASE_TYPES
end

#next_sequence_value(_sequence_name) ⇒ Object

Generate next sequence number for primary key



212
213
214
# File 'lib/active_record/connection_adapters/spanner_adapter.rb', line 212

def next_sequence_value _sequence_name
  SecureRandom.uuid.gsub("-", "").hex & 0x7FFFFFFFFFFFFFFF
end

#prefetch_primary_key?(_table_name = nil) ⇒ Boolean

Returns:

  • (Boolean)


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

def prefetch_primary_key? _table_name = nil
  true
end

#reset!Object Also known as: reconnect!



131
132
133
134
# File 'lib/active_record/connection_adapters/spanner_adapter.rb', line 131

def reset!
  super
  @connection.reset!
end

#return_value_after_insert?(column) ⇒ Boolean

Returns:

  • (Boolean)


216
217
218
# File 'lib/active_record/connection_adapters/spanner_adapter.rb', line 216

def return_value_after_insert? column
  column.auto_incremented_by_db? || column.primary_key?
end

#spanner_schema_cacheObject



137
138
139
# File 'lib/active_record/connection_adapters/spanner_adapter.rb', line 137

def spanner_schema_cache
  @spanner_schema_cache ||= SpannerSchemaCache.new self
end

#supports_bulk_alter?Boolean

Supported features

Returns:

  • (Boolean)


152
153
154
# File 'lib/active_record/connection_adapters/spanner_adapter.rb', line 152

def supports_bulk_alter?
  true
end

#supports_check_constraints?Boolean

Returns:

  • (Boolean)


203
204
205
# File 'lib/active_record/connection_adapters/spanner_adapter.rb', line 203

def supports_check_constraints?
  true
end

#supports_common_table_expressions?Boolean

Returns:

  • (Boolean)


156
157
158
# File 'lib/active_record/connection_adapters/spanner_adapter.rb', line 156

def supports_common_table_expressions?
  true
end

#supports_explain?Boolean

Returns:

  • (Boolean)


160
161
162
# File 'lib/active_record/connection_adapters/spanner_adapter.rb', line 160

def supports_explain?
  false
end

#supports_foreign_keys?Boolean

Returns:

  • (Boolean)


168
169
170
# File 'lib/active_record/connection_adapters/spanner_adapter.rb', line 168

def supports_foreign_keys?
  true
end

#supports_index_sort_order?Boolean

Returns:

  • (Boolean)


172
173
174
# File 'lib/active_record/connection_adapters/spanner_adapter.rb', line 172

def supports_index_sort_order?
  true
end

#supports_insert_on_conflict?Boolean Also known as: supports_insert_on_duplicate_skip?, supports_insert_on_duplicate_update?, supports_insert_conflict_target?

Returns:

  • (Boolean)


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

def supports_insert_on_conflict?
  true
end

#supports_insert_returning?Boolean

Returns:

  • (Boolean)


183
184
185
# File 'lib/active_record/connection_adapters/spanner_adapter.rb', line 183

def supports_insert_returning?
  true
end

#supports_multi_insert?Boolean

Returns:

  • (Boolean)


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

def supports_multi_insert?
  true
end

#supports_optimizer_hints?Boolean

Returns:

  • (Boolean)


191
192
193
# File 'lib/active_record/connection_adapters/spanner_adapter.rb', line 191

def supports_optimizer_hints?
  true
end

#supports_primary_key?Boolean

Returns:

  • (Boolean)


195
196
197
# File 'lib/active_record/connection_adapters/spanner_adapter.rb', line 195

def supports_primary_key?
  true
end

#supports_transaction_isolation?Boolean

Returns:

  • (Boolean)


164
165
166
# File 'lib/active_record/connection_adapters/spanner_adapter.rb', line 164

def supports_transaction_isolation?
  true
end

#supports_virtual_columns?Boolean

Returns:

  • (Boolean)


207
208
209
# File 'lib/active_record/connection_adapters/spanner_adapter.rb', line 207

def supports_virtual_columns?
  true
end

#transform(sql) ⇒ Object



297
298
299
300
301
302
303
304
305
# File 'lib/active_record/connection_adapters/spanner_adapter.rb', line 297

def transform sql
  if ActiveRecord::VERSION::MAJOR >= 8
    preprocess_query sql
  elsif ActiveRecord::VERSION::MAJOR == 7
    transform_query sql
  else
    sql
  end
end

#translate_exception(exception, message:, sql:, binds:) ⇒ Object



327
328
329
330
331
332
333
334
335
336
337
338
339
# File 'lib/active_record/connection_adapters/spanner_adapter.rb', line 327

def translate_exception exception, message:, sql:, binds:
  if exception.is_a? Google::Cloud::FailedPreconditionError
    case exception.message
    when /.*does not specify a non-null value for these NOT NULL columns.*/,
         /.*must not be NULL.*/
      NotNullViolation.new message, sql: sql, binds: binds
    else
      super
    end
  else
    super
  end
end

#use_auto_increment?Boolean

Returns:

  • (Boolean)


88
89
90
# File 'lib/active_record/connection_adapters/spanner_adapter.rb', line 88

def use_auto_increment?
  "AUTO_INCREMENT".casecmp?(@default_sequence_kind || "")
end

#use_identity?Boolean

Returns:

  • (Boolean)


92
93
94
95
96
# File 'lib/active_record/connection_adapters/spanner_adapter.rb', line 92

def use_identity?
  !use_auto_increment? \
  && @default_sequence_kind \
  && !@default_sequence_kind.casecmp?("DISABLED")
end