lib/penthouse/tenants/schema_tenant.rb in penthouse-0.2.0 vs lib/penthouse/tenants/schema_tenant.rb in penthouse-0.3.0
- old
+ new
@@ -4,42 +4,71 @@
# will be sharing a single Postgres instance and therefore performance is
# shared.
#
require_relative './base_tenant'
+require_relative './migratable'
module Penthouse
module Tenants
class SchemaTenant < BaseTenant
+ include Migratable
+
attr_accessor :tenant_schema, :persistent_schemas, :default_schema
private :tenant_schema=, :persistent_schemas=, :default_schema=
# @param identifier [String, Symbol] An identifier for the tenant
# @param tenant_schema [String] your tenant's schema name in Postgres
- # @param tenant_schema [String] your tenant's schema name in Postgres
# @param persistent_schemas [Array<String>] The schemas you always want in the search path
# @param default_schema [String] The global schema name, usually 'public'
def initialize(identifier, tenant_schema:, persistent_schemas: ["shared_extensions"], default_schema: "public")
super(identifier)
- self.tenant_schema = tenant_schema
- self.persistent_schemas = Array(persistent_schemas).flatten
- self.default_schema = default_schema
+ self.tenant_schema = tenant_schema.freeze
+ self.persistent_schemas = Array(persistent_schemas).flatten.freeze
+ self.default_schema = default_schema.freeze
freeze
end
- # ensures we're on the master Octopus shard, just updates the schema name
- # with the tenant name
+ # switches to the tenant schema to run the block, ensuring we switch back
+ # afterwards, regardless of whether an exception occurs
# @param block [Block] The code to execute within the schema
# @yield [SchemaTenant] The current tenant instance
def call(&block)
begin
# set the search path to include the tenant
- ActiveRecord::Base.connection.schema_search_path = persistent_schemas.unshift(tenant_schema).join(", ")
+ ActiveRecord::Base.connection.schema_search_path = persistent_schemas.dup.unshift(tenant_schema).join(", ")
block.yield(self)
ensure
# reset the search path back to the default
- ActiveRecord::Base.connection.schema_search_path = persistent_schemas.unshift(default_schema).join(", ")
+ ActiveRecord::Base.connection.schema_search_path = persistent_schemas.dup.unshift(default_schema).join(", ")
end
end
+
+ # creates the tenant schema
+ # @param run_migrations [Boolean] whether or not to run migrations, defaults to Penthouse.configuration.migrate_tenants?
+ # @param db_schema_file [String] a path to the DB schema file to load, defaults to Penthouse.configuration.db_schema_file
+ def create(run_migrations: Penthouse.configuration.migrate_tenants?, db_schema_file: Penthouse.configuration.db_schema_file)
+ sql = ActiveRecord::Base.send(:sanitize_sql_array, ["create schema if not exists %s", tenant_schema])
+ ActiveRecord::Base.connection.exec_query(sql, 'Create Schema')
+ if !!run_migrations
+ migrate(db_schema_file: db_schema_file)
+ end
+ end
+
+ # drops the tenant schema
+ # @param force [Boolean] whether or not to drop the schema if not empty, defaults to true
+ def delete(force: true)
+ sql = ActiveRecord::Base.send(:sanitize_sql_array, ["drop schema if exists %s %s", tenant_schema, force ? 'cascade' : 'restrict'])
+ ActiveRecord::Base.connection.exec_query(sql, 'Delete Schema')
+ end
+
+ # returns whether or not this tenant's schema exists
+ # @return [Boolean] whether or not the tenant exists
+ def exists?
+ sql = ActiveRecord::Base.send(:sanitize_sql_array, ["select 1 from pg_namespace where nspname = '%s'", tenant_schema])
+ result = ActiveRecord::Base.connection.exec_query(sql, "Schema Exists")
+ !result.rows.empty?
+ end
+
end
end
end