add yaml
parent
bc8a0d82df
commit
44ce475100
2
db.go
2
db.go
|
|
@ -42,6 +42,8 @@ func New(key Type, params ...string) (db DB, err error) {
|
||||||
db, err = rclone.NewRClone(params[0], params[1])
|
db, err = rclone.NewRClone(params[0], params[1])
|
||||||
case FILES:
|
case FILES:
|
||||||
db, err = NewFiles(params[0])
|
db, err = NewFiles(params[0])
|
||||||
|
case YAML:
|
||||||
|
db, err = NewYaml(params[0])
|
||||||
case BOLT:
|
case BOLT:
|
||||||
db, err = NewBolt(params[0])
|
db, err = NewBolt(params[0])
|
||||||
case MINIO:
|
case MINIO:
|
||||||
|
|
|
||||||
12
db_test.go
12
db_test.go
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
@ -198,19 +199,20 @@ type = local
|
||||||
for _, db := range cases {
|
for _, db := range cases {
|
||||||
t.Run(fmt.Sprintf("%T", db), func(t *testing.T) {
|
t.Run(fmt.Sprintf("%T", db), func(t *testing.T) {
|
||||||
log.Printf("Trying %T", db)
|
log.Printf("Trying %T", db)
|
||||||
t.Logf(" %T: set", db)
|
t.Logf(" %T: list @[ns1, ns2] against empty", db)
|
||||||
if keys, err := db.List([]string{"ns1", "ns2"}); err != nil || len(keys) > 0 {
|
if keys, err := db.List([]string{"ns1", "ns2"}); err != nil || len(keys) > 0 {
|
||||||
t.Errorf("%T) cannot List() empty: (%T) %+v: %v", db, err, err, keys)
|
t.Errorf("%T) cannot List() empty: (%T) %+v: %v", db, err, err, keys)
|
||||||
}
|
}
|
||||||
if keys, err := db.List([]string{path.Join("ns1", "ns2")}); err != nil || len(keys) > 0 {
|
t.Logf(" %T: set %s @[ns1, ns2]", db, validKey)
|
||||||
t.Errorf("%T) cannot List() empty w/ /: (%T) %+v: %v", db, err, err, keys)
|
|
||||||
}
|
|
||||||
if err := db.Set(validKey, validValue, "ns1", "ns2"); err != nil {
|
if err := db.Set(validKey, validValue, "ns1", "ns2"); err != nil {
|
||||||
t.Errorf("%T) cannot set: %v", db, err)
|
t.Errorf("%T) cannot set: %v", db, err)
|
||||||
}
|
}
|
||||||
t.Logf(" %T: get", db)
|
t.Logf(" %T: db: %+v", db, db)
|
||||||
|
t.Logf(" %T: get %s @[ns1, ns2]", db, validKey)
|
||||||
if v, err := db.Get(validKey, "ns1", "ns2"); err != nil {
|
if v, err := db.Get(validKey, "ns1", "ns2"); err != nil {
|
||||||
t.Errorf("%T) cannot get: %v", db, err)
|
t.Errorf("%T) cannot get: %v", db, err)
|
||||||
|
log.Printf("%T) cannot get: %v (%+v)", db, err, db)
|
||||||
|
time.Sleep(time.Second * 10)
|
||||||
} else if !bytes.Equal(v, validValue) {
|
} else if !bytes.Equal(v, validValue) {
|
||||||
t.Errorf("%T) wrong get: %q vs %q", db, v, validValue)
|
t.Errorf("%T) wrong get: %q vs %q", db, v, validValue)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
3
type.go
3
type.go
|
|
@ -21,6 +21,7 @@ const (
|
||||||
MINIO = Type(iota)
|
MINIO = Type(iota)
|
||||||
RCLONE = Type(iota)
|
RCLONE = Type(iota)
|
||||||
MAPSTREAM = Type(iota)
|
MAPSTREAM = Type(iota)
|
||||||
|
YAML = Type(iota)
|
||||||
)
|
)
|
||||||
|
|
||||||
func (t Type) String() string {
|
func (t Type) String() string {
|
||||||
|
|
@ -37,6 +38,8 @@ func (t Type) String() string {
|
||||||
return "rclone"
|
return "rclone"
|
||||||
case COCKROACH:
|
case COCKROACH:
|
||||||
return "cockroach"
|
return "cockroach"
|
||||||
|
case YAML:
|
||||||
|
return "yaml"
|
||||||
case FILES:
|
case FILES:
|
||||||
return "files"
|
return "files"
|
||||||
case BOLT:
|
case BOLT:
|
||||||
|
|
|
||||||
132
yaml.go
132
yaml.go
|
|
@ -2,9 +2,12 @@ package storage
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/base64"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"local/storage/resolve"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
@ -43,7 +46,19 @@ func (y *Yaml) Namespaces() ([][]string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (y *Yaml) List(ns []string, limits ...string) ([]string, error) {
|
func (y *Yaml) List(ns []string, limits ...string) ([]string, error) {
|
||||||
return nil, errors.New("not impl")
|
namespace := resolve.Namespace(ns)
|
||||||
|
m, err := y.getMap(namespace)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
limits = resolve.Limits(limits)
|
||||||
|
ks := make([]string, 0, len(m))
|
||||||
|
for k := range m {
|
||||||
|
if k >= limits[0] && k <= limits[1] {
|
||||||
|
ks = append(ks, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ks, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (y *Yaml) Get(key string, ns ...string) ([]byte, error) {
|
func (y *Yaml) Get(key string, ns ...string) ([]byte, error) {
|
||||||
|
|
@ -55,7 +70,21 @@ func (y *Yaml) Get(key string, ns ...string) ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (y *Yaml) GetStream(key string, ns ...string) (io.Reader, error) {
|
func (y *Yaml) GetStream(key string, ns ...string) (io.Reader, error) {
|
||||||
return nil, errors.New("not impl")
|
namespace := resolve.Namespace(ns)
|
||||||
|
m, err := y.getMap(namespace)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
v, ok := m[key]
|
||||||
|
if !ok {
|
||||||
|
return nil, ErrNotFound
|
||||||
|
}
|
||||||
|
s, ok := v.(string)
|
||||||
|
if !ok {
|
||||||
|
return nil, ErrNotFound
|
||||||
|
}
|
||||||
|
b, err := base64.StdEncoding.DecodeString(s)
|
||||||
|
return bytes.NewReader(b), err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (y *Yaml) Set(key string, value []byte, ns ...string) error {
|
func (y *Yaml) Set(key string, value []byte, ns ...string) error {
|
||||||
|
|
@ -67,30 +96,98 @@ func (y *Yaml) Set(key string, value []byte, ns ...string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (y *Yaml) Del(key string, ns ...string) error {
|
func (y *Yaml) Del(key string, ns ...string) error {
|
||||||
return errors.New("not impl")
|
return y.SetStream(key, nil, ns...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (y *Yaml) SetStream(key string, r io.Reader, ns ...string) error {
|
func (y *Yaml) SetStream(key string, r io.Reader, ns ...string) error {
|
||||||
return errors.New("not impl")
|
namespace := resolve.Namespace(ns)
|
||||||
|
var v interface{} = nil
|
||||||
|
if r != nil {
|
||||||
|
b, err := ioutil.ReadAll(r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v = base64.StdEncoding.EncodeToString(b)
|
||||||
|
}
|
||||||
|
m, err := y.getMap()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := setInMap(m, []string{namespace}, key, v); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return y.setMap(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (y *Yaml) Close() error {
|
func (y *Yaml) Close() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (y *Yaml) getMap() (map[string]interface{}, error) {
|
func (y *Yaml) getMap(keys ...string) (map[string]interface{}, error) {
|
||||||
b, err := y.get()
|
b, err := y.get()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var m map[string]interface{}
|
var mBad map[interface{}]interface{}
|
||||||
err = yaml.Unmarshal(b, &m)
|
if err := yaml.Unmarshal(b, &mBad); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
m, err := mbadToM(mBad)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if m == nil {
|
||||||
|
m = map[string]interface{}{}
|
||||||
|
}
|
||||||
|
for _, k := range keys {
|
||||||
|
subv, ok := m[k]
|
||||||
|
if !ok {
|
||||||
|
subv = map[string]interface{}{}
|
||||||
|
m[k] = subv
|
||||||
|
}
|
||||||
|
subm, ok := subv.(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
return nil, ErrNotFound
|
||||||
|
}
|
||||||
|
m = subm
|
||||||
|
}
|
||||||
return m, err
|
return m, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (y *Yaml) setMap(m map[string]interface{}) error {
|
||||||
|
b, err := yaml.Marshal(m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return y.set(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func setInMap(m map[string]interface{}, keys []string, key string, v interface{}) error {
|
||||||
|
if len(keys) == 0 {
|
||||||
|
m[key] = v
|
||||||
|
if v == nil {
|
||||||
|
delete(m, key)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
subv, ok := m[keys[0]]
|
||||||
|
if !ok {
|
||||||
|
subv = map[string]interface{}{}
|
||||||
|
}
|
||||||
|
subm, ok := subv.(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
return errors.New("clobber")
|
||||||
|
}
|
||||||
|
if err := setInMap(subm, keys[1:], key, v); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
m[keys[0]] = subm
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (y *Yaml) get() ([]byte, error) {
|
func (y *Yaml) get() ([]byte, error) {
|
||||||
b, err := ioutil.ReadFile(y.path)
|
b, err := ioutil.ReadFile(y.path)
|
||||||
if err == os.ErrNotExist {
|
if os.IsNotExist(err) {
|
||||||
return []byte{}, nil
|
return []byte{}, nil
|
||||||
}
|
}
|
||||||
return b, err
|
return b, err
|
||||||
|
|
@ -127,3 +224,22 @@ func _keysDFS(m map[string]interface{}) ([][]string, bool, error) {
|
||||||
}
|
}
|
||||||
return keys, hasNonMaps, nil
|
return keys, hasNonMaps, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func mbadToM(mBad map[interface{}]interface{}) (map[string]interface{}, error) {
|
||||||
|
m := map[string]interface{}{}
|
||||||
|
for k, v := range mBad {
|
||||||
|
s, ok := k.(string)
|
||||||
|
if !ok {
|
||||||
|
s = fmt.Sprint(k)
|
||||||
|
}
|
||||||
|
m[s] = v
|
||||||
|
if m2, ok := v.(map[interface{}]interface{}); ok {
|
||||||
|
v2, err := mbadToM(m2)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
m[s] = v2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
11
yaml_test.go
11
yaml_test.go
|
|
@ -43,6 +43,17 @@ func TestKeysDFS(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
for j := range c.want {
|
||||||
|
found := false
|
||||||
|
for i := range got {
|
||||||
|
if fmt.Sprint(got[i]) == fmt.Sprint(c.want[j]) {
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
t.Errorf("want %+v among %+v", c.want[j], got)
|
||||||
|
}
|
||||||
|
}
|
||||||
if fmt.Sprintf("%+v", got) != fmt.Sprintf("%+v", c.want) {
|
if fmt.Sprintf("%+v", got) != fmt.Sprintf("%+v", c.want) {
|
||||||
t.Fatalf("want: %+v\ngot: %+v", c.want, got)
|
t.Fatalf("want: %+v\ngot: %+v", c.want, got)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue