Class: ActiveRecord::ConnectionAdapters::NusaDBAdapter
- Inherits:
-
AbstractAdapter
- Object
- AbstractAdapter
- ActiveRecord::ConnectionAdapters::NusaDBAdapter
- Defined in:
- lib/active_record/connection_adapters/nusadb_adapter.rb
Constant Summary collapse
- ADAPTER_NAME =
"NusaDB"- LAZY_CONNECTION =
ActiveRecord 7.2 rebuilt how an adapter gets its connection, and 8.0 removed the old way:
<= 7.1 ConnectionHandling#nusadb_connection opens the connection and hands it to .new(connection, logger, config); the adapter is simply born connected. >= 7.2 the adapter is resolved from a registry and built with .new(config). It starts with no connection at all: the base class calls the private #connect on first use and owns the result as @raw_connection, which every statement must reach through #with_raw_connection so the base can verify, materialize transactions and retry.Both eras are supported, so this constant -- not the ActiveRecord version number -- is what the code below branches on. #with_raw_connection arrived in 7.1, one release before the lazy-connection contract it belongs to, so a 7.1 adapter is connected eagerly and still talks through it; that is harmless, and it keeps the branch to a single question.
AbstractAdapter.private_method_defined?(:with_raw_connection) || AbstractAdapter.method_defined?(:with_raw_connection)
- COLUMN_TAKES_CAST_TYPE =
ActiveRecord 8.1 inserted
cast_typeas Column's SECOND positional argument -- exactly wheredefaultused to sit. The old call still runs, it just hands the default over as the cast type, and the column dies later withundefined method 'mutable?' for nil, nowhere near the cause. The parameter list is asked rather than the version number because this is not the 7-vs-8 line one would guess: 8.0 kept the old signature and only 8.1 changed it. Column.instance_method(:initialize).parameters.any? do |_kind, name| name == :cast_type end
Class Method Summary collapse
-
.new_client(config) ⇒ Object
7.2+ calls this from #connect.
- .quote_column_name(name) ⇒ Object
-
.quote_string(s) ⇒ Object
Only ' is escaped, and deliberately: the server does not treat \ as an escape character inside a string literal, so doubling backslashes (as the ActiveRecord default does) would store them doubled.
- .quote_table_name(name) ⇒ Object
Instance Method Summary collapse
-
#active? ⇒ Boolean
A connection this adapter has not opened yet is not active -- and saying otherwise is not a white lie on 7.2+, where #active? is what tells the base class whether it still needs to #connect.
- #begin_db_transaction ⇒ Object
- #columns(table_name, _name = nil) ⇒ Object
- #commit_db_transaction ⇒ Object
- #data_source_exists?(name) ⇒ Boolean (also: #table_exists?)
- #data_sources ⇒ Object
- #disconnect! ⇒ Object
- #exec_delete(sql, name = nil, binds = [], **_kwargs) ⇒ Object (also: #exec_update)
- #exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil, **_kwargs) ⇒ Object
- #exec_query(sql, name = "SQL", binds = [], prepare: false, **_kwargs) ⇒ Object
- #exec_rollback_db_transaction ⇒ Object
-
#execute(sql, name = nil, **_kwargs) ⇒ Object
Every keyword splat below absorbs arguments ActiveRecord grew later and passes to adapters that never asked for them --
allow_retry:on #execute,returning:on #exec_insert,async:on #internal_exec_query (all 7.2+). -
#internal_exec_query(sql, name = "SQL", binds = [], prepare: false, **_kwargs) ⇒ Object
#exec_query stopped being the way in.
- #native_database_types ⇒ Object
- #prepared_statements ⇒ Object
-
#primary_keys(table_name) ⇒ Object
The primary-key columns of
table_name, in key order, so ActiveRecord can auto-detect a model's primary key (single- or composite-column) without an explicitself.primary_key. -
#quote_column_name(name) ⇒ Object
<= 7.1 has no class-level quoting to delegate to -- its Quoting module only ever calls the instance methods, whose default raises.
- #quote_string(s) ⇒ Object
- #quote_table_name(name) ⇒ Object
- #supports_migrations? ⇒ Boolean
-
#supports_savepoints? ⇒ Boolean
NusaDB supports savepoints (SAVEPOINT / ROLLBACK TO SAVEPOINT / RELEASE SAVEPOINT), so ActiveRecord can map nested
transaction(requires_new: true)blocks onto them. -
#tables ⇒ Object
--- schema introspection ---.
Class Method Details
.new_client(config) ⇒ Object
7.2+ calls this from #connect. The <= 7.1 hook at the bottom of this file calls it too, so a connection is opened the same way whichever era we are running under.
58 59 60 61 62 63 64 65 66 67 |
# File 'lib/active_record/connection_adapters/nusadb_adapter.rb', line 58 def new_client(config) config = config.symbolize_keys NusaDB.connect( host: config[:host] || "127.0.0.1", port: (config[:port] || 5678).to_i, user: config[:username] || config[:user] || "nusa-root", database: config[:database] || "nusadb", password: config[:password] ) end |
.quote_column_name(name) ⇒ Object
125 126 127 |
# File 'lib/active_record/connection_adapters/nusadb_adapter.rb', line 125 def quote_column_name(name) %("#{name.to_s.gsub('"', '""')}") end |
.quote_string(s) ⇒ Object
Only ' is escaped, and deliberately: the server does not treat \ as an escape character inside a string literal, so doubling backslashes (as the ActiveRecord default does) would store them doubled.
136 137 138 |
# File 'lib/active_record/connection_adapters/nusadb_adapter.rb', line 136 def quote_string(s) s.gsub("'", "''") end |
.quote_table_name(name) ⇒ Object
129 130 131 |
# File 'lib/active_record/connection_adapters/nusadb_adapter.rb', line 129 def quote_table_name(name) quote_column_name(name) end |
Instance Method Details
#active? ⇒ Boolean
A connection this adapter has not opened yet is not active -- and saying otherwise is not a white lie on 7.2+, where #active? is what tells the base class whether it still needs to #connect. Claiming true while @raw_connection is nil sends it straight to a NoMethodError.
73 74 75 |
# File 'lib/active_record/connection_adapters/nusadb_adapter.rb', line 73 def active? !current_raw_connection.nil? end |
#begin_db_transaction ⇒ Object
188 189 190 |
# File 'lib/active_record/connection_adapters/nusadb_adapter.rb', line 188 def begin_db_transaction execute("BEGIN") end |
#columns(table_name, _name = nil) ⇒ Object
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 |
# File 'lib/active_record/connection_adapters/nusadb_adapter.rb', line 215 def columns(table_name, _name = nil) rows = nusa_query("SHOW COLUMNS FROM #{quote_table_name(table_name)}").rows rows.map do |row| col_name = row[0] sql_type = (row[1] || "text").to_s.downcase nullable = row[2].nil? || %w[t true yes 1].include?(row[2].to_s.downcase) cast_type = ActiveRecord::Type.lookup(map_type(sql_type)) = (sql_type, cast_type) # The column has no default either way -- what moves is where +default+ sits in the # argument list. See COLUMN_TAKES_CAST_TYPE. if COLUMN_TAKES_CAST_TYPE Column.new(col_name, cast_type, nil, , nullable) else Column.new(col_name, nil, , nullable) end end end |
#commit_db_transaction ⇒ Object
192 193 194 |
# File 'lib/active_record/connection_adapters/nusadb_adapter.rb', line 192 def commit_db_transaction execute("COMMIT") end |
#data_source_exists?(name) ⇒ Boolean Also known as: table_exists?
206 207 208 |
# File 'lib/active_record/connection_adapters/nusadb_adapter.rb', line 206 def data_source_exists?(name) tables.include?(name.to_s) end |
#data_sources ⇒ Object
211 212 213 |
# File 'lib/active_record/connection_adapters/nusadb_adapter.rb', line 211 def data_sources tables end |
#disconnect! ⇒ Object
77 78 79 80 81 82 83 |
# File 'lib/active_record/connection_adapters/nusadb_adapter.rb', line 77 def disconnect! super current_raw_connection&.close @raw_connection = nil if LAZY_CONNECTION rescue StandardError nil end |
#exec_delete(sql, name = nil, binds = [], **_kwargs) ⇒ Object Also known as: exec_update
183 184 185 |
# File 'lib/active_record/connection_adapters/nusadb_adapter.rb', line 183 def exec_delete(sql, name = nil, binds = [], **_kwargs) log(sql, name) { nusa_query(sql) }.affected end |
#exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil, **_kwargs) ⇒ Object
179 180 181 |
# File 'lib/active_record/connection_adapters/nusadb_adapter.rb', line 179 def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil, **_kwargs) internal_exec_query(sql, name, binds) end |
#exec_query(sql, name = "SQL", binds = [], prepare: false, **_kwargs) ⇒ Object
175 176 177 |
# File 'lib/active_record/connection_adapters/nusadb_adapter.rb', line 175 def exec_query(sql, name = "SQL", binds = [], prepare: false, **_kwargs) internal_exec_query(sql, name, binds) end |
#exec_rollback_db_transaction ⇒ Object
196 197 198 |
# File 'lib/active_record/connection_adapters/nusadb_adapter.rb', line 196 def exec_rollback_db_transaction execute("ROLLBACK") end |
#execute(sql, name = nil, **_kwargs) ⇒ Object
Every keyword splat below absorbs arguments ActiveRecord grew later and passes to adapters
that never asked for them -- allow_retry: on #execute, returning: on #exec_insert,
async: on #internal_exec_query (all 7.2+). Without them the caller gets an ArgumentError.
161 162 163 |
# File 'lib/active_record/connection_adapters/nusadb_adapter.rb', line 161 def execute(sql, name = nil, **_kwargs) log(sql, name) { nusa_query(sql) } end |
#internal_exec_query(sql, name = "SQL", binds = [], prepare: false, **_kwargs) ⇒ Object
#exec_query stopped being the way in. From 7.2 the internal read path (select_all -> select) calls #internal_exec_query, whose base implementation raises NotImplementedError -- so an adapter that overrides only the public #exec_query looks complete, loads fine, and then dies on the first SELECT. This is the real entry point; #exec_query is kept for <= 7.1 (where the base has no #internal_exec_query at all) and for anyone calling it directly.
170 171 172 173 |
# File 'lib/active_record/connection_adapters/nusadb_adapter.rb', line 170 def internal_exec_query(sql, name = "SQL", binds = [], prepare: false, **_kwargs) result = log(sql, name) { nusa_query(sql) } ActiveRecord::Result.new(result.columns, result.rows) end |
#native_database_types ⇒ Object
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
# File 'lib/active_record/connection_adapters/nusadb_adapter.rb', line 101 def native_database_types { primary_key: "INT", string: { name: "TEXT" }, text: { name: "TEXT" }, integer: { name: "INT" }, bigint: { name: "INT" }, float: { name: "FLOAT" }, decimal: { name: "NUMERIC" }, boolean: { name: "BOOL" }, date: { name: "DATE" }, datetime: { name: "TIMESTAMP" }, time: { name: "TIME" } } end |
#prepared_statements ⇒ Object
85 86 87 |
# File 'lib/active_record/connection_adapters/nusadb_adapter.rb', line 85 def prepared_statements false end |
#primary_keys(table_name) ⇒ Object
The primary-key columns of table_name, in key order, so ActiveRecord can auto-detect a
model's primary key (single- or composite-column) without an explicit self.primary_key.
Resolved from information_schema in two steps — the server does not support joining two
information_schema tables in one query, so we look up the PRIMARY KEY constraint name and
then its columns separately.
239 240 241 242 243 244 245 246 247 248 249 250 251 252 |
# File 'lib/active_record/connection_adapters/nusadb_adapter.rb', line 239 def primary_keys(table_name) name = quote(table_name.to_s) constraint = nusa_query( "SELECT constraint_name FROM information_schema.table_constraints " \ "WHERE constraint_type = 'PRIMARY KEY' AND table_name = #{name}" ).rows.first return [] if constraint.nil? nusa_query( "SELECT column_name FROM information_schema.key_column_usage " \ "WHERE table_name = #{name} AND constraint_name = #{quote(constraint[0])} " \ "ORDER BY ordinal_position" ).rows.map { |row| row[0] } end |
#quote_column_name(name) ⇒ Object
<= 7.1 has no class-level quoting to delegate to -- its Quoting module only ever calls the instance methods, whose default raises. Delegating explicitly keeps one implementation reachable from either era.
144 145 146 |
# File 'lib/active_record/connection_adapters/nusadb_adapter.rb', line 144 def quote_column_name(name) self.class.quote_column_name(name) end |
#quote_string(s) ⇒ Object
152 153 154 |
# File 'lib/active_record/connection_adapters/nusadb_adapter.rb', line 152 def quote_string(s) self.class.quote_string(s) end |
#quote_table_name(name) ⇒ Object
148 149 150 |
# File 'lib/active_record/connection_adapters/nusadb_adapter.rb', line 148 def quote_table_name(name) self.class.quote_table_name(name) end |
#supports_migrations? ⇒ Boolean
89 90 91 |
# File 'lib/active_record/connection_adapters/nusadb_adapter.rb', line 89 def supports_migrations? true end |
#supports_savepoints? ⇒ Boolean
NusaDB supports savepoints (SAVEPOINT / ROLLBACK TO SAVEPOINT / RELEASE SAVEPOINT), so
ActiveRecord can map nested transaction(requires_new: true) blocks onto them. The base
adapter's create_savepoint / exec_rollback_to_savepoint / release_savepoint emit exactly the
statements the server accepts, so enabling the capability is all that is needed.
97 98 99 |
# File 'lib/active_record/connection_adapters/nusadb_adapter.rb', line 97 def supports_savepoints? true end |
#tables ⇒ Object
--- schema introspection ---
202 203 204 |
# File 'lib/active_record/connection_adapters/nusadb_adapter.rb', line 202 def tables nusa_query("SHOW TABLES").rows.map { |row| row[0] } end |