add condition filtering support

This commit is contained in:
Stepan Kuzmin 2018-01-22 20:01:44 +03:00
parent 77cd4ae3d2
commit 1ac60664a9
5 changed files with 114 additions and 47 deletions

43
Cargo.lock generated
View File

@ -44,6 +44,18 @@ dependencies = [
"generic-array 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bodyparser"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"iron 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"persistent 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"plugin 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "byte-tools"
version = "0.2.0"
@ -106,7 +118,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "env_logger"
version = "0.5.2"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"atty 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -293,16 +305,26 @@ dependencies = [
"time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "mapbox_expressions_to_sql"
version = "0.1.0"
source = "git+https://github.com/stepankuzmin/rust-mapbox-expressions-to-sql#b59d485b52884b6a523e81154868d48372539ea1"
dependencies = [
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "martin"
version = "0.1.0"
dependencies = [
"env_logger 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"iron 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"iron-test 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"logger 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"mapbox_expressions_to_sql 0.1.0 (git+https://github.com/stepankuzmin/rust-mapbox-expressions-to-sql)",
"persistent 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"postgres 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)",
"r2d2 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
@ -313,6 +335,7 @@ dependencies = [
"serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
"tilejson 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"urlencoded 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -797,6 +820,17 @@ dependencies = [
"percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "urlencoded"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bodyparser 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"iron 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"plugin 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "utf8-ranges"
version = "1.0.0"
@ -865,6 +899,7 @@ dependencies = [
"checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9"
"checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf"
"checksum block-buffer 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1339a1042f5d9f295737ad4d9a6ab6bf81c84a933dba110b9200cd6d1448b814"
"checksum bodyparser 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f023abfa58aad6f6bc4ae0630799e24d5ee0ab8bb2e49f651d9b1f9aa4f52f30"
"checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40"
"checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23"
"checksum bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1b7db437d718977f6dc9b2e3fd6fc343c02ac6b899b73fdd2179163447bd9ce9"
@ -874,7 +909,7 @@ dependencies = [
"checksum crypto-mac 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "779015233ac67d65098614aec748ac1c756ab6677fa2e14cf8b37c08dfed1198"
"checksum digest 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e5b29bf156f3f4b3c4f610a25ff69370616ae6e0657d416de22645483e72af0a"
"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
"checksum env_logger 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f98112cf5e30982be3514040871a6f310504a7406ce1936691649353ec0607e9"
"checksum env_logger 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f15f0b172cb4f52ed5dbf47f774a387cd2315d1bf7894ab5af9b083ae27efa5a"
"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
"checksum fallible-iterator 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6034a9c9dfce417c7710128d202eef406878cd2fe294e76e2ee05259c9b042d"
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
@ -897,6 +932,7 @@ dependencies = [
"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b"
"checksum log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "89f010e843f2b1a31dbd316b3b8d443758bc634bed37aabade59c686d644e0a2"
"checksum logger 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6c9172cb4c2f6c52117e25570983edcbb322f130b1031ae5d5d6b1abe7eeb493"
"checksum mapbox_expressions_to_sql 0.1.0 (git+https://github.com/stepankuzmin/rust-mapbox-expressions-to-sql)" = "<none>"
"checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376"
"checksum md5 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b6d9aab58e540f50b59d5cfa7f0da4c3d437476890e1e0b6206e230dce55a23c"
"checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a"
@ -956,6 +992,7 @@ dependencies = [
"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
"checksum unsafe-any 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f30360d7979f5e9c6e6cea48af192ea8fab4afb3cf72597154b8f08935bc9c7f"
"checksum url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fa35e768d4daf1d85733418a49fb42e10d7f633e394fccab4ab7aba897053fe2"
"checksum urlencoded 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0a52f50139118b60ae91af08bf15ed158817d34b91b9d24c11ffbe21195d33e3"
"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
"checksum uuid 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcc7e3b898aa6f6c08e5295b6c89258d1331e9ac578cc992fb818759951bdc22"
"checksum version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6b772017e347561807c1aa192438c5fd74242a670a6cffacc40f2defd1dc069d"

View File

@ -12,19 +12,21 @@ name = "martin"
path = "src/main.rs"
[dependencies]
log = "0.4.1"
iron = "0.6.0"
regex = "0.2.2"
logger = "0.4.0"
iron-test = "0.6.0"
env_logger = "0.5.1"
rererouter = "0.1.1"
persistent = "0.4.0"
iron = "0.6.0"
iron-test = "0.6.0"
lazy_static = "0.2.11"
log = "0.4.1"
logger = "0.4.0"
mapbox_expressions_to_sql = { git = "https://github.com/stepankuzmin/rust-mapbox-expressions-to-sql" }
persistent = "0.4.0"
postgres = { version = "0.15.1", features = ["with-time", "with-uuid"] }
r2d2 = "0.7.4"
r2d2_postgres = "0.13.0"
regex = "0.2.2"
rererouter = "0.1.1"
serde = "1.0"
serde_derive = "1.0"
serde_json = "1.0"
tilejson = "0.1.0"
r2d2 = "0.7.4"
r2d2_postgres = "0.13.0"
postgres = { version = "0.15.1", features = ["with-time", "with-uuid"] }
urlencoded = "0.6.0"

View File

@ -1,16 +1,18 @@
extern crate iron_test;
extern crate iron;
#[macro_use] extern crate log;
extern crate logger;
extern crate mapbox_expressions_to_sql;
extern crate persistent;
extern crate r2d2_postgres;
extern crate r2d2;
extern crate regex;
extern crate rererouter;
#[macro_use] extern crate serde_derive;
extern crate serde_json;
extern crate serde;
extern crate tilejson;
extern crate urlencoded;
#[macro_use] extern crate log;
#[macro_use] extern crate serde_derive;
use iron::prelude::Chain;
use logger::Logger;

View File

@ -1,8 +1,10 @@
use regex::Captures;
use iron::prelude::{Plugin};
use iron::{status, mime, Request, Response, IronResult};
use iron::prelude::{Plugin};
use mapbox_expressions_to_sql;
use persistent::Read;
use regex::Captures;
use serde_json;
use urlencoded::UrlEncodedQuery;
use super::db;
use super::tileset;
@ -31,6 +33,12 @@ pub fn tileset(req: &mut Request, caps: Captures) -> IronResult<Response> {
Ok(Response::with((status::Ok, serialized_tilejson)))
}
fn get_filter<'a>(req: &'a mut Request) -> Option<&'a String> {
req.get_ref::<UrlEncodedQuery>().ok()
.and_then(|query| query.get("filter"))
.and_then(|filter| filter.last())
}
pub fn tile(req: &mut Request, caps: Captures) -> IronResult<Response> {
let tilesets = req.get::<Read<tileset::Tilesets>>().unwrap();
let tileset = match tilesets.get(&caps["tileset"]) {
@ -41,7 +49,7 @@ pub fn tile(req: &mut Request, caps: Captures) -> IronResult<Response> {
let conn = match db::get_connection(req) {
Ok(conn) => conn,
Err(error) => {
eprintln!("Couldn't get a connection to postgres: {}", error);
error!("Couldn't get a connection to postgres: {}", error);
return Ok(Response::with((status::InternalServerError)));
}
};
@ -50,10 +58,24 @@ pub fn tile(req: &mut Request, caps: Captures) -> IronResult<Response> {
let x: &i32 = &caps["x"].parse().unwrap();
let y: &i32 = &caps["y"].parse().unwrap();
let tile = match tileset::get_tile(conn, &tileset, z, x, y) {
let filter = get_filter(req).cloned();
let condition = match filter {
Some(filter) => {
match mapbox_expressions_to_sql::parse(&filter) {
Ok(condition) => Some(format!("WHERE {}", condition)),
Err(error) => {
error!("Couldn't parse expression: {:?}", error);
return Ok(Response::with((status::InternalServerError)));
}
}
},
None => None
};
let tile = match tileset::get_tile(conn, &tileset, z, x, y, condition) {
Ok(tile) => tile,
Err(error) => {
eprintln!("Couldn't get a tile: {}", error);
error!("Couldn't get a tile: {}", error);
return Ok(Response::with((status::InternalServerError)));
}
};

View File

@ -9,12 +9,37 @@ pub struct Tileset {
schema: String,
pub table: String,
geometry_column: String,
transformed_geometry: String,
srid: i32,
extent: i32,
buffer: i32,
clip_geom: bool,
geometry_type: String,
query: String
geometry_type: String
}
impl Tileset {
pub fn get_query(&self, condition: Option<String>) -> String {
let query = format!(
"SELECT ST_AsMVT(q, '{1}', {3}, 'geom') FROM (\
SELECT ST_AsMVTGeom(\
{2}, \
TileBBox($1, $2, $3, 3857), \
{3}, \
{4}, \
{5}\
) AS geom FROM {0}.{1} {6}\
) AS q;",
self.schema,
self.table,
self.transformed_geometry,
self.extent,
self.buffer,
self.clip_geom,
condition.unwrap_or("".to_string())
);
query
}
}
pub struct Tilesets;
@ -48,35 +73,16 @@ pub fn get_tilesets(conn: PostgresConnection) -> Result<HashMap<String, Tileset>
format!("ST_Transform({0}, 3857)", geometry_column)
};
let query = format!(
"SELECT ST_AsMVT(q, '{1}', {4}, '{2}') FROM (\
SELECT ST_AsMVTGeom(\
{3}, \
TileBBox($1, $2, $3, 3857), \
{4}, \
{5}, \
{6}\
) AS geom FROM {0}.{1}\
) AS q;",
schema,
table,
geometry_column,
transformed_geometry,
default_extent,
default_buffer,
default_clip_geom
);
let tileset = Tileset {
schema: schema,
table: table,
geometry_column: geometry_column,
transformed_geometry: transformed_geometry,
srid: srid,
extent: default_extent,
buffer: default_buffer,
clip_geom: default_clip_geom,
geometry_type: row.get("type"),
query: query
geometry_type: row.get("type")
};
tilesets.insert(id, tileset);
@ -85,10 +91,8 @@ pub fn get_tilesets(conn: PostgresConnection) -> Result<HashMap<String, Tileset>
Ok(tilesets)
}
pub fn get_tile(conn: PostgresConnection, tileset: &Tileset, z: &i32, x: &i32, y: &i32) -> Result<Vec<u8>, Box<Error>> {
debug!("get_tile({}, {}, {})", z, x, y);
let rows = try!(conn.query(&tileset.query, &[&z, &x, &y]));
pub fn get_tile<'a>(conn: PostgresConnection, tileset: &Tileset, z: &i32, x: &i32, y: &i32, condition: Option<String>) -> Result<Vec<u8>, Box<Error>> {
let rows = try!(conn.query(&tileset.get_query(condition), &[&z, &x, &y]));
let tile = rows.get(0).get("st_asmvt");
Ok(tile)
}