Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ test-up:
test-down:
docker compose -f docker/test/docker-compose.yml down

## Drop and reseed the test database from test/seed/v13.sql.gz
## Drop and reseed the test database from test/seed/seed.sql.gz
.PHONY: test-seed
test-seed:
docker compose -f docker/test/docker-compose.yml exec api pnpm run test:create
Expand Down
13 changes: 11 additions & 2 deletions api/app/queries/outcodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,19 @@ export interface OutcodeNearbyRow extends OutcodeRow {
distance: number;
}

// Normalise NULL array_agg results (no source rows passed the matview
// FILTER) into empty arrays so the public contract stays `string[]`.
const COALESCE_ARRAY = (col: string) =>
`COALESCE(${col}, ARRAY[]::text[]) AS ${col}`;

const SELECT_COLUMNS = `
outcode, longitude, latitude, eastings, northings,
admin_district, parish, admin_county, admin_ward,
country, parliamentary_constituency
${COALESCE_ARRAY("admin_district")},
${COALESCE_ARRAY("parish")},
${COALESCE_ARRAY("admin_county")},
${COALESCE_ARRAY("admin_ward")},
${COALESCE_ARRAY("country")},
${COALESCE_ARRAY("parliamentary_constituency")}
`;

const normaliseOutcode = (outcode: string): string =>
Expand Down
4 changes: 2 additions & 2 deletions bin/generate_test_seed
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
#
# Generate test/seed/v13.sql.gz from a loaded postcodesiodb.
# Generate test/seed/seed.sql.gz from a loaded postcodesiodb.
#
# Reads from a fully-populated DB under the `public` schema (typically the dev
# compose stack: POSTGRES_HOST=127.0.0.1 POSTGRES_PORT=5433
Expand All @@ -17,7 +17,7 @@
set -euo pipefail

ROOT="$(cd "$(dirname "$0")/.." && pwd)"
OUT="$ROOT/test/seed/v13.sql.gz"
OUT="$ROOT/test/seed/seed.sql.gz"

HOST="${POSTGRES_HOST:-127.0.0.1}"
PORT="${POSTGRES_PORT:-5433}"
Expand Down
4 changes: 2 additions & 2 deletions bin/load_test_seed
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
#
# Drop and recreate the test database, then load test/seed/v13.sql.gz into it.
# Drop and recreate the test database, then load test/seed/seed.sql.gz into it.
#
# Uses psql with standard POSTGRES_* env vars (same set as the app). Run from
# anywhere psql can reach the target host: host shell against dev compose pg
Expand All @@ -10,7 +10,7 @@
set -euo pipefail

ROOT="$(cd "$(dirname "$0")/.." && pwd)"
SEED="$ROOT/test/seed/v13.sql.gz"
SEED="$ROOT/test/seed/seed.sql.gz"

