split db and bolt to store interface
This commit is contained in:
parent
07ff5ccffb
commit
7e77fd7d27
14 changed files with 419 additions and 545 deletions
74
pkg/store/boltstore.go
Normal file
74
pkg/store/boltstore.go
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
package store
|
||||
|
||||
import (
|
||||
"github.com/boltdb/bolt"
|
||||
)
|
||||
|
||||
const defaultBoltBucket = "default"
|
||||
|
||||
type BoltStore struct {
|
||||
Marshaler
|
||||
db *bolt.DB
|
||||
}
|
||||
|
||||
func NewBoltStore(file string, m Marshaler) (bs *BoltStore, err error) {
|
||||
if m == nil {
|
||||
m = NewGOB()
|
||||
}
|
||||
db, err := bolt.Open(file, 0666, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if err = db.Update(func(tx *bolt.Tx) error {
|
||||
if _, err := tx.CreateBucketIfNotExists([]byte(defaultBoltBucket)); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
return
|
||||
}
|
||||
bs = &BoltStore{m, db}
|
||||
return
|
||||
}
|
||||
|
||||
func (bs *BoltStore) Get(key string, v interface{}) (err error) {
|
||||
err = bs.db.View(func(tx *bolt.Tx) error {
|
||||
b := tx.Bucket([]byte(defaultBoltBucket)).Get([]byte(key))
|
||||
if b == nil {
|
||||
return ErrKeyNotFound
|
||||
}
|
||||
if v != nil {
|
||||
return bs.Unmarshal(b, v)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func (bs *BoltStore) Set(key string, v interface{}) error {
|
||||
return bs.db.Update(func(tx *bolt.Tx) error {
|
||||
b, err := bs.Marshal(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return tx.Bucket([]byte(defaultBoltBucket)).Put([]byte(key), b)
|
||||
})
|
||||
}
|
||||
|
||||
func (bs *BoltStore) ForEach(f func(string, []byte) error) error {
|
||||
return bs.db.View(func(tx *bolt.Tx) error {
|
||||
return tx.Bucket([]byte(defaultBoltBucket)).ForEach(func(k, v []byte) error {
|
||||
return f(string(k), v)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func (bs *BoltStore) Delete(key string) error {
|
||||
return bs.db.Update(func(tx *bolt.Tx) error {
|
||||
return tx.Bucket([]byte(defaultBoltBucket)).Delete([]byte(key))
|
||||
})
|
||||
}
|
||||
|
||||
func (bs *BoltStore) Close() error {
|
||||
return bs.db.Close()
|
||||
}
|
||||
100
pkg/store/dump.go
Normal file
100
pkg/store/dump.go
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
// Copyright (C) 2018 Marius Schellenberger
|
||||
|
||||
package store
|
||||
|
||||
/*import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
type Dumper interface {
|
||||
Dump(io.Writer) error
|
||||
}
|
||||
|
||||
type Restorer interface {
|
||||
Restore(io.Reader) error
|
||||
}
|
||||
|
||||
type DBDump struct {
|
||||
Pages []DumpPage `json:"pages"`
|
||||
Snippets []Snippet `json:"snippets"`
|
||||
Users []User `json:"users"`
|
||||
}
|
||||
|
||||
type DumpPage struct {
|
||||
Title string `json:"title"`
|
||||
LinkTitle string `json:"link_title"`
|
||||
MD string `json:"md"`
|
||||
Created string `json:"created"`
|
||||
Updated string `json:"updated"`
|
||||
Public bool `json:"public"`
|
||||
}
|
||||
|
||||
func verboseLog(prefix, title string, v bool) {
|
||||
if v {
|
||||
fmt.Fprintln(os.Stderr, prefix, title)
|
||||
}
|
||||
}
|
||||
|
||||
func Dump(path string, v bool) (err error) {
|
||||
bs, err := NewBoltStore()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var dump DBDump
|
||||
//TODO bs.GetAllPages
|
||||
var pages []*core.Page
|
||||
for _, p := range pages {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
verboseLog("dump:", p.Title, v)
|
||||
dump.Pages = append(dump.Pages, DumpPage{
|
||||
Title: p.Title,
|
||||
LinkTitle: p.LinkTitle,
|
||||
MD: p.MD,
|
||||
Created: p.Created,
|
||||
Updated: p.Updated,
|
||||
Public: p.Public,
|
||||
})
|
||||
}
|
||||
//TODO snippets
|
||||
//verboseLog("dump:", "snippets", v)
|
||||
verboseLog("dump:", "users", v)
|
||||
dump.Users, err = bs.DumpUsers()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return json.NewEncoder(os.Stdout).Encode(dump)
|
||||
}
|
||||
|
||||
func Restore(path string, v bool) (err error) {
|
||||
i, err := NewIndex(path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer i.Close()
|
||||
bs, err := NewBoltStore()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var dump DBDump
|
||||
err = json.NewDecoder(os.Stdin).Decode(&dump)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, art := range dump.Articles {
|
||||
verboseLog("restore:", art.Title, v)
|
||||
err = i.Restore(&art)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
//TODO snippets
|
||||
//verboseLog("restore:", "snippets", v)
|
||||
verboseLog("restore:", "users", v)
|
||||
err = bs.RestoreUsers(dump.Users)
|
||||
return
|
||||
}*/
|
||||
28
pkg/store/marshal.go
Normal file
28
pkg/store/marshal.go
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
package store
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/gob"
|
||||
)
|
||||
|
||||
type Marshaler interface {
|
||||
Marshal(v interface{}) ([]byte, error)
|
||||
Unmarshal(data []byte, v interface{}) error
|
||||
}
|
||||
|
||||
type gobMarshaler struct{}
|
||||
|
||||
func NewGOB() Marshaler {
|
||||
return gobMarshaler{}
|
||||
}
|
||||
|
||||
func (gobMarshaler) Marshal(v interface{}) (b []byte, err error) {
|
||||
buf := new(bytes.Buffer)
|
||||
err = gob.NewEncoder(buf).Encode(v)
|
||||
b = buf.Bytes()
|
||||
return
|
||||
}
|
||||
|
||||
func (gobMarshaler) Unmarshal(data []byte, v interface{}) error {
|
||||
return gob.NewDecoder(bytes.NewBuffer(data)).Decode(v)
|
||||
}
|
||||
37
pkg/store/store.go
Normal file
37
pkg/store/store.go
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
// Copyright (C) 2018 Marius Schellenberger
|
||||
|
||||
package store
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
//const (
|
||||
// dbFile = "gowiki.db"
|
||||
// defUser = "admin"
|
||||
// defPassword = "gowiki"
|
||||
// userTable = "user"
|
||||
// pageTable = "page"
|
||||
// snippetTable = "snippet"
|
||||
// bcryptCost = 13
|
||||
// indexName = "Index"
|
||||
// welcome = `# Welcome to GoWiki
|
||||
//This is the [Index](/wiki/Index) page.
|
||||
//You can customize it how you like.`
|
||||
// wikiSection = "wiki"
|
||||
//)
|
||||
|
||||
func storeErr(i interface{}) error {
|
||||
return fmt.Errorf("store: %s", i)
|
||||
}
|
||||
|
||||
var ErrKeyNotFound = storeErr("key not found")
|
||||
|
||||
type Store interface {
|
||||
Marshaler
|
||||
Get(string, interface{}) error
|
||||
Set(string, interface{}) error
|
||||
ForEach(func(string, []byte) error) error
|
||||
Delete(string) error
|
||||
Close() error
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue