Skip to content

Commit 37fe4ab

Browse files
🏗️ [db.go] Replaced bbolt db with sqlite3 db
🎨 [db.go] Moved createConfigDir function to seperate file (internal/helpers.go)
1 parent adf3d7e commit 37fe4ab

File tree

7 files changed

+127
-93
lines changed

7 files changed

+127
-93
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ require (
66
github.com/charmbracelet/huh v0.6.0
77
github.com/charmbracelet/lipgloss v1.0.0
88
github.com/charmbracelet/x/term v0.2.0
9+
github.com/mattn/go-sqlite3 v1.14.24
910
github.com/spf13/cobra v1.8.1
10-
go.etcd.io/bbolt v1.4.0
1111
)
1212

1313
require (

go.sum

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@ github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0/go.mod
2525
github.com/charmbracelet/x/term v0.2.0 h1:cNB9Ot9q8I711MyZ7myUR5HFWL/lc3OpU8jZ4hwm0x0=
2626
github.com/charmbracelet/x/term v0.2.0/go.mod h1:GVxgxAbjUrmpvIINHIQnJJKpMlHiZ4cktEQCN6GWyF0=
2727
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
28-
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
29-
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3028
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
3129
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
3230
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
@@ -41,6 +39,8 @@ github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2J
4139
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
4240
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
4341
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
42+
github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM=
43+
github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
4444
github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4=
4545
github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE=
4646
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
@@ -49,8 +49,6 @@ github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELU
4949
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
5050
github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a h1:2MaM6YC3mGu54x+RKAA6JiFFHlHDY1UbkxqppT7wYOg=
5151
github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a/go.mod h1:hxSnBBYLK21Vtq/PHd0S2FYCxBXzBua8ov5s1RobyRQ=
52-
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
53-
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
5452
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
5553
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
5654
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
@@ -60,10 +58,6 @@ github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3k
6058
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
6159
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
6260
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
63-
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
64-
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
65-
go.etcd.io/bbolt v1.4.0 h1:TU77id3TnN/zKr7CO/uk+fBCwF2jGcMuw2B/FMAzYIk=
66-
go.etcd.io/bbolt v1.4.0/go.mod h1:AsD+OCi/qPN1giOX1aiLAha3o1U8rAz65bvN4j0sRuk=
6761
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
6862
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
6963
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -73,5 +67,4 @@ golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
7367
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
7468
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
7569
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
76-
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
7770
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

internal/api/anilist.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,20 @@ func queryAnilist(query string, variables map[string]any) ([]byte, error) {
3333
}
3434

3535
dbConn := db.NewDbConn()
36-
token, err := dbConn.Get("auth_token")
36+
defer dbConn.Close()
37+
38+
err = dbConn.Init(false)
39+
if err != nil {
40+
return nil, err
41+
}
42+
43+
token, err := dbConn.GetConfig("auth_token")
3744
if err != nil {
38-
println(err.Error())
3945
return nil, errors.New("not logged in. Please use \"chibi login\" to continue")
4046
}
4147

4248
req.Header.Set("Content-Type", "application/json")
43-
req.Header.Set("Authorization", "Bearer "+token)
49+
req.Header.Set("Authorization", "Bearer "+*token)
4450

4551
httpClient := &http.Client{}
4652
resp, err := httpClient.Do(req)

internal/db/db.go

Lines changed: 76 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,107 +1,107 @@
11
package db
22

33
import (
4-
"errors"
5-
"fmt"
4+
"database/sql"
65
"os"
76
"path"
8-
"time"
97

108
"github.com/CosmicPredator/chibi/internal"
11-
bolt "go.etcd.io/bbolt"
9+
_ "github.com/mattn/go-sqlite3"
1210
)
1311

14-
// define DbContext type to make CRUD operations
15-
type DbContext struct {}
16-
17-
// creates a new bucket and if exists, it'll skip
18-
func (dc DbContext) createBucket() error {
19-
db, err := dc.openDbConn()
20-
defer db.Close()
21-
if err != nil {
22-
return err
23-
}
24-
return db.Update(func(tx *bolt.Tx) error {
25-
_, err := tx.CreateBucketIfNotExists([]byte(internal.BOLT_BUCKET_NAME))
26-
if err != nil {
27-
return err
28-
}
29-
return nil
30-
})
12+
type DbContext struct {
13+
dbConn *sql.DB
3114
}
3215

33-
// cleans up and prepares os sepcific config folder
34-
// to save .db file
35-
func (dc DbContext) InitDB() error {
36-
osConfigPath, _ := os.UserConfigDir()
37-
configDir := path.Join(osConfigPath, "chibi")
38-
_, err := os.Stat(configDir)
16+
// creates required SQL tables
17+
func (dc *DbContext) createRequiredTables() error {
18+
tx, err := dc.dbConn.Begin()
19+
if err != nil {
20+
return err
21+
}
22+
23+
if _, err = tx.Exec(QUERY_CREATE_TABLE); err != nil {
24+
return err
25+
}
3926

40-
if err == nil {
41-
os.RemoveAll(configDir)
27+
if err = tx.Commit(); err != nil {
28+
tx.Rollback()
29+
return err
4230
}
43-
os.MkdirAll(configDir, 0755)
44-
return dc.createBucket()
31+
return nil
4532
}
4633

47-
// opens the .db file and returns the instance
48-
func (dc *DbContext) openDbConn() (*bolt.DB, error) {
49-
osConfigDir, _ := os.UserConfigDir()
50-
configFilePath := path.Join(osConfigDir, "chibi", internal.BOLT_DB_NAME)
34+
// initialize an SQL instance.
35+
// if isFirstTime is true, it'll clean the os config dir
36+
// and creates a brand new table
37+
func (dc *DbContext) Init(isFirstTime bool) error {
38+
osConfigPath, _ := os.UserConfigDir()
39+
configDir := path.Join(osConfigPath, "chibi")
40+
41+
if isFirstTime {
42+
internal.CreateConfigDir()
43+
}
44+
dbPath := path.Join(configDir, "chibi_config.db")
5145

52-
db, err := bolt.Open(configFilePath, 0755, &bolt.Options{
53-
Timeout: 5 * time.Second,
54-
})
46+
db, err := sql.Open("sqlite3", dbPath)
5547
if err != nil {
56-
return nil, err
48+
return err
5749
}
58-
return db, nil
50+
dc.dbConn = db
51+
if isFirstTime {
52+
err := dc.createRequiredTables()
53+
if err != nil {
54+
return err
55+
}
56+
}
57+
return nil
5958
}
6059

61-
// writes the key value pair to db
62-
func (dc DbContext) Set(key string, value string) error {
63-
db, err := dc.openDbConn()
64-
defer db.Close()
65-
if err != nil {
66-
return err
67-
}
68-
err = db.Update(func(tx *bolt.Tx) error {
69-
b := tx.Bucket([]byte(internal.BOLT_BUCKET_NAME))
70-
if b == nil {
71-
return errors.New("DB Bucket does not exist")
72-
}
73-
err := b.Put([]byte(key), []byte(value))
60+
// add a key value pair to config table
61+
func (dc *DbContext) SetConfig(key string, value string) error {
62+
tx, err := dc.dbConn.Begin()
63+
if err != nil {
64+
return err
65+
}
66+
67+
if _, err = tx.Exec(QUERY_INSERT_CONFIG, key, value); err != nil {
7468
return err
75-
})
76-
return err
69+
}
70+
71+
if err = tx.Commit(); err != nil {
72+
tx.Rollback()
73+
return err
74+
}
75+
76+
return nil
7777
}
7878

79-
// reads the value of specified key from db
80-
func (dc DbContext) Get(key string) (string, error) {
81-
db, err := dc.openDbConn()
82-
defer db.Close()
83-
if err != nil {
84-
return "", err
85-
}
79+
// gets a key's value from the config table
80+
func (dc *DbContext) GetConfig(key string) (*string, error) {
81+
tx, err := dc.dbConn.Begin()
82+
if err != nil {
83+
return nil, err
84+
}
8685

86+
row := tx.QueryRow(QUERY_GET_CONFIG, key)
8787
var value string
88-
err = db.View(func(tx *bolt.Tx) error {
89-
b := tx.Bucket([]byte(internal.BOLT_BUCKET_NAME))
90-
if b == nil {
91-
return errors.New("DB Bucket does not exist")
92-
}
93-
value = string(b.Get([]byte(key)))
94-
if value == "" {
95-
return fmt.Errorf("no value found for the key %s", key)
96-
}
97-
return nil
98-
})
99-
if err != nil {
100-
return "", err
88+
89+
if err = row.Scan(&value); err != nil {
90+
return nil, err
10191
}
102-
return value, err
92+
93+
if err = tx.Commit(); err != nil {
94+
return nil, err
95+
}
96+
return &value, nil
97+
}
98+
99+
// closes the DB instance after usage
100+
func (dc *DbContext) Close() {
101+
dc.dbConn.Close()
103102
}
104103

104+
// returns a brand new DbContext instance
105105
func NewDbConn() *DbContext {
106106
return &DbContext{}
107107
}

internal/db/queries.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package db
2+
3+
const(
4+
QUERY_CREATE_TABLE = `CREATE TABLE IF NOT EXISTS config (
5+
id INTEGER PRIMARY KEY AUTOINCREMENT,
6+
key TEXT NOT NULL,
7+
value TEXT
8+
)`
9+
10+
QUERY_INSERT_CONFIG = `INSERT INTO config (key, value) VALUES (?, ?)`
11+
12+
QUERY_GET_CONFIG = `SELECT value FROM config WHERE key = ?`
13+
)

internal/helpers.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package internal
2+
3+
import (
4+
"os"
5+
"path"
6+
)
7+
8+
// creates a directory "chibi" in os specific config folder.
9+
// in unix-like systems, the path is /home/user/.config/chibi.
10+
// in windows, the path is %AppData%\chibi
11+
func CreateConfigDir() {
12+
osConfigPath, _ := os.UserConfigDir()
13+
configDir := path.Join(osConfigPath, "chibi")
14+
_, err := os.Stat(configDir)
15+
16+
if err == nil {
17+
os.RemoveAll(configDir)
18+
}
19+
os.MkdirAll(configDir, 0755)
20+
}

internal/viewmodel/login_handler.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,15 @@ func HandleLogin() error {
2121
}
2222

2323
dbConn := db.NewDbConn()
24-
err = dbConn.InitDB()
24+
defer dbConn.Close()
25+
26+
err = dbConn.Init(true)
2527
if err != nil {
2628
return err
2729
}
2830

2931
// write access token to db
30-
err = dbConn.Set("auth_token", loginUI.GetAuthToken())
32+
err = dbConn.SetConfig("auth_token", loginUI.GetAuthToken())
3133
if err != nil {
3234
return err
3335
}
@@ -39,12 +41,12 @@ func HandleLogin() error {
3941
return err
4042
}
4143

42-
err = dbConn.Set("user_id", strconv.Itoa(profile.Data.Viewer.Id))
44+
err = dbConn.SetConfig("user_id", strconv.Itoa(profile.Data.Viewer.Id))
4345
if err != nil {
4446
return err
4547
}
4648

47-
err = dbConn.Set("user_name", profile.Data.Viewer.Name)
49+
err = dbConn.SetConfig("user_name", profile.Data.Viewer.Name)
4850
if err != nil {
4951
return err
5052
}

0 commit comments

Comments
 (0)