diff --git a/demos/feature-service-browser/README.md b/demos/feature-service-browser/README.md
new file mode 100644
index 0000000000..12dccc614a
--- /dev/null
+++ b/demos/feature-service-browser/README.md
@@ -0,0 +1,6 @@
+# Running this demo
+
+1. Make sure you run `npm run bootstrap` in the root folder to setup the dependencies
+1. `npm start`
+1. Visit http://localhost:8080
+1. Enter a search term and click "Search" to see results
diff --git a/demos/feature-service-browser/index.html b/demos/feature-service-browser/index.html
new file mode 100644
index 0000000000..6a761197bc
--- /dev/null
+++ b/demos/feature-service-browser/index.html
@@ -0,0 +1,122 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Tree ID
+ Type
+ Condition
+
+
+
+
+
+
Try 'elm' or 'oak' for Type . Try 'fair' or 'good' for Condition .
+
+
There are additional rows that meet your query criteria.
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demos/feature-service-browser/package.json b/demos/feature-service-browser/package.json
new file mode 100644
index 0000000000..9bca889643
--- /dev/null
+++ b/demos/feature-service-browser/package.json
@@ -0,0 +1,18 @@
+{
+ "name": "feature-service-browser",
+ "version": "1.0.3",
+ "private": true,
+ "description": "Vanilla JavaScript demo of @esri/arcgis-rest-feature-service",
+ "author": "",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@esri/arcgis-rest-request": "^1.0.3",
+ "@esri/arcgis-rest-feature-service": "^1.0.3"
+ },
+ "devDependencies": {
+ "http-server": "*"
+ },
+ "scripts": {
+ "start": "http-server ."
+ }
+}
diff --git a/packages/arcgis-rest-feature-service/package.json b/packages/arcgis-rest-feature-service/package.json
index 9d81027e0f..4ef4e2b854 100644
--- a/packages/arcgis-rest-feature-service/package.json
+++ b/packages/arcgis-rest-feature-service/package.json
@@ -1,6 +1,6 @@
{
"name": "@esri/arcgis-rest-feature-service",
- "version": "1.0.2",
+ "version": "1.0.3",
"description": "Feature service helpers for @esri/arcgis-rest-request",
"main": "dist/node/index.js",
"browser": "dist/umd/arcgis-rest-feature-service.umd.js",
diff --git a/packages/arcgis-rest-feature-service/src/features.ts b/packages/arcgis-rest-feature-service/src/features.ts
index b3c170cb65..9940dab26d 100644
--- a/packages/arcgis-rest-feature-service/src/features.ts
+++ b/packages/arcgis-rest-feature-service/src/features.ts
@@ -1,6 +1,12 @@
/* Copyright (c) 2017 Environmental Systems Research Institute, Inc.
* Apache-2.0 */
-import { IFeature } from "@esri/arcgis-rest-common-types";
+import {
+ esriGeometryType,
+ IFeature,
+ IField,
+ IGeometry,
+ ISpatialReference
+} from "@esri/arcgis-rest-common-types";
import { request, IRequestOptions } from "@esri/arcgis-rest-request";
/**
@@ -15,7 +21,101 @@ export interface IFeatureRequestOptions extends IRequestOptions {
}
/**
- * Get an feature by id
+ * @param statisticType - statistical operation to perform (count, sum, min, max, avg, stddev, var)
+ * @param onStatisticField - field on which to perform the statistical operation
+ * @param outStatisticFieldName - a field name for the returned statistic field. If outStatisticFieldName is empty or missing, the server will assign one. A valid field name can only contain alphanumeric characters and an underscore. If the outStatisticFieldName is a reserved keyword of the underlying DBMS, the operation can fail. Try specifying an alternative outStatisticFieldName.
+ */
+export interface IStatisticDefinition {
+ statisticType: "count" | "sum" | "min" | "max" | "avg" | "stddev" | "var";
+ onStatisticField: string;
+ outStatisticFieldName: string;
+}
+
+/**
+ * feature query parameters
+ *
+ * See https://developers.arcgis.com/rest/services-reference/query-feature-service-layer-.htm
+ */
+export interface IQueryFeaturesParams {
+ // TODO: are _any_ of these required?
+ where?: string;
+ objectIds?: [number];
+ geometry?: IGeometry;
+ geometryType?: esriGeometryType;
+ // NOTE: either WKID or ISpatialReference
+ inSR?: string | ISpatialReference;
+ spatialRel?:
+ | "esriSpatialRelIntersects"
+ | "esriSpatialRelContains"
+ | "esriSpatialRelCrosses"
+ | "esriSpatialRelEnvelopeIntersects"
+ | "esriSpatialRelIndexIntersects"
+ | "esriSpatialRelOverlaps"
+ | "esriSpatialRelTouches"
+ | "esriSpatialRelWithin";
+ relationParam?: string;
+ // NOTE: either time=1199145600000 or time=1199145600000, 1230768000000
+ time?: Date | [Date];
+ distance?: number;
+ units?:
+ | "esriSRUnit_Meter"
+ | "esriSRUnit_StatuteMile"
+ | "esriSRUnit_Foot"
+ | "esriSRUnit_Kilometer"
+ | "esriSRUnit_NauticalMile"
+ | "esriSRUnit_USNauticalMile";
+ outFields?: "*" | [string];
+ returnGeometry?: boolean;
+ maxAllowableOffset?: number;
+ geometryPrecision?: number;
+ // NOTE: either WKID or ISpatialReference
+ outSR?: string | ISpatialReference;
+ gdbVersion?: string;
+ returnDistinctValues?: boolean;
+ returnIdsOnly?: boolean;
+ returnCountOnly?: boolean;
+ returnExtentOnly?: boolean;
+ orderByFields?: string;
+ groupByFieldsForStatistics?: string;
+ outStatistics?: [IStatisticDefinition];
+ returnZ?: boolean;
+ returnM?: boolean;
+ multipatchOption?: "xyFootprint";
+ resultOffset?: number;
+ resultRecordCount?: number;
+ // TODO: IQuantizationParameters?
+ quantizationParameters?: any;
+ returnCentroid?: boolean;
+ resultType?: "none" | "standard" | "tile";
+ // TODO: is Date the right type for epoch time in milliseconds?
+ historicMoment?: Date;
+ returnTrueCurves?: false;
+ sqlFormat?: "none" | "standard" | "native";
+ returnExceededLimitFeatures?: boolean;
+}
+
+/**
+ * feature query request options
+ *
+ * @param url - layer service url
+ * @param params - query parameters to be sent to the feature service
+ */
+export interface IQueryFeaturesRequestOptions extends IRequestOptions {
+ url: string;
+ params?: IQueryFeaturesParams;
+}
+
+export interface IQueryFeaturesResponse {
+ objectIdFieldName: string;
+ globalIdFieldName: string;
+ geometryType: esriGeometryType;
+ spatialReference: ISpatialReference;
+ fields: [IField];
+ features: [IFeature];
+}
+
+/**
+ * Get a feature by id
*
* @param requestOptions - Options for the request
* @returns A Promise that will resolve with the feature.
@@ -32,3 +132,31 @@ export function getFeature(
};
return request(url, options).then((response: any) => response.feature);
}
+
+/**
+ * Query features
+ *
+ * @param requestOptions - Options for the request
+ * @returns A Promise that will resolve with the query response.
+ */
+export function queryFeatures(
+ requestOptions: IQueryFeaturesRequestOptions
+): Promise {
+ // set default query parameters
+ // and default to a GET request
+ const options: IQueryFeaturesRequestOptions = {
+ ...{
+ params: {},
+ httpMethod: "GET"
+ },
+ ...requestOptions
+ };
+ if (!options.params.where) {
+ options.params.where = "1=1";
+ }
+ if (!options.params.outFields) {
+ options.params.outFields = "*";
+ }
+ // TODO: do we need to serialize any of the array/object params?
+ return request(`${requestOptions.url}/query`, options);
+}
diff --git a/packages/arcgis-rest-feature-service/test/features.test.ts b/packages/arcgis-rest-feature-service/test/features.test.ts
index 1a231e5de5..b97ce87bbe 100644
--- a/packages/arcgis-rest-feature-service/test/features.test.ts
+++ b/packages/arcgis-rest-feature-service/test/features.test.ts
@@ -1,8 +1,8 @@
-import { getFeature } from "../src/index";
+import { getFeature, queryFeatures } from "../src/index";
import * as fetchMock from "fetch-mock";
-import { featureResponse } from "./mocks/feature";
+import { featureResponse, queryResponse } from "./mocks/feature";
describe("feature", () => {
afterEach(fetchMock.restore);
@@ -23,4 +23,20 @@ describe("feature", () => {
done();
});
});
+
+ it("should supply default query parameters", done => {
+ const params = {
+ url:
+ "https://services.arcgis.com/V6ZHFr6zdgNZuVG0/arcgis/rest/services/Landscape_Trees/FeatureServer/0"
+ };
+ fetchMock.once("*", queryResponse);
+ queryFeatures(params).then(response => {
+ expect(fetchMock.called()).toBeTruthy();
+ const [url, options]: [string, RequestInit] = fetchMock.lastCall("*");
+ expect(url).toEqual(`${params.url}/query?f=json&where=1%3D1&outFields=*`);
+ expect(options.method).toBe("GET");
+ // expect(response.attributes.FID).toEqual(42);
+ done();
+ });
+ });
});
diff --git a/packages/arcgis-rest-feature-service/test/mocks/feature.ts b/packages/arcgis-rest-feature-service/test/mocks/feature.ts
index 3bdfb43266..401f5e2242 100644
--- a/packages/arcgis-rest-feature-service/test/mocks/feature.ts
+++ b/packages/arcgis-rest-feature-service/test/mocks/feature.ts
@@ -11,3 +11,136 @@ export const featureResponse = {
}
}
};
+
+export const queryResponse = {
+ objectIdFieldName: "FID",
+ globalIdFieldName: "",
+ geometryType: "esriGeometryPoint",
+ spatialReference: {
+ wkid: 102100,
+ latestWkid: 3857
+ },
+ // fields: [],
+ features: [
+ {
+ attributes: {
+ FID: 1,
+ Tree_ID: 102,
+ Collected: 1349395200000,
+ Crew: "Linden+ Forrest+ Johnny",
+ Status: "P",
+ Spp_Code: "ULPU",
+ Land_Use: "I",
+ Ht_DBH_ft: 4.5,
+ DBH1: 41,
+ DBH2: 0,
+ DBH3: 0,
+ DBH4: 0,
+ DBH5: 0,
+ DBH6: " ",
+ Height: 74,
+ Live_Top: 74,
+ Crown_Base: 21,
+ Width_NS: 75,
+ Width_EW: 40,
+ Cn_Missing: 10,
+ Cn_DieBack: 15,
+ CLE: 2,
+ Tree_Site: "S",
+ Tree_Age: " ",
+ Notes: " ",
+ Cmn_Name: "Siberian elm",
+ Sci_Name: "Ulmus pumila",
+ GroundArea: 2596,
+ Condition: "Fair",
+ Leaf_Area: 10295,
+ Leaf_Bmass: 144,
+ LAI: 3.96,
+ C_Storage: 6771,
+ C_Seq: 95,
+ S_Value: "3,079.00",
+ Street: "YES",
+ Native: "NO",
+ CO_Rmvd: 5.06,
+ O3_Rmvd: 470.97,
+ NO2_Rmvd: 39.24,
+ PM10_Rmvd: 343.45,
+ SO2_Rmvd: 27.64,
+ PM2p5_Rmvd: 47.84,
+ CO_RVlu: 0.01,
+ O3_Rvlu: 0.42,
+ NO2_Rvlu: 0,
+ PM10_Rvlu: 3.73,
+ SO2_Rvlu: 0,
+ PM2p5_RVlu: 1.99,
+ Isoprene_E: 2.7,
+ Monoterp_E: 13.2,
+ Vocs_E: 15.9,
+ Dedication: " ",
+ Longitude: -82.441189,
+ Latitude: 35.610441,
+ Crown_Height: 53
+ }
+ },
+ {
+ attributes: {
+ FID: 2,
+ Tree_ID: 103,
+ Collected: 1349395200000,
+ Crew: "Linden+ Forrest+ Johnny",
+ Status: "P",
+ Spp_Code: "ULPU",
+ Land_Use: "I",
+ Ht_DBH_ft: 4.5,
+ DBH1: 55,
+ DBH2: 0,
+ DBH3: 0,
+ DBH4: 0,
+ DBH5: 0,
+ DBH6: " ",
+ Height: 70,
+ Live_Top: 70,
+ Crown_Base: 21,
+ Width_NS: 90,
+ Width_EW: 71,
+ Cn_Missing: 5,
+ Cn_DieBack: 15,
+ CLE: 3,
+ Tree_Site: "S",
+ Tree_Age: " ",
+ Notes: " ",
+ Cmn_Name: "Siberian elm",
+ Sci_Name: "Ulmus pumila",
+ GroundArea: 5089,
+ Condition: "Fair",
+ Leaf_Area: 17078,
+ Leaf_Bmass: 238,
+ LAI: 3.36,
+ C_Storage: 13228,
+ C_Seq: 22,
+ S_Value: "4,187.00",
+ Street: "YES",
+ Native: "NO",
+ CO_Rmvd: 8.4,
+ O3_Rmvd: 781.35,
+ NO2_Rmvd: 65.1,
+ PM10_Rmvd: 600.8,
+ SO2_Rmvd: 45.86,
+ PM2p5_Rmvd: 83.68,
+ CO_RVlu: 0.01,
+ O3_Rvlu: 0.69,
+ NO2_Rvlu: 0.01,
+ PM10_Rvlu: 6.53,
+ SO2_Rvlu: 0,
+ PM2p5_RVlu: 3.48,
+ Isoprene_E: 4.47,
+ Monoterp_E: 21.9,
+ Vocs_E: 26.38,
+ Dedication: " ",
+ Longitude: -82.441107,
+ Latitude: 35.610472,
+ Crown_Height: 49
+ }
+ }
+ ]
+};