├── .eslintrc
├── .gitignore
├── .npmignore
├── .nvmrc
├── .travis.yml
├── CHANGELOG.md
├── CODEOWNERS
├── LICENSE
├── README.md
├── bin
├── mapbox-geostats
└── mapbox-geostats-validate
├── index.js
├── lib
├── constants.js
├── create-layer-stats.js
├── create-stats.js
├── get-file-type.js
├── get-value-type.js
├── mapnik-analyze.js
├── register-attribute.js
├── register-attributes-map.js
├── register-feature.js
├── report-stats.js
├── tile-analyze.js
├── type-integer-to-string.js
└── validate-stats.js
├── package-lock.json
├── package.json
├── schema
├── attribute.json
├── layer.json
└── tilestats.json
└── test
├── fixtures
├── expected
│ ├── geojson-invalid-geometry-types.json
│ ├── geometry-extravaganza.json
│ ├── long-attribute-names.json
│ ├── many-types-geojson.json
│ ├── many-types-mbtiles.json
│ ├── myriad-values-1-attr.json
│ ├── myriad-values-5-attrs.json
│ ├── myriad-values-all-attrs.json
│ ├── no-features.json
│ ├── populations-plus-csv.json
│ ├── populations-plus-geojson.json
│ ├── populations-plus-shp.json
│ ├── ports-only-name.json
│ ├── ports.json
│ ├── prototype.json
│ ├── tilestats.json
│ ├── two-layers.json
│ ├── two-thousand-properties-only-two.json
│ ├── two-thousand-properties.json
│ └── vectorgzip.json
└── src
│ ├── big-features-nozip.mbtiles
│ ├── geometry-extravaganza.geojson
│ ├── geometry-invalid-types.geojson
│ ├── invalid.csv
│ ├── invalid.geojson
│ ├── invalid.mbtiles
│ ├── invalid.shp
│ ├── invalid.txt
│ ├── long-attribute-names.geojson
│ ├── many-types.geojson
│ ├── many-types.mbtiles
│ ├── myriad-values.geojson
│ ├── no-features.csv
│ ├── no-features.geojson
│ ├── no-features.mbtiles
│ ├── no-features
│ ├── no-features.dbf
│ ├── no-features.prj
│ ├── no-features.shp
│ └── no-features.shx
│ ├── pngs.mbtiles
│ ├── populations-plus.csv
│ ├── populations-plus.geojson
│ ├── populations-plus
│ ├── populations-plus.dbf
│ ├── populations-plus.prj
│ ├── populations-plus.qpj
│ ├── populations-plus.shp
│ └── populations-plus.shx
│ ├── ports
│ ├── ports.VERSION.txt
│ ├── ports.dbf
│ ├── ports.prj
│ ├── ports.shp
│ └── ports.shx
│ ├── prototype.geojson
│ ├── tilestats.mbtiles
│ ├── two-layers.mbtiles
│ ├── two-thousand-properties.geojson
│ └── vectorgzip.mbtiles
├── test.js
└── utils
└── sloppy-sort.js
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "eslint:recommended",
3 | "env": {
4 | "node": true,
5 | "es6": true
6 | },
7 | "plugins": [
8 | "node"
9 | ],
10 | "rules": {
11 | "no-var": 2,
12 | "prefer-const": 2,
13 | "array-bracket-spacing": [2, "never"],
14 | "brace-style": [2, "1tbs"],
15 | "comma-dangle": [2, "always-multiline"],
16 | "computed-property-spacing": [2, "never"],
17 | "curly": [2, "multi-line"],
18 | "eol-last": 2,
19 | "eqeqeq": [2, "smart"],
20 | "no-extend-native": 2,
21 | "no-mixed-spaces-and-tabs": 2,
22 | "no-spaced-func": 2,
23 | "no-trailing-spaces": 2,
24 | "no-unused-vars": 2,
25 | "no-use-before-define": [2, "nofunc"],
26 | "object-curly-spacing": [2, "always"],
27 | "quotes": [2, "single", "avoid-escape"],
28 | "semi": [2, "always"],
29 | "space-before-function-paren": [2, "never"],
30 | "space-infix-ops": 2,
31 | "spaced-comment": [2, "always"],
32 | "keyword-spacing": [2, { before: true, after: true }],
33 | "strict": 2,
34 |
35 | "node/no-unsupported-features": [2, {"version": 4}],
36 | "node/no-missing-require": 2
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .DS_Store
3 | tmp
4 | coverage
5 | .nyc_output
6 | *.log
7 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | test
2 |
--------------------------------------------------------------------------------
/.nvmrc:
--------------------------------------------------------------------------------
1 | v20.17.0
2 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 |
3 | node_js:
4 | - "8"
5 | - "10"
6 |
7 | addons:
8 | apt:
9 | sources:
10 | - ubuntu-toolchain-r-test
11 | packages:
12 | - libstdc++6 # upgrade libstdc++ on linux to support C++11
13 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # 1.1.1
2 |
3 | - Republish of 1.1.0 without accidental large log file, bloating package size
4 |
5 | # 1.1.0 (deprecated)
6 |
7 | - Upgrade to mapnik 4.3.1
8 | - Test on node 8 + 10
9 |
10 | # 1.0.0
11 |
12 | - Upgrade to mapnik 3.7.0
13 | - Drops windows support
14 |
15 | # 0.5.1
16 |
17 | - Fix issue where tile-analyze Promise was not finishing execution on resolve [#34](https://github.com/mapbox/mapbox-geostats/issues/34)
18 |
19 | # 0.5.0
20 |
21 | - Adds a tilestats schema [#33](https://github.com/mapbox/mapbox-geostats/pull/33)
22 | - Adds a tilestats schema validation method [#33](https://github.com/mapbox/mapbox-geostats/pull/33)
23 | - Checks mbtiles metadata table for a pregenerated tilestats object [#33](https://github.com/mapbox/mapbox-geostats/pull/33)
24 |
25 | # 0.4.0
26 |
27 | - Upgrade mapnik@3.6.0
28 | - Update test fixtures that are now failing due to changes in mapnik core
29 |
30 | # 0.3.1
31 |
32 | - Use `mapbox-file-sniff`'s `quaff`, instead of `sniff`, to better handle large files.
33 |
34 | # 0.3.0
35 |
36 | - Upgrade mapbox-file-sniff@0.5.2
37 | - Use ~ instead of ^ for node-mbtiles and node-mapnik
38 |
--------------------------------------------------------------------------------
/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # global owners
2 |
3 | * @mapbox/maps-api
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2016, Mapbox
2 |
3 | Permission to use, copy, modify, and/or distribute this software for any
4 | purpose with or without fee is hereby granted, provided that the above
5 | copyright notice and this permission notice appear in all copies.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # mapbox-geostats
2 |
3 | [](https://circleci.com/gh/mapbox/mapbox-geostats)
4 |
5 | Generate statistics about geographic data.
6 |
7 | ## Installation
8 | `npm install @mapbox/mapbox-geostats`
9 |
10 | ## About
11 |
12 | You feed the module a file, and it outputs stats about the geographic data in the file.
13 |
14 | ### Input types
15 |
16 | Supports the following file types:
17 |
18 | - GeoJSON (`.geojson`)
19 | - Shapefile (`.shp`, in a directory with its supporting files)
20 | - CSV (`.csv`)
21 | - MBTiles (`.mbtiles`)
22 |
23 | ### Limitations
24 |
25 | You'll notice the following limitations in the output:
26 |
27 | - No more than 1000 layers are counted, and no more than 100 are reported in detail.
28 | - For any given layer, no more than 1000 unique attributes are counted, and no more than 100 are reported in detail.
29 | - For any given attribute, no more than 1000 unique values are counted, and no more than 100 are reported. All values will affect the numeric stats (e.g. `min` and `max`), even if they are not reported or counted.
30 | - Attribute values that are strings longer than 256 characters are counted but not reported.
31 | - Layer names and attribute names that are strings longer than 256 characters are truncated to a length of 256. (This means that if two attribute names only vary after their 256th character, they will be considered the same. Same for layers.)
32 |
33 | #### Avoid limitations by specifying attributes
34 |
35 | Because of the necessary limitation on the number of reported attributes, you may end up with output that does not include details about a particular attribute that you wanted to learn about, because 100 attributes were already reported.
36 |
37 | If you are the victim of this misfortune, use the `attributes` option, documented below, to specify the attribute(s) whose details you'd like to inspect.
38 |
39 | When you use attributes, the limitations on attribute values change based on the following rules.
40 |
41 | - You can count a maximum of 100,000 unique values.
42 | - You can report a maximum of 10,000 unique values.
43 |
44 | So if you've specified a limited number of attributes to inspect, the number of values that will be counted and reported can be tailored to that count. If you specify one attribute, you can see up to 10,000 values reported, 100,000 values counted per attribute. If you specify 5 attributes, you can see up to 2,000 values reported, 20,000 values counted per attribute.
45 |
46 | ## CLI
47 |
48 | `mapbox-geostats` generate a tilestats JSON object
49 | ```
50 | Generate statistics about geographic data.
51 |
52 | Usage
53 | mapbox-geostats
54 |
55 | Output is logged to the console as a JSON string.
56 |
57 | Options
58 | --attributes, -a Specify attributes to analyze. The provided value
59 | will be parsed as an array, split on commas.
60 |
61 | Example
62 | mapbox-geostats population-centers.geojson --attributes name,pop > output.json
63 | ```
64 |
65 | `mapbox-geostats-validate`: validate a tilestats JSON object
66 | ```
67 | Usage
68 | mapbox-geostats-validate
69 |
70 | Output is empty if valid, or a list of errors.
71 |
72 | Example
73 | mapbox-geostats-validate ./path/to/stats.json
74 | ```
75 |
76 | ## Node
77 |
78 | ```js
79 | var geostats = require('@mapbox/mapbox-geostats');
80 |
81 | geostats(filePath, options).then(function (stats) {
82 | // Do something with the stats
83 | }).catch(function (err) {
84 | // Do something with the error
85 | });
86 | ```
87 |
88 | There's just one exposed function:
89 |
90 | ### geostats(filePath[, options])
91 |
92 | Returns a Promise that resolves with a stats object, whose structure is described below.
93 |
94 | `filepath` (*required*) is the path to the file that you'd like to analyze.
95 |
96 | `options` (*optional*) is an optional object that can have the following properties:
97 |
98 | - `attributes`: An array of strings identifying attributes that you want analyzed and reported. By default, all attributes are analyzed and reported until we reach the limitations described above.
99 |
100 | ## Output: the stats
101 |
102 | The tilestats jsonschema is specified in the /schema directory under schema/tilestats.json
103 |
104 | The stats output has this structure:
105 |
106 | ```js
107 | {
108 | // The number of layers in the source data (max. 1000)
109 | "layerCount": Number,
110 | // An array of details about the first 100 layers
111 | "layers": [
112 | {
113 | // The name of this layer
114 | "layer": String,
115 | // The number of features in this layer
116 | "count": Number,
117 | // The dominant geometry type in this layer
118 | "geometry": String,
119 | // The number of unique attributes in this layer (max. 1000)
120 | "attributeCount": Number
121 | // An array of details about the first 100 attributes in this layer
122 | "attributes": [
123 | {
124 | // The name of this attribute
125 | "attribute": String,
126 | // The number of unique values for this attribute (max. 1000)
127 | "count": Number,
128 | // The type of this attribute's values
129 | "type": String, // More info below ...
130 | // An array of this attribute's first 100 unique values
131 | "values": [
132 | // ...
133 | ],
134 | // If there are *any* numbers in the values, the following
135 | // numeric stats will be reported
136 | "min": Number,
137 | "max": Number
138 | }
139 | // ...
140 | ]
141 | }
142 | // ...
143 | ]
144 | }
145 | ```
146 |
147 | You can find more examples in the test fixtures.
148 |
149 | ### Attribute type
150 |
151 | Each attribute has one of the following types:
152 |
153 | - `'string'` if all its values are strings (or `null`).
154 | - `'number'` if all its values are numbers (or `null`).
155 | - `'boolean'` if all its values are booleans (or `null`).
156 | - `'null'` if its only value is `null`.
157 | - `'mixed'` if it has values of multiple types.
158 |
159 | Array and object values are coerced to strings.
160 |
161 | ## Known caveats
162 |
163 | - When reading MBTiles files, the feature count will be high. This is because each feature will be included in multiple tiles, so will be analyzed multiple times.
164 | - `null` sometimes appears unbidden in the attribute value lists generated from GeoJSON sources. (cf. https://github.com/mapnik/node-mapnik/issues/668)
165 | - GeoJSON without any features causes a parsing error. (cf. https://github.com/mapnik/mapnik/issues/3463)
166 | - MBTiles files whose vector data is not gzipped will not be understood. (cf. https://github.com/mapbox/tiletype/issues/4)
167 | - Because layer and attribute names are truncated at 256 characters (see above), if two attribute or layer names only vary after their 256th character, they will be considered the same --- that is, their data will be merged.
168 | - if an MBTiles file has a `tilestats` object in the `json` row of the `metadata` table that will be used instead of generating stats from the raw tiles.
169 |
--------------------------------------------------------------------------------
/bin/mapbox-geostats:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | 'use strict';
3 |
4 | /* eslint-disable no-console */
5 | const meow = require('meow');
6 | const geostats = require('../');
7 |
8 | const help = `
9 | Usage
10 | mapbox-geostats
11 |
12 | Output is logged to the console as a JSON string.
13 |
14 | Options
15 | --attributes, -a Specify attributes to analyze. The provided value
16 | will be parsed as an array, split on commas.
17 |
18 | Example
19 | mapbox-geostats cities.geojson --attributes name,pop > output.json
20 | `;
21 |
22 | const cli = meow(help, {
23 | alias: {
24 | a: 'attributes',
25 | },
26 | });
27 |
28 | const input = cli.input[0];
29 |
30 | const options = {};
31 |
32 | if (cli.flags.attributes) {
33 | options.attributes = cli.flags.attributes.split(',');
34 | }
35 |
36 | if (!input) {
37 | console.log(cli.help);
38 | } else {
39 | geostats(input, options).then((stats) => {
40 | console.log(JSON.stringify(stats));
41 | }).catch((err) => {
42 | console.error(err.stack);
43 | });
44 | }
45 |
--------------------------------------------------------------------------------
/bin/mapbox-geostats-validate:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | 'use strict';
3 |
4 | /* eslint-disable no-console */
5 | const meow = require('meow');
6 | const fs = require('fs');
7 | const validate = require('../lib/validate-stats');
8 |
9 | const help = `
10 | Usage
11 | mapbox-geostats-validate
12 |
13 | Output is empty if valid, or a list of errors.
14 |
15 | Example
16 | mapbox-geostats-validate ./path/to/stats.json
17 | `;
18 |
19 | const cli = meow(help);
20 | const file = cli.input[0];
21 |
22 | if (!file) cli.showHelp();
23 |
24 | let stats;
25 | try {
26 | const raw = fs.readFileSync(file);
27 | console.log(raw);
28 | stats = JSON.parse(raw);
29 | // stats = JSON.parse(fs.readFileSync(file));
30 | } catch (err) {
31 | console.log('Unable to read file');
32 | console.error(err);
33 | console.log(help);
34 | }
35 |
36 | const results = validate(stats);
37 | if (results.length) {
38 | console.log('✘ Invalid');
39 | results.forEach(function(s) {
40 | console.log(`- ${s}`);
41 | });
42 | } else {
43 | console.log('✔ Valid');
44 | }
45 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | var getFileType = require('./lib/get-file-type');
2 | var mapnikAnalyze = require('./lib/mapnik-analyze');
3 | var tileAnalyze = require('./lib/tile-analyze');
4 | var reportStats = require('./lib/report-stats');
5 | var Constants = require('./lib/constants');
6 |
7 | function buildGeoStats(filePath, options) {
8 | options = options || {};
9 |
10 | if (options.attributes) {
11 | if (options.attributes.length > Constants.ATTRIBUTES_MAX_REPORT) {
12 | throw new Error('Cannot report on more than ' + Constants.ATTRIBUTES_MAX_REPORT
13 | + ' attributes');
14 | }
15 | // Conversion to a Set should make for faster lookups
16 | options.attributes = new Set(options.attributes);
17 | }
18 |
19 | // The number of unique values we'll count and record depends on
20 | // the number of attributes we might record
21 | var divisor = (options.attributes)
22 | ? Math.min(options.attributes.size, Constants.ATTRIBUTES_MAX_REPORT)
23 | : Constants.ATTRIBUTES_MAX_REPORT;
24 | options.maxValuesToCount = Math.floor(Constants.VALUES_MAX_COUNT / divisor);
25 | options.maxValuesToReport = Math.floor(Constants.VALUES_MAX_REPORT / divisor);
26 |
27 | return getFileType(filePath)
28 | .then(function (fileType) {
29 | if (fileType === Constants.FILETYPE_MBTILES) return tileAnalyze(filePath, options);
30 | return mapnikAnalyze(filePath, fileType, options);
31 | })
32 | .then(function(stats) {
33 | return reportStats(stats, options);
34 | });
35 | }
36 |
37 | module.exports = buildGeoStats;
38 |
--------------------------------------------------------------------------------
/lib/constants.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {
4 | LAYERS_MAX_REPORT: 100,
5 | LAYERS_MAX_COUNT: 1000,
6 |
7 | ATTRIBUTES_MAX_REPORT: 100,
8 | ATTRIBUTES_MAX_COUNT: 1000,
9 |
10 | VALUES_MAX_REPORT: 10000,
11 | VALUES_MAX_COUNT: 100000,
12 |
13 | VALUE_STRING_MAX_LENGTH: 256,
14 | NAME_TRUNCATE_LENGTH: 256,
15 |
16 | FILETYPE_GEOJSON: 'geojson',
17 | FILETYPE_SHAPEFILE: 'shp',
18 | FILETYPE_CSV: 'csv',
19 | FILETYPE_MBTILES: 'mbtiles',
20 |
21 | VALUE_TYPE_STRING: 'string',
22 | VALUE_TYPE_NUMBER: 'number',
23 | VALUE_TYPE_BOOLEAN: 'boolean',
24 | VALUE_TYPE_NULL: 'null',
25 | VALUE_TYPE_MIXED: 'mixed',
26 | };
27 |
--------------------------------------------------------------------------------
/lib/create-layer-stats.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * Returns a new, empty layer stats object.
5 | *
6 | * @param {string} name
7 | * @returns {Object} The new, empty layer stats.
8 | */
9 | module.exports = function(name) {
10 | return {
11 | name: name,
12 | attributes: Object.create(null),
13 | attributeCountSet: new Set(),
14 | featureCount: 0,
15 | attributeCount: 0,
16 | geometryCounts: Object.create(null),
17 | };
18 | };
19 |
--------------------------------------------------------------------------------
/lib/create-stats.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * Returns a new, empty stats object.
5 | *
6 | * @returns {Object} The new, empty stats.
7 | */
8 | module.exports = function() {
9 | return {
10 | layerCountSet: new Set(),
11 | layers: [],
12 | };
13 | };
14 |
--------------------------------------------------------------------------------
/lib/get-file-type.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const filesniffer = require('@mapbox/mapbox-file-sniff');
4 |
5 | /**
6 | * Returns the file's type, as determined by filesniffer.
7 | *
8 | * @param {string} filePath
9 | * @return {Object} The file's info
10 | */
11 | module.exports = function(filePath) {
12 | return new Promise((resolve, reject) => {
13 | if (!filePath) return reject(new Error('File path required'));
14 |
15 | filesniffer.fromFile(filePath, (err, fileinfo) => {
16 | if (err) return reject(err);
17 | resolve(fileinfo.type);
18 | });
19 | });
20 | };
21 |
--------------------------------------------------------------------------------
/lib/get-value-type.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Constants = require('./constants');
4 |
5 | /**
6 | * Returns the value type we'll report for any given value.
7 | *
8 | * @param {any} value
9 | * @return {string} The value type.
10 | */
11 | module.exports = function(value) {
12 | if (value == null) return Constants.VALUE_TYPE_NULL;
13 | switch (typeof value) {
14 | case 'string':
15 | return Constants.VALUE_TYPE_STRING;
16 | case 'number':
17 | return Constants.VALUE_TYPE_NUMBER;
18 | case 'boolean':
19 | return Constants.VALUE_TYPE_BOOLEAN;
20 | default:
21 | throw new Error('Unknown value type for `' + value + '`');
22 | }
23 | };
24 |
--------------------------------------------------------------------------------
/lib/mapnik-analyze.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const mapnik = require('mapnik');
4 | const path = require('path');
5 | const Constants = require('./constants');
6 | const createStats = require('./create-stats');
7 | const createLayerStats = require('./create-layer-stats');
8 | const registerFeature = require('./register-feature');
9 | const registerAttributesMap = require('./register-attributes-map');
10 | const typeIntegerToString = require('./type-integer-to-string');
11 |
12 | // Register datasource plugins
13 | mapnik.register_default_input_plugins();
14 |
15 | /**
16 | * Returns stats about a file we can analyze with Mapnik.
17 | * Understand the following:
18 | * - .geojson
19 | * - .shp
20 | * - .csv
21 | *
22 | * @param {string} filePath
23 | * @param {string} fileType - One of Constants.FILETYPE_*.
24 | * @param {Object} [options]
25 | * @param {Array} [options.attributes]
26 | * @return {Object} The stats.
27 | */
28 | module.exports = function(filePath, fileType, options) {
29 | options = options || {};
30 | const stats = createStats();
31 | // Derive a fake layer name from the file's name
32 | const layerName = path.basename(filePath, path.extname(filePath));
33 | const layerStats = createLayerStats(layerName);
34 |
35 | stats.layerCountSet.add(layerName);
36 |
37 | const datasourceOptions = { file: filePath };
38 | switch (fileType) {
39 | case Constants.FILETYPE_GEOJSON:
40 | datasourceOptions.type = 'geojson';
41 | datasourceOptions.cache_features = false;
42 | break;
43 | case Constants.FILETYPE_SHAPEFILE:
44 | datasourceOptions.type = 'shape';
45 | break;
46 | case Constants.FILETYPE_CSV:
47 | datasourceOptions.type = 'csv';
48 | break;
49 | default:
50 | throw new Error('Unrecognized type for ' + filePath);
51 | }
52 | const datasource = new mapnik.Datasource(datasourceOptions);
53 |
54 | addFeatures(datasource.featureset());
55 |
56 | stats.layers.push(layerStats);
57 |
58 | return stats;
59 |
60 | function addFeatures(features) {
61 | if (!features) return;
62 | let feature = features.next();
63 | while (feature) {
64 | registerFeature(layerStats, {
65 | type: typeIntegerToString(feature.geometry().type()),
66 | });
67 |
68 | registerAttributesMap(layerStats, options, feature.attributes());
69 |
70 | feature = features.next();
71 | }
72 | }
73 | };
74 |
--------------------------------------------------------------------------------
/lib/register-attribute.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Constants = require('./constants');
4 | const getValueType = require('./get-value-type');
5 |
6 | /**
7 | * Mutates a layer stats object to register stats
8 | * about an attribute (and returns the mutated object).
9 | *
10 | * @param {Object} layerStats
11 | * @param {Object} options
12 | * @param {number} options.maxValuesToCount - The maximum number of unique
13 | * attribute values to register.
14 | * @param {string} name - The attribute name.
15 | * @param {string|number|boolean|null} value - The attribute value.
16 | * @return {Object} The mutated layerStats.
17 | */
18 | module.exports = function(layerStats, options, rawName, value) {
19 | const name = rawName.slice(0, Constants.NAME_TRUNCATE_LENGTH);
20 | const valueType = getValueType(value);
21 | const isValueNull = value === null;
22 |
23 | if (layerStats.attributes[name] === undefined) {
24 | const priorAttributeCount = layerStats.attributeCountSet.size;
25 | if (priorAttributeCount >= Constants.ATTRIBUTES_MAX_COUNT) return;
26 | layerStats.attributeCountSet.add(name);
27 |
28 | if (priorAttributeCount >= Constants.ATTRIBUTES_MAX_REPORT) return;
29 | layerStats.attributes[name] = {
30 | attribute: name,
31 | valueSet: new Set(),
32 | type: valueType,
33 | };
34 | }
35 |
36 | const attribute = layerStats.attributes[name];
37 |
38 | if (isValueNull && attribute.valueSet.has(null)) return;
39 |
40 | if (attribute.type !== Constants.VALUE_TYPE_MIXED
41 | && !isValueNull
42 | && valueType !== attribute.type) {
43 | attribute.type = Constants.VALUE_TYPE_MIXED;
44 | }
45 |
46 | if (typeof value === 'number') {
47 | if (attribute.min === undefined || value < attribute.min) attribute.min = value;
48 | if (attribute.max === undefined || value > attribute.max) attribute.max = value;
49 | }
50 |
51 | if (attribute.valueSet.size >= options.maxValuesToCount) return;
52 |
53 | attribute.valueSet.add(truncateForStorage(value));
54 |
55 | return layerStats;
56 | };
57 |
58 | function truncateForStorage(value) {
59 | if (typeof value !== 'string') return value;
60 | // Store overly long strings at a length one character longer than the max
61 | // so we still know later to remove them from the reported value array
62 | if (value.length <= Constants.VALUE_STRING_MAX_LENGTH) return value;
63 | return value.slice(0, Constants.VALUE_STRING_MAX_LENGTH + 1);
64 | }
65 |
--------------------------------------------------------------------------------
/lib/register-attributes-map.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const registerAttribute = require('./register-attribute');
4 |
5 | /**
6 | * Mutates a layer stats object to register stats
7 | * about an object of attributes (and returns the mutated object).
8 | *
9 | * @param {Object} layerStats
10 | * @param {Object} options
11 | * @param {Set} [options.attributes] - Specific attributes that should be registered.
12 | * @param {Object} attributes - The attributes to register, as an object
13 | * of `name: value`
14 | * @return {Object} The mutated layerStats.
15 | */
16 | module.exports = function(layerStats, options, attributes) {
17 | const specifiedAttributes = options.attributes;
18 |
19 | Object.keys(attributes).forEach((name) => {
20 | const value = attributes[name];
21 | if (specifiedAttributes && !specifiedAttributes.has(name)) return;
22 | registerAttribute(layerStats, options, name, value);
23 | });
24 |
25 | return layerStats;
26 | };
27 |
--------------------------------------------------------------------------------
/lib/register-feature.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * Mutates a layer stats object to register stats
5 | * about a feature (and returns the mutated object).
6 | *
7 | * @param {Object} layerStats
8 | * @param {Object} featureData
9 | * @param {string} featureData.type - The feature's type.
10 | * @return {Object} The mutated layerStats.
11 | */
12 | module.exports = function(layerStats, featureData) {
13 | layerStats.featureCount++;
14 | layerStats.geometryCounts[featureData.type] = 1 +
15 | (layerStats.geometryCounts[featureData.type] || 0);
16 | return layerStats;
17 | };
18 |
--------------------------------------------------------------------------------
/lib/report-stats.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const _ = require('lodash');
4 | const Constants = require('./constants');
5 |
6 | /**
7 | * Returns an object bearing stats, formatted for output & reportage.
8 | *
9 | * @param {Object} stats - See create-layer-stats.js
10 | * @param {Object} options
11 | * @param {number} options.maxValuesToReport - The maximum number of unique
12 | * attribute values to record.
13 | * @return {Object} The report, which adheres to the relevant JSON schema.
14 | */
15 | module.exports = function(stats, options) {
16 |
17 | // if we have a stats object already built from an mbtiles file
18 | if (!stats.layerCountSet &&
19 | stats.layerCount) return stats;
20 |
21 | return {
22 | layerCount: stats.layerCountSet.size,
23 | layers: stats.layers.map(reportLayer),
24 | };
25 |
26 |
27 | function reportLayer(layerStats) {
28 | const result = {
29 | layer: layerStats.name,
30 | count: layerStats.featureCount,
31 | attributeCount: layerStats.attributeCountSet.size,
32 | attributes: _.values(layerStats.attributes).map(reportAttribute),
33 | };
34 |
35 | let dominantGeometry;
36 | let dominantGeometryCount = 0;
37 | Object.keys(layerStats.geometryCounts).forEach((geometry) => {
38 | const count = layerStats.geometryCounts[geometry];
39 | if (count > dominantGeometryCount) {
40 | dominantGeometryCount = count;
41 | dominantGeometry = geometry;
42 | }
43 | });
44 | if (dominantGeometry) result.geometry = dominantGeometry;
45 |
46 | return result;
47 | }
48 |
49 | function reportAttribute(attribute) {
50 | // Convert the Set to an array of limited size
51 | const values = [];
52 | const valueSetIterator = attribute.valueSet.values();
53 | let item = valueSetIterator.next();
54 | while (!item.done && values.length < options.maxValuesToReport) {
55 | if (isValueReportable(item.value)) {
56 | values.push(item.value);
57 | }
58 | item = valueSetIterator.next();
59 | }
60 |
61 | const result = Object.assign({
62 | values: values,
63 | count: attribute.valueSet.size,
64 | }, attribute);
65 | delete result.valueSet;
66 |
67 | return result;
68 | }
69 | };
70 |
71 | function isValueReportable(x) {
72 | if (typeof x === 'string'
73 | && x.length > Constants.VALUE_STRING_MAX_LENGTH) return false;
74 | return true;
75 | }
76 |
--------------------------------------------------------------------------------
/lib/tile-analyze.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const tilelive = require('@mapbox/tilelive');
4 | const tiletype = require('@mapbox/tiletype');
5 | const Transform = require('stream').Transform;
6 | const util = require('util');
7 | const MBTiles = require('@mapbox/mbtiles');
8 | const zlib = require('zlib');
9 | const mapboxVectorTile = require('@mapbox/vector-tile');
10 | const Protobuf = require('pbf');
11 | const _ = require('lodash');
12 | const createLayerStats = require('./create-layer-stats');
13 | const registerFeature = require('./register-feature');
14 | const registerAttributesMap = require('./register-attributes-map');
15 | const typeIntegerToString = require('./type-integer-to-string');
16 | const createStats = require('./create-stats');
17 | const Constants = require('./constants');
18 | const validator = require('./validate-stats');
19 |
20 | const VectorTile = mapboxVectorTile.VectorTile;
21 |
22 | function TileAnalyzeStream(processTile) {
23 | this.processTile = processTile;
24 | Transform.call(this, { objectMode: true });
25 | }
26 |
27 | util.inherits(TileAnalyzeStream, Transform);
28 |
29 | TileAnalyzeStream.prototype._transform = function(data, enc, done) {
30 | // Duck-type the data to see if it's a tile
31 | if (data.x === undefined
32 | || data.y === undefined
33 | || data.z === undefined
34 | || data.buffer === undefined
35 | // Note that tiletype currently does not recognize non-gzipped PBFs
36 | || tiletype.type(data.buffer) !== 'pbf') {
37 | return done();
38 | }
39 | this.processTile(data).then(() => {
40 | done();
41 | }, done);
42 | };
43 |
44 | /**
45 | * Returns stats about an MBTiles file.
46 | *
47 | * @param {string} filePath
48 | * @param {Object} [options]
49 | * @param {Array} [options.attributes]
50 | * @return {Object} The stats.
51 | */
52 | module.exports = function(filePath, options) {
53 | options = options || {};
54 | const stats = createStats();
55 | const layerMap = {};
56 |
57 | function getSource() {
58 | return new Promise((resolve, reject) => {
59 | new MBTiles(filePath, (err, source) => {
60 | if (err) return reject(err);
61 | resolve(source);
62 | });
63 | });
64 | }
65 |
66 | function analyzeSourceStream(source) {
67 | return new Promise((resolve, reject) => {
68 |
69 | // check if the tilestats object has been pre-generated in the mbtiles file
70 | // if so, return that, otherwise generate it it with analyzeSourceStream
71 | source.getInfo((err, info) => {
72 | if (err) reject(err);
73 | if (info.tilestats && validator(info.tilestats)) return resolve(info.tilestats);
74 |
75 | const zxyStream = source.createZXYStream();
76 | const readStream = tilelive.createReadStream(source, { type: 'list' });
77 | zxyStream.on('error', reject)
78 | .pipe(readStream)
79 | .pipe(new TileAnalyzeStream(analyzeTile))
80 | .on('error', reject)
81 | .on('end', () => {
82 | resolve(Object.assign(stats, {
83 | layers: _.values(layerMap),
84 | }));
85 | })
86 | .resume();
87 | });
88 | });
89 | }
90 |
91 | // Unzips and parses tile data, then analyzes each layer
92 | function analyzeTile(tile) {
93 | return new Promise((resolve, reject) => {
94 | zlib.gunzip(tile.buffer, (err, inflatedBuffer) => {
95 | // We'll get this error if the data was not gzipped.
96 | // So we'll just use the original data.
97 | if (err && err.errno === zlib.Z_DATA_ERROR) {
98 | inflatedBuffer = tile.buffer;
99 | } else if (err) {
100 | return reject(err);
101 | }
102 | let vectorTile;
103 | try {
104 | vectorTile = new VectorTile(new Protobuf(inflatedBuffer));
105 | } catch (e) {
106 | // We'll get this error if the data cannot be interpreted as a vector tile.
107 | // We skip this in order to see if we can gather data from other tiles.
108 | if (e.message.indexOf('Unimplemented type') === 0) return resolve();
109 | return reject(e);
110 | }
111 | _.forOwn(vectorTile.layers, analyzeLayer);
112 | resolve();
113 | });
114 | });
115 | }
116 |
117 | function analyzeLayer(layerData, rawLayerName) {
118 | const layerName = rawLayerName.slice(0, Constants.NAME_TRUNCATE_LENGTH);
119 | if (layerMap[layerName] === undefined) {
120 | if (stats.layerCountSet.size > Constants.LAYERS_MAX_COUNT) return;
121 | stats.layerCountSet.add(layerName);
122 |
123 | if (stats.layerCountSet.size > Constants.LAYERS_MAX_REPORT) return;
124 | layerMap[layerName] = createLayerStats(layerName);
125 | }
126 | const layerStats = layerMap[layerName];
127 | for (let i = 0, l = layerData.length; i < l; i++) {
128 | analyzeFeature(layerStats, layerData.feature(i));
129 | }
130 | }
131 |
132 | function analyzeFeature(layerStats, feature) {
133 | registerFeature(layerStats, {
134 | type: typeIntegerToString(feature.type),
135 | });
136 | registerAttributesMap(layerStats, options, feature.properties);
137 | }
138 |
139 | return getSource(filePath).then(analyzeSourceStream);
140 | };
141 |
--------------------------------------------------------------------------------
/lib/type-integer-to-string.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // Copied from https://github.com/mapnik/mapnik/blob/v3.0.11/include/mapnik/geometry_types.hpp
4 |
5 | module.exports = function(mapnikType) {
6 | switch (mapnikType) {
7 | case 1:
8 | return 'Point';
9 | case 2:
10 | return 'LineString';
11 | case 3:
12 | return 'Polygon';
13 | case 4:
14 | return 'MultiPoint';
15 | case 5:
16 | return 'MultiLineString';
17 | case 6:
18 | return 'MultiPolygon';
19 | case 7:
20 | return 'GeometryCollection';
21 | case 0:
22 | default:
23 | return 'Unknown';
24 | }
25 | };
26 |
--------------------------------------------------------------------------------
/lib/validate-stats.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Validator = require('jsonschema').Validator;
4 | const schema = require('../schema/tilestats.json');
5 | const layerSchema = require('../schema/layer.json');
6 | const attributeSchema = require('../schema/attribute.json');
7 |
8 | /**
9 | * Check if a stats JSON object is valid
10 | *
11 | * @param {Object} stats - a JSON tilestats object
12 | * @returns {Boolean|Array} error - returns `true` if the object is valid, or an array error strings
13 | */
14 | module.exports = function(stats) {
15 | const v = new Validator();
16 | v.addSchema(layerSchema, '/layer');
17 | v.addSchema(attributeSchema, '/attribute');
18 |
19 | const results = v.validate(stats, schema);
20 | if (!results.errors.length) return true;
21 | return results.errors.map(function(err) {
22 | return err.stack;
23 | });
24 | };
25 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@mapbox/mapbox-geostats",
3 | "version": "1.1.1",
4 | "description": "Generate statistics about geographic data.",
5 | "main": "index.js",
6 | "bin": {
7 | "mapbox-geostats": "bin/mapbox-geostats",
8 | "mapbox-geostats-validate": "bin/mapbox-geostats-validate"
9 | },
10 | "type": "commonjs",
11 | "scripts": {
12 | "lint": "eslint lib test bin/**",
13 | "lint-fix": "eslint --fix lib test bin/**",
14 | "test": "npm run lint && tap test/test.js",
15 | "coverage": "tap test/test.js --cov --coverage-report=html"
16 | },
17 | "repository": {
18 | "type": "git",
19 | "url": "git+https://github.com/mapbox/mapbox-geostats.git"
20 | },
21 | "author": "Mapbox",
22 | "license": "ISC",
23 | "bugs": {
24 | "url": "https://github.com/mapbox/mapbox-geostats/issues"
25 | },
26 | "homepage": "https://github.com/mapbox/mapbox-geostats#readme",
27 | "dependencies": {
28 | "@mapbox/mapbox-file-sniff": "^1.0.6",
29 | "@mapbox/mbtiles": "^0.12.1",
30 | "@mapbox/tilelive": "^6.1.0",
31 | "@mapbox/tiletype": "^0.3.0",
32 | "@mapbox/vector-tile": "^1.2.1",
33 | "d3-queue": "^3.0.7",
34 | "jsonschema": "^1.1.1",
35 | "lodash": "^4.13.1",
36 | "mapnik": "^4.5.9",
37 | "meow": "^9.0.0",
38 | "pbf": "^2.0.1"
39 | },
40 | "devDependencies": {
41 | "eslint": "^7.32.0",
42 | "eslint-plugin-node": "^11.1.0",
43 | "tap": "^21.1.0"
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/schema/attribute.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "/attribute",
3 | "type": "object",
4 | "properties": {
5 | "attribute": { "type": "string" },
6 | "count": { "type": "number" },
7 | "type": {
8 | "type": "string",
9 | "enum": ["string", "number", "boolean", "null", "mixed"]
10 | },
11 | "values": {
12 | "anyOf": [
13 | { "type": "array", "items": { "type": "string" } },
14 | { "type": "array", "items": { "type": "number" } },
15 | { "type": "array", "items": { "type": "boolean" } },
16 | { "type": "array", "items": { "type": "null" } }
17 | ]
18 | },
19 | "min": { "type": "number" },
20 | "max": { "type": "number" }
21 | },
22 | "required": [ "attribute", "count", "type", "values" ]
23 | }
24 |
--------------------------------------------------------------------------------
/schema/layer.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "/layer",
3 | "type": "object",
4 | "properties": {
5 | "layer": { "type": "string" },
6 | "count": { "type": "number" },
7 | "geometry": {
8 | "type": "string",
9 | "enum": [ "Point", "LineString", "Polygon" ]
10 | },
11 | "attributeCount": { "type": "number" },
12 | "attributes": {
13 | "type": "array",
14 | "items": { "$ref": "/attribute" }
15 | }
16 | },
17 | "required": [ "layer", "count", "geometry", "attributeCount" ]
18 | }
19 |
--------------------------------------------------------------------------------
/schema/tilestats.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "/tilestats",
3 | "type": "object",
4 | "properties": {
5 | "layerCount": { "type": "number" },
6 | "layers": {
7 | "type": "array",
8 | "items": { "$ref": "/layer" }
9 | }
10 | },
11 | "required": [ "layerCount", "layers" ]
12 | }
13 |
--------------------------------------------------------------------------------
/test/fixtures/expected/geojson-invalid-geometry-types.json:
--------------------------------------------------------------------------------
1 | {
2 | "layerCount": 1,
3 | "layers": [
4 | {
5 | "layer": "geometry-invalid-types",
6 | "count": 1,
7 | "attributeCount": 1,
8 | "attributes": [
9 | {
10 | "values": [
11 | "bar"
12 | ],
13 | "count": 1,
14 | "attribute": "foo",
15 | "type": "string"
16 | }
17 | ],
18 | "geometry": "Point"
19 | }
20 | ]
21 | }
22 |
--------------------------------------------------------------------------------
/test/fixtures/expected/geometry-extravaganza.json:
--------------------------------------------------------------------------------
1 | {
2 | "layerCount": 1,
3 | "layers": [
4 | {
5 | "layer": "geometry-extravaganza",
6 | "count": 6,
7 | "attributeCount": 4,
8 | "attributes": [
9 | {
10 | "values": [
11 | "bar",
12 | null
13 | ],
14 | "count": 2,
15 | "attribute": "foo",
16 | "type": "string"
17 | },
18 | {
19 | "values": [
20 | 1,
21 | null
22 | ],
23 | "count": 2,
24 | "attribute": "bar",
25 | "type": "number",
26 | "min": 1,
27 | "max": 1
28 | },
29 | {
30 | "values": [
31 | "doo",
32 | null
33 | ],
34 | "count": 2,
35 | "attribute": "doodoo",
36 | "type": "string"
37 | },
38 | {
39 | "values": [
40 | true
41 | ],
42 | "count": 1,
43 | "attribute": "baz",
44 | "type": "boolean"
45 | }
46 | ],
47 | "geometry": "Point"
48 | }
49 | ]
50 | }
51 |
--------------------------------------------------------------------------------
/test/fixtures/expected/long-attribute-names.json:
--------------------------------------------------------------------------------
1 | {
2 | "layerCount": 1,
3 | "layers": [
4 | {
5 | "layer": "long-attribute-names",
6 | "count": 2,
7 | "attributeCount": 1,
8 | "attributes": [
9 | {
10 | "values": [
11 | 1,
12 | 2
13 | ],
14 | "count": 2,
15 | "attribute": "LoremipsumdolorsitametconsecteturadipisicingelitseddoeiusmodtemporincididuntutlaboreetdoloremagnaaliquaUtenimadminimveniamquisnostrudexercitationullamcolaborisnisiutaliquipexeacommodoconsequatDuisauteiruredolorinreprehenderitinvoluptatevelitessecillumdolor",
16 | "type": "number",
17 | "min": 1,
18 | "max": 2
19 | }
20 | ],
21 | "geometry": "Point"
22 | }
23 | ]
24 | }
25 |
--------------------------------------------------------------------------------
/test/fixtures/expected/many-types-geojson.json:
--------------------------------------------------------------------------------
1 | {
2 | "layerCount": 1,
3 | "layers": [
4 | {
5 | "layer": "many-types",
6 | "count": 6,
7 | "attributeCount": 8,
8 | "attributes": [
9 | {
10 | "values": [
11 | true,
12 | null
13 | ],
14 | "count": 2,
15 | "attribute": "astonishing",
16 | "type": "boolean"
17 | },
18 | {
19 | "values": [
20 | 7,
21 | "7",
22 | null
23 | ],
24 | "count": 3,
25 | "attribute": "mixed",
26 | "type": "mixed",
27 | "min": 7,
28 | "max": 7
29 | },
30 | {
31 | "values": [
32 | "foo",
33 | "bar",
34 | "baz",
35 | "haha",
36 | "hoho",
37 | "hehe"
38 | ],
39 | "count": 6,
40 | "attribute": "name",
41 | "type": "string"
42 | },
43 | {
44 | "values": [
45 | "[1,2,3]",
46 | null
47 | ],
48 | "count": 2,
49 | "attribute": "numbers",
50 | "type": "string"
51 | },
52 | {
53 | "values": [
54 | 6,
55 | 99,
56 | null,
57 | 86
58 | ],
59 | "count": 4,
60 | "attribute": "power",
61 | "type": "number",
62 | "min": 6,
63 | "max": 99
64 | },
65 | {
66 | "values": [
67 | 6,
68 | "{\"foo\":\"bar\"}"
69 | ],
70 | "count": 2,
71 | "attribute": "data",
72 | "type": "mixed",
73 | "min": 6,
74 | "max": 6
75 | },
76 | {
77 | "values": [],
78 | "count": 1,
79 | "attribute": "description",
80 | "type": "string"
81 | },
82 | {
83 | "values": [
84 | null
85 | ],
86 | "count": 1,
87 | "attribute": "onlyNull",
88 | "type": "null"
89 | }
90 | ],
91 | "geometry": "Point"
92 | }
93 | ]
94 | }
95 |
--------------------------------------------------------------------------------
/test/fixtures/expected/many-types-mbtiles.json:
--------------------------------------------------------------------------------
1 | {
2 | "layerCount": 1,
3 | "layers": [
4 | {
5 | "layer": "many-types",
6 | "count": 52,
7 | "attributeCount": 7,
8 | "attributes": [
9 | {
10 | "values": [
11 | true
12 | ],
13 | "count": 1,
14 | "attribute": "astonishing",
15 | "type": "boolean"
16 | },
17 | {
18 | "values": [
19 | 7,
20 | "7"
21 | ],
22 | "count": 2,
23 | "attribute": "mixed",
24 | "type": "mixed",
25 | "min": 7,
26 | "max": 7
27 | },
28 | {
29 | "values": [
30 | "foo",
31 | "bar",
32 | "baz",
33 | "haha",
34 | "hoho",
35 | "hehe"
36 | ],
37 | "count": 6,
38 | "attribute": "name",
39 | "type": "string"
40 | },
41 | {
42 | "values": [
43 | "[1,2,3]"
44 | ],
45 | "count": 1,
46 | "attribute": "numbers",
47 | "type": "string"
48 | },
49 | {
50 | "values": [
51 | 6,
52 | 99,
53 | 86
54 | ],
55 | "count": 3,
56 | "attribute": "power",
57 | "type": "number",
58 | "min": 6,
59 | "max": 99
60 | },
61 | {
62 | "values": [
63 | 6,
64 | "{\"foo\":\"bar\"}"
65 | ],
66 | "count": 2,
67 | "attribute": "data",
68 | "type": "mixed",
69 | "min": 6,
70 | "max": 6
71 | },
72 | {
73 | "values": [],
74 | "count": 1,
75 | "attribute": "description",
76 | "type": "string"
77 | }
78 | ],
79 | "geometry": "Point"
80 | }
81 | ]
82 | }
83 |
--------------------------------------------------------------------------------
/test/fixtures/expected/myriad-values-all-attrs.json:
--------------------------------------------------------------------------------
1 | {
2 | "layerCount": 1,
3 | "layers": [
4 | {
5 | "layer": "myriad-values",
6 | "count": 10010,
7 | "attributeCount": 10,
8 | "attributes": [
9 | {
10 | "values": [
11 | "0-value-0",
12 | "1-value-0",
13 | "2-value-0",
14 | "3-value-0",
15 | "4-value-0",
16 | "5-value-0",
17 | "6-value-0",
18 | "7-value-0",
19 | "8-value-0",
20 | "9-value-0",
21 | "10-value-0",
22 | "11-value-0",
23 | "12-value-0",
24 | "13-value-0",
25 | "14-value-0",
26 | "15-value-0",
27 | "16-value-0",
28 | "17-value-0",
29 | "18-value-0",
30 | "19-value-0",
31 | "20-value-0",
32 | "21-value-0",
33 | "22-value-0",
34 | "23-value-0",
35 | "24-value-0",
36 | "25-value-0",
37 | "26-value-0",
38 | "27-value-0",
39 | "28-value-0",
40 | "29-value-0",
41 | "30-value-0",
42 | "31-value-0",
43 | "32-value-0",
44 | "33-value-0",
45 | "34-value-0",
46 | "35-value-0",
47 | "36-value-0",
48 | "37-value-0",
49 | "38-value-0",
50 | "39-value-0",
51 | "40-value-0",
52 | "41-value-0",
53 | "42-value-0",
54 | "43-value-0",
55 | "44-value-0",
56 | "45-value-0",
57 | "46-value-0",
58 | "47-value-0",
59 | "48-value-0",
60 | "49-value-0",
61 | "50-value-0",
62 | "51-value-0",
63 | "52-value-0",
64 | "53-value-0",
65 | "54-value-0",
66 | "55-value-0",
67 | "56-value-0",
68 | "57-value-0",
69 | "58-value-0",
70 | "59-value-0",
71 | "60-value-0",
72 | "61-value-0",
73 | "62-value-0",
74 | "63-value-0",
75 | "64-value-0",
76 | "65-value-0",
77 | "66-value-0",
78 | "67-value-0",
79 | "68-value-0",
80 | "69-value-0",
81 | "70-value-0",
82 | "71-value-0",
83 | "72-value-0",
84 | "73-value-0",
85 | "74-value-0",
86 | "75-value-0",
87 | "76-value-0",
88 | "77-value-0",
89 | "78-value-0",
90 | "79-value-0",
91 | "80-value-0",
92 | "81-value-0",
93 | "82-value-0",
94 | "83-value-0",
95 | "84-value-0",
96 | "85-value-0",
97 | "86-value-0",
98 | "87-value-0",
99 | "88-value-0",
100 | "89-value-0",
101 | "90-value-0",
102 | "91-value-0",
103 | "92-value-0",
104 | "93-value-0",
105 | "94-value-0",
106 | "95-value-0",
107 | "96-value-0",
108 | "97-value-0",
109 | "98-value-0",
110 | "99-value-0"
111 | ],
112 | "count": 1000,
113 | "attribute": "prop-0",
114 | "type": "string"
115 | },
116 | {
117 | "values": [
118 | "0-value-1",
119 | "1-value-1",
120 | "2-value-1",
121 | "3-value-1",
122 | "4-value-1",
123 | "5-value-1",
124 | "6-value-1",
125 | "7-value-1",
126 | "8-value-1",
127 | "9-value-1",
128 | "10-value-1",
129 | "11-value-1",
130 | "12-value-1",
131 | "13-value-1",
132 | "14-value-1",
133 | "15-value-1",
134 | "16-value-1",
135 | "17-value-1",
136 | "18-value-1",
137 | "19-value-1",
138 | "20-value-1",
139 | "21-value-1",
140 | "22-value-1",
141 | "23-value-1",
142 | "24-value-1",
143 | "25-value-1",
144 | "26-value-1",
145 | "27-value-1",
146 | "28-value-1",
147 | "29-value-1",
148 | "30-value-1",
149 | "31-value-1",
150 | "32-value-1",
151 | "33-value-1",
152 | "34-value-1",
153 | "35-value-1",
154 | "36-value-1",
155 | "37-value-1",
156 | "38-value-1",
157 | "39-value-1",
158 | "40-value-1",
159 | "41-value-1",
160 | "42-value-1",
161 | "43-value-1",
162 | "44-value-1",
163 | "45-value-1",
164 | "46-value-1",
165 | "47-value-1",
166 | "48-value-1",
167 | "49-value-1",
168 | "50-value-1",
169 | "51-value-1",
170 | "52-value-1",
171 | "53-value-1",
172 | "54-value-1",
173 | "55-value-1",
174 | "56-value-1",
175 | "57-value-1",
176 | "58-value-1",
177 | "59-value-1",
178 | "60-value-1",
179 | "61-value-1",
180 | "62-value-1",
181 | "63-value-1",
182 | "64-value-1",
183 | "65-value-1",
184 | "66-value-1",
185 | "67-value-1",
186 | "68-value-1",
187 | "69-value-1",
188 | "70-value-1",
189 | "71-value-1",
190 | "72-value-1",
191 | "73-value-1",
192 | "74-value-1",
193 | "75-value-1",
194 | "76-value-1",
195 | "77-value-1",
196 | "78-value-1",
197 | "79-value-1",
198 | "80-value-1",
199 | "81-value-1",
200 | "82-value-1",
201 | "83-value-1",
202 | "84-value-1",
203 | "85-value-1",
204 | "86-value-1",
205 | "87-value-1",
206 | "88-value-1",
207 | "89-value-1",
208 | "90-value-1",
209 | "91-value-1",
210 | "92-value-1",
211 | "93-value-1",
212 | "94-value-1",
213 | "95-value-1",
214 | "96-value-1",
215 | "97-value-1",
216 | "98-value-1",
217 | "99-value-1"
218 | ],
219 | "count": 1000,
220 | "attribute": "prop-1",
221 | "type": "string"
222 | },
223 | {
224 | "values": [
225 | "0-value-2",
226 | "1-value-2",
227 | "2-value-2",
228 | "3-value-2",
229 | "4-value-2",
230 | "5-value-2",
231 | "6-value-2",
232 | "7-value-2",
233 | "8-value-2",
234 | "9-value-2",
235 | "10-value-2",
236 | "11-value-2",
237 | "12-value-2",
238 | "13-value-2",
239 | "14-value-2",
240 | "15-value-2",
241 | "16-value-2",
242 | "17-value-2",
243 | "18-value-2",
244 | "19-value-2",
245 | "20-value-2",
246 | "21-value-2",
247 | "22-value-2",
248 | "23-value-2",
249 | "24-value-2",
250 | "25-value-2",
251 | "26-value-2",
252 | "27-value-2",
253 | "28-value-2",
254 | "29-value-2",
255 | "30-value-2",
256 | "31-value-2",
257 | "32-value-2",
258 | "33-value-2",
259 | "34-value-2",
260 | "35-value-2",
261 | "36-value-2",
262 | "37-value-2",
263 | "38-value-2",
264 | "39-value-2",
265 | "40-value-2",
266 | "41-value-2",
267 | "42-value-2",
268 | "43-value-2",
269 | "44-value-2",
270 | "45-value-2",
271 | "46-value-2",
272 | "47-value-2",
273 | "48-value-2",
274 | "49-value-2",
275 | "50-value-2",
276 | "51-value-2",
277 | "52-value-2",
278 | "53-value-2",
279 | "54-value-2",
280 | "55-value-2",
281 | "56-value-2",
282 | "57-value-2",
283 | "58-value-2",
284 | "59-value-2",
285 | "60-value-2",
286 | "61-value-2",
287 | "62-value-2",
288 | "63-value-2",
289 | "64-value-2",
290 | "65-value-2",
291 | "66-value-2",
292 | "67-value-2",
293 | "68-value-2",
294 | "69-value-2",
295 | "70-value-2",
296 | "71-value-2",
297 | "72-value-2",
298 | "73-value-2",
299 | "74-value-2",
300 | "75-value-2",
301 | "76-value-2",
302 | "77-value-2",
303 | "78-value-2",
304 | "79-value-2",
305 | "80-value-2",
306 | "81-value-2",
307 | "82-value-2",
308 | "83-value-2",
309 | "84-value-2",
310 | "85-value-2",
311 | "86-value-2",
312 | "87-value-2",
313 | "88-value-2",
314 | "89-value-2",
315 | "90-value-2",
316 | "91-value-2",
317 | "92-value-2",
318 | "93-value-2",
319 | "94-value-2",
320 | "95-value-2",
321 | "96-value-2",
322 | "97-value-2",
323 | "98-value-2",
324 | "99-value-2"
325 | ],
326 | "count": 1000,
327 | "attribute": "prop-2",
328 | "type": "string"
329 | },
330 | {
331 | "values": [
332 | "0-value-3",
333 | "1-value-3",
334 | "2-value-3",
335 | "3-value-3",
336 | "4-value-3",
337 | "5-value-3",
338 | "6-value-3",
339 | "7-value-3",
340 | "8-value-3",
341 | "9-value-3",
342 | "10-value-3",
343 | "11-value-3",
344 | "12-value-3",
345 | "13-value-3",
346 | "14-value-3",
347 | "15-value-3",
348 | "16-value-3",
349 | "17-value-3",
350 | "18-value-3",
351 | "19-value-3",
352 | "20-value-3",
353 | "21-value-3",
354 | "22-value-3",
355 | "23-value-3",
356 | "24-value-3",
357 | "25-value-3",
358 | "26-value-3",
359 | "27-value-3",
360 | "28-value-3",
361 | "29-value-3",
362 | "30-value-3",
363 | "31-value-3",
364 | "32-value-3",
365 | "33-value-3",
366 | "34-value-3",
367 | "35-value-3",
368 | "36-value-3",
369 | "37-value-3",
370 | "38-value-3",
371 | "39-value-3",
372 | "40-value-3",
373 | "41-value-3",
374 | "42-value-3",
375 | "43-value-3",
376 | "44-value-3",
377 | "45-value-3",
378 | "46-value-3",
379 | "47-value-3",
380 | "48-value-3",
381 | "49-value-3",
382 | "50-value-3",
383 | "51-value-3",
384 | "52-value-3",
385 | "53-value-3",
386 | "54-value-3",
387 | "55-value-3",
388 | "56-value-3",
389 | "57-value-3",
390 | "58-value-3",
391 | "59-value-3",
392 | "60-value-3",
393 | "61-value-3",
394 | "62-value-3",
395 | "63-value-3",
396 | "64-value-3",
397 | "65-value-3",
398 | "66-value-3",
399 | "67-value-3",
400 | "68-value-3",
401 | "69-value-3",
402 | "70-value-3",
403 | "71-value-3",
404 | "72-value-3",
405 | "73-value-3",
406 | "74-value-3",
407 | "75-value-3",
408 | "76-value-3",
409 | "77-value-3",
410 | "78-value-3",
411 | "79-value-3",
412 | "80-value-3",
413 | "81-value-3",
414 | "82-value-3",
415 | "83-value-3",
416 | "84-value-3",
417 | "85-value-3",
418 | "86-value-3",
419 | "87-value-3",
420 | "88-value-3",
421 | "89-value-3",
422 | "90-value-3",
423 | "91-value-3",
424 | "92-value-3",
425 | "93-value-3",
426 | "94-value-3",
427 | "95-value-3",
428 | "96-value-3",
429 | "97-value-3",
430 | "98-value-3",
431 | "99-value-3"
432 | ],
433 | "count": 1000,
434 | "attribute": "prop-3",
435 | "type": "string"
436 | },
437 | {
438 | "values": [
439 | "0-value-4",
440 | "1-value-4",
441 | "2-value-4",
442 | "3-value-4",
443 | "4-value-4",
444 | "5-value-4",
445 | "6-value-4",
446 | "7-value-4",
447 | "8-value-4",
448 | "9-value-4",
449 | "10-value-4",
450 | "11-value-4",
451 | "12-value-4",
452 | "13-value-4",
453 | "14-value-4",
454 | "15-value-4",
455 | "16-value-4",
456 | "17-value-4",
457 | "18-value-4",
458 | "19-value-4",
459 | "20-value-4",
460 | "21-value-4",
461 | "22-value-4",
462 | "23-value-4",
463 | "24-value-4",
464 | "25-value-4",
465 | "26-value-4",
466 | "27-value-4",
467 | "28-value-4",
468 | "29-value-4",
469 | "30-value-4",
470 | "31-value-4",
471 | "32-value-4",
472 | "33-value-4",
473 | "34-value-4",
474 | "35-value-4",
475 | "36-value-4",
476 | "37-value-4",
477 | "38-value-4",
478 | "39-value-4",
479 | "40-value-4",
480 | "41-value-4",
481 | "42-value-4",
482 | "43-value-4",
483 | "44-value-4",
484 | "45-value-4",
485 | "46-value-4",
486 | "47-value-4",
487 | "48-value-4",
488 | "49-value-4",
489 | "50-value-4",
490 | "51-value-4",
491 | "52-value-4",
492 | "53-value-4",
493 | "54-value-4",
494 | "55-value-4",
495 | "56-value-4",
496 | "57-value-4",
497 | "58-value-4",
498 | "59-value-4",
499 | "60-value-4",
500 | "61-value-4",
501 | "62-value-4",
502 | "63-value-4",
503 | "64-value-4",
504 | "65-value-4",
505 | "66-value-4",
506 | "67-value-4",
507 | "68-value-4",
508 | "69-value-4",
509 | "70-value-4",
510 | "71-value-4",
511 | "72-value-4",
512 | "73-value-4",
513 | "74-value-4",
514 | "75-value-4",
515 | "76-value-4",
516 | "77-value-4",
517 | "78-value-4",
518 | "79-value-4",
519 | "80-value-4",
520 | "81-value-4",
521 | "82-value-4",
522 | "83-value-4",
523 | "84-value-4",
524 | "85-value-4",
525 | "86-value-4",
526 | "87-value-4",
527 | "88-value-4",
528 | "89-value-4",
529 | "90-value-4",
530 | "91-value-4",
531 | "92-value-4",
532 | "93-value-4",
533 | "94-value-4",
534 | "95-value-4",
535 | "96-value-4",
536 | "97-value-4",
537 | "98-value-4",
538 | "99-value-4"
539 | ],
540 | "count": 1000,
541 | "attribute": "prop-4",
542 | "type": "string"
543 | },
544 | {
545 | "values": [
546 | "0-value-5",
547 | "1-value-5",
548 | "2-value-5",
549 | "3-value-5",
550 | "4-value-5",
551 | "5-value-5",
552 | "6-value-5",
553 | "7-value-5",
554 | "8-value-5",
555 | "9-value-5",
556 | "10-value-5",
557 | "11-value-5",
558 | "12-value-5",
559 | "13-value-5",
560 | "14-value-5",
561 | "15-value-5",
562 | "16-value-5",
563 | "17-value-5",
564 | "18-value-5",
565 | "19-value-5",
566 | "20-value-5",
567 | "21-value-5",
568 | "22-value-5",
569 | "23-value-5",
570 | "24-value-5",
571 | "25-value-5",
572 | "26-value-5",
573 | "27-value-5",
574 | "28-value-5",
575 | "29-value-5",
576 | "30-value-5",
577 | "31-value-5",
578 | "32-value-5",
579 | "33-value-5",
580 | "34-value-5",
581 | "35-value-5",
582 | "36-value-5",
583 | "37-value-5",
584 | "38-value-5",
585 | "39-value-5",
586 | "40-value-5",
587 | "41-value-5",
588 | "42-value-5",
589 | "43-value-5",
590 | "44-value-5",
591 | "45-value-5",
592 | "46-value-5",
593 | "47-value-5",
594 | "48-value-5",
595 | "49-value-5",
596 | "50-value-5",
597 | "51-value-5",
598 | "52-value-5",
599 | "53-value-5",
600 | "54-value-5",
601 | "55-value-5",
602 | "56-value-5",
603 | "57-value-5",
604 | "58-value-5",
605 | "59-value-5",
606 | "60-value-5",
607 | "61-value-5",
608 | "62-value-5",
609 | "63-value-5",
610 | "64-value-5",
611 | "65-value-5",
612 | "66-value-5",
613 | "67-value-5",
614 | "68-value-5",
615 | "69-value-5",
616 | "70-value-5",
617 | "71-value-5",
618 | "72-value-5",
619 | "73-value-5",
620 | "74-value-5",
621 | "75-value-5",
622 | "76-value-5",
623 | "77-value-5",
624 | "78-value-5",
625 | "79-value-5",
626 | "80-value-5",
627 | "81-value-5",
628 | "82-value-5",
629 | "83-value-5",
630 | "84-value-5",
631 | "85-value-5",
632 | "86-value-5",
633 | "87-value-5",
634 | "88-value-5",
635 | "89-value-5",
636 | "90-value-5",
637 | "91-value-5",
638 | "92-value-5",
639 | "93-value-5",
640 | "94-value-5",
641 | "95-value-5",
642 | "96-value-5",
643 | "97-value-5",
644 | "98-value-5",
645 | "99-value-5"
646 | ],
647 | "count": 1000,
648 | "attribute": "prop-5",
649 | "type": "string"
650 | },
651 | {
652 | "values": [
653 | "0-value-6",
654 | "1-value-6",
655 | "2-value-6",
656 | "3-value-6",
657 | "4-value-6",
658 | "5-value-6",
659 | "6-value-6",
660 | "7-value-6",
661 | "8-value-6",
662 | "9-value-6",
663 | "10-value-6",
664 | "11-value-6",
665 | "12-value-6",
666 | "13-value-6",
667 | "14-value-6",
668 | "15-value-6",
669 | "16-value-6",
670 | "17-value-6",
671 | "18-value-6",
672 | "19-value-6",
673 | "20-value-6",
674 | "21-value-6",
675 | "22-value-6",
676 | "23-value-6",
677 | "24-value-6",
678 | "25-value-6",
679 | "26-value-6",
680 | "27-value-6",
681 | "28-value-6",
682 | "29-value-6",
683 | "30-value-6",
684 | "31-value-6",
685 | "32-value-6",
686 | "33-value-6",
687 | "34-value-6",
688 | "35-value-6",
689 | "36-value-6",
690 | "37-value-6",
691 | "38-value-6",
692 | "39-value-6",
693 | "40-value-6",
694 | "41-value-6",
695 | "42-value-6",
696 | "43-value-6",
697 | "44-value-6",
698 | "45-value-6",
699 | "46-value-6",
700 | "47-value-6",
701 | "48-value-6",
702 | "49-value-6",
703 | "50-value-6",
704 | "51-value-6",
705 | "52-value-6",
706 | "53-value-6",
707 | "54-value-6",
708 | "55-value-6",
709 | "56-value-6",
710 | "57-value-6",
711 | "58-value-6",
712 | "59-value-6",
713 | "60-value-6",
714 | "61-value-6",
715 | "62-value-6",
716 | "63-value-6",
717 | "64-value-6",
718 | "65-value-6",
719 | "66-value-6",
720 | "67-value-6",
721 | "68-value-6",
722 | "69-value-6",
723 | "70-value-6",
724 | "71-value-6",
725 | "72-value-6",
726 | "73-value-6",
727 | "74-value-6",
728 | "75-value-6",
729 | "76-value-6",
730 | "77-value-6",
731 | "78-value-6",
732 | "79-value-6",
733 | "80-value-6",
734 | "81-value-6",
735 | "82-value-6",
736 | "83-value-6",
737 | "84-value-6",
738 | "85-value-6",
739 | "86-value-6",
740 | "87-value-6",
741 | "88-value-6",
742 | "89-value-6",
743 | "90-value-6",
744 | "91-value-6",
745 | "92-value-6",
746 | "93-value-6",
747 | "94-value-6",
748 | "95-value-6",
749 | "96-value-6",
750 | "97-value-6",
751 | "98-value-6",
752 | "99-value-6"
753 | ],
754 | "count": 1000,
755 | "attribute": "prop-6",
756 | "type": "string"
757 | },
758 | {
759 | "values": [
760 | "0-value-7",
761 | "1-value-7",
762 | "2-value-7",
763 | "3-value-7",
764 | "4-value-7",
765 | "5-value-7",
766 | "6-value-7",
767 | "7-value-7",
768 | "8-value-7",
769 | "9-value-7",
770 | "10-value-7",
771 | "11-value-7",
772 | "12-value-7",
773 | "13-value-7",
774 | "14-value-7",
775 | "15-value-7",
776 | "16-value-7",
777 | "17-value-7",
778 | "18-value-7",
779 | "19-value-7",
780 | "20-value-7",
781 | "21-value-7",
782 | "22-value-7",
783 | "23-value-7",
784 | "24-value-7",
785 | "25-value-7",
786 | "26-value-7",
787 | "27-value-7",
788 | "28-value-7",
789 | "29-value-7",
790 | "30-value-7",
791 | "31-value-7",
792 | "32-value-7",
793 | "33-value-7",
794 | "34-value-7",
795 | "35-value-7",
796 | "36-value-7",
797 | "37-value-7",
798 | "38-value-7",
799 | "39-value-7",
800 | "40-value-7",
801 | "41-value-7",
802 | "42-value-7",
803 | "43-value-7",
804 | "44-value-7",
805 | "45-value-7",
806 | "46-value-7",
807 | "47-value-7",
808 | "48-value-7",
809 | "49-value-7",
810 | "50-value-7",
811 | "51-value-7",
812 | "52-value-7",
813 | "53-value-7",
814 | "54-value-7",
815 | "55-value-7",
816 | "56-value-7",
817 | "57-value-7",
818 | "58-value-7",
819 | "59-value-7",
820 | "60-value-7",
821 | "61-value-7",
822 | "62-value-7",
823 | "63-value-7",
824 | "64-value-7",
825 | "65-value-7",
826 | "66-value-7",
827 | "67-value-7",
828 | "68-value-7",
829 | "69-value-7",
830 | "70-value-7",
831 | "71-value-7",
832 | "72-value-7",
833 | "73-value-7",
834 | "74-value-7",
835 | "75-value-7",
836 | "76-value-7",
837 | "77-value-7",
838 | "78-value-7",
839 | "79-value-7",
840 | "80-value-7",
841 | "81-value-7",
842 | "82-value-7",
843 | "83-value-7",
844 | "84-value-7",
845 | "85-value-7",
846 | "86-value-7",
847 | "87-value-7",
848 | "88-value-7",
849 | "89-value-7",
850 | "90-value-7",
851 | "91-value-7",
852 | "92-value-7",
853 | "93-value-7",
854 | "94-value-7",
855 | "95-value-7",
856 | "96-value-7",
857 | "97-value-7",
858 | "98-value-7",
859 | "99-value-7"
860 | ],
861 | "count": 1000,
862 | "attribute": "prop-7",
863 | "type": "string"
864 | },
865 | {
866 | "values": [
867 | "0-value-8",
868 | "1-value-8",
869 | "2-value-8",
870 | "3-value-8",
871 | "4-value-8",
872 | "5-value-8",
873 | "6-value-8",
874 | "7-value-8",
875 | "8-value-8",
876 | "9-value-8",
877 | "10-value-8",
878 | "11-value-8",
879 | "12-value-8",
880 | "13-value-8",
881 | "14-value-8",
882 | "15-value-8",
883 | "16-value-8",
884 | "17-value-8",
885 | "18-value-8",
886 | "19-value-8",
887 | "20-value-8",
888 | "21-value-8",
889 | "22-value-8",
890 | "23-value-8",
891 | "24-value-8",
892 | "25-value-8",
893 | "26-value-8",
894 | "27-value-8",
895 | "28-value-8",
896 | "29-value-8",
897 | "30-value-8",
898 | "31-value-8",
899 | "32-value-8",
900 | "33-value-8",
901 | "34-value-8",
902 | "35-value-8",
903 | "36-value-8",
904 | "37-value-8",
905 | "38-value-8",
906 | "39-value-8",
907 | "40-value-8",
908 | "41-value-8",
909 | "42-value-8",
910 | "43-value-8",
911 | "44-value-8",
912 | "45-value-8",
913 | "46-value-8",
914 | "47-value-8",
915 | "48-value-8",
916 | "49-value-8",
917 | "50-value-8",
918 | "51-value-8",
919 | "52-value-8",
920 | "53-value-8",
921 | "54-value-8",
922 | "55-value-8",
923 | "56-value-8",
924 | "57-value-8",
925 | "58-value-8",
926 | "59-value-8",
927 | "60-value-8",
928 | "61-value-8",
929 | "62-value-8",
930 | "63-value-8",
931 | "64-value-8",
932 | "65-value-8",
933 | "66-value-8",
934 | "67-value-8",
935 | "68-value-8",
936 | "69-value-8",
937 | "70-value-8",
938 | "71-value-8",
939 | "72-value-8",
940 | "73-value-8",
941 | "74-value-8",
942 | "75-value-8",
943 | "76-value-8",
944 | "77-value-8",
945 | "78-value-8",
946 | "79-value-8",
947 | "80-value-8",
948 | "81-value-8",
949 | "82-value-8",
950 | "83-value-8",
951 | "84-value-8",
952 | "85-value-8",
953 | "86-value-8",
954 | "87-value-8",
955 | "88-value-8",
956 | "89-value-8",
957 | "90-value-8",
958 | "91-value-8",
959 | "92-value-8",
960 | "93-value-8",
961 | "94-value-8",
962 | "95-value-8",
963 | "96-value-8",
964 | "97-value-8",
965 | "98-value-8",
966 | "99-value-8"
967 | ],
968 | "count": 1000,
969 | "attribute": "prop-8",
970 | "type": "string"
971 | },
972 | {
973 | "values": [
974 | "0-value-9",
975 | "1-value-9",
976 | "2-value-9",
977 | "3-value-9",
978 | "4-value-9",
979 | "5-value-9",
980 | "6-value-9",
981 | "7-value-9",
982 | "8-value-9",
983 | "9-value-9",
984 | "10-value-9",
985 | "11-value-9",
986 | "12-value-9",
987 | "13-value-9",
988 | "14-value-9",
989 | "15-value-9",
990 | "16-value-9",
991 | "17-value-9",
992 | "18-value-9",
993 | "19-value-9",
994 | "20-value-9",
995 | "21-value-9",
996 | "22-value-9",
997 | "23-value-9",
998 | "24-value-9",
999 | "25-value-9",
1000 | "26-value-9",
1001 | "27-value-9",
1002 | "28-value-9",
1003 | "29-value-9",
1004 | "30-value-9",
1005 | "31-value-9",
1006 | "32-value-9",
1007 | "33-value-9",
1008 | "34-value-9",
1009 | "35-value-9",
1010 | "36-value-9",
1011 | "37-value-9",
1012 | "38-value-9",
1013 | "39-value-9",
1014 | "40-value-9",
1015 | "41-value-9",
1016 | "42-value-9",
1017 | "43-value-9",
1018 | "44-value-9",
1019 | "45-value-9",
1020 | "46-value-9",
1021 | "47-value-9",
1022 | "48-value-9",
1023 | "49-value-9",
1024 | "50-value-9",
1025 | "51-value-9",
1026 | "52-value-9",
1027 | "53-value-9",
1028 | "54-value-9",
1029 | "55-value-9",
1030 | "56-value-9",
1031 | "57-value-9",
1032 | "58-value-9",
1033 | "59-value-9",
1034 | "60-value-9",
1035 | "61-value-9",
1036 | "62-value-9",
1037 | "63-value-9",
1038 | "64-value-9",
1039 | "65-value-9",
1040 | "66-value-9",
1041 | "67-value-9",
1042 | "68-value-9",
1043 | "69-value-9",
1044 | "70-value-9",
1045 | "71-value-9",
1046 | "72-value-9",
1047 | "73-value-9",
1048 | "74-value-9",
1049 | "75-value-9",
1050 | "76-value-9",
1051 | "77-value-9",
1052 | "78-value-9",
1053 | "79-value-9",
1054 | "80-value-9",
1055 | "81-value-9",
1056 | "82-value-9",
1057 | "83-value-9",
1058 | "84-value-9",
1059 | "85-value-9",
1060 | "86-value-9",
1061 | "87-value-9",
1062 | "88-value-9",
1063 | "89-value-9",
1064 | "90-value-9",
1065 | "91-value-9",
1066 | "92-value-9",
1067 | "93-value-9",
1068 | "94-value-9",
1069 | "95-value-9",
1070 | "96-value-9",
1071 | "97-value-9",
1072 | "98-value-9",
1073 | "99-value-9"
1074 | ],
1075 | "count": 1000,
1076 | "attribute": "prop-9",
1077 | "type": "string"
1078 | }
1079 | ],
1080 | "geometry": "Point"
1081 | }
1082 | ]
1083 | }
1084 |
--------------------------------------------------------------------------------
/test/fixtures/expected/no-features.json:
--------------------------------------------------------------------------------
1 | {
2 | "layerCount": 1,
3 | "layers": [
4 | {
5 | "layer": "no-features",
6 | "count": 0,
7 | "attributeCount": 0,
8 | "attributes": []
9 | }
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/test/fixtures/expected/ports-only-name.json:
--------------------------------------------------------------------------------
1 | {
2 | "layerCount": 1,
3 | "layers": [
4 | {
5 | "layer": "ports",
6 | "count": 1081,
7 | "attributeCount": 1,
8 | "attributes": [
9 | {
10 | "values": [
11 | "Sint Nicolaas",
12 | "Campana",
13 | "Zarate",
14 | "Puerto Belgrano/Bahia Blanca",
15 | "Puerto Galvan/Bahia Blanca",
16 | "Ingeniero White/Bahia Blanca",
17 | "Saint John's",
18 | "Fremantle",
19 | "Botany Bay",
20 | "Rockhampton",
21 | "Oostende (Ostend)",
22 | "Zeebrugge",
23 | "Burgas",
24 | "Mina Sulman Port",
25 | "Sitrah",
26 | "Saint George",
27 | "Mucuripe",
28 | "Niteroi",
29 | "Sao Francisco do Sul",
30 | "Chatham",
31 | "Clarenville",
32 | "Comox",
33 | "Esquimalt",
34 | "Grand Bank",
35 | "North Sydney",
36 | "Caraquet",
37 | "Chicoutimi",
38 | "Corner Brook",
39 | "Digby",
40 | "Harbour Grace",
41 | "Pictou",
42 | "Shelburne",
43 | "Sorel",
44 | "Springdale",
45 | "Saint-John's",
46 | "Coronel",
47 | "Lota",
48 | "Talcahuano",
49 | "San Antonio",
50 | "Haimen",
51 | "Qinhuangdao",
52 | "Yantian",
53 | "Yingkou",
54 | "Moin",
55 | "Banes",
56 | "Caibarien",
57 | "Isabela de Sagua",
58 | "Nuevitas",
59 | "Famagusta",
60 | "Cuxhaven",
61 | "Eckernforde",
62 | "Nordenham",
63 | "Papenburg",
64 | "Wismar",
65 | "Nyborg",
66 | "Helsingor",
67 | "Odense",
68 | "Frederikshavn",
69 | "Haderslev",
70 | "Horsens",
71 | "Kalundborg",
72 | "Kolding",
73 | "Nakskov",
74 | "Nykobing Falster",
75 | "Randers",
76 | "Rudkobing",
77 | "Svendborg",
78 | "Vejle",
79 | "Skagen",
80 | "Puerto Plata",
81 | "Rio Haina",
82 | "Mostaganem",
83 | "Damietta",
84 | "Safaga",
85 | "Algeciras",
86 | "Aviles",
87 | "Ferrol",
88 | "Huelva",
89 | "Pasajes",
90 | "Rota",
91 | "Cadiz",
92 | "Kotka",
93 | "Veitsiluoto",
94 | "Arcachon",
95 | "Deauville",
96 | "Fecamp",
97 | "La Pallice",
98 | "Saint-Malo",
99 | "Sete",
100 | "Greenock",
101 | "Poole",
102 | "Falmouth",
103 | "Leith",
104 | "Montrose",
105 | "Newport",
106 | "Sunderland",
107 | "Teesport",
108 | "Poti",
109 | "Piraeus",
110 | "Saint George's",
111 | "Cayenne",
112 | "Bakar",
113 | "Rovinj",
114 | "Sibenik",
115 | "Gonaives",
116 | "Sorong",
117 | "Alleppey",
118 | "Kakinada",
119 | "Tuticorin",
120 | "Sligo",
121 | "Licata",
122 | "Alghero",
123 | "Bagnoli",
124 | "Barletta",
125 | "Brindisi",
126 | "Crotone",
127 | "Gallipoli",
128 | "Imperia",
129 | "La Maddalena",
130 | "La Spezia",
131 | "Marsala",
132 | "Messina",
133 | "Molfetta",
134 | "Monfalcone",
135 | "Monopoli",
136 | "Pesaro",
137 | "Porto Torres",
138 | "Ravenna",
139 | "Siracusa",
140 | "Taranto",
141 | "Torre Annunziata",
142 | "Omura",
143 | "Amagasaki",
144 | "Fushiki",
145 | "Imabari",
146 | "Iwakuni",
147 | "Kainan",
148 | "Kanazawa",
149 | "Kawasaki",
150 | "Kokura",
151 | "Maizuru",
152 | "Matsusaka",
153 | "Miyazu",
154 | "Muroran",
155 | "Niigata",
156 | "Saganoseki",
157 | "Sasebo",
158 | "Shimizu",
159 | "Shimotsu",
160 | "Wakayama",
161 | "Yokosuka",
162 | "Galle",
163 | "Ventspils",
164 | "Frontera",
165 | "Minatitlan",
166 | "Pajaritos",
167 | "Santa Rosalia",
168 | "Progreso",
169 | "Tuxpan",
170 | "Kemaman",
171 | "Den Helder",
172 | "Dordrecht",
173 | "Delfzijl",
174 | "Arendal",
175 | "Drammen",
176 | "Halden",
177 | "Harstad",
178 | "Larvik",
179 | "Moss",
180 | "Sandefjord",
181 | "Tonsberg",
182 | "Lyttelton",
183 | "Qalhat",
184 | "Sohar",
185 | "Balboa",
186 | "Cristobal",
187 | "Pedregal",
188 | "Callao",
189 | "Matarani",
190 | "Swinoujscie",
191 | "Leixoes",
192 | "Setubal",
193 | "Aveiro",
194 | "Viana do Castelo",
195 | "Galati",
196 | "Nakhodka",
197 | "Kandalaksha",
198 | "Kholmsk",
199 | "Korsakov",
200 | "Kronshtadt",
201 | "Novorossiysk",
202 | "Tuapse",
203 | "Jubail",
204 | "Ras al Khafji",
205 | "Falkenberg",
206 | "Ahus",
207 | "Harnosand",
208 | "Hoganas",
209 | "Karlshamn",
210 | "Karlskrona",
211 | "Nynashamn",
212 | "Oskarshamn",
213 | "Oxelosund",
214 | "Pitea",
215 | "Sodertalje",
216 | "Trelleborg",
217 | "Uddevalla",
218 | "Ystad",
219 | "Bangkok",
220 | "Laem Chabang",
221 | "Sriracha",
222 | "Point Lisas",
223 | "Mersin",
224 | "Berdyansk",
225 | "Kerch",
226 | "Richmond",
227 | "Wilmington",
228 | "Quincy",
229 | "Nawiliwili",
230 | "Monterey",
231 | "Gloucester City",
232 | "Bayonne",
233 | "Baltimore",
234 | "Jacksonville",
235 | "Newport News",
236 | "Port Arthur",
237 | "Portsmouth",
238 | "Alexandria",
239 | "Brownsville",
240 | "Vancouver",
241 | "Guanta",
242 | "Keelung",
243 | "Arrecife",
244 | "St Thomas",
245 | "Basseterre",
246 | "New Orleans",
247 | "Freeport",
248 | "Trenton",
249 | "Goderich",
250 | "Midland",
251 | "St Joseph",
252 | "Racine",
253 | "Menominee",
254 | "Escanaba",
255 | "Sacramento",
256 | "Great Yarmouth",
257 | "Dundee",
258 | "Portmahomack Harbor",
259 | "Wick",
260 | "Oban",
261 | "Douglas",
262 | "Londonderry",
263 | "Silloth",
264 | "Ambriz",
265 | "Cabinda",
266 | "Soyo",
267 | "Durres",
268 | "Curacao",
269 | "Al Fujayrah",
270 | "Caleta Olivia",
271 | "Puerto Deseado",
272 | "Rio Gallegos",
273 | "Rio Grande",
274 | "San Julian",
275 | "Coffs Harbour",
276 | "Esperance",
277 | "Port Augusta",
278 | "Bowen",
279 | "Bundaberg",
280 | "Burketown",
281 | "Carnarvon",
282 | "Cooktown",
283 | "Derby",
284 | "Eden",
285 | "George Town",
286 | "Geraldton",
287 | "Karumba",
288 | "Kingscote",
289 | "Maryborough",
290 | "Strahan",
291 | "Mongla",
292 | "Aracaju",
293 | "Fortaleza",
294 | "Macapa",
295 | "Navegantes",
296 | "Pelotas",
297 | "Campbell River",
298 | "Goose Bay",
299 | "Masset",
300 | "Matane",
301 | "Nanisivik",
302 | "New Richmond",
303 | "Port Hardy",
304 | "Port Hawkesbury",
305 | "Squamish",
306 | "Stephenville",
307 | "Stewart",
308 | "Tahsis",
309 | "Sandspit",
310 | "Tuktoyaktuk",
311 | "Ancud",
312 | "Castro",
313 | "Chanaral",
314 | "Puerto Natales",
315 | "Taltal",
316 | "Guangzhou",
317 | "Jiangyin",
318 | "Lianyungang",
319 | "Sanya",
320 | "Zhanjiang",
321 | "Zhoushan",
322 | "San-Pedro",
323 | "Cartagena",
324 | "Tolu",
325 | "Tumaco",
326 | "Turbo",
327 | "Baracoa",
328 | "Nicaro",
329 | "Nueva Gerona",
330 | "Helgoland",
331 | "Travemunde",
332 | "Thisted",
333 | "Manta",
334 | "Esmeraldas",
335 | "Corralejo",
336 | "Ceuta",
337 | "Melilla",
338 | "San Sebastian de la Gomera",
339 | "Santa Cruz de La Palma",
340 | "Parnu",
341 | "Kuopio",
342 | "Joensuu",
343 | "Varkaus",
344 | "Savusavu",
345 | "Cherbourg",
346 | "Caen",
347 | "Calvi",
348 | "Propriano",
349 | "Quimper",
350 | "Vannes",
351 | "Yap",
352 | "Bristol",
353 | "Hull",
354 | "Newcastle upon Tyne",
355 | "Tyne",
356 | "Rochester",
357 | "Tema",
358 | "Alexandroupolis",
359 | "Kos",
360 | "Paros",
361 | "Samos",
362 | "Nanortalik",
363 | "Qaanaaq",
364 | "New Amsterdam",
365 | "La Ceiba",
366 | "Tela",
367 | "Mali Losinj",
368 | "Jacmel",
369 | "Jeremie",
370 | "Lhokseumawe",
371 | "Nunukan",
372 | "Panjang",
373 | "Tanjung Priok",
374 | "Mangalore",
375 | "Porbandar",
376 | "Ratnagiri",
377 | "Bantry",
378 | "Wexford",
379 | "Khorramshahr",
380 | "Djupivogur",
381 | "Faskrudsfjordur",
382 | "Raufarhofn",
383 | "Pantelleria",
384 | "Catania",
385 | "Fiumicino",
386 | "Lampedusa",
387 | "Manfredonia",
388 | "Ocho Rios",
389 | "Port Antonio",
390 | "Nishinoomote",
391 | "Akita",
392 | "Hachinohe",
393 | "Ishigaki",
394 | "Matsuyama",
395 | "Sakata",
396 | "Takamatsu",
397 | "Wakkanai",
398 | "Tottori",
399 | "Lamu",
400 | "Gunsan",
401 | "Pohang",
402 | "Samcheok",
403 | "Sokcho",
404 | "Ulsan",
405 | "Tripoli",
406 | "Buchanan",
407 | "Agadir",
408 | "Al Hoceima",
409 | "Dakhla",
410 | "Antalaha",
411 | "Manakara",
412 | "Mananjary",
413 | "Morondava",
414 | "Toamasina",
415 | "Loreto",
416 | "Campeche",
417 | "Cozumel",
418 | "La Paz",
419 | "Playa del Carmen",
420 | "Puerto Penasco",
421 | "Puerto Vallarta",
422 | "Coatzacoalcos",
423 | "Bassein",
424 | "Nacala",
425 | "Pemba",
426 | "Quelimane",
427 | "Port Louis",
428 | "Malacca",
429 | "Port Dickson",
430 | "Walvis Bay",
431 | "Calabar",
432 | "Groningen",
433 | "Alta",
434 | "Andenes",
435 | "Bronnoysund",
436 | "Farsund",
437 | "Floro",
438 | "Kristiansand",
439 | "Namsos",
440 | "Rorvik",
441 | "Sandnessjoen",
442 | "Stokmarknes",
443 | "Stord",
444 | "Picton",
445 | "Dunedin",
446 | "Salalah",
447 | "Gwadar",
448 | "Bocas del Toro",
449 | "La Palma",
450 | "Chimbote",
451 | "Ilo",
452 | "Mollendo",
453 | "Pisco",
454 | "Dumaguete",
455 | "General Santos",
456 | "Buka",
457 | "Daru",
458 | "Lae",
459 | "Madang",
460 | "Gdansk",
461 | "Gdynia",
462 | "Aguadilla",
463 | "Arecibo",
464 | "Mayaguez",
465 | "Faro",
466 | "Bora-Bora",
467 | "Tulcea",
468 | "Amderma",
469 | "Anadyr",
470 | "Pevek",
471 | "Kaolack",
472 | "Ziguinchor",
473 | "Longyearbyen",
474 | "Gizo",
475 | "Viru Harbour",
476 | "Kismayu",
477 | "Karlstad",
478 | "Lidkoping",
479 | "Skelleftea",
480 | "Umea",
481 | "Providenciales",
482 | "Songkhla",
483 | "Bandirma",
484 | "Samsun",
485 | "Sinop",
486 | "Trabzon",
487 | "Sevastopol",
488 | "Skagway",
489 | "Valdez",
490 | "Apalachicola",
491 | "Annapolis",
492 | "Cambridge",
493 | "Portland",
494 | "Bremerton",
495 | "Rockland",
496 | "Santa Cruz",
497 | "Chesapeake",
498 | "Cumana",
499 | "Hai Phong",
500 | "Corfu",
501 | "Tangier",
502 | "Hamilton",
503 | "Windsor",
504 | "Rouge River",
505 | "Owen Sound",
506 | "Sault Ste Marie",
507 | "Saginaw",
508 | "Cheboygan",
509 | "Muskegon",
510 | "Gary",
511 | "Waukegan",
512 | "Houghton",
513 | "Wrangell",
514 | "Petersburg",
515 | "Kemi",
516 | "Vaasa",
517 | "Turku",
518 | "Liepaja",
519 | "Europoort",
520 | "Stornoway Harbor",
521 | "Lisboa",
522 | "Bonanza",
523 | "Ibiza",
524 | "Rostov-Na-Donu",
525 | "Tel Aviv Yafo",
526 | "Tunis",
527 | "Bejaia",
528 | "Alger",
529 | "St Louis",
530 | "Tin Can Island",
531 | "Mocambique",
532 | "Assab",
533 | "Massawa",
534 | "Elat",
535 | "Al Kuwayt",
536 | "Bombay",
537 | "Jawaharlal Nehru Port",
538 | "Cochin",
539 | "Madras",
540 | "Calcutta",
541 | "Phuket",
542 | "Pulau Pinang",
543 | "Belawan",
544 | "Semarang",
545 | "Kupang",
546 | "Kuching",
547 | "Miri",
548 | "Kota Kinabalu",
549 | "Pelabuhan Sandakan",
550 | "Ujungpandang",
551 | "Davao",
552 | "Nanjing",
553 | "Hankow",
554 | "Chang Sha",
555 | "Khabarovsk",
556 | "Petropavlovsk",
557 | "Namibe",
558 | "Bahia Blanca",
559 | "La Plata",
560 | "Ushuaia",
561 | "Puerto Madryn",
562 | "Pago Pago",
563 | "Mackay",
564 | "Port Lincoln",
565 | "Port Pirie",
566 | "Albany",
567 | "Barrow Island",
568 | "Bunbury",
569 | "Burnie",
570 | "Geelong",
571 | "Gladstone",
572 | "Newcastle",
573 | "Port Kembla",
574 | "Thursday Island",
575 | "Townsville",
576 | "Weipa",
577 | "Whyalla",
578 | "Wyndham",
579 | "Brussel (Bruxelles)",
580 | "Gent (Ghent)",
581 | "Ilheus",
582 | "Maceio",
583 | "Natal",
584 | "Vitoria",
585 | "Ocean Falls",
586 | "Argentia",
587 | "Bathurst",
588 | "Gaspe",
589 | "Port Alberni",
590 | "Powell River",
591 | "Sept-Iles",
592 | "Sydney",
593 | "Trois-Rivieres (Three Rivers)",
594 | "Yarmouth",
595 | "Rimouski",
596 | "Riviere-du-Loup",
597 | "Saint-Anthony",
598 | "Summerside",
599 | "Arica",
600 | "Tocopilla",
601 | "Beihai",
602 | "Jiangmen",
603 | "Wenzhou",
604 | "Yantai",
605 | "Zhuhai",
606 | "Santa Marta",
607 | "Buenaventura",
608 | "Praia",
609 | "Golfito",
610 | "Cienfuegos",
611 | "Manzanillo",
612 | "Matanzas",
613 | "Santiago de Cuba",
614 | "Emden",
615 | "Flensburg",
616 | "Wilhelmshaven",
617 | "Esbjerg",
618 | "Sonderborg",
619 | "Ronne",
620 | "Barahona",
621 | "Cabo Rojo",
622 | "Oran",
623 | "A Coruna",
624 | "Almeria",
625 | "Gijon",
626 | "San Sebastian",
627 | "Santander",
628 | "Tarragona",
629 | "Oulu",
630 | "Boulogne-sur-Mer",
631 | "Brest",
632 | "Cannes",
633 | "Dieppe",
634 | "Granville",
635 | "La Rochelle",
636 | "Lorient",
637 | "Morlaix",
638 | "Rochefort",
639 | "Toulon",
640 | "Owendo",
641 | "Aberdeen",
642 | "Liverpool",
643 | "Plymouth",
644 | "Batumi",
645 | "Kavala",
646 | "Chios",
647 | "Kalamata",
648 | "Patras",
649 | "Volos",
650 | "Uummannaq",
651 | "Puerto Barrios",
652 | "Pula",
653 | "Rijeka",
654 | "Split",
655 | "Banjarmasin",
656 | "Tanjung Pandan",
657 | "Port Blair",
658 | "Kandla",
659 | "Pondicherry",
660 | "Cork",
661 | "Galway",
662 | "Bushehr",
663 | "Ancona",
664 | "Bari",
665 | "Cagliari",
666 | "Olbia",
667 | "Pescara",
668 | "Reggio Calabria",
669 | "Trapani",
670 | "Aomori",
671 | "Hakodate",
672 | "Kagoshima",
673 | "Kochi",
674 | "Kushiro",
675 | "Niihama",
676 | "Oita",
677 | "Shimonoseki",
678 | "Tomakomai",
679 | "Toyama",
680 | "Ube",
681 | "Malindi",
682 | "Trincomalee",
683 | "Klaipeda",
684 | "Safi",
685 | "Ensenada",
686 | "Guaymas",
687 | "Salina Cruz",
688 | "Saipan",
689 | "Nouadhibou",
690 | "Luderitz",
691 | "Bluefields",
692 | "Alesund",
693 | "Batsfjord",
694 | "Bodo",
695 | "Hammerfest",
696 | "Haugesund",
697 | "Kirkenes",
698 | "Kristiansund",
699 | "Mo i Rana",
700 | "Molde",
701 | "Mosjoen",
702 | "Narvik",
703 | "Stavanger",
704 | "Vadso",
705 | "Vardo",
706 | "New Plymouth",
707 | "Gisborne",
708 | "Greymouth",
709 | "Napier",
710 | "Tauranga",
711 | "Wanganui",
712 | "Westport",
713 | "Whangarei",
714 | "Timaru",
715 | "Talara",
716 | "Masbate",
717 | "Subic Bay",
718 | "Alotau",
719 | "Kavieng",
720 | "Kieta",
721 | "Rabaul",
722 | "Vanimo",
723 | "Ponce",
724 | "Sines",
725 | "Horta",
726 | "Arkhangelsk",
727 | "Murmansk",
728 | "Tiksi",
729 | "Jizan",
730 | "Berbera",
731 | "Nieuw Nickerie",
732 | "Malmo",
733 | "Gavle",
734 | "Halmstad",
735 | "Helsingborg",
736 | "Hudiksvall",
737 | "Kalmar",
738 | "Ornskoldsvik",
739 | "Ronneby",
740 | "Soderhamn",
741 | "Vastervik",
742 | "Visby",
743 | "Tekirdag",
744 | "Tanga",
745 | "Kherson",
746 | "Colonia",
747 | "Cordova",
748 | "Ketchikan",
749 | "Bangor",
750 | "Stockton",
751 | "Bridgeport",
752 | "New Haven",
753 | "Port Everglades",
754 | "Savannah",
755 | "Gulfport",
756 | "Newark",
757 | "Astoria",
758 | "Corpus Christi",
759 | "Pascagoula",
760 | "Tacoma",
761 | "Beaumont",
762 | "Olympia",
763 | "Port Angeles",
764 | "Port Townsend",
765 | "Puerto Cabello",
766 | "Mukalla",
767 | "East London",
768 | "Mossel Bay",
769 | "Richards Bay",
770 | "Erie",
771 | "Bay City",
772 | "Milwaukee",
773 | "Coos Bay",
774 | "Sitka",
775 | "Kodiak",
776 | "Lobito",
777 | "Abu Dhabi",
778 | "Comodoro Rivadavia",
779 | "Mar del Plata",
780 | "Cairns",
781 | "Broome",
782 | "Devonport",
783 | "Hobart",
784 | "Antwerpen",
785 | "Varna",
786 | "Belize City",
787 | "Belem",
788 | "Paranagua",
789 | "Porto Alegre",
790 | "Recife",
791 | "Salvador",
792 | "Santos",
793 | "Charlottetown",
794 | "Halifax",
795 | "Nanaimo",
796 | "Quebec",
797 | "Victoria",
798 | "Prince Rupert",
799 | "Saint-John",
800 | "Antofagasta",
801 | "Iquique",
802 | "Puerto Montt",
803 | "Haikou",
804 | "Ningbo",
805 | "Xiamen",
806 | "Abidjan",
807 | "Douala",
808 | "Pointe Noire",
809 | "Barranquilla",
810 | "Moroni",
811 | "Mariel",
812 | "Larnaca",
813 | "Limassol",
814 | "Bremen",
815 | "Hamburg",
816 | "Djibouti",
817 | "Aalborg",
818 | "Fredericia",
819 | "Alicante",
820 | "Bilbao",
821 | "Valencia",
822 | "Fox Bay",
823 | "Ajaccio",
824 | "Bastia",
825 | "Bordeaux",
826 | "Calais",
827 | "Dunkerque",
828 | "Honfleur",
829 | "Libreville",
830 | "Port Gentil",
831 | "Belfast",
832 | "Dover",
833 | "Inverness",
834 | "Takoradi",
835 | "Basse-Terre",
836 | "Pointe-a-Pitre",
837 | "Banjul",
838 | "Bata",
839 | "Iraklion",
840 | "Thessaloniki",
841 | "Kourou",
842 | "Georgetown",
843 | "Puerto Cortes",
844 | "Zadar",
845 | "Surabaya",
846 | "Manado",
847 | "Senipah",
848 | "Bhavnagar",
849 | "Visakhapatnam",
850 | "Limerick",
851 | "Bandar Abbas",
852 | "Reykjavik",
853 | "Seydisfjordur",
854 | "Trieste",
855 | "Hiroshima",
856 | "Kobe",
857 | "Nagasaki",
858 | "Otaru",
859 | "Tokyo",
860 | "Monrovia",
861 | "Colombo",
862 | "Casablanca",
863 | "Monaco",
864 | "Acapulco",
865 | "Mazatlan",
866 | "Tampico",
867 | "Beira",
868 | "Maputo",
869 | "Nouakchott",
870 | "Fort-de-France",
871 | "Noumea",
872 | "Port Harcourt",
873 | "Corinto",
874 | "Rotterdam",
875 | "Bergen",
876 | "Tromso",
877 | "Trondheim",
878 | "Nelson",
879 | "Muscat",
880 | "Cebu",
881 | "Zamboanga",
882 | "Port Moresby",
883 | "Wewak",
884 | "Porto",
885 | "Ponta Delgada",
886 | "Papeete",
887 | "Doha",
888 | "Kaliningrad",
889 | "Vladivostok",
890 | "Vyborg",
891 | "Port Sudan",
892 | "Mogadishu",
893 | "Paramaribo",
894 | "Goteborg",
895 | "Lulea",
896 | "Norrkoping",
897 | "Lome",
898 | "Izmir",
899 | "Kaohsiung",
900 | "Taichung",
901 | "Odessa",
902 | "Montevideo",
903 | "Juneau",
904 | "Nome",
905 | "Hilo",
906 | "Bellingham",
907 | "Houston",
908 | "Longview",
909 | "Kingstown",
910 | "La Guaira",
911 | "Maracaibo",
912 | "Da Nang",
913 | "Port Vila",
914 | "Apia",
915 | "Hodeidah",
916 | "Ottawa",
917 | "Buffalo",
918 | "Cleveland",
919 | "Green Bay",
920 | "Duluth",
921 | "Eureka",
922 | "Luanda",
923 | "Kralendijk, Bonaire",
924 | "Philipsburg",
925 | "Adelaide",
926 | "Brisbane",
927 | "Port Hedland",
928 | "Chittagong",
929 | "Bridgetown",
930 | "Montreal",
931 | "Punta Arenas",
932 | "Valdivia",
933 | "Dalian",
934 | "Fuzhou",
935 | "Qingdao",
936 | "Shanghai",
937 | "Shantou",
938 | "Puntarenas",
939 | "Kiel",
940 | "Roseau",
941 | "Santo Domingo",
942 | "Vigo",
943 | "Santa Cruz de Tenerife",
944 | "Tallinn",
945 | "Suva",
946 | "Saint-Tropez",
947 | "Glasgow",
948 | "Southampton",
949 | "Gibraltar",
950 | "Conakry",
951 | "Bissau",
952 | "Canea",
953 | "Katakolon",
954 | "San Jose",
955 | "Hong Kong",
956 | "Port-au-Prince",
957 | "Dublin",
958 | "Waterford",
959 | "Haifa",
960 | "Livorno",
961 | "Ischia",
962 | "Kingston",
963 | "Kitakyushu",
964 | "Mombasa",
965 | "Phnom Penh",
966 | "Beirut",
967 | "Male",
968 | "Veracruz",
969 | "Yangon",
970 | "Wellington",
971 | "Szczecin",
972 | "Jeddah",
973 | "Dakar",
974 | "Singapore",
975 | "Freetown",
976 | "Stockholm",
977 | "Canakkale",
978 | "Anchorage",
979 | "Long Beach",
980 | "Oakland",
981 | "Philadelphia",
982 | "Charleston",
983 | "Ho Chi Minh City",
984 | "Aden",
985 | "Durban",
986 | "Port Elizabeth",
987 | "Detroit",
988 | "Port Of Memphis",
989 | "Tri-City Port",
990 | "Helsinki",
991 | "Sankt-Peterburg",
992 | "Oranjestad",
993 | "Dubai",
994 | "Buenos Aires",
995 | "Darwin",
996 | "Melbourne",
997 | "Perth",
998 | "Cotonou",
999 | "Nassau",
1000 | "Rio de Janeiro",
1001 | "Valparaiso",
1002 | "Tianjin",
1003 | "Bremerhaven",
1004 | "Rostock",
1005 | "Tuborg",
1006 | "Guayaquil",
1007 | "Port Said",
1008 | "Barcelona",
1009 | "Malaga",
1010 | "Palma de Mallorca",
1011 | "Le Havre",
1012 | "Marseille",
1013 | "Nice",
1014 | "London",
1015 | "Gythion",
1016 | "Rhodes",
1017 | "Dubrovnik",
1018 | "Civitavecchia",
1019 | "Palermo",
1020 | "Savona",
1021 | "Marghera",
1022 | "Montego Bay",
1023 | "Osaka",
1024 | "Yokohama",
1025 | "Riga",
1026 | "Cabo San Lucas",
1027 | "Marsaxlokk",
1028 | "Amsterdam",
1029 | "Oslo",
1030 | "Auckland",
1031 | "Karachi",
1032 | "Colon",
1033 | "Manila",
1034 | "San Juan",
1035 | "Istanbul",
1036 | "Taipei",
1037 | "Dar es Salaam",
1038 | "Mobile",
1039 | "Los Angeles",
1040 | "San Diego",
1041 | "San Francisco",
1042 | "Miami",
1043 | "Tampa",
1044 | "Honolulu",
1045 | "Boston",
1046 | "New York",
1047 | "Galveston",
1048 | "Norfolk",
1049 | "Seattle",
1050 | "Cape Town",
1051 | "Toronto",
1052 | "Chicago"
1053 | ],
1054 | "count": 1042,
1055 | "attribute": "name",
1056 | "type": "string"
1057 | }
1058 | ],
1059 | "geometry": "Point"
1060 | }
1061 | ]
1062 | }
1063 |
--------------------------------------------------------------------------------
/test/fixtures/expected/ports.json:
--------------------------------------------------------------------------------
1 | {
2 | "layerCount": 1,
3 | "layers": [
4 | {
5 | "layer": "ports",
6 | "count": 1081,
7 | "attributeCount": 5,
8 | "attributes": [
9 | {
10 | "values": [
11 | "Port"
12 | ],
13 | "count": 1,
14 | "attribute": "featurecla",
15 | "type": "string"
16 | },
17 | {
18 | "values": [
19 | "Sint Nicolaas",
20 | "Campana",
21 | "Zarate",
22 | "Puerto Belgrano/Bahia Blanca",
23 | "Puerto Galvan/Bahia Blanca",
24 | "Ingeniero White/Bahia Blanca",
25 | "Saint John's",
26 | "Fremantle",
27 | "Botany Bay",
28 | "Rockhampton",
29 | "Oostende (Ostend)",
30 | "Zeebrugge",
31 | "Burgas",
32 | "Mina Sulman Port",
33 | "Sitrah",
34 | "Saint George",
35 | "Mucuripe",
36 | "Niteroi",
37 | "Sao Francisco do Sul",
38 | "Chatham",
39 | "Clarenville",
40 | "Comox",
41 | "Esquimalt",
42 | "Grand Bank",
43 | "North Sydney",
44 | "Caraquet",
45 | "Chicoutimi",
46 | "Corner Brook",
47 | "Digby",
48 | "Harbour Grace",
49 | "Pictou",
50 | "Shelburne",
51 | "Sorel",
52 | "Springdale",
53 | "Saint-John's",
54 | "Coronel",
55 | "Lota",
56 | "Talcahuano",
57 | "San Antonio",
58 | "Haimen",
59 | "Qinhuangdao",
60 | "Yantian",
61 | "Yingkou",
62 | "Moin",
63 | "Banes",
64 | "Caibarien",
65 | "Isabela de Sagua",
66 | "Nuevitas",
67 | "Famagusta",
68 | "Cuxhaven",
69 | "Eckernforde",
70 | "Nordenham",
71 | "Papenburg",
72 | "Wismar",
73 | "Nyborg",
74 | "Helsingor",
75 | "Odense",
76 | "Frederikshavn",
77 | "Haderslev",
78 | "Horsens",
79 | "Kalundborg",
80 | "Kolding",
81 | "Nakskov",
82 | "Nykobing Falster",
83 | "Randers",
84 | "Rudkobing",
85 | "Svendborg",
86 | "Vejle",
87 | "Skagen",
88 | "Puerto Plata",
89 | "Rio Haina",
90 | "Mostaganem",
91 | "Damietta",
92 | "Safaga",
93 | "Algeciras",
94 | "Aviles",
95 | "Ferrol",
96 | "Huelva",
97 | "Pasajes",
98 | "Rota",
99 | "Cadiz",
100 | "Kotka",
101 | "Veitsiluoto",
102 | "Arcachon",
103 | "Deauville",
104 | "Fecamp",
105 | "La Pallice",
106 | "Saint-Malo",
107 | "Sete",
108 | "Greenock",
109 | "Poole",
110 | "Falmouth",
111 | "Leith",
112 | "Montrose",
113 | "Newport",
114 | "Sunderland",
115 | "Teesport",
116 | "Poti",
117 | "Piraeus",
118 | "Saint George's"
119 | ],
120 | "count": 1000,
121 | "attribute": "name",
122 | "type": "string"
123 | },
124 | {
125 | "values": [
126 | 5,
127 | 10,
128 | 20,
129 | 30,
130 | 50,
131 | 75
132 | ],
133 | "count": 6,
134 | "attribute": "natlscale",
135 | "type": "number",
136 | "min": 5,
137 | "max": 75
138 | },
139 | {
140 | "values": [
141 | 8,
142 | 7,
143 | 6,
144 | 5,
145 | 4,
146 | 3
147 | ],
148 | "count": 6,
149 | "attribute": "scalerank",
150 | "type": "number",
151 | "min": 3,
152 | "max": 8
153 | },
154 | {
155 | "values": [
156 | "www.rocargo.com/SanNicolas.html",
157 | "www.consejoportuario.com.ar",
158 | "",
159 | "www.ab.gov.ag",
160 | "www.fremantleports.com.au",
161 | "www.sydneyports.com.au",
162 | "www.gpcl.com.au",
163 | "www.portofoostende.be",
164 | "www.zeebruggeport.be",
165 | "www.port-burgas.com",
166 | "www.bahrainports.gov.bh",
167 | "www.docasdoceara.com.br",
168 | "www.portosrio.gov.br",
169 | "www.apsfs.sc.gov.br",
170 | "www.cornerbrookport.com",
171 | "www.portofdigby.ns.ca",
172 | "www.pictoumarineterminals.com",
173 | "www.sjpa.com",
174 | "www.puertotalcahuano.cl",
175 | "www.sanantonioport.com",
176 | "www.yantian-port.com",
177 | "www.japdeva.go.cr",
178 | "www.cuxport.de",
179 | "www.stadtwerke-eckernfoerde.de",
180 | "www.hafen-wismar.de",
181 | "www.adp-as.com",
182 | "www.helsingoerhavn.dk",
183 | "www.nyborg.dk/Engelsk/Tourism/NyborgsHarbours",
184 | "www.frederikshavnhavn.dk",
185 | "www.horsenshavn.dk",
186 | "www.portofkalundborg.dk",
187 | "www.koldingport.dk",
188 | "www.guldborgsundhavne.dk",
189 | "www.randershavn.dk",
190 | "www.langelandkommune.dk",
191 | "www.vejleport.dk",
192 | "www.skagenhavn.dk",
193 | "www.apordom.gov.do",
194 | "www.dam-port.com",
195 | "www.mts.gov.eg",
196 | "www.apba.es",
197 | "www.avilesport.com",
198 | "www.apfsc.com",
199 | "www.puertohuelva.com",
200 | "www.puertopasajes.net",
201 | "www.puertocadiz.com",
202 | "www.portofkotka.fi",
203 | "www.arcachon.com",
204 | "www.fecamp.cci.fr",
205 | "www.larochelle.port.fr",
206 | "www.saint-malo.cci.fr",
207 | "www.sete.port.fr",
208 | "www.clydeport.co.uk",
209 | "www.phc.co.uk",
210 | "www.falmouthport.co.uk",
211 | "www.forthports.co.uk",
212 | "www.montroseport.co.uk",
213 | "www.abports.co.uk/custinfo/ports/newport.htm",
214 | "www.portofsunderland.org.uk",
215 | "www.pdports.co.uk",
216 | "www.potiseaport.com",
217 | "www.olp.gr",
218 | "www.medmarinas.com",
219 | "www.grenadacruiseport.com",
220 | "www.guyane.cci.fr",
221 | "www.portauthority-sibenik.hr",
222 | "www.apn.gouv.ht",
223 | "www.kakinadaseaports.in",
224 | "tuticorinport.gov.in",
225 | "www.porto.br.it",
226 | "www.portolaspezia.it",
227 | "www.porto.monfalcone.gorizia.it",
228 | "www.port.ravenna.it",
229 | "www.port.taranto.it",
230 | "www.city.omura.nagasaki.jp",
231 | "www.pref.ishikawa.jp",
232 | "www.city.kawasaki.jp/58/58yuuti/home/etop.html",
233 | "www.kitaqport.or.jp",
234 | "www.port.maizuru.kyoto.jp",
235 | "www.info.city.tsu.mie.jp",
236 | "www.pref.niigata.lg.jp/kowanshinko/1208883684365.html",
237 | "www.city.sasebo.nagasaki.jp",
238 | "www.portofshimizu.com",
239 | "www.city.yokosuka.kanagawa.jp/minato",
240 | "www.slpa.lk",
241 | "www.portofventspils.lv",
242 | "www.bajaport.com",
243 | "www.puertosyucatan.com",
244 | "www.puerto-de-tuxpan.com.mx",
245 | "www.portsworld.com/Ports/kemamanport.htm",
246 | "www.havendenhelder.nl",
247 | "www.groningen-seaports.com",
248 | "www.drammenhavn.no",
249 | "www.larvikhavn.vf.no",
250 | "www.moss-havn.no",
251 | "www.lpc.co.nz",
252 | "portofsohar.com",
253 | "www.ppc.com.pa",
254 | "www.cocatram.org.ni/puertosca/pto_pedregal_panama.html",
255 | "www.enapu.com.pe"
256 | ],
257 | "count": 578,
258 | "attribute": "website",
259 | "type": "string"
260 | }
261 | ],
262 | "geometry": "Point"
263 | }
264 | ]
265 | }
266 |
--------------------------------------------------------------------------------
/test/fixtures/expected/prototype.json:
--------------------------------------------------------------------------------
1 | {
2 | "layerCount": 1,
3 | "layers": [
4 | {
5 | "attributeCount": 2,
6 | "attributes": [
7 | {
8 | "attribute": "constructor",
9 | "count": 2,
10 | "max": 2,
11 | "min": 1,
12 | "type": "number",
13 | "values": [
14 | 1,
15 | 2
16 | ]
17 | },
18 | {
19 | "attribute": "prototype",
20 | "count": 2,
21 | "type": "string",
22 | "values": [
23 | "foo",
24 | null
25 | ]
26 | }
27 | ],
28 | "count": 2,
29 | "geometry": "Point",
30 | "layer": "prototype"
31 | }
32 | ]
33 | }
34 |
--------------------------------------------------------------------------------
/test/fixtures/expected/two-layers.json:
--------------------------------------------------------------------------------
1 | {
2 | "layerCount": 2,
3 | "layers": [
4 | {
5 | "layer": "point-two",
6 | "count": 17,
7 | "attributeCount": 0,
8 | "attributes": [],
9 | "geometry": "Point"
10 | },
11 | {
12 | "layer": "point-one",
13 | "count": 17,
14 | "attributeCount": 0,
15 | "attributes": [],
16 | "geometry": "Point"
17 | }
18 | ]
19 | }
20 |
--------------------------------------------------------------------------------
/test/fixtures/expected/two-thousand-properties-only-two.json:
--------------------------------------------------------------------------------
1 | {
2 | "layerCount": 1,
3 | "layers": [
4 | {
5 | "layer": "two-thousand-properties",
6 | "count": 1,
7 | "attributeCount": 2,
8 | "attributes": [
9 | {
10 | "values": [
11 | "prop-value-1031"
12 | ],
13 | "count": 1,
14 | "attribute": "prop-1031",
15 | "type": "string"
16 | },
17 | {
18 | "values": [
19 | "prop-value-21"
20 | ],
21 | "count": 1,
22 | "attribute": "prop-21",
23 | "type": "string"
24 | }
25 | ],
26 | "geometry": "Point"
27 | }
28 | ]
29 | }
30 |
--------------------------------------------------------------------------------
/test/fixtures/expected/two-thousand-properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "layerCount": 1,
3 | "layers": [
4 | {
5 | "layer": "two-thousand-properties",
6 | "count": 1,
7 | "attributeCount": 1000,
8 | "attributes": [
9 | {
10 | "values": [
11 | "prop-value-0"
12 | ],
13 | "count": 1,
14 | "attribute": "prop-0",
15 | "type": "string"
16 | },
17 | {
18 | "values": [
19 | "prop-value-1"
20 | ],
21 | "count": 1,
22 | "attribute": "prop-1",
23 | "type": "string"
24 | },
25 | {
26 | "values": [
27 | "prop-value-10"
28 | ],
29 | "count": 1,
30 | "attribute": "prop-10",
31 | "type": "string"
32 | },
33 | {
34 | "values": [
35 | "prop-value-100"
36 | ],
37 | "count": 1,
38 | "attribute": "prop-100",
39 | "type": "string"
40 | },
41 | {
42 | "values": [
43 | "prop-value-1000"
44 | ],
45 | "count": 1,
46 | "attribute": "prop-1000",
47 | "type": "string"
48 | },
49 | {
50 | "values": [
51 | "prop-value-1001"
52 | ],
53 | "count": 1,
54 | "attribute": "prop-1001",
55 | "type": "string"
56 | },
57 | {
58 | "values": [
59 | "prop-value-1002"
60 | ],
61 | "count": 1,
62 | "attribute": "prop-1002",
63 | "type": "string"
64 | },
65 | {
66 | "values": [
67 | "prop-value-1003"
68 | ],
69 | "count": 1,
70 | "attribute": "prop-1003",
71 | "type": "string"
72 | },
73 | {
74 | "values": [
75 | "prop-value-1004"
76 | ],
77 | "count": 1,
78 | "attribute": "prop-1004",
79 | "type": "string"
80 | },
81 | {
82 | "values": [
83 | "prop-value-1005"
84 | ],
85 | "count": 1,
86 | "attribute": "prop-1005",
87 | "type": "string"
88 | },
89 | {
90 | "values": [
91 | "prop-value-1006"
92 | ],
93 | "count": 1,
94 | "attribute": "prop-1006",
95 | "type": "string"
96 | },
97 | {
98 | "values": [
99 | "prop-value-1007"
100 | ],
101 | "count": 1,
102 | "attribute": "prop-1007",
103 | "type": "string"
104 | },
105 | {
106 | "values": [
107 | "prop-value-1008"
108 | ],
109 | "count": 1,
110 | "attribute": "prop-1008",
111 | "type": "string"
112 | },
113 | {
114 | "values": [
115 | "prop-value-1009"
116 | ],
117 | "count": 1,
118 | "attribute": "prop-1009",
119 | "type": "string"
120 | },
121 | {
122 | "values": [
123 | "prop-value-101"
124 | ],
125 | "count": 1,
126 | "attribute": "prop-101",
127 | "type": "string"
128 | },
129 | {
130 | "values": [
131 | "prop-value-1010"
132 | ],
133 | "count": 1,
134 | "attribute": "prop-1010",
135 | "type": "string"
136 | },
137 | {
138 | "values": [
139 | "prop-value-1011"
140 | ],
141 | "count": 1,
142 | "attribute": "prop-1011",
143 | "type": "string"
144 | },
145 | {
146 | "values": [
147 | "prop-value-1012"
148 | ],
149 | "count": 1,
150 | "attribute": "prop-1012",
151 | "type": "string"
152 | },
153 | {
154 | "values": [
155 | "prop-value-1013"
156 | ],
157 | "count": 1,
158 | "attribute": "prop-1013",
159 | "type": "string"
160 | },
161 | {
162 | "values": [
163 | "prop-value-1014"
164 | ],
165 | "count": 1,
166 | "attribute": "prop-1014",
167 | "type": "string"
168 | },
169 | {
170 | "values": [
171 | "prop-value-1015"
172 | ],
173 | "count": 1,
174 | "attribute": "prop-1015",
175 | "type": "string"
176 | },
177 | {
178 | "values": [
179 | "prop-value-1016"
180 | ],
181 | "count": 1,
182 | "attribute": "prop-1016",
183 | "type": "string"
184 | },
185 | {
186 | "values": [
187 | "prop-value-1017"
188 | ],
189 | "count": 1,
190 | "attribute": "prop-1017",
191 | "type": "string"
192 | },
193 | {
194 | "values": [
195 | "prop-value-1018"
196 | ],
197 | "count": 1,
198 | "attribute": "prop-1018",
199 | "type": "string"
200 | },
201 | {
202 | "values": [
203 | "prop-value-1019"
204 | ],
205 | "count": 1,
206 | "attribute": "prop-1019",
207 | "type": "string"
208 | },
209 | {
210 | "values": [
211 | "prop-value-102"
212 | ],
213 | "count": 1,
214 | "attribute": "prop-102",
215 | "type": "string"
216 | },
217 | {
218 | "values": [
219 | "prop-value-1020"
220 | ],
221 | "count": 1,
222 | "attribute": "prop-1020",
223 | "type": "string"
224 | },
225 | {
226 | "values": [
227 | "prop-value-1021"
228 | ],
229 | "count": 1,
230 | "attribute": "prop-1021",
231 | "type": "string"
232 | },
233 | {
234 | "values": [
235 | "prop-value-1022"
236 | ],
237 | "count": 1,
238 | "attribute": "prop-1022",
239 | "type": "string"
240 | },
241 | {
242 | "values": [
243 | "prop-value-1023"
244 | ],
245 | "count": 1,
246 | "attribute": "prop-1023",
247 | "type": "string"
248 | },
249 | {
250 | "values": [
251 | "prop-value-1024"
252 | ],
253 | "count": 1,
254 | "attribute": "prop-1024",
255 | "type": "string"
256 | },
257 | {
258 | "values": [
259 | "prop-value-1025"
260 | ],
261 | "count": 1,
262 | "attribute": "prop-1025",
263 | "type": "string"
264 | },
265 | {
266 | "values": [
267 | "prop-value-1026"
268 | ],
269 | "count": 1,
270 | "attribute": "prop-1026",
271 | "type": "string"
272 | },
273 | {
274 | "values": [
275 | "prop-value-1027"
276 | ],
277 | "count": 1,
278 | "attribute": "prop-1027",
279 | "type": "string"
280 | },
281 | {
282 | "values": [
283 | "prop-value-1028"
284 | ],
285 | "count": 1,
286 | "attribute": "prop-1028",
287 | "type": "string"
288 | },
289 | {
290 | "values": [
291 | "prop-value-1029"
292 | ],
293 | "count": 1,
294 | "attribute": "prop-1029",
295 | "type": "string"
296 | },
297 | {
298 | "values": [
299 | "prop-value-103"
300 | ],
301 | "count": 1,
302 | "attribute": "prop-103",
303 | "type": "string"
304 | },
305 | {
306 | "values": [
307 | "prop-value-1030"
308 | ],
309 | "count": 1,
310 | "attribute": "prop-1030",
311 | "type": "string"
312 | },
313 | {
314 | "values": [
315 | "prop-value-1031"
316 | ],
317 | "count": 1,
318 | "attribute": "prop-1031",
319 | "type": "string"
320 | },
321 | {
322 | "values": [
323 | "prop-value-1032"
324 | ],
325 | "count": 1,
326 | "attribute": "prop-1032",
327 | "type": "string"
328 | },
329 | {
330 | "values": [
331 | "prop-value-1033"
332 | ],
333 | "count": 1,
334 | "attribute": "prop-1033",
335 | "type": "string"
336 | },
337 | {
338 | "values": [
339 | "prop-value-1034"
340 | ],
341 | "count": 1,
342 | "attribute": "prop-1034",
343 | "type": "string"
344 | },
345 | {
346 | "values": [
347 | "prop-value-1035"
348 | ],
349 | "count": 1,
350 | "attribute": "prop-1035",
351 | "type": "string"
352 | },
353 | {
354 | "values": [
355 | "prop-value-1036"
356 | ],
357 | "count": 1,
358 | "attribute": "prop-1036",
359 | "type": "string"
360 | },
361 | {
362 | "values": [
363 | "prop-value-1037"
364 | ],
365 | "count": 1,
366 | "attribute": "prop-1037",
367 | "type": "string"
368 | },
369 | {
370 | "values": [
371 | "prop-value-1038"
372 | ],
373 | "count": 1,
374 | "attribute": "prop-1038",
375 | "type": "string"
376 | },
377 | {
378 | "values": [
379 | "prop-value-1039"
380 | ],
381 | "count": 1,
382 | "attribute": "prop-1039",
383 | "type": "string"
384 | },
385 | {
386 | "values": [
387 | "prop-value-104"
388 | ],
389 | "count": 1,
390 | "attribute": "prop-104",
391 | "type": "string"
392 | },
393 | {
394 | "values": [
395 | "prop-value-1040"
396 | ],
397 | "count": 1,
398 | "attribute": "prop-1040",
399 | "type": "string"
400 | },
401 | {
402 | "values": [
403 | "prop-value-1041"
404 | ],
405 | "count": 1,
406 | "attribute": "prop-1041",
407 | "type": "string"
408 | },
409 | {
410 | "values": [
411 | "prop-value-1042"
412 | ],
413 | "count": 1,
414 | "attribute": "prop-1042",
415 | "type": "string"
416 | },
417 | {
418 | "values": [
419 | "prop-value-1043"
420 | ],
421 | "count": 1,
422 | "attribute": "prop-1043",
423 | "type": "string"
424 | },
425 | {
426 | "values": [
427 | "prop-value-1044"
428 | ],
429 | "count": 1,
430 | "attribute": "prop-1044",
431 | "type": "string"
432 | },
433 | {
434 | "values": [
435 | "prop-value-1045"
436 | ],
437 | "count": 1,
438 | "attribute": "prop-1045",
439 | "type": "string"
440 | },
441 | {
442 | "values": [
443 | "prop-value-1046"
444 | ],
445 | "count": 1,
446 | "attribute": "prop-1046",
447 | "type": "string"
448 | },
449 | {
450 | "values": [
451 | "prop-value-1047"
452 | ],
453 | "count": 1,
454 | "attribute": "prop-1047",
455 | "type": "string"
456 | },
457 | {
458 | "values": [
459 | "prop-value-1048"
460 | ],
461 | "count": 1,
462 | "attribute": "prop-1048",
463 | "type": "string"
464 | },
465 | {
466 | "values": [
467 | "prop-value-1049"
468 | ],
469 | "count": 1,
470 | "attribute": "prop-1049",
471 | "type": "string"
472 | },
473 | {
474 | "values": [
475 | "prop-value-105"
476 | ],
477 | "count": 1,
478 | "attribute": "prop-105",
479 | "type": "string"
480 | },
481 | {
482 | "values": [
483 | "prop-value-1050"
484 | ],
485 | "count": 1,
486 | "attribute": "prop-1050",
487 | "type": "string"
488 | },
489 | {
490 | "values": [
491 | "prop-value-1051"
492 | ],
493 | "count": 1,
494 | "attribute": "prop-1051",
495 | "type": "string"
496 | },
497 | {
498 | "values": [
499 | "prop-value-1052"
500 | ],
501 | "count": 1,
502 | "attribute": "prop-1052",
503 | "type": "string"
504 | },
505 | {
506 | "values": [
507 | "prop-value-1053"
508 | ],
509 | "count": 1,
510 | "attribute": "prop-1053",
511 | "type": "string"
512 | },
513 | {
514 | "values": [
515 | "prop-value-1054"
516 | ],
517 | "count": 1,
518 | "attribute": "prop-1054",
519 | "type": "string"
520 | },
521 | {
522 | "values": [
523 | "prop-value-1055"
524 | ],
525 | "count": 1,
526 | "attribute": "prop-1055",
527 | "type": "string"
528 | },
529 | {
530 | "values": [
531 | "prop-value-1056"
532 | ],
533 | "count": 1,
534 | "attribute": "prop-1056",
535 | "type": "string"
536 | },
537 | {
538 | "values": [
539 | "prop-value-1057"
540 | ],
541 | "count": 1,
542 | "attribute": "prop-1057",
543 | "type": "string"
544 | },
545 | {
546 | "values": [
547 | "prop-value-1058"
548 | ],
549 | "count": 1,
550 | "attribute": "prop-1058",
551 | "type": "string"
552 | },
553 | {
554 | "values": [
555 | "prop-value-1059"
556 | ],
557 | "count": 1,
558 | "attribute": "prop-1059",
559 | "type": "string"
560 | },
561 | {
562 | "values": [
563 | "prop-value-106"
564 | ],
565 | "count": 1,
566 | "attribute": "prop-106",
567 | "type": "string"
568 | },
569 | {
570 | "values": [
571 | "prop-value-1060"
572 | ],
573 | "count": 1,
574 | "attribute": "prop-1060",
575 | "type": "string"
576 | },
577 | {
578 | "values": [
579 | "prop-value-1061"
580 | ],
581 | "count": 1,
582 | "attribute": "prop-1061",
583 | "type": "string"
584 | },
585 | {
586 | "values": [
587 | "prop-value-1062"
588 | ],
589 | "count": 1,
590 | "attribute": "prop-1062",
591 | "type": "string"
592 | },
593 | {
594 | "values": [
595 | "prop-value-1063"
596 | ],
597 | "count": 1,
598 | "attribute": "prop-1063",
599 | "type": "string"
600 | },
601 | {
602 | "values": [
603 | "prop-value-1064"
604 | ],
605 | "count": 1,
606 | "attribute": "prop-1064",
607 | "type": "string"
608 | },
609 | {
610 | "values": [
611 | "prop-value-1065"
612 | ],
613 | "count": 1,
614 | "attribute": "prop-1065",
615 | "type": "string"
616 | },
617 | {
618 | "values": [
619 | "prop-value-1066"
620 | ],
621 | "count": 1,
622 | "attribute": "prop-1066",
623 | "type": "string"
624 | },
625 | {
626 | "values": [
627 | "prop-value-1067"
628 | ],
629 | "count": 1,
630 | "attribute": "prop-1067",
631 | "type": "string"
632 | },
633 | {
634 | "values": [
635 | "prop-value-1068"
636 | ],
637 | "count": 1,
638 | "attribute": "prop-1068",
639 | "type": "string"
640 | },
641 | {
642 | "values": [
643 | "prop-value-1069"
644 | ],
645 | "count": 1,
646 | "attribute": "prop-1069",
647 | "type": "string"
648 | },
649 | {
650 | "values": [
651 | "prop-value-107"
652 | ],
653 | "count": 1,
654 | "attribute": "prop-107",
655 | "type": "string"
656 | },
657 | {
658 | "values": [
659 | "prop-value-1070"
660 | ],
661 | "count": 1,
662 | "attribute": "prop-1070",
663 | "type": "string"
664 | },
665 | {
666 | "values": [
667 | "prop-value-1071"
668 | ],
669 | "count": 1,
670 | "attribute": "prop-1071",
671 | "type": "string"
672 | },
673 | {
674 | "values": [
675 | "prop-value-1072"
676 | ],
677 | "count": 1,
678 | "attribute": "prop-1072",
679 | "type": "string"
680 | },
681 | {
682 | "values": [
683 | "prop-value-1073"
684 | ],
685 | "count": 1,
686 | "attribute": "prop-1073",
687 | "type": "string"
688 | },
689 | {
690 | "values": [
691 | "prop-value-1074"
692 | ],
693 | "count": 1,
694 | "attribute": "prop-1074",
695 | "type": "string"
696 | },
697 | {
698 | "values": [
699 | "prop-value-1075"
700 | ],
701 | "count": 1,
702 | "attribute": "prop-1075",
703 | "type": "string"
704 | },
705 | {
706 | "values": [
707 | "prop-value-1076"
708 | ],
709 | "count": 1,
710 | "attribute": "prop-1076",
711 | "type": "string"
712 | },
713 | {
714 | "values": [
715 | "prop-value-1077"
716 | ],
717 | "count": 1,
718 | "attribute": "prop-1077",
719 | "type": "string"
720 | },
721 | {
722 | "values": [
723 | "prop-value-1078"
724 | ],
725 | "count": 1,
726 | "attribute": "prop-1078",
727 | "type": "string"
728 | },
729 | {
730 | "values": [
731 | "prop-value-1079"
732 | ],
733 | "count": 1,
734 | "attribute": "prop-1079",
735 | "type": "string"
736 | },
737 | {
738 | "values": [
739 | "prop-value-108"
740 | ],
741 | "count": 1,
742 | "attribute": "prop-108",
743 | "type": "string"
744 | },
745 | {
746 | "values": [
747 | "prop-value-1080"
748 | ],
749 | "count": 1,
750 | "attribute": "prop-1080",
751 | "type": "string"
752 | },
753 | {
754 | "values": [
755 | "prop-value-1081"
756 | ],
757 | "count": 1,
758 | "attribute": "prop-1081",
759 | "type": "string"
760 | },
761 | {
762 | "values": [
763 | "prop-value-1082"
764 | ],
765 | "count": 1,
766 | "attribute": "prop-1082",
767 | "type": "string"
768 | },
769 | {
770 | "values": [
771 | "prop-value-1083"
772 | ],
773 | "count": 1,
774 | "attribute": "prop-1083",
775 | "type": "string"
776 | },
777 | {
778 | "values": [
779 | "prop-value-1084"
780 | ],
781 | "count": 1,
782 | "attribute": "prop-1084",
783 | "type": "string"
784 | },
785 | {
786 | "values": [
787 | "prop-value-1085"
788 | ],
789 | "count": 1,
790 | "attribute": "prop-1085",
791 | "type": "string"
792 | },
793 | {
794 | "values": [
795 | "prop-value-1086"
796 | ],
797 | "count": 1,
798 | "attribute": "prop-1086",
799 | "type": "string"
800 | },
801 | {
802 | "values": [
803 | "prop-value-1087"
804 | ],
805 | "count": 1,
806 | "attribute": "prop-1087",
807 | "type": "string"
808 | }
809 | ],
810 | "geometry": "Point"
811 | }
812 | ]
813 | }
814 |
--------------------------------------------------------------------------------
/test/fixtures/expected/vectorgzip.json:
--------------------------------------------------------------------------------
1 | {
2 | "layerCount": 1,
3 | "layers": [
4 | {
5 | "layer": "world_merc",
6 | "count": 245,
7 | "attributeCount": 11,
8 | "attributes": [
9 | {
10 | "values": [
11 | 44,
12 | 238174,
13 | 8260,
14 | 2740,
15 | 2820,
16 | 124670,
17 | 20,
18 | 273669,
19 | 768230,
20 | 71,
21 | 43,
22 | 5,
23 | 1001,
24 | 13017,
25 | 2281,
26 | 5120,
27 | 108438,
28 | 65755,
29 | 11062,
30 | 2799,
31 | 845942,
32 | 11063,
33 | 527,
34 | 909351,
35 | 17652,
36 | 6463,
37 | 34150,
38 | 226705,
39 | 2568,
40 | 932743,
41 | 65209,
42 | 4700,
43 | 74880,
44 | 26,
45 | 46540,
46 | 125920,
47 | 223,
48 | 103870,
49 | 5106,
50 | 62298,
51 | 10982,
52 | 403,
53 | 24,
54 | 924,
55 | 4243,
56 | 2318,
57 | 75,
58 | 4838,
59 | 27684,
60 | 99545,
61 | 6889,
62 | 2805,
63 | 4239,
64 | 10100,
65 | 2072,
66 | 100000,
67 | 8245,
68 | 7727,
69 | 8815,
70 | 30459,
71 | 1827,
72 | 1217,
73 | 70,
74 | 366,
75 | 55010,
76 | 1000,
77 | 25767,
78 | 6949,
79 | 22754,
80 | 34,
81 | 41045,
82 | 34895,
83 | 55,
84 | 12890,
85 | 10843,
86 | 24572,
87 | 19685,
88 | 2756,
89 | 11189,
90 | 5592,
91 | 9210,
92 | 10025,
93 | 297319,
94 | 163620,
95 | 2171,
96 | 29411,
97 | 31800,
98 | 43737,
99 | 36450,
100 | 1083,
101 | 8824,
102 | 56914,
103 | 19180,
104 | 12041,
105 | 73,
106 | 9873,
107 | 1782,
108 | 269970,
109 | 23080,
110 | 1023
111 | ],
112 | "count": 204,
113 | "attribute": "AREA",
114 | "type": "number",
115 | "min": 0,
116 | "max": 1638094
117 | },
118 | {
119 | "values": [
120 | "AC",
121 | "AG",
122 | "AJ",
123 | "AL",
124 | "AM",
125 | "AO",
126 | "AQ",
127 | "AR",
128 | "AS",
129 | "BA",
130 | "BB",
131 | "BD",
132 | "BF",
133 | "BG",
134 | "BH",
135 | "BK",
136 | "BL",
137 | "BM",
138 | "BN",
139 | "BP",
140 | "BR",
141 | "BU",
142 | "BX",
143 | "CA",
144 | "CB",
145 | "CE",
146 | "CF",
147 | "CG",
148 | "BY",
149 | "CH",
150 | "AF",
151 | "BT",
152 | "CI",
153 | "CJ",
154 | "CM",
155 | "CD",
156 | "CN",
157 | "CO",
158 | "CS",
159 | "CT",
160 | "CU",
161 | "CV",
162 | "CW",
163 | "CY",
164 | "DA",
165 | "DJ",
166 | "DO",
167 | "DR",
168 | "EC",
169 | "EG",
170 | "EI",
171 | "EK",
172 | "EN",
173 | "ER",
174 | "ES",
175 | "ET",
176 | "AU",
177 | "EZ",
178 | "FG",
179 | "FI",
180 | "FJ",
181 | "FK",
182 | "FM",
183 | "FP",
184 | "FR",
185 | "GA",
186 | "GB",
187 | "GG",
188 | "GH",
189 | "GJ",
190 | "GL",
191 | "GM",
192 | "GQ",
193 | "GR",
194 | "GT",
195 | "GV",
196 | "GY",
197 | "HA",
198 | "HO",
199 | "HR",
200 | "HU",
201 | "IC",
202 | "IN",
203 | "IR",
204 | "IS",
205 | "IT",
206 | "IV",
207 | "IZ",
208 | "JA",
209 | "JM",
210 | "JO",
211 | "KE",
212 | "KG",
213 | "KN",
214 | "KR",
215 | "KS",
216 | "KU",
217 | "KZ",
218 | "LA",
219 | "LE"
220 | ],
221 | "count": 243,
222 | "attribute": "FIPS",
223 | "type": "string"
224 | },
225 | {
226 | "values": [
227 | "AG",
228 | "DZ",
229 | "AZ",
230 | "AL",
231 | "AM",
232 | "AO",
233 | "AS",
234 | "AR",
235 | "AU",
236 | "BH",
237 | "BB",
238 | "BM",
239 | "BS",
240 | "BD",
241 | "BZ",
242 | "BA",
243 | "BO",
244 | "MM",
245 | "BJ",
246 | "SB",
247 | "BR",
248 | "BG",
249 | "BN",
250 | "CA",
251 | "KH",
252 | "LK",
253 | "CG",
254 | "CD",
255 | "BI",
256 | "CN",
257 | "AF",
258 | "BT",
259 | "CL",
260 | "KY",
261 | "CM",
262 | "TD",
263 | "KM",
264 | "CO",
265 | "CR",
266 | "CF",
267 | "CU",
268 | "CV",
269 | "CK",
270 | "CY",
271 | "DK",
272 | "DJ",
273 | "DM",
274 | "DO",
275 | "EC",
276 | "EG",
277 | "IE",
278 | "GQ",
279 | "EE",
280 | "ER",
281 | "SV",
282 | "ET",
283 | "AT",
284 | "CZ",
285 | "GF",
286 | "FI",
287 | "FJ",
288 | "FK",
289 | "FM",
290 | "PF",
291 | "FR",
292 | "GM",
293 | "GA",
294 | "GE",
295 | "GH",
296 | "GD",
297 | "GL",
298 | "DE",
299 | "GU",
300 | "GR",
301 | "GT",
302 | "GN",
303 | "GY",
304 | "HT",
305 | "HN",
306 | "HR",
307 | "HU",
308 | "IS",
309 | "IN",
310 | "IR",
311 | "IL",
312 | "IT",
313 | "CI",
314 | "IQ",
315 | "JP",
316 | "JM",
317 | "JO",
318 | "KE",
319 | "KG",
320 | "KP",
321 | "KI",
322 | "KR",
323 | "KW",
324 | "KZ",
325 | "LA",
326 | "LB"
327 | ],
328 | "count": 245,
329 | "attribute": "ISO2",
330 | "type": "string"
331 | },
332 | {
333 | "values": [
334 | "ATG",
335 | "DZA",
336 | "AZE",
337 | "ALB",
338 | "ARM",
339 | "AGO",
340 | "ASM",
341 | "ARG",
342 | "AUS",
343 | "BHR",
344 | "BRB",
345 | "BMU",
346 | "BHS",
347 | "BGD",
348 | "BLZ",
349 | "BIH",
350 | "BOL",
351 | "MMR",
352 | "BEN",
353 | "SLB",
354 | "BRA",
355 | "BGR",
356 | "BRN",
357 | "CAN",
358 | "KHM",
359 | "LKA",
360 | "COG",
361 | "COD",
362 | "BDI",
363 | "CHN",
364 | "AFG",
365 | "BTN",
366 | "CHL",
367 | "CYM",
368 | "CMR",
369 | "TCD",
370 | "COM",
371 | "COL",
372 | "CRI",
373 | "CAF",
374 | "CUB",
375 | "CPV",
376 | "COK",
377 | "CYP",
378 | "DNK",
379 | "DJI",
380 | "DMA",
381 | "DOM",
382 | "ECU",
383 | "EGY",
384 | "IRL",
385 | "GNQ",
386 | "EST",
387 | "ERI",
388 | "SLV",
389 | "ETH",
390 | "AUT",
391 | "CZE",
392 | "GUF",
393 | "FIN",
394 | "FJI",
395 | "FLK",
396 | "FSM",
397 | "PYF",
398 | "FRA",
399 | "GMB",
400 | "GAB",
401 | "GEO",
402 | "GHA",
403 | "GRD",
404 | "GRL",
405 | "DEU",
406 | "GUM",
407 | "GRC",
408 | "GTM",
409 | "GIN",
410 | "GUY",
411 | "HTI",
412 | "HND",
413 | "HRV",
414 | "HUN",
415 | "ISL",
416 | "IND",
417 | "IRN",
418 | "ISR",
419 | "ITA",
420 | "CIV",
421 | "IRQ",
422 | "JPN",
423 | "JAM",
424 | "JOR",
425 | "KEN",
426 | "KGZ",
427 | "PRK",
428 | "KIR",
429 | "KOR",
430 | "KWT",
431 | "KAZ",
432 | "LAO",
433 | "LBN"
434 | ],
435 | "count": 245,
436 | "attribute": "ISO3",
437 | "type": "string"
438 | },
439 | {
440 | "values": [
441 | 17.078,
442 | 28.163,
443 | 40.43,
444 | 41.143,
445 | 40.534,
446 | -12.296,
447 | -14.318,
448 | -35.377,
449 | -24.973,
450 | 26.019,
451 | 13.153,
452 | 32.336,
453 | 24.628,
454 | 24.218,
455 | 17.219,
456 | 44.169,
457 | -16.715,
458 | 21.718,
459 | 10.541,
460 | -9.611,
461 | -10.772,
462 | 42.761,
463 | 4.468,
464 | 59.081,
465 | 12.714,
466 | 7.612,
467 | -0.055,
468 | -2.876,
469 | -3.356,
470 | 33.42,
471 | 33.677,
472 | 27.415,
473 | -23.389,
474 | 19.314,
475 | 5.133,
476 | 15.361,
477 | -11.758,
478 | 3.9,
479 | 9.971,
480 | 6.571,
481 | 21.297,
482 | 15.071,
483 | -21.219,
484 | 35.043,
485 | 56.058,
486 | 11.9,
487 | 15.475,
488 | 19.015,
489 | -1.385,
490 | 26.494,
491 | 53.177,
492 | 1.607,
493 | 58.674,
494 | 16.045,
495 | 13.736,
496 | 8.626,
497 | 47.683,
498 | 49.743,
499 | 3.924,
500 | 64.504,
501 | -17.819,
502 | -51.665,
503 | 6.883,
504 | -17.626,
505 | 46.565,
506 | 13.453,
507 | -0.591,
508 | 42.176,
509 | 7.96,
510 | 12.118,
511 | 74.719,
512 | 51.11,
513 | 13.385,
514 | 39.666,
515 | 15.256,
516 | 10.439,
517 | 4.792,
518 | 19.142,
519 | 14.819,
520 | 45.723,
521 | 47.07,
522 | 64.764,
523 | 21,
524 | 32.565,
525 | 31.026,
526 | 42.7,
527 | 7.632,
528 | 33.048,
529 | 36.491,
530 | 18.151,
531 | 30.703,
532 | 0.53,
533 | 41.465,
534 | 39.778,
535 | -1.508,
536 | 36.504,
537 | 29.476,
538 | 48.16,
539 | 19.905,
540 | 33.92
541 | ],
542 | "count": 245,
543 | "attribute": "LAT",
544 | "type": "number",
545 | "min": -54.422,
546 | "max": 78.83
547 | },
548 | {
549 | "values": [
550 | -61.783,
551 | 2.632,
552 | 47.395,
553 | 20.068,
554 | 44.563,
555 | 17.544,
556 | -170.73,
557 | -65.167,
558 | 136.189,
559 | 50.562,
560 | -59.559,
561 | -64.709,
562 | -78.014,
563 | 89.941,
564 | -88.602,
565 | 17.786,
566 | -64.671,
567 | 96.041,
568 | 2.469,
569 | 160.109,
570 | -53.089,
571 | 25.231,
572 | 114.591,
573 | -109.433,
574 | 104.564,
575 | 80.704,
576 | 15.986,
577 | 23.654,
578 | 29.887,
579 | 106.514,
580 | 65.216,
581 | 90.429,
582 | -69.433,
583 | -81.198,
584 | 12.277,
585 | 18.665,
586 | 43.337,
587 | -73.076,
588 | -83.946,
589 | 20.483,
590 | -77.781,
591 | -23.634,
592 | -159.782,
593 | 33.219,
594 | 9.264,
595 | 42.516,
596 | -61.356,
597 | -70.729,
598 | -78.497,
599 | 29.872,
600 | -8.152,
601 | 10.488,
602 | 25.793,
603 | 38.219,
604 | -88.866,
605 | 39.616,
606 | 14.912,
607 | 15.338,
608 | -53.241,
609 | 26.272,
610 | 177.974,
611 | -58.694,
612 | 158.235,
613 | -149.462,
614 | 2.55,
615 | -15.386,
616 | 11.797,
617 | 43.518,
618 | -1.207,
619 | -61.678,
620 | -41.391,
621 | 9.851,
622 | 144.707,
623 | 21.766,
624 | -90.398,
625 | -10.942,
626 | -58.974,
627 | -72.278,
628 | -86.863,
629 | 16.693,
630 | 19.134,
631 | -18.48,
632 | 78.5,
633 | 54.301,
634 | 34.851,
635 | 12.8,
636 | -5.556,
637 | 43.772,
638 | 139.068,
639 | -77.32,
640 | 36.319,
641 | 37.858,
642 | 74.555,
643 | 126.451,
644 | 175.036,
645 | 128.103,
646 | 47.376,
647 | 67.301,
648 | 102.471,
649 | 35.888
650 | ],
651 | "count": 244,
652 | "attribute": "LON",
653 | "type": "number",
654 | "min": -178.131,
655 | "max": 179.219
656 | },
657 | {
658 | "values": [
659 | "Antigua and Barbuda",
660 | "Algeria",
661 | "Azerbaijan",
662 | "Albania",
663 | "Armenia",
664 | "Angola",
665 | "American Samoa",
666 | "Argentina",
667 | "Australia",
668 | "Bahrain",
669 | "Barbados",
670 | "Bermuda",
671 | "Bahamas",
672 | "Bangladesh",
673 | "Belize",
674 | "Bosnia and Herzegovina",
675 | "Bolivia",
676 | "Burma",
677 | "Benin",
678 | "Solomon Islands",
679 | "Brazil",
680 | "Bulgaria",
681 | "Brunei Darussalam",
682 | "Canada",
683 | "Cambodia",
684 | "Sri Lanka",
685 | "Congo",
686 | "Democratic Republic of the Congo",
687 | "Burundi",
688 | "China",
689 | "Afghanistan",
690 | "Bhutan",
691 | "Chile",
692 | "Cayman Islands",
693 | "Cameroon",
694 | "Chad",
695 | "Comoros",
696 | "Colombia",
697 | "Costa Rica",
698 | "Central African Republic",
699 | "Cuba",
700 | "Cape Verde",
701 | "Cook Islands",
702 | "Cyprus",
703 | "Denmark",
704 | "Djibouti",
705 | "Dominica",
706 | "Dominican Republic",
707 | "Ecuador",
708 | "Egypt",
709 | "Ireland",
710 | "Equatorial Guinea",
711 | "Estonia",
712 | "Eritrea",
713 | "El Salvador",
714 | "Ethiopia",
715 | "Austria",
716 | "Czech Republic",
717 | "French Guiana",
718 | "Finland",
719 | "Fiji",
720 | "Falkland Islands (Malvinas)",
721 | "Micronesia, Federated States of",
722 | "French Polynesia",
723 | "France",
724 | "Gambia",
725 | "Gabon",
726 | "Georgia",
727 | "Ghana",
728 | "Grenada",
729 | "Greenland",
730 | "Germany",
731 | "Guam",
732 | "Greece",
733 | "Guatemala",
734 | "Guinea",
735 | "Guyana",
736 | "Haiti",
737 | "Honduras",
738 | "Croatia",
739 | "Hungary",
740 | "Iceland",
741 | "India",
742 | "Iran (Islamic Republic of)",
743 | "Israel",
744 | "Italy",
745 | "Cote d'Ivoire",
746 | "Iraq",
747 | "Japan",
748 | "Jamaica",
749 | "Jordan",
750 | "Kenya",
751 | "Kyrgyzstan",
752 | "Korea, Democratic People's Republic of",
753 | "Kiribati",
754 | "Korea, Republic of",
755 | "Kuwait",
756 | "Kazakhstan",
757 | "Lao People's Democratic Republic",
758 | "Lebanon"
759 | ],
760 | "count": 245,
761 | "attribute": "NAME",
762 | "type": "string"
763 | },
764 | {
765 | "values": [
766 | 83039,
767 | 32854159,
768 | 8352021,
769 | 3153731,
770 | 3017661,
771 | 16095214,
772 | 64051,
773 | 38747148,
774 | 20310208,
775 | 724788,
776 | 291933,
777 | 64174,
778 | 323295,
779 | 15328112,
780 | 275546,
781 | 3915238,
782 | 9182015,
783 | 47967266,
784 | 8490301,
785 | 472419,
786 | 186830759,
787 | 7744591,
788 | 373831,
789 | 32270507,
790 | 13955507,
791 | 19120763,
792 | 3609851,
793 | 58740547,
794 | 7858791,
795 | 1312978855,
796 | 25067407,
797 | 637013,
798 | 16295102,
799 | 45591,
800 | 17795149,
801 | 10145609,
802 | 797902,
803 | 4494579,
804 | 4327228,
805 | 4191429,
806 | 11259905,
807 | 506807,
808 | 13984,
809 | 836321,
810 | 5416945,
811 | 804206,
812 | 67827,
813 | 9469601,
814 | 13060993,
815 | 72849793,
816 | 4143294,
817 | 484098,
818 | 1344312,
819 | 4526722,
820 | 6668356,
821 | 78985857,
822 | 8291979,
823 | 10191762,
824 | 192099,
825 | 5246004,
826 | 828046,
827 | 2975,
828 | 110058,
829 | 255632,
830 | 60990544,
831 | 1617029,
832 | 1290693,
833 | 4473409,
834 | 2253501,
835 | 105237,
836 | 57475,
837 | 82652369,
838 | 16857,
839 | 11099737,
840 | 12709564,
841 | 9002656,
842 | 739472,
843 | 9296291,
844 | 683411,
845 | 455149,
846 | 10086387,
847 | 295732,
848 | 1134403141,
849 | 69420607,
850 | 6692037,
851 | 5864636,
852 | 18584701,
853 | 27995984,
854 | 127896740,
855 | 2682469,
856 | 5544066,
857 | 35598952,
858 | 5203547,
859 | 23615611,
860 | 92003,
861 | 47869837,
862 | 2700,
863 | 15210609,
864 | 566391,
865 | 401074
866 | ],
867 | "count": 229,
868 | "attribute": "POP2005",
869 | "type": "number",
870 | "min": 0,
871 | "max": 1312978855
872 | },
873 | {
874 | "values": [
875 | 19,
876 | 2,
877 | 142,
878 | 150,
879 | 9,
880 | 0
881 | ],
882 | "count": 6,
883 | "attribute": "REGION",
884 | "type": "number",
885 | "min": 0,
886 | "max": 150
887 | },
888 | {
889 | "values": [
890 | 29,
891 | 15,
892 | 145,
893 | 39,
894 | 17,
895 | 61,
896 | 5,
897 | 53,
898 | 21,
899 | 34,
900 | 13,
901 | 35,
902 | 11,
903 | 54,
904 | 151,
905 | 14,
906 | 30,
907 | 154,
908 | 155,
909 | 57,
910 | 143,
911 | 0,
912 | 18
913 | ],
914 | "count": 23,
915 | "attribute": "SUBREGION",
916 | "type": "number",
917 | "min": 0,
918 | "max": 155
919 | },
920 | {
921 | "values": [
922 | 28,
923 | 12,
924 | 31,
925 | 8,
926 | 51,
927 | 24,
928 | 16,
929 | 32,
930 | 36,
931 | 48,
932 | 52,
933 | 60,
934 | 44,
935 | 50,
936 | 84,
937 | 70,
938 | 68,
939 | 104,
940 | 204,
941 | 90,
942 | 76,
943 | 100,
944 | 96,
945 | 124,
946 | 116,
947 | 144,
948 | 178,
949 | 180,
950 | 108,
951 | 156,
952 | 4,
953 | 64,
954 | 152,
955 | 136,
956 | 120,
957 | 148,
958 | 174,
959 | 170,
960 | 188,
961 | 140,
962 | 192,
963 | 132,
964 | 184,
965 | 196,
966 | 208,
967 | 262,
968 | 212,
969 | 214,
970 | 218,
971 | 818,
972 | 372,
973 | 226,
974 | 233,
975 | 232,
976 | 222,
977 | 231,
978 | 40,
979 | 203,
980 | 254,
981 | 246,
982 | 242,
983 | 238,
984 | 583,
985 | 258,
986 | 250,
987 | 270,
988 | 266,
989 | 268,
990 | 288,
991 | 308,
992 | 304,
993 | 276,
994 | 316,
995 | 300,
996 | 320,
997 | 324,
998 | 328,
999 | 332,
1000 | 340,
1001 | 191,
1002 | 348,
1003 | 352,
1004 | 356,
1005 | 364,
1006 | 376,
1007 | 380,
1008 | 384,
1009 | 368,
1010 | 392,
1011 | 388,
1012 | 400,
1013 | 404,
1014 | 417,
1015 | 408,
1016 | 296,
1017 | 410,
1018 | 414,
1019 | 398,
1020 | 418,
1021 | 422
1022 | ],
1023 | "count": 245,
1024 | "attribute": "UN",
1025 | "type": "number",
1026 | "min": 4,
1027 | "max": 894
1028 | }
1029 | ],
1030 | "geometry": "Polygon"
1031 | }
1032 | ]
1033 | }
1034 |
--------------------------------------------------------------------------------
/test/fixtures/src/big-features-nozip.mbtiles:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mapbox/mapbox-geostats/38840099078b1b4c7043c247db59b464c770919f/test/fixtures/src/big-features-nozip.mbtiles
--------------------------------------------------------------------------------
/test/fixtures/src/geometry-extravaganza.geojson:
--------------------------------------------------------------------------------
1 | {
2 | "type": "FeatureCollection",
3 | "features": [
4 | {
5 | "type": "Feature",
6 | "properties": {
7 | "foo": "bar"
8 | },
9 | "geometry": {
10 | "type": "Point",
11 | "coordinates": [125.6, 10.1]
12 | }
13 | },
14 | {
15 | "type": "Feature",
16 | "properties": {
17 | "foo": "bar"
18 | },
19 | "geometry": {
20 | "type": "MultiPoint",
21 | "coordinates": [[0, 0], [1, 1]]
22 | }
23 | },
24 | {
25 | "type": "Feature",
26 | "properties": {
27 | "foo": "bar"
28 | },
29 | "geometry": {
30 | "type": "MultiLineString",
31 | "coordinates": [
32 | [[0, 0], [1, 1], [2, 2]],
33 | [[10, 10], [11, 11], [12, 12]]
34 | ]
35 | }
36 | },
37 | {
38 | "type": "Feature",
39 | "properties": {
40 | "bar": 1
41 | },
42 | "geometry": {
43 | "type": "MultiPolygon",
44 | "coordinates": [
45 | [
46 | [
47 | [101.2, 1.2], [101.8, 1.2], [101.8, 1.8], [101.2, 1.8], [101.2, 1.2]
48 | ],
49 | [
50 | [101.2, 1.2], [101.3, 1.2], [101.3, 1.3], [101.2, 1.3], [101.2, 1.2]
51 | ],
52 | [
53 | [101.6, 1.4], [101.7, 1.4], [101.7, 1.5], [101.6, 1.5], [101.6, 1.4]
54 | ],
55 | [
56 | [101.5, 1.6], [101.6, 1.6], [101.6, 1.7], [101.5, 1.7], [101.5, 1.6]
57 | ]
58 | ],
59 | [
60 | [
61 | [100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0]
62 | ],
63 | [
64 | [100.35, 0.35], [100.65, 0.35], [100.65, 0.65], [100.35, 0.65], [100.35, 0.35]
65 | ]
66 | ]
67 | ]
68 | }
69 | },
70 | {
71 | "type": "Feature",
72 | "properties": {
73 | "doodoo": "doo"
74 | },
75 | "geometry": {
76 | "type": "GeometryCollection",
77 | "geometries": [
78 | {
79 | "type": "Point",
80 | "coordinates": [100.0, 0.0]
81 | },
82 | {
83 | "type": "LineString",
84 | "coordinates": [[101.0, 0.0], [102.0, 1.0]]
85 | }
86 | ]
87 | }
88 | },
89 | {
90 | "type": "Feature",
91 | "properties": {
92 | "baz": true
93 | },
94 | "geometry": {
95 | "type": "Point",
96 | "coordinates": [100.6, 4.1]
97 | }
98 | }
99 | ]
100 | }
101 |
--------------------------------------------------------------------------------
/test/fixtures/src/geometry-invalid-types.geojson:
--------------------------------------------------------------------------------
1 | {
2 | "type": "FeatureCollection",
3 | "features": [
4 | {
5 | "type": "Feature",
6 | "properties": {
7 | "foo": "bar"
8 | },
9 | "geometry": {
10 | "type": "doodoodoo",
11 | "coordinates": []
12 | }
13 | },
14 | {
15 | "type": "Feature",
16 | "properties": {
17 | "foo": "bar"
18 | },
19 | "geometry": {
20 | "type": "Point",
21 | "coordinates": [1, 1]
22 | }
23 | },
24 | {
25 | "type": "Feature",
26 | "properties": {
27 | "baz": true
28 | },
29 | "geometry": {
30 | "type": "doodoodoo",
31 | "coordinates": []
32 | }
33 | }
34 | ]
35 | }
36 |
--------------------------------------------------------------------------------
/test/fixtures/src/invalid.csv:
--------------------------------------------------------------------------------
1 | X,foo
2 | 1,bar
3 |
--------------------------------------------------------------------------------
/test/fixtures/src/invalid.geojson:
--------------------------------------------------------------------------------
1 | {
2 | "type": "FeatureCollection",
3 | "features": [
4 | "harumph"
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/test/fixtures/src/invalid.mbtiles:
--------------------------------------------------------------------------------
1 | doo doo doo
2 |
--------------------------------------------------------------------------------
/test/fixtures/src/invalid.shp:
--------------------------------------------------------------------------------
1 | '
2 | 2� doo doo doo
3 |
--------------------------------------------------------------------------------
/test/fixtures/src/invalid.txt:
--------------------------------------------------------------------------------
1 | doo doo doo
2 |
--------------------------------------------------------------------------------
/test/fixtures/src/long-attribute-names.geojson:
--------------------------------------------------------------------------------
1 | {
2 | "type": "FeatureCollection",
3 | "features": [
4 | {
5 | "type": "Feature",
6 | "properties": {
7 | "LoremipsumdolorsitametconsecteturadipisicingelitseddoeiusmodtemporincididuntutlaboreetdoloremagnaaliquaUtenimadminimveniamquisnostrudexercitationullamcolaborisnisiutaliquipexeacommodoconsequatDuisauteiruredolorinreprehenderitinvoluptatevelitessecillumdoloreeufugiatnullapariaturExcepteursintoccaecatcupidatat": 1
8 | },
9 | "geometry": {
10 | "type": "Point",
11 | "coordinates": [1, 1]
12 | }
13 | },
14 | {
15 | "type": "Feature",
16 | "properties": {
17 | "LoremipsumdolorsitametconsecteturadipisicingelitseddoeiusmodtemporincididuntutlaboreetdoloremagnaaliquaUtenimadminimveniamquisnostrudexercitationullamcolaborisnisiutaliquipexeacommodoconsequatDuisauteiruredolorinreprehenderitinvoluptatevelitessecillumdoloreeufugiatnullapariaturExcepteursintoccaecatcupidatat": 2
18 | },
19 | "geometry": {
20 | "type": "Point",
21 | "coordinates": [1, 1]
22 | }
23 | }
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/test/fixtures/src/many-types.geojson:
--------------------------------------------------------------------------------
1 | {
2 | "type": "FeatureCollection",
3 | "features": [
4 | {
5 | "type": "Feature",
6 | "properties": {
7 | "name": "foo",
8 | "power": 6,
9 | "mixed": 7,
10 | "numbers": [1, 2, 3],
11 | "astonishing": true
12 | },
13 | "geometry": {
14 | "type": "Point",
15 | "coordinates": [
16 | 84.72656249999999,
17 | 55.7765730186677
18 | ]
19 | }
20 | },
21 | {
22 | "type": "Feature",
23 | "properties": {
24 | "name": "bar",
25 | "mixed": "7",
26 | "power": 99
27 | },
28 | "geometry": {
29 | "type": "LineString",
30 | "coordinates": [
31 | [
32 | 84.462890625,
33 | 55.32914440840507
34 | ],
35 | [
36 | 86.0009765625,
37 | 55.751849391735284
38 | ],
39 | [
40 | 86.044921875,
41 | 56.04749958329888
42 | ]
43 | ]
44 | }
45 | },
46 | {
47 | "type": "Feature",
48 | "properties": {
49 | "name": "baz"
50 | },
51 | "geometry": {
52 | "type": "Point",
53 | "coordinates": [
54 | 83.49609375,
55 | 56.48676175249086
56 | ]
57 | }
58 | },
59 | {
60 | "type": "Feature",
61 | "properties": {
62 | "name": "haha"
63 | },
64 | "geometry": {
65 | "type": "Point",
66 | "coordinates": [
67 | 85.341796875,
68 | 56.8249328650072
69 | ]
70 | }
71 | },
72 | {
73 | "type": "Feature",
74 | "properties": {
75 | "name": "hoho",
76 | "numbers": [1, 2, 3],
77 | "data": 6
78 | },
79 | "geometry": {
80 | "type": "LineString",
81 | "coordinates": [
82 | [
83 | 85.8251953125,
84 | 55.50374985927514
85 | ],
86 | [
87 | 86.4404296875,
88 | 55.677584411089505
89 | ],
90 | [
91 | 86.7919921875,
92 | 55.65279803318956
93 | ]
94 | ]
95 | }
96 | },
97 | {
98 | "type": "Feature",
99 | "properties": {
100 | "name": "hehe",
101 | "power": 86,
102 | "data": {
103 | "foo": "bar"
104 | },
105 | "onlyNull": null,
106 | "description": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
107 | },
108 | "geometry": {
109 | "type": "Polygon",
110 | "coordinates": [
111 | [
112 | [
113 | 80.947265625,
114 | 57.397624055000456
115 | ],
116 | [
117 | 80.5078125,
118 | 56.145549500679074
119 | ],
120 | [
121 | 81.650390625,
122 | 56.145549500679074
123 | ],
124 | [
125 | 81.650390625,
126 | 56.559482483762245
127 | ],
128 | [
129 | 80.947265625,
130 | 57.397624055000456
131 | ]
132 | ]
133 | ]
134 | }
135 | }
136 | ]
137 | }
138 |
--------------------------------------------------------------------------------
/test/fixtures/src/many-types.mbtiles:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mapbox/mapbox-geostats/38840099078b1b4c7043c247db59b464c770919f/test/fixtures/src/many-types.mbtiles
--------------------------------------------------------------------------------
/test/fixtures/src/no-features.csv:
--------------------------------------------------------------------------------
1 | X,Y
2 |
--------------------------------------------------------------------------------
/test/fixtures/src/no-features.geojson:
--------------------------------------------------------------------------------
1 | {
2 | "type": "FeatureCollection",
3 | "features": []
4 | }
5 |
--------------------------------------------------------------------------------
/test/fixtures/src/no-features.mbtiles:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mapbox/mapbox-geostats/38840099078b1b4c7043c247db59b464c770919f/test/fixtures/src/no-features.mbtiles
--------------------------------------------------------------------------------
/test/fixtures/src/no-features/no-features.dbf:
--------------------------------------------------------------------------------
1 | _ ! W
--------------------------------------------------------------------------------
/test/fixtures/src/no-features/no-features.prj:
--------------------------------------------------------------------------------
1 | GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]]
--------------------------------------------------------------------------------
/test/fixtures/src/no-features/no-features.shp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mapbox/mapbox-geostats/38840099078b1b4c7043c247db59b464c770919f/test/fixtures/src/no-features/no-features.shp
--------------------------------------------------------------------------------
/test/fixtures/src/no-features/no-features.shx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mapbox/mapbox-geostats/38840099078b1b4c7043c247db59b464c770919f/test/fixtures/src/no-features/no-features.shx
--------------------------------------------------------------------------------
/test/fixtures/src/pngs.mbtiles:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mapbox/mapbox-geostats/38840099078b1b4c7043c247db59b464c770919f/test/fixtures/src/pngs.mbtiles
--------------------------------------------------------------------------------
/test/fixtures/src/populations-plus/populations-plus.dbf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mapbox/mapbox-geostats/38840099078b1b4c7043c247db59b464c770919f/test/fixtures/src/populations-plus/populations-plus.dbf
--------------------------------------------------------------------------------
/test/fixtures/src/populations-plus/populations-plus.prj:
--------------------------------------------------------------------------------
1 | GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]]
--------------------------------------------------------------------------------
/test/fixtures/src/populations-plus/populations-plus.qpj:
--------------------------------------------------------------------------------
1 | GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]]
2 |
--------------------------------------------------------------------------------
/test/fixtures/src/populations-plus/populations-plus.shp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mapbox/mapbox-geostats/38840099078b1b4c7043c247db59b464c770919f/test/fixtures/src/populations-plus/populations-plus.shp
--------------------------------------------------------------------------------
/test/fixtures/src/populations-plus/populations-plus.shx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mapbox/mapbox-geostats/38840099078b1b4c7043c247db59b464c770919f/test/fixtures/src/populations-plus/populations-plus.shx
--------------------------------------------------------------------------------
/test/fixtures/src/ports/ports.VERSION.txt:
--------------------------------------------------------------------------------
1 | 2.0.0
--------------------------------------------------------------------------------
/test/fixtures/src/ports/ports.dbf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mapbox/mapbox-geostats/38840099078b1b4c7043c247db59b464c770919f/test/fixtures/src/ports/ports.dbf
--------------------------------------------------------------------------------
/test/fixtures/src/ports/ports.prj:
--------------------------------------------------------------------------------
1 | GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.017453292519943295]]
--------------------------------------------------------------------------------
/test/fixtures/src/ports/ports.shp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mapbox/mapbox-geostats/38840099078b1b4c7043c247db59b464c770919f/test/fixtures/src/ports/ports.shp
--------------------------------------------------------------------------------
/test/fixtures/src/ports/ports.shx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mapbox/mapbox-geostats/38840099078b1b4c7043c247db59b464c770919f/test/fixtures/src/ports/ports.shx
--------------------------------------------------------------------------------
/test/fixtures/src/prototype.geojson:
--------------------------------------------------------------------------------
1 | {
2 | "type": "FeatureCollection",
3 | "features": [
4 | {
5 | "type": "Feature",
6 | "properties": {
7 | "constructor": 2,
8 | "prototype": "foo"
9 | },
10 | "geometry": {
11 | "type": "Point",
12 | "coordinates": [
13 | 84.72656249999999,
14 | 55.7765730186677
15 | ]
16 | }
17 | },
18 | {
19 | "type": "Feature",
20 | "properties": {
21 | "constructor": 1
22 | },
23 | "geometry": {
24 | "type": "LineString",
25 | "coordinates": [
26 | [
27 | 84.462890625,
28 | 55.32914440840507
29 | ],
30 | [
31 | 86.0009765625,
32 | 55.751849391735284
33 | ],
34 | [
35 | 86.044921875,
36 | 56.04749958329888
37 | ]
38 | ]
39 | }
40 | }
41 | ]
42 | }
43 |
--------------------------------------------------------------------------------
/test/fixtures/src/tilestats.mbtiles:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mapbox/mapbox-geostats/38840099078b1b4c7043c247db59b464c770919f/test/fixtures/src/tilestats.mbtiles
--------------------------------------------------------------------------------
/test/fixtures/src/two-layers.mbtiles:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mapbox/mapbox-geostats/38840099078b1b4c7043c247db59b464c770919f/test/fixtures/src/two-layers.mbtiles
--------------------------------------------------------------------------------
/test/fixtures/src/vectorgzip.mbtiles:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mapbox/mapbox-geostats/38840099078b1b4c7043c247db59b464c770919f/test/fixtures/src/vectorgzip.mbtiles
--------------------------------------------------------------------------------
/test/test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const test = require('tap').test;
4 | const _ = require('lodash');
5 | const path = require('path');
6 | const fs = require('fs');
7 | const sloppySort = require('./utils/sloppy-sort');
8 | const geostats = require('../');
9 | const validator = require('../lib/validate-stats');
10 |
11 | function fixturePath(fileName) {
12 | return path.join(__dirname, 'fixtures', fileName);
13 | }
14 |
15 | function getExpected(name) {
16 | return new Promise((resolve, reject) => {
17 | fs.readFile(fixturePath(path.join('expected', name + '.json')), 'utf8', (err, data) => {
18 | if (err) return reject(err);
19 | resolve(JSON.parse(data));
20 | });
21 | });
22 | }
23 |
24 | test('Errors without a file path', t => {
25 | geostats().then(() => {
26 | t.fail('should have errored');
27 | t.end();
28 | }).catch(err => {
29 | t.ok(err, 'errored');
30 | t.end();
31 | });
32 | });
33 |
34 | test('Errors when MBTiles file not found', t => {
35 | geostats(fixturePath('doodoodoo.mbtiles')).then(() => {
36 | t.fail('should have errored');
37 | t.end();
38 | }).catch(err => {
39 | t.ok(err, 'errored');
40 | t.end();
41 | });
42 | });
43 |
44 | test('Errors when Mapnik-interpreted file not found', t => {
45 | geostats(fixturePath('doodoodoo.csv')).then(() => {
46 | t.fail('should have errored');
47 | t.end();
48 | }).catch(err => {
49 | t.ok(err, 'errored');
50 | t.end();
51 | });
52 | });
53 |
54 | test('GeoJSON with many value types, input matching MBTiles', t => {
55 | Promise.all([
56 | geostats(fixturePath('src/many-types.geojson')),
57 | getExpected('many-types-geojson'),
58 | ]).then((output) => {
59 | t.same(sloppySort(output[0]), sloppySort(output[1]), 'expected output');
60 | t.end();
61 | }).catch(t.threw);
62 | });
63 |
64 | // Key difference between the MBTiles and the GeoJSON output now
65 | // is that when Mapnik reads the GeoJSON it inserts `null` values
66 | // in weird places
67 | test('MBTiles with many value types, input matching GeoJSON', t => {
68 | Promise.all([
69 | geostats(fixturePath('src/many-types.mbtiles')),
70 | getExpected('many-types-mbtiles'),
71 | ]).then((output) => {
72 | t.same(sloppySort(output[0]), sloppySort(output[1]), 'expected output');
73 | t.end();
74 | }).catch(t.threw);
75 | });
76 |
77 | test('GeoJSON with over 100 unique attributes and values, input matching Shapefile and CSV',
78 | t => {
79 | Promise.all([
80 | geostats(fixturePath('src/populations-plus.geojson')),
81 | getExpected('populations-plus-geojson'),
82 | ]).then((output) => {
83 | t.same(output[0], output[1], 'expected output');
84 | t.end();
85 | }).catch(t.threw);
86 | }
87 | );
88 |
89 | // Key difference between the Shapefile and the GeoJSON output right now
90 | // seems to be that the shapefile has converted `null` to `""` in
91 | // predominantly string-valued attributes
92 | test('Shapefile with over 100 unique attributes and values, input matching GeoJSON and CSV',
93 | t => {
94 | Promise.all([
95 | geostats(fixturePath('src/populations-plus/populations-plus.shp')),
96 | getExpected('populations-plus-shp'),
97 | ]).then((output) => {
98 | t.same(output[0], output[1], 'expected output');
99 | t.end();
100 | }).catch(t.threw);
101 | }
102 | );
103 |
104 | // Key difference between the CSV and Shapefile and GeoJSON is that it
105 | // includes X and Y attributes (it also converts `null` to `""`, like Shapefile)
106 | test('CSV with over 100 unique attributes and values, input matching GeoJSON and Shapefile',
107 | t => {
108 | Promise.all([
109 | geostats(fixturePath('src/populations-plus.csv')),
110 | getExpected('populations-plus-csv'),
111 | ]).then((output) => {
112 | t.same(output[0], output[1], 'expected output');
113 | t.end();
114 | }).catch(t.threw);
115 | }
116 | );
117 |
118 | test('Shapefile with over 1000 unique values', t => {
119 | Promise.all([
120 | geostats(fixturePath('src/ports/ports.shp')),
121 | getExpected('ports'),
122 | ]).then((output) => {
123 | t.same(output[0], output[1], 'expected output');
124 | t.end();
125 | }).catch(t.threw);
126 | });
127 |
128 | test('MBTiles with gzipped data', t => {
129 | Promise.all([
130 | geostats(fixturePath('src/vectorgzip.mbtiles')),
131 | getExpected('vectorgzip'),
132 | ]).then((output) => {
133 | t.same(sloppySort(output[0]), sloppySort(output[1]), 'expected output');
134 | t.end();
135 | }).catch(t.threw);
136 | });
137 |
138 | test('MBTiles with raster data', t => {
139 | geostats(fixturePath('src/pngs.mbtiles')).then((output) => {
140 | t.same(output, { layerCount: 0, layers: [] }, 'empty output');
141 | t.end();
142 | }).catch(t.threw);
143 | });
144 |
145 | test('GeoJSON with over 1000 unique attributes', t => {
146 | Promise.all([
147 | geostats(fixturePath('src/two-thousand-properties.geojson')),
148 | getExpected('two-thousand-properties'),
149 | ]).then((output) => {
150 | const actual = sloppySort(output[0]);
151 | t.same(actual, sloppySort(output[1]), 'expected output');
152 | t.equal(actual.layers[0].attributeCount, 1000, 'attributeCount stops at 1000');
153 | t.equal(actual.layers[0].attributes.length, 100, 'attribute details stop at 100');
154 | t.end();
155 | }).catch(t.threw);
156 | });
157 |
158 | test('GeoJSON with many geometry types', t => {
159 | Promise.all([
160 | geostats(fixturePath('src/geometry-extravaganza.geojson')),
161 | getExpected('geometry-extravaganza'),
162 | ]).then((output) => {
163 | t.same(sloppySort(output[0]), sloppySort(output[1]), 'expected output');
164 | t.end();
165 | }).catch(t.threw);
166 | });
167 |
168 | test('MBTiles with no features', t => {
169 | geostats(fixturePath('src/no-features.mbtiles')).then((output) => {
170 | t.same(output, { layerCount: 0, layers: [] }, 'empty output');
171 | t.end();
172 | }).catch(t.threw);
173 | });
174 |
175 | test('Shapefile with no features', t => {
176 | Promise.all([
177 | geostats(fixturePath('src/no-features/no-features.shp')),
178 | getExpected('no-features'),
179 | ]).then((output) => {
180 | t.same(sloppySort(output[0]), sloppySort(output[1]), 'expected output');
181 | t.end();
182 | }).catch(t.threw);
183 | });
184 |
185 | test('CSV with no features', t => {
186 | Promise.all([
187 | geostats(fixturePath('src/no-features.csv')),
188 | getExpected('no-features'),
189 | ]).then((output) => {
190 | t.same(sloppySort(output[0]), sloppySort(output[1]), 'expected output');
191 | t.end();
192 | }).catch(t.threw);
193 | });
194 |
195 | // Currently this is blocked by a bug in node-mapnik
196 | // test('GeoJSON with no features still outputs', t => {
197 | // geostats(fixturePath('src/no-features.geojson')).then((output) => {
198 | // var expected = {
199 | // layerCount: 1,
200 | // layers: [
201 | // {
202 | // attributeCount: 0,
203 | // attributes: [],
204 | // count: 0,
205 | // layer: 'no-features'
206 | // }
207 | // ]
208 | // };
209 | // t.same(output, expected, 'expected output');
210 | // t.end();
211 | // }).catch(t.threw);
212 | // });
213 |
214 | test('invalid GeoJSON', t => {
215 | geostats(fixturePath('src/invalid.geojson')).then(() => {
216 | t.fail('should have errored');
217 | t.end();
218 | }).catch(err => {
219 | t.ok(err, 'errored');
220 | t.end();
221 | });
222 | });
223 |
224 | test('GeoJSON skips invalid geometry types', t => {
225 | Promise.all([
226 | geostats(fixturePath('src/geometry-invalid-types.geojson')),
227 | getExpected('geojson-invalid-geometry-types'),
228 | ]).then((output) => {
229 | t.same(output[0], output[1], 'expected geostats');
230 | t.end();
231 | }).catch((err) => {
232 | t.fail(err);
233 | });
234 | });
235 |
236 | test('invalid Shapefile', t => {
237 | geostats(fixturePath('src/invalid.shp')).then(() => {
238 | t.fail('should have errored');
239 | t.end();
240 | }).catch(err => {
241 | t.ok(err, 'errored');
242 | t.end();
243 | });
244 | });
245 |
246 | test('invalid CSV', t => {
247 | geostats(fixturePath('src/invalid.csv')).then(() => {
248 | t.fail('should have errored');
249 | t.end();
250 | }).catch(err => {
251 | t.ok(err, 'errored');
252 | t.end();
253 | });
254 | });
255 |
256 | test('invalid MBTiles', t => {
257 | geostats(fixturePath('src/invalid.mbtiles')).then(() => {
258 | t.fail('should have errored');
259 | t.end();
260 | }).catch(err => {
261 | t.ok(err, 'errored');
262 | t.end();
263 | });
264 | });
265 |
266 | test('invalid file format', t => {
267 | geostats(fixturePath('src/invalid.txt')).then(() => {
268 | t.fail('should have errored');
269 | t.end();
270 | }).catch(err => {
271 | t.ok(err, 'errored');
272 | t.end();
273 | });
274 | });
275 |
276 | test('Shapefile with specified attribute with over 1000 values', t => {
277 | Promise.all([
278 | geostats(fixturePath('src/ports/ports.shp'), {
279 | attributes: ['name'],
280 | }),
281 | getExpected('ports-only-name'),
282 | ]).then((output) => {
283 | const actual = sloppySort(output[0]);
284 | t.same(actual, sloppySort(output[1]), 'expected output');
285 | const nameAttribute = _.find(actual.layers[0].attributes, attribute => {
286 | return attribute.attribute === 'name';
287 | });
288 | t.equal(nameAttribute.count, 1042, 'value count did not stop at 1000');
289 | t.equal(nameAttribute.values.length, 1042, 'value details did not stop at 100');
290 | t.end();
291 | }).catch(t.threw);
292 | });
293 |
294 | test('GeoJSON with specified attributes', t => {
295 | Promise.all([
296 | geostats(fixturePath('src/two-thousand-properties.geojson'), {
297 | attributes: ['prop-21', 'prop-1031'],
298 | }),
299 | getExpected('two-thousand-properties-only-two'),
300 | ]).then((output) => {
301 | t.same(sloppySort(output[0]), sloppySort(output[1]), 'expected output');
302 | t.end();
303 | }).catch(t.threw);
304 | });
305 |
306 | test('GeoJSON with over 10000 unique values and no specified attributes', t => {
307 | Promise.all([
308 | geostats(fixturePath('src/myriad-values.geojson')),
309 | getExpected('myriad-values-all-attrs'),
310 | ]).then((output) => {
311 | const actual = sloppySort(output[1]);
312 | t.same(sloppySort(output[0]), actual, 'expected output');
313 | t.ok(actual.layers[0].attributes.every(attribute => {
314 | return attribute.count === 1000;
315 | }), 'value counts stop at 1000');
316 | t.ok(actual.layers[0].attributes.every(attribute => {
317 | return attribute.values.length === 100;
318 | }), 'value details stop at 100');
319 | t.end();
320 | }).catch(t.threw);
321 | });
322 |
323 | test('GeoJSON with over 10000 unique values and one specified attribute', t => {
324 | Promise.all([
325 | geostats(fixturePath('src/myriad-values.geojson'), {
326 | attributes: ['prop-3'],
327 | }),
328 | getExpected('myriad-values-1-attr'),
329 | ]).then((output) => {
330 | const actual = sloppySort(output[1]);
331 | t.same(sloppySort(output[0]), actual, 'expected output');
332 | t.ok(actual.layers[0].attributes.every(attribute => {
333 | return attribute.count === 10010;
334 | }), 'value count does not stop yet');
335 | t.ok(actual.layers[0].attributes.every(attribute => {
336 | return attribute.values.length === 10000;
337 | }), 'value details stop at 10000');
338 | t.end();
339 | }).catch(t.threw);
340 | });
341 |
342 | test('GeoJSON with over 10000 unique values and five specified attribute', t => {
343 | Promise.all([
344 | geostats(fixturePath('src/myriad-values.geojson'), {
345 | attributes: ['prop-1', 'prop-2', 'prop-3', 'prop-4', 'prop-5'],
346 | }),
347 | getExpected('myriad-values-5-attrs'),
348 | ]).then((output) => {
349 | const actual = sloppySort(output[1]);
350 | t.same(sloppySort(output[0]), actual, 'expected output');
351 | t.ok(actual.layers[0].attributes.every(attribute => {
352 | return attribute.count === 10010;
353 | }), 'value counts does not stop yet');
354 | t.ok(actual.layers[0].attributes.every(attribute => {
355 | return attribute.values.length === 2000;
356 | }), 'value details stop at 2000');
357 | t.end();
358 | }).catch(t.threw);
359 | });
360 |
361 | test('Trying to report on more than 100 attributes', t => {
362 | t.throws(() => {
363 | geostats(fixturePath('src/populations-plus.geojson'), {
364 | attributes: ['attr-0', 'attr-1', 'attr-2', 'attr-3', 'attr-4', 'attr-5',
365 | 'attr-6', 'attr-7', 'attr-8', 'attr-9', 'attr-10', 'attr-11', 'attr-12',
366 | 'attr-13', 'attr-14', 'attr-15', 'attr-16', 'attr-17', 'attr-18', 'attr-19',
367 | 'attr-20', 'attr-21', 'attr-22', 'attr-23', 'attr-24', 'attr-25', 'attr-26',
368 | 'attr-27', 'attr-28', 'attr-29', 'attr-30', 'attr-31', 'attr-32', 'attr-33',
369 | 'attr-34', 'attr-35', 'attr-36', 'attr-37', 'attr-38', 'attr-39', 'attr-40',
370 | 'attr-41', 'attr-42', 'attr-43', 'attr-44', 'attr-45', 'attr-46', 'attr-47',
371 | 'attr-48', 'attr-49', 'attr-50', 'attr-51', 'attr-52', 'attr-53', 'attr-54',
372 | 'attr-55', 'attr-56', 'attr-57', 'attr-58', 'attr-59', 'attr-60', 'attr-61',
373 | 'attr-62', 'attr-63', 'attr-64', 'attr-65', 'attr-66', 'attr-67', 'attr-68',
374 | 'attr-69', 'attr-70', 'attr-71', 'attr-72', 'attr-73', 'attr-74', 'attr-75',
375 | 'attr-76', 'attr-77', 'attr-78', 'attr-79', 'attr-80', 'attr-81', 'attr-82',
376 | 'attr-83', 'attr-84', 'attr-85', 'attr-86', 'attr-87', 'attr-88', 'attr-89',
377 | 'attr-90', 'attr-91', 'attr-92', 'attr-93', 'attr-94', 'attr-95', 'attr-96',
378 | 'attr-97', 'attr-98', 'attr-99', 'attr-100', 'attr-101', 'attr-102',
379 | 'attr-103', 'attr-104', 'attr-105', 'attr-106', 'attr-107', 'attr-108',
380 | 'attr-109'],
381 | });
382 | }, 'throws');
383 | t.end();
384 | });
385 |
386 | test('GeoJSON with prototype attribute', t => {
387 | Promise.all([
388 | geostats(fixturePath('src/prototype.geojson')),
389 | getExpected('prototype'),
390 | ]).then((output) => {
391 | t.same(sloppySort(output[0]), sloppySort(output[1]), 'expected output');
392 | t.end();
393 | }).catch(t.threw);
394 | });
395 |
396 | test('truncate attribute names', t => {
397 | Promise.all([
398 | geostats(fixturePath('src/long-attribute-names.geojson')),
399 | getExpected('long-attribute-names'),
400 | ]).then((output) => {
401 | t.same(sloppySort(output[0]), sloppySort(output[1]), 'expected output');
402 | t.end();
403 | }).catch(t.threw);
404 | });
405 |
406 | test('MBTiles with two layers', t => {
407 | Promise.all([
408 | geostats(fixturePath('src/two-layers.mbtiles')),
409 | getExpected('two-layers'),
410 | ]).then((output) => {
411 | t.same(sloppySort(output[0]), sloppySort(output[1]), 'expected output');
412 | t.end();
413 | }).catch(t.threw);
414 | });
415 |
416 | test('MBTiles with tilestats metadata table returns as expected', t => {
417 | Promise.all([
418 | geostats(fixturePath('src/tilestats.mbtiles')),
419 | getExpected('tilestats'),
420 | ]).then((output) => {
421 | t.same(sloppySort(output[0]), sloppySort(output[1]), 'expected output');
422 | t.end();
423 | }).catch(t.threw);
424 | });
425 |
426 | test('[validator] valid stats object', t => {
427 | const stats = {
428 | layerCount: 1,
429 | layers: [
430 | {
431 | layer: 'test-layer',
432 | count: 3,
433 | geometry: 'Point',
434 | attributeCount: 1,
435 | attributes: [
436 | {
437 | attribute: 'test-attribute',
438 | count: 3,
439 | type: 'number',
440 | values: [2, 5, 19],
441 | min: 2,
442 | max: 19,
443 | },
444 | ],
445 | },
446 | ],
447 | };
448 |
449 | t.ok(validator(stats));
450 | t.end();
451 | });
452 |
453 | test('[validator] invalid stats object - no layers', t => {
454 | const stats = {
455 | layerCount: 1,
456 | };
457 |
458 | const results = validator(stats);
459 | t.equal(results.length, 1, 'only one error');
460 | t.equal(results[0], 'instance requires property "layers"', 'expected error message');
461 | t.end();
462 | });
463 |
464 | test('[validator] invalid layer object - no layer name', t => {
465 | const stats = {
466 | layerCount: 1,
467 | layers: [
468 | {
469 | count: 3,
470 | geometry: 'Point',
471 | attributeCount: 1,
472 | attributes: [
473 | {
474 | attribute: 'test-attribute',
475 | count: 3,
476 | type: 'number',
477 | values: [2, 5, 19],
478 | min: 2,
479 | max: 19,
480 | },
481 | ],
482 | },
483 | ],
484 | };
485 |
486 | const results = validator(stats);
487 | t.equal(results.length, 1, 'only one error');
488 | t.equal(results[0], 'instance.layers[0] requires property "layer"', 'expected error message');
489 | t.end();
490 | });
491 |
492 | test('[validator] invalid layer object - no layer name', t => {
493 | const stats = {
494 | layerCount: 'wrong type',
495 | layers: [
496 | {
497 | geometry: 'Point',
498 | attributes: [
499 | {
500 | attribute: 'test-attribute',
501 | type: 'number',
502 | min: 2,
503 | max: 19,
504 | },
505 | ],
506 | },
507 | ],
508 | };
509 |
510 | const expected = sloppySort([
511 | 'instance.layerCount is not of a type(s) number',
512 | 'instance.layers[0] requires property "count"',
513 | 'instance.layers[0].attributes[0] requires property "values"',
514 | 'instance.layers[0] requires property "layer"',
515 | 'instance.layers[0].attributes[0] requires property "count"',
516 | 'instance.layers[0] requires property "attributeCount"',
517 | ]);
518 |
519 | const results = validator(stats);
520 | t.same(sloppySort(results), expected, 'expect lots of errors');
521 | t.end();
522 | });
523 |
524 | test('[validator] invalid attributes contain mulitple types', t => {
525 | const stats = {
526 | layerCount: 1,
527 | layers: [
528 | {
529 | layer: 'test-layer',
530 | count: 3,
531 | geometry: 'Point',
532 | attributeCount: 1,
533 | attributes: [
534 | {
535 | attribute: 'test-attribute',
536 | count: 3,
537 | type: 'number',
538 | values: [2, 'five', null],
539 | min: 2,
540 | max: 19,
541 | },
542 | ],
543 | },
544 | ],
545 | };
546 |
547 | const results = validator(stats);
548 | t.equal(results.length, 1, 'only one error');
549 | t.equal(results[0], 'instance.layers[0].attributes[0].values is not any of [subschema 0],[subschema 1],[subschema 2],[subschema 3]', 'expected error message');
550 | t.end();
551 | });
552 |
--------------------------------------------------------------------------------
/test/utils/sloppy-sort.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const _ = require('lodash');
4 |
5 | // The purpose of the sloppy sort is only to ensure some
6 | // deterministic order in this module's JSON output.
7 | // Because of async operations in some places (esp. tile-analyze),
8 | // items in arrays (e.g. attributes, values) might not always
9 | // appear in the same the same order, but should always
10 | // have the same items.
11 |
12 | function sloppySortComparator(first, second) {
13 | const isFirstObject = _.isPlainObject(first);
14 | const isSecondObject = _.isPlainObject(second);
15 | if (!isFirstObject && isSecondObject) return -1;
16 | if (isFirstObject && !isSecondObject) return 1;
17 | if (isFirstObject && isSecondObject) {
18 | if (first.attribute < second.attribute) return -1;
19 | if (first.attribute > second.attribute) return 1;
20 | return 0;
21 | }
22 |
23 | const isFirstNumber = _.isNumber(first);
24 | const isSecondNumber = _.isNumber(second);
25 | if (!isFirstNumber && isSecondNumber) return -1;
26 | if (isFirstNumber && !isSecondNumber) return 1;
27 | if (isFirstNumber && isSecondNumber) {
28 | if (first < second) return -1;
29 | if (first > second) return 1;
30 | return 0;
31 | }
32 |
33 | const isFirstNull = _.isNull(first);
34 | const isSecondNull = _.isNull(second);
35 | if (!isFirstNull && isSecondNull) return -1;
36 | if (isFirstNull && !isSecondNull) return 1;
37 | if (isFirstNull && isSecondNull) return 0;
38 |
39 | if (String(first) < String(second)) return -1;
40 | if (String(first) > String(second)) return 1;
41 | return 0;
42 | }
43 |
44 | function sloppySortArray(arr) {
45 | return arr.map(sloppySort).sort(sloppySortComparator);
46 | }
47 |
48 | function sloppySortObject(obj) {
49 | return _.mapValues(obj, sloppySort);
50 | }
51 |
52 | function sloppySort(item) {
53 | if (_.isPlainObject(item)) return sloppySortObject(item);
54 | if (_.isArray(item)) return sloppySortArray(item);
55 | return item;
56 | }
57 |
58 | module.exports = sloppySort;
59 |
--------------------------------------------------------------------------------