@@ -639,4 +639,108 @@ mod tests {
639639 ) . unwrap ( ) ;
640640 assert ! ( incoming. matches_sql_pattern( & template) ) ;
641641 }
642+
643+ #[ test]
644+ fn test_order_by_is_rejected ( ) {
645+ assert ! ( parse_sql_query(
646+ "SELECT AVG(value) FROM cpu_usage WHERE time BETWEEN DATEADD(s, -10, NOW()) AND NOW() GROUP BY L1, L2 ORDER BY L1"
647+ ) . is_none( ) ) ;
648+ }
649+
650+ // ── scrape_interval > 1s regression tests (issue #201) ───────────────────
651+
652+ fn check_query_with_interval (
653+ sql : & str ,
654+ scrape_interval : f64 ,
655+ expected_types : Vec < QueryType > ,
656+ expected_error : Option < QueryError > ,
657+ ) {
658+ let schema = create_test_schema ( ) ;
659+ let matcher = SQLPatternMatcher :: new ( schema, scrape_interval) ;
660+ let query_data =
661+ parse_sql_query ( sql) . unwrap_or_else ( || panic ! ( "Failed to parse query: {}" , sql) ) ;
662+ let result = matcher. query_info_to_pattern ( & query_data) ;
663+ assert_eq ! ( result. query_type, expected_types) ;
664+ assert_eq ! ( result. error, expected_error) ;
665+ }
666+
667+ /// scraped_intervals = 15/15 = 1.0; bug fires 1.0 < 15.0 → false positive error
668+ #[ test]
669+ fn test_bug_201_single_interval_spatial_query_not_rejected ( ) {
670+ check_query_with_interval (
671+ "SELECT AVG(value) FROM cpu_usage \
672+ WHERE time BETWEEN DATEADD(s, -15, '2025-10-01 00:00:00') AND '2025-10-01 00:00:00' \
673+ GROUP BY L1, L2, L3, L4",
674+ 15.0 ,
675+ vec ! [ QueryType :: Spatial ] ,
676+ None ,
677+ ) ;
678+ }
679+
680+ /// scraped_intervals = 30/15 = 2.0; bug fires 2.0 < 15.0 → false positive error
681+ #[ test]
682+ fn test_bug_201_two_interval_temporal_query_not_rejected ( ) {
683+ check_query_with_interval (
684+ "SELECT SUM(value) FROM cpu_usage \
685+ WHERE time BETWEEN DATEADD(s, -30, '2025-10-01 00:00:00') AND '2025-10-01 00:00:00' \
686+ GROUP BY L1, L2, L3, L4",
687+ 15.0 ,
688+ vec ! [ QueryType :: TemporalGeneric ] ,
689+ None ,
690+ ) ;
691+ }
692+
693+ /// scraped_intervals = 30/15 = 2.0 with QUANTILE agg → TemporalQuantile
694+ #[ test]
695+ fn test_bug_201_temporal_quantile_not_rejected ( ) {
696+ check_query_with_interval (
697+ "SELECT QUANTILE(0.95, value) FROM cpu_usage \
698+ WHERE time BETWEEN DATEADD(s, -30, '2025-10-01 00:00:00') AND '2025-10-01 00:00:00' \
699+ GROUP BY L1, L2, L3, L4",
700+ 15.0 ,
701+ vec ! [ QueryType :: TemporalQuantile ] ,
702+ None ,
703+ ) ;
704+ }
705+
706+ /// scraped_intervals = 30/15 = 2.0 with subset of labels → SpatioTemporal
707+ #[ test]
708+ fn test_bug_201_spatiotemporal_not_rejected ( ) {
709+ check_query_with_interval (
710+ "SELECT SUM(value) FROM cpu_usage \
711+ WHERE time BETWEEN DATEADD(s, -30, '2025-10-01 00:00:00') AND '2025-10-01 00:00:00' \
712+ GROUP BY L1",
713+ 15.0 ,
714+ vec ! [ QueryType :: SpatioTemporal ] ,
715+ None ,
716+ ) ;
717+ }
718+
719+ /// Spatial-of-temporal: outer has UNUSED time (not checked), inner scraped_intervals = 30/15 = 2.0
720+ #[ test]
721+ fn test_bug_201_spatial_of_temporal_not_rejected ( ) {
722+ check_query_with_interval (
723+ "SELECT SUM(result) FROM \
724+ (SELECT SUM(value) AS result FROM cpu_usage \
725+ WHERE time BETWEEN DATEADD(s, -30, '2025-10-01 00:00:00') AND '2025-10-01 00:00:00' \
726+ GROUP BY L1, L2, L3, L4) \
727+ GROUP BY L1",
728+ 15.0 ,
729+ vec ! [ QueryType :: Spatial , QueryType :: TemporalGeneric ] ,
730+ None ,
731+ ) ;
732+ }
733+
734+ /// scraped_intervals = 14/15 = 0.93 < 1.0 → should still be rejected (guard still works)
735+ #[ test]
736+ fn test_bug_201_sub_interval_query_still_rejected ( ) {
737+ check_query_with_interval (
738+ "SELECT AVG(value) FROM cpu_usage \
739+ WHERE time BETWEEN DATEADD(s, -14, '2025-10-01 00:00:00') AND '2025-10-01 00:00:00' \
740+ GROUP BY L1, L2, L3, L4",
741+ 15.0 ,
742+ vec ! [ ] ,
743+ Some ( QueryError :: SpatialDurationSmall ) ,
744+ ) ;
745+ }
642746}
0 commit comments