gadm-ts/dist/items.js
2026-03-23 17:35:02 +01:00

168 lines
15 KiB
JavaScript

/**
* Items — GeoJSON boundary fetcher.
*
* Reads geometry from a local GeoPackage file when available,
* falls back to the GADM CDN. Results include corrected names
* from the parquet database.
*/
import { getNames } from './names.js';
import { getBoundaryFromGpkg } from './gpkg-reader.js';
import { readFileSync } from 'fs';
import { resolve, dirname } from 'path';
import { fileURLToPath } from 'url';
const __filename_ = fileURLToPath(import.meta.url);
const __dirname_ = dirname(__filename_);
// ---------- constants ----------
const GADM_URL = 'https://geodata.ucdavis.edu/gadm/gadm4.1/json/gadm41_{}_{}.json';
/** Continent → ISO3 codes mapping */
const CONTINENT_MAP = JSON.parse(readFileSync(resolve(__dirname_, '../data/gadm_continent.json'), 'utf-8'));
// ---------- main function ----------
/**
* Fetch GeoJSON boundaries for administrative areas.
* Tries local GeoPackage first, falls back to GADM CDN.
*/
export async function getItems(opts) {
let { name, admin, contentLevel = -1, cache } = opts;
// Normalize to arrays
let names = typeof name === 'string' ? [name] : (name || []);
let admins = typeof admin === 'string' ? [admin] : (admin || []);
if (names.length === 0 && admins.length === 0) {
throw new Error('At least "name" or "admin" need to be set.');
}
// Continent expansion
if (names.length === 1 && names[0].toLowerCase() in CONTINENT_MAP) {
admins = CONTINENT_MAP[names[0].toLowerCase()];
names = [];
}
// Fetch all items
const allFeatures = [];
for (const n of names) {
const features = await fetchSingleItem(n, '', contentLevel, cache);
allFeatures.push(...features);
}
for (const a of admins) {
const features = await fetchSingleItem('', a, contentLevel, cache);
allFeatures.push(...features);
}
return {
type: 'FeatureCollection',
features: allFeatures,
};
}
// ---------- internal ----------
async function fetchSingleItem(name, admin, contentLevel, cache) {
// Step 1: Look up the area to find its level + GID
const lookupOpts = name ? { name } : { admin };
const lookup = await getNames(lookupOpts);
if (lookup.rows.length > 1) {
const id = name || admin;
throw new Error(`The requested name ("${id}") is not unique (${lookup.rows.length} results). ` +
`Use the "admin" parameter instead. ` +
`To find the GADM code, use: getNames({ name: "${id}" })`);
}
const level = lookup.level;
const gidCol = `GID_${level}`;
const gadmId = lookup.rows[0][gidCol] || '';
// Step 2: Resolve content level
const contentLookup = await getNames({
...(name ? { name } : { admin }),
contentLevel,
});
const resolvedLevel = contentLookup.level;
// Step 3: Try local GeoPackage first
let localResult = await tryLocalGpkg(gadmId, name || admin, level, resolvedLevel, cache);
// Step 4: Fallback to GADM CDN
if (!localResult) {
localResult = await fetchFromCDN(name, admin, gadmId, level, resolvedLevel);
}
if (resolvedLevel === level) {
localResult.forEach(f => f.properties.isOuter = true);
}
return localResult;
}
/**
* Read boundaries from local GeoPackage.
* Returns features with all matching rows at the resolved content level.
*/
async function tryLocalGpkg(gadmId, id, level, resolvedLevel, cache) {
// Query the GeoPackage for all rows belonging to this region
const gidCol = `GID_${level}`;
const nameCols = [];
for (let l = 0; l <= Math.min(resolvedLevel, 5); l++) {
nameCols.push(`NAME_${l}`, `GID_${l}`);
}
const result = await getBoundaryFromGpkg(gadmId, resolvedLevel, cache);
if (!result || result.features.length === 0)
return null;
// Convert BoundaryFeature → GeoJSONFeature
const features = result.features.map(f => ({
type: 'Feature',
properties: f.properties,
geometry: f.geometry,
}));
return features;
}
/**
* Fallback: fetch from GADM CDN + correct names from parquet.
*/
async function fetchFromCDN(name, admin, gadmId, level, resolvedLevel) {
const iso3 = gadmId.substring(0, 3);
const url = GADM_URL.replace('{}', iso3).replace('{}', String(resolvedLevel));
let data;
try {
const res = await fetch(url);
if (!res.ok)
throw new Error(`HTTP ${res.status}`);
data = await res.json();
}
catch (e) {
throw new Error(`Cannot retrieve data from GADM server. ` +
`Try opening: ${url}. ` +
`If it fails, the error is from GADM servers.`);
}
// Convert to features
const rawFeatures = data.features || [];
let features = rawFeatures.map((f) => ({
type: 'Feature',
properties: { ...f.properties, ...(f.properties?.COUNTRY ? { NAME_0: f.properties.COUNTRY } : {}) },
geometry: f.geometry,
}));
// Name correction from parquet
const isos = [...new Set(features.map(f => f.properties.GID_0).filter(Boolean))];
if (isos.length > 0) {
const completeRows = [];
for (const iso of isos) {
const nr = await getNames({ admin: iso, contentLevel: resolvedLevel, complete: true });
completeRows.push(...nr.rows);
}
const gidKey = (row) => {
const parts = [];
for (let i = 0; i <= resolvedLevel; i++) {
parts.push(row[`GID_${i}`] || '');
}
return parts.join('|');
};
const nameLookup = new Map();
for (const row of completeRows) {
nameLookup.set(gidKey(row), row);
}
for (const feature of features) {
const key = gidKey(feature.properties);
const correct = nameLookup.get(key);
if (correct) {
for (let i = 0; i <= resolvedLevel; i++) {
if (correct[`NAME_${i}`]) {
feature.properties[`NAME_${i}`] = correct[`NAME_${i}`];
}
}
}
}
}
// Filter to the requested area
const id = name || admin;
const colPrefix = name ? 'NAME_' : 'GID_';
const filterCol = `${colPrefix}${level}`;
features = features.filter(f => f.properties[filterCol]?.toLowerCase() === id.toLowerCase());
return features;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaXRlbXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaXRlbXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7OztHQU1HO0FBQ0gsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLFlBQVksQ0FBQztBQUN0QyxPQUFPLEVBQUUsbUJBQW1CLEVBQWtCLE1BQU0sa0JBQWtCLENBQUM7QUFDdkUsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLElBQUksQ0FBQztBQUNsQyxPQUFPLEVBQUUsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUN4QyxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sS0FBSyxDQUFDO0FBRXBDLE1BQU0sV0FBVyxHQUFHLGFBQWEsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0FBQ25ELE1BQU0sVUFBVSxHQUFHLE9BQU8sQ0FBQyxXQUFXLENBQUMsQ0FBQztBQThCeEMsa0NBQWtDO0FBRWxDLE1BQU0sUUFBUSxHQUFHLGlFQUFpRSxDQUFDO0FBRW5GLHFDQUFxQztBQUNyQyxNQUFNLGFBQWEsR0FBNkIsSUFBSSxDQUFDLEtBQUssQ0FDdEQsWUFBWSxDQUFDLE9BQU8sQ0FBQyxVQUFVLEVBQUUsNkJBQTZCLENBQUMsRUFBRSxPQUFPLENBQUMsQ0FDNUUsQ0FBQztBQUVGLHNDQUFzQztBQUV0Qzs7O0dBR0c7QUFDSCxNQUFNLENBQUMsS0FBSyxVQUFVLFFBQVEsQ0FBQyxJQUFrQjtJQUM3QyxJQUFJLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxZQUFZLEdBQUcsQ0FBQyxDQUFDLEVBQUUsS0FBSyxFQUFFLEdBQUcsSUFBSSxDQUFDO0lBRXJELHNCQUFzQjtJQUN0QixJQUFJLEtBQUssR0FBRyxPQUFPLElBQUksS0FBSyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lB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