diff --git a/package.json b/package.json index 64385d0f..acb6879d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@macrostrat/api-v2", - "version": "2.1.6", + "version": "2.1.7", "description": "An API for stratigraphic and geological information (Version 2).", "main": "server.js", "repository": { diff --git a/v2/CHANGELOG.md b/v2/CHANGELOG.md index ee6d008a..4837a080 100644 --- a/v2/CHANGELOG.md +++ b/v2/CHANGELOG.md @@ -1,5 +1,22 @@ # Macrostrat API v2 Changelog +## [2.1.7] - 2025-11-19 + +- Allow multiple `status_code` values in `/columns` route +- Add `status_code` filter option to + + +## [2.1.5] - 2025-11-07 + +- Add `t_units` and `t_sections` summary parameters to short `/columns` output + +## [2.x.x] Series - 2024 to 2025 + +Moved the entire API to be based on PostgreSQL instead of a mix of PostgreSQL +and MariaDB. + +-------- + ## tl;dr - Added `?sample` to every route (except `/mobile`), which returns 5 records. diff --git a/v2/columns.ts b/v2/columns.ts index 28a3a64a..fe13c2cc 100644 --- a/v2/columns.ts +++ b/v2/columns.ts @@ -148,27 +148,32 @@ module.exports = function (req, res, next, callback) { } var geo = ""; - var params = [ - Object.keys(new_cols).map(function (d) { - return parseInt(d); - }), - ]; + + const col_ids = Object.keys(new_cols).map(function (d) { + return parseInt(d); + }); + + let params = { + col_ids, + }; var limit = "sample" in req.query ? " LIMIT 5" : ""; var groupBy = ""; - var orderby = ""; + let orderBy = ""; if (req.query.status_code) { - params.push(decodeURI(req.query.status_code)); + params["status_code"] = larkin.parseMultipleStrings( + decodeURI(req.query.status_code), + ); } else { - params.push("active"); + params["status_code"] = ["active"]; } if (req.query.format && api.acceptedFormats.geo[req.query.format]) { if (req.query.shape) { geo = - ", ST_AsGeoJSON(ST_Intersection(col_areas.col_area, ST_MakeValid($3))) geojson"; - params.push(req.query.shape); + ", ST_AsGeoJSON(ST_Intersection(col_areas.col_area, ST_MakeValid(:shape))) geojson"; + params["shape"] = req.query.shape; } else { geo = ", ST_AsGeoJSON(col_areas.col_area) geojson"; } @@ -176,20 +181,17 @@ module.exports = function (req, res, next, callback) { } if (req.query.lat && req.query.lng && req.query.adjacents) { - orderby = - "ORDER BY ST_Distance(ST_SetSRID(col_areas.col_area, 4326), ST_GeometryFromText($3, 4326))"; - params.push( - "POINT(" + - larkin.normalizeLng(req.query.lng) + - " " + - req.query.lat + - ")", - ); + orderBy = + "ORDER BY ST_Distance(ST_SetSRID(col_areas.col_area, 4326), ST_GeometryFromText(ST_MakePoint(:lng, :lat), 4326))"; + params["lat"] = req.query.lat; + params["lng"] = larkin.normalizeLng(req.query.lng); groupBy = ", col_areas.col_area"; } else if (req.query.col_id && req.query.adjacents) { - orderby = - "ORDER BY ST_Distance(ST_Centroid(col_areas.col_area), (SELECT ST_Centroid(col_area) FROM macrostrat.col_areas WHERE col_id = $3))"; - params.push(req.query.col_id); + orderBy = `ORDER BY ST_Distance( + ST_Centroid(col_areas.col_area), + (SELECT ST_Centroid(col_area) FROM macrostrat.col_areas WHERE col_id = :col_id) + )`; + params["col_id"] = req.query.col_id; groupBy = ", col_areas.col_area"; } @@ -215,10 +217,10 @@ module.exports = function (req, res, next, callback) { LEFT JOIN macrostrat.col_areas on col_areas.col_id = cols.id LEFT JOIN macrostrat.col_groups ON col_groups.id = cols.col_group_id LEFT JOIN macrostrat.col_refs ON cols.id = col_refs.col_id - WHERE cols.status_code = $2 - AND cols.id = ANY($1) + WHERE cols.status_code = ANY(:status_code) + AND cols.id = ANY(:col_ids) GROUP BY col_areas.col_id, cols.id, col_groups.col_group, col_groups.id ${groupBy} - ${orderby} + ${orderBy} ${limit} `, params, diff --git a/v2/definitions/columns.ts b/v2/definitions/columns.ts index 8104ed27..ad3f7928 100644 --- a/v2/definitions/columns.ts +++ b/v2/definitions/columns.ts @@ -48,9 +48,13 @@ module.exports = function (req, res, next, cb) { where.push("cols.project_id = ANY(:project_id)"); params["project_id"] = larkin.parseMultipleIds(req.query.project_id); } - if (req.query.status) { - where.push("status_code = :status"); - params["status"] = req.query.status; + if (req.query.status_code || req.query.status) { + // `status` parameter still works but has been superseded by `status_code` + // multiple status codes can be provided + where.push("status_code = ANY(:status_code)"); + params["status_code"] = larkin.parseMultipleIds( + req.query.status_code ?? req.query.status, + ); } if (where.length) { diff --git a/v2/defs.ts b/v2/defs.ts index 8528d075..4c43d339 100644 --- a/v2/defs.ts +++ b/v2/defs.ts @@ -1,3 +1,6 @@ +const statusCodeExplanation = + "string, column status codes, values 'active','in process','obsolete'. Defaults to 'active'"; + (function () { const sharedUnitFilters = { unit_id: "integer, a valid unit id", @@ -42,6 +45,7 @@ adjacents: "boolean, if lat/lng or col_id is specified, optionally return all units in columns that touch the polygon containing the supplied lat/lng", project_id: "a Macrostrat project ID", + status_code: statusCodeExplanation, response: "Any available response_type. Default is short.", format: "string, desired output format", }; @@ -455,8 +459,8 @@ col_group_id: "integer, one or more column group ids", col_name: "string, column name", project_id: "integer, one or more project ids", - status: - "string, status of column, values 'active','in process','obsolete'", + status_code: statusCodeExplanation, + status: "same as status_code (deprecated signature)", all: "Return all column definitions", format: "Desired output format", }, diff --git a/v2/fossils.ts b/v2/fossils.ts index 795f2c58..b37a5110 100644 --- a/v2/fossils.ts +++ b/v2/fossils.ts @@ -33,6 +33,7 @@ module.exports = function (req, res, next) { req.query.col_group_id || req.query.strat_name_id || req.query.strat_name_concept_id || + req.query.project_id || "sample" in req.query ) { callback(null, { diff --git a/v2/units.ts b/v2/units.ts index 595c2d2c..84365920 100644 --- a/v2/units.ts +++ b/v2/units.ts @@ -121,6 +121,7 @@ module.exports = function (req, res, next, cb) { } }); } else if (req.query.col_id && req.query.adjacents) { + /** TODO: this can probably be improved with a spatial join instead of a subquery */ var col_ids = larkin.parseMultipleIds(req.query.col_id), placeholders = col_ids.map(function (d, i) { return "$" + (i + 1);