Skip to content

Commit 9ac40db

Browse files
authored
Add docker-compose setup for demo/testing (#188)
* add docker compose demo for one-line containerized testing * optimize go build * log queries in demo db * set default basemap
1 parent 638e9d9 commit 9ac40db

File tree

9 files changed

+249
-3
lines changed

9 files changed

+249
-3
lines changed

.dockerignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
*
2+
.*
3+
4+
!go.mod
5+
!go.sum
6+
!*.go
7+
!cql
8+
!assets
9+
!internal

Dockerfile

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,14 @@ ARG TARGETARCH
1212
ARG VERSION
1313

1414
WORKDIR /app
15-
COPY . ./
1615

17-
RUN CGO_ENABLED=0 GOOS=linux GOARCH=${TARGETARCH} go build -v -ldflags "-s -w -X main.programVersion=${VERSION}"
16+
ENV CGO_ENABLED=1
17+
RUN go env -w GOCACHE=/go-cache
18+
RUN go env -w GOMODCACHE=/gomod-cache
19+
COPY go.* ./
20+
RUN --mount=type=cache,target=/gomod-cache go mod download
21+
COPY . ./
22+
RUN --mount=type=cache,target=/gomod-cache --mount=type=cache,target=/go-cache CGO_ENABLED=0 GOOS=linux GOARCH=${TARGETARCH} go build -v -ldflags "-s -w -X main.programVersion=${VERSION}"
1823

1924
FROM --platform=${TARGETARCH} ${BASE_REGISTRY}/${BASE_IMAGE} AS multi-stage
2025

demo/README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,17 @@
22

33
Contains example code to demonstrate the capabilities of `pg_featureserv`.
44

5+
### Quick start (Docker Compose)
6+
7+
```sh
8+
cd demo
9+
docker compose up -d
10+
```
11+
12+
Access the UI: `http://localhost:9000`
13+
14+
The SQL commands in demo/initdb will be run once on database creation. To re-run the init scripts, tear down the database and recreate.
15+
516
### Routing example
617

718
A demo using OpenLayers and PgRouting.

demo/docker-compose.yaml

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# pg_featureserv Docker Compose example setup.
2+
# To run: docker compose up -d --build
3+
4+
services:
5+
db:
6+
image: postgis/postgis:16-3.5
7+
platform: linux/amd64
8+
environment:
9+
POSTGRES_DB: postgres
10+
POSTGRES_USER: postgres
11+
POSTGRES_PASSWORD: postgres
12+
volumes:
13+
# - ./demodata:/var/lib/postgresql/data
14+
- ./initdb:/docker-entrypoint-initdb.d:ro
15+
healthcheck:
16+
test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER || exit 1"]
17+
interval: 5s
18+
timeout: 5s
19+
retries: 12
20+
21+
pg_featureserv:
22+
build:
23+
context: ..
24+
dockerfile: Dockerfile
25+
target: multi-stage
26+
args:
27+
GOLANG_VERSION: "1.21.6"
28+
TARGETARCH: "amd64"
29+
PLATFORM: "amd64"
30+
BASE_REGISTRY: "registry.access.redhat.com"
31+
BASE_IMAGE: "ubi8-micro"
32+
VERSION: "dev"
33+
image: pg_featureserv:dev-amd64
34+
restart: unless-stopped
35+
platform: linux/amd64
36+
environment:
37+
DATABASE_URL: postgres://postgres:postgres@db/postgres
38+
PGFS_DATABASE_FUNCTIONINCLUDES: postgisftw
39+
depends_on:
40+
db:
41+
condition: service_healthy
42+
ports:
43+
- "9000:9000"

demo/initdb/01-init.sql

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
CREATE EXTENSION IF NOT EXISTS postgis;
2+
ALTER SYSTEM SET log_statement = 'all';
3+
SELECT pg_reload_conf();

demo/initdb/02-functions.sql

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
-- Lightweight demo functions that do not depend on external datasets
2+
CREATE SCHEMA IF NOT EXISTS postgisftw;
3+
4+
-- us_grid with id
5+
CREATE OR REPLACE FUNCTION postgisftw.us_grid(
6+
num_x integer DEFAULT 10,
7+
num_y integer DEFAULT 10)
8+
RETURNS TABLE(id text, geom geometry)
9+
AS $$
10+
DECLARE
11+
lon_min CONSTANT numeric := -128;
12+
lon_max CONSTANT numeric := -64;
13+
lat_min CONSTANT numeric := 24;
14+
lat_max CONSTANT numeric := 49;
15+
dlon numeric;
16+
dlat numeric;
17+
BEGIN
18+
dlon := (lon_max - lon_min) / num_x;
19+
dlat := (lat_max - lat_min) / num_y;
20+
RETURN QUERY
21+
SELECT
22+
x.x::text || '_' || y.y::text AS fid,
23+
ST_MakeEnvelope(
24+
lon_min + (x.x - 1) * dlon, lat_min + (y.y - 1) * dlat,
25+
lon_min + x.x * dlon, lat_min + y.y * dlat, 4326
26+
) AS geom
27+
FROM generate_series(1, num_x) AS x(x)
28+
CROSS JOIN generate_series(1, num_y) AS y(y);
29+
END;
30+
$$ LANGUAGE plpgsql STABLE STRICT;
31+
32+
COMMENT ON FUNCTION postgisftw.us_grid IS 'Generates a grid of rectangles covering the USA';
33+
34+
-- us_grid without id
35+
CREATE OR REPLACE FUNCTION postgisftw.us_grid_noid(
36+
num_x integer DEFAULT 10,
37+
num_y integer DEFAULT 10)
38+
RETURNS TABLE(geom geometry)
39+
AS $$
40+
DECLARE
41+
lon_min CONSTANT numeric := -128;
42+
lon_max CONSTANT numeric := -64;
43+
lat_min CONSTANT numeric := 24;
44+
lat_max CONSTANT numeric := 49;
45+
dlon numeric;
46+
dlat numeric;
47+
BEGIN
48+
dlon := (lon_max - lon_min) / num_x;
49+
dlat := (lat_max - lat_min) / num_y;
50+
RETURN QUERY
51+
SELECT
52+
ST_MakeEnvelope(
53+
lon_min + (x.x - 1) * dlon, lat_min + (y.y - 1) * dlat,
54+
lon_min + x.x * dlon, lat_min + y.y * dlat, 4326
55+
) AS geom
56+
FROM generate_series(1, num_x) AS x(x)
57+
CROSS JOIN generate_series(1, num_y) AS y(y);
58+
END;
59+
$$ LANGUAGE plpgsql STABLE STRICT;
60+
61+
-- geo_grid over arbitrary extent
62+
CREATE OR REPLACE FUNCTION postgisftw.geo_grid(
63+
num_x integer DEFAULT 10,
64+
num_y integer DEFAULT 10,
65+
lon_min numeric DEFAULT -180.0,
66+
lat_min numeric DEFAULT -90.0,
67+
lon_max numeric DEFAULT 180.0,
68+
lat_max numeric DEFAULT 90.0)
69+
RETURNS TABLE(id text, geom geometry)
70+
AS $$
71+
DECLARE
72+
dlon numeric;
73+
dlat numeric;
74+
BEGIN
75+
dlon := (lon_max - lon_min) / num_x;
76+
dlat := (lat_max - lat_min) / num_y;
77+
RETURN QUERY
78+
SELECT
79+
x.x::text || '_' || y.y::text AS id,
80+
ST_MakeEnvelope(
81+
lon_min + (x.x - 1) * dlon, lat_min + (y.y - 1) * dlat,
82+
lon_min + x.x * dlon, lat_min + y.y * dlat, 4326
83+
) AS geom
84+
FROM generate_series(1, num_x) AS x(x)
85+
CROSS JOIN generate_series(1, num_y) AS y(y);
86+
END;
87+
$$ LANGUAGE plpgsql IMMUTABLE STRICT;
88+
89+
COMMENT ON FUNCTION postgisftw.geo_grid IS 'Generates a grid of rectangles over a geographic extent';
90+
91+
-- Simple buffer function (no external deps)
92+
CREATE OR REPLACE FUNCTION postgisftw.buffer(
93+
input geometry DEFAULT 'POINT(0 0)'::geometry,
94+
dist numeric DEFAULT 10)
95+
RETURNS TABLE(geom geometry)
96+
AS $$
97+
BEGIN
98+
RETURN QUERY SELECT ST_Buffer(ST_SetSRID(input, 4326), dist) AS geom;
99+
END;
100+
$$ LANGUAGE plpgsql STABLE STRICT;
101+

demo/initdb/03-hexagon.sql

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
-- Hexagon tiling helpers (no external datasets)
2+
CREATE OR REPLACE FUNCTION hexagon(i integer, j integer, edge float8)
3+
RETURNS geometry
4+
AS $$
5+
DECLARE
6+
h float8 := edge*cos(pi()/6.0);
7+
cx float8 := 1.5*i*edge;
8+
cy float8 := h*(2*j+abs(i%2));
9+
BEGIN
10+
RETURN ST_MakePolygon(ST_MakeLine(ARRAY[
11+
ST_Point(cx - 1.0*edge, cy + 0),
12+
ST_Point(cx - 0.5*edge, cy + -1*h),
13+
ST_Point(cx + 0.5*edge, cy + -1*h),
14+
ST_Point(cx + 1.0*edge, cy + 0),
15+
ST_Point(cx + 0.5*edge, cy + h),
16+
ST_Point(cx - 0.5*edge, cy + h),
17+
ST_Point(cx - 1.0*edge, cy + 0)
18+
]));
19+
END;
20+
$$ LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE;
21+
22+
CREATE OR REPLACE FUNCTION hexagoncoordinates(bounds geometry, edge float8,
23+
OUT i integer, OUT j integer)
24+
RETURNS SETOF record
25+
AS $$
26+
DECLARE
27+
h float8 := edge*cos(pi()/6);
28+
mini integer := floor(st_xmin(bounds) / (1.5*edge));
29+
minj integer := floor(st_ymin(bounds) / (2*h));
30+
maxi integer := ceil(st_xmax(bounds) / (1.5*edge));
31+
maxj integer := ceil(st_ymax(bounds) / (2*h));
32+
BEGIN
33+
FOR i, j IN
34+
SELECT a, b
35+
FROM generate_series(mini, maxi) a,
36+
generate_series(minj, maxj) b
37+
LOOP
38+
RETURN NEXT;
39+
END LOOP;
40+
END;
41+
$$ LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE;
42+
43+
CREATE OR REPLACE FUNCTION postgisftw.hex_grid(
44+
edge_len numeric DEFAULT 1,
45+
lon_min numeric DEFAULT -180.0,
46+
lat_min numeric DEFAULT -80.0,
47+
lon_max numeric DEFAULT 180.0,
48+
lat_max numeric DEFAULT 80.0)
49+
RETURNS TABLE(geom geometry(Polygon, 3857), i integer, j integer)
50+
AS $$
51+
DECLARE
52+
boxwm geometry;
53+
BEGIN
54+
boxwm := ST_Transform(ST_MakeEnvelope(lon_min, lat_min, lon_max, lat_max, 4326), 3857);
55+
RETURN QUERY
56+
SELECT ST_SetSRID(hexagon(h.i, h.j, edge_len), 3857), h.i, h.j
57+
FROM (SELECT * FROM hexagoncoordinates(boxwm, edge_len)) AS h;
58+
END;
59+
$$ LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE;
60+

demo/initdb/04-views.sql

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
CREATE TABLE cities (
2+
id serial PRIMARY KEY,
3+
name text,
4+
geom geometry(Point, 4326)
5+
);
6+
7+
INSERT INTO cities (name, geom) VALUES
8+
('Paris', ST_SetSRID(ST_MakePoint(2.3522, 48.8566), 4326)),
9+
('NYC', ST_SetSRID(ST_MakePoint(-74.0060, 40.7128), 4326));
10+
11+
-- View with geometry and featureID column (no PK)
12+
CREATE VIEW cities_view AS
13+
SELECT id AS id, name, geom FROM cities;
14+

internal/conf/config.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ func setDefaultConfig() {
5151
viper.SetDefault("Metadata.Title", "pg-featureserv")
5252
viper.SetDefault("Metadata.Description", "Crunchy Data Feature Server for PostGIS")
5353

54-
viper.SetDefault("Website.BasemapUrl", "")
54+
viper.SetDefault("Website.BasemapUrl", "https://{a-d}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png")
5555
}
5656

5757
// Config for system

0 commit comments

Comments
 (0)