lazy_db.go RawHistoryFolder
1package sqlite
2
3import (
4 "context"
5 "database/sql"
6 "fmt"
7 "sync"
8
9 "github.com/bnema/dumber/internal/application/port"
10 "github.com/bnema/dumber/internal/logging"
11)
12
13// LazyDB implements port.DatabaseProvider with lazy initialization.
14// The database connection is created on first access, deferring the ~300-400ms
15// WASM compilation and migration overhead until actually needed.
16//
17// Currently unused: the application uses eager initialization via OpenDatabase
18// in RunParallelDBWebKit. This implementation is kept for potential future use
19// in scenarios where deferring database initialization past first paint provides
20// additional latency benefits, or for CLI commands that may not need DB access.
21type LazyDB struct {
22 dbPath string
23 db *sql.DB
24 err error
25 once sync.Once
26 mu sync.RWMutex
27}
28
29// Compile-time interface check.
30var _ port.DatabaseProvider = (*LazyDB)(nil)
31
32// NewLazyDB creates a new lazy database provider.
33// The actual connection is not established until DB() is called.
34func NewLazyDB(dbPath string) *LazyDB {
35 return &LazyDB{dbPath: dbPath}
36}
37
38// DB returns the database connection, initializing it if necessary.
39// This method is thread-safe and will only initialize once.
40func (l *LazyDB) DB(ctx context.Context) (*sql.DB, error) {
41 l.once.Do(func() {
42 log := logging.FromContext(ctx)
43 log.Debug().Str("path", l.dbPath).Msg("lazy database initialization starting")
44
45 db, err := NewConnection(ctx, l.dbPath)
46
47 // Acquire lock before assigning to ensure IsInitialized() sees
48 // a consistent state when reading l.db under RLock.
49 l.mu.Lock()
50 l.db = db
51 l.err = err
52 l.mu.Unlock()
53
54 if err != nil {
55 log.Error().Err(err).Msg("lazy database initialization failed")
56 } else {
57 log.Debug().Msg("lazy database initialized successfully")
58 }
59 })
60
61 l.mu.RLock()
62 db, err := l.db, l.err
63 l.mu.RUnlock()
64
65 if err != nil {
66 return nil, fmt.Errorf("database initialization failed: %w", err)
67 }
68 return db, nil
69}
70
71// Close closes the database connection if it was initialized.
72func (l *LazyDB) Close() error {
73 l.mu.Lock()
74 defer l.mu.Unlock()
75
76 if l.db != nil {
77 return l.db.Close()
78 }
79 return nil
80}
81
82// IsInitialized returns true if the database has been initialized.
83func (l *LazyDB) IsInitialized() bool {
84 l.mu.RLock()
85 defer l.mu.RUnlock()
86 return l.db != nil
87}
88
89// Path returns the database path.
90func (l *LazyDB) Path() string {
91 return l.dbPath
92}