sqldump-to
Version:
Stream SQL dump to newline delimited json
143 lines (112 loc) • 3.54 kB
JavaScript
const JSON5 = require('json5');
const { createFileWriteStream } = require('./util/fs');
class SQLSignalParserWriter {
constructor() {
this.isDone = false;
this.config = {};
this.schema = {};
this.databaseWriteQueues = { default: {} };
this.isWritingToFile = false;
this.currentTableQueue = null;
this.writeFromBuffers = this.writeFromBuffers.bind(this);
this.checkDone = this.checkDone.bind(this);
this.checkQueueInterval = setInterval(this.writeFromBuffers, 10);
}
get partSuffix() {
const {
workerPart,
totalWorkers,
} = this.config;
let partSuffix = `_${process.pid}`;
if (totalWorkers <= 1) {
partSuffix = '';
} else if (typeof workerPart === 'number') {
partSuffix = `_${workerPart}`;
}
return partSuffix;
}
setCurrentTableQueue() {
const { databaseName, tableName } = this.schema;
const database = databaseName || 'default';
let databaseQueue = this.databaseWriteQueues[database];
if (databaseQueue === undefined) {
databaseQueue = {};
this.databaseWriteQueues[database] = databaseQueue;
}
if (databaseQueue[tableName] === undefined) {
let writeStream = process.stdout;
if (this.isWritingToFile === true) {
const { outputDir } = this.config;
const directory = databaseName ? `${outputDir}/${databaseName}` : outputDir;
const filename = `${tableName}${this.partSuffix}.json`;
writeStream = createFileWriteStream({ directory, filename });
}
databaseQueue[tableName] = {
buffer: '',
writeStream,
};
}
this.currentTableQueue = databaseQueue[tableName];
}
handleData(data) {
const msg = data
.toString()
.replace(/(?!\B'[^']*)(NULL|\\N)(?![^']*'\B)/g, 'null');
try {
const parsed = JSON5.parse(msg);
if (Array.isArray(parsed)) {
const record = {};
for (let i = 0; i < parsed.length; i += 1) {
const key = this.schema.columns[i].name;
record[key] = parsed[i];
}
this.currentTableQueue.buffer += `${JSON.stringify(record)}\n`;
} else if (parsed.schema) {
Object.assign(this.schema, parsed.schema);
this.setCurrentTableQueue();
} else if (parsed.config) {
Object.assign(this.config, parsed.config);
if (parsed.config.outputDir) {
this.isWritingToFile = true;
}
}
} catch (err) {
console.error('Unable to parse string', msg);
console.error(err);
}
}
end() {
this.isDone = true;
this.writeFromBuffers();
}
checkDone() {
if (this.isDone === true) {
clearInterval(this.checkQueueInterval);
process.exit();
}
}
writeFromBuffers() {
const { databaseWriteQueues } = this;
const writes = [];
Object.keys(databaseWriteQueues).forEach((database) => {
const databaseQueue = databaseWriteQueues[database];
Object.keys(databaseQueue).forEach((tableName) => {
const { buffer, writeStream } = databaseQueue[tableName];
databaseQueue[tableName].buffer = '';
if (buffer.length) {
writes.push(new Promise((resolve) => {
writeStream.write(buffer, resolve);
}));
}
});
});
if (writes.length) {
Promise.all(writes)
.then(() => { this.checkDone(); })
.catch((err) => { throw err; });
} else {
this.checkDone();
}
}
}
module.exports = SQLSignalParserWriter;