From 4b2a4808b603c32d3ed850ae55e3f1e82e4dd5d2 Mon Sep 17 00:00:00 2001 From: William Valentin Date: Wed, 4 Feb 2026 16:44:57 -0800 Subject: [PATCH] feat: add geo points endpoint --- apps/web/app/api/geo/route.ts | 29 ++++++++++++++++++++++++ apps/web/app/api/geo/shape.ts | 19 ++++++++++++++++ apps/web/src/__tests__/geo-route.test.ts | 17 ++++++++++++++ 3 files changed, 65 insertions(+) create mode 100644 apps/web/app/api/geo/route.ts create mode 100644 apps/web/app/api/geo/shape.ts create mode 100644 apps/web/src/__tests__/geo-route.test.ts diff --git a/apps/web/app/api/geo/route.ts b/apps/web/app/api/geo/route.ts new file mode 100644 index 0000000..114023e --- /dev/null +++ b/apps/web/app/api/geo/route.ts @@ -0,0 +1,29 @@ +import { getDb } from "@tline/db"; + +import { shapeGeoRows } from "./shape"; + +export const runtime = "nodejs"; + +export async function GET(): Promise { + const db = getDb(); + + const rows = await db< + { + id: string; + gps_lat: number | null; + gps_lon: number | null; + }[] + >` + select + a.id, + a.gps_lat, + a.gps_lon + from assets a + where a.gps_lat is not null + and a.gps_lon is not null + order by a.capture_ts_utc asc nulls last, a.id asc + limit 1000 + `; + + return Response.json(shapeGeoRows(rows)); +} diff --git a/apps/web/app/api/geo/shape.ts b/apps/web/app/api/geo/shape.ts new file mode 100644 index 0000000..bd2633e --- /dev/null +++ b/apps/web/app/api/geo/shape.ts @@ -0,0 +1,19 @@ +type GeoRow = { + id: string; + gps_lat: number | null; + gps_lon: number | null; +}; + +type GeoPoint = { + id: string; + gps_lat: number | null; + gps_lon: number | null; +}; + +export function shapeGeoRows(rows: GeoRow[]): GeoPoint[] { + return rows.map((row) => ({ + id: row.id, + gps_lat: row.gps_lat, + gps_lon: row.gps_lon, + })); +} diff --git a/apps/web/src/__tests__/geo-route.test.ts b/apps/web/src/__tests__/geo-route.test.ts new file mode 100644 index 0000000..c6d39a8 --- /dev/null +++ b/apps/web/src/__tests__/geo-route.test.ts @@ -0,0 +1,17 @@ +import { test, expect } from "bun:test"; + +test("shapeGeoRows returns id/lat/lon only", async () => { + const { shapeGeoRows } = await import("../../app/api/geo/shape"); + const rows = [ + { + id: "a", + gps_lat: 40.1, + gps_lon: -73.9, + capture_ts_utc: "2026-02-01T00:00:00.000Z", + media_type: "image", + }, + ]; + expect(shapeGeoRows(rows)).toEqual([ + { id: "a", gps_lat: 40.1, gps_lon: -73.9 }, + ]); +});