Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Google BigQuery Node): Node improvements #4877

Merged
merged 67 commits into from
Apr 19, 2023
Merged
Show file tree
Hide file tree
Changes from 65 commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
256182f
:zap: setup
michael-radency Dec 9, 2022
7f28632
Merge branch 'master' of https://github.com/n8n-io/n8n into node-118-…
michael-radency Dec 9, 2022
4ca987d
:zap: finished v2 setup
michael-radency Dec 9, 2022
877f62d
Merge branch 'master' of https://github.com/n8n-io/n8n into node-118-…
michael-radency Dec 9, 2022
c02d698
Merge branch 'master' of https://github.com/n8n-io/n8n into node-118-…
michael-radency Dec 12, 2022
0b235c7
Merge branch 'master' of https://github.com/n8n-io/n8n into node-118-…
michael-radency Dec 12, 2022
49e071a
:zap: fix return all, fix simplify with nested schema
michael-radency Dec 12, 2022
62df587
Merge branch 'master' of https://github.com/n8n-io/n8n into node-118-…
michael-radency Dec 13, 2022
3812def
:zap: fix for external tables, updated scopes
michael-radency Dec 13, 2022
05d77d0
Merge branch 'master' of https://github.com/n8n-io/n8n into node-118-…
michael-radency Dec 13, 2022
bad1a5a
:zap: query operation
michael-radency Dec 13, 2022
852c138
Merge branch 'master' of https://github.com/n8n-io/n8n into node-118-…
michael-radency Dec 14, 2022
e66dcf5
Merge branch 'master' of https://github.com/n8n-io/n8n into node-118-…
michael-radency Jan 5, 2023
e164647
:zap: linter fixes
michael-radency Jan 5, 2023
aff961c
Merge branch 'master' of https://github.com/n8n-io/n8n into node-118-…
michael-radency Jan 5, 2023
6078300
Merge branch 'master' of https://github.com/n8n-io/n8n into node-118-…
michael-radency Jan 6, 2023
4a93597
:zap: fixed not processed errors when inserting, move main loop to ex…
michael-radency Jan 6, 2023
0eeb82a
Merge branch 'master' of https://github.com/n8n-io/n8n into node-118-…
michael-radency Jan 6, 2023
7cdefe6
:zap: customizible batch size when inserting, improoved errors
michael-radency Jan 6, 2023
dd27909
:zap: options for mapping input
michael-radency Jan 6, 2023
3b9af71
Merge branch 'master' of https://github.com/n8n-io/n8n into node-118-…
michael-radency Jan 10, 2023
93454fc
Merge branch 'master' of https://github.com/n8n-io/n8n into node-118-…
michael-radency Jan 10, 2023
6e6b5c7
:zap: fix for inserting RECORD type
michael-radency Jan 10, 2023
8e60e66
Merge branch 'master' of https://github.com/n8n-io/n8n into node-118-…
michael-radency Jan 10, 2023
3d24413
:zap: updated simplify logic
michael-radency Jan 10, 2023
2fdf31e
:zap: fix for return with selected fields
michael-radency Jan 11, 2023
2fcda63
:zap: option to return table schema
michael-radency Jan 11, 2023
fea744e
Merge branch 'master' of https://github.com/n8n-io/n8n into node-118-…
michael-radency Jan 26, 2023
d52c754
:zap: linter fixes
michael-radency Jan 26, 2023
3bd0ad3
Merge branch 'master' of https://github.com/n8n-io/n8n into node-118-…
michael-radency Jan 30, 2023
fdccf64
:zap: fix imports
michael-radency Jan 30, 2023
f767cfc
:zap: query resource and fixes, rlc for projects
michael-radency Jan 30, 2023
e352642
Merge branch 'master' of https://github.com/n8n-io/n8n into node-118-…
michael-radency Jan 30, 2023
8e2a210
:zap: removed simplify, added raw output option
michael-radency Jan 30, 2023
48f879e
Merge branch 'master' of https://github.com/n8n-io/n8n into node-118-…
michael-radency Jan 30, 2023
29f75ac
:zap: rlc for tables and datasets, no urls option
michael-radency Jan 30, 2023
856fc01
Merge branch 'master' of https://github.com/n8n-io/n8n into node-118-…
michael-radency Jan 30, 2023
21860bc
Merge branch 'master' of https://github.com/n8n-io/n8n into node-118-…
michael-radency Jan 31, 2023
fd90ba6
:zap: updated hints and description of query parameter, fix getMany V…
michael-radency Jan 31, 2023
70adcf0
Merge branch 'master' of https://github.com/n8n-io/n8n into node-118-…
michael-radency Jan 31, 2023
17cf312
:zap: added case when rows are empty
michael-radency Jan 31, 2023
0c1cd9b
Merge branch 'master' of https://github.com/n8n-io/n8n into node-118-…
michael-radency Jan 31, 2023
f9e21a7
Merge branch 'master' of https://github.com/n8n-io/n8n into node-118-…
michael-radency Mar 23, 2023
2d33e53
:zap: linter fixes
michael-radency Mar 23, 2023
571244d
Merge branch 'master' of https://github.com/n8n-io/n8n into node-118-…
michael-radency Mar 24, 2023
98f0f4b
:zap: UI update, one resource
michael-radency Mar 24, 2023
2d966fa
:zap: fix for output with field named json
michael-radency Mar 24, 2023
42b3812
Merge branch 'master' of https://github.com/n8n-io/n8n into node-118-…
michael-radency Mar 24, 2023
d0deced
:zap: using jobs instead queries
michael-radency Mar 27, 2023
1499c75
Merge branch 'master' of https://github.com/n8n-io/n8n into node-118-…
michael-radency Mar 27, 2023
49c0a66
Merge branch 'master' of https://github.com/n8n-io/n8n into node-118-…
michael-radency Mar 27, 2023
e98a5e0
:zap: added error message
michael-radency Mar 28, 2023
2653867
:zap: search for RLCs, fixes
michael-radency Mar 28, 2023
2bbe74e
:zap: json processing
michael-radency Mar 28, 2023
35f7b37
:zap: removed getAll operation
michael-radency Mar 29, 2023
7e3bc67
:zap: executeQuery update
michael-radency Mar 29, 2023
3adfac1
:zap: unit test
michael-radency Mar 29, 2023
0e17b18
Merge branch 'master' of https://github.com/n8n-io/n8n into node-118-…
michael-radency Mar 29, 2023
d040cd4
Merge branch 'master' of https://github.com/n8n-io/n8n into node-118-…
michael-radency Mar 30, 2023
01f94d0
Merge branch 'master' of https://github.com/n8n-io/n8n into node-118-…
michael-radency Apr 4, 2023
79a83a6
:zap: tests setup, fixes
michael-radency Apr 4, 2023
c10323b
Merge branch 'master' of https://github.com/n8n-io/n8n into node-118-…
michael-radency Apr 4, 2023
8bd24df
Merge branch 'master' of https://github.com/n8n-io/n8n into node-118-…
michael-radency Apr 4, 2023
6b15986
Merge branch 'master' of https://github.com/n8n-io/n8n into node-118-…
michael-radency Apr 5, 2023
d4e5b69
:zap: tests
michael-radency Apr 5, 2023
a46fd2b
Merge remote-tracking branch 'upstream/master' into node-118-google-b…
agobrech Apr 19, 2023
d46e40f
Remove script for checking unused loadOptions
agobrech Apr 19, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import type { ICredentialType, INodeProperties } from 'n8n-workflow';

