mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
Merge 426177bf87
into d2dd1796a8
This commit is contained in:
commit
386c324903
|
@ -10,18 +10,22 @@ import {
|
|||
|
||||
import {
|
||||
baserowApiRequest,
|
||||
baserowFileUploadRequest,
|
||||
baserowApiRequestAllItems,
|
||||
getJwtToken,
|
||||
TableFieldMapper,
|
||||
toOptions,
|
||||
getTableFields,
|
||||
} from './GenericFunctions';
|
||||
import { operationFields } from './OperationDescription';
|
||||
import type {
|
||||
BaserowCredentials,
|
||||
FieldsUiValues,
|
||||
FileOperation,
|
||||
GetAllAdditionalOptions,
|
||||
LoadedResource,
|
||||
Operation,
|
||||
Resource,
|
||||
RowOperation,
|
||||
Row,
|
||||
} from './types';
|
||||
|
||||
|
@ -53,6 +57,10 @@ export class Baserow implements INodeType {
|
|||
type: 'options',
|
||||
noDataExpression: true,
|
||||
options: [
|
||||
{
|
||||
name: 'File',
|
||||
value: 'file',
|
||||
},
|
||||
{
|
||||
name: 'Row',
|
||||
value: 'row',
|
||||
|
@ -104,6 +112,48 @@ export class Baserow implements INodeType {
|
|||
],
|
||||
default: 'getAll',
|
||||
},
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['file'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Upload',
|
||||
value: 'upload',
|
||||
description: 'Upload a file',
|
||||
action: 'Upload a file',
|
||||
},
|
||||
{
|
||||
name: 'Upload via URL',
|
||||
value: 'upload-via-url',
|
||||
description: 'Upload a file via URL',
|
||||
action: 'Upload a file via URL',
|
||||
},
|
||||
],
|
||||
default: 'upload',
|
||||
},
|
||||
{
|
||||
displayName: 'Input Data Field Name',
|
||||
name: 'binaryPropertyName',
|
||||
|
||||
type: 'string',
|
||||
default: 'data',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['upload'],
|
||||
resource: ['file'],
|
||||
},
|
||||
},
|
||||
required: true,
|
||||
description:
|
||||
'The name of the input field containing the binary file data to be uploaded. Supported file types: PNG, JPEG.',
|
||||
},
|
||||
...operationFields,
|
||||
],
|
||||
};
|
||||
|
@ -155,182 +205,250 @@ export class Baserow implements INodeType {
|
|||
|
||||
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
||||
const items = this.getInputData();
|
||||
const mapper = new TableFieldMapper();
|
||||
const returnData: INodeExecutionData[] = [];
|
||||
const operation = this.getNodeParameter('operation', 0) as Operation;
|
||||
|
||||
const tableId = this.getNodeParameter('tableId', 0) as string;
|
||||
const returnData: INodeExecutionData[] = [];
|
||||
const resource = this.getNodeParameter('resource', 0) as Resource;
|
||||
const operation = this.getNodeParameter('operation', 0) as RowOperation | FileOperation;
|
||||
|
||||
const credentials = await this.getCredentials<BaserowCredentials>('baserowApi');
|
||||
const jwtToken = await getJwtToken.call(this, credentials);
|
||||
const fields = await mapper.getTableFields.call(this, tableId, jwtToken);
|
||||
mapper.createMappings(fields);
|
||||
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
try {
|
||||
if (operation === 'getAll') {
|
||||
// ----------------------------------
|
||||
// getAll
|
||||
// ----------------------------------
|
||||
if (resource === 'row') {
|
||||
const tableId = this.getNodeParameter('tableId', 0) as string;
|
||||
const fields = await getTableFields.call(this, tableId, jwtToken);
|
||||
|
||||
// https://api.baserow.io/api/redoc/#operation/list_database_table_rows
|
||||
const mapper = new TableFieldMapper();
|
||||
mapper.createMappings(fields);
|
||||
|
||||
const { order, filters, filterType, search } = this.getNodeParameter(
|
||||
'additionalOptions',
|
||||
i,
|
||||
) as GetAllAdditionalOptions;
|
||||
if (operation === 'getAll') {
|
||||
// ----------------------------------
|
||||
// getAll
|
||||
// ----------------------------------
|
||||
|
||||
const qs: IDataObject = {};
|
||||
// https://api.baserow.io/api/redoc/#operation/list_database_table_rows
|
||||
|
||||
if (order?.fields) {
|
||||
qs.order_by = order.fields
|
||||
.map(({ field, direction }) => `${direction}${mapper.setField(field)}`)
|
||||
.join(',');
|
||||
}
|
||||
const returnAll = this.getNodeParameter('returnAll', 0, false) as boolean;
|
||||
const limit = this.getNodeParameter('limit', 0, 0);
|
||||
|
||||
if (filters?.fields) {
|
||||
filters.fields.forEach(({ field, operator, value }) => {
|
||||
qs[`filter__field_${mapper.setField(field)}__${operator}`] = value;
|
||||
});
|
||||
}
|
||||
const { order, filters, filterType, search } = this.getNodeParameter(
|
||||
'additionalOptions',
|
||||
i,
|
||||
) as GetAllAdditionalOptions;
|
||||
|
||||
if (filterType) {
|
||||
qs.filter_type = filterType;
|
||||
}
|
||||
const qs: IDataObject = {};
|
||||
|
||||
if (search) {
|
||||
qs.search = search;
|
||||
}
|
||||
|
||||
const endpoint = `/api/database/rows/table/${tableId}/`;
|
||||
const rows = (await baserowApiRequestAllItems.call(
|
||||
this,
|
||||
'GET',
|
||||
endpoint,
|
||||
jwtToken,
|
||||
{},
|
||||
qs,
|
||||
)) as Row[];
|
||||
|
||||
rows.forEach((row) => mapper.idsToNames(row));
|
||||
const executionData = this.helpers.constructExecutionMetaData(
|
||||
this.helpers.returnJsonArray(rows),
|
||||
{ itemData: { item: i } },
|
||||
);
|
||||
returnData.push(...executionData);
|
||||
} else if (operation === 'get') {
|
||||
// ----------------------------------
|
||||
// get
|
||||
// ----------------------------------
|
||||
|
||||
// https://api.baserow.io/api/redoc/#operation/get_database_table_row
|
||||
|
||||
const rowId = this.getNodeParameter('rowId', i) as string;
|
||||
const endpoint = `/api/database/rows/table/${tableId}/${rowId}/`;
|
||||
const row = await baserowApiRequest.call(this, 'GET', endpoint, jwtToken);
|
||||
|
||||
mapper.idsToNames(row as Row);
|
||||
const executionData = this.helpers.constructExecutionMetaData(
|
||||
this.helpers.returnJsonArray(row as Row),
|
||||
{ itemData: { item: i } },
|
||||
);
|
||||
returnData.push(...executionData);
|
||||
} else if (operation === 'create') {
|
||||
// ----------------------------------
|
||||
// create
|
||||
// ----------------------------------
|
||||
|
||||
// https://api.baserow.io/api/redoc/#operation/create_database_table_row
|
||||
|
||||
const body: IDataObject = {};
|
||||
|
||||
const dataToSend = this.getNodeParameter('dataToSend', 0) as
|
||||
| 'defineBelow'
|
||||
| 'autoMapInputData';
|
||||
|
||||
if (dataToSend === 'autoMapInputData') {
|
||||
const incomingKeys = Object.keys(items[i].json);
|
||||
const rawInputsToIgnore = this.getNodeParameter('inputsToIgnore', i) as string;
|
||||
const inputDataToIgnore = rawInputsToIgnore.split(',').map((c) => c.trim());
|
||||
|
||||
for (const key of incomingKeys) {
|
||||
if (inputDataToIgnore.includes(key)) continue;
|
||||
body[key] = items[i].json[key];
|
||||
mapper.namesToIds(body);
|
||||
if (order?.fields) {
|
||||
qs.order_by = order.fields
|
||||
.map(({ field, direction }) => `${direction}${mapper.setField(field)}`)
|
||||
.join(',');
|
||||
}
|
||||
} else {
|
||||
const fieldsUi = this.getNodeParameter('fieldsUi.fieldValues', i, []) as FieldsUiValues;
|
||||
for (const field of fieldsUi) {
|
||||
body[`field_${field.fieldId}`] = field.fieldValue;
|
||||
|
||||
if (filters?.fields) {
|
||||
filters.fields.forEach(({ field, operator, value }) => {
|
||||
qs[`filter__field_${mapper.setField(field)}__${operator}`] = value;
|
||||
});
|
||||
}
|
||||
|
||||
if (filterType) {
|
||||
qs.filter_type = filterType;
|
||||
}
|
||||
|
||||
if (search) {
|
||||
qs.search = search;
|
||||
}
|
||||
|
||||
const endpoint = `/api/database/rows/table/${tableId}/`;
|
||||
const rows = (await baserowApiRequestAllItems.call(
|
||||
this,
|
||||
'GET',
|
||||
endpoint,
|
||||
jwtToken,
|
||||
{},
|
||||
qs,
|
||||
returnAll,
|
||||
limit,
|
||||
)) as Row[];
|
||||
|
||||
rows.forEach((row) => mapper.idsToNames(row));
|
||||
const executionData = this.helpers.constructExecutionMetaData(
|
||||
this.helpers.returnJsonArray(rows),
|
||||
{ itemData: { item: i } },
|
||||
);
|
||||
returnData.push(...executionData);
|
||||
} else if (operation === 'get') {
|
||||
// ----------------------------------
|
||||
// get
|
||||
// ----------------------------------
|
||||
|
||||
// https://api.baserow.io/api/redoc/#operation/get_database_table_row
|
||||
|
||||
const rowId = this.getNodeParameter('rowId', i) as string;
|
||||
const endpoint = `/api/database/rows/table/${tableId}/${rowId}/`;
|
||||
const row = await baserowApiRequest.call(this, 'GET', endpoint, jwtToken);
|
||||
|
||||
mapper.idsToNames(row as Row);
|
||||
const executionData = this.helpers.constructExecutionMetaData(
|
||||
this.helpers.returnJsonArray(row as Row),
|
||||
{ itemData: { item: i } },
|
||||
);
|
||||
returnData.push(...executionData);
|
||||
} else if (operation === 'create') {
|
||||
// ----------------------------------
|
||||
// create
|
||||
// ----------------------------------
|
||||
|
||||
// https://api.baserow.io/api/redoc/#operation/create_database_table_row
|
||||
|
||||
const body: IDataObject = {};
|
||||
|
||||
const dataToSend = this.getNodeParameter('dataToSend', 0) as
|
||||
| 'defineBelow'
|
||||
| 'autoMapInputData';
|
||||
|
||||
if (dataToSend === 'autoMapInputData') {
|
||||
const incomingKeys = Object.keys(items[i].json);
|
||||
const rawInputsToIgnore = this.getNodeParameter('inputsToIgnore', i) as string;
|
||||
const inputDataToIgnore = rawInputsToIgnore.split(',').map((c) => c.trim());
|
||||
|
||||
for (const key of incomingKeys) {
|
||||
if (inputDataToIgnore.includes(key)) continue;
|
||||
body[key] = items[i].json[key];
|
||||
mapper.namesToIds(body);
|
||||
}
|
||||
} else {
|
||||
const fieldsUi = this.getNodeParameter(
|
||||
'fieldsUi.fieldValues',
|
||||
i,
|
||||
[],
|
||||
) as FieldsUiValues;
|
||||
for (const field of fieldsUi) {
|
||||
body[`field_${field.fieldId}`] = field.fieldValue;
|
||||
}
|
||||
}
|
||||
|
||||
const endpoint = `/api/database/rows/table/${tableId}/`;
|
||||
const createdRow = await baserowApiRequest.call(this, 'POST', endpoint, jwtToken, body);
|
||||
|
||||
mapper.idsToNames(createdRow as Row);
|
||||
const executionData = this.helpers.constructExecutionMetaData(
|
||||
this.helpers.returnJsonArray(createdRow as Row),
|
||||
{ itemData: { item: i } },
|
||||
);
|
||||
returnData.push(...executionData);
|
||||
} else if (operation === 'update') {
|
||||
// ----------------------------------
|
||||
// update
|
||||
// ----------------------------------
|
||||
|
||||
// https://api.baserow.io/api/redoc/#operation/update_database_table_row
|
||||
|
||||
const rowId = this.getNodeParameter('rowId', i) as string;
|
||||
|
||||
const body: IDataObject = {};
|
||||
|
||||
const dataToSend = this.getNodeParameter('dataToSend', 0) as
|
||||
| 'defineBelow'
|
||||
| 'autoMapInputData';
|
||||
|
||||
if (dataToSend === 'autoMapInputData') {
|
||||
const incomingKeys = Object.keys(items[i].json);
|
||||
const rawInputsToIgnore = this.getNodeParameter('inputsToIgnore', i) as string;
|
||||
const inputsToIgnore = rawInputsToIgnore.split(',').map((c) => c.trim());
|
||||
|
||||
for (const key of incomingKeys) {
|
||||
if (inputsToIgnore.includes(key)) continue;
|
||||
body[key] = items[i].json[key];
|
||||
mapper.namesToIds(body);
|
||||
}
|
||||
} else {
|
||||
const fieldsUi = this.getNodeParameter(
|
||||
'fieldsUi.fieldValues',
|
||||
i,
|
||||
[],
|
||||
) as FieldsUiValues;
|
||||
for (const field of fieldsUi) {
|
||||
body[`field_${field.fieldId}`] = field.fieldValue;
|
||||
}
|
||||
}
|
||||
|
||||
const endpoint = `/api/database/rows/table/${tableId}/${rowId}/`;
|
||||
const updatedRow = await baserowApiRequest.call(
|
||||
this,
|
||||
'PATCH',
|
||||
endpoint,
|
||||
jwtToken,
|
||||
body,
|
||||
);
|
||||
|
||||
mapper.idsToNames(updatedRow as Row);
|
||||
const executionData = this.helpers.constructExecutionMetaData(
|
||||
this.helpers.returnJsonArray(updatedRow as Row),
|
||||
{ itemData: { item: i } },
|
||||
);
|
||||
returnData.push(...executionData);
|
||||
} else if (resource === 'row' && operation === 'delete') {
|
||||
// ----------------------------------
|
||||
// delete
|
||||
// ----------------------------------
|
||||
|
||||
// https://api.baserow.io/api/redoc/#operation/delete_database_table_row
|
||||
|
||||
const rowId = this.getNodeParameter('rowId', i) as string;
|
||||
|
||||
const endpoint = `/api/database/rows/table/${tableId}/${rowId}/`;
|
||||
await baserowApiRequest.call(this, 'DELETE', endpoint, jwtToken);
|
||||
|
||||
const executionData = this.helpers.constructExecutionMetaData(
|
||||
[{ json: { success: true } }],
|
||||
{ itemData: { item: i } },
|
||||
);
|
||||
returnData.push(...executionData);
|
||||
}
|
||||
} else if (resource === 'file') {
|
||||
if (operation === 'upload-via-url') {
|
||||
// ----------------------------------
|
||||
// upload-via-url
|
||||
// ----------------------------------
|
||||
|
||||
const endpoint = `/api/database/rows/table/${tableId}/`;
|
||||
const createdRow = await baserowApiRequest.call(this, 'POST', endpoint, jwtToken, body);
|
||||
// https://api.baserow.io/api/redoc/#tag/User-files/operation/upload_via_url
|
||||
|
||||
mapper.idsToNames(createdRow as Row);
|
||||
const executionData = this.helpers.constructExecutionMetaData(
|
||||
this.helpers.returnJsonArray(createdRow as Row),
|
||||
{ itemData: { item: i } },
|
||||
);
|
||||
returnData.push(...executionData);
|
||||
} else if (operation === 'update') {
|
||||
// ----------------------------------
|
||||
// update
|
||||
// ----------------------------------
|
||||
const url = this.getNodeParameter('url', i) as string;
|
||||
const endpoint = '/api/user-files/upload-via-url/';
|
||||
const body = { url };
|
||||
const file = await baserowApiRequest.call(this, 'POST', endpoint, jwtToken, body);
|
||||
|
||||
// https://api.baserow.io/api/redoc/#operation/update_database_table_row
|
||||
const executionData = this.helpers.constructExecutionMetaData(
|
||||
this.helpers.returnJsonArray(file),
|
||||
{ itemData: { item: i } },
|
||||
);
|
||||
returnData.push(...executionData);
|
||||
} else if (operation === 'upload') {
|
||||
// ----------------------------------
|
||||
// upload
|
||||
// ----------------------------------
|
||||
|
||||
const rowId = this.getNodeParameter('rowId', i) as string;
|
||||
// https://api.baserow.io/api/redoc/#tag/User-files/operation/upload_file
|
||||
|
||||
const body: IDataObject = {};
|
||||
const binaryPropertyName = this.getNodeParameter('binaryPropertyName', i);
|
||||
const { fileName, mimeType } = this.helpers.assertBinaryData(i, binaryPropertyName);
|
||||
const binaryDataBuffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName);
|
||||
|
||||
const dataToSend = this.getNodeParameter('dataToSend', 0) as
|
||||
| 'defineBelow'
|
||||
| 'autoMapInputData';
|
||||
const file = await baserowFileUploadRequest.call(
|
||||
this,
|
||||
jwtToken,
|
||||
binaryDataBuffer,
|
||||
fileName as string,
|
||||
mimeType,
|
||||
);
|
||||
|
||||
if (dataToSend === 'autoMapInputData') {
|
||||
const incomingKeys = Object.keys(items[i].json);
|
||||
const rawInputsToIgnore = this.getNodeParameter('inputsToIgnore', i) as string;
|
||||
const inputsToIgnore = rawInputsToIgnore.split(',').map((c) => c.trim());
|
||||
|
||||
for (const key of incomingKeys) {
|
||||
if (inputsToIgnore.includes(key)) continue;
|
||||
body[key] = items[i].json[key];
|
||||
mapper.namesToIds(body);
|
||||
}
|
||||
} else {
|
||||
const fieldsUi = this.getNodeParameter('fieldsUi.fieldValues', i, []) as FieldsUiValues;
|
||||
for (const field of fieldsUi) {
|
||||
body[`field_${field.fieldId}`] = field.fieldValue;
|
||||
}
|
||||
const executionData = this.helpers.constructExecutionMetaData(
|
||||
this.helpers.returnJsonArray(file),
|
||||
{ itemData: { item: i } },
|
||||
);
|
||||
returnData.push(...executionData);
|
||||
}
|
||||
|
||||
const endpoint = `/api/database/rows/table/${tableId}/${rowId}/`;
|
||||
const updatedRow = await baserowApiRequest.call(this, 'PATCH', endpoint, jwtToken, body);
|
||||
|
||||
mapper.idsToNames(updatedRow as Row);
|
||||
const executionData = this.helpers.constructExecutionMetaData(
|
||||
this.helpers.returnJsonArray(updatedRow as Row),
|
||||
{ itemData: { item: i } },
|
||||
);
|
||||
returnData.push(...executionData);
|
||||
} else if (operation === 'delete') {
|
||||
// ----------------------------------
|
||||
// delete
|
||||
// ----------------------------------
|
||||
|
||||
// https://api.baserow.io/api/redoc/#operation/delete_database_table_row
|
||||
|
||||
const rowId = this.getNodeParameter('rowId', i) as string;
|
||||
|
||||
const endpoint = `/api/database/rows/table/${tableId}/${rowId}/`;
|
||||
await baserowApiRequest.call(this, 'DELETE', endpoint, jwtToken);
|
||||
|
||||
const executionData = this.helpers.constructExecutionMetaData(
|
||||
[{ json: { success: true } }],
|
||||
{ itemData: { item: i } },
|
||||
);
|
||||
returnData.push(...executionData);
|
||||
}
|
||||
} catch (error) {
|
||||
if (this.continueOnFail()) {
|
||||
|
|
|
@ -1,20 +1,57 @@
|
|||
import type {
|
||||
IDataObject,
|
||||
IExecuteFunctions,
|
||||
IHookFunctions,
|
||||
IHttpRequestMethods,
|
||||
IHttpRequestOptions,
|
||||
ILoadOptionsFunctions,
|
||||
IRequestOptions,
|
||||
IPollFunctions,
|
||||
JsonObject,
|
||||
} from 'n8n-workflow';
|
||||
import { NodeApiError } from 'n8n-workflow';
|
||||
|
||||
import type { Accumulator, BaserowCredentials, LoadedResource } from './types';
|
||||
|
||||
export async function baserowFileUploadRequest(
|
||||
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions,
|
||||
jwtToken: string,
|
||||
file: Buffer,
|
||||
fileName: string,
|
||||
mimeType: string,
|
||||
) {
|
||||
const credentials = await this.getCredentials<BaserowCredentials>('baserowApi');
|
||||
|
||||
const options: IHttpRequestOptions = {
|
||||
headers: {
|
||||
Authorization: `JWT ${jwtToken}`,
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
method: 'POST',
|
||||
url: `${credentials.host}/api/user-files/upload-file/`,
|
||||
json: false,
|
||||
body: {
|
||||
file: {
|
||||
value: file,
|
||||
options: {
|
||||
filename: fileName,
|
||||
contentType: mimeType,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
try {
|
||||
return await this.helpers.httpRequest(options);
|
||||
} catch (error) {
|
||||
throw new NodeApiError(this.getNode(), error as JsonObject);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a request to Baserow API.
|
||||
*/
|
||||
export async function baserowApiRequest(
|
||||
this: IExecuteFunctions | ILoadOptionsFunctions,
|
||||
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IPollFunctions,
|
||||
method: IHttpRequestMethods,
|
||||
endpoint: string,
|
||||
jwtToken: string,
|
||||
|
@ -23,17 +60,26 @@ export async function baserowApiRequest(
|
|||
) {
|
||||
const credentials = await this.getCredentials<BaserowCredentials>('baserowApi');
|
||||
|
||||
const options: IRequestOptions = {
|
||||
const options: IHttpRequestOptions = {
|
||||
headers: {
|
||||
Authorization: `JWT ${jwtToken}`,
|
||||
},
|
||||
method,
|
||||
body,
|
||||
qs,
|
||||
uri: `${credentials.host}${endpoint}`,
|
||||
url: `${credentials.host}${endpoint}`,
|
||||
json: true,
|
||||
};
|
||||
|
||||
if (body.formData) {
|
||||
options.json = false;
|
||||
options.headers = {
|
||||
...options.headers,
|
||||
'Content-Type': 'multipart/form-data',
|
||||
};
|
||||
options.returnFullResponse = true;
|
||||
}
|
||||
|
||||
if (Object.keys(qs).length === 0) {
|
||||
delete options.qs;
|
||||
}
|
||||
|
@ -43,7 +89,7 @@ export async function baserowApiRequest(
|
|||
}
|
||||
|
||||
try {
|
||||
return await this.helpers.request(options);
|
||||
return await this.helpers.httpRequest(options);
|
||||
} catch (error) {
|
||||
throw new NodeApiError(this.getNode(), error as JsonObject);
|
||||
}
|
||||
|
@ -53,27 +99,28 @@ export async function baserowApiRequest(
|
|||
* Get all results from a paginated query to Baserow API.
|
||||
*/
|
||||
export async function baserowApiRequestAllItems(
|
||||
this: IExecuteFunctions,
|
||||
this: IExecuteFunctions | IPollFunctions,
|
||||
method: IHttpRequestMethods,
|
||||
endpoint: string,
|
||||
jwtToken: string,
|
||||
body: IDataObject,
|
||||
qs: IDataObject = {},
|
||||
returnAll: boolean = false,
|
||||
limit: number = 0,
|
||||
): Promise<IDataObject[]> {
|
||||
const returnData: IDataObject[] = [];
|
||||
let responseData;
|
||||
|
||||
qs.page = 1;
|
||||
qs.size = 100;
|
||||
|
||||
const returnAll = this.getNodeParameter('returnAll', 0, false);
|
||||
const limit = this.getNodeParameter('limit', 0, 0);
|
||||
if (!qs.size) {
|
||||
qs.size = 100;
|
||||
}
|
||||
|
||||
do {
|
||||
responseData = await baserowApiRequest.call(this, method, endpoint, jwtToken, body, qs);
|
||||
returnData.push(...(responseData.results as IDataObject[]));
|
||||
|
||||
if (!returnAll && returnData.length > limit) {
|
||||
if (!returnAll && limit > 0 && returnData.length > limit) {
|
||||
return returnData.slice(0, limit);
|
||||
}
|
||||
|
||||
|
@ -87,21 +134,21 @@ export async function baserowApiRequestAllItems(
|
|||
* Get a JWT token based on Baserow account username and password.
|
||||
*/
|
||||
export async function getJwtToken(
|
||||
this: IExecuteFunctions | ILoadOptionsFunctions,
|
||||
this: IExecuteFunctions | ILoadOptionsFunctions | IPollFunctions,
|
||||
{ username, password, host }: BaserowCredentials,
|
||||
) {
|
||||
const options: IRequestOptions = {
|
||||
const options: IHttpRequestOptions = {
|
||||
method: 'POST',
|
||||
body: {
|
||||
username,
|
||||
password,
|
||||
},
|
||||
uri: `${host}/api/user/token-auth/`,
|
||||
url: `${host}/api/user/token-auth/`,
|
||||
json: true,
|
||||
};
|
||||
|
||||
try {
|
||||
const { token } = (await this.helpers.request(options)) as { token: string };
|
||||
const { token } = (await this.helpers.httpRequest(options)) as { token: string };
|
||||
return token;
|
||||
} catch (error) {
|
||||
throw new NodeApiError(this.getNode(), error as JsonObject);
|
||||
|
@ -127,6 +174,15 @@ export async function getFieldNamesAndIds(
|
|||
};
|
||||
}
|
||||
|
||||
export async function getTableFields(
|
||||
this: IExecuteFunctions | IPollFunctions,
|
||||
table: string,
|
||||
jwtToken: string,
|
||||
): Promise<LoadedResource[]> {
|
||||
const endpoint = `/api/database/fields/table/${table}/`;
|
||||
return await baserowApiRequest.call(this, 'GET', endpoint, jwtToken);
|
||||
}
|
||||
|
||||
export const toOptions = (items: LoadedResource[]) =>
|
||||
items.map(({ name, id }) => ({ name, value: id }));
|
||||
|
||||
|
@ -140,15 +196,6 @@ export class TableFieldMapper {
|
|||
|
||||
mapIds = true;
|
||||
|
||||
async getTableFields(
|
||||
this: IExecuteFunctions,
|
||||
table: string,
|
||||
jwtToken: string,
|
||||
): Promise<LoadedResource[]> {
|
||||
const endpoint = `/api/database/fields/table/${table}/`;
|
||||
return await baserowApiRequest.call(this, 'GET', endpoint, jwtToken);
|
||||
}
|
||||
|
||||
createMappings(tableFields: LoadedResource[]) {
|
||||
this.nameToIdMapping = this.createNameToIdMapping(tableFields);
|
||||
this.idToNameMapping = this.createIdToNameMapping(tableFields);
|
||||
|
@ -181,6 +228,10 @@ export class TableFieldMapper {
|
|||
});
|
||||
}
|
||||
|
||||
idToName(id: string) {
|
||||
return this.idToNameMapping[id] ?? id;
|
||||
}
|
||||
|
||||
namesToIds(obj: Record<string, unknown>) {
|
||||
Object.entries(obj).forEach(([key, value]) => {
|
||||
if (this.nameToIdMapping[key] !== undefined) {
|
||||
|
@ -189,4 +240,8 @@ export class TableFieldMapper {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
nameToId(name: string) {
|
||||
return this.nameToIdMapping[name] ?? name;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,11 @@ export const operationFields: INodeProperties[] = [
|
|||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Database Name or ID',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['row'],
|
||||
},
|
||||
},
|
||||
name: 'databaseId',
|
||||
type: 'options',
|
||||
default: '',
|
||||
|
@ -18,6 +23,11 @@ export const operationFields: INodeProperties[] = [
|
|||
},
|
||||
{
|
||||
displayName: 'Table Name or ID',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['row'],
|
||||
},
|
||||
},
|
||||
name: 'tableId',
|
||||
type: 'options',
|
||||
default: '',
|
||||
|
@ -442,4 +452,32 @@ export const operationFields: INodeProperties[] = [
|
|||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'File',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['file'],
|
||||
operation: ['upload'],
|
||||
},
|
||||
},
|
||||
name: 'file',
|
||||
type: 'resourceLocator',
|
||||
default: '',
|
||||
required: true,
|
||||
description: 'The file to upload',
|
||||
},
|
||||
{
|
||||
displayName: 'File URL',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['file'],
|
||||
operation: ['upload-via-url'],
|
||||
},
|
||||
},
|
||||
name: 'url',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
description: 'The URL of the file to upload',
|
||||
},
|
||||
];
|
||||
|
|
173
packages/nodes-base/nodes/Baserow/test/GenericFunctions.test.ts
Normal file
173
packages/nodes-base/nodes/Baserow/test/GenericFunctions.test.ts
Normal file
|
@ -0,0 +1,173 @@
|
|||
import type {
|
||||
IExecuteFunctions,
|
||||
IHookFunctions,
|
||||
ILoadOptionsFunctions,
|
||||
IN8nHttpFullResponse,
|
||||
IN8nHttpResponse,
|
||||
INode,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import { baserowApiRequest, baserowFileUploadRequest, getJwtToken } from '../GenericFunctions';
|
||||
import { username } from 'minifaker';
|
||||
import { httpRequest } from 'n8n-core';
|
||||
|
||||
export const node: INode = {
|
||||
id: 'c4a5ca75-18c7-4cc8-bf7d-5d57bb7d84da',
|
||||
name: 'Baserow Upload',
|
||||
type: 'n8n-nodes-base.Baserow',
|
||||
typeVersion: 1,
|
||||
position: [0, 0],
|
||||
parameters: {
|
||||
operation: 'upload',
|
||||
domain: 'file',
|
||||
},
|
||||
};
|
||||
|
||||
describe('Baserow GenericFunctions', () => {
|
||||
describe('getJwtToken', () => {
|
||||
const mockThis = {
|
||||
helpers: {
|
||||
httpRequest: jest.fn().mockResolvedValue({
|
||||
token: 'jwt',
|
||||
}),
|
||||
},
|
||||
} as unknown as IExecuteFunctions | ILoadOptionsFunctions;
|
||||
|
||||
it('should return the JWT token', async () => {
|
||||
const jwtToken = await getJwtToken.call(mockThis, {
|
||||
username: 'user',
|
||||
password: 'password',
|
||||
host: 'https://my-host.com',
|
||||
});
|
||||
|
||||
expect(jwtToken).toBe('jwt');
|
||||
});
|
||||
});
|
||||
|
||||
describe('baserowApiRequest', () => {
|
||||
const mockThis = {
|
||||
helpers: {
|
||||
requestWithAuthentication: jest.fn().mockResolvedValue({ statusCode: 200 }),
|
||||
httpRequest: jest.fn(),
|
||||
},
|
||||
getNode() {
|
||||
return node;
|
||||
},
|
||||
getCredentials: jest.fn(),
|
||||
getNodeParameter: jest.fn(),
|
||||
} as unknown as IExecuteFunctions | ILoadOptionsFunctions;
|
||||
|
||||
it('should upload a file via url', async () => {
|
||||
mockThis.getCredentials.mockResolvedValue({
|
||||
host: 'https://my-host.com',
|
||||
});
|
||||
|
||||
mockThis.helpers.httpRequest.mockResolvedValue({
|
||||
statusCode: 200,
|
||||
body: {
|
||||
size: 2147483647,
|
||||
mime_type: 'string',
|
||||
is_image: true,
|
||||
image_width: 32767,
|
||||
image_height: 32767,
|
||||
uploaded_at: '2019-08-24T14:15:22Z',
|
||||
url: 'http://example.com',
|
||||
thumbnails: {
|
||||
property1: null,
|
||||
property2: null,
|
||||
},
|
||||
name: 'string',
|
||||
original_name: 'string',
|
||||
},
|
||||
} as IN8nHttpFullResponse | IN8nHttpResponse);
|
||||
|
||||
const jwtToken = 'jwt';
|
||||
const fileUrl = 'http://example.com/image.png';
|
||||
|
||||
const body = {
|
||||
file_url: fileUrl,
|
||||
};
|
||||
|
||||
await baserowApiRequest.call(
|
||||
mockThis,
|
||||
'POST',
|
||||
'/api/user-files/upload-via-url/',
|
||||
jwtToken,
|
||||
body,
|
||||
);
|
||||
|
||||
expect(mockThis.getCredentials).toHaveBeenCalledWith('baserowApi');
|
||||
expect(mockThis.helpers.httpRequest).toHaveBeenCalledWith({
|
||||
headers: {
|
||||
Authorization: `JWT ${jwtToken}`,
|
||||
},
|
||||
method: 'POST',
|
||||
url: 'https://my-host.com/api/user-files/upload-via-url/',
|
||||
body,
|
||||
json: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('baserowFileUploadRequest', () => {
|
||||
const mockThis = {
|
||||
helpers: {
|
||||
requestWithAuthentication: jest.fn().mockResolvedValue({ statusCode: 200 }),
|
||||
httpRequest: jest.fn(),
|
||||
},
|
||||
getNode() {
|
||||
return node;
|
||||
},
|
||||
getCredentials: jest.fn(),
|
||||
getNodeParameter: jest.fn(),
|
||||
} as unknown as IExecuteFunctions | ILoadOptionsFunctions;
|
||||
|
||||
it('should make an authenticated API file-upload request to Baserow', async () => {
|
||||
mockThis.getCredentials.mockResolvedValue({
|
||||
host: 'https://my-host.com',
|
||||
});
|
||||
|
||||
// see https://api.baserow.io/api/redoc/#tag/User-files/operation/upload_file
|
||||
mockThis.helpers.httpRequest.mockResolvedValue({
|
||||
statusCode: 200,
|
||||
body: {
|
||||
size: 2147483647,
|
||||
mime_type: 'string',
|
||||
is_image: true,
|
||||
image_width: 32767,
|
||||
image_height: 32767,
|
||||
uploaded_at: '2019-08-24T14:15:22Z',
|
||||
url: 'http://example.com',
|
||||
thumbnails: {
|
||||
property1: null,
|
||||
property2: null,
|
||||
},
|
||||
name: 'string',
|
||||
original_name: 'string',
|
||||
},
|
||||
} as IN8nHttpFullResponse | IN8nHttpResponse);
|
||||
|
||||
const jwtToken = 'jwt';
|
||||
const file = Buffer.from('file');
|
||||
const filename = 'filename.txt';
|
||||
const mimeType = 'text/plain';
|
||||
|
||||
await baserowFileUploadRequest.call(mockThis, jwtToken, file, filename, mimeType);
|
||||
|
||||
expect(mockThis.getCredentials).toHaveBeenCalledWith('baserowApi');
|
||||
|
||||
expect(mockThis.helpers.httpRequest).toHaveBeenCalledWith({
|
||||
body: {
|
||||
file: {
|
||||
options: { contentType: 'text/plain', filename: 'filename.txt' },
|
||||
value: file,
|
||||
},
|
||||
},
|
||||
headers: { Authorization: 'JWT jwt', 'Content-Type': 'multipart/form-data' },
|
||||
json: false,
|
||||
method: 'POST',
|
||||
url: 'https://my-host.com/api/user-files/upload-file/',
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,143 @@
|
|||
import { constructExecutionMetaData, returnJsonArray } from 'n8n-core';
|
||||
import type {
|
||||
IExecuteFunctions,
|
||||
IHookFunctions,
|
||||
ILoadOptionsFunctions,
|
||||
INode,
|
||||
INodeExecutionData,
|
||||
} from 'n8n-workflow';
|
||||
import nock from 'nock';
|
||||
|
||||
import { Baserow } from '../../../Baserow.node';
|
||||
import { baserowApiRequest, getTableFields } from '../../../GenericFunctions';
|
||||
import type { GetAllAdditionalOptions } from '../../../types';
|
||||
|
||||
jest.mock('../../../GenericFunctions', () => {
|
||||
const originalModule: { [key: string]: any } = jest.requireActual('../../../GenericFunctions');
|
||||
return {
|
||||
...originalModule,
|
||||
baserowApiRequest: jest.fn().mockResolvedValue({
|
||||
size: 2147483647,
|
||||
mime_type: 'string',
|
||||
is_image: true,
|
||||
image_width: 32767,
|
||||
image_height: 32767,
|
||||
uploaded_at: '2019-08-24T14:15:22Z',
|
||||
url: 'http://example.com',
|
||||
thumbnails: {
|
||||
property1: null,
|
||||
property2: null,
|
||||
},
|
||||
name: 'string',
|
||||
original_name: 'string',
|
||||
}),
|
||||
getJwtToken: jest.fn().mockResolvedValue('jwt'),
|
||||
};
|
||||
});
|
||||
|
||||
describe('Baserow Node', () => {
|
||||
beforeAll(() => {
|
||||
nock.disableNetConnect();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
nock.restore();
|
||||
jest.unmock('../../../GenericFunctions');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe('resource: file', () => {
|
||||
it('upload-via-url should upload a file via url', async () => {
|
||||
const mockThis = {
|
||||
helpers: {
|
||||
returnJsonArray,
|
||||
constructExecutionMetaData,
|
||||
httpRequest: jest.fn().mockResolvedValue({
|
||||
count: 1,
|
||||
next: null,
|
||||
previous: null,
|
||||
results: {
|
||||
id: 1,
|
||||
order: '^-?\\(?:\\.\\)?$',
|
||||
field_1: 'baz',
|
||||
},
|
||||
}),
|
||||
},
|
||||
getNode() {
|
||||
return {
|
||||
id: 'c4a5ca75-18c7-4cc8-bf7d-5d57bb7d84da',
|
||||
name: 'Baserow upload-via-url',
|
||||
type: 'n8n-nodes-base.Baserow',
|
||||
typeVersion: 1,
|
||||
position: [0, 0],
|
||||
parameters: {
|
||||
operation: 'upload-via-url',
|
||||
resource: 'file',
|
||||
tableId: 1,
|
||||
rowId: 1,
|
||||
},
|
||||
} as INode;
|
||||
},
|
||||
getCredentials: jest.fn().mockResolvedValue({
|
||||
username: 'user',
|
||||
password: 'password',
|
||||
host: 'https://my-host.com',
|
||||
}),
|
||||
getInputData: () => [
|
||||
{
|
||||
json: {},
|
||||
},
|
||||
],
|
||||
getNodeParameter: (parameter: string) => {
|
||||
switch (parameter) {
|
||||
case 'resource':
|
||||
return 'file';
|
||||
case 'operation':
|
||||
return 'upload-via-url';
|
||||
case 'url':
|
||||
return 'https://example.com/image.jpg';
|
||||
case 'additionalOptions':
|
||||
return {} as GetAllAdditionalOptions;
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
continueOnFail: () => false,
|
||||
} as unknown as IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions;
|
||||
|
||||
const node = new Baserow();
|
||||
const response: INodeExecutionData[][] = await node.execute.call(mockThis);
|
||||
expect(baserowApiRequest).toHaveBeenCalledTimes(1);
|
||||
expect(baserowApiRequest).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
'POST',
|
||||
'/api/user-files/upload-via-url/',
|
||||
'jwt',
|
||||
{ url: 'https://example.com/image.jpg' },
|
||||
);
|
||||
|
||||
expect(response).toEqual([
|
||||
[
|
||||
{
|
||||
json: {
|
||||
image_height: 32767,
|
||||
image_width: 32767,
|
||||
is_image: true,
|
||||
mime_type: 'string',
|
||||
name: 'string',
|
||||
original_name: 'string',
|
||||
size: 2147483647,
|
||||
thumbnails: { property1: null, property2: null },
|
||||
uploaded_at: '2019-08-24T14:15:22Z',
|
||||
url: 'http://example.com',
|
||||
},
|
||||
pairedItem: { item: 0 },
|
||||
},
|
||||
],
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
156
packages/nodes-base/nodes/Baserow/test/node/file/upload.test.ts
Normal file
156
packages/nodes-base/nodes/Baserow/test/node/file/upload.test.ts
Normal file
|
@ -0,0 +1,156 @@
|
|||
import { constructExecutionMetaData, returnJsonArray } from 'n8n-core';
|
||||
import type {
|
||||
IExecuteFunctions,
|
||||
IHookFunctions,
|
||||
ILoadOptionsFunctions,
|
||||
INode,
|
||||
INodeExecutionData,
|
||||
} from 'n8n-workflow';
|
||||
import nock from 'nock';
|
||||
|
||||
import { Baserow } from '../../../Baserow.node';
|
||||
import { baserowFileUploadRequest } from '../../../GenericFunctions';
|
||||
import type { GetAllAdditionalOptions } from '../../../types';
|
||||
|
||||
jest.mock('../../../GenericFunctions', () => {
|
||||
const originalModule: { [key: string]: any } = jest.requireActual('../../../GenericFunctions');
|
||||
return {
|
||||
...originalModule,
|
||||
baserowFileUploadRequest: jest.fn().mockResolvedValue({
|
||||
size: 2147483647,
|
||||
mime_type: 'string',
|
||||
is_image: true,
|
||||
image_width: 32767,
|
||||
image_height: 32767,
|
||||
uploaded_at: '2019-08-24T14:15:22Z',
|
||||
url: 'http://example.com',
|
||||
thumbnails: {
|
||||
property1: null,
|
||||
property2: null,
|
||||
},
|
||||
name: 'string',
|
||||
original_name: 'string',
|
||||
}),
|
||||
getJwtToken: jest.fn().mockResolvedValue('jwt'),
|
||||
};
|
||||
});
|
||||
|
||||
describe('Baserow Node', () => {
|
||||
beforeAll(() => {
|
||||
nock.disableNetConnect();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
nock.restore();
|
||||
jest.unmock('../../../GenericFunctions');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe('resource: file', () => {
|
||||
it('upload should upload a file', async () => {
|
||||
const buffer = Buffer.from('test');
|
||||
|
||||
const mockThis = {
|
||||
helpers: {
|
||||
returnJsonArray,
|
||||
constructExecutionMetaData,
|
||||
assertBinaryData: jest
|
||||
.fn()
|
||||
.mockReturnValue({ fileName: 'test.png', mimeType: 'image/png' }),
|
||||
getBinaryDataBuffer: jest.fn().mockResolvedValue(buffer),
|
||||
httpRequest: jest.fn().mockResolvedValue({
|
||||
count: 1,
|
||||
next: null,
|
||||
previous: null,
|
||||
results: {
|
||||
id: 1,
|
||||
order: '^-?\\(?:\\.\\)?$',
|
||||
field_1: 'baz',
|
||||
},
|
||||
}),
|
||||
},
|
||||
getNode() {
|
||||
return {
|
||||
id: 'c4a5ca75-18c7-4cc8-bf7d-5d57bb7d84da',
|
||||
name: 'Baserow upload',
|
||||
type: 'n8n-nodes-base.Baserow',
|
||||
typeVersion: 1,
|
||||
position: [0, 0],
|
||||
parameters: {
|
||||
operation: 'upload',
|
||||
resource: 'file',
|
||||
},
|
||||
} as INode;
|
||||
},
|
||||
getCredentials: jest.fn().mockResolvedValue({
|
||||
username: 'user',
|
||||
password: 'password',
|
||||
host: 'https://my-host.com',
|
||||
}),
|
||||
getInputData: () => [
|
||||
{
|
||||
json: {},
|
||||
},
|
||||
],
|
||||
getNodeParameter: (parameter: string) => {
|
||||
switch (parameter) {
|
||||
case 'resource':
|
||||
return 'file';
|
||||
case 'operation':
|
||||
return 'upload';
|
||||
case 'url':
|
||||
return 'https://example.com/image.jpg';
|
||||
case 'additionalOptions':
|
||||
return {} as GetAllAdditionalOptions;
|
||||
case 'binaryPropertyName':
|
||||
return 'data';
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
continueOnFail: () => false,
|
||||
} as unknown as IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions;
|
||||
|
||||
const node = new Baserow();
|
||||
const response: INodeExecutionData[][] = await node.execute.call(mockThis);
|
||||
|
||||
expect(mockThis.helpers.assertBinaryData).toHaveBeenCalledTimes(1);
|
||||
expect(mockThis.helpers.getBinaryDataBuffer).toHaveBeenCalledTimes(1);
|
||||
|
||||
expect(baserowFileUploadRequest).toHaveBeenCalledTimes(1);
|
||||
expect(baserowFileUploadRequest).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
'jwt',
|
||||
buffer,
|
||||
'test.png',
|
||||
'image/png',
|
||||
);
|
||||
|
||||
expect(response).toEqual([
|
||||
[
|
||||
{
|
||||
json: {
|
||||
size: 2147483647,
|
||||
mime_type: 'string',
|
||||
is_image: true,
|
||||
image_width: 32767,
|
||||
image_height: 32767,
|
||||
uploaded_at: '2019-08-24T14:15:22Z',
|
||||
url: 'http://example.com',
|
||||
thumbnails: {
|
||||
property1: null,
|
||||
property2: null,
|
||||
},
|
||||
name: 'string',
|
||||
original_name: 'string',
|
||||
},
|
||||
pairedItem: { item: 0 },
|
||||
},
|
||||
],
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
140
packages/nodes-base/nodes/Baserow/test/node/rows/create.test.ts
Normal file
140
packages/nodes-base/nodes/Baserow/test/node/rows/create.test.ts
Normal file
|
@ -0,0 +1,140 @@
|
|||
import { constructExecutionMetaData, returnJsonArray } from 'n8n-core';
|
||||
import type {
|
||||
IExecuteFunctions,
|
||||
IHookFunctions,
|
||||
ILoadOptionsFunctions,
|
||||
INode,
|
||||
INodeExecutionData,
|
||||
} from 'n8n-workflow';
|
||||
import nock from 'nock';
|
||||
|
||||
import { Baserow } from '../../../Baserow.node';
|
||||
import { baserowApiRequest, getTableFields } from '../../../GenericFunctions';
|
||||
import type { GetAllAdditionalOptions } from '../../../types';
|
||||
|
||||
jest.mock('../../../GenericFunctions', () => {
|
||||
const originalModule: { [key: string]: any } = jest.requireActual('../../../GenericFunctions');
|
||||
return {
|
||||
...originalModule,
|
||||
baserowApiRequest: jest.fn().mockResolvedValue({
|
||||
id: 1,
|
||||
field_1: 'baz',
|
||||
}),
|
||||
getJwtToken: jest.fn().mockResolvedValue('jwt'),
|
||||
getTableFields: jest.fn().mockResolvedValue([
|
||||
{
|
||||
id: '1',
|
||||
name: 'my_field_name',
|
||||
},
|
||||
]),
|
||||
};
|
||||
});
|
||||
|
||||
describe('Baserow Node', () => {
|
||||
beforeAll(() => {
|
||||
nock.disableNetConnect();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
nock.restore();
|
||||
jest.unmock('../../../GenericFunctions');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe('resource: row', () => {
|
||||
it('create should create a record', async () => {
|
||||
const mockThis = {
|
||||
helpers: {
|
||||
returnJsonArray,
|
||||
constructExecutionMetaData,
|
||||
httpRequest: jest.fn().mockResolvedValue({
|
||||
count: 1,
|
||||
next: null,
|
||||
previous: null,
|
||||
results: {
|
||||
id: 1,
|
||||
order: '^-?\\(?:\\.\\)?$',
|
||||
field_1: 'baz',
|
||||
},
|
||||
}),
|
||||
},
|
||||
getNode() {
|
||||
return {
|
||||
id: 'c4a5ca75-18c7-4cc8-bf7d-5d57bb7d84da',
|
||||
name: 'Baserow get',
|
||||
type: 'n8n-nodes-base.Baserow',
|
||||
typeVersion: 1,
|
||||
position: [0, 0],
|
||||
parameters: {
|
||||
operation: 'create',
|
||||
resource: 'row',
|
||||
tableId: 1,
|
||||
rowId: 1,
|
||||
},
|
||||
} as INode;
|
||||
},
|
||||
getCredentials: jest.fn().mockResolvedValue({
|
||||
username: 'user',
|
||||
password: 'password',
|
||||
host: 'https://my-host.com',
|
||||
}),
|
||||
getInputData: () => [
|
||||
{
|
||||
json: {
|
||||
my_field_name: 'new value',
|
||||
},
|
||||
},
|
||||
],
|
||||
getNodeParameter: (parameter: string) => {
|
||||
switch (parameter) {
|
||||
case 'resource':
|
||||
return 'row';
|
||||
case 'operation':
|
||||
return 'create';
|
||||
case 'tableId':
|
||||
return 1;
|
||||
case 'dataToSend':
|
||||
return 'autoMapInputData';
|
||||
case 'inputsToIgnore':
|
||||
return '';
|
||||
case 'additionalOptions':
|
||||
return {} as GetAllAdditionalOptions;
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
continueOnFail: () => false,
|
||||
} as unknown as IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions;
|
||||
|
||||
const node = new Baserow();
|
||||
const response: INodeExecutionData[][] = await node.execute.call(mockThis);
|
||||
|
||||
expect(getTableFields).toHaveBeenCalledTimes(1);
|
||||
expect(baserowApiRequest).toHaveBeenCalledTimes(1);
|
||||
expect(baserowApiRequest).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
'POST',
|
||||
'/api/database/rows/table/1/',
|
||||
'jwt',
|
||||
{ field_1: 'new value' },
|
||||
);
|
||||
|
||||
expect(response).toEqual([
|
||||
[
|
||||
{
|
||||
json: {
|
||||
id: 1,
|
||||
my_field_name: 'baz',
|
||||
},
|
||||
pairedItem: {
|
||||
item: 0,
|
||||
},
|
||||
},
|
||||
],
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
125
packages/nodes-base/nodes/Baserow/test/node/rows/delete.test.ts
Normal file
125
packages/nodes-base/nodes/Baserow/test/node/rows/delete.test.ts
Normal file
|
@ -0,0 +1,125 @@
|
|||
import { constructExecutionMetaData, returnJsonArray } from 'n8n-core';
|
||||
import type {
|
||||
IExecuteFunctions,
|
||||
IHookFunctions,
|
||||
ILoadOptionsFunctions,
|
||||
INode,
|
||||
INodeExecutionData,
|
||||
} from 'n8n-workflow';
|
||||
import nock from 'nock';
|
||||
|
||||
import { Baserow } from '../../../Baserow.node';
|
||||
import { baserowApiRequest, getTableFields } from '../../../GenericFunctions';
|
||||
import type { GetAllAdditionalOptions } from '../../../types';
|
||||
|
||||
jest.mock('../../../GenericFunctions', () => {
|
||||
const originalModule: { [key: string]: any } = jest.requireActual('../../../GenericFunctions');
|
||||
return {
|
||||
...originalModule,
|
||||
baserowApiRequest: jest.fn().mockResolvedValue({
|
||||
id: 1,
|
||||
order: '^-?\\(?:\\.\\)?$',
|
||||
field_1: 'baz',
|
||||
}),
|
||||
getJwtToken: jest.fn().mockResolvedValue('jwt'),
|
||||
getTableFields: jest.fn().mockResolvedValue([
|
||||
{
|
||||
id: '1',
|
||||
name: 'my_field_name',
|
||||
},
|
||||
]),
|
||||
};
|
||||
});
|
||||
|
||||
describe('Baserow Node', () => {
|
||||
beforeAll(() => {
|
||||
nock.disableNetConnect();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
nock.restore();
|
||||
jest.unmock('../../../GenericFunctions');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe('resource: row', () => {
|
||||
it('delete should delete a record', async () => {
|
||||
const mockThis = {
|
||||
helpers: {
|
||||
returnJsonArray,
|
||||
constructExecutionMetaData,
|
||||
},
|
||||
getNode() {
|
||||
return {
|
||||
id: 'c4a5ca75-18c7-4cc8-bf7d-5d57bb7d84da',
|
||||
name: 'Baserow delete',
|
||||
type: 'n8n-nodes-base.Baserow',
|
||||
typeVersion: 1,
|
||||
position: [0, 0],
|
||||
parameters: {
|
||||
operation: 'delete',
|
||||
resource: 'row',
|
||||
tableId: 1,
|
||||
rowId: 1,
|
||||
},
|
||||
} as INode;
|
||||
},
|
||||
getCredentials: jest.fn().mockResolvedValue({
|
||||
username: 'user',
|
||||
password: 'password',
|
||||
host: 'https://my-host.com',
|
||||
}),
|
||||
getInputData: () => [
|
||||
{
|
||||
json: {},
|
||||
},
|
||||
],
|
||||
getNodeParameter: (parameter: string) => {
|
||||
switch (parameter) {
|
||||
case 'resource':
|
||||
return 'row';
|
||||
case 'operation':
|
||||
return 'delete';
|
||||
case 'tableId':
|
||||
return 1;
|
||||
case 'rowId':
|
||||
return 1;
|
||||
case 'additionalOptions':
|
||||
return {} as GetAllAdditionalOptions;
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
continueOnFail: () => false,
|
||||
} as unknown as IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions;
|
||||
|
||||
const node = new Baserow();
|
||||
const response: INodeExecutionData[][] = await node.execute.call(mockThis);
|
||||
|
||||
expect(getTableFields).toHaveBeenCalledTimes(1);
|
||||
expect(baserowApiRequest).toHaveBeenCalledTimes(1);
|
||||
expect(baserowApiRequest).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
'DELETE',
|
||||
'/api/database/rows/table/1/1/',
|
||||
'jwt',
|
||||
);
|
||||
|
||||
expect(response).toEqual([
|
||||
[
|
||||
{
|
||||
json: {
|
||||
success: true,
|
||||
},
|
||||
pairedItem: {
|
||||
item: 0,
|
||||
},
|
||||
},
|
||||
],
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
137
packages/nodes-base/nodes/Baserow/test/node/rows/get.test.ts
Normal file
137
packages/nodes-base/nodes/Baserow/test/node/rows/get.test.ts
Normal file
|
@ -0,0 +1,137 @@
|
|||
import { constructExecutionMetaData, returnJsonArray } from 'n8n-core';
|
||||
import type {
|
||||
IExecuteFunctions,
|
||||
IHookFunctions,
|
||||
ILoadOptionsFunctions,
|
||||
INode,
|
||||
INodeExecutionData,
|
||||
} from 'n8n-workflow';
|
||||
import nock from 'nock';
|
||||
|
||||
import { Baserow } from '../../../Baserow.node';
|
||||
import { baserowApiRequest, getTableFields } from '../../../GenericFunctions';
|
||||
import type { GetAllAdditionalOptions } from '../../../types';
|
||||
|
||||
jest.mock('../../../GenericFunctions', () => {
|
||||
const originalModule: { [key: string]: any } = jest.requireActual('../../../GenericFunctions');
|
||||
return {
|
||||
...originalModule,
|
||||
baserowApiRequest: jest.fn().mockResolvedValue({
|
||||
id: 1,
|
||||
order: '^-?\\(?:\\.\\)?$',
|
||||
field_1: 'baz',
|
||||
}),
|
||||
getJwtToken: jest.fn().mockResolvedValue('jwt'),
|
||||
getTableFields: jest.fn().mockResolvedValue([
|
||||
{
|
||||
id: '1',
|
||||
name: 'my_field_name',
|
||||
},
|
||||
]),
|
||||
};
|
||||
});
|
||||
|
||||
describe('Baserow Node', () => {
|
||||
beforeAll(() => {
|
||||
nock.disableNetConnect();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
nock.restore();
|
||||
jest.unmock('../../../GenericFunctions');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe('resource: row', () => {
|
||||
it('get should fetch a record', async () => {
|
||||
const mockThis = {
|
||||
helpers: {
|
||||
returnJsonArray,
|
||||
constructExecutionMetaData,
|
||||
httpRequest: jest.fn().mockResolvedValue({
|
||||
count: 1,
|
||||
next: null,
|
||||
previous: null,
|
||||
results: {
|
||||
id: 1,
|
||||
order: '^-?\\(?:\\.\\)?$',
|
||||
field_1: 'baz',
|
||||
},
|
||||
}),
|
||||
},
|
||||
getNode() {
|
||||
return {
|
||||
id: 'c4a5ca75-18c7-4cc8-bf7d-5d57bb7d84da',
|
||||
name: 'Baserow get',
|
||||
type: 'n8n-nodes-base.Baserow',
|
||||
typeVersion: 1,
|
||||
position: [0, 0],
|
||||
parameters: {
|
||||
operation: 'get',
|
||||
resource: 'row',
|
||||
tableId: 1,
|
||||
rowId: 1,
|
||||
},
|
||||
} as INode;
|
||||
},
|
||||
getCredentials: jest.fn().mockResolvedValue({
|
||||
username: 'user',
|
||||
password: 'password',
|
||||
host: 'https://my-host.com',
|
||||
}),
|
||||
getInputData: () => [
|
||||
{
|
||||
json: {},
|
||||
},
|
||||
],
|
||||
getNodeParameter: (parameter: string) => {
|
||||
switch (parameter) {
|
||||
case 'resource':
|
||||
return 'row';
|
||||
case 'operation':
|
||||
return 'get';
|
||||
case 'tableId':
|
||||
return 1;
|
||||
case 'rowId':
|
||||
return 1;
|
||||
case 'additionalOptions':
|
||||
return {} as GetAllAdditionalOptions;
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
continueOnFail: () => false,
|
||||
} as unknown as IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions;
|
||||
|
||||
const node = new Baserow();
|
||||
const response: INodeExecutionData[][] = await node.execute.call(mockThis);
|
||||
|
||||
expect(getTableFields).toHaveBeenCalledTimes(1);
|
||||
expect(baserowApiRequest).toHaveBeenCalledTimes(1);
|
||||
expect(baserowApiRequest).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
'GET',
|
||||
'/api/database/rows/table/1/1/',
|
||||
'jwt',
|
||||
);
|
||||
|
||||
expect(response).toEqual([
|
||||
[
|
||||
{
|
||||
json: {
|
||||
id: 1,
|
||||
order: '^-?\\(?:\\.\\)?$',
|
||||
my_field_name: 'baz',
|
||||
},
|
||||
pairedItem: {
|
||||
item: 0,
|
||||
},
|
||||
},
|
||||
],
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
123
packages/nodes-base/nodes/Baserow/test/node/rows/getAll.test.ts
Normal file
123
packages/nodes-base/nodes/Baserow/test/node/rows/getAll.test.ts
Normal file
|
@ -0,0 +1,123 @@
|
|||
import { constructExecutionMetaData, returnJsonArray } from 'n8n-core';
|
||||
import type {
|
||||
IExecuteFunctions,
|
||||
IHookFunctions,
|
||||
ILoadOptionsFunctions,
|
||||
INode,
|
||||
INodeExecutionData,
|
||||
} from 'n8n-workflow';
|
||||
import nock from 'nock';
|
||||
|
||||
import { Baserow } from '../../../Baserow.node';
|
||||
import { getTableFields } from '../../../GenericFunctions';
|
||||
import type { GetAllAdditionalOptions } from '../../../types';
|
||||
|
||||
jest.mock('../../../GenericFunctions', () => {
|
||||
const originalModule: { [key: string]: any } = jest.requireActual('../../../GenericFunctions');
|
||||
return {
|
||||
...originalModule,
|
||||
getJwtToken: jest.fn().mockResolvedValue('jwt'),
|
||||
getTableFields: jest.fn().mockResolvedValue([
|
||||
{
|
||||
id: '1',
|
||||
name: 'my_field_name',
|
||||
},
|
||||
]),
|
||||
};
|
||||
});
|
||||
|
||||
describe('Baserow Node', () => {
|
||||
beforeAll(() => {
|
||||
nock.disableNetConnect();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
nock.restore();
|
||||
jest.unmock('../../../GenericFunctions');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe('resource: row', () => {
|
||||
it('getAll should fetch all records', async () => {
|
||||
const mockThis = {
|
||||
helpers: {
|
||||
returnJsonArray,
|
||||
constructExecutionMetaData,
|
||||
httpRequest: jest.fn().mockResolvedValue({
|
||||
count: 1,
|
||||
next: null,
|
||||
previous: null,
|
||||
results: [
|
||||
{
|
||||
id: 1,
|
||||
order: '^-?\\(?:\\.\\)?$',
|
||||
field_1: 'baz',
|
||||
},
|
||||
],
|
||||
}),
|
||||
},
|
||||
getNode() {
|
||||
return {
|
||||
id: 'c4a5ca75-18c7-4cc8-bf7d-5d57bb7d84da',
|
||||
name: 'Baserow getAll',
|
||||
type: 'n8n-nodes-base.Baserow',
|
||||
typeVersion: 1,
|
||||
position: [0, 0],
|
||||
parameters: {
|
||||
operation: 'getAll',
|
||||
resource: 'row',
|
||||
tableId: 1,
|
||||
},
|
||||
} as INode;
|
||||
},
|
||||
getCredentials: jest.fn().mockResolvedValue({
|
||||
username: 'user',
|
||||
password: 'password',
|
||||
host: 'https://my-host.com',
|
||||
}),
|
||||
getInputData: () => [
|
||||
{
|
||||
json: {},
|
||||
},
|
||||
],
|
||||
getNodeParameter: (parameter: string) => {
|
||||
switch (parameter) {
|
||||
case 'resource':
|
||||
return 'row';
|
||||
case 'operation':
|
||||
return 'getAll';
|
||||
case 'tableId':
|
||||
return 1;
|
||||
case 'additionalOptions':
|
||||
return {} as GetAllAdditionalOptions;
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
continueOnFail: () => false,
|
||||
} as unknown as IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions;
|
||||
|
||||
const node = new Baserow();
|
||||
const response: INodeExecutionData[][] = await node.execute.call(mockThis);
|
||||
|
||||
expect(getTableFields).toHaveBeenCalledTimes(1);
|
||||
expect(response).toEqual([
|
||||
[
|
||||
{
|
||||
json: {
|
||||
id: 1,
|
||||
order: '^-?\\(?:\\.\\)?$',
|
||||
my_field_name: 'baz',
|
||||
},
|
||||
pairedItem: {
|
||||
item: 0,
|
||||
},
|
||||
},
|
||||
],
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
144
packages/nodes-base/nodes/Baserow/test/node/rows/update.test.ts
Normal file
144
packages/nodes-base/nodes/Baserow/test/node/rows/update.test.ts
Normal file
|
@ -0,0 +1,144 @@
|
|||
import { constructExecutionMetaData, returnJsonArray } from 'n8n-core';
|
||||
import type {
|
||||
IExecuteFunctions,
|
||||
IHookFunctions,
|
||||
ILoadOptionsFunctions,
|
||||
INode,
|
||||
INodeExecutionData,
|
||||
} from 'n8n-workflow';
|
||||
import nock from 'nock';
|
||||
|
||||
import { Baserow } from '../../../Baserow.node';
|
||||
import { baserowApiRequest, getTableFields } from '../../../GenericFunctions';
|
||||
import type { GetAllAdditionalOptions } from '../../../types';
|
||||
|
||||
jest.mock('../../../GenericFunctions', () => {
|
||||
const originalModule: { [key: string]: any } = jest.requireActual('../../../GenericFunctions');
|
||||
return {
|
||||
...originalModule,
|
||||
baserowApiRequest: jest.fn().mockResolvedValue({
|
||||
id: 1,
|
||||
order: '^-?\\(?:\\.\\)?$',
|
||||
field_1: 'changed',
|
||||
}),
|
||||
getJwtToken: jest.fn().mockResolvedValue('jwt'),
|
||||
getTableFields: jest.fn().mockResolvedValue([
|
||||
{
|
||||
id: '1',
|
||||
name: 'my_field_name',
|
||||
},
|
||||
]),
|
||||
};
|
||||
});
|
||||
|
||||
describe('Baserow Node', () => {
|
||||
beforeAll(() => {
|
||||
nock.disableNetConnect();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
nock.restore();
|
||||
jest.unmock('../../../GenericFunctions');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe('resource: row', () => {
|
||||
it('update should update a record', async () => {
|
||||
const mockThis = {
|
||||
helpers: {
|
||||
returnJsonArray,
|
||||
constructExecutionMetaData,
|
||||
httpRequest: jest.fn().mockResolvedValue({
|
||||
count: 1,
|
||||
next: null,
|
||||
previous: null,
|
||||
results: {
|
||||
id: 1,
|
||||
order: '^-?\\(?:\\.\\)?$',
|
||||
field_1: 'baz',
|
||||
},
|
||||
}),
|
||||
},
|
||||
getNode() {
|
||||
return {
|
||||
id: 'c4a5ca75-18c7-4cc8-bf7d-5d57bb7d84da',
|
||||
name: 'Baserow get',
|
||||
type: 'n8n-nodes-base.Baserow',
|
||||
typeVersion: 1,
|
||||
position: [0, 0],
|
||||
parameters: {
|
||||
operation: 'update',
|
||||
resource: 'row',
|
||||
tableId: 1,
|
||||
rowId: 1,
|
||||
},
|
||||
} as INode;
|
||||
},
|
||||
getCredentials: jest.fn().mockResolvedValue({
|
||||
username: 'user',
|
||||
password: 'password',
|
||||
host: 'https://my-host.com',
|
||||
}),
|
||||
getInputData: () => [
|
||||
{
|
||||
json: {
|
||||
my_field_name: 'changed',
|
||||
},
|
||||
},
|
||||
],
|
||||
getNodeParameter: (parameter: string) => {
|
||||
switch (parameter) {
|
||||
case 'resource':
|
||||
return 'row';
|
||||
case 'operation':
|
||||
return 'update';
|
||||
case 'tableId':
|
||||
return 1;
|
||||
case 'rowId':
|
||||
return 1;
|
||||
case 'dataToSend':
|
||||
return 'autoMapInputData';
|
||||
case 'inputsToIgnore':
|
||||
return '';
|
||||
case 'additionalOptions':
|
||||
return {} as GetAllAdditionalOptions;
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
continueOnFail: () => false,
|
||||
} as unknown as IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions;
|
||||
|
||||
const node = new Baserow();
|
||||
const response: INodeExecutionData[][] = await node.execute.call(mockThis);
|
||||
|
||||
expect(getTableFields).toHaveBeenCalledTimes(1);
|
||||
expect(baserowApiRequest).toHaveBeenCalledTimes(1);
|
||||
expect(baserowApiRequest).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
'PATCH',
|
||||
'/api/database/rows/table/1/1/',
|
||||
'jwt',
|
||||
{ field_1: 'changed' },
|
||||
);
|
||||
|
||||
expect(response).toEqual([
|
||||
[
|
||||
{
|
||||
json: {
|
||||
id: 1,
|
||||
order: '^-?\\(?:\\.\\)?$',
|
||||
my_field_name: 'changed',
|
||||
},
|
||||
pairedItem: {
|
||||
item: 0,
|
||||
},
|
||||
},
|
||||
],
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,232 @@
|
|||
import { constructExecutionMetaData, returnJsonArray } from 'n8n-core';
|
||||
import type {
|
||||
IExecuteFunctions,
|
||||
IHookFunctions,
|
||||
ILoadOptionsFunctions,
|
||||
INode,
|
||||
INodeExecutionData,
|
||||
} from 'n8n-workflow';
|
||||
import nock from 'nock';
|
||||
|
||||
import { BaserowTrigger } from '../../../BaserowTrigger.node';
|
||||
import { baserowApiRequestAllItems, getTableFields } from '../../../GenericFunctions';
|
||||
import type { GetAllAdditionalOptions } from '../../../types';
|
||||
|
||||
jest.mock('../../../GenericFunctions', () => {
|
||||
const originalModule: { [key: string]: any } = jest.requireActual('../../../GenericFunctions');
|
||||
return {
|
||||
...originalModule,
|
||||
baserowApiRequestAllItems: jest.fn(),
|
||||
getJwtToken: jest.fn().mockResolvedValue('jwt'),
|
||||
getTableFields: jest.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
describe('Baserow Trigger Node', () => {
|
||||
beforeEach(() => {
|
||||
jest.useFakeTimers();
|
||||
jest.setSystemTime(new Date('2024-12-10T12:57:41Z'));
|
||||
});
|
||||
|
||||
beforeAll(() => {
|
||||
nock.disableNetConnect();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
nock.restore();
|
||||
jest.unmock('../../../GenericFunctions');
|
||||
});
|
||||
|
||||
describe('trigger', () => {
|
||||
it('should not trigger when no new record', async () => {
|
||||
const mockThis = {
|
||||
helpers: {
|
||||
returnJsonArray,
|
||||
constructExecutionMetaData,
|
||||
httpRequest: jest.fn().mockResolvedValue({
|
||||
count: 0,
|
||||
next: null,
|
||||
previous: null,
|
||||
results: [],
|
||||
}),
|
||||
},
|
||||
getWorkflowStaticData() {
|
||||
return {
|
||||
node: {},
|
||||
};
|
||||
},
|
||||
getMode() {
|
||||
return 'auto';
|
||||
},
|
||||
getNode() {
|
||||
return {
|
||||
id: 'c4a5ca75-18c7-4cc8-bf7d-5d57bb7d84da',
|
||||
name: 'Baserow Trigger',
|
||||
type: 'n8n-nodes-base.baserowTrigger',
|
||||
typeVersion: 1,
|
||||
position: [0, 0],
|
||||
parameters: {
|
||||
databaseId: 1,
|
||||
tableId: 1,
|
||||
},
|
||||
} as INode;
|
||||
},
|
||||
getCredentials: jest.fn().mockResolvedValue({
|
||||
username: 'user',
|
||||
password: 'password',
|
||||
host: 'https://my-host.com',
|
||||
}),
|
||||
getInputData: () => [
|
||||
{
|
||||
json: {},
|
||||
},
|
||||
],
|
||||
getNodeParameter: (parameter: string) => {
|
||||
switch (parameter) {
|
||||
case 'databaseId':
|
||||
return 1;
|
||||
case 'tableId':
|
||||
return 1;
|
||||
case 'additionalFields':
|
||||
return { viewId: 1 };
|
||||
case 'additionalOptions':
|
||||
return {} as GetAllAdditionalOptions;
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
continueOnFail: () => false,
|
||||
} as unknown as IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions;
|
||||
|
||||
getTableFields.mockResolvedValue([
|
||||
{
|
||||
id: '1',
|
||||
name: 'my_field_name',
|
||||
},
|
||||
]);
|
||||
|
||||
baserowApiRequestAllItems.mockResolvedValue([]);
|
||||
|
||||
const node = new BaserowTrigger();
|
||||
const response: INodeExecutionData[][] | null = await node.poll.call(mockThis);
|
||||
|
||||
expect(baserowApiRequestAllItems).toHaveBeenCalledTimes(1);
|
||||
expect(getTableFields).toHaveBeenCalled();
|
||||
|
||||
expect(response).toBeNull();
|
||||
});
|
||||
it('should trigger when new record', async () => {
|
||||
const mockThis = {
|
||||
helpers: {
|
||||
returnJsonArray,
|
||||
constructExecutionMetaData,
|
||||
httpRequest: jest.fn().mockResolvedValue({
|
||||
count: 1,
|
||||
next: null,
|
||||
previous: null,
|
||||
results: [
|
||||
{
|
||||
id: 1,
|
||||
order: '^-?\\(?:\\.\\)?$',
|
||||
field_1: 'baz',
|
||||
},
|
||||
],
|
||||
}),
|
||||
},
|
||||
getMode() {
|
||||
return 'auto';
|
||||
},
|
||||
getWorkflowStaticData() {
|
||||
return {
|
||||
node: {},
|
||||
};
|
||||
},
|
||||
getNode() {
|
||||
return {
|
||||
id: 'c4a5ca75-18c7-4cc8-bf7d-5d57bb7d84da',
|
||||
name: 'Baserow Trigger',
|
||||
type: 'n8n-nodes-base.baserowTrigger',
|
||||
typeVersion: 1,
|
||||
position: [0, 0],
|
||||
parameters: {
|
||||
databaseId: 1,
|
||||
tableId: 1,
|
||||
},
|
||||
} as INode;
|
||||
},
|
||||
getCredentials: jest.fn().mockResolvedValue({
|
||||
username: 'user',
|
||||
password: 'password',
|
||||
host: 'https://my-host.com',
|
||||
}),
|
||||
getInputData: () => [
|
||||
{
|
||||
json: {},
|
||||
},
|
||||
],
|
||||
getNodeParameter: (parameter: string) => {
|
||||
switch (parameter) {
|
||||
case 'databaseId':
|
||||
return 1;
|
||||
case 'tableId':
|
||||
return 1;
|
||||
case 'triggerField':
|
||||
return 'changed_at';
|
||||
case 'additionalOptions':
|
||||
return {} as GetAllAdditionalOptions;
|
||||
case 'additionalFields':
|
||||
return { viewId: 1 };
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
continueOnFail: () => false,
|
||||
} as unknown as IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions;
|
||||
|
||||
baserowApiRequestAllItems.mockResolvedValue([
|
||||
{
|
||||
id: 1,
|
||||
order: '^-?\\(?:\\.\\)?$',
|
||||
field_1: 'baz',
|
||||
},
|
||||
]);
|
||||
|
||||
getTableFields.mockResolvedValue([
|
||||
{
|
||||
id: '1',
|
||||
name: 'my_field_name',
|
||||
},
|
||||
]);
|
||||
|
||||
const node = new BaserowTrigger();
|
||||
const response: INodeExecutionData[][] | null = await node.poll.call(mockThis);
|
||||
|
||||
expect(getTableFields).toHaveBeenCalledTimes(1);
|
||||
expect(baserowApiRequestAllItems).toHaveBeenCalledTimes(1);
|
||||
expect(baserowApiRequestAllItems).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
'GET',
|
||||
'/api/database/rows/table/1/',
|
||||
undefined,
|
||||
{},
|
||||
{ filter__changed_at__date_after: 'Africa/Abidjan?2024-12-10T12:57:41Z', view_id: 1 },
|
||||
);
|
||||
|
||||
expect(response).toEqual([
|
||||
[
|
||||
{
|
||||
json: {
|
||||
id: 1,
|
||||
order: '^-?\\(?:\\.\\)?$',
|
||||
my_field_name: 'baz',
|
||||
},
|
||||
},
|
||||
],
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -35,7 +35,9 @@ export type Row = Record<string, string>;
|
|||
|
||||
export type FieldsUiValues = Array<{
|
||||
fieldId: string;
|
||||
fieldValue: string;
|
||||
fieldValue: string | string[];
|
||||
}>;
|
||||
|
||||
export type Operation = 'create' | 'delete' | 'update' | 'get' | 'getAll';
|
||||
export type Resource = 'file' | 'row' | 'table' | 'database';
|
||||
export type RowOperation = 'create' | 'delete' | 'update' | 'get' | 'getAll';
|
||||
export type FileOperation = 'upload' | 'upload-via-url';
|
||||
|
|
Loading…
Reference in a new issue