1- from typing import Generator , List , Tuple , Union
1+ from typing import Any , Generator , List , Tuple , Union
22
33from psycopg2 .extensions import AsIs , register_adapter
44from pydantic import AnyUrl , HttpUrl
55from sqlalchemy import ForeignKey , create_engine , func , select
66from sqlalchemy .engine import Engine
77from sqlalchemy .orm import DeclarativeBase , Mapped , Session , mapped_column , relationship
8+ from sqlalchemy .orm .query import RowReturningQuery
89from sqlalchemy .types import CHAR , DECIMAL , JSON , Integer , String , Uuid
910
1011from .models import BinaryBool , LanguageIdentifier
@@ -507,6 +508,72 @@ def get_number_of_posts(
507508 )
508509 return query .count ()
509510
511+ def _apply_filters (
512+ self ,
513+ query : RowReturningQuery [Tuple [Any , ...]],
514+ note_includes_text : Union [str , None ] = None ,
515+ note_excludes_text : Union [str , None ] = None ,
516+ post_includes_text : Union [str , None ] = None ,
517+ post_excludes_text : Union [str , None ] = None ,
518+ language : Union [LanguageIdentifier , None ] = None ,
519+ topic_ids : Union [List [TopicId ], None ] = None ,
520+ note_status : Union [List [str ], None ] = None ,
521+ note_created_at_from : Union [TwitterTimestamp , None ] = None ,
522+ note_created_at_to : Union [TwitterTimestamp , None ] = None ,
523+ x_user_names : Union [List [str ], None ] = None ,
524+ x_user_followers_count_from : Union [int , None ] = None ,
525+ x_user_follow_count_from : Union [int , None ] = None ,
526+ post_like_count_from : Union [int , None ] = None ,
527+ post_repost_count_from : Union [int , None ] = None ,
528+ post_impression_count_from : Union [int , None ] = None ,
529+ post_includes_media : Union [bool , None ] = None ,
530+ ) -> RowReturningQuery [Tuple [Any , ...]]:
531+ # Apply note filters
532+ if note_includes_text :
533+ query = query .filter (NoteRecord .summary .like (f"%{ note_includes_text } %" ))
534+ if note_excludes_text :
535+ query = query .filter (~ NoteRecord .summary .like (f"%{ note_excludes_text } %" ))
536+ if language :
537+ query = query .filter (NoteRecord .language == language )
538+ if topic_ids :
539+ subq = (
540+ select (NoteTopicAssociation .note_id )
541+ .filter (NoteTopicAssociation .topic_id .in_ (topic_ids ))
542+ .group_by (NoteTopicAssociation .note_id )
543+ .subquery ()
544+ )
545+ query = query .join (subq , NoteRecord .note_id == subq .c .note_id )
546+ if note_status :
547+ query = query .filter (NoteRecord .current_status .in_ (note_status ))
548+ if note_created_at_from :
549+ query = query .filter (NoteRecord .created_at >= note_created_at_from )
550+ if note_created_at_to :
551+ query = query .filter (NoteRecord .created_at <= note_created_at_to )
552+
553+ # Apply post filters
554+ if post_includes_text :
555+ query = query .filter (PostRecord .text .like (f"%{ post_includes_text } %" ))
556+ if post_excludes_text :
557+ query = query .filter (~ PostRecord .text .like (f"%{ post_excludes_text } %" ))
558+ if x_user_names :
559+ query = query .filter (XUserRecord .name .in_ (x_user_names ))
560+ if x_user_followers_count_from :
561+ query = query .filter (XUserRecord .followers_count >= x_user_followers_count_from )
562+ if x_user_follow_count_from :
563+ query = query .filter (XUserRecord .following_count >= x_user_follow_count_from )
564+ if post_like_count_from :
565+ query = query .filter (PostRecord .like_count >= post_like_count_from )
566+ if post_repost_count_from :
567+ query = query .filter (PostRecord .repost_count >= post_repost_count_from )
568+ if post_impression_count_from :
569+ query = query .filter (PostRecord .impression_count >= post_impression_count_from )
570+ if post_includes_media :
571+ query = query .filter (PostRecord .media_details .any ())
572+ elif post_includes_media is False :
573+ query = query .filter (~ PostRecord .media_details .any ())
574+
575+ return query
576+
510577 def search_notes_with_posts (
511578 self ,
512579 note_includes_text : Union [str , None ] = None ,
@@ -529,61 +596,34 @@ def search_notes_with_posts(
529596 limit : int = 100 ,
530597 ) -> Generator [Tuple [NoteModel , PostModel | None ], None , None ]:
531598 with Session (self .engine ) as sess :
532- # Base query joining notes, posts and users
533599 query = (
534600 sess .query (NoteRecord , PostRecord )
535601 .outerjoin (PostRecord , NoteRecord .post_id == PostRecord .post_id )
536602 .outerjoin (XUserRecord , PostRecord .user_id == XUserRecord .user_id )
537603 )
538604
539- # Apply note filters
540- if note_includes_text :
541- query = query .filter (NoteRecord .summary .like (f"%{ note_includes_text } %" ))
542- if note_excludes_text :
543- query = query .filter (~ NoteRecord .summary .like (f"%{ note_excludes_text } %" ))
544- if language :
545- query = query .filter (NoteRecord .language == language )
546- if topic_ids :
547- subq = (
548- select (NoteTopicAssociation .note_id )
549- .filter (NoteTopicAssociation .topic_id .in_ (topic_ids ))
550- .group_by (NoteTopicAssociation .note_id )
551- .subquery ()
552- )
553- query = query .join (subq , NoteRecord .note_id == subq .c .note_id )
554- if note_status :
555- query = query .filter (NoteRecord .current_status .in_ (note_status ))
556- if note_created_at_from :
557- query = query .filter (NoteRecord .created_at >= note_created_at_from )
558- if note_created_at_to :
559- query = query .filter (NoteRecord .created_at <= note_created_at_to )
560-
561- # Apply post filters
562- if post_includes_text :
563- query = query .filter (PostRecord .text .like (f"%{ post_includes_text } %" ))
564- if post_excludes_text :
565- query = query .filter (~ PostRecord .text .like (f"%{ post_excludes_text } %" ))
566- if x_user_names :
567- query = query .filter (XUserRecord .name .in_ (x_user_names ))
568- if x_user_followers_count_from :
569- query = query .filter (XUserRecord .followers_count >= x_user_followers_count_from )
570- if x_user_follow_count_from :
571- query = query .filter (XUserRecord .following_count >= x_user_follow_count_from )
572- if post_like_count_from :
573- query = query .filter (PostRecord .like_count >= post_like_count_from )
574- if post_repost_count_from :
575- query = query .filter (PostRecord .repost_count >= post_repost_count_from )
576- if post_impression_count_from :
577- query = query .filter (PostRecord .impression_count >= post_impression_count_from )
578- if post_includes_media :
579- query = query .filter (PostRecord .media_details .any ())
580- if post_includes_media is False :
581- query = query .filter (~ PostRecord .media_details .any ())
582-
583- # Pagination
605+ query = self ._apply_filters (
606+ query ,
607+ note_includes_text ,
608+ note_excludes_text ,
609+ post_includes_text ,
610+ post_excludes_text ,
611+ language ,
612+ topic_ids ,
613+ note_status ,
614+ note_created_at_from ,
615+ note_created_at_to ,
616+ x_user_names ,
617+ x_user_followers_count_from ,
618+ x_user_follow_count_from ,
619+ post_like_count_from ,
620+ post_repost_count_from ,
621+ post_impression_count_from ,
622+ post_includes_media ,
623+ )
624+
584625 query = query .offset (offset ).limit (limit )
585626
586- # Execute query and yield results
587627 for note_record , post_record in query .all ():
588628 note = NoteModel (
589629 note_id = note_record .note_id ,
@@ -627,49 +667,25 @@ def count_search_results(
627667 .outerjoin (XUserRecord , PostRecord .user_id == XUserRecord .user_id )
628668 )
629669
630- # Apply note filters
631- if note_includes_text :
632- query = query .filter (NoteRecord .summary .like (f"%{ note_includes_text } %" ))
633- if note_excludes_text :
634- query = query .filter (~ NoteRecord .summary .like (f"%{ note_excludes_text } %" ))
635- if language :
636- query = query .filter (NoteRecord .language == language )
637- if topic_ids :
638- subq = (
639- select (NoteTopicAssociation .note_id )
640- .filter (NoteTopicAssociation .topic_id .in_ (topic_ids ))
641- .group_by (NoteTopicAssociation .note_id )
642- .subquery ()
643- )
644- query = query .join (subq , NoteRecord .note_id == subq .c .note_id )
645- if note_status :
646- query = query .filter (NoteRecord .current_status .in_ (note_status ))
647- if note_created_at_from :
648- query = query .filter (NoteRecord .created_at >= note_created_at_from )
649- if note_created_at_to :
650- query = query .filter (NoteRecord .created_at <= note_created_at_to )
651-
652- # Apply post filters
653- if post_includes_text :
654- query = query .filter (PostRecord .text .like (f"%{ post_includes_text } %" ))
655- if post_excludes_text :
656- query = query .filter (~ PostRecord .text .like (f"%{ post_excludes_text } %" ))
657- if x_user_names :
658- query = query .filter (XUserRecord .name .in_ (x_user_names ))
659- if x_user_followers_count_from :
660- query = query .filter (XUserRecord .followers_count >= x_user_followers_count_from )
661- if x_user_follow_count_from :
662- query = query .filter (XUserRecord .following_count >= x_user_follow_count_from )
663- if post_like_count_from :
664- query = query .filter (PostRecord .like_count >= post_like_count_from )
665- if post_repost_count_from :
666- query = query .filter (PostRecord .repost_count >= post_repost_count_from )
667- if post_impression_count_from :
668- query = query .filter (PostRecord .impression_count >= post_impression_count_from )
669- if post_includes_media :
670- query = query .filter (PostRecord .media_details .any ())
671- elif post_includes_media is False :
672- query = query .filter (~ PostRecord .media_details .any ())
670+ query = self ._apply_filters (
671+ query ,
672+ note_includes_text ,
673+ note_excludes_text ,
674+ post_includes_text ,
675+ post_excludes_text ,
676+ language ,
677+ topic_ids ,
678+ note_status ,
679+ note_created_at_from ,
680+ note_created_at_to ,
681+ x_user_names ,
682+ x_user_followers_count_from ,
683+ x_user_follow_count_from ,
684+ post_like_count_from ,
685+ post_repost_count_from ,
686+ post_impression_count_from ,
687+ post_includes_media ,
688+ )
673689
674690 return query .scalar () or 0
675691
0 commit comments