google-big-query-labels
Version:
Encode strings so they are compatible with google big query labels.
94 lines (70 loc) • 2.37 kB
JavaScript
const bigInt = require('big-integer');
const prefix = 'l';
const labelAlphabet = '_-0123456789abcdefghijklmnopqrstuvwxyz';
const base64Alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
const base64UrlAlphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
module.exports = {
prefix,
encode,
decode,
labelAlphabet,
encodeBase64,
decodeBase64,
encodeBase64Url,
decodeBase64Url
};
function encode(toEncode, originCharacters) {
const bigIntArg = toEncode.split('').reduce((memo, char) => {
const index = originCharacters.indexOf(char);
if (index === -1) {
throw new TypeError(`Character ${char} is not in character set ${originCharacters}`);
}
return memo + `<${index}>`;
// Prefixing with 1 to handle the case that the encoded string begins with
// the first character in the provided alphabet e.g. A in base64Url.
}, '1');
let encodedVal;
try {
encodedVal = bigInt(bigIntArg, originCharacters.length);
} catch (e) {
throw new TypeError(`${toEncode} is not a valid base ${base} string.`);
}
let str = '';
do {
str = labelAlphabet.substr(encodedVal.mod(labelAlphabet.length).valueOf(), 1) + str;
encodedVal = encodedVal.divide(labelAlphabet.length);
} while (encodedVal.greater(0));
return prefix + str;
}
function decode(encoded, originCharacters) {
let decodedVal = bigInt(0);
const str = encoded.slice(1, encoded.length);
const len = str.length;
for (let pos = 0; pos < len; pos += 1) {
const ch = str.substr(pos, 1);
const encPos = labelAlphabet.indexOf(ch);
if (encPos < 0) {
throw new Error('Invalid encoded data');
}
decodedVal = decodedVal.add(encPos);
if (pos < len - 1) {
decodedVal = decodedVal.multiply(labelAlphabet.length);
}
}
const chars = decodedVal.toArray(originCharacters.length).value.map(digit => originCharacters[digit]);
// Again, handles the leading 0 char index case.
chars.shift();
return chars.join('');
}
function encodeBase64(toEncode) {
return encode(toEncode, base64Alphabet);
}
function decodeBase64(encoded) {
return decode(encoded, base64Alphabet);
}
function encodeBase64Url(toEncode) {
return encode(toEncode, base64UrlAlphabet);
}
function decodeBase64Url(toDecode) {
return decode(toDecode, base64UrlAlphabet);
}