/** * Extracts rows from a string of values in a SQL INSERT INTO statement, where each row is a comma-separated list of values enclosed in parentheses, possibly with the last row incomplete. * @param {string} input * @returns {{rows: string[][], unCompleted:string}} * @example extractRowsFromSQLValues("(1,'-)',0),(2,'Demographics_of_American_Samoa',0)") // { rows: [["1","'-)'","0"],["2","'Demographics_of_American_Samoa'","0"]], unCompleted: "" } */ export const extractRowsFromSQLValues = (input) => { const rows = [] let index = 0 let unCompleted = "" while (index < input.length) { if (input[index] === "(") { const row = [] index++ // Skip the opening '(' let value = "" let insideQuotes = false let rowComplete = false while (index < input.length && !rowComplete) { if (input[index] === "'") { // An escaped quote is preceded by an odd number of backslashes. let backslashCount = 0 let backIndex = index - 1 while (backIndex >= 0 && input[backIndex] === "\\") { backslashCount++ backIndex-- } if (backslashCount % 2 === 0) { insideQuotes = !insideQuotes } } if (input[index] === "," && !insideQuotes) { row.push(value) value = "" } else if (input[index] === ")" && !insideQuotes) { row.push(value) rows.push(row) rowComplete = true } else { value += input[index] } index++ } if (!rowComplete) { // If row is not completed, save it to unCompleted unCompleted = "(" if (row.length > 0) { unCompleted += row.join(",") + "," + value } else if (value.length > 0) { unCompleted += value } break } } else { index++ } } return { rows, unCompleted } }