From 75bdbbfb80429db2b3f2db7b6bf3eabc8955288c Mon Sep 17 00:00:00 2001 From: javi Date: Wed, 2 Dec 2015 14:11:14 +0100 Subject: [PATCH] removed provider --- lib/torque/provider/filterableJson.js | 883 -------------------------- 1 file changed, 883 deletions(-) delete mode 100644 lib/torque/provider/filterableJson.js diff --git a/lib/torque/provider/filterableJson.js b/lib/torque/provider/filterableJson.js deleted file mode 100644 index 6946a03..0000000 --- a/lib/torque/provider/filterableJson.js +++ /dev/null @@ -1,883 +0,0 @@ -var torque = require('../'); -var _ = require('underscore'); -var Profiler = require('../profiler'); - - var Uint8Array = torque.types.Uint8Array; - var Int32Array = torque.types.Int32Array; - var Uint32Array = torque.types.Uint32Array; - - // format('hello, {0}', 'rambo') -> "hello, rambo" - function format(str) { - for(var i = 1; i < arguments.length; ++i) { - var attrs = arguments[i]; - for(var attr in attrs) { - str = str.replace(RegExp('\\{' + attr + '\\}', 'g'), attrs[attr]); - } - } - return str; - } - - var filterableJson = function (options) { - this._ready = false; - this._tileQueue = []; - this.options = options; - this._filters = {}; - this._tileProcessingQueue=[] - this._workers = []; - this._maxWorkerNo = this.options.maxWorkerNo || 4; - - this.setupWorkerPool() - - this.options.tiler_protocol = options.tiler_protocol || 'http'; - this.options.tiler_domain = options.tiler_domain || 'cartodb.com'; - this.options.tiler_port = options.tiler_port || 80; - - // check options - if (options.resolution === undefined ) throw new Error("resolution should be provided"); - if(options.start === undefined) { - this._fetchKeySpan(); - } else { - this._setReady(true); - } - }; - - - - filterableJson.prototype = { - - setupWorkerPool:function(){ - for(var i=0; i< this._maxWorkerNo; i++){ - this._workers.push(this.createProccessTileWorker()) - } - }, - - getAvalaibleWorker:function(){ - return this._workers.pop() - }, - - releaseWorker:function(worker){ - this._workers.push(worker) - this.processNextTileRequestInQueue() - }, - - processNextTileRequestInQueue:function(){ - if(this._tileProcessingQueue.length>0){ - job = this._tileProcessingQueue.pop() - this.requestWorker(job.rows,job.coord,job.zoom, job.options, job.callback) - } - }, - - requestWorker:function(rows,coord,zoom,options,callback){ - worker = this.getAvalaibleWorker() - self = this - if(worker){ - worker.onmessage = function(e){ - callback(e.data) - self.releaseWorker(this) - } - worker.postMessage(JSON.stringify({rows: rows, coord: {x:coord.x,y:coord.y}, zoom:zoom, options: options})) - } - else{ - this.addToTileProcessingQueue(rows,coord,zoom,options,callback) - } - }, - - addToTileProcessingQueue:function(rows,coord,zoom, options, callback){ - this._tileProcessingQueue.push({rows:rows, coord:coord, zoom:zoom, options: options, callback:callback}) - }, - - /** - * Creates a worker to process the tile - */ - createProccessTileWorker: function(){ - var workerFunction = "var proccessTile ="+ this.proccessTileSerial.toString() - var wrapper = "; self.onmessage = function(e){var data = JSON.parse(e.data); JSON.stringify(self.postMessage(proccessTile(data.rows,data.coord, data.zoom, data.options)))}" - var script = workerFunction + wrapper; - var blob = new Blob([script], {type: "text/javascript"}) - var worker = new Worker(window.URL.createObjectURL(blob)) - return worker - }, - - proccessTile: function(rows, coord, zoom, callback){ - var self = this; - if(typeof(Worker) === "undefined"){ - callback(this.proccessTileSerial(rows,coord,zoom, this.options)) - } - else { - var workerSafeOptions = { - resolution: this.options.resolution, - fields: this.options.fields - } - this.requestWorker(rows, coord, zoom, workerSafeOptions, callback) - } - }, - - /** - * return the torque tile encoded in an efficient javascript - * structure: - * { - * x:Uint8Array x coordinates in tile reference system, normally from 0-255 - * y:Uint8Array y coordinates in tile reference system - * Index: Array index to the properties - * } - */ - proccessTileSerial: function(rows, coord, zoom, options) { - // utility function for hashing categories - var r; - var x = new Uint8Array(rows.length); - var y = new Uint8Array(rows.length); - - if(typeof(Profiler) != 'undefined') { - var prof_mem = Profiler.metric('ProviderJSON:mem'); - var prof_point_count = Profiler.metric('ProviderJSON:point_count'); - var prof_process_time = Profiler.metric('ProviderJSON:process_time').start() - } - - var categoryMapping = {} - var categoryMappingSize = {} - var fields = options.fields; - - for (var i = 0 ; i < fields.length; ++i) { - if (fields[i].type === 'cat') { - categoryMapping[i] = {}; - categoryMappingSize[i] = 0; - } - } - - // count number of steps - var maxDateSlots = Object.keys(rows[0].d).length; - var steps = maxDateSlots; - - - // reserve memory for all the steps - var timeIndex = new Int32Array(maxDateSlots + 1); //index-size - var timeCount = new Int32Array(maxDateSlots + 1); - var renderData = new Float32Array(rows.length * steps); //(this.options.valueDataType || type)(steps); - var renderDataPos = new Uint32Array(rows.length * steps); - - if(typeof(Profiler) !='undefined'){ - prof_mem.inc( - 4 * maxDateSlots + // timeIndex - 4 * maxDateSlots + // timeCount - steps + //renderData - steps * 4 - ); //renderDataPos - - prof_point_count.inc(rows.length); - } - - var rowsPerSlot = {}; - // var steps = _.range(maxDateSlots); - var steps = [] - - for(var i=0 ; i< maxDateSlots; i++){ - steps.push(i) - } - - // precache pixel positions - for (var r = 0; r < rows.length; ++r) { - var row = rows[r]; - x[r] = row.x * options.resolution; - // fix value when it's in the tile EDGE - // TODO: this should be fixed in SQL query - if (row.y === -1) { - y[r] = 0; - } else { - y[r] = row.y * options.resolution; - } - - var vals = row.d; - - for (var j = 0, len = steps.length; j < len; ++j) { - var rr = rowsPerSlot[steps[j]] || (rowsPerSlot[steps[j]] = []); - var k = 'f' + (j + 1) - var v = vals[k]; - if (options.fields[j].type === 'cat') { - var mapping = categoryMapping[j]; - var m = mapping[v] - if (!m) { - var count = ++categoryMappingSize[j]; - v = mapping[String(v)] = count; - } else { - v = m; - } - } - rr.push([r, v]); - } - - } - - // for each timeslot search active buckets - var renderDataIndex = 0; - var timeSlotIndex = 0; - var i = 0; - for(var i = 0; i <= maxDateSlots; ++i) { - var c = 0; - var slotRows = rowsPerSlot[i] - if(slotRows) { - for (var r = 0; r < slotRows.length; ++r) { - var rr = slotRows[r]; - ++c; - renderDataPos[renderDataIndex] = rr[0] - renderData[renderDataIndex] = rr[1]; - ++renderDataIndex; - } - } - timeIndex[i] = timeSlotIndex; - timeCount[i] = c; - timeSlotIndex += c; - } - - if(typeof(Profiler) !='undefined'){ - prof_process_time.end(); - } - - // invert the mapping - var invertedMapping = {} - for (var i = 0 ; i < fields.length; ++i) { - if (fields[i].type === 'cat') { - var cat = categoryMapping[i]; - invertedMapping[i] = {} - for (var k in cat) { - invertedMapping[i][cat[k]] = k; - } - } - } - - return { - x: x, - y: y, - z: zoom, - coord: { - x: coord.x, - y: coord.y, - z: zoom - }, - timeCount: timeCount, - timeIndex: timeIndex, - renderDataPos: renderDataPos, - renderData: renderData, - maxDate: maxDateSlots, - categories: invertedMapping - }; - }, - - // returns a tile resampled to `zoom` - resample: function (tile, zoom) { - }, - - _generateFilterSQLForCat: function(name, categories, exclusive, escape_quotes) { - return name + (exclusive ? " not in ": " in") + '(' + categories.map(function(c) { - if (escape_quotes) { - // escape ', double escape. one for javascript, another one for postgres - c = c.replace("'", "''''"); - return "''" + c + "''"; - } else { - c = c.replace("'", "''"); - return "'" + c + "'"; - } - }).join(',') + ')'; - }, - - _generateFilterSQLForRange: function(name,range) { - var result = "" - if (range.start) { - result += " " + name + " > " + range.start; - } - if (range.end) { - if (range.start) { - result += " and " - } - result += " " + name + " < " + range.end; - } - return result - }, - - _setFilters:function(filters){ - this.filters = filters - }, - - _generateFiltersSQL: function(escape_quotes, filter_columns) { - filter_columns = filter_columns || []; - escape_quotes = escape_quotes === undefined ? true: false; - var self = this; - return Object.keys(this._filters).map(function(filterName) { - if (_.contains(filter_columns, filterName)) { - return "" - } - var filter = self._filters[filterName] - if (filter) { - if (filter.type == 'range') { - return self._generateFilterSQLForRange(filterName, filter.range) - } - else if (filter.type == 'cat' && filter.categories.length) { - return self._generateFilterSQLForCat(filterName, filter.categories, filter.exclusive, escape_quotes) - } - else { - return "" - } - } - else{ - return "" - } - }).filter(function(f) { - return f.length > 0; - }).map(function(f) { - return "(" + f + ")"; - }).join(' and ') - }, - - url: function(subhost) { - var opts = this.options; - return opts.sql_api_template.replace('{user}', (opts.user_name || opts.user)).replace('{s}', subhost) + "/api/v1/sql"; - }, - - _hash: function(str) { - var hash = 0; - if (!str || str.length == 0) return hash; - for (var i = 0, l = str.length; i < l; ++i) { - hash = (( (hash << 5 ) - hash ) + str.charCodeAt(i)) | 0; - } - return hash; - }, - - _extraParams: function() { - if (this.options.extra_params) { - var p = []; - for(var k in this.options.extra_params) { - var v = this.options.extra_params[k]; - if (v) { - p.push(k + "=" + encodeURIComponent(v)); - } - } - return p.join('&'); - } - return null; - }, - - isHttps: function() { - return this.options.sql_api_protocol && this.options.sql_api_protocol === 'https'; - }, - - // execute actual query - sql: function(sql, callback, options) { - options = options || {}; - var subdomains = this.options.subdomains || 'abcd'; - url = this.url(subdomains[Math.abs(this._hash(sql))%subdomains.length]); - var extra = this._extraParams(); - torque.net.get( url + "?q=" + encodeURIComponent(sql) + (extra ? "&" + extra: ''), function (data) { - if(options.parseJSON) { - data = JSON.parse(data && data.responseText); - } - callback && callback(data); - }); - }, - - getTileData: function(coord, zoom, callback) { - if(!this._ready) { - this._tileQueue.push([coord, zoom, callback]); - } else { - this._getTileData(coord, zoom, callback); - } - }, - - _setReady: function(ready) { - this._ready = true; - this._processQueue(); - this.options.ready && this.options.ready(); - }, - - _processQueue: function() { - var item; - while (item = this._tileQueue.pop()) { - this._getTileData.apply(this, item); - } - }, - - _getTableSQL: function(coord, zoom) { - return format("(WITH opt as ( SELECT table_name as tt FROM selectivity(x:={x}, y:={y}, z:={z}, tables:=ARRAY[{overview_tables}], where_clause:='{filters}') where nrows > 5000 and cost < 400000 order by nrows asc limit 1) select (CASE WHEN EXISTS(select 1 from opt) THEN (select tt from opt) else '{table}' END))", { - overview_tables: this.options.overview_tables.map(function(t) { return "'" + t + "'"; }).join(','), - table: this.options.table, - z: zoom, - x: coord.x, - y: coord.y, - filters: this._generateFiltersSQL() - }); - }, - - /** - * `tile` the tile the point resides on - * `x` the x pixel coord on the tile - * 'y' the y pixel coord on the tile - * 'maxNo' the maximum number of points to return - * 'pixel tollerance around click' How many pixels to search around the click point - * @applyFilters: apply current filters to fetch the data - * 'callback' function(rows) returns an array of the data for that point - */ - getDataForTorquePixel: function(tile, x, y, maxNo, tolerance, applyFilters, callback){ - shift = 23 - tile.z - tolerance = tolerance || 20 - //TODO: use quadkey to filter - var sql = [ - "select * from {table}", - "where (quadkey between (xyz2range({x},{y},{z})).min and (xyz2range({x},{y},{z})).max) ", - "and (((quadkey_x & (255 << {shift})) >> {shift}) - {torque_tile_x}) between -{tolerance} and {tolerance}", - "and (((quadkey_y & (255 << {shift})) >> {shift}) - {torque_tile_y}) between -{tolerance} and {tolerance} " - ] - - if (applyFilters) { - var f = this._generateFiltersSQL(false); - if (f.length) { - sql.push("and (" + f + ")"); - } - } - - sql.push("limit {maxNo}"); - - sql = sql.join(' ') - - var query = format(sql,{ - x: tile.x, - y: tile.y, - z: tile.z, - table: this.options.table, - torque_tile_x: x, - torque_tile_y: y, - maxNo: maxNo, - shift: shift, - tolerance: tolerance - }) - - this.sql(query,function(data){ - if (data) { - var rows = JSON.parse(data.responseText).rows; - callback(rows) - } - else { - callback(null) - } - }) - }, - - /** - * `coord` object like {x : tilex, y: tiley } - * `zoom` quadtree zoom level - */ - _getTileData: function(coord, zoom, callback) { - var prof_fetch_time = Profiler.metric('ProviderJSON:tile_fetch_time').start() - this.table = this.options.table; - var numTiles = 1 << zoom; - - var column_conv = this.options.column; - - var sql = "select * from torque_tile_json({x}, {y}, {zoom}, ARRAY[{fields}], {table}, '{filters}')"; - - var query = format(sql, { - zoom: zoom, - x: coord.x, - y: coord.y, - fields: _.map(this.options.fields, function(f) { - if (f.type === 'cat') { - return "'mode() within group (order by " + f.name + ")'"; - } - var agg = f.agg || 'avg'; - return "'" + agg + "(" + (f.column || f.name) + ")'"; - }).join(','), - column: column_conv, - table: this._getTableSQL(coord, zoom), - filters: this._generateFiltersSQL() - }); - - - var self = this; - this.sql(query, function (data) { - if (data) { - var rows = JSON.parse(data.responseText).rows; - if (rows.length !== 0) { - self.proccessTile(rows, coord, zoom,callback); - } else { - callback(null); - } - } else { - callback(null); - } - prof_fetch_time.end(); - }); - }, - - getKeySpan: function() { - return { - start: this.options.start * 1000, - end: this.options.end * 1000, - step: this.options.step, - steps: this.options.steps, - columnType: this.options.is_time ? 'date': 'number' - }; - }, - - setColumn: function(column, isTime) { - this.options.column = column; - this.options.is_time = isTime === undefined ? true: false; - this.reload(); - }, - - setResolution: function(res) { - this.options.resolution = res; - }, - - // return true if tiles has been changed - setOptions: function(opt) { - var refresh = false; - - if(opt.resolution !== undefined && opt.resolution !== this.options.resolution) { - this.options.resolution = opt.resolution; - refresh = true; - } - - if(opt.steps !== undefined && opt.steps !== this.options.steps) { - this.setSteps(opt.steps, { silent: true }); - refresh = true; - } - - if(opt.column !== undefined && opt.column !== this.options.column) { - this.options.column = opt.column; - refresh = true; - } - - if(opt.countby !== undefined && opt.countby !== this.options.countby) { - this.options.countby = opt.countby; - refresh = true; - } - - if(opt.data_aggregation !== undefined) { - var c = opt.data_aggregation === 'cumulative'; - if (this.options.cumulative !== c) { - this.options.cumulative = c; - refresh = true; - } - } - - if (refresh) this.reload(); - return refresh; - - }, - - reload: function() { - this._ready = false; - this._fetchKeySpan(); - }, - - setSQL: function(sql) { - if (this.options.sql != sql) { - this.options.sql = sql; - this.reload(); - } - }, - - getSteps: function() { - return Math.min(this.options.steps, this.options.data_steps); - }, - - setSteps: function(steps, opt) { - opt = opt || {}; - if (this.options.steps !== steps) { - this.options.steps = steps; - this.options.step = (this.options.end - this.options.start)/this.getSteps(); - this.options.step = this.options.step || 1; - if (!opt.silent) this.reload(); - } - }, - - getBounds: function() { - return this.options.bounds; - }, - - getSQL: function() { - return this.options.sql || "select * from " + this.options.table; - }, - - _tilerHost: function() { - var opts = this.options; - var user = (opts.user_name || opts.user); - return opts.tiler_protocol + - "://" + (user ? user + "." : "") + - opts.tiler_domain + - ((opts.tiler_port != "") ? (":" + opts.tiler_port) : ""); - }, - - _fetchKeySpan: function() { - this._setReady(true); - }, - - _generateBoundsQuery: function(tiles){ - return tiles.map( function(tile){ - return "(quadkey between (xyz2range("+tile.x+","+tile.y+","+tile.z+")).min and (xyz2range("+tile.x+","+tile.y+","+tile.z+")).max)" - }).join(" or ") - }, - - getAggregationForTiles: function(varName, agg, tiles, own_filter, callback) { - var tilesFilter = this._generateBoundsQuery(tiles); - this.tablesForFilter(tilesFilter, function(tables) { - // select the table with less than 100k records - var table = tables.filter(function(f) { - return f.nrows < 50000 && f.cost < 30000; - }) - table = table.length ? table[0].table_name: this.options.overview_tables[this.options.overview_tables.length - 1] - // get multiplicator factor from table name - var factor = (+_.last(table.split('_'))); - if (agg == 'avg') { - factor = 1; - } - this._getAggregationForTiles(varName, agg, tiles, table, own_filter, factor, callback) - }.bind(this)); - }, - - getHistogramForTiles: function(varName, start, end, bins, tiles, own_filter, callback) { - var tilesFilter = this._generateBoundsQuery(tiles); - this.tablesForFilter(tilesFilter, function(tables) { - // select the table with less than 100k records - var table = tables.filter(function(f) { - return f.nrows < 50000 && f.cost < 30000; - }) - table = table.length ? table[0].table_name: this.options.overview_tables[this.options.overview_tables.length - 1] - // get multiplicator factor from table name - var factor = (+_.last(table.split('_'))); - this._getHistogramForTiles(varName, start, end, bins, tiles, table, own_filter, factor, callback) - }.bind(this)); - }, - - categorySearch: function(attr, query, callback) { - var sql = format("select category_value as category, category_count as \"value\" from {table}_{varName}_category_statistics where category_value like '{query}%' limit 100", { - table: this.options.table, - varName: attr, - query: query - }) - - this.sql(sql, function(data) { - callback(JSON.parse(data.responseText).rows); - }); - }, - - _getAggregationForTiles : function(varName, agg, tiles, table, own_filter, factor, callback) { - var sql = [ 'select {agg}({varName}) as result from {table} {tiles} where {bounds} {filters}' ] - - var ff = this._generateFiltersSQL(false, own_filter ? []: [varName]) - var filters = ff ? " and " + ff: "" - - var tiles_query = tiles.map(function (t, i) { - return "xyz2range(" + t.x + "," + t.y + "," + t.z + ") q" + i; - }).join(',') - - if (tiles_query) { - tiles_query = "," + tiles_query - } - - var bounds = tiles.map(function(t, i) { - return format("(quadkey between q{i}.min and q{i}.max)", { i: i }) - }).join('or') - - if (bounds) { - bounds = '(' + bounds + ')'; - } - - var query = format(sql.join('\n'), { - varName: varName, - table: table, - tiles: tiles_query, - filters: filters, - bounds: bounds, - agg: agg - }); - - var self = this; - this.sql(query, function (data) { - if (data) { - var rows = JSON.parse(data.responseText).rows; - // multiply by factor - callback({ result: rows[0].result * factor, nulls: 0}); - } else { - callback(null); - } - }); - }, - - _getHistogramForTiles: function(varName, start, end, bins, tiles, table, own_filter, factor, callback){ - - var sql = [ - 'with source as (', - 'select {varName} from {table} {tiles} where {bounds} {filters}', - '),' - ] - if (start !== undefined) { - sql = sql.concat([ - 'width as (', - 'select {start} as min,', - '{end} as max,', - '{bins} as buckets', - '),' - ]) - } else { - start = start === undefined ? 'min(' + varName + ')': start; - end = end === undefined ? 'max(' + varName + ')': end; - bins = bins === undefined ? 50: bins; - sql = sql.concat([ - 'width as (', - 'select {start} as min,', - '{end} as max,', - '{bins} as buckets', - 'from source', - '),' - ]) - } - sql = sql.concat([ - '_bw as ( select (max - min)/buckets as bw from width ),', - 'histogram as (', - 'select least(buckets, width_bucket({varName}, min, max, buckets)) - 1 as bucket,', - 'numrange(min({varName})::numeric, max({varName})::numeric, \'[]\') as range,', - 'count(*) as freq', - 'from source, width ', - 'group by bucket', - 'order by bucket', - ')', - 'select min + bucket*bw as start, min + (bucket+1)*bw as end, bucket as bin, lower(range) as min, upper(range) as max, freq from histogram, _bw, width;' - ]); - - var ff = this._generateFiltersSQL(false, own_filter ? []: [varName]) - var filters = ff ? " and " + ff: "" - - var tiles_query = tiles.map(function (t, i) { - return "xyz2range(" + t.x + "," + t.y + "," + t.z + ") q" + i; - }).join(',') - - if (tiles_query) { - tiles_query = "," + tiles_query - } - - var bounds = tiles.map(function(t, i) { - return format("(quadkey between q{i}.min and q{i}.max)", { i: i }) - }).join('or') - - if (bounds) { - bounds = '(' + bounds + ')'; - } - - var query = format(sql.join('\n'), { - varName: varName, - table: table, - tiles: tiles_query, - filters: filters, - bounds: bounds, - bins: bins, - start: start, - end: end - }); - - var self = this; - this.sql(query, function (data) { - if (data) { - var rows = JSON.parse(data.responseText).rows; - // multiply by factor - rows.forEach(function(r) { - r.freq = r.freq * factor; - }) - - callback(rows); - } else { - callback(null); - } - }); - }, - - getCategoriesForTiles: function(varName, tiles, callback){ - var tilesFilter = this._generateBoundsQuery(tiles); - this.tablesForFilter(tilesFilter, function(tables) { - // select the table with less than 100k records - var table = tables.filter(function(f) { - return f.nrows < 50000 && f.cost < 30000; - }) - table = table.length ? table[0].table_name: this.options.overview_tables[this.options.overview_tables.length - 1] - var factor = (+_.last(table.split('_'))); - this._getCategoriesForTiles(varName, tiles, table, factor, callback) - }.bind(this)); - }, - - _getCategoriesForTiles: function(varName, tiles, table, factor, callback){ - - /*var sql = [ - 'SELECT CAST(category AS text), value, false as agg, nulls_count, min_val, max_val, count, categories_count', - ' FROM categories, summary, categories_summary', - ' WHERE rank < {{=it._limit}}', - 'UNION ALL', - 'SELECT \'Other\' category, sum(value), true as agg, nulls_count, min_val, max_val, count, categories_count', - ' FROM categories, summary, categories_summary', - ' WHERE rank >= {{=it._limit}}', - 'GROUP BY nulls_count, min_val, max_val, count, categories_count' - ]*/ - - var sql = [ - 'select {varName} category, count(1) as "value" from {table} {tiles} where {bounds} {filters} group by 1 order by 2 desc limit {num_cats}', - ] - - var filters = this._generateFiltersSQL(false, [varName]) ? " and "+ this._generateFiltersSQL(false, [varName]) : "" - - var tiles_query = tiles.map(function (t, i) { - return "xyz2range(" + t.x + "," + t.y + "," + t.z + ") q" + i; - }).join(',') - - if (tiles_query) { - tiles_query = "," + tiles_query - } - - var bounds = tiles.map(function(t, i) { - return format("(quadkey between q{i}.min and q{i}.max)", { i: i }) - }).join('or') - - if (bounds) { - bounds = '(' + bounds + ')'; - } - - var query = format(sql.join('\n'), { - varName: varName, - table: table, - filters: filters, - tiles: tiles_query, - bounds: bounds, - num_cats: 20 - }); - - var self = this; - this.sql(query, function (data) { - if (data) { - var rows = JSON.parse(data.responseText).rows; - rows.forEach(function(r) { - r.value = factor * r.value; - }); - callback(rows); - } else { - callback(null); - } - }); - }, - - - tablesForFilter: function(filter, callback) { - var filters = this._generateFiltersSQL() - if (filters) { - filters = "(" + filters + ") AND (" + filter + ")"; - } else { - filters = filter; - } - // calcualte the table to fecth the histogram - // use the tile 0,0,0 using the quadkey range query - var sql = format("SELECT * FROM selectivity(x:=0, y:=0, z:=0, tables:=ARRAY[{overview_tables}], where_clause:='{filters}') order by nrows desc", { - overview_tables: this.options.overview_tables.map(function(t) { return "'" + t + "'"; }).join(','), - filters: filters - }); - this.sql(sql, function(data) { - callback(JSON.parse(data.responseText).rows); - }); - } - - }; - -module.exports = filterableJson;