...

Source file src/github.com/go-kivik/kivik/v4/pouchdb/db.go

Documentation: github.com/go-kivik/kivik/v4/pouchdb

     1  // Licensed under the Apache License, Version 2.0 (the "License"); you may not
     2  // use this file except in compliance with the License. You may obtain a copy of
     3  // the License at
     4  //
     5  //  http://www.apache.org/licenses/LICENSE-2.0
     6  //
     7  // Unless required by applicable law or agreed to in writing, software
     8  // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
     9  // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    10  // License for the specific language governing permissions and limitations under
    11  // the License.
    12  
    13  //go:build js
    14  
    15  package pouchdb
    16  
    17  import (
    18  	"bytes"
    19  	"context"
    20  	"encoding/json"
    21  	"io"
    22  	"net/http"
    23  	"sync/atomic"
    24  
    25  	"github.com/gopherjs/gopherjs/js"
    26  
    27  	"github.com/go-kivik/kivik/v4/driver"
    28  	internal "github.com/go-kivik/kivik/v4/int/errors"
    29  	"github.com/go-kivik/kivik/v4/pouchdb/bindings"
    30  )
    31  
    32  type db struct {
    33  	db *bindings.DB
    34  
    35  	client *client
    36  
    37  	// these are set to 1 when compaction begins, and unset when the
    38  	// callback returns.
    39  	compacting  uint32
    40  	viewCleanup uint32
    41  }
    42  
    43  var _ driver.DB = (*db)(nil)
    44  
    45  func (d *db) AllDocs(ctx context.Context, options driver.Options) (driver.Rows, error) {
    46  	opts := map[string]interface{}{}
    47  	options.Apply(opts)
    48  	result, err := d.db.AllDocs(ctx, opts)
    49  	if err != nil {
    50  		return nil, err
    51  	}
    52  	return &rows{
    53  		Object: result,
    54  	}, nil
    55  }
    56  
    57  func (d *db) Query(ctx context.Context, ddoc, view string, options driver.Options) (driver.Rows, error) {
    58  	opts := map[string]interface{}{}
    59  	options.Apply(opts)
    60  	result, err := d.db.Query(ctx, ddoc, view, opts)
    61  	if err != nil {
    62  		return nil, err
    63  	}
    64  	return &rows{
    65  		Object: result,
    66  	}, nil
    67  }
    68  
    69  type document struct {
    70  	id   string
    71  	rev  string
    72  	body io.Reader
    73  	done bool
    74  }
    75  
    76  func (d *document) Next(row *driver.Row) error {
    77  	if d.done {
    78  		return io.EOF
    79  	}
    80  	d.done = true
    81  	row.ID = d.id
    82  	row.Rev = d.rev
    83  	row.Doc = d.body
    84  	return nil
    85  }
    86  
    87  func (d *document) Close() error {
    88  	d.done = true
    89  	return nil
    90  }
    91  
    92  func (d *document) UpdateSeq() string { return "" }
    93  func (d *document) Offset() int64     { return 0 }
    94  func (d *document) TotalRows() int64  { return 0 }
    95  
    96  func (d *db) Get(ctx context.Context, docID string, options driver.Options) (*driver.Document, error) {
    97  	opts := map[string]interface{}{}
    98  	options.Apply(opts)
    99  	doc, rev, err := d.db.Get(ctx, docID, opts)
   100  	if err != nil {
   101  		return nil, err
   102  	}
   103  	return &driver.Document{
   104  		Rev:  rev,
   105  		Body: io.NopCloser(bytes.NewReader(doc)),
   106  	}, nil
   107  }
   108  
   109  func (d *db) CreateDoc(ctx context.Context, doc interface{}, options driver.Options) (docID, rev string, err error) {
   110  	jsonDoc, err := json.Marshal(doc)
   111  	if err != nil {
   112  		return "", "", err
   113  	}
   114  	jsDoc := js.Global.Get("JSON").Call("parse", string(jsonDoc))
   115  	opts := map[string]interface{}{}
   116  	options.Apply(opts)
   117  	return d.db.Post(ctx, jsDoc, opts)
   118  }
   119  
   120  func (d *db) Put(ctx context.Context, docID string, doc interface{}, options driver.Options) (rev string, err error) {
   121  	jsonDoc, err := json.Marshal(doc)
   122  	if err != nil {
   123  		return "", err
   124  	}
   125  	jsDoc := js.Global.Get("JSON").Call("parse", string(jsonDoc))
   126  	if id := jsDoc.Get("_id"); id != js.Undefined {
   127  		if id.String() != docID {
   128  			return "", &internal.Error{Status: http.StatusBadRequest, Message: "id argument must match _id field in document"}
   129  		}
   130  	}
   131  	opts := map[string]interface{}{}
   132  	options.Apply(opts)
   133  	jsDoc.Set("_id", docID)
   134  	return d.db.Put(ctx, jsDoc, opts)
   135  }
   136  
   137  func (d *db) Delete(ctx context.Context, docID string, options driver.Options) (newRev string, err error) {
   138  	opts := map[string]interface{}{}
   139  	options.Apply(opts)
   140  	rev, _ := opts["rev"].(string)
   141  	return d.db.Delete(ctx, docID, rev, opts)
   142  }
   143  
   144  func (d *db) Stats(ctx context.Context) (*driver.DBStats, error) {
   145  	i, err := d.db.Info(ctx)
   146  	return &driver.DBStats{
   147  		Name:           i.Name,
   148  		CompactRunning: atomic.LoadUint32(&d.compacting) == 1 || atomic.LoadUint32(&d.viewCleanup) == 1,
   149  		DocCount:       i.DocCount,
   150  		UpdateSeq:      i.UpdateSeq,
   151  	}, err
   152  }
   153  
   154  func (d *db) Compact(context.Context) error {
   155  	if atomic.LoadUint32(&d.compacting) == 1 {
   156  		return &internal.Error{Status: http.StatusTooManyRequests, Message: "kivik: compaction already running"}
   157  	}
   158  	atomic.StoreUint32(&d.compacting, 1)
   159  	defer atomic.StoreUint32(&d.compacting, 0)
   160  	return d.db.Compact()
   161  }
   162  
   163  // CompactView is unimplemented for PouchDB.
   164  func (d *db) CompactView(context.Context, string) error {
   165  	return nil
   166  }
   167  
   168  func (d *db) ViewCleanup(context.Context) error {
   169  	if atomic.LoadUint32(&d.viewCleanup) == 1 {
   170  		return &internal.Error{Status: http.StatusTooManyRequests, Message: "kivik: view cleanup already running"}
   171  	}
   172  	atomic.StoreUint32(&d.viewCleanup, 1)
   173  	defer atomic.StoreUint32(&d.viewCleanup, 0)
   174  	return d.db.ViewCleanup()
   175  }
   176  
   177  func (d *db) Close() error {
   178  	return d.db.Close()
   179  }
   180  
   181  var _ driver.Purger = &db{}
   182  
   183  func (d *db) Purge(ctx context.Context, docRevMap map[string][]string) (*driver.PurgeResult, error) {
   184  	result := &driver.PurgeResult{
   185  		Purged: make(map[string][]string, len(docRevMap)),
   186  	}
   187  	for docID, revs := range docRevMap {
   188  		for _, rev := range revs {
   189  			delRevs, err := d.db.Purge(ctx, docID, rev)
   190  			if err != nil {
   191  				return result, err
   192  			}
   193  			if result.Purged[docID] == nil {
   194  				result.Purged[docID] = delRevs
   195  			} else {
   196  				result.Purged[docID] = append(result.Purged[docID], delRevs...)
   197  			}
   198  		}
   199  	}
   200  	return result, nil
   201  }
   202  

View as plain text