move tile query to db

This commit is contained in:
Stepan Kuzmin 2018-03-23 19:47:44 +03:00
parent 25e4a8b8cb
commit 31ec5f8615
6 changed files with 103 additions and 85 deletions

34
Cargo.lock generated
View File

@ -52,7 +52,7 @@ dependencies = [
"percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
"sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"skeptic 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -233,8 +233,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"semver 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -666,7 +666,7 @@ dependencies = [
[[package]]
name = "itoa"
version = "0.4.0"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -744,8 +744,8 @@ dependencies = [
"postgres 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
"r2d2 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
"r2d2_postgres 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -1191,7 +1191,7 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1201,23 +1201,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde"
version = "1.0.33"
version = "1.0.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde_derive"
version = "1.0.33"
version = "1.0.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive_internals 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive_internals 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.12.14 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_derive_internals"
version = "0.21.0"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1230,9 +1230,9 @@ version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"itoa 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1774,7 +1774,7 @@ dependencies = [
"checksum indexmap 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b9378f1f3923647a9aea6af4c6b5de68cc8a71415459ad25ef191191c48f5b7"
"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08"
"checksum ipconfig 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9ec4e18c0a0d4340870c14284293632d8421f419008371422dd327892b88877c"
"checksum itoa 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "92a9df60778f789c37f76778ae8d0a2471c41baa8b059d98a5873c978f549587"
"checksum itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c069bbec61e1ca5a596166e55dfe4773ff745c3d16b700013bcaff9a6df2c682"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a"
"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73"
@ -1838,9 +1838,9 @@ dependencies = [
"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
"checksum semver 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bee2bc909ab2d8d60dab26e8cad85b25d795b14603a0dcb627b78b9d30b6454b"
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
"checksum serde 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)" = "4fe95aa0d46f04ce5c3a88bdcd4114ecd6144ed0b2725ebca2f1127744357807"
"checksum serde_derive 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)" = "23b163a6ce7e1aa897919f9d8e40bd1f8a6f95342ed57727ae31387a01a7a356"
"checksum serde_derive_internals 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)" = "370aa477297975243dc914d0b0e1234927520ec311de507a560fbd1c80f7ab8c"
"checksum serde 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)" = "0e100d00fb985a5bf16b857a436450e404fa613de3321b2e383947a93cbd75df"
"checksum serde_derive 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)" = "86daebd995aa948b069d886f2105f2425cd66103049855e45c15c58c573f12c5"
"checksum serde_derive_internals 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6b3f714f52a41e371c5e141e9dafcead60921349bec76b44d79000c88aba3cfc"
"checksum serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "5c508584d9913df116b91505eec55610a2f5b16e9ed793c46e4d0152872b3e74"
"checksum sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d"
"checksum sha2 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7daca11f2fdb8559c4f6c588386bed5e2ad4b6605c1442935a7f08144a918688"

View File

@ -4,8 +4,11 @@ use r2d2::{Config, Pool, PooledConnection};
use std::error::Error;
use std::io;
use super::utils;
use super::source::Source;
// static GET_SOURCES_QUERY: &'static str = include_str!("scripts/get_sources.sql");
pub type PostgresPool = Pool<PostgresConnectionManager>;
pub type PostgresConnection = PooledConnection<PostgresConnectionManager>;
@ -25,10 +28,11 @@ impl Actor for DbExecutor {
#[derive(Debug)]
pub struct GetTile {
pub source: Source,
pub z: u32,
pub x: u32,
pub y: u32,
pub source: Source,
pub condition: Option<String>,
}
impl Message for GetTile {
@ -40,7 +44,43 @@ impl Handler<GetTile> for DbExecutor {
fn handle(&mut self, msg: GetTile, _: &mut Self::Context) -> Self::Result {
let conn = self.0.get().unwrap();
let query = msg.source.get_query(msg.z, msg.x, msg.y, None);
let source = msg.source;
let mercator_bounds = utils::tilebbox(msg.z, msg.x, msg.y);
let (geometry_column_mercator, original_bounds) = if source.srid == 3857 {
(source.geometry_column.clone(), mercator_bounds.clone())
} else {
(
format!("ST_Transform({0}, 3857)", source.geometry_column),
format!("ST_Transform({0}, {1})", mercator_bounds, source.srid),
)
};
let columns: Vec<String> = source
.properties
.keys()
.map(|column| format!("\"{0}\"", column))
.collect();
let properties = columns.join(",");
let condition = msg.condition
.map_or("".to_string(), |condition| format!("AND {}", condition));
let query = format!(
include_str!("scripts/get_tile.sql"),
id = source.id,
geometry_column = source.geometry_column,
geometry_column_mercator = geometry_column_mercator,
original_bounds = original_bounds,
mercator_bounds = mercator_bounds,
extent = source.extent,
buffer = source.buffer,
clip_geom = source.clip_geom,
properties = properties,
condition = condition,
);
let tile: Vec<u8> = conn.query(&query, &[])
.map(|rows| rows.get(0).get("st_asmvt"))

View File

@ -59,13 +59,16 @@ fn tile(req: HttpRequest<State>) -> Box<Future<Item = HttpResponse, Error = Erro
.ok_or(error::ErrorNotFound("invalid y"))
.unwrap();
let condition = None;
req.state()
.db
.send(GetTile {
source: source.clone(),
z: z,
x: x,
y: y,
source: source.clone(),
condition: condition,
})
.from_err()
.and_then(|res| match res {

View File

@ -0,0 +1,20 @@
WITH columns AS (
SELECT
ns.nspname AS table_schema,
class.relname AS table_name,
attr.attname AS column_name,
trim(leading '_' from tp.typname) AS type_name
FROM pg_attribute attr
JOIN pg_catalog.pg_class AS class ON class.oid = attr.attrelid
JOIN pg_catalog.pg_namespace AS ns ON ns.oid = class.relnamespace
JOIN pg_catalog.pg_type AS tp ON tp.oid = attr.atttypid
WHERE NOT attr.attisdropped AND attr.attnum > 0)
SELECT
f_table_schema, f_table_name, f_geometry_column, srid, type,
jsonb_object_agg(columns.column_name, columns.type_name) as properties
FROM geometry_columns
LEFT JOIN columns ON
geometry_columns.f_table_schema = columns.table_schema AND
geometry_columns.f_table_name = columns.table_name AND
geometry_columns.f_geometry_column != columns.column_name
GROUP BY f_table_schema, f_table_name, f_geometry_column, srid, type;

14
src/scripts/get_tile.sql Normal file
View File

@ -0,0 +1,14 @@
WITH bounds AS (SELECT {mercator_bounds} as mercator, {original_bounds} as original)
SELECT ST_AsMVT(tile, '{id}', {extent}, 'geom') FROM (
SELECT
ST_AsMVTGeom(
{geometry_column_mercator},
bounds.mercator,
{extent},
{buffer},
{clip_geom}
) AS geom,
{properties}
FROM {id}, bounds
WHERE {geometry_column} && bounds.original {condition}
) AS tile WHERE geom IS NOT NULL

View File

@ -1,4 +1,3 @@
use std::borrow::Cow;
use std::collections::HashMap;
use std::error::Error;
@ -10,75 +9,17 @@ pub struct Source {
pub id: String,
schema: String,
table: String,
geometry_column: String,
srid: u32,
extent: u32,
buffer: u32,
clip_geom: bool,
pub geometry_column: String,
pub srid: u32,
pub extent: u32,
pub buffer: u32,
pub clip_geom: bool,
geometry_type: String,
properties: HashMap<String, String>,
pub properties: HashMap<String, String>,
}
pub type Sources = HashMap<String, Source>;
impl Source {
fn geometry_column_mercator(&self) -> Cow<str> {
if self.srid == 3857 {
self.geometry_column.as_str().into()
} else {
format!("ST_Transform({0}, 3857)", self.geometry_column).into()
}
}
fn properties_query(&self) -> String {
let keys: Vec<String> = self.properties
.keys()
.map(|key| format!("\"{0}\"", key))
.collect();
keys.join(",")
}
pub fn get_query(&self, z: u32, x: u32, y: u32, condition: Option<String>) -> String {
let mercator_bounds = utils::tilebbox(z, x, y);
let original_bounds: Cow<str> = if self.srid == 3857 {
mercator_bounds.as_str().into()
} else {
format!("ST_Transform({0}, {1})", mercator_bounds, self.srid).into()
};
let query = format!(
"WITH bounds AS (SELECT {mercator_bounds} as mercator, {original_bounds} as original) \
SELECT ST_AsMVT(tile, '{id}', {extent}, 'geom') FROM (\
SELECT \
ST_AsMVTGeom(\
{geometry_column_mercator},\
bounds.mercator,\
{extent},\
{buffer},\
{clip_geom}\
) AS geom,\
{properties} \
FROM {id}, bounds \
WHERE {geometry_column} && bounds.original {condition}\
) AS tile WHERE geom IS NOT NULL",
id = self.id,
geometry_column = self.geometry_column,
geometry_column_mercator = self.geometry_column_mercator(),
original_bounds = original_bounds,
mercator_bounds = mercator_bounds,
extent = self.extent,
buffer = self.buffer,
clip_geom = self.clip_geom,
properties = self.properties_query(),
condition = condition.map_or("".to_string(), |condition| format!("AND {}", condition)),
);
query
}
}
pub fn get_sources(conn: PostgresConnection) -> Result<HashMap<String, Source>, Box<Error>> {
let query = "
WITH columns AS (