Add pagination support in database queries for announces

- Implemented pagination at the database level for improved performance when no search query is provided.
- Added a new method `get_filtered_announces_count` in `AnnounceManager` to retrieve the total count of filtered announces for pagination.
- Adjusted the `ReticulumMeshChat` class to utilize the new count method and handle pagination more efficiently.
This commit is contained in:
Sudo-Ivan committed 2026-01-14 11:01:50 -06:00
1 parent 29b7fb6449
commit 2fb42d27fa
2 files changed
+71 -3

No files matched your search

+30 -3
View File
@@ -5525,14 +5525,40 @@ class ReticulumMeshChat:
blocked_identity_hashes = [b["destination_hash"] for b in blocked]
# fetch announces from database
# If we don't have a search query, we can paginate at the database level
# which is much faster than fetching thousands of records and then paginating in Python.
db_limit = limit if not search_query else None
db_offset = offset if not search_query else 0
results = self.announce_manager.get_filtered_announces(
aspect=aspect,
identity_hash=identity_hash,
destination_hash=destination_hash,
query=None, # We filter in Python to support name search
blocked_identity_hashes=blocked_identity_hashes,
limit=db_limit,
offset=db_offset,
)
# fetch total count if we paginated in DB
total_count = 0
if not search_query:
# Get the count from the database for the same filters
# We should probably add a get_filtered_announces_count method to announce_manager
if db_limit is None:
total_count = len(results)
else:
# We need the total count for pagination to work in the frontend
total_count = self.announce_manager.get_filtered_announces_count(
aspect=aspect,
identity_hash=identity_hash,
destination_hash=destination_hash,
query=None,
blocked_identity_hashes=blocked_identity_hashes,
)
# ... rest of processing ...
# pre-fetch icons and other data to avoid N+1 queries in convert_db_announce_to_dict
other_user_hashes = [r["destination_hash"] for r in results]
user_icons = {}
@@ -5671,13 +5697,14 @@ class ReticulumMeshChat:
)
]
# apply pagination
total_count = len(all_announces)
if offset is not None or limit is not None:
# Re-calculate total_count after search filter
total_count = len(all_announces)
# apply pagination after search
start = offset
end = start + (limit if limit is not None else total_count)
paginated_results = all_announces[start:end]
else:
# We already paginated in DB, and total_count was calculated before processing
paginated_results = all_announces
return web.json_response(
+41
View File
@@ -89,3 +89,44 @@ class AnnounceManager:
params.extend([limit, offset])
return self.db.provider.fetchall(sql, params)
def get_filtered_announces_count(
self,
aspect=None,
identity_hash=None,
destination_hash=None,
query=None,
blocked_identity_hashes=None,
):
sql = """
SELECT COUNT(*) as count
FROM announces a
LEFT JOIN contacts c ON (
a.identity_hash = c.remote_identity_hash OR
a.destination_hash = c.lxmf_address OR
a.destination_hash = c.lxst_address
)
WHERE 1=1
"""
params = []
if aspect:
sql += " AND a.aspect = ?"
params.append(aspect)
if identity_hash:
sql += " AND a.identity_hash = ?"
params.append(identity_hash)
if destination_hash:
sql += " AND a.destination_hash = ?"
params.append(destination_hash)
if query:
like_term = f"%{query}%"
sql += " AND (a.destination_hash LIKE ? OR a.identity_hash LIKE ?)"
params.extend([like_term, like_term])
if blocked_identity_hashes:
placeholders = ", ".join(["?"] * len(blocked_identity_hashes))
sql += f" AND a.identity_hash NOT IN ({placeholders})"
params.extend(blocked_identity_hashes)
result = self.db.provider.fetchone(sql, params)
return result["count"] if result else 0