Adapt QueryRewriter to new requirements
This commit is contained in:
@@ -1,5 +1,10 @@
|
||||
var _ = require('underscore');
|
||||
var TableNameParser = require('./table_name_parser');
|
||||
|
||||
// this is meant as a hack for development (otherwise we'd be coupling
|
||||
// this to Camshaft impolementation)
|
||||
var queryBuilder = require('camshaft/lib/filter/query-builder');
|
||||
|
||||
function OverviewsQueryRewriter(options) {
|
||||
|
||||
this.options = options;
|
||||
@@ -119,26 +124,34 @@ function replace_table_in_query(sql, old_table_name, replacement) {
|
||||
return sql.replace(new RegExp(regexp, 'g'), replacement);
|
||||
}
|
||||
|
||||
function overviews_query(query, overviews, zoom_level_expression) {
|
||||
|
||||
function replace_table_in_query_with_schema(query, table, schema, replacement) {
|
||||
if ( replacement ) {
|
||||
query = replace_table_in_query(query, table, replacement);
|
||||
var parsed_table = TableNameParser.parse(table);
|
||||
if (!parsed_table.schema && schema) {
|
||||
// replace also the qualified table name, if the table wasn't qualified
|
||||
parsed_table.schema = schema;
|
||||
table = TableNameParser.table_identifier(parsed_table);
|
||||
query = replace_table_in_query(query, table, replacement);
|
||||
}
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
// Build query to use overviews for a variant zoom level (given by a expression to
|
||||
// be evaluated by the database server)
|
||||
function overviews_query_with_zoom_expression(query, overviews, zoom_level_expression) {
|
||||
var replaced_query = query;
|
||||
var sql = "WITH\n _vovw_scale AS ( SELECT " + zoom_level_expression + " AS _vovw_z )";
|
||||
var replacement;
|
||||
for ( var table in overviews ) {
|
||||
if (overviews.hasOwnProperty(table)) {
|
||||
var table_overviews = overviews[table];
|
||||
var table_view = overviews_view_name(table);
|
||||
var schema = table_overviews.schema;
|
||||
replacement = "(\n" + overviews_view_for_table(table, table_overviews) + "\n ) AS " + table_view;
|
||||
replaced_query = replace_table_in_query(replaced_query, table, replacement);
|
||||
var parsed_table = TableNameParser.parse(table);
|
||||
if (!parsed_table.schema && schema) {
|
||||
// replace also the qualified table name, if the table wasn't qualified
|
||||
parsed_table.schema = schema;
|
||||
table = TableNameParser.table_identifier(parsed_table);
|
||||
replaced_query = replace_table_in_query(replaced_query, table, replacement);
|
||||
}
|
||||
}
|
||||
}
|
||||
_.each(_.keys(overviews), function(table) {
|
||||
var table_overviews = overviews[table];
|
||||
var table_view = overviews_view_name(table);
|
||||
var schema = table_overviews.schema;
|
||||
replacement = "(\n" + overviews_view_for_table(table, table_overviews) + "\n ) AS " + table_view;
|
||||
replaced_query = replace_table_in_query_with_schema(replaced_query, table, schema, replacement);
|
||||
});
|
||||
if ( replaced_query !== query ) {
|
||||
sql += "\n";
|
||||
sql += replaced_query;
|
||||
@@ -148,6 +161,54 @@ function overviews_query(query, overviews, zoom_level_expression) {
|
||||
return sql;
|
||||
}
|
||||
|
||||
// Build query to use overviews for a specific zoom level value
|
||||
function overviews_query_with_definite_zoom(query, overviews, zoom_level) {
|
||||
var replaced_query = query;
|
||||
var replacement;
|
||||
_.each(_.keys(overviews), function(table) {
|
||||
var table_overviews = overviews[table];
|
||||
var schema = table_overviews.schema;
|
||||
replacement = overview_table_for_zoom_level(table_overviews, zoom_level);
|
||||
replaced_query = replace_table_in_query_with_schema(replaced_query, table, schema, replacement);
|
||||
});
|
||||
return replaced_query;
|
||||
}
|
||||
|
||||
// Find a suitable overview table for a specific zoom_level
|
||||
function overview_table_for_zoom_level(table_overviews, zoom_level) {
|
||||
var overview_table;
|
||||
if ( table_overviews ) {
|
||||
overview_table = table_overviews[zoom_level];
|
||||
if ( !overview_table ) {
|
||||
_.every(_.keys(table_overviews).sort(function(x,y){ return x-y; }), function(overview_zoom) {
|
||||
if ( +overview_zoom > +zoom_level ) {
|
||||
overview_table = table_overviews[overview_zoom];
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if ( overview_table ) {
|
||||
overview_table = overview_table.table;
|
||||
}
|
||||
return overview_table;
|
||||
}
|
||||
|
||||
function apply_filters_to_query(query, filters) {
|
||||
// TODO: it'd be nice to have a public API in camshaft to apply filters!
|
||||
if ( filters && !_.isEmpty(filters)) {
|
||||
query = queryBuilder.getSql(query, filters);
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
function zoom_level_for_bounding_box(query, bounding_box) {
|
||||
// TODO: implement
|
||||
return '100'; // force use of base table
|
||||
}
|
||||
|
||||
// Transform an SQL query so that it uses overviews.
|
||||
// overviews contains metadata about the overviews to be used:
|
||||
// { 'table-name': {1: { table: 'overview-table-1' }, ... }, ... }
|
||||
@@ -166,13 +227,50 @@ function overviews_query(query, overviews, zoom_level_expression) {
|
||||
// doesnn't prevent substitution inside literals).
|
||||
// But the transformation will currently only be applied to simple queries
|
||||
// of the form detected by the overviews_supported_query function.
|
||||
OverviewsQueryRewriter.prototype.query = function(query, data) {
|
||||
var overviews = this.overviews_metadata(data);
|
||||
if ( !overviews || !this.is_supported_query(query)) {
|
||||
OverviewsQueryRewriter.prototype.query = function(query, data, options) {
|
||||
options = options || {};
|
||||
|
||||
var overviews = data && data.overviews;
|
||||
var unfiltered_query = data && data.unfiltered_query;
|
||||
var filters = data && data.filters;
|
||||
|
||||
if ( !unfiltered_query ) {
|
||||
unfiltered_query = query;
|
||||
}
|
||||
|
||||
if ( !overviews || !this.is_supported_query(unfiltered_query)) {
|
||||
return query;
|
||||
}
|
||||
var zoom_level_expression = this.options.zoom_level || '0';
|
||||
return overviews_query(query, overviews, zoom_level_expression);
|
||||
|
||||
var rewritten_query;
|
||||
|
||||
var zoom_level_expression = this.options.zoom_level;
|
||||
var zoom_level;
|
||||
if ( _.has(options, 'bounding_box') ) {
|
||||
// The presence of this key, even if it has a null value indicates the
|
||||
// query cannot handle dynamic zoom expressinos (is not for the tiler)
|
||||
zoom_level = zoom_level_for_bounding_box(unfiltered_query, options.bounding_box);
|
||||
} else if ( options.zoom_level ) {
|
||||
zoom_level = options.zoom_level;
|
||||
}
|
||||
if ( !zoom_level && !zoom_level_expression ) {
|
||||
zoom_level = '0';
|
||||
}
|
||||
|
||||
if ( zoom_level || zoom_level === '0' || zoom_level === 0 ) {
|
||||
rewritten_query = overviews_query_with_definite_zoom(unfiltered_query, overviews, zoom_level);
|
||||
} else {
|
||||
rewritten_query = overviews_query_with_zoom_expression(unfiltered_query, overviews, zoom_level_expression);
|
||||
}
|
||||
|
||||
if ( rewritten_query === unfiltered_query ) {
|
||||
// could not or didn't need to alter the query
|
||||
rewritten_query = query;
|
||||
} else {
|
||||
rewritten_query = apply_filters_to_query(rewritten_query, filters);
|
||||
}
|
||||
|
||||
return rewritten_query;
|
||||
};
|
||||
|
||||
OverviewsQueryRewriter.prototype.is_supported_query = function(sql) {
|
||||
@@ -188,7 +286,3 @@ OverviewsQueryRewriter.prototype.is_supported_query = function(sql) {
|
||||
);
|
||||
return !!(sql.match(unwrapped_query) || sql.match(wrapped_query));
|
||||
};
|
||||
|
||||
OverviewsQueryRewriter.prototype.overviews_metadata = function(data) {
|
||||
return data && data.overviews;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user