diff --git a/x/sqlite/delete.go b/x/sqlite/delete.go index c07795ce7..28ddd221e 100644 --- a/x/sqlite/delete.go +++ b/x/sqlite/delete.go @@ -48,21 +48,23 @@ func (d *db) Delete(ctx context.Context, docID string, options driver.Options) ( } defer tx.Rollback() - var curRev revision + var found bool err = tx.QueryRowContext(ctx, fmt.Sprintf(` - SELECT rev, rev_id - FROM %q - WHERE id = $1 - ORDER BY rev DESC, rev_id DESC - LIMIT 1 - `, d.name), data.ID).Scan(&curRev.rev, &curRev.id) + SELECT child.id IS NULL + FROM %[2]q AS rev + LEFT JOIN %[2]q AS child ON rev.id = child.id AND rev.rev = child.parent_rev AND rev.rev_id = child.parent_rev_id + JOIN %[1]q AS doc ON rev.id = doc.id AND rev.rev = doc.rev AND rev.rev_id = doc.rev_id + WHERE rev.id = $1 + AND rev.rev = $2 + AND rev.rev_id = $3 + `, d.name, d.name+"_revs"), data.ID, delRev.rev, delRev.id).Scan(&found) switch { case errors.Is(err, sql.ErrNoRows): return "", &internal.Error{Status: http.StatusNotFound, Message: "not found"} case err != nil: return "", err } - if curRev.String() != optRev { + if !found { return "", &internal.Error{Status: http.StatusConflict, Message: "conflict"} } var r revision diff --git a/x/sqlite/delete_test.go b/x/sqlite/delete_test.go index e509c98ed..27445fb12 100644 --- a/x/sqlite/delete_test.go +++ b/x/sqlite/delete_test.go @@ -120,7 +120,7 @@ func TestDBDelete(t *testing.T) { wantErr: "conflict", }, { - name: "delete losing rev for conflict", + name: "delete losing rev for conflict should succeed", setup: func(t *testing.T, db driver.DB) { _, err := db.Put(context.Background(), "foo", map[string]string{ "cat": "meow", @@ -139,7 +139,7 @@ func TestDBDelete(t *testing.T) { }, id: "foo", options: kivik.Rev("1-aaa"), - wantRev: "2-xxxxx", + wantRev: "2-df2a4fe30cde39c357c8d1105748d1b9", }, { name: "invalid rev format",