You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

58 lines
1.5 KiB
JavaScript

"use strict";
const assert = require("assert");
const unreachable = require("@joepie91/unreachable")("zapdb-kv");
const integerCoder = require("./integer");
function decimalToInteger(value, precision = 0) {
let multiplier = 10n ** BigInt(precision);
let match = /^(-?)([0-9]+)(?:\.([0-9]+))?$/.exec(value);
if (match != null) {
let isNegative = (match[1] !== "");
let whole = BigInt(match[2]) * multiplier;
let fraction = (match[3] != null)
? BigInt(match[3].slice(0, precision))
: BigInt(0);
let signMultiplier = (isNegative)
? -1n
: 1n;
return (whole + fraction) * signMultiplier;
} else {
throw unreachable("Decimal regex did not match");
}
}
function integerToDecimal(integer, precision = 0) {
let multiplier = 10n ** BigInt(precision);
let wholes = integer / multiplier; // this is integer division!
let fraction = integer - (wholes * multiplier); // modulo
// TODO: Support float mode? Or maybe custom transforms on a database level, eg. to feed this through a user-specified decimal library?
return `${wholes}.${fraction}`;
}
module.exports = {
encode: function (value, asIndexKey, { precision }) {
let integer = decimalToInteger(value, precision);
return integerCoder.encode(integer, asIndexKey);
},
decode: function (buffer, offset, { precision }) {
let result = integerCoder.decode(buffer, offset);
assert(result.blobID === undefined);
let decimal = integerToDecimal(result.value, precision);
return {
bytesRead: result.bytesRead,
value: decimal,
auxiliaryBlob: undefined
};
}
};