mirror of
https://github.com/n8n-io/n8n.git
synced 2025-02-21 02:56:40 -08:00
✨ Make it possible to define how values should be interpreted
This commit is contained in:
parent
8b1e3d7ba9
commit
f82436dc8d
|
@ -23,6 +23,10 @@ export interface ILookupValues {
|
||||||
lookupValue: string;
|
lookupValue: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ValueInputOption = 'RAW' | 'USER_ENTERED';
|
||||||
|
|
||||||
|
export type ValueRenderOption = 'FORMATTED_VALUE' | 'FORMULA' | 'UNFORMATTED_VALUE';
|
||||||
|
|
||||||
export class GoogleSheet {
|
export class GoogleSheet {
|
||||||
id: string;
|
id: string;
|
||||||
credentials: IGoogleAuthCredentials;
|
credentials: IGoogleAuthCredentials;
|
||||||
|
@ -43,7 +47,7 @@ export class GoogleSheet {
|
||||||
/**
|
/**
|
||||||
* Returns the cell values
|
* Returns the cell values
|
||||||
*/
|
*/
|
||||||
async getData(range: string): Promise<string[][] | undefined> {
|
async getData(range: string, valueRenderMode: ValueRenderOption): Promise<string[][] | undefined> {
|
||||||
const client = await this.getAuthenticationClient();
|
const client = await this.getAuthenticationClient();
|
||||||
|
|
||||||
const response = await Sheets.spreadsheets.values.get(
|
const response = await Sheets.spreadsheets.values.get(
|
||||||
|
@ -51,7 +55,7 @@ export class GoogleSheet {
|
||||||
auth: client,
|
auth: client,
|
||||||
spreadsheetId: this.id,
|
spreadsheetId: this.id,
|
||||||
range,
|
range,
|
||||||
valueRenderOption: 'UNFORMATTED_VALUE',
|
valueRenderOption: valueRenderMode,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -62,7 +66,7 @@ export class GoogleSheet {
|
||||||
/**
|
/**
|
||||||
* Sets the cell values
|
* Sets the cell values
|
||||||
*/
|
*/
|
||||||
async batchUpdate(updateData: ISheetUpdateData[]) {
|
async batchUpdate(updateData: ISheetUpdateData[], valueInputMode: ValueInputOption) {
|
||||||
const client = await this.getAuthenticationClient();
|
const client = await this.getAuthenticationClient();
|
||||||
|
|
||||||
const response = await Sheets.spreadsheets.values.batchUpdate(
|
const response = await Sheets.spreadsheets.values.batchUpdate(
|
||||||
|
@ -70,10 +74,9 @@ export class GoogleSheet {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
auth: client,
|
auth: client,
|
||||||
spreadsheetId: this.id,
|
spreadsheetId: this.id,
|
||||||
valueInputOption: 'RAW',
|
valueInputOption: valueInputMode,
|
||||||
resource: {
|
resource: {
|
||||||
data: updateData,
|
data: updateData,
|
||||||
valueInputOption: "USER_ENTERED",
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -85,7 +88,7 @@ export class GoogleSheet {
|
||||||
/**
|
/**
|
||||||
* Sets the cell values
|
* Sets the cell values
|
||||||
*/
|
*/
|
||||||
async setData(range: string, data: string[][]) {
|
async setData(range: string, data: string[][], valueInputMode: ValueInputOption) {
|
||||||
const client = await this.getAuthenticationClient();
|
const client = await this.getAuthenticationClient();
|
||||||
|
|
||||||
const response = await Sheets.spreadsheets.values.update(
|
const response = await Sheets.spreadsheets.values.update(
|
||||||
|
@ -94,7 +97,7 @@ export class GoogleSheet {
|
||||||
auth: client,
|
auth: client,
|
||||||
spreadsheetId: this.id,
|
spreadsheetId: this.id,
|
||||||
range,
|
range,
|
||||||
valueInputOption: 'RAW',
|
valueInputOption: valueInputMode,
|
||||||
resource: {
|
resource: {
|
||||||
values: data
|
values: data
|
||||||
}
|
}
|
||||||
|
@ -108,7 +111,7 @@ export class GoogleSheet {
|
||||||
/**
|
/**
|
||||||
* Appends the cell values
|
* Appends the cell values
|
||||||
*/
|
*/
|
||||||
async appendData(range: string, data: string[][]) {
|
async appendData(range: string, data: string[][], valueInputMode: ValueInputOption) {
|
||||||
const client = await this.getAuthenticationClient();
|
const client = await this.getAuthenticationClient();
|
||||||
|
|
||||||
const response = await Sheets.spreadsheets.values.append(
|
const response = await Sheets.spreadsheets.values.append(
|
||||||
|
@ -117,7 +120,7 @@ export class GoogleSheet {
|
||||||
auth: client,
|
auth: client,
|
||||||
spreadsheetId: this.id,
|
spreadsheetId: this.id,
|
||||||
range,
|
range,
|
||||||
valueInputOption: 'RAW',
|
valueInputOption: valueInputMode,
|
||||||
resource: {
|
resource: {
|
||||||
values: data
|
values: data
|
||||||
}
|
}
|
||||||
|
@ -196,9 +199,9 @@ export class GoogleSheet {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async appendSheetData(inputData: IDataObject[], range: string, keyRowIndex: number): Promise<string[][]> {
|
async appendSheetData(inputData: IDataObject[], range: string, keyRowIndex: number, valueInputMode: ValueInputOption): Promise<string[][]> {
|
||||||
const data = await this.convertStructuredDataToArray(inputData, range, keyRowIndex);
|
const data = await this.convertStructuredDataToArray(inputData, range, keyRowIndex);
|
||||||
return this.appendData(range, data);
|
return this.appendData(range, data, valueInputMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -213,7 +216,7 @@ export class GoogleSheet {
|
||||||
* @returns {Promise<string[][]>}
|
* @returns {Promise<string[][]>}
|
||||||
* @memberof GoogleSheet
|
* @memberof GoogleSheet
|
||||||
*/
|
*/
|
||||||
async updateSheetData(inputData: IDataObject[], indexKey: string, range: string, keyRowIndex: number, dataStartRowIndex: number): Promise<string[][]> {
|
async updateSheetData(inputData: IDataObject[], indexKey: string, range: string, keyRowIndex: number, dataStartRowIndex: number, valueInputMode: ValueInputOption, valueRenderMode: ValueRenderOption): Promise<string[][]> {
|
||||||
// Get current data in Google Sheet
|
// Get current data in Google Sheet
|
||||||
let rangeStart: string, rangeEnd: string;
|
let rangeStart: string, rangeEnd: string;
|
||||||
let sheet: string | undefined = undefined;
|
let sheet: string | undefined = undefined;
|
||||||
|
@ -224,7 +227,7 @@ export class GoogleSheet {
|
||||||
|
|
||||||
const keyRowRange = `${sheet ? sheet + '!' : ''}${rangeStart}${dataStartRowIndex}:${rangeEnd}${dataStartRowIndex}`;
|
const keyRowRange = `${sheet ? sheet + '!' : ''}${rangeStart}${dataStartRowIndex}:${rangeEnd}${dataStartRowIndex}`;
|
||||||
|
|
||||||
const sheetDatakeyRow = await this.getData(keyRowRange);
|
const sheetDatakeyRow = await this.getData(keyRowRange, valueRenderMode);
|
||||||
|
|
||||||
if (sheetDatakeyRow === undefined) {
|
if (sheetDatakeyRow === undefined) {
|
||||||
throw new Error('Could not retrieve the key row!');
|
throw new Error('Could not retrieve the key row!');
|
||||||
|
@ -242,7 +245,7 @@ export class GoogleSheet {
|
||||||
let keyColumnRange = String.fromCharCode(characterCode);
|
let keyColumnRange = String.fromCharCode(characterCode);
|
||||||
keyColumnRange = `${sheet ? sheet + '!' : ''}${keyColumnRange}:${keyColumnRange}`;
|
keyColumnRange = `${sheet ? sheet + '!' : ''}${keyColumnRange}:${keyColumnRange}`;
|
||||||
|
|
||||||
const sheetDataKeyColumn = await this.getData(keyColumnRange);
|
const sheetDataKeyColumn = await this.getData(keyColumnRange, valueRenderMode);
|
||||||
|
|
||||||
if (sheetDataKeyColumn === undefined) {
|
if (sheetDataKeyColumn === undefined) {
|
||||||
throw new Error('Could not retrieve the key column!');
|
throw new Error('Could not retrieve the key column!');
|
||||||
|
@ -312,7 +315,7 @@ export class GoogleSheet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.batchUpdate(updateData);
|
return this.batchUpdate(updateData, valueInputMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -386,7 +389,7 @@ export class GoogleSheet {
|
||||||
getRange = `${sheet}!${getRange}`;
|
getRange = `${sheet}!${getRange}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const keyColumnData = await this.getData(getRange);
|
const keyColumnData = await this.getData(getRange, 'UNFORMATTED_VALUE');
|
||||||
|
|
||||||
if (keyColumnData === undefined) {
|
if (keyColumnData === undefined) {
|
||||||
throw new Error('Could not retrieve the column data!');
|
throw new Error('Could not retrieve the column data!');
|
||||||
|
|
|
@ -11,6 +11,8 @@ import {
|
||||||
IGoogleAuthCredentials,
|
IGoogleAuthCredentials,
|
||||||
ILookupValues,
|
ILookupValues,
|
||||||
ISheetUpdateData,
|
ISheetUpdateData,
|
||||||
|
ValueInputOption,
|
||||||
|
ValueRenderOption,
|
||||||
} from './GoogleSheet';
|
} from './GoogleSheet';
|
||||||
|
|
||||||
|
|
||||||
|
@ -258,6 +260,110 @@ export class GoogleSheets implements INodeType {
|
||||||
description: 'The name of the key to identify which<br />data should be updated in the sheet.',
|
description: 'The name of the key to identify which<br />data should be updated in the sheet.',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
displayName: 'Options',
|
||||||
|
name: 'options',
|
||||||
|
type: 'collection',
|
||||||
|
placeholder: 'Add Option',
|
||||||
|
default: {},
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
displayName: 'Value Input Mode',
|
||||||
|
name: 'valueInputMode',
|
||||||
|
type: 'options',
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
'/operation': [
|
||||||
|
'append',
|
||||||
|
'update',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'RAW',
|
||||||
|
value: 'RAW',
|
||||||
|
description: 'The values will not be parsed and will be stored as-is.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'User Entered',
|
||||||
|
value: 'USER_ENTERED',
|
||||||
|
description: 'The values will be parsed as if the user typed them into the UI. Numbers will stay as numbers, but strings may be converted to numbers, dates, etc. following the same rules that are applied when entering text into a cell via the Google Sheets UI.'
|
||||||
|
},
|
||||||
|
],
|
||||||
|
default: 'RAW',
|
||||||
|
description: 'Determines how data should be interpreted.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Value Render Mode',
|
||||||
|
name: 'valueRenderMode',
|
||||||
|
type: 'options',
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
'/operation': [
|
||||||
|
'lookup',
|
||||||
|
'read',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'Formatted Value',
|
||||||
|
value: 'FORMATTED_VALUE',
|
||||||
|
description: 'Values will be calculated & formatted in the reply according to the cell\'s formatting.Formatting is based on the spreadsheet\'s locale, not the requesting user\'s locale.For example, if A1 is 1.23 and A2 is =A1 and formatted as currency, then A2 would return "$1.23".',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Formula',
|
||||||
|
value: 'FORMULA',
|
||||||
|
description: ' Values will not be calculated. The reply will include the formulas. For example, if A1 is 1.23 and A2 is =A1 and formatted as currency, then A2 would return "=A1".',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Unformatted Value',
|
||||||
|
value: 'UNFORMATTED_VALUE',
|
||||||
|
description: 'Values will be calculated, but not formatted in the reply. For example, if A1 is 1.23 and A2 is =A1 and formatted as currency, then A2 would return the number 1.23.'
|
||||||
|
},
|
||||||
|
],
|
||||||
|
default: 'UNFORMATTED_VALUE',
|
||||||
|
description: 'Determines how values should be rendered in the output.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Value Render Mode',
|
||||||
|
name: 'valueRenderMode',
|
||||||
|
type: 'options',
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
'/operation': [
|
||||||
|
'update',
|
||||||
|
],
|
||||||
|
'/rawData': [
|
||||||
|
false
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'Formatted Value',
|
||||||
|
value: 'FORMATTED_VALUE',
|
||||||
|
description: 'Values will be calculated & formatted in the reply according to the cell\'s formatting.Formatting is based on the spreadsheet\'s locale, not the requesting user\'s locale.For example, if A1 is 1.23 and A2 is =A1 and formatted as currency, then A2 would return "$1.23".',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Formula',
|
||||||
|
value: 'FORMULA',
|
||||||
|
description: ' Values will not be calculated. The reply will include the formulas. For example, if A1 is 1.23 and A2 is =A1 and formatted as currency, then A2 would return "=A1".',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Unformatted Value',
|
||||||
|
value: 'UNFORMATTED_VALUE',
|
||||||
|
description: 'Values will be calculated, but not formatted in the reply. For example, if A1 is 1.23 and A2 is =A1 and formatted as currency, then A2 would return the number 1.23.'
|
||||||
|
},
|
||||||
|
],
|
||||||
|
default: 'UNFORMATTED_VALUE',
|
||||||
|
description: 'Determines how values should be rendered in the output.',
|
||||||
|
},
|
||||||
|
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -281,6 +387,10 @@ export class GoogleSheets implements INodeType {
|
||||||
|
|
||||||
const operation = this.getNodeParameter('operation', 0) as string;
|
const operation = this.getNodeParameter('operation', 0) as string;
|
||||||
|
|
||||||
|
const options = this.getNodeParameter('options', 0, {}) as IDataObject;
|
||||||
|
|
||||||
|
const valueInputMode = (options.valueInputMode || 'RAW') as ValueInputOption;
|
||||||
|
const valueRenderMode = (options.valueRenderMode || 'FORMATTED_VALUE') as ValueRenderOption;
|
||||||
|
|
||||||
if (operation === 'append') {
|
if (operation === 'append') {
|
||||||
// ----------------------------------
|
// ----------------------------------
|
||||||
|
@ -296,7 +406,7 @@ export class GoogleSheets implements INodeType {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Convert data into array format
|
// Convert data into array format
|
||||||
const data = await sheet.appendSheetData(setData, range, keyRow);
|
const data = await sheet.appendSheetData(setData, range, keyRow, valueInputMode);
|
||||||
|
|
||||||
// TODO: Should add this data somewhere
|
// TODO: Should add this data somewhere
|
||||||
// TODO: Should have something like add metadata which does not get passed through
|
// TODO: Should have something like add metadata which does not get passed through
|
||||||
|
@ -307,7 +417,7 @@ export class GoogleSheets implements INodeType {
|
||||||
// lookup
|
// lookup
|
||||||
// ----------------------------------
|
// ----------------------------------
|
||||||
|
|
||||||
const sheetData = await sheet.getData(range);
|
const sheetData = await sheet.getData(range, valueRenderMode);
|
||||||
|
|
||||||
if (sheetData === undefined) {
|
if (sheetData === undefined) {
|
||||||
return [];
|
return [];
|
||||||
|
@ -336,7 +446,7 @@ export class GoogleSheets implements INodeType {
|
||||||
|
|
||||||
const rawData = this.getNodeParameter('rawData', 0) as boolean;
|
const rawData = this.getNodeParameter('rawData', 0) as boolean;
|
||||||
|
|
||||||
const sheetData = await sheet.getData(range);
|
const sheetData = await sheet.getData(range, valueRenderMode);
|
||||||
|
|
||||||
let returnData: IDataObject[];
|
let returnData: IDataObject[];
|
||||||
if (!sheetData) {
|
if (!sheetData) {
|
||||||
|
@ -376,7 +486,7 @@ export class GoogleSheets implements INodeType {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await sheet.batchUpdate(updateData);
|
const data = await sheet.batchUpdate(updateData, valueInputMode);
|
||||||
} else {
|
} else {
|
||||||
const keyName = this.getNodeParameter('key', 0) as string;
|
const keyName = this.getNodeParameter('key', 0) as string;
|
||||||
const keyRow = this.getNodeParameter('keyRow', 0) as number;
|
const keyRow = this.getNodeParameter('keyRow', 0) as number;
|
||||||
|
@ -387,7 +497,7 @@ export class GoogleSheets implements INodeType {
|
||||||
setData.push(item.json);
|
setData.push(item.json);
|
||||||
});
|
});
|
||||||
|
|
||||||
const data = await sheet.updateSheetData(setData, keyName, range, keyRow, dataStartRow);
|
const data = await sheet.updateSheetData(setData, keyName, range, keyRow, dataStartRow, valueInputMode, valueRenderMode);
|
||||||
}
|
}
|
||||||
// TODO: Should add this data somewhere
|
// TODO: Should add this data somewhere
|
||||||
// TODO: Should have something like add metadata which does not get passed through
|
// TODO: Should have something like add metadata which does not get passed through
|
||||||
|
|
Loading…
Reference in a new issue