Skip to content

Commit d145422

Browse files
greenrobotloryruta
authored andcommitted
IdSync: write property flags to JSON only if non-zero #25
Also, add some TODOs to add dicts for faster lookups
1 parent f228834 commit d145422

3 files changed

Lines changed: 67 additions & 15 deletions

File tree

example/ollama/objectbox-model.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@
1818
{
1919
"id": "2:7160924628219144152",
2020
"name": "document",
21-
"type": 9,
22-
"flags": 0
21+
"type": 9
2322
},
2423
{
2524
"id": "3:1544317969640594905",

objectbox/model/idsync.py

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@
1010

1111

1212
class IdSync:
13+
"""
14+
Synchronizes a model with the IDs from model JSON file.
15+
After syncing, the model will have all IDs assigned.
16+
The JSON file is written (from scratch) based on the model.
17+
"""
18+
1319
def __init__(self, model: Model, model_json_filepath: str):
1420
self.model = model
1521

@@ -63,8 +69,9 @@ def _save_model_json(self):
6369
"id": str(prop.iduid),
6470
"name": prop.name,
6571
"type": prop._ob_type,
66-
"flags": prop._flags
6772
}
73+
if prop._flags != 0:
74+
prop_json["flags"] = prop._flags
6875
if prop.index is not None:
6976
prop_json["indexId"] = str(prop.index.iduid)
7077
entity_json["properties"].append(prop_json)
@@ -80,6 +87,7 @@ def _find_entity_json_by_uid(self, uid: int) -> Optional[Dict[str, Any]]:
8087
""" Finds entity JSON by UID. """
8188
if self.model_json is None:
8289
return None
90+
# TODO put entities in a dict (e.g. while/after loading) for faster lookup
8391
for entity_json in self.model_json["entities"]:
8492
if IdUid.from_str(entity_json["id"]).uid == uid:
8593
return entity_json
@@ -89,20 +97,23 @@ def _find_entity_json_by_name(self, entity_name: str) -> Optional[Dict[str, Any]
8997
""" Finds entity JSON by name. """
9098
if self.model_json is None:
9199
return None
100+
# TODO put entities in a dict (e.g. while/after loading) for faster lookup
92101
for entity_json in self.model_json["entities"]:
93102
if entity_json["name"] == entity_name:
94103
return entity_json
95104
return None
96105

97106
def _find_property_json_by_uid(self, entity_json: Dict[str, Any], uid: int) -> Optional[Dict[str, Any]]:
98107
""" Finds entity property JSON by property UID. """
108+
# TODO put properties in a multi-dict (e.g. while/after loading) for faster lookup
99109
for prop_json in entity_json["properties"]:
100110
if IdUid.from_str(prop_json["id"]).uid == uid:
101111
return prop_json
102112
return None
103113

104114
def _find_property_json_by_name(self, entity_json: Dict[str, Any], prop_name: str) -> Optional[Dict[str, Any]]:
105115
""" Finds entity property JSON by property name. """
116+
# TODO put properties in a multi-dict (e.g. while/after loading) for faster lookup
106117
for prop_json in entity_json["properties"]:
107118
if prop_json["name"] == prop_name:
108119
return prop_json
@@ -113,6 +124,7 @@ def _generate_uid() -> int:
113124
return random.getrandbits(63) + 1 # 0 would be invalid
114125

115126
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
116128
""" Validates that a user supplied UID is not assigned for any other entity/property/index.
117129
Raises a ValueError if the UID is already assigned elsewhere.
118130
"""
@@ -141,9 +153,12 @@ def _validate_matching_prop(self, entity: _Entity, prop: Property, prop_json: Di
141153
# raise ValueError(f"name {prop.name} != name {prop_json['name']} (in JSON)")
142154
if prop._ob_type != prop_json["type"]:
143155
raise ValueError(f"OBX type {prop._ob_type} != OBX type {prop_json['type']} (in JSON)")
144-
elif prop._flags != prop_json["flags"]:
145-
raise ValueError(f"flags {prop._flags} != flags {prop_json['flags']} (in JSON)")
146-
elif prop.index is None and "indexId" in prop_json:
156+
157+
json_flags = prop_json.get("flags", 0)
158+
if prop._flags != json_flags:
159+
raise ValueError(f"flags {prop._flags} != flags {json_flags} (in JSON)")
160+
161+
if prop.index is None and "indexId" in prop_json:
147162
raise ValueError("property hasn't index, but index found in JSON")
148163
elif prop.index is not None and "indexId" not in prop_json:
149164
raise ValueError("property has index, but index not found in JSON")
@@ -169,7 +184,7 @@ def _load_or_assign_index(self, entity: _Entity, prop: Property, prop_json: Opti
169184

170185
if (iduid_json is not None) and (not index.has_uid() or index.iduid.uid == iduid_json.uid): # Load
171186
index.iduid = IdUid.from_str(prop_json["indexId"])
172-
else: # Assign
187+
else: # Assign new ID to new index
173188
index.iduid = IdUid(self.model.last_index_iduid.id + 1, index.uid)
174189
self.model.last_index_iduid = index.iduid
175190

@@ -186,11 +201,11 @@ def _load_or_assign_property(self, entity: _Entity, prop: Property, entity_json:
186201
if entity_json is not None:
187202
prop_json = self._find_property_json_by_name(entity_json, prop.name)
188203

189-
if prop_json is not None: # Load
204+
if prop_json is not None: # Load existing IDs from JSON
190205
# Property was matched with a JSON property (either by UID or by name), make sure they're equal
191206
self._validate_matching_prop(entity, prop, prop_json)
192207
prop.iduid = IdUid.from_str(prop_json["id"])
193-
else: # Assign
208+
else: # Assign new ID to new property
194209
if not prop.has_uid():
195210
prop.iduid.uid = self._generate_uid()
196211
prop.iduid = IdUid(entity.last_property_iduid.id + 1, prop.iduid.uid)
@@ -209,10 +224,10 @@ def _load_or_assign_entity(self, entity: _Entity):
209224
else:
210225
entity_json = self._find_entity_json_by_name(entity.name)
211226

212-
if entity_json is not None: # Load
227+
if entity_json is not None: # Load existing IDs from JSON
213228
entity.iduid = IdUid.from_str(entity_json["id"])
214229
entity.last_property_iduid = IdUid.from_str(entity_json["lastPropertyId"])
215-
else: # Assign
230+
else: # Assign new ID to new entity
216231
if not entity.has_uid():
217232
entity.iduid.uid = self._generate_uid()
218233
entity.iduid = IdUid(self.model.last_entity_iduid.id + 1, entity.iduid.uid)

tests/test_idsync.py

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,25 +64,63 @@ def test_empty(env):
6464
# assert len(doc['retiredRelationUids']) == 0
6565
# assert len(doc['version']) == 1
6666

67-
def test_basics(env):
67+
68+
def test_json(env):
6869
@Entity()
6970
class MyEntity:
7071
id = Id()
71-
name = String()
72+
my_string = String()
73+
my_string_indexed = String(index=Index())
74+
7275
model = Model()
7376
model.entity(MyEntity)
7477
env.sync(model)
7578
doc = env.json()
76-
# debug: pprint(doc)
79+
# debug: pprint(doc)
80+
7781
json_e0 = doc['entities'][0]
7882
e0_id = json_e0['id']
7983
assert e0_id == str(MyEntity.iduid)
8084
assert e0_id.startswith("1:")
8185
assert json_e0['name'] == "MyEntity"
86+
8287
json_p0 = json_e0['properties'][0]
8388
p0_id = json_p0['id']
8489
assert p0_id == str(MyEntity.get_property('id').iduid)
8590
assert p0_id.startswith("1:")
91+
assert json_p0['name'] == "id"
92+
assert json_p0['flags'] == 1
93+
assert json_p0.get('indexId') is None
94+
95+
json_p1 = json_e0['properties'][1]
96+
assert json_p1['id'] == str(MyEntity.get_property('my_string').iduid)
97+
assert json_p1['name'] == "my_string"
98+
assert json_p1.get('flags') is None
99+
assert json_p1.get('indexId') is None
100+
101+
json_p2 = json_e0['properties'][2]
102+
assert json_p2['id'] == str(MyEntity.get_property('my_string_indexed').iduid)
103+
assert json_p2['name'] == "my_string_indexed"
104+
assert json_p2['flags'] == 8
105+
assert json_p2['indexId'] == str(MyEntity.get_property('my_string_indexed').index.iduid)
106+
assert json_e0['lastPropertyId'] == json_p2['id']
107+
108+
assert doc['lastEntityId'] == e0_id
109+
assert doc['lastIndexId'] == json_p2['indexId']
110+
111+
112+
def test_basics(env):
113+
@Entity()
114+
class MyEntity:
115+
id = Id()
116+
name = String()
117+
118+
model = Model()
119+
model.entity(MyEntity)
120+
env.sync(model)
121+
assert MyEntity.id == 1
122+
assert MyEntity.uid != 0
123+
entity_ids = str(MyEntity.iduid)
86124

87125
# create new database and populate with two objects
88126
store = env.store()
@@ -102,7 +140,7 @@ class MyEntity:
102140
model.entity(MyEntity)
103141
assert str(model.entities[0].iduid) == "0:0"
104142
env.sync(model)
105-
assert str(model.entities[0].iduid) == e0_id
143+
assert str(model.entities[0].iduid) == entity_ids
106144

107145
# open existing database
108146
store = env.store()

0 commit comments

Comments
 (0)