graphile-postgis 1.1.1 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -45
- package/constants.d.ts +1 -0
- package/constants.js +10 -1
- package/esm/constants.d.ts +13 -0
- package/esm/constants.js +9 -0
- package/esm/index.d.ts +24 -0
- package/esm/index.js +25 -33
- package/esm/plugins/codec.d.ts +19 -0
- package/esm/plugins/codec.js +174 -0
- package/esm/plugins/detect-extension.d.ts +14 -0
- package/esm/plugins/detect-extension.js +57 -0
- package/esm/plugins/geometry-fields.d.ts +21 -0
- package/esm/plugins/geometry-fields.js +245 -0
- package/esm/plugins/inflection.d.ts +8 -0
- package/esm/plugins/inflection.js +52 -0
- package/esm/plugins/register-types.d.ts +22 -0
- package/esm/plugins/register-types.js +319 -0
- package/esm/preset.d.ts +18 -0
- package/esm/preset.js +30 -0
- package/esm/types.d.ts +84 -0
- package/esm/utils.d.ts +21 -0
- package/esm/utils.js +18 -7
- package/index.d.ts +24 -15
- package/index.js +39 -47
- package/package.json +23 -18
- package/plugins/codec.d.ts +19 -0
- package/plugins/codec.js +180 -0
- package/plugins/detect-extension.d.ts +14 -0
- package/plugins/detect-extension.js +60 -0
- package/plugins/geometry-fields.d.ts +21 -0
- package/plugins/geometry-fields.js +248 -0
- package/plugins/inflection.d.ts +8 -0
- package/plugins/inflection.js +55 -0
- package/plugins/register-types.d.ts +22 -0
- package/plugins/register-types.js +325 -0
- package/preset.d.ts +18 -0
- package/preset.js +33 -0
- package/types.d.ts +69 -44
- package/utils.d.ts +16 -0
- package/utils.js +17 -6
- package/PostgisExtensionDetectionPlugin.d.ts +0 -3
- package/PostgisExtensionDetectionPlugin.js +0 -28
- package/PostgisInflectionPlugin.d.ts +0 -3
- package/PostgisInflectionPlugin.js +0 -36
- package/PostgisRegisterTypesPlugin.d.ts +0 -3
- package/PostgisRegisterTypesPlugin.js +0 -234
- package/PostgisVersionPlugin.d.ts +0 -3
- package/PostgisVersionPlugin.js +0 -24
- package/Postgis_GeometryCollection_GeometriesPlugin.d.ts +0 -3
- package/Postgis_GeometryCollection_GeometriesPlugin.js +0 -43
- package/Postgis_LineString_PointsPlugin.d.ts +0 -3
- package/Postgis_LineString_PointsPlugin.js +0 -40
- package/Postgis_MultiLineString_LineStringsPlugin.d.ts +0 -3
- package/Postgis_MultiLineString_LineStringsPlugin.js +0 -38
- package/Postgis_MultiPoint_PointsPlugin.d.ts +0 -3
- package/Postgis_MultiPoint_PointsPlugin.js +0 -38
- package/Postgis_MultiPolygon_PolygonsPlugin.d.ts +0 -3
- package/Postgis_MultiPolygon_PolygonsPlugin.js +0 -38
- package/Postgis_Point_LatitudeLongitudePlugin.d.ts +0 -3
- package/Postgis_Point_LatitudeLongitudePlugin.js +0 -43
- package/Postgis_Polygon_RingsPlugin.d.ts +0 -3
- package/Postgis_Polygon_RingsPlugin.js +0 -49
- package/esm/PostgisExtensionDetectionPlugin.js +0 -26
- package/esm/PostgisInflectionPlugin.js +0 -34
- package/esm/PostgisRegisterTypesPlugin.js +0 -229
- package/esm/PostgisVersionPlugin.js +0 -22
- package/esm/Postgis_GeometryCollection_GeometriesPlugin.js +0 -41
- package/esm/Postgis_LineString_PointsPlugin.js +0 -38
- package/esm/Postgis_MultiLineString_LineStringsPlugin.js +0 -36
- package/esm/Postgis_MultiPoint_PointsPlugin.js +0 -36
- package/esm/Postgis_MultiPolygon_PolygonsPlugin.js +0 -36
- package/esm/Postgis_Point_LatitudeLongitudePlugin.js +0 -41
- package/esm/Postgis_Polygon_RingsPlugin.js +0 -47
- package/esm/makeGeoJSONType.js +0 -39
- package/makeGeoJSONType.d.ts +0 -1
- package/makeGeoJSONType.js +0 -42
package/README.md
CHANGED
|
@@ -1,61 +1,38 @@
|
|
|
1
1
|
# graphile-postgis
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
<img height="250" src="https://raw.githubusercontent.com/constructive-io/constructive/refs/heads/main/assets/outline-logo.svg" />
|
|
5
|
-
</p>
|
|
6
|
-
|
|
7
|
-
<p align="center" width="100%">
|
|
8
|
-
<a href="https://github.com/constructive-io/constructive/actions/workflows/run-tests.yaml">
|
|
9
|
-
<img height="20" src="https://github.com/constructive-io/constructive/actions/workflows/run-tests.yaml/badge.svg" />
|
|
10
|
-
</a>
|
|
11
|
-
<a href="https://github.com/constructive-io/constructive/blob/main/LICENSE">
|
|
12
|
-
<img height="20" src="https://img.shields.io/badge/license-MIT-blue.svg"/>
|
|
13
|
-
</a>
|
|
14
|
-
<a href="https://www.npmjs.com/package/graphile-postgis">
|
|
15
|
-
<img height="20" src="https://img.shields.io/github/package-json/v/constructive-io/constructive?filename=graphile%2Fgraphile-postgis%2Fpackage.json"/>
|
|
16
|
-
</a>
|
|
17
|
-
</p>
|
|
18
|
-
|
|
19
|
-
**`graphile-postgis`** registers GeoJSON scalars, PostGIS geometry/geography GraphQL types, and convenience fields for common spatial columns in PostGraphile/Graphile schemas.
|
|
20
|
-
|
|
21
|
-
## 🚀 Installation
|
|
22
|
-
|
|
23
|
-
```sh
|
|
24
|
-
pnpm add graphile-postgis
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
## ✨ Features
|
|
3
|
+
PostGIS support for PostGraphile v5.
|
|
28
4
|
|
|
29
|
-
|
|
30
|
-
- Convenience fields for common spatial column types
|
|
31
|
-
- Works with PostGraphile CLI or library usage
|
|
5
|
+
Automatically generates GraphQL types for PostGIS geometry and geography columns, including GeoJSON scalar types, dimension-aware interfaces, and subtype-specific fields (coordinates, points, rings, etc.).
|
|
32
6
|
|
|
33
|
-
##
|
|
7
|
+
## Installation
|
|
34
8
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
```sh
|
|
38
|
-
postgraphile --append-plugins graphile-postgis
|
|
9
|
+
```bash
|
|
10
|
+
npm install graphile-postgis
|
|
39
11
|
```
|
|
40
12
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
### Library
|
|
13
|
+
## Usage
|
|
44
14
|
|
|
45
|
-
```
|
|
46
|
-
import
|
|
15
|
+
```typescript
|
|
16
|
+
import { GraphilePostgisPreset } from 'graphile-postgis';
|
|
47
17
|
|
|
48
|
-
const
|
|
49
|
-
|
|
18
|
+
const preset = {
|
|
19
|
+
extends: [GraphilePostgisPreset]
|
|
50
20
|
};
|
|
51
21
|
```
|
|
52
22
|
|
|
53
|
-
##
|
|
23
|
+
## Features
|
|
54
24
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
25
|
+
- GeoJSON scalar type for input/output
|
|
26
|
+
- GraphQL interfaces for geometry and geography base types
|
|
27
|
+
- Dimension-aware interfaces (XY, XYZ, XYM, XYZM)
|
|
28
|
+
- Concrete types for all geometry subtypes: Point, LineString, Polygon, MultiPoint, MultiLineString, MultiPolygon, GeometryCollection
|
|
29
|
+
- Subtype-specific fields (x/y/z for Points, points for LineStrings, exterior/interiors for Polygons, etc.)
|
|
30
|
+
- Geography-aware field naming (longitude/latitude/height instead of x/y/z)
|
|
31
|
+
- Graceful degradation when PostGIS is not installed
|
|
32
|
+
|
|
33
|
+
## License
|
|
34
|
+
|
|
35
|
+
MIT
|
|
59
36
|
|
|
60
37
|
---
|
|
61
38
|
|
package/constants.d.ts
CHANGED
package/constants.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.GIS_SUBTYPE_NAME = exports.SUBTYPE_STRING_BY_SUBTYPE = exports.GisSubtype = void 0;
|
|
3
|
+
exports.CONCRETE_SUBTYPES = exports.GIS_SUBTYPE_NAME = exports.SUBTYPE_STRING_BY_SUBTYPE = exports.GisSubtype = void 0;
|
|
4
4
|
var GisSubtype;
|
|
5
5
|
(function (GisSubtype) {
|
|
6
6
|
GisSubtype[GisSubtype["Geometry"] = 0] = "Geometry";
|
|
@@ -32,3 +32,12 @@ exports.GIS_SUBTYPE_NAME = {
|
|
|
32
32
|
[GisSubtype.MultiPolygon]: 'MultiPolygon',
|
|
33
33
|
[GisSubtype.GeometryCollection]: 'GeometryCollection'
|
|
34
34
|
};
|
|
35
|
+
exports.CONCRETE_SUBTYPES = [
|
|
36
|
+
GisSubtype.Point,
|
|
37
|
+
GisSubtype.LineString,
|
|
38
|
+
GisSubtype.Polygon,
|
|
39
|
+
GisSubtype.MultiPoint,
|
|
40
|
+
GisSubtype.MultiLineString,
|
|
41
|
+
GisSubtype.MultiPolygon,
|
|
42
|
+
GisSubtype.GeometryCollection
|
|
43
|
+
];
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare enum GisSubtype {
|
|
2
|
+
Geometry = 0,
|
|
3
|
+
Point = 1,
|
|
4
|
+
LineString = 2,
|
|
5
|
+
Polygon = 3,
|
|
6
|
+
MultiPoint = 4,
|
|
7
|
+
MultiLineString = 5,
|
|
8
|
+
MultiPolygon = 6,
|
|
9
|
+
GeometryCollection = 7
|
|
10
|
+
}
|
|
11
|
+
export declare const SUBTYPE_STRING_BY_SUBTYPE: Record<GisSubtype, string>;
|
|
12
|
+
export declare const GIS_SUBTYPE_NAME: Record<GisSubtype, string>;
|
|
13
|
+
export declare const CONCRETE_SUBTYPES: GisSubtype[];
|
package/esm/constants.js
CHANGED
|
@@ -29,3 +29,12 @@ export const GIS_SUBTYPE_NAME = {
|
|
|
29
29
|
[GisSubtype.MultiPolygon]: 'MultiPolygon',
|
|
30
30
|
[GisSubtype.GeometryCollection]: 'GeometryCollection'
|
|
31
31
|
};
|
|
32
|
+
export const CONCRETE_SUBTYPES = [
|
|
33
|
+
GisSubtype.Point,
|
|
34
|
+
GisSubtype.LineString,
|
|
35
|
+
GisSubtype.Polygon,
|
|
36
|
+
GisSubtype.MultiPoint,
|
|
37
|
+
GisSubtype.MultiLineString,
|
|
38
|
+
GisSubtype.MultiPolygon,
|
|
39
|
+
GisSubtype.GeometryCollection
|
|
40
|
+
];
|
package/esm/index.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PostGraphile v5 PostGIS Plugin
|
|
3
|
+
*
|
|
4
|
+
* Provides PostGIS geometry/geography type support for PostGraphile v5.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* import { GraphilePostgisPreset } from 'graphile-postgis';
|
|
9
|
+
*
|
|
10
|
+
* const preset = {
|
|
11
|
+
* extends: [GraphilePostgisPreset]
|
|
12
|
+
* };
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export { GraphilePostgisPreset } from './preset';
|
|
16
|
+
export { PostgisCodecPlugin } from './plugins/codec';
|
|
17
|
+
export { PostgisInflectionPlugin } from './plugins/inflection';
|
|
18
|
+
export { PostgisExtensionDetectionPlugin } from './plugins/detect-extension';
|
|
19
|
+
export { PostgisRegisterTypesPlugin } from './plugins/register-types';
|
|
20
|
+
export { PostgisGeometryFieldsPlugin } from './plugins/geometry-fields';
|
|
21
|
+
export { GisSubtype, SUBTYPE_STRING_BY_SUBTYPE, GIS_SUBTYPE_NAME, CONCRETE_SUBTYPES } from './constants';
|
|
22
|
+
export { getGISTypeDetails, getGISTypeModifier, getGISTypeName } from './utils';
|
|
23
|
+
export type { GisTypeDetails, GisFieldValue } from './types';
|
|
24
|
+
export type { PostgisExtensionInfo } from './plugins/detect-extension';
|
package/esm/index.js
CHANGED
|
@@ -1,33 +1,25 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
import
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
await Postgis_MultiLineString_LineStringsPlugin(builder, options);
|
|
27
|
-
// Enhancing the `MultiPolygon` type:
|
|
28
|
-
await Postgis_MultiPolygon_PolygonsPlugin(builder, options);
|
|
29
|
-
// Enhancing the `GeometryCollection` type:
|
|
30
|
-
await Postgis_GeometryCollection_GeometriesPlugin(builder, options);
|
|
31
|
-
};
|
|
32
|
-
export { PostgisExtensionDetectionPlugin, PostgisInflectionPlugin, PostgisRegisterTypesPlugin, PostgisVersionPlugin, Postgis_GeometryCollection_GeometriesPlugin, Postgis_LineString_PointsPlugin, Postgis_MultiLineString_LineStringsPlugin, Postgis_MultiPoint_PointsPlugin, Postgis_MultiPolygon_PolygonsPlugin, Postgis_Point_LatitudeLongitudePlugin, Postgis_Polygon_RingsPlugin };
|
|
33
|
-
export default PostgisPlugin;
|
|
1
|
+
/**
|
|
2
|
+
* PostGraphile v5 PostGIS Plugin
|
|
3
|
+
*
|
|
4
|
+
* Provides PostGIS geometry/geography type support for PostGraphile v5.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* import { GraphilePostgisPreset } from 'graphile-postgis';
|
|
9
|
+
*
|
|
10
|
+
* const preset = {
|
|
11
|
+
* extends: [GraphilePostgisPreset]
|
|
12
|
+
* };
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
// Preset (recommended entry point)
|
|
16
|
+
export { GraphilePostgisPreset } from './preset';
|
|
17
|
+
// Individual plugins
|
|
18
|
+
export { PostgisCodecPlugin } from './plugins/codec';
|
|
19
|
+
export { PostgisInflectionPlugin } from './plugins/inflection';
|
|
20
|
+
export { PostgisExtensionDetectionPlugin } from './plugins/detect-extension';
|
|
21
|
+
export { PostgisRegisterTypesPlugin } from './plugins/register-types';
|
|
22
|
+
export { PostgisGeometryFieldsPlugin } from './plugins/geometry-fields';
|
|
23
|
+
// Constants and utilities
|
|
24
|
+
export { GisSubtype, SUBTYPE_STRING_BY_SUBTYPE, GIS_SUBTYPE_NAME, CONCRETE_SUBTYPES } from './constants';
|
|
25
|
+
export { getGISTypeDetails, getGISTypeModifier, getGISTypeName } from './utils';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import 'graphile-build-pg';
|
|
2
|
+
import type { GraphileConfig } from 'graphile-config';
|
|
3
|
+
/**
|
|
4
|
+
* PostgisCodecPlugin
|
|
5
|
+
*
|
|
6
|
+
* Teaches PostGraphile v5 how to handle PostgreSQL's geometry and geography types.
|
|
7
|
+
*
|
|
8
|
+
* This plugin:
|
|
9
|
+
* 1. Creates codecs for geometry/geography via gather.hooks.pgCodecs_findPgCodec
|
|
10
|
+
* 2. The registered codecs use castFromPg to wrap geometry values in
|
|
11
|
+
* json_build_object() with __gisType, __srid, __geojson metadata
|
|
12
|
+
* 3. fromPg normalizes the geometry type names for resolveType lookups
|
|
13
|
+
*
|
|
14
|
+
* Without castFromPg, PostGraphile defaults to `column::text` which returns
|
|
15
|
+
* WKB hex — unusable for GraphQL. The json_build_object wrapper provides
|
|
16
|
+
* structured metadata that downstream plugins use for type resolution and
|
|
17
|
+
* field values (x/y coordinates, GeoJSON, SRID, etc.).
|
|
18
|
+
*/
|
|
19
|
+
export declare const PostgisCodecPlugin: GraphileConfig.Plugin;
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import 'graphile-build-pg';
|
|
2
|
+
import sql from 'pg-sql2';
|
|
3
|
+
/**
|
|
4
|
+
* Map from PostGIS uppercase geometry type names (from geometrytype()) to
|
|
5
|
+
* our mixed-case format used by resolveType lookups.
|
|
6
|
+
*
|
|
7
|
+
* PostGIS `geometrytype()` returns uppercase: 'POINT', 'POINTZ', 'MULTIPOLYGON', etc.
|
|
8
|
+
* Our GIS_SUBTYPE_NAME uses mixed case: 'Point', 'LineString', 'MultiPolygon', etc.
|
|
9
|
+
* The getGISTypeName() utility produces: 'Point', 'PointZ', 'MultiPolygonZM', etc.
|
|
10
|
+
*/
|
|
11
|
+
const GIS_TYPE_NORMALIZE = {
|
|
12
|
+
POINT: 'Point',
|
|
13
|
+
POINTZ: 'PointZ',
|
|
14
|
+
POINTM: 'PointM',
|
|
15
|
+
POINTZM: 'PointZM',
|
|
16
|
+
LINESTRING: 'LineString',
|
|
17
|
+
LINESTRINGZ: 'LineStringZ',
|
|
18
|
+
LINESTRINGM: 'LineStringM',
|
|
19
|
+
LINESTRINGZM: 'LineStringZM',
|
|
20
|
+
POLYGON: 'Polygon',
|
|
21
|
+
POLYGONZ: 'PolygonZ',
|
|
22
|
+
POLYGONM: 'PolygonM',
|
|
23
|
+
POLYGONZM: 'PolygonZM',
|
|
24
|
+
MULTIPOINT: 'MultiPoint',
|
|
25
|
+
MULTIPOINTZ: 'MultiPointZ',
|
|
26
|
+
MULTIPOINTM: 'MultiPointM',
|
|
27
|
+
MULTIPOINTZM: 'MultiPointZM',
|
|
28
|
+
MULTILINESTRING: 'MultiLineString',
|
|
29
|
+
MULTILINESTRINGZ: 'MultiLineStringZ',
|
|
30
|
+
MULTILINESTRINGM: 'MultiLineStringM',
|
|
31
|
+
MULTILINESTRINGZM: 'MultiLineStringZM',
|
|
32
|
+
MULTIPOLYGON: 'MultiPolygon',
|
|
33
|
+
MULTIPOLYGONZ: 'MultiPolygonZ',
|
|
34
|
+
MULTIPOLYGONM: 'MultiPolygonM',
|
|
35
|
+
MULTIPOLYGONZM: 'MultiPolygonZM',
|
|
36
|
+
GEOMETRYCOLLECTION: 'GeometryCollection',
|
|
37
|
+
GEOMETRYCOLLECTIONZ: 'GeometryCollectionZ',
|
|
38
|
+
GEOMETRYCOLLECTIONM: 'GeometryCollectionM',
|
|
39
|
+
GEOMETRYCOLLECTIONZM: 'GeometryCollectionZM'
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Normalize the __gisType from PostGIS uppercase to our mixed-case format.
|
|
43
|
+
* Falls back to the raw value if not in the map.
|
|
44
|
+
*/
|
|
45
|
+
function normalizeGisType(raw) {
|
|
46
|
+
return GIS_TYPE_NORMALIZE[raw] ?? raw;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Build a codec for a PostGIS geometry or geography type.
|
|
50
|
+
*
|
|
51
|
+
* The codec:
|
|
52
|
+
* - castFromPg: wraps the SQL column in json_build_object() with __gisType,
|
|
53
|
+
* __srid, and __geojson fields (using PostGIS functions ST_SRID, ST_AsGeoJSON,
|
|
54
|
+
* geometrytype). This replaces the default ::text cast.
|
|
55
|
+
* - fromPg: parses the JSON text result and normalizes __gisType case.
|
|
56
|
+
* - toPg: converts GeoJSON input back to a PostGIS-compatible value using
|
|
57
|
+
* ST_GeomFromGeoJSON.
|
|
58
|
+
*/
|
|
59
|
+
function buildGisCodec(typeName, schemaName, typeOid, serviceName) {
|
|
60
|
+
return {
|
|
61
|
+
name: typeName,
|
|
62
|
+
sqlType: sql.identifier(schemaName, typeName),
|
|
63
|
+
/**
|
|
64
|
+
* castFromPg replaces the default `::text` cast. PostGraphile calls this
|
|
65
|
+
* to determine the SQL expression for selecting the column value.
|
|
66
|
+
*
|
|
67
|
+
* We wrap in json_build_object() so the result contains:
|
|
68
|
+
* - __gisType: geometry subtype name (e.g. "POINT", "POLYGON")
|
|
69
|
+
* - __srid: spatial reference ID
|
|
70
|
+
* - __geojson: the GeoJSON representation
|
|
71
|
+
*
|
|
72
|
+
* The result is cast to ::text so PostgreSQL sends it as a string,
|
|
73
|
+
* which fromPg then JSON.parses.
|
|
74
|
+
*/
|
|
75
|
+
// NOTE: `fragment` is evaluated 4 times in the SQL. This is acceptable because
|
|
76
|
+
// PostGraphile v5 always passes simple column references here.
|
|
77
|
+
// If this changes, consider wrapping in a LATERAL subexpression.
|
|
78
|
+
castFromPg(fragment) {
|
|
79
|
+
return sql.fragment `(case when (${fragment}) is null then null else json_build_object(
|
|
80
|
+
'__gisType', ${sql.identifier(schemaName, 'geometrytype')}(${fragment}),
|
|
81
|
+
'__srid', ${sql.identifier(schemaName, 'st_srid')}(${fragment}),
|
|
82
|
+
'__geojson', ${sql.identifier(schemaName, 'st_asgeojson')}(${fragment})::json
|
|
83
|
+
)::text end)`;
|
|
84
|
+
},
|
|
85
|
+
/**
|
|
86
|
+
* fromPg receives the text value from PostgreSQL (output of castFromPg)
|
|
87
|
+
* and converts it to a JavaScript object.
|
|
88
|
+
*
|
|
89
|
+
* If castFromPg is working correctly, the value is always valid JSON.
|
|
90
|
+
* We normalize __gisType from PostGIS uppercase to our mixed-case format.
|
|
91
|
+
*/
|
|
92
|
+
fromPg(value) {
|
|
93
|
+
let parsed;
|
|
94
|
+
try {
|
|
95
|
+
parsed = JSON.parse(value);
|
|
96
|
+
}
|
|
97
|
+
catch (e) {
|
|
98
|
+
throw new Error(`Failed to parse PostGIS geometry value: ${e instanceof Error ? e.message : String(e)}. ` +
|
|
99
|
+
`Raw value (first 200 chars): ${String(value).slice(0, 200)}`);
|
|
100
|
+
}
|
|
101
|
+
if (parsed && typeof parsed === 'object' && parsed.__gisType) {
|
|
102
|
+
parsed.__gisType = normalizeGisType(parsed.__gisType);
|
|
103
|
+
}
|
|
104
|
+
return parsed;
|
|
105
|
+
},
|
|
106
|
+
/**
|
|
107
|
+
* toPg serializes a JavaScript value for insertion into PostgreSQL.
|
|
108
|
+
* Accepts GeoJSON objects and converts them to a JSON string that
|
|
109
|
+
* PostgreSQL can process via ST_GeomFromGeoJSON.
|
|
110
|
+
*/
|
|
111
|
+
toPg(value) {
|
|
112
|
+
if (value && typeof value === 'object' && '__geojson' in value) {
|
|
113
|
+
return JSON.stringify(value.__geojson);
|
|
114
|
+
}
|
|
115
|
+
return JSON.stringify(value);
|
|
116
|
+
},
|
|
117
|
+
attributes: undefined,
|
|
118
|
+
executor: undefined,
|
|
119
|
+
extensions: {
|
|
120
|
+
oid: typeOid,
|
|
121
|
+
pg: {
|
|
122
|
+
serviceName,
|
|
123
|
+
schemaName,
|
|
124
|
+
name: typeName
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* PostgisCodecPlugin
|
|
131
|
+
*
|
|
132
|
+
* Teaches PostGraphile v5 how to handle PostgreSQL's geometry and geography types.
|
|
133
|
+
*
|
|
134
|
+
* This plugin:
|
|
135
|
+
* 1. Creates codecs for geometry/geography via gather.hooks.pgCodecs_findPgCodec
|
|
136
|
+
* 2. The registered codecs use castFromPg to wrap geometry values in
|
|
137
|
+
* json_build_object() with __gisType, __srid, __geojson metadata
|
|
138
|
+
* 3. fromPg normalizes the geometry type names for resolveType lookups
|
|
139
|
+
*
|
|
140
|
+
* Without castFromPg, PostGraphile defaults to `column::text` which returns
|
|
141
|
+
* WKB hex — unusable for GraphQL. The json_build_object wrapper provides
|
|
142
|
+
* structured metadata that downstream plugins use for type resolution and
|
|
143
|
+
* field values (x/y coordinates, GeoJSON, SRID, etc.).
|
|
144
|
+
*/
|
|
145
|
+
export const PostgisCodecPlugin = {
|
|
146
|
+
name: 'PostgisCodecPlugin',
|
|
147
|
+
version: '2.0.0',
|
|
148
|
+
description: 'Registers codecs for PostGIS geometry and geography types',
|
|
149
|
+
gather: {
|
|
150
|
+
hooks: {
|
|
151
|
+
async pgCodecs_findPgCodec(info, event) {
|
|
152
|
+
if (event.pgCodec) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
const { pgType: type, serviceName } = event;
|
|
156
|
+
// Find the namespace for this type by its OID
|
|
157
|
+
const typeNamespace = await info.helpers.pgIntrospection.getNamespace(serviceName, type.typnamespace);
|
|
158
|
+
if (!typeNamespace) {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
// We look for geometry/geography types in any schema (PostGIS can be
|
|
162
|
+
// installed in different schemas, commonly 'public' or 'postgis')
|
|
163
|
+
if (type.typname === 'geometry') {
|
|
164
|
+
event.pgCodec = buildGisCodec('geometry', typeNamespace.nspname, type._id, serviceName);
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
if (type.typname === 'geography') {
|
|
168
|
+
event.pgCodec = buildGisCodec('geography', typeNamespace.nspname, type._id, serviceName);
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import 'graphile-build';
|
|
2
|
+
import 'graphile-build-pg';
|
|
3
|
+
import type { GraphileConfig } from 'graphile-config';
|
|
4
|
+
export type { PostgisExtensionInfo } from '../types';
|
|
5
|
+
/**
|
|
6
|
+
* PostgisExtensionDetectionPlugin
|
|
7
|
+
*
|
|
8
|
+
* Detects PostGIS presence in the database by searching for geometry/geography
|
|
9
|
+
* codecs in the pgRegistry. Stores detected info on the build object for
|
|
10
|
+
* downstream plugins.
|
|
11
|
+
*
|
|
12
|
+
* Gracefully degrades if PostGIS is not installed.
|
|
13
|
+
*/
|
|
14
|
+
export declare const PostgisExtensionDetectionPlugin: GraphileConfig.Plugin;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import 'graphile-build';
|
|
2
|
+
import 'graphile-build-pg';
|
|
3
|
+
/**
|
|
4
|
+
* PostgisExtensionDetectionPlugin
|
|
5
|
+
*
|
|
6
|
+
* Detects PostGIS presence in the database by searching for geometry/geography
|
|
7
|
+
* codecs in the pgRegistry. Stores detected info on the build object for
|
|
8
|
+
* downstream plugins.
|
|
9
|
+
*
|
|
10
|
+
* Gracefully degrades if PostGIS is not installed.
|
|
11
|
+
*/
|
|
12
|
+
export const PostgisExtensionDetectionPlugin = {
|
|
13
|
+
name: 'PostgisExtensionDetectionPlugin',
|
|
14
|
+
version: '2.0.0',
|
|
15
|
+
description: 'Detects PostGIS extension in the database',
|
|
16
|
+
schema: {
|
|
17
|
+
hooks: {
|
|
18
|
+
build(build) {
|
|
19
|
+
const pgRegistry = build.input?.pgRegistry;
|
|
20
|
+
if (!pgRegistry) {
|
|
21
|
+
return build;
|
|
22
|
+
}
|
|
23
|
+
let geometryCodec = null;
|
|
24
|
+
let geographyCodec = null;
|
|
25
|
+
let schemaName = 'public';
|
|
26
|
+
// Search through codecs for geometry and geography types
|
|
27
|
+
for (const codec of Object.values(pgRegistry.pgCodecs)) {
|
|
28
|
+
const pg = codec?.extensions?.pg;
|
|
29
|
+
if (!pg)
|
|
30
|
+
continue;
|
|
31
|
+
if (pg.name === 'geometry') {
|
|
32
|
+
geometryCodec = codec;
|
|
33
|
+
schemaName = pg.schemaName || 'public';
|
|
34
|
+
}
|
|
35
|
+
else if (pg.name === 'geography') {
|
|
36
|
+
geographyCodec = codec;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// PostGIS requires at least the geometry codec to be present.
|
|
40
|
+
// Geography is optional — not all databases use geography columns,
|
|
41
|
+
// so PostGraphile may not introspect the geography type at all.
|
|
42
|
+
if (!geometryCodec) {
|
|
43
|
+
return build;
|
|
44
|
+
}
|
|
45
|
+
const postgisInfo = {
|
|
46
|
+
schemaName,
|
|
47
|
+
geometryCodec,
|
|
48
|
+
geographyCodec
|
|
49
|
+
};
|
|
50
|
+
return build.extend(build, {
|
|
51
|
+
pgGISExtensionInfo: postgisInfo,
|
|
52
|
+
pgGISGraphQLTypesByCodecAndSubtype: {}
|
|
53
|
+
}, 'PostgisExtensionDetectionPlugin adding PostGIS build state');
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import 'graphile-build';
|
|
2
|
+
import 'graphile-build-pg';
|
|
3
|
+
import type { GraphileConfig } from 'graphile-config';
|
|
4
|
+
import '../types';
|
|
5
|
+
/**
|
|
6
|
+
* PostgisGeometryFieldsPlugin
|
|
7
|
+
*
|
|
8
|
+
* Enhances PostGIS geometry object types with subtype-specific fields:
|
|
9
|
+
*
|
|
10
|
+
* - Point: x/longitude, y/latitude, optional z/height
|
|
11
|
+
* - LineString: points array
|
|
12
|
+
* - Polygon: exterior ring, interiors array
|
|
13
|
+
* - MultiPoint: points array
|
|
14
|
+
* - MultiLineString: lines array
|
|
15
|
+
* - MultiPolygon: polygons array
|
|
16
|
+
* - GeometryCollection: geometries array (uses dimension interface)
|
|
17
|
+
*
|
|
18
|
+
* Uses the GraphQLObjectType_fields hook to add fields based on the
|
|
19
|
+
* type's scope (isPgGISType, pgGISCodecName, pgGISTypeDetails).
|
|
20
|
+
*/
|
|
21
|
+
export declare const PostgisGeometryFieldsPlugin: GraphileConfig.Plugin;
|