Skip to content

feat(provision): upgrade to latest PostGIS spatial-relation stack + 5 RelationSpatial entries + ORM tests#24

Merged
pyramation merged 4 commits intomainfrom
devin/1776487651-spatial-relations-blueprint
Apr 18, 2026
Merged

feat(provision): upgrade to latest PostGIS spatial-relation stack + 5 RelationSpatial entries + ORM tests#24
pyramation merged 4 commits intomainfrom
devin/1776487651-spatial-relations-blueprint

Conversation

@pyramation
Copy link
Copy Markdown
Contributor

Summary

Showcases the new cross-table PostGIS spatial-relation feature end-to-end against agentic-db. Wires 5 @spatialRelation entries into the blueprint and exercises each via the ORM integration suite.

Dependency bump (to pick up the feature):

  • @constructive-io/graphql-codegen 4.28.0 → 4.30.0
  • @pgpm/metaschema-schema / @pgpm/metaschema-modules 0.20.2 → 0.21.0
  • New workspace dep: graphile-postgis@2.11.0 in packages/integration-tests

New production code (packages/provision/src/schemas/spatial-relations.ts): calls metaschema_modules_public.provision_spatial_relation(...) — the dispatcher shipped in constructive-db#844 — once per relation. All 5 use st_dwithin since every agentic-db geom column is a Point.

# Source → Target Relation Radius
1 memories.location_geo places.location_geo nearbyPlaces 5 km
2 memories.location_geo contacts.location_geo nearbyContacts 2 km
3 trips.destination_geo venues.location nearbyVenues 1 km
4 events.location_geo venues.location nearbyVenues 500 m
5 memories.location_geo memories.location_geo nearbyMemories 1 km (self)

Relation names are camelCase (not snake_case) so PostGraphile's inflection produces filter fields like nearbyPlaces matching every other field convention in the schema. Operator tokens remain snake_case per the earlier discussion (st_dwithin, etc.).

Test fixture (packages/integration-tests/__fixtures__/seed/spatial-relations.sql): bakes matching @spatialRelation column comments directly so ORM tests don't require the full blueprint pipeline to run. This mirrors what provision_spatial_relation would emit.

ORM tests (orm.test.ts):

  • Registers PostgisSpatialRelationsPlugin explicitly in the test preset — ConstructivePreset ships the plugin but does not auto-enable it (opt-in).
  • Adds describe('RelationSpatial via ORM') with 5 tests, one per entry, each with positive + negative matches.
  • Flips bboxIntersects2D from "expected failure" back to "expected success" now that constructive#992 merged (GeoJSON inputs get wrapped with ST_GeomFromGeoJSON).
  • Seeds MEMORY_FERRY (~260 m from MEMORY_SF) + places/venues/contacts/events fixtures for deterministic pos/neg matches.

Result: 36/36 ORM tests pass locally.

Review & Testing Checklist for Human

  • Self-relation semantics: the nearbyMemories test assumes the plugin excludes the owner row from self-relations (other.pk <> self.pk). That's why MEMORY_FERRY is used as the filter target — is this the semantic we want to lock in, or should self-relations include the owner row?
  • Relation naming: I picked camelCase (nearbyPlaces) for relation names so they match PostGraphile's inflection on filter fields. The earlier discussion about st_contains snake_case was about operator tokens specifically, but please confirm relation names in camelCase is what you want (it's what the plugin actually consumes for GraphQL field names).
  • Pre-existing build errors: packages/provision has ~227 pre-existing TypeScript errors from the metaschema 0.20.2→0.21.0 bump (table_ref / ref / source_ref properties were renamed). These are NOT introduced by this PR — they reproduce on main after the dep bump. Tests still run fine via ts-jest but pnpm build is red. Should be addressed as a separate cleanup PR; flagging so it's not a surprise.
  • Lockfile churn: pnpm-lock.yaml has large diff (7k insertions / 9.6k deletions) from the dep bump. Expected but not independently verified.
  • Test plan: eval "$(pgpm env)" && cd packages/integration-tests && pnpm test -- --testPathPattern 'orm.test' should produce 36 passed, 36 total.

Notes

  • Blueprint provisioning (packages/provision/src/schemas/spatial-relations.ts) is the production path but was not run end-to-end against a real pgpm provision in this session — the pre-existing build errors in packages/provision blocked a full build. The ORM tests cover the feature via the smart-tag fixture file, which emits exactly what provision_spatial_relation would.
  • Related merged PRs for context: constructive#993 (plugin), constructive-db#843 / #844 (metaschema + blueprint node), constructive#997 / #999 (node type registry + skill docs).

Link to Devin session: https://app.devin.ai/sessions/c5eeee65a3c546c4ac6753bb05fa03e0
Requested by: @pyramation

Adds a new `spatial-relations.ts` provision module that registers 5
@spatialRelation virtual filters across the agentic-db schema, and
exercises each via `orm.\*.findMany({ where: { <name>: { some: ... } } })`
in the integration suite.

Relations (all `st_dwithin` since every agentic-db geom column is a Point):
  1. memories  → places    @ 5 km    "memories near a known place"
  2. memories  → contacts  @ 2 km    "memories near where a contact lives"
  3. trips     → venues    @ 1 km    "trips whose destination is near a venue"
  4. events    → venues    @ 500 m   "events near a specific venue (no FK)"
  5. memories  → memories  @ 1 km    self-relation "what else happened near this memory"

Implementation:
- packages/provision/src/schemas/spatial-relations.ts: calls the
  metaschema_modules_public.provision_spatial_relation() dispatcher
  (shipped in constructive-db#844) for each row; graceful on re-run.
- packages/provision/src/provision.ts: wired after cross-relations.
- packages/integration-tests/__fixtures__/seed/spatial-relations.sql:
  bakes matching `@spatialRelation` column comments so tests don't
  require the full blueprint pipeline to run.
- packages/integration-tests/__tests__/orm.test.ts:
  * registers PostgisSpatialRelationsPlugin in the test preset (the
    ConstructivePreset ships the plugin but doesn't auto-enable it)
  * adds the RelationSpatial describe-block with one test per entry
  * flips bboxIntersects2D back to "expected success" now that
    constructive#992 merged (GeoJSON is wrapped with ST_GeomFromGeoJSON)
- test-data.sql: adds MEMORY_FERRY (~260 m from MEMORY_SF) so the
  self-relation has a matching "other" row (the plugin excludes the
  owner row from self-joins) + places/venues/contacts/events fixtures
  chosen for deterministic positive/negative matches.

Relation names are camelCase in both the blueprint and the seeded
tags so PostGraphile's inflection produces `nearbyPlaces`/etc. on
the generated filter input — matching every other field convention
in the schema.

All 36 ORM tests pass locally (5 RelationSpatial + the restored
scalar bboxIntersects2D test + 30 existing).
@devin-ai-integration
Copy link
Copy Markdown

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

GraphilePostgisPreset (in graphile-postgis@2.11.0) already registers
PostgisSpatialRelationsPlugin in its plugins array, and ConstructivePreset
extends GraphilePostgisPreset. So `extends: [ConstructivePreset]` is
all that's needed — my earlier explicit registration was a leftover from
debugging and is redundant.

All 36 ORM tests still pass.
ConstructivePreset → GraphilePostgisPreset already pulls graphile-postgis
in transitively, and nothing in this package imports it directly after
the previous commit removed the explicit plugin registration. Dropping
the direct dep in packages/integration-tests/package.json.

Tests still 36/36.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant