Skip to content

Commit 0ea9979

Browse files
authored
Merge pull request #226 from poissoncorp/RDBC-839
RDBC-839 Use find_identity_property - implement get identity property
2 parents 9f371a1 + 1dbd814 commit 0ea9979

File tree

12 files changed

+407
-294
lines changed

12 files changed

+407
-294
lines changed

ravendb/documents/bulk_insert_operation.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
from ravendb.http.server_node import ServerNode
2626
from ravendb.http.raven_command import RavenCommand
2727
from ravendb.documents.operations.misc import GetOperationStateOperation
28-
from ravendb.documents.session.entity_to_json import EntityToJson
28+
from ravendb.documents.session.entity_to_json import EntityToJsonStatic
2929
from ravendb.documents.session.document_info import DocumentInfo
3030
from ravendb.json.metadata_as_dictionary import MetadataAsDictionary
3131
from ravendb.documents.commands.batches import CommandType
@@ -322,7 +322,7 @@ def _write_string_no_escape(self, data: str) -> None:
322322

323323
def _write_document(self, entity: object, metadata: MetadataAsDictionary):
324324
document_info = DocumentInfo(metadata_instance=metadata)
325-
json_dict = EntityToJson.convert_entity_to_json_internal_static(entity, self._conventions, document_info, True)
325+
json_dict = EntityToJsonStatic.convert_entity_to_json(entity, self._conventions, document_info, True)
326326
self._current_data_buffer += bytearray(json.dumps(json_dict), encoding="utf-8")
327327

328328
def _ensure_ongoing_operation(self) -> None:

ravendb/documents/conventions.py

Lines changed: 42 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from abc import abstractmethod, ABC
66
from datetime import timedelta, datetime
77
from enum import Enum
8-
from typing import Dict, List, Tuple, Callable, Union, Optional, Generic, Type
8+
from typing import Dict, List, Tuple, Callable, Union, Optional, Generic, Type, Any, TYPE_CHECKING
99

1010
import inflect
1111

@@ -25,6 +25,11 @@
2525

2626
_T = TypeVar("_T")
2727

28+
if TYPE_CHECKING:
29+
from ravendb.documents.session.document_session_operations.in_memory_document_session_operations import (
30+
InMemoryDocumentSessionOperations,
31+
)
32+
2833

2934
class DocumentConventions(object):
3035
@classmethod
@@ -63,7 +68,8 @@ def __init__(self):
6368

6469
# Utilities
6570
self.document_id_generator: Optional[Callable[[str, object], str]] = None
66-
self._find_identity_property = lambda q: q.__name__ == "key"
71+
self._find_identity_property_name: Callable[[Type[Any]], str] = lambda type_: "Id"
72+
self._id_property_name_cache: Dict[Type, str] = {}
6773
self._find_python_class: Optional[Callable[[str, Dict], str]] = None
6874
self._find_collection_name: Callable[[Type], str] = self.default_get_collection_name
6975
self._find_collection_name_for_dict: Callable[[str], str] = self.default_get_collection_name_for_dict
@@ -106,7 +112,7 @@ def find_collection_name(self) -> Callable[[type], str]:
106112

107113
@find_collection_name.setter
108114
def find_collection_name(self, value) -> None:
109-
self.__assert_not_frozen()
115+
self._assert_not_frozen()
110116
self._find_collection_name = value
111117

112118
@property
@@ -122,7 +128,7 @@ def __default(key: str, doc: Dict) -> Optional[str]:
122128

123129
@find_python_class.setter
124130
def find_python_class(self, value: Callable[[str, Dict], str]):
125-
self.__assert_not_frozen()
131+
self._assert_not_frozen()
126132
self._find_python_class = value
127133

