n8n-nodes-base
Version:
Base nodes of n8n
435 lines • 16.2 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.description = void 0;
exports.execute = execute;
const n8n_workflow_1 = require("n8n-workflow");
const commonDescription_1 = require("./commonDescription");
const GoogleSheets_types_1 = require("../../helpers/GoogleSheets.types");
const GoogleSheets_utils_1 = require("../../helpers/GoogleSheets.utils");
exports.description = [
{
displayName: 'Data Mode',
name: 'dataMode',
type: 'options',
options: [
{
name: 'Auto-Map Input Data to Columns',
value: 'autoMapInputData',
description: 'Use when node input properties match destination column names',
},
{
name: 'Map Each Column Below',
value: 'defineBelow',
description: 'Set the value for each destination column',
},
{
name: 'Nothing',
value: 'nothing',
description: 'Do not send anything',
},
],
displayOptions: {
show: {
resource: ['sheet'],
operation: ['appendOrUpdate'],
'@version': [3],
},
hide: {
...GoogleSheets_utils_1.untilSheetSelected,
},
},
default: 'defineBelow',
description: 'Whether to insert the input data this node receives in the new row',
},
{
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-miscased, n8n-nodes-base/node-param-display-name-wrong-for-dynamic-options
displayName: 'Column to match on',
name: 'columnToMatchOn',
type: 'options',
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
typeOptions: {
loadOptionsDependsOn: ['sheetName.value'],
loadOptionsMethod: 'getSheetHeaderRowAndSkipEmpty',
},
default: '',
hint: "Used to find the correct row to update. Doesn't get changed.",
displayOptions: {
show: {
resource: ['sheet'],
operation: ['appendOrUpdate'],
'@version': [3],
},
hide: {
...GoogleSheets_utils_1.untilSheetSelected,
},
},
},
{
displayName: 'Value of Column to Match On',
name: 'valueToMatchOn',
type: 'string',
default: '',
displayOptions: {
show: {
resource: ['sheet'],
operation: ['appendOrUpdate'],
dataMode: ['defineBelow'],
'@version': [3],
},
hide: {
...GoogleSheets_utils_1.untilSheetSelected,
},
},
},
{
displayName: 'Values to Send',
name: 'fieldsUi',
placeholder: 'Add Field',
type: 'fixedCollection',
typeOptions: {
multipleValues: true,
},
displayOptions: {
show: {
resource: ['sheet'],
operation: ['appendOrUpdate'],
dataMode: ['defineBelow'],
'@version': [3],
},
hide: {
...GoogleSheets_utils_1.untilSheetSelected,
},
},
default: {},
options: [
{
displayName: 'Field',
name: 'values',
values: [
{
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-wrong-for-dynamic-options
displayName: 'Column',
name: 'column',
type: 'options',
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
typeOptions: {
loadOptionsDependsOn: ['sheetName.value', 'columnToMatchOn'],
loadOptionsMethod: 'getSheetHeaderRowAndAddColumn',
},
default: '',
},
{
displayName: 'Column Name',
name: 'columnName',
type: 'string',
default: '',
displayOptions: {
show: {
column: ['newColumn'],
},
},
},
{
displayName: 'Value',
name: 'fieldValue',
type: 'string',
default: '',
},
],
},
],
},
{
displayName: 'Columns',
name: 'columns',
type: 'resourceMapper',
noDataExpression: true,
default: {
mappingMode: 'defineBelow',
value: null,
},
required: true,
typeOptions: {
loadOptionsDependsOn: ['sheetName.value'],
resourceMapper: {
resourceMapperMethod: 'getMappingColumns',
mode: 'upsert',
fieldWords: {
singular: 'column',
plural: 'columns',
},
addAllFields: true,
multiKeyMatch: false,
allowEmptyValues: true,
},
},
displayOptions: {
show: {
resource: ['sheet'],
operation: ['appendOrUpdate'],
'@version': [{ _cnd: { gte: 4.7 } }],
},
hide: {
...GoogleSheets_utils_1.untilSheetSelected,
},
},
},
{
displayName: 'Columns',
name: 'columns',
type: 'resourceMapper',
noDataExpression: true,
default: {
mappingMode: 'defineBelow',
value: null,
},
required: true,
typeOptions: {
loadOptionsDependsOn: ['sheetName.value'],
resourceMapper: {
resourceMapperMethod: 'getMappingColumns',
mode: 'upsert',
fieldWords: {
singular: 'column',
plural: 'columns',
},
addAllFields: true,
multiKeyMatch: false,
},
},
displayOptions: {
show: {
resource: ['sheet'],
operation: ['appendOrUpdate'],
'@version': [{ _cnd: { between: { from: 4, to: 4.6 } } }],
},
hide: {
...GoogleSheets_utils_1.untilSheetSelected,
},
},
},
{
displayName: 'Options',
name: 'options',
type: 'collection',
placeholder: 'Add option',
default: {},
displayOptions: {
show: {
resource: ['sheet'],
operation: ['appendOrUpdate'],
},
hide: {
...GoogleSheets_utils_1.untilSheetSelected,
},
},
options: [
commonDescription_1.cellFormat,
commonDescription_1.locationDefine,
commonDescription_1.handlingExtraData,
{
...commonDescription_1.handlingExtraData,
displayOptions: { show: { '/columns.mappingMode': ['autoMapInputData'] } },
},
commonDescription_1.useAppendOption,
],
},
];
async function execute(sheet, sheetName, sheetId) {
const items = this.getInputData();
const nodeVersion = this.getNode().typeVersion;
const range = `${sheetName}!A:Z`;
const valueInputMode = this.getNodeParameter('options.cellFormat', 0, (0, GoogleSheets_utils_1.cellFormatDefault)(nodeVersion));
const options = this.getNodeParameter('options', 0, {});
const valueRenderMode = (options.valueRenderMode || 'UNFORMATTED_VALUE');
const locationDefineOption = options.locationDefine?.values;
let keyRowIndex = 0;
let dataStartRowIndex = 1;
if (locationDefineOption) {
if (locationDefineOption.headerRow) {
keyRowIndex = parseInt(locationDefineOption.headerRow, 10) - 1;
}
if (locationDefineOption.firstDataRow) {
dataStartRowIndex = parseInt(locationDefineOption.firstDataRow, 10) - 1;
}
}
let dataMode = nodeVersion < 4
? this.getNodeParameter('dataMode', 0)
: this.getNodeParameter('columns.mappingMode', 0);
let columnNames = [];
const sheetData = (await sheet.getData(sheetName, 'FORMATTED_VALUE')) ?? [];
if (!sheetData[keyRowIndex] && dataMode !== 'autoMapInputData') {
if (!sheetData.length) {
dataMode = 'autoMapInputData';
}
else {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Could not retrieve the column names from row ${keyRowIndex + 1}`);
}
}
columnNames = sheetData[keyRowIndex] ?? [];
if (nodeVersion >= 4.4) {
const schema = this.getNodeParameter('columns.schema', 0);
(0, GoogleSheets_utils_1.checkForSchemaChanges)(this.getNode(), columnNames, schema);
}
const newColumns = new Set();
const columnsToMatchOn = nodeVersion < 4
? [this.getNodeParameter('columnToMatchOn', 0)]
: this.getNodeParameter('columns.matchingColumns', 0);
// TODO: Add support for multiple columns to match on in the next overhaul
const keyIndex = columnNames.indexOf(columnsToMatchOn[0]);
const columnValuesList = await sheet.getColumnValues({
range,
keyIndex,
dataStartRowIndex,
valueRenderMode,
sheetData,
});
const updateData = [];
const appendData = [];
const errorOnUnexpectedColumn = (key, i) => {
if (!columnNames.includes(key)) {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Unexpected fields in node input', {
itemIndex: i,
description: `The input field '${key}' doesn't match any column in the Sheet. You can ignore this by changing the 'Handling extra data' field, which you can find under 'Options'.`,
});
}
};
const addNewColumn = (key) => {
if (!columnNames.includes(key) && key !== GoogleSheets_types_1.ROW_NUMBER) {
newColumns.add(key);
}
};
const mappedValues = [];
for (let i = 0; i < items.length; i++) {
if (dataMode === 'nothing')
continue;
const inputData = [];
if (dataMode === 'autoMapInputData') {
const handlingExtraDataOption = options.handlingExtraData || 'insertInNewColumn';
if (handlingExtraDataOption === 'ignoreIt') {
inputData.push(items[i].json);
}
if (handlingExtraDataOption === 'error') {
Object.keys(items[i].json).forEach((key) => errorOnUnexpectedColumn(key, i));
inputData.push(items[i].json);
}
if (handlingExtraDataOption === 'insertInNewColumn') {
Object.keys(items[i].json).forEach(addNewColumn);
inputData.push(items[i].json);
}
}
else {
const valueToMatchOn = nodeVersion < 4
? this.getNodeParameter('valueToMatchOn', i, '')
: this.getNodeParameter(`columns.value[${columnsToMatchOn[0]}]`, i, '');
if (valueToMatchOn === '') {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), "The 'Column to Match On' parameter is required", {
itemIndex: i,
});
}
if (nodeVersion < 4) {
const valuesToSend = this.getNodeParameter('fieldsUi.values', i, []);
if (!valuesToSend?.length) {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), "At least one value has to be added under 'Values to Send'");
}
const fields = valuesToSend.reduce((acc, entry) => {
if (entry.column === 'newColumn') {
const columnName = entry.columnName;
if (!columnNames.includes(columnName)) {
newColumns.add(columnName);
}
acc[columnName] = entry.fieldValue;
}
else {
acc[entry.column] = entry.fieldValue;
}
return acc;
}, {});
fields[columnsToMatchOn[0]] = valueToMatchOn;
inputData.push(fields);
}
else {
const mappingValues = this.getNodeParameter('columns.value', i);
if (Object.keys(mappingValues).length === 0) {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), "At least one value has to be added under 'Values to Send'");
}
// Setting empty values to empty string so that they are not ignored by the API
Object.keys(mappingValues).forEach((key) => {
if (mappingValues[key] === undefined || mappingValues[key] === null) {
mappingValues[key] = '';
}
});
inputData.push(mappingValues);
mappedValues.push(mappingValues);
}
}
if (newColumns.size) {
const newColumnNames = columnNames.concat([...newColumns]);
await sheet.updateRows(sheetName, [newColumnNames], options.cellFormat || (0, GoogleSheets_utils_1.cellFormatDefault)(nodeVersion), keyRowIndex + 1);
columnNames = newColumnNames;
sheetData[keyRowIndex] = newColumnNames;
newColumns.clear();
}
const indexKey = columnsToMatchOn[0];
const preparedData = await sheet.prepareDataForUpdateOrUpsert({
inputData,
indexKey,
range,
keyRowIndex,
dataStartRowIndex,
valueRenderMode,
upsert: true,
columnNamesList: [columnNames.concat([...newColumns])],
columnValuesList,
});
updateData.push(...preparedData.updateData);
appendData.push(...preparedData.appendData);
}
const columnNamesList = [columnNames.concat([...newColumns])];
if (updateData.length) {
await sheet.batchUpdate(updateData, valueInputMode);
}
if (appendData.length) {
const lastRow = sheetData.length + 1;
const useAppend = options.useAppend;
if (options.useAppend) {
await sheet.appendSheetData({
inputData: appendData,
range,
keyRowIndex: keyRowIndex + 1,
valueInputMode,
columnNamesList,
lastRow,
useAppend,
});
}
else {
await sheet.appendEmptyRowsOrColumns(sheetId, 1, 0);
await sheet.appendSheetData({
inputData: appendData,
range,
keyRowIndex: keyRowIndex + 1,
valueInputMode,
columnNamesList,
lastRow,
});
}
}
if (nodeVersion < 4 || dataMode === 'autoMapInputData') {
return items.map((item, index) => {
item.pairedItem = { item: index };
return item;
});
}
else {
const returnData = [];
for (const [index, entry] of mappedValues.entries()) {
returnData.push({
json: entry,
pairedItem: { item: index },
});
}
return returnData;
}
}
//# sourceMappingURL=appendOrUpdate.operation.js.map