Bryn =>
Shanahan
Login

CSV to SQL

I created this small snippet to convert CSV files to SQL insert statements

Font Size

/* eslint-disable */
import { parse } from "csv-parse/sync";
let fileInput = document.createElement('input')
fileInput.type = 'file'
let button = document.createElement("button");
let container = document.createElement("div");
let resultContainer = document.createElement("div");
let idContainer = document.createElement("div");
let targetFiles: FileList
interface Lang<Primitives> {
formatValue(value: string): Primitives;
formatColumn(col: string): string;
}
class PSQLLang implements Lang<string | number | boolean> {
valueRegex = /'/g;
empty = "null";
formatValue(value: string) {
if (!value) return this.empty;
try {
let parsed = JSON.parse(value);
if (typeof parsed === "number") {
return parsed;
} else if (typeof parsed === "boolean") {
return parsed;
}
} catch (e) {}
return `'${value.replace(this.valueRegex, "''")}'`;
}
columnRegex = /"/g;
formatColumn(col: string) {
return `"${col.replace(this.columnRegex, '\\"')}"`;
}
}
const langs = {
psql: new PSQLLang()
};
function cols(columns: string[]) {
return {
index: (index: number) => {
return {
is: (columnName: any) => columns.indexOf(columnName) === index
};
}
};
}
async function readBlob (blob: Blob) {
let fr = new FileReader()
return new Promise(resolve => {
fr.onload = () => {
fr.onload = undefined
resolve(fr.result)
}
fr.readAsText(blob)
})
}
function tryParse(value: string | null) {
try {
return JSON.parse(value!);
} catch {}
}
function getCurrentRequestId() {
return tryParse(localStorage.getItem("req_id")) || 0;
}
function getNewRequest() {
let id = getCurrentRequestId();
id++;
localStorage.setItem("req_id", JSON.stringify(id));
return id;
}
idContainer.innerText = "Id: " + getNewRequest();
async function main() {
let requestId = getNewRequest();
let text = await readBlob(targetFiles.item(0))
if (getCurrentRequestId() !== requestId) return;
const lines = parse(text) as string[][];
let columnNames = lines.shift()!;
let columns = cols(columnNames);
let template =
`
INSERT INTO location (${columnNames
.map((val) => langs.psql.formatColumn(val))
.join(",")})
VALUES ` +
lines
.map(
(line) =>
`(${line
.map((val, i) => {
let formatted = langs.psql.formatValue(val);
const col = columns.index(i);
if (
(col.is("phone") || col.is("postcode")) &&
typeof formatted === "number"
) {
return `'${formatted}'`;
}
if (
(col.is("address") || col.is("phone")) &&
formatted === langs.psql.empty
) {
return "''";
}
return formatted;
})
.join(", ")})`
)
.join(",\n")
.trim() +
";";
let file = new Blob([template], { type: "text/plain;charset=utf-8" });
let url = URL.createObjectURL(file);
let a = document.createElement("a");
a.href = url;
a.download = "tmpFile.sql";
a.innerText = "Download";
resultContainer.innerHTML = "";
resultContainer.append(a);
a.onclick = () => {
a.remove();
};
}
container.append(idContainer);
container.append(fileInput)
container.append(button);
container.append(resultContainer);
fileInput.onchange = (e: InputEvent) => {
let target = e.target as HTMLInputElement
button.disabled = !target.files.length
targetFiles = target.files
}
button.textContent = "Run";
button.onclick = () => {
button.textContent = "Loading";
main().then(() => {
button.textContent = "Run";
});
};
// main();
document.body.innerHTML = "";
document.body.append(container);