actions/upsert-row/upsert-row.mjs
import { v4 as uuid } from "uuid"; import common from "../common/worksheet.mjs"; import { VALUE_RENDER_OPTION } from "../../common/constants.mjs"; import { omitEmptyKey, toSingleLineString, } from "../../common/utils.mjs"; const { googleSheets } = common.props; export default { ...common, key: "google_sheets-upsert-row", name: "Upsert Row", description: "Upsert a row of data in a Google Sheet. [See the documentation](https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.values/append)", version: "0.1.17", annotations: { destructiveHint: true, openWorldHint: true, readOnlyHint: false, }, type: "action", props: { googleSheets, drive: { propDefinition: [ googleSheets, "watchedDrive", ], }, sheetId: { propDefinition: [ googleSheets, "sheetID", (c) => ({ driveId: googleSheets.methods.getDriveId(c.drive), }), ], }, worksheetId: { propDefinition: [ googleSheets, "worksheetIDs", (c) => ({ sheetId: c.sheetId, }), ], }, insert: { propDefinition: [ googleSheets, "cells", ], label: "Insert - Cells / Column Values", description: toSingleLineString(` Insert statement: the row data you want to add to the Google sheet if the key *doesn't* exist. If the key *does* exist and **Update** is not set, the row will be updated using this array. Enter individual cell values or enter a custom expression to pass an array with each element representing a cell/column value (e.g. \`{{ [5, "test"] }}\`). `), }, column: { propDefinition: [ googleSheets, "column", ], label: "Key Column", description: "The column of the sheet to lookup (e.g. `A`). This column functions as the key column for the upsert operation.", }, value: { type: "string", label: "Key Value", description: "The value of the key to search for in **Key Column**. Defaults to the value in **Insert**'s \"key\" column if left blank.", optional: true, }, updates: { type: "object", label: "Update - Column / Values", description: toSingleLineString(` Update statment: if the spreadsheet contains duplicate key **Value** in some row in the specified **Column**, individual cells in the *first* duplicate row will be updated using this object's column-value pairs.<br /> Enter the column name for the key (e.g. \`B\`) and the corresponding column value (e.g. \`test\`). You may also enter a custom expression and pass a JSON object with key/value pairs representing columns and values (e.g. \`{{ { A: 5, B: "test" } }}\`). `), optional: true, }, }, async run({ $ }) { const { sheetId, worksheetId, insert, column, value, updates, } = this; const worksheet = await this.getWorksheetById(sheetId, worksheetId); const colIndex = this.googleSheets._getColumnIndex(column) - 1; const keyValue = value ? value : insert[colIndex]; const hiddenWorksheetTitle = uuid(); const addSheetResult = await this.googleSheets.createWorksheet(sheetId, { title: hiddenWorksheetTitle, hidden: true, gridProperties: { rowCount: 2, columnCount: 1, }, }); const hiddenSheetId = addSheetResult.properties.sheetId; try { const matchResult = await this.googleSheets.addRowsToSheet({ spreadsheetId: sheetId, range: hiddenWorksheetTitle, rows: [ [ keyValue, ], [ this.googleSheets.buildMatchFormula("A1", worksheet?.properties?.title, { column, searchType: 0, }), ], ], params: { includeValuesInResponse: true, responseValueRenderOption: VALUE_RENDER_OPTION.FORMATTED_VALUE, }, }); const matchedRow = matchResult.updatedData?.values?.[1]?.[0]; const shouldUpdate = matchedRow && matchedRow !== "#N/A"; if (!shouldUpdate) { const result = await this.googleSheets.addRowsToSheet({ spreadsheetId: sheetId, range: worksheet?.properties?.title, rows: [ insert, ], }); $.export("$summary", `Couldn't find the key, "${keyValue}", so inserted new row: "${insert}"`); return result; } const updateParams = [ sheetId, worksheet?.properties?.title, matchedRow, ]; const sanitizedUpdates = omitEmptyKey(updates); const updateRowCells = sanitizedUpdates && Object.keys(sanitizedUpdates).length; const updatePromise = updateRowCells ? this.googleSheets.updateRowCells(...updateParams, sanitizedUpdates) : this.googleSheets.updateRow(...updateParams, insert); const result = await updatePromise; $.export("$summary", `Successfully updated row ${matchedRow}`); return result; } finally { await this.googleSheets.deleteWorksheet(sheetId, hiddenSheetId); } }, };