mirror of
https://github.com/safing/portbase
synced 2025-09-02 02:29:59 +00:00
Work on datbase controller
This commit is contained in:
parent
818cb332b4
commit
3d60431376
6 changed files with 77 additions and 90 deletions
|
@ -1,6 +1,7 @@
|
||||||
package database
|
package database
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -35,6 +36,9 @@ func (c *Controller) Get(key string) (record.Record, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r.Lock()
|
||||||
|
defer r.Unlock()
|
||||||
|
|
||||||
if !r.Meta().CheckValidity(time.Now().Unix()) {
|
if !r.Meta().CheckValidity(time.Now().Unix()) {
|
||||||
return nil, ErrNotFound
|
return nil, ErrNotFound
|
||||||
}
|
}
|
||||||
|
@ -44,14 +48,27 @@ func (c *Controller) Get(key string) (record.Record, error) {
|
||||||
|
|
||||||
// Put saves a record in the database.
|
// Put saves a record in the database.
|
||||||
func (c *Controller) Put(r record.Record) error {
|
func (c *Controller) Put(r record.Record) error {
|
||||||
|
if c.storage.ReadOnly() {
|
||||||
|
return ErrReadOnly
|
||||||
|
}
|
||||||
|
|
||||||
return c.storage.Put(r)
|
return c.storage.Put(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Delete a record from the database.
|
||||||
func (c *Controller) Delete(key string) error {
|
func (c *Controller) Delete(key string) error {
|
||||||
|
if c.storage.ReadOnly() {
|
||||||
|
return ErrReadOnly
|
||||||
|
}
|
||||||
|
|
||||||
r, err := c.Get(key)
|
r, err := c.Get(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r.Lock()
|
||||||
|
defer r.Unlock()
|
||||||
|
|
||||||
r.Meta().Deleted = time.Now().Unix()
|
r.Meta().Deleted = time.Now().Unix()
|
||||||
return c.Put(r)
|
return c.Put(r)
|
||||||
}
|
}
|
||||||
|
@ -59,10 +76,36 @@ func (c *Controller) Delete(key string) error {
|
||||||
// Partial
|
// Partial
|
||||||
// What happens if I mutate a value that does not yet exist? How would I know its type?
|
// What happens if I mutate a value that does not yet exist? How would I know its type?
|
||||||
func (c *Controller) InsertPartial(key string, partialObject interface{}) error {
|
func (c *Controller) InsertPartial(key string, partialObject interface{}) error {
|
||||||
|
if c.storage.ReadOnly() {
|
||||||
|
return ErrReadOnly
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) InsertValue(key string, attribute string, value interface{}) error {
|
func (c *Controller) InsertValue(key string, attribute string, value interface{}) error {
|
||||||
|
if c.storage.ReadOnly() {
|
||||||
|
return ErrReadOnly
|
||||||
|
}
|
||||||
|
|
||||||
|
r, err := c.Get(key)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Lock()
|
||||||
|
defer r.Unlock()
|
||||||
|
|
||||||
|
if r.IsWrapped() {
|
||||||
|
wrapper, ok := r.(*record.Wrapper)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("record is malformed")
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,17 +116,33 @@ func (c *Controller) Query(q *query.Query, local, internal bool) (*iterator.Iter
|
||||||
|
|
||||||
// Meta
|
// Meta
|
||||||
func (c *Controller) SetAbsoluteExpiry(key string, time int64) error {
|
func (c *Controller) SetAbsoluteExpiry(key string, time int64) error {
|
||||||
|
if c.storage.ReadOnly() {
|
||||||
|
return ErrReadOnly
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) SetRelativateExpiry(key string, duration int64) error {
|
func (c *Controller) SetRelativateExpiry(key string, duration int64) error {
|
||||||
|
if c.storage.ReadOnly() {
|
||||||
|
return ErrReadOnly
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) MakeCrownJewel(key string) error {
|
func (c *Controller) MakeCrownJewel(key string) error {
|
||||||
|
if c.storage.ReadOnly() {
|
||||||
|
return ErrReadOnly
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) MakeSecret(key string) error {
|
func (c *Controller) MakeSecret(key string) error {
|
||||||
|
if c.storage.ReadOnly() {
|
||||||
|
return ErrReadOnly
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,8 +8,9 @@ import (
|
||||||
|
|
||||||
// Errors
|
// Errors
|
||||||
var (
|
var (
|
||||||
ErrNotFound = errors.New("database: entry could not be found")
|
ErrNotFound = errors.New("database entry could not be found")
|
||||||
ErrPermissionDenied = errors.New("database: access to record denied")
|
ErrPermissionDenied = errors.New("access to database record denied")
|
||||||
|
ErrReadOnly = errors.New("database is read only")
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
|
@ -1,78 +0,0 @@
|
||||||
package query
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/tidwall/gjson"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
emptyString = ""
|
|
||||||
)
|
|
||||||
|
|
||||||
// Fetcher provides an interface to supply the query matcher a method to retrieve values from an object.
|
|
||||||
type Fetcher interface {
|
|
||||||
GetString(key string) (value string, ok bool)
|
|
||||||
GetInt(key string) (value int64, ok bool)
|
|
||||||
GetFloat(key string) (value float64, ok bool)
|
|
||||||
GetBool(key string) (value bool, ok bool)
|
|
||||||
Exists(key string) bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// JSONFetcher is a json string with get functions.
|
|
||||||
type JSONFetcher struct {
|
|
||||||
json string
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewJSONFetcher adds the Fetcher interface to a JSON string.
|
|
||||||
func NewJSONFetcher(json string) *JSONFetcher {
|
|
||||||
return &JSONFetcher{
|
|
||||||
json: json,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetString returns the string found by the given json key and whether it could be successfully extracted.
|
|
||||||
func (jf *JSONFetcher) GetString(key string) (value string, ok bool) {
|
|
||||||
result := gjson.Get(jf.json, key)
|
|
||||||
if !result.Exists() || result.Type != gjson.String {
|
|
||||||
return emptyString, false
|
|
||||||
}
|
|
||||||
return result.String(), true
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetInt returns the int found by the given json key and whether it could be successfully extracted.
|
|
||||||
func (jf *JSONFetcher) GetInt(key string) (value int64, ok bool) {
|
|
||||||
result := gjson.Get(jf.json, key)
|
|
||||||
if !result.Exists() || result.Type != gjson.Number {
|
|
||||||
return 0, false
|
|
||||||
}
|
|
||||||
return result.Int(), true
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetFloat returns the float found by the given json key and whether it could be successfully extracted.
|
|
||||||
func (jf *JSONFetcher) GetFloat(key string) (value float64, ok bool) {
|
|
||||||
result := gjson.Get(jf.json, key)
|
|
||||||
if !result.Exists() || result.Type != gjson.Number {
|
|
||||||
return 0, false
|
|
||||||
}
|
|
||||||
return result.Float(), true
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetBool returns the bool found by the given json key and whether it could be successfully extracted.
|
|
||||||
func (jf *JSONFetcher) GetBool(key string) (value bool, ok bool) {
|
|
||||||
result := gjson.Get(jf.json, key)
|
|
||||||
switch {
|
|
||||||
case !result.Exists():
|
|
||||||
return false, false
|
|
||||||
case result.Type == gjson.True:
|
|
||||||
return true, true
|
|
||||||
case result.Type == gjson.False:
|
|
||||||
return false, true
|
|
||||||
default:
|
|
||||||
return false, false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exists returns the whether the given key exists.
|
|
||||||
func (jf *JSONFetcher) Exists(key string) bool {
|
|
||||||
result := gjson.Get(jf.json, key)
|
|
||||||
return result.Exists()
|
|
||||||
}
|
|
|
@ -2,13 +2,12 @@ package badger
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/dgraph-io/badger"
|
"github.com/dgraph-io/badger"
|
||||||
|
|
||||||
"github.com/Safing/portbase/database/iterator"
|
"github.com/Safing/portbase/database/iterator"
|
||||||
"github.com/Safing/portbase/database/record"
|
|
||||||
"github.com/Safing/portbase/database/query"
|
"github.com/Safing/portbase/database/query"
|
||||||
|
"github.com/Safing/portbase/database/record"
|
||||||
"github.com/Safing/portbase/database/storage"
|
"github.com/Safing/portbase/database/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -85,7 +84,7 @@ func (b *Badger) Get(key string) (record.Record, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
m, err := model.NewRawWrapper(b.name, string(item.Key()), data)
|
m, err := record.NewRawWrapper(b.name, string(item.Key()), data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -100,12 +99,7 @@ func (b *Badger) Put(m record.Record) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
err = b.db.Update(func(txn *badger.Txn) error {
|
err = b.db.Update(func(txn *badger.Txn) error {
|
||||||
if m.Meta().GetAbsoluteExpiry() > 0 {
|
return txn.Set([]byte(m.DatabaseKey()), data)
|
||||||
txn.SetWithTTL([]byte(m.DatabaseKey()), data, time.Duration(m.Meta().GetRelativeExpiry()))
|
|
||||||
} else {
|
|
||||||
txn.Set([]byte(m.DatabaseKey()), data)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -126,6 +120,11 @@ func (b *Badger) Query(q *query.Query) (*iterator.Iterator, error) {
|
||||||
return nil, errors.New("query not implemented by badger")
|
return nil, errors.New("query not implemented by badger")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ReadOnly returns whether the database is read only.
|
||||||
|
func (b *Badger) ReadOnly() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// Maintain runs a light maintenance operation on the database.
|
// Maintain runs a light maintenance operation on the database.
|
||||||
func (b *Badger) Maintain() error {
|
func (b *Badger) Maintain() error {
|
||||||
b.db.RunValueLogGC(0.7)
|
b.db.RunValueLogGC(0.7)
|
||||||
|
|
|
@ -13,6 +13,7 @@ type Interface interface {
|
||||||
Delete(key string) error
|
Delete(key string) error
|
||||||
Query(q *query.Query) (*iterator.Iterator, error)
|
Query(q *query.Query) (*iterator.Iterator, error)
|
||||||
|
|
||||||
|
ReadOnly() bool
|
||||||
Maintain() error
|
Maintain() error
|
||||||
MaintainThorough() error
|
MaintainThorough() error
|
||||||
Shutdown() error
|
Shutdown() error
|
||||||
|
|
|
@ -4,8 +4,8 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/Safing/portbase/database/iterator"
|
"github.com/Safing/portbase/database/iterator"
|
||||||
"github.com/Safing/portbase/database/record"
|
|
||||||
"github.com/Safing/portbase/database/query"
|
"github.com/Safing/portbase/database/query"
|
||||||
|
"github.com/Safing/portbase/database/record"
|
||||||
"github.com/Safing/portbase/database/storage"
|
"github.com/Safing/portbase/database/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -50,6 +50,11 @@ func (s *Sinkhole) Query(q *query.Query) (*iterator.Iterator, error) {
|
||||||
return nil, errors.New("query not implemented by sinkhole")
|
return nil, errors.New("query not implemented by sinkhole")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ReadOnly returns whether the database is read only.
|
||||||
|
func (s *Sinkhole) ReadOnly() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// Maintain runs a light maintenance operation on the database.
|
// Maintain runs a light maintenance operation on the database.
|
||||||
func (s *Sinkhole) Maintain() error {
|
func (s *Sinkhole) Maintain() error {
|
||||||
return nil
|
return nil
|
||||||
|
|
Loading…
Add table
Reference in a new issue