HOST="${POSTGRES_HOST:-127.0.0.1}"
PORT="${POSTGRES_PORT:-5432}"
Expand Down
4 changes: 2 additions & 2 deletions docs/api/bulk-postcode-lookup.api.mdx

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions docs/api/lookup-postcode.api.mdx

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions docs/api/nearest-postcode.api.mdx

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions docs/api/postcode-lookup.api.mdx

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions docs/api/random-postcode.api.mdx

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/postcode/schema.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ The Postcode schema represents all geographical and administrative information a
| `northings` | integer \| null | Ordnance Survey grid reference northing (Y-coordinate) with 1-meter resolution. May be null if geolocation unavailable. | 179951 |
| `country` | string | The UK constituent country for this postcode (England, Scotland, Wales, Northern Ireland, Channel Islands, or Isle of Man). | "England" |
| `nhs_ha` | string \| null | The NHS health authority area for this postcode. | "London" |
| `admin_county` | string \| null | The administrative county for this postcode. May be empty for areas without county-level administration. | "" |
| `admin_county` | string \| null | The administrative county for this postcode. Null where the postcode falls outside a county-level authority (the underlying GSS code is then a pseudo such as `E99999999`, surfaced under `codes.admin_county`). | null |
| `admin_district` | string \| null | The administrative district or unitary authority for this postcode. | "Westminster" |
| `admin_ward` | string \| null | The electoral/administrative ward for this postcode. | "St. James's" |
| `longitude` | number \| null | WGS84 longitude coordinate (east-west position). May be null if geolocation unavailable. | -0.12767 |
Expand Down
2 changes: 1 addition & 1 deletion latest
Original file line number Diff line number Diff line change
@@ -1 +1 @@
https://postcodesio.s3.amazonaws.com/public/postcodesio-2026-05-26-1447.sql.gz
https://postcodesio.s3.amazonaws.com/public/postcodesio-2026-05-29-1141.sql.gz
4 changes: 2 additions & 2 deletions openapi/components/schemas/Postcode.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ properties:
title: County
type: string
nullable: true
description: "The administrative county for this postcode. May be empty for areas without county-level administration."
example: ""
description: "The administrative county for this postcode. Null where the postcode falls outside a county-level authority (the underlying GSS code is then a pseudo such as `E99999999`, surfaced under `codes.admin_county`)."
example: null
admin_district:
title: District
type: string
Expand Down
4 changes: 2 additions & 2 deletions static/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -755,8 +755,8 @@
"title": "County",
"type": "string",
"nullable": true,
"description": "The administrative county for this postcode. May be empty for areas without county-level administration.",
"example": ""
"description": "The administrative county for this postcode. Null where the postcode falls outside a county-level authority (the underlying GSS code is then a pseudo such as `E99999999`, surfaced under `codes.admin_county`).",
"example": null
},
"admin_district": {
"title": "District",
Expand Down
4 changes: 2 additions & 2 deletions static/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -657,8 +657,8 @@ components:
title: County
type: string
nullable: true
description: The administrative county for this postcode. May be empty for areas without county-level administration.
example: ''
description: The administrative county for this postcode. Null where the postcode falls outside a county-level authority (the underlying GSS code is then a pseudo such as `E99999999`, surfaced under `codes.admin_county`).
example: null
admin_district:
title: District
type: string
Expand Down
4 changes: 2 additions & 2 deletions test/postcodes.e2e.integration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ describe("Postcodes E2E", () => {
senedd_constituency_no: null,
admin_district: "Aberdeen City",
parish: null,
admin_county: "(pseudo) Scotland",
admin_county: null,
date_of_introduction: "201106",
date_of_termination: null,
index_of_multiple_deprivation: 3888,
Expand Down Expand Up @@ -129,7 +129,7 @@ describe("Postcodes E2E", () => {
senedd_constituency_no: null,
admin_district: "Southwark",
parish: "Southwark, unparished area",
admin_county: "(pseudo) England (UA/MD/LB)",
admin_county: null,
date_of_introduction: "201008",
date_of_termination: null,
index_of_multiple_deprivation: 8253,
Expand Down
28 changes: 14 additions & 14 deletions test/queries.outcodes.integration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ describe("queries/outcodes (contract)", () => {
describe("find()", () => {
it("returns aggregated row for a known outcode", async () => {
expect(await find("AB10")).toEqual({
admin_county: ["(pseudo) Scotland"],
admin_county: [],
admin_district: ["Aberdeen City"],
admin_ward: [
"Airyhall/Broomhill/Garthdee",
Expand All @@ -25,13 +25,13 @@ describe("queries/outcodes (contract)", () => {
longitude: -2.1207891580547087,
northings: 804948,
outcode: "AB10",
parish: null,
parish: [],
parliamentary_constituency: ["Aberdeen North", "Aberdeen South"],
});
});
it("normalises whitespace and case", async () => {
expect(await find(" ab 10 ")).toEqual({
admin_county: ["(pseudo) Scotland"],
admin_county: [],
admin_district: ["Aberdeen City"],
admin_ward: [
"Airyhall/Broomhill/Garthdee",
Expand All @@ -47,7 +47,7 @@ describe("queries/outcodes (contract)", () => {
longitude: -2.1207891580547087,
northings: 804948,
outcode: "AB10",
parish: null,
parish: [],
parliamentary_constituency: ["Aberdeen North", "Aberdeen South"],
});
});
Expand All @@ -64,7 +64,7 @@ describe("queries/outcodes (contract)", () => {
it("returns ordered outcodes near the anchor", async () => {
expect(await nearest({ ...ANCHOR, radius: "5000", limit: "5" })).toEqual([
{
admin_county: ["(pseudo) Scotland"],
admin_county: [],
admin_district: ["Aberdeen City"],
admin_ward: [
"George St/Harbour",
Expand All @@ -78,11 +78,11 @@ describe("queries/outcodes (contract)", () => {
longitude: -2.092987414556961,
northings: 805386,
outcode: "AB11",
parish: null,
parish: [],
parliamentary_constituency: ["Aberdeen South"],
},
{
admin_county: ["(pseudo) Scotland"],
admin_county: [],
admin_district: ["Aberdeen City"],
admin_ward: [
"Airyhall/Broomhill/Garthdee",
Expand All @@ -99,11 +99,11 @@ describe("queries/outcodes (contract)", () => {
longitude: -2.1207891580547087,
northings: 804948,
outcode: "AB10",
parish: null,
parish: [],
parliamentary_constituency: ["Aberdeen North", "Aberdeen South"],
},
{
admin_county: ["(pseudo) Scotland"],
admin_county: [],
admin_district: ["Aberdeen City"],
admin_ward: [
"Dyce/Bucksburn/Danestone",
Expand All @@ -119,11 +119,11 @@ describe("queries/outcodes (contract)", () => {
longitude: -2.156713303385415,
northings: 807697,
outcode: "AB16",
parish: null,
parish: [],
parliamentary_constituency: ["Aberdeen North"],
},
{
admin_county: ["(pseudo) Scotland"],
admin_county: [],
admin_district: ["Aberdeen City", "Aberdeenshire"],
admin_ward: [
"Airyhall/Broomhill/Garthdee",
Expand All @@ -141,7 +141,7 @@ describe("queries/outcodes (contract)", () => {
longitude: -2.169419444644466,
northings: 805204,
outcode: "AB15",
parish: null,
parish: [],
parliamentary_constituency: [
"Aberdeen North",
"Aberdeen South",
Expand Down Expand Up @@ -169,7 +169,7 @@ describe("queries/outcodes (contract)", () => {
it("shapes a known outcode row into the public JSON response", async () => {
const row = await find("AB10");
expect(row && toJson(row)).toEqual({
admin_county: ["(pseudo) Scotland"],
admin_county: [],
admin_district: ["Aberdeen City"],
admin_ward: [
"Airyhall/Broomhill/Garthdee",
Expand All @@ -185,7 +185,7 @@ describe("queries/outcodes (contract)", () => {
longitude: -2.1207891580547087,
northings: 804948,
outcode: "AB10",
parish: null,
parish: [],
parliamentary_constituency: ["Aberdeen North", "Aberdeen South"],
});
});
Expand Down
Loading
Loading