diff --git a/decode.ts b/decode.ts index 96ddfbe1..2cee0619 100644 --- a/decode.ts +++ b/decode.ts @@ -25,6 +25,8 @@ import { decodePathArray, decodePoint, decodePointArray, + decodePolygon, + decodePolygonArray, decodeStringArray, decodeTid, decodeTidArray, @@ -144,6 +146,10 @@ function decodeText(value: Uint8Array, typeOid: number): any { return decodePoint(strValue); case Oid.point_array: return decodePointArray(strValue); + case Oid.polygon: + return decodePolygon(strValue); + case Oid.polygon_array: + return decodePolygonArray(strValue); case Oid.tid: return decodeTid(strValue); case Oid.tid_array: diff --git a/oid.ts b/oid.ts index 8ba4c902..10916bbc 100644 --- a/oid.ts +++ b/oid.ts @@ -45,8 +45,7 @@ export const Oid = { lseg: 601, path: 602, box: 603, - // deno-lint-ignore camelcase - _polygon_0: 604, + polygon: 604, line: 628, // deno-lint-ignore camelcase line_array: 629, @@ -125,7 +124,7 @@ export const Oid = { // deno-lint-ignore camelcase _tinterval_1: 1025, // deno-lint-ignore camelcase - _polygon_1: 1027, + polygon_array: 1027, // deno-lint-ignore camelcase oid_array: 1028, // deno-lint-ignore camelcase diff --git a/query/decoders.ts b/query/decoders.ts index b56b2e8c..51edbc03 100644 --- a/query/decoders.ts +++ b/query/decoders.ts @@ -1,5 +1,14 @@ import { parseArray } from "./array_parser.ts"; -import { Box, Float8, Line, LineSegment, Path, Point, TID } from "./types.ts"; +import { + Box, + Float8, + Line, + LineSegment, + Path, + Point, + Polygon, + TID, +} from "./types.ts"; // Datetime parsing based on: // https://github.com/bendrucker/postgres-date/blob/master/index.js @@ -251,6 +260,14 @@ export function decodePointArray(value: string) { return parseArray(value, decodePoint); } +export function decodePolygon(value: string): Polygon { + return decodePath(value); +} + +export function decodePolygonArray(value: string) { + return parseArray(value, decodePolygon); +} + export function decodeStringArray(value: string) { if (!value) return null; return parseArray(value); diff --git a/query/types.ts b/query/types.ts index df73a854..a0fc1bbf 100644 --- a/query/types.ts +++ b/query/types.ts @@ -54,6 +54,11 @@ export interface Point { y: Float8; } +/** + * https://www.postgresql.org/docs/13/datatype-geometric.html#DATATYPE-POLYGON + */ +export type Polygon = Point[]; + /** * https://www.postgresql.org/docs/13/datatype-oid.html */ diff --git a/tests/data_types.ts b/tests/data_types.ts index a64ea781..f481a164 100644 --- a/tests/data_types.ts +++ b/tests/data_types.ts @@ -16,6 +16,7 @@ import { LineSegment, Path, Point, + Polygon, TID, Timestamp, } from "../query/types.ts"; @@ -37,6 +38,14 @@ function generateRandomNumber(max_value: number) { return Math.round((Math.random() * max_value + Number.EPSILON) * 100) / 100; } +// deno-lint-ignore camelcase +function generateRandomPoint(max_value = 100): Point { + return { + x: String(generateRandomNumber(max_value)) as Float8, + y: String(generateRandomNumber(max_value)) as Float8, + }; +} + const CLIENT = new Client(TEST_CONNECTION_PARAMS); const testClient = getTestClient(CLIENT, SETUP); @@ -806,37 +815,55 @@ testClient(async function boxArray() { testClient(async function path() { const points = Array.from( { length: Math.floor((Math.random() + 1) * 10) }, - () => { - return [ - String(generateRandomNumber(100)), - String(generateRandomNumber(100)), - ]; - }, + generateRandomPoint, ); const selectRes = await CLIENT.queryArray<[Path]>( - `SELECT '(${points.map(([x, y]) => `(${x},${y})`).join(",")})'::PATH`, + `SELECT '(${points.map(({ x, y }) => `(${x},${y})`).join(",")})'::PATH`, ); - assertEquals(selectRes.rows[0][0], points.map(([x, y]) => ({ x, y }))); + assertEquals(selectRes.rows[0][0], points); }); testClient(async function pathArray() { const points = Array.from( { length: Math.floor((Math.random() + 1) * 10) }, - () => { - return [ - String(generateRandomNumber(100)), - String(generateRandomNumber(100)), - ]; - }, + generateRandomPoint, ); const selectRes = await CLIENT.queryArray<[[Path]]>( `SELECT ARRAY['(${ - points.map(([x, y]) => `(${x},${y})`).join(",") + points.map(({ x, y }) => `(${x},${y})`).join(",") })'::PATH]`, ); - assertEquals(selectRes.rows[0][0][0], points.map(([x, y]) => ({ x, y }))); + assertEquals(selectRes.rows[0][0][0], points); +}); + +testClient(async function polygon() { + const points = Array.from( + { length: Math.floor((Math.random() + 1) * 10) }, + generateRandomPoint, + ); + + const selectRes = await CLIENT.queryArray<[Polygon]>( + `SELECT '(${points.map(({ x, y }) => `(${x},${y})`).join(",")})'::POLYGON`, + ); + + assertEquals(selectRes.rows[0][0], points); +}); + +testClient(async function polygonArray() { + const points = Array.from( + { length: Math.floor((Math.random() + 1) * 10) }, + generateRandomPoint, + ); + + const selectRes = await CLIENT.queryArray<[[Polygon]]>( + `SELECT ARRAY['(${ + points.map(({ x, y }) => `(${x},${y})`).join(",") + })'::POLYGON]`, + ); + + assertEquals(selectRes.rows[0][0][0], points); });