Skip to content

Instantly share code, notes, and snippets.

@umisama
Created December 18, 2015 12:46
Show Gist options
  • Save umisama/c6179c2296ce90bc5faa to your computer and use it in GitHub Desktop.
Save umisama/c6179c2296ce90bc5faa to your computer and use it in GitHub Desktop.
document database prototype
package docdb
import (
"bytes"
"encoding/json"
"fmt"
"github.com/syndtr/goleveldb/leveldb"
"github.com/syndtr/goleveldb/leveldb/util"
"reflect"
"strconv"
)
type Bucket struct {
parent *DB
name []byte
}
func (b *Bucket) Store(doc []byte) error {
val := map[string]interface{}{}
err := json.Unmarshal(doc, &val)
if err != nil {
return fmt.Errorf("invalid document type")
}
idval, ok := val["id"]
if !ok {
return fmt.Errorf("property 'id' is not found")
}
id, err := b.generateLevelDbID(idval)
if err != nil {
return err
}
err = b.parent.db.Put(id, doc, nil)
if err != nil {
return err
}
return nil
}
func (b *Bucket) getByStringID(id interface{}) ([]byte, error) {
lid, err := b.generateLevelDbID(id)
if err != nil {
return nil, err
}
dat, err := b.parent.db.Get(lid, nil)
if err != nil {
return nil, err
}
return dat, nil
}
func (b *Bucket) GetByQuery(query []byte) ([]byte, error) {
it := b.parent.db.NewIterator(util.BytesPrefix(b.name), nil)
defer it.Release()
queryobj := map[string]interface{}{}
err := json.Unmarshal(query, &queryobj)
if err != nil {
return nil, err
}
dbiterator:
for it.Next() {
obj := map[string]interface{}{}
err = json.Unmarshal(it.Value(), &obj)
if err != nil {
continue
}
for qk, qv := range queryobj {
if v, ok := obj[qk]; ok {
if !reflect.DeepEqual(qv, v) {
continue dbiterator
}
}
return it.Value(), nil
}
return nil, nil
}
func (b *Bucket) generateLevelDbID(id interface{}) ([]byte, error) {
idstr := ""
switch t := id.(type) {
case int:
idstr = strconv.Itoa(t)
case string:
idstr = t
default:
return nil, fmt.Errorf("invalid ID type")
}
return bytes.Join([][]byte{b.name, {0x2d}, []byte(idstr)}, nil), nil
}
type DB struct {
db *leveldb.DB
}
func OpenDB(path string, writable bool) (*DB, error) {
bdb, err := leveldb.OpenFile(path, nil)
if err != nil {
return nil, err
}
if !writable {
err = bdb.SetReadOnly()
if err != nil {
return nil, err
}
}
return &DB{
db: bdb,
}, nil
}
func (db *DB) GetBucket(name string) *Bucket {
return &Bucket{
parent: db,
name: []byte(name),
}
}
func (db *DB) CreateBucket(name string) (*Bucket, error) {
return &Bucket{}, nil
}
func (db *DB) Close() error {
return db.db.Close()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment