chore: import upstream snapshot with attribution
CI / compile_and_lint (push) Failing after 0s
CI / docker_build (linux/amd64, -linux-amd64-duckdb, duckdb) (push) Failing after 0s
CI / docker_build (linux/arm64, -linux-arm64, minimal) (push) Failing after 2s
CI / docker_build (linux/arm64, -linux-arm64-duckdb, duckdb) (push) Failing after 1s
CI / docker_build (linux/amd64, minimal) (push) Failing after 1s
CI / test (, sqlite, sqlite::memory:) (push) Has been skipped
CI / test (mssql, mssql, mssql://root:Password123!@127.0.0.1/sqlpage) (push) Has been skipped
CI / test (mysql, mysql, mysql://root:Password123!@127.0.0.1/sqlpage) (push) Has been skipped
CI / test (oracle, oracle, Driver=Oracle 21 ODBC driver;Dbq=//127.0.0.1:1521/FREEPDB1;Uid=root;Pwd=Password123!) (push) Has been skipped
CI / test (postgres, odbc, Driver=PostgreSQL Unicode;Server=127.0.0.1;Port=5432;Database=sqlpage;UID=root;PWD=Password123!, true) (push) Has been skipped
CI / test (postgres, postgres, postgres://root:Password123!@127.0.0.1/sqlpage) (push) Has been skipped
CI / playwright (push) Has been skipped
CI / docker_build (linux/arm/v7, -linux-arm-v7, minimal) (push) Failing after 0s
CI / hurl_examples (push) Failing after 8s
deploy website / deploy_official_site (push) Failing after 1s
CI / hurl (${{ matrix.example }}) (push) Has been skipped
CI / docker_push (duckdb) (push) Has been cancelled
CI / docker_push (minimal) (push) Has been cancelled
CI / windows_test (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 12:31:57 +08:00
commit d718c5a372
986 changed files with 74597 additions and 0 deletions
@@ -0,0 +1,24 @@
# SQLPage multiple choice question example
This is a very simple example of a website that stores a list of
possible answers to a multiple choice question in a database table,
and then displays the question and the possible answers to the user.
When the user selects an answer, the website will save the user's
choice in the database and display other users' choices as well.
## Screenshots
| Question answering form | Results table | Question edition |
| --- | --- | --- |
| ![Question answering form](screenshots/main_form.png) | ![Results table](screenshots/results.png) | ![Question edition](screenshots/admin.png) |
## How to run
Just run the sqlpage binary (`./sqlpage.bin`) from this folder.
## Interesting files
[admin.sql](admin.sql) uses the [dynamic component](https://sql-page.com/documentation.sql?component=dynamic#component) to create a single page with one form per MCQ option.
[website_header.json](website_header.json) contains the [shell](https://sql-page.com/documentation.sql?component=shell#component) that is then used in all pages using the `dynamic` component to create a consistent look and feel between pages.
@@ -0,0 +1,36 @@
select 'dynamic' as component, sqlpage.read_file_as_text('website_header.json') as properties;
select 'alert' as component, 'Saved' as title, 'success' as color where $saved is not null;
select 'alert' as component, 'Deleted' as title, 'danger' as color where $deleted is not null;
select 'alert' as component, 'This option cannot be deleted' as title, 'danger' as color, 'If an option has already been chosen by at least one respondant, then it cannot be deleted' as description where $cannot_delete is not null;
select 'dynamic' as component,
json_array(
json_object(
'component', 'form',
'title', CONCAT('Option ', id),
'action', CONCAT('edit_option.sql?id=', id),
'validate', '',
'id', CONCAT('option', id)
),
json_object(
'type', 'text',
'name', 'profile_description',
'label', 'Profile description',
'value', profile_description
),
json_object(
'type', 'number',
'name', 'score',
'min', 0,
'label', 'Score',
'value', score
),
json_object('component', 'button', 'size', 'sm'),
json_object('title', 'Delete', 'outline', 'danger', 'icon', 'trash', 'link', CONCAT('delete_option.sql?id=', id)),
json_object('title', 'Save', 'outline', 'success', 'icon', 'device-floppy', 'form', CONCAT('option', id))
) as properties
from dog_lover_profiles;
select 'button' as component, 'center' as justify;
select 'Create new question' as title, 'create_question.sql' as link;
@@ -0,0 +1,4 @@
insert into dog_lover_profiles(profile_description, score) values ('', 50)
returning
'redirect' as component,
'admin.sql' as link;
@@ -0,0 +1,7 @@
select 'redirect' as component, 'admin.sql?cannot_delete' as link
where exists (select 1 from answers where profile_id = $id);
delete from dog_lover_profiles where id = $id
returning
'redirect' as component,
'admin.sql?deleted' as link;
@@ -0,0 +1,8 @@
services:
web:
image: lovasoa/sqlpage:main
ports:
- "8080:8080"
volumes:
- .:/var/www
- ./sqlpage:/etc/sqlpage
@@ -0,0 +1,6 @@
update dog_lover_profiles
set profile_description = :profile_description, score = :score
where id = $id
returning
'redirect' as component,
'admin.sql?saved' as link;
@@ -0,0 +1,9 @@
select 'dynamic' as component, sqlpage.read_file_as_text('website_header.json') as properties;
SELECT
'form' AS component,
'What dog lover are you ?' AS title,
'process.sql' AS action;
select 'radio' as type, 'profile' as name, id as value, profile_description as label
from dog_lover_profiles;
@@ -0,0 +1,4 @@
insert into answers(profile_id)
select CAST(:profile as integer)
where :profile is not null
returning 'redirect' as component, 'results.sql' as link;
@@ -0,0 +1,7 @@
select 'dynamic' as component, sqlpage.read_file_as_text('website_header.json') as properties;
select timestamp, profile_description, score from answers
inner join dog_lover_profiles on dog_lover_profiles.id = answers.profile_id;
select 'csv' as component;
select * from answers;
Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

@@ -0,0 +1,14 @@
create table dog_lover_profiles(
id integer primary key,
profile_description text not null,
score integer not null
);
insert into dog_lover_profiles(profile_description, score)
values ('I love dogs', 100), ('I hate them', 0);
create table answers(
id integer primary key,
profile_id integer not null references dog_lover_profiles(id),
timestamp timestamp not null default current_timestamp
);
@@ -0,0 +1,24 @@
GET http://localhost:8080
HTTP 200
[Asserts]
header "Content-Type" contains "text/html"
body contains "What dog lover are you ?"
body contains "process.sql"
body contains "I love dogs"
body contains "I hate them"
body not contains "An error occurred"
POST http://localhost:8080/process.sql
[FormParams]
profile: 1
HTTP 302
[Asserts]
header "Location" == "results.sql"
GET http://localhost:8080/results.sql
HTTP 200
[Asserts]
header "Content-Type" contains "text/html"
body contains "I love dogs"
body contains "100"
body not contains "An error occurred"
@@ -0,0 +1,7 @@
{
"component": "shell",
"title": "SQLPage Questions",
"icon": "help-hexagon",
"link": "/index.sql",
"menu_item": ["index", "results", "admin"]
}