database

package
v1.16.8 Latest Latest
Warning

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

Go to latest
Published: Mar 24, 2026 License: MIT Imports: 7 Imported by: 0

README

Database Hub

O Database Hub fornece uma camada de abstracao para multiplas conexoes de banco de dados no DevClaw.

Visao Geral

O Hub permite:

  • Usar SQLite como backend padrao (zero configuracao)
  • Adicionar PostgreSQL/Supabase para producao
  • Extensibilidade para MySQL, CockroachDB, etc.
  • Busca vetorial nativa com pgvector
  • Gerenciamento via tools do agente
  • Rate limiting para prevenir abuso
  • Metricas do pool de conexoes para monitoramento

Arquitetura

┌─────────────────────────────────────────────────────────────┐
│                    DATABASE HUB                             │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐         │
│  │   Backend   │  │   Vector    │  │  Migration  │         │
│  │   Factory   │  │   Store     │  │   Manager   │         │
│  └─────────────┘  └─────────────┘  └─────────────┘         │
├─────────────────────────────────────────────────────────────┤
│                    BACKENDS                                 │
│  ┌────────┐  ┌────────────┐  ┌───────┐                     │
│  │ SQLite │  │ PostgreSQL │  │ MySQL │                     │
│  │(padrao)│  │ + pgvector │  │(futuro)│                    │
│  └────────┘  └────────────┘  └───────┘                     │
└─────────────────────────────────────────────────────────────┘

Estrutura de Arquivos

pkg/devclaw/database/
├── interfaces.go        # Interfaces core (Backend, VectorStore, Migrator, HealthChecker)
├── config.go            # Estruturas de configuracao
├── hub.go               # Hub central, gerencia conexoes
├── factory.go           # Factory pattern para backends
├── backends/
│   ├── types.go         # Tipos compartilhados (VectorConfig, SearchResult)
│   ├── sqlite.go        # Backend SQLite + InMemoryVectorStore
│   └── postgresql.go    # Backend PostgreSQL + PgVectorStore
└── README.md            # Esta documentacao

Interfaces

Backend
type Backend struct {
    Name     string
    Type     BackendType
    DB       *sql.DB
    Config   Config
    Migrator Migrator
    Vector   VectorStore
    Health   HealthChecker
}
VectorStore
type VectorStore interface {
    Insert(ctx context.Context, collection string, id string, vector []float32, metadata map[string]any) error
    Search(ctx context.Context, collection string, vector []float32, k int, filter map[string]any) ([]SearchResult, error)
    Delete(ctx context.Context, collection string, id string) error
    SupportsVector() bool
}
Migrator
type Migrator interface {
    CurrentVersion(ctx context.Context) (int, error)
    Migrate(ctx context.Context, target int) error
    NeedsMigration(ctx context.Context) (bool, error)
}
HealthChecker com Metricas do Pool
type HealthStatus struct {
    Healthy bool          `json:"healthy"`
    Latency time.Duration `json:"latency"`
    Version string        `json:"version"`
    Error   string        `json:"error,omitempty"`

    // Metricas do pool de conexoes
    OpenConnections   int           `json:"open_connections"`
    InUse             int           `json:"in_use"`
    Idle              int           `json:"idle"`
    WaitCount         int64         `json:"wait_count"`
    WaitDuration      time.Duration `json:"wait_duration"`
    MaxOpenConns      int           `json:"max_open_conns"`
    MaxIdleClosed     int64         `json:"max_idle_closed"`
    MaxLifetimeClosed int64         `json:"max_lifetime_closed"`
}

Configuracao

SQLite (Padrao)
database:
  hub:
    backend: "sqlite"
    sqlite:
      path: "./data/devclaw.db"
      journal_mode: "WAL"
      busy_timeout: 5000
      foreign_keys: true
PostgreSQL
database:
  hub:
    backend: "postgresql"
    postgresql:
      host: "localhost"
      port: 5432
      database: "devclaw"
      user: "devclaw"
      password: "${POSTGRES_PASSWORD}"
      ssl_mode: "require"

      # Connection pooling
      max_open_conns: 25
      max_idle_conns: 10
      conn_max_lifetime: "30m"

      # Vector search (pgvector)
      vector:
        enabled: true
        dimensions: 1536
        index_type: "hnsw"  # hnsw | ivfflat
