sdk

package
v0.0.0-...-b25413d Latest Latest
Warning

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

Go to latest
Published: Sep 22, 2025 License: MIT Imports: 46 Imported by: 0

Documentation

Index

Examples

Constants

This section is empty.

Variables

View Source
var ErrNoTarget = errors.New("no target database resolved")
View Source
var (
	ErrValidatorNotFound = errors.New("validator not found")
)

ErrValidatorNotFound is returned when a validator plugin cannot be found.

Functions

func DefaultErrorClassifier

func DefaultErrorClassifier(err error) (bool, bool)

DefaultErrorClassifier provides baseline classification for common errors.

func LabelsFromContext

func LabelsFromContext(ctx context.Context, rules CtxValueRules) []string

LabelsFromContext extracts labels from context values according to rules.

func LabelsFromGRPC

func LabelsFromGRPC(ctx context.Context, rules GRPCLabelRules) []string

LabelsFromGRPC extracts labels from gRPC metadata within a context.

func LabelsFromHTTP

func LabelsFromHTTP(r *http.Request, rules HTTPLabelRules) []string

LabelsFromHTTP extracts labels from an *http.Request based on rules.

func LabelsFromJWT

func LabelsFromJWT(claims map[string]any, rules JWTLabelRules) []string

LabelsFromJWT extracts labels from a claims map based on rules.

func UnifiedDiff

func UnifiedDiff(a, b string) string

UnifiedDiff returns a unified diff string of two inputs.

func WithHTTPRequest

func WithHTTPRequest(ctx context.Context, r *http.Request) context.Context

WithHTTPRequest stores *http.Request in context for AutoLabelResolver.

func WithJWTClaims

func WithJWTClaims(ctx context.Context, claims map[string]any) context.Context

WithJWTClaims stores JWT claims in context for AutoLabelResolver.

func WithTenantID

func WithTenantID(ctx context.Context, tenantID string) context.Context

WithTenantID attaches a tenant ID to the context.

Types

type ApplyOptions

type ApplyOptions struct {
	// DryRun skips applying changes and only computes the diff.
	DryRun bool
	Actor  string
}

type AutoLabelResolverOptions

type AutoLabelResolverOptions struct {
	HTTP *HTTPLabelRules
	GRPC *GRPCLabelRules
	JWT  *JWTLabelRules
	Ctx  *CtxValueRules
	Hint *SelectionHint
}

AutoLabelResolverOptions configures AutoLabelResolver sources.

type Connector

type Connector func(ctx context.Context, driver, dsnOrURL string) (*sql.DB, error)

Connector is responsible for establishing physical database connections.

type CtxValueRules

type CtxValueRules struct {
	KeyMap map[any]string // context key -> label name
	Fixed  map[string]string
}

CtxValueRules configures label extraction from context values.

type DBConfig

type DBConfig struct {
	Driver      string // mysql|postgres|mongo
	DSN         string
	Schema      string
	TablePrefix string
}

DBConfig specifies database connection parameters.

type DiffReport

type DiffReport struct {
	// Added is the number of newly created fields.
	Added int
	// Deleted is the number of removed fields.
	Deleted int
	// Updated is the number of modified fields.
	Updated int
}

func CalculateDiff

func CalculateDiff(changes []registry.Change) DiffReport

CalculateDiff returns counts of added, deleted and updated changes.

type DisplayMeta

type DisplayMeta = registry.DisplayMeta

type DisplayOptions

type DisplayOptions = registry.DisplayOption

type EqExpr

type EqExpr struct{ Label, Value string }

func (EqExpr) Eval

func (e EqExpr) Eval(has func(label string) bool) bool

type ErrorClassifier

type ErrorClassifier func(error) (transient bool, retryable bool)

ErrorClassifier determines whether an error is transient and retryable.

type FailoverPolicy

type FailoverPolicy struct {
	Enabled           bool
	MaxAttempts       int
	BaseBackoff       time.Duration
	MaxBackoff        time.Duration
	JitterRatio       float64
	OpenAfterFailures int
	OpenDuration      time.Duration
	HalfOpenProbe     int
	PreferOnFail      *SelectionHint
	AllowWriteRetry   bool
}

FailoverPolicy controls retry and circuit breaker behavior.

