1package blockstore
2
3import (
4 "context"
5 "fmt"
6
7 "github.com/bluesky-social/indigo/atproto/syntax"
8 "github.com/haileyok/cocoon/models"
9 blocks "github.com/ipfs/go-block-format"
10 "github.com/ipfs/go-cid"
11 "gorm.io/gorm"
12 "gorm.io/gorm/clause"
13)
14
15type SqliteBlockstore struct {
16 db *gorm.DB
17 did string
18 readonly bool
19 inserts []blocks.Block
20}
21
22func New(did string, db *gorm.DB) *SqliteBlockstore {
23 return &SqliteBlockstore{
24 did: did,
25 db: db,
26 readonly: false,
27 inserts: []blocks.Block{},
28 }
29}
30
31func NewReadOnly(did string, db *gorm.DB) *SqliteBlockstore {
32 return &SqliteBlockstore{
33 did: did,
34 db: db,
35 readonly: true,
36 inserts: []blocks.Block{},
37 }
38}
39
40func (bs *SqliteBlockstore) Get(ctx context.Context, cid cid.Cid) (blocks.Block, error) {
41 var block models.Block
42 if err := bs.db.Raw("SELECT * FROM blocks WHERE did = ? AND cid = ?", bs.did, cid.Bytes()).Scan(&block).Error; err != nil {
43 return nil, err
44 }
45
46 b, err := blocks.NewBlockWithCid(block.Value, cid)
47 if err != nil {
48 return nil, err
49 }
50
51 return b, nil
52}
53
54func (bs *SqliteBlockstore) Put(ctx context.Context, block blocks.Block) error {
55 bs.inserts = append(bs.inserts, block)
56
57 if bs.readonly {
58 return nil
59 }
60
61 b := models.Block{
62 Did: bs.did,
63 Cid: block.Cid().Bytes(),
64 Rev: syntax.NewTIDNow(0).String(), // TODO: WARN, this is bad. don't do this
65 Value: block.RawData(),
66 }
67
68 if err := bs.db.Clauses(clause.OnConflict{
69 Columns: []clause.Column{{Name: "did"}, {Name: "cid"}},
70 UpdateAll: true,
71 }).Create(&b).Error; err != nil {
72 return err
73 }
74
75 return nil
76}
77
78func (bs *SqliteBlockstore) DeleteBlock(context.Context, cid.Cid) error {
79 panic("not implemented")
80}
81
82func (bs *SqliteBlockstore) Has(context.Context, cid.Cid) (bool, error) {
83 panic("not implemented")
84}
85
86func (bs *SqliteBlockstore) GetSize(context.Context, cid.Cid) (int, error) {
87 panic("not implemented")
88}
89
90func (bs *SqliteBlockstore) PutMany(context.Context, []blocks.Block) error {
91 panic("not implemented")
92}
93
94func (bs *SqliteBlockstore) AllKeysChan(ctx context.Context) (<-chan cid.Cid, error) {
95 panic("not implemented")
96}
97
98func (bs *SqliteBlockstore) HashOnRead(enabled bool) {
99 panic("not implemented")
100}
101
102func (bs *SqliteBlockstore) UpdateRepo(ctx context.Context, root cid.Cid, rev string) error {
103 if err := bs.db.Exec("UPDATE repos SET root = ?, rev = ? WHERE did = ?", root.Bytes(), rev, bs.did).Error; err != nil {
104 return err
105 }
106
107 return nil
108}
109
110func (bs *SqliteBlockstore) Execute(ctx context.Context) error {
111 if !bs.readonly {
112 return fmt.Errorf("blockstore was not readonly")
113 }
114
115 bs.readonly = false
116 for _, b := range bs.inserts {
117 bs.Put(ctx, b)
118 }
119 bs.readonly = true
120
121 return nil
122}
123
124func (bs *SqliteBlockstore) GetLog() []blocks.Block {
125 return bs.inserts
126}