UNPKG

@absolute/change-tracker-node-sdk

Version:

ChangeTracker SDK for Node.js

179 lines (152 loc) 5.63 kB
const {Field, Row, Table} = require('./models') /** * createMap - Create ModelMapper * @param {object} model - the model to map * @returns {ModelMapper} ModelMapper instance **/ function createMap(model) { return ModelMapper(model); } /** * mapAll - Create ModelMapper and map alla the primitive fields of model (string, number, boolean, Date) * @param {object} model - the model to map * @returns {ModelMapper} ModelMapper instance **/ function mapAll(model) { return ModelMapper(model).mapAll(); } /** * map - Create ModelMapper and map a single field using function or dot-separed string * @param {object} model - the model to map * @param {string|function} mapping - function or dot-separed string used to map a field of the model * @param {string} fieldName - the name of mapped field in the result model * @returns {ModelMapper}ModelMapper instance **/ function map(model, mapping, fieldName) { return ModelMapper(model).map(mapping, fieldName); } /** * toTable - Utility to create a table model * @param {string} name - the table name * @param {Row[]} rows - array containing the table rows * @returns {Table} Table instance **/ function toTable (name, rows) { return new Table(name, rows); } /** * @typedef ModelMapper **/ function ModelMapper(model) { if (!model || typeof model !== 'object') throw 'ChangeTracker, ModelMapper, Error: model must be an plain object'; const _model = Symbol('model'); const _fields = Symbol('fields'); const self = { [_model]: model, [_fields]: {}, /** * Map all the primitive fields of the model (string, number, boolean, Date) * @returns {ModelMapper} ModelMapper instance **/ mapAll() { const keys = Object.keys(self[_model]); keys.map(key => { if (!isSimpleType(self[_model][key])) return; //TODO: how avoid accessing? self[_fields][key] = () => self[_model][key]; }) return self; }, /** * Map a single field using function or dot-separed string * @param {string|function} mapping - function or dot-separed string used to map a field of the model * @param {string} fieldName - the name of mapped field in the result model * @returns {ModelMapper}ModelMapper instance **/ map(mapping, fieldName) { if (!mapping || !fieldName) throw `ChangeTracker, ModelMapper, Map Error:invalid mapping ${mapping} or field ${fieldName}`; if (typeof mapping === 'function') { self[_fields][fieldName] = mapping; return self; } if (typeof mapping !== 'string') throw `ChangeTracker, ModelMapper, Map Error: mapper should be of type function or string`; //non empty tokens only let tokens = mapping.split('.').filter(el => !!el); let currentModel = self[_model]; for (let token of tokens) { currentModel = typeof currentModel === 'object' && currentModel[token]; //breaks validation control and maps error anyway //the error is managed by toList function; if (!currentModel) break; } //iterates through model to retrieve self[_fields][fieldName] = (m) => tokens.reduce((p, c) => p[c], m); return self; }, /** * ignore - ignore a specific field * @param {string} fieldName - the name of mapped field in the result model * @returns {ModelMapper} ModelMapper instance **/ ignore(fieldName) { delete self[_fields][fieldName]; return self; }, /** * returns an array of mapped fields * @returns {Field[]} the mapped fields **/ toList() { return Object.keys(self[_fields]).map(key => { try { return new Field(key, convertValue(self[_fields][key](self[_model]))); } catch (ex) { console.log(`ChangeTracker, Error generating Field model for field "${key}"`) } }).filter(el => typeof el !== 'undefined'); }, /** * returns * @param {string} key - the row key value * @param {Table[]} [linkedTables] - linked tables * @returns {Row} the mapped fields **/ toRow(key, linkedTables) { const row = new Row(key); row.fields = self.toList(); if (Array.isArray(linkedTables)) row.tables = linkedTables; return row; } }; return self; } function isSimpleType(value) { switch (typeof value) { case 'string': case 'boolean': case 'number': return true; case 'object': return value instanceof Date; } return false; } function convertValue(value) { switch (typeof value) { case 'undefined': return ''; case 'object': if (value instanceof Date) return value.toISOString(); break; case 'boolean': case 'number': case 'string': return value.toString(); } return '' } module.exports = { createMap, mapAll, map, toTable }