meson_bolt_localdb

package module
v0.0.0-...-54ba531 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 28, 2021 License: Apache-2.0 Imports: 11 Imported by: 0

README

meson-bolt-localdb

It's a local file db based on bblot & BoltHold

How to use

go get github.com/daqnext/meson-bolt-localdb
go get go.etcd.io/bbolt
Open db file
import mesondb "github.com/daqnext/meson-bolt-localdb"
import "go.etcd.io/bbolt"

var store *mesondb.Store
var err error
store, err = mesondb.Open("test.db", 0666, nil)
if err != nil {
    log.Println("bolthold can't open")
	return
}
defer store.Close()

use custom option

op:=&mesondb.Options{
    Decoder: func(data []byte, value interface{}) error {
        //define your own decoder

        return nil
    },
    Encoder: func(value interface{}) ([]byte, error) {
        //define your own encoder

        return []byte{},nil
    },
    //other bbolt options
    //...
    Options:&bbolt.Options{},
}
store, err = mesondb.Open("test.db", 0666,op)

defalut Decoder and Encoder use "golang/gob" except int (int8 int16...) float32 and float64, number value use the encoder which result []byte can be sorted correctly.

Define struct
type Pointer struct {
	Name string
}

type FileInfoWithIndex struct {
	HashKey        string `boltholdKey:"HashKey"`
	BindName       string `boltholdIndex:"BindName"`
	LastAccessTime int64  `boltholdIndex:"LastAccessTime"`
	FileSize       int64
	Rate           float64 `boltholdIndex:"Rate"`
	P              *Pointer
}

You can use tag "boltholdIndex","boltholdUnique" to create index. It can be used to do query. If you use tag "boltholdKey" means this field is the Key for this record in key-value storage

Insert to db

single insert

p := &Pointer{"pointName"}
fileInfo := FileInfoWithIndex{BindName: "bindName-1", LastAccessTime: int64(rand.Intn(100)), FileSize: int64(rand.Intn(100)), P: p}
err = store.Insert("1", fileInfo)
if err != nil {
	log.Println(err)
}

fileInfo = FileInfoWithIndex{BindName: "bindName-2", LastAccessTime: int64(rand.Intn(100)), FileSize: int64(rand.Intn(100)), P: p}
err = store.Insert("2", fileInfo)
if err != nil {
	log.Println(err)
}

batch insert

err = store.Bolt().Update(func(tx *bbolt.Tx) error {
	for i := 0; i < 100; i++ {
		hashKey := fmt.Sprintf("%d", i)
		bindName := fmt.Sprintf("bindname-%01d", rand.Intn(10)+4)
		p := &Pointer{"pointName"}
		fileInfo := FileInfoWithIndex{
			BindName:       bindName,
			LastAccessTime: int64(rand.Intn(100) - 50),
			FileSize:       int64(rand.Intn(100)),
			Rate:           float64(rand.Intn(1000))*0.33 - 150,
			P:              p
		}

		err := store.TxInsert(tx, hashKey, fileInfo)
		if err != nil {
			log.Println(err)
		}
	}
	return nil
})
if err != nil {
	log.Println(err)
}

if the key is already exist, err ErrKeyExists will return.

Upsert() and TxUpsert() can be used. Upsert() and TxUpsert() inserts the record if it doesn't exist. If it does already exist, then it updates the existing record

query or get

get by key

var info FileInfoWithIndex
err := store.Get("1", &info)
if err != nil {
	log.Println(err)
}
log.Println(info)

var info2 FileInfoWithIndex
err = store.Get("2", &info2)
if err != nil {
	log.Println(err)
}
log.Println(info2)

if this given key not exist, err ErrNotFound will return.

use query

log.Println("query by some index")
var infos []FileInfoWithIndex
q:=mesondb.NewQuery("LastAccessTime").Range(mesondb.Condition(mesondb.OpGe,int64(-20)),mesondb.Condition(mesondb.OpLe,int64(20)))
err:=store.Find(&infos,q)
if err != nil {
	log.Println(err)
}
for _,v:=range infos2{
	log.Println(v)
}

query condition example:

