UNPKG

firebase-tools

Version:
110 lines (109 loc) 4.48 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.command = void 0; const pg = require("pg"); const clc = require("colorette"); const cloud_sql_connector_1 = require("@google-cloud/cloud-sql-connector"); const command_1 = require("../command"); const projectUtils_1 = require("../projectUtils"); const ensureApis_1 = require("../dataconnect/ensureApis"); const requirePermissions_1 = require("../requirePermissions"); const fileUtils_1 = require("../dataconnect/fileUtils"); const schemaMigration_1 = require("../dataconnect/schemaMigration"); const requireAuth_1 = require("../requireAuth"); const connect_1 = require("../gcp/cloudsql/connect"); const cloudSqlAdminClient = require("../gcp/cloudsql/cloudsqladmin"); const prompt_1 = require("../prompt"); const logger_1 = require("../logger"); const error_1 = require("../error"); const fbToolsAuthClient_1 = require("../gcp/cloudsql/fbToolsAuthClient"); const interactive_1 = require("../gcp/cloudsql/interactive"); const sqlKeywords = [ "SELECT", "FROM", "WHERE", "INSERT", "UPDATE", "DELETE", "JOIN", "GROUP", "ORDER", "LIMIT", "GRANT", "CREATE", "DROP", ]; async function promptForQuery() { let query = ""; const line = ""; do { let line = await (0, prompt_1.input)({ message: query ? "> " : "Enter your SQL query (or '.exit'):", transformer: (input) => { return input .split(" ") .map((word) => (sqlKeywords.includes(word.toUpperCase()) ? clc.cyan(word) : word)) .join(" "); }, nonInteractive: false, }); line = line.trimEnd(); if (line.toLowerCase() === ".exit") { return ".exit"; } query += (query ? "\n" : "") + line; } while (line !== "" && !query.endsWith(";")); return query; } async function mainShellLoop(conn) { while (true) { const query = await promptForQuery(); if (query.toLowerCase() === ".exit") { break; } if (query === "") { continue; } if (await (0, interactive_1.confirmDangerousQuery)(query)) { await (0, interactive_1.interactiveExecuteQuery)(query, conn); } else { logger_1.logger.info(clc.yellow("Query cancelled.")); } } } exports.command = new command_1.Command("dataconnect:sql:shell [serviceId]") .description("start a shell connected directly to your Data Connect service's linked CloudSQL instance") .before(requirePermissions_1.requirePermissions, ["firebasedataconnect.services.list", "cloudsql.instances.connect"]) .before(requireAuth_1.requireAuth) .action(async (serviceId, options) => { const projectId = (0, projectUtils_1.needProjectId)(options); await (0, ensureApis_1.ensureApis)(projectId); const serviceInfo = await (0, fileUtils_1.pickService)(projectId, options.config, serviceId); const { instanceId, databaseId } = (0, schemaMigration_1.getIdentifiers)(serviceInfo.schema); const { user: username } = await (0, connect_1.getIAMUser)(options); const instance = await cloudSqlAdminClient.getInstance(projectId, instanceId); const connectionName = instance.connectionName; if (!connectionName) { throw new error_1.FirebaseError(`Could not get instance connection string for ${options.instanceId}:${options.databaseId}`); } const connector = new cloud_sql_connector_1.Connector({ auth: new fbToolsAuthClient_1.FBToolsAuthClient(), }); const clientOpts = await connector.getOptions({ instanceConnectionName: connectionName, ipType: cloud_sql_connector_1.IpAddressTypes.PUBLIC, authType: cloud_sql_connector_1.AuthTypes.IAM, }); const pool = new pg.Pool(Object.assign(Object.assign({}, clientOpts), { user: username, database: databaseId })); const conn = await pool.connect(); logger_1.logger.info(`Logged in as ${username}`); logger_1.logger.info(clc.cyan("Welcome to Data Connect Cloud SQL Shell")); logger_1.logger.info(clc.gray("Type your your SQL query or '.exit' to quit, queries should end with ';' or add empty line to execute.")); await mainShellLoop(conn); logger_1.logger.info(clc.yellow("Exiting shell...")); conn.release(); await pool.end(); connector.close(); return { projectId, serviceId }; });