OpenSQLiteStore opens (creating if needed) the Hub database at path with WAL journaling and runs migrations. A nil logger is replaced with a no-op.
(ctx context.Context, path string, logger *zap.Logger)
| 79 | // OpenSQLiteStore opens (creating if needed) the Hub database at path with WAL |
| 80 | // journaling and runs migrations. A nil logger is replaced with a no-op. |
| 81 | func OpenSQLiteStore(ctx context.Context, path string, logger *zap.Logger) (*SQLiteStore, error) { |
| 82 | if logger == nil { |
| 83 | logger = zap.NewNop() |
| 84 | } |
| 85 | // WAL gives concurrent readers alongside one writer; busy_timeout absorbs |
| 86 | // brief contention without surfacing errors. |
| 87 | dsn := fmt.Sprintf("file:%s?_pragma=journal_mode(WAL)&_pragma=busy_timeout(5000)&_pragma=synchronous(NORMAL)", path) |
| 88 | db, err := sql.Open("sqlite", dsn) |
| 89 | if err != nil { |
| 90 | return nil, fmt.Errorf("hub: open sqlite at %s: %w", path, err) |
| 91 | } |
| 92 | if err := db.PingContext(ctx); err != nil { |
| 93 | _ = db.Close() |
| 94 | return nil, fmt.Errorf("hub: ping sqlite at %s: %w", path, err) |
| 95 | } |
| 96 | if _, err := db.ExecContext(ctx, schema); err != nil { |
| 97 | _ = db.Close() |
| 98 | return nil, fmt.Errorf("hub: migrate schema: %w", err) |
| 99 | } |
| 100 | return &SQLiteStore{db: db, logger: logger}, nil |
| 101 | } |
| 102 | |
| 103 | // Close releases the underlying database. |
| 104 | func (s *SQLiteStore) Close() error { return s.db.Close() } |