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.
Files changed (76) hide show
  1. package/README.md +22 -45
  2. package/constants.d.ts +1 -0
  3. package/constants.js +10 -1
  4. package/esm/constants.d.ts +13 -0
  5. package/esm/constants.js +9 -0
  6. package/esm/index.d.ts +24 -0
  7. package/esm/index.js +25 -33
  8. package/esm/plugins/codec.d.ts +19 -0
  9. package/esm/plugins/codec.js +174 -0
  10. package/esm/plugins/detect-extension.d.ts +14 -0
  11. package/esm/plugins/detect-extension.js +57 -0
  12. package/esm/plugins/geometry-fields.d.ts +21 -0
  13. package/esm/plugins/geometry-fields.js +245 -0
  14. package/esm/plugins/inflection.d.ts +8 -0
  15. package/esm/plugins/inflection.js +52 -0
  16. package/esm/plugins/register-types.d.ts +22 -0
  17. package/esm/plugins/register-types.js +319 -0
  18. package/esm/preset.d.ts +18 -0
  19. package/esm/preset.js +30 -0
  20. package/esm/types.d.ts +84 -0
  21. package/esm/utils.d.ts +21 -0
  22. package/esm/utils.js +18 -7
  23. package/index.d.ts +24 -15
  24. package/index.js +39 -47
  25. package/package.json +23 -18
  26. package/plugins/codec.d.ts +19 -0
  27. package/plugins/codec.js +180 -0
  28. package/plugins/detect-extension.d.ts +14 -0
  29. package/plugins/detect-extension.js +60 -0
  30. package/plugins/geometry-fields.d.ts +21 -0
  31. package/plugins/geometry-fields.js +248 -0
  32. package/plugins/inflection.d.ts +8 -0
  33. package/plugins/inflection.js +55 -0
  34. package/plugins/register-types.d.ts +22 -0
  35. package/plugins/register-types.js +325 -0
  36. package/preset.d.ts +18 -0
  37. package/preset.js +33 -0
  38. package/types.d.ts +69 -44
  39. package/utils.d.ts +16 -0
  40. package/utils.js +17 -6
  41. package/PostgisExtensionDetectionPlugin.d.ts +0 -3
  42. package/PostgisExtensionDetectionPlugin.js +0 -28
  43. package/PostgisInflectionPlugin.d.ts +0 -3
  44. package/PostgisInflectionPlugin.js +0 -36
  45. package/PostgisRegisterTypesPlugin.d.ts +0 -3
  46. package/PostgisRegisterTypesPlugin.js +0 -234
  47. package/PostgisVersionPlugin.d.ts +0 -3
  48. package/PostgisVersionPlugin.js +0 -24
  49. package/Postgis_GeometryCollection_GeometriesPlugin.d.ts +0 -3
  50. package/Postgis_GeometryCollection_GeometriesPlugin.js +0 -43
  51. package/Postgis_LineString_PointsPlugin.d.ts +0 -3
  52. package/Postgis_LineString_PointsPlugin.js +0 -40
  53. package/Postgis_MultiLineString_LineStringsPlugin.d.ts +0 -3
  54. package/Postgis_MultiLineString_LineStringsPlugin.js +0 -38
  55. package/Postgis_MultiPoint_PointsPlugin.d.ts +0 -3
  56. package/Postgis_MultiPoint_PointsPlugin.js +0 -38
  57. package/Postgis_MultiPolygon_PolygonsPlugin.d.ts +0 -3
  58. package/Postgis_MultiPolygon_PolygonsPlugin.js +0 -38
  59. package/Postgis_Point_LatitudeLongitudePlugin.d.ts +0 -3
  60. package/Postgis_Point_LatitudeLongitudePlugin.js +0 -43
  61. package/Postgis_Polygon_RingsPlugin.d.ts +0 -3
  62. package/Postgis_Polygon_RingsPlugin.js +0 -49
  63. package/esm/PostgisExtensionDetectionPlugin.js +0 -26
  64. package/esm/PostgisInflectionPlugin.js +0 -34
  65. package/esm/PostgisRegisterTypesPlugin.js +0 -229
  66. package/esm/PostgisVersionPlugin.js +0 -22
  67. package/esm/Postgis_GeometryCollection_GeometriesPlugin.js +0 -41
  68. package/esm/Postgis_LineString_PointsPlugin.js +0 -38
  69. package/esm/Postgis_MultiLineString_LineStringsPlugin.js +0 -36
  70. package/esm/Postgis_MultiPoint_PointsPlugin.js +0 -36
  71. package/esm/Postgis_MultiPolygon_PolygonsPlugin.js +0 -36
  72. package/esm/Postgis_Point_LatitudeLongitudePlugin.js +0 -41
  73. package/esm/Postgis_Polygon_RingsPlugin.js +0 -47
  74. package/esm/makeGeoJSONType.js +0 -39
  75. package/makeGeoJSONType.d.ts +0 -1
  76. package/makeGeoJSONType.js +0 -42
