Merge remote-tracking branch 'blessed/master' into 1073-aggregation-false
This commit is contained in:
@@ -6,17 +6,16 @@ const assert = require('../support/assert');
|
||||
const TestClient = require('../support/test-client');
|
||||
const serverOptions = require('../../lib/cartodb/server_options');
|
||||
|
||||
const suites = [{
|
||||
desc: 'mvt (mapnik)',
|
||||
usePostGIS: false
|
||||
}];
|
||||
|
||||
if (process.env.POSTGIS_VERSION >= '20400') {
|
||||
suites.push({
|
||||
const suites = [
|
||||
{
|
||||
desc: 'mvt (mapnik)',
|
||||
usePostGIS: false
|
||||
},
|
||||
{
|
||||
desc: 'mvt (postgis)',
|
||||
usePostGIS: true
|
||||
});
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
// Generate points with values and times.
|
||||
// The point location is spanned over a given length, by default it is 0 so
|
||||
|
||||
@@ -171,8 +171,7 @@ describe('buffer size per format', function () {
|
||||
});
|
||||
});
|
||||
|
||||
const describe_pg = process.env.POSTGIS_VERSION >= '20400' ? describe : describe.skip;
|
||||
describe_pg('using postgis mvt renderer', function() {
|
||||
describe('using postgis mvt renderer', function() {
|
||||
before(function () {
|
||||
serverOptions.renderer.mvt.usePostGIS = true;
|
||||
});
|
||||
@@ -505,8 +504,7 @@ describe('buffer size per format for named maps w/o placeholders', function () {
|
||||
});
|
||||
});
|
||||
|
||||
const describe_pg = process.env.POSTGIS_VERSION >= '20400' ? describe : describe.skip;
|
||||
describe_pg('using postgis mvt renderer', function() {
|
||||
describe('using postgis mvt renderer', function() {
|
||||
before(function () {
|
||||
serverOptions.renderer.mvt.usePostGIS = true;
|
||||
});
|
||||
|
||||
@@ -0,0 +1,835 @@
|
||||
'use strict';
|
||||
|
||||
require('../support/test_helper');
|
||||
|
||||
const assert = require('../support/assert');
|
||||
const TestClient = require('../support/test-client');
|
||||
|
||||
const POINTS_SQL_1 = `
|
||||
select
|
||||
x + 4 as cartodb_id,
|
||||
st_setsrid(st_makepoint(x*10 + 18, x*10 + 5), 4326) as the_geom,
|
||||
st_transform(st_setsrid(st_makepoint(x*10 + 18, x*10 + 5), 4326), 3857) as the_geom_webmercator,
|
||||
x as value,
|
||||
CASE
|
||||
WHEN x % 2 = 0 THEN 'even'
|
||||
ELSE 'odd'
|
||||
END AS type
|
||||
from generate_series(-3, 3) x
|
||||
`;
|
||||
|
||||
const defaultLayers = [{
|
||||
type: 'cartodb',
|
||||
options: {
|
||||
sql: POINTS_SQL_1,
|
||||
aggregation: {
|
||||
threshold: 1
|
||||
}
|
||||
}
|
||||
}];
|
||||
|
||||
function createVectorMapConfig (layers = defaultLayers) {
|
||||
return {
|
||||
version: '1.8.0',
|
||||
layers: layers
|
||||
};
|
||||
}
|
||||
|
||||
describe('cluster', function () {
|
||||
describe('w/o aggregation', function () {
|
||||
it('should return error while fetching disaggregated features', function (done) {
|
||||
const mapConfig = createVectorMapConfig([{
|
||||
type: 'cartodb',
|
||||
options: {
|
||||
sql: POINTS_SQL_1,
|
||||
cartocss: TestClient.CARTOCSS.POINTS,
|
||||
cartocss_version: '2.3.0'
|
||||
}
|
||||
}]);
|
||||
const testClient = new TestClient(mapConfig);
|
||||
const zoom = 0;
|
||||
const cartodb_id = 1;
|
||||
const layerId = 0;
|
||||
const params = {
|
||||
response: {
|
||||
status: 400
|
||||
}
|
||||
};
|
||||
|
||||
testClient.getClusterFeatures(zoom, cartodb_id, layerId, params, (err, body) => {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
assert.deepStrictEqual(body, {
|
||||
errors:[ 'Map f697fb370c6479559ae2f66d684e8227 has no aggregation defined for layer 0' ],
|
||||
errors_with_context:[
|
||||
{
|
||||
layer: {
|
||||
index: '0',
|
||||
type: 'cartodb'
|
||||
},
|
||||
message: 'Map f697fb370c6479559ae2f66d684e8227 has no aggregation defined for layer 0',
|
||||
subtype: 'aggregation',
|
||||
type: 'layer'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
testClient.drain(done);
|
||||
});
|
||||
});
|
||||
|
||||
it('with aggregation disabled should return error while fetching disaggregated features', function (done) {
|
||||
const mapConfig = createVectorMapConfig([{
|
||||
type: 'cartodb',
|
||||
options: {
|
||||
sql: POINTS_SQL_1,
|
||||
aggregation: false
|
||||
}
|
||||
}]);
|
||||
const testClient = new TestClient(mapConfig);
|
||||
const zoom = 0;
|
||||
const cartodb_id = 1;
|
||||
const layerId = 0;
|
||||
const params = {
|
||||
response: {
|
||||
status: 400
|
||||
}
|
||||
};
|
||||
|
||||
testClient.getClusterFeatures(zoom, cartodb_id, layerId, params, (err, body) => {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
assert.deepStrictEqual(body, {
|
||||
errors:[ 'Map 7521bcd1029c401289dd651ce91d5d9d has no aggregation defined for layer 0' ],
|
||||
errors_with_context:[
|
||||
{
|
||||
layer: {
|
||||
index: '0',
|
||||
type: 'cartodb'
|
||||
},
|
||||
message: 'Map 7521bcd1029c401289dd651ce91d5d9d has no aggregation defined for layer 0',
|
||||
subtype: 'aggregation',
|
||||
type: 'layer'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
testClient.drain(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('fetch features within a cluster grid', function () {
|
||||
const suite = [
|
||||
{
|
||||
zoom: 0,
|
||||
cartodb_id: 1,
|
||||
resolution: 0.5,
|
||||
expected: [ { cartodb_id: 1, value: -3, type: 'odd' } ]
|
||||
},
|
||||
{
|
||||
zoom: 0,
|
||||
cartodb_id: 2,
|
||||
resolution: 0.5,
|
||||
expected: [ { cartodb_id: 2, value: -2, type: 'even' } ]
|
||||
},
|
||||
{
|
||||
zoom: 0,
|
||||
cartodb_id: 3,
|
||||
resolution: 0.5,
|
||||
expected: [ { cartodb_id: 3, value: -1, type: 'odd' } ]
|
||||
},
|
||||
{
|
||||
zoom: 0,
|
||||
cartodb_id: 4,
|
||||
resolution: 0.5,
|
||||
expected: [ { cartodb_id: 4, value: 0, type: 'even' } ]
|
||||
},
|
||||
{
|
||||
zoom: 0,
|
||||
cartodb_id: 5,
|
||||
resolution: 0.5,
|
||||
expected: [ { cartodb_id: 5, value: 1, type: 'odd' } ]
|
||||
},
|
||||
{
|
||||
zoom: 0,
|
||||
cartodb_id: 6,
|
||||
resolution: 0.5,
|
||||
expected: [ { cartodb_id: 6, value: 2, type: 'even' } ]
|
||||
},
|
||||
{
|
||||
zoom: 0,
|
||||
cartodb_id: 7,
|
||||
resolution: 0.5,
|
||||
expected: [ { cartodb_id: 7, value: 3, type: 'odd' } ]
|
||||
},
|
||||
{
|
||||
zoom: 0,
|
||||
cartodb_id: 1,
|
||||
resolution: 1,
|
||||
expected: [ { cartodb_id: 1, value: -3, type: 'odd' } ]
|
||||
},
|
||||
{
|
||||
zoom: 0,
|
||||
cartodb_id: 2,
|
||||
resolution: 1,
|
||||
expected: [ { cartodb_id: 2, value: -2, type: 'even' } ]
|
||||
},
|
||||
{
|
||||
zoom: 0,
|
||||
cartodb_id: 3,
|
||||
resolution: 1,
|
||||
expected: [ { cartodb_id: 3, value: -1, type: 'odd' } ]
|
||||
},
|
||||
{
|
||||
zoom: 0,
|
||||
cartodb_id: 4,
|
||||
resolution: 1,
|
||||
expected: [ { cartodb_id: 4, value: 0, type: 'even' } ]
|
||||
},
|
||||
{
|
||||
zoom: 0,
|
||||
cartodb_id: 5,
|
||||
resolution: 1,
|
||||
expected: [ { cartodb_id: 5, value: 1, type: 'odd' } ]
|
||||
},
|
||||
{
|
||||
zoom: 0,
|
||||
cartodb_id: 6,
|
||||
resolution: 1,
|
||||
expected: [ { cartodb_id: 6, value: 2, type: 'even' } ]
|
||||
},
|
||||
{
|
||||
zoom: 0,
|
||||
cartodb_id: 7,
|
||||
resolution: 1,
|
||||
expected: [ { cartodb_id: 7, value: 3, type: 'odd' } ]
|
||||
},
|
||||
{
|
||||
zoom: 0,
|
||||
cartodb_id: 1,
|
||||
resolution: 50,
|
||||
expected: [
|
||||
{ cartodb_id: 1, value: -3, type: 'odd' },
|
||||
{ cartodb_id: 2, value: -2, type: 'even' }
|
||||
]
|
||||
},
|
||||
{
|
||||
zoom: 0,
|
||||
cartodb_id: 5,
|
||||
resolution: 50,
|
||||
expected: [
|
||||
{ cartodb_id: 4, value: 0, type: 'even' },
|
||||
{ cartodb_id: 5, value: 1, type: 'odd' },
|
||||
{ cartodb_id: 6, value: 2, type: 'even' },
|
||||
{ cartodb_id: 7, value: 3, type: 'odd' }
|
||||
]
|
||||
},
|
||||
{
|
||||
zoom: 1,
|
||||
cartodb_id: 1,
|
||||
resolution: 1,
|
||||
expected: [ { cartodb_id: 1, value: -3, type: 'odd' } ]
|
||||
},
|
||||
{
|
||||
zoom: 1,
|
||||
cartodb_id: 2,
|
||||
resolution: 1,
|
||||
expected: [ { cartodb_id: 2, value: -2, type: 'even' } ]
|
||||
},
|
||||
{
|
||||
zoom: 1,
|
||||
cartodb_id: 3,
|
||||
resolution: 1,
|
||||
expected: [ { cartodb_id: 3, value: -1, type: 'odd' } ]
|
||||
},
|
||||
{
|
||||
zoom: 1,
|
||||
cartodb_id: 4,
|
||||
resolution: 1,
|
||||
expected: [ { cartodb_id: 4, value: 0, type: 'even' } ]
|
||||
},
|
||||
{
|
||||
zoom: 1,
|
||||
cartodb_id: 5,
|
||||
resolution: 1,
|
||||
expected: [ { cartodb_id: 5, value: 1, type: 'odd' } ]
|
||||
},
|
||||
{
|
||||
zoom: 1,
|
||||
cartodb_id: 6,
|
||||
resolution: 1,
|
||||
expected: [ { cartodb_id: 6, value: 2, type: 'even' } ]
|
||||
},
|
||||
{
|
||||
zoom: 1,
|
||||
cartodb_id: 7,
|
||||
resolution: 1,
|
||||
expected: [ { cartodb_id: 7, value: 3, type: 'odd' } ]
|
||||
},
|
||||
{
|
||||
zoom: 1,
|
||||
cartodb_id: 1,
|
||||
resolution: 50,
|
||||
expected: [
|
||||
{ cartodb_id: 1, value: -3, type: 'odd' },
|
||||
{ cartodb_id: 2, value: -2, type: 'even'}
|
||||
]
|
||||
},
|
||||
{
|
||||
zoom: 1,
|
||||
cartodb_id: 5,
|
||||
resolution: 50,
|
||||
expected: [
|
||||
{ cartodb_id: 4, value: 0, type: 'even' },
|
||||
{ cartodb_id: 5, value: 1, type: 'odd' }
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
suite.forEach(({ zoom, cartodb_id, resolution, expected }) => {
|
||||
const description = `should get features for z: ${zoom} cartodb_id: ${cartodb_id}, res: ${resolution}`;
|
||||
it(description, function (done) {
|
||||
const mapConfig = createVectorMapConfig([{
|
||||
type: 'cartodb',
|
||||
options: {
|
||||
sql: POINTS_SQL_1,
|
||||
aggregation: {
|
||||
threshold: 1,
|
||||
resolution: resolution
|
||||
}
|
||||
}
|
||||
}]);
|
||||
const testClient = new TestClient(mapConfig);
|
||||
const layerId = 0;
|
||||
const params = {};
|
||||
|
||||
testClient.getClusterFeatures(zoom, cartodb_id, layerId, params, (err, body) => {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
assert.deepStrictEqual(body.rows, expected);
|
||||
testClient.drain(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('valid aggregation input', function () {
|
||||
const suite = [
|
||||
{
|
||||
zoom: 0,
|
||||
cartodb_id: 1,
|
||||
resolution: 1,
|
||||
aggregation: { columns: ['type'] },
|
||||
expected: [ { _cdb_feature_count: 1, type: 'odd' } ]
|
||||
},
|
||||
{
|
||||
zoom: 0,
|
||||
cartodb_id: 2,
|
||||
resolution: 1,
|
||||
aggregation: { columns: ['type'] },
|
||||
expected: [ { _cdb_feature_count: 1, type: 'even' } ]
|
||||
},
|
||||
{
|
||||
zoom: 0,
|
||||
cartodb_id: 3,
|
||||
resolution: 1,
|
||||
aggregation: { columns: ['type'] },
|
||||
expected: [ { _cdb_feature_count: 1, type: 'odd' } ]
|
||||
},
|
||||
{
|
||||
zoom: 0,
|
||||
cartodb_id: 4,
|
||||
resolution: 1,
|
||||
aggregation: { columns: ['type'] },
|
||||
expected: [ { _cdb_feature_count: 1, type: 'even' } ]
|
||||
},
|
||||
{
|
||||
zoom: 0,
|
||||
cartodb_id: 5,
|
||||
resolution: 1,
|
||||
aggregation: { columns: ['type'] },
|
||||
expected: [ { _cdb_feature_count: 1, type: 'odd' } ]
|
||||
},
|
||||
{
|
||||
zoom: 0,
|
||||
cartodb_id: 6,
|
||||
resolution: 1,
|
||||
aggregation: { columns: ['type'] },
|
||||
expected: [ { _cdb_feature_count: 1, type: 'even' } ]
|
||||
},
|
||||
{
|
||||
zoom: 0,
|
||||
cartodb_id: 7,
|
||||
resolution: 1,
|
||||
aggregation: { columns: ['type'] },
|
||||
expected: [ { _cdb_feature_count: 1, type: 'odd' } ]
|
||||
},
|
||||
{
|
||||
zoom: 0,
|
||||
cartodb_id: 1,
|
||||
resolution: 50,
|
||||
aggregation: { columns: ['type'] },
|
||||
expected: [
|
||||
{ _cdb_feature_count: 1, type: 'even' },
|
||||
{ _cdb_feature_count: 1, type: 'odd' }
|
||||
]
|
||||
},
|
||||
{
|
||||
zoom: 0,
|
||||
cartodb_id: 5,
|
||||
resolution: 50,
|
||||
aggregation: { columns: ['type'] },
|
||||
expected: [
|
||||
{ _cdb_feature_count: 2, type: 'even' },
|
||||
{ _cdb_feature_count: 2, type: 'odd' }
|
||||
]
|
||||
},
|
||||
{
|
||||
zoom: 0,
|
||||
cartodb_id: 1,
|
||||
resolution: 1,
|
||||
aggregation: {
|
||||
columns: [ 'type' ],
|
||||
expressions: {
|
||||
max_value: {
|
||||
aggregate_function: 'max',
|
||||
aggregated_column: 'value',
|
||||
}
|
||||
}
|
||||
},
|
||||
expected: [ { _cdb_feature_count: 1, type: 'odd', max_value: -3 } ]
|
||||
},
|
||||
{
|
||||
zoom: 0,
|
||||
cartodb_id: 2,
|
||||
resolution: 1,
|
||||
aggregation: {
|
||||
columns: [ 'type' ],
|
||||
expressions: {
|
||||
max_value: {
|
||||
aggregate_function: 'max',
|
||||
aggregated_column: 'value',
|
||||
}
|
||||
}
|
||||
},
|
||||
expected: [ { _cdb_feature_count: 1, type: 'even', max_value: -2 } ]
|
||||
},
|
||||
{
|
||||
zoom: 0,
|
||||
cartodb_id: 3,
|
||||
resolution: 1,
|
||||
aggregation: {
|
||||
columns: [ 'type' ],
|
||||
expressions: {
|
||||
max_value: {
|
||||
aggregate_function: 'max',
|
||||
aggregated_column: 'value',
|
||||
}
|
||||
}
|
||||
},
|
||||
expected: [ { _cdb_feature_count: 1, type: 'odd', max_value: -1 } ]
|
||||
},
|
||||
{
|
||||
zoom: 0,
|
||||
cartodb_id: 4,
|
||||
resolution: 1,
|
||||
aggregation: {
|
||||
columns: [ 'type' ],
|
||||
expressions: {
|
||||
max_value: {
|
||||
aggregate_function: 'max',
|
||||
aggregated_column: 'value',
|
||||
}
|
||||
}
|
||||
},
|
||||
expected: [ { _cdb_feature_count: 1, type: 'even', max_value: 0 } ]
|
||||
},
|
||||
{
|
||||
zoom: 0,
|
||||
cartodb_id: 5,
|
||||
resolution: 1,
|
||||
aggregation: {
|
||||
columns: [ 'type' ],
|
||||
expressions: {
|
||||
max_value: {
|
||||
aggregate_function: 'max',
|
||||
aggregated_column: 'value',
|
||||
}
|
||||
}
|
||||
},
|
||||
expected: [ { _cdb_feature_count: 1, type: 'odd', max_value: 1 } ]
|
||||
},
|
||||
{
|
||||
zoom: 0,
|
||||
cartodb_id: 6,
|
||||
resolution: 1,
|
||||
aggregation: {
|
||||
columns: [ 'type' ],
|
||||
expressions: {
|
||||
max_value: {
|
||||
aggregate_function: 'max',
|
||||
aggregated_column: 'value',
|
||||
}
|
||||
}
|
||||
},
|
||||
expected: [ { _cdb_feature_count: 1, type: 'even', max_value: 2 } ]
|
||||
},
|
||||
{
|
||||
zoom: 0,
|
||||
cartodb_id: 7,
|
||||
resolution: 1,
|
||||
aggregation: {
|
||||
columns: [ 'type' ],
|
||||
expressions: {
|
||||
max_value: {
|
||||
aggregate_function: 'max',
|
||||
aggregated_column: 'value',
|
||||
}
|
||||
}
|
||||
},
|
||||
expected: [ { _cdb_feature_count: 1, type: 'odd', max_value: 3 } ]
|
||||
},
|
||||
{
|
||||
zoom: 0,
|
||||
cartodb_id: 1,
|
||||
resolution: 50,
|
||||
aggregation: {
|
||||
columns: [ 'type' ],
|
||||
expressions: {
|
||||
max_value: {
|
||||
aggregate_function: 'max',
|
||||
aggregated_column: 'value',
|
||||
}
|
||||
}
|
||||
},
|
||||
expected: [
|
||||
{ _cdb_feature_count: 1, type: 'even', max_value: -2 },
|
||||
{ _cdb_feature_count: 1, type: 'odd', max_value: -3 }
|
||||
]
|
||||
},
|
||||
{
|
||||
zoom: 0,
|
||||
cartodb_id: 5,
|
||||
resolution: 50,
|
||||
aggregation: {
|
||||
columns: [ 'type' ],
|
||||
expressions: {
|
||||
max_value: {
|
||||
aggregate_function: 'max',
|
||||
aggregated_column: 'value',
|
||||
}
|
||||
}
|
||||
},
|
||||
expected: [
|
||||
{ _cdb_feature_count: 2, type: 'even', max_value: 2 },
|
||||
{ _cdb_feature_count: 2, type: 'odd', max_value: 3 }
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
suite.forEach(({ zoom, cartodb_id, resolution, aggregation, expected }) => {
|
||||
it(`should aggregate by type; z: ${zoom}, cartodb_id: ${cartodb_id}, res: ${resolution}`, function (done) {
|
||||
const mapConfig = createVectorMapConfig([{
|
||||
type: 'cartodb',
|
||||
options: {
|
||||
sql: POINTS_SQL_1,
|
||||
aggregation: {
|
||||
threshold: 1,
|
||||
resolution
|
||||
}
|
||||
}
|
||||
}]);
|
||||
const testClient = new TestClient(mapConfig);
|
||||
const layerId = 0;
|
||||
const params = { aggregation };
|
||||
|
||||
testClient.getClusterFeatures(zoom, cartodb_id, layerId, params, (err, body) => {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
assert.deepStrictEqual(body.rows, expected);
|
||||
|
||||
testClient.drain(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('invalid aggregation input', function () {
|
||||
const expectedColumnsError = {
|
||||
errors:[ 'Invalid aggregation input, columns should be and array of column names' ],
|
||||
errors_with_context:[
|
||||
{
|
||||
layer: {
|
||||
index: '0',
|
||||
type: 'cartodb'
|
||||
},
|
||||
message: 'Invalid aggregation input, columns should be and array of column names',
|
||||
subtype: 'aggregation',
|
||||
type: 'layer'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const expectedExpressionsError = {
|
||||
errors:[ 'Invalid aggregation input, expressions should be and object with valid functions' ],
|
||||
errors_with_context:[
|
||||
{
|
||||
layer: {
|
||||
index: '0',
|
||||
type: 'cartodb'
|
||||
},
|
||||
message: 'Invalid aggregation input, expressions should be and object with valid functions',
|
||||
subtype: 'aggregation',
|
||||
type: 'layer'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const invalidFunctionExpressionsError = {
|
||||
errors:[ 'function wadus(integer) does not exist' ],
|
||||
errors_with_context:[
|
||||
{
|
||||
message: 'function wadus(integer) does not exist',
|
||||
type: 'unknown'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const invalidColumnExpressionsError = {
|
||||
errors:[ 'column \"wadus\" does not exist' ],
|
||||
errors_with_context:[
|
||||
{
|
||||
message: 'column \"wadus\" does not exist',
|
||||
type: 'unknown'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
|
||||
const expectedAggregatedColumnError = {
|
||||
errors:[ 'Invalid aggregation input, aggregated column should be an string' ],
|
||||
errors_with_context:[
|
||||
{
|
||||
layer: {
|
||||
index: '0',
|
||||
type: 'cartodb'
|
||||
},
|
||||
message: 'Invalid aggregation input, aggregated column should be an string',
|
||||
subtype: 'aggregation',
|
||||
type: 'layer'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const expectedAggregateFunctionError = {
|
||||
errors:[ 'Invalid aggregation input, aggregate function should be an string' ],
|
||||
errors_with_context:[
|
||||
{
|
||||
layer: {
|
||||
index: '0',
|
||||
type: 'cartodb'
|
||||
},
|
||||
message: 'Invalid aggregation input, aggregate function should be an string',
|
||||
subtype: 'aggregation',
|
||||
type: 'layer'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const suite = [
|
||||
{
|
||||
description: 'empty aggregation object should respond with error',
|
||||
zoom: 0,
|
||||
cartodb_id: 1,
|
||||
resolution: 1,
|
||||
aggregation: {},
|
||||
expected: expectedColumnsError
|
||||
},
|
||||
{
|
||||
description: 'empty aggregation array should respond with error',
|
||||
zoom: 0,
|
||||
cartodb_id: 1,
|
||||
resolution: 1,
|
||||
aggregation: [],
|
||||
expected: expectedColumnsError
|
||||
},
|
||||
{
|
||||
description: 'aggregation as string should respond with error',
|
||||
zoom: 0,
|
||||
cartodb_id: 1,
|
||||
resolution: 1,
|
||||
aggregation: 'wadus',
|
||||
expected: expectedColumnsError
|
||||
},
|
||||
{
|
||||
description: 'empty columns array should respond with error',
|
||||
zoom: 0,
|
||||
cartodb_id: 1,
|
||||
resolution: 1,
|
||||
aggregation: { columns: [] },
|
||||
expected: expectedColumnsError
|
||||
},
|
||||
{
|
||||
description: 'empty columns object should respond with error',
|
||||
zoom: 0,
|
||||
cartodb_id: 1,
|
||||
resolution: 1,
|
||||
aggregation: { columns: {} },
|
||||
expected: expectedColumnsError
|
||||
},
|
||||
{
|
||||
description: 'columns as string should respond with error',
|
||||
zoom: 0,
|
||||
cartodb_id: 1,
|
||||
resolution: 1,
|
||||
aggregation: { columns: 'wadus' },
|
||||
expected: expectedColumnsError
|
||||
},
|
||||
{
|
||||
description: 'columns as null should respond with error',
|
||||
zoom: 0,
|
||||
cartodb_id: 1,
|
||||
resolution: 1,
|
||||
aggregation: { columns: null },
|
||||
expected: expectedColumnsError
|
||||
},
|
||||
{
|
||||
description: 'empty expressions array should respond with error',
|
||||
zoom: 0,
|
||||
cartodb_id: 1,
|
||||
resolution: 1,
|
||||
aggregation: { columns: [ 'type' ], expressions: [] },
|
||||
expected: expectedExpressionsError
|
||||
},
|
||||
{
|
||||
description: 'empty expressions number should respond with error',
|
||||
zoom: 0,
|
||||
cartodb_id: 1,
|
||||
resolution: 1,
|
||||
aggregation: { columns: [ 'type' ], expressions: 1 },
|
||||
expected: expectedExpressionsError
|
||||
},
|
||||
{
|
||||
description: 'expressions as string should respond with error',
|
||||
zoom: 0,
|
||||
cartodb_id: 1,
|
||||
resolution: 1,
|
||||
aggregation: { columns: [ 'type' ], expressions: 'wadus' },
|
||||
expected: expectedExpressionsError
|
||||
},
|
||||
{
|
||||
description: 'expressions as null should respond with error',
|
||||
zoom: 0,
|
||||
cartodb_id: 1,
|
||||
resolution: 1,
|
||||
aggregation: { columns: [ 'type' ], expressions: null },
|
||||
expected: expectedExpressionsError
|
||||
},
|
||||
{
|
||||
description: 'invalid aggregation function should respond with error',
|
||||
zoom: 0,
|
||||
cartodb_id: 1,
|
||||
resolution: 1,
|
||||
aggregation: {
|
||||
columns: [ 'type' ],
|
||||
expressions: {
|
||||
max_value: {
|
||||
aggregate_function: 'wadus',
|
||||
aggregated_column: 'value'
|
||||
}
|
||||
}
|
||||
},
|
||||
expected: invalidFunctionExpressionsError
|
||||
},
|
||||
{
|
||||
description: 'invalid aggregation column should respond with error',
|
||||
zoom: 0,
|
||||
cartodb_id: 1,
|
||||
resolution: 1,
|
||||
aggregation: {
|
||||
columns: [ 'type' ],
|
||||
expressions: {
|
||||
max_value: {
|
||||
aggregate_function: 'max',
|
||||
aggregated_column: 'wadus'
|
||||
}
|
||||
}
|
||||
},
|
||||
status: 404,
|
||||
expected: invalidColumnExpressionsError
|
||||
},
|
||||
{
|
||||
description: 'aggregated column as non string should respond with error',
|
||||
zoom: 0,
|
||||
cartodb_id: 1,
|
||||
resolution: 1,
|
||||
aggregation: {
|
||||
columns: [ 'type' ],
|
||||
expressions: {
|
||||
max_value: {
|
||||
aggregate_function: 'max',
|
||||
aggregated_column: 1
|
||||
}
|
||||
}
|
||||
},
|
||||
expected: expectedAggregatedColumnError
|
||||
},
|
||||
{
|
||||
description: 'aggregate function as non string should respond with error',
|
||||
zoom: 0,
|
||||
cartodb_id: 1,
|
||||
resolution: 1,
|
||||
aggregation: {
|
||||
columns: [ 'type' ],
|
||||
expressions: {
|
||||
max_value: {
|
||||
aggregate_function: 1,
|
||||
aggregated_column: 'value'
|
||||
}
|
||||
}
|
||||
},
|
||||
expected: expectedAggregateFunctionError
|
||||
}
|
||||
];
|
||||
|
||||
suite.forEach(({ description, zoom, cartodb_id, resolution, aggregation, expected, status = 400 }) => {
|
||||
it(description, function (done) {
|
||||
const mapConfig = createVectorMapConfig([{
|
||||
type: 'cartodb',
|
||||
options: {
|
||||
sql: POINTS_SQL_1,
|
||||
aggregation: {
|
||||
threshold: 1,
|
||||
resolution
|
||||
}
|
||||
}
|
||||
}]);
|
||||
const testClient = new TestClient(mapConfig);
|
||||
const layerId = 0;
|
||||
const params = {
|
||||
response: { status },
|
||||
aggregation
|
||||
};
|
||||
|
||||
testClient.getClusterFeatures(zoom, cartodb_id, layerId, params, (err, body) => {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
assert.deepStrictEqual(body, expected);
|
||||
|
||||
testClient.drain(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -90,6 +90,26 @@ describe('histogram-dataview', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('should work with min >= start and max <= end, autodetect bins', function(done) {
|
||||
var params = {
|
||||
start: 50,
|
||||
end: 500
|
||||
};
|
||||
|
||||
this.testClient = new TestClient(mapConfig, 1234);
|
||||
this.testClient.getDataview('pop_max_histogram', params, function(err, dataview) {
|
||||
assert.ok(!err, err);
|
||||
|
||||
assert.ok(6 === dataview.bins_count, 'Unexpected bin count: ' + dataview.bins_count);
|
||||
assert.ok(6 === dataview.bins.length, 'Unexpected number of bins: ' + dataview.bins.length);
|
||||
dataview.bins.forEach(function(bin) {
|
||||
assert.ok(bin.min >= params.start, 'bin min < start: ' + JSON.stringify(bin));
|
||||
assert.ok(bin.max <= params.end, 'bin max > end: ' + JSON.stringify(bin));
|
||||
});
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should get bin_width right when max > min in filter', function(done) {
|
||||
var params = {
|
||||
bins: 10,
|
||||
|
||||
@@ -7,8 +7,7 @@ const mapConfigFactory = require('../fixtures/test_mapconfigFactory');
|
||||
const serverOptions = require('../../lib/cartodb/server_options');
|
||||
|
||||
const usePgMvtRenderer = serverOptions.renderer.mvt.usePostGIS;
|
||||
const postgisVersion = process.env.POSTGIS_VERSION;
|
||||
const describe_mvt = postgisVersion >= '20400' || !usePgMvtRenderer ? describe : describe.skip;
|
||||
const describe_mvt = !usePgMvtRenderer ? describe : describe.skip;
|
||||
|
||||
describe_mvt('date-wrapping', () => {
|
||||
let testClient;
|
||||
|
||||
@@ -7,12 +7,10 @@ const TestClient = require('../support/test-client');
|
||||
const serverOptions = require('../../lib/cartodb/server_options');
|
||||
|
||||
describe('layergroup metadata', function () {
|
||||
|
||||
const usePgMvtRenderer = process.env.POSTGIS_VERSION >= '20400';
|
||||
const originalUsePostGIS = serverOptions.renderer.mvt.usePostGIS;
|
||||
|
||||
before(function () {
|
||||
serverOptions.renderer.mvt.usePostGIS = usePgMvtRenderer;
|
||||
serverOptions.renderer.mvt.usePostGIS = true;
|
||||
});
|
||||
|
||||
after(function () {
|
||||
|
||||
@@ -6,17 +6,16 @@ const assert = require('../support/assert');
|
||||
const TestClient = require('../support/test-client');
|
||||
const serverOptions = require('../../lib/cartodb/server_options');
|
||||
|
||||
const suites = [{
|
||||
desc: 'mapnik',
|
||||
usePostGIS: false
|
||||
}];
|
||||
|
||||
if (process.env.POSTGIS_VERSION >= '20400') {
|
||||
suites.push({
|
||||
const suites = [
|
||||
{
|
||||
desc: 'mapnik',
|
||||
usePostGIS: false
|
||||
},
|
||||
{
|
||||
desc: 'postgis',
|
||||
usePostGIS: true
|
||||
});
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
describe('mvt regressions', function () {
|
||||
|
||||
|
||||
+240
-242
@@ -22,273 +22,271 @@ function createMapConfig(sql = TestClient.SQL.ONE_POINT) {
|
||||
}
|
||||
|
||||
describe('mvt (mapnik)', mvt(false));
|
||||
if (process.env.POSTGIS_VERSION >= '20400') {
|
||||
describe('mvt (postgis)', mvt(true));
|
||||
}
|
||||
describe('mvt (postgis)', mvt(true));
|
||||
|
||||
function mvt(usePostGIS) {
|
||||
return function () {
|
||||
const originalUsePostGIS = serverOptions.renderer.mvt.usePostGIS;
|
||||
before(function () {
|
||||
serverOptions.renderer.mvt.usePostGIS = usePostGIS;
|
||||
});
|
||||
after(function (){
|
||||
serverOptions.renderer.mvt.usePostGIS = originalUsePostGIS;
|
||||
});
|
||||
return function () {
|
||||
const originalUsePostGIS = serverOptions.renderer.mvt.usePostGIS;
|
||||
before(function () {
|
||||
serverOptions.renderer.mvt.usePostGIS = usePostGIS;
|
||||
});
|
||||
after(function (){
|
||||
serverOptions.renderer.mvt.usePostGIS = originalUsePostGIS;
|
||||
});
|
||||
|
||||
describe('named map tile', function () {
|
||||
it('should get default named vector tile', function (done) {
|
||||
const apikeyToken = 1234;
|
||||
const templateName = `mvt-template-${usePostGIS ? 'postgis' : 'mapnik'}`;
|
||||
const template = {
|
||||
version: '0.0.1',
|
||||
name: templateName,
|
||||
placeholders: {
|
||||
buffersize: {
|
||||
type: 'number',
|
||||
default: 0
|
||||
describe('named map tile', function () {
|
||||
it('should get default named vector tile', function (done) {
|
||||
const apikeyToken = 1234;
|
||||
const templateName = `mvt-template-${usePostGIS ? 'postgis' : 'mapnik'}`;
|
||||
const template = {
|
||||
version: '0.0.1',
|
||||
name: templateName,
|
||||
placeholders: {
|
||||
buffersize: {
|
||||
type: 'number',
|
||||
default: 0
|
||||
}
|
||||
},
|
||||
layergroup: {
|
||||
version: '1.7.0',
|
||||
layers: [{
|
||||
type: 'cartodb',
|
||||
options: {
|
||||
sql: 'select * from populated_places_simple_reduced limit 10',
|
||||
cartocss: TestClient.CARTOCSS.POINTS,
|
||||
cartocss_version: '2.3.0',
|
||||
}
|
||||
}]
|
||||
}
|
||||
};
|
||||
|
||||
const testClient = new TestClient(template, apikeyToken);
|
||||
testClient.keysToDelete['map_tpl|localhost'] = 0;
|
||||
|
||||
testClient.getNamedTile(templateName, 0, 0, 0, 'mvt', {}, (err, res, tile) => {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
const tileJSON = tile.toJSON();
|
||||
|
||||
assert.equal(tileJSON[0].features.length, 10);
|
||||
|
||||
testClient.drain(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('analysis-layers-dataviews-mvt', function () {
|
||||
|
||||
function createMapConfig(layers, dataviews, analysis) {
|
||||
return {
|
||||
version: '1.5.0',
|
||||
layers: layers,
|
||||
dataviews: dataviews || {},
|
||||
analyses: analysis || []
|
||||
};
|
||||
}
|
||||
|
||||
var CARTOCSS = [
|
||||
"#points {",
|
||||
" marker-fill-opacity: 1.0;",
|
||||
" marker-line-color: #FFF;",
|
||||
" marker-line-width: 0.5;",
|
||||
" marker-line-opacity: 1.0;",
|
||||
" marker-placement: point;",
|
||||
" marker-type: ellipse;",
|
||||
" marker-width: 8;",
|
||||
" marker-fill: red;",
|
||||
" marker-allow-overlap: true;",
|
||||
"}"
|
||||
].join('\n');
|
||||
|
||||
var mapConfig = createMapConfig(
|
||||
[
|
||||
{
|
||||
"type": "cartodb",
|
||||
"options": {
|
||||
"source": {
|
||||
"id": "2570e105-7b37-40d2-bdf4-1af889598745"
|
||||
},
|
||||
"cartocss": CARTOCSS,
|
||||
"cartocss_version": "2.3.0"
|
||||
}
|
||||
}
|
||||
],
|
||||
{
|
||||
pop_max_histogram: {
|
||||
source: {
|
||||
id: '2570e105-7b37-40d2-bdf4-1af889598745'
|
||||
},
|
||||
type: 'histogram',
|
||||
options: {
|
||||
column: 'pop_max'
|
||||
}
|
||||
}
|
||||
},
|
||||
layergroup: {
|
||||
version: '1.7.0',
|
||||
layers: [{
|
||||
type: 'cartodb',
|
||||
options: {
|
||||
sql: 'select * from populated_places_simple_reduced limit 10',
|
||||
cartocss: TestClient.CARTOCSS.POINTS,
|
||||
cartocss_version: '2.3.0',
|
||||
[
|
||||
{
|
||||
"id": "2570e105-7b37-40d2-bdf4-1af889598745",
|
||||
"type": "source",
|
||||
"params": {
|
||||
"query": "select * from populated_places_simple_reduced"
|
||||
}
|
||||
}]
|
||||
}
|
||||
};
|
||||
|
||||
const testClient = new TestClient(template, apikeyToken);
|
||||
testClient.keysToDelete['map_tpl|localhost'] = 0;
|
||||
|
||||
testClient.getNamedTile(templateName, 0, 0, 0, 'mvt', {}, (err, res, tile) => {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
const tileJSON = tile.toJSON();
|
||||
|
||||
assert.equal(tileJSON[0].features.length, 10);
|
||||
|
||||
testClient.drain(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('analysis-layers-dataviews-mvt', function () {
|
||||
|
||||
function createMapConfig(layers, dataviews, analysis) {
|
||||
return {
|
||||
version: '1.5.0',
|
||||
layers: layers,
|
||||
dataviews: dataviews || {},
|
||||
analyses: analysis || []
|
||||
};
|
||||
}
|
||||
|
||||
var CARTOCSS = [
|
||||
"#points {",
|
||||
" marker-fill-opacity: 1.0;",
|
||||
" marker-line-color: #FFF;",
|
||||
" marker-line-width: 0.5;",
|
||||
" marker-line-opacity: 1.0;",
|
||||
" marker-placement: point;",
|
||||
" marker-type: ellipse;",
|
||||
" marker-width: 8;",
|
||||
" marker-fill: red;",
|
||||
" marker-allow-overlap: true;",
|
||||
"}"
|
||||
].join('\n');
|
||||
|
||||
var mapConfig = createMapConfig(
|
||||
[
|
||||
{
|
||||
"type": "cartodb",
|
||||
"options": {
|
||||
"source": {
|
||||
"id": "2570e105-7b37-40d2-bdf4-1af889598745"
|
||||
},
|
||||
"cartocss": CARTOCSS,
|
||||
"cartocss_version": "2.3.0"
|
||||
}
|
||||
}
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
it('should get pop_max column from dataview', function (done) {
|
||||
var testClient = new TestClient(mapConfig);
|
||||
|
||||
testClient.getTile(0, 0, 0, { format: 'mvt', layers: 0 }, function (err, res, MVT) {
|
||||
var geojsonTile = JSON.parse(MVT.toGeoJSONSync(0));
|
||||
assert.ok(!err, err);
|
||||
|
||||
assert.ok(Array.isArray(geojsonTile.features));
|
||||
assert.ok(geojsonTile.features.length > 0);
|
||||
var feature = geojsonTile.features[0];
|
||||
assert.ok(feature.properties.hasOwnProperty('pop_max'), 'Missing pop_max property');
|
||||
|
||||
testClient.drain(done);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
const testCases = [
|
||||
{
|
||||
pop_max_histogram: {
|
||||
source: {
|
||||
id: '2570e105-7b37-40d2-bdf4-1af889598745'
|
||||
},
|
||||
type: 'histogram',
|
||||
options: {
|
||||
column: 'pop_max'
|
||||
desc: 'should get empty mvt with code 204 (no content)',
|
||||
coords: { z: 0, x: 0, y: 0 },
|
||||
format: 'mvt',
|
||||
response: {
|
||||
status: 204,
|
||||
headers: {
|
||||
'Content-Type': undefined
|
||||
}
|
||||
}
|
||||
},
|
||||
mapConfig: createMapConfig(TestClient.SQL.EMPTY)
|
||||
},
|
||||
[
|
||||
{
|
||||
"id": "2570e105-7b37-40d2-bdf4-1af889598745",
|
||||
"type": "source",
|
||||
"params": {
|
||||
"query": "select * from populated_places_simple_reduced"
|
||||
{
|
||||
desc: 'should get mvt tile with code 200 (ok)',
|
||||
coords: { z: 0, x: 0, y: 0 },
|
||||
format: 'mvt',
|
||||
response: {
|
||||
status: 200,
|
||||
headers: {
|
||||
'Content-Type': 'application/x-protobuf'
|
||||
}
|
||||
}
|
||||
]
|
||||
);
|
||||
},
|
||||
mapConfig: createMapConfig()
|
||||
}
|
||||
];
|
||||
|
||||
it('should get pop_max column from dataview', function (done) {
|
||||
var testClient = new TestClient(mapConfig);
|
||||
testCases.forEach(function (test) {
|
||||
it(test.desc, done => {
|
||||
var testClient = new TestClient(test.mapConfig);
|
||||
const { z, x, y } = test.coords;
|
||||
const { format, response } = test;
|
||||
|
||||
testClient.getTile(0, 0, 0, { format: 'mvt', layers: 0 }, function (err, res, MVT) {
|
||||
var geojsonTile = JSON.parse(MVT.toGeoJSONSync(0));
|
||||
assert.ok(!err, err);
|
||||
|
||||
assert.ok(Array.isArray(geojsonTile.features));
|
||||
assert.ok(geojsonTile.features.length > 0);
|
||||
var feature = geojsonTile.features[0];
|
||||
assert.ok(feature.properties.hasOwnProperty('pop_max'), 'Missing pop_max property');
|
||||
|
||||
testClient.drain(done);
|
||||
testClient.getTile(z, x, y, { format, response }, err => {
|
||||
assert.ifError(err);
|
||||
testClient.drain(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
describe('overviews', function () {
|
||||
function createMapConfig(layers, dataviews, analysis) {
|
||||
return {
|
||||
version: '1.8.0',
|
||||
layers: layers,
|
||||
dataviews: dataviews || {},
|
||||
analyses: analysis || []
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
const testCases = [
|
||||
{
|
||||
desc: 'should get empty mvt with code 204 (no content)',
|
||||
coords: { z: 0, x: 0, y: 0 },
|
||||
format: 'mvt',
|
||||
response: {
|
||||
status: 204,
|
||||
headers: {
|
||||
'Content-Type': undefined
|
||||
}
|
||||
},
|
||||
mapConfig: createMapConfig(TestClient.SQL.EMPTY)
|
||||
},
|
||||
{
|
||||
desc: 'should get mvt tile with code 200 (ok)',
|
||||
coords: { z: 0, x: 0, y: 0 },
|
||||
format: 'mvt',
|
||||
response: {
|
||||
status: 200,
|
||||
headers: {
|
||||
'Content-Type': 'application/x-protobuf'
|
||||
}
|
||||
},
|
||||
mapConfig: createMapConfig()
|
||||
}
|
||||
];
|
||||
|
||||
testCases.forEach(function (test) {
|
||||
it(test.desc, done => {
|
||||
var testClient = new TestClient(test.mapConfig);
|
||||
const { z, x, y } = test.coords;
|
||||
const { format, response } = test;
|
||||
|
||||
testClient.getTile(z, x, y, { format, response }, err => {
|
||||
assert.ifError(err);
|
||||
testClient.drain(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('overviews', function () {
|
||||
function createMapConfig(layers, dataviews, analysis) {
|
||||
return {
|
||||
version: '1.8.0',
|
||||
layers: layers,
|
||||
dataviews: dataviews || {},
|
||||
analyses: analysis || []
|
||||
};
|
||||
}
|
||||
|
||||
it('should use overviews to fetch mvt data', function (done) {
|
||||
const mapConfig = createMapConfig(
|
||||
[
|
||||
{
|
||||
"type": "cartodb",
|
||||
"options": {
|
||||
"sql": 'SELECT * FROM test_table_overviews',
|
||||
"cartocss": TestClient.CARTOCSS.POINTS,
|
||||
"cartocss_version": "2.3.0"
|
||||
it('should use overviews to fetch mvt data', function (done) {
|
||||
const mapConfig = createMapConfig(
|
||||
[
|
||||
{
|
||||
"type": "cartodb",
|
||||
"options": {
|
||||
"sql": 'SELECT * FROM test_table_overviews',
|
||||
"cartocss": TestClient.CARTOCSS.POINTS,
|
||||
"cartocss_version": "2.3.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
);
|
||||
]
|
||||
);
|
||||
|
||||
const testClient = new TestClient(mapConfig);
|
||||
const [ z, x, y ] = [ 0, 0, 0 ];
|
||||
const options = { format: 'mvt' };
|
||||
const testClient = new TestClient(mapConfig);
|
||||
const [ z, x, y ] = [ 0, 0, 0 ];
|
||||
const options = { format: 'mvt' };
|
||||
|
||||
testClient.getTile(z, x, y, options, function (err, res, mvt) {
|
||||
assert.ifError(err);
|
||||
testClient.getTile(z, x, y, options, function (err, res, mvt) {
|
||||
assert.ifError(err);
|
||||
|
||||
const geojsonTile = JSON.parse(mvt.toGeoJSONSync(0));
|
||||
const geojsonTile = JSON.parse(mvt.toGeoJSONSync(0));
|
||||
|
||||
assert.ok(Array.isArray(geojsonTile.features));
|
||||
assert.ok(geojsonTile.features.length > 0);
|
||||
assert.ok(Array.isArray(geojsonTile.features));
|
||||
assert.ok(geojsonTile.features.length > 0);
|
||||
|
||||
const feature = geojsonTile.features[0];
|
||||
const feature = geojsonTile.features[0];
|
||||
|
||||
assert.ok(feature.properties.hasOwnProperty('_feature_count'), 'Missing _feature_count property');
|
||||
assert.equal(feature.properties.cartodb_id, 1);
|
||||
assert.equal(feature.properties.name, 'Hawai');
|
||||
assert.equal(feature.properties._feature_count, 5); // original table has _feature_count = 1
|
||||
assert.equal(feature.properties.value, 3); // original table has value = 1.0
|
||||
assert.ok(feature.properties.hasOwnProperty('_feature_count'), 'Missing _feature_count property');
|
||||
assert.equal(feature.properties.cartodb_id, 1);
|
||||
assert.equal(feature.properties.name, 'Hawai');
|
||||
assert.equal(feature.properties._feature_count, 5); // original table has _feature_count = 1
|
||||
assert.equal(feature.properties.value, 3); // original table has value = 1.0
|
||||
|
||||
testClient.drain(done);
|
||||
testClient.drain(done);
|
||||
});
|
||||
});
|
||||
|
||||
it('first layer should use overviews, second layer shouldn\'t', function (done) {
|
||||
const mapConfig = createMapConfig(
|
||||
[
|
||||
{
|
||||
"type": "cartodb",
|
||||
"options": {
|
||||
"sql": 'SELECT * FROM test_table_overviews',
|
||||
"cartocss": TestClient.CARTOCSS.POINTS,
|
||||
"cartocss_version": "2.3.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "cartodb",
|
||||
"options": {
|
||||
"sql": 'SELECT * FROM test_table',
|
||||
"cartocss": TestClient.CARTOCSS.POINTS,
|
||||
"cartocss_version": "2.3.0"
|
||||
}
|
||||
}
|
||||
]
|
||||
);
|
||||
|
||||
const testClient = new TestClient(mapConfig);
|
||||
const [ z, x, y ] = [ 0, 0, 0 ];
|
||||
const options = { format: 'mvt' };
|
||||
|
||||
testClient.getTile(z, x, y, options, function (err, res, mvt) {
|
||||
assert.ifError(err);
|
||||
|
||||
const tileWithOverviews = JSON.parse(mvt.toGeoJSONSync(0));
|
||||
const tileWithoutOverviews = JSON.parse(mvt.toGeoJSONSync(1));
|
||||
|
||||
assert.ok(Array.isArray(tileWithOverviews.features));
|
||||
assert.equal(tileWithOverviews.features.length, 1);
|
||||
assert.equal(tileWithOverviews.features[0].properties._feature_count, 5);
|
||||
|
||||
assert.ok(Array.isArray(tileWithoutOverviews.features));
|
||||
assert.equal(tileWithoutOverviews.features.length, 5);
|
||||
assert.equal(tileWithoutOverviews.features[0].properties._feature_count, undefined);
|
||||
|
||||
testClient.drain(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('first layer should use overviews, second layer shouldn\'t', function (done) {
|
||||
const mapConfig = createMapConfig(
|
||||
[
|
||||
{
|
||||
"type": "cartodb",
|
||||
"options": {
|
||||
"sql": 'SELECT * FROM test_table_overviews',
|
||||
"cartocss": TestClient.CARTOCSS.POINTS,
|
||||
"cartocss_version": "2.3.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "cartodb",
|
||||
"options": {
|
||||
"sql": 'SELECT * FROM test_table',
|
||||
"cartocss": TestClient.CARTOCSS.POINTS,
|
||||
"cartocss_version": "2.3.0"
|
||||
}
|
||||
}
|
||||
]
|
||||
);
|
||||
|
||||
const testClient = new TestClient(mapConfig);
|
||||
const [ z, x, y ] = [ 0, 0, 0 ];
|
||||
const options = { format: 'mvt' };
|
||||
|
||||
testClient.getTile(z, x, y, options, function (err, res, mvt) {
|
||||
assert.ifError(err);
|
||||
|
||||
const tileWithOverviews = JSON.parse(mvt.toGeoJSONSync(0));
|
||||
const tileWithoutOverviews = JSON.parse(mvt.toGeoJSONSync(1));
|
||||
|
||||
assert.ok(Array.isArray(tileWithOverviews.features));
|
||||
assert.equal(tileWithOverviews.features.length, 1);
|
||||
assert.equal(tileWithOverviews.features[0].properties._feature_count, 5);
|
||||
|
||||
assert.ok(Array.isArray(tileWithoutOverviews.features));
|
||||
assert.equal(tileWithoutOverviews.features.length, 5);
|
||||
assert.equal(tileWithoutOverviews.features[0].properties._feature_count, undefined);
|
||||
|
||||
testClient.drain(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -276,11 +276,11 @@ describe('rate limit middleware', function () {
|
||||
});
|
||||
});
|
||||
|
||||
const describe_pg = process.env.POSTGIS_VERSION >= '20400' ? describe : describe.skip;
|
||||
|
||||
const originalUsePostGIS = serverOptions.renderer.mvt.usePostGIS;
|
||||
|
||||
describe('rate limit and vector tiles (mapnik)', () => { rateLimitAndVectorTilesTest(false); });
|
||||
describe_pg('rate limit and vector tiles (postgis)', () => { rateLimitAndVectorTilesTest(true); });
|
||||
describe('rate limit and vector tiles (mapnik)', () => rateLimitAndVectorTilesTest(false));
|
||||
describe('rate limit and vector tiles (postgis)', () => rateLimitAndVectorTilesTest(true));
|
||||
|
||||
function rateLimitAndVectorTilesTest(usePostGIS) {
|
||||
|
||||
|
||||
@@ -6,17 +6,16 @@ var assert = require('../../support/assert');
|
||||
var TestClient = require('../../support/test-client');
|
||||
const serverOptions = require('../../../lib/cartodb/server_options');
|
||||
|
||||
const suites = [{
|
||||
desc: 'mvt (mapnik)',
|
||||
usePostGIS: false
|
||||
}];
|
||||
|
||||
if (process.env.POSTGIS_VERSION >= '20400') {
|
||||
suites.push({
|
||||
const suites = [
|
||||
{
|
||||
desc: 'mvt (mapnik)',
|
||||
usePostGIS: false
|
||||
},
|
||||
{
|
||||
desc: 'mvt (postgis)',
|
||||
usePostGIS: true
|
||||
});
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
suites.forEach(({desc, usePostGIS}) => {
|
||||
describe(`[${desc}] Create mapnik layergroup`, function() {
|
||||
|
||||
@@ -6,11 +6,10 @@ const assert = require('../support/assert');
|
||||
const TestClient = require('../support/test-client');
|
||||
const serverOptions = require('../../lib/cartodb/server_options');
|
||||
|
||||
const describe_pg = process.env.POSTGIS_VERSION >= '20400' ? describe : describe.skip;
|
||||
const originalUsePostGIS = serverOptions.renderer.mvt.usePostGIS;
|
||||
|
||||
describe('tilejson via mapnik renderer', () => { tileJsonSuite(false); });
|
||||
describe_pg('tilejson via postgis renderer', () => { tileJsonSuite(true); });
|
||||
describe('tilejson via mapnik renderer', () => tileJsonSuite(false));
|
||||
describe('tilejson via postgis renderer', () => tileJsonSuite(true));
|
||||
|
||||
function tileJsonSuite(usePostGIS) {
|
||||
|
||||
|
||||
@@ -394,9 +394,8 @@ describe('user database timeout limit', function () {
|
||||
});
|
||||
});
|
||||
|
||||
const describe_pg = process.env.POSTGIS_VERSION >= '20400' ? describe : describe.skip;
|
||||
describe('fetching vector tiles via mapnik renderer', () => { testFetchingVectorTiles(false); });
|
||||
describe_pg('fetching vector tiles via postgis renderer', () => { testFetchingVectorTiles(true); });
|
||||
describe('fetching vector tiles via mapnik renderer', () => testFetchingVectorTiles(false));
|
||||
describe('fetching vector tiles via postgis renderer', () => testFetchingVectorTiles(true));
|
||||
|
||||
function testFetchingVectorTiles(usePostGIS) {
|
||||
const originalUsePostGIS = serverOptions.renderer.mvt.usePostGIS;
|
||||
|
||||
@@ -69,17 +69,16 @@ const INVALID_FORMAT_ERROR = {
|
||||
]
|
||||
};
|
||||
|
||||
const suites = [{
|
||||
desc: 'mvt (mapnik)',
|
||||
usePostGIS: false
|
||||
}];
|
||||
|
||||
if (process.env.POSTGIS_VERSION >= '20400') {
|
||||
suites.push({
|
||||
const suites = [
|
||||
{
|
||||
desc: 'mvt (mapnik)',
|
||||
usePostGIS: false
|
||||
},
|
||||
{
|
||||
desc: 'mvt (postgis)',
|
||||
usePostGIS: true
|
||||
});
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
suites.forEach((suite) => {
|
||||
const { desc, usePostGIS } = suite;
|
||||
|
||||
@@ -73,20 +73,6 @@ echo "PUBLICPASS: ${PUBLICPASS}"
|
||||
echo "TESTUSER: ${TESTUSER}"
|
||||
echo "TESTPASS: ${TESTPASS}"
|
||||
|
||||
# Sets the env variable POSTGIS_VERSION as Major * 10000 + Minor * 100 + Patch
|
||||
# For example, for 2.4.5 ~> 20405
|
||||
auto_postgis_version() {
|
||||
local POSTGIS_STR=$(psql -c "Select default_version from pg_available_extensions WHERE name = 'postgis';" -t);
|
||||
local pg_version=$(echo $POSTGIS_STR | awk -F '.' '{print $1 * 10000 + $2 * 100 + $3}')
|
||||
|
||||
echo $pg_version
|
||||
}
|
||||
|
||||
if [ -z "$POSTGIS_VERSION" ]; then
|
||||
export POSTGIS_VERSION=$(auto_postgis_version)
|
||||
echo "POSTGIS_VERSION: ${POSTGIS_VERSION}"
|
||||
fi
|
||||
|
||||
if test x"$PREPARE_PGSQL" = xyes; then
|
||||
|
||||
echo "preparing postgres..."
|
||||
@@ -110,13 +96,6 @@ if test x"$PREPARE_PGSQL" = xyes; then
|
||||
ALL_SQL_SCRIPTS="${REMOTE_SQL_SCRIPTS} ${LOCAL_SQL_SCRIPTS}"
|
||||
for i in ${ALL_SQL_SCRIPTS}
|
||||
do
|
||||
# Strip PARALLEL labels for PostgreSQL releases before 9.6
|
||||
if [ $PG_PARALLEL -eq 0 ]; then
|
||||
TMPFILE=$(mktemp /tmp/$(basename $0).XXXXXXXX)
|
||||
sed -e 's/PARALLEL \= [A-Z]*,/''/g' \
|
||||
-e 's/PARALLEL [A-Z]*/''/g' sql/$i.sql > $TMPFILE
|
||||
mv $TMPFILE sql/$i.sql
|
||||
fi
|
||||
cat sql/${i}.sql |
|
||||
sed -e 's/cartodb\./public./g' -e "s/''cartodb''/''public''/g" |
|
||||
sed "s/:PUBLICUSER/${PUBLICUSER}/" |
|
||||
|
||||
@@ -620,6 +620,111 @@ TestClient.prototype.getFeatureAttributes = function(featureId, layerId, params,
|
||||
);
|
||||
};
|
||||
|
||||
TestClient.prototype.getClusterFeatures = function (zoom, clusterId, layerId, params, callback) {
|
||||
var self = this;
|
||||
|
||||
if (!callback) {
|
||||
callback = params;
|
||||
params = {};
|
||||
}
|
||||
|
||||
var extraParams = {};
|
||||
|
||||
if (this.apiKey) {
|
||||
extraParams.api_key = this.apiKey;
|
||||
}
|
||||
|
||||
// if (params && params.filters) {
|
||||
// extraParams.filters = JSON.stringify(params.filters);
|
||||
// }
|
||||
|
||||
var url = '/api/v1/map';
|
||||
if (Object.keys(extraParams).length > 0) {
|
||||
url += '?' + qs.stringify(extraParams);
|
||||
}
|
||||
|
||||
var expectedResponse = params.response || {
|
||||
status: 200,
|
||||
headers: {
|
||||
'Content-Type': 'application/json; charset=utf-8'
|
||||
}
|
||||
};
|
||||
|
||||
step(
|
||||
function createLayergroup() {
|
||||
var next = this;
|
||||
assert.response(self.server,
|
||||
{
|
||||
url: url,
|
||||
method: 'POST',
|
||||
headers: {
|
||||
host: 'localhost',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
data: JSON.stringify(self.mapConfig)
|
||||
},
|
||||
{
|
||||
status: 200,
|
||||
headers: {
|
||||
'Content-Type': 'application/json; charset=utf-8'
|
||||
}
|
||||
},
|
||||
function(res, err) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
var parsedBody = JSON.parse(res.body);
|
||||
|
||||
if (parsedBody.layergroupid) {
|
||||
self.keysToDelete['map_cfg|' + LayergroupToken.parse(parsedBody.layergroupid).token] = 0;
|
||||
self.keysToDelete['user:localhost:mapviews:global'] = 5;
|
||||
}
|
||||
|
||||
return next(null, parsedBody.layergroupid);
|
||||
}
|
||||
);
|
||||
},
|
||||
function getCLusterFeatures (err, layergroupId) {
|
||||
assert.ifError(err);
|
||||
|
||||
var next = this;
|
||||
|
||||
let queryParams = '';
|
||||
if (params.aggregation) {
|
||||
queryParams = qs.stringify({ aggregation: JSON.stringify(params.aggregation) });
|
||||
}
|
||||
|
||||
url = `/api/v1/map/${layergroupId}/${layerId}/${zoom}/cluster/${clusterId}?${queryParams}`;
|
||||
|
||||
assert.response(self.server,
|
||||
{
|
||||
url: url,
|
||||
method: 'GET',
|
||||
headers: {
|
||||
host: 'localhost'
|
||||
}
|
||||
},
|
||||
expectedResponse,
|
||||
function(res, err) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
next(null, JSON.parse(res.body));
|
||||
}
|
||||
);
|
||||
},
|
||||
function finish(err, attributes) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
return callback(null, attributes);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
TestClient.prototype.getTile = function(z, x, y, params, callback) {
|
||||
var self = this;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user