multitenancy

package
v0.9.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 18, 2026 License: Apache-2.0 Imports: 8 Imported by: 0

Documentation

Overview

Package multitenancy provides PostgreSQL schema-per-tenant support on top of GORM.

It wraps a gorm.DB connection with tenant-aware operations: registering shared and tenant-specific models, migrating them, switching the active tenant schema, and cleaning up a tenant's schema on offboarding. The concrete database behavior is provided by a registered Adapter (see the postgres subpackage).

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrDriverAlreadyRegistered = errors.New("driver already registered")
	ErrNoRegisteredAdapter     = errors.New("no registered adapter for driver")
)

Adapter registry errors.

Functions

func Register

func Register(name string, adapter Adapter)

Register adds a new Adapter to the default registry under the specified driver name. It panics if an Adapter for the given driver name is already registered.

Types

type Adapter

type Adapter interface {
	// AdaptDB enhances an existing [gorm.DB] instance with additional functionalities and returns
	// a new [DB] instance. The returned DB instance should be used by a single goroutine at a time
	// to ensure thread safety and prevent concurrent access issues.
	AdaptDB(ctx context.Context, db *gorm.DB) (*DB, error)
}

Adapter defines an interface for enhancing gorm.DB instances with additional functionalities.

type DB

type DB struct {
	*gorm.DB
	// contains filtered or unexported fields
}

DB wraps a GORM DB connection, integrating support for multitenancy operations. It provides a unified interface for managing tenant-specific and shared data within a multi-tenant application, leveraging GORM's ORM capabilities for database operations.

func NewDB

func NewDB(d driver.DBFactory, tx *gorm.DB) *DB

NewDB creates a new DB instance using the provided driver.DBFactory and gorm.DB instance. This function is intended for use by Adapter implementations to create new instances of DB with multitenancy support. Not intended for direct use in application code.

func Open

func Open(dialector gorm.Dialector, opts ...gorm.Option) (*DB, error)

Open is a drop-in replacement for gorm.Open. It returns a new DB instance using the provided dialector (see the postgres subpackage) and options.

import (
	gormpg "gorm.io/driver/postgres"

	"github.com/openkcm/cmk/internal/multitenancy"
	"github.com/openkcm/cmk/internal/multitenancy/postgres"
)

dsn := "postgres://user:password@localhost:5432/dbname?sslmode=disable"
db, err := multitenancy.Open(postgres.New(postgres.Config{Config: gormpg.Config{DSN: dsn}}))
if err != nil {
	// handle err
}

func (*DB) Begin

func (db *DB) Begin(opts ...*sql.TxOptions) *DB

Begin begins a transaction.

func (*DB) CurrentTenant

func (db *DB) CurrentTenant(ctx context.Context) string

CurrentTenant returns the identifier for the current tenant context or an empty string if no context is set.

func (*DB) MigrateSharedModels

func (db *DB) MigrateSharedModels(ctx context.Context) error

MigrateSharedModels migrates all registered shared/public models.

Safe for concurrent use by multiple goroutines w.r.t. ensuring data integrity and schema isolation.

func (*DB) MigrateTenantModels

func (db *DB) MigrateTenantModels(ctx context.Context, tenantID string) error

MigrateTenantModels migrates all registered tenant-specific models for the specified tenant. This method is intended to be used when onboarding a new tenant or updating an existing tenant's schema to match the latest model definitions.

Safe for concurrent use by multiple goroutines w.r.t. ensuring data integrity and schema isolation.

func (*DB) OffboardTenant

func (db *DB) OffboardTenant(ctx context.Context, tenantID string) error

OffboardTenant cleans up the database by dropping the tenant-specific schema and associated tables. This method is intended to be used after a tenant has been removed.

Safe for concurrent use by multiple goroutines w.r.t. ensuring data integrity and schema isolation.

func (*DB) RegisterModels

func (db *DB) RegisterModels(ctx context.Context, models ...driver.TenantTabler) error

RegisterModels registers GORM model structs for multitenancy support, preparing models for tenant-specific operations.

Not safe for concurrent use by multiple goroutines. Call this method from your main function or during application initialization.

func (*DB) Session

func (db *DB) Session(config *gorm.Session) *DB

Session returns a new copy of the DB, which has a new session with the configuration.

func (*DB) Transaction

func (db *DB) Transaction(fc func(tx *DB) error, opts ...*sql.TxOptions) (err error)

Transaction starts a transaction as a block, returns an error if there's any error within the block. If the function passed to tx returns an error, the transaction will be rolled back automatically, otherwise, the transaction will be committed.

func (*DB) UseTenant

func (db *DB) UseTenant(ctx context.Context, tenantID string) (reset func() error, err error)

UseTenant configures the database for operations specific to a tenant. A reset function is returned to revert the database context to its original state.

Technically safe for concurrent use by multiple goroutines, but should not be used concurrently w.r.t. ensuring data integrity and schema isolation. Either use DB.WithTenant, or ensure that this method is called within a transaction or from its own database connection.

func (*DB) WithContext

func (db *DB) WithContext(ctx context.Context) *DB

WithContext sets the context for the DB.

func (*DB) WithTenant

func (db *DB) WithTenant(
	ctx context.Context,
	tenantID string,
	fc func(tx *DB) error,
	opts ...*sql.TxOptions,
) (err error)

WithTenant executes the provided function within the context of a specific tenant, ensuring that the database operations are scoped to the tenant's schema. It runs in a transaction that is committed on success and rolled back on error.

Safe for concurrent use by multiple goroutines w.r.t. ensuring data integrity and schema isolation.

type TenantModel

type TenantModel struct {
	// DomainURL is the domain URL of the tenant; same as [net/url.URL.Host].
	DomainURL string `json:"domainURL" mapstructure:"domainURL" gorm:"column:domain_url;uniqueIndex;size:128"`

	// SchemaName is the schema name of the tenant.
	//
	// Field-level permissions are restricted to read and create.
	//
	// The following constraints are applied:
	// 	- unique index
	// 	- size: 63
	//  - check: Not less than 3 characters long
	//nolint:lll // gorm struct tags must be a single line; the DB column constraints are load-bearing
	SchemaName string `` /* 133-byte string literal not displayed */
}

TenantModel a basic GoLang struct which includes the following fields: DomainURL, SchemaName. It's intended to be embedded into any public model that needs to be scoped to a tenant.

For example:

type Tenant struct {
  multitenancy.TenantModel
}

Directories

Path Synopsis
Package driver provides the foundational interfaces for implementing multitenancy support within database systems.
Package driver provides the foundational interfaces for implementing multitenancy support within database systems.
Package logext provides a custom logger that logs messages to the provided output.
Package logext provides a custom logger that logs messages to the provided output.
Package migrator provides utilities for database migration management.
Package migrator provides utilities for database migration management.
Package namespace provides utilities for validating tenant names in a consistent manner across different database systems.
Package namespace provides utilities for validating tenant names in a consistent manner across different database systems.
Package postgres provides a gorm.Dialector implementation for PostgreSQL databases to support multitenancy in GORM applications, enabling tenant-specific operations and shared resources management using the "shared database, separate schemas" approach.
Package postgres provides a gorm.Dialector implementation for PostgreSQL databases to support multitenancy in GORM applications, enabling tenant-specific operations and shared resources management using the "shared database, separate schemas" approach.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL