Documentation
¶
Overview ¶
Package dockage is an embedded document (json) database.
Index ¶
- Variables
- type DB
- func (db *DB) AddView(v View)
- func (db *DB) Close() error
- func (db *DB) Delete(ids ...string) (reserr error)
- func (db *DB) DeleteView(v string) (reserr error)
- func (db *DB) Get(docs interface{}, firstID string, restID ...string) (reserr error)
- func (db *DB) Put(docs ...interface{}) (reserr error)
- func (db *DB) Query(params Q) (reslist []Res, rescount int, reserr error)
- type Emitter
- type KV
- type Options
- type Q
- type Res
- type View
- type ViewFn
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( ErrNoID = errors.New("no id field in doc json") ErrNoRev = errors.New("no rev field in doc json") ErrInvalidID = fmt.Errorf("id must not contain these characters: %s %s %s %s %s", viewsp, keysp, syssp, viewk2x, viewx2k) ErrNoMatchRev = errors.New("rev field in doc json not matching") )
errors
Functions ¶
This section is empty.
Types ¶
type DB ¶
type DB struct {
// contains filtered or unexported fields
}
DB represents a database instance.
Example (Cas) ¶
// CAS is performed using a mandatory rev field inside json document.
db := createDB()
defer db.Close()
docID := "CMNT::001"
cmnt := &comment{
ID: docID,
By: "Frodo Baggins",
Text: "Hi!",
At: time.Now(),
Tags: []string{"tech", "golang"},
}
fmt.Println(db.Put(cmnt))
var res []comment
err := db.Get(&res, docID)
fmt.Println(err)
*cmnt = res[0]
fmt.Println(cmnt.ID)
fmt.Println(cmnt.By)
fmt.Println(cmnt.Text)
fmt.Println(cmnt.Tags)
fmt.Println(cmnt.Rev)
rev := cmnt.Rev
cmnt.Rev = "dummy"
fmt.Println("error:", db.Put(cmnt))
cmnt.Rev = rev
cmnt.Text = "Back again!"
fmt.Println(db.Put(cmnt))
res = nil
err = db.Get(&res, docID)
fmt.Println(err)
*cmnt = res[0]
fmt.Println(cmnt.ID)
fmt.Println(cmnt.By)
fmt.Println(cmnt.Text)
fmt.Println(cmnt.Tags)
fmt.Println(cmnt.Rev)
Output: <nil> <nil> CMNT::001 Frodo Baggins Hi! [tech golang] 0000000000000000 error: rev field in doc json not matching <nil> <nil> CMNT::001 Frodo Baggins Back again! [tech golang] 0000000000000001
Example (Doc1) ¶
db := createDB()
defer db.Close()
type post struct {
ID string `json:"id"`
Rev string `json:"rev"`
By string `json:"by,omitempty"`
Text string `json:"text,omitempty"`
At time.Time `json:"at,omitempty"`
Tags []string `json:"tags,omitempty"`
}
db.AddView(NewView("tags",
func(em Emitter, id string, doc interface{}) {
c, ok := doc.(*post)
if !ok {
return
}
for _, v := range c.Tags {
em.Emit([]byte(v), nil)
}
return
}))
db.AddView(NewView("time-day",
func(em Emitter, id string, doc interface{}) {
c, ok := doc.(*post)
if !ok {
return
}
em.Emit([]byte(c.At.Format("2006-01-02")), nil)
return
}))
p := &post{
ID: "POST:001",
By: "Frodo Baggins",
Text: "Awesome blog post!",
At: time.Now(),
Tags: []string{"golang", "nosql"},
}
db.Put(p)
var result []post
db.Get(&result, "POST:001")
db.Delete("POST:001")
db.Query(Q{View: "time-day", Start: []byte("2018-05-20"), End: []byte("2018-05-30")})
db.Query(Q{View: "tags", Start: []byte("golang"), Prefix: []byte("golang")})
fmt.Println(p.ID)
Output: POST:001
func (*DB) AddView ¶
AddView adds a view. All views must be added right after Open(...). It is not safe to call this method concurrently.
func (*DB) Delete ¶
Delete a list of documents based on their ids. All documents will be deleted from database in one write transaction.
Example ¶
db := createDB()
defer db.Close()
cmnt := &comment{
ID: "CMNT::001",
By: "Frodo Baggins",
Text: "Hi!",
At: time.Now(),
Tags: []string{"tech", "golang"},
}
fmt.Println(db.Put(cmnt))
fmt.Println(db.Delete("CMNT::001"))
var res []comment
err := db.Get(&res, "CMNT::001")
fmt.Println(err, res)
Output: <nil> <nil> Key not found []
func (*DB) DeleteView ¶ added in v0.2.1
DeleteView deletes the data of a view.
func (*DB) Get ¶ added in v0.2.1
Get a list of documents based on their ids. Param docs is pointer to slice of struct. All documents will be read from database in one read transaction.
Example ¶
db := createDB()
defer db.Close()
var list []interface{}
for i := 1; i <= 3; i++ {
cmnt := comment{
ID: fmt.Sprintf("CMNT::%03d", i),
By: "Frodo Baggins",
Text: "Hi!",
At: time.Now(),
Tags: []string{"tech", "golang"},
}
list = append(list, cmnt)
}
fmt.Println(db.Put(list...))
var res []comment
err := db.Get(&res,
"CMNT::001",
"CMNT::002",
"CMNT::003")
fmt.Println(err)
for _, v := range res {
fmt.Printf("%s %s %s\n", v.ID, v.Text, v.By)
}
Output: <nil> <nil> CMNT::001 Hi! Frodo Baggins CMNT::002 Hi! Frodo Baggins CMNT::003 Hi! Frodo Baggins
func (*DB) Put ¶
Put a list of documents inside database, in a single transaction. Document must have a json field named "id" and a json field named "rev". All documents passed by docs parameter will be inserted into the database in one transaction. Also all views will be computer in the same transaction.
Example ¶
db := createDB()
defer db.Close()
cmnt := comment{
ID: "CMNT::001",
By: "Frodo Baggins",
Text: "Hi!",
At: time.Now(),
Tags: []string{"tech", "golang"},
}
fmt.Println(db.Put(cmnt))
var res []comment
err := db.Get(&res, "CMNT::001")
fmt.Println(err)
cmnt = res[0]
fmt.Println(cmnt.ID)
fmt.Println(cmnt.By)
fmt.Println(cmnt.Text)
fmt.Println(cmnt.Tags)
Output: <nil> <nil> CMNT::001 Frodo Baggins Hi! [tech golang]
func (*DB) Query ¶
Query queries a view using provided parameters. If no View is provided, it searches all ids using parameters. Number of results is always limited - default 100 documents. If total count for a query is needed by setting params.Count to true, no documents will be returned - because it might be a costly action. All documents will be read from database in one read transaction.
type Options ¶
type Options struct {
// 1. Mandatory flags
// -------------------
// Directory to store the data in. Should exist and be writable.
Dir string
// Directory to store the value log in. Can be the same as Dir. Should
// exist and be writable.
ValueDir string
}
Options are params for creating DB object.
type Res ¶ added in v0.2.1
Res represents the result of a Query(...) call. Key is the document key, Index is the calculated index and Val is the calculated value by the view.
type View ¶
type View struct {
// contains filtered or unexported fields
}
View is a calculated, persistent index.
Example ¶
db := createDB()
defer db.Close()
// em Emitter allows to emit our view index into the view, in this case
// the tags of a comment. By emitting tags one by one, it is possible
// to query comments based on their tags.
db.AddView(NewView("tags",
func(em Emitter, id string, doc interface{}) {
c, ok := doc.(*comment)
if !ok {
return
}
for _, v := range c.Tags {
em.Emit([]byte(v), nil)
}
}))
var list []interface{}
for i := 1; i <= 3; i++ {
cmnt := &comment{
ID: fmt.Sprintf("CMNT::%03d", i),
By: "Frodo Baggins",
Text: "Hi!",
At: time.Now(),
Tags: []string{"tech", "golang"},
}
list = append(list, cmnt)
}
fmt.Println(db.Put(list...))
res, _, err := db.Query(Q{View: "tags", Start: []byte("tech")})
fmt.Println(err)
for _, v := range res {
fmt.Printf("%s %s %s\n", v.Key, v.Val, v.Index)
}
Output: <nil> <nil> CMNT::001 tech CMNT::002 tech CMNT::003 tech
Example (ByTime) ¶
db := createDB()
defer db.Close()
db.AddView(NewView("by_time",
func(em Emitter, id string, doc interface{}) {
c, ok := doc.(*comment)
if !ok {
return
}
t := c.At
if t.IsZero() {
return
}
em.Emit([]byte(t.Format("2006-01-02")), nil)
return
}))
at := time.Date(2018, 1, 1, 12, 0, 0, 0, time.Local)
var list []interface{}
for i := 1; i <= 3; i++ {
cmnt := &comment{
ID: fmt.Sprintf("CMNT::%03d", i),
By: "Frodo Baggins",
Text: "Hi!",
At: at,
Tags: []string{"tech", "golang"},
}
list = append(list, cmnt)
at = at.Add(time.Hour * 24)
}
fmt.Println(db.Put(list...))
start := []byte("2018-01-01")
prefix := []byte("2018-01")
res, _, err := db.Query(Q{View: "by_time", Start: start, Prefix: prefix})
fmt.Println(err)
for _, v := range res {
fmt.Printf("%s %s %s\n", v.Key, v.Val, v.Index)
}
Output: <nil> <nil> CMNT::001 2018-01-01 CMNT::002 2018-01-02 CMNT::003 2018-01-03
Example (Count) ¶
db := createDB()
defer db.Close()
db.AddView(NewView("tags",
func(em Emitter, id string, doc interface{}) {
c, ok := doc.(comment)
if !ok {
return
}
for _, v := range c.Tags {
em.Emit([]byte(v), nil)
}
return
}))
var list []interface{}
for i := 1; i <= 3; i++ {
cmnt := comment{
ID: fmt.Sprintf("CMNT::%03d", i),
By: "Frodo Baggins",
Text: "Hi!",
At: time.Now(),
Tags: []string{"tech", "golang"},
}
list = append(list, cmnt)
}
fmt.Println(db.Put(list...))
res, cnt, err := db.Query(Q{View: "tags", Start: []byte("tech"), Count: true})
fmt.Println(err)
fmt.Println(len(res))
fmt.Println(cnt)
Output: <nil> <nil> 0 3
Example (End) ¶
db := createDB()
defer db.Close()
db.AddView(NewView("by_time",
func(em Emitter, id string, doc interface{}) {
c, ok := doc.(*comment)
if !ok {
return
}
t := c.At
if t.IsZero() {
return
}
em.Emit([]byte(t.Format("2006-01-02")), nil)
return
}))
at := time.Date(2018, 1, 1, 12, 0, 0, 0, time.Local)
var list []interface{}
for i := 1; i <= 3; i++ {
cmnt := &comment{
ID: fmt.Sprintf("CMNT::%03d", i),
By: "Frodo Baggins",
Text: "Hi!",
At: at,
Tags: []string{"tech", "golang"},
}
list = append(list, cmnt)
at = at.Add(time.Hour * 24)
}
fmt.Println(db.Put(list...))
start := []byte("2018-01-01")
prefix := []byte("2018-01")
end := []byte("2018-01-03") // exclusive
res, _, err := db.Query(Q{View: "by_time", Start: start, Prefix: prefix, End: end})
fmt.Println(err)
for _, v := range res {
fmt.Printf("%s %s %s\n", v.Key, v.Val, v.Index)
}
Output: <nil> <nil> CMNT::001 2018-01-01 CMNT::002 2018-01-02
Example (EndAll) ¶
db := createDB()
defer db.Close()
db.AddView(NewView("by_time",
func(em Emitter, id string, doc interface{}) {
c, ok := doc.(*comment)
if !ok {
return
}
t := c.At
if t.IsZero() {
return
}
em.Emit([]byte(t.Format("2006-01-02")), []byte(c.By))
return
}))
at := time.Date(2018, 1, 1, 12, 0, 0, 0, time.Local)
var list []interface{}
for i := 1; i <= 3; i++ {
cmnt := &comment{
ID: fmt.Sprintf("CMNT::%03d", i),
By: "Frodo Baggins",
Text: "Hi!",
At: at,
Tags: []string{"tech", "golang"},
}
list = append(list, cmnt)
at = at.Add(time.Hour * 24)
}
fmt.Println(db.Put(list...))
start := []byte("2018-01-01")
prefix := []byte("2018-01")
end := []byte("2018-01\uffff")
res, _, err := db.Query(Q{View: "by_time", Start: start, Prefix: prefix, End: end})
fmt.Println(err)
for _, v := range res {
fmt.Printf("%s %s %s\n", v.Key, v.Val, v.Index)
}
Output: <nil> <nil> CMNT::001 Frodo Baggins 2018-01-01 CMNT::002 Frodo Baggins 2018-01-02 CMNT::003 Frodo Baggins 2018-01-03
Example (Limit) ¶
db := createDB()
defer db.Close()
db.AddView(NewView("by_time",
func(em Emitter, id string, doc interface{}) {
c, ok := doc.(*comment)
if !ok {
return
}
t := c.At
if t.IsZero() {
return
}
em.Emit([]byte(t.Format("2006-01-02")), nil)
return
}))
at := time.Date(2018, 1, 1, 12, 0, 0, 0, time.Local)
var list []interface{}
for i := 1; i <= 3; i++ {
cmnt := &comment{
ID: fmt.Sprintf("CMNT::%03d", i),
By: "Frodo Baggins",
Text: "Hi!",
At: at,
Tags: []string{"tech", "golang"},
}
list = append(list, cmnt)
at = at.Add(time.Hour * 24)
}
fmt.Println(db.Put(list...))
start := []byte("2018-01-01")
prefix := []byte("2018-01")
res, _, err := db.Query(Q{View: "by_time", Start: start, Prefix: prefix, Limit: 1})
fmt.Println(err)
for _, v := range res {
fmt.Printf("%s %s %s\n", v.Key, v.Val, v.Index)
}
Output: <nil> <nil> CMNT::001 2018-01-01
Example (Skip) ¶
db := createDB()
defer db.Close()
db.AddView(NewView("by_time",
func(em Emitter, id string, doc interface{}) {
c, ok := doc.(*comment)
if !ok {
return
}
t := c.At
if t.IsZero() {
return
}
em.Emit([]byte(t.Format("2006-01-02")), []byte(c.By))
return
}))
at := time.Date(2018, 1, 1, 12, 0, 0, 0, time.Local)
var list []interface{}
for i := 1; i <= 3; i++ {
cmnt := &comment{
ID: fmt.Sprintf("CMNT::%03d", i),
By: "Frodo Baggins",
Text: "Hi!",
At: at,
Tags: []string{"tech", "golang"},
}
list = append(list, cmnt)
at = at.Add(time.Hour * 24)
}
fmt.Println(db.Put(list...))
start := []byte("2018-01-01")
prefix := []byte("2018-01")
end := []byte("2018-01\uffff")
res, _, err := db.Query(Q{View: "by_time", Start: start, Prefix: prefix, End: end, Skip: 1})
fmt.Println(err)
for _, v := range res {
fmt.Printf("%s %s %s\n", v.Key, v.Val, v.Index)
}
Output: <nil> <nil> CMNT::002 Frodo Baggins 2018-01-02 CMNT::003 Frodo Baggins 2018-01-03
Example (TimestampInt64) ¶
db := createDB()
defer db.Close()
type comment struct {
ID string `json:"id"`
Rev string `json:"rev"`
By string `json:"by,omitempty"`
Text string `json:"text,omitempty"`
At int64 `json:"at,omitempty"`
Tags []string `json:"tags,omitempty"`
}
db.AddView(NewView("by_time",
func(em Emitter, id string, doc interface{}) {
c, ok := doc.(*comment)
if !ok {
return
}
t := c.At
ts := make([]byte, 8)
binary.BigEndian.PutUint64(ts, uint64(t))
em.Emit(ts, nil)
return
}))
at := time.Date(2018, 1, 1, 12, 0, 0, 0, time.Local)
startTS := at.Unix()
first := startTS
var list []interface{}
for i := 1; i <= 3; i++ {
cmnt := &comment{
ID: fmt.Sprintf("CMNT::%03d", i),
By: "Frodo Baggins",
Text: "Hi!",
At: startTS,
Tags: []string{"tech", "golang"},
}
list = append(list, cmnt)
at = at.Add(time.Hour * 24)
startTS = at.Unix()
}
fmt.Println(db.Put(list...))
start := make([]byte, 8)
binary.BigEndian.PutUint64(start, uint64(first))
res, _, err := db.Query(Q{View: "by_time", Start: start})
fmt.Println(err)
for _, v := range res {
fmt.Printf("%s %s %x\n", v.Key, v.Val, v.Index)
}
Output: <nil> <nil> CMNT::001 000000005a49f188 CMNT::002 000000005a4b4308 CMNT::003 000000005a4c9488
Example (ViewVal) ¶
db := createDB()
defer db.Close()
db.AddView(NewView("by_time",
func(em Emitter, id string, doc interface{}) {
c, ok := doc.(*comment)
if !ok {
return
}
t := c.At
if t.IsZero() {
return
}
em.Emit([]byte(t.Format("2006-01-02")), []byte(c.By))
return
}))
at := time.Date(2018, 1, 1, 12, 0, 0, 0, time.Local)
var list []interface{}
for i := 1; i <= 3; i++ {
cmnt := &comment{
ID: fmt.Sprintf("CMNT::%03d", i),
By: "Frodo Baggins",
Text: "Hi!",
At: at,
Tags: []string{"tech", "golang"},
}
list = append(list, cmnt)
at = at.Add(time.Hour * 24)
}
fmt.Println(db.Put(list...))
start := []byte("2018-01-01")
prefix := []byte("2018-01")
res, _, err := db.Query(Q{View: "by_time", Start: start, Prefix: prefix})
fmt.Println(err)
for _, v := range res {
fmt.Printf("%s %s %s\n", v.Key, v.Val, v.Index)
}
Output: <nil> <nil> CMNT::001 Frodo Baggins 2018-01-01 CMNT::002 Frodo Baggins 2018-01-02 CMNT::003 Frodo Baggins 2018-01-03