Documentation
¶
Overview ¶
Package driver provides the foundational interfaces for implementing multitenancy support within database systems. It outlines the necessary components for managing tenant lifecycles, including onboarding, offboarding, and handling shared resources. These interfaces serve as a contract for database management systems (DBMS) to ensure consistent multitenant operations, abstracting the complexities of tenant-specific data handling. Developers should integrate these interfaces with their database solutions to enable scalable and isolated data management for each tenant, leveraging the flexibility and power of GORM for ORM operations. This package is intended for use by developers implementing multitenant architectures, with the core application logic residing elsewhere.
Index ¶
Examples ¶
Constants ¶
const PublicSchemaEnvVar = "GMT_PUBLIC_SCHEMA_NAME"
PublicSchemaEnvVar is the environment variable that contains the name of the public schema.
Variables ¶
Functions ¶
func ModelsToInterfaces ¶
func ModelsToInterfaces(models []TenantTabler) []interface{}
ModelsToInterfaces converts a slice of TenantTabler models to a slice of interface{}.
func ParseDSNQueryParams ¶
ParseDSNQueryParams parses the query parameters from the dsn string and decodes them into a generic type T (non-pointer struct). It returns the parsed parameters and an error if any occurred.
The dsn string should be in the format of a standard URL with query parameters. For example: "user:password@tcp(localhost:3306)/dbname?charset=utf8&parseTime=True&loc=Local".
Example ¶
package main import ( "fmt" "time" "github.com/thisaftermath/gorm-multitenancy/v8/pkg/driver" ) func main() { type backoffOptions struct { MaxRetries int `mapstructure:"max_retries"` Interval time.Duration `mapstructure:"retry_interval"` MaxInterval time.Duration `mapstructure:"retry_max_interval"` } type dsnOptions struct { DisableRetry bool `mapstructure:"disable_retry"` Retry backoffOptions `mapstructure:",squash"` } dsn := "mysql://user:password@tcp(localhost:3306)/dbname?disable_retry=true&max_retries=6&retry_interval=2s&retry_max_interval=30s" opts, err := driver.ParseDSNQueryParams[dsnOptions](dsn) if err != nil { panic(err) } // Use the parsed options. fmt.Printf("DisableRetry: %v\n", opts.DisableRetry) fmt.Printf("MaxRetries: %d\n", opts.Retry.MaxRetries) fmt.Printf("Interval: %s\n", opts.Retry.Interval) fmt.Printf("MaxInterval: %s\n", opts.Retry.MaxInterval) }
Output: DisableRetry: true MaxRetries: 6 Interval: 2s MaxInterval: 30s
func PublicSchemaName ¶
func PublicSchemaName() string
PublicSchemaName returns the name of the public schema as defined by the PublicSchemaEnvVar environment variable, defaulting to "public" if the variable is not set. This schema name is used to identify shared models.
Types ¶
type DBFactory ¶
type DBFactory interface { // RegisterModels registers GORM model structs for multitenancy support within a specific database. // It prepares models for tenant-specific operations and is idempotent. Returns an error if registration fails. RegisterModels(ctx context.Context, db *gorm.DB, models ...TenantTabler) error // maintaining integrity and compatibility of shared data across tenants. Returns an error if migration fails. MigrateSharedModels(ctx context.Context, db *gorm.DB) error // MigrateTenantModels prepares and updates data structures for a specific tenant within a specific database, // handling onboarding and ongoing schema evolution. Returns an error if setup or migration fails. MigrateTenantModels(ctx context.Context, db *gorm.DB, tenantID string) error // OffboardTenant cleans up the database for a removed tenant within a specific database, supporting clean offboarding. // Returns an error if the process fails. OffboardTenant(ctx context.Context, db *gorm.DB, tenantID string) error // UseTenant configures the database for operations specific to a tenant within a specific database, abstracting // database-specific operations for tenant context configuration. Returns a reset function to revert the database context // and an error if the operation fails. UseTenant(ctx context.Context, db *gorm.DB, tenantID string) (reset func() error, err error) // CurrentTenant returns the identifier for the current tenant context within a specific database or an empty string // if no context is set. CurrentTenant(ctx context.Context, db *gorm.DB) string }
DBFactory defines operations for managing the lifecycle of tenants within a multitenant database architecture. It abstracts tenant-specific operations such as onboarding, offboarding, and managing shared resources. Implementations of this interface are designed to integrate multitenancy support with GORM's features, providing a consistent approach across different database backends.
type ModelRegistry ¶
type ModelRegistry struct { TenantModels []TenantTabler // TenantModels contains the models that are specific to a tenant. }
ModelRegistry holds the models registered for multitenancy support, categorizing them into shared and tenant-specific models. Not intended for direct use in application code.
func NewModelRegistry ¶
func NewModelRegistry(models ...TenantTabler) (*ModelRegistry, error)
NewModelRegistry creates and initializes a new ModelRegistry with the provided models, categorizing them into shared and tenant-specific based on their characteristics. It returns an error if any model fails validation. Not intended for direct use in application code.
type TenantTabler ¶
type TenantTabler interface { schema.Tabler // it does not belong to a single tenant. IsSharedModel() bool }
TenantTabler defines an interface for models within a multi-tenant architecture, extending schema.Tabler. Models must define their table name and indicate if they are shared across tenants. Crucial for differentiating between shared and tenant-specific data.
Implementations of this interface should return true for [IsSharedModel] if the model is shared across tenants, indicating it does not belong to a single tenant.
Example of a shared model:
type User struct { gorm.Model Email string } func (User) TableName() string { return "public.users" } func (User) IsSharedModel() bool { return true }
Example of a tenant-specific model:
type Product struct { gorm.Model TenantID string Name string } func (Product) TableName() string { return "products" } func (Product) IsSharedModel() bool { return false }
type URL ¶
URL is a wrapper around the standard stdurl.URL type that includes the original URL string. It is designed to handle additional special cases for driver URL-like strings, such as the @tcp(localhost:3306) format used by MySQL.
func ParseURL ¶
ParseURL parses the provided rawURL string and returns a new URL instance. This function is a convenience wrapper around the URL.Parse method, allowing for direct parsing of raw URL strings into the URL type.
Example ¶
package main import ( "fmt" "github.com/thisaftermath/gorm-multitenancy/v8/pkg/driver" ) func main() { dsn := "mysql://user:password@tcp(localhost:3306)/dbname" u, err := driver.ParseURL(dsn) if err != nil { panic(err) } fmt.Println("Scheme:", u.Scheme) fmt.Println("Host:", u.Host) fmt.Println("Path:", u.Path) fmt.Println("User:", u.User.String()) fmt.Println("Raw URL:", u.Raw()) fmt.Println("Sanitized URL:", u.String()) }
Output: Scheme: mysql Host: localhost:3306 Path: /dbname User: user:password Raw URL: mysql://user:password@tcp(localhost:3306)/dbname Sanitized URL: mysql://user:password@localhost:3306/dbname