Class: Apartment::Adapters::PostgresqlSchemaAdapter

Inherits:
AbstractAdapter show all
Defined in:
lib/apartment/adapters/postgresql_schema_adapter.rb

Overview

v4 PostgreSQL adapter using schema-based tenant isolation.

Resolves tenant-specific connection configs by setting ‘schema_search_path` to the raw tenant name (not environmentified — schemas are named directly, unlike database-per-tenant adapters) plus any persistent schemas from Apartment.config.postgres_config. Lifecycle operations (create/drop) execute DDL against the default connection.

Instance Attribute Summary

Attributes inherited from AbstractAdapter

#connection_config

Instance Method Summary collapse

Methods inherited from AbstractAdapter

#create, #default_tenant, #drop, #environmentify, #initialize, #migrate, #process_excluded_models, #process_pinned_model, #process_pinned_models, #seed, #tenant_container_gone?, #validated_connection_config

Constructor Details

This class inherits a constructor from Apartment::Adapters::AbstractAdapter

Instance Method Details

#failsafe_error_classesObject

The schema-strategy missing-tenant error: a dropped schema is not caught at switch time (search_path accepts a non-existent schema silently) — it surfaces on the first query as ActiveRecord::StatementInvalid (PG::UndefinedTable, 42P01). That is the same shape as a missing table in a live schema, so #tenant_container_exists? does the disambiguating to_regnamespace check.

ApartmentError is included because ConnectionHandling wraps errors raised during pool resolution (e.g. the dev-mode pending-migration check, which queries schema_migrations in the gone schema) as ApartmentError with the StatementInvalid as #cause; #container_error? then unwraps and classifies it the same as the query-time case, and re-raises any other ApartmentError.



53
54
55
# File 'lib/apartment/adapters/postgresql_schema_adapter.rb', line 53

def failsafe_error_classes
  [ActiveRecord::StatementInvalid, Apartment::ApartmentError]
end

#qualify_pinned_table_name(klass) ⇒ Object



19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/apartment/adapters/postgresql_schema_adapter.rb', line 19

def qualify_pinned_table_name(klass)
  if klass.apartment_explicit_table_name?
    original = klass.table_name
    table = original.sub(/\A[^.]+\./, '')
    klass.table_name = "#{default_tenant}.#{table}"
    klass.apartment_mark_processed!(:explicit, original)
  else
    original_prefix = klass.table_name_prefix
    klass.table_name_prefix = "#{default_tenant}."
    klass.reset_table_name
    klass.apartment_mark_processed!(:convention, original_prefix)
  end
end

#resolve_connection_config(tenant, base_config: nil) ⇒ Object



33
34
35
36
37
38
39
# File 'lib/apartment/adapters/postgresql_schema_adapter.rb', line 33

def resolve_connection_config(tenant, base_config: nil)
  config = base_config || send(:base_config)
  persistent = Apartment.config.postgres_config&.persistent_schemas || []
  search_path = [tenant, *persistent].map { |s| %("#{s}") }.join(',')

  config.merge('schema_search_path' => search_path)
end

#shared_pinned_connection?Boolean

Returns:

  • (Boolean)


15
16
17
# File 'lib/apartment/adapters/postgresql_schema_adapter.rb', line 15

def shared_pinned_connection?
  !Apartment.config.force_separate_pinned_pool
end