Skip to content

Commit

Permalink
refactor: move website examples into data files
Browse files Browse the repository at this point in the history
The examples showcased on the website were previously all defined in the
the YAML front matter of _index.md. This commit moves them to separate
data files[1], which are easier to edit and test.

[1]: https://gohugo.io/templates/data-templates/
  • Loading branch information
not-my-profile committed Jul 14, 2023
1 parent 6562356 commit 30b9dab
Show file tree
Hide file tree
Showing 16 changed files with 267 additions and 297 deletions.
58 changes: 18 additions & 40 deletions web/book/tests/documentation/website.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::fs::read_dir;

use regex::Regex;
use serde_yaml::Value;

Expand All @@ -8,48 +10,24 @@ fn sql_normalize(sql: &str) -> String {
re.replace_all(sql, " ").trim().to_string()
}

fn website_contents() -> Value {
let contents = include_str!("../../../website/content/_index.md").replace("---", "");
serde_yaml::from_str::<Value>(&contents).unwrap()
}

fn website_examples() -> Vec<Value> {
let value = website_contents();

value
.get("showcase_section")
.unwrap()
.get("examples")
.unwrap()
.as_sequence()
.unwrap()
.clone()
}

fn website_hero_example() -> String {
let value = website_contents();

value
.get("hero_section")
.unwrap()
.get("prql_example")
.unwrap()
.as_str()
.unwrap()
.to_string()
}

#[test]
fn test_website_examples() {
for example in website_examples() {
for example in read_dir("../website/data/examples")
.unwrap()
.into_iter()
.flatten()
{
let file = std::fs::File::open(example.path()).unwrap();
let example: Value = serde_yaml::from_reader(file).unwrap();
let prql = example.get("prql").unwrap().as_str().unwrap();
let sql = example.get("sql").unwrap().as_str().unwrap();
assert_eq!(sql_normalize(&compile(prql).unwrap()), sql_normalize(sql));
}
}

#[test]
fn test_website_hero_example() {
let prql = website_hero_example();
compile(&prql).unwrap();
let compiled_sql = compile(prql).unwrap();

if let Some(sql) = example.get("sql") {
assert_eq!(
sql_normalize(&compiled_sql),
sql_normalize(sql.as_str().unwrap())
);
}
}
}
262 changes: 14 additions & 248 deletions web/website/content/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,29 +11,7 @@ hero_section:
enable: false
link: https://prql-lang.org/book/
label: "Reference"
prql_example: |
from invoices
filter invoice_date >= @1970-01-16
derive {
transaction_fees = 0.8,
income = total - transaction_fees
}
filter income > 1
group customer_id (
aggregate {
average total,
sum_income = sum income,
ct = count total,
}
)
sort {-sum_income}
take 10
join c=customers (==customer_id)
derive name = f"{c.last_name}, {c.first_name}"
select {
c.customer_id, name, sum_income
}
derive db_version = s"version()"
# the PRQL example is defined in data/examples/hero.yaml

why_prql_section:
enable: true
Expand Down Expand Up @@ -80,71 +58,19 @@ showcase_section:
- link: "/book/"
label: "Book"
examples:
- id: basics
label: Basic example
prql: |
from employees
select {id, first_name, age}
sort age
take 10
sql: |
SELECT
id,
first_name,
age
FROM
employees
ORDER BY
age
LIMIT
10
- id: friendly-syntax
label: Friendly syntax
prql: |
from track_plays
filter plays > 10_000 # Readable numbers
filter (length | in 60..240) # Ranges with `..`
filter recorded > @2008-01-01 # Simple date literals
filter released - recorded < 180days # Nice interval literals
sort {-length} # Concise order direction
sql: |
SELECT
*
FROM
track_plays
WHERE
plays > 10000
AND length BETWEEN 60 AND 240
AND recorded > DATE '2008-01-01'
AND released - recorded < INTERVAL 180 DAY
ORDER BY
length DESC
- id: orthogonal
label: Orthogonality
prql: |
from employees
# `filter` before aggregations...
filter start_date > @2021-01-01
group country (
aggregate {max_salary = max salary}
)
# ...and `filter` after aggregations!
filter max_salary > 100_000
sql: |
SELECT
country,
MAX(salary) AS max_salary
FROM
employees
WHERE
start_date > DATE '2021-01-01'
GROUP BY
country
HAVING
MAX(salary) > 100000
# The examples are defined in data/examples/, this list just defines their order.
- basic
- friendly-syntax
- orthogonal
- expressions
- f-strings
- windows
- functions
- top-n
- s-strings
- joins
- null-handling
- dialects

