From 2e3d9cf33ff31219dced08fe9e57552298dfcd08 Mon Sep 17 00:00:00 2001 From: Nicolas Guerrero Date: Sun, 31 Jan 2021 05:31:03 -0500 Subject: [PATCH 1/2] feat: Add support for polygon and polygon array --- decode.ts | 6 ++++++ oid.ts | 5 ++--- query/decoders.ts | 19 ++++++++++++++++++- query/types.ts | 5 +++++ tests/data_types.ts | 39 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 70 insertions(+), 4 deletions(-) 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..b887ebb6 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"; @@ -840,3 +841,41 @@ testClient(async function pathArray() { assertEquals(selectRes.rows[0][0][0], points.map(([x, y]) => ({ x, y }))); }); + +testClient(async function polygon() { + const points = Array.from( + { length: Math.floor((Math.random() + 1) * 10) }, + () => { + return [ + String(generateRandomNumber(100)), + String(generateRandomNumber(100)), + ]; + }, + ); + + const selectRes = await CLIENT.queryArray<[Polygon]>( + `SELECT '(${points.map(([x, y]) => `(${x},${y})`).join(",")})'::POLYGON`, + ); + + assertEquals(selectRes.rows[0][0], points.map(([x, y]) => ({ x, y }))); +}); + +testClient(async function polygonArray() { + const points = Array.from( + { length: Math.floor((Math.random() + 1) * 10) }, + () => { + return [ + String(generateRandomNumber(100)), + String(generateRandomNumber(100)), + ]; + }, + ); + + const selectRes = await CLIENT.queryArray<[[Polygon]]>( + `SELECT ARRAY['(${ + points.map(([x, y]) => `(${x},${y})`).join(",") + })'::POLYGON]`, + ); + + assertEquals(selectRes.rows[0][0][0], points.map(([x, y]) => ({ x, y }))); +}); From 2655e141ae80e5f684eba31010ff2ee7c8520822 Mon Sep 17 00:00:00 2001 From: Nicolas Guerrero Date: Sun, 31 Jan 2021 05:40:15 -0500 Subject: [PATCH 2/2] Simplify the tests --- tests/data_types.ts | 52 +++++++++++++++++---------------------------- 1 file changed, 20 insertions(+), 32 deletions(-) diff --git a/tests/data_types.ts b/tests/data_types.ts index b887ebb6..f481a164 100644 --- a/tests/data_types.ts +++ b/tests/data_types.ts @@ -38,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); @@ -807,75 +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) }, - () => { - return [ - String(generateRandomNumber(100)), - String(generateRandomNumber(100)), - ]; - }, + generateRandomPoint, ); const selectRes = await CLIENT.queryArray<[Polygon]>( - `SELECT '(${points.map(([x, y]) => `(${x},${y})`).join(",")})'::POLYGON`, + `SELECT '(${points.map(({ x, y }) => `(${x},${y})`).join(",")})'::POLYGON`, ); - assertEquals(selectRes.rows[0][0], points.map(([x, y]) => ({ x, y }))); + assertEquals(selectRes.rows[0][0], points); }); testClient(async function polygonArray() { const points = Array.from( { length: Math.floor((Math.random() + 1) * 10) }, - () => { - return [ - String(generateRandomNumber(100)), - String(generateRandomNumber(100)), - ]; - }, + generateRandomPoint, ); const selectRes = await CLIENT.queryArray<[[Polygon]]>( `SELECT ARRAY['(${ - points.map(([x, y]) => `(${x},${y})`).join(",") + points.map(({ x, y }) => `(${x},${y})`).join(",") })'::POLYGON]`, ); - assertEquals(selectRes.rows[0][0][0], points.map(([x, y]) => ({ x, y }))); + assertEquals(selectRes.rows[0][0][0], points); });