UNPKG

@codetanzania/emis-incident-type

Version:

A representation of an entity which classify emergency(or disaster) from the most generalised(nature and family) to the most specific (main event and peril).

650 lines (608 loc) 18.5 kB
'use strict'; /** * @module IncidentType * @name IncidentType * @alias Disaster * @alias Hazard * @alias EventType * @description A representation of an entity which classify * emergency(or disaster) from the most generalised(nature and family) to the * most specific (main event and peril). * * @see {@link https://en.wikipedia.org/wiki/Disaster} * @see {@link https://www.unisdr.org/we/inform/terminology} * @see {@link https://www.emdat.be/Glossary} * @see {@link http://www.irdrinternational.org/wp-content/uploads/2014/04/IRDR_DATA-Project-Report-No.-1.pdf} * @see {@link http://cred.be/sites/default/files/DisCatClass_264.pdf} * @see {@link http://cred.be/sites/default/files/DisCatClass_264.pdf} * @see {@link https://www.emdat.be/guidelines} * @see {@link http://www.glidenumber.net/glide/public/about.jsp} * * @author lally elias <lallyelias87@gmail.com> * @license MIT * @since 0.1.0 * @version 1.1.0 * @public */ /* dependencies */ const _ = require('lodash'); const { getString, getStrings } = require('@lykmapipo/env'); const { Schema, SchemaTypes, model, SCHEMA_OPTIONS, copyInstance, } = require('@lykmapipo/mongoose-common'); const actions = require('mongoose-rest-actions'); const randomColor = require('randomcolor'); const { ObjectId } = SchemaTypes; /* constants */ /* natures */ const NATURE_OTHER = 'Generic'; const NATURE_NATURAL = 'Natural'; const NATURE_TECHNOLOGICAL = 'Technological'; const NATURES = getStrings('INCIDENTTYPE_NATURES', [ NATURE_NATURAL, NATURE_TECHNOLOGICAL, NATURE_OTHER, ]); /* families */ const FAMILY_OTHER = 'Generic'; const FAMILIES = getStrings('INCIDENTTYPE_FAMILIES', [ 'Geophysical', 'Meteorological', 'Hydrological', 'Climatological', 'Biological', 'Extra-terrestrial', 'Accident', 'Fire', 'Terrorism', 'Conflicts', 'Technological', FAMILY_OTHER, ]); /* cap categories */ const CAP_CATEGORY_OTHER = 'Generic'; const CAP_CATEGORIES = getStrings('INCIDENTTYPE_CAP_CATEGORIES', [ 'Geo', 'Met', 'Safety', 'Security', 'Rescue', 'Fire', 'Health', 'Env', 'Transport', 'Infra', 'CBRNE', CAP_CATEGORY_OTHER, ]); /* schema options */ const POPULATION_MAX_DEPTH = 1; const MODEL_NAME = getString('MODEL_NAME', 'IncidentType'); const COLLECTION_NAME = getString('COLLECTION_NAME', 'incidenttypes'); const OPTION_AUTOPOPULATE = { select: { code: 1, nature: 1, family: 1, name: 1, color: 1, icon: 1 }, maxDepth: POPULATION_MAX_DEPTH, }; /** * @name IncidentTypeSchema * @type {Schema} * @since 0.1.0 * @version 1.1.0 * @private */ const IncidentTypeSchema = new Schema( { /** * @name main * @description Top(generic or main) incident type(or disaster) under * which specific incident type(or disaster) is derived. * * If not set the incident type will be treated as generic and will be * affected by any logics implemented accordingly. * * @type {object} * @property {object} type - schema(data) type * @property {string} ref - referenced model(or collection) * @property {boolean} index - ensure database index * @property {boolean} exists - ensure ref exists before save * @property {object} autopopulate - auto population(eager loading) options * @property {boolean} taggable - allow field use for tagging * * @since 1.1.0 * @version 0.1.0 * @instance * @example * { * _id: "5bcda2c073dd0700048fb846", * "nature": "Natural", * "family": "Hydrological", * "name": "Flood", * "color": "#45b726" * } */ main: { type: ObjectId, ref: MODEL_NAME, index: true, exists: true, autopopulate: OPTION_AUTOPOPULATE, taggable: true, }, /** * @name nature * @description Human readable nature(or origin) of * an incident type(or disaster) i.e Natural or Technological/Man-Made. * * @type {object} * @property {object} type - schema(data) type * @property {boolean} trim - force trimming * @property {boolean} required - mark required * @property {string[]} enum - collection of allowed values * @property {boolean} index - ensure database index * @property {boolean} searchable - allow for searching * @property {boolean} taggable - allow field use for tagging * @property {object} fake - fake data generator options * * @since 0.1.0 * @version 1.1.0 * @instance * @example * Natural */ nature: { type: String, trim: true, required: true, enum: NATURES, default: NATURE_OTHER, index: true, searchable: true, taggable: true, fake: true, }, /** * @name family * @description Human readable family(group) of an incident(or disaster) * i.e Biological, Climatological etc. * * @type {object} * @property {object} type - schema(data) type * @property {boolean} trim - force trimming * @property {boolean} required - mark required * @property {string[]} enum - collection of allowed values * @property {boolean} index - ensure database index * @property {boolean} searchable - allow for searching * @property {boolean} taggable - allow field use for tagging * @property {object} fake - fake data generator options * * @since 0.1.0 * @version 1.1.0 * @instance * @example * Biological */ family: { type: String, trim: true, required: true, enum: FAMILIES, default: FAMILY_OTHER, index: true, searchable: true, taggable: true, fake: true, }, /** * @name code * @description Human readable given code of an incident type(or disaster). * * If not specified it will be generated from first letters of nature, * family and name of incident type(or disaster). * * @type {object} * @property {object} type - schema(data) type * @property {boolean} trim - force trimming * @property {boolean} uppercase - force value to uppercase * @property {boolean} required - mark required * @property {boolean} index - ensure database index * @property {boolean} searchable - allow searching * @property {boolean} taggable - allow field use for tagging * * @author lally elias <lallyelias87@gmail.com> * @since 1.1.0 * @version 1.1.0 * @instance * @example * NHF */ code: { type: String, trim: true, uppercase: true, required: true, index: true, searchable: true, taggable: true, }, /** * @name cap * @description Human readable Common Alert Protocol(CAP) code(or category) * of an incident type(or disaster). * * @type {object} * @property {object} type - schema(data) type * @property {boolean} trim - force trimming * @property {boolean} required - mark required * @property {string[]} enum - collection of allowed values * @property {boolean} index - ensure database index * @property {boolean} searchable - allow for searching * @property {boolean} taggable - allow field use for tagging * @property {object} fake - fake data generator options * * @author lally elias <lallyelias87@gmail.com> * @since 0.1.0 * @version 1.0.0 * @instance * @example * Geo */ cap: { type: String, trim: true, required: true, enum: CAP_CATEGORIES, default: CAP_CATEGORY_OTHER, index: true, searchable: true, taggable: true, fake: true, }, /** * @name name * @description Human readable name of an incident type(or disaster) * e.g Flood etc. * * @type {object} * @property {object} type - schema(data) type * @property {boolean} trim - force trimming * @property {boolean} required - mark required * @property {boolean} startcase - forcing start case(or title case) * @property {boolean} index - ensure database index * @property {boolean} searchable - allow searching * @property {boolean} taggable - allow field use for tagging * @property {object} fake - fake data generator options * * @since 0.1.0 * @version 1.1.0 * @instance * @example * Flood */ name: { type: String, trim: true, required: true, startcase: true, index: true, searchable: true, taggable: true, fake: { generator: 'hacker', type: 'noun', }, }, /** * @name description * @description A brief summary(definition) about an incident type if * available i.e additional details that clarify what is an * incident type(or disaster). * * @type {object} * @property {object} type - schema(data) type * @property {boolean} trim - force trimming * @property {boolean} index - ensure database index * @property {boolean} searchable - allow for searching * @property {object} fake - fake data generator options * * @since 0.1.0 * @version 1.1.0 * @instance * @example * Overflow of water from a stream channel onto normally dry land. */ description: { type: String, trim: true, index: true, searchable: true, fake: { generator: 'lorem', type: 'paragraph', }, }, /** * @name color * @description A color code(in hexadecimal format) used to differentiate * incident types visually. * * @type {object} * @property {object} type - schema(data) type * @property {boolean} trim - force trimming * @property {boolean} uppercase - force upper-casing * @property {boolean} default - default value set when none provided * @property {object} fake - fake data generator options * * @since 0.1.0 * @version 1.1.0 * @instance * @example * #20687C */ color: { type: String, trim: true, uppercase: true, default: function() { return randomColor({ luminosity: 'light' }); }, fake: true, }, /** * @name icon * @description An icon(in url, base64, svg formats) used to differentiate * incident types(or disaster) visually. * * @type {object} * @property {object} type - schema(data) type * @property {boolean} trim - force trimming * @property {boolean} default - default value set when none provided * * @since 1.1.0 * @version 0.1.0 * @instance */ icon: { type: String, trim: true, }, /** * @name characteristics * @description Human readable typical or noticeable features associated * with an incident type(or disaster) event. * * @type {object} * @property {object} type - schema(data) type * @property {boolean} default - default value set when none provided * @property {boolean} compact - remove falsey values * @property {boolean} duplicate - remove duplicate values * @property {boolean} index - ensure database index * @property {boolean} searchable - allow for searching * @property {object} fake - fake data generator options * * @since 1.1.0 * @version 0.1.0 * @instance */ characteristics: { type: [String], default: undefined, compact: true, duplicate: false, index: true, searchable: true, fake: { generator: 'lorem', type: 'sentence', }, }, /** * @name causes * @description Human readable possible actions or conditions that may lead * to an incident type(or disaster) event. * * @type {object} * @property {object} type - schema(data) type * @property {boolean} default - default value set when none provided * @property {boolean} compact - remove falsey values * @property {boolean} duplicate - remove duplicate values * @property {boolean} index - ensure database index * @property {boolean} searchable - allow for searching * @property {object} fake - fake data generator options * * @since 1.1.0 * @version 0.1.0 * @instance */ causes: { type: [String], default: undefined, compact: true, duplicate: false, index: true, searchable: true, fake: { generator: 'lorem', type: 'sentence', }, }, /** * @name areas * @description Areas(i.e city, state, village etc) liable to suffer from * an incident type(or disaster) events. * * @type {object} * @property {object} type - schema(data) type * @property {boolean} default - default value set when none provided * @property {boolean} compact - remove falsey values * @property {boolean} duplicate - remove duplicate values * @property {boolean} index - ensure database index * @property {boolean} searchable - allow for searching * @property {boolean} taggable - allow field use for tagging * @property {object} fake - fake data generator options * * @since 1.1.0 * @version 0.1.0 * @instance */ areas: { type: [String], default: undefined, compact: true, duplicate: false, index: true, searchable: true, taggable: true, fake: { generator: 'address', type: 'streetName', }, }, /** * @name risks * @alias injuries * @description Human readable possible risks or injuries that may be caused * by an incident type(or disaster) event. * * @type {object} * @property {object} type - schema(data) type * @property {boolean} default - default value set when none provided * @property {boolean} compact - remove falsey values * @property {boolean} duplicate - remove duplicate values * @property {boolean} index - ensure database index * @property {boolean} searchable - allow for searching * @property {object} fake - fake data generator options * * @since 1.1.0 * @version 0.1.0 * @instance */ risks: { type: [String], default: undefined, compact: true, duplicate: false, index: true, searchable: true, fake: { generator: 'lorem', type: 'sentence', }, }, }, SCHEMA_OPTIONS ); /* *------------------------------------------------------------------------------ * Indexes *------------------------------------------------------------------------------ */ const uniqueIndex = { nature: 1, family: 1, name: 1, code: 1 }; IncidentTypeSchema.index(uniqueIndex, { unique: true }); /* *------------------------------------------------------------------------------ * Hook *------------------------------------------------------------------------------ */ IncidentTypeSchema.pre('validate', function preValidate(next) { this.preValidate(next); }); /* *------------------------------------------------------------------------------ * Instance *------------------------------------------------------------------------------ */ /** * @name preValidate * @function preValidate * @description incident type schema pre validation hook logic * @param {function} done callback to invoke on success or error * @since 1.1.0 * @version 0.1.0 * @instance */ IncidentTypeSchema.methods.preValidate = function preValidate(done) { // copy from parent this.nature = this.nature || _.get(this, 'main.nature'); this.family = this.family || _.get(this, 'main.family'); this.cap = this.cap || _.get(this, 'main.cap'); this.color = this.color || _.get(this, 'main.color'); this.icon = this.icon || _.get(this, 'main.icon'); // ensure given code if (this.name && _.isEmpty(this.code)) { // TODO honor main incident type // prepare given code let code = _.compact( [this.nature, this.family].concat(this.name.split(' ')) ); // generate given code code = _.reduce( code, function generateGivenCode(code, word) { return _.toUpper(code + _.first(word)); }, '' ); // assign given code this.code = code; } // set color if (_.isEmpty(this.color)) { this.color = randomColor({ luminosity: 'light' }); } // continue return done(); }; /* *------------------------------------------------------------------------------ * Statics *------------------------------------------------------------------------------ */ /* constants */ IncidentTypeSchema.statics.MODEL_NAME = MODEL_NAME; IncidentTypeSchema.statics.COLLECTION_NAME = COLLECTION_NAME; IncidentTypeSchema.statics.OPTION_AUTOPOPULATE = OPTION_AUTOPOPULATE; IncidentTypeSchema.statics.POPULATION_MAX_DEPTH = POPULATION_MAX_DEPTH; IncidentTypeSchema.statics.NATURE_OTHER = NATURE_OTHER; IncidentTypeSchema.statics.NATURE_NATURAL = NATURE_NATURAL; IncidentTypeSchema.statics.NATURE_TECHNOLOGICAL = NATURE_TECHNOLOGICAL; IncidentTypeSchema.statics.NATURES = NATURES; IncidentTypeSchema.statics.FAMILY_OTHER = FAMILY_OTHER; IncidentTypeSchema.statics.FAMILIES = FAMILIES; IncidentTypeSchema.statics.CAP_CATEGORY_OTHER = CAP_CATEGORY_OTHER; IncidentTypeSchema.statics.CAP_CATEGORIES = CAP_CATEGORIES; /** * @name prepareSeedCriteria * @function prepareSeedCriteria * @description prepare incidenttype seeding upsert criteria * @param {Object} seed plain object incidenttype seed * @return {Object} criteria used to upsert incidenttype * * @author lally elias <lallyelias87@gmail.com> * @since 1.5.0 * @version 0.1.0 * @public */ IncidentTypeSchema.statics.prepareSeedCriteria = seed => { // prepare incidenttype upsert criteria by _id or fields let criteria = copyInstance(seed); criteria = ( criteria._id ? _.pick(criteria, '_id') : _.pick(criteria, 'nature', 'family', 'name') ); // return incidenttypes upsert criteria return criteria; }; /* *------------------------------------------------------------------------------ * Plugins *------------------------------------------------------------------------------ */ /* plug mongoose rest actions */ IncidentTypeSchema.plugin(actions); /* export incident type model */ exports = module.exports = model(MODEL_NAME, IncidentTypeSchema);