const scopes = ['https://www.googleapis.com/auth/bigquery'];
const scopes = [
'https://www.googleapis.com/auth/bigquery',
'https://www.googleapis.com/auth/cloud-platform',
'https://www.googleapis.com/auth/drive',
];

export class GoogleBigQueryOAuth2Api implements ICredentialType {
name = 'googleBigQueryOAuth2Api';
Expand Down
313 changes: 24 additions & 289 deletions packages/nodes-base/nodes/Google/BigQuery/GoogleBigQuery.node.ts
Original file line number Diff line number Diff line change
@@ -1,291 +1,26 @@
import type {
IExecuteFunctions,
IDataObject,
ILoadOptionsFunctions,
INodeExecutionData,
INodePropertyOptions,
INodeType,
INodeTypeDescription,
JsonObject,
} from 'n8n-workflow';
import { NodeApiError } from 'n8n-workflow';

import { googleApiRequest, googleApiRequestAllItems, simplify } from './GenericFunctions';

import { recordFields, recordOperations } from './RecordDescription';

import { v4 as uuid } from 'uuid';

export class GoogleBigQuery implements INodeType {
description: INodeTypeDescription = {
displayName: 'Google BigQuery',
name: 'googleBigQuery',
icon: 'file:googleBigQuery.svg',
group: ['input'],
version: 1,
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
description: 'Consume Google BigQuery API',
defaults: {
name: 'Google BigQuery',
},
inputs: ['main'],
outputs: ['main'],
credentials: [
{
name: 'googleApi',
required: true,
displayOptions: {
show: {
authentication: ['serviceAccount'],
},
},
},
{
name: 'googleBigQueryOAuth2Api',
required: true,
displayOptions: {
show: {
authentication: ['oAuth2'],
},
},
},
],
properties: [
{
displayName: 'Authentication',
name: 'authentication',
type: 'options',
noDataExpression: true,
options: [
{
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-miscased
name: 'OAuth2 (recommended)',
value: 'oAuth2',
},
{
name: 'Service Account',
value: 'serviceAccount',
},
],
default: 'oAuth2',
},
{
displayName: 'Resource',
name: 'resource',
type: 'options',
noDataExpression: true,
options: [
{
name: 'Record',
value: 'record',
},
],
default: 'record',
},
...recordOperations,
...recordFields,
],
};

methods = {
loadOptions: {
async getProjects(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = [];
const { projects } = await googleApiRequest.call(this, 'GET', '/v2/projects');
for (const project of projects) {
returnData.push({
name: project.friendlyName as string,
value: project.id,
});
}
return returnData;
},
async getDatasets(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const projectId = this.getCurrentNodeParameter('projectId');
const returnData: INodePropertyOptions[] = [];
const { datasets } = await googleApiRequest.call(
this,
'GET',
`/v2/projects/${projectId}/datasets`,
);
for (const dataset of datasets) {
returnData.push({
name: dataset.datasetReference.datasetId as string,
value: dataset.datasetReference.datasetId,
});
}
return returnData;
},
async getTables(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const projectId = this.getCurrentNodeParameter('projectId');
const datasetId = this.getCurrentNodeParameter('datasetId');
const returnData: INodePropertyOptions[] = [];
const { tables } = await googleApiRequest.call(
this,
'GET',
`/v2/projects/${projectId}/datasets/${datasetId}/tables`,
);
for (const table of tables) {
returnData.push({
name: table.tableReference.tableId as string,
value: table.tableReference.tableId,
});
}
return returnData;
},
},
};

async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
const items = this.getInputData();
const returnData: INodeExecutionData[] = [];
const length = items.length;
const qs: IDataObject = {};
let responseData;
const resource = this.getNodeParameter('resource', 0);
const operation = this.getNodeParameter('operation', 0);

if (resource === 'record') {
// *********************************************************************
// record
// *********************************************************************

if (operation === 'create') {
// ----------------------------------
// record: create
// ----------------------------------

// https://cloud.google.com/bigquery/docs/reference/rest/v2/tabledata/insertAll

const projectId = this.getNodeParameter('projectId', 0) as string;
const datasetId = this.getNodeParameter('datasetId', 0) as string;
const tableId = this.getNodeParameter('tableId', 0) as string;
const rows: IDataObject[] = [];
const body: IDataObject = {};

for (let i = 0; i < length; i++) {
const options = this.getNodeParameter('options', i);
Object.assign(body, options);
if (body.traceId === undefined) {
body.traceId = uuid();
}
const columns = this.getNodeParameter('columns', i) as string;
const columnList = columns.split(',').map((column) => column.trim());
const record: IDataObject = {};

for (const key of Object.keys(items[i].json)) {
if (columnList.includes(key)) {
record[`${key}`] = items[i].json[key];
}
}
rows.push({ json: record });
}

body.rows = rows;

try {
responseData = await googleApiRequest.call(
this,
'POST',
`/v2/projects/${projectId}/datasets/${datasetId}/tables/${tableId}/insertAll`,
body,
);

const executionData = this.helpers.constructExecutionMetaData(
this.helpers.returnJsonArray(responseData as IDataObject),
{ itemData: { item: 0 } },
);
returnData.push(...executionData);
} catch (error) {
if (this.continueOnFail()) {
const executionErrorData = this.helpers.constructExecutionMetaData(
this.helpers.returnJsonArray({ error: error.message }),
{ itemData: { item: 0 } },
);
returnData.push(...executionErrorData);
}
throw new NodeApiError(this.getNode(), error as JsonObject, { itemIndex: 0 });
}
} else if (operation === 'getAll') {
// ----------------------------------
// record: getAll
// ----------------------------------

// https://cloud.google.com/bigquery/docs/reference/rest/v2/tables/get

const returnAll = this.getNodeParameter('returnAll', 0);
const projectId = this.getNodeParameter('projectId', 0) as string;
const datasetId = this.getNodeParameter('datasetId', 0) as string;
const tableId = this.getNodeParameter('tableId', 0) as string;
const simple = this.getNodeParameter('simple', 0) as boolean;
let fields;

if (simple) {
const { schema } = await googleApiRequest.call(
this,
'GET',
`/v2/projects/${projectId}/datasets/${datasetId}/tables/${tableId}`,
{},
);
fields = schema.fields.map((field: IDataObject) => field.name);
}

for (let i = 0; i < length; i++) {
try {
const options = this.getNodeParameter('options', i);
Object.assign(qs, options);

if (qs.selectedFields) {
fields = (qs.selectedFields as string).split(',');
}

if (returnAll) {
responseData = await googleApiRequestAllItems.call(
this,
'rows',
'GET',
`/v2/projects/${projectId}/datasets/${datasetId}/tables/${tableId}/data`,
{},
qs,
);
} else {
qs.maxResults = this.getNodeParameter('limit', i);
responseData = await googleApiRequest.call(
this,
'GET',
`/v2/projects/${projectId}/datasets/${datasetId}/tables/${tableId}/data`,
{},
qs,
);
}

if (!returnAll) {
responseData = responseData.rows;
}
responseData = simple
? simplify(responseData as IDataObject[], fields as string[])
: responseData;

const executionData = this.helpers.constructExecutionMetaData(
this.helpers.returnJsonArray(responseData as IDataObject[]),
{ itemData: { item: i } },
);
returnData.push(...executionData);
} catch (error) {
if (this.continueOnFail()) {
const executionErrorData = this.helpers.constructExecutionMetaData(
this.helpers.returnJsonArray({ error: error.message }),
{ itemData: { item: i } },
);
returnData.push(...executionErrorData);
continue;
}
throw new NodeApiError(this.getNode(), error as JsonObject, { itemIndex: i });
}
}
}
}

return this.prepareOutputData(returnData);
import type { INodeTypeBaseDescription, IVersionedNodeType } from 'n8n-workflow';
import { VersionedNodeType } from 'n8n-workflow';

import { GoogleBigQueryV1 } from './v1/GoogleBigQueryV1.node';
import { GoogleBigQueryV2 } from './v2/GoogleBigQueryV2.node';

export class GoogleBigQuery extends VersionedNodeType {
constructor() {
const baseDescription: INodeTypeBaseDescription = {
displayName: 'Google BigQuery',
name: 'googleBigQuery',
icon: 'file:googleBigQuery.svg',
group: ['input'],
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
description: 'Consume Google BigQuery API',
defaultVersion: 2,
};

const nodeVersions: IVersionedNodeType['nodeVersions'] = {
1: new GoogleBigQueryV1(baseDescription),
2: new GoogleBigQueryV2(baseDescription),
};

super(nodeVersions, baseDescription);
}
}
Loading