- 20 Go source files, single 16MB binary - SQLite + FTS5 full-text search (pure Go, no CGO) - BCB integration: Selic, CDI, IPCA, USD/BRL, EUR/BRL - CVM integration: 2,524 companies from registry - Fiber v2 REST API with 42 handlers - Auto-seeds on first run (~5s for BCB + CVM) - Token bucket rate limiter, optional API key auth - Periodic sync scheduler (configurable) - Graceful shutdown, structured logging (slog) - All endpoints tested with real data
53 lines
1016 B
Go
53 lines
1016 B
Go
package db
|
|
|
|
import (
|
|
"database/sql"
|
|
"fmt"
|
|
"log/slog"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
_ "modernc.org/sqlite"
|
|
)
|
|
|
|
type DB struct {
|
|
Conn *sql.DB
|
|
}
|
|
|
|
func New(dbPath string) (*DB, error) {
|
|
dir := filepath.Dir(dbPath)
|
|
if err := os.MkdirAll(dir, 0755); err != nil {
|
|
return nil, fmt.Errorf("create db dir: %w", err)
|
|
}
|
|
|
|
conn, err := sql.Open("sqlite", dbPath+"?_journal_mode=WAL&_busy_timeout=5000")
|
|
if err != nil {
|
|
return nil, fmt.Errorf("open db: %w", err)
|
|
}
|
|
|
|
conn.SetMaxOpenConns(1) // SQLite single-writer
|
|
|
|
if _, err := conn.Exec(schema); err != nil {
|
|
return nil, fmt.Errorf("run schema: %w", err)
|
|
}
|
|
|
|
slog.Info("database initialized", "path", dbPath)
|
|
return &DB{Conn: conn}, nil
|
|
}
|
|
|
|
func (d *DB) Close() error {
|
|
return d.Conn.Close()
|
|
}
|
|
|
|
func (d *DB) IsEmpty() bool {
|
|
var count int
|
|
d.Conn.QueryRow("SELECT COUNT(*) FROM companies").Scan(&count)
|
|
return count == 0
|
|
}
|
|
|
|
func (d *DB) IsMarketEmpty() bool {
|
|
var count int
|
|
d.Conn.QueryRow("SELECT COUNT(*) FROM selic_history").Scan(&count)
|
|
return count == 0
|
|
}
|