Supabase
database:
  hub:
    backend: "postgresql"
    postgresql:
      supabase_url: "${SUPABASE_URL}"
      password: "${SUPABASE_DB_PASSWORD}"
      vector:
        enabled: true

Uso Programatico

Inicializando o Hub
import "github.com/jholhewres/devclaw/pkg/devclaw/database"

hub, err := database.NewHub(config.Hub, logger)
if err != nil {
    log.Fatal(err)
}
defer hub.Close()
Obtendo Backend
// Backend primario
backend := hub.Primary()

// Backend especifico
backend, err := hub.GetBackend("memory")
Executando Queries
ctx := context.Background()

// Query
rows, err := hub.Query(ctx, "", "SELECT * FROM users WHERE active = ?", true)
defer rows.Close()

// Exec
result, err := hub.Exec(ctx, "", "INSERT INTO users (name) VALUES (?)", "John")
Busca Vetorial
// Inserir embedding
vector := []float32{0.1, 0.2, 0.3, ...} // 1536 dimensoes
err := backend.Vector.Insert(ctx, "memory", "doc-123", vector, map[string]any{
    "source": "chat",
    "user_id": "user-456",
})

// Buscar similares
results, err := backend.Vector.Search(ctx, "memory", queryVector, 10, nil)
for _, r := range results {
    fmt.Printf("ID: %s, Score: %.2f\n", r.ID, r.Score)
}
Health Check
// Status de todos backends
status := hub.Status(ctx)
for name, info := range status {
    fmt.Printf("%s: %v\n", name, info["healthy"])
}

// Ping individual
if err := backend.Health.Ping(ctx); err != nil {
    log.Printf("backend unhealthy: %v", err)
}

Tools do Agente

O Database Hub fornece tools nativas para o agente:

Tool Descricao Rate Limit
db_hub_status Status de saude de todos backends com metricas do pool Nao
db_hub_query Executar SELECT queries Nao
db_hub_execute Executar INSERT/UPDATE/DELETE Nao
db_hub_schema Ver schema/tabelas do banco (validado contra SQL injection) Nao
db_hub_migrate Executar migrations Nao
db_hub_backup Criar backup do banco (SQLite apenas) Nao
db_hub_backends Listar backends disponiveis Nao
db_hub_raw Executar SQL raw 10 ops/seg
Seguranca
  • db_hub_schema: Valida nomes de tabelas (apenas alphanumericos e underscore)
  • db_hub_backup: Valida caminhos contra path traversal
  • db_hub_query: Apenas SELECT, PRAGMA, SHOW, EXPLAIN permitidos
  • db_hub_raw: Rate limiting de 10 operacoes/segundo por sessao
Exemplos de Uso
Usuario: Qual o status do banco de dados?
Agente: [usa db_hub_status] O banco SQLite esta saudavel, versao do schema: 5.

Usuario: Mostre todas as tabelas
Agente: [usa db_hub_schema] Tabelas: jobs, session_entries, audit_log...

Usuario: Quantas sessoes temos?
Agente: [usa db_hub_query] SELECT COUNT(*) FROM session_entries → 127 sessoes.

Migracao SQLite → PostgreSQL

  1. Configure o PostgreSQL no YAML
  2. Execute o backup: [usa db_hub_backup]
  3. Altere o backend no YAML
  4. Reinicie o DevClaw
  5. O Hub criara as tabelas automaticamente
  6. Restaure os dados (futuro: tool de migracao automatica)

Comparativo

Aspecto SQLite PostgreSQL + pgvector
Busca vetorial In-memory O(n) Index HNSW O(log n)
Concorrencia WAL, 1 writer MVCC, multi writers
Full-text search FTS5 basico tsvector avancado
Escalabilidade ~10k chunks Milhoes de chunks
Backup Copiar arquivo PITR, replication
Setup Zero config Requer servidor

Testes

Testes Unitarios (SQLite)
# Rodar testes
go test ./pkg/devclaw/database/... -v -cover

