package badger import ( "fmt" "time" "unsafe" "git.loyso.art/frx/eway/internal/entity" badger "github.com/dgraph-io/badger/v4" ) var ( categorySequenceIDKey = []byte("!!cat_seq!!") queueSequenceIDKey = []byte("!!que_seq!!") ) type client struct { db *badger.DB nextCategoryIDSeq *badger.Sequence nextQueueIDSeq *badger.Sequence } func NewClient(db *badger.DB) (*client, error) { categorySeqGen, err := db.GetSequence(categorySequenceIDKey, 10) if err != nil { return nil, fmt.Errorf("getting sequence for categories: %w", err) } queueSeqGen, err := db.GetSequence(queueSequenceIDKey, 10) if err != nil { return nil, fmt.Errorf("getting sequence for queues: %w", err) } return &client{ db: db, nextCategoryIDSeq: categorySeqGen, nextQueueIDSeq: queueSeqGen, }, nil } // Close closes the underlying sequences in the client. Should be called right before // underlying *badger.DB closed. func (c *client) Close() error { err := c.nextCategoryIDSeq.Release() if err != nil { return fmt.Errorf("releasing next_category_sequence: %w", err) } return nil } func (c *client) Category() entity.CategoryRepository { return newCategoryClient(c.db, c.nextCategoryIDSeq) } func (c *client) GoodsItem() entity.GoodsItemRepository { return newGoodsItemClient(c.db) } func (c *client) QueueClient() entity.MessageQueue { nc := c.Table("queues") return newQueueClient(nc, c.nextQueueIDSeq) } func (c *client) Table(name string) namedClient { tableBytes := unsafe.Slice(unsafe.StringData("!!"+name+"!!"), len(name)+4) return namedClient{ table: tableBytes, db: c.db, } } type namedClient struct { table []byte db *badger.DB } type putOpt func(*badger.Entry) func withTTL(duration time.Duration) putOpt { return func(e *badger.Entry) { e.WithTTL(duration) } } func (c *namedClient) Put(key, value []byte, opts ...putOpt) error { return c.db.Update(func(txn *badger.Txn) error { tableKey := c.makeKey(key) entry := badger.NewEntry(tableKey, value) for _, opt := range opts { opt(entry) } return txn.SetEntry(entry) }) } func (c *namedClient) Get(key []byte) ([]byte, error) { var out []byte err := c.db.View(func(txn *badger.Txn) error { item, err := txn.Get(c.makeKey(key)) if err != nil { return err } out = make([]byte, item.ValueSize()) out, err = item.ValueCopy(out) return err }) if err != nil { return nil, err } return out, nil } func (c *namedClient) makeKey(key []byte) (out []byte) { return append(c.table, key...) }