Skip to content

Commit 0e89124

Browse files
cursoragentlovasoa
andcommitted
feat: Add sqlpage.set_variable function
Co-authored-by: contact <[email protected]>
1 parent 17d8925 commit 0e89124

File tree

9 files changed

+123
-7
lines changed

9 files changed

+123
-7
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
# CHANGELOG.md
22

33
## unrelease
4+
- **New Function**: `sqlpage.set_variable(name, value)`
5+
- Returns a URL with the specified variable set to the given value, preserving other existing variables.
6+
- This is a shorthand for `sqlpage.link(sqlpage.path(), json_patch(sqlpage.variables('get'), json_object(name, value)))`.
47
- **Variable System Improvements**: URL and POST parameters are now immutable, preventing accidental modification. User-defined variables created with `SET` remain mutable.
58
- **BREAKING**: `$variable` no longer accesses POST parameters. Use `:variable` instead.
69
- **What changed**: Previously, `$x` would return a POST parameter value if no GET parameter named `x` existed.

examples/official-site/component.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,6 @@ select
149149
select
150150
name as title,
151151
icon,
152-
sqlpage.link('component.sql', json_object('component', name)) as link
152+
sqlpage.set_variable('component', name) as link
153153
from component
154154
order by name;

examples/official-site/examples/layouts.sql

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ For more information on how to use layouts, see the [shell component documentati
3030
select 'list' as component, 'Available SQLPage shell layouts' as title;
3131
select
3232
column1 as title,
33-
sqlpage.link('', json_object('layout', lower(column1), 'sidebar', $sidebar)) as link,
33+
sqlpage.set_variable('layout', lower(column1)) as link,
3434
$layout = lower(column1) as active,
3535
column3 as icon,
3636
column2 as description
@@ -43,7 +43,7 @@ from (VALUES
4343
select 'list' as component, 'Available Menu layouts' as title;
4444
select
4545
column1 as title,
46-
sqlpage.link('', json_object('layout', $layout, 'sidebar', column1 = 'Sidebar')) as link,
46+
sqlpage.set_variable('sidebar', column1 = 'Sidebar') as link,
4747
(column1 = 'Sidebar' AND $sidebar = 1) OR (column1 = 'Horizontal' AND $sidebar = 0) as active,
4848
column2 as description,
4949
column3 as icon

examples/official-site/functions.sql

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ FROM example WHERE component = 'shell' LIMIT 1;
1111
select 'breadcrumb' as component;
1212
select 'SQLPage' as title, '/' as link, 'Home page' as description;
1313
select 'Functions' as title, '/functions.sql' as link, 'List of all functions' as description;
14-
select $function as title, sqlpage.link('functions.sql', json_object('function', $function)) as link where $function IS NOT NULL;
14+
select $function as title, sqlpage.set_variable('function', $function) as link where $function IS NOT NULL;
1515

1616
select 'text' as component, 'SQLPage built-in functions' as title where $function IS NULL;
1717
select '
@@ -60,7 +60,7 @@ select
6060
select
6161
name as title,
6262
icon,
63-
sqlpage.link('functions.sql', json_object('function', name)) as link
63+
sqlpage.set_variable('function', name) as link
6464
from sqlpage_functions
6565
where $function IS NOT NULL
6666
order by name;
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
INSERT INTO
2+
sqlpage_functions (
3+
"name",
4+
"introduced_in_version",
5+
"icon",
6+
"description_md"
7+
)
8+
VALUES
9+
(
10+
'set_variable',
11+
'0.40.0',
12+
'variable',
13+
'Returns a URL that is the same as the current page''s URL, but with a variable set to a new value.
14+
15+
This function is useful when you want to create a link that changes a parameter on the current page, while preserving other parameters.
16+
17+
It is equivalent to `sqlpage.link(sqlpage.path(), json_patch(sqlpage.variables(''get''), json_object(name, value)))`.
18+
19+
### Example
20+
21+
Let''s say you have a list of products, and you want to filter them by category. You can use `sqlpage.set_variable` to create links that change the category filter, without losing other potential filters (like a search query or a sort order).
22+
23+
```sql
24+
select ''button'' as component, ''sm'' as size, ''center'' as justify;
25+
select
26+
category as title,
27+
sqlpage.set_variable(''category'', category) as link,
28+
case when $category = category then ''primary'' else ''secondary'' end as color
29+
from categories;
30+
```
31+
32+
### Parameters
33+
- `name` (TEXT): The name of the variable to set.
34+
- `value` (TEXT): The value to set the variable to. If `NULL` is passed, the variable is removed from the URL.
35+
'
36+
);
37+
38+
INSERT INTO
39+
sqlpage_function_parameters (
40+
"function",
41+
"index",
42+
"name",
43+
"description_md",
44+
"type"
45+
)
46+
VALUES
47+
(
48+
'set_variable',
49+
1,
50+
'name',
51+
'The name of the variable to set.',
52+
'TEXT'
53+
),
54+
(
55+
'set_variable',
56+
2,
57+
'value',
58+
'The value to set the variable to.',
59+
'TEXT'
60+
);

src/webserver/database/sqlpage_functions/functions.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ super::function_definition_macro::sqlpage_functions! {
4646
read_file_as_text((&RequestInfo), file_path: Option<Cow<str>>);
4747
request_method((&RequestInfo));
4848
run_sql((&ExecutionContext, &mut DbConn), sql_file_path: Option<Cow<str>>, variables: Option<Cow<str>>);
49+
set_variable((&ExecutionContext), name: Cow<str>, value: Option<Cow<str>>);
4950

5051
uploaded_file_mime_type((&RequestInfo), upload_name: Cow<str>);
5152
uploaded_file_path((&RequestInfo), upload_name: Cow<str>);
@@ -612,6 +613,39 @@ async fn run_sql<'a>(
612613
Ok(Some(Cow::Owned(String::from_utf8(json_results_bytes)?)))
613614
}
614615

616+
async fn set_variable<'a>(
617+
context: &'a ExecutionContext,
618+
name: Cow<'a, str>,
619+
value: Option<Cow<'a, str>>,
620+
) -> anyhow::Result<String> {
621+
let mut params_map = serde_json::Map::with_capacity(context.url_params.len() + 1);
622+
623+
for (k, v) in &context.url_params {
624+
params_map.insert(k.clone(), serde_json::to_value(v)?);
625+
}
626+
627+
if let Some(value) = value {
628+
params_map.insert(
629+
name.into_owned(),
630+
serde_json::Value::String(value.into_owned()),
631+
);
632+
} else {
633+
params_map.remove(&*name);
634+
}
635+
636+
let json_val = serde_json::Value::Object(params_map);
637+
let encoded: URLParameters = serde_json::from_value(json_val)?;
638+
639+
let mut url = context.path.clone();
640+
let encoded_str = encoded.get();
641+
if !encoded_str.is_empty() {
642+
url.push('?');
643+
url.push_str(encoded_str);
644+
}
645+
646+
Ok(url)
647+
}
648+
615649
#[tokio::test]
616650
async fn test_hash_password() {
617651
let s = hash_password(Some("password".to_string()))
Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,7 @@
1-
set what_does_it_do = 'wo' || 'rks';
2-
select 'text' as component, 'It ' || $what_does_it_do || ' !' as contents;
1+
set url = sqlpage.set_variable('y', '2');
2+
set path = sqlpage.path();
3+
select 'text' as component,
4+
case
5+
when $url = $path || '?x=1&y=2' OR $url = $path || '?y=2&x=1' THEN 'It works !'
6+
else 'error: ' || $url
7+
end as contents;
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
set url = sqlpage.set_variable('x', null);
2+
set path = sqlpage.path();
3+
select 'text' as component,
4+
case
5+
when $url = $path THEN 'It works !'
6+
else 'error: ' || $url
7+
end as contents;
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
set url = sqlpage.set_variable('x', '2');
2+
set path = sqlpage.path();
3+
select 'text' as component,
4+
case
5+
when $url = $path || '?x=2' THEN 'It works !'
6+
else 'error: ' || $url
7+
end as contents;

0 commit comments

Comments
 (0)