<commit_before>var Step = require('step');
var PSQL = require('cartodb-psql');
var _ = require('underscore');
var RendererParams = require('../renderers/renderer_params');
var queue = require('queue-async');


function MapBackend(app, renderCache, mapStore) {
    this._app = app;
    this._renderCache = renderCache;
    this._mapStore = mapStore;
}

module.exports = MapBackend;


// Gets a tile for a given set of tile ZXY coords. (OSM style)
// Call with .png for images, or .grid.json for UTFGrid tiles
//
// query string arguments:
//
// * sql - use SQL to filter displayed results or perform operations pre-render
// * style - assign a per tile style using carto
// * interactivity - specify which columns to represent in the UTFGrid
// * cache_buster - specify to ensure a new renderer is used
// * geom_type - specify default style to use if no style present
//
// Triggers beforeTileRender and afterTileRender render filters
//
MapBackend.prototype.getTileOrGrid = function(req, res, callback){

    var self = this;

    req.profiler.start('getTileOrGrid');

    var renderer;

    Step(
        function() {
            self._app.beforeTileRender(req, res, this);
        },
        function(err){
            req.profiler.done('beforeTileRender');
            if (err) throw err;
            if (req.params.format === 'grid.json' && !req.params.interactivity) {
                if ( ! req.params.token ) { // token embeds interactivity
                    throw new Error("Missing interactivity parameter");
                }
            }
            self._renderCache.getRenderer(req, this);

        },
        function(err, r, is_cached) {
            req.profiler.done('getRenderer');
            renderer = r;
            if ( is_cached ) {
                res.header('X-Windshaft-Cache', Date.now() - renderer.ctime);
            }
            if (err) throw err;
            renderer.getTile(+req.params.z, +req.params.x, +req.params.y, this);
        },
        function(err, tile, headers) {
            req.profiler.done('render-'+req.params.format.replace('.','-'));
            if (err) throw err;
            self._app.afterTileRender(req, res, tile, headers || {}, this);
        },
        function(err, tile, headers) {
            req.profiler.done('afterTileRender');
            if ( renderer ) {
                renderer.release();
                req.profiler.done('renderer_release');
            }
            // this should end getTileOrGrid profile task
            req.profiler.end();
            callback(err, req, res, tile, headers);
        }
    );
};

