Repository: mdowds/python-mock-firestore

Issue:
Query._apply_cursor is not working for first element
Hello,

Got problem with `start_after` and after some digging I found that `Query._apply_cursor` is not working properly when first doc is passed.

Let's take a look at problematic fragment:
```
        for idx, doc in enumerate(doc_snapshot):
            index = None
            for k, v in document_fields.items():
                if doc.to_dict().get(k, None) == v:
                    index = idx
                else:
                    index = None
            if index:
                if before and start:
                    return islice(docs, index, None, None)
                ...
```
We search for index of matching document in inner `for` loop but if found index equals 0 it won't go inside `if index:`

Following test will fail on current version:
```
    def test_collection_start_after(self):
        fs = MockFirestore()
        fs._data = {'foo': {
            'first': {'id': 1},
            'second': {'id': 2},
            'third': {'id': 3}
        }}
        docs = list(fs.collection('foo').start_after({'id': 1}).stream())
        self.assertEqual({'id': 2}, docs[0].to_dict())
        self.assertEqual(2, len(docs))
```

Solution:
In `_apply_cursor` add explicit check for None

`if index is not None:`


Discussion:

Patch:
diff --git a/mockfirestore/document.py b/mockfirestore/document.py
index 24c8a68..ccd3ba7 100644
--- a/mockfirestore/document.py
+++ b/mockfirestore/document.py
@@ -27,9 +27,15 @@ class DocumentSnapshot:
         timestamp = Timestamp.from_now()
         return timestamp
 
+    def get(self, field_path: str) -> Any:
+        if not self.exists:
+            return None
+        else:
+            return reduce(operator.getitem, field_path.split('.'), self._doc)
+
     def _get_by_field_path(self, field_path: str) -> Any:
         try:
-            return reduce(operator.getitem, field_path.split('.'), self._doc)
+            return self.get(field_path)
         except KeyError:
             return None
 
diff --git a/mockfirestore/query.py b/mockfirestore/query.py
index a17c12f..354df4b 100644
--- a/mockfirestore/query.py
+++ b/mockfirestore/query.py
@@ -103,7 +103,7 @@ class Query:
                     index = idx
                 else:
                     index = None
-            if index:
+            if index is not None:
                 if before and start:
                     return islice(docs, index, None, None)
                 elif not before and start:


Test patch:
diff --git a/tests/test_collection_reference.py b/tests/test_collection_reference.py
index 0eeadaf..5507811 100644
--- a/tests/test_collection_reference.py
+++ b/tests/test_collection_reference.py
@@ -232,7 +232,7 @@ class TestCollectionReference(TestCase):
         docs = list(fs.collection('foo').start_at({'id': 2}).stream())
         self.assertEqual({'id': 2}, docs[0].to_dict())
         self.assertEqual(2, len(docs))
-    
+
     def test_collection_start_at_order_by(self):
         fs = MockFirestore()
         fs._data = {'foo': {
@@ -251,9 +251,9 @@ class TestCollectionReference(TestCase):
             'second': {'id': 2},
             'third': {'id': 3}
         }}
-        docs = list(fs.collection('foo').start_after({'id': 2}).stream())
-        self.assertEqual({'id': 3}, docs[0].to_dict())
-        self.assertEqual(1, len(docs))
+        docs = list(fs.collection('foo').start_after({'id': 1}).stream())
+        self.assertEqual({'id': 2}, docs[0].to_dict())
+        self.assertEqual(2, len(docs))
 
     def test_collection_start_after_order_by(self):
         fs = MockFirestore()
@@ -298,7 +298,7 @@ class TestCollectionReference(TestCase):
         docs = list(fs.collection('foo').end_at({'id': 2}).stream())
         self.assertEqual({'id': 2}, docs[1].to_dict())
         self.assertEqual(2, len(docs))
-    
+
     def test_collection_end_at_order_by(self):
         fs = MockFirestore()
         fs._data = {'foo': {
diff --git a/tests/test_document_snapshot.py b/tests/test_document_snapshot.py
index 19cce06..7d60e4b 100644
--- a/tests/test_document_snapshot.py
+++ b/tests/test_document_snapshot.py
@@ -46,3 +46,45 @@ class TestDocumentSnapshot(TestCase):
         doc_snapshot = doc_ref.get()
         self.assertIs(doc_ref, doc_snapshot.reference)
 
+    def test_documentSnapshot_get_by_existing_field_path(self):
+        fs = MockFirestore()
+        fs._data = {'foo': {
+            'first': {'id': 1, 'contact': {
+                'email': 'email@test.com'
+            }}
+        }}
+        doc = fs.collection('foo').document('first').get()
+        self.assertEqual(doc.get('contact.email'), 'email@test.com')
+
+    def test_documentSnapshot_get_by_non_existing_field_path(self):
+        fs = MockFirestore()
+        fs._data = {'foo': {
+            'first': {'id': 1, 'contact': {
+                'email': 'email@test.com'
+            }}
+        }}
+        doc = fs.collection('foo').document('first').get()
+        with self.assertRaises(KeyError):
+            doc.get('contact.phone')
+
+    def test_documentSnapshot_get_in_an_non_existing_document(self):
+        fs = MockFirestore()
+        fs._data = {'foo': {
+            'first': {'id': 1, 'contact': {
+                'email': 'email@test.com'
+            }}
+        }}
+        doc = fs.collection('foo').document('second').get()
+        self.assertIsNone(doc.get('contact.email'))
+
+    def test_documentSnapshot_get_returns_a_copy_of_the_data_stored(self):
+        fs = MockFirestore()
+        fs._data = {'foo': {
+            'first': {'id': 1, 'contact': {
+                'email': 'email@test.com'
+            }}
+        }}
+        doc = fs.collection('foo').document('first').get()
+        self.assertIsNot(
+            doc.get('contact'),fs._data['foo']['first']['contact']
+        )