241 lines
5.1 KiB
Go
241 lines
5.1 KiB
Go
package bolt
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"strconv"
|
|
|
|
"github.com/boltdb/bolt"
|
|
"github.com/influxdata/chronograf/v2"
|
|
)
|
|
|
|
var (
|
|
cellBucket = []byte("cellsv2")
|
|
)
|
|
|
|
func (c *Client) initializeCells(ctx context.Context, tx *bolt.Tx) error {
|
|
if _, err := tx.CreateBucketIfNotExists([]byte(cellBucket)); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// FindCellByID retrieves a cell by id.
|
|
func (c *Client) FindCellByID(ctx context.Context, id platform.ID) (*platform.Cell, error) {
|
|
var d *platform.Cell
|
|
|
|
err := c.db.View(func(tx *bolt.Tx) error {
|
|
dash, err := c.findCellByID(ctx, tx, id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
d = dash
|
|
return nil
|
|
})
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return d, nil
|
|
}
|
|
|
|
func (c *Client) findCellByID(ctx context.Context, tx *bolt.Tx, id platform.ID) (*platform.Cell, error) {
|
|
var d platform.Cell
|
|
|
|
v := tx.Bucket(cellBucket).Get([]byte(id))
|
|
|
|
if len(v) == 0 {
|
|
return nil, platform.ErrCellNotFound
|
|
}
|
|
|
|
if err := json.Unmarshal(v, &d); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &d, nil
|
|
}
|
|
|
|
// FindCell retrieves a cell using an arbitrary cell filter.
|
|
func (c *Client) FindCell(ctx context.Context, filter platform.CellFilter) (*platform.Cell, error) {
|
|
if filter.ID != nil {
|
|
return c.FindCellByID(ctx, *filter.ID)
|
|
}
|
|
|
|
var d *platform.Cell
|
|
err := c.db.View(func(tx *bolt.Tx) error {
|
|
filterFn := filterCellsFn(filter)
|
|
return c.forEachCell(ctx, tx, func(dash *platform.Cell) bool {
|
|
if filterFn(dash) {
|
|
d = dash
|
|
return false
|
|
}
|
|
return true
|
|
})
|
|
})
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if d == nil {
|
|
return nil, platform.ErrCellNotFound
|
|
}
|
|
|
|
return d, nil
|
|
}
|
|
|
|
func filterCellsFn(filter platform.CellFilter) func(d *platform.Cell) bool {
|
|
if filter.ID != nil {
|
|
return func(d *platform.Cell) bool {
|
|
return d.ID == *filter.ID
|
|
}
|
|
}
|
|
|
|
return func(d *platform.Cell) bool { return true }
|
|
}
|
|
|
|
// FindCells retrives all cells that match an arbitrary cell filter.
|
|
func (c *Client) FindCells(ctx context.Context, filter platform.CellFilter) ([]*platform.Cell, int, error) {
|
|
if filter.ID != nil {
|
|
d, err := c.FindCellByID(ctx, *filter.ID)
|
|
if err != nil {
|
|
return nil, 0, err
|
|
}
|
|
|
|
return []*platform.Cell{d}, 1, nil
|
|
}
|
|
|
|
ds := []*platform.Cell{}
|
|
err := c.db.View(func(tx *bolt.Tx) error {
|
|
dashs, err := c.findCells(ctx, tx, filter)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
ds = dashs
|
|
return nil
|
|
})
|
|
|
|
if err != nil {
|
|
return nil, 0, err
|
|
}
|
|
|
|
return ds, len(ds), nil
|
|
}
|
|
|
|
func (c *Client) findCells(ctx context.Context, tx *bolt.Tx, filter platform.CellFilter) ([]*platform.Cell, error) {
|
|
ds := []*platform.Cell{}
|
|
|
|
filterFn := filterCellsFn(filter)
|
|
err := c.forEachCell(ctx, tx, func(d *platform.Cell) bool {
|
|
if filterFn(d) {
|
|
ds = append(ds, d)
|
|
}
|
|
return true
|
|
})
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return ds, nil
|
|
}
|
|
|
|
// CreateCell creates a platform cell and sets d.ID.
|
|
func (c *Client) CreateCell(ctx context.Context, d *platform.Cell) error {
|
|
return c.db.Update(func(tx *bolt.Tx) error {
|
|
id, err := tx.Bucket(cellBucket).NextSequence()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
d.ID = platform.ID(strconv.Itoa(int(id)))
|
|
|
|
return c.putCell(ctx, tx, d)
|
|
})
|
|
}
|
|
|
|
// PutCell will put a cell without setting an ID.
|
|
func (c *Client) PutCell(ctx context.Context, d *platform.Cell) error {
|
|
return c.db.Update(func(tx *bolt.Tx) error {
|
|
return c.putCell(ctx, tx, d)
|
|
})
|
|
}
|
|
|
|
func (c *Client) putCell(ctx context.Context, tx *bolt.Tx, d *platform.Cell) error {
|
|
v, err := json.Marshal(d)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := tx.Bucket(cellBucket).Put([]byte(d.ID), v); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// forEachCell will iterate through all cells while fn returns true.
|
|
func (c *Client) forEachCell(ctx context.Context, tx *bolt.Tx, fn func(*platform.Cell) bool) error {
|
|
cur := tx.Bucket(cellBucket).Cursor()
|
|
for k, v := cur.First(); k != nil; k, v = cur.Next() {
|
|
d := &platform.Cell{}
|
|
if err := json.Unmarshal(v, d); err != nil {
|
|
return err
|
|
}
|
|
if !fn(d) {
|
|
break
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// UpdateCell updates a cell according the parameters set on upd.
|
|
func (c *Client) UpdateCell(ctx context.Context, id platform.ID, upd platform.CellUpdate) (*platform.Cell, error) {
|
|
var d *platform.Cell
|
|
err := c.db.Update(func(tx *bolt.Tx) error {
|
|
dash, err := c.updateCell(ctx, tx, id, upd)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
d = dash
|
|
return nil
|
|
})
|
|
|
|
return d, err
|
|
}
|
|
|
|
func (c *Client) updateCell(ctx context.Context, tx *bolt.Tx, id platform.ID, upd platform.CellUpdate) (*platform.Cell, error) {
|
|
d, err := c.findCellByID(ctx, tx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if upd.Name != nil {
|
|
d.Name = *upd.Name
|
|
}
|
|
|
|
if upd.Visualization != nil {
|
|
d.Visualization = upd.Visualization
|
|
}
|
|
|
|
if err := c.putCell(ctx, tx, d); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return d, nil
|
|
}
|
|
|
|
// DeleteCell deletes a cell and prunes it from the index.
|
|
func (c *Client) DeleteCell(ctx context.Context, id platform.ID) error {
|
|
return c.db.Update(func(tx *bolt.Tx) error {
|
|
return c.deleteCell(ctx, tx, id)
|
|
})
|
|
}
|
|
|
|
func (c *Client) deleteCell(ctx context.Context, tx *bolt.Tx, id platform.ID) error {
|
|
_, err := c.findCellByID(ctx, tx, id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return tx.Bucket(cellBucket).Delete([]byte(id))
|
|
}
|