Skip to content

stratapkg/spatial

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

@stratapkg/spatial

PostGIS extension for Prisma — typed spatial queries, automatic WKB↔GeoJSON conversion, and geometry-aware findMany with mixed scalar + geo filters.

Installation

bun add @stratapkg/spatial

Setup

1. Add generator to schema

generator spatial {
  provider = "stratapkg-spatial"
  output   = "./generated/spatial"
}

2. Annotate geometry fields

model City {
  id       Int    @id @default(autoincrement())
  name     String
  /// @spatial srid=4326
  location Unsupported("geometry(Point,4326)")?
  /// @spatial srid=4326
  boundary Unsupported("geometry(Polygon,4326)")?
}

3. Run generator

bunx prisma generate

4. Use the extension

import { PrismaClient } from './generated/client'
import { withSpatial } from '@stratapkg/spatial'
import { spatialConfig } from './generated/spatial'

const prisma = new PrismaClient({ adapter })
  .$extends(withSpatial(spatialConfig))

Queries

Radius search

await prisma.city.findMany({
  where: {
    population: { gte: 100_000 },
    location: {
      $near: { lat: 59.9, lon: 30.3 },
      $maxDistance: 5000, // metres
    },
  },
  orderBy: {
    location: { $near: { lat: 59.9, lon: 30.3 } },
  },
  take: 10,
})

Intersection

await prisma.city.findMany({
  where: {
    boundary: { $intersects: someGeoJsonPolygon },
  },
})

Within polygon

await prisma.city.findMany({
  where: {
    location: { $within: someGeoJsonPolygon },
  },
})

Geometry columns are returned as GeoJSON automatically — no manual WKB parsing needed.

How it works

The generator reads /// doc comments on Unsupported fields and emits:

  • generated/spatial/index.ts — config map with SRID and geometry type per field
  • generated/spatial/types.d.tsGeometryPoint<SRID>, GeometryPolygon<SRID> etc.

The runtime extension intercepts findMany/findFirst/findUnique, extracts geo operators from where/orderBy, and builds a single CTE query:

WITH scalar_filter AS (
    SELECT id FROM "City" WHERE population >= 100000
)
SELECT c.*, ST_AsGeoJSON(c.location) as location
FROM "City" c
INNER JOIN scalar_filter sf ON c.id = sf.id
WHERE ST_DWithin(
    c.location::geography, 
    ST_SetSRID(ST_Point(30.3, 59.9), 4326)::geography,
    5000
)
ORDER BY c.location <-> ST_SetSRID(ST_Point(30.3, 59.9), 4326)
LIMIT 10

One query. No N+1.

Requirements

  • Prisma >= 7.0
  • PostgreSQL with PostGIS extension enabled
  • Any Prisma adapter (adapter-agnostic)

License

MIT

About

PostGIS extension for Prisma — typed spatial queries and GeoJSON conversion

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors