duckweb_match
table · LOAD duckweb
duckweb_match(VARCHAR, VARCHAR) -> TABLEGates a branch of render on a route pattern, returning the captured parameters.
duckweb_match is a table function, and that is the whole point of it. It returns no rows when the pattern does not match and exactly one row when it does, so a branch joins against it rather than filtering on it:
SELECT duckweb_chunk('<h1>item ' || m.id || '</h1>')
FROM duckweb_match(route, '/item/:id') m
WHERE method = 'GET'Writing WHERE route = '/item/1' instead looks equivalent and is not. An ungrouped aggregate emits its one row even when its filter matched nothing, so a branch gated by a WHERE clause leaks output into responses belonging to other routes. Every branch must be gated relationally, including the ones that capture nothing:
SELECT duckweb_end() FROM duckweb_match(route, '/') WHERE method = 'GET'Patterns
A pattern is a path where a segment beginning with : captures. The captured names become result columns, in the order they appear, after a route column that is always there and holds the target as it arrived — query string and all. So
FROM duckweb_match(route, '/r/:region/:year') myields m.route, m.region and m.year. All are VARCHAR; cast if you need otherwise.
Because the columns depend on the pattern, the pattern is read at bind time, before any row exists — it has to be a constant expression. A pattern computed from a column is an error, which is why an app lists its routes literally, once, in a hit(route) macro.
Matching rules
- Captures are percent-decoded:
/r/NSW%201givesNSW 1. - An empty segment never matches a capture, so
/item/does not match/item/:id. - Leading and trailing slashes are discarded, so
/a/and/aare one route. - The query string is ignored here; duckweb_query reads it.