@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
JavaScript
;
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;
};