Repository: Clinical-Genomics/cgbeacon2

Issue:
Code to delete a dataset

Discussion:

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index cdb3286..77505dd 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,3 +4,4 @@
 - Info endpoint (/) for API v1
 - Add new datasets using the command line
 - Update existing datasets using the command line
+- Delete a dataset using the command line
diff --git a/cgbeacon2/cli/add.py b/cgbeacon2/cli/add.py
index 5dc977a..64cb633 100644
--- a/cgbeacon2/cli/add.py
+++ b/cgbeacon2/cli/add.py
@@ -42,9 +42,14 @@ def dataset(id, name, build, desc, version, url, cc, info, update):
     dataset_obj = {
         '_id' : id,
         'name' : name,
-        'assembly_id' : build,
-        'created' : datetime.datetime.now(),
+        'assembly_id' : build
     }
+
+    if update is True:
+        dataset_obj["updated"] = datetime.datetime.now()
+    else:
+        dataset_obj["created"] = datetime.datetime.now()
+
     if desc is not None:
         dataset_obj["description"] = desc
 
diff --git a/cgbeacon2/cli/commands.py b/cgbeacon2/cli/commands.py
index c06e941..cbbaad0 100644
--- a/cgbeacon2/cli/commands.py
+++ b/cgbeacon2/cli/commands.py
@@ -6,6 +6,7 @@ from flask.cli import FlaskGroup
 
 from cgbeacon2.server import create_app
 from .add import add
+from .delete import delete
 
 @click.version_option(__version__)
 @click.group(cls=FlaskGroup, create_app=create_app, invoke_without_command=False, add_default_commands=True,
@@ -16,3 +17,4 @@ def cli(**_):
 
 
 cli.add_command(add)
+cli.add_command(delete)
diff --git a/cgbeacon2/cli/delete.py b/cgbeacon2/cli/delete.py
new file mode 100644
index 0000000..04956fa
--- /dev/null
+++ b/cgbeacon2/cli/delete.py
@@ -0,0 +1,32 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+import click
+from flask.cli import with_appcontext, current_app
+
+from cgbeacon2.utils.delete import delete_dataset
+
+@click.group()
+def delete():
+    """Delete items from database using the CLI"""
+    pass
+
+@delete.command()
+@with_appcontext
+@click.option('-id', type=click.STRING, nargs=1, required=True, help="dataset ID")
+def dataset(id):
+    """Delete a dataset using its _id key
+
+    Accepts:
+        id(str): dataset _id field
+    """
+
+    click.echo(f"deleting dataset with id '{id}' from database")
+
+    deleted = delete_dataset(mongo_db=current_app.db, id=id)
+
+    if deleted is None:
+        click.echo("Aborting")
+    elif deleted == 0:
+        click.echo(f"Coundn't find a dataset with id '{id}' in database.")
+    elif deleted == 1:
+        click.echo("Dataset was successfully deleted")
diff --git a/cgbeacon2/utils/add.py b/cgbeacon2/utils/add.py
index 8095a0e..0c9bf67 100644
--- a/cgbeacon2/utils/add.py
+++ b/cgbeacon2/utils/add.py
@@ -24,13 +24,12 @@ def add_dataset(mongo_db, dataset_dict, update=False):
         if old_dataset is None:
             LOG.fatal("Couldn't find any dataset with id '{}' in the database".format(dataset_dict['_id']))
             return
-
+        dataset_dict["created"] = old_dataset["created"]
         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)
 
diff --git a/cgbeacon2/utils/delete.py b/cgbeacon2/utils/delete.py
new file mode 100644
index 0000000..d551319
--- /dev/null
+++ b/cgbeacon2/utils/delete.py
@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+import logging
+
+LOG = logging.getLogger(__name__)
+
+def delete_dataset(mongo_db, id):
+    """Delete a dataset from dataset collection
+
+    Accepts:
+        id(str): dataset id
+
+    Returns:
+        result.deleted(int): number of deleted documents
+    """
+
+    collection = "dataset"
+
+    try:
+        result = mongo_db[collection].delete_one({"_id":id})
+    except Exception as err:
+        LOG.error(err)
+        return
+    return result.deleted_count


