Files
2025-08-06 15:06:18 -07:00

304 lines
9.3 KiB
Markdown

# Package database
## Overview
Package database provides the data access layer for the query orchestration platform. It manages PostgreSQL database connections, schema migrations, and generated query functions using SQLC. The package implements a repository pattern with type-safe database operations and comprehensive transaction support.
## Architecture
### Service Layer Architecture
The database access follows a clean, layered architecture pattern:
1. **Repository Layer** (`repository/`)
- SQLC-generated code providing type-safe database queries
- `Queries` struct contains all database operations
- Generated from SQL files in `queries/` directory
- Accessed throughout codebase via `ConfigProvider.GetDBQueries()`
2. **Service Layer** (`internal/*/service.go`)
- Each domain has its own service containing business logic
- Services use the repository layer for all database access
- Examples: `client/service.go`, `document/service.go`, `query/service.go`
3. **Configuration Layer** (`internal/serviceconfig/database/`)
- Manages database connections and connection pooling
- Provides transaction support via `ExecuteDBTransaction()`
- Handles migration execution on startup
4. **Database Access Pattern**
```
API Controllers → Service Layer (business logic)
ConfigProvider.GetDBQueries()
Repository Layer (SQLC-generated)
PostgreSQL Database
```
### Architecture Principles
- **No Direct SQL in Business Logic**: All SQL queries are defined in `.sql` files
- **Type Safety**: SQLC generates Go types from SQL schemas
- **Clean Separation**: HTTP handlers → Services → Repository → Database
- **Transaction Support**: Coordinated through ConfigProvider interface
- **Code Generation**: Repository code is generated, not hand-written
- **Single Source of Truth**: Database schema defined in migrations
### Core Components
#### Database Schema
The database schema supports document processing and query orchestration with the following key entities:
- **Clients**: Customer configurations with associated document sets
- **Documents**: Uploaded files with processing state tracking
- **Queries**: Data extraction and processing definitions with versioning
- **Collectors**: Query collection specifications per client
- **Results**: Processed query outputs linked to documents
- **Text Extractions**: OCR results from document processing
- **Batch Uploads**: Batch document upload tracking with progress monitoring
#### Migration System
- Uses `golang-migrate` for schema version management
- Migrations stored in `migrations/` directory with up/down SQL files
- Automatic migration execution on startup
- Support for extensions, tables, views, and functions
#### Query Generation
- SQLC generates type-safe Go code from SQL queries
- Query definitions in `queries/` directory
- Generated code in `repository/` subdirectory
- Automatic struct mapping and null handling
### Key Files
- **migrations.go**: Database migration management and execution
- **queries/*.sql**: SQLC query definitions for each entity
- **repository/db.go**: Database connection interface and transaction support
- **repository/*.sql.go**: Generated query functions from SQLC
- **repository/models.go**: Generated data models and type definitions
- **database.md**: Schema documentation with Mermaid diagram
- **diagram.mmd**: Visual database schema representation
## Database Schema Design
### Tables
#### Core Tables
- **clients**: Customer configurations and metadata
- **documents**: Document upload tracking and processing status
- **documentCleans**: Cleaned document content storage
- **documentTextExtractions**: OCR text extraction results
- **queries**: Query definitions with JSON configurations
- **queryVersions**: Query version history and dependency tracking
- **results**: Query execution results per document
- **collectors**: Client-specific query collections
- **collectorVersions**: Collector version history
- **batch_uploads**: Batch document upload tracking with progress and failure metrics
### Views
#### Query Views
- **fullActiveQueries**: Complete active query information with dependencies
- **queryActiveVersions**: Current active version for each query
- **queryActiveDependencies**: Recursive dependency resolution
- **activeQueryNameTypeMap**: Mapping of query names to types
#### Collector Views
- **fullActiveCollectorVersions**: Active collector configurations
- **collectorActiveVersions**: Current version for each collector
- **collectorQueryDependencyTree**: Full dependency graph for collectors
#### Document Views
- **currentTextEntries**: Latest text extraction for each document
- **latestDocumentTextResults**: Most recent results per document
### Custom Functions
- **uuid_generate_v7()**: Generates time-ordered UUIDs for better indexing
- **json_matches_schema()**: Validates JSON against schema definitions
## Usage
### Database Connection
```go
// Create database configuration
dbConfig := &serviceconfig.DBConfig{
DBHost: "localhost",
DBPort: 5432,
DBName: "querydb",
DBUser: "dbuser",
DBPassword: "dbpass",
}
// Initialize connection pool
err := dbConfig.SetDBPoolConfig()
if err != nil {
return err
}
// Get repository queries instance
queries := dbConfig.GetDBQueries()
```
### Transaction Management
```go
// Execute operations in a transaction
err := dbConfig.ExecuteDBTransaction(ctx, func(ctx context.Context, qtx *repository.Queries) error {
// All operations here run in a single transaction
client, err := qtx.CreateClient(ctx, repository.CreateClientParams{
ID: clientID,
Name: clientName,
})
if err != nil {
return err // Transaction will rollback
}
// Additional operations...
return nil // Transaction will commit
})
```
### Query Examples
```go
// Get a document by ID
document, err := queries.GetDocument(ctx, documentID)
// List documents for a client
documents, err := queries.ListDocumentsByClient(ctx, repository.ListDocumentsByClientParams{
ClientID: clientID,
Limit: 50,
Offset: 0,
})
// Create a query result
result, err := queries.CreateResult(ctx, repository.CreateResultParams{
TextEntryID: textEntryID,
QueryID: queryID,
Result: resultJSON,
})
```
## Migration Management
### Creating Migrations
```bash
# Create a new migration
migrate create -ext sql -dir internal/database/migrations -seq add_new_feature
# This creates:
# - 000000XX_add_new_feature.up.sql
# - 000000XX_add_new_feature.down.sql
```
### Migration Conventions
- Use sequential numbering with zero padding
- Provide complete rollback logic in down migrations
- Test both up and down migrations
- Include data migrations where necessary
### Migration Execution
Migrations run automatically on application startup via:
```go
migrator := database.NewMigrator(dbURL)
err := migrator.Up()
```
## SQLC Integration
### Configuration
SQLC is configured via `sqlc.yml` in the project root with:
- PostgreSQL engine with pgx/v5 driver
- Queries sourced from `internal/database/queries/`
- Schema from `internal/database/migrations/`
- Generated code output to `internal/database/repository/`
- Custom rules enforcing query performance and safety
- UUID type mapping to `github.com/google/uuid`
### Query Definition Format
```sql
-- name: GetDocument :one
SELECT * FROM documents
WHERE id = $1;
-- name: ListDocumentsByClient :many
SELECT * FROM documents
WHERE clientId = $1
ORDER BY created DESC
LIMIT $2 OFFSET $3;
-- name: UpdateDocumentStatus :exec
UPDATE documents
SET status = $2, updated = CURRENT_TIMESTAMP
WHERE id = $1;
```
### Generated Code Features
SQLC generates:
- Type-safe query functions with parameter structs
- Struct definitions matching table schemas
- Null handling with pointers for nullable fields
- UUID type support via google/uuid package
- SQL comments included in generated code
- Enum validation methods
- Empty slice initialization for array returns
## Testing
### Test Database Setup
Tests use testcontainers to spin up PostgreSQL instances:
```go
container := test.NewDatabaseContainer(t)
dbConfig := container.DBConfig(t)
```
### Repository Testing
- Each repository file has corresponding test coverage
- Tests validate CRUD operations
- Transaction rollback testing
- Concurrent access validation
## Performance Considerations
### Connection Pooling
- Uses pgx connection pooling
- Configurable pool size and timeouts
- Health check pings with timeout
- Automatic connection recovery
### Query Optimization
- Views provide pre-computed joins
- Recursive CTEs for dependency resolution
- Proper use of LIMIT/OFFSET for pagination
- JSON indexing for configuration queries
## Data Types
### Custom Types
- **UUID**: Used for all primary keys
- **JSONB**: Query configurations and results
- **Timestamptz**: All timestamp fields timezone-aware
- **Text**: Unbounded string storage
- **Custom Enums**: Via CHECK constraints
### Null Handling
- Explicit NULL/NOT NULL constraints
- Go sql.Null* types for nullable fields
- Default values where appropriate
## Security
### Access Control
- Database credentials via environment variables
- Connection string sanitization
- Parameterized queries prevent SQL injection
- No dynamic SQL construction
### Data Protection
- Sensitive data fields identified
- Audit fields (created, updated) on all tables
- Logical deletion support where needed