128134
def get_python_class(self, key: str, document: Dict) -> str:
@@ -134,7 +140,7 @@ def transform_class_collection_name_to_document_id_prefix(self) -> Callable[[str
134140

135141
@transform_class_collection_name_to_document_id_prefix.setter
136142
def transform_class_collection_name_to_document_id_prefix(self, value: Callable[[str], str]) -> None:
137-
self.__assert_not_frozen()
143+
self._assert_not_frozen()
138144
self._transform_class_collection_name_to_document_id_prefix = value
139145

140146
@property
@@ -167,7 +173,7 @@ def find_python_class_name(self) -> Callable[[type], str]:
167173

168174
@find_python_class_name.setter
169175
def find_python_class_name(self, value) -> None:
170-
self.__assert_not_frozen()
176+
self._assert_not_frozen()
171177
self._find_python_class_name = value
172178

173179
@property
@@ -176,7 +182,7 @@ def should_ignore_entity_changes(self) -> ShouldIgnoreEntityChanges:
176182

177183
@should_ignore_entity_changes.setter
178184
def should_ignore_entity_changes(self, value: ShouldIgnoreEntityChanges) -> None:
179-
self.__assert_not_frozen()
185+
self._assert_not_frozen()
180186
self._should_ignore_entity_changes = value
181187

182188
@property
@@ -185,7 +191,7 @@ def load_balancer_context_seed(self) -> int:
185191

186192
@load_balancer_context_seed.setter
187193
def load_balancer_context_seed(self, value: int):
188-
self.__assert_not_frozen()
194+
self._assert_not_frozen()
189195
self._load_balancer_context_seed = value
190196

191197
@property
@@ -194,7 +200,7 @@ def load_balance_behavior(self):
194200

195201
@load_balance_behavior.setter
196202
def load_balance_behavior(self, value: LoadBalanceBehavior):
197-
self.__assert_not_frozen()
203+
self._assert_not_frozen()
198204
self._load_balance_behavior = value
199205

200206
@property
@@ -203,7 +209,7 @@ def read_balance_behavior(self) -> ReadBalanceBehavior:
203209

204210
@read_balance_behavior.setter
205211
def read_balance_behavior(self, value: ReadBalanceBehavior):
206-
self.__assert_not_frozen()
212+
self._assert_not_frozen()
207213
self._read_balance_behavior = value
208214

209215
@property
@@ -216,9 +222,17 @@ def disable_atomic_document_writes_in_cluster_wide_transaction(self) -> bool:
216222

217223
@disable_atomic_document_writes_in_cluster_wide_transaction.setter
218224
def disable_atomic_document_writes_in_cluster_wide_transaction(self, value: bool):
219-
self.__assert_not_frozen()
225+
self._assert_not_frozen()
220226
self._disable_atomic_document_writes_in_cluster_wide_transaction = value
221227

228+
@property
229+
def find_identity_property_name(self) -> Callable[[Type[Any]], str]:
230+
return self._find_identity_property_name
231+
232+
@find_identity_property_name.setter
233+
def find_identity_property_name(self, find_identity_property_name_function: Callable[[Type[Any]], str]):
234+
self._find_identity_property_name = find_identity_property_name_function
235+
222236
@staticmethod
223237
def json_default(o):
224238
if o is None:
@@ -325,7 +339,7 @@ def default_get_collection_name_for_dict(key: str) -> str:
325339
return result
326340

327341
@staticmethod
328-
def try_get_type_from_metadata(metadata):
342+
def try_get_type_from_metadata(metadata: Dict[str, Any]) -> Optional[str]:
329343
if "Raven-Python-Type" in metadata:
330344
return metadata["Raven-Python-Type"]
331345
return None
@@ -355,7 +369,7 @@ def range_field_name(field_name, type_name):
355369

356370
return field_name
357371

358-
def __assert_not_frozen(self) -> None:
372+
def _assert_not_frozen(self) -> None:
359373
if self._frozen:
360374
raise RuntimeError(
361375
"Conventions has been frozen after documentStore.initialize()" " and no changes can be applied to them"
@@ -370,7 +384,7 @@ def clone(self) -> DocumentConventions:
370384
cloned._save_enums_as_integers = self._save_enums_as_integers
371385
cloned.identity_parts_separator = self.identity_parts_separator
372386
cloned.disable_topology_updates = self.disable_topology_updates
373-
cloned._find_identity_property = self._find_identity_property
387+
cloned._find_identity_property_name = self._find_identity_property_name
374388

375389
cloned.document_id_generator = self.document_id_generator
376390

@@ -384,6 +398,19 @@ def clone(self) -> DocumentConventions:
384398
cloned._read_balance_behavior = self._read_balance_behavior
385399
cloned._load_balance_behavior = self._load_balance_behavior
386400
self._max_http_cache_size = self._max_http_cache_size
401+
return cloned
402+
403+
def get_identity_property_name(self, object_type: Type[Any]) -> Optional[str]:
404+
# Check the cache first
405+
if object_type in self._id_property_name_cache:
406+
return self._id_property_name_cache[object_type]
407+
408+
id_property_name = self.find_identity_property_name(object_type)
409+
410+
# Cache the result
411+
self._id_property_name_cache[object_type] = id_property_name
412+
413+
return id_property_name
387414

388415
def update_from(self, configuration: ClientConfiguration):
389416
if configuration.disabled and self._original_configuration is None:
@@ -479,7 +506,7 @@ def update_from(self, configuration: ClientConfiguration):
479506

480507
@staticmethod
481508
def default_transform_collection_name_to_document_id_prefix(collection_name: str) -> str:
482-
upper_count = len(list(filter(str.isupper, collection_name)))
509+
upper_count = len(list(filter(str.isupper, [char for char in collection_name])))
483510
if upper_count <= 1:
484511
return collection_name.lower()
485512

ravendb/documents/identity/hilo.py

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from __future__ import annotations
22
import datetime
33
from threading import Lock
4-
from typing import Any, Union, Optional, Iterable, Dict, Tuple, Callable
4+
from typing import Any, Union, Optional, Iterable, Dict, Tuple, Callable, Type
55

66
from typing import TYPE_CHECKING
77

@@ -15,22 +15,27 @@
1515

1616
class GenerateEntityIdOnTheClient:
1717
def __init__(self, conventions: "DocumentConventions", generate_id: Callable[[Any], str]):
18-
self.__conventions = conventions
19-
self.__generate_id = generate_id
18+
self._conventions = conventions
19+
self._generate_id = generate_id
20+
21+
def get_identity_property_name(self, object_type: Type[Any]) -> str:
22+
return self._conventions.get_identity_property_name(object_type)
2023

2124
def try_get_id_from_instance(self, entity: Union[object, dict]) -> Tuple[bool, Union[str, None]]:
2225
if not entity:
2326
raise ValueError("Entity cannot be None")
24-
identity_property = "Id" # todo: make sure it's ok, create get_identity_property within conventions if not
27+
28+
identity_property = self.get_identity_property_name(entity.__class__)
29+
2530
value = (entity if isinstance(entity, dict) else entity.__dict__).get(identity_property, None)
2631
if isinstance(value, str):
2732
return True, value
2833
return False, None
2934

3035
def get_or_generate_document_id(self, entity) -> str:
31-
key = self.try_get_id_from_instance(entity)[1]
32-
if key is None:
33-
key = self.__generate_id(entity)
36+
success, key = self.try_get_id_from_instance(entity)
37+
if not success:
38+
key = self._generate_id(entity)
3439

3540
if key and key.startswith("/"):
3641
raise ValueError(f"Cannot use value '{key}' as a document id because it begins with a '/'")
@@ -43,22 +48,22 @@ def generate_document_key_for_storage(self, entity: object) -> str:
4348
return key
4449

4550
def try_set_identity(self, entity: object, key: str, is_projection: bool = False) -> None:
46-
self.__try_set_identity_internal(entity, key, is_projection)
51+
self._try_set_identity_internal(entity, key, is_projection)
4752

48-
def __try_set_identity_internal(self, entity: Union[object, dict], key: str, is_projection: bool = False) -> None:
49-
identity_property = "Id" # todo: get_identity_property...
53+
def _try_set_identity_internal(self, entity: Union[object, dict], key: str, is_projection: bool = False) -> None:
54+
identity_property_name = self._conventions.get_identity_property_name(entity.__class__)
5055

51-
if identity_property is None:
56+
if identity_property_name is None:
5257
return
5358

54-
if is_projection and entity.__getattribute__(identity_property):
59+
if is_projection and entity.__getattribute__(identity_property_name):
5560
# identity property was already set
5661
return
5762

5863
if isinstance(entity, dict):
59-
entity[identity_property] = key
64+
entity[identity_property_name] = key
6065
return
61-
entity.__setattr__(identity_property, key)
66+
entity.__setattr__(identity_property_name, key)
6267

6368

6469
class MultiDatabaseHiLoGenerator:

ravendb/documents/operations/compare_exchange/compare_exchange.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from ravendb.documents.session.document_session_operations.misc import _update_metadata_modifications
1010
from ravendb.exceptions.raven_exceptions import RavenException
1111
from ravendb.json.metadata_as_dictionary import MetadataAsDictionary
12-
from ravendb.documents.session.entity_to_json import EntityToJson
12+
from ravendb.documents.session.entity_to_json import EntityToJsonStatic
1313
from ravendb.tools.utils import Utils
1414

1515
_T = TypeVar("_T")
@@ -148,7 +148,7 @@ def get_command(
148148
if not self.__value:
149149
return None
150150

151-
entity = EntityToJson.convert_entity_to_json_internal_static(self.__value.value, conventions, None, False)
151+
entity = EntityToJsonStatic.convert_entity_to_json(self.__value.value, conventions, None, False)
152152

153153
entity_json = entity if isinstance(entity, dict) else None
154154
metadata = (
@@ -229,7 +229,7 @@ def update_value(self, value: CompareExchangeValue):
229229
self.__value.index = self._index
230230

231231
if self.__value.value is not None:
232-
EntityToJson.populate_entity_static(self.__value.value, value.value)
232+
EntityToJsonStatic.populate_entity(self.__value.value, value.value)
233233

234234
@staticmethod
235235
def prepare_metadata_for_put(

0 commit comments

Comments
 (0)