type FieldDef

type FieldDef = registry.FieldMeta

type FieldDiff

type FieldDiff struct {
	Name      string
	MetaDef   FieldDef
	TargetDef FieldDef
	Reason    string
}

FieldDiff describes a discrepancy between MetaDB and target definitions.

type FieldMeta

type FieldMeta = registry.FieldMeta

type FileProvider

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

FileProvider reads target configurations from a JSON file.

func NewFileProvider

func NewFileProvider(path string) *FileProvider

NewFileProvider creates a provider for the given file path.

func (*FileProvider) Fetch

Fetch loads target configs from the file, expanding environment variables in DSNs.

type GRPCLabelRules

type GRPCLabelRules struct {
	MetaMap map[string]string // metadata key -> label name
	Fixed   map[string]string
}

GRPCLabelRules configures label extraction from gRPC metadata.

type HTTPLabelRules

type HTTPLabelRules struct {
	HeaderMap map[string]string // header name -> label name
	Fixed     map[string]string
}

HTTPLabelRules configures label extraction from HTTP headers.

type HasExpr

type HasExpr struct{ Label string }

func (HasExpr) Eval

func (e HasExpr) Eval(has func(label string) bool) bool

type HotReloadRegistry

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

HotReloadRegistry is an RCU-style implementation of TargetRegistry.

func NewHotReloadRegistry

func NewHotReloadRegistry(defaultConn *TargetConn) *HotReloadRegistry

NewHotReloadRegistry creates a registry initialized with the default connection.

func (*HotReloadRegistry) Default

func (r *HotReloadRegistry) Default() (TargetConn, bool)

Default returns the default target connection.

func (*HotReloadRegistry) DefaultKey

func (r *HotReloadRegistry) DefaultKey() string

DefaultKey returns the current default key.

func (*HotReloadRegistry) FindAllByLabels

func (r *HotReloadRegistry) FindAllByLabels(labels ...string) []string

FindAllByLabels returns keys of targets containing all the specified labels.

func (*HotReloadRegistry) FindAnyByLabels

func (r *HotReloadRegistry) FindAnyByLabels(labels ...string) []string

FindAnyByLabels returns keys of targets containing any of the specified labels.

func (*HotReloadRegistry) FindByLabel

func (r *HotReloadRegistry) FindByLabel(label string) []string

FindByLabel returns keys of targets having the given label.

func (*HotReloadRegistry) FindByQuery

func (r *HotReloadRegistry) FindByQuery(q Query) []string

FindByQuery returns keys of targets matching q.

func (*HotReloadRegistry) ForEachByQuery

func (r *HotReloadRegistry) ForEachByQuery(q Query, fn func(key string, t TargetConn) error) error

ForEachByQuery executes fn for each target matching q.

func (*HotReloadRegistry) Get

func (r *HotReloadRegistry) Get(key string) (TargetConn, bool)

Get retrieves a target by key.

func (*HotReloadRegistry) Keys

func (r *HotReloadRegistry) Keys() []string

Keys returns a copy of available keys.

func (*HotReloadRegistry) Register

func (r *HotReloadRegistry) Register(ctx context.Context, key string, cfg TargetConfig, mk Connector) (err error)

Register adds a new target.

func (*HotReloadRegistry) ReplaceAll

func (r *HotReloadRegistry) ReplaceAll(ctx context.Context, cfgs map[string]TargetConfig, mk Connector, defaultKey string) (err error)

ReplaceAll swaps the registry contents atomically.

func (*HotReloadRegistry) SetDefault

func (r *HotReloadRegistry) SetDefault(key string)

SetDefault marks the given key as default if it exists.

func (*HotReloadRegistry) Snapshot

func (r *HotReloadRegistry) Snapshot() map[string]TargetConn

Snapshot returns a copy of the current targets.

func (*HotReloadRegistry) Unregister

func (r *HotReloadRegistry) Unregister(key string) (err error)

Unregister removes a target. The connection is closed after publishing the snapshot.

func (*HotReloadRegistry) Update

func (r *HotReloadRegistry) Update(ctx context.Context, key string, cfg TargetConfig, mk Connector) (err error)

Update replaces an existing target's connection.

type InExpr