# Coverage report
go test ./pkg/devclaw/database/... -coverprofile=coverage.out
go tool cover -html=coverage.out
Testes de Integracao (PostgreSQL)

Os testes de integracao requerem um PostgreSQL com pgvector:

# 1. Iniciar container PostgreSQL com pgvector
docker run -d --name devclaw-test-pg \
  -e POSTGRES_USER=test \
  -e POSTGRES_PASSWORD=test \
  -e POSTGRES_DB=devclaw_test \
  -p 5432:5432 \
  pgvector/pgvector:pg16

# 2. Executar testes de integracao
go test -tags=integration ./pkg/devclaw/database/backends/... -v

# 3. Parar container
docker stop devclaw-test-pg && docker rm devclaw-test-pg

Variaveis de ambiente para configuracao:

  • PGHOST - Host PostgreSQL (default: localhost)
  • PGPORT - Porta PostgreSQL (default: 5432)
  • PGUSER - Usuario (default: test)
  • PGPASSWORD - Senha (default: test)
  • PGDATABASE - Banco de dados (default: devclaw_test)
Cobertura Atual
Pacote Cobertura
database/ ~62%
database/backends/ ~32%

Extensibilidade

Para adicionar um novo backend (ex: CockroachDB):

  1. Implemente as interfaces em backends/cockroachdb.go
  2. Adicione a config em config.go
  3. Registre o factory em factory.go
  4. Adicione testes em backends/cockroachdb_test.go

Documentation

Overview

Package database provides a unified database abstraction layer (Database Hub) that supports multiple backends (SQLite, PostgreSQL, MySQL) with a common interface. SQLite is the default backend, requiring zero configuration.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Backend

type Backend struct {
	// Name is the identifier for this backend (e.g., "primary", "analytics")
	Name string

	// Type indicates the database type
	Type BackendType

	// DB is the underlying database connection
	DB *sql.DB

	// Config holds the backend configuration
	Config Config

	// Migrator handles schema migrations
	Migrator Migrator

	// Vector provides vector search capabilities (nil if not supported)
	Vector VectorStore

	// Health monitors database health
	Health HealthChecker
}

Backend represents a database backend connection with all its capabilities.

type BackendFactory

type BackendFactory interface {
	// Create creates a new backend with the given configuration.
	Create(config Config) (*Backend, error)

	// Supports returns true if this factory can create the given backend type.
	Supports(backendType BackendType) bool
}

BackendFactory creates database backends based on configuration.

type BackendType

type BackendType string

BackendType identifies the type of database backend.

const (
	BackendSQLite     BackendType = "sqlite"
	BackendPostgreSQL BackendType = "postgresql"
	BackendMySQL      BackendType = "mysql"
)

type Config

type Config struct {
	// Type identifies the backend type
	Type BackendType `yaml:"type"`

	// Path is for SQLite databases
	Path string `yaml:"path"`

	// Host is for network databases (PostgreSQL, MySQL)
	Host string `yaml:"host"`

	// Port is for network databases
	Port int `yaml:"port"`

	// Database name
	Database string `yaml:"database"`

	// User for authentication
	User string `yaml:"user"`

	// Password for authentication (supports ${ENV_VAR} expansion)
	Password string `yaml:"password"`

	// SSLMode for PostgreSQL: disable, require, verify-full
	SSLMode string `yaml:"ssl_mode"`

	// Connection pooling
	MaxOpenConns    int           `yaml:"max_open_conns"`
	MaxIdleConns    int           `yaml:"max_idle_conns"`
	ConnMaxLifetime time.Duration `yaml:"conn_max_lifetime"`

	// Supabase-specific
	SupabaseURL     string `yaml:"supabase_url"`
	SupabaseAnonKey string `yaml:"supabase_anon_key"`

	// Vector search configuration
	Vector VectorConfig `yaml:"vector"`

	// Journal mode for SQLite (default: WAL)
	JournalMode string `yaml:"journal_mode"`

	// Busy timeout for SQLite in milliseconds (default: 5000)
	BusyTimeout int `yaml:"busy_timeout"`
}

Config represents a generic database connection configuration.

type HealthChecker

