supporting big data backend with links and row create, update and delete

This commit is contained in:
Christoph Dyllick-Brenzinger 2024-01-29 10:08:13 +01:00
parent 787f33de4e
commit 5198fdad55
13 changed files with 127 additions and 51 deletions

View file

@ -8,7 +8,7 @@ export class SeaTable extends VersionedNodeType {
constructor() {
const baseDescription: INodeTypeBaseDescription = {
displayName: 'SeaTable',
name: 'seaTable',
name: 'seatable',
icon: 'file:seatable.svg',
group: ['output'],
subtitle: '={{$parameter["resource"] + ": " + $parameter["operation"]}}',

View file

@ -29,6 +29,9 @@ import type {
IFile,
} from './actions/Interfaces';
// for date transformations
import moment from 'moment';
// remove last backslash
const userBaseUri = (uri?: string) => {
if (uri === undefined) return uri;
@ -310,6 +313,33 @@ export function splitStringColumnsToArrays(
row[column.name] = input.split(',').map((item) => item.trim());
}
}
if (column.type == 'number') {
if (typeof row[column.name] === 'string') {
const input = row[column.name] as string;
row[column.name] = parseFloat(input);
}
}
if (column.type == 'rate' || column.type == 'duration') {
if (typeof row[column.name] === 'string') {
const input = row[column.name] as string;
row[column.name] = parseInt(input);
}
}
if (column.type == 'checkbox') {
if (typeof row[column.name] === 'string') {
const input = row[column.name] as string;
row[column.name] = false;
if (input === 'true' || input === 'on' || input === '1') {
row[column.name] = true;
}
}
}
if (column.type == 'date') {
if (typeof row[column.name] === 'string') {
const input = row[column.name] as string;
row[column.name] = moment(input, 'YYYY-mm-dd', true);
}
}
});
return row;
}

View file

