Match `FOR VALID_TIME CONTAINS ` or `FOR VALID_TIME FROM TO ` and strip whichever is present.
(sql: &str)
| 176 | /// Match `FOR VALID_TIME CONTAINS <int>` or |
| 177 | /// `FOR VALID_TIME FROM <int> TO <int>` and strip whichever is present. |
| 178 | fn strip_valid_time(sql: &str) -> Result<Option<(String, ValidTime)>, TemporalParseError> { |
| 179 | let Some(start) = keyword_position_outside_literals(sql, "FOR VALID_TIME") else { |
| 180 | return Ok(None); |
| 181 | }; |
| 182 | let after_kw = start + "FOR VALID_TIME".len(); |
| 183 | let tail_raw = &sql[after_kw..]; |
| 184 | let tail_upper_owned = tail_raw.to_uppercase(); |
| 185 | let tail_upper = tail_upper_owned.trim_start(); |
| 186 | let leading_ws = tail_raw.len() - tail_raw.trim_start().len(); |
| 187 | |
| 188 | if let Some(rest) = tail_upper.strip_prefix("CONTAINS") { |
| 189 | let arg_abs = after_kw + leading_ws + "CONTAINS".len(); |
| 190 | let (ms, end_abs) = parse_trailing_i64(sql, arg_abs)?; |
| 191 | let _ = rest; |
| 192 | let mut out = String::with_capacity(sql.len()); |
| 193 | out.push_str(&sql[..start]); |
| 194 | out.push(' '); |
| 195 | out.push_str(&sql[end_abs..]); |
| 196 | return Ok(Some((out, ValidTime::At(ms)))); |
| 197 | } |
| 198 | if let Some(rest) = tail_upper.strip_prefix("FROM") { |
| 199 | let arg_abs = after_kw + leading_ws + "FROM".len(); |
| 200 | let (lo, lo_end) = parse_trailing_i64(sql, arg_abs)?; |
| 201 | let after_lo_raw = &sql[lo_end..]; |
| 202 | let after_lo_upper_owned = after_lo_raw.to_uppercase(); |
| 203 | let after_lo_upper = after_lo_upper_owned.trim_start(); |
| 204 | let leading_ws2 = after_lo_raw.len() - after_lo_raw.trim_start().len(); |
| 205 | let Some(_after_to) = after_lo_upper.strip_prefix("TO") else { |
| 206 | return Err(TemporalParseError( |
| 207 | "FOR VALID_TIME FROM <ms> must be followed by TO <ms>".into(), |
| 208 | )); |
| 209 | }; |
| 210 | let hi_arg = lo_end + leading_ws2 + "TO".len(); |
| 211 | let (hi, hi_end) = parse_trailing_i64(sql, hi_arg)?; |
| 212 | let _ = rest; |
| 213 | let mut out = String::with_capacity(sql.len()); |
| 214 | out.push_str(&sql[..start]); |
| 215 | out.push(' '); |
| 216 | out.push_str(&sql[hi_end..]); |
| 217 | if hi <= lo { |
| 218 | return Err(TemporalParseError(format!( |
| 219 | "FOR VALID_TIME FROM {lo} TO {hi}: hi must be > lo" |
| 220 | ))); |
| 221 | } |
| 222 | return Ok(Some((out, ValidTime::Range(lo, hi)))); |
| 223 | } |
| 224 | Err(TemporalParseError( |
| 225 | "FOR VALID_TIME must be followed by CONTAINS or FROM".into(), |
| 226 | )) |
| 227 | } |
| 228 | |
| 229 | /// Resolve a temporal expression token to milliseconds since Unix epoch. |
| 230 | /// |
no test coverage detected