diff --git a/redisinsight/api/src/modules/feature/repositories/local.features-config.repository.spec.ts b/redisinsight/api/src/modules/feature/repositories/local.features-config.repository.spec.ts index 70a91c7cd1..75cf9d0cb7 100644 --- a/redisinsight/api/src/modules/feature/repositories/local.features-config.repository.spec.ts +++ b/redisinsight/api/src/modules/feature/repositories/local.features-config.repository.spec.ts @@ -6,7 +6,7 @@ import { mockFeaturesConfigEntity, mockRepository, MockType, -} from 'src/__mocks__'; +} from 'src/__mocks__' import { LocalFeaturesConfigRepository } from 'src/modules/feature/repositories/local.features-config.repository'; import { FeaturesConfigEntity } from 'src/modules/feature/entities/features-config.entity'; import { plainToClass } from 'class-transformer'; @@ -85,6 +85,21 @@ describe('LocalFeaturesConfigRepository', () => { expect(result).toEqual(mockFeaturesConfig); }); + it('should fail to create with unique constraint and return existing', async () => { + repository.findOneBy.mockResolvedValueOnce(null); + repository.findOneBy.mockResolvedValueOnce(mockFeaturesConfig); + repository.save.mockRejectedValueOnce({ code: 'SQLITE_CONSTRAINT' }); + + const result = await service.getOrCreate(); + + expect(result).toEqual(mockFeaturesConfig); + }); + it('should fail when failed to create new and error is not unique constraint', async () => { + repository.findOneBy.mockResolvedValueOnce(null); + repository.save.mockRejectedValueOnce(new Error()); + + await expect(service.getOrCreate()).rejects.toThrow(Error); + }); }); describe('update', () => { diff --git a/redisinsight/api/src/modules/feature/repositories/local.features-config.repository.ts b/redisinsight/api/src/modules/feature/repositories/local.features-config.repository.ts index 98ce7a6926..93922d053c 100644 --- a/redisinsight/api/src/modules/feature/repositories/local.features-config.repository.ts +++ b/redisinsight/api/src/modules/feature/repositories/local.features-config.repository.ts @@ -43,13 +43,21 @@ export class LocalFeaturesConfigRepository extends FeaturesConfigRepository { let entity = await this.repository.findOneBy({ id: this.id }); if (!entity) { - this.logger.log('Creating features config entity'); + try { + this.logger.log('Creating features config entity'); - entity = await this.repository.save(plainToClass(FeaturesConfigEntity, { - id: this.id, - data: defaultConfig, - controlNumber: this.generateControlNumber(), - })); + entity = await this.repository.save(plainToClass(FeaturesConfigEntity, { + id: this.id, + data: defaultConfig, + controlNumber: this.generateControlNumber(), + })); + } catch (e) { + if (e.code === 'SQLITE_CONSTRAINT') { + return this.getOrCreate(); + } + + throw e; + } } return classToClass(FeaturesConfig, entity); diff --git a/redisinsight/api/src/modules/settings/repositories/local.agreements.repository.spec.ts b/redisinsight/api/src/modules/settings/repositories/local.agreements.repository.spec.ts index 3e70018593..b99d760a86 100644 --- a/redisinsight/api/src/modules/settings/repositories/local.agreements.repository.spec.ts +++ b/redisinsight/api/src/modules/settings/repositories/local.agreements.repository.spec.ts @@ -55,6 +55,21 @@ describe('LocalAgreementsRepository', () => { data: undefined, }); }); + it('should fail to create with unique constraint and return existing', async () => { + repository.findOneBy.mockResolvedValueOnce(null); + repository.findOneBy.mockResolvedValueOnce(mockAgreements); + repository.save.mockRejectedValueOnce({ code: 'SQLITE_CONSTRAINT' }); + + const result = await service.getOrCreate(); + + expect(result).toEqual(mockAgreements); + }); + it('should fail when failed to create new and error is not unique constraint', async () => { + repository.findOneBy.mockResolvedValueOnce(null); + repository.save.mockRejectedValueOnce(new Error()); + + await expect(service.getOrCreate()).rejects.toThrow(Error); + }); }); describe('update', () => { @@ -62,7 +77,7 @@ describe('LocalAgreementsRepository', () => { const result = await service.update(mockSessionMetadata, mockAgreements); expect(result).toEqual(mockAgreements); - expect(repository.update).toHaveBeenCalledWith({}, { + expect(repository.save).toHaveBeenCalledWith({ ...mockAgreementsEntity, }); }); diff --git a/redisinsight/api/src/modules/settings/repositories/local.agreements.repository.ts b/redisinsight/api/src/modules/settings/repositories/local.agreements.repository.ts index f16e1f5da2..68a2876423 100644 --- a/redisinsight/api/src/modules/settings/repositories/local.agreements.repository.ts +++ b/redisinsight/api/src/modules/settings/repositories/local.agreements.repository.ts @@ -18,14 +18,24 @@ export class LocalAgreementsRepository extends AgreementsRepository { let entity = await this.repository.findOneBy({}); if (!entity) { - entity = await this.repository.save(this.repository.create()); + try { + entity = await this.repository.save(this.repository.create({ id: 1 })); + } catch (e) { + if (e.code === 'SQLITE_CONSTRAINT') { + return this.getOrCreate(); + } + + throw e; + } } return classToClass(Agreements, entity); } async update(_: SessionMetadata, agreements: Agreements): Promise { - await this.repository.update({}, classToClass(AgreementsEntity, agreements)); + const entity = classToClass(AgreementsEntity, agreements); + + await this.repository.save(entity); return this.getOrCreate(); } diff --git a/redisinsight/api/src/modules/settings/repositories/local.settings.repository.spec.ts b/redisinsight/api/src/modules/settings/repositories/local.settings.repository.spec.ts index b0135e16c5..f995abf949 100644 --- a/redisinsight/api/src/modules/settings/repositories/local.settings.repository.spec.ts +++ b/redisinsight/api/src/modules/settings/repositories/local.settings.repository.spec.ts @@ -50,6 +50,21 @@ describe('LocalSettingsRepository', () => { data: undefined, }); }); + it('should fail to create with unique constraint and return existing', async () => { + repository.findOneBy.mockResolvedValueOnce(null); + repository.findOneBy.mockResolvedValueOnce(mockSettings); + repository.save.mockRejectedValueOnce({ code: 'SQLITE_CONSTRAINT' }); + + const result = await service.getOrCreate(); + + expect(result).toEqual(mockSettings); + }); + it('should fail when failed to create new and error is not unique constraint', async () => { + repository.findOneBy.mockResolvedValueOnce(null); + repository.save.mockRejectedValueOnce(new Error()); + + await expect(service.getOrCreate()).rejects.toThrow(Error); + }); }); describe('update', () => { @@ -57,9 +72,7 @@ describe('LocalSettingsRepository', () => { const result = await service.update(mockSessionMetadata, mockSettings); expect(result).toEqual(mockSettings); - expect(repository.update).toHaveBeenCalledWith({}, { - ...mockSettingsEntity, - }); + expect(repository.save).toHaveBeenCalledWith(mockSettingsEntity); }); }); }); diff --git a/redisinsight/api/src/modules/settings/repositories/local.settings.repository.ts b/redisinsight/api/src/modules/settings/repositories/local.settings.repository.ts index 48330e0b05..6786985d5a 100644 --- a/redisinsight/api/src/modules/settings/repositories/local.settings.repository.ts +++ b/redisinsight/api/src/modules/settings/repositories/local.settings.repository.ts @@ -18,14 +18,24 @@ export class LocalSettingsRepository extends SettingsRepository { let entity = await this.repository.findOneBy({}); if (!entity) { - entity = await this.repository.save(this.repository.create()); + try { + entity = await this.repository.save(this.repository.create({ id : 1 })); + } catch (e) { + if (e.code === 'SQLITE_CONSTRAINT') { + return this.getOrCreate(); + } + + throw e; + } } return classToClass(Settings, entity); } async update(_: SessionMetadata, settings: Settings): Promise { - await this.repository.update({}, classToClass(SettingsEntity, settings)); + const entity = classToClass(SettingsEntity, settings); + + await this.repository.save(entity); return this.getOrCreate(); }