UNPKG

@datastax/astra-db-ts

Version:
186 lines (185 loc) 6.39 kB
"use strict"; // Copyright Datastax, Inc // SPDX-License-Identifier: Apache-2.0 Object.defineProperty(exports, "__esModule", { value: true }); exports.coerceNums = exports.coerceNumber = exports.coerceBigNumber = exports.NumCoercionError = exports.buildGetNumCoercionForPathFn = void 0; const bignumber_js_1 = require("bignumber.js"); const utils_js_1 = require("../../../lib/utils.js"); const utils_js_2 = require("../../../lib/api/ser-des/utils.js"); const index_js_1 = require("../../../lib/index.js"); const $NumCoercion = Symbol('NumCoercion'); const buildGetNumCoercionForPathFn = (cfg) => { return (typeof cfg?.enableBigNumbers === 'object') ? collNumCoercionFnFromCfg(cfg.enableBigNumbers) : cfg?.enableBigNumbers; }; exports.buildGetNumCoercionForPathFn = buildGetNumCoercionForPathFn; const collNumCoercionFnFromCfg = (cfg) => { const defaultCoercion = cfg['*']; if (!defaultCoercion) { throw new Error('The configuration must contain a "*" key'); } // Minor optimization to make `{ '*': 'xyz' }` equal in performance to `() => 'xyz'` if (Object.keys(cfg).length === 1) { return () => defaultCoercion; } const tree = buildNumCoercionTree(cfg); return (path) => { return findMatchingPath(path, tree) ?? defaultCoercion; }; }; const buildNumCoercionTree = (cfg) => { const result = Object.create(null); Object.entries(cfg).forEach(([path, coercion]) => { const keys = (0, index_js_1.unescapeFieldPath)(path); let current = result; keys.forEach((key, index) => { current[key] ?? (current[key] = Object.create(null)); if (index === keys.length - 1) { current[key][$NumCoercion] = coercion; } current = current[key]; }); }); return result; }; const findMatchingPath = (path, tree) => { let coercion = undefined; for (let i = 0; tree && i <= path.length; i++) { if (i === path.length) { return tree[$NumCoercion]; } const exactMatch = tree[path[i]]; if (exactMatch) { tree = exactMatch; } else { tree = tree['*']; coercion = tree?.[$NumCoercion] ?? coercion; } } return coercion; }; class NumCoercionError extends Error { constructor(path, value, from, to) { super(`Failed to coerce value from ${from} to ${to} at path: ${path.join('.')}`); Object.defineProperty(this, "path", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "value", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "from", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "to", { enumerable: true, configurable: true, writable: true, value: void 0 }); this.path = path; this.value = value; this.from = from; this.to = to; } } exports.NumCoercionError = NumCoercionError; const coerceBigNumber = (value, path, getNumCoercionForPath, pathMatches) => { const coercer = getNumCoercionForPath(path, pathMatches); if (typeof coercer === 'function') { return coercer(value, path); } switch (coercer) { case 'number': { return value.toNumber(); } case 'strict_number': { const asNum = value.toNumber(); if (!value.isEqualTo(asNum)) { throw new NumCoercionError(path, value, 'bignumber', 'number'); } return asNum; } case 'bigint': { if (!value.isInteger()) { throw new NumCoercionError(path, value, 'bignumber', 'bigint'); } return BigInt(value.toFixed(0)); } case 'bignumber': return value; case 'string': return value.toString(); case 'number_or_string': { const asNum = value.toNumber(); if (!value.isEqualTo(asNum)) { return value.toString(); } return asNum; } } }; exports.coerceBigNumber = coerceBigNumber; const coerceNumber = (value, path, getNumCoercionForPath, pathMatches) => { const coercer = getNumCoercionForPath(path, pathMatches); if (typeof coercer === 'function') { return coercer(value, path); } switch (coercer) { case 'bigint': { if (!Number.isInteger(value)) { throw new NumCoercionError(path, value, 'number', 'bigint'); } return BigInt(value); } case 'bignumber': return (0, bignumber_js_1.BigNumber)(value); case 'string': return String(value); case 'number': case 'strict_number': case 'number_or_string': return value; } }; exports.coerceNumber = coerceNumber; const coerceNums = (val, getNumCoercionForPath) => { return coerceNumsImpl(val, [], getNumCoercionForPath, (p) => (0, utils_js_2.pathMatches)([], p)); }; exports.coerceNums = coerceNums; const coerceNumsImpl = (val, path, getNumCoercionForPath, pathMatchesFn) => { if (typeof val === 'number') { return (0, exports.coerceNumber)(val, path, getNumCoercionForPath, pathMatchesFn); } if (!val || typeof val !== 'object') { return val; } if ((0, utils_js_1.isBigNumber)(val)) { return (0, exports.coerceBigNumber)(val, path, getNumCoercionForPath, pathMatchesFn); } path.push('<temp>'); if (Array.isArray(val)) { for (let i = 0; i < val.length; i++) { path[path.length - 1] = i; val[i] = coerceNumsImpl(val[i], path, getNumCoercionForPath, (p) => (0, utils_js_2.pathMatches)(path, p)); } } else { for (const key of Object.keys(val)) { path[path.length - 1] = key; val[key] = coerceNumsImpl(val[key], path, getNumCoercionForPath, (p) => (0, utils_js_2.pathMatches)(path, p)); } } path.pop(); return val; };