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