//Equal
mesondb.NewQuery("indexFieldName").Equal(someValue)
//Range
mesondb.NewQuery("indexFieldName").Range(mesondb.Condition(mesondb.OpGe,someValue),mesondb.Condition(mesondb.OpLe,someValue))
//Offset Limit Exclude Desc Asc
mesondb.NewQuery("indexFieldName").Range(mesondb.Condition(mesondb.OpGe,someValue)).Limit(10).Offset(10).Exclude(v1,v2,..).Desc()
//if you do not define the Range, it will scan all index value 
mesondb.NewQuery("indexFieldName").Limit(10).Offset(10).Exclude(v1,v2,..).Desc()
//Use indexField "mesondb.Key" to query the Key. It also can use Range query if the Key is sortable
mesondb.NewQuery(mesondb.Key).Range(mesondb.Condition(mesondb.OpGe,someValue))
//Operator
//mesondb.OpGt ">"
//mesondb.OpGe ">="
//mesondb.OpLt "<"
//mesondb.OpLe "<="

The Range query can not get the correct result if the index value is not sortable. Do not use Range query with unsortable index or key.

Number and string are sortable with default Encoder.

//if the query is nil, it will get all the value
log.Println("query all value")
var infos []FileInfoWithIndex
err := store.Find(&infos4, nil)
if err != nil {
log.Println(err)
}
for _, v := range infos {
log.Println(v)
}

Update query
log.Println("update query")
q := mesondb.NewQuery("LastAccessTime").Range(mesondb.Condition(mesondb.OpGe, 10), mesondb.Condition(mesondb.OpLe, 20))
err := store.UpdateMatching(&FileInfoWithIndex{}, q, func(record interface{}) error {
	v, ok := record.(*FileInfoWithIndex)
	if !ok {
	    log.Println("interface{} trans error")
	}
	v.FileSize = 999
	return nil
})
if err != nil {
	log.Println(err)
}
Delete

by key

// input the Key and dataType
err:=store.Delete("1",&FileInfoWithIndex{})
if err != nil {
	log.Println(err)
}

by query

log.Println("delete query")
q := mesondb.NewQuery("LastAccessTime").Range(mesondb.Condition(mesondb.OpGe, 10), mesondb.Condition(mesondb.OpLe, 20))
err := store.DeleteMatching(&FileInfoWithIndex{}, q)
if err != nil {
	log.Println(err)
}

Documentation

Index

Constants

View Source
const BoltholdIndexTag = "boltholdIndex"

BoltholdIndexTag is the struct tag used to define a field as indexable for a bolthold

View Source
const BoltholdKeyTag = "boltholdKey"

BoltholdKeyTag is the struct tag used to define an a field as a key for use in a Find query

View Source
const BoltholdUniqueTag = "boltholdUnique"

BoltholdUniqueTag is the struct tag used to define a field as unique constraint

View Source
const Key = ""

Key is shorthand for specifying a query to run again the Key in a bolthold, simply returns "" Where(bolthold.Key).Eq("testkey")

Variables

View Source
var ErrKeyExists = errors.New("This Key already exists in this bolthold for this type")

ErrKeyExists is the error returned when data is being Inserted for a Key that already exists

View Source
var ErrNotFound = errors.New("No data found for this key")

ErrNotFound is returned when no data is found for the given key

View Source
var ErrUniqueExists = errors.New("This value cannot be written due to the unique constraint on the field")

ErrUniqueExists is the error thrown when data is being inserted for a unique constraint value that already exists

Functions

func ByteToFloat32

func ByteToFloat32(bytes []byte) float32

func ByteToFloat64

func ByteToFloat64(bytes []byte) float64

func BytesToInt64

func BytesToInt64(buf []byte) int64

func DefaultDecode

func DefaultDecode(data []byte, value interface{}) error

DefaultDecode is the default decoding func for bolthold (Gob)

func DefaultEncode

func DefaultEncode(value interface{}) ([]byte, error)

DefaultEncode is the default encoding func for bolthold (Gob)

func Float32ToByte

func Float32ToByte(float float32) []byte

func Float64ToByte

