Class: PgReports::Connection::Registry

Inherits:
Object
  • Object
show all
Defined in:
lib/pg_reports/connection/registry.rb

Overview

Registry of named PostgreSQL targets.

In a Rails app the :primary target is auto-registered on first access from ActiveRecord::Base.connection_db_config — no configuration is required. Additional targets can be registered explicitly via Configuration#add_target for setups where the dashboard should reach databases the host app cannot.

Current target/database is tracked in a Thread.current slot, switched via PgReports.with_target / PgReports.with_database for block-scoped usage.

Defined Under Namespace

Classes: UnknownTarget

Constant Summary collapse

THREAD_KEY_TARGET =
:pg_reports_current_target
THREAD_KEY_DATABASE =
:pg_reports_current_database

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeRegistry

Returns a new instance of Registry.



20
21
22
23
24
25
# File 'lib/pg_reports/connection/registry.rb', line 20

def initialize
  @targets = {}
  @default_name = :primary
  @auto_registered = false
  @mutex = Mutex.new
end

Instance Attribute Details

#default_nameObject

Returns the value of attribute default_name.



27
28
29
# File 'lib/pg_reports/connection/registry.rb', line 27

def default_name
  @default_name
end

Instance Method Details

#current_connectionObject

Resolve the AR connection to use right now (current target + database). Honors PgReports.with_target / with_database thread-local context.



60
61
62
63
# File 'lib/pg_reports/connection/registry.rb', line 60

def current_connection
  target = fetch(current_name)
  target.connection_for(current_database)
end

#current_databaseObject



79
80
81
# File 'lib/pg_reports/connection/registry.rb', line 79

def current_database
  Thread.current[THREAD_KEY_DATABASE]
end

#current_database_nameObject

The database name in effect for the current target.



71
72
73
# File 'lib/pg_reports/connection/registry.rb', line 71

def current_database_name
  current_database || fetch(current_name).default_database
end

#current_nameObject



75
76
77
# File 'lib/pg_reports/connection/registry.rb', line 75

def current_name
  Thread.current[THREAD_KEY_TARGET]
end

#current_targetObject

Returns the target that current_connection would resolve to.



66
67
68
# File 'lib/pg_reports/connection/registry.rb', line 66

def current_target
  fetch(current_name)
end

#ensure_default_registered!Object

Auto-discover the :primary target from ActiveRecord on first need. Idempotent and thread-safe.



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/pg_reports/connection/registry.rb', line 122

def ensure_default_registered!
  return if @auto_registered
  return unless defined?(ActiveRecord::Base)

  @mutex.synchronize do
    return if @auto_registered

    unless @targets.key?(:primary)
      spec = primary_spec_from_active_record
      @targets[:primary] = Target.new(:primary, spec) if spec
    end

    @auto_registered = true
  end
end

#fetch(name = nil) ⇒ Object



52
53
54
55
56
# File 'lib/pg_reports/connection/registry.rb', line 52

def fetch(name = nil)
  ensure_default_registered!
  key = (name || current_name || @default_name).to_sym
  @targets.fetch(key) { raise UnknownTarget, "Unknown target #{key.inspect}. Known: #{@targets.keys.inspect}" }
end

#register(name, spec) ⇒ Object

Register or overwrite a target.



34
35
36
# File 'lib/pg_reports/connection/registry.rb', line 34

def register(name, spec)
  @targets[name.to_sym] = Target.new(name, spec)
end

#reset!Object

For tests / reload scenarios. Restores the registry to a fresh state —closes all derived pools, drops all registered targets, resets default_name back to :primary, and re-arms auto-registration.



111
112
113
114
115
116
117
118
# File 'lib/pg_reports/connection/registry.rb', line 111

def reset!
  @mutex.synchronize do
    @targets.each_value(&:disconnect!)
    @targets.clear
    @default_name = :primary
    @auto_registered = false
  end
end

#target?(name) ⇒ Boolean

Returns:

  • (Boolean)


48
49
50
# File 'lib/pg_reports/connection/registry.rb', line 48

def target?(name)
  targets.any? { |t| t.name == name.to_sym }
end

#target_namesObject



44
45
46
# File 'lib/pg_reports/connection/registry.rb', line 44

def target_names
  targets.map(&:name)
end

#targetsObject

All known targets (auto-registers :primary if needed first).



39
40
41
42
# File 'lib/pg_reports/connection/registry.rb', line 39

def targets
  ensure_default_registered!
  @targets.values
end

#with_context(target: nil, database: nil) ⇒ Object

Switch target and/or database for the duration of the block. Semantics:

  • target given → switches target AND clears the database override

    (the previous database belongs to the previous
    target's cluster and would not be valid on a new
    one). Pass `database:` explicitly to override on
    the new target.
    
  • target nil → keeps the active target, switches only database.

  • database nil → uses the (possibly new) target’s default database.



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/pg_reports/connection/registry.rb', line 91

def with_context(target: nil, database: nil)
  prev_target = Thread.current[THREAD_KEY_TARGET]
  prev_database = Thread.current[THREAD_KEY_DATABASE]

  if target
    Thread.current[THREAD_KEY_TARGET] = target.to_sym
    Thread.current[THREAD_KEY_DATABASE] = database&.to_s
  elsif database
    Thread.current[THREAD_KEY_DATABASE] = database.to_s
  end

  yield
ensure
  Thread.current[THREAD_KEY_TARGET] = prev_target
  Thread.current[THREAD_KEY_DATABASE] = prev_database
end