Skip to content

Commit df7030c

Browse files
committed
idsync: collect assigned UIDs for fast lookup + unit test #25
1 parent 7b3b6f1 commit df7030c

2 files changed

Lines changed: 49 additions & 20 deletions

File tree

objectbox/model/idsync.py

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ def __init__(self, model: Model, model_json_filepath: str):
2121

2222
self.model_filepath = model_json_filepath
2323
self.model_json = None
24+
25+
self._assigned_uids: Set[int] = set()
26+
2427
self._load_model_json()
2528

2629
def _load_model_json(self):
@@ -35,6 +38,16 @@ def _load_model_json(self):
3538
self.model_json = json.load(model_file)
3639
logger.debug(f"Syncing model with model file: {self.model_filepath}")
3740

41+
self._load_assigned_uids()
42+
43+
def _load_assigned_uids(self):
44+
for entity_json in self.model_json["entities"]:
45+
self._assigned_uids.add(IdUid.from_str(entity_json["id"]).uid)
46+
for prop_json in entity_json["properties"]:
47+
self._assigned_uids.add(IdUid.from_str(prop_json["id"]).uid)
48+
if "indexId" in prop_json:
49+
self._assigned_uids.add(IdUid.from_str(prop_json["indexId"]).uid)
50+
3851
def _save_model_json(self):
3952
""" Replaces model JSON with the serialized model whose ID/UIDs are assigned. """
4053

@@ -119,31 +132,20 @@ def _find_property_json_by_name(self, entity_json: Dict[str, Any], prop_name: st
119132
return prop_json
120133
return None
121134

122-
@staticmethod
123-
def _generate_uid() -> int:
124-
return random.getrandbits(63) + 1 # 0 would be invalid
135+
def _generate_uid(self) -> int:
136+
while True:
137+
generated_uid = random.getrandbits(63) + 1 # 0 would be invalid
138+
if generated_uid not in self._assigned_uids:
139+
break
140+
self._assigned_uids.add(generated_uid)
141+
return generated_uid
125142

126143
def _validate_uid_unassigned(self, uid: int):
127-
# TODO use a dict/set for all assigned UIDs (for all entities/properties/indexes) for faster lookup
128144
""" Validates that a user supplied UID is not assigned for any other entity/property/index.
129145
Raises a ValueError if the UID is already assigned elsewhere.
130146
"""
131-
132-
try:
133-
entity_json = self._find_entity_json_by_uid(uid)
134-
if entity_json is not None:
135-
raise ValueError(f"in Entity \"{entity_json['name']}\" ({entity_json['id']})")
136-
137-
for entity_json in self.model_json["entities"]:
138-
prop_json = self._find_property_json_by_uid(entity_json, uid)
139-
if prop_json is not None:
140-
raise ValueError(f"in Property \"{entity_json['name']}.{prop_json['name']}\" ({prop_json['id']})")
141-
for prop_json in entity_json["properties"]:
142-
if "indexId" in prop_json and IdUid.from_str(prop_json["indexId"]).uid == uid:
143-
raise ValueError(
144-
f"in Property index \"{entity_json['name']}.{prop_json['name']}\" ({prop_json['id']})")
145-
except ValueError as error:
146-
raise ValueError(f"User supplied UID \"{uid}\" found {error}")
147+
if uid in self._assigned_uids:
148+
raise ValueError(f"User supplied UID {uid} is already assigned elsewhere")
147149

148150
def _validate_matching_prop(self, entity: _Entity, prop: Property, prop_json: Dict[str, Any]):
149151
""" Validates that the given property matches the JSON property. """

tests/test_idsync.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,3 +468,30 @@ class EntityD:
468468
name = String()
469469
age = Int8()
470470
assert_model_json_written(True, EntityD)
471+
472+
473+
def test_model_uid_already_assigned(env):
474+
""" Tests an invalid situation where the user supplies a UID which is already present elsewhere in the JSON. """
475+
476+
@Entity()
477+
class EntityA:
478+
id = Id()
479+
prop = Property(str)
480+
481+
model = Model()
482+
model.entity(EntityA)
483+
env.sync(model)
484+
485+
entitya_uid = EntityA.uid
486+
487+
# Rename property, but use a UID which is already assigned
488+
@Entity()
489+
class EntityA:
490+
id = Id()
491+
renamed_prop = Property(str, uid=entitya_uid)
492+
493+
model = Model()
494+
model.entity(EntityA)
495+
with pytest.raises(ValueError) as e:
496+
env.sync(model)
497+
assert f"User supplied UID {entitya_uid} is already assigned elsewhere" == str(e.value)

0 commit comments

Comments
 (0)