func Float64ToByte(float float64) []byte

func Int64ToBytes

func Int64ToBytes(i int64) []byte

func NextSequence

func NextSequence() interface{}

NextSequence is used to create a sequential key for inserts Inserts a uint64 as the key store.Insert(bolthold.NextSequence(), data)

Types

type BucketSource

type BucketSource interface {
	Bucket(name []byte) *bolt.Bucket
	CreateBucketIfNotExists(name []byte) (*bolt.Bucket, error)
}

BucketSource is the source of a bucket for running a query or updating data Buckets and Transactions both implement BucketSource. This allows for choosing a specific bucket or transaction when running a query

type Criterion

type Criterion struct {
	// contains filtered or unexported fields
}

func Condition

func Condition(op Operator, value interface{}) *Criterion

type DecodeFunc

type DecodeFunc func(data []byte, value interface{}) error

DecodeFunc is a function for decoding a value from bytes

type EncodeFunc

type EncodeFunc func(value interface{}) ([]byte, error)

EncodeFunc is a function for encoding a value into bytes

type Index

type Index struct {
	IndexFunc func(name string, value interface{}) ([]byte, error)
	Unique    bool
}

Index is a function that returns the indexable, encoded bytes of the passed in value

type Operator

type Operator int
const (
	OpGt Operator
	OpGe
	OpLt
	OpLe
)

type Options

type Options struct {
	Encoder EncodeFunc
	Decoder DecodeFunc
	*bolt.Options
}

Options allows you set different options from the defaults For example the encoding and decoding funcs which default to Gob

type Query

type Query struct {
	// contains filtered or unexported fields
}

func NewQuery

func NewQuery(index string) *Query

func (*Query) Asc

func (q *Query) Asc() *Query

func (*Query) Desc

func (q *Query) Desc() *Query

func (*Query) Equal

func (q *Query) Equal(value interface{}) *Query

func (*Query) Exclude

func (q *Query) Exclude(value ...interface{}) *Query

func (*Query) Limit

func (q *Query) Limit(limit int) *Query

func (*Query) Offset

func (q *Query) Offset(offset int) *Query

func (*Query) Range

func (q *Query) Range(c ...*Criterion) *Query

type QueryType

type QueryType int
const QueryEqual QueryType = 2
const QueryRange QueryType = 1

type SliceIndex

type SliceIndex func(name string, value interface{}) ([][]byte, error)

SliceIndex is a function that returns all of the indexable values in a slice

type Store

type Store struct {
	// contains filtered or unexported fields
}

Store is a bolthold wrapper around a bolt DB

func Open

func Open(filename string, mode os.FileMode, options *Options) (*Store, error)

Open opens or creates a bolthold file.

func (*Store) Bolt

func (s *Store) Bolt() *bolt.DB

Bolt returns the underlying Bolt DB the bolthold is based on

func (*Store) Close

func (s *Store) Close() error

Close closes the bolt db

func (*Store) Count

func (s *Store) Count(dataType interface{}, query *Query) (int, error)

Count returns the current record count for the passed in datatype

func (*Store) Delete

func (s *Store) Delete(key, dataType interface{}) error

Delete deletes a record from the bolthold, datatype just needs to be an example of the type stored so that the proper bucket and indexes are updated

func (*Store) DeleteMatching

func (s *Store) DeleteMatching(dataType interface{}, query *Query) error

DeleteMatching deletes all of the records that match the passed in query

func (*Store) Find

func (s *Store) Find(result interface{}, query *Query) error

Find retrieves a set of values from the bolthold that matches the passed in query result must be a pointer to a slice. The result of the query will be appended to the passed in result slice, rather than the passed in slice being emptied.

func (*Store) FindOne

func (s *Store) FindOne(result interface{}, query *Query) error

FindOne returns a single record, and so result is NOT a slice, but an pointer to a struct, if no record is found that matches the query, then it returns ErrNotFound

func (*Store) Get

func (s *Store) Get(key, result interface{}) error

Get retrieves a value from bolthold and puts it into result. Result must be a pointer

func (*Store) IndexExists

