@esri/arcgis-rest-feature-service
Version:
Feature layer query and edit helpers for @esri/arcgis-rest-js
286 lines • 12.3 kB
JavaScript
;
/* Copyright (c) 2017-2018 Environmental Systems Research Institute, Inc.
* Apache-2.0 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.queryPbfAsGeoJSONOrArcGIS = queryPbfAsGeoJSONOrArcGIS;
exports.getFeature = getFeature;
exports.queryFeatures = queryFeatures;
exports.queryAllFeatures = queryAllFeatures;
const arcgis_rest_request_1 = require("@esri/arcgis-rest-request");
const geoJSONPbfParser_js_1 = require("./pbf-parser/geoJSONPbfParser.js");
const arcGISPbfParser_js_1 = require("./pbf-parser/arcGISPbfParser.js");
/**
* Query and decode pbf features on the client. Improves performance on slow networks and large queries.
* Handles both f=pbf-as-geojson and f=pbf-as-arcgis format query params and handles errors.
*
* @param url - A feature service url
* @param queryOptions - Options for the request that has been passed through appendCustomParams
* @returns A Promise that will resolve with the query response.
*/
function queryPbfAsGeoJSONOrArcGIS(url, queryOptions) {
// if f=pbf-as-geojson, we need to set outSR=4326 to satisfy geojson crs standard
// if f-pbf-as-geojson, outSR should not be set, or should be 4326 otherwise throw error
if (queryOptions.params.f === "pbf-as-geojson" &&
queryOptions.params.outSR &&
queryOptions.params.outSR !== "4326") {
throw new arcgis_rest_request_1.ArcGISRequestError("Unsupported outSR for GeoJSON requests.", 422, null, url, queryOptions);
}
// default pbf request to EPSG:4326 if requesting pbf-as-geojson to satisfy geojson crs standard
const geoJSONSpatialReference = queryOptions.params.f === "pbf-as-geojson" ? { outSR: "4326" } : {};
// query with f=pbf and rawResponse:true on behalf of the user to fetch metadata with the pbf response
const customOptions = Object.assign(Object.assign({}, queryOptions), { params: Object.assign(Object.assign(Object.assign({}, queryOptions.params), geoJSONSpatialReference), { f: "pbf" }), rawResponse: true });
return (0, arcgis_rest_request_1.request)(`${(0, arcgis_rest_request_1.cleanUrl)(url)}/query`, customOptions).then(async (response) => {
var _a;
// if pbf request to service returns a json format, there is an error
if ((_a = response.headers.get("content-type")) === null || _a === void 0 ? void 0 : _a.includes("application/json")) {
const err = (await response.json()).error;
// throw auth error, else throw generic request error
if ((err === null || err === void 0 ? void 0 : err.code) === 498 || (err === null || err === void 0 ? void 0 : err.code) === 499) {
throw new arcgis_rest_request_1.ArcGISAuthError(err.message, err.code, response, url, customOptions);
}
throw new arcgis_rest_request_1.ArcGISRequestError(err.message, err.code, response, url, customOptions);
}
try {
const arrayBuffer = await response.arrayBuffer();
/* istanbul ignore else --@preserve */
if (queryOptions.params.f === "pbf-as-arcgis") {
return (0, arcGISPbfParser_js_1.default)(arrayBuffer);
}
/* istanbul ignore else --@preserve */
if (queryOptions.params.f === "pbf-as-geojson") {
return (0, geoJSONPbfParser_js_1.default)(arrayBuffer);
}
}
catch (error) {
if (error instanceof arcgis_rest_request_1.ArcGISRequestError) {
// Append response, url, customOptions
error.response = response;
error.url = url;
error.options = customOptions;
throw error;
}
else {
// catch all for any errors that occur during the parsing of the pbf response
throw new arcgis_rest_request_1.ArcGISRequestError("Unable to decode pbf response.", 500, response, url, customOptions);
}
}
});
}
/**
* Get a feature by id.
*
* ```js
* import { getFeature } from '@esri/arcgis-rest-feature-service';
*
* const url = "https://services.arcgis.com/V6ZHFr6zdgNZuVG0/arcgis/rest/services/Landscape_Trees/FeatureServer/0";
*
* getFeature({
* url,
* id: 42
* }).then(feature => {
* console.log(feature.attributes.FID); // 42
* });
* ```
*
* @param requestOptions - Options for the request
* @returns A Promise that will resolve with the feature or the [response](https://developer.mozilla.org/en-US/docs/Web/API/Response) itself if `rawResponse: true` was passed in.
*/
function getFeature(requestOptions) {
const url = `${(0, arcgis_rest_request_1.cleanUrl)(requestOptions.url)}/${requestOptions.id}`;
// default to a GET request
const options = Object.assign({ httpMethod: "GET" }, requestOptions);
return (0, arcgis_rest_request_1.request)(url, options).then((response) => {
if (options.rawResponse) {
return response;
}
return response.feature;
});
}
/**
* Query a feature service. See [REST Documentation](https://developers.arcgis.com/rest/services-reference/query-feature-service-layer-.htm) for more information.
*
* ```js
* import { queryFeatures } from '@esri/arcgis-rest-feature-service';
*
* queryFeatures({
* url: "http://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer/3",
* where: "STATE_NAME = 'Alaska'"
* })
* .then(result)
* ```
*
* @param requestOptions - Options for the request
* @returns A Promise that will resolve with the query response.
*/
function queryFeatures(requestOptions) {
var _a, _b;
const queryOptions = (0, arcgis_rest_request_1.appendCustomParams)(requestOptions, [
"where",
"objectIds",
"relationParam",
"time",
"distance",
"units",
"outFields",
"geometry",
"geometryType",
"spatialRel",
"returnGeometry",
"maxAllowableOffset",
"geometryPrecision",
"inSR",
"outSR",
"gdbVersion",
"returnDistinctValues",
"returnIdsOnly",
"returnCountOnly",
"returnExtentOnly",
"orderByFields",
"groupByFieldsForStatistics",
"outStatistics",
"returnZ",
"returnM",
"multipatchOption",
"resultOffset",
"resultRecordCount",
"quantizationParameters",
"returnCentroid",
"resultType",
"historicMoment",
"returnTrueCurves",
"sqlFormat",
"returnExceededLimitFeatures",
"f"
], {
httpMethod: "GET",
params: Object.assign({
// set default query parameters
where: "1=1", outFields: "*" }, requestOptions.params)
});
if (((_a = queryOptions.params) === null || _a === void 0 ? void 0 : _a.f) === "pbf-as-geojson" ||
((_b = queryOptions.params) === null || _b === void 0 ? void 0 : _b.f) === "pbf-as-arcgis") {
return queryPbfAsGeoJSONOrArcGIS(requestOptions.url, queryOptions);
}
return (0, arcgis_rest_request_1.request)(`${(0, arcgis_rest_request_1.cleanUrl)(requestOptions.url)}/query`, queryOptions);
}
/**
* Query a feature service to retrieve all features. See [REST Documentation](https://developers.arcgis.com/rest/services-reference/query-feature-service-layer-.htm) for more information.
*
* ```js
* import { queryAllFeatures } from '@esri/arcgis-rest-feature-service';
*
* queryAllFeatures({
* url: "http://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer/3",
* where: "STATE_NAME = 'Alaska'"
* })
* .then(result)
* ```
*
* @param requestOptions - Options for the request
* @returns A Promise that will resolve with the query response.
*/
async function queryAllFeatures(requestOptions) {
var _a, _b, _c, _d;
let firstResponse = true;
let offset = 0;
let hasMore = true;
let allFeaturesResponse = null;
const userRecordCount = requestOptions.resultRecordCount ||
((_a = requestOptions.params) === null || _a === void 0 ? void 0 : _a.resultRecordCount);
// Throw error if user requests 100,000 or more features
if (userRecordCount && userRecordCount >= 100000) {
throw new arcgis_rest_request_1.ArcGISRequestError("resultRecordCount must be less than 100,000.", 400, null, requestOptions.url, requestOptions);
}
let recordCountToUse;
if (userRecordCount) {
// Use user-provided recordCount directly
recordCountToUse = userRecordCount;
}
else {
// retrieve the maxRecordCount for the service only if user did not provide resultRecordCount
const pageSizeResponse = await (0, arcgis_rest_request_1.request)(requestOptions.url, {
httpMethod: "GET",
authentication: requestOptions.authentication
});
// default the pageSize to 2000 if it is not provided
recordCountToUse = pageSizeResponse.maxRecordCount || 2000;
}
while (hasMore) {
const pagedOptions = Object.assign(Object.assign({}, requestOptions), { params: Object.assign(Object.assign({ where: "1=1", outFields: "*" }, (requestOptions.params || {})), { resultOffset: offset, resultRecordCount: recordCountToUse }) });
const queryOptions = (0, arcgis_rest_request_1.appendCustomParams)(pagedOptions, [
"where",
"objectIds",
"relationParam",
"time",
"distance",
"units",
"outFields",
"geometry",
"geometryType",
"spatialRel",
"returnGeometry",
"maxAllowableOffset",
"geometryPrecision",
"inSR",
"outSR",
"gdbVersion",
"orderByFields",
"groupByFieldsForStatistics",
"outStatistics",
"returnZ",
"returnM",
"multipatchOption",
"resultOffset",
"resultRecordCount",
"maxRecordCountFactor",
"quantizationParameters",
"resultType",
"historicMoment",
"returnTrueCurves",
"sqlFormat",
"f"
], {
httpMethod: "GET",
params: Object.assign({ where: "1=1", outFields: "*", returnExceededLimitFeatures: true }, pagedOptions.params)
});
let response;
if (((_b = queryOptions.params) === null || _b === void 0 ? void 0 : _b.f) === "pbf-as-geojson" ||
((_c = queryOptions.params) === null || _c === void 0 ? void 0 : _c.f) === "pbf-as-arcgis") {
response = (await queryPbfAsGeoJSONOrArcGIS(requestOptions.url, queryOptions));
}
else {
response = await (0, arcgis_rest_request_1.request)(`${(0, arcgis_rest_request_1.cleanUrl)(requestOptions.url)}/query`, queryOptions);
}
// save the first response structure
if (!allFeaturesResponse) {
allFeaturesResponse = Object.assign({}, response);
}
else {
// append features of subsequent requests
allFeaturesResponse.features = allFeaturesResponse.features.concat(response.features);
}
const returnedCount = response.features.length;
// Use the returned feature count as the page size for subsequent requests if user record count exceeds service limits
if (firstResponse) {
firstResponse = false;
if (returnedCount > 0 && returnedCount < recordCountToUse) {
recordCountToUse = returnedCount;
}
}
const exceededTransferLimit =
// ArcGIS JSON | pbf-as-arcgis: exceededTransferLimit is on the response object
response.exceededTransferLimit ||
(
// GeoJSON | pbf-as-geojson: exceededTransferLimit is on properties in the response object
(_d = response.properties) === null || _d === void 0 ? void 0 : _d.exceededTransferLimit);
// check if there are more features
if (returnedCount < recordCountToUse || !exceededTransferLimit) {
hasMore = false;
}
else {
offset += recordCountToUse;
}
}
return allFeaturesResponse;
}
//# sourceMappingURL=query.js.map