Class: ActiveRecord::ConnectionAdapters::LibsqlAdapter
- Inherits:
-
AbstractAdapter
- Object
- AbstractAdapter
- ActiveRecord::ConnectionAdapters::LibsqlAdapter
- Defined in:
- lib/active_record/connection_adapters/libsql_adapter.rb
Constant Summary collapse
- ADAPTER_NAME =
'Turso'- NATIVE_DATABASE_TYPES =
SQLite 互換の型マッピング(libSQL は SQLite 方言)datetime / timestamp は ‘datetime’ を使う。‘TEXT’ にすると PRAGMA table_info が ‘TEXT’ を返し、AR の type_map が Type::Text にマッピングしてしまう。Type::Text は Time を UTC に変換せず文字列化するため、WHERE scheduled_at <= ? の比較が文字列比較で壊れる。
{ primary_key: 'INTEGER PRIMARY KEY AUTOINCREMENT', string: { name: 'TEXT' }, text: { name: 'TEXT' }, integer: { name: 'INTEGER' }, float: { name: 'REAL' }, decimal: { name: 'REAL' }, datetime: { name: 'datetime' }, timestamp: { name: 'datetime' }, time: { name: 'time' }, date: { name: 'date' }, binary: { name: 'BLOB' }, boolean: { name: 'INTEGER' }, json: { name: 'TEXT' } }.freeze
Instance Method Summary collapse
- #active? ⇒ Boolean
-
#adapter_name ⇒ Object
———————————————————————– Adapter 識別 ———————————————————————–.
- #affected_rows(_raw_result) ⇒ Object
-
#begin_db_transaction ⇒ Object
———————————————————————– トランザクション ———————————————————————–.
-
#cast_result(raw_result) ⇒ Object
perform_query が返した結果をそのまま使う(すでに ActiveRecord::Result).
- #columns(table_name) ⇒ Object
- #commit_db_transaction ⇒ Object
-
#connect! ⇒ Object
———————————————————————– 接続管理(AR 8 スタイル) AR の ConnectionPool はスレッドごとに独立した Adapter インスタンスを払い出すため ———————————————————————–.
-
#discard! ⇒ Object
fork 後の子プロセスで呼ばれる。 sqlite3 gem の fork safety が接続を強制クローズするため、 参照を破棄して子プロセスで新しい接続を確立できるようにする。 AR の ConnectionPool が fork 後に各コネクションに対して呼ぶ。.
- #disconnect! ⇒ Object
- #exec_rollback_db_transaction ⇒ Object
-
#last_inserted_id(_result) ⇒ Object
———————————————————————– INSERT 後の id AR 8 は last_inserted_id(result) を呼ぶ ———————————————————————–.
-
#native_database_types ⇒ Object
———————————————————————– スキーマ情報 ———————————————————————–.
-
#perform_query(raw_connection, sql, _binds, type_casted_binds, prepare:, notification_payload:, batch: false) ⇒ Object
AR 8 が with_raw_connection { |conn| } で呼ぶ中核メソッド.
-
#quote_column_name(name) ⇒ Object
———————————————————————– クォート ———————————————————————–.
- #quote_table_name(name) ⇒ Object
- #quoted_false ⇒ Object
- #quoted_true ⇒ Object
- #supports_ddl_transactions? ⇒ Boolean
- #supports_explain? ⇒ Boolean
- #supports_lazy_transactions? ⇒ Boolean
- #supports_migrations? ⇒ Boolean
- #supports_primary_key? ⇒ Boolean
- #supports_savepoints? ⇒ Boolean
-
#sync ⇒ Object
Embedded Replica モードでリモートから最新フレームを手動同期する。 Remote モードでは何もしない(no-op)。.
- #table_exists?(table_name) ⇒ Boolean
- #tables(_name = nil) ⇒ Object
- #write_query?(sql) ⇒ Boolean
Instance Method Details
#active? ⇒ Boolean
112 113 114 115 116 117 118 119 |
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 112 def active? return false unless @raw_connection @raw_connection.query('SELECT 1') true rescue StandardError false end |
#adapter_name ⇒ Object
Adapter 識別
65 66 67 |
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 65 def adapter_name ADAPTER_NAME end |
#affected_rows(_raw_result) ⇒ Object
203 204 205 |
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 203 def affected_rows(_raw_result) @last_affected_rows || 0 end |
#begin_db_transaction ⇒ Object
トランザクション
211 212 213 |
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 211 def begin_db_transaction @raw_connection&.begin_transaction end |
#cast_result(raw_result) ⇒ Object
perform_query が返した結果をそのまま使う(すでに ActiveRecord::Result)
199 200 201 |
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 199 def cast_result(raw_result) raw_result end |
#columns(table_name) ⇒ Object
248 249 250 251 252 253 254 255 256 257 258 259 260 |
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 248 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_transaction ⇒ Object
215 216 217 |
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 215 def commit_db_transaction @raw_connection&.commit_transaction end |
#connect! ⇒ Object
接続管理(AR 8 スタイル)AR の ConnectionPool はスレッドごとに独立した Adapter インスタンスを払い出すため
107 108 109 110 |
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 107 def connect! @raw_database, @raw_connection = build_libsql_connection super end |
#discard! ⇒ Object
fork 後の子プロセスで呼ばれる。sqlite3 gem の fork safety が接続を強制クローズするため、参照を破棄して子プロセスで新しい接続を確立できるようにする。AR の ConnectionPool が fork 後に各コネクションに対して呼ぶ。
131 132 133 134 135 136 |
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 131 def discard! @raw_connection = nil @raw_database = nil TursoLibsql.reinitialize_runtime! 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_transaction ⇒ Object
219 220 221 |
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 219 def exec_rollback_db_transaction @raw_connection&.rollback_transaction end |
#last_inserted_id(_result) ⇒ Object
INSERT 後の id AR 8 は last_inserted_id(result) を呼ぶ
228 229 230 |
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 228 def last_inserted_id(_result) @raw_connection&.last_insert_rowid end |
#native_database_types ⇒ Object
スキーマ情報
236 237 238 |
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 236 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| } で呼ぶ中核メソッド
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 167 def perform_query(raw_connection, sql, _binds, type_casted_binds, prepare:, notification_payload:, batch: false) # バインドパラメータを SQL に展開する(libsql の ? プレースホルダーに対応) = if type_casted_binds&.any? i = -1 sql.gsub('?') do i += 1 quote(type_casted_binds[i]) end else sql end # libSQL / SQLite は FOR UPDATE / FOR UPDATE SKIP LOCKED / FOR SHARE を # サポートしない。AR の SQLite3 adapter はこれらを除去するが、 # libsql_adapter は直接 Hrana HTTP / SQLite3::Database を呼ぶため自前で除去する。 = sanitize_for_update() if read_query?() rows = raw_connection.query() notification_payload[:row_count] = rows.size if notification_payload build_result(rows) else affected = raw_connection.execute() @last_affected_rows = affected.to_i notification_payload[:row_count] = @last_affected_rows if notification_payload ActiveRecord::Result.empty end rescue RuntimeError => e raise translate_exception(e, message: e., sql: , binds: []) end |
#quote_column_name(name) ⇒ Object
クォート
270 271 272 |
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 270 def quote_column_name(name) %("#{name.to_s.gsub('"', '""')}") end |
#quote_table_name(name) ⇒ Object
274 275 276 |
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 274 def quote_table_name(name) %("#{name.to_s.gsub('"', '""')}") end |
#quoted_false ⇒ Object
282 283 284 |
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 282 def quoted_false '0' end |
#quoted_true ⇒ Object
278 279 280 |
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 278 def quoted_true '1' end |
#supports_ddl_transactions? ⇒ Boolean
77 78 79 |
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 77 def supports_ddl_transactions? false end |
#supports_explain? ⇒ Boolean
85 86 87 |
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 85 def supports_explain? false end |
#supports_lazy_transactions? ⇒ Boolean
89 90 91 |
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 89 def supports_lazy_transactions? false end |
#supports_migrations? ⇒ Boolean
69 70 71 |
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 69 def supports_migrations? true end |
#supports_primary_key? ⇒ Boolean
73 74 75 |
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 73 def supports_primary_key? true end |
#supports_savepoints? ⇒ Boolean
81 82 83 |
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 81 def supports_savepoints? false end |
#sync ⇒ Object
Embedded Replica モードでリモートから最新フレームを手動同期する。Remote モードでは何もしない(no-op)。
157 158 159 |
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 157 def sync @raw_database&.sync end |
#table_exists?(table_name) ⇒ Boolean
262 263 264 |
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 262 def table_exists?(table_name) tables.include?(table_name.to_s) end |
#tables(_name = nil) ⇒ Object
240 241 242 243 244 245 246 |
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 240 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
93 94 95 96 97 |
# File 'lib/active_record/connection_adapters/libsql_adapter.rb', line 93 def write_query?(sql) !READ_QUERY.match?(sql) rescue ArgumentError !READ_QUERY.match?(sql.b) end |