diff --git a/backend/src/entities/table/utils/form-full-table-structure.ts b/backend/src/entities/table/utils/form-full-table-structure.ts index b576ca962..bad9da8c8 100644 --- a/backend/src/entities/table/utils/form-full-table-structure.ts +++ b/backend/src/entities/table/utils/form-full-table-structure.ts @@ -9,15 +9,17 @@ export function formFullTableStructure( ): Array { const { search_fields, excluded_fields } = tableSettings || {}; - return structure.map(({ column_name, column_default, data_type, data_type_params, allow_null, character_maximum_length, extra }) => ({ - column_name, - column_default, - data_type, - data_type_params: data_type_params || undefined, - isExcluded: excluded_fields?.includes(column_name) || false, - isSearched: search_fields?.includes(column_name) || false, - auto_increment: checkFieldAutoincrement(column_default, extra), - allow_null, - character_maximum_length, - })); + return structure.map( + ({ column_name, column_default, data_type, data_type_params, allow_null, character_maximum_length, extra }) => ({ + column_name, + column_default, + data_type, + data_type_params: data_type_params || undefined, + isExcluded: excluded_fields?.includes(column_name) || false, + isSearched: search_fields?.includes(column_name) || false, + auto_increment: checkFieldAutoincrement(column_default, extra), + allow_null, + character_maximum_length, + }), + ); } diff --git a/backend/test/ava-tests/saas-tests/table-postgres-e2e.test.ts b/backend/test/ava-tests/saas-tests/table-postgres-e2e.test.ts index b0ace8a89..046e738e8 100644 --- a/backend/test/ava-tests/saas-tests/table-postgres-e2e.test.ts +++ b/backend/test/ava-tests/saas-tests/table-postgres-e2e.test.ts @@ -26,6 +26,8 @@ import { getTestData } from '../../utils/get-test-data.js'; import { registerUserAndReturnUserInfo } from '../../utils/register-user-and-return-user-info.js'; import { TestUtils } from '../../utils/test.utils.js'; import { WinstonLogger } from '../../../src/entities/logging/winston-logger.js'; +import { getTestKnex } from '../../utils/get-test-knex.js'; +import { getRandomTestTableName } from '../../utils/get-random-test-table-name.js'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); @@ -225,6 +227,56 @@ test.serial(`${currentTest} should return rows of selected table without search } }); +test.serial(`${currentTest} should return rows of selected table with generated as identity primary key`, async (t) => { + try { + const connectionToTestDB = getTestData(mockFactory).connectionToPostgres; + const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; + const testTableName = getRandomTestTableName().toLowerCase(); + const testTableColumnName = `${faker.lorem.words(1)}_${faker.lorem.words(1)}`; + const testTableSecondColumnName = `${faker.lorem.words(1)}_${faker.lorem.words(1)}`; + + const Knex = getTestKnex(connectionToTestDB); + + // await Knex.schema.dropTableIfExists(testTableName); + await Knex.schema.createTable(testTableName, (table) => { + table.integer('id').primary(); + table.string(testTableColumnName); + table.string(testTableSecondColumnName); + table.timestamps(); + }); + + await Knex.raw(`ALTER TABLE ${testTableName} ALTER COLUMN id ADD GENERATED BY DEFAULT AS IDENTITY`); + + 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 getTableRowsResponse = await request(app.getHttpServer()) + .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}`) + .set('Cookie', firstUserToken) + .set('Content-Type', 'application/json') + .set('Accept', 'application/json'); + t.is(getTableRowsResponse.status, 200); + + const getTableRowsRO = JSON.parse(getTableRowsResponse.text); + console.log('🚀 ~ getTableRowsRO:', getTableRowsRO); + + t.is(typeof getTableRowsRO, 'object'); + t.is(getTableRowsRO.hasOwnProperty('rows'), true); + t.is(getTableRowsRO.hasOwnProperty('primaryColumns'), true); + t.is(getTableRowsRO.hasOwnProperty('pagination'), true); + t.is(getTableRowsRO.hasOwnProperty('large_dataset'), true); + } catch (e) { + console.error(e); + throw e; + } +}); + test.serial(`${currentTest} should return rows of selected table with search and without pagination`, async (t) => { try { const connectionToTestDB = getTestData(mockFactory).connectionToPostgres; diff --git a/shared-code/src/data-access-layer/data-access-objects/data-access-object-postgres.ts b/shared-code/src/data-access-layer/data-access-objects/data-access-object-postgres.ts index 1d6af3aa7..5eddf4edb 100644 --- a/shared-code/src/data-access-layer/data-access-objects/data-access-object-postgres.ts +++ b/shared-code/src/data-access-layer/data-access-objects/data-access-object-postgres.ts @@ -350,19 +350,30 @@ export class DataAccessObjectPostgres extends BasicDataAccessObject implements I } const knex = await this.configureKnex(); let result = await knex('information_schema.columns') - .select('column_name', 'column_default', 'data_type', 'udt_name', 'is_nullable', 'character_maximum_length') + .select( + 'column_name', + 'column_default', + 'data_type', + 'udt_name', + 'is_nullable', + 'character_maximum_length', + 'is_identity', + 'identity_generation', + ) .orderBy('dtd_identifier') .where(`table_name`, tableName) .andWhere('table_schema', this.connection.schema ? this.connection.schema : 'public'); + const generatedIdentities: Array = ['BY DEFAULT', 'ALWAYS']; const customTypeIndexes: Array = []; result = result.map((element, i) => { - const { is_nullable, data_type } = element; + const { is_nullable, data_type, identity_generation } = element; element.allow_null = is_nullable === 'YES'; delete element.is_nullable; if (data_type === 'USER-DEFINED') { customTypeIndexes.push(i); } + element.extra = generatedIdentities.includes(identity_generation) ? 'auto_increment' : undefined; return element; });