1package pouchdb 2 3import ( 4 "bytes" 5 "context" 6 "encoding/json" 7 "fmt" 8 "io/ioutil" 9 "os" 10 11 "github.com/gopherjs/gopherjs/js" 12 13 "github.com/go-kivik/kivik" 14 "github.com/go-kivik/kivik/driver" 15 "github.com/go-kivik/kivik/errors" 16 "github.com/go-kivik/pouchdb/bindings" 17) 18 19type db struct { 20 db *bindings.DB 21 22 client *client 23 24 // compacting is set true when compaction begins, and unset when the 25 // callback returns. 26 compacting bool 27} 28 29var _ driver.DB = &db{} 30 31func (d *db) AllDocs(ctx context.Context, options map[string]interface{}) (driver.Rows, error) { 32 result, err := d.db.AllDocs(ctx, options) 33 if err != nil { 34 return nil, err 35 } 36 return &rows{ 37 Object: result, 38 }, nil 39} 40 41func (d *db) Query(ctx context.Context, ddoc, view string, options map[string]interface{}) (driver.Rows, error) { 42 result, err := d.db.Query(ctx, ddoc, view, options) 43 if err != nil { 44 return nil, err 45 } 46 return &rows{ 47 Object: result, 48 }, nil 49} 50 51func (d *db) Get(ctx context.Context, docID string, options map[string]interface{}) (*driver.Document, error) { 52 doc, rev, err := d.db.Get(ctx, docID, options) 53 if err != nil { 54 return nil, err 55 } 56 return &driver.Document{ 57 ContentLength: int64(len(doc)), 58 Rev: rev, 59 Body: ioutil.NopCloser(bytes.NewReader(doc)), 60 }, nil 61} 62 63func (d *db) CreateDoc(ctx context.Context, doc interface{}, options map[string]interface{}) (docID, rev string, err error) { 64 jsonDoc, err := json.Marshal(doc) 65 if err != nil { 66 return "", "", err 67 } 68 jsDoc := js.Global.Get("JSON").Call("parse", string(jsonDoc)) 69 return d.db.Post(ctx, jsDoc, options) 70} 71 72func (d *db) Put(ctx context.Context, docID string, doc interface{}, options map[string]interface{}) (rev string, err error) { 73 jsonDoc, err := json.Marshal(doc) 74 if err != nil { 75 return "", err 76 } 77 jsDoc := js.Global.Get("JSON").Call("parse", string(jsonDoc)) 78 if id := jsDoc.Get("_id"); id != js.Undefined { 79 if id.String() != docID { 80 return "", errors.Status(kivik.StatusBadAPICall, "id argument must match _id field in document") 81 } 82 } 83 jsDoc.Set("_id", docID) 84 return d.db.Put(ctx, jsDoc, options) 85} 86 87func (d *db) Delete(ctx context.Context, docID, rev string, options map[string]interface{}) (newRev string, err error) { 88 return d.db.Delete(ctx, docID, rev, options) 89} 90 91func (d *db) Stats(ctx context.Context) (*driver.DBStats, error) { 92 i, err := d.db.Info(ctx) 93 return &driver.DBStats{ 94 Name: i.Name, 95 CompactRunning: d.compacting, 96 DocCount: i.DocCount, 97 UpdateSeq: i.UpdateSeq, 98 }, err 99} 100 101func (d *db) Compact(_ context.Context) error { 102 d.compacting = true 103 go func() { 104 defer func() { d.compacting = false }() 105 if err := d.db.Compact(); err != nil { 106 fmt.Fprintf(os.Stderr, "compaction failed: %s\n", err) 107 } 108 }() 109 return nil 110} 111 112// CompactView is unimplemented for PouchDB. 113func (d *db) CompactView(_ context.Context, _ string) error { 114 return nil 115} 116 117func (d *db) ViewCleanup(_ context.Context) error { 118 d.compacting = true 119 go func() { // FIXME: #14 120 defer func() { d.compacting = false }() 121 if err := d.db.ViewCleanup(); err != nil { 122 fmt.Fprintf(os.Stderr, "view cleanup failed: %s\n", err) 123 } 124 }() 125 return nil 126} 127 128var securityNotImplemented = errors.Status(kivik.StatusNotImplemented, "kivik: security interface not supported by PouchDB") 129 130func (d *db) Security(ctx context.Context) (*driver.Security, error) { 131 return nil, securityNotImplemented 132} 133 134func (d *db) SetSecurity(_ context.Context, _ *driver.Security) error { 135 return securityNotImplemented 136} 137