Source: new-utils.js

"use strict";
const customErrors = require("./errors");
const util = require("./utils");

const Long = require("long");

/**
 * @param {String} entity
 * @param {String} name
 */
function throwNotSupported(name) {
    throw new ReferenceError(`${name} is not supported by our driver`);
}

const errorTypeMap = {
    ...customErrors,
    Error,
    RangeError,
    ReferenceError,
    SyntaxError,
    TypeError,
};

const concatenationMark = "#";

/**
 * A wrapper function to map napi errors to Node.js errors or custom errors.
 * Because NAPI-RS does not support throwing errors different that Error, for example
 * TypeError, RangeError, etc. or custom, driver-specific errors, this function is used
 * to catch the original error and throw a new one with the appropriate type.
 * This should be used to wrap all NAPI-RS functions that may throw errors.
 *
 * @param {Function} fn The original function to be wrapped.
 * @returns {Function} A wrapped function with error handling logic.
 */
function napiErrorHandler(fn) {
    return function (...args) {
        try {
            return fn.apply(this, args);
        } catch (error) {
            // Check if message is of format errorType#errorMessage, if so map it to
            // appropriate error, otherwise throw the original error.
            const [errorType, ...messageParts] =
                error.message.split(concatenationMark);
            const message = messageParts.join(concatenationMark);

            if (errorTypeMap[errorType]) {
                const newError = new errorTypeMap[errorType](message);
                newError.stack = error.stack;
                throw newError;
            }
            throw error;
        }
    };
}

// maxInt value is based on how does Long split values between internal high and low fields.
const maxInt = BigInt(0x100000000);
const minusOne = BigInt(-1);

/**
 * Converts from bigint provided by napi into Long type used by the datastax library
 * BigInt is the way napi handles values too big for js Number type,
 * while Long is the way datastax code handles 64-bit integers.
 * @param {bigint} from
 * @returns {Long}
 */
function bigintToLong(from) {
    let lo = from % maxInt;
    let hi = from / maxInt;
    if (lo < 0) hi += minusOne;
    return Long.fromValue({
        low: Number(lo),
        high: Number(hi),
        unsigned: false,
    });
}

/**
 * Converts from Long type used by the datastax library into bigint used by napi
 * @param {Long} from
 * @returns {bigint}
 */
function longToBigint(from) {
    let lo = BigInt(from.low);
    let hi = BigInt(from.high);
    let r = lo + maxInt * hi;
    if (lo < 0) r += maxInt;
    return r;
}

/**
 * Ensure the value is one of the accepted numeric types, and convert them to BigInt
 * @param {string | number | Long | BigInt} value
 */
function arbitraryValueToBigInt(value) {
    if (typeof value === "bigint") return value;
    if (typeof value === "string" || typeof value == "number")
        return BigInt(value);
    if (value instanceof Long) return longToBigint(value);

    throw new TypeError(
        "Not a valid BigInt value, obtained " + util.inspect(value),
    );
}

exports.throwNotSupported = throwNotSupported;
exports.napiErrorHandler = napiErrorHandler;
exports.throwNotSupported = throwNotSupported;
exports.bigintToLong = bigintToLong;
exports.longToBigint = longToBigint;
exports.arbitraryValueToBigInt = arbitraryValueToBigInt;