UNPKG

pg-safe-numbers

Version:
245 lines (200 loc) 6.9 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.safeParseInt = safeParseInt; exports.floatTrim = floatTrim; exports.floatCompare = floatCompare; exports.safeParseFloat = safeParseFloat; exports.pgSetTypeParsers = pgSetTypeParsers; exports.pgUnsetTypeParsers = pgUnsetTypeParsers; var _util = require('util'); var _util2 = _interopRequireDefault(_util); var _postgresArray = require('postgres-array'); var _postgresArray2 = _interopRequireDefault(_postgresArray); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } let DefaultPg = null; let DefaultSequelize = null; try { DefaultPg = require('pg'); } catch (err) {} // eslint-disable-line no-empty try { DefaultSequelize = require('sequelize'); } catch (err) {} // eslint-disable-line no-empty /** * Default handler for unsafe int parser. * @param {Number} parsed Parsed value. * @param {String} text Input string. * @return Optional value to be returned by the parser. */ function defaultUnsafeInt(parsed, text) { throw new TypeError(`Unsafe int parse ${ _util2.default.inspect(text) } to ${ _util2.default.inspect(parsed) }.`); } /** * Default handler for unsafe float parser. * @param {Number} parsed Parsed value. * @param {String} text Input string. * @return Optional value to be returned by the parser. */ function defaultUnsafeFloat(parsed, text) { throw new TypeError(`Unsafe float parse ${ _util2.default.inspect(text) } to ${ _util2.default.inspect(parsed) }.`); } /** * Parse integer delegating unsafe input to the handler. * @param {String} text * @param {Function} unsafeHandler = defaultUnsafeInt * @return {Number|NaN} Parsed value or unsafe handler's result. */ function safeParseInt(text) { let unsafeHandler = arguments.length <= 1 || arguments[1] === undefined ? defaultUnsafeInt : arguments[1]; const parsed = parseInt(text, 10); if (Number.isSafeInteger(parsed) || isNaN(parsed)) { return parsed; } return unsafeHandler(parsed, text); } /** * Trim float (currently on the right only). * @param {string} text Float string. * @return {string} */ function floatTrim(text) { if (text.indexOf('.') !== -1) { return text.replace(/[0\s\uFEFF\xA0]+$/g, ''); } return text; } /** * Compare number with it's floating point string represenation. * @param {Number} parsed * @param {String} text * @return {Boolean} True if the parsed number is the same as precision text representation. */ function floatCompare(parsed, text) { let precision = (text.match(/[0-9]/g) || []).length; return floatTrim(parsed.toPrecision(precision)) === floatTrim(text); } /** * Parse float delegating unsafe input to the handler. * @param {String} text * @param {Function} unsafeHandler = defaultUnsafeFloat * @return {Number|NaN|+/-Infinity} Parsed value or unsafe handler's result. */ function safeParseFloat(text) { let unsafeHandler = arguments.length <= 1 || arguments[1] === undefined ? defaultUnsafeFloat : arguments[1]; let parsed = parseFloat(text); if (floatCompare(parsed, text) || isNaN(parsed) || !isFinite(parsed)) { return parsed; } return unsafeHandler(parsed, text); } /** * Remember old parsers so they can be unset. * @type {Array} */ let pgSetTypeParsersStack = []; /** * Replace default pg parsers for Int8 and Numberic data types. * @param {pg?} .pg * @param {function(parsed, text)?} unsafeInt Function handler to deal with unsafe input, default throws TypeError. * @param {function(parsed, text)?} unsafeFloat Function handler to deal with unsafe input, default throws TypeError. * @return {array} Previous parsers. */ function pgSetTypeParsers() { var _ref = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; var _ref$pg = _ref.pg; let pg = _ref$pg === undefined ? DefaultPg : _ref$pg; var _ref$Sequelize = _ref.Sequelize; let Sequelize = _ref$Sequelize === undefined ? DefaultSequelize : _ref$Sequelize; var _ref$unsafeInt = _ref.unsafeInt; let unsafeInt = _ref$unsafeInt === undefined ? defaultUnsafeInt : _ref$unsafeInt; var _ref$unsafeFloat = _ref.unsafeFloat; let unsafeFloat = _ref$unsafeFloat === undefined ? defaultUnsafeFloat : _ref$unsafeFloat; let result = []; if (pg) { const PgTypes = { Int8: 20, Int8Array: 1016, Numeric: 1700, NumericArray: 1231 }; // Remember old parsers. ['Int8', 'Int8Array', 'Numeric', 'NumericArray'].forEach(type => { result.push({ kind: 'pg', info: { oid: PgTypes[type], format: 'text', func: pg.types.getTypeParser(PgTypes[type], 'text') } }); }); const safeParseIntFunction = function (text) { return safeParseInt(text, unsafeInt); }; const safeParseFloatFunction = function (text) { return safeParseFloat(text, unsafeFloat); }; pg.types.setTypeParser(PgTypes.Int8, 'text', safeParseIntFunction); pg.types.setTypeParser(PgTypes.Numeric, 'text', safeParseFloatFunction); pg.types.setTypeParser(PgTypes.Int8Array, 'text', function (text) { return _postgresArray2.default.parse(text, safeParseIntFunction); }); pg.types.setTypeParser(PgTypes.Int8Numeric, 'text', function (text) { return _postgresArray2.default.parse(text, safeParseFloatFunction); }); } if (Sequelize) { result.push({ kind: 'sequelize', info: { type: 'DECIMAL', parse: Sequelize.postgres.DECIMAL.parse } }); Sequelize.postgres.DECIMAL.parse = function (value) { return safeParseFloat(value, unsafeFloat); }; } pgSetTypeParsersStack.push(result); return result; } /** * Reverts to previously used type parsers. * TODO: Do it in context of pg. */ function pgUnsetTypeParsers() { var _ref2 = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; var _ref2$pg = _ref2.pg; let pg = _ref2$pg === undefined ? DefaultPg : _ref2$pg; var _ref2$Sequelize = _ref2.Sequelize; let Sequelize = _ref2$Sequelize === undefined ? DefaultSequelize : _ref2$Sequelize; const previous = pgSetTypeParsersStack.pop(); for (const _ref3 of previous) { const kind = _ref3.kind; const info = _ref3.info; switch (kind) { case 'pg': if (pg) { const oid = info.oid; const format = info.format; const func = info.func; pg.types.setTypeParser(oid, format, func); } break; case 'sequelize': if (Sequelize) { const type = info.type; const parse = info.parse; Sequelize.postgres[type].parse = parse; } break; default: throw new TypeError(`Unknown kind ${ kind }, expected "pg" or "sequelize".`); } } } /** * @see pgSetTypeParsers */ exports.default = pgSetTypeParsers;