node-firestore-import-export
Version:
Firestore data import and export
113 lines (112 loc) • 4.85 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const commander = require("commander");
const prompt = require("prompt");
const colors = require("colors");
const process = require("process");
const fs = require("fs");
const import_1 = require("../lib/import");
const firestore_helpers_1 = require("../lib/firestore-helpers");
const loadJsonFile = require("load-json-file");
const packageInfo = require('../../package.json');
const accountCredentialsPathParamKey = 'accountCredentials';
const accountCredentialsPathParamDescription = 'Google Cloud account credentials JSON file';
const backupFileParamKey = 'backupFile';
const backupFileParamDescription = 'Filename to store backup. (e.g. backups/full-backup.json)';
const nodePathParamKey = 'nodePath';
const nodePathParamDescription = 'Path to database node (has to be a collection) where import will to start (e.g. collectionA/docB/collectionC).' +
' Imports at root level if missing.';
const yesToImportParamKey = 'yes';
const yesToImportParamDescription = 'Unattended import without confirmation (like hitting "y" from the command line).';
commander.version(packageInfo.version)
.option(`-a, --${accountCredentialsPathParamKey} <path>`, accountCredentialsPathParamDescription)
.option(`-b, --${backupFileParamKey} <path>`, backupFileParamDescription)
.option(`-n, --${nodePathParamKey} <path>`, nodePathParamDescription)
.option(`-y, --${yesToImportParamKey}`, yesToImportParamDescription)
.parse(process.argv);
const accountCredentialsPath = commander[accountCredentialsPathParamKey];
if (!accountCredentialsPath) {
console.log(colors.bold(colors.red('Missing: ')) + colors.bold(accountCredentialsPathParamKey) + ' - ' + accountCredentialsPathParamDescription);
commander.help();
process.exit(1);
}
if (!fs.existsSync(accountCredentialsPath)) {
console.log(colors.bold(colors.red('Account credentials file does not exist: ')) + colors.bold(accountCredentialsPath));
commander.help();
process.exit(1);
}
const backupFile = commander[backupFileParamKey];
if (!backupFile) {
console.log(colors.bold(colors.red('Missing: ')) + colors.bold(backupFileParamKey) + ' - ' + backupFileParamDescription);
commander.help();
process.exit(1);
}
if (!fs.existsSync(backupFile)) {
console.log(colors.bold(colors.red('Backup file does not exist: ')) + colors.bold(backupFile));
commander.help();
process.exit(1);
}
const nodePath = commander[nodePathParamKey];
const importPathPromise = firestore_helpers_1.getCredentialsFromFile(accountCredentialsPath)
.then(credentials => {
const db = firestore_helpers_1.getFirestoreDBReference(credentials);
return firestore_helpers_1.getDBReferenceFromPath(db, nodePath);
});
const unattendedConfirmation = commander[yesToImportParamKey];
Promise.all([loadJsonFile(backupFile), importPathPromise])
.then((res) => {
if (unattendedConfirmation) {
return res;
}
const [data, pathReference] = res;
const nodeLocation = pathReference
.path || '[database root]';
// For some reason, Firestore, DocumentReference, and CollectionReference interfaces
// don't show a projectId property even though they do have them.
// @todo: Remove any when that is fixed, or find the correct interface
const projectID = pathReference.projectId ||
pathReference.firestore.projectId;
const importText = `About to import data ${backupFile} to the '${projectID}' firestore at '${nodeLocation}'.`;
console.log(`\n\n${colors.bold(colors.blue(importText))}`);
console.log(colors.bgYellow(colors.blue(' === Warning: This will overwrite existing data. Do you want to proceed? === ')));
return new Promise((resolve, reject) => {
prompt.message = 'firestore-import';
prompt.start();
prompt.get({
properties: {
response: {
description: colors.red(`Proceed with import? [y/N] `)
}
}
}, (err, result) => {
if (err) {
return reject(err);
}
switch (result.response.trim().toLowerCase()) {
case 'y':
resolve(res);
break;
default:
reject('Import aborted.');
}
});
});
})
.then((res) => {
const [data, pathReference] = res;
return import_1.default(data, pathReference);
})
.then(() => {
console.log(colors.bold(colors.green('All done 🎉')));
})
.catch((error) => {
if (error instanceof Error) {
console.log(colors.red(`${error.name}: ${error.message}`));
console.log(colors.red(error.stack));
process.exit(1);
}
else {
console.log(colors.red(error));
}
});