Skip to content

Commit

Permalink
feat(Google Sheets Node): Allow to use header names as JSON path (#3165)
Browse files Browse the repository at this point in the history
* Add option to match key by keypath when append data to google sheet

* ⚡ Fix build issue and option order

Co-authored-by: Jack Rudenko <i@madappgang.com>
Co-authored-by: Jan Oberhauser <jan.oberhauser@gmail.com>
  • Loading branch information
3 people authored Apr 29, 2022
1 parent d5b9b0c commit 770c4fe
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 10 deletions.
19 changes: 11 additions & 8 deletions packages/nodes-base/nodes/Google/Sheet/GoogleSheet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import {
utils as xlsxUtils,
} from 'xlsx';

import { get } from 'lodash';

export interface ISheetOptions {
scope: string[];
}
Expand Down Expand Up @@ -245,8 +247,8 @@ export class GoogleSheet {
}


async appendSheetData(inputData: IDataObject[], range: string, keyRowIndex: number, valueInputMode: ValueInputOption): Promise<string[][]> {
const data = await this.convertStructuredDataToArray(inputData, range, keyRowIndex);
async appendSheetData(inputData: IDataObject[], range: string, keyRowIndex: number, valueInputMode: ValueInputOption, usePathForKeyRow: boolean): Promise<string[][]> {
const data = await this.convertStructuredDataToArray(inputData, range, keyRowIndex, usePathForKeyRow);
return this.appendData(range, data, valueInputMode);
}

Expand Down Expand Up @@ -344,7 +346,7 @@ export class GoogleSheet {
if (itemKey === undefined || itemKey === null) {
// Item does not have the indexKey so we can ignore it or append it if upsert true
if (upsert) {
const data = await this.appendSheetData([inputItem], this.encodeRange(range), keyRowIndex, valueInputMode);
const data = await this.appendSheetData([inputItem], this.encodeRange(range), keyRowIndex, valueInputMode, false);
}
continue;
}
Expand All @@ -354,7 +356,7 @@ export class GoogleSheet {
if (itemKeyIndex === -1) {
// Key does not exist in the Sheet so it can not be updated so skip it or append it if upsert true
if (upsert) {
const data = await this.appendSheetData([inputItem], this.encodeRange(range), keyRowIndex, valueInputMode);
const data = await this.appendSheetData([inputItem], this.encodeRange(range), keyRowIndex, valueInputMode, false);
}
continue;
}
Expand Down Expand Up @@ -472,7 +474,7 @@ export class GoogleSheet {
}


async convertStructuredDataToArray(inputData: IDataObject[], range: string, keyRowIndex: number): Promise<string[][]> {
async convertStructuredDataToArray(inputData: IDataObject[], range: string, keyRowIndex: number, usePathForKeyRow: boolean): Promise<string[][]> {
let startColumn, endColumn;
let sheet: string | undefined = undefined;
if (range.includes('!')) {
Expand Down Expand Up @@ -501,9 +503,10 @@ export class GoogleSheet {
inputData.forEach((item) => {
rowData = [];
keyColumnOrder.forEach((key) => {
const data = item[key];
if (item.hasOwnProperty(key) && data !== null && typeof data !== 'undefined') {
rowData.push(data.toString());
if (usePathForKeyRow && (get(item, key) !== undefined)) { //match by key path
rowData.push(get(item, key)!.toString());
} else if (!usePathForKeyRow && item.hasOwnProperty(key) && item[key] !== null && item[key] !== undefined) { //match by exact key name
rowData.push(item[key]!.toString());
} else {
rowData.push('');
}
Expand Down
19 changes: 17 additions & 2 deletions packages/nodes-base/nodes/Google/Sheet/GoogleSheets.node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,20 @@ export class GoogleSheets implements INodeType {
},
description: 'By default only the first result gets returned. If options gets set all found matches get returned.',
},
{
displayName: 'Use Header Names as JSON Paths',
name: 'usePathForKeyRow',
type: 'boolean',
default: false,
displayOptions: {
show: {
'/operation': [
'append',
],
},
},
description: 'Enable if you want to match the headers as path, for example, the row header "category.name" will match the "category" object and get the field "name" from it. By default "category.name" will match with the field with exact name, not nested object.',
},
{
displayName: 'Value Input Mode',
name: 'valueInputMode',
Expand Down Expand Up @@ -674,7 +688,6 @@ export class GoogleSheets implements INodeType {
default: 'UNFORMATTED_VALUE',
description: 'Determines how values should be rendered in the output.',
},

],
},

Expand Down Expand Up @@ -1089,8 +1102,10 @@ export class GoogleSheets implements INodeType {
setData.push(item.json);
});

const usePathForKeyRow = (options.usePathForKeyRow || false) as boolean;

// Convert data into array format
const data = await sheet.appendSheetData(setData, sheet.encodeRange(range), keyRow, valueInputMode);
const data = await sheet.appendSheetData(setData, sheet.encodeRange(range), keyRow, valueInputMode, usePathForKeyRow);

// TODO: Should add this data somewhere
// TODO: Should have something like add metadata which does not get passed through
Expand Down

0 comments on commit 770c4fe

Please sign in to comment.