Test patch:
diff --git a/tests/cli/add/__init__.py b/tests/cli/add/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/cli/test_add_dataset.py b/tests/cli/add/test_add_dataset.py
similarity index 97%
rename from tests/cli/test_add_dataset.py
rename to tests/cli/add/test_add_dataset.py
index 2369fff..244fc6f 100644
--- a/tests/cli/test_add_dataset.py
+++ b/tests/cli/add/test_add_dataset.py
@@ -1,11 +1,12 @@
 # -*- coding: utf-8 -*-
-from cgbeacon2.cli.commands import cli
+import datetime
 
+from cgbeacon2.cli.commands import cli
 
 def test_add_dataset_no_id(test_dataset_cli, mock_app):
     """Test the cli command which adds a dataset to db without a required param"""
 
-     # test add a dataset_obj using the app cli
+    # test add a dataset_obj using the app cli
     runner = mock_app.test_cli_runner()
 
     dataset = test_dataset_cli
@@ -174,6 +175,7 @@ def test_update_dataset(test_dataset_cli, mock_app, database):
     runner = mock_app.test_cli_runner()
 
     dataset = test_dataset_cli
+    dataset["created"] = datetime.datetime.now()
 
     # Having a database dataset collection with one item
     result = database["dataset"].insert_one(dataset)
@@ -202,3 +204,4 @@ def test_update_dataset(test_dataset_cli, mock_app, database):
     # And the dataset should be updated
     updated_dataset = database["dataset"].find_one({"_id": dataset["_id"]})
     assert updated_dataset["version"] == 2
+    assert updated_dataset["updated"] is not None
diff --git a/tests/cli/delete/__init__.py b/tests/cli/delete/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/cli/delete/test_delete_dataset.py b/tests/cli/delete/test_delete_dataset.py
new file mode 100644
index 0000000..486dade
--- /dev/null
+++ b/tests/cli/delete/test_delete_dataset.py
@@ -0,0 +1,57 @@
+# -*- coding: utf-8 -*-
+import click
+
+from cgbeacon2.cli.commands import cli
+
+def test_delete_non_existing_dataset(mock_app):
+    """Test the command to delete a dataset when dataset doesn't exist"""
+
+    # test add a dataset_obj using the app cli
+    runner = mock_app.test_cli_runner()
+
+    # When invoking the command without the -id parameter
+    result =  runner.invoke(cli, [
+        'delete',
+        'dataset',
+        '-id', 'foo'
+        ])
+
+    # Then the command should run
+    assert result.exit_code == 0
+
+    # and return a warning
+    assert "Coundn't find a dataset with id 'foo' in database" in result.output
+
+def test_delete_existing_dataset(test_dataset_cli, mock_app, database):
+    """Test the command line to delete an existing dataset"""
+
+    # test add a dataset_obj using the app cli
+    runner = mock_app.test_cli_runner()
+
+    dataset = test_dataset_cli
+
+    # When a dataset is inserted into database
+    result =  runner.invoke(cli, [
+       'add',
+       'dataset',
+       '-id', dataset["_id"],
+       '-name', dataset["name"],
+       ])
+
+    new_dataset = database["dataset"].find_one()
+    assert new_dataset is not None
+
+    # If the dataset delete command is invoked providing the right database id
+    result =  runner.invoke(cli, [
+       'delete',
+       'dataset',
+       '-id', new_dataset["_id"],
+       ])
+
+    # Then the command should be executed with no errors
+    assert result.exit_code == 0
+    assert "Dataset was successfully deleted" in result.output
+
+    # And the dataset should be removed from the database
+    new_dataset = database["dataset"].find_one()
+    assert new_dataset is None