func (s *Store) IndexExists(source BucketSource, typeName, indexName string) bool

IndexExists tests if an index exists for the passed in field name

func (*Store) Insert

func (s *Store) Insert(key, data interface{}) error

Insert inserts the passed in data into the the bolthold

If the the key already exists in the bolthold, then an ErrKeyExists is returned If the data struct has a field tagged as `boltholdKey` and it is the same type as the Insert key, AND the data struct is passed by reference, AND the key field is currently set to the zero-value for that type, then that field will be set to the value of the insert key.

To use this with bolthold.NextSequence() use a type of `uint64` for the key field.

func (*Store) ReIndex

func (s *Store) ReIndex(exampleType interface{}, bucketName []byte) error

ReIndex removes any existing indexes and adds all the indexes defined by the passed in datatype example This function allows you to index an already existing boltDB file, or refresh any missing indexes if bucketName is nil, then we'll assume a bucketName of storer.Type() if a bucketname is specified, then the data will be copied to the bolthold standard bucket of storer.Type()

func (*Store) RemoveIndex

func (s *Store) RemoveIndex(dataType interface{}, indexName string) error

RemoveIndex removes an index from the store.

func (*Store) TxCount

func (s *Store) TxCount(tx *bolt.Tx, dataType interface{}, query *Query) (int, error)

TxCount returns the current record count from within the given transaction for the passed in datatype

func (*Store) TxDelete

func (s *Store) TxDelete(tx *bolt.Tx, key, dataType interface{}) error

TxDelete is the same as Delete except it allows you specify your own transaction

func (*Store) TxDeleteMatching

func (s *Store) TxDeleteMatching(tx *bolt.Tx, dataType interface{}, query *Query) error

TxDeleteMatching does the same as DeleteMatching, but allows you to specify your own transaction

func (*Store) TxFind

func (s *Store) TxFind(tx *bolt.Tx, result interface{}, query *Query) error

TxFind allows you to pass in your own bolt transaction to retrieve a set of values from the bolthold

func (*Store) TxFindOne

func (s *Store) TxFindOne(tx *bolt.Tx, result interface{}, query *Query) error

TxFindOne allows you to pass in your own bolt transaction to retrieve a single record from the bolthold

func (*Store) TxGet

func (s *Store) TxGet(tx *bolt.Tx, key, result interface{}) error

TxGet allows you to pass in your own bolt transaction to retrieve a value from the bolthold and puts it into result

func (*Store) TxInsert

func (s *Store) TxInsert(tx *bolt.Tx, key, data interface{}) error

TxInsert is the same as Insert except it allows you specify your own transaction

func (*Store) TxUpdate

func (s *Store) TxUpdate(tx *bolt.Tx, key interface{}, data interface{}) error

TxUpdate is the same as Update except it allows you to specify your own transaction

func (*Store) TxUpdateMatching

func (s *Store) TxUpdateMatching(tx *bolt.Tx, dataType interface{}, query *Query,
	update func(record interface{}) error) error

TxUpdateMatching does the same as UpdateMatching, but allows you to specify your own transaction

func (*Store) TxUpsert

func (s *Store) TxUpsert(tx *bolt.Tx, key interface{}, data interface{}) error

TxUpsert is the same as Upsert except it allows you to specify your own transaction

func (*Store) Update

func (s *Store) Update(key interface{}, data interface{}) error

Update updates an existing record in the bolthold if the Key doesn't already exist in the store, then it fails with ErrNotFound

func (*Store) UpdateMatching

func (s *Store) UpdateMatching(dataType interface{}, query *Query, update func(record interface{}) error) error

UpdateMatching runs the update function for every record that match the passed in query Note that the type of record in the update func always has to be a pointer

func (*Store) Upsert

func (s *Store) Upsert(key interface{}, data interface{}) error

Upsert inserts the record into the bolthold if it doesn't exist. If it does already exist, then it updates the existing record

type Storer

type Storer interface {
	Type() string              // used as the boltdb bucket name
	Indexes() map[string]Index // [indexname]indexFunc

}

Storer is the Interface to implement to skip reflect calls on all data passed into the bolthold

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL