Module: ActiveRecord::ConnectionAdapters::Duckdb::DatabaseStatements
- Included in:
- ActiveRecord::ConnectionAdapters::DuckdbAdapter
- Defined in:
- lib/active_record/connection_adapters/duckdb/database_statements.rb
Instance Method Summary collapse
-
#build_result(result) ⇒ ActiveRecord::Result
Builds an ActiveRecord::Result from a DuckDB result.
-
#cast_result(result) ⇒ ActiveRecord::Result
Casts a DuckDB result to ActiveRecord::Result format.
-
#columns_for_insert(table_name) ⇒ Array<ActiveRecord::ConnectionAdapters::Column>
Returns columns that should be included in INSERT statements.
-
#exec_delete(sql, name = nil, binds = []) ⇒ Integer
(also: #exec_update)
Executes a DELETE statement and returns the number of affected rows.
-
#exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil, returning: nil) ⇒ ActiveRecord::Result
Executes an INSERT statement with optional RETURNING clause.
-
#exec_query(sql, name = nil, binds = [], prepare: false) ⇒ ActiveRecord::Result
Executes a query and returns an ActiveRecord::Result.
-
#execute(sql, name = nil) ⇒ DuckDB::Result
Executes a SQL statement against the DuckDB database.
-
#fetch_type_metadata(sql_type) ⇒ ActiveRecord::ConnectionAdapters::SqlTypeMetadata
Fetches type metadata for a SQL type string.
-
#last_inserted_id(result) ⇒ Object
Extracts the last inserted ID from an insert result.
-
#perform_query(raw_connection, sql, binds, type_casted_binds, prepare: false, notification_payload: nil, batch: false, async: false, **kwargs) ⇒ DuckDB::Result
Performs a query with optional bind parameters.
-
#return_value_after_insert?(column) ⇒ Boolean
Determines if a column value should be returned after insert This is crucial - it tells Rails which columns should use RETURNING.
-
#write_query?(_sql) ⇒ Boolean
Determines if a SQL query is a write operation.
Instance Method Details
#build_result(result) ⇒ ActiveRecord::Result
Builds an ActiveRecord::Result from a DuckDB result
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
# File 'lib/active_record/connection_adapters/duckdb/database_statements.rb', line 182 def build_result(result) # Handle DuckDB result format return ActiveRecord::Result.empty if result.nil? # DuckDB results have .columns and .to_a, not .rows columns = result.columns.map do |col| if col.respond_to?(:name) col.name elsif col.respond_to?(:column_name) col.column_name else col.to_s end end rows = result.to_a ActiveRecord::Result.new(columns, rows) end |
#cast_result(result) ⇒ ActiveRecord::Result
Casts a DuckDB result to ActiveRecord::Result format
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/active_record/connection_adapters/duckdb/database_statements.rb', line 64 def cast_result(result) return ActiveRecord::Result.empty(affected_rows: @affected_rows_before_warnings) if result.nil? columns = result.columns.map do |col| if col.respond_to?(:name) col.name elsif col.respond_to?(:column_name) col.column_name else col.to_s end end ActiveRecord::Result.new(columns, result.to_a) end |
#columns_for_insert(table_name) ⇒ Array<ActiveRecord::ConnectionAdapters::Column>
Returns columns that should be included in INSERT statements
151 152 153 154 155 156 |
# File 'lib/active_record/connection_adapters/duckdb/database_statements.rb', line 151 def columns_for_insert(table_name) columns(table_name).reject do |column| # Exclude columns that have a default function (like nextval) column.default_function.present? end end |
#exec_delete(sql, name = nil, binds = []) ⇒ Integer Also known as: exec_update
Executes a DELETE statement and returns the number of affected rows
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/active_record/connection_adapters/duckdb/database_statements.rb', line 108 def exec_delete(sql, name = nil, binds = []) # :nodoc: reconnect unless raw_connection if binds.any? # For bound queries, handle them with proper logging log(sql, name, binds) do bind_values = binds.map(&:value_for_database) raw_connection.query(sql, *bind_values) end.rows_changed else # For non-bound queries, use execute directly result = execute(sql, name) result.rows_changed end end |
#exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil, returning: nil) ⇒ ActiveRecord::Result
Executes an INSERT statement with optional RETURNING clause
133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/active_record/connection_adapters/duckdb/database_statements.rb', line 133 def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil, returning: nil) # Rails 8 will pass returning: [pk] when it wants the ID back if returning&.any? returning_columns = returning.map { |c| quote_column_name(c) }.join(', ') sql = "#{sql} RETURNING #{returning_columns}" unless sql.include?('RETURNING') elsif pk && !sql.include?('RETURNING') # Add RETURNING for the primary key sql = "#{sql} RETURNING #{quote_column_name(pk)}" end # Execute the query and return the result # Rails 8 will handle extracting the ID from the result exec_query(sql, name, binds) end |
#exec_query(sql, name = nil, binds = [], prepare: false) ⇒ ActiveRecord::Result
Executes a query and returns an ActiveRecord::Result
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/active_record/connection_adapters/duckdb/database_statements.rb', line 86 def exec_query(sql, name = nil, binds = [], prepare: false) reconnect unless raw_connection log(sql, name, binds) do result = if binds.any? # Use the modern parameter binding approach exec_query_with_binds(sql, binds) else # Fallback to direct execution with quoted values # Your existing quote method will handle any unquoted values raw_connection.query(sql) end build_result(result) end end |
#execute(sql, name = nil) ⇒ DuckDB::Result
Executes a SQL statement against the DuckDB database
19 20 21 22 23 24 25 26 27 28 |
# File 'lib/active_record/connection_adapters/duckdb/database_statements.rb', line 19 def execute(sql, name = nil) # :nodoc: # In case a query is being executed before the connection is open, reconnect. reconnect unless raw_connection log(sql, name) do ActiveSupport::Dependencies.interlock.permit_concurrent_loads do raw_connection.query(sql) end end end |
#fetch_type_metadata(sql_type) ⇒ ActiveRecord::ConnectionAdapters::SqlTypeMetadata
Fetches type metadata for a SQL type string
204 205 206 207 208 209 210 211 212 213 214 215 |
# File 'lib/active_record/connection_adapters/duckdb/database_statements.rb', line 204 def (sql_type) # Parse DuckDB types and map to Rails types type, limit, precision, scale = parse_type_info(sql_type) ActiveRecord::ConnectionAdapters::SqlTypeMetadata.new( sql_type: sql_type, type: type.to_sym, limit: limit, precision: precision, scale: scale ) end |
#last_inserted_id(result) ⇒ Object
Extracts the last inserted ID from an insert result
170 171 172 173 174 175 176 177 |
# File 'lib/active_record/connection_adapters/duckdb/database_statements.rb', line 170 def last_inserted_id(result) # Handle ActiveRecord::Result from RETURNING clause if result.is_a?(ActiveRecord::Result) && result.rows.any? id_value = result.rows.first.first return id_value end super end |
#perform_query(raw_connection, sql, binds, type_casted_binds, prepare: false, notification_payload: nil, batch: false, async: false, **kwargs) ⇒ DuckDB::Result
Performs a query with optional bind parameters
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/active_record/connection_adapters/duckdb/database_statements.rb', line 41 def perform_query(raw_connection, sql, binds, type_casted_binds, prepare: false, notification_payload: nil, batch: false, async: false, **kwargs) result = if binds.any? # Use the modern parameter binding approach exec_query_with_binds(sql, binds) else # Fallback to direct execution with quoted values # Your existing quote method will handle any unquoted values raw_connection.query(sql) end result end |
#return_value_after_insert?(column) ⇒ Boolean
Determines if a column value should be returned after insert This is crucial - it tells Rails which columns should use RETURNING
162 163 164 165 |
# File 'lib/active_record/connection_adapters/duckdb/database_statements.rb', line 162 def return_value_after_insert?(column) # Return true for any column with a sequence default column.default_function&.include?('nextval') || super end |
#write_query?(_sql) ⇒ Boolean
Determines if a SQL query is a write operation
11 12 13 |
# File 'lib/active_record/connection_adapters/duckdb/database_statements.rb', line 11 def write_query?(_sql) false end |