type InExpr struct {
	Label  string
	Values []string
}

func (InExpr) Eval

func (e InExpr) Eval(has func(label string) bool) bool

type JWTLabelRules

type JWTLabelRules struct {
	ClaimMap map[string]string // claim name -> label name
	Fixed    map[string]string
}

JWTLabelRules configures label extraction from JWT claims.

type LabelExpr

type LabelExpr interface {
	Eval(has func(label string) bool) bool
}

type MetaDBProvider

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

MetaDBProvider reads target configuration from a MetaStore.

func NewMetaDBProvider

func NewMetaDBProvider(meta metapkg.MetaStore) *MetaDBProvider

NewMetaDBProvider creates a provider backed by MetaStore.

func (*MetaDBProvider) Fetch

Fetch retrieves target configurations from the meta store.

type NotExpr

type NotExpr struct{ Label string }

func (NotExpr) Eval

func (e NotExpr) Eval(has func(label string) bool) bool

type Query

type Query struct {
	AND []LabelExpr
	OR  [][]LabelExpr
}

func ParseQuery

func ParseQuery(s string) (Query, error)

func QueryFromLabels

func QueryFromLabels(labels []string) Query

QueryFromLabels builds a Query that ANDs all label strings. "k=v" becomes EqExpr and plain "k" becomes HasExpr.

type ReadSource

type ReadSource int

ReadSource specifies the origin for reading custom field definitions.

const (
	// ReadFromTarget reads metadata from the target database (default).
	ReadFromTarget ReadSource = iota
	// ReadFromMeta reads metadata from the MetaDB.
	ReadFromMeta
	// ReadAuto reads from target first then falls back to MetaDB on failure or empty result.
	ReadAuto
)

type ReconcileReport

type ReconcileReport struct {
	MissingInTarget []FieldDef
	MissingInMeta   []FieldDef
	Mismatched      []FieldDiff
}

ReconcileReport summarizes differences between MetaDB and target custom field definitions. MissingInTarget lists fields defined in MetaDB but absent in target. MissingInMeta lists fields present in target but missing in MetaDB. Mismatched captures fields with conflicting attributes.

type ScanResult

type ScanResult = schema.ScanResult

type SelectionHint

type SelectionHint struct {
	Strategy    SelectionStrategy
	PreferLabel string
	HashSource  string
}

SelectionHint provides optional parameters for selection strategies.

type SelectionStrategy

type SelectionStrategy int

SelectionStrategy indicates how to choose a key from multiple matches.

const (
	// SelectFirst picks the first key in sorted order.
	SelectFirst SelectionStrategy = iota
	// SelectPreferLabel prioritizes targets with a given label.
	SelectPreferLabel
	// SelectConsistentHash chooses a target based on a consistent hash of
	// a provided source string.
	SelectConsistentHash
)

type Service

type Service interface {
	// Scan reads schema information from the database.
	Scan(ctx context.Context, cfg DBConfig) ([]registry.FieldMeta, error)
	// Export dumps registry metadata as YAML.
	Export(ctx context.Context, cfg DBConfig) ([]byte, error)
	// Apply updates the registry based on the provided YAML.
	Apply(ctx context.Context, cfg DBConfig, yaml []byte, opts ApplyOptions) (DiffReport, error)
	// MigrateRegistry upgrades or downgrades the registry schema.
	MigrateRegistry(ctx context.Context, cfg DBConfig, target int) error
	// RegistryVersion returns the current registry schema version.
	RegistryVersion(ctx context.Context, cfg DBConfig) (int, error)
	// ListCustomFields returns custom field metadata.
	ListCustomFields(ctx context.Context, dbID int64, table string) ([]registry.FieldMeta, error)
	// CreateCustomField inserts a new field into the registry.
	CreateCustomField(ctx context.Context, fm registry.FieldMeta) error
	// UpdateCustomField modifies an existing field.
	UpdateCustomField(ctx context.Context, fm registry.FieldMeta) error
	// DeleteCustomField removes a field from the registry.
	DeleteCustomField(ctx context.Context, table, column string) error
	// ReconcileCustomFields compares metadata between target and MetaDB and optionally repairs discrepancies.
	ReconcileCustomFields(ctx context.Context, dbID int64, table string, repair bool) (*ReconcileReport, error)
	// StartTargetWatcher periodically fetches target configurations from a provider.
	StartTargetWatcher(ctx context.Context, p TargetProvider, interval time.Duration) (stop func())
}

