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
Original file line number Diff line number Diff line change
Expand Up @@ -5,101 +5,122 @@ import { IGlobalDatabaseContext } from '../../../../common/application/global-da
import { BaseType } from '../../../../common/data-injection.tokens.js';
import { ConnectionEntity } from '../../../connection/connection.entity.js';
import {
CreatePersonalTableSettingsDs,
PersonalTableSettingsData,
CreatePersonalTableSettingsDs,
PersonalTableSettingsData,
} from '../data-structures/create-personal-table-settings.ds.js';
import { FoundPersonalTableSettingsDto } from '../dto/found-personal-table-settings.dto.js';
import { buildNewPersonalTableSettingsEntity } from '../utils/build-new-personal-table-settings-entity.util.js';
import { ICreateUpdatePersonalTableSettings } from './personal-table-settings.use-cases.interface.js';

@Injectable({ scope: Scope.REQUEST })
export class CreateUpdatePersonalTableSettingsUseCase
extends AbstractUseCase<CreatePersonalTableSettingsDs, FoundPersonalTableSettingsDto>
implements ICreateUpdatePersonalTableSettings
extends AbstractUseCase<CreatePersonalTableSettingsDs, FoundPersonalTableSettingsDto>
implements ICreateUpdatePersonalTableSettings
{
constructor(
@Inject(BaseType.GLOBAL_DB_CONTEXT)
protected _dbContext: IGlobalDatabaseContext,
) {
super();
}
constructor(
@Inject(BaseType.GLOBAL_DB_CONTEXT)
protected _dbContext: IGlobalDatabaseContext,
) {
super();
}

public async implementation(
personalTableSettingsData: CreatePersonalTableSettingsDs,
): Promise<FoundPersonalTableSettingsDto> {
const {
table_settings_metadata: { connection_id, master_password, table_name, user_id },
table_settings_data,
} = personalTableSettingsData;
public async implementation(
personalTableSettingsData: CreatePersonalTableSettingsDs,
): Promise<FoundPersonalTableSettingsDto> {
const {
table_settings_metadata: { connection_id, master_password, table_name, user_id },
table_settings_data,
} = personalTableSettingsData;

const foundConnection = await this._dbContext.connectionRepository.findAndDecryptConnection(
connection_id,
master_password,
);
const foundConnection = await this._dbContext.connectionRepository.findAndDecryptConnection(
connection_id,
master_password,
);

await this.validatePersonalTableSettingsData(table_settings_data, foundConnection, table_name);
await this.validatePersonalTableSettingsData(table_settings_data, foundConnection, table_name);

const foundTableSettings = await this._dbContext.personalTableSettingsRepository.findUserTableSettings(
user_id,
connection_id,
table_name,
);
const foundTableSettings = await this._dbContext.personalTableSettingsRepository.findUserTableSettings(
user_id,
connection_id,
table_name,
);

const settings = foundTableSettings || {};
const newSettingsEntity = buildNewPersonalTableSettingsEntity(table_settings_data);
newSettingsEntity.connection_id = foundConnection.id;
newSettingsEntity.table_name = table_name;
newSettingsEntity.user_id = user_id;
Object.assign(settings, newSettingsEntity);
return await this._dbContext.personalTableSettingsRepository.save(settings);
}
const newSettingsEntity = buildNewPersonalTableSettingsEntity(table_settings_data);

private async validatePersonalTableSettingsData(
settingsData: PersonalTableSettingsData,
connection: ConnectionEntity,
tableName: string,
): Promise<void> {
const { columns_view, list_fields, list_per_page, ordering, ordering_field } = settingsData;
const dao = getDataAccessObject(connection);
const tableStructure = await dao.getTableStructure(tableName, null);
const tableColumnNames = tableStructure.map((col) => col.column_name);
const errors = [];
if (foundTableSettings) {
if (newSettingsEntity.columns_view !== undefined) {
foundTableSettings.columns_view = newSettingsEntity.columns_view;
}
if (newSettingsEntity.list_fields !== undefined) {
foundTableSettings.list_fields = newSettingsEntity.list_fields;
}
if (newSettingsEntity.list_per_page !== undefined) {
foundTableSettings.list_per_page = newSettingsEntity.list_per_page;
}
if (newSettingsEntity.ordering !== undefined) {
foundTableSettings.ordering = newSettingsEntity.ordering;
}
if (newSettingsEntity.ordering_field !== undefined) {
foundTableSettings.ordering_field = newSettingsEntity.ordering_field;
}
if (newSettingsEntity.original_names !== undefined) {
foundTableSettings.original_names = newSettingsEntity.original_names;
}
Comment on lines +51 to +68
Copy link

Copilot AI Jan 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The explicit field-by-field update approach is verbose and not maintainable. Consider using a loop to iterate over the properties of newSettingsEntity instead of checking each field individually. This would make the code more maintainable and prevent issues if new fields are added in the future. For example, you could iterate over Object.keys(newSettingsEntity) and only assign properties that are not undefined.

Suggested change
if (newSettingsEntity.columns_view !== undefined) {
foundTableSettings.columns_view = newSettingsEntity.columns_view;
}
if (newSettingsEntity.list_fields !== undefined) {
foundTableSettings.list_fields = newSettingsEntity.list_fields;
}
if (newSettingsEntity.list_per_page !== undefined) {
foundTableSettings.list_per_page = newSettingsEntity.list_per_page;
}
if (newSettingsEntity.ordering !== undefined) {
foundTableSettings.ordering = newSettingsEntity.ordering;
}
if (newSettingsEntity.ordering_field !== undefined) {
foundTableSettings.ordering_field = newSettingsEntity.ordering_field;
}
if (newSettingsEntity.original_names !== undefined) {
foundTableSettings.original_names = newSettingsEntity.original_names;
}
for (const key of Object.keys(newSettingsEntity) as (keyof typeof newSettingsEntity)[]) {
const value = newSettingsEntity[key];
if (value !== undefined) {
(foundTableSettings as any)[key] = value;
}
}

Copilot uses AI. Check for mistakes.
return await this._dbContext.personalTableSettingsRepository.save(foundTableSettings);
} else {
newSettingsEntity.connection_id = foundConnection.id;
newSettingsEntity.table_name = table_name;
newSettingsEntity.user_id = user_id;
return await this._dbContext.personalTableSettingsRepository.save(newSettingsEntity);
}
}

if (columns_view !== null && columns_view !== undefined) {
const invalidColumns = columns_view.filter((col) => !tableColumnNames.includes(col));
if (invalidColumns.length > 0) {
errors.push(`Invalid columns in columns_view: ${invalidColumns.join(', ')}`);
}
}
private async validatePersonalTableSettingsData(
settingsData: PersonalTableSettingsData,
connection: ConnectionEntity,
tableName: string,
): Promise<void> {
const { columns_view, list_fields, list_per_page, ordering, ordering_field } = settingsData;
const dao = getDataAccessObject(connection);
const tableStructure = await dao.getTableStructure(tableName, null);
const tableColumnNames = tableStructure.map((col) => col.column_name);
const errors = [];

if (list_fields !== null && list_fields !== undefined) {
const invalidFields = list_fields.filter((field) => !tableColumnNames.includes(field));
if (invalidFields.length > 0) {
errors.push(`Invalid columns in list_fields: ${invalidFields.join(', ')}`);
}
}
if (columns_view !== null && columns_view !== undefined) {
const invalidColumns = columns_view.filter((col) => !tableColumnNames.includes(col));
if (invalidColumns.length > 0) {
errors.push(`Invalid columns in columns_view: ${invalidColumns.join(', ')}`);
}
}

if (list_per_page !== null && list_per_page !== undefined) {
if (typeof list_per_page !== 'number' || list_per_page < 1 || list_per_page > 1000) {
errors.push('list_per_page must be a number between 1 and 1000');
}
}
if (list_fields !== null && list_fields !== undefined) {
const invalidFields = list_fields.filter((field) => !tableColumnNames.includes(field));
if (invalidFields.length > 0) {
errors.push(`Invalid columns in list_fields: ${invalidFields.join(', ')}`);
}
}

if (ordering !== null && ordering !== undefined) {
const validOrderings = ['ASC', 'DESC'];
if (!validOrderings.includes(ordering)) {
errors.push(`ordering must be one of: ${validOrderings.join(', ')}`);
}
}
if (list_per_page !== null && list_per_page !== undefined) {
if (typeof list_per_page !== 'number' || list_per_page < 1 || list_per_page > 1000) {
errors.push('list_per_page must be a number between 1 and 1000');
}
}

if (ordering_field !== null && ordering_field !== undefined) {
if (!tableColumnNames.includes(ordering_field)) {
errors.push(`Invalid ordering_field: ${ordering_field}`);
}
}
if (ordering !== null && ordering !== undefined) {
const validOrderings = ['ASC', 'DESC'];
if (!validOrderings.includes(ordering)) {
errors.push(`ordering must be one of: ${validOrderings.join(', ')}`);
}
}

if (errors.length > 0) {
throw new BadRequestException(`Validation failed: ${errors.join('; ')}`);
}
}
if (ordering_field !== null && ordering_field !== undefined) {
if (!tableColumnNames.includes(ordering_field)) {
errors.push(`Invalid ordering_field: ${ordering_field}`);
}
}

if (errors.length > 0) {
throw new BadRequestException(`Validation failed: ${errors.join('; ')}`);
}
}
}
Loading
Loading