diff --git a/martin-core/src/tiles/mbtiles/source.rs b/martin-core/src/tiles/mbtiles/source.rs index 41b251efc..51bbefd33 100644 --- a/martin-core/src/tiles/mbtiles/source.rs +++ b/martin-core/src/tiles/mbtiles/source.rs @@ -7,12 +7,12 @@ use std::sync::Arc; use async_trait::async_trait; use martin_tile_utils::{TileCoord, TileData, TileInfo}; -use mbtiles::{MbtError, MbtilesPool}; +use mbtiles::{MbtError, MbtType, MbtilesPool}; use tilejson::TileJSON; use tracing::trace; use crate::tiles::mbtiles::MbtilesError; -use crate::tiles::{BoxedSource, MartinCoreResult, Source, UrlQuery}; +use crate::tiles::{BoxedSource, MartinCoreResult, Source, Tile, UrlQuery}; /// Tile source that reads from `MBTiles` files. #[derive(Clone)] @@ -21,6 +21,7 @@ pub struct MbtSource { mbtiles: Arc, tilejson: TileJSON, tile_info: TileInfo, + mbt_type: MbtType, } #[expect(clippy::missing_fields_in_debug)] @@ -29,6 +30,7 @@ impl Debug for MbtSource { f.debug_struct("MbtSource") .field("id", &self.id) .field("path", &self.mbtiles.as_ref()) + .field("mbt_type", &self.mbt_type) .finish() } } @@ -51,15 +53,29 @@ impl MbtSource { .detect_format(&meta.tilejson) .await .and_then(|v| v.ok_or(MbtError::NoTilesFound)) - .map_err(|e| MbtilesError::InvalidMetadata(e.to_string(), path))?; + .map_err(|e| MbtilesError::InvalidMetadata(e.to_string(), path.clone()))?; + + let mbt_type = mbt + .detect_type() + .await + .map_err(|e| MbtilesError::InvalidMetadata(e.to_string(), path.clone()))?; Ok(Self { id, mbtiles: Arc::new(mbt), tilejson: meta.tilejson, tile_info, + mbt_type, }) } + + /// Maps `MbtError` to `MbtilesError`, preserving source ID context for `SqlxError`. + fn map_mbt_error(error: MbtError, id: String) -> MbtilesError { + match error { + MbtError::SqlxError(_) => MbtilesError::AcquireConnError(id), + other => MbtilesError::MbtilesLibraryError(other), + } + } } #[async_trait] @@ -98,7 +114,7 @@ impl Source for MbtSource { .mbtiles .get_tile(xyz.z, xyz.x, xyz.y) .await - .map_err(|_| MbtilesError::AcquireConnError(self.id.clone()))? + .map_err(|e| Self::map_mbt_error(e, self.id.clone()))? { Ok(tile) } else { @@ -109,4 +125,29 @@ impl Source for MbtSource { Ok(Vec::new()) } } + + async fn get_tile_with_etag( + &self, + xyz: TileCoord, + _url_query: Option<&UrlQuery>, + ) -> MartinCoreResult { + if let Some((data, hash)) = self + .mbtiles + .get_tile_and_hash(self.mbt_type, xyz.z, xyz.x, xyz.y) + .await + .map_err(|e| Self::map_mbt_error(e, self.id.clone()))? + { + if let Some(hash_str) = hash { + Ok(Tile::new_with_etag(data, self.tile_info, hash_str)) + } else { + Ok(Tile::new_hash_etag(data, self.tile_info)) + } + } else { + trace!( + "Couldn't find tile data in {}/{}/{} of {}", + xyz.z, xyz.x, xyz.y, &self.id + ); + Ok(Tile::new_hash_etag(Vec::new(), self.tile_info)) + } + } } diff --git a/tests/fixtures/mbtiles/webp.sql b/tests/fixtures/mbtiles/webp.sql index 08c7c22e9..599b73446 100644 --- a/tests/fixtures/mbtiles/webp.sql +++ b/tests/fixtures/mbtiles/webp.sql @@ -12,10 +12,10 @@ INSERT INTO metadata VALUES ('center','0,0,0'), ('minzoom','0'), ('maxzoom','0'); -CREATE TABLE IF NOT EXISTS "tiles"( - zoom_level int, - tile_column int, - tile_row int, +CREATE TABLE tiles ( + zoom_level integer, + tile_column integer, + tile_row integer, tile_data blob ); INSERT INTO tiles VALUES(0,0,0,x'524946463A000000574542505650380A0000002F000000');