Service exposes high level operations for custom field registry. Service provides database operations for custom field registry.

Example (MultiTarget)
package main

import (
	"context"
	"database/sql"
	"os"

	"github.com/faciam-dev/gcfm/sdk"
)

func main() {
	meta, _ := sql.Open("postgres", os.Getenv("META_DSN"))
	dbA, _ := sql.Open("mysql", os.Getenv("TENANT_A_DSN"))
	dbB, _ := sql.Open("mysql", os.Getenv("TENANT_B_DSN"))

	svc := sdk.New(sdk.ServiceConfig{
		DB:         dbA,
		Driver:     "mysql",
		MetaDB:     meta,
		MetaDriver: "postgres",
		MetaSchema: "gcfm_meta",
		Targets: []sdk.TargetConfig{
			{Key: "tenant:A", DB: dbA, Driver: "mysql", Schema: ""},
			{Key: "tenant:B", DB: dbB, Driver: "mysql", Schema: ""},
		},
		TargetResolver: sdk.TenantResolverFromPrefix("tenant:"),
	})

	ctx := sdk.WithTenantID(context.Background(), "A")
	_, _ = svc.ListCustomFields(ctx, 1, "posts")
}
Example (Quickstart)
package main

import (
	"context"
	"log"

	"github.com/faciam-dev/gcfm/sdk"
)

func main() {
	ctx := context.Background()
	svc := sdk.New(sdk.ServiceConfig{})
	cfg := sdk.DBConfig{
		DSN:    "mysql://user:pass@tcp(localhost:3306)/app",
		Schema: "app",
	}

	yaml, err := svc.Export(ctx, cfg)
	if err != nil {
		log.Fatal(err)
	}

	if _, err := svc.Apply(ctx, cfg, yaml, sdk.ApplyOptions{DryRun: true}); err != nil {
		log.Fatal(err)
	}

	if err := svc.MigrateRegistry(ctx, cfg, 0); err != nil {
		log.Fatal(err)
	}
}
Example (SeparateMetaDB)
package main

import (
	"database/sql"
	"os"

	"github.com/faciam-dev/gcfm/sdk"
)

func main() {
	meta, _ := sql.Open("postgres", os.Getenv("META_DSN"))
	target, _ := sql.Open("mysql", os.Getenv("TARGET_DSN"))
	_ = sdk.New(sdk.ServiceConfig{
		DB:         target,
		Driver:     "mysql",
		MetaDB:     meta,
		MetaDriver: "postgres",
		MetaSchema: "gcfm_meta",
	})
}

func New

func New(cfg ServiceConfig) Service

New returns a Service initialized with the given configuration. Validator plugins under PluginDir are loaded automatically.

type ServiceConfig

type ServiceConfig struct {
	Logger          *zap.SugaredLogger
	PluginDir       string
	PluginPublicKey string
	PluginEnabled   *bool
	Recorder        *audit.Recorder
	Notifier        notifier.Broker

	// Default connection for monitored databases. Kept for backward
	// compatibility.
	DB     *sql.DB
	Driver string
	Schema string

	// Optional separate connection for metadata storage. When omitted,
	// the above DB/Driver/Schema values are used.
	MetaDB     *sql.DB
	MetaDriver string
	MetaSchema string

	// Target databases for monitoring. If empty, the default DB/Driver/
	// Schema fields represent the only target.
	Targets []TargetConfig

	// TargetResolver selects a target based on the request context. When
	// nil, operations fall back to the default target.
	TargetResolver TargetResolver

	// TargetResolverV2 returns either a direct key or a query. When both
	// V1 and V2 are provided, V2 takes precedence.
	TargetResolverV2 TargetResolverV2

	// DefaultStrategy determines how to choose among multiple candidates
	// returned by a query. The zero value means SelectFirst.
	DefaultStrategy SelectionStrategy

	// DefaultPreferLabel is used when DefaultStrategy is SelectPreferLabel
	// and no hint is supplied.
	DefaultPreferLabel string

	// Connector creates new DB connections. When nil, a default
	// implementation based on sql.Open and PingContext is used.
	Connector Connector

	// Failover controls retry and circuit breaker behavior.
	Failover FailoverPolicy

	// ErrorClassifier distinguishes transient errors for retry decisions.
	ErrorClassifier ErrorClassifier

	// ReadSource selects where to read custom field metadata from.
	ReadSource ReadSource
}

