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
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:
@@ -0,0 +1,34 @@
|
||||
# Handling json data in Microsoft SQL Server
|
||||
|
||||
This demonstrates both how to produce and read json data from a SQL query
|
||||
in MS SQL Server (or Azure SQL Database), for creating advanced forms.
|
||||
|
||||
This lets your user interact with your database with a simple web interface,
|
||||
even when you have multiple tables, with one-to-many relationships.
|
||||
|
||||

|
||||
|
||||
## Documentation
|
||||
|
||||
SQLPage requires JSON to create multi-select input (dropdowns where an user can select multiple values).
|
||||
The result of these multi-selects is a JSON array, which also needs to be read by SQL queries.
|
||||
|
||||
This example demonstrates how to consume [JSON](https://en.wikipedia.org/wiki/JSON) data from a SQL Server database,
|
||||
using the [`OPENJSON`](https://docs.microsoft.com/en-us/sql/t-sql/functions/openjson-transact-sql)
|
||||
function to parse the JSON data into a table,
|
||||
and [`FOR JSON PATH`](https://learn.microsoft.com/en-us/sql/relational-databases/json/format-query-results-as-json-with-for-json-sql-server)
|
||||
to format query results as a JSON array.
|
||||
|
||||
|
||||
This demonstrates an application designed for managing groups and users, allowing the creation of new groups, adding users, and assigning users to one or multiple groups.
|
||||
|
||||
The application has the following sections:
|
||||
|
||||
- **Create a New Group**: A form where users can enter the name of a new group.
|
||||
- **Groups Display**: A list of existing groups.
|
||||
- **Add a User**: A form where users can enter the name of a new user and select one or multiple groups to assign to this user.
|
||||
- **Users Display**: A list of existing users and their associated group memberships.
|
||||
|
||||
When users submit the form, their selections are packaged up and sent to the database server. The server receives these selections as a structured JSON array.
|
||||
|
||||
The database then takes this list of selections and temporarily converts it into a format it can work with using the `OPENJSON` function, before saving the information permanently in the database tables. This allows the system to process multiple selections at once in an efficient way.
|
||||
@@ -0,0 +1,30 @@
|
||||
services:
|
||||
web:
|
||||
image: lovasoa/sqlpage:main
|
||||
ports:
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- .:/var/www
|
||||
- ./sqlpage:/etc/sqlpage
|
||||
depends_on:
|
||||
- db
|
||||
environment:
|
||||
RUST_LOG: sqlpage=debug
|
||||
DATABASE_URL: mssql://sa:YourStrong!Passw0rd@db:1433/
|
||||
db:
|
||||
image: mcr.microsoft.com/mssql/server:2022-latest
|
||||
volumes:
|
||||
- ./sqlpage/mssql-migrations:/migrations
|
||||
environment:
|
||||
ACCEPT_EULA: Y
|
||||
MSSQL_SA_PASSWORD: YourStrong!Passw0rd
|
||||
MSSQL_PID: Express
|
||||
command: >
|
||||
bash -c "
|
||||
/opt/mssql/bin/sqlservr &
|
||||
until /opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P YourStrong!Passw0rd -C -Q 'SELECT 1;'; do
|
||||
echo 'Waiting for database...'
|
||||
sleep 1
|
||||
done
|
||||
/opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P YourStrong!Passw0rd -C -i /migrations/0001_db_init.sql
|
||||
tail -f /dev/null"
|
||||
@@ -0,0 +1,37 @@
|
||||
select 'form' as component, 'Create a new Group' as title, 'Create' as validate;
|
||||
select 'Name' as name;
|
||||
|
||||
insert into groups(name) select :Name where :Name is not null;
|
||||
|
||||
select 'list' as component, 'Groups' as title, 'No group yet' as empty_title;
|
||||
select name as title from groups;
|
||||
|
||||
select 'form' as component, 'Add a user' as title, 'Add' as validate;
|
||||
select 'UserName' as name, 'Name' as label;
|
||||
select
|
||||
'Memberships[]' as name,
|
||||
'Group memberships' as label,
|
||||
'select' as type,
|
||||
1 as multiple,
|
||||
'press ctrl to select multiple values' as description,
|
||||
(
|
||||
SELECT name as label, id as value
|
||||
FROM groups
|
||||
FOR JSON PATH -- this builds a JSON array of objects
|
||||
) as options;
|
||||
|
||||
insert into users(name) select :UserName where :UserName is not null;
|
||||
|
||||
insert into group_members(group_id, user_id)
|
||||
select json_elem.value, IDENT_CURRENT('users')
|
||||
from openjson(:Memberships) as json_elem
|
||||
where :Memberships is not null;
|
||||
|
||||
select 'list' as component, 'Users' as title, 'No user yet' as empty_title;
|
||||
select
|
||||
users.name as title,
|
||||
string_agg(groups.name, ', ') as description
|
||||
from users
|
||||
left join group_members on users.id = group_members.user_id
|
||||
left join groups on groups.id = group_members.group_id
|
||||
group by users.id, users.name;
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 122 KiB |
+35
@@ -0,0 +1,35 @@
|
||||
create table users (
|
||||
id int primary key IDENTITY(1,1),
|
||||
name varchar(255) not null
|
||||
);
|
||||
|
||||
create table groups (
|
||||
id int primary key IDENTITY(1,1),
|
||||
name varchar(255) not null
|
||||
);
|
||||
|
||||
create table group_members (
|
||||
group_id int not null,
|
||||
user_id int not null,
|
||||
constraint PK_group_members primary key (group_id, user_id),
|
||||
constraint FK_group_members_groups foreign key (group_id) references groups (id),
|
||||
constraint FK_group_members_users foreign key (user_id) references users (id)
|
||||
);
|
||||
|
||||
CREATE TABLE questions(
|
||||
id INT PRIMARY KEY IDENTITY(1,1),
|
||||
question_text TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE survey_answers(
|
||||
id INT PRIMARY KEY IDENTITY(1,1),
|
||||
question_id INT,
|
||||
answer TEXT,
|
||||
timestamp DATETIME DEFAULT GETDATE(),
|
||||
CONSTRAINT FK_survey_answers_questions FOREIGN KEY (question_id) REFERENCES questions(id)
|
||||
);
|
||||
|
||||
INSERT INTO questions(question_text) VALUES
|
||||
('What is your name?'),
|
||||
('What is your age?'),
|
||||
('What is your favorite color?');
|
||||
@@ -0,0 +1,11 @@
|
||||
# Migrations for Microsoft SQL Server
|
||||
|
||||
This folder contains the migrations for the Microsoft SQL Server example.
|
||||
|
||||
At the time of writing, SQLPage does not support applying migrations for Microsoft SQL Server
|
||||
automatically, so we need to apply them manually.
|
||||
|
||||
We write the migrations in a folder called `mssql-migrations`, instead of the usual `migrations`
|
||||
folder, and we use the `sqlcmd` tool to apply them.
|
||||
|
||||
See [how it is done in the docker-compose file](../../docker-compose.yml).
|
||||
@@ -0,0 +1,27 @@
|
||||
SELECT 'form' as component, 'Survey' as title;
|
||||
SELECT id as name, question_text as label, 'textarea' as type
|
||||
FROM questions;
|
||||
|
||||
-- Save all the answers to the database, whatever the number and id of the questions
|
||||
INSERT INTO survey_answers (question_id, answer)
|
||||
SELECT
|
||||
question_id,
|
||||
json_unquote(
|
||||
json_extract(
|
||||
sqlpage.variables('post'),
|
||||
concat('$."', question_id, '"')
|
||||
)
|
||||
)
|
||||
FROM json_table(
|
||||
json_keys(sqlpage.variables('post')),
|
||||
'$[*]' columns (question_id int path '$')
|
||||
) as question_ids;
|
||||
|
||||
-- Show the answers
|
||||
select 'card' as component, 'Survey results' as title;
|
||||
select
|
||||
questions.question_text as title,
|
||||
survey_answers.answer as description,
|
||||
'On ' || survey_answers.timestamp as footer
|
||||
from survey_answers
|
||||
inner join questions on questions.id = survey_answers.question_id;
|
||||
@@ -0,0 +1 @@
|
||||
../../test.hurl
|
||||
Reference in New Issue
Block a user