An implementation of the ATProto statusphere example app but in Go
1package database
2
3import (
4 "database/sql"
5 "errors"
6 "fmt"
7 "log/slog"
8 "os"
9
10 _ "github.com/glebarez/go-sqlite"
11)
12
13type DB struct {
14 db *sql.DB
15}
16
17func New(dbPath string) (*DB, error) {
18 if dbPath != ":memory:" {
19 err := createDbFile(dbPath)
20 if err != nil {
21 return nil, fmt.Errorf("create db file: %w", err)
22 }
23 }
24
25 db, err := sql.Open("sqlite", dbPath)
26 if err != nil {
27 return nil, fmt.Errorf("open database: %w", err)
28 }
29
30 err = db.Ping()
31 if err != nil {
32 return nil, fmt.Errorf("ping db: %w", err)
33 }
34
35 err = createOauthRequestsTable(db)
36 if err != nil {
37 return nil, fmt.Errorf("creating oauth requests table: %w", err)
38 }
39
40 err = createOauthSessionsTable(db)
41 if err != nil {
42 return nil, fmt.Errorf("creating oauth sessions table: %w", err)
43 }
44
45 err = createStatusTable(db)
46 if err != nil {
47 return nil, fmt.Errorf("creating status table: %w", err)
48 }
49
50 err = createProfileTable(db)
51 if err != nil {
52 return nil, fmt.Errorf("creating profile table: %w", err)
53 }
54
55 return &DB{db: db}, nil
56}
57
58func (d *DB) Close() {
59 err := d.db.Close()
60 if err != nil {
61 slog.Error("failed to close db", "error", err)
62 }
63}
64
65func createDbFile(dbFilename string) error {
66 if _, err := os.Stat(dbFilename); !errors.Is(err, os.ErrNotExist) {
67 return nil
68 }
69
70 f, err := os.Create(dbFilename)
71 if err != nil {
72 return fmt.Errorf("create db file : %w", err)
73 }
74 f.Close()
75 return nil
76}