@absolute/change-tracker-node-sdk
Version:
ChangeTracker SDK for Node.js
179 lines (152 loc) • 5.63 kB
JavaScript
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
}