Skip to content

Commit

Permalink
Merge branch 'hotfix/2.19.1'
Browse files Browse the repository at this point in the history
  • Loading branch information
jwalgran committed Oct 20, 2017
2 parents cf9ef8c + d314ad8 commit 033aa71
Show file tree
Hide file tree
Showing 6 changed files with 220 additions and 5 deletions.
37 changes: 37 additions & 0 deletions http/middleware.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
module.exports = {
instanceConfig: function(opts) {
return function (req, res, next) {
var start = Date.now(),
hasInstance = !!req.query.instance_id;
if (!hasInstance) {
// If we don't have an instance_id (e.g. a health-check request)
// skip this middleware.
next();
return;
}
req.instanceConfig = {};
opts.dbPool.connect(function(err, client, done) {
if (!err) {
var instanceId = parseInt(req.query.instance_id, 10);
client.query('SELECT config FROM treemap_instance WHERE id = $1',
[instanceId], function(err, result) {
if (!err && result && result.rows && result.rows.length > 0) {
req.instanceConfig = JSON.parse(result.rows[0].config);
}
done();
if (opts.debug) {
console.log('[instanceConfig] query time ' + (Date.now() - start));
}
next(err);
});
} else {
done();
if (opts.debug) {
console.log('[instanceConfig] query time ' + (Date.now() - start));
}
next(err);
}
});
};
}
};
13 changes: 12 additions & 1 deletion http/windshaftServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,22 @@
var debug = require('debug')('windshaft:server');
var express = require('express');
var RedisPool = require('redis-mpool');
var Pg = require('pg');
var _ = require('underscore');
var mapnik = require('mapnik');

var windshaft = require('windshaft');

var MapController = require('./mapController.js');

var middleware = require('./middleware.js');

