Repository: mdowds/python-mock-firestore

Issue:
Deleting documents
Hello again! 

I also noticed that the delete() function for `DocumentReference` wasn't added.

I added the following to `main.py` as a quick fix but would love to hear your thoughts:

```    
def delete(self):
    get_by_path(self._data, self._path).clear()
```
I also tried:
```    
def delete(self):
    self.set({})
```

They both seemed to have similar behavior and passed my unit tests

Discussion:
christippett: Thought I'd help close a few other issues while I was at it. Added automatic generation of an ID when creating a new document (resolves #1).
mdowds: Hi @christippett , many thanks for the PR, and for taking on some of the issues others have raised! That all looks good to me, I'll get it merged.

Patch:
diff --git a/mockfirestore/main.py b/mockfirestore/main.py
index b660af3..f028129 100644
--- a/mockfirestore/main.py
+++ b/mockfirestore/main.py
@@ -1,4 +1,6 @@
 import operator
+import random
+import string
 from collections import OrderedDict
 from functools import reduce
 from itertools import islice
@@ -28,11 +30,21 @@ class DocumentReference:
         self._data = data
         self._path = path
 
+    @property
+    def id(self):
+        return self._path[-1]
+
     def get(self) -> DocumentSnapshot:
         return DocumentSnapshot(get_by_path(self._data, self._path))
 
-    def set(self, data: Document):
-        set_by_path(self._data, self._path, data)
+    def delete(self):
+        delete_by_path(self._data, self._path)
+
+    def set(self, data: Dict, merge=False):
+        if merge:
+            self.update(data)
+        else:
+            set_by_path(self._data, self._path, data)
 
     def update(self, data: Dict[str, Any]):
         get_by_path(self._data, self._path).update(data)
@@ -86,8 +98,10 @@ class CollectionReference:
         self._data = data
         self._path = path
 
-    def document(self, name: str) -> DocumentReference:
+    def document(self, name: Optional[str] = None) -> DocumentReference:
         collection = get_by_path(self._data, self._path)
+        if name is None:
+            name = generate_random_string()
         new_path = self._path + [name]
         if name not in collection:
             set_by_path(self._data, new_path, {})
@@ -109,6 +123,12 @@ class CollectionReference:
         collection = get_by_path(self._data, self._path)
         return Query(collection).limit(limit_amount)
 
+    def list_documents(self, page_size: Optional[int] = None) -> Sequence[DocumentReference]:
+        docs = []
+        for key in get_by_path(self._data, self._path):
+            docs.append(self.document(key))
+        return docs
+
 
 class MockFirestore:
 
@@ -132,3 +152,12 @@ def get_by_path(data: Dict[str, T], path: Sequence[str]) -> T:
 def set_by_path(data: Dict[str, T], path: Sequence[str], value: T):
     """Set a value in a nested object in root by item sequence."""
     get_by_path(data, path[:-1])[path[-1]] = value
+
+
+def delete_by_path(data: Dict[str, T], path: Sequence[str]):
+    """Delete a value in a nested object in root by item sequence."""
+    del get_by_path(data, path[:-1])[path[-1]]
+
+
+def generate_random_string():
+    return ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(20))


Test patch:
diff --git a/tests/test_collection_reference.py b/tests/test_collection_reference.py
index 0d23227..7e14e1f 100644
--- a/tests/test_collection_reference.py
+++ b/tests/test_collection_reference.py
@@ -1,6 +1,6 @@
 from unittest import TestCase
 
-from mockfirestore import MockFirestore
+from mockfirestore import MockFirestore, DocumentReference
 
 
 class TestCollectionReference(TestCase):
@@ -146,3 +146,15 @@ class TestCollectionReference(TestCase):
         docs = list(fs.collection('foo').order_by('order').limit(2).get())
         self.assertEqual({'order': 1}, docs[0].to_dict())
         self.assertEqual({'order': 2}, docs[1].to_dict())
+
+    def test_collection_listDocuments(self):
+        fs = MockFirestore()
+        fs._data = {'foo': {
+            'first': {'order': 2},
+            'second': {'order': 1},
+            'third': {'order': 3}
+        }}
+        doc_refs = list(fs.collection('foo').list_documents())
+        self.assertEqual(3, len(doc_refs))
+        for doc_ref in doc_refs:
+            self.assertIsInstance(doc_ref, DocumentReference)
diff --git a/tests/test_document_reference.py b/tests/test_document_reference.py
index e1eecfc..3e5e7e5 100644
--- a/tests/test_document_reference.py
+++ b/tests/test_document_reference.py
@@ -12,6 +12,21 @@ class TestDocumentReference(TestCase):
         doc = fs.collection('foo').document('first').get().to_dict()
         self.assertEqual({'id': 1}, doc)
 
+    def test_document_get_documentIdEqualsKey(self):
+        fs = MockFirestore()
+        fs._data = {'foo': {
+            'first': {'id': 1}
+        }}
+        doc_ref = fs.collection('foo').document('first')
+        self.assertEqual('first', doc_ref.id)
+
+    def test_document_get_newDocumentReturnsDefaultId(self):
+        fs = MockFirestore()
+        doc_ref = fs.collection('foo').document()
+        doc = doc_ref.get()
+        self.assertNotEqual(None, doc_ref.id)
+        self.assertFalse(doc.exists)
+
     def test_document_get_documentDoesNotExist(self):
         fs = MockFirestore()
         fs._data = {'foo': {}}
@@ -60,6 +75,24 @@ class TestDocumentReference(TestCase):
         doc = fs.collection('foo').document('bar').get().to_dict()
         self.assertEqual(doc_content, doc)
 
+    def test_document_set_mergeNewValue(self):
+        fs = MockFirestore()
+        fs._data = {'foo': {
+            'first': {'id': 1}
+        }}
+        fs.collection('foo').document('first').set({'updated': True}, merge=True)
+        doc = fs.collection('foo').document('first').get().to_dict()
+        self.assertEqual({'id': 1, 'updated': True}, doc)
+
+    def test_document_set_overwriteValue(self):
+        fs = MockFirestore()
+        fs._data = {'foo': {
+            'first': {'id': 1}
+        }}
+        fs.collection('foo').document('first').set({'new_id': 1}, merge=False)
+        doc = fs.collection('foo').document('first').get().to_dict()
+        self.assertEqual({'new_id': 1}, doc)
+
     def test_document_update_addNewValue(self):
         fs = MockFirestore()
         fs._data = {'foo': {
@@ -77,3 +110,12 @@ class TestDocumentReference(TestCase):
         fs.collection('foo').document('first').update({'id': 2})
         doc = fs.collection('foo').document('first').get().to_dict()
         self.assertEqual({'id': 2}, doc)
+
+    def test_document_delete_documentDoesNotExistAfterDelete(self):
+        fs = MockFirestore()
+        fs._data = {'foo': {
+            'first': {'id': 1}
+        }}
+        fs.collection('foo').document('first').delete()
+        doc = fs.collection('foo').document('first').get()
+        self.assertEqual(False, doc.exists)