MCPcopy Create free account
hub / github.com/NodeDB-Lab/nodedb / parse_as_of_expr

Function parse_as_of_expr

nodedb-sql/src/parser/preprocess/temporal.rs:331–401  ·  view source on GitHub ↗

Extract the temporal expression that follows an AS-OF keyword at `offset` in `sql`. Returns `(resolved_ms, end_offset_exclusive)`. The expression is delimited by end-of-string or the next keyword-boundary token (a subsequent `AS OF`, or certain SQL keywords that cannot appear inside a temporal expression). Quoted string literals are consumed whole.

(sql: &str, offset: usize)

Source from the content-addressed store, hash-verified

329/// token (a subsequent `AS OF`, or certain SQL keywords that cannot appear
330/// inside a temporal expression). Quoted string literals are consumed whole.
331fn parse_as_of_expr(sql: &str, offset: usize) -> Result<(i64, usize), TemporalParseError> {
332 let rest = &sql[offset..];
333 let trimmed = rest.trim_start();
334 let leading = rest.len() - trimmed.len();
335 let abs_start = offset + leading;
336
337 // If the next non-whitespace character opens a quoted string, consume
338 // through the closing quote.
339 if trimmed.starts_with('\'') || trimmed.starts_with('"') {
340 let quote = trimmed
341 .chars()
342 .next()
343 .expect("invariant: trimmed.starts_with('\\'' | '\"') guarantees at least one char");
344 let inner_start = 1;
345 let close = trimmed[inner_start..].find(quote).ok_or_else(|| {
346 TemporalParseError(format!(
347 "AS OF temporal expression: unterminated string literal at offset {abs_start}"
348 ))
349 })?;
350 let end_rel = inner_start + close + 1; // include closing quote
351 let token = &trimmed[..end_rel];
352 let ms = parse_temporal_expr(token)?;
353 return Ok((ms, abs_start + end_rel));
354 }
355
356 // Otherwise scan to the next whitespace-delimited boundary. We stop at:
357 // a) another `AS OF` sequence (another clause),
358 // b) certain SQL delimiter tokens: WHERE, LIMIT, ORDER, GROUP, HAVING,
359 // UNION, EXCEPT, INTERSECT, FETCH, FOR, OFFSET, semicolon.
360 let stop_tokens = [
361 "AS OF",
362 "WHERE",
363 "LIMIT",
364 "ORDER",
365 "GROUP",
366 "HAVING",
367 "UNION",
368 "EXCEPT",
369 "INTERSECT",
370 "FETCH",
371 "OFFSET",
372 ";",
373 ];
374 let upper_trimmed = trimmed.to_uppercase();
375 let mut end_rel = trimmed.len();
376 for stop in &stop_tokens {
377 // Only match at a word boundary (preceded by whitespace or start).
378 let mut search_from = 0;
379 while let Some(pos) = upper_trimmed[search_from..].find(stop) {
380 let abs_pos = search_from + pos;
381 let at_boundary = abs_pos == 0
382 || upper_trimmed[..abs_pos].ends_with(|c: char| c.is_ascii_whitespace());
383 if at_boundary {
384 end_rel = end_rel.min(abs_pos);
385 break;
386 }
387 search_from = abs_pos + 1;
388 }

Callers 2

strip_as_of_system_timeFunction · 0.85
strip_as_of_valid_timeFunction · 0.85

Calls 7

TemporalParseErrorClass · 0.85
parse_temporal_exprFunction · 0.85
lenMethod · 0.45
expectMethod · 0.45
nextMethod · 0.45
findMethod · 0.45
is_emptyMethod · 0.45

Tested by

no test coverage detected