@arcgis/core
Version:
ArcGIS Maps SDK for JavaScript: A complete 2D and 3D mapping and data visualization API
6 lines (5 loc) • 15.4 kB
JavaScript
/*
All material copyright ESRI, All Rights Reserved, unless otherwise specified.
See https://js.arcgis.com/4.33/esri/copyright.txt for details.
*/
import{indexOf as e,PositionHint as t}from"../../../core/arrayUtils.js";import{toConst as s}from"../../../core/compilerUtils.js";import i from"../../../core/Error.js";import"../../../core/has.js";import{clone as r}from"../../../core/lang.js";import{removeMaybe as a,destroyMaybe as n}from"../../../core/maybe.js";import{signalFromSignalOrOptions as u,throwIfAborted as l}from"../../../core/promiseUtils.js";import{getMetersPerUnitForSR as o}from"../../../core/unitUtils.js";import{isSerializable as h}from"../../../core/support/jsonUtils.js";import{getTransformation as c}from"../../../geometry/projectionUtils.js";import{set as m,create as f,expandWithAABB as d,negativeInfinity as y}from"../../../geometry/support/aaBoundingBox.js";import{fromValues as p,create as g}from"../../../geometry/support/aaBoundingRect.js";import{getBoundsXY as x}from"../../../geometry/support/boundsUtils.js";import{isExtent as w,isPolygon as F}from"../../../geometry/support/jsonUtils.js";import{equals as _,isValid as S}from"../../../geometry/support/spatialReferenceUtils.js";import{convertFromGeometry as R}from"../featureConversionUtils.js";import{getWhereClause as I}from"./attributeSupport.js";import{cleanFromGeometryEngine as Q,getGeometry as j}from"./geometryUtils.js";import{project as E,projectMany as b}from"./projectionSupport.js";import{QueryEngineCache as A}from"./QueryEngineCache.js";import{queryCapabilities as T}from"./QueryEngineCapabilities.js";import{QueryEngineResult as v}from"./QueryEngineResult.js";import{queryEngineEmptyResult as C,normalizeAttributeBinsQuery as P,normalizeQuery as M}from"./queryUtils.js";import{validateAttributeBinsQuery as z,validateQuery as G,validateStatisticsQuery as O}from"./queryValidationUtils.js";import{getSpatialQueryOperator as U,canQueryWithRBush as q}from"./spatialQuerySupport.js";import{getTimeExtent as k,getTimeOperator as B}from"./timeSupport.js";import Z from"../../support/FieldsIndex.js";import{noBudget as H}from"../../../views/support/Scheduler.js";const N="unsupported-query";class J{constructor(e,t=null,s,i,r){this.attributes=e,this.geometry=s,this.centroid=i,this.filterFlags=r,this.groupId=-1,this.displayId=t}}class L{constructor(e){this._changeHandle=null,this.capabilities={query:T},this.geometryType=e.geometryType,this.hasM=!!e.hasM,this.hasZ=!!e.hasZ,this.spatialReference=e.spatialReference,this.definitionExpression=e.definitionExpression,this.featureStore=e.featureStore,this.aggregateAdapter=e.aggregateAdapter,this._cache=e.cache??new A,this.timeInfo=e.timeInfo,this.featureIdInfo=e.featureIdInfo,"object-id"===e.featureIdInfo.type&&(this.objectIdField=e.featureIdInfo.fieldName),this._changeHandle=this.featureStore.events.on("changed",(()=>this._clearCache())),this.fieldsIndex=h(e.fieldsIndex)?e.fieldsIndex:Z.fromJSON(e.fieldsIndex),!e.availableFields||1===e.availableFields.length&&"*"===e.availableFields[0]?this.availableFields=new Set(this.fieldsIndex.fields.map((e=>e.name))):this.availableFields=new Set(e.availableFields.map((e=>this.fieldsIndex.get(e)?.name)).filter((e=>null!=e))),e.scheduler&&e.priority&&(this._frameTask=e.scheduler.registerTask(e.priority))}destroy(){this._changeHandle=a(this._changeHandle),this._frameTask=a(this._frameTask),this._clearCache(),n(this._cache)}get featureAdapter(){return this.featureStore.featureAdapter}_clearCache(){this._cache.clear(),this._allFeaturesPromise=null,this._timeExtentPromise=null,this._fullExtentPromise=null}async executeQuery(e,t){const s=u(t);try{const t=await this._executeQuery(e,{},s);return await t.createQueryResponse()}catch(i){if(i!==C)throw i;return new v([],e,this).createQueryResponse()}}async executeQueryForCount(e={},t){const s=u(t);try{return(await this._executeQuery(e,{returnGeometry:!1,returnCentroid:!1,outSR:null},s)).createQueryResponseForCount()}catch(i){if(i!==C)throw i;return 0}}async executeQueryForExtent(e,t){const s=u(t),i=e.outSR;try{const t=await this._executeQuery(e,{returnGeometry:!0,returnCentroid:!1,outSR:null},s),r=t.size;if(!r)return{count:0,extent:null};return{count:r,extent:await this._getBounds(t.items,t.spatialReference,i||this.spatialReference)}}catch(r){if(r===C)return{count:0,extent:null};throw r}}async executeQueryForIds(e,t){return this.executeQueryForIdSet(e,t).then((e=>Array.from(e)))}async executeQueryForIdSet(e,t){const s=u(t);try{const t=await this._executeQuery(e,{returnGeometry:!0,returnCentroid:!1,outSR:null},s),i=t.items,r=new Set;return await this.reschedule((()=>{for(const e of i)r.add(t.featureAdapter.getObjectId(e))}),s),r}catch(i){if(i===C)return new Set;throw i}}async executeQueryForLatestObservations(e,t){const s=u(t);if(!this.timeInfo?.trackIdField)throw new i(N,"Missing timeInfo or timeInfo.trackIdField",{query:e,timeInfo:this.timeInfo});try{const t=await this._executeQuery(e,{},s);return await this.reschedule((()=>this._filterLatest(t)),s),await t.createQueryResponse()}catch(r){if(r!==C)throw r;return new v([],e,this).createQueryResponse()}}async executeAttributeBinsQuery(e,t){const s=u(t);let i;e=r(e);try{e=await this.schedule((()=>P(e,this.definitionExpression,this.spatialReference)),s),e=await this.reschedule((()=>z(e,{availableFields:this.availableFields,fieldsIndex:this.fieldsIndex,geometryType:this.geometryType,spatialReference:this.spatialReference})),s);const t=await this.reschedule((()=>this._executeSceneFilterQuery(e,s)),s);i=await this.reschedule((()=>this._executeGeometryQuery(e,t,s)),s),await this.reschedule((()=>this._executeAggregateIdsQuery(i)),s),await this.reschedule((()=>this.executeObjectIdsQuery(i)),s),await this.reschedule((()=>this.executeTimeQuery(i)),s),await this.reschedule((()=>this.executeAttributesQuery(i)),s)}catch(a){if(a!==C)throw a;i=new v([],e,this)}return i.createQueryBinsResponse(e)}async executeQueryForSummaryStatistics(e={},t,s){const i=u(s),{field:r,normalizationField:a,valueExpression:n}=t;return(await this._executeQueryForStatistics(e,{field:r,normalizationField:a,valueExpression:n},i)).createSummaryStatisticsResponse(t)}async executeQueryForUniqueValues(e={},t,s){const i=u(s),{field:r,field2:a,field3:n,valueExpression:l}=t;return(await this._executeQueryForStatistics(e,{field:r,field2:a,field3:n,valueExpression:l},i)).createUniqueValuesResponse(t)}async executeQueryForClassBreaks(e={},t,s){const i=u(s),{field:r,normalizationField:a,valueExpression:n}=t;return(await this._executeQueryForStatistics(e,{field:r,normalizationField:a,valueExpression:n},i)).createClassBreaksResponse(t)}async executeQueryForHistogram(e={},t,s){const i=u(s),{field:r,normalizationField:a,valueExpression:n}=t;return(await this._executeQueryForStatistics(e,{field:r,normalizationField:a,valueExpression:n},i)).createHistogramResponse(t)}async fetchRecomputedExtents(e){const t=u(e);this._timeExtentPromise||=k(this.timeInfo,this.featureStore);const[s,i]=await Promise.all([this._getFullExtent(),this._timeExtentPromise]);return l(t),{fullExtent:s,timeExtent:i}}async _getBounds(e,t,s){const i=m(f(),y);await this.featureStore.forEachBounds(e,(e=>d(i,e)));const r={xmin:i[0],ymin:i[1],xmax:i[3],ymax:i[4],spatialReference:Q(this.spatialReference)};this.hasZ&&isFinite(i[2])&&isFinite(i[5])&&(r.zmin=i[2],r.zmax=i[5],r.hasZ=!0);const a=E(r,t,s);if(a.spatialReference=Q(s),a.xmax-a.xmin===0){const e=o(a.spatialReference);a.xmin-=e,a.xmax+=e}if(a.ymax-a.ymin===0){const e=o(a.spatialReference);a.ymin-=e,a.ymax+=e}if(this.hasZ&&null!=a.zmin&&null!=a.zmax&&a.zmax-a.zmin===0){const e=o(a.spatialReference);a.zmin-=e,a.zmax+=e}return a}_getFullExtent(){return this._fullExtentPromise||="getFullExtent"in this.featureStore&&this.featureStore.getFullExtent?Promise.resolve(this.featureStore.getFullExtent(this.spatialReference)):this._getAllFeatures().then((e=>this._getBounds(e,this.spatialReference,this.spatialReference))),this._fullExtentPromise}async schedule(e,t){return this._frameTask?.schedule(e,t)??e(H)}async reschedule(e,t){return this._frameTask?.reschedule(e,t)??e(H)}async _getAllFeaturesQueryEngineResult(e){return new v(await this._getAllFeatures(),e,this)}async _getAllFeatures(){if(null==this._allFeaturesPromise){const e=[];this._allFeaturesPromise=(async()=>await this.featureStore.forEach((t=>e.push(t))))().then((()=>s(e)))}const e=this._allFeaturesPromise,t=await e;return e===this._allFeaturesPromise?t.slice():this._getAllFeatures()}async _executeQuery(e,t,s){e=r(e),e=await this.schedule((()=>M(e,this.definitionExpression,this.spatialReference)),s),e=await this.reschedule((()=>G(e,{availableFields:this.availableFields,fieldsIndex:this.fieldsIndex,geometryType:this.geometryType,spatialReference:this.spatialReference})),s),e={...e,...t};const i=await this.reschedule((()=>this._executeSceneFilterQuery(e,s)),s),a=await this.reschedule((()=>this._executeGeometryQuery(e,i,s)),s);return await this.reschedule((()=>this._executeAggregateIdsQuery(a)),s),await this.reschedule((()=>this.executeObjectIdsQuery(a)),s),await this.reschedule((()=>this.executeTimeQuery(a)),s),await this.reschedule((()=>this.executeAttributesQuery(a)),s),a}async _executeSceneFilterQuery(e,t){if(null==e.sceneFilter)return null;const{outSR:s,returnGeometry:i,returnCentroid:r}=e,a=this.featureStore.featureSpatialReference,n=e.sceneFilter.geometry,u=null==a||_(a,n.spatialReference)?n:E(n,a);if(!u)return null;const l=i||r,o=S(s)&&!_(this.spatialReference,s)&&l?async e=>this._project(e,s):e=>e,h=this.featureAdapter,c=await this.reschedule((()=>this.searchFeatures(V(u))),t);if("disjoint"===e.sceneFilter.spatialRelationship){if(!c.length)return null;const s=new Set;for(const e of c)s.add(h.getObjectId(e));const i=await this.reschedule((()=>this._getAllFeatures()),t),r=await this.reschedule((async()=>{const r=await U("esriSpatialRelDisjoint",u,this.geometryType,this.hasZ,this.hasM),a=e=>!s.has(h.getObjectId(e))||r(h.getGeometry(e)),n=await this.runSpatialFilter(i,a,t);return new v(n,e,this)}),t);return o(r)}if(!c.length)return new v([],e,this);if(this._canExecuteSinglePass(u,e))return o(new v(c,e,this));const m=await U("esriSpatialRelContains",u,this.geometryType,this.hasZ,this.hasM),f=await this.runSpatialFilter(c,(e=>m(h.getGeometry(e))),t);return o(new v(f,e,this))}async _executeGeometryQuery(s,i,r){if(null!=i&&0===i.items.length)return i;const{geometry:a,outSR:n,returnGeometry:u,returnCentroid:l}=s,o=i?null:this._getCacheKey(s),h=o?this._cache.get(o):null;if(h)return new v(h,s,this);const c=S(n)&&!_(this.spatialReference,n),m=u||l,f=async e=>(c&&m&&await this._project(e,n),o&&this._cache.put(o,e.items),e),d=this.featureStore.featureSpatialReference,y=!a||null==d||_(d,a.spatialReference)?a:E(a,d);if(!y)return f(null!=i?i:await this._getAllFeaturesQueryEngineResult(s));const p=this.featureAdapter;let g=await this.reschedule((()=>this.searchFeatures(V(a))),r);const x=s.spatialRel??"esriSpatialRelIntersects";if("esriSpatialRelDisjoint"===x){if(!g.length)return f(null!=i?i:await this._getAllFeaturesQueryEngineResult(s));const e=new Set;for(const s of g)e.add(p.getObjectId(s));const t=null!=i?i.items:await this.reschedule((()=>this._getAllFeatures()),r),a=await this.reschedule((async()=>{const i=await U(x,y,this.geometryType,this.hasZ,this.hasM),a=t=>!e.has(p.getObjectId(t))||i(p.getGeometry(t)),n=await this.runSpatialFilter(t,a,r);return new v(n,s,this)}),r);return f(a)}if(null!=i){const s=new t;g=g.filter((t=>e(i.items,t,i.items.length,s)>=0))}if(!g.length){const e=new v([],s,this);return o&&this._cache.put(o,e.items),e}if(this._canExecuteSinglePass(y,s))return f(new v(g,s,this));const w=await U(x,y,this.geometryType,this.hasZ,this.hasM),F=await this.runSpatialFilter(g,(e=>w(p.getGeometry(e))),r);return f(new v(F,s,this))}_executeAggregateIdsQuery(e){if(0===e.items.length||!e.query.aggregateIds?.length||null==this.aggregateAdapter)return;const t=new Set;for(const i of e.query.aggregateIds){this.aggregateAdapter.getFeatureObjectIds(i).forEach((e=>t.add(e)))}const s=this.featureAdapter.getObjectId;e.items=e.items.filter((e=>t.has(s(e))))}executeObjectIdsQuery(e){if(0===e.items.length||!e.query.objectIds?.length)return;const t=new Set(e.query.objectIds),s=this.featureAdapter.getObjectId;e.items=e.items.filter((e=>t.has(s(e))))}executeTimeQuery(e){if(0===e.items.length)return;const t=B(this.timeInfo,e.query.timeExtent,this.featureAdapter);null!=t&&(e.items=e.items.filter(t))}executeAttributesQuery(e){if(0===e.items.length)return;const t=I(e.query.where,this.fieldsIndex);if(t){if(!t.isStandardized)throw new TypeError("Where clause is not standardized");e.items=e.items.filter((e=>t.testFeature(e,this.featureAdapter)))}}async runSpatialFilter(e,t,s){if(!t)return e;if(null==this._frameTask)return e.filter((e=>t(e)));let i=0;const r=new Array,a=async n=>{for(;i<e.length;){const u=e[i++];t(u)&&(r.push(u),n.madeProgress()),n.done&&await this.reschedule((e=>a(e)),s)}};return this.reschedule((e=>a(e)),s).then((()=>r))}_filterLatest(e){const{trackIdField:t,startTimeField:s,endTimeField:i}=this.timeInfo,r=i||s,a=new Map,n=this.featureAdapter.getAttribute;for(const u of e.items){const e=n(u,t),s=n(u,r),i=a.get(e);(!i||s>n(i,r))&&a.set(e,u)}e.items=Array.from(a.values())}_getCacheKey(e){const{geometry:t,spatialRel:s,returnGeometry:i,returnCentroid:r,outSR:a,resultType:n,cacheHint:u}=e;if("tile"!==n&&!u)return null;const l=i||r;return S(a)&&!_(this.spatialReference,a)&&l?JSON.stringify([t,s,a]):JSON.stringify([t,s])}_canExecuteSinglePass(e,t){const{spatialRel:s}=t;return q(e)&&("esriSpatialRelEnvelopeIntersects"===s||"esriGeometryPoint"===this.geometryType&&("esriSpatialRelIntersects"===s||"esriSpatialRelContains"===s))}async _project(e,t){if(!t||_(this.spatialReference,t))return e;const i=this.featureAdapter;let r;try{const e=await this._getFullExtent();r=c(this.spatialReference,t,e)}catch{}const a=await b(e.items.map((e=>j(this.geometryType,this.hasZ,this.hasM,i.getGeometry(e)))),this.spatialReference,t,r);return e.items=s(a.map(((t,s)=>i.cloneWithGeometry(e.items[s],R(t,this.hasZ,this.hasM))))),e}async searchFeatures(e){const t=new Set;await Promise.all(e.map((e=>this.featureStore.forEachInBounds(e,(e=>t.add(e))))));const s=Array.from(t.values());return t.clear(),s}async _executeQueryForStatistics(e,t,s){e=r(e);try{e=await this.schedule((()=>M(e,this.definitionExpression,this.spatialReference)),s),e=await this.reschedule((()=>O(e,t,{availableFields:this.availableFields,fieldsIndex:this.fieldsIndex,geometryType:this.geometryType,spatialReference:this.spatialReference})),s);const i=await this.reschedule((()=>this._executeSceneFilterQuery(e,s)),s),r=await this.reschedule((()=>this._executeGeometryQuery(e,i,s)),s);return await this.reschedule((()=>this._executeAggregateIdsQuery(r)),s),await this.reschedule((()=>this.executeObjectIdsQuery(r)),s),await this.reschedule((()=>this.executeTimeQuery(r)),s),await this.reschedule((()=>this.executeAttributesQuery(r)),s),r}catch(i){if(i!==C)throw i;return new v([],e,this)}}get test(){}}function V(e){if(q(e)){if(w(e))return[p(Math.min(e.xmin,e.xmax),Math.min(e.ymin,e.ymax),Math.max(e.xmin,e.xmax),Math.max(e.ymin,e.ymax))];if(F(e))return e.rings.map((e=>p(Math.min(e[0][0],e[2][0]),Math.min(e[0][1],e[2][1]),Math.max(e[0][0],e[2][0]),Math.max(e[0][1],e[2][1]))))}return[x(g(),e)]}export{J as Feature,L as QueryEngine,V as getQueryBBoxes};