Paginate address book contacts

This commit is contained in:
2026-07-30 05:22:09 +02:00
parent 1545ea711e
commit bf1d7c9678
7 changed files with 231 additions and 16 deletions
+66 -1
View File
@@ -2421,14 +2421,79 @@ def list_contacts(
principal: ApiPrincipal,
*,
address_book_id: str | None = None,
address_list_id: str | None = None,
query: str | None = None,
limit: int = 200,
offset: int = 0,
include_deleted: bool = False,
) -> list[Contact]:
contact_query = _filtered_contact_query(
session,
principal,
address_book_id=address_book_id,
address_list_id=address_list_id,
query=query,
include_deleted=include_deleted,
)
return (
contact_query.order_by(Contact.display_name.asc(), Contact.id.asc())
.offset(max(0, offset))
.limit(max(1, min(limit, 500)))
.all()
)
def count_contacts(
session: Session,
principal: ApiPrincipal,
*,
address_book_id: str | None = None,
address_list_id: str | None = None,
query: str | None = None,
include_deleted: bool = False,
) -> int:
contact_query = _filtered_contact_query(
session,
principal,
address_book_id=address_book_id,
address_list_id=address_list_id,
query=query,
include_deleted=include_deleted,
)
return int(
contact_query.order_by(None)
.with_entities(func.count(func.distinct(Contact.id)))
.scalar()
or 0
)
def _filtered_contact_query(
session: Session,
principal: ApiPrincipal,
*,
address_book_id: str | None,
address_list_id: str | None,
query: str | None,
include_deleted: bool,
):
contact_query = _visible_contact_query(session, principal, include_deleted=include_deleted, include_deleted_books=include_deleted)
if address_book_id:
get_visible_address_book(session, principal, address_book_id, include_deleted=include_deleted)
contact_query = contact_query.filter(Contact.address_book_id == address_book_id)
if address_list_id:
address_list = get_visible_address_list(
session,
principal,
address_list_id,
include_deleted=include_deleted,
)
if address_book_id and address_list.address_book_id != address_book_id:
raise AddressBookError("Address list does not belong to the selected address book.")
contact_query = contact_query.join(
AddressListEntry,
AddressListEntry.contact_id == Contact.id,
).filter(AddressListEntry.address_list_id == address_list_id)
normalized_query = _trim(query)
if normalized_query:
pattern = f"%{normalized_query.lower()}%"
@@ -2439,7 +2504,7 @@ def list_contacts(
func.lower(ContactEmail.email).like(pattern),
)
)
return contact_query.order_by(Contact.display_name.asc(), Contact.id.asc()).limit(max(1, min(limit, 500))).all()
return contact_query.distinct()
def get_visible_contact(session: Session, principal: ApiPrincipal, contact_id: str, *, include_deleted: bool = False) -> Contact: