All files / lib/query filter-and-transform.js

93.87% Statements 46/49
94.28% Branches 33/35
100% Functions 10/10
93.87% Lines 46/49

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 1147x 7x 7x     14x 14x           14x   14x   14x 1x           13x 8x     5x               14x       14x       14x 6x 1x     6x 1x     6x 1x     6x     14x       14x 14x       14x 14x 14x 14x       14x 9x       5x 1x 4x 3x 1x 1x             5x 7x 1x     6x     5x         5x   5x 15x       7x  
const _ = require('lodash')
const { query } = require('winnow')
const helpers = require('../helpers')
 
function filterAndTransform (json, requestParams) {
  const { features, type, ...restJson } = json
  const params = FilterAndTransformParams.create(requestParams)
    .removeParamsAlreadyApplied(json.filtersApplied)
    .addToEsri()
    .addInputCrs(json)
    .normalizeObjectIds()
 
  const result = query(json, params)
 
  const { objectIds, outStatistics } = params
 
  if (outStatistics) {
    return {
      statistics: result,
      ...restJson
    }
  }
 
  if (!objectIds) {
    return result
  }
 
  return {
    ...result,
    features: filterByObjectIds(result, objectIds)
  }
}
 
class FilterAndTransformParams {
  static create (requestParams) {
    return new FilterAndTransformParams(requestParams)
  }
 
  constructor (requestParams) {
    Object.assign(this, requestParams)
  }
 
  removeParamsAlreadyApplied (alreadyApplied) {
    for (const key in alreadyApplied) {
      if (key === 'projection') {
        delete this.outSR
      }
 
      if (key === 'offset') {
        delete this.resultOffset
      }
 
      if (key === 'limit') {
        delete this.resultRecordCount
      }
 
      delete this[key]
    }
 
    return this
  }
 
  addToEsri () {
    this.toEsri = this.f !== 'geojson' && !this.returnExtentOnly
    return this
  }
 
  addInputCrs (data = {}) {
    const { metadata = {} } = data
    this.inputCrs = this.inputCrs || this.sourceSR || metadata.crs || helpers.getCollectionCrs(data) || 4326
    delete this.sourceSR
    return this
  }
 
  normalizeObjectIds () {
    if (!this.objectIds) {
      return this
    }
 
    let ids
    if (Array.isArray(this.objectIds)) {
      ids = this.objectIds
    } else if (typeof this.objectIds === 'string') {
      ids = this.objectIds.split(',')
    } else Eif (typeof this.objectIds === 'number') {
      ids = [this.objectIds]
    } else {
      const error = new Error('Invalid "objectIds" parameter.')
      error.code = 400
      throw error
    }
 
    this.objectIds = ids.map(i => {
      if (isNaN(i)) {
        return i
      }
 
      return parseInt(i)
    })
 
    return this
  }
}
 
function filterByObjectIds (data, objectIds) {
  const idField = _.get(data, 'metadata.idField') || 'OBJECTID'
 
  return data.features.filter(({ attributes = {}, properties = {} }) => {
    return objectIds.includes(attributes[idField]) || objectIds.includes(properties[idField])
  })
}
 
module.exports = { filterAndTransform }