1+ use pg_interval:: Interval ;
2+ use super :: parse_error:: ParseError ;
3+ use interval_norm:: IntervalNorm ;
4+
5+ use super :: {
6+ scale_date,
7+ scale_time,
8+ DAYS_PER_MONTH ,
9+ MONTHS_PER_YEAR ,
10+ SECONDS_PER_MIN ,
11+ HOURS_PER_DAY ,
12+ MINUTES_PER_HOUR ,
13+ MICROS_PER_SECOND
14+ } ;
15+
16+ impl Interval {
17+ pub fn from_postgres < ' a > ( iso_str : & ' a str ) -> Result < Interval , ParseError > {
18+ let mut delim = vec ! ( "years" , "months" , "mons" , "days" , "hours" , "minutes" , "seconds" ) ;
19+ let mut time_tokens = iso_str. split ( " " ) . collect :: < Vec < & str > > ( ) ;
20+ // clean up empty values caused by n spaces between values.
21+ time_tokens. retain ( |& token| token != "" ) ;
22+ // since there might not be space between the delim and the
23+ // value we need to scan each token.
24+ let mut final_tokens = Vec :: with_capacity ( time_tokens. len ( ) ) ;
25+ for token in time_tokens {
26+ if is_token_alphanumeric ( token) ? {
27+ let ( val, unit) = split_token ( token) ?;
28+ final_tokens. push ( val) ;
29+ final_tokens. push ( unit) ;
30+ } else {
31+ final_tokens. push ( token. to_owned ( ) ) ;
32+ }
33+ }
34+ if final_tokens. len ( ) % 2 != 0 {
35+ return Err ( ParseError :: from_invalid_interval ( "Invalid amount tokens were found." ) ) ;
36+ }
37+ // Consume our tokens and build up the
38+ // normalized interval.
39+ let mut val = 0.0 ;
40+ let mut is_numeric = true ;
41+ let mut interval = IntervalNorm :: default ( ) ;
42+ for token in final_tokens {
43+ if is_numeric {
44+ val = token. parse :: < f64 > ( ) ?;
45+ is_numeric = false ;
46+ } else {
47+ consume_token ( & mut interval, val, token, & mut delim) ?;
48+ is_numeric = true ;
49+ }
50+ }
51+ interval. try_into_interval ( )
52+ }
53+ }
54+
55+ /// Does the token contain both alphabetic and numeric characters?
56+ fn is_token_alphanumeric < ' a > ( val : & ' a str ) -> Result < bool , ParseError > {
57+ let mut has_numeric = false ;
58+ let mut has_alpha = false ;
59+ for character in val. chars ( ) {
60+ if character. is_numeric ( ) || character == '-' || character == '.' {
61+ has_numeric = true ;
62+ } else if character. is_alphabetic ( ) {
63+ has_alpha = true ;
64+ } else {
65+ return Err (
66+ ParseError :: from_invalid_interval ( "String can only contain alpha numeric characters." )
67+ ) ;
68+ }
69+ }
70+ Ok ( has_numeric && has_alpha)
71+ }
72+
73+ /// Split the token into two tokens as they might of not been
74+ /// seperated by a space.
75+ fn split_token < ' a > ( val : & ' a str ) -> Result < ( String , String ) , ParseError > {
76+ let mut is_numeric_done = false ;
77+ let mut value = String :: new ( ) ;
78+ let mut delim = String :: new ( ) ;
79+ for character in val. chars ( ) {
80+ if ( character. is_numeric ( ) || character == '-' || character == '.' ) && !is_numeric_done {
81+ value. push ( character) ;
82+ } else if character. is_alphabetic ( ) {
83+ is_numeric_done = true ;
84+ delim. push ( character)
85+ } else {
86+ return Err (
87+ ParseError :: from_invalid_interval ( "String can only contain alpha numeric characters." )
88+ ) ;
89+ }
90+ }
91+ Ok ( ( value, delim) )
92+ }
93+
94+ /// Consume the token parts and add to the normalized interval.
95+ fn consume_token < ' a > (
96+ interval : & mut IntervalNorm ,
97+ val : f64 ,
98+ delim : String ,
99+ delim_list : & mut Vec < & ' a str >
100+ ) -> Result < ( ) , ParseError > {
101+ // Unlike iso8601 the delimiter can only appear once
102+ // so we need to check if the token can be found in
103+ // the deliminator list.
104+ if delim_list. contains ( & & * delim) {
105+ match & * delim {
106+ "years" => {
107+ let ( year, month) = scale_date ( val, MONTHS_PER_YEAR ) ;
108+ interval. years += year;
109+ interval. months += month;
110+ delim_list. retain ( |x| * x != "years" ) ;
111+ Ok ( ( ) )
112+ } ,
113+ "months" | "mons" => {
114+ let ( month, day) = scale_date ( val, DAYS_PER_MONTH ) ;
115+ interval. months += month;
116+ interval. days += day;
117+ delim_list. retain ( |x| * x != "months" && * x != "mons" ) ;
118+ Ok ( ( ) )
119+ } ,
120+ "days" => {
121+ let ( days, hours) = scale_date ( val, HOURS_PER_DAY ) ;
122+ interval. days += days;
123+ interval. hours += hours as i64 ;
124+ delim_list. retain ( |x| * x != "days" ) ;
125+ Ok ( ( ) )
126+ } ,
127+ "hours" => {
128+ let ( hours, minutes) = scale_time ( val, MINUTES_PER_HOUR ) ;
129+ interval. hours += hours;
130+ interval. minutes += minutes;
131+ delim_list. retain ( |x| * x != "hours" ) ;
132+ Ok ( ( ) )
133+ } ,
134+ "minutes" => {
135+ let ( minutes, seconds) = scale_time ( val, SECONDS_PER_MIN ) ;
136+ interval. minutes += minutes;
137+ interval. seconds += seconds;
138+ delim_list. retain ( |x| * x != "minutes" ) ;
139+ Ok ( ( ) )
140+ } ,
141+ "seconds" => {
142+ let ( seconds, microseconds) = scale_time ( val, MICROS_PER_SECOND ) ;
143+ interval. seconds += seconds;
144+ interval. microseconds += microseconds;
145+ delim_list. retain ( |x| * x != "seconds" ) ;
146+ Ok ( ( ) )
147+ }
148+ _ => {
149+ Err (
150+ ParseError :: from_invalid_interval ( "Invalid deliminator." )
151+ )
152+ }
153+ }
154+ } else {
155+ Err (
156+ ParseError :: from_invalid_interval ( "Invalid deliminator2" )
157+ )
158+ }
159+ }
160+
161+ #[ cfg( test) ]
162+ mod tests {
163+ use pg_interval:: Interval ;
164+
165+ #[ test]
166+ fn test_from_postgres_1 ( ) {
167+ let interval = Interval :: from_postgres ( "1 years" ) . unwrap ( ) ;
168+ let interval_exp = Interval :: new ( 12 , 0 , 0 ) ;
169+ assert_eq ! ( interval, interval_exp) ;
170+ }
171+
172+ #[ test]
173+ fn test_from_postgres_2 ( ) {
174+ let interval = Interval :: from_postgres ( "1years" ) . unwrap ( ) ;
175+ let interval_exp = Interval :: new ( 12 , 0 , 0 ) ;
176+ assert_eq ! ( interval, interval_exp) ;
177+ }
178+
179+ #[ test]
180+ fn test_from_postgres_3 ( ) {
181+ let interval = Interval :: from_postgres ( "1 years 1 months" ) . unwrap ( ) ;
182+ let interval_exp = Interval :: new ( 13 , 0 , 0 ) ;
183+ assert_eq ! ( interval, interval_exp) ;
184+ }
185+
186+ #[ test]
187+ fn test_from_postgres_4 ( ) {
188+ let interval = Interval :: from_postgres ( "1years 1months" ) . unwrap ( ) ;
189+ let interval_exp = Interval :: new ( 13 , 0 , 0 ) ;
190+ assert_eq ! ( interval, interval_exp) ;
191+ }
192+
193+
194+ #[ test]
195+ fn test_from_postgres_5 ( ) {
196+ let interval = Interval :: from_postgres ( "1 years 1 mons 1 days" ) . unwrap ( ) ;
197+ let interval_exp = Interval :: new ( 13 , 1 , 0 ) ;
198+ assert_eq ! ( interval, interval_exp) ;
199+ }
200+
201+ #[ test]
202+ fn test_from_postgres_6 ( ) {
203+ let interval = Interval :: from_postgres ( "1years 1mons 1days" ) . unwrap ( ) ;
204+ let interval_exp = Interval :: new ( 13 , 1 , 0 ) ;
205+ assert_eq ! ( interval, interval_exp) ;
206+ }
207+
208+ #[ test]
209+ fn test_from_postgres_7 ( ) {
210+ let interval = Interval :: from_postgres ( "1 years 1 months 1 days 1 hours" ) . unwrap ( ) ;
211+ let interval_exp = Interval :: new ( 13 , 1 , 3600000000 ) ;
212+ assert_eq ! ( interval, interval_exp) ;
213+ }
214+
215+ #[ test]
216+ fn test_from_postgres_8 ( ) {
217+ let interval = Interval :: from_postgres ( "1years 1months 1days 1hours" ) . unwrap ( ) ;
218+ let interval_exp = Interval :: new ( 13 , 1 , 3600000000 ) ;
219+ assert_eq ! ( interval, interval_exp) ;
220+ }
221+
222+
223+ #[ test]
224+ fn test_from_postgres_9 ( ) {
225+ let interval = Interval :: from_postgres ( "1 years 1 months 1 days 1 hours 10 minutes" ) . unwrap ( ) ;
226+ let interval_exp = Interval :: new ( 13 , 1 , 4200000000 ) ;
227+ assert_eq ! ( interval, interval_exp) ;
228+ }
229+
230+
231+ #[ test]
232+ fn test_from_postgres_10 ( ) {
233+ let interval = Interval :: from_postgres ( "1 years 1 months 1 days 1 hours 10 minutes 15 seconds" ) . unwrap ( ) ;
234+ let interval_exp = Interval :: new ( 13 , 1 , 4215000000 ) ;
235+ assert_eq ! ( interval, interval_exp) ;
236+ }
237+
238+ #[ test]
239+ fn test_from_postgres_11 ( ) {
240+ let interval = Interval :: from_postgres ( "1 hours" ) . unwrap ( ) ;
241+ let interval_exp = Interval :: new ( 0 , 0 , 3600000000 ) ;
242+ assert_eq ! ( interval, interval_exp) ;
243+ }
244+
245+ #[ test]
246+ fn test_from_postgres_12 ( ) {
247+ let interval = Interval :: from_postgres ( "1 hours 10 minutes" ) . unwrap ( ) ;
248+ let interval_exp = Interval :: new ( 0 , 0 , 4200000000 ) ;
249+ assert_eq ! ( interval, interval_exp) ;
250+ }
251+
252+
253+ #[ test]
254+ fn test_from_postgres_13 ( ) {
255+ let interval = Interval :: from_postgres ( "1 hours 10 minutes 15 seconds" ) . unwrap ( ) ;
256+ let interval_exp = Interval :: new ( 0 , 0 , 4215000000 ) ;
257+ assert_eq ! ( interval, interval_exp) ;
258+ }
259+
260+ #[ test]
261+ fn test_from_postgres_14 ( ) {
262+ let interval = Interval :: from_postgres ( "-1 years" ) . unwrap ( ) ;
263+ let interval_exp = Interval :: new ( -12 , 0 , 0 ) ;
264+ assert_eq ! ( interval, interval_exp) ;
265+ }
266+
267+ #[ test]
268+ fn test_from_postgres_15 ( ) {
269+ let interval = Interval :: from_postgres ( "-1years" ) . unwrap ( ) ;
270+ let interval_exp = Interval :: new ( -12 , 0 , 0 ) ;
271+ assert_eq ! ( interval, interval_exp) ;
272+ }
273+
274+
275+ #[ test]
276+ fn test_from_postgres_16 ( ) {
277+ let interval = Interval :: from_postgres ( "-1 years -1 months" ) . unwrap ( ) ;
278+ let interval_exp = Interval :: new ( -13 , 0 , 0 ) ;
279+ assert_eq ! ( interval, interval_exp) ;
280+ }
281+
282+ #[ test]
283+ fn test_from_postgres_17 ( ) {
284+ let interval = Interval :: from_postgres ( "-1 years -1months -1 days" ) . unwrap ( ) ;
285+ let interval_exp = Interval :: new ( -13 , -1 , 0 ) ;
286+ assert_eq ! ( interval, interval_exp) ;
287+ }
288+
289+ #[ test]
290+ fn test_from_postgres_18 ( ) {
291+ let interval = Interval :: from_postgres ( "-1 years -1 months -1 days -1 hours" ) . unwrap ( ) ;
292+ let interval_exp = Interval :: new ( -13 , -1 , -3600000000 ) ;
293+ assert_eq ! ( interval, interval_exp) ;
294+ }
295+
296+ #[ test]
297+ fn test_from_postgres_19 ( ) {
298+ let interval = Interval :: from_postgres ( "-1 years -1 months -1days -1hours -10minutes" ) . unwrap ( ) ;
299+ let interval_exp = Interval :: new ( -13 , -1 , -4200000000 ) ;
300+ assert_eq ! ( interval, interval_exp) ;
301+ }
302+
303+ #[ test]
304+ fn test_from_postgres_20 ( ) {
305+ let interval = Interval :: from_postgres ( "-1years -1 mons -1 days -1hours -10minutes -15seconds" ) . unwrap ( ) ;
306+ let interval_exp = Interval :: new ( -13 , -1 , -4215000000 ) ;
307+ assert_eq ! ( interval, interval_exp) ;
308+ }
309+
310+ #[ test]
311+ fn test_from_postgres_21 ( ) {
312+ let interval = Interval :: from_postgres ( "-1 hours" ) . unwrap ( ) ;
313+ let interval_exp = Interval :: new ( 0 , 0 , -3600000000 ) ;
314+ assert_eq ! ( interval, interval_exp) ;
315+ }
316+
317+ #[ test]
318+ fn test_from_postgres_22 ( ) {
319+ let interval = Interval :: from_postgres ( "-1 hours -10minutes" ) . unwrap ( ) ;
320+ let interval_exp = Interval :: new ( 0 , 0 , -4200000000 ) ;
321+ assert_eq ! ( interval, interval_exp) ;
322+ }
323+
324+ #[ test]
325+ fn test_from_postgres_23 ( ) {
326+ let interval = Interval :: from_postgres ( "-1 hours -10minutes -15 seconds" ) . unwrap ( ) ;
327+ let interval_exp = Interval :: new ( 0 , 0 , -4215000000 ) ;
328+ assert_eq ! ( interval, interval_exp) ;
329+ }
330+
331+
332+ #[ test]
333+ fn test_from_postgres_24 ( ) {
334+ let interval = Interval :: from_postgres ( "years 1" ) ;
335+ assert_eq ! ( interval. is_err( ) , true ) ;
336+ }
337+
338+ #[ test]
339+ fn test_from_postgres_25 ( ) {
340+ let interval = Interval :: from_postgres ( "- years" ) ;
341+ assert_eq ! ( interval. is_err( ) , true ) ;
342+ }
343+
344+ #[ test]
345+ fn test_from_postgres_26 ( ) {
346+ let interval = Interval :: from_postgres ( "10" ) ;
347+ assert_eq ! ( interval. is_err( ) , true ) ;
348+ }
349+
350+ #[ test]
351+ fn test_from_postgres_27 ( ) {
352+ let interval = Interval :: from_postgres ( "1.2 years" ) . unwrap ( ) ;
353+ let interval_exp = Interval :: new ( 14 , 0 , 0 ) ;
354+ assert_eq ! ( interval, interval_exp) ;
355+ }
356+
357+ #[ test]
358+ fn test_from_postgres_28 ( ) {
359+ let interval = Interval :: from_postgres ( "1.2 months" ) . unwrap ( ) ;
360+ let interval_exp = Interval :: new ( 1 , 6 , 0 ) ;
361+ assert_eq ! ( interval, interval_exp) ;
362+ }
363+
364+ #[ test]
365+ fn test_from_postgres_29 ( ) {
366+ let interval = Interval :: from_postgres ( "1.2 seconds" ) . unwrap ( ) ;
367+ let interval_exp = Interval :: new ( 0 , 0 , 1_200_000 ) ;
368+ assert_eq ! ( interval, interval_exp) ;
369+ }
370+
371+ }
0 commit comments