var dbPool = new Pg.Pool({
user: process.env.OTM_DB_USER || 'otm',
password: process.env.OTM_DB_PASSWORD || 'otm',
host: process.env.OTM_DB_HOST || 'localhost',
port: process.env.OTM_DB_PORT || 5432,
database: process.env.OTM_DB_NAME || 'otm'
});
//
// @param opts server options object. Example value:
// {
Expand Down Expand Up @@ -74,6 +83,8 @@ module.exports = function(opts) {
var app = bootstrap(opts);
addFilters(app, opts);

app.use(middleware.instanceConfig({dbPool: dbPool}));

var redisPool = makeRedisPool(opts.redis);

var map_store = new windshaft.storage.MapStore({
Expand Down
7 changes: 4 additions & 3 deletions makeSql.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,22 +32,23 @@ var displayFiltersToWhere = require('./displayFiltersToWhere');
var filtersToTables = require('./filtersToTables');
var addDefaultsToFilter = require('./addDefaultsToFilter');
var config = require('./config');
var units = require('./units');
var utils = require('./filterObjectUtils');


// Create a SQL query to return info about map features.
// Assumes that instanceid is an integer, ready to be plugged
// directly into SQL
function makeSqlForMapFeatures(filterString, displayString, restrictFeatureString, instanceid,
zoom, isUtfGridRequest, isPolygonRequest) {
zoom, isUtfGridRequest, isPolygonRequest, instanceConfig) {
var geom_spec = config.sqlForMapFeatures.fields.geom,
geom_field = isPolygonRequest ? geom_spec.polygon : geom_spec.point,
parsedFilterObject = filterString ? JSON.parse(filterString) : {},
displayFilters = displayString ? JSON.parse(displayString) : undefined,
restrictFeatureFilters = restrictFeatureString ? JSON.parse(restrictFeatureString) : undefined,

filterObject = addDefaultsToFilter(parsedFilterObject, zoom, isPolygonRequest),

filterObjectWithDefaults = addDefaultsToFilter(parsedFilterObject, zoom, isPolygonRequest),
filterObject = units.convertFilterUnits(filterObjectWithDefaults, instanceConfig),
tables = filtersToTables(filterObject, displayFilters, isPolygonRequest, isUtfGridRequest),

where = '',
Expand Down
3 changes: 2 additions & 1 deletion server.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@ var windshaftConfig = {
instanceid,
zoom,
isUtfGridRequest,
isPolygonRequest);
isPolygonRequest,
req.instanceConfig);
if (isPolygonRequest) {
req.params.style = styles.polygonalMapFeature;
} else if (isUtfGridRequest) {
Expand Down
70 changes: 70 additions & 0 deletions test/testUnits.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
"use strict";

var assert = require("assert");
var _ = require("underscore");
var units = require("../units");
var config = require("../config");

describe('convertFilterUnits', function() {
var round = function(number, precision) {
var factor = Math.pow(10, precision);
var tempNumber = number * factor;
var roundedTempNumber = Math.round(tempNumber);
return roundedTempNumber / factor;
};

it('exists', function() {
assert.ok(_.isFunction(units.convertFilterUnits),
'convertFilterUnits function should exist');
});

it('ignores non-convertible fields', function(){
var filter = {'tree.something': {'IS': 'some value'}};
var config = {value_display: {tree: {diameter: {'units': 'in'}}}};
var expectedFilter = _.clone(filter);
units.convertFilterUnits(filter, config);
assert.deepEqual(filter, expectedFilter, 'Filter should not change');
});

it('does not change a value with default unit', function(){
var filter = {'tree.diameter': {'MIN': 1, 'MAX': 2}};
var config = {value_display: {tree: {diameter: {'units': 'in'}}}};
var expectedFilter = _.clone(filter);
units.convertFilterUnits(filter, config);
assert.deepEqual(filter, expectedFilter, 'Filter should not change');
});

it('converts min and max diameter filter', function(){
var filter = {'tree.diameter': {'MIN': 1, 'MAX': 2}};
var config = {value_display: {tree: {diameter: {'units': 'cm'}}}};
var expectedFilter = {'tree.diameter': {'MIN': 0.393701, 'MAX': 0.787402}};
units.convertFilterUnits(filter, config);
// Round before asserting because the actual conversion to compare floats with a known level of precision
filter['tree.diameter'].MIN = round(filter['tree.diameter'].MIN, 6);
filter['tree.diameter'].MAX = round(filter['tree.diameter'].MAX, 6);
assert.deepEqual(filter, expectedFilter, 'Filter should show cm->in conversion');
});

it('converts min and max filter with alternate syntax', function(){
var filter = {'tree.diameter': {'MIN': {'VALUE': 1}, 'MAX': {'VALUE': 2}}};
var config = {value_display: {tree: {diameter: {'units': 'cm'}}}};
var expectedFilter = {'tree.diameter': {'MIN': {'VALUE': 0.393701}, 'MAX': {'VALUE': 0.787402}}};
units.convertFilterUnits(filter, config);
// Round before asserting because the actual conversion to compare floats with a known level of precision
filter['tree.diameter'].MIN.VALUE = round(filter['tree.diameter'].MIN.VALUE, 6);
filter['tree.diameter'].MAX.VALUE = round(filter['tree.diameter'].MAX.VALUE, 6);
assert.deepEqual(filter, expectedFilter, 'Filter should show cm->in conversion');
});

it('converts min and max bioswale filter', function(){
var filter = {'bioswale.drainage_area': {'MIN': 1, 'MAX': 2}};
var config = {value_display: {bioswale: {drainage_area: {'units': 'sq_m'}}}};
var expectedFilter = {'bioswale.drainage_area': {'MIN': 10.7643, 'MAX': 21.5285}};
units.convertFilterUnits(filter, config);
// Round before asserting because the actual conversion to compare floats with a known level of precision
filter['bioswale.drainage_area'].MIN = round(filter['bioswale.drainage_area'].MIN, 4);
filter['bioswale.drainage_area'].MAX = round(filter['bioswale.drainage_area'].MAX, 4);
assert.deepEqual(filter, expectedFilter, 'Filter should show sq_ft->sq_m conversion');
});

});
95 changes: 95 additions & 0 deletions units.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
"use strict";

var _ = require("underscore");

var convertableFields = ['tree.diameter', 'tree.height', 'tree.canopy_height',
'plot.width', 'plot.length', 'bioswale.drainage_area',
'rainBarrel.capacity', 'rainGarden.drainage_area'];

var unitDefaults = {
plot: {
width: 'in',
length: 'in'
},
tree: {
diameter: 'in',
height: 'ft',
canopy_height: 'ft'
},
bioswale: {
drainage_area: 'sq_ft'
},
rainBarrel: {
capacity: 'gal'
},
rainGarden: {
drainage_area: 'sq_ft'
}
};

var unitConversions = {
'in': {'in': 1, 'ft': 1 / 12, 'cm': 2.54, 'm': 0.0254},
'ft': {'in': 12, 'ft': 1, 'cm': 30.48, 'm': 0.3048},
'lbs/year': {'lbs/year': 1, 'kg/year': 0.453592},
'lbs': {'lbs': 1, 'kg': 0.453592},
'gal': {'gal': 1, 'L': 3.785},
'gal/year': {'gal/year': 1, 'L/year': 3.785},
'kwh/year': {'kwh/year': 1},
'sq_m': {'sq_m': 1, 'sq_ft': 10.7639},
'sq_ft': {'sq_m': 0.0929, 'sq_ft': 1}
};

function getFilterFactor(instanceConfig, model, field) {
var unit, defaultUnit,
factor = 1;
if (instanceConfig.value_display[model]) {
if (instanceConfig.value_display[model][field]) {
unit = instanceConfig.value_display[model][field].units;
defaultUnit = unitDefaults[model][field];
factor = 1 / unitConversions[defaultUnit][unit];
}
}
return factor;
}

function convertFilterValue(value, factor) {
if (_.isObject(value)) {
_.each(['MIN', 'MAX', 'IS'], function(k) {
var floatValue;
if (value[k]) {
if (_.isObject(value[k])) {
floatValue = parseFloat(value[k].VALUE);
if (_.isNumber(floatValue)) {
value[k].VALUE = floatValue * factor;
}
} else {
floatValue = parseFloat(value[k]);
if (_.isNumber(floatValue)) {
value[k] = floatValue * factor;
}
}
}
});
}
return value;
}

function convertFilterUnits(filterObject, instanceConfig) {
// if there is no unit configuration, there is no need to convert
if (instanceConfig && instanceConfig.value_display) {
_.each(_.keys(filterObject), function(fieldName) {
var value = filterObject[fieldName];
if (_.contains(convertableFields, fieldName)) {
var model = fieldName.split('.')[0],
field = fieldName.substring(fieldName.indexOf('.') + 1),
factor = getFilterFactor(instanceConfig, model, field);
convertFilterValue(value, factor);
}
});
}
return filterObject;
}

exports = module.exports = {
convertFilterUnits: convertFilterUnits
};

0 comments on commit 033aa71

Please sign in to comment.