package/README.md CHANGED
@@ -1,61 +1,38 @@
1
1
  # graphile-postgis
2
2
 
3
- <p align="center" width="100%">
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
- - Registers GeoJSON scalars and PostGIS `geometry` / `geography` GraphQL types
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
- ## 📦 Usage
7
+ ## Installation
34
8
 
35
- ### CLI
36
-
37
- ```sh
38
- postgraphile --append-plugins graphile-postgis
9
+ ```bash
10
+ npm install graphile-postgis
39
11
  ```
40
12
 
41
- Make sure your database has the `postgis` extension enabled so the plugin can expose the spatial types.
42
-
43
- ### Library
13
+ ## Usage
44
14
 
45
- ```ts
46
- import PostgisPlugin from 'graphile-postgis';
15
+ ```typescript
16
+ import { GraphilePostgisPreset } from 'graphile-postgis';
47
17
 
48
- const options = {
49
- appendPlugins: [PostgisPlugin]
18
+ const preset = {
19
+ extends: [GraphilePostgisPreset]
50
20
  };
51
21
  ```
52
22
 
53
- ## 🧪 Testing
23
+ ## Features
54
24
 
55
- ```sh
56
- # requires a local Postgres with PostGIS available (defaults to postgres/password@localhost:5432)
57
- pnpm --filter graphile-postgis test
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
@@ -10,3 +10,4 @@ export declare enum GisSubtype {
10
10
  }
11
11
  export declare const SUBTYPE_STRING_BY_SUBTYPE: Record<GisSubtype, string>;
12
12
  export declare const GIS_SUBTYPE_NAME: Record<GisSubtype, string>;
13
+ export declare const CONCRETE_SUBTYPES: GisSubtype[];
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
- import PostgisExtensionDetectionPlugin from './PostgisExtensionDetectionPlugin';
2
- import PostgisInflectionPlugin from './PostgisInflectionPlugin';
3
- import PostgisRegisterTypesPlugin from './PostgisRegisterTypesPlugin';
4
- import PostgisVersionPlugin from './PostgisVersionPlugin';
5
- import Postgis_GeometryCollection_GeometriesPlugin from './Postgis_GeometryCollection_GeometriesPlugin';
6
- import Postgis_LineString_PointsPlugin from './Postgis_LineString_PointsPlugin';
7
- import Postgis_MultiLineString_LineStringsPlugin from './Postgis_MultiLineString_LineStringsPlugin';
8
- import Postgis_MultiPoint_PointsPlugin from './Postgis_MultiPoint_PointsPlugin';
9
- import Postgis_MultiPolygon_PolygonsPlugin from './Postgis_MultiPolygon_PolygonsPlugin';
10
- import Postgis_Point_LatitudeLongitudePlugin from './Postgis_Point_LatitudeLongitudePlugin';
11
- import Postgis_Polygon_RingsPlugin from './Postgis_Polygon_RingsPlugin';
12
- const PostgisPlugin = async (builder, options) => {
13
- await PostgisVersionPlugin(builder, options);
14
- await PostgisInflectionPlugin(builder, options);
15
- await PostgisExtensionDetectionPlugin(builder, options);
16
- await PostgisRegisterTypesPlugin(builder, options);
17
- // Enhancing the `Point` type:
18
- await Postgis_Point_LatitudeLongitudePlugin(builder, options);
19
- // Enhancing the `LineString` type:
20
- await Postgis_LineString_PointsPlugin(builder, options);
21
- // Enhancing the `Polygon` type:
22
- await Postgis_Polygon_RingsPlugin(builder, options);
23
- // Enhancing the `MultiPoint` type:
24
- await Postgis_MultiPoint_PointsPlugin(builder, options);
25
- // Enhancing the `MultiLineString` type:
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;