first commit
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,156 @@
|
||||
import { DateTime } from 'luxon';
|
||||
import type { IDataObject, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
|
||||
import { jsonParse, NodeOperationError } from 'n8n-workflow';
|
||||
|
||||
import type { SchemaField, TableRawData, TableSchema } from './interfaces';
|
||||
|
||||
function getFieldValue(schemaField: SchemaField, field: IDataObject, parseTimestamps = false) {
|
||||
if (schemaField.type === 'RECORD') {
|
||||
return simplify([field.v as TableRawData], schemaField.fields as unknown as SchemaField[]);
|
||||
} else {
|
||||
let value = field.v;
|
||||
if (schemaField.type === 'JSON') {
|
||||
try {
|
||||
value = jsonParse(value as string);
|
||||
} catch (error) {}
|
||||
} else if (schemaField.type === 'TIMESTAMP' && parseTimestamps) {
|
||||
const dt = DateTime.fromSeconds(Number(value));
|
||||
value = dt.isValid ? dt.toISO() : value;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
export function wrapData(data: IDataObject | IDataObject[]): INodeExecutionData[] {
|
||||
if (!Array.isArray(data)) {
|
||||
return [{ json: data }];
|
||||
}
|
||||
return data.map((item) => ({
|
||||
json: item,
|
||||
}));
|
||||
}
|
||||
|
||||
export function simplify(
|
||||
data: TableRawData[],
|
||||
schema: SchemaField[],
|
||||
includeSchema = false,
|
||||
parseTimestamps = false,
|
||||
) {
|
||||
const returnData: IDataObject[] = [];
|
||||
for (const entry of data) {
|
||||
const record: IDataObject = {};
|
||||
|
||||
for (const [index, field] of entry.f.entries()) {
|
||||
if (schema[index].mode !== 'REPEATED') {
|
||||
record[schema[index].name] = getFieldValue(schema[index], field, parseTimestamps);
|
||||
} else {
|
||||
record[schema[index].name] = (field.v as unknown as IDataObject[]).flatMap(
|
||||
(repeatedField) => {
|
||||
return getFieldValue(
|
||||
schema[index],
|
||||
repeatedField as unknown as IDataObject,
|
||||
parseTimestamps,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (includeSchema) {
|
||||
record._schema = schema;
|
||||
}
|
||||
|
||||
returnData.push(record);
|
||||
}
|
||||
|
||||
return returnData;
|
||||
}
|
||||
|
||||
export function prepareOutput(
|
||||
this: IExecuteFunctions,
|
||||
response: IDataObject,
|
||||
itemIndex: number,
|
||||
rawOutput: boolean,
|
||||
includeSchema = false,
|
||||
) {
|
||||
let responseData;
|
||||
|
||||
if (response === undefined) return [];
|
||||
|
||||
if (rawOutput) {
|
||||
responseData = response;
|
||||
} else {
|
||||
const { rows, schema } = response;
|
||||
const parseTimestamps = this.getNode().typeVersion >= 2.1;
|
||||
|
||||
if (rows !== undefined && schema !== undefined) {
|
||||
const fields = (schema as TableSchema).fields;
|
||||
responseData = rows;
|
||||
|
||||
responseData = simplify(
|
||||
responseData as TableRawData[],
|
||||
fields,
|
||||
includeSchema,
|
||||
parseTimestamps,
|
||||
);
|
||||
} else if (schema && includeSchema) {
|
||||
responseData = { success: true, _schema: schema };
|
||||
} else {
|
||||
responseData = { success: true };
|
||||
}
|
||||
}
|
||||
|
||||
const executionData = this.helpers.constructExecutionMetaData(
|
||||
wrapData(responseData as IDataObject[]),
|
||||
{
|
||||
itemData: { item: itemIndex },
|
||||
},
|
||||
);
|
||||
|
||||
return executionData;
|
||||
}
|
||||
|
||||
export function checkSchema(
|
||||
this: IExecuteFunctions,
|
||||
schema: TableSchema,
|
||||
record: IDataObject,
|
||||
i: number,
|
||||
) {
|
||||
const returnData = { ...record };
|
||||
|
||||
schema.fields.forEach(({ name, mode, type, fields }) => {
|
||||
if (mode === 'REQUIRED' && returnData[name] === undefined) {
|
||||
throw new NodeOperationError(
|
||||
this.getNode(),
|
||||
`The property '${name}' is required, please define it in the 'Fields to Send'`,
|
||||
{ itemIndex: i },
|
||||
);
|
||||
}
|
||||
if (type !== 'STRING' && returnData[name] === '') {
|
||||
returnData[name] = null;
|
||||
}
|
||||
if (type === 'JSON') {
|
||||
let value = returnData[name];
|
||||
if (typeof value === 'object') {
|
||||
value = JSON.stringify(value);
|
||||
}
|
||||
returnData[name] = value;
|
||||
}
|
||||
if (type === 'RECORD' && typeof returnData[name] !== 'object') {
|
||||
let parsedField;
|
||||
try {
|
||||
parsedField = jsonParse(returnData[name] as string);
|
||||
} catch (error) {
|
||||
const recordField = fields ? `Field Schema:\n ${JSON.stringify(fields)}` : '';
|
||||
throw new NodeOperationError(
|
||||
this.getNode(),
|
||||
`The property '${name}' is a RECORD type, but the value is nor an object nor a valid JSON string`,
|
||||
{ itemIndex: i, description: recordField },
|
||||
);
|
||||
}
|
||||
returnData[name] = parsedField as IDataObject;
|
||||
}
|
||||
});
|
||||
|
||||
return returnData;
|
||||
}
|
||||
Reference in New Issue
Block a user