Files
MeshChatX/meshchatx/src/backend/message_handler.py

121 lines
4.1 KiB
Python

from .database import Database
class MessageHandler:
def __init__(self, db: Database):
self.db = db
def get_conversation_messages(
self,
local_hash,
destination_hash,
limit=100,
offset=0,
after_id=None,
before_id=None,
):
query = """
SELECT * FROM lxmf_messages
WHERE peer_hash = ?
"""
params = [destination_hash]
if after_id:
query += " AND id > ?"
params.append(after_id)
if before_id:
query += " AND id < ?"
params.append(before_id)
query += " ORDER BY id DESC LIMIT ? OFFSET ?"
params.extend([limit, offset])
return self.db.provider.fetchall(query, params)
def delete_conversation(self, local_hash, destination_hash):
query = "DELETE FROM lxmf_messages WHERE peer_hash = ?"
self.db.provider.execute(query, [destination_hash])
def search_messages(self, local_hash, search_term):
like_term = f"%{search_term}%"
query = """
SELECT peer_hash, MAX(timestamp) as max_ts
FROM lxmf_messages
WHERE title LIKE ? OR content LIKE ? OR peer_hash LIKE ?
GROUP BY peer_hash
"""
params = [like_term, like_term, like_term]
return self.db.provider.fetchall(query, params)
def get_conversations(
self,
local_hash,
search=None,
filter_unread=False,
filter_failed=False,
filter_has_attachments=False,
limit=None,
offset=0,
):
# Optimized using peer_hash column and JOINs to avoid N+1 queries
query = """
SELECT
m1.*,
a.app_data as peer_app_data,
c.display_name as custom_display_name,
con.custom_image as contact_image,
i.icon_name, i.foreground_colour, i.background_colour,
r.last_read_at,
(SELECT COUNT(*) FROM lxmf_messages m_failed
WHERE m_failed.peer_hash = m1.peer_hash AND m_failed.state = 'failed') as failed_count
FROM lxmf_messages m1
INNER JOIN (
SELECT peer_hash, MAX(timestamp) as max_ts
FROM lxmf_messages
WHERE peer_hash IS NOT NULL
GROUP BY peer_hash
) m2 ON m1.peer_hash = m2.peer_hash AND m1.timestamp = m2.max_ts
LEFT JOIN announces a ON a.destination_hash = m1.peer_hash
LEFT JOIN custom_destination_display_names c ON c.destination_hash = m1.peer_hash
LEFT JOIN contacts con ON con.remote_identity_hash = m1.peer_hash
LEFT JOIN lxmf_user_icons i ON i.destination_hash = m1.peer_hash
LEFT JOIN lxmf_conversation_read_state r ON r.destination_hash = m1.peer_hash
"""
params = []
where_clauses = []
if filter_unread:
where_clauses.append(
"(r.last_read_at IS NULL OR m1.timestamp > strftime('%s', r.last_read_at))"
)
if filter_failed:
where_clauses.append("m1.state = 'failed'")
if filter_has_attachments:
where_clauses.append(
"(m1.fields IS NOT NULL AND m1.fields != '{}' AND m1.fields != '')"
)
if search:
like_term = f"%{search}%"
# Search in latest message info OR search across ALL messages for this peer
where_clauses.append("""
(m1.title LIKE ? OR m1.content LIKE ? OR m1.peer_hash LIKE ? OR c.display_name LIKE ?
OR m1.peer_hash IN (SELECT peer_hash FROM lxmf_messages WHERE title LIKE ? OR content LIKE ?))
""")
params.extend(
[like_term, like_term, like_term, like_term, like_term, like_term]
)
if where_clauses:
query += " WHERE " + " AND ".join(where_clauses)
query += " GROUP BY m1.peer_hash ORDER BY m1.timestamp DESC"
if limit is not None:
query += " LIMIT ? OFFSET ?"
params.extend([limit, offset])
return self.db.provider.fetchall(query, params)