type HealthChecker interface {
	// Ping checks basic database connectivity.
	Ping(ctx context.Context) error

	// Status returns detailed health status.
	Status(ctx context.Context) HealthStatus
}

HealthChecker interface for monitoring database health.

type HealthStatus

type HealthStatus struct {
	Healthy bool          `json:"healthy"`
	Latency time.Duration `json:"latency"`
	Version string        `json:"version"`
	Error   string        `json:"error,omitempty"`

	// Connection pool metrics
	OpenConnections   int           `json:"open_connections"`
	InUse             int           `json:"in_use"`
	Idle              int           `json:"idle"`
	WaitCount         int64         `json:"wait_count"`
	WaitDuration      time.Duration `json:"wait_duration"`
	MaxOpenConns      int           `json:"max_open_conns"`
	MaxIdleClosed     int64         `json:"max_idle_closed"`
	MaxLifetimeClosed int64         `json:"max_lifetime_closed"`
}

HealthStatus represents the health state of a database backend.

type Hub

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

Hub is the central database management system that orchestrates multiple database backends and provides a unified API.

func NewHub

func NewHub(config HubConfig, logger *slog.Logger) (*Hub, error)

NewHub creates a new Database Hub with the given configuration.

func (*Hub) AddBackend

func (h *Hub) AddBackend(ctx context.Context, name string, config Config) error

AddBackend creates and registers a new database backend.

func (*Hub) Close

func (h *Hub) Close() error

Close closes all database connections.

func (*Hub) DB

func (h *Hub) DB() *sql.DB

DB returns the sql.DB of the primary backend for direct access.

func (*Hub) Exec

func (h *Hub) Exec(ctx context.Context, backendName string, query string, args ...any) (sql.Result, error)

Exec executes a statement on the specified backend.

func (*Hub) GetBackend

func (h *Hub) GetBackend(name string) (*Backend, error)

GetBackend returns a backend by name, or the primary backend if name is empty.

func (*Hub) ListBackends

func (h *Hub) ListBackends() []string

ListBackends returns the names of all registered backends.

func (*Hub) Migrate

func (h *Hub) Migrate(ctx context.Context, backendName string, target int) error

Migrate runs migrations on the specified backend (or primary if empty).

func (*Hub) Primary

func (h *Hub) Primary() *Backend

Primary returns the primary database backend.

func (*Hub) Query

func (h *Hub) Query(ctx context.Context, backendName string, query string, args ...any) (*sql.Rows, error)

Query executes a query on the specified backend.

func (*Hub) RegisterFactory

func (h *Hub) RegisterFactory(backendType BackendType, factory BackendFactory)

RegisterFactory registers a backend factory for a specific backend type.

func (*Hub) RemoveBackend

func (h *Hub) RemoveBackend(name string) error

RemoveBackend removes a backend by name (cannot remove primary).

func (*Hub) Status

func (h *Hub) Status(ctx context.Context) map[string]HealthStatus

Status returns the health status of all backends.

func (*Hub) VectorSearch

func (h *Hub) VectorSearch(ctx context.Context, backendName string, collection string, queryVector []float32, k int, filter map[string]any) ([]SearchResult, error)

VectorSearch performs a vector similarity search on the specified backend. The queryVector must be pre-computed (use an embedding provider to convert text to vector).

type HubConfig

type HubConfig struct {
	// Backend is the primary database backend type (default: "sqlite")
	Backend BackendType `yaml:"backend"`

	// SQLite configuration
	SQLite SQLiteConfig `yaml:"sqlite"`

	// PostgreSQL configuration (includes Supabase)
	PostgreSQL PostgreSQLConfig `yaml:"postgresql"`

	// MySQL configuration
	MySQL MySQLConfig `yaml:"mysql"`

	// Additional named connections for multi-database setups
	Connections map[string]Config `yaml:"connections"`

	// Memory database configuration (can differ from primary)
	Memory MemoryDBConfig `yaml:"memory"`
}

HubConfig represents the complete database hub configuration.

func DefaultHubConfig

func DefaultHubConfig() HubConfig

DefaultHubConfig returns the default hub configuration (SQLite).

func (HubConfig) Effective

func (c HubConfig) Effective() HubConfig

Effective returns a copy with default values filled in for zero fields.