/// Gets attributes for a given layer feature
//
/// Calls req2params, then expects parameters:
///
/// * token - MapConfig identifier
/// * layer - Layer number
/// * fid   - Feature identifier
///
/// The referenced layer must have been configured
/// to allow for attributes fetching.
/// See https://github.com/CartoDB/Windshaft/wiki/MapConfig-1.1.0
///
/// @param testMode if true generates a call returning requested
///                 columns plus the fid column of the first record
///                 it is only meant to check validity of configuration
///
MapBackend.prototype.getFeatureAttributes = function(req, res, testMode) {
    var self = this;

    var mapConfig;
    var params;
    Step(
        function (){
            self._app.req2params(req, this);
        },
        function getMapConfig(err) {
            req.profiler.done('req2params');
            if (err) throw err;
            params = req.params;
            self._mapStore.load(params.token, this);
        },
        function getPGClient(err, data) {
            if (err) throw err;

            req.profiler.done('MapStore.load');
            mapConfig = data;

            var dbParams = RendererParams.dbParamsFromReqParams(params);
            return new PSQL(dbParams);
        },
        function getAttributes(err, pg) {
            if (err) throw err;

            var layer = mapConfig.getLayer(params.layer);
            if ( ! layer ) {
                throw new Error("Map " + params.token +
                    " has no layer number " + params.layer);
            }
            var attributes = layer.options.attributes;
            if ( ! attributes ) {
                throw new Error("Layer " + params.layer +
                    " has no exposed attributes");
            }

            // NOTE: we're assuming that the presence of "attributes"
            //       means it is well-formed (should be checked at
            //       MapConfig construction/validation time).

            var fid_col = attributes.id;
            var att_cols = attributes.columns;

            // prepare columns with double quotes<commit_msg>Use datasource for layer when retrieving attributes<commit_after>var Step = require('step');
var PSQL = require('cartodb-psql');
var _ = require('underscore');
var RendererParams = require('../renderers/renderer_params');
var queue = require('queue-async');


function MapBackend(app, renderCache, mapStore) {
    this._app = app;
    this._renderCache = renderCache;
    this._mapStore = mapStore;
}

module.exports = MapBackend;


// Gets a tile for a given set of tile ZXY coords. (OSM style)
// Call with .png for images, or .grid.json for UTFGrid tiles
//
// query string arguments:
//
// * sql - use SQL to filter displayed results or perform operations pre-render
// * style - assign a per tile style using carto
// * interactivity - specify which columns to represent in the UTFGrid
// * cache_buster - specify to ensure a new renderer is used
// * geom_type - specify default style to use if no style present
//
// Triggers beforeTileRender and afterTileRender render filters
//
MapBackend.prototype.getTileOrGrid = function(req, res, callback){

    var self = this;

    req.profiler.start('getTileOrGrid');

    var renderer;

    Step(
        function() {
            self._app.beforeTileRender(req, res, this);
        },
        function(err){
            req.profiler.done('beforeTileRender');
            if (err) throw err;
            if (req.params.format === 'grid.json' && !req.params.interactivity) {
                if ( ! req.params.token ) { // token embeds interactivity
                    throw new Error("Missing interactivity parameter");
                }
            }
            self._renderCache.getRenderer(req, this);

        },
        function(err, r, is_cached) {
            req.profiler.done('getRenderer');
            renderer = r;
            if ( is_cached ) {
                res.header('X-Windshaft-Cache', Date.now() - renderer.ctime);
            }
            if (err) throw err;
            renderer.getTile(+req.params.z, +req.params.x, +req.params.y, this);
        },
        function(err, tile, headers) {
            req.profiler.done('render-'+req.params.format.replace('.','-'));
            if (err) throw err;
            self._app.afterTileRender(req, res, tile, headers || {}, this);
        },
        function(err, tile, headers) {
            req.profiler.done('afterTileRender');
            if ( renderer ) {
                renderer.release();
                req.profiler.done('renderer_release');
            }
            // this should end getTileOrGrid profile task
            req.profiler.end();
            callback(err, req, res, tile, headers);
        }
    );
};

/// Gets attributes for a given layer feature
//
/// Calls req2params, then expects parameters:
///
/// * token - MapConfig identifier
/// * layer - Layer number
/// * fid   - Feature identifier
///
/// The referenced layer must have been configured
/// to allow for attributes fetching.
/// See https://github.com/CartoDB/Windshaft/wiki/MapConfig-1.1.0
///
/// @param testMode if true generates a call returning requested
///                 columns plus the fid column of the first record
///                 it is only meant to check validity of configuration
///
MapBackend.prototype.getFeatureAttributes = function(req, res, testMode) {
    var self = this;

    var mapConfig;
    var params;
    Step(
        function (){
            self._app.req2params(req, this);
        },
        function getMapConfig(err) {
            req.profiler.done('req2params');
            if (err) throw err;
            params = req.params;
            self._mapStore.load(params.token, this);
        },
        function getPGClient(err, data) {
            if (err) throw err;

            req.profiler.done('MapStore.load');
            mapConfig = data;

            var dbParams = RendererParams.dbParamsFromReqParams(params);
            _.extend(dbParams, mapConfig.getLayerDatasource(params.layer));
            return new PSQL(dbParams);
        },
        function getAttributes(err, pg) {
            if (err) throw err;

            var layer = mapConfig.getLayer(params.layer);
            if ( ! layer ) {
                throw new Error("Map " + params.token +
                    " has no layer number " + params.layer);
            }
            var attributes = layer.options.attributes;
            if ( ! attributes ) {
                throw new Error("Layer " + params.layer +
                    " has no exposed attributes");
            }

            // NOTE: we're assuming that the presence of "attributes"
            //       means it is well-formed (should be checked at
            //       MapConfig construction/validation time).

            var fid_col = attributes.id;
            var att_cols = attributes.columns;

            // prepare columns with double quotes
{'fraction_non_alphanumeric': 0.11462904911180773, 'fraction_numerical': 0.0012539184952978057, 'mean_word_length': 1.902061855670103, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2335994', 'n_tokens_mistral': 2573, 'n_tokens_neox': 2536, 'n_words': 731}