mirror of
https://github.com/safing/portbase
synced 2025-09-01 18:19:57 +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
|
||||
|
||||
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
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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 (
|
||||
"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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue