Skip to content

Commit 09840e2

Browse files
committed
add convenience method for loading multiple models by unique ids
1 parent 897f04a commit 09840e2

2 files changed

Lines changed: 53 additions & 0 deletions

File tree

src/bubble_data_api_client/client/orm.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
from bubble_data_api_client.client.raw_client import RawClient
99
from bubble_data_api_client.config import get_config
10+
from bubble_data_api_client.constraints import ConstraintTypes, constraint
1011

1112

1213
def _get_client() -> RawClient:
@@ -39,6 +40,7 @@ async def create(cls, **data: typing.Any) -> typing.Self:
3940

4041
@classmethod
4142
async def get(cls, uid: str) -> typing.Self | None:
43+
"""Retrieve a single thing by its unique ID."""
4244
async with _get_client() as client:
4345
try:
4446
response = await client.retrieve(cls._typename, uid)
@@ -49,6 +51,16 @@ async def get(cls, uid: str) -> typing.Self | None:
4951
return None
5052
raise
5153

54+
@classmethod
55+
async def get_many(cls, uids: list[str]) -> dict[str, typing.Self]:
56+
"""Retrieve multiple things by their unique IDs, keyed by uid."""
57+
if not uids:
58+
return {}
59+
items: list[typing.Self] = await cls.list(
60+
constraints=[constraint("_id", ConstraintTypes.IN, uids)],
61+
)
62+
return {item.uid: item for item in items}
63+
5264
async def save(self) -> None:
5365
async with _get_client() as client:
5466
data = self.model_dump(exclude={"uid"})

src/tests/integration/test_orm.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,44 @@ async def test_orm_integration():
4747
# verify deletion
4848
thing4 = await IntegrationTestModel.get(thing.uid)
4949
assert thing4 is None
50+
51+
52+
@pytest.mark.asyncio
53+
async def test_get_many():
54+
"""Integration test for get_many method."""
55+
# create multiple things
56+
thing1 = await IntegrationTestModel.create(text="item1")
57+
thing2 = await IntegrationTestModel.create(text="item2")
58+
thing3 = await IntegrationTestModel.create(text="item3")
59+
60+
try:
61+
# get_many with all uids
62+
results = await IntegrationTestModel.get_many([thing1.uid, thing2.uid, thing3.uid])
63+
assert len(results) == 3
64+
assert isinstance(results, dict)
65+
assert results[thing1.uid].text == "item1"
66+
assert results[thing2.uid].text == "item2"
67+
assert results[thing3.uid].text == "item3"
68+
69+
# get_many with subset of uids
70+
results = await IntegrationTestModel.get_many([thing1.uid, thing3.uid])
71+
assert len(results) == 2
72+
assert thing1.uid in results
73+
assert thing2.uid not in results
74+
assert thing3.uid in results
75+
76+
# get_many with empty list
77+
results = await IntegrationTestModel.get_many([])
78+
assert results == {}
79+
80+
# get_many with non-existent uid
81+
results = await IntegrationTestModel.get_many([thing1.uid, "non_existent_uid"])
82+
assert len(results) == 1
83+
assert thing1.uid in results
84+
assert "non_existent_uid" not in results
85+
86+
finally:
87+
# cleanup
88+
await thing1.delete()
89+
await thing2.delete()
90+
await thing3.delete()

0 commit comments

Comments
 (0)