Class: Tina4::Drivers::PostgresDriver
- Inherits:
-
Object
- Object
- Tina4::Drivers::PostgresDriver
- Defined in:
- lib/tina4/drivers/postgres_driver.rb
Instance Attribute Summary collapse
-
#connection ⇒ Object
readonly
Returns the value of attribute connection.
Instance Method Summary collapse
- #apply_limit(sql, limit, offset = 0) ⇒ Object
- #begin_transaction ⇒ Object
- #close ⇒ Object
- #columns(table_name) ⇒ Object
- #commit ⇒ Object
- #connect(connection_string, username: nil, password: nil) ⇒ Object
- #execute(sql, params = []) ⇒ Object
- #execute_query(sql, params = []) ⇒ Object
- #last_insert_id ⇒ Object
- #placeholder ⇒ Object
- #placeholders(count) ⇒ Object
- #rollback ⇒ Object
- #tables ⇒ Object
Instance Attribute Details
#connection ⇒ Object (readonly)
Returns the value of attribute connection.
6 7 8 |
# File 'lib/tina4/drivers/postgres_driver.rb', line 6 def connection @connection end |
Instance Method Details
#apply_limit(sql, limit, offset = 0) ⇒ Object
92 93 94 |
# File 'lib/tina4/drivers/postgres_driver.rb', line 92 def apply_limit(sql, limit, offset = 0) "#{sql} LIMIT #{limit} OFFSET #{offset}" end |
#begin_transaction ⇒ Object
96 97 98 |
# File 'lib/tina4/drivers/postgres_driver.rb', line 96 def begin_transaction @connection.exec("BEGIN") end |
#close ⇒ Object
20 21 22 |
# File 'lib/tina4/drivers/postgres_driver.rb', line 20 def close @connection&.close end |
#columns(table_name) ⇒ Object
114 115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/tina4/drivers/postgres_driver.rb', line 114 def columns(table_name) sql = "SELECT column_name, data_type, is_nullable, column_default FROM information_schema.columns WHERE table_name = $1" rows = execute_query(sql, [table_name]) rows.map do |r| { name: r[:column_name], type: r[:data_type], nullable: r[:is_nullable] == "YES", default: r[:column_default], primary_key: false } end end |
#commit ⇒ Object
100 101 102 |
# File 'lib/tina4/drivers/postgres_driver.rb', line 100 def commit @connection.exec("COMMIT") end |
#connect(connection_string, username: nil, password: nil) ⇒ Object
8 9 10 11 12 13 14 15 16 17 18 |
# File 'lib/tina4/drivers/postgres_driver.rb', line 8 def connect(connection_string, username: nil, password: nil) require "pg" url = connection_string if username || password uri = URI.parse(url) uri.user = username if username uri.password = password if password url = uri.to_s end @connection = PG.connect(url) end |
#execute(sql, params = []) ⇒ Object
34 35 36 37 38 39 40 41 |
# File 'lib/tina4/drivers/postgres_driver.rb', line 34 def execute(sql, params = []) converted_sql = convert_placeholders(sql) if params.empty? @connection.exec(converted_sql) else @connection.exec_params(converted_sql, params) end end |
#execute_query(sql, params = []) ⇒ Object
24 25 26 27 28 29 30 31 32 |
# File 'lib/tina4/drivers/postgres_driver.rb', line 24 def execute_query(sql, params = []) converted_sql = convert_placeholders(sql) result = if params.empty? @connection.exec(converted_sql) else @connection.exec_params(converted_sql, params) end result.map { |row| decode_blobs(symbolize_keys(row)) } end |
#last_insert_id ⇒ Object
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/tina4/drivers/postgres_driver.rb', line 43 def last_insert_id # Issue #38: ``SELECT lastval()`` raises on tables with no sequence # (UUID, ULID, hash PKs etc.). The exception itself isn't fatal, # but the pg gem marks the whole transaction as aborted, so every # subsequent statement on this connection fails with # ``PG::InFailedSqlTransaction`` — far away from the real cause. # # Fix: wrap the probe in a SAVEPOINT. If ``lastval()`` raises, we # ROLLBACK TO SAVEPOINT and the outer transaction stays usable; # ``last_insert_id`` just returns ``nil`` (same as before for # tables without a sequence). On success we RELEASE SAVEPOINT. begin @connection.exec("SAVEPOINT _t4_lastval_probe") rescue PG::Error # No active transaction (autocommit/idle) — fall back to a plain # probe; psycopg2-style transaction abort can't happen here. begin result = @connection.exec("SELECT lastval()") return result.first["lastval"].to_i rescue PG::Error return nil end end begin result = @connection.exec("SELECT lastval()") @connection.exec("RELEASE SAVEPOINT _t4_lastval_probe") result.first["lastval"].to_i rescue PG::Error begin @connection.exec("ROLLBACK TO SAVEPOINT _t4_lastval_probe") @connection.exec("RELEASE SAVEPOINT _t4_lastval_probe") rescue PG::Error # If even the rollback fails, there's nothing we can do — the # connection is in a state we can't recover. Surface nil so # callers don't get a half-set last_id. end nil end end |
#placeholder ⇒ Object
84 85 86 |
# File 'lib/tina4/drivers/postgres_driver.rb', line 84 def placeholder "?" end |
#placeholders(count) ⇒ Object
88 89 90 |
# File 'lib/tina4/drivers/postgres_driver.rb', line 88 def placeholders(count) (1..count).map { |i| "$#{i}" }.join(", ") end |
#rollback ⇒ Object
104 105 106 |
# File 'lib/tina4/drivers/postgres_driver.rb', line 104 def rollback @connection.exec("ROLLBACK") end |
#tables ⇒ Object
108 109 110 111 112 |
# File 'lib/tina4/drivers/postgres_driver.rb', line 108 def tables sql = "SELECT tablename FROM pg_tables WHERE schemaname = 'public'" rows = execute_query(sql) rows.map { |r| r[:tablename] } end |