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