All files / 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                                                                 16x 12x 8x       16x   16x 4x 4x               12x   12x 7x     5x 4x     4x 4x         5x     2x   1x   1x           8x 8x 5x     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