@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
JavaScript
'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);