firebase-tools-extra
Version:
Extra functionality for firebase-tools with support for emulators and auth through service account.
149 lines (148 loc) • 7.33 kB
JavaScript
import { __assign, __awaiter, __generator } from "tslib";
import { slashPathToFirestoreRef, initializeFirebase, deleteFirestoreCollection, readJsonFile, writeFilePromise, tryToJsonParse, } from '../utils';
import { error } from '../logger';
/**
* Get data from Firestore get response (handles docs and collections).
* Returns null if no data is found at that location.
* @param res - Response from calling Firestore get
* @returns Data from response
*/
function firestoreDataFromResponse(res) {
var _a;
if (typeof res.data === 'function') {
return res.data() || null;
}
if ((_a = res.docs) === null || _a === void 0 ? void 0 : _a.length) {
return res.docs.map(function (docSnap) { return (__assign(__assign({}, docSnap.data()), {
// TODO: Look into if this should be __name__ for better imports and not colliding with real data
id: docSnap.id })); });
}
return null;
}
/**
* Get data from Firestore at given path (works for documents & collections)
* @param actionPath - Path where to run firestore get
* @param options - Options object
* @returns Data value that results from running get within Firestore
*/
export function firestoreGet(actionPath, options) {
return __awaiter(this, void 0, void 0, function () {
var _a, emulator, debug, fbInstance, ref, res, dataToOutput, err_1;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
_a = options || {}, emulator = _a.emulator, debug = _a.debug;
fbInstance = initializeFirebase({ emulator: emulator, debug: debug });
ref = slashPathToFirestoreRef(fbInstance.firestore(), actionPath, options);
_b.label = 1;
case 1:
_b.trys.push([1, 6, , 7]);
return [4 /*yield*/, ref.get()];
case 2:
res = _b.sent();
dataToOutput = firestoreDataFromResponse(res);
if (!(options === null || options === void 0 ? void 0 : options.output)) return [3 /*break*/, 4];
// Write results to file at path provided in options.output
return [4 /*yield*/, writeFilePromise(process.cwd() + "/" + options.output, JSON.stringify(dataToOutput, null, 2))];
case 3:
// Write results to file at path provided in options.output
_b.sent();
return [3 /*break*/, 5];
case 4:
// Write results to stdout (console.log is used instead of process.stdout.write so that newline is automatically appended)
/* eslint-disable no-console */
console.log((options === null || options === void 0 ? void 0 : options.pretty) ? JSON.stringify(dataToOutput, null, 2)
: JSON.stringify(dataToOutput));
_b.label = 5;
case 5: return [2 /*return*/, dataToOutput];
case 6:
err_1 = _b.sent();
error("Error with firestore:get at path \"" + actionPath + "\": ", err_1.message);
throw err_1;
case 7: return [2 /*return*/];
}
});
});
}
/**
* Run write action for Firestore
* @param action - Firestore action to run
* @param actionPath - Path at which Firestore action should be run
* @param filePath - Path to file to write
* @param options - Options object
* @returns Results of running action within Firestore
*/
export function firestoreWrite(action, actionPath, filePath, options) {
if (action === void 0) { action = 'set'; }
return __awaiter(this, void 0, void 0, function () {
var _a, emulator, debug, fbInstance, errMsg, dataToWrite, ref, missingActionErr, res, err_2;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
_a = options || {}, emulator = _a.emulator, debug = _a.debug;
fbInstance = initializeFirebase({ emulator: emulator, debug: debug });
if (!filePath && !(options === null || options === void 0 ? void 0 : options.data)) {
errMsg = "File path or data is required to run " + action + " at path \"" + actionPath + "\"";
error(errMsg);
throw new Error(errMsg);
}
dataToWrite = (options === null || options === void 0 ? void 0 : options.data) ? tryToJsonParse(options.data)
: readJsonFile(filePath);
ref = slashPathToFirestoreRef(fbInstance.firestore(), actionPath, options);
// TODO: Support passing timestamps
// Confirm ref has action as a method
if (typeof ref[action] !== 'function') {
missingActionErr = "Ref at provided path \"" + actionPath + "\" does not have action \"" + action + "\"";
error(missingActionErr);
throw new Error(missingActionErr);
}
_b.label = 1;
case 1:
_b.trys.push([1, 3, , 4]);
return [4 /*yield*/, ref[action](dataToWrite)];
case 2:
res = _b.sent();
return [2 /*return*/, res];
case 3:
err_2 = _b.sent();
error("Error with " + action + " at path \"" + actionPath + "\": ", err_2.message);
throw err_2;
case 4: return [2 /*return*/];
}
});
});
}
/**
* Delete data from Firestore
* @param actionPath - Path at which Firestore action should be run
* @param options - Options object
* @returns Action within Firestore
*/
export function firestoreDelete(actionPath, options) {
return __awaiter(this, void 0, void 0, function () {
var _a, emulator, debug, fbInstance, res, err_3;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
_a = options || {}, emulator = _a.emulator, debug = _a.debug;
fbInstance = initializeFirebase({ emulator: emulator, debug: debug });
// Delete Firestore Collection or SubCollection
if (actionPath.split('/').length % 2) {
return [2 /*return*/, deleteFirestoreCollection(fbInstance.firestore(), actionPath, (options === null || options === void 0 ? void 0 : options.batchSize) || 200)];
}
_b.label = 1;
case 1:
_b.trys.push([1, 3, , 4]);
return [4 /*yield*/, fbInstance.firestore().doc(actionPath).delete()];
case 2:
res = _b.sent();
return [2 /*return*/, res];
case 3:
err_3 = _b.sent();
error("firestore:delete at path \"" + actionPath + "\": ", err_3.message);
throw err_3;
case 4: return [2 /*return*/];
}
});
});
}