Skip to content

Commit 2f20be4

Browse files
author
Chris Elder
committed
FAB-2047 Add delete by ID to CouchDB Layer
Motivation for this change: Add DeleteDoc method to the CouchDB layer in order to provide delete by ID capability. This is a first step to allow the ledger to delete CouchDB records. - Add DeleteDoc to couchdb.go - Add unit tests for delete in couchdb_test.go Change-Id: I0466bea76f02d16a7c62b07d978a48c20ad80281 Signed-off-by: Chris Elder <[email protected]>
1 parent 6a2408b commit 2f20be4

File tree

2 files changed

+109
-4
lines changed

2 files changed

+109
-4
lines changed

core/ledger/util/couchdb/couchdb.go

+51-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright IBM Corp. 2016 All Rights Reserved.
2+
Copyright IBM Corp. 2016, 2017 All Rights Reserved.
33
44
Licensed under the Apache License, Version 2.0 (the "License");
55
you may not use this file except in compliance with the License.
@@ -733,6 +733,55 @@ func (dbclient *CouchDatabase) ReadDocRange(startKey, endKey string, limit, skip
733733

734734
}
735735

736+
//DeleteDoc method provides function to delete a document from the database by id
737+
func (dbclient *CouchDatabase) DeleteDoc(id, rev string) error {
738+
739+
logger.Debugf("Entering DeleteDoc() id=%s", id)
740+
741+
deleteURL, err := url.Parse(dbclient.couchInstance.conf.URL)
742+
if err != nil {
743+
logger.Errorf("URL parse error: %s", err.Error())
744+
return err
745+
}
746+
747+
deleteURL.Path = dbclient.dbName
748+
// id can contain a '/', so encode separately
749+
deleteURL = &url.URL{Opaque: deleteURL.String() + "/" + encodePathElement(id)}
750+
751+
if rev == "" {
752+
753+
//See if the document already exists, we need the rev for delete
754+
_, revdoc, err2 := dbclient.ReadDoc(id)
755+
if err2 != nil {
756+
//set the revision to indicate that the document was not found
757+
rev = ""
758+
} else {
759+
//set the revision to the rev returned from the document read
760+
rev = revdoc
761+
}
762+
}
763+
764+
logger.Debugf(" rev=%s", rev)
765+
766+
resp, couchDBReturn, err := dbclient.handleRequest(http.MethodDelete, deleteURL.String(), nil, rev, "")
767+
if err != nil {
768+
fmt.Printf("couchDBReturn=%v", couchDBReturn)
769+
if couchDBReturn != nil && couchDBReturn.StatusCode == 404 {
770+
logger.Debug("Document not found (404), returning nil value instead of 404 error")
771+
// non-existent document should return nil value instead of a 404 error
772+
// for details see https://github.com/hyperledger-archives/fabric/issues/936
773+
return nil
774+
}
775+
return err
776+
}
777+
defer resp.Body.Close()
778+
779+
logger.Debugf("Exiting DeleteDoc()")
780+
781+
return nil
782+
783+
}
784+
736785
//QueryDocuments method provides function for processing a query
737786
func (dbclient *CouchDatabase) QueryDocuments(query string, limit, skip int) (*[]QueryResult, error) {
738787

@@ -796,7 +845,6 @@ func (dbclient *CouchDatabase) QueryDocuments(query string, limit, skip int) (*[
796845

797846
logger.Debugf("Adding row to resultset: %s", row)
798847

799-
//TODO Replace the temporary NewHeight version when available
800848
var addDocument = &QueryResult{jsonDoc.ID, row}
801849

802850
results = append(results, *addDocument)
@@ -821,7 +869,7 @@ func (dbclient *CouchDatabase) handleRequest(method, connectURL string, data io.
821869
}
822870

823871
//add content header for PUT
824-
if method == http.MethodPut || method == http.MethodPost {
872+
if method == http.MethodPut || method == http.MethodPost || method == http.MethodDelete {
825873

826874
//If the multipartBoundary is not set, then this is a JSON and content-type should be set
827875
//to application/json. Else, this is contains an attachment and needs to be multipart

core/ledger/util/couchdb/couchdb_test.go

+58-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright IBM Corp. 2016 All Rights Reserved.
2+
Copyright IBM Corp. 2016, 2017 All Rights Reserved.
33
44
Licensed under the Apache License, Version 2.0 (the "License");
55
you may not use this file except in compliance with the License.
@@ -332,3 +332,60 @@ func TestDBSaveAttachment(t *testing.T) {
332332

333333
}
334334
}
335+
336+
func TestDBDeleteDocument(t *testing.T) {
337+
338+
if ledgerconfig.IsCouchDBEnabled() == true {
339+
340+
cleanup()
341+
defer cleanup()
342+
343+
//create a new instance and database object
344+
couchInstance, err := CreateCouchInstance(connectURL, username, password)
345+
testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create couch instance"))
346+
db := CouchDatabase{couchInstance: *couchInstance, dbName: database}
347+
348+
//create a new database
349+
_, errdb := db.CreateDatabaseIfNotExist()
350+
testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to create database"))
351+
352+
//Save the test document
353+
_, saveerr := db.SaveDoc("2", "", assetJSON, nil)
354+
testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document"))
355+
356+
//Attempt to retrieve the test document
357+
_, _, readErr := db.ReadDoc("2")
358+
testutil.AssertNoError(t, readErr, fmt.Sprintf("Error when trying to retrieve a document with attachment"))
359+
360+
//Delete the test document
361+
deleteErr := db.DeleteDoc("2", "")
362+
testutil.AssertNoError(t, deleteErr, fmt.Sprintf("Error when trying to delete a document"))
363+
364+
//Attempt to retrieve the test document
365+
readValue, _, _ := db.ReadDoc("2")
366+
testutil.AssertNil(t, readValue)
367+
368+
}
369+
}
370+
371+
func TestDBDeleteNonExistingDocument(t *testing.T) {
372+
373+
if ledgerconfig.IsCouchDBEnabled() == true {
374+
375+
cleanup()
376+
defer cleanup()
377+
378+
//create a new instance and database object
379+
couchInstance, err := CreateCouchInstance(connectURL, username, password)
380+
testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create couch instance"))
381+
db := CouchDatabase{couchInstance: *couchInstance, dbName: database}
382+
383+
//create a new database
384+
_, errdb := db.CreateDatabaseIfNotExist()
385+
testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to create database"))
386+
387+
//Save the test document
388+
deleteErr := db.DeleteDoc("2", "")
389+
testutil.AssertNoError(t, deleteErr, fmt.Sprintf("Error when trying to delete a non existing document"))
390+
}
391+
}

0 commit comments

Comments
 (0)