Repository: Clinical-Genomics/cgbeacon2

Issue:
Code to create/edit a dataset

Discussion:

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 39f8afb..cdb3286 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,6 @@
 ## [x.x.x] -
 
 ### Added
--  Info endpoint (/) for API v1
+- Info endpoint (/) for API v1
 - Add new datasets using the command line
+- Update existing datasets using the command line
diff --git a/cgbeacon2/cli/add.py b/cgbeacon2/cli/add.py
index d40a9f6..5dc977a 100644
--- a/cgbeacon2/cli/add.py
+++ b/cgbeacon2/cli/add.py
@@ -22,9 +22,10 @@ def add():
 @click.option('-url', type=click.STRING, nargs=1, required=False, help="external url")
 @click.option('-cc', type=click.STRING, nargs=1, required=False, help="consent code key. i.e. HMB")
 @click.option('-info', type=(str, str), multiple=True, required=False, help="key-value pair of args. i.e.: FOO 1")
+@click.option('--update', is_flag=True)
 @with_appcontext
-def dataset(id, name, build, desc, version, url, cc, info, ):
-    """Creates a dataset object in the database
+def dataset(id, name, build, desc, version, url, cc, info, update):
+    """Creates a dataset object in the database or updates a pre-existing one
 
     Accepts:
         id(str): dataset unique ID (mandatory)
@@ -35,10 +36,9 @@ def dataset(id, name, build, desc, version, url, cc, info, ):
         url(): URL to an external system providing more dataset information (RFC 3986 format).
         cc(str): https://journals.plos.org/plosgenetics/article?id=10.1371/journal.pgen.1005772
         info(list of tuples): Additional structured metadata, key-value pairs
+        update(bool): Update a dataset already present in the database with the same id
     """
 
-    click.echo("Adding a new dataset to database")
-
     dataset_obj = {
         '_id' : id,
         'name' : name,
@@ -75,9 +75,9 @@ def dataset(id, name, build, desc, version, url, cc, info, ):
 
         dataset_obj["consent_code"] = cc
 
-    inserted_id, collection = add_dataset(mongo_db=current_app.db, dataset_dict=dataset_obj)
+    inserted_id= add_dataset(mongo_db=current_app.db, dataset_dict=dataset_obj, update=update)
 
     if inserted_id:
-        click.echo(f"Inserted dataset with ID '{inserted_id}' into database collection '{collection}'")
+        click.echo(f"Dataset collection was successfully updated for dataset '{inserted_id}'")
     else:
-        click.echo('Aborted')
+        click.echo(f"An error occurred while updating dataset collection")
diff --git a/cgbeacon2/utils/add.py b/cgbeacon2/utils/add.py
index e613ae9..8095a0e 100644
--- a/cgbeacon2/utils/add.py
+++ b/cgbeacon2/utils/add.py
@@ -3,7 +3,7 @@ import logging
 
 LOG = logging.getLogger(__name__)
 
-def add_dataset(mongo_db, dataset_dict):
+def add_dataset(mongo_db, dataset_dict, update=False):
     """Add/modify a dataset
 
     Accepts:
@@ -11,17 +11,31 @@ def add_dataset(mongo_db, dataset_dict):
         dataset_dict(dict)
 
     Returns:
-        inserted_id(str), collection(str): a tuple with values inserted_id and collection name
+        inserted_id(str): the _id of the added/updated dataset
     """
 
     inserted_id = None
     collection = "dataset"
 
+    if update is True: # update an existing dataset
+        #LOG.info(f"Updating dataset collection with dataset id: {id}..")
+        old_dataset = mongo_db[collection].find_one({'_id': dataset_dict['_id']})
+
+        if old_dataset is None:
+            LOG.fatal("Couldn't find any dataset with id '{}' in the database".format(dataset_dict['_id']))
+            return
+
+        result = mongo_db[collection].replace_one({'_id': dataset_dict['_id']}, dataset_dict)
+        if result.modified_count > 0:
+            return dataset_dict['_id']
+        else:
+            return
+
     try:
         result = mongo_db[collection].insert_one(dataset_dict)
 
     except Exception as err:
-        LOG.fatal('Error while inserting a new dataset to database:{}'.format(err))
-        quit()
+        LOG.error(err)
+        return
 
-    return result.inserted_id, collection
+    return result.inserted_id


Test patch:
diff --git a/tests/cli/test_add_dataset.py b/tests/cli/test_add_dataset.py
index 6e02f00..2369fff 100644
--- a/tests/cli/test_add_dataset.py
+++ b/tests/cli/test_add_dataset.py
@@ -133,3 +133,72 @@ def test_add_dataset_wrong_consent(test_dataset_cli, mock_app, database):
     # and no dataset should be saved to database
     new_dataset = database["dataset"].find_one()
     assert new_dataset is None
+
+
+def test_update_non_existent_dataset(test_dataset_cli, mock_app, database):
+    """Test try to update a dataset that doesn't exist. Should return error"""
+
+    # test add a dataset_obj using the app cli
+    runner = mock_app.test_cli_runner()
+
+    dataset = test_dataset_cli
+
+    # Having an empty dataset collection
+    result = database["dataset"].find_one()
+    assert result is None
+
+    # When invoking the add command with the update flag to update a dataset
+    result =  runner.invoke(cli, [
+       'add',
+       'dataset',
+       '-id', dataset["_id"],
+       '-name', dataset["name"],
+       '-build', dataset["build"],
+       '-desc', dataset["description"],
+       '-version', dataset["version"],
+       '-url', dataset["url"],
+       '-cc', dataset["consent_code"],
+       '-info', 'FOO', '7',
+       '-info', 'BAR', 'XYZ',
+       '--update'
+       ])
+    # Then the command should print error
+    assert result.exit_code == 0
+    assert "An error occurred while updating dataset collection" in result.output
+
+
+def test_update_dataset(test_dataset_cli, mock_app, database):
+    """Test try to update a dataset that exists."""
+
+    # test add a dataset_obj using the app cli
+    runner = mock_app.test_cli_runner()
+
+    dataset = test_dataset_cli
+
+    # Having a database dataset collection with one item
+    result = database["dataset"].insert_one(dataset)
+    assert result is not None
+
+    # When invoking the add command with the update flag to update a dataset
+    result =  runner.invoke(cli, [
+       'add',
+       'dataset',
+       '-id', dataset["_id"],
+       '-name', dataset["name"],
+       '-build', dataset["build"],
+       '-desc', dataset["description"],
+       '-version', 2.0, # update to version 2
+       '-url', dataset["url"],
+       '-cc', dataset["consent_code"],
+       '-info', 'FOO', '7',
+       '-info', 'BAR', 'XYZ',
+       '--update'
+       ])
+
+    # Then the command should NOT print error
+    assert result.exit_code == 0
+    assert "Dataset collection was successfully updated" in result.output
+
+    # And the dataset should be updated
+    updated_dataset = database["dataset"].find_one({"_id": dataset["_id"]})
+    assert updated_dataset["version"] == 2