Work on datbase controller

This commit is contained in:
Daniel 2018-09-07 19:15:40 +02:00
parent 818cb332b4
commit 3d60431376
6 changed files with 77 additions and 90 deletions

View file

@ -1,6 +1,7 @@
package database
import (
"errors"
"sync"
"time"
@ -35,6 +36,9 @@ func (c *Controller) Get(key string) (record.Record, error) {
return nil, err
}
r.Lock()
defer r.Unlock()
if !r.Meta().CheckValidity(time.Now().Unix()) {
return nil, ErrNotFound
}
@ -44,14 +48,27 @@ func (c *Controller) Get(key string) (record.Record, error) {
// Put saves a record in the database.
func (c *Controller) Put(r record.Record) error {
if c.storage.ReadOnly() {
return ErrReadOnly
}
return c.storage.Put(r)
}
// Delete a record from the database.
func (c *Controller) Delete(key string) error {
if c.storage.ReadOnly() {
return ErrReadOnly
}
r, err := c.Get(key)
if err != nil {
return err
}
r.Lock()
defer r.Unlock()
r.Meta().Deleted = time.Now().Unix()
return c.Put(r)
}
@ -59,10 +76,36 @@ func (c *Controller) Delete(key string) error {
// Partial
// 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 {
if c.storage.ReadOnly() {
return ErrReadOnly
}
return nil
}
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
}
@ -73,17 +116,33 @@ func (c *Controller) Query(q *query.Query, local, internal bool) (*iterator.Iter
// Meta
func (c *Controller) SetAbsoluteExpiry(key string, time int64) error {
if c.storage.ReadOnly() {
return ErrReadOnly
}
return nil
}
func (c *Controller) SetRelativateExpiry(key string, duration int64) error {
if c.storage.ReadOnly() {
return ErrReadOnly
}
return nil
}
func (c *Controller) MakeCrownJewel(key string) error {
if c.storage.ReadOnly() {
return ErrReadOnly
}
return nil
}
func (c *Controller) MakeSecret(key string) error {
if c.storage.ReadOnly() {
return ErrReadOnly
}
return nil
}

View file

@ -8,8 +8,9 @@ import (
// Errors
var (
ErrNotFound = errors.New("database: entry could not be found")
ErrPermissionDenied = errors.New("database: access to record denied")
ErrNotFound = errors.New("database entry could not be found")
ErrPermissionDenied = errors.New("access to database record denied")
ErrReadOnly = errors.New("database is read only")
)
func init() {

View file

@ -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()
}

View file

@ -2,13 +2,12 @@ package badger
import (
"errors"
"time"
"github.com/dgraph-io/badger"
"github.com/Safing/portbase/database/iterator"
"github.com/Safing/portbase/database/record"
"github.com/Safing/portbase/database/query"
"github.com/Safing/portbase/database/record"
"github.com/Safing/portbase/database/storage"
)
@ -85,7 +84,7 @@ func (b *Badger) Get(key string) (record.Record, error) {
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 {
return nil, err
}
@ -100,12 +99,7 @@ func (b *Badger) Put(m record.Record) error {
}
err = b.db.Update(func(txn *badger.Txn) error {
if m.Meta().GetAbsoluteExpiry() > 0 {
txn.SetWithTTL([]byte(m.DatabaseKey()), data, time.Duration(m.Meta().GetRelativeExpiry()))
} else {
txn.Set([]byte(m.DatabaseKey()), data)
}
return nil
return txn.Set([]byte(m.DatabaseKey()), data)
})
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")
}
// ReadOnly returns whether the database is read only.
func (b *Badger) ReadOnly() bool {
return false
}
// Maintain runs a light maintenance operation on the database.
func (b *Badger) Maintain() error {
b.db.RunValueLogGC(0.7)

View file

@ -13,6 +13,7 @@ type Interface interface {
Delete(key string) error
Query(q *query.Query) (*iterator.Iterator, error)
ReadOnly() bool
Maintain() error
MaintainThorough() error
Shutdown() error

View file

@ -4,8 +4,8 @@ import (
"errors"
"github.com/Safing/portbase/database/iterator"
"github.com/Safing/portbase/database/record"
"github.com/Safing/portbase/database/query"
"github.com/Safing/portbase/database/record"
"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")
}
// ReadOnly returns whether the database is read only.
func (s *Sinkhole) ReadOnly() bool {
return false
}
// Maintain runs a light maintenance operation on the database.
func (s *Sinkhole) Maintain() error {
return nil