mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-19 11:01:15 +00:00
feat(Google Analytics Node): Overhaul for google analytics node
This commit is contained in:
255
packages/nodes-base/nodes/Google/Analytics/v2/helpers/utils.ts
Normal file
255
packages/nodes-base/nodes/Google/Analytics/v2/helpers/utils.ts
Normal file
@@ -0,0 +1,255 @@
|
||||
import { IExecuteFunctions, ILoadOptionsFunctions } from 'n8n-core';
|
||||
import {
|
||||
IDataObject,
|
||||
INodeListSearchItems,
|
||||
INodePropertyOptions,
|
||||
NodeOperationError,
|
||||
} from 'n8n-workflow';
|
||||
import { DateTime } from 'luxon';
|
||||
|
||||
// tslint:disable-next-line:no-any
|
||||
export function simplify(responseData: any | [any]) {
|
||||
const returnData = [];
|
||||
for (const {
|
||||
columnHeader: { dimensions, metricHeader },
|
||||
data: { rows },
|
||||
} of responseData) {
|
||||
if (rows === undefined) {
|
||||
// Do not error if there is no data
|
||||
continue;
|
||||
}
|
||||
const metrics = metricHeader.metricHeaderEntries.map((entry: { name: string }) => entry.name);
|
||||
for (const row of rows) {
|
||||
const rowDimensions: IDataObject = {};
|
||||
const rowMetrics: IDataObject = {};
|
||||
if (dimensions) {
|
||||
for (let i = 0; i < dimensions.length; i++) {
|
||||
rowDimensions[dimensions[i]] = row.dimensions[i];
|
||||
for (const [index, metric] of metrics.entries()) {
|
||||
rowMetrics[metric] = row.metrics[0].values[index];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (const [index, metric] of metrics.entries()) {
|
||||
rowMetrics[metric] = row.metrics[0].values[index];
|
||||
}
|
||||
}
|
||||
returnData.push({ ...rowDimensions, ...rowMetrics });
|
||||
}
|
||||
}
|
||||
|
||||
return returnData;
|
||||
}
|
||||
|
||||
// tslint:disable-next-line:no-any
|
||||
export function merge(responseData: [any]) {
|
||||
const response: { columnHeader: IDataObject; data: { rows: [] } } = {
|
||||
columnHeader: responseData[0].columnHeader,
|
||||
data: responseData[0].data,
|
||||
};
|
||||
const allRows = [];
|
||||
for (const {
|
||||
data: { rows },
|
||||
} of responseData) {
|
||||
allRows.push(...rows);
|
||||
}
|
||||
response.data.rows = allRows as [];
|
||||
return [response];
|
||||
}
|
||||
|
||||
export function simplifyGA4(response: IDataObject) {
|
||||
if (!response.rows) return [];
|
||||
const dimensionHeaders = ((response.dimensionHeaders as IDataObject[]) || []).map(
|
||||
(header) => header.name as string,
|
||||
);
|
||||
const metricHeaders = ((response.metricHeaders as IDataObject[]) || []).map(
|
||||
(header) => header.name as string,
|
||||
);
|
||||
const returnData: IDataObject[] = [];
|
||||
|
||||
(response.rows as IDataObject[]).forEach((row) => {
|
||||
if (!row) return;
|
||||
const rowDimensions: IDataObject = {};
|
||||
const rowMetrics: IDataObject = {};
|
||||
dimensionHeaders.forEach((dimension, index) => {
|
||||
rowDimensions[dimension] = (row.dimensionValues as IDataObject[])[index].value;
|
||||
});
|
||||
metricHeaders.forEach((metric, index) => {
|
||||
rowMetrics[metric] = (row.metricValues as IDataObject[])[index].value;
|
||||
});
|
||||
returnData.push({ ...rowDimensions, ...rowMetrics });
|
||||
});
|
||||
|
||||
return returnData;
|
||||
}
|
||||
|
||||
export function processFilters(expression: IDataObject): IDataObject[] {
|
||||
const processedFilters: IDataObject[] = [];
|
||||
|
||||
Object.entries(expression).forEach((entry) => {
|
||||
const [filterType, filters] = entry;
|
||||
|
||||
(filters as IDataObject[]).forEach((filter) => {
|
||||
let fieldName = '';
|
||||
switch (filter.listName) {
|
||||
case 'other':
|
||||
fieldName = filter.name as string;
|
||||
delete filter.name;
|
||||
break;
|
||||
case 'custom':
|
||||
fieldName = filter.name as string;
|
||||
delete filter.name;
|
||||
break;
|
||||
default:
|
||||
fieldName = filter.listName as string;
|
||||
}
|
||||
delete filter.listName;
|
||||
|
||||
if (filterType === 'inListFilter') {
|
||||
filter.values = (filter.values as string).split(',');
|
||||
}
|
||||
|
||||
if (filterType === 'numericFilter') {
|
||||
filter.value = {
|
||||
[filter.valueType as string]: filter.value,
|
||||
};
|
||||
delete filter.valueType;
|
||||
}
|
||||
|
||||
if (filterType === 'betweenFilter') {
|
||||
filter.fromValue = {
|
||||
[filter.valueType as string]: filter.fromValue,
|
||||
};
|
||||
filter.toValue = {
|
||||
[filter.valueType as string]: filter.toValue,
|
||||
};
|
||||
delete filter.valueType;
|
||||
}
|
||||
|
||||
processedFilters.push({
|
||||
filter: {
|
||||
fieldName,
|
||||
[filterType]: filter,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return processedFilters;
|
||||
}
|
||||
|
||||
export function prepareDateRange(
|
||||
this: IExecuteFunctions | ILoadOptionsFunctions,
|
||||
period: string,
|
||||
itemIndex: number,
|
||||
) {
|
||||
const dateRanges: IDataObject[] = [];
|
||||
|
||||
switch (period) {
|
||||
case 'today':
|
||||
dateRanges.push({
|
||||
startDate: DateTime.local().startOf('day').toISODate(),
|
||||
endDate: DateTime.now().toISODate(),
|
||||
});
|
||||
break;
|
||||
case 'yesterday':
|
||||
dateRanges.push({
|
||||
startDate: DateTime.local().startOf('day').minus({ days: 1 }).toISODate(),
|
||||
endDate: DateTime.local().endOf('day').minus({ days: 1 }).toISODate(),
|
||||
});
|
||||
break;
|
||||
case 'lastCalendarWeek':
|
||||
const begginingOfLastWeek = DateTime.local().startOf('week').minus({ weeks: 1 }).toISODate();
|
||||
const endOfLastWeek = DateTime.local().endOf('week').minus({ weeks: 1 }).toISODate();
|
||||
dateRanges.push({
|
||||
startDate: begginingOfLastWeek,
|
||||
endDate: endOfLastWeek,
|
||||
});
|
||||
break;
|
||||
case 'lastCalendarMonth':
|
||||
const begginingOfLastMonth = DateTime.local()
|
||||
.startOf('month')
|
||||
.minus({ months: 1 })
|
||||
.toISODate();
|
||||
const endOfLastMonth = DateTime.local().endOf('month').minus({ months: 1 }).toISODate();
|
||||
dateRanges.push({
|
||||
startDate: begginingOfLastMonth,
|
||||
endDate: endOfLastMonth,
|
||||
});
|
||||
break;
|
||||
case 'last7days':
|
||||
dateRanges.push({
|
||||
startDate: DateTime.now().minus({ days: 7 }).toISODate(),
|
||||
endDate: DateTime.now().toISODate(),
|
||||
});
|
||||
break;
|
||||
case 'last30days':
|
||||
dateRanges.push({
|
||||
startDate: DateTime.now().minus({ days: 30 }).toISODate(),
|
||||
endDate: DateTime.now().toISODate(),
|
||||
});
|
||||
break;
|
||||
case 'custom':
|
||||
const start = DateTime.fromISO(this.getNodeParameter('startDate', itemIndex, '') as string);
|
||||
const end = DateTime.fromISO(this.getNodeParameter('endDate', itemIndex, '') as string);
|
||||
|
||||
if (start > end) {
|
||||
throw new NodeOperationError(
|
||||
this.getNode(),
|
||||
`Parameter Start: ${start.toISO()} cannot be after End: ${end.toISO()}`,
|
||||
);
|
||||
}
|
||||
|
||||
dateRanges.push({
|
||||
startDate: start.toISODate(),
|
||||
endDate: end.toISODate(),
|
||||
});
|
||||
|
||||
break;
|
||||
default:
|
||||
throw new NodeOperationError(
|
||||
this.getNode(),
|
||||
`The period '${period}' is not supported, to specify own period use 'custom' option`,
|
||||
);
|
||||
}
|
||||
|
||||
return dateRanges;
|
||||
}
|
||||
|
||||
export const defaultStartDate = () => DateTime.now().startOf('day').minus({ days: 8 }).toISO();
|
||||
|
||||
export const defaultEndDate = () => DateTime.now().startOf('day').minus({ days: 1 }).toISO();
|
||||
|
||||
export function checkDuplicates(
|
||||
this: IExecuteFunctions,
|
||||
data: IDataObject[],
|
||||
key: string,
|
||||
type: string,
|
||||
) {
|
||||
const fields = data.map((item) => item[key] as string);
|
||||
const duplicates = fields.filter((field, i) => fields.indexOf(field) !== i);
|
||||
const unique = Array.from(new Set(duplicates));
|
||||
if (unique.length) {
|
||||
throw new NodeOperationError(
|
||||
this.getNode(),
|
||||
`A ${type} is specified more than once (${unique.join(', ')})`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function sortLoadOptions(data: INodePropertyOptions[] | INodeListSearchItems[]) {
|
||||
const returnData = [...data];
|
||||
returnData.sort((a, b) => {
|
||||
const aName = a.name.toLowerCase();
|
||||
const bName = b.name.toLowerCase();
|
||||
if (aName < bName) {
|
||||
return -1;
|
||||
}
|
||||
if (aName > bName) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
return returnData;
|
||||
}
|
||||
Reference in New Issue
Block a user