Skip to content

Commit dba57ea

Browse files
feat(firestore): add get() method
1 parent 93a9fae commit dba57ea

File tree

2 files changed

+136
-0
lines changed

2 files changed

+136
-0
lines changed

firebase/firestore/__init__.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from google.cloud.firestore import Client
1818
from google.cloud.firestore_v1._helpers import *
1919

20+
from ._utils import _from_datastore
2021
from firebase._exception import raise_detailed_error
2122

2223

@@ -194,6 +195,57 @@ def delete(self, token=None):
194195

195196
raise_detailed_error(response)
196197

198+
def get(self, field_paths=None, token=None):
199+
""" Read data from a document in firestore.
200+
201+
202+
:type field_paths: list
203+
:param field_paths: (Optional) A list of field paths
204+
(``.``-delimited list of field names) to filter data, and
205+
return the filtered values only, defaults
206+
to :data:`None`.
207+
208+
:type token: str
209+
:param token: (Optional) Firebase Auth User ID Token, defaults
210+
to :data:`None`.
211+
212+
213+
:return: The whole data stored in the document unless filtered
214+
to retrieve specific fields.
215+
:rtype: dict
216+
"""
217+
218+
path = self._path.copy()
219+
self._path.clear()
220+
221+
if self._credentials:
222+
db_ref = _build_db(self.__datastore, path)
223+
224+
result = db_ref.get(field_paths=field_paths)
225+
226+
return result.to_dict()
227+
228+
else:
229+
230+
mask = ''
231+
232+
if field_paths:
233+
for field_path in field_paths:
234+
mask = f"{mask}mask.fieldPaths={field_path}&"
235+
236+
req_ref = f"{self._base_url}/{'/'.join(path)}?{mask}key={self._api_key}"
237+
238+
if token:
239+
headers = {"Authorization": "Firebase " + token}
240+
response = self._requests.get(req_ref, headers=headers)
241+
242+
else:
243+
response = self._requests.get(req_ref)
244+
245+
raise_detailed_error(response)
246+
247+
return _from_datastore(response.json())
248+
197249
def set(self, data, token=None):
198250
""" Add data to a document in firestore.
199251

firebase/firestore/_utils.py

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
2+
# Copyright (c) 2022 Asif Arman Rahman
3+
# Licensed under MIT (https://github.com/AsifArmanRahman/firebase/blob/main/LICENSE)
4+
5+
# --------------------------------------------------------------------------------------
6+
7+
8+
from base64 import b64decode
9+
10+
11+
def _from_datastore(data):
12+
""" Converts a map of Firestore ``data``-s to Python dictionary.
13+
14+
15+
:type data: dict
16+
:param data: A map of firestore data.
17+
18+
19+
:return: A dictionary of native Python values converted
20+
from the ``data``.
21+
:rtype: dict
22+
"""
23+
24+
data_to_restructure = data['fields']
25+
26+
for key, val in data_to_restructure.items():
27+
28+
if val.get('mapValue'):
29+
data_to_restructure[key] = _from_datastore(val['mapValue'])
30+
31+
elif val.get('arrayValue'):
32+
arr = []
33+
34+
for x in val['arrayValue']['values']:
35+
arr.append(_decode_datastore(x))
36+
37+
data_to_restructure[key] = arr
38+
39+
else:
40+
data_to_restructure[key] = _decode_datastore(val)
41+
42+
return data_to_restructure
43+
44+
45+
def _decode_datastore(value):
46+
""" Converts a Firestore ``value`` to a native Python value.
47+
48+
49+
:type value: dict
50+
:param value: A Firestore data to be decoded / parsed /
51+
converted.
52+
53+
54+
:return: A native Python value converted from the ``value``.
55+
:rtype: :data:`None` or :class:`bool` or :class:`bytes`
56+
or :class:`int` or :class:`float` or :class:`str` or
57+
:class:`dict`
58+
59+
:raises TypeError: For value types that are unsupported.
60+
"""
61+
62+
if value.get('nullValue', False) is None:
63+
return value['nullValue']
64+
65+
elif value.get('booleanValue') is not None:
66+
return bool(value['booleanValue'])
67+
68+
elif value.get('bytesValue'):
69+
return b64decode(value['bytesValue'].encode('utf-8'))
70+
71+
elif value.get('integerValue'):
72+
return int(value['integerValue'])
73+
74+
elif value.get('doubleValue'):
75+
return float(value['doubleValue'])
76+
77+
elif value.get('stringValue'):
78+
return str(value['stringValue'])
79+
80+
elif value.get('mapValue'):
81+
return _from_datastore(value['mapValue'])
82+
83+
else:
84+
raise TypeError("Cannot convert to a Python Value", value, "Invalid type", type(value))

0 commit comments

Comments
 (0)