Class: ActiveRecord::ConnectionAdapters::LibsqlAdapter

Inherits:
AbstractAdapter
  • Object
show all
Defined in:
lib/active_record/connection_adapters/libsql_adapter.rb

Constant Summary collapse

ADAPTER_NAME =
'Turso'
NATIVE_DATABASE_TYPES =

SQLite 互換の型マッピング(libSQL は SQLite 方言)

{
  primary_key: 'INTEGER PRIMARY KEY AUTOINCREMENT',
  string: { name: 'TEXT' },
  text: { name: 'TEXT' },
  integer: { name: 'INTEGER' },
  float: { name: 'REAL' },
  decimal: { name: 'REAL' },
  datetime: { name: 'TEXT' },
  timestamp: { name: 'TEXT' },
  time: { name: 'TEXT' },
  date: { name: 'TEXT' },
  binary: { name: 'BLOB' },
  boolean: { name: 'INTEGER' },
  json: { name: 'TEXT' }
}.freeze

Instance Method Summary collapse

Instance Method Details

#active?Boolean

Returns:

  • (Boolean)


107
108
109
110
111
112
113
114
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 107

def active?
  return false unless @raw_connection

  @raw_connection.query('SELECT 1')
  true
rescue StandardError
  false
end

#adapter_nameObject


Adapter 識別




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

def adapter_name
  ADAPTER_NAME
end

#affected_rows(raw_result) ⇒ Object



169
170
171
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 169

def affected_rows(raw_result)
  raw_result.length
end

#begin_db_transactionObject


トランザクション




177
178
179
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 177

def begin_db_transaction
  @raw_connection&.begin_transaction
end

#cast_result(raw_result) ⇒ Object

perform_query が返した結果をそのまま使う(すでに ActiveRecord::Result)



165
166
167
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 165

def cast_result(raw_result)
  raw_result
end

#columns(table_name) ⇒ Object



214
215
216
217
218
219
220
221
222
223
224
225
226
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 214

def columns(table_name)
  result = internal_exec_query(
    "PRAGMA table_info(#{quote_table_name(table_name)})",
    'SCHEMA'
  )
  result.map do |row|
    sql_type    = row['type'].to_s
    cast_type   = type_map.lookup(sql_type) || Type::Value.new
    sql_type_md = (sql_type)
    null        = row['notnull'].to_i.zero?
    COLUMN_BUILDER.call(row['name'], cast_type, row['dflt_value'], sql_type_md, null)
  end
end

#commit_db_transactionObject



181
182
183
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 181

def commit_db_transaction
  @raw_connection&.commit_transaction
end

#connect!Object


接続管理(AR 8 スタイル)AR の ConnectionPool はスレッドごとに独立した Adapter インスタンスを払い出すため




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

def connect!
  @raw_database, @raw_connection = build_libsql_connection
  super
end

#disconnect!Object



121
122
123
124
125
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 121

def disconnect!
  @raw_connection = nil
  @raw_database = nil
  super
end

#exec_rollback_db_transactionObject



185
186
187
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 185

def exec_rollback_db_transaction
  @raw_connection&.rollback_transaction
end

#last_inserted_id(_result) ⇒ Object


INSERT 後の id AR 8 は last_inserted_id(result) を呼ぶ




194
195
196
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 194

def last_inserted_id(_result)
  @raw_connection&.last_insert_rowid
end

#native_database_typesObject


スキーマ情報




202
203
204
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 202

def native_database_types
  NATIVE_DATABASE_TYPES
end

#perform_query(raw_connection, sql, _binds, type_casted_binds, prepare:, notification_payload:, batch: false) ⇒ Object

AR 8 が with_raw_connection { |conn| } で呼ぶ中核メソッド



139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 139

def perform_query(raw_connection, sql, _binds, type_casted_binds, prepare:, notification_payload:, batch: false)
  # バインドパラメータを SQL に展開する(libsql の ? プレースホルダーに対応)
  expanded_sql = if type_casted_binds&.any?
                   i = -1
                   sql.gsub('?') do
                     i += 1
                     quote(type_casted_binds[i])
                   end
                 else
                   sql
                 end

  if read_query?(expanded_sql)
    rows = raw_connection.query(expanded_sql)
    notification_payload[:row_count] = rows.size if notification_payload
    build_result(rows)
  else
    affected = raw_connection.execute(expanded_sql)
    notification_payload[:row_count] = affected if notification_payload
    ActiveRecord::Result.empty(affected_rows: affected.to_i)
  end
rescue RuntimeError => e
  raise translate_exception(e, message: e.message, sql: expanded_sql, binds: [])
end

#quote_column_name(name) ⇒ Object


クォート




236
237
238
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 236

def quote_column_name(name)
  %("#{name.to_s.gsub('"', '""')}")
end

#quote_table_name(name) ⇒ Object



240
241
242
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 240

def quote_table_name(name)
  %("#{name.to_s.gsub('"', '""')}")
end

#quoted_falseObject



248
249
250
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 248

def quoted_false
  '0'
end

#quoted_trueObject



244
245
246
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 244

def quoted_true
  '1'
end

#reconnect!Object



116
117
118
119
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 116

def reconnect!
  @raw_database, @raw_connection = build_libsql_connection
  super
end

#supports_ddl_transactions?Boolean

Returns:

  • (Boolean)


72
73
74
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 72

def supports_ddl_transactions?
  false
end

#supports_explain?Boolean

Returns:

  • (Boolean)


80
81
82
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 80

def supports_explain?
  false
end

#supports_lazy_transactions?Boolean

Returns:

  • (Boolean)


84
85
86
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 84

def supports_lazy_transactions?
  false
end

#supports_migrations?Boolean

Returns:

  • (Boolean)


64
65
66
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 64

def supports_migrations?
  true
end

#supports_primary_key?Boolean

Returns:

  • (Boolean)


68
69
70
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 68

def supports_primary_key?
  true
end

#supports_savepoints?Boolean

Returns:

  • (Boolean)


76
77
78
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 76

def supports_savepoints?
  false
end

#syncObject

Embedded Replica モードでリモートから最新フレームを手動同期する。Remote モードでは何もしない(no-op)。



129
130
131
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 129

def sync
  @raw_database&.sync
end

#table_exists?(table_name) ⇒ Boolean

Returns:

  • (Boolean)


228
229
230
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 228

def table_exists?(table_name)
  tables.include?(table_name.to_s)
end

#tables(_name = nil) ⇒ Object



206
207
208
209
210
211
212
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 206

def tables(_name = nil)
  result = internal_exec_query(
    "SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'",
    'SCHEMA'
  )
  result.rows.flatten
end

#write_query?(sql) ⇒ Boolean

Returns:

  • (Boolean)


88
89
90
91
92
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 88

def write_query?(sql)
  !READ_QUERY.match?(sql)
rescue ArgumentError
  !READ_QUERY.match?(sql.b)
end