Skip to content

Commit 4265d02

Browse files
committed
fix(graphile-postgis): emit ST_<op>(owner, target) — directional operand order
Tag grammar reads as '<owner_col> <op> <target_col>' so the PostGIS call must be ST_<op>(owner, target). Symmetric operators hid the bug; st_within/st_contains/st_covers/st_coveredby inverted the match set. Also corrects test filter operator name to equalTo (graphile idiom) instead of eq.
1 parent fdddc7c commit 4265d02

2 files changed

Lines changed: 25 additions & 19 deletions

File tree

graphile/graphile-postgis/src/plugins/spatial-relations.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -446,11 +446,17 @@ function buildSpatialJoinFragment(
446446
innerAlias: SQL,
447447
distanceValue: SQL | null
448448
): SQL {
449-
const inner = sql`${innerAlias}.${sql.identifier(rel.targetAttributeName)}`;
450-
const outer = sql`${outerAlias}.${sql.identifier(rel.ownerAttributeName)}`;
449+
// Tag grammar reads as "<owner_col> <op> <target_col>" (e.g. "location
450+
// st_within counties.geom"), so the emitted PostGIS call is always
451+
// `ST_<op>(owner_col, target_col)`. For symmetric operators
452+
// (st_intersects, st_dwithin, st_equals, &&) the ordering is immaterial;
453+
// for directional ones (st_within, st_contains, st_covers, st_coveredby)
454+
// reversing the operands inverts the set of matched rows.
455+
const ownerExpr = sql`${outerAlias}.${sql.identifier(rel.ownerAttributeName)}`;
456+
const targetExpr = sql`${innerAlias}.${sql.identifier(rel.targetAttributeName)}`;
451457
if (rel.operator.kind === 'infix') {
452-
// Only `&&` today — simple inline.
453-
return sql`${inner} && ${outer}`;
458+
// Only `&&` today — simple inline (symmetric).
459+
return sql`${ownerExpr} && ${targetExpr}`;
454460
}
455461
const fn = sql.identifier(schemaName, rel.operator.pgToken);
456462
if (rel.operator.parametric) {
@@ -461,9 +467,9 @@ function buildSpatialJoinFragment(
461467
`a distance value in spatial relation '${rel.relationName}'.`
462468
);
463469
}
464-
return sql`${fn}(${inner}, ${outer}, ${distanceValue})`;
470+
return sql`${fn}(${ownerExpr}, ${targetExpr}, ${distanceValue})`;
465471
}
466-
return sql`${fn}(${inner}, ${outer})`;
472+
return sql`${fn}(${ownerExpr}, ${targetExpr})`;
467473
}
468474

469475
/** Build the `other.pk <> self.pk` exclusion predicate for self-relations. */

graphql/orm-test/__tests__/postgis-spatial-relations.test.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ describe('PostgisSpatialRelationsPlugin (ORM, live PG)', () => {
164164
const r = await orm.telemedicineClinic
165165
.findMany({
166166
select: { id: true, name: true },
167-
where: { county: { some: { name: { eq: 'Bay County' } } } },
167+
where: { county: { some: { name: { equalTo: 'Bay County' } } } },
168168
})
169169
.execute();
170170
expect(r.ok).toBe(true);
@@ -177,7 +177,7 @@ describe('PostgisSpatialRelationsPlugin (ORM, live PG)', () => {
177177
const r = await orm.telemedicineClinic
178178
.findMany({
179179
select: { id: true },
180-
where: { county: { some: { name: { eq: 'LA County' } } } },
180+
where: { county: { some: { name: { equalTo: 'LA County' } } } },
181181
})
182182
.execute();
183183
expect(r.ok).toBe(true);
@@ -188,7 +188,7 @@ describe('PostgisSpatialRelationsPlugin (ORM, live PG)', () => {
188188
const r = await orm.telemedicineClinic
189189
.findMany({
190190
select: { id: true },
191-
where: { county: { some: { name: { eq: 'NYC County' } } } },
191+
where: { county: { some: { name: { equalTo: 'NYC County' } } } },
192192
})
193193
.execute();
194194
expect(r.ok).toBe(true);
@@ -213,7 +213,7 @@ describe('PostgisSpatialRelationsPlugin (ORM, live PG)', () => {
213213
.findMany({
214214
select: { id: true },
215215
where: {
216-
intersectingCounty: { some: { name: { eq: 'Bay County' } } },
216+
intersectingCounty: { some: { name: { equalTo: 'Bay County' } } },
217217
},
218218
})
219219
.execute();
@@ -228,7 +228,7 @@ describe('PostgisSpatialRelationsPlugin (ORM, live PG)', () => {
228228
.findMany({
229229
select: { id: true },
230230
where: {
231-
coveringCounty: { some: { name: { eq: 'LA County' } } },
231+
coveringCounty: { some: { name: { equalTo: 'LA County' } } },
232232
},
233233
})
234234
.execute();
@@ -245,7 +245,7 @@ describe('PostgisSpatialRelationsPlugin (ORM, live PG)', () => {
245245
const r = await orm.telemedicineClinic
246246
.findMany({
247247
select: { id: true },
248-
where: { county: { none: { name: { eq: 'NYC County' } } } },
248+
where: { county: { none: { name: { equalTo: 'NYC County' } } } },
249249
})
250250
.execute();
251251
expect(r.ok).toBe(true);
@@ -260,7 +260,7 @@ describe('PostgisSpatialRelationsPlugin (ORM, live PG)', () => {
260260
const r = await orm.telemedicineClinic
261261
.findMany({
262262
select: { id: true },
263-
where: { county: { every: { name: { startsWith: 'B' } } } },
263+
where: { county: { every: { name: { equalTo: 'Bay County' } } } },
264264
})
265265
.execute();
266266
expect(r.ok).toBe(true);
@@ -281,7 +281,7 @@ describe('PostgisSpatialRelationsPlugin (ORM, live PG)', () => {
281281
where: {
282282
nearbyClinic: {
283283
distance: 10.0,
284-
some: { specialty: { eq: 'cardiology' } },
284+
some: { specialty: { equalTo: 'cardiology' } },
285285
},
286286
},
287287
})
@@ -349,8 +349,8 @@ describe('PostgisSpatialRelationsPlugin (ORM, live PG)', () => {
349349
select: { id: true },
350350
where: {
351351
and: [
352-
{ county: { some: { name: { eq: 'Bay County' } } } },
353-
{ specialty: { eq: 'cardiology' } },
352+
{ county: { some: { name: { equalTo: 'Bay County' } } } },
353+
{ specialty: { equalTo: 'cardiology' } },
354354
],
355355
},
356356
})
@@ -365,8 +365,8 @@ describe('PostgisSpatialRelationsPlugin (ORM, live PG)', () => {
365365
select: { id: true },
366366
where: {
367367
or: [
368-
{ county: { some: { name: { eq: 'Bay County' } } } },
369-
{ name: { eq: 'LA Pediatrics' } },
368+
{ county: { some: { name: { equalTo: 'Bay County' } } } },
369+
{ name: { equalTo: 'LA Pediatrics' } },
370370
],
371371
},
372372
})
@@ -384,7 +384,7 @@ describe('PostgisSpatialRelationsPlugin (ORM, live PG)', () => {
384384
.findMany({
385385
select: { id: true },
386386
where: {
387-
not: { county: { some: { name: { eq: 'Bay County' } } } },
387+
not: { county: { some: { name: { equalTo: 'Bay County' } } } },
388388
},
389389
})
390390
.execute();

0 commit comments

Comments
 (0)