Skip to content

Commit f6afd05

Browse files
Add methods for get or add/update model (#182)
1 parent 7c7a8b9 commit f6afd05

File tree

3 files changed

+171
-2
lines changed

3 files changed

+171
-2
lines changed

diffsync/__init__.py

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -790,19 +790,41 @@ def get_or_instantiate(
790790
"""
791791
return self.store.get_or_instantiate(model=model, ids=ids, attrs=attrs)
792792

793+
def get_or_add_model_instance(self, obj: DiffSyncModel) -> Tuple[DiffSyncModel, bool]:
794+
"""Attempt to get the object with provided obj identifiers or instantiate obj.
795+
796+
Args:
797+
obj: An obj of the DiffSyncModel to get or add.
798+
799+
Returns:
800+
Provides the existing or new object and whether it was created or not.
801+
"""
802+
return self.store.get_or_add_model_instance(obj=obj)
803+
793804
def update_or_instantiate(self, model: Type[DiffSyncModel], ids: Dict, attrs: Dict) -> Tuple[DiffSyncModel, bool]:
794805
"""Attempt to update an existing object with provided ids/attrs or instantiate it with provided identifiers and attrs.
795806
796807
Args:
797-
model (DiffSyncModel): The DiffSyncModel to get or create.
798-
ids (Dict): Identifiers for the DiffSyncModel to get or create with.
808+
model (DiffSyncModel): The DiffSyncModel to update or create.
809+
ids (Dict): Identifiers for the DiffSyncModel to update or create with.
799810
attrs (Dict): Attributes when creating/updating an object if it doesn't exist. Pass in empty dict, if no specific attrs.
800811
801812
Returns:
802813
Tuple[DiffSyncModel, bool]: Provides the existing or new object and whether it was created or not.
803814
"""
804815
return self.store.update_or_instantiate(model=model, ids=ids, attrs=attrs)
805816

817+
def update_or_add_model_instance(self, obj: DiffSyncModel) -> Tuple[DiffSyncModel, bool]:
818+
"""Attempt to update an existing object with provided obj ids/attrs or instantiate obj.
819+
820+
Args:
821+
instance: An instance of the DiffSyncModel to update or create.
822+
823+
Returns:
824+
Provides the existing or new object and whether it was created or not.
825+
"""
826+
return self.store.update_or_add_model_instance(obj=obj)
827+
806828
def count(self, model: Union[Text, "DiffSyncModel", Type["DiffSyncModel"], None] = None):
807829
"""Count how many objects of one model type exist in the backend store.
808830

diffsync/store/__init__.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,24 @@ def get_or_instantiate(
159159

160160
return obj, created
161161

162+
def get_or_add_model_instance(self, obj: "DiffSyncModel") -> Tuple["DiffSyncModel", bool]:
163+
"""Attempt to get the object with provided obj identifiers or instantiate obj.
164+
165+
Args:
166+
obj: An obj of the DiffSyncModel to get or add.
167+
168+
Returns:
169+
Provides the existing or new object and whether it was added or not.
170+
"""
171+
model = obj.get_type()
172+
ids = obj.get_unique_id()
173+
174+
try:
175+
return self.get(model=model, identifier=ids), False
176+
except ObjectNotFound:
177+
self.add(obj=obj)
178+
return obj, True
179+
162180
def update_or_instantiate(
163181
self, *, model: Type["DiffSyncModel"], ids: Dict, attrs: Dict
164182
) -> Tuple["DiffSyncModel", bool]:
@@ -188,6 +206,33 @@ def update_or_instantiate(
188206

189207
return obj, created
190208

209+
def update_or_add_model_instance(self, obj: "DiffSyncModel") -> Tuple["DiffSyncModel", bool]:
210+
"""Attempt to update an existing object with provided ids/attrs or instantiate obj.
211+
212+
Args:
213+
instance: An instance of the DiffSyncModel to update or create.
214+
215+
Returns:
216+
Provides the existing or new object and whether it was added or not.
217+
"""
218+
model = obj.get_type()
219+
ids = obj.get_unique_id()
220+
attrs = obj.get_attrs()
221+
222+
added = False
223+
try:
224+
obj = self.get(model=model, identifier=ids)
225+
except ObjectNotFound:
226+
# Add the object to the diffsync instance
227+
self.add(obj=obj)
228+
added = True
229+
230+
# Update existing obj with attrs
231+
for attr, value in attrs.items():
232+
setattr(obj, attr, value)
233+
234+
return obj, added
235+
191236
def _get_object_class_and_model(
192237
self, model: Union[Text, "DiffSyncModel", Type["DiffSyncModel"]]
193238
) -> Tuple[Union["DiffSyncModel", Type["DiffSyncModel"], None], str]:

tests/unit/test_diffsync.py

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,72 @@ def test_diffsync_get_or_instantiate_retrieve_existing_object_wo_attrs(generic_d
162162
assert obj.description is None
163163

164164

165+
def test_diffsync_get_or_add_model_instance_create_non_existent_object(generic_diffsync):
166+
generic_diffsync.interface = Interface
167+
intf_identifiers = {"device_name": "device1", "name": "eth1"}
168+
intf = generic_diffsync.interface(**intf_identifiers)
169+
170+
# Assert that the object does not currently exist.
171+
with pytest.raises(ObjectNotFound):
172+
generic_diffsync.get(Interface, intf_identifiers)
173+
174+
obj, created = generic_diffsync.get_or_add_model_instance(intf)
175+
assert created
176+
assert obj is generic_diffsync.get(Interface, intf_identifiers)
177+
assert obj is generic_diffsync.get("interface", intf_identifiers)
178+
179+
180+
def test_diffsync_get_or_add_model_instance_retrieve_existing_object(generic_diffsync):
181+
intf_identifiers = {"device_name": "device1", "name": "eth1"}
182+
intf = Interface(**intf_identifiers)
183+
generic_diffsync.add(intf)
184+
185+
obj, created = generic_diffsync.get_or_add_model_instance(intf)
186+
assert obj is intf
187+
assert not created
188+
189+
190+
def test_diffsync_get_or_add_model_instance_retrieve_existing_object_w_attrs(generic_diffsync):
191+
intf_identifiers = {"device_name": "device1", "name": "eth1"}
192+
intf_attrs = {"interface_type": "ethernet"}
193+
intf_combine = {**intf_identifiers, **intf_attrs}
194+
intf = Interface(**intf_combine)
195+
generic_diffsync.add(intf)
196+
197+
obj, created = generic_diffsync.get_or_add_model_instance(intf)
198+
assert obj is intf
199+
assert not created
200+
assert obj.interface_type == "ethernet"
201+
assert obj.description is None
202+
203+
204+
def test_diffsync_get_or_add_model_instance_retrieve_create_non_existent_w_attrs(generic_diffsync):
205+
generic_diffsync.interface = Interface
206+
intf_identifiers = {"device_name": "device1", "name": "eth1"}
207+
intf_attrs = {"interface_type": "1000base-t", "description": "Testing"}
208+
intf_combine = {**intf_identifiers, **intf_attrs}
209+
intf = Interface(**intf_combine)
210+
211+
obj, created = generic_diffsync.get_or_add_model_instance(intf)
212+
assert created
213+
assert obj.interface_type == "1000base-t"
214+
assert obj.description == "Testing"
215+
assert obj is generic_diffsync.get(Interface, intf_identifiers)
216+
assert obj is generic_diffsync.get("interface", intf_identifiers)
217+
218+
219+
def test_diffsync_get_or_add_model_instance_retrieve_existing_object_wo_attrs(generic_diffsync):
220+
intf_identifiers = {"device_name": "device1", "name": "eth1"}
221+
intf = Interface(**intf_identifiers)
222+
generic_diffsync.add(intf)
223+
224+
obj, created = generic_diffsync.get_or_add_model_instance(intf)
225+
assert obj is intf
226+
assert not created
227+
assert obj.interface_type == "ethernet"
228+
assert obj.description is None
229+
230+
165231
def test_diffsync_update_or_instantiate_retrieve_existing_object_w_updated_attrs(generic_diffsync):
166232
intf_identifiers = {"device_name": "device1", "name": "eth1"}
167233
intf_attrs = {"interface_type": "1000base-t", "description": "Testing"}
@@ -194,6 +260,42 @@ def test_diffsync_update_or_instantiate_create_object_w_attrs(generic_diffsync):
194260
assert obj.description == "Testing"
195261

196262

263+
def test_diffsync_update_or_add_model_instance_retrieve_existing_object_w_updated_attrs(generic_diffsync):
264+
intf_identifiers = {"device_name": "device1", "name": "eth1"}
265+
intf_attrs = {"interface_type": "1000base-t", "description": "Testing"}
266+
intf_combine = {**intf_identifiers, **intf_attrs}
267+
intf = Interface(**intf_combine)
268+
generic_diffsync.add(intf)
269+
270+
obj, created = generic_diffsync.update_or_add_model_instance(intf)
271+
assert obj is intf
272+
assert not created
273+
assert obj.interface_type == "1000base-t"
274+
assert obj.description == "Testing"
275+
276+
277+
def test_diffsync_update_or_add_model_instance_create_object(generic_diffsync):
278+
intf_identifiers = {"device_name": "device1", "name": "eth1"}
279+
intf = Interface(**intf_identifiers)
280+
281+
obj, created = generic_diffsync.update_or_add_model_instance(intf)
282+
assert created
283+
assert obj.interface_type == "ethernet"
284+
assert obj.description is None
285+
286+
287+
def test_diffsync_update_or_add_model_instance_create_object_w_attrs(generic_diffsync):
288+
intf_identifiers = {"device_name": "device1", "name": "eth1"}
289+
intf_attrs = {"interface_type": "1000base-t", "description": "Testing"}
290+
intf_combine = {**intf_identifiers, **intf_attrs}
291+
intf = Interface(**intf_combine)
292+
293+
obj, created = generic_diffsync.update_or_add_model_instance(intf)
294+
assert created
295+
assert obj.interface_type == "1000base-t"
296+
assert obj.description == "Testing"
297+
298+
197299
def test_diffsync_get_with_generic_model(generic_diffsync, generic_diffsync_model):
198300
generic_diffsync.add(generic_diffsync_model)
199301
# The generic_diffsync_model has an empty identifier/unique-id

0 commit comments

Comments
 (0)