From 3a368caea5142bfb09228994d6c1d0f6ba503afe Mon Sep 17 00:00:00 2001 From: Grigory Date: Tue, 21 Nov 2023 21:29:17 -0500 Subject: [PATCH] GeoTrellisPath.parse should preserve unrecognized uri parameters (#3529) * GeoTrellisPath.parse should preserve unrecognized uri parameters * Adjust tests * CHANGELOG.md update --- CHANGELOG.md | 1 + .../geotrellis/store/GeoTrellisPath.scala | 19 +++++++++------ .../geotrellis/store/GeoTrellisPathSpec.scala | 24 +++++++++++++++---- 3 files changed, 32 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index af2baa11c8..6fe092e4f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix FileRangeReaderProvider parsing URI in windows [#3507](https://github.com/locationtech/geotrellis/pull/3507) - Regrid: force crop to avoid going out of memory [#3518](https://github.com/locationtech/geotrellis/pull/3518) - Fix rounding errors/numerical instability in GridExtent and LayoutTileSource [#3520](https://github.com/locationtech/geotrellis/pull/3520) +- GeoTrellisPath.parse should preserve unrecognized uri parameters [#3529](https://github.com/locationtech/geotrellis/pull/3529) ## [3.7.0] - 2023-02-26 diff --git a/store/src/main/scala/geotrellis/store/GeoTrellisPath.scala b/store/src/main/scala/geotrellis/store/GeoTrellisPath.scala index fa81ab5d14..d98ac9d97d 100644 --- a/store/src/main/scala/geotrellis/store/GeoTrellisPath.scala +++ b/store/src/main/scala/geotrellis/store/GeoTrellisPath.scala @@ -55,9 +55,9 @@ object GeoTrellisPath { implicit def toGeoTrellisDataPath(path: String): GeoTrellisPath = parse(path) def parseOption(path: String): Option[GeoTrellisPath] = { - val layerNameParam: String = "layer" - val zoomLevelParam: String = "zoom" - val bandCountParam: String = "band_count" + val layerNameParam = "layer" + val zoomLevelParam = "zoom" + val bandCountParam = "band_count" val uri = UrlWithAuthority.parseOption(path).fold(Url.parse(path))(identity) val queryString = uri.query @@ -70,13 +70,18 @@ object GeoTrellisPath { case _ => "" } - s"${scheme.split("\\+").last}://$authority${uri.path}".some + val queryStringFiltered = { + val filtered = queryString.removeAll(layerNameParam, zoomLevelParam, bandCountParam) + if(filtered.isEmpty) "" else s"?${filtered.toString()}" + } + + s"${scheme.split("\\+").last}://$authority${uri.path}$queryStringFiltered".trim.some } catalogPath.fold(Option.empty[GeoTrellisPath]) { catalogPath => - val maybeLayerName: Option[String] = queryString.param(layerNameParam) - val maybeZoomLevel: Option[Int] = queryString.param(zoomLevelParam).map(_.toInt) - val bandCount: Option[Int] = queryString.param(bandCountParam).map(_.toInt) + val maybeLayerName = queryString.param(layerNameParam) + val maybeZoomLevel = queryString.param(zoomLevelParam).map(_.toInt) + val bandCount = queryString.param(bandCountParam).map(_.toInt) (maybeLayerName, maybeZoomLevel) match { case (Some(layerName), Some(zoomLevel)) => diff --git a/store/src/test/scala/geotrellis/store/GeoTrellisPathSpec.scala b/store/src/test/scala/geotrellis/store/GeoTrellisPathSpec.scala index 3b2764c22c..2ddf61da12 100644 --- a/store/src/test/scala/geotrellis/store/GeoTrellisPathSpec.scala +++ b/store/src/test/scala/geotrellis/store/GeoTrellisPathSpec.scala @@ -23,12 +23,12 @@ class GeoTrellisPathSpec extends AnyFunSpec { it("should fail to parse without a layer") { val path = GeoTrellisPath.parseOption("file:///foo/bar?zoom=1") - assert(path == None) + assert(path.isEmpty) } it("should fail to parse without a zoom") { val path = GeoTrellisPath.parseOption("file:///foo/bar?layer=baz") - assert(path == None) + assert(path.isEmpty) } it("should parse a local absolute file path without scheme") { @@ -59,7 +59,7 @@ class GeoTrellisPathSpec extends AnyFunSpec { val path = GeoTrellisPath.parse("file:///foo/bar?layer=baz&band_count=1&zoom=10") assert(path.layerName == "baz") assert(path.zoomLevel == 10) - assert(path.bandCount == Some(1)) + assert(path.bandCount.contains(1)) } it("should parse hdfs scheme") { @@ -74,6 +74,20 @@ class GeoTrellisPathSpec extends AnyFunSpec { assert(path.layerName == "foo") } + it("should parse hbase scheme") { + val path = GeoTrellisPath.parse("hbase://zookeeper:2181?master=master_host&attributes=attributes_table&layers=layers_table&layer=foo&zoom=1") + assert(path.value == "hbase://zookeeper:2181?master=master_host&attributes=attributes_table&layers=layers_table") + assert(path.layerName == "foo") + assert(path.zoomLevel == 1) + } + + it("should parse accumulo scheme") { + val path = GeoTrellisPath.parse("accumulo://root:@localhost/fake?attributes=attributes&layers=tiles&layer=foo&zoom=1") + assert(path.value == "accumulo://root:@localhost/fake?attributes=attributes&layers=tiles") + assert(path.layerName == "foo") + assert(path.zoomLevel == 1) + } + it("should parse absolute file scheme with gt+ prefix") { val path = GeoTrellisPath.parse("gt+file:///absolute/path?layer=foo&zoom=1") assert(path.value == "file:///absolute/path") @@ -92,9 +106,9 @@ class GeoTrellisPathSpec extends AnyFunSpec { assert(path.layerName == "foo") } - it("should ignore invalid parameters") { + it("should not ignore invalid parameters") { val path = GeoTrellisPath.parse("file:///foo/bar?layer=baz&zoom=1&invalid=not&nope=1") - assert(path == GeoTrellisPath("file:///foo/bar", "baz", 1, None)) + assert(path == GeoTrellisPath("file:///foo/bar?invalid=not&nope=1", "baz", 1, None)) } } }