Class: QueryGuard::Migrations::PostgreSQLAdapter
- Inherits:
-
DatabaseAdapter
- Object
- DatabaseAdapter
- QueryGuard::Migrations::PostgreSQLAdapter
- Defined in:
- lib/query_guard/migrations/postgresql_adapter.rb
Overview
PostgreSQL-specific metadata adapter
Queries PostgreSQL system catalog to estimate table sizes and determine lock risk based on row count and write activity.
Row count thresholds (from PostgreSQL best practices):
- < 1M rows: Low lock risk, fast schema changes
- 1M - 10M rows: Medium lock risk, monitor lock times
- 10M - 100M rows: High lock risk, use concurrent operations
-
100M rows: Critical risk, requires special handling
Constant Summary collapse
- LOCK_THRESHOLDS =
Lock duration thresholds (milliseconds) Based on typical PostgreSQL behavior
{ low: 1_000_000, # < 1M rows medium: 10_000_000, # 1M - 10M rows high: 100_000_000, # 10M - 100M rows critical: Float::INFINITY # > 100M rows }.freeze
Instance Method Summary collapse
-
#clear_cache ⇒ Object
Clear the row count cache.
-
#connected? ⇒ Boolean
Check if connection is healthy.
-
#estimate_lock_risk(table_name) ⇒ Symbol?
Estimate lock risk based on table size.
-
#estimate_table_rows(table_name) ⇒ Integer?
Estimate row count using PostgreSQL statistics.
-
#initialize(connection, schema: "public", cache: true) ⇒ PostgreSQLAdapter
constructor
Initialize PostgreSQL adapter.
-
#list_tables ⇒ Array<String>
List all tables in schema.
-
#table_exists?(table_name) ⇒ Boolean
Check if table exists.
Constructor Details
#initialize(connection, schema: "public", cache: true) ⇒ PostgreSQLAdapter
Initialize PostgreSQL adapter
30 31 32 33 34 35 |
# File 'lib/query_guard/migrations/postgresql_adapter.rb', line 30 def initialize(connection, schema: "public", cache: true) @connection = connection @schema = schema @cache_enabled = cache @cache = {} if cache end |
Instance Method Details
#clear_cache ⇒ Object
Clear the row count cache
Call this if you've made schema changes and want fresh stats.
152 153 154 |
# File 'lib/query_guard/migrations/postgresql_adapter.rb', line 152 def clear_cache @cache.clear if @cache_enabled && @cache end |
#connected? ⇒ Boolean
Check if connection is healthy
137 138 139 140 141 142 143 144 145 146 147 |
# File 'lib/query_guard/migrations/postgresql_adapter.rb', line 137 def connected? return false if @connection.nil? begin @connection.exec_query("SELECT 1 LIMIT 1") true rescue StandardError => e warn "Database connection check failed: #{e.}" false end end |
#estimate_lock_risk(table_name) ⇒ Symbol?
Estimate lock risk based on table size
Larger tables take longer to lock and rewrite, increasing risk of production impact.
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/query_guard/migrations/postgresql_adapter.rb', line 76 def estimate_lock_risk(table_name) rows = estimate_table_rows(table_name) return nil if rows.nil? case rows when 0...LOCK_THRESHOLDS[:low] :low when LOCK_THRESHOLDS[:low]...LOCK_THRESHOLDS[:medium] :medium when LOCK_THRESHOLDS[:medium]...LOCK_THRESHOLDS[:high] :high else :critical end end |
#estimate_table_rows(table_name) ⇒ Integer?
Estimate row count using PostgreSQL statistics
Uses pg_class.reltuples for estimated row count. Falls back to COUNT(*) if stats unavailable.
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/query_guard/migrations/postgresql_adapter.rb', line 44 def estimate_table_rows(table_name) return nil unless connected? return @cache[table_name.to_s] if @cache_enabled && @cache.key?(table_name.to_s) begin # Use PostgreSQL statistics (faster, less accurate) result = @connection.exec_query( "SELECT reltuples::bigint as estimated_rows FROM pg_class WHERE relname = $1 AND relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = $2) LIMIT 1", "GetTableRows", [[table_name.to_s, :string], [@schema, :string]] ) rows = result.rows.dig(0, 0)&.to_i @cache[table_name.to_s] = rows if @cache_enabled rows rescue StandardError => e # Fail gracefully - log if possible, return nil warn "Failed to get row count for #{table_name}: #{e.}" nil end end |
#list_tables ⇒ Array<String>
List all tables in schema
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
# File 'lib/query_guard/migrations/postgresql_adapter.rb', line 116 def list_tables return [] unless connected? begin result = @connection.exec_query( "SELECT table_name FROM information_schema.tables WHERE table_schema = $1 ORDER BY table_name", "ListTables", [[@schema, :string]] ) result.rows.flatten rescue StandardError => e warn "Failed to list tables: #{e.}" [] end end |
#table_exists?(table_name) ⇒ Boolean
Check if table exists
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/query_guard/migrations/postgresql_adapter.rb', line 96 def table_exists?(table_name) return false unless connected? begin result = @connection.exec_query( "SELECT 1 FROM information_schema.tables WHERE table_schema = $1 AND table_name = $2 LIMIT 1", "CheckTableExists", [[@schema, :string], [table_name.to_s, :string]] ) result.rows.any? rescue StandardError => e warn "Failed to check if table exists #{table_name}: #{e.}" false end end |