UNPKG

@dataplan/pg

Version:
114 lines 4.62 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.parseArray = void 0; exports.makeParseArrayWithTransform = makeParseArrayWithTransform; const BACKSLASH = "\\"; const DQUOT = '"'; const LBRACE = "{"; const RBRACE = "}"; const LBRACKET = "["; const EQUALS = "="; const COMMA = ","; /** When the raw value is this, it means a literal `null` */ const NULL_STRING = "NULL"; const EMPTY_ARRAY = Object.freeze([]); /** * Parses an array according to * https://www.postgresql.org/docs/17/arrays.html#ARRAYS-IO * * Trusts the data (mostly), so only hook up to trusted Postgres servers. */ function makeParseArrayWithTransform(transform) { const haveTransform = transform != null; return function parseArray(str) { const rbraceIndex = str.length - 1; if (rbraceIndex === 1) { return EMPTY_ARRAY; } if (str[rbraceIndex] !== RBRACE) { throw new Error("Invalid array text - must end with }"); } // If starts with `[`, it is specifying the index boundas. Skip past first `=`. let position = 0; if (str[position] === LBRACKET) { position = str.indexOf(EQUALS) + 1; } if (str[position++] !== LBRACE) { throw new Error("Invalid array text - must start with {"); } const output = []; let current = output; const stack = []; let currentStringStart = position; // Allocate on first assignment let currentString = ""; let expectValue = true; for (; position < rbraceIndex; ++position) { let char = str[position]; // > The array output routine will put double quotes around element values if // > they are empty strings, contain curly braces, delimiter characters, double // > quotes, backslashes, or white space, or match the word NULL. Double quotes // > and backslashes embedded in element values will be backslash-escaped. if (char === DQUOT) { // It's escaped currentStringStart = ++position; let dquot = str.indexOf(DQUOT, currentStringStart); let backSlash = str.indexOf(BACKSLASH, currentStringStart); while (backSlash !== -1 && backSlash < dquot) { position = backSlash; const part = str.slice(currentStringStart, position); currentString += part; currentStringStart = ++position; if (dquot === position++) { // This was an escaped doublequote; find the next one! dquot = str.indexOf(DQUOT, position); } // Either way, find the next backslash backSlash = str.indexOf(BACKSLASH, position); } position = dquot; const part = str.slice(currentStringStart, position); currentString += part; current.push(haveTransform ? transform(currentString) : currentString); currentString = ""; expectValue = false; } else if (char === LBRACE) { const newArray = []; current.push(newArray); stack.push(current); current = newArray; currentStringStart = position + 1; expectValue = true; } else if (char === COMMA) { expectValue = true; } else if (char === RBRACE) { expectValue = false; const arr = stack.pop(); if (arr === undefined) { throw new Error("Invalid array text - too many '}'"); } current = arr; } else if (expectValue) { currentStringStart = position; while ((char = str[position]) !== COMMA && char !== RBRACE && position < rbraceIndex) { ++position; } const part = str.slice(currentStringStart, position--); current.push(part === NULL_STRING ? null : haveTransform ? transform(part) : part); expectValue = false; } else { throw new Error("Was expecting delimeter"); } } return output; }; } exports.parseArray = makeParseArrayWithTransform(); //# sourceMappingURL=parseArray.js.map