type JobStorage

type JobStorage interface {
	Save(job any) error
	Delete(id string) error
	LoadAll() ([]any, error)
}

JobStorage interface for scheduler job persistence. This mirrors the existing JobStorage interface for compatibility.

type MemoryDBConfig

type MemoryDBConfig struct {
	// Backend type (default: same as primary)
	Backend BackendType `yaml:"backend"`

	// Path for SQLite memory database
	Path string `yaml:"path"`

	// UsePrimary indicates to use the primary database for memory storage
	UsePrimary bool `yaml:"use_primary"`
}

MemoryDBConfig configures the memory database (can be separate from primary).

type Migrator

type Migrator interface {
	// CurrentVersion returns the current schema version.
	CurrentVersion(ctx context.Context) (int, error)

	// Migrate applies migrations up to the target version.
	// If target is 0, migrates to the latest version.
	Migrate(ctx context.Context, target int) error

	// NeedsMigration returns true if the schema is outdated.
	NeedsMigration(ctx context.Context) (bool, error)
}

Migrator interface for database schema migrations.

type MySQLConfig

type MySQLConfig struct {
	// Host (default: "localhost")
	Host string `yaml:"host"`

	// Port (default: 3306)
	Port int `yaml:"port"`

	// Database name
	Database string `yaml:"database"`

	// User for authentication
	User string `yaml:"user"`

	// Password for authentication (supports ${ENV_VAR} expansion)
	Password string `yaml:"password"`

	// Connection pooling
	MaxOpenConns    int           `yaml:"max_open_conns"`
	MaxIdleConns    int           `yaml:"max_idle_conns"`
	ConnMaxLifetime time.Duration `yaml:"conn_max_lifetime"`
}

MySQLConfig holds MySQL configuration.

func (MySQLConfig) ToConfig

func (m MySQLConfig) ToConfig() Config

ToConfig converts MySQLConfig to generic Config.

type MySQLFactory

type MySQLFactory struct{}

MySQLFactory creates MySQL backends. This is a placeholder that will be implemented in the mysql.go file.

func (*MySQLFactory) Create

func (f *MySQLFactory) Create(config Config) (*Backend, error)

Create creates a new MySQL backend with the given configuration.

func (*MySQLFactory) Supports

func (f *MySQLFactory) Supports(backendType BackendType) bool

Supports returns true for MySQL backend type.

type PostgreSQLConfig

type PostgreSQLConfig struct {
	// Host (default: "localhost")
	Host string `yaml:"host"`

	// Port (default: 5432)
	Port int `yaml:"port"`

	// Database name
	Database string `yaml:"database"`

	// User for authentication
	User string `yaml:"user"`

	// Password for authentication (supports ${ENV_VAR} expansion)
	Password string `yaml:"password"`

	// SSL mode: disable, require, verify-ca, verify-full
	SSLMode string `yaml:"ssl_mode"`

	// Connection pooling
	MaxOpenConns    int           `yaml:"max_open_conns"`
	MaxIdleConns    int           `yaml:"max_idle_conns"`
	ConnMaxLifetime time.Duration `yaml:"conn_max_lifetime"`
	ConnMaxIdleTime time.Duration `yaml:"conn_max_idle_time"`

	// Supabase-specific (alternative to standard config)
	SupabaseURL     string `yaml:"supabase_url"`
	SupabaseAnonKey string `yaml:"supabase_anon_key"`

	// Vector search (pgvector)
	Vector VectorConfig `yaml:"vector"`
}

PostgreSQLConfig holds PostgreSQL and Supabase configuration.

func DefaultPostgreSQLConfig

func DefaultPostgreSQLConfig() PostgreSQLConfig

DefaultPostgreSQLConfig returns default PostgreSQL configuration.

func (PostgreSQLConfig) ToConfig

func (p PostgreSQLConfig) ToConfig() Config

ToConfig converts PostgreSQLConfig to generic Config.

type PostgreSQLFactory

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

PostgreSQLFactory creates PostgreSQL backends (including Supabase).

func NewPostgreSQLFactory

func NewPostgreSQLFactory(logger *slog.Logger) *PostgreSQLFactory

