mirror of
https://github.com/safing/portbase
synced 2025-09-01 10:09:50 +00:00
Add GetMeta to database storage interface
This commit is contained in:
parent
3f3786b854
commit
0061572e1b
11 changed files with 170 additions and 32 deletions
|
@ -42,7 +42,7 @@ func (c *Controller) Injected() bool {
|
|||
return c.storage.Injected()
|
||||
}
|
||||
|
||||
// Get return the record with the given key.
|
||||
// Get returns the record with the given key.
|
||||
func (c *Controller) Get(key string) (record.Record, error) {
|
||||
if shuttingDown.IsSet() {
|
||||
return nil, ErrShuttingDown
|
||||
|
@ -76,6 +76,28 @@ func (c *Controller) Get(key string) (record.Record, error) {
|
|||
return r, nil
|
||||
}
|
||||
|
||||
// Get returns the metadata of the record with the given key.
|
||||
func (c *Controller) GetMeta(key string) (*record.Meta, error) {
|
||||
if shuttingDown.IsSet() {
|
||||
return nil, ErrShuttingDown
|
||||
}
|
||||
|
||||
m, err := c.storage.GetMeta(key)
|
||||
if err != nil {
|
||||
// replace not found error
|
||||
if err == storage.ErrNotFound {
|
||||
return nil, ErrNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !m.CheckValidity() {
|
||||
return nil, ErrNotFound
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// Put saves a record in the database, executes any registered
|
||||
// pre-put hooks and finally send an update to all subscribers.
|
||||
// The record must be locked and secured from concurrent access
|
||||
|
|
|
@ -201,6 +201,40 @@ func (i *Interface) getRecord(dbName string, dbKey string, mustBeWriteable bool)
|
|||
return r, db, nil
|
||||
}
|
||||
|
||||
func (i *Interface) getMeta(dbName string, dbKey string, mustBeWriteable bool) (m *record.Meta, db *Controller, err error) {
|
||||
if dbName == "" {
|
||||
dbName, dbKey = record.ParseKey(dbKey)
|
||||
}
|
||||
|
||||
db, err = getController(dbName)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if mustBeWriteable && db.ReadOnly() {
|
||||
return nil, db, ErrReadOnly
|
||||
}
|
||||
|
||||
r := i.checkCache(dbName + ":" + dbKey)
|
||||
if r != nil {
|
||||
if !i.options.hasAccessPermission(r) {
|
||||
return nil, db, ErrPermissionDenied
|
||||
}
|
||||
return r.Meta(), db, nil
|
||||
}
|
||||
|
||||
m, err = db.GetMeta(dbKey)
|
||||
if err != nil {
|
||||
return nil, db, err
|
||||
}
|
||||
|
||||
if !m.CheckPermission(i.options.Local, i.options.Internal) {
|
||||
return nil, db, ErrPermissionDenied
|
||||
}
|
||||
|
||||
return m, db, nil
|
||||
}
|
||||
|
||||
// InsertValue inserts a value into a record.
|
||||
func (i *Interface) InsertValue(key string, attribute string, value interface{}) error {
|
||||
r, db, err := i.getRecord(getDBFromKey, key, true)
|
||||
|
@ -236,7 +270,7 @@ func (i *Interface) Put(r record.Record) (err error) {
|
|||
// get record or only database
|
||||
var db *Controller
|
||||
if !i.options.HasAllPermissions() {
|
||||
_, db, err = i.getRecord(r.DatabaseName(), r.DatabaseKey(), true)
|
||||
_, db, err = i.getMeta(r.DatabaseName(), r.DatabaseKey(), true)
|
||||
if err != nil && err != ErrNotFound {
|
||||
return err
|
||||
}
|
||||
|
@ -247,7 +281,7 @@ func (i *Interface) Put(r record.Record) (err error) {
|
|||
}
|
||||
}
|
||||
|
||||
// Check if database is read only before we add to the cache.
|
||||
// Check if database is read only.
|
||||
if db.ReadOnly() {
|
||||
return ErrReadOnly
|
||||
}
|
||||
|
@ -274,7 +308,7 @@ func (i *Interface) PutNew(r record.Record) (err error) {
|
|||
// get record or only database
|
||||
var db *Controller
|
||||
if !i.options.HasAllPermissions() {
|
||||
_, db, err = i.getRecord(r.DatabaseName(), r.DatabaseKey(), true)
|
||||
_, db, err = i.getMeta(r.DatabaseName(), r.DatabaseKey(), true)
|
||||
if err != nil && err != ErrNotFound {
|
||||
return err
|
||||
}
|
||||
|
@ -285,6 +319,11 @@ func (i *Interface) PutNew(r record.Record) (err error) {
|
|||
}
|
||||
}
|
||||
|
||||
// Check if database is read only.
|
||||
if db.ReadOnly() {
|
||||
return ErrReadOnly
|
||||
}
|
||||
|
||||
r.Lock()
|
||||
if r.Meta() != nil {
|
||||
r.Meta().Reset()
|
||||
|
@ -328,6 +367,13 @@ func (i *Interface) PutMany(dbName string) (put func(record.Record) error) {
|
|||
}
|
||||
}
|
||||
|
||||
// Check if database is read only.
|
||||
if db.ReadOnly() {
|
||||
return func(r record.Record) error {
|
||||
return ErrReadOnly
|
||||
}
|
||||
}
|
||||
|
||||
// start database access
|
||||
dbBatch, errs := db.PutMany()
|
||||
finished := abool.New()
|
||||
|
@ -462,6 +508,11 @@ func (i *Interface) Delete(key string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// Check if database is read only.
|
||||
if db.ReadOnly() {
|
||||
return ErrReadOnly
|
||||
}
|
||||
|
||||
i.options.Apply(r)
|
||||
r.Meta().Delete()
|
||||
return db.Put(r)
|
||||
|
@ -495,6 +546,11 @@ func (i *Interface) Purge(ctx context.Context, q *query.Query) (int, error) {
|
|||
return 0, err
|
||||
}
|
||||
|
||||
// Check if database is read only before we add to the cache.
|
||||
if db.ReadOnly() {
|
||||
return 0, ErrReadOnly
|
||||
}
|
||||
|
||||
return db.Purge(ctx, q, i.options.Local, i.options.Internal)
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ Please note that some feeders may have other special characters. It is advised t
|
|||
## Operators
|
||||
|
||||
| Name | Textual | Req. Type | Internal Type | Compared with |
|
||||
|---|---|---|---|
|
||||
|-------------------------|--------------------|-----------|---------------|---------------------------|
|
||||
| Equals | `==` | int | int64 | `==` |
|
||||
| GreaterThan | `>` | int | int64 | `>` |
|
||||
| GreaterThanOrEqual | `>=` | int | int64 | `>=` |
|
||||
|
@ -38,11 +38,11 @@ Please note that some feeders may have other special characters. It is advised t
|
|||
| StartsWith | `startswith`, `sw` | string | string | `strings.HasPrefix()` |
|
||||
| EndsWith | `endswith`, `ew` | string | string | `strings.HasSuffix()` |
|
||||
| In | `in` | string | string | for loop with `==` |
|
||||
| Matches | `matches`, `re` | string | int64 | `regexp.Regexp.Matches()` |
|
||||
| Matches | `matches`, `re` | string | string | `regexp.Regexp.Matches()` |
|
||||
| Is | `is` | bool* | bool | `==` |
|
||||
| Exists | `exists`, `ex` | any | n/a | n/a |
|
||||
|
||||
\*accepts strings: 1, t, T, TRUE, true, True, 0, f, F, FALSE
|
||||
\*accepts strings: 1, t, T, true, True, TRUE, 0, f, F, false, False, FALSE
|
||||
|
||||
## Escaping
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ var (
|
|||
registry = make(map[string]*Database)
|
||||
registryLock sync.Mutex
|
||||
|
||||
nameConstraint = regexp.MustCompile("^[A-Za-z0-9_-]{4,}$")
|
||||
nameConstraint = regexp.MustCompile("^[A-Za-z0-9_-]{3,}$")
|
||||
)
|
||||
|
||||
// Register registers a new database.
|
||||
|
@ -56,7 +56,7 @@ func Register(new *Database) (*Database, error) {
|
|||
} else {
|
||||
// register new database
|
||||
if !nameConstraint.MatchString(new.Name) {
|
||||
return nil, errors.New("database name must only contain alphanumeric and `_-` characters and must be at least 4 characters long")
|
||||
return nil, errors.New("database name must only contain alphanumeric and `_-` characters and must be at least 3 characters long")
|
||||
}
|
||||
|
||||
now := time.Now().Round(time.Second)
|
||||
|
|
|
@ -82,6 +82,18 @@ func (b *Badger) Get(key string) (record.Record, error) {
|
|||
return m, nil
|
||||
}
|
||||
|
||||
// GetMeta returns the metadata of a database record.
|
||||
func (b *Badger) GetMeta(key string) (*record.Meta, error) {
|
||||
// TODO: Replace with more performant variant.
|
||||
|
||||
r, err := b.Get(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return r.Meta(), nil
|
||||
}
|
||||
|
||||
// Put stores a record in the database.
|
||||
func (b *Badger) Put(r record.Record) (record.Record, error) {
|
||||
data, err := r.MarshalRecord(r)
|
||||
|
|
|
@ -96,6 +96,18 @@ func (b *BBolt) Get(key string) (record.Record, error) {
|
|||
return r, nil
|
||||
}
|
||||
|
||||
// GetMeta returns the metadata of a database record.
|
||||
func (b *BBolt) GetMeta(key string) (*record.Meta, error) {
|
||||
// TODO: Replace with more performant variant.
|
||||
|
||||
r, err := b.Get(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return r.Meta(), nil
|
||||
}
|
||||
|
||||
// Put stores a record in the database.
|
||||
func (b *BBolt) Put(r record.Record) (record.Record, error) {
|
||||
data, err := r.MarshalRecord(r)
|
||||
|
|
|
@ -104,6 +104,18 @@ func (fst *FSTree) Get(key string) (record.Record, error) {
|
|||
return r, nil
|
||||
}
|
||||
|
||||
// GetMeta returns the metadata of a database record.
|
||||
func (fst *FSTree) GetMeta(key string) (*record.Meta, error) {
|
||||
// TODO: Replace with more performant variant.
|
||||
|
||||
r, err := fst.Get(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return r.Meta(), nil
|
||||
}
|
||||
|
||||
// Put stores a record in the database.
|
||||
func (fst *FSTree) Put(r record.Record) (record.Record, error) {
|
||||
dstPath, err := fst.buildFilePath(r.DatabaseKey(), true)
|
||||
|
|
|
@ -44,6 +44,18 @@ func (hm *HashMap) Get(key string) (record.Record, error) {
|
|||
return r, nil
|
||||
}
|
||||
|
||||
// GetMeta returns the metadata of a database record.
|
||||
func (hm *HashMap) GetMeta(key string) (*record.Meta, error) {
|
||||
// TODO: Replace with more performant variant.
|
||||
|
||||
r, err := hm.Get(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return r.Meta(), nil
|
||||
}
|
||||
|
||||
// Put stores a record in the database.
|
||||
func (hm *HashMap) Put(r record.Record) (record.Record, error) {
|
||||
hm.dbLock.Lock()
|
||||
|
|
|
@ -11,7 +11,8 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
errNotImplemented = errors.New("not implemented")
|
||||
// ErrNotImplemented is returned when a function is not implemented by a storage.
|
||||
ErrNotImplemented = errors.New("not implemented")
|
||||
)
|
||||
|
||||
// InjectBase is a dummy base structure to reduce boilerplate code for injected storage interfaces.
|
||||
|
@ -22,22 +23,27 @@ var _ Interface = &InjectBase{}
|
|||
|
||||
// Get returns a database record.
|
||||
func (i *InjectBase) Get(key string) (record.Record, error) {
|
||||
return nil, errNotImplemented
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
|
||||
// Get returns a database record.
|
||||
func (i *InjectBase) GetMeta(key string) (*record.Meta, error) {
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
|
||||
// Put stores a record in the database.
|
||||
func (i *InjectBase) Put(m record.Record) (record.Record, error) {
|
||||
return nil, errNotImplemented
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
|
||||
// Delete deletes a record from the database.
|
||||
func (i *InjectBase) Delete(key string) error {
|
||||
return errNotImplemented
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
// Query returns a an iterator for the supplied query.
|
||||
func (i *InjectBase) Query(q *query.Query, local, internal bool) (*iterator.Iterator, error) {
|
||||
return nil, errNotImplemented
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
|
||||
// ReadOnly returns whether the database is read only.
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
type Interface interface {
|
||||
// Primary Interface
|
||||
Get(key string) (record.Record, error)
|
||||
GetMeta(key string) (*record.Meta, error)
|
||||
Put(m record.Record) (record.Record, error)
|
||||
Delete(key string) error
|
||||
Query(q *query.Query, local, internal bool) (*iterator.Iterator, error)
|
||||
|
|
|
@ -44,6 +44,11 @@ func (s *Sinkhole) Get(key string) (record.Record, error) {
|
|||
return nil, storage.ErrNotFound
|
||||
}
|
||||
|
||||
// GetMeta returns the metadata of a database record.
|
||||
func (s *Sinkhole) GetMeta(key string) (*record.Meta, error) {
|
||||
return nil, storage.ErrNotFound
|
||||
}
|
||||
|
||||
// Put stores a record in the database.
|
||||
func (s *Sinkhole) Put(r record.Record) (record.Record, error) {
|
||||
return r, nil
|
||||
|
|
Loading…
Add table
Reference in a new issue