All files / FeatureServer/lib/generate-renderer validate-classification-definition.js

100% Statements 32/32
100% Branches 18/18
100% Functions 7/7
100% Lines 32/32

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 1061x 1x   1x                                                                 19x 15x 11x       19x   19x 4x 4x               15x   15x 10x     5x 4x     4x 4x         5x     2x   1x   1x           11x 11x 8x     3x 1x   2x   2x 1x         2x 2x       1x  
const joi = require('joi')
const { CodedError } = require('../helpers/errors')
 
const classificationDefinitionSchema = joi
  .object({
    type: joi
      .string()
      .valid('classBreaksDef', 'uniqueValueDef')
      .error(new Error('invalid classification type')),
    baseSymbol: joi
      .object({
        type: joi
          .string()
          .valid('esriSMS', 'esriSLS', 'esriSFS')
          .required()
          .error(
            new Error(
              'baseSymbol requires a valid type: esriSMS, esriSLS, esriSFS'
            )
          )
      })
      .optional()
      .unknown(),
    uniqueValueFields: joi.array().items(joi.string())
  })
  .required()
  .unknown()
  .messages({
    'any.required': 'classification definition is required'
  })
 
function validateClassificationDefinition (
  definition,
  geometryType,
  classification
) {
  validateDefinitionShape(definition)
  validateDefinitionSymbolAgainstGeometry(definition.baseSymbol, geometryType)
  validateUniqueValueFields(definition, classification)
}
 
function validateDefinitionShape (definition) {
  const { error } = classificationDefinitionSchema.validate(definition)
 
  if (error) {
    error.code = 400
    throw error
  }
}
 
function validateDefinitionSymbolAgainstGeometry (
  baseSymbol = {},
  geometryType
) {
  const { type: symbolType } = baseSymbol
 
  if (!symbolType) {
    return
  }
 
  if (symbolLookup(geometryType) !== symbolType) {
    const error = new Error(
      'Classification defintion uses a base symbol type that is incompatiable with dataset geometry'
    )
    error.code = 400
    throw error
  }
}
 
function symbolLookup (geometryType) {
  switch (geometryType) {
    case 'esriGeometryPoint':
    case 'esriGeometryMultipoint':
      return 'esriSMS'
    case 'esriGeometryPolyline':
      return 'esriSLS'
    case 'esriGeometryPolygon':
      return 'esriSFS'
    default:
  }
}
 
function validateUniqueValueFields (definition, classification) {
  const { uniqueValueFields, type } = definition
  if (type !== 'uniqueValueDef') {
    return
  }
 
  if (!uniqueValueFields) {
    throw new CodedError('uniqueValueDef requires a classification definition with "uniqueValueFields" array', 400)
  }
  const classificationFieldNames = Object.keys(classification[0])
 
  if (areFieldsMissingFromClassification(uniqueValueFields, classificationFieldNames)) {
    throw new CodedError(`Unique value definition fields are incongruous with classification fields: ${uniqueValueFields.join(', ')} : ${classificationFieldNames.join(', ')}`, 400)
  }
}
 
function areFieldsMissingFromClassification (definitionFields, classificationFieldNames) {
  return definitionFields.some(
    (fieldName) => !classificationFieldNames.includes(fieldName)
  )
}
 
module.exports = validateClassificationDefinition