ServiceConfig holds optional configuration for Service.

DB, Driver and Schema specify the default connection to the monitored database. If the Meta* fields are left nil or empty, they inherit these default values.

type Snapshot

type Snapshot struct {
	ID      int64
	Semver  string
	TakenAt time.Time
	Author  string
}

Snapshot describes a stored registry snapshot.

type SnapshotClient

type SnapshotClient interface {
	List(ctx context.Context, tenant string) ([]Snapshot, error)
	Create(ctx context.Context, tenant, bump, msg string) (Snapshot, error)
	Apply(ctx context.Context, tenant, ver string) error
	Diff(ctx context.Context, tenant, from, to string) (string, error)
}

SnapshotClient provides snapshot operations.

type TargetConfig

type TargetConfig struct {
	Key    string // unique identifier like "tenant:foo" or "db:orders"
	Driver string
	Schema string
	Labels []string // optional tags such as "tenant:foo" or "region:tokyo"

	// Physical connection information (hot reload target).
	DSN          string
	MaxOpenConns int
	MaxIdleConns int
	ConnMaxIdle  time.Duration
	ConnMaxLife  time.Duration

	// Backward compatibility: pre-established connection. Connections
	// provided via DB are not subject to hot reload.
	DB *sql.DB
}

TargetConfig defines an individual monitored database.

type TargetConn

type TargetConn struct {
	DB      *sql.DB
	Driver  string
	Schema  string
	Dialect ormdriver.Dialect
	Labels  map[string]struct{}
}

TargetConn represents a monitored database connection.

type TargetDecision

type TargetDecision struct {
	Key   string
	Query *Query
	Hint  *SelectionHint
}

TargetDecision represents a proposal for selecting a target. Either Key or Query (or both) may be specified.

type TargetProvider

type TargetProvider interface {
	Fetch(ctx context.Context) (cfgs map[string]TargetConfig, defaultKey string, version string, err error)
}

TargetProvider fetches target configurations from an external source.

type TargetRegistry

type TargetRegistry interface {
	Register(ctx context.Context, key string, cfg TargetConfig, mk Connector) error
	Unregister(key string) error
	Update(ctx context.Context, key string, cfg TargetConfig, mk Connector) error
	ReplaceAll(ctx context.Context, cfgs map[string]TargetConfig, mk Connector, defaultKey string) error
	Snapshot() map[string]TargetConn
	Get(key string) (TargetConn, bool)
	Default() (TargetConn, bool)
	SetDefault(key string)
	Keys() []string
	FindByLabel(label string) []string
	FindAllByLabels(labels ...string) []string
	FindAnyByLabels(labels ...string) []string
	FindByQuery(q Query) []string
	ForEachByQuery(q Query, fn func(key string, t TargetConn) error) error
}

TargetRegistry manages monitored database connections.

type TargetResolver

type TargetResolver func(ctx context.Context) (key string, ok bool)

TargetResolver chooses a target key from the request context. It returns the key and true on success.

func TenantResolverFromPrefix

func TenantResolverFromPrefix(prefix string) TargetResolver

TenantResolverFromPrefix returns a TargetResolver that looks up tenant ID with given prefix.

type TargetResolverV2

type TargetResolverV2 func(ctx context.Context) (TargetDecision, bool)

TargetResolverV2 returns a TargetDecision derived from the request context. It returns false when no decision could be made.

func AutoLabelResolver

func AutoLabelResolver(opts AutoLabelResolverOptions) TargetResolverV2

AutoLabelResolver builds a TargetResolverV2 that aggregates labels from various sources and turns them into a Query.

type TargetWatcher

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

TargetWatcher periodically applies configuration updates from a provider.

type TenantIDKey

type TenantIDKey struct{}

TenantIDKey is the context key used by WithTenantID.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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