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,19 @@
# Using PostGIS to build a geographic data application
## Introduction
This is a small application that uses [PostGIS](https://postgis.net/)
to save data associated with geographic coordinates.
If you are using a SQLite database, see [this other example instead](../make%20a%20geographic%20data%20application%20using%20sqlite%20extensions/),
which implements the same application using the `spatialite` extension for SQLite.
### Installation
You need to install the `postgis` extension for postgres. Follow [the official instructions](https://postgis.net/documentation/getting_started/).
Then you can instruct SQLPage to connect to your database by editing the [`sqlpage/sqlpage.json`](./sqlpage/sqlpage.json) file.
## Screenshots
![](./screenshots/code.png)
@@ -0,0 +1,11 @@
INSERT INTO spatial_data (title, geom, description)
VALUES (
:Title,
ST_MakePoint(
CAST(:Longitude AS REAL),
CAST(:Latitude AS REAL
), 4326),
:Text
) RETURNING
'redirect' AS component,
'index.sql' AS link;
@@ -0,0 +1,17 @@
services:
web:
image: lovasoa/sqlpage:main
ports:
- "8080:8080"
volumes:
- .:/var/www
- ./sqlpage:/etc/sqlpage
depends_on:
- db
environment:
DATABASE_URL: postgres://postgres:postgres@db/postgres
db:
image: postgis/postgis:latest
platform: linux/amd64
environment:
POSTGRES_PASSWORD: postgres
@@ -0,0 +1,24 @@
SELECT 'shell' as component,
'Point edition' AS title,
'/' as link,
'book' as icon;
UPDATE spatial_data
SET description = :Text
WHERE id = $id::int AND :Text IS NOT NULL;
SELECT 'form' AS component, title
FROM spatial_data WHERE id = $id::int;
SELECT
'Text' AS name,
'Description for the point: ' || title AS description,
'textarea' AS type,
description AS value
FROM spatial_data
WHERE id = $id::int;
SELECT 'text' as component,
description as contents_md
FROM spatial_data
WHERE id = $id::int;
@@ -0,0 +1,38 @@
SELECT 'shell' as component,
'Map' AS title,
'/' as link,
'book' as icon;
SELECT 'map' AS component,
ST_Y(geom) AS latitude,
ST_X(geom) AS longitude
FROM spatial_data
WHERE id = $id::int;
SELECT 'map' as component,
'Points of interest' as title,
2 as zoom,
700 as height;
SELECT title,
ST_Y(geom) AS latitude,
ST_X(geom) AS longitude,
format('[View](point.sql?id=%s) [Edit](edition_form.sql?id=%s)', id, id) as description_md
FROM spatial_data;
SELECT 'list' as component,
'My points' as title;
SELECT title,
'point.sql?id=' || id as link,
'red' as color,
'world-pin' as icon
FROM spatial_data;
SELECT 'form' AS component,
'Add a point' AS title,
'add_point.sql' AS action;
SELECT 'Title' AS name;
SELECT 'Latitude' AS name, 'number' AS type, 0.00000001 AS step;
SELECT 'Longitude' AS name, 'number' AS type, 0.00000001 AS step;
SELECT 'Text' AS name, 'textarea' AS type;
@@ -0,0 +1,58 @@
SELECT 'shell' as component,
title,
'/' as link,
'index' as menu_item,
'book' as icon
FROM spatial_data
WHERE id = $id::int;
SELECT 'datagrid' as component, title FROM spatial_data WHERE id = $id::int;
SELECT 'Latitude' as title,
ST_Y(geom) as description,
'purple' as color,
'world-latitude' as icon
FROM spatial_data WHERE id = $id::int;
SELECT 'Longitude' as title,
ST_X(geom) as description,
'purple' as color,
'world-longitude' as icon
FROM spatial_data WHERE id = $id::int;
SELECT 'Created at' as title,
created_at as description,
'calendar' as icon,
'Date and time of creation' as footer
FROM spatial_data WHERE id = $id::int;
SELECT 'Label' as title,
title as description,
'geo:' || ST_Y(geom) || ',' || ST_X(geom) || '?z=16' AS link,
'blue' as color,
'world' as icon,
'User-generated point name' as footer
FROM spatial_data
WHERE id = $id::int;
SELECT 'text' as component,
description ||
format(E'\n\n [Edit description](edition_form.sql?id=%s)', id)
as contents_md
FROM spatial_data
WHERE id = $id::int;
SELECT 'list' as component, 'Closest points' as title;
SELECT to_label as title,
ROUND(distance::decimal, 3) || ' km' as description,
'point.sql?id=' || to_id as link,
'red' as color,
'world-pin' as icon
FROM distances
WHERE from_id = $id::int
ORDER BY distance
LIMIT 5;
SELECT 'map' AS component,
ST_Y(geom) AS latitude, ST_X(geom) AS longitude
FROM spatial_data WHERE id = $id::int;
Binary file not shown.

After

Width:  |  Height:  |  Size: 846 KiB

@@ -0,0 +1,24 @@
CREATE EXTENSION IF NOT EXISTS postgis;
-- Create a table with a postgis geometry column
CREATE TABLE IF NOT EXISTS spatial_data (
id serial primary key NOT NULL,
title text NOT NULL,
geom geometry NULL,
description text NOT NULL,
created_at timestamp without time zone NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE OR REPLACE VIEW distances AS
SELECT from_point.id AS from_id,
from_point.title AS from_label,
to_point.id AS to_id,
to_point.title AS to_label,
ST_Distance(
from_point.geom,
to_point.geom,
TRUE
) AS distance
FROM spatial_data AS from_point, spatial_data AS to_point
WHERE from_point.id != to_point.id;
@@ -0,0 +1,3 @@
{
"database_url": "postgres://my_username:my_password@localhost:5432/my_geographic_database"
}
@@ -0,0 +1,53 @@
GET http://localhost:8080/
HTTP 200
[Asserts]
body contains "Points of interest"
body contains "Add a point"
body not contains "An error occurred"
POST http://localhost:8080/add_point.sql
[FormParams]
Title: Hurl Paris
Latitude: 48.8566
Longitude: 2.3522
Text: First Hurl point
HTTP 302
[Asserts]
header "Location" == "index.sql"
POST http://localhost:8080/add_point.sql
[FormParams]
Title: Hurl Lyon
Latitude: 45.764
Longitude: 4.8357
Text: Second Hurl point
HTTP 302
GET http://localhost:8080/
HTTP 200
[Captures]
paris_id: xpath "substring-after(string(//a[normalize-space(.)='Hurl Paris']/@href), 'id=')"
[Asserts]
body contains "Hurl Paris"
body contains "Hurl Lyon"
body htmlUnescape contains "point.sql?id={{paris_id}}"
body not contains "An error occurred"
GET http://localhost:8080/point.sql?id={{paris_id}}
HTTP 200
[Asserts]
body contains "48.8566"
body contains "2.3522"
body contains "First Hurl point"
body contains "Closest points"
body contains "Hurl Lyon"
body htmlUnescape contains "edition_form.sql?id={{paris_id}}"
body not contains "An error occurred"
POST http://localhost:8080/edition_form.sql?id={{paris_id}}
[FormParams]
Text: Updated Hurl point
HTTP 200
[Asserts]
body contains "Updated Hurl point"
body not contains "An error occurred"