class Apartment::Adapters::PostgresqlSchemaAdapter
Separate Adapter for Postgresql when using schemas
Public Class Methods
new(config)
click to toggle source
Calls superclass method
Apartment::Adapters::AbstractAdapter::new
# File lib/apartment/adapters/postgresql_adapter.rb, line 27 def initialize(config) super reset end
Public Instance Methods
current()
click to toggle source
# File lib/apartment/adapters/postgresql_adapter.rb, line 52 def current @current || default_tenant end
default_tenant()
click to toggle source
# File lib/apartment/adapters/postgresql_adapter.rb, line 33 def default_tenant @default_tenant = Apartment.default_tenant || 'public' end
init()
click to toggle source
Calls superclass method
Apartment::Adapters::AbstractAdapter#init
# File lib/apartment/adapters/postgresql_adapter.rb, line 47 def init super Apartment.connection.schema_search_path = full_search_path end
reset()
click to toggle source
Reset schema search path to the default schema_search_path
@return {String} default schema search path
# File lib/apartment/adapters/postgresql_adapter.rb, line 41 def reset @current = default_tenant Apartment.connection.schema_search_path = full_search_path reset_sequence_names end
Protected Instance Methods
connect_to_new(tenant = nil)
click to toggle source
Set schema search path to new schema
# File lib/apartment/adapters/postgresql_adapter.rb, line 73 def connect_to_new(tenant = nil) return reset if tenant.nil? raise ActiveRecord::StatementInvalid, "Could not find schema #{tenant}" unless schema_exists?(tenant) @current = tenant.is_a?(Array) ? tenant.map(&:to_s) : tenant.to_s Apartment.connection.schema_search_path = full_search_path # When the PostgreSQL version is < 9.3, # there is a issue for prepared statement with changing search_path. # https://www.postgresql.org/docs/9.3/static/sql-prepare.html Apartment.connection.clear_cache! if postgresql_version < 90_300 reset_sequence_names rescue *rescuable_exceptions raise TenantNotFound, "One of the following schema(s) is invalid: \"#{tenant}\" #{full_search_path}" end
drop_command(conn, tenant)
click to toggle source
# File lib/apartment/adapters/postgresql_adapter.rb, line 67 def drop_command(conn, tenant) conn.execute(%(DROP SCHEMA "#{tenant}" CASCADE)) end
process_excluded_model(excluded_model)
click to toggle source
# File lib/apartment/adapters/postgresql_adapter.rb, line 58 def process_excluded_model(excluded_model) excluded_model.constantize.tap do |klass| # Ensure that if a schema *was* set, we override table_name = klass.table_name.split('.', 2).last klass.table_name = "#{default_tenant}.#{table_name}" end end
Private Instance Methods
create_tenant_command(conn, tenant)
click to toggle source
# File lib/apartment/adapters/postgresql_adapter.rb, line 97 def create_tenant_command(conn, tenant) # NOTE: This was causing some tests to fail because of the database strategy for rspec if ActiveRecord::Base.connection.open_transactions.positive? conn.execute(%(CREATE SCHEMA "#{tenant}")) else schema = %(BEGIN; CREATE SCHEMA "#{tenant}"; COMMIT;) conn.execute(schema) end rescue *rescuable_exceptions => e rollback_transaction(conn) raise e end
full_search_path()
click to toggle source
Generate the final search path to set including persistent_schemas
# File lib/apartment/adapters/postgresql_adapter.rb, line 119 def full_search_path persistent_schemas.map(&:inspect).join(', ') end
persistent_schemas()
click to toggle source
# File lib/apartment/adapters/postgresql_adapter.rb, line 123 def persistent_schemas [@current, Apartment.persistent_schemas].flatten end
postgresql_version()
click to toggle source
# File lib/apartment/adapters/postgresql_adapter.rb, line 127 def postgresql_version # ActiveRecord::ConnectionAdapters::PostgreSQLAdapter#postgresql_version is # public from Rails 5.0. Apartment.connection.send(:postgresql_version) end
reset_sequence_names()
click to toggle source
# File lib/apartment/adapters/postgresql_adapter.rb, line 133 def reset_sequence_names # sequence_name contains the schema, so it must be reset after switch # There is `reset_sequence_name`, but that method actually goes to the database # to find out the new name. Therefore, we do this hack to only unset the name, # and it will be dynamically found the next time it is needed descendants_to_unset = ActiveRecord::Base.descendants .select { |c| c.instance_variable_defined?(:@sequence_name) } .reject do |c| c.instance_variable_defined?(:@explicit_sequence_name) && c.instance_variable_get(:@explicit_sequence_name) end descendants_to_unset.each do |c| # NOTE: due to this https://github.com/rails-on-services/apartment/issues/81 # unreproduceable error we're checking before trying to remove it c.remove_instance_variable :@sequence_name if c.instance_variable_defined?(:@sequence_name) end end
rollback_transaction(conn)
click to toggle source
# File lib/apartment/adapters/postgresql_adapter.rb, line 113 def rollback_transaction(conn) conn.execute('ROLLBACK;') end
schema_exists?(schemas)
click to toggle source
# File lib/apartment/adapters/postgresql_adapter.rb, line 151 def schema_exists?(schemas) return true unless Apartment.tenant_presence_check Array(schemas).all? { |schema| Apartment.connection.schema_exists?(schema.to_s) } end
tenant_exists?(tenant)
click to toggle source
# File lib/apartment/adapters/postgresql_adapter.rb, line 91 def tenant_exists?(tenant) return true unless Apartment.tenant_presence_check Apartment.connection.schema_exists?(tenant) end