# Currently excluded because it's lots of text
# prql: |
Expand All @@ -161,166 +87,6 @@ showcase_section:
# )
# )

- id: expressions
label: Expressions
prql: |
from track_plays
derive {
finished = started + unfinished,
fin_share = finished / started, # Use previous definitions
fin_ratio = fin_share / (1-fin_share), # BTW, hanging commas are optional!
}
sql: |
SELECT
*,
started + unfinished AS finished,
((started + unfinished) / started) AS fin_share,
(
((started + unfinished) / started) / (1 - ((started + unfinished) / started))
) AS fin_ratio
FROM
track_plays
# markdown-link-check-disable
- id: f-strings
label: F-strings
prql: |
from web
# Just like Python
select url = f"https://www.{domain}.{tld}/{page}"
sql: |
SELECT
CONCAT('https://www.', domain, '.', tld, '/', page) AS url
FROM
web
# markdown-link-check-enable
- id: windows
label: Windows
prql: |
from employees
group employee_id (
sort month
window rolling:12 (
derive {trail_12_m_comp = sum paycheck}
)
)
sql: |
SELECT
*,
SUM(paycheck) OVER (
PARTITION BY employee_id
ORDER BY
month ROWS BETWEEN 11 PRECEDING AND CURRENT ROW
) AS trail_12_m_comp
FROM
employees
- id: functions
label: Functions
prql: |
let fahrenheit_from_celsius = temp -> temp * 9/5 + 32
from weather
select temp_f = (fahrenheit_from_celsius temp_c)
sql: |
SELECT
(temp_c * 9 / 5) + 32 AS temp_f
FROM
weather
- id: top-n
label: Top N by group
prql: |
# Most recent employee in each role
# Quite difficult in SQL...
from employees
group role (
sort join_date
take 1
)
sql: |
WITH table_0 AS (
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY role
ORDER BY
join_date
) AS _expr_0
FROM
employees
)
SELECT
*
FROM
table_0
WHERE
_expr_0 <= 1
- id: s-string
label: S-strings
prql: |
# There's no `version` in PRQL, but s-strings
# let us embed SQL as an escape hatch:
from x
derive db_version = s"version()"
sql: |
SELECT
*,
version() AS db_version
FROM x
- id: joins
label: Joins
prql: |
from employees
join b=benefits (==employee_id)
join side:left p=positions (p.id==employees.employee_id)
select {employees.employee_id, p.role, b.vision_coverage}
sql: |
SELECT
employees.employee_id,
p.role,
b.vision_coverage
FROM
employees
JOIN benefits AS b ON employees.employee_id = b.employee_id
LEFT JOIN positions AS p ON p.id = employees.employee_id
- id: null-handling
label: Null handling
prql: |
from users
filter last_login != null
filter deleted_at == null
derive channel = channel ?? "unknown"
sql: |
SELECT
*,
COALESCE(channel, 'unknown') AS channel
FROM
users
WHERE
last_login IS NOT NULL
AND deleted_at IS NULL
- id: dialects
label: Dialects
prql: |
prql target:sql.mssql # Will generate TOP rather than LIMIT
from employees
sort age
take 10
sql: |
SELECT
TOP (10) *
FROM
employees
ORDER BY
age
principles_section:
enable: true
title: "Principles"
Expand Down
17 changes: 17 additions & 0 deletions web/website/data/examples/basic.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
label: Basic example
prql: |
from employees
select {id, first_name, age}
sort age
take 10
sql: |
SELECT
id,
first_name,
age
FROM
employees
ORDER BY
age
LIMIT
10
14 changes: 14 additions & 0 deletions web/website/data/examples/dialects.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
label: Dialects
prql: |
prql target:sql.mssql # Will generate TOP rather than LIMIT
from employees
sort age
take 10
sql: |
SELECT
TOP (10) *
FROM
employees
ORDER BY
age
Loading

0 comments on commit 30b9dab

Please sign in to comment.