Skip to content
This repository was archived by the owner on Jan 13, 2026. It is now read-only.

Commit 7eb981e

Browse files
authored
Merge pull request #50 from PDOK/PDOK-17545/fix-crs
Pdok 17545/fix crs
2 parents 5c83b4f + 347a178 commit 7eb981e

15 files changed

+160
-152
lines changed

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,9 @@ docker run -v `pwd`/examples:/examples -p 8080:8080 -it pdok/gomagpie start-serv
4646
--synonyms-file internal/search/testdata/synonyms.csv
4747
```
4848

49-
Now open <http://localhost:8080>. See [examples](examples) for more details.
49+
Now open <http://localhost:8080>or open <http://localhost:8080/api> to check the openAPI specification.
50+
51+
See [examples](examples) for more details.
5052

5153
### Run ETL
5254

@@ -57,9 +59,8 @@ Create database using the ETL commands.
5759
docker run --rm --name postgis -e POSTGRES_PASSWORD=postgres -e POSTGRES_DB=test_db -p 5432:5432 postgis/postgis
5860

5961
./gomagpie create-search-index --db-name test_db
60-
6162
./gomagpie import-file --db-name test_db \
62-
--file internal/etl/testdata/addresses-crs84.gpkg \
63+
--file internal/etl/testdata/addresses-rd.gpkg \
6364
--feature-table "addresses" \
6465
--config-file internal/etl/testdata/config.yaml \
6566
--collection-id "addresses"

cmd/main.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ const (
3838
dbSslModeFlag = "db-ssl-mode"
3939
dbUsernameFlag = "db-username"
4040
searchIndexFlag = "search-index"
41+
sridFlag = "srid"
4142
fileFlag = "file"
4243
featureTableFlag = "feature-table"
4344
featureTableFidFlag = "fid"
@@ -286,6 +287,13 @@ func main() {
286287
Required: false,
287288
Value: "search_index",
288289
},
290+
&cli.PathFlag{
291+
Name: sridFlag,
292+
EnvVars: []string{strcase.ToScreamingSnake(sridFlag)},
293+
Usage: "SRID search-index bbox column, e.g. 28992 (RD) or 4326 (WSG84). The source geopackage its bbox should be in the same SRID.",
294+
Required: false,
295+
Value: "28992",
296+
},
289297
&cli.StringFlag{
290298
Name: languageFlag,
291299
EnvVars: []string{strcase.ToScreamingSnake(languageFlag)},
@@ -300,7 +308,7 @@ func main() {
300308
if err != nil {
301309
return err
302310
}
303-
return etl.CreateSearchIndex(dbConn, c.String(searchIndexFlag), lang)
311+
return etl.CreateSearchIndex(dbConn, c.String(searchIndexFlag), c.Int(sridFlag), lang)
304312
},
305313
},
306314
{

internal/etl/etl.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ type Transform interface {
3333
type Load interface {
3434

3535
// Init the target database by creating an empty search index
36-
Init(index string, lang language.Tag) error
36+
Init(index string, srid int, lang language.Tag) error
3737

3838
// Load records into search index
3939
Load(records []t.SearchIndexRecord, index string) (int64, error)
@@ -46,13 +46,13 @@ type Load interface {
4646
}
4747

4848
// CreateSearchIndex creates empty search index in target database
49-
func CreateSearchIndex(dbConn string, searchIndex string, lang language.Tag) error {
49+
func CreateSearchIndex(dbConn string, searchIndex string, srid int, lang language.Tag) error {
5050
db, err := newTargetToLoad(dbConn)
5151
if err != nil {
5252
return err
5353
}
5454
defer db.Close()
55-
return db.Init(searchIndex, lang)
55+
return db.Init(searchIndex, srid, lang)
5656
}
5757

5858
// ImportFile import source data into target search index using extract-transform-load principle

internal/etl/etl_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ func TestCreateSearchIndex(t *testing.T) {
4141
dbConn := makeDbConnection(dbPort)
4242

4343
// when/then
44-
err = CreateSearchIndex(dbConn, "search_index", language.Dutch)
44+
err = CreateSearchIndex(dbConn, "search_index", 28992, language.Dutch)
4545
assert.NoError(t, err)
4646
err = insertTestData(ctx, dbConn)
4747
assert.NoError(t, err)
@@ -62,9 +62,9 @@ func TestCreateSearchIndexIdempotent(t *testing.T) {
6262
dbConn := makeDbConnection(dbPort)
6363

6464
// when/then
65-
err = CreateSearchIndex(dbConn, "search_index", language.English)
65+
err = CreateSearchIndex(dbConn, "search_index", 28992, language.English)
6666
assert.NoError(t, err)
67-
err = CreateSearchIndex(dbConn, "search_index", language.English) // second time, should not fail
67+
err = CreateSearchIndex(dbConn, "search_index", 28992, language.English) // second time, should not fail
6868
assert.NoError(t, err)
6969
}
7070

@@ -116,7 +116,7 @@ func TestImportGeoPackage(t *testing.T) {
116116
}
117117

118118
// when/then
119-
err = CreateSearchIndex(dbConn, "search_index", language.English)
119+
err = CreateSearchIndex(dbConn, "search_index", 4326, language.English)
120120
assert.NoError(t, err)
121121

122122
table := config.FeatureTable{Name: "addresses", FID: "fid", Geom: "geom"}

internal/etl/load/postgres.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ func (p *Postgres) Optimize() error {
6060
//
6161
// Since not all DDL in Postgres support the "if not exists" syntax we use a bit
6262
// of pl/pgsql to make it idempotent.
63-
func (p *Postgres) Init(index string, lang language.Tag) error {
63+
func (p *Postgres) Init(index string, srid int, lang language.Tag) error {
6464

6565
geometryType := `
6666
do $$ begin
@@ -112,7 +112,7 @@ func (p *Postgres) Init(index string, lang language.Tag) error {
112112
geometry geometry(point, %[2]d) null,
113113
ts tsvector generated always as (to_tsvector('custom_dict', suggest)) stored,
114114
primary key (id, collection_id, collection_version)
115-
) -- partition by list(collection_id);`, index, t.WGS84) // TODO partitioning comes later
115+
) -- partition by list(collection_id);`, index, srid) // TODO partitioning comes later
116116
_, err = p.db.Exec(p.ctx, searchIndexTable)
117117
if err != nil {
118118
return fmt.Errorf("error creating search index table: %w", err)
20.7 MB
Binary file not shown.

internal/etl/transform/transform.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ import (
1616
"github.com/twpayne/go-geom"
1717
)
1818

19-
const WGS84 = 4326
20-
2119
type RawRecord struct {
2220
FeatureID int64
2321
FieldValues []any
@@ -71,7 +69,7 @@ func (t Transformer) Transform(records []RawRecord, collection config.GeoSpatial
7169
return nil, err
7270
}
7371

74-
geometry := r.Geometry.SetSRID(WGS84)
72+
geometry := r.Geometry
7573

7674
externalFid, err := generateExternalFid(collection.ID, collection.Search.ETL.ExternalFid, r.ExternalFidValues)
7775
if err != nil {
@@ -119,7 +117,7 @@ func (r RawRecord) transformBbox() (*geom.Polygon, error) {
119117
if util.SurfaceArea(r.Bbox) <= 0 {
120118
return nil, errors.New("bbox area must be greater than zero")
121119
}
122-
return r.Bbox.Polygon().SetSRID(WGS84), nil
120+
return r.Bbox.Polygon(), nil
123121
}
124122

125123
func slicesToStringMap(keys []string, values []any) (map[string]string, error) {

internal/search/datasources/postgres/postgres.go

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -223,15 +223,9 @@ func parseBbox(bbox *geom.Bounds, bboxSRID d.SRID) (string, []any, error) {
223223
var bboxQueryArgs []any
224224
var err error
225225
if bbox != nil {
226-
if bboxSRID != d.WGS84SRIDPostgis {
227-
bboxFilter = `AND
228-
(st_intersects(st_transform(r.geometry, $13::int), st_geomfromtext($12::text, $13::int)) OR st_intersects(st_transform(r.bbox, $13::int), st_geomfromtext($12::text, $13::int)))
229-
`
230-
} else {
231-
bboxFilter = `AND
232-
(st_intersects(r.geometry, st_geomfromtext($12::text, $13::int)) OR st_intersects(r.bbox, st_geomfromtext($12::text, $13::int)))
233-
`
234-
}
226+
bboxFilter = `AND
227+
(st_intersects(st_transform(r.geometry, $13::int), st_geomfromtext($12::text, $13::int)) OR st_intersects(st_transform(r.bbox, $13::int), st_geomfromtext($12::text, $13::int)))
228+
`
235229
bboxWkt, err = wkt.Marshal(bbox.Polygon())
236230
if err != nil {
237231
return "", []any{}, err

internal/search/main.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ func (s *Search) Search() http.HandlerFunc {
5858
engine.RenderProblem(engine.ProblemBadRequest, w, err.Error())
5959
return
6060
}
61-
collections, searchTerms, outputSRID, bbox, bboxSRID, limit, err := parseQueryParams(r.URL.Query())
61+
collections, searchTerms, outputSRID, outputCRS, bbox, bboxSRID, limit, err := parseQueryParams(r.URL.Query())
6262
if err != nil {
6363
engine.RenderProblem(engine.ProblemBadRequest, w, err.Error())
6464
return
@@ -77,7 +77,7 @@ func (s *Search) Search() http.HandlerFunc {
7777
handleQueryError(w, err)
7878
return
7979
}
80-
if err = s.enrichFeaturesWithHref(fc); err != nil {
80+
if err = s.enrichFeaturesWithHref(fc, outputCRS); err != nil {
8181
engine.RenderProblem(engine.ProblemServerError, w, err.Error())
8282
return
8383
}
@@ -94,7 +94,8 @@ func (s *Search) Search() http.HandlerFunc {
9494
}
9595
}
9696

97-
func (s *Search) enrichFeaturesWithHref(fc *domain.FeatureCollection) error {
97+
//nolint:nestif
98+
func (s *Search) enrichFeaturesWithHref(fc *domain.FeatureCollection, outputCRS string) error {
9899
for _, feat := range fc.Features {
99100
collectionID, ok := feat.Properties[domain.PropCollectionID]
100101
if !ok || collectionID == "" {
@@ -114,6 +115,10 @@ func (s *Search) enrichFeaturesWithHref(fc *domain.FeatureCollection) error {
114115
}
115116
href += "?f=json"
116117

118+
if outputCRS != "" {
119+
href += "&crs=" + outputCRS
120+
}
121+
117122
// add href to feature both in GeoJSON properties (for broad compatibility and in line with OGC API Features part 5) and as a Link.
118123
feat.Properties[domain.PropHref] = href
119124
feat.Links = []domain.Link{

internal/search/main_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ func TestSearch(t *testing.T) {
7373
assert.NoError(t, err)
7474

7575
// given empty search index
76-
err = etl.CreateSearchIndex(dbConn, testSearchIndex, language.Dutch)
76+
err = etl.CreateSearchIndex(dbConn, testSearchIndex, 28992, language.Dutch)
7777
assert.NoError(t, err)
7878

7979
// given imported geopackage (creates two collections in search_index with identical data)
@@ -263,12 +263,13 @@ func importAddressesGpkg(collectionName string, dbConn string) error {
263263
collection := config.CollectionByID(conf, collectionName)
264264
table := config.FeatureTable{Name: "addresses", FID: "fid", Geom: "geom"}
265265
return etl.ImportFile(*collection, testSearchIndex,
266-
"internal/etl/testdata/addresses-crs84.gpkg", table, 5000, dbConn)
266+
"internal/etl/testdata/addresses-rd.gpkg", table, 5000, dbConn)
267267
}
268268

269269
func setupPostgis(ctx context.Context, t *testing.T) (nat.Port, testcontainers.Container, error) {
270270
req := testcontainers.ContainerRequest{
271271
Image: "docker.io/postgis/postgis:16-3.5", // use debian, not alpine (proj issues between environments)
272+
Name: "postgis",
272273
Env: map[string]string{
273274
"POSTGRES_USER": "postgres",
274275
"POSTGRES_PASSWORD": "postgres",

0 commit comments

Comments
 (0)