Commit 8ad6aa52 authored by Adrien Pavie's avatar Adrien Pavie
Browse files

Add XLSX output format and changelog

parent 3a5c20f7
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
## Next version (to be released)
### Added
- Support of XLSX format
- Changelog file
### Fixed
- Links and some install commands of Readme
## 0.1.0 - 2019-12-30
### Added
- Initial release (UI, backend, various themes)
......@@ -7,7 +7,7 @@ const fs = require('fs');
const util = require('util');
const exec = util.promisify(require('child_process').exec);
const CONFIG = require('../../config.json');
const FORMAT_TO_EXT = { "csv": "csv", "shapefile": "shp.zip", "geojson": "geojson" };
const FORMAT_TO_EXT = { "csv": "csv", "shapefile": "shp.zip", "geojson": "geojson", "xlsx": "xlsx" };
const GEOM_TO_COND = { "point": "ST_GeometryType(t.way) = 'ST_Point'", "line": "ST_GeometryType(t.way) = 'ST_LineString'", "polygon": "ST_GeometryType(t.way) IN ('ST_Polygon', 'ST_MultiPolygon')" };
// Create pool of connections
......@@ -190,8 +190,19 @@ function getThemeData(theme, boundary, options) {
}
const geomCond = geomConds.sort((a, b) => a.sort - b.sort).map(g => g.cond).join(" AND ");
// Create geometry column
let geom = options.aspoint ? "t.centroid AS geom" : "t.way AS geom";
if(format === "csv" && theme.skipGeomCSV) { geom = ""; }
else if(format === "xlsx") {
if(theme.skipGeomCSV) { geom = ""; }
else {
geom = options.aspoint ?
"ST_X(ST_Transform(t.centroid, 4326)) AS x, ST_Y(ST_Transform(t.centroid, 4326)) AS y"
: "ST_AsText(ST_Transform(t.way, 4326)) AS wkt";
}
}
// Create SQL request
const geom = format === "csv" && theme.skipGeomCSV ? "" : (options.aspoint ? "t.centroid AS geom" : "t.way AS geom");
let request = theme.geomtypes.map(g => (
theme.sql
.replace(/<TABLE>/g, `boundary b, planet_osm_${g} t${hasAdm8 ? ", boundary b2" : ""}`)
......@@ -221,7 +232,7 @@ function getThemeData(theme, boundary, options) {
const sql2bash = txt => txt.replace(/"/g, '\\"').replace(/\n/g, " ");
// Common conditional geometry system for GeoJSON/CSV and Shapefile as point
if(["geojson", "csv"].includes(format) || (format === "shapefile" && options.aspoint)) {
if(["geojson", "csv", "xlsx"].includes(format) || (format === "shapefile" && options.aspoint)) {
request = request
.replace(/<GEOMCOND>/g, geomCond)
.replace(/<GEOMCONDPT>/g, geomCond.replace(/t\.centroid/g, "t.way"));
......@@ -235,6 +246,10 @@ function getThemeData(theme, boundary, options) {
else if(format === "csv") {
bashCommands.push(`ogr2ogr -f "CSV" ${outFile} PG:"host=${CONFIG.PG_HOST} user=${CONFIG.PG_USER} dbname=${CONFIG.PG_DB_CLEAN} port=${CONFIG.PG_PORT}" -sql "${sql2bash(request)}" -t_srs EPSG:4326 -lco GEOMETRY=${options.aspoint ? "AS_XY" : "AS_WKT"} -lco SEPARATOR=SEMICOLON`);
}
// XLS
else if(format === "xlsx") {
bashCommands.push(`ogr2ogr -f "XLSX" ${outFile} PG:"host=${CONFIG.PG_HOST} user=${CONFIG.PG_USER} dbname=${CONFIG.PG_DB_CLEAN} port=${CONFIG.PG_PORT}" -sql "${sql2bash(request)}"`);
}
// Shapefile
else if(format === "shapefile") {
bashCommands.push(`mkdir -p ${baseFilePath}`);
......
......@@ -9,8 +9,8 @@ const compression = require("compression");
const fs = require('fs');
const db = require('./db');
const themes = require('./themes');
const FORMAT_TO_MIME = { "csv": "text/csv", "shapefile": "application/zip", "geojson": "application/vnd.geo+json", "zip": "application/zip" };
const FORMAT_TO_EXT = { "csv": "csv", "shapefile": "shp.zip", "geojson": "geojson", "zip": "zip" };
const FORMAT_TO_MIME = { "csv": "text/csv", "shapefile": "application/zip", "geojson": "application/vnd.geo+json", "zip": "application/zip", "xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" };
const FORMAT_TO_EXT = { "csv": "csv", "shapefile": "shp.zip", "geojson": "geojson", "zip": "zip", "xlsx": "xlsx" };
// Init API
const app = express();
......@@ -66,7 +66,7 @@ app.use('/doc', express.static(__dirname+'/../doc'));
*
* @apiParam {String} themeId Theme of data to extract (one in /themes list)
* @apiParam {String} boundaryId Boundary of area where data must be extracted (one in /boundaries list)
* @apiParam {String} [format=csv] Output file format (csv, geojson, shapefile)
* @apiParam {String} [format=csv] Output file format (csv, geojson, shapefile, xlsx)
* @apiParam {Number} [radius] Filter by radius around boundary centroid (in kilometers) instead of boundary polygon (max 50)
* @apiParam {Boolean} [aspoint=false] Geometry will always be point if set to true (center of complete geometry)
* @apiParam {Boolean} [metadata=false] Add a metadata file for the generated dataset, in <a href="https://scdl.opendatafrance.net/docs/schemas/catalogue.html">SCDL format</a>
......@@ -78,7 +78,7 @@ app.use('/doc', express.static(__dirname+'/../doc'));
*/
app.get("/data/:themeId/:boundaryId", (req, res) => {
// Check format
const formats = [ "csv", "geojson", "shapefile" ];
const formats = Object.keys(FORMAT_TO_EXT);
const format = req.query.format || "csv";
if(!formats.includes(format)) {
return res.status(400).send("format parameter is invalid (should be "+formats.join(", ")+")");
......
......@@ -67,6 +67,7 @@
<option value="csv" selected>Tableur CSV</option>
<option value="geojson">GeoJSON</option>
<option value="shapefile">ESRI Shapefile</option>
<option value="xlsx">Tableur Excel (XLSX)</option>
</select>
</div>
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment