Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion web/book/src/reference/stdlib/date.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ Here is the list of the specifiers currently supported:
| | | |
| | | **TIME SPECIFIERS:** |
| `%H` | `00` | Hour number (00-23) |
| `%k` | ` 0` | Same as `%H` but space-padded. Same as `%_H`. |
| `%-H` | `0` | Hour number (0-23) |
| `%I` | `12` | Hour number in 12-hour clocks (01--12), zero-padded to 2 digits. |
| `%p` | `AM` | `AM` or `PM` in 12-hour clocks. |
| `%M` | `34` | Minute number (00-59), zero-padded to 2 digits. |
Expand All @@ -120,4 +120,7 @@ Here is the list of the specifiers currently supported:
| `%n` | | Literal newline (`\n`). |
| `%%` | | Literal percent sign. |

Space-padded specifiers — chrono's `%_`-prefixed forms and their `%k` / `%l`
aliases — are not supported by any dialect.

[^1]: This is different from chrono, for which `%f` represents nanoseconds
48 changes: 48 additions & 0 deletions web/book/tests/documentation/book.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use itertools::Itertools;
use mdbook_prql::{code_block_lang_tags, LangTag};
use prqlc::{pl_to_prql, pl_to_rq, prql_to_pl};
use pulldown_cmark::Tag;
use regex::Regex;
use walkdir::WalkDir;

use super::compile;
Expand Down Expand Up @@ -164,6 +165,53 @@ Remove `no-fmt` as a language label to assert successfully compiling the formatt
}
}

/// The date & time format specifier table in `reference/stdlib/date.md` is
/// introduced as "the list of the specifiers currently supported", so assert
/// that each row does compile — otherwise the table silently drifts from the
/// dialect implementations in `sql/dialect.rs`.
///
/// We check against Postgres, matching the other examples on that page; which
/// specifiers are supported varies by dialect.
#[test]
fn test_date_format_specifiers_compile() -> Result<()> {
let text = fs::read_to_string("./src/reference/stdlib/date.md")?;
// The first cell of each row of the specifier table, e.g. ``| `%Y` |``.
let specifier_cell = Regex::new(r"(?m)^\| `(%[^`]+)` *\|")?;

let specifiers: Vec<&str> = specifier_cell
.captures_iter(&text)
.map(|c| c.get(1).unwrap().as_str())
.collect();
// Guard against the test passing vacuously if the table's formatting
// changes and the regex stops matching.
if specifiers.len() < 20 {
bail!(
"Expected to find the date specifier table; only matched {} rows",
specifiers.len()
);
}

let mut errs = Vec::new();
for specifier in specifiers {
let prql = format!(
r#"prql target:sql.postgres
from tbl
select {{ a = (tbl.col | date.to_text "{specifier}") }}
"#
);
if let Err(e) = compile(&prql) {
errs.push(format!(
"`{specifier}` is documented as supported, but fails to compile:\n{e}"
));
}
}
if errs.is_empty() {
Ok(())
} else {
Err(anyhow!(errs.join("\n")))
}
}

struct Example {
/// Name contains the file, the heading, and the index of the example.
name: String,
Expand Down
Loading