Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 4 additions & 2 deletions backend/src/entities/connection/connection.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -709,7 +709,8 @@ export class ConnectionController {
return errors;
}

if (!connectionData.username) errors.push(Messages.USERNAME_MISSING);
if (!connectionData.username && connectionData.type !== ConnectionTypesEnum.redis)
errors.push(Messages.USERNAME_MISSING);

if (
connectionData.type === ConnectionTypesEnum.dynamodb ||
Expand All @@ -718,7 +719,8 @@ export class ConnectionController {
return errors;
}

if (!connectionData.database) errors.push(Messages.DATABASE_MISSING);
if (!connectionData.database && connectionData.type !== ConnectionTypesEnum.redis)
errors.push(Messages.DATABASE_MISSING);
if (process.env.NODE_ENV !== 'test' && !connectionData.ssh) {
if (!this.isMongoHost(connectionData.host)) {
if (!validator.isFQDN(connectionData.host) && !validator.isIP(connectionData.host))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,13 @@ export async function validateCreateConnectionData(
// );
// }
// }
if (!username) errors.push(Messages.USERNAME_MISSING);
if (!username && type !== ConnectionTypesEnum.redis) errors.push(Messages.USERNAME_MISSING);

if (type !== ConnectionTypesEnum.dynamodb && type !== ConnectionTypesEnum.elasticsearch) {
if (
type !== ConnectionTypesEnum.dynamodb &&
type !== ConnectionTypesEnum.elasticsearch &&
type !== ConnectionTypesEnum.redis
) {
if (!database) errors.push(Messages.DATABASE_MISSING);
if (port < 0 || port > 65535 || !port) errors.push(Messages.PORT_MISSING);
if (typeof port !== 'number') errors.push(Messages.PORT_FORMAT_INCORRECT);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ export class ExportCSVFromTableUseCase
connection.type === 'mongodb' ||
connection.type === 'dynamodb' ||
connection.type === 'elasticsearch' ||
connection.type === 'redis' ||
isConnectionTypeAgent(connection.type)
) {
return new StreamableFile(csv.stringify(rowsStream as any, { header: true }));
Expand Down
4 changes: 3 additions & 1 deletion backend/src/enums/connection-type.enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ export enum ConnectionTypeTestEnum {
mongodb = 'mongodb',
dynamodb = 'dynamodb',
elasticsearch = 'elasticsearch',
cassandra = 'cassandra',
cassandra = 'cassandra',
redis = 'redis',
agent_postgres = 'agent_postgres',
agent_mysql = 'agent_mysql',
agent_oracledb = 'agent_oracledb',
Expand All @@ -17,4 +18,5 @@ export enum ConnectionTypeTestEnum {
agent_mongodb = 'agent_mongodb',
agent_elasticsearch = 'agent_elasticsearch',
agent_cassandra = 'agent_cassandra',
agent_redis = 'agent_redis',
}
158 changes: 158 additions & 0 deletions backend/test/ava-tests/saas-tests/table-postgres-e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2513,6 +2513,164 @@ test.serial(`${currentTest} should update row in table and return result`, async
t.is(rows[updateRowIndex][testTableSecondColumnName], row[testTableSecondColumnName]);
});

test.serial(`${currentTest} should update row in table and return result, when table has json field`, async (t) => {
const connectionToTestDB = getTestData(mockFactory).connectionToPostgres;
const firstUserToken = (await registerUserAndReturnUserInfo(app)).token;
const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } =
await createTestTable(connectionToTestDB, undefined, undefined, true);

testTables.push(testTableName);

const createConnectionResponse = await request(app.getHttpServer())
.post('/connection')
.send(connectionToTestDB)
.set('Cookie', firstUserToken)
.set('Content-Type', 'application/json')
.set('Accept', 'application/json');
const createConnectionRO = JSON.parse(createConnectionResponse.text);
t.is(createConnectionResponse.status, 201);

const fakeName = faker.person.firstName();
const fakeMail = faker.internet.email();

const row = {
[testTableColumnName]: fakeName,
[testTableSecondColumnName]: fakeMail,
['json_field']: [
{
id: 'PgSAwanAwptE',
url: 'www.example.com',
name: 'test',
type: 'test type',
metadata: {},
reference: null,
created_at: '2025-09-25T18:51:09.188Z',
updated_at: '2025-09-25T18:51:09.188Z',
description: 'some test field',
},
],
['jsonb_field']: [
{
id: 'PgSAwanAwptE',
url: 'www.example.com',
name: 'test',
type: 'test type',
metadata: {},
reference: null,
created_at: '2025-09-25T18:51:09.188Z',
updated_at: '2025-09-25T18:51:09.188Z',
description: 'some test field',
},
],
};
const rowToUpdate = JSON.stringify(row);
const updateRowInTableResponse = await request(app.getHttpServer())
.put(`/table/row/${createConnectionRO.id}?tableName=${testTableName}&id=1`)
.send(rowToUpdate)
.set('Cookie', firstUserToken)
.set('Content-Type', 'application/json')
.set('Accept', 'application/json');

const updateRowInTableRO = JSON.parse(updateRowInTableResponse.text);
t.is(updateRowInTableResponse.status, 200);
t.is(updateRowInTableRO.hasOwnProperty('row'), true);
t.is(updateRowInTableRO.hasOwnProperty('structure'), true);
t.is(updateRowInTableRO.hasOwnProperty('foreignKeys'), true);
t.is(updateRowInTableRO.hasOwnProperty('primaryColumns'), true);
t.is(updateRowInTableRO.hasOwnProperty('readonly_fields'), true);
t.is(updateRowInTableRO.row[testTableColumnName], row[testTableColumnName]);
t.is(updateRowInTableRO.row[testTableSecondColumnName], row[testTableSecondColumnName]);

//checking that the line was updated
const getTableRowsResponse = await request(app.getHttpServer())
.get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=1&perPage=50`)
.set('Cookie', firstUserToken)
.set('Content-Type', 'application/json')
.set('Accept', 'application/json');
t.is(getTableRowsResponse.status, 200);

const getTableRowsRO = JSON.parse(getTableRowsResponse.text);

t.is(getTableRowsRO.hasOwnProperty('rows'), true);
t.is(getTableRowsRO.hasOwnProperty('primaryColumns'), true);
t.is(getTableRowsRO.hasOwnProperty('pagination'), true);

const { rows, primaryColumns, pagination } = getTableRowsRO;

const updateRowIndex = rows.map((row) => row.id).indexOf(1);
t.is(rows.length, 42);
t.is(rows[updateRowIndex][testTableColumnName], row[testTableColumnName]);
t.is(rows[updateRowIndex][testTableSecondColumnName], row[testTableSecondColumnName]);

// add row with json field
const newRow = {
[testTableColumnName]: faker.person.firstName(),
[testTableSecondColumnName]: faker.internet.email(),
['json_field']: {
id: 'newRowId',
url: 'www.newrow.com',
name: 'new row',
type: 'new type',
metadata: {},
reference: null,
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
description: 'new row description',
},
};
const addRowInTableResponse = await request(app.getHttpServer())
.post(`/table/row/${createConnectionRO.id}?tableName=${testTableName}`)
.send(JSON.stringify(newRow))
.set('Cookie', firstUserToken)
.set('Content-Type', 'application/json')
.set('Accept', 'application/json');

const addRowInTableRO = JSON.parse(addRowInTableResponse.text);
t.is(addRowInTableResponse.status, 201);
t.is(addRowInTableRO.hasOwnProperty('row'), true);
t.is(typeof addRowInTableRO.row['json_field'], 'object');

// update the added row

const updatedNewRow = {
[testTableColumnName]: faker.person.firstName(),
[testTableSecondColumnName]: faker.internet.email(),
['json_field']: [
{
id: 'updatedNewRowId',
url: 'www.updatednewrow.com',
name: 'updated new row',
type: 'updated new type',
metadata: {},
reference: null,
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
description: 'updated new row description',
},
],
};

const updateNewRowInTableResponse = await request(app.getHttpServer())
.put(`/table/row/${createConnectionRO.id}?tableName=${testTableName}&id=${addRowInTableRO.row.id}`)
.send(updatedNewRow)
.set('Cookie', firstUserToken)
.set('Content-Type', 'application/json')
.set('Accept', 'application/json');

const updateNewRowInTableRO = JSON.parse(updateNewRowInTableResponse.text);
t.is(updateNewRowInTableResponse.status, 200);
t.is(updateNewRowInTableRO.hasOwnProperty('row'), true);
t.is(updateNewRowInTableRO.hasOwnProperty('structure'), true);
t.is(updateNewRowInTableRO.hasOwnProperty('foreignKeys'), true);
t.is(updateNewRowInTableRO.hasOwnProperty('primaryColumns'), true);
t.is(updateNewRowInTableRO.hasOwnProperty('readonly_fields'), true);
t.is(updateNewRowInTableRO.row[testTableColumnName], updatedNewRow[testTableColumnName]);
t.is(updateNewRowInTableRO.row[testTableSecondColumnName], updatedNewRow[testTableSecondColumnName]);
t.is(typeof updateNewRowInTableRO.row['json_field'], 'object');
t.is(Array.isArray(updateNewRowInTableRO.row['json_field']), true);
t.is(updateNewRowInTableRO.row['json_field'][0].id, 'updatedNewRowId');
});

test.serial(`${currentTest} should throw an exception when connection id not passed in request`, async (t) => {
const connectionToTestDB = getTestData(mockFactory).connectionToPostgres;
const firstUserToken = (await registerUserAndReturnUserInfo(app)).token;
Expand Down
Loading
Loading