Skip to content

Commit 45174c6

Browse files
committed
feat(querylist): Get first result
1 parent 2463af4 commit 45174c6

File tree

2 files changed

+47
-0
lines changed

2 files changed

+47
-0
lines changed

src/libvcs/_internal/query_list.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from typing import Any, Callable, Optional, Protocol, TypeVar, Union
1212

1313
T = TypeVar("T", Any, Any)
14+
no_arg = object()
1415

1516

1617
def keygetter(
@@ -370,6 +371,9 @@ class QueryList(list[T]):
370371
>>> query.filter(foods__fruit__in="banana")[0].city
371372
'Tampa'
372373
374+
>>> query.get(foods__fruit__in="banana").city
375+
'Tampa'
376+
373377
**With objects (nested)**:
374378
375379
>>> from typing import Optional
@@ -417,6 +421,9 @@ class QueryList(list[T]):
417421
>>> query.filter(food__fruit__in="banana")[0].city
418422
'Tampa'
419423
424+
>>> query.get(food__fruit__in="banana").city
425+
'Tampa'
426+
420427
>>> query.filter(food__breakfast="waffles")
421428
[Restaurant(place='Chicago suburbs',
422429
city='Elmhurst',
@@ -506,3 +513,18 @@ def val_match(obj: Union[str, list[Any]]) -> bool:
506513
_filter = filter_lookup
507514

508515
return self.__class__(k for k in self if _filter(k))
516+
517+
def get(
518+
self,
519+
matcher: Optional[Union[Callable[[T], bool], T]] = None,
520+
default: Optional[Any] = no_arg,
521+
**kwargs: Any,
522+
) -> Optional[T]:
523+
objs = self.filter(matcher=matcher, **kwargs)
524+
if len(objs) > 1:
525+
raise Exception("Multiple objects returned")
526+
elif len(objs) == 0:
527+
if default == no_arg:
528+
raise Exception("No objects found")
529+
return default
530+
return objs[0]

tests/_internal/test_query_list.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,3 +257,28 @@ def test_filter(
257257
assert qs.filter(filter_expr) == expected_result
258258
else:
259259
assert qs.filter() == expected_result
260+
261+
if (
262+
isinstance(expected_result, list)
263+
and len(expected_result) > 0
264+
and not isinstance(expected_result[0], dict)
265+
):
266+
if len(expected_result) == 1:
267+
if isinstance(filter_expr, dict):
268+
assert qs.get(**filter_expr) == expected_result[0]
269+
else:
270+
assert qs.get(filter_expr) == expected_result[0]
271+
elif len(expected_result) > 1:
272+
with pytest.raises(Exception) as e:
273+
if isinstance(filter_expr, dict):
274+
assert qs.get(**filter_expr) == expected_result
275+
else:
276+
assert qs.get(filter_expr) == expected_result
277+
assert e.match("Multiple objects returned")
278+
elif len(expected_result) == 0:
279+
with pytest.raises(Exception) as e:
280+
if isinstance(filter_expr, dict):
281+
assert qs.get(**filter_expr) == expected_result
282+
else:
283+
assert qs.get(filter_expr) == expected_result
284+
assert e.match("No objects found")

0 commit comments

Comments
 (0)