Skip to content

Commit

Permalink
Fix updating of docs
Browse files Browse the repository at this point in the history
And allow fetching specific revs
  • Loading branch information
flimzy committed Jun 4, 2017
1 parent 27ae94b commit 986b3a7
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 26 deletions.
39 changes: 19 additions & 20 deletions driver/memory/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,14 @@ func (d *db) Query(ctx context.Context, ddoc, view string, opts map[string]inter

func (d *db) Get(_ context.Context, docID string, opts map[string]interface{}) (json.RawMessage, error) {
if existing, ok := d.db.docs[docID]; ok {
if rev, ok := opts["rev"].(string); ok {
for _, r := range existing.revs {
if rev == fmt.Sprintf("%d-%s", r.ID, r.Rev) {
return r.data, nil
}
}
return nil, errors.Status(kivik.StatusNotFound, "missing")
}
last := existing.revs[len(existing.revs)-1]
return last.data, nil
}
Expand All @@ -59,13 +67,6 @@ type docMeta struct {
}

func (d *db) Put(_ context.Context, docID string, doc interface{}) (rev string, err error) {
if existing, ok := d.db.docs[docID]; ok {
last := existing.revs[len(existing.revs)-1]
lastRev := fmt.Sprintf("%d-%s", last.RevID, last.Rev)
if rev != lastRev {
return "", errors.Status(kivik.StatusConflict, "document update conflict")
}
}
docJSON, err := json.Marshal(doc)
if err != nil {
return "", errors.Status(kivik.StatusBadRequest, "invalid JSON")
Expand All @@ -74,25 +75,23 @@ func (d *db) Put(_ context.Context, docID string, doc interface{}) (rev string,
if e := json.Unmarshal(docJSON, &meta); e != nil {
return "", errors.Status(kivik.StatusInternalServerError, "failed to decode encoded document; this is a bug!")
}

if last, ok := d.db.latestRevision(docID); ok {
lastRev := fmt.Sprintf("%d-%s", last.ID, last.Rev)
if meta.Rev != lastRev {
return "", errors.Status(kivik.StatusConflict, "document update conflict")
}
rev := d.db.addRevision(docID, docJSON, nil)
return rev, nil
}

if meta.Rev != "" {
// Rev should not be set for a new document
return "", errors.Status(kivik.StatusConflict, "document update conflict")
}
d.db.mutex.Lock()
defer d.db.mutex.Unlock()
revID := int64(1)
revStr := randStr()
d.db.docs[docID] = &document{
revs: []*revision{
{
ID: docID,
RevID: revID,
Rev: revStr,
data: docJSON,
},
},
}
return fmt.Sprintf("%d-%s", revID, revStr), nil
return d.db.addRevision(docID, docJSON, nil), nil
}

func (d *db) Delete(_ context.Context, docID, rev string) (newRev string, err error) {
Expand Down
92 changes: 86 additions & 6 deletions driver/memory/db_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func TestPut(t *testing.T) {
Name string
DocID string
Doc interface{}
Setup func(driver.DB)
Setup func() driver.DB
Status int
Error string
}
Expand All @@ -92,8 +92,10 @@ func TestPut(t *testing.T) {
Name: "Conflict",
DocID: "foo",
Doc: map[string]string{"_id": "foo", "_rev": "bar"},
Setup: func(db driver.DB) {
Setup: func() driver.DB {
db := setupDB(t, nil)
db.Put(context.Background(), "foo", map[string]string{"_id": "foo"})
return db
},
Status: 409,
Error: "document update conflict",
Expand All @@ -116,12 +118,30 @@ func TestPut(t *testing.T) {
Status: 409,
Error: "document update conflict",
},
func() putTest {
db := setupDB(t, nil)
rev, err := db.Put(context.Background(), "foo", map[string]string{"_id": "foo", "foo": "bar"})
if err != nil {
panic(err)
}
return putTest{
Name: "Update",
DocID: "foo",
Setup: func() driver.DB { return db },
Doc: map[string]string{"_id": "foo", "_rev": rev},
}
}(),
}
for _, test := range tests {
func(test putTest) {
t.Run(test.Name, func(t *testing.T) {
t.Parallel()
db := setupDB(t, test.Setup)
var db driver.DB
if test.Setup != nil {
db = test.Setup()
} else {
db = setupDB(t, nil)
}
var msg string
var status int
if _, err := db.Put(context.Background(), test.DocID, test.Doc); err != nil {
Expand All @@ -144,7 +164,7 @@ func TestGet(t *testing.T) {
Name string
ID string
Opts map[string]interface{}
Setup func(driver.DB)
Setup func() driver.DB
Status int
Error string
Expected interface{}
Expand All @@ -159,19 +179,79 @@ func TestGet(t *testing.T) {
{
Name: "ExistingDoc",
ID: "foo",
Setup: func(db driver.DB) {
Setup: func() driver.DB {
db := setupDB(t, nil)
if _, err := db.Put(context.Background(), "foo", map[string]string{"_id": "foo", "foo": "bar"}); err != nil {
panic(err)
}
return db
},
Expected: map[string]string{"_id": "foo", "foo": "bar"},
},
func() getTest {
db := setupDB(t, nil)
rev, err := db.Put(context.Background(), "foo", map[string]string{"_id": "foo", "foo": "Bar"})
if err != nil {
panic(err)
}
return getTest{
Name: "SpecificRev",
ID: "foo",
Setup: func() driver.DB { return db },
Opts: map[string]interface{}{
"rev": rev,
},
Expected: map[string]string{"_id": "foo", "foo": "Bar"},
}
}(),
func() getTest {
db := setupDB(t, nil)
rev, err := db.Put(context.Background(), "foo", map[string]string{"_id": "foo", "foo": "Bar"})
if err != nil {
panic(err)
}
_, err = db.Put(context.Background(), "foo", map[string]string{"_id": "foo", "foo": "baz", "_rev": rev})
if err != nil {
panic(err)
}
return getTest{
Name: "OldRev",
ID: "foo",
Setup: func() driver.DB { return db },
Opts: map[string]interface{}{
"rev": rev,
},
Expected: map[string]string{"_id": "foo", "foo": "Bar"},
}
}(),
{
Name: "MissingRev",
ID: "foo",
Opts: map[string]interface{}{
"rev": "1-4c6114c65e295552ab1019e2b046b10e",
},
Setup: func() driver.DB {
db := setupDB(t, nil)
_, err := db.Put(context.Background(), "foo", map[string]string{"_id": "foo", "foo": "Bar"})
if err != nil {
panic(err)
}
return db
},
Status: 404,
Error: "missing",
},
}
for _, test := range tests {
func(test getTest) {
t.Run(test.Name, func(t *testing.T) {
t.Parallel()
db := setupDB(t, test.Setup)
var db driver.DB
if test.Setup != nil {
db = test.Setup()
} else {
db = setupDB(t, nil)
}
var msg string
var status int
docJSON, err := db.Get(context.Background(), test.ID, test.Opts)
Expand Down

0 comments on commit 986b3a7

Please sign in to comment.