66from typing import Dict , List , Optional , Tuple , no_type_check
77
88import six
9+ import sqlalchemy
910import structlog
1011from sqlalchemy import and_ , func , literal , or_
11- from sqlalchemy .orm import Query , load_only
12+ from sqlalchemy .orm import Query , aliased , load_only
1213
1314from opentaxii .common .sqldb import BaseSQLDatabaseAPI
1415from opentaxii .persistence import OpenTAXII2PersistenceAPI , OpenTAXIIPersistenceAPI
@@ -801,61 +802,44 @@ def _apply_match_version(
801802 if "all" in match_version :
802803 return query
803804 version_filters = []
805+
804806 for value in match_version :
805807 if value == "first" :
808+ VersionSTIXObject = aliased (taxii2models .STIXObject , name = "oso_min" )
809+
806810 min_versions_subq = (
807- self .db .session .query (
808- taxii2models .STIXObject .id ,
809- func .min (taxii2models .STIXObject .version ).label ("min_version" ),
811+ sqlalchemy .select (
812+ func .min (VersionSTIXObject .version ).label ("min_version" ),
810813 )
811- .filter (
812- taxii2models .STIXObject .collection_id == collection_id ,
814+ .where ( # type: ignore[call-arg]
815+ VersionSTIXObject .collection_id == collection_id ,
816+ VersionSTIXObject .id == taxii2models .STIXObject .id ,
813817 )
814- .group_by (taxii2models .STIXObject .id )
815- .subquery ()
818+ .group_by (VersionSTIXObject .id )
819+ .scalar_subquery () # type: ignore[attr-defined]
820+ .correlate (taxii2models .STIXObject )
816821 )
817- min_version_pks = (
818- self .db .session .query (taxii2models .STIXObject .pk )
819- .select_from (taxii2models .STIXObject )
820- .join (
821- min_versions_subq ,
822- (
823- (taxii2models .STIXObject .id == min_versions_subq .c .id )
824- & (
825- taxii2models .STIXObject .version
826- == min_versions_subq .c .min_version
827- )
828- ),
829- )
822+ version_filters .append (
823+ min_versions_subq == taxii2models .STIXObject .version
830824 )
831- version_filters .append (taxii2models .STIXObject .pk .in_ (min_version_pks ))
832825 elif value == "last" :
826+ VersionSTIXObject = aliased (taxii2models .STIXObject , name = "oso_max" )
827+
833828 max_versions_subq = (
834- self .db .session .query (
835- taxii2models .STIXObject .id ,
836- func .max (taxii2models .STIXObject .version ).label ("max_version" ),
829+ sqlalchemy .select (
830+ func .max (VersionSTIXObject .version ).label ("max_version" )
837831 )
838- .filter (
839- taxii2models .STIXObject .collection_id == collection_id ,
832+ .where ( # type: ignore[call-arg]
833+ VersionSTIXObject .collection_id == collection_id ,
834+ VersionSTIXObject .id == taxii2models .STIXObject .id ,
840835 )
841- .group_by (taxii2models .STIXObject .id )
842- .subquery ()
836+ .group_by (VersionSTIXObject .id )
837+ .scalar_subquery () # type: ignore[attr-defined]
838+ .correlate (taxii2models .STIXObject )
843839 )
844- max_version_pks = (
845- self .db .session .query (taxii2models .STIXObject .pk )
846- .select_from (taxii2models .STIXObject )
847- .join (
848- max_versions_subq ,
849- (
850- (taxii2models .STIXObject .id == max_versions_subq .c .id )
851- & (
852- taxii2models .STIXObject .version
853- == max_versions_subq .c .max_version
854- )
855- ),
856- )
840+ version_filters .append (
841+ max_versions_subq == taxii2models .STIXObject .version
857842 )
858- version_filters .append (taxii2models .STIXObject .pk .in_ (max_version_pks ))
859843 else :
860844 version_filters .append (taxii2models .STIXObject .version == value )
861845 query = query .filter (reduce (or_ , version_filters ))
@@ -874,7 +858,7 @@ def _apply_limit(
874858 self , query : Query , limit : Optional [int ] = None
875859 ) -> Tuple [Query , bool ]:
876860 if limit is not None :
877- more = limit < query .count ()
861+ more = limit < query .limit ( limit + 1 ). count ()
878862 query = query .limit (limit )
879863 else :
880864 more = False
0 commit comments