11use crate :: http:: Request ;
2+ use crate :: router:: request_matcher:: { MethodMatcher , RequestMatcher } ;
23use crate :: router:: route_datetime:: RouteDateTime ;
3- use crate :: router:: trace:: TraceInfo ;
4- use crate :: router:: { WeekdayMatcher , RequestMatcher , Route , RouteData , Trace } ;
5- use std:: collections:: HashMap ;
4+ use crate :: router:: route_time:: RouteTime ;
5+ use crate :: router:: route_weekday:: RouteWeekday ;
6+ use crate :: router:: trace:: { TraceInfo , TraceInfoDateTimeCondition } ;
7+ use crate :: router:: { Route , RouteData , Trace } ;
8+ use chrono:: { DateTime , Utc } ;
9+ use serde:: { Deserialize , Serialize } ;
10+ use std:: collections:: BTreeMap ;
11+ use std:: collections:: BTreeSet ;
612
713#[ derive( Debug , Clone ) ]
814pub struct DateTimeMatcher < T : RouteData > {
9- matchers : HashMap < RouteDateTime , Box < dyn RequestMatcher < T > > > ,
10- no_matcher : Box < dyn RequestMatcher < T > > ,
15+ any_datetime : Box < dyn RequestMatcher < T > > ,
16+ conditions : BTreeSet < DateTimeCondition > ,
17+ condition_groups : BTreeMap < BTreeSet < DateTimeCondition > , Box < dyn RequestMatcher < T > > > ,
1118 count : usize ,
1219}
1320
21+ #[ derive( Serialize , Deserialize , Debug , Clone , Hash , Eq , PartialEq , Ord , PartialOrd ) ]
22+ #[ serde( rename_all = "snake_case" ) ]
23+ #[ serde( tag = "type" , content = "date_time_type" ) ]
24+ pub enum DateTimeCondition {
25+ DateTimeRange ( Vec < RouteDateTime > ) ,
26+ TimeRange ( Vec < RouteTime > ) ,
27+ Weekdays ( RouteWeekday ) ,
28+ }
29+
1430impl < T : RouteData > RequestMatcher < T > for DateTimeMatcher < T > {
1531 fn insert ( & mut self , route : Route < T > ) {
1632 self . count += 1 ;
1733
34+ let mut condition_group = BTreeSet :: new ( ) ;
35+ let mut conditions = BTreeSet :: new ( ) ;
36+
1837 match route. datetime ( ) {
19- Some ( route_datetimes) => {
20- for route_datetime in route_datetimes {
21- self . matchers
22- . entry ( route_datetime. clone ( ) )
23- . or_insert_with ( || Self :: create_sub_matcher ( ) )
24- . insert ( route. clone ( ) ) ;
25- }
38+ Some ( route_datetime) => {
39+ let condition = DateTimeCondition :: DateTimeRange ( route_datetime. clone ( ) ) ;
40+ condition_group. insert ( condition. clone ( ) ) ;
41+ conditions. insert ( condition) ;
2642 }
27- None => {
28- self . no_matcher . insert ( route) ;
43+ None => ( ) ,
44+ }
45+
46+ match route. weekdays ( ) {
47+ Some ( route_weekdays) => {
48+ let condition = DateTimeCondition :: Weekdays ( route_weekdays. clone ( ) ) ;
49+ condition_group. insert ( condition. clone ( ) ) ;
50+ conditions. insert ( condition) ;
2951 }
52+ None => ( ) ,
3053 }
31- }
3254
33- fn remove ( & mut self , id : & str ) -> bool {
34- let mut removed = false ;
55+ match route. time ( ) {
56+ Some ( route_time) => {
57+ let condition = DateTimeCondition :: TimeRange ( route_time. clone ( ) ) ;
58+ condition_group. insert ( condition. clone ( ) ) ;
59+ conditions. insert ( condition) ;
60+ }
61+ None => ( ) ,
62+ }
3563
36- if self . no_matcher . remove ( id) {
37- self . count -= 1 ;
64+ if conditions. is_empty ( ) {
65+ self . any_datetime . insert ( route) ;
66+
67+ return ;
68+ }
69+
70+ self . conditions . extend ( conditions) ;
3871
39- return true ;
72+ if !self . condition_groups . contains_key ( & condition_group) {
73+ self . condition_groups . insert ( condition_group. clone ( ) , Self :: create_sub_matcher ( ) ) ;
4074 }
4175
42- self . matchers . retain ( |_, matcher| {
76+ let matcher = self . condition_groups . get_mut ( & condition_group) . unwrap ( ) ;
77+
78+ matcher. insert ( route)
79+ }
80+
81+ fn remove ( & mut self , id : & str ) -> bool {
82+ let mut removed = false ;
83+
84+ for matcher in self . condition_groups . values_mut ( ) {
4385 removed = removed || matcher. remove ( id) ;
86+ }
4487
45- matcher. len ( ) > 0
46- } ) ;
88+ removed = removed || self . any_datetime . remove ( id) ;
4789
4890 if removed {
4991 self . count -= 1 ;
@@ -53,63 +95,108 @@ impl<T: RouteData> RequestMatcher<T> for DateTimeMatcher<T> {
5395 }
5496
5597 fn match_request ( & self , request : & Request ) -> Vec < & Route < T > > {
56- let mut routes = self . no_matcher . match_request ( request) ;
98+ let mut rules = self . any_datetime . match_request ( request) ;
99+ let mut execute_conditions = BTreeMap :: new ( ) ;
57100
58101 if let Some ( datetime) = request. created_at . as_ref ( ) {
59- for ( datetime_matcher, matcher) in & self . matchers {
60- if datetime_matcher. match_datetime ( datetime) {
61- routes. extend ( matcher. match_request ( request) ) ;
102+ ' group: for ( conditions, matcher) in & self . condition_groups {
103+ for condition in conditions {
104+ match execute_conditions. get ( condition) {
105+ None => {
106+ // Execute condition
107+ let result = condition. match_value ( datetime) ;
108+
109+ // Save result
110+ execute_conditions. insert ( condition. clone ( ) , result) ;
111+
112+ if !result {
113+ continue ' group;
114+ }
115+ }
116+ Some ( result) => {
117+ if !result {
118+ continue ' group;
119+ }
120+ }
121+ }
62122 }
123+
124+ rules. extend ( matcher. match_request ( request) ) ;
63125 }
64126 }
65127
66- routes
128+ rules
67129 }
68130
69131 fn trace ( & self , request : & Request ) -> Vec < Trace < T > > {
70- let mut traces = self . no_matcher . trace ( request) ;
132+ let mut traces = self . any_datetime . trace ( request) ;
133+ let mut execute_conditions = BTreeMap :: new ( ) ;
71134
72135 if let Some ( datetime) = request. created_at . as_ref ( ) {
73- for ( datetime_matcher, matcher) in & self . matchers {
74- if datetime_matcher. match_datetime ( datetime) {
75- let datetime_traces = matcher. trace ( request) ;
76-
77- traces. push ( Trace :: new (
78- true ,
79- true ,
80- matcher. len ( ) as u64 ,
81- datetime_traces,
82- TraceInfo :: DateTime {
83- request : datetime. to_string ( ) ,
84- against : datetime_matcher. to_string ( ) ,
85- } ,
86- ) ) ;
87- } else {
88- traces. push ( Trace :: new (
89- false ,
90- true ,
91- matcher. len ( ) as u64 ,
92- Vec :: new ( ) ,
93- TraceInfo :: DateTime {
94- request : datetime. to_string ( ) ,
95- against : datetime_matcher. to_string ( ) ,
96- } ,
97- ) )
136+ for ( conditions, matcher) in & self . condition_groups {
137+ let mut matched = true ;
138+ let mut executed = true ;
139+ let mut traces_info_datetime = Vec :: new ( ) ;
140+
141+ for condition in conditions {
142+ match execute_conditions. get ( condition) {
143+ None => {
144+ // Execute condition
145+ let result = condition. match_value ( datetime) ;
146+ matched = matched && result;
147+
148+ // Save result (only if executed to mimic cache behavior)
149+ if executed {
150+ execute_conditions. insert ( condition. clone ( ) , matched) ;
151+ }
152+
153+ traces_info_datetime. push ( TraceInfoDateTimeCondition {
154+ result : if executed { Some ( result) } else { None } ,
155+ condition : condition. clone ( ) ,
156+ against : datetime. clone ( ) ,
157+ cached : false ,
158+ } ) ;
159+
160+ executed = matched;
161+ }
162+ Some ( result) => {
163+ matched = matched && * result;
164+
165+ traces_info_datetime. push ( TraceInfoDateTimeCondition {
166+ result : if executed { Some ( * result) } else { None } ,
167+ condition : condition. clone ( ) ,
168+ against : datetime. clone ( ) ,
169+ cached : true ,
170+ } ) ;
171+
172+ executed = matched;
173+ }
174+ }
98175 }
176+
177+ traces. push ( Trace :: new (
178+ matched,
179+ true ,
180+ matcher. len ( ) as u64 ,
181+ if matched { matcher. trace ( request) } else { Vec :: new ( ) } ,
182+ TraceInfo :: DateTimeGroup {
183+ conditions : traces_info_datetime,
184+ } ,
185+ ) ) ;
99186 }
100187 }
101188
102189 traces
103190 }
104191
105192 fn cache ( & mut self , limit : u64 , level : u64 ) -> u64 {
106- let mut new_limit = self . no_matcher . cache ( limit, level ) ;
193+ let mut new_limit = limit;
107194
108- for matcher in self . matchers . values_mut ( ) {
195+ for matcher in self . condition_groups . values_mut ( ) {
109196 new_limit = matcher. cache ( new_limit, level) ;
110197 }
111198
112- new_limit
199+ self . any_datetime . cache ( new_limit, level )
113200 }
114201
115202 fn len ( & self ) -> usize {
@@ -128,15 +215,40 @@ impl<T: RouteData> RequestMatcher<T> for DateTimeMatcher<T> {
128215impl < T : RouteData > Default for DateTimeMatcher < T > {
129216 fn default ( ) -> Self {
130217 DateTimeMatcher {
131- matchers : HashMap :: new ( ) ,
132- no_matcher : Self :: create_sub_matcher ( ) ,
218+ any_datetime : DateTimeMatcher :: create_sub_matcher ( ) ,
219+ conditions : BTreeSet :: new ( ) ,
220+ condition_groups : BTreeMap :: new ( ) ,
133221 count : 0 ,
134222 }
135223 }
136224}
137225
138226impl < T : RouteData > DateTimeMatcher < T > {
139227 pub fn create_sub_matcher ( ) -> Box < dyn RequestMatcher < T > > {
140- Box :: < WeekdayMatcher < T > > :: default ( )
228+ Box :: < MethodMatcher < T > > :: default ( )
229+ }
230+ }
231+
232+ impl DateTimeCondition {
233+ pub fn match_value ( & self , datetime : & DateTime < Utc > ) -> bool {
234+ match self {
235+ DateTimeCondition :: DateTimeRange ( route_date_time) => {
236+ for range in route_date_time {
237+ if range. match_datetime ( datetime) {
238+ return true ;
239+ }
240+ }
241+ return false ;
242+ } ,
243+ DateTimeCondition :: TimeRange ( route_time) => {
244+ for range in route_time {
245+ if range. match_datetime ( datetime) {
246+ return true ;
247+ }
248+ }
249+ return false ;
250+ } ,
251+ DateTimeCondition :: Weekdays ( route_weekday) => route_weekday. match_datetime ( datetime) ,
252+ }
141253 }
142254}
0 commit comments