Files
hetty/pkg/db/bolt/proj.go

177 lines
3.9 KiB
Go
Raw Normal View History

2025-01-13 23:15:18 +01:00
package bolt
import (
"bytes"
"context"
"encoding/gob"
"errors"
"fmt"
"github.com/oklog/ulid"
bolt "go.etcd.io/bbolt"
"github.com/dstotijn/hetty/pkg/proj"
)
var (
ErrProjectsBucketNotFound = errors.New("bolt: projects bucket not found")
ErrProjectBucketNotFound = errors.New("bolt: project bucket not found")
)
var (
projectsBucketName = []byte("projects")
projectKey = []byte("project")
)
func projectsBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
b := tx.Bucket(projectsBucketName)
if b == nil {
return nil, ErrProjectsBucketNotFound
}
return b, nil
}
func projectBucket(tx *bolt.Tx, projectID []byte) (*bolt.Bucket, error) {
pb, err := projectsBucket(tx)
if err != nil {
return nil, err
}
b := pb.Bucket(projectID[:])
if b == nil {
return nil, ErrProjectBucketNotFound
}
return b, nil
}
func (db *Database) UpsertProject(ctx context.Context, project proj.Project) error {
buf := bytes.Buffer{}
err := gob.NewEncoder(&buf).Encode(project)
if err != nil {
return fmt.Errorf("bolt: failed to encode project: %w", err)
}
err = db.bolt.Update(func(tx *bolt.Tx) error {
b, err := createNestedBucket(tx, projectsBucketName, project.ID[:])
if err != nil {
return fmt.Errorf("bolt: failed to create project bucket: %w", err)
}
err = b.Put(projectKey, buf.Bytes())
if err != nil {
return fmt.Errorf("bolt: failed to upsert project: %w", err)
}
_, err = b.CreateBucketIfNotExists(reqLogsBucketName)
if err != nil {
return fmt.Errorf("bolt: failed to create request logs bucket: %w", err)
}
_, err = b.CreateBucketIfNotExists(senderReqsBucketName)
if err != nil {
return fmt.Errorf("bolt: failed to create sender requests bucket: %w", err)
}
return nil
})
if err != nil {
return fmt.Errorf("bolt: failed to commit transaction: %w", err)
}
return nil
}
func (db *Database) FindProjectByID(ctx context.Context, projectID ulid.ULID) (project proj.Project, err error) {
err = db.bolt.View(func(tx *bolt.Tx) error {
bucket, err := projectBucket(tx, projectID[:])
if errors.Is(err, ErrProjectsBucketNotFound) || errors.Is(err, ErrProjectBucketNotFound) {
return proj.ErrProjectNotFound
}
if err != nil {
return err
}
rawProject := bucket.Get(projectKey)
if rawProject == nil {
return proj.ErrProjectNotFound
}
err = gob.NewDecoder(bytes.NewReader(rawProject)).Decode(&project)
if err != nil {
return fmt.Errorf("failed to decode project: %w", err)
}
return nil
})
if err != nil {
return proj.Project{}, fmt.Errorf("bolt: failed to commit transaction: %w", err)
}
return project, nil
}
func (db *Database) DeleteProject(ctx context.Context, projectID ulid.ULID) error {
err := db.bolt.Update(func(tx *bolt.Tx) error {
pb, err := projectsBucket(tx)
if err != nil {
return err
}
err = pb.DeleteBucket(projectID[:])
if err != nil {
return fmt.Errorf("failed to delete project bucket: %w", err)
}
return nil
})
if err != nil {
return fmt.Errorf("bolt: failed to commit transaction: %w", err)
}
return nil
}
func (db *Database) Projects(ctx context.Context) ([]proj.Project, error) {
projects := make([]proj.Project, 0)
err := db.bolt.View(func(tx *bolt.Tx) error {
pb, err := projectsBucket(tx)
if err != nil {
return err
}
err = pb.ForEachBucket(func(projectID []byte) error {
bucket, err := projectBucket(tx, projectID)
if err != nil {
return err
}
rawProject := bucket.Get(projectKey)
if rawProject == nil {
return proj.ErrProjectNotFound
}
var project proj.Project
err = gob.NewDecoder(bytes.NewReader(rawProject)).Decode(&project)
if err != nil {
return fmt.Errorf("bolt: failed to decode project: %w", err)
}
projects = append(projects, project)
return nil
})
if err != nil {
return fmt.Errorf("bolt: failed to iterate over projects: %w", err)
}
return nil
})
if err != nil {
return nil, fmt.Errorf("bolt: failed to commit transaction: %w", err)
}
return projects, nil
}