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
@@ -0,0 +1,56 @@
|
||||
select 'http_header' as component,
|
||||
'public, max-age=300, stale-while-revalidate=3600, stale-if-error=86400' as "Cache-Control";
|
||||
|
||||
select 'dynamic' as component, properties FROM example WHERE component = 'shell' LIMIT 1;
|
||||
|
||||
select 'hero' as component,
|
||||
'Custom URLs' as title,
|
||||
'SQLPage lets you customize responses to URLs that don''t match any file, using `404.sql`.' as description_md,
|
||||
'not_found.jpg' as image;
|
||||
|
||||
select 'text' as component, '
|
||||
# Handling custom URLs
|
||||
|
||||
By default, SQLPage serves the file that matches the URL requested by the client.
|
||||
If your users enter `https://example.com/about`, SQLPage will serve the file `about/index.sql` in your project.
|
||||
If you create a file named `about.sql`, SQLPage will serve it when the user requests either `https://example.com/about.sql` or `https://example.com/about` (since v0.33, the `.sql` suffix is optional).
|
||||
|
||||
But what if you want to handle URLs that don''t match any file in your project ?
|
||||
For example, what if you have a blog, and you want nice urls like `example.com/blog/my-trip-to-rome`,
|
||||
but you don''t want to create a file for each blog post ?
|
||||
By default, SQLPage would return a sad 404 error if you don''t have a file named `blog/my-trip-to-rome/index.sql`
|
||||
in your project''s root directory.
|
||||
|
||||
But you can customize this behavior by creating a file named `404.sql` in your project.
|
||||
|
||||
## The 404.sql file
|
||||
|
||||
When SQLPage doesn''t find a file that matches the URL requested by the client, it will serve the file `404.sql` if it exists.
|
||||
|
||||
Since v0.28, when SQLPage receives a request for a URL like `https://example.com/a/b/c`, it will look for the file `a/b/c/index.sql` in your project,
|
||||
and if it doesn''t find it, it will then search for, in order:
|
||||
- `/a/b/404.sql`
|
||||
- `/a/404.sql`
|
||||
- `/404.sql`
|
||||
|
||||
## Basic routing example
|
||||
|
||||
So, you have a `blog_posts` table in your database, with columns `name`, and `content`.
|
||||
You want to serve the content of the blog post with id `:id` when the user requests `example.com/blog/:id`.
|
||||
You can do this by creating a `404.sql` file in the `blog` directory of your project:
|
||||
|
||||
```sql
|
||||
-- blog/404.sql
|
||||
|
||||
-- Get the id from the URL
|
||||
set name = substr(sqlpage.path(), 1+length(''/blog/''));
|
||||
|
||||
-- Get the blog post from the database
|
||||
select ''text'' as component,
|
||||
content as contents_md
|
||||
from blog_posts
|
||||
where name = $name;
|
||||
```
|
||||
|
||||
Now, when a user requests `example.com/blog/my-trip-to-rome`, SQLPage will serve the content of the blog post with name `my-trip-to-rome` from the `blog_posts` table.
|
||||
' as contents_md;
|
||||
@@ -0,0 +1 @@
|
||||
select 'redirect' as component, '../documentation.sql' as link;
|
||||
|
After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 193 KiB |
|
After Width: | Height: | Size: 210 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 89 KiB |
|
After Width: | Height: | Size: 262 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 53 KiB |
@@ -0,0 +1,28 @@
|
||||
select 'shell' as component,
|
||||
'SQLPage: get started!' as title,
|
||||
'database' as icon,
|
||||
'/' as link,
|
||||
'en-US' as lang,
|
||||
'Hosted SQLPage: set-up a SQLPage website in three clicks.' as description,
|
||||
'documentation' as menu_item,
|
||||
'Poppins' as font;
|
||||
|
||||
SELECT 'hero' as component,
|
||||
'Hosted SQLPage' as title,
|
||||
'Work In Progress: We are working on a cloud version of SQLPage
|
||||
that will enable you to effortlessly set up your website online without the need to download any software or configure your own server.' as description,
|
||||
'https://upload.wikimedia.org/wikipedia/commons/thumb/9/94/Baustelle_H%C3%B6lzla_6066312.jpg/1024px-Baustelle_H%C3%B6lzla_6066312.jpg' as image,
|
||||
'https://forms.gle/z1qmuCwdNT5Am7gp6' as link,
|
||||
'Get notified when we are ready' as link_text;
|
||||
|
||||
SELECT 'text' as component,
|
||||
'Try SQLPage online today' as title,
|
||||
'
|
||||
If you want to fiddle around with SQLPage without installing anything on your computer, you can still try it out online today.
|
||||
|
||||
Repl.it is an online development environment that allows you to run SQLPage in your browser.
|
||||
|
||||
Try [the SQLPage repl](https://replit.com/@pimaj62145/SQLPage).
|
||||
Click *Use template* to create your own editable copy of the demo website, then click *Run* to see the result.
|
||||
On the left side you can edit the SQLPage code, on the right side you can see the result.
|
||||
' as contents_md;
|
||||
@@ -0,0 +1,87 @@
|
||||
select 'http_header' as component,
|
||||
'public, max-age=300, stale-while-revalidate=3600, stale-if-error=86400' as "Cache-Control",
|
||||
'<https://sql-page.com/your-first-sql-website/>; rel="canonical"' as "Link";
|
||||
|
||||
set os = COALESCE($os, case
|
||||
when sqlpage.header('user-agent') like '%windows%' then 'windows'
|
||||
when sqlpage.header('user-agent') like '%x11; linux%' then 'linux'
|
||||
when sqlpage.header('user-agent') like '%x11; ubuntu; linux%' then 'linux'
|
||||
when sqlpage.header('user-agent') like '%x11; debian; linux%' then 'linux'
|
||||
when sqlpage.header('user-agent') like '%macintosh%' then 'macos'
|
||||
else 'any'
|
||||
end);
|
||||
|
||||
-- Fetch the page title and header from the database
|
||||
select 'dynamic' as component, json_patch(json_extract(properties, '$[0]'), json_object(
|
||||
'title', 'SQL to Website - Tutorial',
|
||||
'description', 'Convert your SQL database into a website in minutes. In this 5-minute guide, we will create a simple website from scratch, and learn the basics of SQLPage.'
|
||||
)) as properties
|
||||
FROM example WHERE component = 'shell' LIMIT 1;
|
||||
|
||||
SET req = '{
|
||||
"url": "https://api.github.com/repos/sqlpage/SQLPage/releases/latest",
|
||||
"timeout_ms": 200
|
||||
}';
|
||||
SET api_results = sqlpage.fetch_with_meta($req);
|
||||
SET sqlpage_version = COALESCE(json_extract($api_results, '$.body.tag_name'), '');
|
||||
|
||||
SELECT 'hero' as component,
|
||||
'Your first SQL Website' as title,
|
||||
'[SQLPage](/) is a free tool for building data-driven apps quickly.
|
||||
|
||||
Let''s create a simple website with a database from scratch, to learn SQLPage basics.' as description_md,
|
||||
case $os
|
||||
when 'linux' then 'get_started_linux.webp'
|
||||
when 'macos' then 'get_started_macos.webp'
|
||||
when 'windows' then 'get_started_windows.webp'
|
||||
else 'get_started.webp'
|
||||
end as image,
|
||||
CASE $os
|
||||
WHEN 'macos' THEN '#download'
|
||||
WHEN 'windows' THEN 'https://github.com/sqlpage/SQLPage/releases/latest/download/sqlpage-windows.zip'
|
||||
WHEN 'linux' THEN 'https://github.com/sqlpage/SQLPage/releases/latest/download/sqlpage-linux.tgz'
|
||||
ELSE 'https://github.com/sqlpage/SQLPage/releases'
|
||||
END AS link,
|
||||
CASE $os
|
||||
WHEN 'macos' THEN CONCAT('Install SQLPage ', $sqlpage_version, ' using Homebrew')
|
||||
WHEN 'windows' THEN CONCAT('Download SQLPage ', $sqlpage_version, ' for Windows')
|
||||
WHEN 'linux' THEN CONCAT('Download SQLPage ', $sqlpage_version, ' for Linux')
|
||||
ELSE CONCAT('Download SQLPage ', $sqlpage_version)
|
||||
END AS link_text;
|
||||
|
||||
SELECT 'alert' as component,
|
||||
'Afraid of the setup ? Do it the easy way !' as title,
|
||||
'mood-happy' as icon,
|
||||
'teal' as color,
|
||||
'You don’t want to install anything on your computer ?
|
||||
You can use a preconfigured SQLPage hosted on our servers, and get your app online in minutes, without **ever having to configure a server** yourself.' as description_md,
|
||||
'https://datapage.app' AS link,
|
||||
'Host your app on our servers' as link_text;
|
||||
select 'https://editor.datapage.app' as link, 'Try SQLPage from your browser' as title, 'teal' as color;
|
||||
|
||||
SELECT 'alert' as component,
|
||||
'Do you prefer videos ?' as title,
|
||||
'brand-youtube' as icon,
|
||||
'purple' as color,
|
||||
'We made videos to introduce you to SQLPage. You can watch them on YouTube. The videos cover everything from the underlying technology to the philosophy behind SQLPage to the actual steps to create your first website.' as description_md,
|
||||
'https://www.youtube.com/watch?v=9NJgH_-zXjY' AS link,
|
||||
'Watch the introduction video' as link_text;
|
||||
select 'https://www.youtube.com/watch?v=6D5D10v18b0&list=PLTue_qIAHxActQnLn_tHWZUNXziZTeraB' as link, 'Tutorial video series' as title;
|
||||
|
||||
select 'text' as component,
|
||||
sqlpage.read_file_as_text(
|
||||
printf('your-first-sql-website/tutorial-install-%s.md',
|
||||
case
|
||||
when $os = 'windows' then 'windows'
|
||||
when $os = 'macos' then 'macos'
|
||||
else 'any'
|
||||
end
|
||||
)
|
||||
) as contents_md,
|
||||
true as article,
|
||||
'download' as id;
|
||||
|
||||
select 'text' as component,
|
||||
sqlpage.read_file_as_text('your-first-sql-website/tutorial.md') as contents_md,
|
||||
true as article,
|
||||
'tutorial' as id;
|
||||
@@ -0,0 +1,146 @@
|
||||
# Understanding SQL Migrations: Your Database, Layer by Layer
|
||||
|
||||
Maintaining a structured and evolving database is crucial for web app development. Rarely do we get a schema 100% correct on day one. New insights about the shape of the application are discovered over time, or business needs themselves evolve. In the world of databases, we can evolve schemas using migration files. These files are just more SQL that append or amend layers of development. Think of this process like sedimentary rock layers. Each migration adds a layer, and together, these layers create a complete, functional structure along with a visible trail of historical changes.
|
||||
|
||||
## What Makes up a SQL Migration File?
|
||||
|
||||
SQL migrations are incremental changes to a database. These changes can include creating tables, adding columns, modifying data types, or even inserting or updating records. Each migration is a distinct script that applies a specific change.
|
||||
|
||||
### Use Caution!
|
||||
|
||||
Since migration files change the database, they can have unintended consequences if not thought through carefully. For instance, you may accidentally delete a column that is still being used by your application or remove records that are still needed.
|
||||
|
||||
> ⚠️ Be thoughtful, double-check your work, and **always back up your data before running a migration**.
|
||||
|
||||
### Order Matters
|
||||
|
||||
**It's important that migrations are distinct ordered files** as SQLPage uses the sequence of migration files to build the database over time: `0001_initial_setup.sql`, `0002_my_first_change.sql`, `0003_my_next_change`, etc.
|
||||
|
||||
### No take-backs!
|
||||
|
||||
**Do not make changes to an existing migration file** in production. If a previously implemented migration file is altered, it will confuse SQLPage and cause a crash.
|
||||
|
||||
*If you are in early stages of development and are okay with losing data*, you can delete the database and start over with an altered migration file. However, in a production environment, especially once persisted data is involved, this is not an option.
|
||||
|
||||
It's like trying to go back in time and change a previous sedimentary layer. That's not how rocks work, and that's not how migrations work.
|
||||
|
||||
Append or amend; do not try to change the past.
|
||||
|
||||
## Examples
|
||||
|
||||
Let's start off easy with a simple database to store user information: `first_name`, `last_name`, `email`, `phone`, and `password_hash`. Our first migration actually creates the `users` table with these columns. That is, we migrate from *nothing* to *having a users table*.
|
||||
|
||||
**`sqlpage/migrations/001_create_users.sql`**:
|
||||
```sql
|
||||
create table users (
|
||||
id integer primary key autoincrement,
|
||||
first_name not null,
|
||||
last_name not null,
|
||||
email not null unique,
|
||||
phone,
|
||||
rewards_level,
|
||||
password_hash not null
|
||||
);
|
||||
```
|
||||
|
||||
In the terminal, we can see the new schema:
|
||||
|
||||
```console
|
||||
sqlite> .schema
|
||||
CREATE TABLE users (
|
||||
id integer primary key autoincrement,
|
||||
first_name not null,
|
||||
last_name not null,
|
||||
email not null unique,
|
||||
phone,
|
||||
rewards_level,
|
||||
password_hash not null
|
||||
);
|
||||
```
|
||||
|
||||
### A Simple Change
|
||||
|
||||
Later, we discover we need a `middle_name` column, so we create a new migration file to add this column to the `users` table. Remember, we must ensure the order is written into the filename so SQLPage can apply them in the correct order when building the database.
|
||||
|
||||
**`sqlpage/migrations/002_add_middle_name.sql`**:
|
||||
```sql
|
||||
alter table users add column middle_name;
|
||||
```
|
||||
|
||||
In the terminal:
|
||||
|
||||
```console
|
||||
sqlite> .schema
|
||||
CREATE TABLE users (
|
||||
id integer primary key autoincrement,
|
||||
first_name not null,
|
||||
last_name not null,
|
||||
email not null unique,
|
||||
phone,
|
||||
rewards_level integer,
|
||||
password_hash not null,
|
||||
middle_name
|
||||
);
|
||||
```
|
||||
|
||||
### A More Complex Change
|
||||
|
||||
But notice here, SQLite has appended the column to the very end. What if we really need that `middle_name` column to be next to the other name columns? Further, what if we realize `rewards_level` should really be an integer and only one between 1 and 20?
|
||||
|
||||
We can create a new migration file to make these changes, albeit a bit more complicated.
|
||||
|
||||
Because we'll be altering column types and modifying column order, we'll need to *create a temporary table* to hold the data while we drop the original table and recreate it with the new schema.
|
||||
|
||||
**`sqlpage/migrations/003_alter_users.sql`**:
|
||||
```sql
|
||||
create table users_temp (
|
||||
id integer primary key autoincrement,
|
||||
first_name not null,
|
||||
last_name not null,
|
||||
middle_name,
|
||||
email not null unique,
|
||||
phone,
|
||||
rewards_level integer check(rewards_level between 1 and 20),
|
||||
password_hash not null
|
||||
);
|
||||
|
||||
insert into users_temp select id, first_name, last_name, middle_name, email, phone, rewards_level, password_hash from users;
|
||||
|
||||
drop table users; -- backups are important!
|
||||
|
||||
alter table users_temp rename to users;
|
||||
```
|
||||
|
||||
In the terminal:
|
||||
|
||||
```console
|
||||
sqlite> .schema
|
||||
CREATE TABLE users (
|
||||
id integer primary key autoincrement,
|
||||
first_name not null,
|
||||
last_name not null,
|
||||
middle_name,
|
||||
email not null unique,
|
||||
phone,
|
||||
rewards_level integer check(rewards_level between 1 and 20),
|
||||
password_hash not null
|
||||
);
|
||||
```
|
||||
|
||||
## Conclusion
|
||||
|
||||
SQL migration is our tool for evolving databases over time. By creating distinct, ordered migration files, we can incrementally build and modify our databases without losing data or breaking our application functionality. Just **remember to always back up data before running a migration**, and always be thoughtful about changes.
|
||||
|
||||
Since SQLPage runs migrations forward in time, we won't dive into the complexities of rolling back migrations here. Just remember, we can't change the past, only build upon it.
|
||||
|
||||
[Rollbacks](https://en.wikipedia.org/wiki/Rollback_(data_management)) are an intriguing topic that you may run into in other frameworks.
|
||||
|
||||
## Further Study
|
||||
|
||||
To learn more on the migrations topic, consider the Wikipedia article on [Schema Migration](https://en.wikipedia.org/wiki/Schema_migration). **Note**: database engines are different, so be sure to review the documentation for your specific database engine and what types of SQL statements are permitted. For SQLite, the [official documentation](https://www.sqlite.org/lang_altertable.html) is a good place to start.
|
||||
|
||||
Best migrations on your evolving database journey! 👋
|
||||
|
||||
---
|
||||
|
||||
Article written by [Matthew Larkin](https://github.com/matthewlarkin) for [SQLPage](https://sql-page.com/).
|
||||
@@ -0,0 +1,14 @@
|
||||
select 'http_header' as component,
|
||||
'public, max-age=300, stale-while-revalidate=3600, stale-if-error=86400' as "Cache-Control",
|
||||
'<https://sql-page.com/your-first-sql-website/migrations>; rel="canonical"' as "Link";
|
||||
|
||||
select 'dynamic' as component, json_patch(json_extract(properties, '$[0]'), json_object(
|
||||
'title', 'SQLPage migrations',
|
||||
'description', 'Manage your database schema with SQLPage using migrations.'
|
||||
)) as properties
|
||||
FROM example WHERE component = 'shell' LIMIT 1;
|
||||
|
||||
-- Article by Matthew Larkin
|
||||
select 'text' as component,
|
||||
sqlpage.read_file_as_text('your-first-sql-website/migrations.md') as contents_md,
|
||||
true as article;
|
||||
@@ -0,0 +1,353 @@
|
||||
# **Hosting SQLPage Behind a Reverse Proxy**
|
||||
|
||||
Hosting SQLPage behind a reverse proxy can help with security, scalability, and flexibility.
|
||||
In this guide, we will guide you step-by-step on how to host SQLPage behind a reverse proxy using
|
||||
[NGINX](https://www.nginx.com/).
|
||||
|
||||
## Why host SQLPage behind a Reverse Proxy ?
|
||||
|
||||
Here are some reasons why you might want to host SQLPage behind a reverse proxy:
|
||||
|
||||
- **customize your application's URLs**, removing `.sql` extensions and changing URL parameters
|
||||
- **protect against attacks** such as denial-of-service (DoS) by rate limiting incoming requests
|
||||
- **improve performance** by caching responses and serving static files without involving SQLPage
|
||||
- **enable HTTPS** on the front-end, even when SQLPage is running on HTTP
|
||||
- **host multiple applications** or multiple instances of SQLPage on the same server
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before you begin, you will need the following:
|
||||
|
||||
- A server running SQLPage. In this guide, we will assume SQLPage is running on `localhost:8080`
|
||||
- Nginx installed on your server. On Ubuntu, you can install NGINX using `sudo apt install nginx`
|
||||
- A domain name pointing to your server (optional)
|
||||
- An SSL certificate obtained from Certbot (optional)
|
||||
|
||||
## Configuring the Reverse Proxy
|
||||
|
||||
NGINX uses a hierarchical configuration structure. The global configuration file (`/etc/nginx/nginx.conf`) contains settings that apply to the entire server, such as logging, caching, and rate limiting.Site-specific configuration files, stored in `/etc/nginx/sites-available/`, contain directives for individual websites or applications. These site-specific configurations are activated by creating symbolic links in the `/etc/nginx/sites-enabled/` directory. This setup allows for clean and organized management of multiple sites on a single server.
|
||||
|
||||
To host SQLPage behind a reverse proxy, you will need to create a new configuration file in the `/etc/nginx/sites-available/` directory, and then create a symbolic link to it in the `/etc/nginx/sites-enabled/` directory.
|
||||
|
||||
Create a file named `sqlpage` in the `/etc/nginx/sites-available/` directory:
|
||||
```bash
|
||||
sudo nano /etc/nginx/sites-available/sqlpage
|
||||
```
|
||||
|
||||
Add the following configuration to the file:
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name example.com;
|
||||
|
||||
location / {
|
||||
proxy_pass http://localhost:8080;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Save the file and create a symbolic link to it in the `/etc/nginx/sites-enabled/` directory:
|
||||
```bash
|
||||
sudo ln -s /etc/nginx/sites-available/sqlpage /etc/nginx/sites-enabled/sqlpage
|
||||
```
|
||||
|
||||
Test the configuration and reload NGINX:
|
||||
```bash
|
||||
sudo nginx -t
|
||||
sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
Your SQLPage instance is now hosted behind a reverse proxy using NGINX. You can access it by visiting `http://example.com`.
|
||||
|
||||
|
||||
### Streaming-friendly proxy settings
|
||||
|
||||
SQLPage streams HTML by default so the browser can render results while the database is still sending rows.
|
||||
If you have slow SQL queries (you shouldn't), you can add the following directive to your location block:
|
||||
|
||||
```nginx
|
||||
proxy_buffering off;
|
||||
```
|
||||
|
||||
That will allow users to start seeing the top of your pages faster,
|
||||
but will increase the load on your SQLPage server, and reduce the amount of users you can serve concurrently.
|
||||
|
||||
Refer to the official documentation for [proxy buffering](https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffering), [gzip](https://nginx.org/en/docs/http/ngx_http_gzip_module.html), and [chunked transfer](https://nginx.org/en/docs/http/ngx_http_core_module.html#chunked_transfer_encoding) when tuning these values.
|
||||
|
||||
When SQLPage sits behind a reverse proxy, set `compress_responses` to `false` [in `sqlpage.json`](https://github.com/sqlpage/SQLPage/blob/main/configuration.md) so that NGINX compresses once at the edge.
|
||||
|
||||
### URL Rewriting
|
||||
|
||||
URL rewriting is a powerful feature that allows you to manipulate URLs to make them more readable, search-engine-friendly, and easy to maintain.
|
||||
In this section, we will cover how to use URL rewriting with SQLPage.
|
||||
|
||||
Note that for basic URL rewriting, you can use a simple [`404.sql`](/your-first-sql-website/custom_urls.sql) file to handle custom URLs.
|
||||
However, for more complex rewriting rules, you can use NGINX's `rewrite` directive.
|
||||
|
||||
#### Example: Rewriting `/products/$id` to `/products.sql?id=$id`
|
||||
|
||||
Let's say you want your users to access product details using URLs like `/products/123` instead of `/products.sql?id=123`. This can be achieved using the `rewrite` directive in NGINX.
|
||||
|
||||
Here is an example configuration:
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name example.com;
|
||||
|
||||
location / {
|
||||
proxy_pass http://localhost:8080;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
}
|
||||
|
||||
location /products/ {
|
||||
rewrite ^/products/([^/]+)$ /products.sql?id=$1 last;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This configuration uses the `rewrite` directive to rewrite URLs of the form `/products/$id` to `/products.sql?id=$id`. The `^/products/([^/]+)$` pattern matches URLs that start with `/products/` and captures the dynamic parameter `$id` using parentheses. The `last` flag indicates that this rewrite rule should be the last one to be applied; if the pattern matches, the rewritten URL is passed to the next location block,
|
||||
in this case, the proxy_pass directive.
|
||||
|
||||
**How it Works**
|
||||
|
||||
When a request is made to `/products/123`, the rewrite rule is triggered, and the URL is rewritten to `/products.sql?id=123`. The `proxy_pass` directive then forwards the rewritten URL to the SQLPage instance, which processes the request and returns the response.
|
||||
|
||||
#### Example: Removing `.sql` Extension from URLs
|
||||
|
||||
Let's say you want to remove the `.sql` extension from all URLs to make them cleaner and more user-friendly. This can be achieved using the `rewrite` directive in NGINX.
|
||||
|
||||
```nginx
|
||||
location / {
|
||||
|
||||
# When a request doesn't end with a '/' and doesn't have an extension, add '.sql' at the end
|
||||
rewrite ^/((.*/)?[^/.]+)$ /$1.sql last;
|
||||
|
||||
proxy_pass http://localhost:8080;
|
||||
}
|
||||
```
|
||||
|
||||
### Hosting Multiple Applications
|
||||
|
||||
You may want to use the same web server to host SQLPage together with
|
||||
another application such as a blog, a different website, or another instance of SQLPage.
|
||||
In this section, we will cover how to host multiple applications behind a reverse proxy using NGINX.
|
||||
|
||||
#### Example: Hosting Two Applications with Different domain names
|
||||
|
||||
Let's say you want to host two separate instances of SQLPage on the same server, each accessible via a different domain name: `app1.example.com` and `app2.example.com`. This can be achieved by creating two separate configuration files in the `/etc/nginx/sites-available/` directory and then creating symbolic links to them in the `/etc/nginx/sites-enabled/` directory.
|
||||
|
||||
Create `/etc/nginx/sites-available/app1`, and `/etc/nginx/sites-available/app2` configuration files,
|
||||
and add the following configuration to each file, replacing `localhost:8080` and `app1.example.com` with the appropriate values:
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name app1.example.com;
|
||||
|
||||
location / {
|
||||
proxy_pass http://localhost:8080;
|
||||
}
|
||||
}
|
||||
```
|
||||
Then create symbolic links to the configuration files in the `/etc/nginx/sites-enabled/` directory.
|
||||
|
||||
#### Hosting on a Subpath
|
||||
|
||||
You may have multiple applications to host, but a single domain name to use. In this case, you can host each application on a different subpath of the domain name, for example, `example.com/app1` and `example.com/app2`.
|
||||
|
||||
To host SQLPage on a subpath, you can use a single NGINX configuration file with a `location` block that specifies the subpath:
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name example.com;
|
||||
|
||||
location /sqlpage {
|
||||
proxy_pass http://localhost:8080;
|
||||
}
|
||||
}
|
||||
```
|
||||
This configuration sets up a reverse proxy that forwards incoming requests from `example.com/sqlpage` to `localhost:8080`, where SQLPage is running.
|
||||
|
||||
And in the SQLPage configuration file, at `./sqlpage/sqlpage.json`,
|
||||
you can specify the base URL as `/sqlpage`:
|
||||
|
||||
```json
|
||||
{
|
||||
"site_prefix": "/sqlpage"
|
||||
}
|
||||
```
|
||||
|
||||
### IP Rate Limiting
|
||||
|
||||
To enable IP rate limiting for your SQLPage instance, you can use the
|
||||
[`limit_req` module in NGINX](http://nginx.org/en/docs/http/ngx_http_limit_req_module.html).
|
||||
|
||||
Define a global rate limiting zone in `/etc/nginx/nginx.conf`:
|
||||
|
||||
```nginx
|
||||
http {
|
||||
...
|
||||
limit_req_zone $binary_remote_addr zone=myzone:10m rate=10r/m;
|
||||
}
|
||||
```
|
||||
|
||||
Then use it in your site's configuration in `/etc/nginx/sites-available/sqlpage`:
|
||||
|
||||
```nginx
|
||||
server {
|
||||
...
|
||||
|
||||
location / {
|
||||
limit_req zone=myzone;
|
||||
proxy_pass http://localhost:8080;
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
This configuration sets up a reverse proxy that forwards incoming requests from `example.com` to `localhost:8080`, where SQLPage is running, and enables IP rate limiting to prevent abuse.
|
||||
|
||||
|
||||
### Static File Serving
|
||||
|
||||
The [`try_files`](https://nginx.org/en/docs/http/ngx_http_core_module.html#try_files) directive in Nginx specifies the files to attempt to serve before falling back to a specified URI or passing the request to a proxy server. It's typically used within a location block to define the behavior when a request matches that location.
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name example.com;
|
||||
|
||||
location ~ \.sql$ {
|
||||
include sqlpage_proxy.conf;
|
||||
}
|
||||
|
||||
location / {
|
||||
try_files $uri @reverse_proxy;
|
||||
}
|
||||
|
||||
location @reverse_proxy {
|
||||
include sqlpage_proxy.conf;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
And in `/etc/nginx/sqlpage_proxy.conf`:
|
||||
|
||||
```nginx
|
||||
proxy_pass http://localhost:8080;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
proxy_buffering on;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Host $host;
|
||||
```
|
||||
|
||||
### Caching and Buffering
|
||||
|
||||
To enable caching and buffering for your SQLPage instance, you can use the
|
||||
[`proxy_cache`](https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_cache)
|
||||
and [`proxy_buffering`](https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffering)
|
||||
directives in NGINX.
|
||||
|
||||
Declare the cache in `/etc/nginx/nginx.conf` :
|
||||
|
||||
```nginx
|
||||
http {
|
||||
...
|
||||
proxy_cache mycache;
|
||||
# Cache settings: 1 hour for 200 and 302 responses, 1 minute for 404 responses
|
||||
proxy_cache_valid 200 302 1h;
|
||||
proxy_cache_valid 404 1m;
|
||||
}
|
||||
```
|
||||
|
||||
and then in your sqlpage nginx configuration file `/etc/nginx/sites-available/sqlpage` :
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name example.com;
|
||||
|
||||
location / {
|
||||
proxy_pass http://sqlpage;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
proxy_cache mycache;
|
||||
# Buffering: when a client is slow to read the response, quickly read the response from SQLPage and store it in a buffer, then send it to the slow client, while SQLPage can continue processing other requests
|
||||
proxy_buffering on;
|
||||
proxy_buffer_size 128k;
|
||||
proxy_buffers 4 256k;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### **HTTPS and Certbot**
|
||||
|
||||
To let nginx handle HTTPS instead of SQLPage, you can obtain an SSL certificate from Certbot and configure nginx to use it.
|
||||
|
||||
Install certbot using the following command:
|
||||
```bash
|
||||
sudo snap install --classic certbot
|
||||
```
|
||||
|
||||
Obtain an SSL certificate using the following command:
|
||||
```bash
|
||||
sudo certbot --nginx -d example.com
|
||||
```
|
||||
|
||||
### Binding to a UNIX socket
|
||||
|
||||
Binding SQLPage to a Unix socket can reduce latency and enhance security by bypassing the network stack and restricting access to the socket file. Unix sockets are suitable for communication within the same host, offering lower overhead compared to TCP/IP.
|
||||
|
||||
#### SQLPage Configuration
|
||||
|
||||
Edit `./sqlpage/sqlpage.json`. Remove the `listen_on` and `port` configuration entries if they are present.
|
||||
|
||||
```json
|
||||
{
|
||||
"unix_socket": "/var/run/sqlpage.sock"
|
||||
}
|
||||
```
|
||||
|
||||
#### NGINX Configuration
|
||||
|
||||
In `/etc/nginx/sites-available/sqlpage`:
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name example.com;
|
||||
|
||||
location / {
|
||||
proxy_pass http://unix:/var/run/sqlpage.sock;
|
||||
proxy_set_header Host $host;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# Example NGINX configuration for SQLPage
|
||||
|
||||
You can find a fully working example of an NGINX configuration for SQLPage
|
||||
illustrating all the features described in this guide
|
||||
in the [examples/nginx](https://github.com/sqlpage/SQLPage/tree/main/examples/nginx)
|
||||
directory of the SQLPage Github repository.
|
||||
The example uses Docker and docker-compose to run NGINX and SQLPage.
|
||||
@@ -0,0 +1,5 @@
|
||||
select 'http_header' as component,
|
||||
'public, max-age=300, stale-while-revalidate=3600, stale-if-error=86400' as "Cache-Control";
|
||||
|
||||
select 'dynamic' as component, properties FROM example WHERE component = 'shell' LIMIT 1;
|
||||
select 'text' as component, sqlpage.read_file_as_text('your-first-sql-website/nginx.md') as contents_md;
|
||||
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 398 KiB |
@@ -0,0 +1,25 @@
|
||||
# Download SQLPage
|
||||
|
||||
SQLPage is a small single-file program that will
|
||||
execute the SQL files you write,
|
||||
and render the database responses as nice web pages.
|
||||
|
||||
If you have already downloaded SQLPage,
|
||||
you can skip this step and [start writing your website](#tutorial).
|
||||
|
||||
[Download the latest SQLPage](https://github.com/sqlpage/SQLPage/releases) for your operating system.
|
||||
In the _release assets_ section, you will find files named `sqlpage-windows.zip`, `sqlpage-linux.tgz`, and `sqlpage-macos.tgz`.
|
||||
Download the one that corresponds to your operating system, and extract the executable file from the archive.
|
||||
|
||||
> **Note**: On Mac OS, Apple blocks the execution of downloaded files by default. The easiest way to run SQLPage is to use [Homebrew](https://brew.sh).
|
||||
|
||||
> **Note**: Advanced users can alternatively install SQLPage using:
|
||||
> - [docker](https://hub.docker.com/repository/docker/lovasoa/SQLPage/general) (docker images are also available for ARM, making it easy to run SQLPage on a Raspberry Pi, for example),
|
||||
> - [brew](https://formulae.brew.sh/formula/sqlpage) (the easiest way to install SQLPage on Mac OS),
|
||||
> - [nix](https://search.nixos.org/packages?channel=unstable&show=sqlpage) (declarative package management for reproducible deployments),
|
||||
> - [scoop](https://scoop.sh/#/apps?q=sqlpage&id=305b3437817cd197058954a2f76ac1cf0e444116) (a command-line installer for Windows),
|
||||
> - or [cargo](https://crates.io/crates/sqlpage) (the Rust package manager).
|
||||
|
||||
You can also find the source code of SQLPage on [GitHub](https://github.com/sqlpage/SQLPage), [install rust](https://www.rust-lang.org/tools/install) on your computer, and compile it yourself with `cargo install sqlpage`.
|
||||
|
||||
See the instructions for [MacOS](?os=macos#download), or for [Windows](?os=windows#download).
|
||||
@@ -0,0 +1,18 @@
|
||||
# Download SQLPage for Mac OS
|
||||
|
||||
On Mac OS, Apple blocks the execution of downloaded files by default. The easiest way to run SQLPage is to use [Homebrew](https://brew.sh).
|
||||
Open a terminal and run the following commands:
|
||||
|
||||
```sh
|
||||
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
||||
brew install sqlpage
|
||||
sqlpage
|
||||
```
|
||||
|
||||
> **Note**: Advanced users can alternatively install SQLPage using
|
||||
> [the precompiled binaries](https://github.com/sqlpage/SQLPage/releases/latest),
|
||||
> [docker](https://hub.docker.com/repository/docker/lovasoa/SQLPage/general),
|
||||
> [nix](https://search.nixos.org/packages?channel=unstable&show=sqlpage),
|
||||
> or [cargo](https://crates.io/crates/sqlpage).
|
||||
|
||||
> **Not on Mac OS?** See the instructions for [Windows](?os=windows#download), or for [Other Systems](?os=any#download).
|
||||
@@ -0,0 +1,14 @@
|
||||
# Download the SQLPage executable for Windows
|
||||
|
||||
SQLPage offers a small executable file (`sqlpage.exe`) that will take requests to your website,
|
||||
execute the SQL files you write, and render the database responses as nice web pages.
|
||||
|
||||
[Download the latest SQLPage for Windows](https://github.com/sqlpage/SQLPage/releases/latest/download/sqlpage-windows.zip).
|
||||
Download the file, and extract the executable file from the zip archive.
|
||||
|
||||
> **Note**: Advanced users can alternatively install SQLPage using
|
||||
> [docker](https://hub.docker.com/repository/docker/lovasoa/SQLPage/general),
|
||||
> [scoop](https://scoop.sh/#/apps?q=sqlpage&id=305b3437817cd197058954a2f76ac1cf0e444116),
|
||||
> or [cargo](https://crates.io/crates/sqlpage).
|
||||
|
||||
> **Not on Windows?** See the instructions for [Mac OS](?os=macos#download), or for [Other Systems](?os=any#download).
|
||||
@@ -0,0 +1,199 @@
|
||||
# Building your website locally
|
||||
|
||||
Create a folder on your computer where you will store all contents related to your sql website.
|
||||
In the rest of this tutorial, we will call this folder the **root folder** of your website.
|
||||
|
||||
- On **Windows**, place the `sqlpage.exe` you downloaded above at the root of the folder. Then double-click the `sqlpage.exe` file to start the server.
|
||||
- On **Linux**, place `sqlpage.bin` at the root of the folder. Then open a terminal, cd to the root folder of your website, and run `./sqlpage.bin` to start the server.
|
||||
- On **Mac OS**, if you installed SQLPage using Homebrew, then you do not need to place anything at the root of the folder. Open Terminal, cd to the root folder of your website, and type `sqlpage` to start the server.
|
||||
|
||||

|
||||
|
||||
You should see a message in your terminal telling you that SQLPage is ready, and giving you the address of your website.
|
||||
|
||||
You can open your website locally by visiting [`http://localhost:8080`](http://localhost:8080)
|
||||
|
||||
SQLPage should have automatically created a folder called `sqlpage` with a SQLite database file named `sqlpage.db`. This is your website's default database - don't worry, we'll learn how to connect to other databases like PostgreSQL, MySQL, or SQL Server later!
|
||||
|
||||
# Your website's first SQL file
|
||||
|
||||
In the root folder of your SQLPage website, create a new SQL file called `index.sql`.
|
||||
Open it in a text editor that supports SQL syntax highlighting (I recommend [VSCode](https://code.visualstudio.com/)).
|
||||
|
||||
The `index.sql` file will be executed every time a visitor opens your website's home page, and the results will be displayed to the visitor
|
||||
using the components you specify in the file.
|
||||
|
||||
Let's start with a simple `index.sql` that displays a list of popular websites:
|
||||
|
||||
```sql
|
||||
SELECT 'list' AS component,
|
||||
'Popular websites' AS title;
|
||||
|
||||
SELECT 'Hello' AS title,
|
||||
'world' AS description,
|
||||
'https://wikipedia.org' AS link;
|
||||
```
|
||||
|
||||

|
||||
|
||||
The first line of the file defines the component that will be used to display the data, and properties of that component.
|
||||
In this case, we use the [`list` component](/component.sql?component=list) to display a list of items.
|
||||
The second line defines the data that will populate the component.
|
||||
All the components you can use and their properties are documented in [SQLPage's online documentation](https://sql-page.com/documentation.sql).
|
||||
|
||||
# Your database schema
|
||||
|
||||
> If you already have a database populated with data,
|
||||
> or if you intend to use other tools to manage your database structure,
|
||||
> you can skip this section.
|
||||
|
||||
The [database schema](https://en.wikipedia.org/wiki/Database_schema) for your SQLPage website
|
||||
can be defined using SQL scripts located in the
|
||||
**`sqlpage/migrations`** subdirectory of your website's root folder.
|
||||
|
||||
For our first website, let's create a file located in `sqlpage/migrations/0001_create_users_table.sql` with the following contents:
|
||||
|
||||
```sql
|
||||
CREATE TABLE users (
|
||||
id INTEGER PRIMARY KEY,
|
||||
name TEXT NOT NULL
|
||||
);
|
||||
```
|
||||
|
||||
If you need to quickly test a database schema and associated queries online,
|
||||
before making any change to your database, I can recommend [sqliteonline.com](https://sqliteonline.com/) (which actually also works with Postgres, MySQL, and SQL Server).
|
||||
|
||||
Please read our [**introduction to database migrations**](./migrations.sql) to
|
||||
learn how to maintain your database schema in the long term.
|
||||
|
||||
> **Note**: The migration system is not supported on Microsoft SQL Server databases.
|
||||
> If you are using a SQL Server database, you should create your tables using a different tool, such as _SQL Server Management Studio_.
|
||||
|
||||
# Connect to a custom database
|
||||
|
||||
By default, SQLPage uses a [SQLite](https://www.sqlite.org/about.html) database stored in a file named `sqlpage.db`
|
||||
in the `sqlpage` configuration folder.
|
||||
You can change this by creating a file named `sqlpage.json` in a folder called `sqlpage`.
|
||||
So, if your website's root folder is `/my_website`, you should create a file at `/my_website/sqlpage/sqlpage.json`.
|
||||
|
||||
Here is an example `sqlpage.json` file:
|
||||
|
||||
```sql
|
||||
{ "database_url": "sqlite://:memory:" }
|
||||
```
|
||||
|
||||
This will tell SQLPage to use an in-memory SQLite database instead of the default file-based database. While this means all changes to the database will be lost when you stop the SQLPage server, it's useful for quickly testing and iterating on your database schema.
|
||||
If you then deploy your website online using a service like [DataPage.app](https://datapage.app), it will automatically use a persisted database instead.
|
||||
|
||||
Later, when you want to deploy your website online, you can switch back to a persistent database like
|
||||
|
||||
- a SQLite file with `sqlite://your-database-file.db` ([see options](https://docs.rs/sqlx-oldapi/latest/sqlx_oldapi/sqlite/struct.SqliteConnectOptions.html)),
|
||||
- a PostgreSQL-compatible server with `postgres://user:password@host/database` ([see options](https://docs.rs/sqlx-oldapi/latest/sqlx_oldapi/postgres/struct.PgConnectOptions.html)),
|
||||
- a MySQL-compatible server with `mysql://user:password@host/database` ([see options](https://docs.rs/sqlx-oldapi/latest/sqlx_oldapi/mysql/struct.MySqlConnectOptions.html)),
|
||||
- a Microsoft SQL Server with `mssql://user:password@host/database` ([see options](https://docs.rs/sqlx-oldapi/latest/sqlx_oldapi/mssql/struct.MssqlConnectOptions.html#method.from_str), [note about named instances](https://github.com/sqlpage/SQLPage/issues/92)),
|
||||
- any ODBC-compatible database like DuckDB, ClickHouse, Databricks, Snowflake, BigQuery, Oracle, Db2, and many more. See [ODBC database connection instructions](https://github.com/sqlpage/SQLPage#odbc-setup).
|
||||
|
||||
> If `user` or `password` **contains special characters**, you should [**percent-encode**](https://en.wikipedia.org/wiki/Percent-encoding) them.
|
||||
>
|
||||
> For instance, a SQL Server database named `db` running on `localhost` port `1433` with the username `funny:user` and the password `p@ssw0rd` would be represented as
|
||||
> `mssql://funny%3Auser:p%40ssw0rd@localhost:1433/db`.
|
||||
|
||||
For more information about the properties that can be set in sqlpage.json, see [SQLPage's configuration documentation](https://github.com/sqlpage/SQLPage/blob/main/configuration.md#configuring-sqlpage)
|
||||
|
||||

|
||||
|
||||
# Use parameterized SQL queries to let users interact with your database
|
||||
|
||||
### Displaying a form
|
||||
|
||||
Let's create a form to let our users insert data into our database. Add the following code to your `index.sql` file:
|
||||
|
||||
```sql
|
||||
SELECT 'form' AS component, 'Add a user' AS title;
|
||||
SELECT 'Username' as name, TRUE as required;
|
||||
```
|
||||
|
||||
The first SELECT statement opens the [`form` component](https://sql-page.com/component.sql?component=form).
|
||||
The second SELECT statement adds a field to the form. Since we do not specify a `type`, it will be a text field. The label displayed above the field will be the same as its name by default.
|
||||
|
||||
### Handling form submission
|
||||
|
||||
Nothing happens when you submit the form at the moment. Let's fix that.
|
||||
Add the following below the previous code:
|
||||
|
||||
```sql
|
||||
INSERT INTO users (name)
|
||||
SELECT :Username
|
||||
WHERE :Username IS NOT NULL;
|
||||
```
|
||||
|
||||
The snippet above uses an [`INSERT INTO SELECT` SQL statement](https://www.sqlite.org/lang_insert.html) to
|
||||
[safely](../safety.sql) insert a new row into the `users` table when the form is submitted.
|
||||
It uses a `WHERE` clause to make sure that the `INSERT` statement is only executed when the `:Username` parameter is present.
|
||||
The `:Username` parameter is set to `NULL` when you initially load the page, and then SQLPage automatically sets it to the value
|
||||
from the text field when the user submits the form.
|
||||
|
||||
#### Parameters
|
||||
|
||||
There are two types of parameters you can use in your SQL queries:
|
||||
|
||||
- **URL parameters** like **`$ParameterName`**. If you add `?x=1&y=2` to the end of the URL of your page, `$x` will be set to the string `'1'` and `$y` will be set to the string `'2'`. This is useful to create links with parameters. For instance, if you have a database of products, you can create a link to a product page with the URL `product?product_id=12` (or `product.sql?product_id=12` - both work). Then, in the `product.sql` file, you can use the `$product_id` variable to get the product with the corresponding ID from your database. URL parameters are also sometimes called *query parameters*, or *GET parameters*.
|
||||
- **Form parameters** like **`:ParameterName`**. They refer to the value of the field with the corresponding `name` entered by the user in a [form](/component.sql?component=form). If no form was submitted, it is set to `NULL`. Form parameters are also sometimes called *POST parameters*.
|
||||
|
||||
> Note: Currently, if a `$parameter` is not present in the URL, it is first looked for in the form parameters. If it is not found there either, it is set to `NULL`. Please do not rely on this behavior, as it may change in the future.
|
||||
|
||||
You can also set parameters yourself at any point in your SQL files in order to reuse
|
||||
their value in several places, using the `SET ParameterName = value` syntax.
|
||||
For instance, we could use the following code to save the username in uppercase:
|
||||
|
||||
```sql
|
||||
SET Username = UPPER(:Username);
|
||||
INSERT INTO users (name) VALUES ($Username);
|
||||
```
|
||||
|
||||
### Displaying data from our database
|
||||
|
||||
Now, users are present in our database, but we can't see them.
|
||||
Let's see how to use data from our database to populate a [list](/component.sql?component=list) component, in order to display the list of users.
|
||||
|
||||
Add the following code to your `index.sql` file:
|
||||
|
||||
```sql
|
||||
SELECT 'list' AS component, 'Users' AS title;
|
||||
SELECT name AS title, CONCAT(name, ' is a user on this website.') as description FROM users;
|
||||
```
|
||||
|
||||
### Your first SQLPage website is ready!
|
||||
|
||||
You can view [the full source code for this example on Github](https://github.com/sqlpage/SQLPage/tree/main/examples/simple-website-example)
|
||||
|
||||
Here is a screenshot of the final result:
|
||||
|
||||

|
||||
|
||||
To go further, have a look at [the examples](../examples/).
|
||||
|
||||
|
||||
# Deploy your SQLPage website online
|
||||
|
||||
### Using DataPage.app
|
||||
To deploy your SQLPage website online, the easiest way is to use [DataPage.app](https://datapage.app),
|
||||
a managed hosting service for SQLPage websites maintained by the same people who develop SQLPage.
|
||||
Just create an account, and follow the instructions to upload your website to our servers. It will be live in seconds!
|
||||
|
||||
### Manually
|
||||
If you prefer to host your website yourself, you can use a cloud provider or a VPS provider. You will need to:
|
||||
- Configure domain name resolution to point to your server
|
||||
- Open the port you are using (8080 by default) in your server's firewall
|
||||
- [Setup docker](https://github.com/sqlpage/SQLPage?tab=readme-ov-file#with-docker) or another process manager such as [systemd](https://github.com/sqlpage/SQLPage/blob/main/sqlpage.service) to start SQLPage automatically when your server boots and to keep it running
|
||||
- Optionally, [setup a reverse proxy](nginx.sql) to avoid exposing SQLPage directly to the internet
|
||||
- Optionally, setup a TLS certificate to enable HTTPS
|
||||
- Configure connection to a cloud database or a database running on your server in [`sqlpage.json`](https://github.com/sqlpage/SQLPage/blob/main/configuration.md#configuring-sqlpage)
|
||||
|
||||
# Go further
|
||||
|
||||
- Check out [learnsqlpage.com](https://learnsqlpage.com) by Nick Antonaccio for an in-depth tutorial with many examples
|
||||
- Read the [SQLPage documentation](/documentation.sql) to learn about all the components available in SQLPage
|
||||
- Read about [SQLPage's extensions to SQL](/extensions-to-sql) for a specification of the SQL syntax you can use in SQLPage, the data types used when exchanging data with the browser and with the database, a clear explanation of how *SQLPage variables* and *SQLPage functions* work.
|
||||
- Join the [SQLPage community](https://github.com/sqlpage/SQLPage/discussions) to ask questions and share your projects
|
||||
- If you like videos better, check this series that shows how to build and deploy your app from scratch [SQLPage on Youtube](https://www.youtube.com/playlist?list=PLTue_qIAHxAf9fEjBY2CN0N_5XOiffOk_)
|
||||