Skip to main content

Geometric Types

point, circle, box, lseg, line, path and polygon each decode to their own class (Point, Circle, Box, LineSegment, Line, Path and Polygon) instead of a plain object. Every one of them has a toString()/toPostgres() that prints exactly what PostgreSQL prints, so casting the value back through its own type (::point, ::box, ...) round-trips, and a toJSON() that gives its fields: JSON.stringify(point) gives {"x":1,"y":2}, and String(point) is what gives "(1,2)".

import { Connection } from 'postgrejs';

const connection = new Connection('postgres://localhost');
await connection.connect();

const r = await connection.query("select point(1,2) as p, box(point(0,0),point(1,1)) as b");
r.rows[0][0]; // Point { x: 1, y: 2 }
r.rows[0][1]; // Box { x1: 1, y1: 1, x2: 0, y2: 0 }

Box and LineSegment exist as separate classes, not one shared {x1,y1,x2,y2} shape, because a plain object of those four numbers is otherwise indistinguishable between the two types; the same is true of Path and Polygon over a list of points. A plain object matching a type's own shape ({x,y} for Point, {x,y,radius} or {x,y,r} for Circle, {x1,y1,x2,y2} for Box/LineSegment, {a,b,c} for Line) is still accepted as a parameter, for code that built one before these classes existed, but only for Point/Circle/Line, since Box and LineSegment share a shape and only the class says which one is meant.

Point​

KeyTypeDescription
xnumber
ynumber

new Point(x?, y?), both defaulting to 0.

Circle​

KeyTypeDescription
xnumberCenter
ynumberCenter
radiusnumberRadius (pg's own spelling)

new Circle(x?, y?, radius?), all defaulting to 0. r is still there as an accessor onto the same number (this class's own name for the radius before v3.10), but radius is the actual property: it's what Object.keys()/JSON.stringify() report, and what a plain-object parameter can spell either way.

Box​

A rectangle given by two opposite corners. PostgreSQL normalizes the corners to upper-right/ lower-left on the way in, so box(point(0,0), point(1,1)) decodes as x1: 1, y1: 1, x2: 0, y2: 0. That reordering is the server's, not something this class does.

KeyTypeDescription
x1, y1numberOne corner
x2, y2numberThe opposite corner

new Box(x1?, y1?, x2?, y2?), all defaulting to 0.

LineSegment​

The straight line between two points. It has the same shape as Box and is kept separate for the reason above.

KeyTypeDescription
x1, y1numberOne endpoint
x2, y2numberThe other endpoint

new LineSegment(x1?, y1?, x2?, y2?), all defaulting to 0.

Line​

The infinite line Ax + By + C = 0, carried as its three coefficients. A pair of points would be a second, lossy spelling of the same line, so PostgreSQL stores and prints the coefficients directly and this class does too.

KeyTypeDescription
a, b, cnumberCoefficients of Ax + By + C = 0

new Line(a?, b?, c?), all defaulting to 0.

Path and Polygon​

Both hold a list of Points (plain {x,y} objects are accepted in the constructor and kept as Points). Path.isClosed tracks whether the path is open ([...], printed with square brackets) or closed ((...), the default; a literal with no brackets, path '1,2,3,4', comes back closed). A Polygon is always closed.

KeyTypeDescription
pointsPoint[]
isClosedbooleanPath only

new Path(points?, isClosed?) — points defaults to [], isClosed to true. new Polygon(points?).

import { Path } from 'postgrejs';

await connection.query('select $1::path as p', {
params: [new Path([{ x: 1, y: 1 }, { x: 2, y: 2 }], false)], // open path
});

A plain array of points is not accepted for Path/Polygon parameters: determine() reads an array as a point[] array parameter, so a Path/Polygon has to be constructed explicitly to be told apart from one.

See Data Types & Type Mapping for the full guide.