@ -17,8 +17,7 @@ export const linkAddDescription: LinkProperties = [
},
},
default: '',
description:
'The name of SeaTable table to access. Choose from the list, or specify a name using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description: 'If you use an expression, provide it in the way "<table_name>:::<table_id>".',
},
{
displayName: 'Link column',
@ -36,7 +35,8 @@ export const linkAddDescription: LinkProperties = [
},
required: true,
default: '',
description: 'Select the column to create a link.',
description:
'If you use an expression, provide it in the way "<column_name>:::<link_id>:::<other_table_id>".',
},
{
displayName: 'Row ID from the source table',

View file

@ -7,18 +7,21 @@ export async function add(this: IExecuteFunctions, index: number): Promise<INode
const linkColumnSourceId = this.getNodeParameter('linkColumnSourceId', index) as string;
const linkColumnTargetId = this.getNodeParameter('linkColumnTargetId', index) as string;
const body = {
link_id: linkColumn.split(':::')[1],
table_id: tableName.split(':::')[1],
other_table_id: linkColumn.split(':::')[2],
other_rows_ids_map: {
[linkColumnSourceId]: [linkColumnTargetId],
},
};
const responseData = await seaTableApiRequest.call(
this,
{},
'POST',
'/dtable-server/api/v1/dtables/{{dtable_uuid}}/links/',
{
link_id: linkColumn.split(':::')[1],
table_id: tableName.split(':::')[1],
table_row_id: linkColumnSourceId,
other_table_id: linkColumn.split(':::')[2],
other_table_row_id: linkColumnTargetId,
},
'/dtable-db/api/v1/base/{{dtable_uuid}}/links/',
body,
);
return this.helpers.returnJsonArray(responseData as IDataObject[]);

View file

@ -17,8 +17,7 @@ export const linkRemoveDescription: LinkProperties = [
},
},
default: '',
description:
'The name of SeaTable table to access. Choose from the list, or specify a name using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description: 'If you use an expression, provide it in the way "<table_name>:::<table_id>".',
},
{
displayName: 'Link column',
@ -36,7 +35,7 @@ export const linkRemoveDescription: LinkProperties = [
},
required: true,
default: '',
description: 'Select the column to create a link.',
description: 'If you use an expression, provide it in the way "<column_name>:::<link_id>:::<other_table_id>".',
},
{
displayName: 'Row ID from the source table',

View file

@ -10,18 +10,21 @@ export async function remove(
const linkColumnSourceId = this.getNodeParameter('linkColumnSourceId', index) as string;
const linkColumnTargetId = this.getNodeParameter('linkColumnTargetId', index) as string;
const body = {
link_id: linkColumn.split(':::')[1],
table_id: tableName.split(':::')[1],
other_table_id: linkColumn.split(':::')[2],
other_rows_ids_map: {
[linkColumnSourceId]: [linkColumnTargetId],
},
};
const responseData = await seaTableApiRequest.call(
this,
{},
'DELETE',
'/dtable-server/api/v1/dtables/{{dtable_uuid}}/links/',
{
link_id: linkColumn.split(':::')[1],
table_id: tableName.split(':::')[1],
table_row_id: linkColumnSourceId,
other_table_id: linkColumn.split(':::')[2],
other_table_row_id: linkColumnTargetId,
},
'/dtable-db/api/v1/base/{{dtable_uuid}}/links/',
body,
);
return this.helpers.returnJsonArray(responseData as IDataObject[]);

View file

@ -80,7 +80,7 @@ export const rowCreateDescription: RowProperties = [
name: 'columnName',
type: 'options',
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
'Choose from the list, or specify the column name using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
typeOptions: {
loadOptionsDependsOn: ['tableName'],
loadOptionsMethod: 'getTableUpdateAbleColumns',
@ -104,7 +104,21 @@ export const rowCreateDescription: RowProperties = [
},
},
default: {},
description: 'Add destination column with its value',
description:
'Add destination column with its value. Provide the value in this way:<br>Date: YYYY-MM-DD or YYYY-MM-DD hh:mm<br>Duration: time in seconds<br>Checkbox: true, on or 1<br>Multi-Select: comma separated list',
},
{
displayName: 'Save to "Big Data" backend',
name: 'bigdata',
type: 'boolean',
displayOptions: {
show: {
resource: ['row'],
operation: ['create'],
},
},
default: false,
description: 'This requires the activation of the Big Data backend in the base.',
},
{
displayName: 'Hint: Link, files, images or digital signatures have to be added separately.',

View file

@ -19,6 +19,7 @@ export async function create(
const fieldsToSend = this.getNodeParameter('fieldsToSend', index) as
| 'defineBelow'
| 'autoMapInputData';
const bigdata = this.getNodeParameter('bigdata', index) as string;
const body = {
table_name: tableName,
@ -48,15 +49,29 @@ export async function create(
// string to array: multi-select and collaborators
rowInput = splitStringColumnsToArrays(rowInput, tableColumns);
body.row = rowInput;
// save to big data backend
if (bigdata) {
body.rows = [rowInput];
const responseData = await seaTableApiRequest.call(
this,
{},
'POST',
'/dtable-db/api/v1/insert-rows/{{dtable_uuid}}/',
body,
);
return this.helpers.returnJsonArray(responseData as IDataObject[]);
}
// save to normal backend
else {
body.row = rowInput;
const responseData = await seaTableApiRequest.call(
this,
{},
'POST',
'/dtable-server/api/v1/dtables/{{dtable_uuid}}/rows/',
body,
);
return this.helpers.returnJsonArray(responseData as IDataObject[]);
const responseData = await seaTableApiRequest.call(
this,
{},
'POST',
'/dtable-server/api/v1/dtables/{{dtable_uuid}}/rows/',
body,
);
return this.helpers.returnJsonArray(responseData as IDataObject[]);
}
}

View file

@ -36,5 +36,6 @@ export const rowRemoveDescription: RowProperties = [
},
},
default: '',
description: 'Remove any row from the normal or big data backend based on its unique row ID.',
},
];

View file

@ -10,14 +10,14 @@ export async function remove(
const requestBody: IDataObject = {
table_name: tableName,
row_id: rowId,
row_ids: [rowId],
};
const responseData = await seaTableApiRequest.call(
this,
{},
'DELETE',
'/dtable-server/api/v1/dtables/{{dtable_uuid}}/rows/',
'/dtable-db/api/v1/delete-rows/{{dtable_uuid}}/',
requestBody,
);

View file

@ -26,7 +26,7 @@ export const rowUpdateDescription: RowProperties = [
type: 'options',
required: true,
typeOptions: {
loadOptionsDependsOn: ['tableName'],
loadOptionsDependsOn: ['tableName'],
loadOptionsMethod: 'getRowIds',
},
displayOptions: {
@ -97,7 +97,7 @@ export const rowUpdateDescription: RowProperties = [
name: 'columnName',
type: 'options',
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
'Choose from the list, or specify the column name using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
typeOptions: {
loadOptionsDependsOn: ['tableName'],
loadOptionsMethod: 'getTableUpdateAbleColumns',
@ -121,7 +121,8 @@ export const rowUpdateDescription: RowProperties = [
},
},
default: {},
description: 'Add destination column with its value',
description:
'Add destination column with its value. Provide the value in this way:<br>Date: YYYY-MM-DD or YYYY-MM-DD hh:mm<br>Duration: time in seconds<br>Checkbox: true, on or 1<br>Multi-Select: comma separated list',
},
{
displayName: 'Hint: Link, files, images or digital signatures have to be added separately.',

View file

@ -21,10 +21,6 @@ export async function update(
| 'autoMapInputData';
const rowId = this.getNodeParameter('rowId', index) as string;
const body = {
table_name: tableName,
row_id: rowId,
} as IDataObject;
let rowInput = {} as IRowObject;
// get rowInput, an object of key:value pairs like { Name: 'Promo Action 1', Status: "Draft" }.
@ -49,13 +45,21 @@ export async function update(
// string to array: multi-select and collaborators
rowInput = splitStringColumnsToArrays(rowInput, tableColumns);
body.row = rowInput;
const body = {
table_name: tableName,
updates: [
{
row_id: rowId,
row: rowInput,
},
],
} as IDataObject;
const responseData = await seaTableApiRequest.call(
this,
{},
'PUT',
'/dtable-server/api/v1/dtables/{{dtable_uuid}}/rows/',
'/dtable-db/api/v1/update-rows/{{dtable_uuid}}/',
body,
);

View file

@ -37,7 +37,7 @@ export async function getTableNameAndId(
for (const table of tables) {
returnData.push({
name: table.name,
value: table.name + ':::' + table._id,
value: table.name + ':::' + table['_id'],
});
}
return returnData;
@ -80,9 +80,11 @@ export async function getSearchableColumns(
export async function getLinkColumns(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = [];
let tableName = this.getCurrentNodeParameter('tableName') as string;
tableName = tableName.split(':::')[0];
//const tableId = (tableName.split(':::')[1] ? tableName.split(':::')[1] : "");
const table = this.getCurrentNodeParameter('tableName') as string;
const tableName = table.split(':::')[0];
const tableId = table.split(':::')[1];
if (tableName) {
const columns = await seaTableApiRequest.call(
this,
@ -94,9 +96,13 @@ export async function getLinkColumns(this: ILoadOptionsFunctions): Promise<INode
);
for (const col of columns.columns) {
if (col.type === 'link') {
// make sure that the "other table id" is returned and not the same table id again.
const otid =
tableId !== col.data.other_table_id ? col.data.other_table_id : col.data.table_id;
returnData.push({
name: col.name,
value: col.name + ':::' + col.data.link_id + ':::' + col.data.other_table_id,
value: col.name + ':::' + col.data.link_id + ':::' + otid,
});
}
}