UNPKG

@seasketch/geoprocessing

Version:

Geoprocessing and reporting framework for SeaSketch 2.0

152 lines (141 loc) 4.76 kB
import fs from "fs-extra"; import path from "node:path"; import { datasourcesSchema, Datasource, FeatureCollection, Polygon, MultiPolygon, } from "../../../src/types/index.js"; import { isInternalVectorDatasource, isInternalRasterDatasource, datasourceConfig, } from "../../../src/datasources/index.js"; import { getJsonPath, getFlatGeobufPath } from "./pathUtils.js"; import { isFeatureCollection, loadFgbFromDisk } from "../../../src/index.js"; import { globalDatasources } from "../../../src/datasources/global.js"; /** * Manage datasources for a geoprocessing project */ /** Creates or updates datasource record on disk */ export async function createOrUpdateDatasource( inputDatasource: Datasource, newDatasourcePath?: string, ): Promise<Datasource> { let dSources = readDatasources(newDatasourcePath); let finalDatasource: Datasource = inputDatasource; const dIndex = dSources.findIndex( (dSource) => dSource.datasourceId === inputDatasource.datasourceId, ); const dExists = dIndex > -1; if (dExists) { if (process.env.NODE_ENV !== "test") console.log( `Updating ${inputDatasource.datasourceId} record in project/datasources.json file`, ); // Update in place if ( isInternalVectorDatasource(inputDatasource) || isInternalRasterDatasource(inputDatasource) ) { finalDatasource = { ...dSources[dIndex], ...inputDatasource, lastUpdated: new Date().toISOString(), }; dSources[dIndex] = finalDatasource; } } else { if (process.env.NODE_ENV !== "test") console.log( `Adding ${inputDatasource.datasourceId} record in project/datasources.json file`, ); // Just add onto the end dSources = dSources.concat(inputDatasource); } writeDatasources(dSources, newDatasourcePath); return finalDatasource; } /** * Reads datasources from disk, validates them, and returns deep copy. * If datasource file not exist then start a new one and ensure directory exists */ export function readDatasources(filePath?: string) { // Start with default datasources const pds: Datasource[] = globalDatasources as Datasource[]; // Override datasources path const finalFilePath = filePath && filePath.length > 0 ? filePath : datasourceConfig.defaultDatasourcesPath; const diskPds = (() => { try { const dsString = fs.readFileSync(finalFilePath).toString(); try { return JSON.parse(dsString); } catch { throw new Error( `Unable to parse JSON found in ${finalFilePath}, fix it and try again`, ); } } catch { console.log( `Datasource file not found at ${finalFilePath}, using default datasources`, ); fs.ensureDirSync(path.dirname(datasourceConfig.defaultDatasourcesPath)); // fallback to default return pds; } })(); const result = datasourcesSchema.safeParse(diskPds); if (result.success) { return result.data; } else { console.error("Datasources file is invalid. Did you make manual changes?"); console.log(JSON.stringify(result.error.issues, null, 2)); throw new Error("Please fix or report this issue"); } } export function writeDatasources(pd: Datasource[], filePath?: string) { const finalFilePath = filePath && filePath.length > 0 ? filePath : datasourceConfig.defaultDatasourcesPath; fs.writeJSONSync(finalFilePath, pd, { spaces: 2 }); } /** * Reads in vector datasource geojson as FeatureCollection * @param ds internal vector datasource to load features, with geojson format available * @param dstPath path to directory with datasource * @returns datasource features */ export function readDatasourceGeojsonById( datasourceId: string, dstPath: string, ) { const jsonPath = getJsonPath(dstPath, datasourceId); if (!fs.existsSync(jsonPath)) throw new Error(`GeoJSON form of datasource does not exist at ${jsonPath}`); const polys = fs.readJsonSync(jsonPath); if (isFeatureCollection(polys)) { return polys as FeatureCollection<Polygon | MultiPolygon>; } else throw new Error( `GeoJSON at ${jsonPath} is not a FeatureCollection. Check datasource.`, ); } export function readDatasourceFgbById(datasourceId: string, dstPath: string) { const fgbPath = getFlatGeobufPath(dstPath, datasourceId); if (!fs.existsSync(fgbPath)) throw new Error( `Flatgeobuf form of datasource does not exist at ${fgbPath}`, ); const polys = loadFgbFromDisk(fgbPath); if (isFeatureCollection(polys)) { return polys as FeatureCollection<Polygon | MultiPolygon>; } else throw new Error( `GeoJSON at ${fgbPath} is not a FeatureCollection. Check datasource.`, ); }