NewPostgreSQLFactory creates a new PostgreSQL factory.

func (*PostgreSQLFactory) Create

func (f *PostgreSQLFactory) Create(config Config) (*Backend, error)

Create creates a new PostgreSQL backend with the given configuration.

func (*PostgreSQLFactory) Supports

func (f *PostgreSQLFactory) Supports(backendType BackendType) bool

Supports returns true for PostgreSQL backend type.

type SQLiteConfig

type SQLiteConfig struct {
	// Path to the database file (default: "./data/devclaw.db")
	Path string `yaml:"path"`

	// Journal mode (default: WAL)
	JournalMode string `yaml:"journal_mode"`

	// Busy timeout in milliseconds (default: 5000)
	BusyTimeout int `yaml:"busy_timeout"`

	// Enable foreign keys (default: true)
	ForeignKeys bool `yaml:"foreign_keys"`
}

SQLiteConfig holds SQLite-specific configuration.

func DefaultSQLiteConfig

func DefaultSQLiteConfig() SQLiteConfig

DefaultSQLiteConfig returns default SQLite configuration.

func (SQLiteConfig) ToConfig

func (s SQLiteConfig) ToConfig() Config

ToConfig converts SQLiteConfig to generic Config.

type SQLiteFactory

type SQLiteFactory struct{}

SQLiteFactory creates SQLite backends.

func (*SQLiteFactory) Create

func (f *SQLiteFactory) Create(config Config) (*Backend, error)

Create creates a new SQLite backend with the given configuration.

func (*SQLiteFactory) Supports

func (f *SQLiteFactory) Supports(backendType BackendType) bool

Supports returns true for SQLite backend type.

type SearchResult

type SearchResult struct {
	ID       string         `json:"id"`
	Score    float64        `json:"score"`
	Metadata map[string]any `json:"metadata,omitempty"`
	Text     string         `json:"text,omitempty"`
}

SearchResult represents a single vector search result with score and metadata.

type SessionPersister

type SessionPersister interface {
	SaveEntry(sessionID string, entry any) error
	LoadSession(sessionID string) (any, any, error)
	SaveFacts(sessionID string, facts []string) error
	SaveMeta(sessionID, channel, chatID string, config any, activeSkills []string) error
	DeleteSession(sessionID string) error
	Rotate(sessionID string, maxLines int) error
	LoadAll() (map[string]any, error)
	Close() error
}

SessionPersister interface for session storage operations. This mirrors the existing SessionPersister interface for compatibility.

type VectorConfig

type VectorConfig struct {
	// Enabled activates vector search support
	Enabled bool `yaml:"enabled"`

	// Dimensions of the embedding vectors (default: 1536 for OpenAI)
	Dimensions int `yaml:"dimensions"`

	// Provider: "native" (pgvector), "memory" (in-memory for SQLite), "external"
	Provider string `yaml:"provider"`

	// Index type for pgvector: "hnsw" or "ivfflat"
	IndexType string `yaml:"index_type"`

	// Lists parameter for IVFFlat index (default: 100)
	IVFLists int `yaml:"ivf_lists"`

	// M parameter for HNSW index (default: 16)
	HNSWM int `yaml:"hnsw_m"`
}

VectorConfig configures vector search capabilities.

func DefaultVectorConfig

func DefaultVectorConfig() VectorConfig

DefaultVectorConfig returns default vector configuration.

type VectorStore

type VectorStore interface {
	// Insert adds a vector with associated metadata to the collection.
	Insert(ctx context.Context, collection string, id string, vector []float32, metadata map[string]any) error

	// Search performs a similarity search and returns the top k results.
	Search(ctx context.Context, collection string, vector []float32, k int, filter map[string]any) ([]SearchResult, error)

	// Delete removes a vector from the collection.
	Delete(ctx context.Context, collection string, id string) error

	// SupportsVector returns true if the backend supports native vector operations.
	SupportsVector() bool
}

VectorStore interface for vector similarity search operations. Implementations: pgvector (PostgreSQL), InMemoryVectorStore (SQLite fallback).

Directories

Path Synopsis
Package backends provides database backend implementations.
Package backends provides database backend implementations.

Jump to

Keyboard shortcuts

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