UNPKG

@arcgis/core

Version:

ArcGIS Maps SDK for JavaScript: A complete 2D and 3D mapping and data visualization API

3 lines (2 loc) • 16.5 kB
/* COPYRIGHT Esri - https://js.arcgis.com/5.0.8/LICENSE.txt */ import has from"../has.js";import{some as e}from"../iteratorUtils.js";import{isAggregate as t,aggregateFunction as r}from"./AggregateFunctions.js";import{DateOnly as a}from"./DateOnly.js";import{SqlError as s}from"./errorSupport.js";import{sqlCalculateFunction as n}from"./sqlArithmeticUtils.js";import{sqlCompare as i,flipSqlComparisonOperator as o,prepareDateFieldToTimestampLiteralComparisonData as l,isDateOrTimeValue as u}from"./sqlCompareUtils.js";import{isDateTime as c,isTimestampOffset as p,isTimeOnly as m,isDateOnly as h,parseTime as d,parseTimestamp as f,parseDate as _,convertToExecutingTimeZone as N}from"./sqlDateParsingUtils.js";import{SqlInterval as g}from"./SqlInterval.js";import{SqlTimeStampOffset as v}from"./SqlTimestampOffset.js";import{iterateSqlNodes as y}from"./sqlVisitor.js";import{isStandardized as S,evaluateFunction as T}from"./StandardizedFunctions.js";import{TimeOnly as w}from"./TimeOnly.js";import{WhereGrammar as D}from"./WhereGrammar.js";import{isDate as I}from"../../support/guards.js";import{getLuxonTimeZone as x}from"../../time/timeZoneUtils.js";import{DateTime as $,FixedOffsetZone as E}from"luxon";const F=new Set(["current_timestamp","current_date","current_time"]);class b{constructor(e){this.staticData=e}makeBool(e){return J(e)}featureValue(e,t,r,a){return se(e,t,r,a)}equalsNull(e){return null===e}applyLike(e,t,r){return te(e,t,r)}ensureArray(e){return B(e)}applyIn(e,t){return Q(e,t)}currentTimestamp(e){return P(e)}currentDate(e){return H(e)}currentTime(e){return X(e)}makeSqlInterval(e,t,r){return g.createFromValueAndQualifier(e,t,r)}convertInterval(e){return g.isInterval(e)?e.valueInMilliseconds():e}compare(e,t,r){return i(t,r,e)}calculate(e,t,r,a){return n(e,t,r,a)}evaluateTime(e){return d(e)}evaluateTimestamp(e,t){return f(e,t)}evaluateDate(e,t){return _(e,t)}evaluateFunction(e,t,r){return T(e,t,r)}lookup(e,t){const r=t[e];return void 0===r?null:r}between(e,t){return null==e||null==t[0]||null==t[1]?null:i(e,t[0],">=")&&i(e,t[1],"<=")}notbetween(e,t){return null==e||null==t[0]||null==t[1]?null:i(e,t[0],"<")||i(e,t[1],">")}ternaryNot(e){return W(e)}ternaryAnd(e,t){return G(e,t)}ternaryOr(e,t){return K(e,t)}}function A(e,...t){return`this.${e}(${t.join(", ")})`}function V(e){return void 0===e?"void 0":JSON.stringify(e)}function O({type:e,start:t,end:r}){return`{type: ${V(e)}, start: ${U(t)}, end: ${U(r)}}`}function U({type:e,period:t,precision:r,secondary:a}){return JSON.stringify({type:e,period:t,precision:r,secondary:a})}function j({type:e,size:t,withtimezone:r}){return JSON.stringify({type:e,size:t,withtimezone:r})}const k="feature",q="lookups",C="attributeAdapter",R="fieldsIndex",L="timeZone",Z="currentUser";class z{constructor(e,t){this._parseTree=e,this._fieldsIndex=t,this._staticData=Object.create(null),this._nextStaticDataId=0,this._tempVars=new Set,this._nextTempVarId=0}compile(){const e=this._compileNode(this._parseTree),t=`\n ${this._tempVars.size>0?`var ${Array.from(this._tempVars).join(", ")};`:""}\n return this.convertInterval(${e});\n `;return new Function(k,q,C,R,L,Z,t).bind(new b(this._staticData))}_storeStaticData(e){const t="static$"+this._nextStaticDataId++;return this._staticData[t]=e,t}_compileRefStaticData(e){return`this.staticData[${V(e)}]`}_generateTempVar(){const e="temp$"+this._nextTempVarId++;return this._tempVars.add(e),e}_compileSimpleCase(e){const t=this._compileNode(e.operand),r=this._generateTempVar(),a=[];for(const s of e.clauses){const e=A("compare",V("="),r,this._compileNode(s.operand)),t=this._compileNode(s.value);a.push(`${e} ? (${t}) :`)}return null!=e.else?a.push(this._compileNode(e.else)):a.push(V(null)),`(${r} = ${t}, ${a.join(" ")})`}_compileSearchedCase(e){const t=[];for(const r of e.clauses){const e=A("makeBool",this._compileNode(r.operand)),a=this._compileNode(r.value);t.push(`${e} ? (${a}) :`)}return null!=e.else?t.push(this._compileNode(e.else)):t.push(V(null)),t.join(" ")}_compileInExpr(e,t){const r=new Set,a=[];for(const i of t.value)"number"===i.type||"string"===i.type?r.add(i.value):a.push(i);const s=this._compileNode(e),n=A("ensureArray",this._compileNode({type:"expression-list",location:t.location,value:a}));if(r.size>0){const e=this._compileRefStaticData(this._storeStaticData(r)),t=this._generateTempVar();return a.length>0?`(${t} = ${s}, ${e}.has(${t}) || ${A("applyIn",t,n)})`:`(${t} = ${s}, ${t} == null ? null : ${e}.has(${t}))`}return A("applyIn",s,n)}_compileNode(e){switch(e.type){case"interval":return A("makeSqlInterval",this._compileNode(e.value),"interval-qualifier"===e.qualifier.type?O(e.qualifier):U(e.qualifier),V(e.op));case"case-expression":return"simple"===e.format?this._compileSimpleCase(e):this._compileSearchedCase(e);case"parameter":return A("lookup",V(e.value.toLowerCase()),q);case"expression-list":return`[${e.value.map(e=>this._compileNode(e)).join(", ")}]`;case"unary-expression":return A("ternaryNot",this._compileNode(e.expr));case"binary-expression":switch(e.operator){case"AND":return A("ternaryAnd",this._compileNode(e.left),this._compileNode(e.right));case"OR":return A("ternaryOr",this._compileNode(e.left),this._compileNode(e.right));case"IS":if("null"!==e.right.type)throw new s("UnsupportedIsRhs");return A("equalsNull",this._compileNode(e.left));case"ISNOT":if("null"!==e.right.type)throw new s("UnsupportedIsRhs");return`!${A("equalsNull",this._compileNode(e.left))}`;case"IN":return this._compileInExpr(e.left,e.right);case"NOT IN":return A("ternaryNot",this._compileInExpr(e.left,e.right));case"BETWEEN":return A("between",this._compileNode(e.left),this._compileNode(e.right));case"NOTBETWEEN":return A("notbetween",this._compileNode(e.left),this._compileNode(e.right));case"LIKE":return A("applyLike",this._compileNode(e.left),this._compileNode(e.right),V(e.escape));case"NOT LIKE":return A("ternaryNot",A("applyLike",this._compileNode(e.left),this._compileNode(e.right),V(e.escape)));case"<>":case"<":case">":case">=":case"<=":case"=":if(re(e,e.operator,this._fieldsIndex)){const t=e.comparisonData;return A("compare",V(t.op),A("featureValue",k,V(t.fieldName),V(null),C),this._compileRefStaticData(this._storeStaticData(t.comparisonEpochMs)))}return A("compare",V(e.operator),this._compileNode(e.left),this._compileNode(e.right));case"*":case"-":case"+":case"/":case"||":return A("calculate",V(e.operator),this._compileNode(e.left),this._compileNode(e.right),L);default:throw new s("UnsupportedOperator",{operator:e.operator})}case"null":case"boolean":case"string":case"number":return V(e.value);case"time":try{return this._compileRefStaticData(this._storeStaticData(d(e.value)))}catch{return A("evaluateTime",V(e.value))}case"date":try{return this._compileRefStaticData(this._storeStaticData(_(e.value,"unknown")))}catch{return A("evaluateDate",V(e.value),V("unknown"))}case"timestamp":try{return this._compileRefStaticData(this._storeStaticData(f(e.value,"unknown")))}catch{return A("evaluateTimestamp",V(e.value),V("unknown"))}case"current-time":return"date"===e.mode?A("currentDate",L):"time"===e.mode?A("currentTime",L):A("currentTimestamp",L);case"current-user":return Z;case"column-reference":return A("featureValue",k,V(e.column),R,C);case"data-type":return j(e.value);case"function":return A("evaluateFunction",V(e.name),this._compileNode(e.args),L)}throw new s("UnsupportedSyntax",{node:e.type})}}class M{static create(e,t={}){return new M(e,t.fieldsIndex,t.timeZone??void 0,t.currentUser)}constructor(e,t,r="UTC",a=null){this.fieldsIndex=t,this.timeZone=r,this.currentUser=a,this.parameters={},this._compiledExecutor=null,this._hasDateFunctions=void 0,this.parseTree=D.parse(e);const{isStandardized:s,isAggregate:n,currentUserRequired:i,referencedFieldNames:o}=this._extractExpressionInfo(t);this._referencedFieldNames=o,this.isStandardized=s,this.isAggregate=n,this.currentUserRequired=i}static convertValueToStorageFormat(e,t=null){if(null===t)return I(e)?e.getTime():c(e)?e.toMillis():p(e)?e.toStorageFormat():m(e)?e.toStorageString():h(e)?e.toStorageFormat():e;switch(t){case"date":return I(e)?e.getTime():c(e)?e.toMillis():p(e)?e.toMilliseconds():h(e)?e.toNumber():e;case"date-only":return I(e)?a.fromDateJS(e).toString():p(e)?a.fromSqlTimeStampOffset(e).toString():c(e)?a.fromDateTime(e).toString():e;case"time-only":return I(e)?w.fromDateJS(e).toStorageString():c(e)?w.fromDateTime(e).toStorageString():p(e)?w.fromSqlTimeStampOffset(e).toStorageString():m(e)?e.toStorageString():e;case"timestamp-offset":if(I(e))return v.fromJSDate(e).toStorageFormat();if(c(e))return v.fromDateTime(e).toStorageFormat();if(p(e))return e.toStorageFormat()}return e}get fieldNames(){return this._referencedFieldNames}testSet(e,t=ne,r=this.currentUser){return!!this._evaluateNode(this.parseTree,null,t,e,r)}calculateValue(e,t=ne,r=this.currentUser){const a=this._evaluateNode(this.parseTree,e,t,null,r);return g.isInterval(a)?a.valueInMilliseconds()/864e5:a}tryGetCompiledExecutor(){if(null!=this._compiledExecutor)return this._compiledExecutor;if(has("esri-csp-restrictions"))return null;const e=new z(this.parseTree,this.fieldsIndex);return this._compiledExecutor=e.compile(),this._compiledExecutor}calculateValueCompiled(e,t=ne,r=this.currentUser){const a=this.tryGetCompiledExecutor();return null==a?this.calculateValue(e,t):a(e,this.parameters,t,this.fieldsIndex,this.timeZone,r??null)}testFeature(e,t=ne,r=this.currentUser){return!!this._evaluateNode(this.parseTree,e,t,null,r)}testFeatureCompiled(e,t=ne,r=this.currentUser){const a=this.tryGetCompiledExecutor();return null==a?this.testFeature(e,t):!!a(e,this.parameters,t,this.fieldsIndex,this.timeZone,r??null)}get hasDateFunctions(){return null!=this._hasDateFunctions||(this._hasDateFunctions=e(y(this.parseTree),e=>"current-time"===e.type||"function"===e.type&&F.has(e.name.toLowerCase()))),this._hasDateFunctions}getFunctions(){const e=new Set;for(const t of y(this.parseTree))"function"===t.type&&e.add(t.name.toLowerCase());return Array.from(e)}getExpressions(){const e=new Map;for(const t of y(this.parseTree))if("function"===t.type){const r=t.name.toLowerCase(),a=t.args.value[0];if("column-reference"===a.type){const t=a.column,s=`${r}-${t}`;e.has(s)||e.set(s,{aggregateType:r,field:t})}}return Array.from(e.values())}getVariables(){const e=new Set;for(const t of y(this.parseTree))"parameter"===t.type&&e.add(t.value.toLowerCase());return Array.from(e)}_extractExpressionInfo(e){const r=[],a=new Set;let s=!0,n=!1,i=!1;for(const o of y(this.parseTree))switch(o.type){case"column-reference":{const t=e?.get(o.column);let s,n;t?s=n=t.name??"":(n=o.column,s=n.toLowerCase()),a.has(s)||(a.add(s),r.push(n)),o.column=n;break}case"current-user":i=!0;break;case"function":{const{name:e,args:r}=o,a=r.value.length;s&&(s=S(e,a)),!1===n&&(n=t(e,a));break}}return{referencedFieldNames:Array.from(r),isStandardized:s,isAggregate:n,currentUserRequired:i}}_evaluateNode(e,a,o,l,u){let c;switch(e.type){case"interval":{const t=this._evaluateNode(e.value,a,o,l,u);return g.createFromValueAndQualifier(t,e.qualifier,e.op)}case"case-expression":if("simple"===e.format){const t=this._evaluateNode(e.operand,a,o,l,u);for(let r=0;r<e.clauses.length;r++)if(i(t,this._evaluateNode(e.clauses[r].operand,a,o,l,u),"="))return this._evaluateNode(e.clauses[r].value,a,o,l,u);if(null!==e.else)return this._evaluateNode(e.else,a,o,l,u)}else{for(let t=0;t<e.clauses.length;t++)if(J(this._evaluateNode(e.clauses[t].operand,a,o,l,u)))return this._evaluateNode(e.clauses[t].value,a,o,l,u);if(null!==e.else)return this._evaluateNode(e.else,a,o,l,u)}return null;case"parameter":return c=this.parameters[e.value.toLowerCase()],I(c)?$.fromJSDate(c):null!=c&&"object"==typeof c&&"toDateTime"in c?c.toDateTime():c;case"expression-list":{const t=[];for(const r of e.value)t.push(this._evaluateNode(r,a,o,l,u));return t}case"unary-expression":return W(this._evaluateNode(e.expr,a,o,l,u));case"binary-expression":switch(e.operator){case"AND":return G(this._evaluateNode(e.left,a,o,l,u),this._evaluateNode(e.right,a,o,l,u));case"OR":return K(this._evaluateNode(e.left,a,o,l,u),this._evaluateNode(e.right,a,o,l,u));case"IS":if("null"!==e.right.type)throw new s("UnsupportedIsRhs");return null===this._evaluateNode(e.left,a,o,l,u);case"ISNOT":if("null"!==e.right.type)throw new s("UnsupportedIsRhs");return null!==this._evaluateNode(e.left,a,o,l,u);case"IN":{const t=B(this._evaluateNode(e.right,a,o,l,u));return Q(this._evaluateNode(e.left,a,o,l,u),t)}case"NOT IN":{const t=B(this._evaluateNode(e.right,a,o,l,u));return W(Q(this._evaluateNode(e.left,a,o,l,u),t))}case"BETWEEN":{const t=this._evaluateNode(e.left,a,o,l,u),r=this._evaluateNode(e.right,a,o,l,u);return null==t||null==r[0]||null==r[1]?null:i(t,r[0],">=")&&i(t,r[1],"<=")}case"NOTBETWEEN":{const t=this._evaluateNode(e.left,a,o,l,u),r=this._evaluateNode(e.right,a,o,l,u);return null==t||null==r[0]||null==r[1]?null:i(t,r[0],"<")||i(t,r[1],">")}case"LIKE":return te(this._evaluateNode(e.left,a,o,l,u),this._evaluateNode(e.right,a,o,l,u),e.escape);case"NOT LIKE":return W(te(this._evaluateNode(e.left,a,o,l,u),this._evaluateNode(e.right,a,o,l,u),e.escape));case"<>":case"<":case">":case">=":case"<=":case"=":if(re(e,e.operator,this.fieldsIndex)){const t=e.comparisonData;return i(se(a,t.fieldName,null,o),t.comparisonEpochMs,t.op)}return i(this._evaluateNode(e.left,a,o,l,u),this._evaluateNode(e.right,a,o,l,u),e.operator);case"-":case"+":case"*":case"/":case"||":return n(e.operator,this._evaluateNode(e.left,a,o,l,u),this._evaluateNode(e.right,a,o,l,u),this.timeZone)}case"null":case"boolean":case"string":case"number":return e.value;case"date":return e.parsedValue??=_(e.value,"unknown"),e.parsedValue;case"timestamp":return e.parsedValue??=f(e.value,"unknown"),e.parsedValue;case"time":return e.parsedValue??=d(e.value),e.parsedValue;case"current-time":return"date"===e.mode?H(this.timeZone):"time"===e.mode?X(this.timeZone):P(this.timeZone);case"current-user":return u??null;case"column-reference":return se(a,e.column,this.fieldsIndex,o);case"data-type":return e.value;case"function":{if(this.isAggregate&&t(e.name,e.args.value.length)){const t=[];for(const r of e.args?.value||[]){const e=[];for(const t of l||[])e.push(this._evaluateNode(r,t,o,null,u));t.push(e)}return r(e.name,t)}const s=this._evaluateNode(e.args,a,o,l,u);return T(e.name,s,this.timeZone)}}throw new s("UnsupportedSyntax",{node:e.type})}}function J(e){return!0===e}function B(e){return Array.isArray(e)?e:[e]}function W(e){return null!==e?!0!==e:null}function G(e,t){return null!=e&&null!=t?!0===e&&!0===t:!1!==e&&!1!==t&&null}function K(e,t){return null!=e&&null!=t?!0===e||!0===t:!0===e||!0===t||null}function Q(e,t){if(null==e)return null;let r=!1;for(const a of t)if(null==a)r=null;else{if(e===a){r=!0;break}if(u(e)&&u(a)&&(r=i(e,a,"="),r))break}return r}function P(e){return N(new Date,e)}function H(e){return a.fromNow(e)}function X(e){const t=N(new Date,e);return w.fromDateTime(t)}const Y="-[]/{}()*+?.\\^$|";function ee(e,t){const r=t;let a="",s=0;for(let n=0;n<e.length;n++){const t=e.charAt(n);switch(s){case 0:t===r?s=1:Y.includes(t)?a+="\\"+t:a+="%"===t?".*":"_"===t?".":t;break;case 1:Y.includes(t)?a+="\\"+t:a+=t,s=0}}return new RegExp("^"+a+"$","m")}function te(e,t,r){if(null==e)return null;return ee(t,r).test(e)}function re(e,t,r){if("comparisonData"in e)return null!=e.comparisonData;try{if(null==r)return!1;let a,s;if("column-reference"===e.left.type&&"timestamp"===e.right.type)a=e.left,s=e.right;else{if("timestamp"!==e.left.type||"column-reference"!==e.right.type)return!1;a=e.right,s=e.left,t=o(t)}const n=r.get(a.column);if("esriFieldTypeDate"!==n?.type&&"date"!==n?.type)return!1;const i=r.getTimeZone(n.name),u=null!=i?x(i):E.utcInstance;return!!u.isUniversal&&(e.comparisonData=l(n.name,u,t,s.value),!0)}finally{"comparisonData"in e||(e.comparisonData=null)}}function ae(e){return e&&"object"==typeof e.attributes}function se(e,t,r,s){if("getAttributeSQL"in s)return s.getAttributeSQL(e,t);const n=s.getAttribute(e,t);if(null==n)return n;const i=r?.get(t);switch(i?.type){case"esriFieldTypeDate":case"date":{const e=r?.getTimeZone(i.name);return N(new Date(n),null!=e?x(e):E.utcInstance)}case"esriFieldTypeDateOnly":case"date-only":return a.fromReader(n);case"esriFieldTypeTimeOnly":case"time-only":return w.fromReader(n);case"esriFieldTypeTimestampOffset":case"timestamp-offset":return new v(n)}return n}const ne={getAttribute:(e,t)=>(ae(e)?e.attributes:e)[t]};export{M as default};