UNPKG

@sap/xsodata

Version:

Expose data from a HANA database as OData V2 service with help of .xsodata files.

246 lines (213 loc) 6.6 kB
'use strict'; const Big = require('big.js'); const timeRegexObj = /^P((\d+)Y)?((\d+)M)?((\d+)D)?T((\d+)H)?((\d+)M)?((\d+)(?:\.(\d*))?S)?$/i; const timeRegexObjTime = /^time'P((\d+)Y)?((\d+)M)?((\d+)D)?T((\d+)H)?((\d+)M)?((\d+)(?:\.(\d*))?S)?'$/i; const XsODataTypeError = require('./../errors/typeError'); function padZero(string, len) { if (string.length < len) { return new Array(len - string.length + 1).join('0') + string; } return string; } exports.checkEdmTime = function ( value, dbDataType, withTimePrefix, YMDmustBeZero, allowFractions, getYMD ) { const matches = withTimePrefix === true ? timeRegexObjTime.exec(value) : timeRegexObj.exec(value); assertNoFractions(matches, allowFractions); if (YMDmustBeZero) { assertYMDZero(matches, dbDataType); } if (getYMD === false) { return buildTimeFromMatches(matches); } assertSecondTimeMin(matches); const date = buildDateFromMatches(matches); const time = buildTimeFromMatches(matches); return date + ' ' + time; }; function assertNoFractions(matches, allowFractions) { if (!allowFractions && matches[13] && Number.parseInt(matches[13]) !== 0) { throw new XsODataTypeError( `Fractional part for OData type Edm.Time not supported` ); } } function assertYMDZero(matches, dbDataType) { if (matches[1] && Number.parseInt(matches[1]) !== 0) { throw new XsODataTypeError( `value must be compatible to hana type ${dbDataType} (check year)` ); } if (matches[3] && Number.parseInt(matches[3]) !== 0) { throw new XsODataTypeError( `value must be compatible to hana type ${dbDataType} (check month)` ); } if (matches[5] && Number.parseInt(matches[5]) !== 0) { throw new XsODataTypeError( `value must be compatible to hana type ${dbDataType} (check day)` ); } } function assertSecondTimeMin(matches) { if (!matches[2] || Number.parseInt(matches[2]) <= 0) { throw new XsODataTypeError( 'value must be compatible to hana type SECONDTIME (check year)' ); } if (!matches[4] || Number.parseInt(matches[4]) <= 0) { throw new XsODataTypeError( 'value must be compatible to hana type SECONDTIME (check month)' ); } if (!matches[6] || Number.parseInt(matches[6]) <= 0) { throw new XsODataTypeError( 'value must be compatible to hana type SECONDTIME (check day)' ); } } function buildTimeFromMatches(matches) { const hh = matches[8] ? padZero(matches[8], 2) : '00'; const mm = matches[10] ? padZero(matches[10], 2) : '00'; const ss = matches[12] ? padZero(matches[12], 2) : '00'; return [hh, mm, ss].join(':'); } function buildDateFromMatches(matches) { const yyyy = matches[2] ? padZero(matches[2], 4) : '00'; const mm = matches[4] ? padZero(matches[4], 2) : '00'; const dd = matches[6] ? padZero(matches[6], 2) : '00'; return [yyyy, mm, dd].join('-'); } exports.datetime7 = function (dbValue, addLetterTbehindDate) { let parts = dbValue.split('.'); let dateAndTime = parts[0]; let frac = parts[1]; if (addLetterTbehindDate && dateAndTime.indexOf('T') === -1) { const dtPart = dateAndTime.split(' '); dateAndTime = dtPart.join('T'); } if (parts.length === 1) { return '' + dateAndTime + '.0000000'; } else { while (frac.length < 7) { frac += '0'; } /* hdb db driver returned only 3 digits if (frac.length > 7 && frac.substring(7) !== '00') { throw new Error('Fractional value can not be converted'); } */ frac = frac.substr(0, 7); return '' + dateAndTime + '.' + frac; } }; /** * Converts the input <code>decimalString</code> into the decimal notation, if it is specified in the exponential * notation. * @param {string} decimalString - string representing a decimal value. * @returns {string} decimal value in the decimal notation. */ exports.formatDecimal = function formatDecimal(decimalString) { let decimalValue; if (!decimalString) { return decimalString; } if ( decimalString.indexOf('e') !== -1 || decimalString.indexOf('E') !== -1 ) { decimalValue = new Big(decimalString); return decimalValue.toFixed(); } return decimalString; }; function getOut(expInt, point, man) { let out = ''; let pre = 0; while (pre < point && man[pre] !== '0') { pre++; } const post = man.length === point ? 0 : man.length - point - 1; const spre = man.substr(point - pre, pre); const spost = man.substr(point + 1, post); if (expInt === 0) { out += pre === 0 ? '0' : spre; if (post !== 0) { out += '.'; out += spost; } return out; } if (expInt > 0) { out += spre; if (post) { if (expInt >= post) { out += spost; expInt -= post; } else { out += spost.substr(0, expInt); out += '.'; out += spost.substr(expInt); return out; } } while (expInt > 0) { out += '0'; expInt--; } return out; } else { expInt *= -1; if (pre - expInt <= 0) { out += '0.'; while (expInt > pre) { out += '0'; expInt--; } out += spre; out += spost; } else { out += spre.substr(0, pre - expInt); out += '.'; out += spre.substr(pre - expInt); } } return out; } exports.decimal_db_to_uri = function (decimalAsString) { const arr = decimalAsString.split(/[eE]/); if (arr.length === 1) { // input was "3" return decimalAsString; } if (arr[1] === '') { // input was"3e" return decimalAsString.substr(0, decimalAsString.length - 1); } let man = arr[0]; const exp = arr[1]; let sign = ''; if (man[0] === '+' || man[0] === '-') { sign = man[0]; man = man.substr(1); } let point = man.indexOf('.'); if (point === -1) { point = man.length; } let expInt = parseInt(exp); let out = sign; out += getOut(expInt, point, man); return out; };