Skip to content

Commit 407694f

Browse files
committed
fix(goatlib): use rowid as fallback for missing id column in CQL evaluator
1 parent 751dcac commit 407694f

File tree

2 files changed

+35
-17
lines changed

2 files changed

+35
-17
lines changed

apps/web/components/reports/elements/renderers/MapElementRenderer.tsx

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -129,16 +129,22 @@ const MapElementRenderer: React.FC<MapElementRendererProps> = ({
129129
} else if (atlasPage.filterToCurrentFeature && atlasPage.feature) {
130130
// Filter coverage layer to only show the current feature
131131
const currentFeatureId = atlasPage.feature.id;
132+
const idFilter = {
133+
op: "=",
134+
args: [{ property: "id" }, currentFeatureId],
135+
};
132136
filtered = filtered.map((layer) => {
133137
if (layer.id !== covLayerId) return layer;
138+
const existingCql = layer.query?.cql;
139+
// Combine with existing CQL filter if present
140+
const combinedCql = existingCql
141+
? { op: "and", args: [existingCql, idFilter] }
142+
: idFilter;
134143
return {
135144
...layer,
136145
query: {
137146
...layer.query,
138-
cql: {
139-
op: "=",
140-
args: [{ property: "id" }, currentFeatureId],
141-
},
147+
cql: combinedCql,
142148
},
143149
};
144150
});
@@ -195,21 +201,28 @@ const MapElementRenderer: React.FC<MapElementRendererProps> = ({
195201
const containerWidth = container?.clientWidth ?? 400;
196202
const containerHeight = container?.clientHeight ?? 300;
197203
const minDim = Math.min(containerWidth, containerHeight);
198-
const paddingPx = Math.round((marginPercent / 100) * minDim);
204+
// Clamp padding so it doesn't exceed what fitBounds can handle
205+
// (padding on both sides must leave at least 1px for the map)
206+
const maxPadding = Math.floor(Math.min(containerWidth, containerHeight) / 2) - 1;
207+
const paddingPx = Math.min(Math.round((marginPercent / 100) * minDim), Math.max(0, maxPadding));
199208

200209
// Fit the map to the atlas page bounds with margin-based padding
201-
mapRef.current.fitBounds(
202-
[
203-
[west, south],
204-
[east, north],
205-
],
206-
{
207-
padding: paddingPx,
208-
duration: 0, // No animation for print preview
209-
maxZoom: 18, // Prevent excessive zoom for small features
210-
bearing: configBearing, // Preserve rotation from config
211-
}
212-
);
210+
try {
211+
mapRef.current.fitBounds(
212+
[
213+
[west, south],
214+
[east, north],
215+
],
216+
{
217+
padding: paddingPx,
218+
duration: 0, // No animation for print preview
219+
maxZoom: 18, // Prevent excessive zoom for small features
220+
bearing: configBearing, // Preserve rotation from config
221+
}
222+
);
223+
} catch {
224+
// fitBounds can throw if the canvas is too small for the given padding
225+
}
213226
}, [atlasPage, isAtlasControlled, mapLoaded, configViewState?.bearing, element.config?.atlas?.margin_percent]);
214227

215228
// Handle double-click to enter navigation mode

packages/python/goatlib/src/goatlib/storage/cql_evaluator.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,11 @@ def attribute(self, node):
137137
# Use the actual geometry column name
138138
return self._quote_identifier(self.geometry_column)
139139

140+
# When filtering on "id" but the table has no id column, use rowid
141+
# (GeoAPI uses DuckDB's rowid as fallback feature ID)
142+
if name.lower() == "id" and "id" not in self.field_names:
143+
return "rowid"
144+
140145
# Validate column name
141146
if name.lower() not in self.field_names:
142147
raise ValueError(f"Unknown field: {name}. Valid fields: {self.field_names}")

0 commit comments

Comments
 (0)