mtc

package module
v0.0.3-fork.0 Latest Latest
Warning

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

Go to latest
Published: Dec 10, 2025 License: MIT Imports: 6 Imported by: 0

README

Fork Notice

  • This repository is a fork of github.com/mickamy/mtc.
  • Module path has been changed to github.com/KiraboshiSys/mtc for long-term internal use.

mtc — Multi-Tenant Connector for Go (RLS + Context)

mtc is a lightweight Go library that automatically applies tenant-scoped context values (like app.tenant_id) to PostgreSQL connections using Row-Level Security (RLS).

Features

  • Propagates tenant IDs from context.Context into PostgreSQL GUCs.
  • Applies the tenant both for explicit transactions (BeginTx) and autocommit statements (QueryContext, ExecContext) by bracketing each query with set_config(..., false) / RESET.
  • Works with any database/sql driver; pgx is supported out of the box.
  • Validates tenant setting name to avoid SQL injection (reset setting safety).
  • Keeps session state clean by resetting the tenant setting on pooled connections.

Installation

go get github.com/KiraboshiSys/mtc

Quick Start

package main

import (
	"context"
	"database/sql"
	"fmt"

	"github.com/jackc/pgx/v5/stdlib"
	"github.com/KiraboshiSys/mtc"
)

type tenantKey struct{}

func tenantFromContext(ctx context.Context) (string, error) {
	if v, ok := ctx.Value(tenantKey{}).(string); ok && v != "" {
		return v, nil
	}
	return "", nil
}

func main() {
	connector := mtc.New(
		stdlib.GetDefaultDriver(),
		"postgres://user:pass@localhost:5432/app?sslmode=disable",
		tenantFromContext,
		mtc.WithSettingName("app.tenant_id"),
	)

	db := sql.OpenDB(connector)
	defer db.Close()

	ctx := context.WithValue(context.Background(), tenantKey{}, "tenant-123")

	var tenant string
	if err := db.QueryRowContext(ctx, "select current_setting('app.tenant_id', true)").Scan(&tenant); err != nil {
		panic(err)
	}
	fmt.Println("tenant:", tenant)

	tx, err := db.BeginTx(ctx, nil)
	if err != nil {
		panic(err)
	}
	defer tx.Rollback()

	// Within this transaction the tenant is visible via current_setting as well.
}

mtc plays nicely with PostgreSQL RLS policies that depend on current_setting('app.tenant_id', true).

License

MIT

Documentation

Overview

Package mtc provides a Multi-Tenant Connector for PostgreSQL. It applies tenant-scoped context values transaction-locally via set_config(..., true) right after BeginTx, for safe RLS operation.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Connector

type Connector struct {
	// contains filtered or unexported fields
}

Connector injects tenant ID into PostgreSQL "transaction-local" settings so that RLS policies can rely on current_setting(settingName, true).

func New

func New(drv driver.Driver, dsn string, fn TenantIDFunc, opts ...Option) *Connector

New returns a Connector with optional settings.

func (*Connector) Connect

func (c *Connector) Connect(ctx context.Context) (driver.Conn, error)

Connect is called when a new physical connection is created. NOTE: We DO NOT set tenant here to avoid session-scope leaks.

func (*Connector) Driver

func (c *Connector) Driver() driver.Driver

type Option

type Option func(*Connector)

Option configures Connector.

func WithSettingName

func WithSettingName(name string) Option

WithSettingName sets the PostgreSQL GUC name used for tenant scoping (default: "app.tenant_id"). It must match ^[a-z_][a-z0-9_.]*$ (e.g. "app.tenant_id").

type TenantIDFunc

type TenantIDFunc func(context.Context) (string, error)

TenantIDFunc defines a function that extracts tenant ID from context.Context.

Jump to

Keyboard shortcuts

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