13
13
use bigdecimal:: BigDecimal ;
14
14
use std:: fmt;
15
15
16
+ mod datetime;
17
+ pub use datetime:: {
18
+ DateTimeField , Interval , IntervalValue , ParsedDate , ParsedDateTime , ParsedTimestamp ,
19
+ } ;
20
+
21
+ #[ derive( Debug ) ]
22
+ pub struct ValueError ( String ) ;
23
+
24
+ impl std:: error:: Error for ValueError { }
25
+
26
+ impl fmt:: Display for ValueError {
27
+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
28
+ write ! ( f, "{}" , self . 0 )
29
+ }
30
+ }
31
+
16
32
/// Primitive SQL values such as number and string
17
33
#[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
18
34
pub enum Value {
@@ -29,14 +45,14 @@ pub enum Value {
29
45
/// Boolean value true or false
30
46
Boolean ( bool ) ,
31
47
/// `DATE '...'` literals
32
- Date ( String ) ,
48
+ Date ( String , ParsedDate ) ,
33
49
/// `TIME '...'` literals
34
50
Time ( String ) ,
35
51
/// `TIMESTAMP '...'` literals
36
- Timestamp ( String ) ,
52
+ Timestamp ( String , ParsedTimestamp ) ,
37
53
/// INTERVAL literals, roughly in the following format:
38
54
///
39
- /// ```ignore
55
+ /// ```text
40
56
/// INTERVAL '<value>' <leading_field> [ (<leading_precision>) ]
41
57
/// [ TO <last_field> [ (<fractional_seconds_precision>) ] ]
42
58
/// ```
@@ -45,47 +61,13 @@ pub enum Value {
45
61
/// The parser does not validate the `<value>`, nor does it ensure
46
62
/// that the `<leading_field>` units >= the units in `<last_field>`,
47
63
/// so the user will have to reject intervals like `HOUR TO YEAR`.
48
- Interval {
49
- /// The raw [value] that was present in `INTERVAL '[value]'`
50
- value : String ,
51
- /// The unit of the first field in the interval. `INTERVAL 'T' MINUTE`
52
- /// means `T` is in minutes
53
- leading_field : DateTimeField ,
54
- /// How many digits the leading field is allowed to occupy.
55
- ///
56
- /// The interval `INTERVAL '1234' MINUTE(3)` is **illegal**, but `INTERVAL
57
- /// '123' MINUTE(3)` is fine.
58
- ///
59
- /// This parser does not do any validation that fields fit.
60
- leading_precision : Option < u64 > ,
61
- /// How much precision to keep track of
62
- ///
63
- /// If this is ommitted, then you are supposed to ignore all of the
64
- /// non-lead fields. If it is less precise than the final field, you
65
- /// are supposed to ignore the final field.
66
- ///
67
- /// For the following specifications:
68
- ///
69
- /// * `INTERVAL '1:1:1' HOURS TO SECONDS` the `last_field` gets
70
- /// `Some(DateTimeField::Second)` and interpreters should generate an
71
- /// interval equivalent to `3661` seconds.
72
- /// * In `INTERVAL '1:1:1' HOURS` the `last_field` gets `None` and
73
- /// interpreters should generate an interval equivalent to `3600`
74
- /// seconds.
75
- /// * In `INTERVAL '1:1:1' HOURS TO MINUTES` the interval should be
76
- /// equivalent to `3660` seconds.
77
- last_field : Option < DateTimeField > ,
78
- /// The seconds precision can be specified in SQL source as
79
- /// `INTERVAL '__' SECOND(_, x)` (in which case the `leading_field`
80
- /// will be `Second` and the `last_field` will be `None`),
81
- /// or as `__ TO SECOND(x)`.
82
- fractional_seconds_precision : Option < u64 > ,
83
- } ,
64
+ Interval ( IntervalValue ) ,
84
65
/// `NULL` value
85
66
Null ,
86
67
}
87
68
88
69
impl fmt:: Display for Value {
70
+ #[ allow( clippy:: unneeded_field_pattern) ] // want to be warned if we add another field
89
71
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
90
72
match self {
91
73
Value :: Long ( v) => write ! ( f, "{}" , v) ,
@@ -94,16 +76,17 @@ impl fmt::Display for Value {
94
76
Value :: NationalStringLiteral ( v) => write ! ( f, "N'{}'" , v) ,
95
77
Value :: HexStringLiteral ( v) => write ! ( f, "X'{}'" , v) ,
96
78
Value :: Boolean ( v) => write ! ( f, "{}" , v) ,
97
- Value :: Date ( v) => write ! ( f, "DATE '{}'" , escape_single_quote_string( v) ) ,
79
+ Value :: Date ( v, _ ) => write ! ( f, "DATE '{}'" , escape_single_quote_string( v) ) ,
98
80
Value :: Time ( v) => write ! ( f, "TIME '{}'" , escape_single_quote_string( v) ) ,
99
- Value :: Timestamp ( v) => write ! ( f, "TIMESTAMP '{}'" , escape_single_quote_string( v) ) ,
100
- Value :: Interval {
81
+ Value :: Timestamp ( v, _) => write ! ( f, "TIMESTAMP '{}'" , escape_single_quote_string( v) ) ,
82
+ Value :: Interval ( IntervalValue {
83
+ parsed : _,
101
84
value,
102
85
leading_field : DateTimeField :: Second ,
103
86
leading_precision : Some ( leading_precision) ,
104
87
last_field,
105
88
fractional_seconds_precision : Some ( fractional_seconds_precision) ,
106
- } => {
89
+ } ) => {
107
90
// When the leading field is SECOND, the parser guarantees that
108
91
// the last field is None.
109
92
assert ! ( last_field. is_none( ) ) ;
@@ -115,13 +98,14 @@ impl fmt::Display for Value {
115
98
fractional_seconds_precision
116
99
)
117
100
}
118
- Value :: Interval {
101
+ Value :: Interval ( IntervalValue {
102
+ parsed : _,
119
103
value,
120
104
leading_field,
121
105
leading_precision,
122
106
last_field,
123
107
fractional_seconds_precision,
124
- } => {
108
+ } ) => {
125
109
write ! (
126
110
f,
127
111
"INTERVAL '{}' {}" ,
@@ -144,29 +128,6 @@ impl fmt::Display for Value {
144
128
}
145
129
}
146
130
147
- #[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
148
- pub enum DateTimeField {
149
- Year ,
150
- Month ,
151
- Day ,
152
- Hour ,
153
- Minute ,
154
- Second ,
155
- }
156
-
157
- impl fmt:: Display for DateTimeField {
158
- fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
159
- f. write_str ( match self {
160
- DateTimeField :: Year => "YEAR" ,
161
- DateTimeField :: Month => "MONTH" ,
162
- DateTimeField :: Day => "DAY" ,
163
- DateTimeField :: Hour => "HOUR" ,
164
- DateTimeField :: Minute => "MINUTE" ,
165
- DateTimeField :: Second => "SECOND" ,
166
- } )
167
- }
168
- }
169
-
170
131
pub struct EscapeSingleQuoteString < ' a > ( & ' a str ) ;
171
132
172
133
impl < ' a > fmt:: Display for EscapeSingleQuoteString < ' a > {
@@ -185,3 +146,39 @@ impl<'a> fmt::Display for EscapeSingleQuoteString<'a> {
185
146
pub fn escape_single_quote_string ( s : & str ) -> EscapeSingleQuoteString < ' _ > {
186
147
EscapeSingleQuoteString ( s)
187
148
}
149
+
150
+ #[ cfg( test) ]
151
+ mod test {
152
+ use super :: * ;
153
+
154
+ /// An extremely default interval value
155
+ fn ivalue ( ) -> IntervalValue {
156
+ IntervalValue {
157
+ value : "" . into ( ) ,
158
+ parsed : ParsedDateTime :: default ( ) ,
159
+ leading_field : DateTimeField :: Year ,
160
+ leading_precision : None ,
161
+ last_field : None ,
162
+ fractional_seconds_precision : None ,
163
+ }
164
+ }
165
+
166
+ #[ test]
167
+ fn interval_values ( ) {
168
+ let mut iv = ivalue ( ) ;
169
+ iv. parsed . year = None ;
170
+ match iv. computed_permissive ( ) {
171
+ Err ( ValueError { .. } ) => { }
172
+ Ok ( why) => panic ! ( "should not be okay: {:?}" , why) ,
173
+ }
174
+ }
175
+
176
+ #[ test]
177
+ fn iterate_datetimefield ( ) {
178
+ use DateTimeField :: * ;
179
+ assert_eq ! (
180
+ Year . into_iter( ) . take( 10 ) . collect:: <Vec <_>>( ) ,
181
+ vec![ Month , Day , Hour , Minute , Second ]
182
+ )
183
+ }
184
+ }
0 commit comments