Skip to content

Commit 338104e

Browse files
committed
RDBC-664 Provide better comments and simplify convert_to_entity_static, add the test for documents serialization when no object_type specified
1 parent b2eccad commit 338104e

File tree

2 files changed

+89
-22
lines changed

2 files changed

+89
-22
lines changed

ravendb/documents/session/entity_to_json.py

Lines changed: 51 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -146,75 +146,104 @@ def convert_to_entity_by_key_static(
146146
except Exception as e:
147147
raise RuntimeError(f"Could not convert document {key} to entity of type {entity_class}", e)
148148

149+
@staticmethod
150+
def _invoke_after_conversion_to_entity_event(
151+
session_hook: Optional["InMemoryDocumentSessionOperations"],
152+
key: str,
153+
object_type: Optional[_T],
154+
document_deepcopy: dict,
155+
):
156+
if session_hook:
157+
session_hook.after_conversion_to_entity_invoke(
158+
AfterConversionToEntityEventArgs(session_hook, key, object_type, document_deepcopy)
159+
)
160+
149161
@staticmethod
150162
def convert_to_entity_static(
151163
document: dict,
152164
object_type: [_T],
153165
conventions: "DocumentConventions",
154166
session_hook: Optional["InMemoryDocumentSessionOperations"] = None,
155167
) -> _T:
168+
# This method has two steps - extract the type (I), and then convert it into the entity (II)
169+
# todo: Separate it into two different functions and isolate the return statements from the first part
170+
171+
# I. Extract the object type
156172
metadata = document.pop("@metadata")
157173
document_deepcopy = deepcopy(document)
174+
175+
# 1. Get type from metadata
158176
type_from_metadata = conventions.try_get_type_from_metadata(metadata)
159-
is_inherit = False
177+
is_projection = False
160178
key = metadata.get(constants.Documents.Metadata.ID, None)
179+
180+
# Fire before conversion to entity events
161181
if session_hook:
162182
session_hook.before_conversion_to_entity_invoke(
163183
BeforeConversionToEntityEventArgs(session_hook, key, object_type, document_deepcopy)
164184
)
165185

186+
# 1.1 Check if passed object type (or extracted from metadata) is a dictionary
166187
if object_type == dict or type_from_metadata == "builtins.dict":
167-
session_hook.after_conversion_to_entity_invoke(
168-
AfterConversionToEntityEventArgs(session_hook, key, document_deepcopy, document_deepcopy)
169-
)
188+
EntityToJson._invoke_after_conversion_to_entity_event(session_hook, key, object_type, document_deepcopy)
170189
return document_deepcopy
171190

191+
# 1.2 If there's no object type in metadata
172192
if type_from_metadata is None:
193+
# 1.2.1 Try to set it with passed object type
173194
if object_type is not None:
174195
metadata["Raven-Python-Type"] = "{0}.{1}".format(object_type.__module__, object_type.__name__)
175-
else: # no type defined on document or during load, return a dict
196+
# 1.2.2 no type defined on document or during load, return a dict
197+
else:
176198
dyn = _DynamicStructure(**document_deepcopy)
177-
if session_hook:
178-
session_hook.after_conversion_to_entity_invoke(
179-
AfterConversionToEntityEventArgs(session_hook, key, document_deepcopy, dyn)
180-
)
199+
EntityToJson._invoke_after_conversion_to_entity_event(session_hook, key, object_type, document_deepcopy)
181200
return dyn
201+
202+
# 2. There was a type in the metadata
182203
else:
183204
object_from_metadata = Utils.import_class(type_from_metadata)
205+
# 2.1 Import was successful
184206
if object_from_metadata is not None:
185-
if object_type is None:
207+
# 2.1.1 Set object_type to successfully imported type/ from metadata inherits from passed object_type
208+
if object_type is None or Utils.is_inherit(object_type, object_from_metadata):
186209
object_type = object_from_metadata
187210

188-
elif Utils.is_inherit(object_type, object_from_metadata):
189-
object_type = object_from_metadata
190-
is_inherit = True
211+
# 2.1.2 Passed type is not a type from metadata, neither there's no inheritance - probably projection
191212
elif object_type is not object_from_metadata:
192-
# todo: projection
213+
is_projection = True
193214
if not all([name in object_from_metadata.__dict__ for name in object_type.__dict__]):
194215
raise exceptions.InvalidOperationException(
195216
f"Cannot covert document from type {object_from_metadata} to {object_type}"
196217
)
218+
219+
# We have object type set - it was either extracted or passed through args
220+
221+
# II. Conversion to entity part
222+
223+
# By custom defined 'from_json' serializer class method
197224
# todo: make separate interface to do from_json
198225
if "from_json" in object_type.__dict__ and inspect.ismethod(object_type.from_json):
199226
entity = object_type.from_json(document_deepcopy)
200227

201-
elif is_inherit:
202-
entity = Utils.convert_json_dict_to_object(document_deepcopy, object_type)
203-
204-
else:
228+
# By projection
229+
elif is_projection:
205230
entity = _DynamicStructure(**document_deepcopy)
206231
entity.__class__ = object_type
207232
try:
208233
entity = Utils.initialize_object(document_deepcopy, object_type)
209234
except TypeError as e:
210235
raise InvalidOperationException("Probably projection error", e)
211236

237+
# Happy path - successful extraction of the type from metadata, if not - got object_type passed to arguments
238+
else:
239+
entity = Utils.convert_json_dict_to_object(document_deepcopy, object_type)
240+
241+
EntityToJson._invoke_after_conversion_to_entity_event(session_hook, key, object_type, document_deepcopy)
242+
243+
# Try to set Id
212244
if "Id" in entity.__dict__:
213245
entity.Id = metadata.get("@id", None)
214-
if session_hook:
215-
session_hook.after_conversion_to_entity_invoke(
216-
AfterConversionToEntityEventArgs(session_hook, key, document_deepcopy, entity)
217-
)
246+
218247
return entity
219248

220249
def remove_from_missing(self, entity):
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
from ravendb import DocumentStore
2+
import numpy as np
3+
4+
from ravendb.tests.test_base import TestBase
5+
6+
7+
class DocName(dict):
8+
def __init__(self, x, y):
9+
super().__init__()
10+
self["x"] = x
11+
self["y"] = y
12+
self["z"] = 123
13+
14+
15+
class TestRDBC664(TestBase):
16+
def setUp(self):
17+
super(TestRDBC664, self).setUp()
18+
19+
def write_to_ravenDB(self, array1, array2, store: DocumentStore):
20+
with store.open_session() as session:
21+
for x, y in zip(array1, array2):
22+
x, y = int(x), int(y)
23+
input_to_store = DocName(x, y)
24+
session.store(input_to_store, "abc_%d" % x)
25+
26+
session.save_changes()
27+
28+
def query_ravenDB(self, query_string, store: DocumentStore):
29+
with store.open_session() as session:
30+
results = session.advanced.raw_query(query_string).wait_for_non_stale_results()
31+
print(results)
32+
for r in results:
33+
print(r)
34+
35+
def test_can_deserialize_documents_after_raw_query_with_no_object_type_specified(self):
36+
arr = np.arange(0, 10, 1)
37+
self.write_to_ravenDB(arr, arr * 3, self.store)
38+
self.query_ravenDB("from 'DocNames' where z==123", self.store)

0 commit comments

Comments
 (0)