2019-02-27 02:19:44 +08:00
|
|
|
'use strict';
|
|
|
|
|
|
|
|
require('../support/test_helper');
|
|
|
|
|
2019-02-27 19:43:26 +08:00
|
|
|
const assert = require('../support/assert');
|
2019-02-27 02:19:44 +08:00
|
|
|
const TestClient = require('../support/test-client');
|
|
|
|
|
|
|
|
const POINTS_SQL_1 = `
|
|
|
|
select
|
|
|
|
x + 4 as cartodb_id,
|
2019-03-12 22:18:31 +08:00
|
|
|
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,
|
2019-03-01 18:21:18 +08:00
|
|
|
x as value,
|
|
|
|
CASE
|
|
|
|
WHEN x % 2 = 0 THEN 'even'
|
|
|
|
ELSE 'odd'
|
|
|
|
END AS type
|
2019-02-27 02:19:44 +08:00
|
|
|
from generate_series(-3, 3) x
|
|
|
|
`;
|
|
|
|
|
|
|
|
const defaultLayers = [{
|
|
|
|
type: 'cartodb',
|
|
|
|
options: {
|
|
|
|
sql: POINTS_SQL_1,
|
2019-02-27 19:43:26 +08:00
|
|
|
aggregation: {
|
|
|
|
threshold: 1
|
|
|
|
}
|
2019-02-27 02:19:44 +08:00
|
|
|
}
|
|
|
|
}];
|
|
|
|
|
|
|
|
function createVectorMapConfig (layers = defaultLayers) {
|
|
|
|
return {
|
|
|
|
version: '1.8.0',
|
|
|
|
layers: layers
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
describe('cluster', function () {
|
2019-03-02 00:21:55 +08:00
|
|
|
describe('w/o aggregation', function () {
|
2019-02-28 01:54:21 +08:00
|
|
|
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, {
|
2019-03-12 22:18:31 +08:00
|
|
|
errors:[ 'Map f697fb370c6479559ae2f66d684e8227 has no aggregation defined for layer 0' ],
|
2019-02-28 01:54:21 +08:00
|
|
|
errors_with_context:[
|
|
|
|
{
|
2019-02-28 19:13:15 +08:00
|
|
|
layer: {
|
|
|
|
index: '0',
|
|
|
|
type: 'cartodb'
|
|
|
|
},
|
2019-03-12 22:18:31 +08:00
|
|
|
message: 'Map f697fb370c6479559ae2f66d684e8227 has no aggregation defined for layer 0',
|
2019-02-28 19:13:15 +08:00
|
|
|
subtype: 'aggregation',
|
|
|
|
type: 'layer'
|
2019-02-28 01:54:21 +08:00
|
|
|
}
|
|
|
|
]
|
|
|
|
});
|
2019-02-28 19:13:15 +08:00
|
|
|
|
|
|
|
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, {
|
2019-03-12 22:18:31 +08:00
|
|
|
errors:[ 'Map 7521bcd1029c401289dd651ce91d5d9d has no aggregation defined for layer 0' ],
|
2019-02-28 19:13:15 +08:00
|
|
|
errors_with_context:[
|
|
|
|
{
|
|
|
|
layer: {
|
|
|
|
index: '0',
|
|
|
|
type: 'cartodb'
|
|
|
|
},
|
2019-03-12 22:18:31 +08:00
|
|
|
message: 'Map 7521bcd1029c401289dd651ce91d5d9d has no aggregation defined for layer 0',
|
2019-02-28 19:13:15 +08:00
|
|
|
subtype: 'aggregation',
|
|
|
|
type: 'layer'
|
|
|
|
}
|
|
|
|
]
|
|
|
|
});
|
|
|
|
|
2019-02-28 01:54:21 +08:00
|
|
|
testClient.drain(done);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2019-03-02 00:21:55 +08:00
|
|
|
describe('fetch features within a cluster grid', function () {
|
2019-02-27 19:43:26 +08:00
|
|
|
const suite = [
|
|
|
|
{
|
2019-02-28 01:54:21 +08:00
|
|
|
zoom: 0,
|
2019-02-27 19:43:26 +08:00
|
|
|
cartodb_id: 1,
|
2019-02-28 01:54:21 +08:00
|
|
|
resolution: 0.5,
|
2019-03-01 18:21:18 +08:00
|
|
|
expected: [ { cartodb_id: 1, value: -3, type: 'odd' } ]
|
2019-02-27 19:43:26 +08:00
|
|
|
},
|
|
|
|
{
|
2019-02-28 01:54:21 +08:00
|
|
|
zoom: 0,
|
2019-02-27 19:43:26 +08:00
|
|
|
cartodb_id: 2,
|
2019-02-28 01:54:21 +08:00
|
|
|
resolution: 0.5,
|
2019-03-01 18:21:18 +08:00
|
|
|
expected: [ { cartodb_id: 2, value: -2, type: 'even' } ]
|
2019-02-27 19:43:26 +08:00
|
|
|
},
|
|
|
|
{
|
2019-02-28 01:54:21 +08:00
|
|
|
zoom: 0,
|
2019-02-27 19:43:26 +08:00
|
|
|
cartodb_id: 3,
|
2019-02-28 01:54:21 +08:00
|
|
|
resolution: 0.5,
|
2019-03-01 18:21:18 +08:00
|
|
|
expected: [ { cartodb_id: 3, value: -1, type: 'odd' } ]
|
2019-02-27 19:43:26 +08:00
|
|
|
},
|
|
|
|
{
|
2019-02-28 01:54:21 +08:00
|
|
|
zoom: 0,
|
2019-02-27 19:43:26 +08:00
|
|
|
cartodb_id: 4,
|
2019-02-28 01:54:21 +08:00
|
|
|
resolution: 0.5,
|
2019-03-01 18:21:18 +08:00
|
|
|
expected: [ { cartodb_id: 4, value: 0, type: 'even' } ]
|
2019-02-27 19:43:26 +08:00
|
|
|
},
|
|
|
|
{
|
2019-02-28 01:54:21 +08:00
|
|
|
zoom: 0,
|
2019-02-27 19:43:26 +08:00
|
|
|
cartodb_id: 5,
|
2019-02-28 01:54:21 +08:00
|
|
|
resolution: 0.5,
|
2019-03-01 18:21:18 +08:00
|
|
|
expected: [ { cartodb_id: 5, value: 1, type: 'odd' } ]
|
2019-02-27 19:43:26 +08:00
|
|
|
},
|
|
|
|
{
|
2019-02-28 01:54:21 +08:00
|
|
|
zoom: 0,
|
2019-02-27 19:43:26 +08:00
|
|
|
cartodb_id: 6,
|
2019-02-28 01:54:21 +08:00
|
|
|
resolution: 0.5,
|
2019-03-01 18:21:18 +08:00
|
|
|
expected: [ { cartodb_id: 6, value: 2, type: 'even' } ]
|
2019-02-28 01:54:21 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
zoom: 0,
|
|
|
|
cartodb_id: 7,
|
|
|
|
resolution: 0.5,
|
2019-03-01 18:21:18 +08:00
|
|
|
expected: [ { cartodb_id: 7, value: 3, type: 'odd' } ]
|
2019-02-28 01:54:21 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
zoom: 0,
|
|
|
|
cartodb_id: 1,
|
|
|
|
resolution: 1,
|
2019-03-01 18:21:18 +08:00
|
|
|
expected: [ { cartodb_id: 1, value: -3, type: 'odd' } ]
|
2019-02-28 01:54:21 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
zoom: 0,
|
|
|
|
cartodb_id: 2,
|
|
|
|
resolution: 1,
|
2019-03-01 18:21:18 +08:00
|
|
|
expected: [ { cartodb_id: 2, value: -2, type: 'even' } ]
|
2019-02-28 01:54:21 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
zoom: 0,
|
|
|
|
cartodb_id: 3,
|
|
|
|
resolution: 1,
|
2019-03-01 18:21:18 +08:00
|
|
|
expected: [ { cartodb_id: 3, value: -1, type: 'odd' } ]
|
2019-02-28 01:54:21 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
zoom: 0,
|
|
|
|
cartodb_id: 4,
|
|
|
|
resolution: 1,
|
2019-03-01 18:21:18 +08:00
|
|
|
expected: [ { cartodb_id: 4, value: 0, type: 'even' } ]
|
2019-02-28 01:54:21 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
zoom: 0,
|
|
|
|
cartodb_id: 5,
|
|
|
|
resolution: 1,
|
2019-03-01 18:21:18 +08:00
|
|
|
expected: [ { cartodb_id: 5, value: 1, type: 'odd' } ]
|
2019-02-28 01:54:21 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
zoom: 0,
|
|
|
|
cartodb_id: 6,
|
|
|
|
resolution: 1,
|
2019-03-01 18:21:18 +08:00
|
|
|
expected: [ { cartodb_id: 6, value: 2, type: 'even' } ]
|
2019-02-28 01:54:21 +08:00
|
|
|
},
|
2019-02-27 19:43:26 +08:00
|
|
|
{
|
2019-02-28 01:54:21 +08:00
|
|
|
zoom: 0,
|
|
|
|
cartodb_id: 7,
|
|
|
|
resolution: 1,
|
2019-03-01 18:21:18 +08:00
|
|
|
expected: [ { cartodb_id: 7, value: 3, type: 'odd' } ]
|
2019-02-28 01:54:21 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
zoom: 0,
|
2019-02-27 19:43:26 +08:00
|
|
|
cartodb_id: 1,
|
|
|
|
resolution: 50,
|
|
|
|
expected: [
|
2019-03-01 18:21:18 +08:00
|
|
|
{ cartodb_id: 1, value: -3, type: 'odd' },
|
2019-03-12 22:18:31 +08:00
|
|
|
{ cartodb_id: 2, value: -2, type: 'even' }
|
2019-02-27 19:43:26 +08:00
|
|
|
]
|
|
|
|
},
|
|
|
|
{
|
2019-02-28 01:54:21 +08:00
|
|
|
zoom: 0,
|
|
|
|
cartodb_id: 5,
|
|
|
|
resolution: 50,
|
|
|
|
expected: [
|
2019-03-12 17:35:16 +08:00
|
|
|
{ cartodb_id: 4, value: 0, type: 'even' },
|
2019-03-01 18:21:18 +08:00
|
|
|
{ cartodb_id: 5, value: 1, type: 'odd' },
|
|
|
|
{ cartodb_id: 6, value: 2, type: 'even' },
|
|
|
|
{ cartodb_id: 7, value: 3, type: 'odd' }
|
2019-02-28 01:54:21 +08:00
|
|
|
]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
zoom: 1,
|
|
|
|
cartodb_id: 1,
|
|
|
|
resolution: 1,
|
2019-03-01 18:21:18 +08:00
|
|
|
expected: [ { cartodb_id: 1, value: -3, type: 'odd' } ]
|
2019-02-28 01:54:21 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
zoom: 1,
|
|
|
|
cartodb_id: 2,
|
|
|
|
resolution: 1,
|
2019-03-01 18:21:18 +08:00
|
|
|
expected: [ { cartodb_id: 2, value: -2, type: 'even' } ]
|
2019-02-28 01:54:21 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
zoom: 1,
|
|
|
|
cartodb_id: 3,
|
|
|
|
resolution: 1,
|
2019-03-01 18:21:18 +08:00
|
|
|
expected: [ { cartodb_id: 3, value: -1, type: 'odd' } ]
|
2019-02-28 01:54:21 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
zoom: 1,
|
|
|
|
cartodb_id: 4,
|
|
|
|
resolution: 1,
|
2019-03-01 18:21:18 +08:00
|
|
|
expected: [ { cartodb_id: 4, value: 0, type: 'even' } ]
|
2019-02-28 01:54:21 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
zoom: 1,
|
|
|
|
cartodb_id: 5,
|
|
|
|
resolution: 1,
|
2019-03-01 18:21:18 +08:00
|
|
|
expected: [ { cartodb_id: 5, value: 1, type: 'odd' } ]
|
2019-02-28 01:54:21 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
zoom: 1,
|
|
|
|
cartodb_id: 6,
|
|
|
|
resolution: 1,
|
2019-03-01 18:21:18 +08:00
|
|
|
expected: [ { cartodb_id: 6, value: 2, type: 'even' } ]
|
2019-02-28 01:54:21 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
zoom: 1,
|
|
|
|
cartodb_id: 7,
|
|
|
|
resolution: 1,
|
2019-03-01 18:21:18 +08:00
|
|
|
expected: [ { cartodb_id: 7, value: 3, type: 'odd' } ]
|
2019-02-28 01:54:21 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
zoom: 1,
|
|
|
|
cartodb_id: 1,
|
|
|
|
resolution: 50,
|
|
|
|
expected: [
|
2019-03-01 18:21:18 +08:00
|
|
|
{ cartodb_id: 1, value: -3, type: 'odd' },
|
2019-03-12 22:18:31 +08:00
|
|
|
{ cartodb_id: 2, value: -2, type: 'even'}
|
2019-02-28 01:54:21 +08:00
|
|
|
]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
zoom: 1,
|
2019-02-27 19:43:26 +08:00
|
|
|
cartodb_id: 5,
|
|
|
|
resolution: 50,
|
|
|
|
expected: [
|
2019-03-12 17:35:16 +08:00
|
|
|
{ cartodb_id: 4, value: 0, type: 'even' },
|
2019-03-12 22:18:31 +08:00
|
|
|
{ cartodb_id: 5, value: 1, type: 'odd' }
|
2019-02-27 19:43:26 +08:00
|
|
|
]
|
|
|
|
}
|
|
|
|
];
|
|
|
|
|
2019-02-28 01:54:21 +08:00
|
|
|
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) {
|
2019-02-27 19:43:26 +08:00
|
|
|
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 = {};
|
|
|
|
|
2019-02-28 01:54:21 +08:00
|
|
|
testClient.getClusterFeatures(zoom, cartodb_id, layerId, params, (err, body) => {
|
2019-02-27 19:43:26 +08:00
|
|
|
if (err) {
|
|
|
|
return done(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
assert.deepStrictEqual(body.rows, expected);
|
|
|
|
testClient.drain(done);
|
|
|
|
});
|
|
|
|
});
|
2019-02-27 02:19:44 +08:00
|
|
|
});
|
|
|
|
});
|
2019-03-01 18:21:18 +08:00
|
|
|
|
2019-03-02 00:21:55 +08:00
|
|
|
describe('valid aggregation input', function () {
|
2019-03-01 18:21:18 +08:00
|
|
|
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: [
|
2019-03-12 17:35:16 +08:00
|
|
|
{ _cdb_feature_count: 1, type: 'even' },
|
2019-03-12 22:18:31 +08:00
|
|
|
{ _cdb_feature_count: 1, type: 'odd' }
|
2019-03-01 18:21:18 +08:00
|
|
|
]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
zoom: 0,
|
|
|
|
cartodb_id: 5,
|
|
|
|
resolution: 50,
|
|
|
|
aggregation: { columns: ['type'] },
|
|
|
|
expected: [
|
2019-03-12 17:35:16 +08:00
|
|
|
{ _cdb_feature_count: 2, type: 'even' },
|
2019-03-01 18:21:18 +08:00
|
|
|
{ _cdb_feature_count: 2, type: 'odd' }
|
|
|
|
]
|
2019-03-01 22:45:38 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
zoom: 0,
|
|
|
|
cartodb_id: 1,
|
|
|
|
resolution: 1,
|
|
|
|
aggregation: {
|
|
|
|
columns: [ 'type' ],
|
|
|
|
expressions: {
|
|
|
|
max_value: {
|
2019-03-02 00:02:06 +08:00
|
|
|
aggregate_function: 'max',
|
2019-03-01 22:45:38 +08:00
|
|
|
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: {
|
2019-03-02 00:02:06 +08:00
|
|
|
aggregate_function: 'max',
|
2019-03-01 22:45:38 +08:00
|
|
|
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: {
|
2019-03-02 00:02:06 +08:00
|
|
|
aggregate_function: 'max',
|
2019-03-01 22:45:38 +08:00
|
|
|
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: {
|
2019-03-02 00:02:06 +08:00
|
|
|
aggregate_function: 'max',
|
2019-03-01 22:45:38 +08:00
|
|
|
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: {
|
2019-03-02 00:02:06 +08:00
|
|
|
aggregate_function: 'max',
|
2019-03-01 22:45:38 +08:00
|
|
|
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: {
|
2019-03-02 00:02:06 +08:00
|
|
|
aggregate_function: 'max',
|
2019-03-01 22:45:38 +08:00
|
|
|
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: {
|
2019-03-02 00:02:06 +08:00
|
|
|
aggregate_function: 'max',
|
2019-03-01 22:45:38 +08:00
|
|
|
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: {
|
2019-03-02 00:02:06 +08:00
|
|
|
aggregate_function: 'max',
|
2019-03-01 22:45:38 +08:00
|
|
|
aggregated_column: 'value',
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
expected: [
|
2019-03-12 17:35:16 +08:00
|
|
|
{ _cdb_feature_count: 1, type: 'even', max_value: -2 },
|
2019-03-12 22:18:31 +08:00
|
|
|
{ _cdb_feature_count: 1, type: 'odd', max_value: -3 }
|
2019-03-01 22:45:38 +08:00
|
|
|
]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
zoom: 0,
|
|
|
|
cartodb_id: 5,
|
|
|
|
resolution: 50,
|
|
|
|
aggregation: {
|
|
|
|
columns: [ 'type' ],
|
|
|
|
expressions: {
|
|
|
|
max_value: {
|
2019-03-02 00:02:06 +08:00
|
|
|
aggregate_function: 'max',
|
2019-03-01 22:45:38 +08:00
|
|
|
aggregated_column: 'value',
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
expected: [
|
2019-03-12 17:35:16 +08:00
|
|
|
{ _cdb_feature_count: 2, type: 'even', max_value: 2 },
|
2019-03-01 22:45:38 +08:00
|
|
|
{ _cdb_feature_count: 2, type: 'odd', max_value: 3 }
|
|
|
|
]
|
2019-03-01 18:21:18 +08:00
|
|
|
}
|
|
|
|
];
|
|
|
|
|
|
|
|
suite.forEach(({ zoom, cartodb_id, resolution, aggregation, expected }) => {
|
2019-03-12 17:35:16 +08:00
|
|
|
it(`should aggregate by type; z: ${zoom}, cartodb_id: ${cartodb_id}, res: ${resolution}`, function (done) {
|
2019-03-01 18:21:18 +08:00
|
|
|
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);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2019-03-01 22:17:22 +08:00
|
|
|
|
2019-03-02 00:21:55 +08:00
|
|
|
describe('invalid aggregation input', function () {
|
2019-03-01 22:17:22 +08:00
|
|
|
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 = {
|
2019-03-01 22:45:38 +08:00
|
|
|
errors:[ 'Invalid aggregation input, expressions should be and object with valid functions' ],
|
2019-03-01 22:17:22 +08:00
|
|
|
errors_with_context:[
|
|
|
|
{
|
|
|
|
layer: {
|
|
|
|
index: '0',
|
|
|
|
type: 'cartodb'
|
|
|
|
},
|
2019-03-01 22:45:38 +08:00
|
|
|
message: 'Invalid aggregation input, expressions should be and object with valid functions',
|
2019-03-01 22:17:22 +08:00
|
|
|
subtype: 'aggregation',
|
|
|
|
type: 'layer'
|
|
|
|
}
|
|
|
|
]
|
|
|
|
};
|
|
|
|
|
2019-03-02 00:02:06 +08:00
|
|
|
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'
|
|
|
|
}
|
|
|
|
]
|
|
|
|
};
|
|
|
|
|
2019-03-01 22:17:22 +08:00
|
|
|
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
|
2019-03-02 00:02:06 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
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
|
2019-03-01 22:17:22 +08:00
|
|
|
}
|
|
|
|
];
|
|
|
|
|
2019-03-02 00:02:06 +08:00
|
|
|
suite.forEach(({ description, zoom, cartodb_id, resolution, aggregation, expected, status = 400 }) => {
|
2019-03-01 22:17:22 +08:00
|
|
|
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 = {
|
2019-03-02 00:02:06 +08:00
|
|
|
response: { status },
|
2019-03-01 22:17:22 +08:00
|
|
|
aggregation
|
|
|
|
};
|
|
|
|
|
|
|
|
testClient.getClusterFeatures(zoom, cartodb_id, layerId, params, (err, body) => {
|
|
|
|
if (err) {
|
|
|
|
return done(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
assert.deepStrictEqual(body, expected);
|
|
|
|
|
|
|
|
testClient.drain(done);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2019-02-27 02:19:44 +08:00
|
|
|
});
|