Skip to content

Commit 5030b34

Browse files
#RI-4661 - resolve comments
1 parent 91635df commit 5030b34

File tree

5 files changed

+58
-60
lines changed

5 files changed

+58
-60
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { MigrationInterface, QueryRunner } from "typeorm";
2+
3+
export class DatabaseRecommendationUnique1687435940110 implements MigrationInterface {
4+
name = 'DatabaseRecommendationUnique1687435940110'
5+
6+
public async up(queryRunner: QueryRunner): Promise<void> {
7+
await queryRunner.query(`DROP INDEX "IDX_2487bdd9dbde3fdf65bcb96fc5"`);
8+
await queryRunner.query(`DROP INDEX "IDX_d6107e5e16648b038c511f3b00"`);
9+
await queryRunner.query(`CREATE TABLE "temporary_database_recommendations" ("id" varchar PRIMARY KEY NOT NULL, "databaseId" varchar NOT NULL, "name" varchar NOT NULL, "read" boolean NOT NULL DEFAULT (0), "disabled" boolean NOT NULL DEFAULT (0), "vote" varchar, "hide" boolean NOT NULL DEFAULT (0), "createdAt" datetime NOT NULL DEFAULT (datetime('now')), "params" blob, "encryption" varchar, CONSTRAINT "UQ_b772d2856a42685ce4227321251" UNIQUE ("databaseId", "name"), CONSTRAINT "FK_2487bdd9dbde3fdf65bcb96fc52" FOREIGN KEY ("databaseId") REFERENCES "database_instance" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`);
10+
await queryRunner.query(`INSERT OR IGNORE INTO "temporary_database_recommendations"("id", "databaseId", "name", "read", "disabled", "vote", "hide", "createdAt", "params", "encryption") SELECT "id", "databaseId", "name", "read", "disabled", "vote", "hide", "createdAt", "params", "encryption" FROM "database_recommendations"`);
11+
await queryRunner.query(`DROP TABLE "database_recommendations"`);
12+
await queryRunner.query(`ALTER TABLE "temporary_database_recommendations" RENAME TO "database_recommendations"`);
13+
await queryRunner.query(`CREATE INDEX "IDX_2487bdd9dbde3fdf65bcb96fc5" ON "database_recommendations" ("databaseId") `);
14+
await queryRunner.query(`CREATE INDEX "IDX_d6107e5e16648b038c511f3b00" ON "database_recommendations" ("createdAt") `);
15+
}
16+
17+
public async down(queryRunner: QueryRunner): Promise<void> {
18+
await queryRunner.query(`DROP INDEX "IDX_d6107e5e16648b038c511f3b00"`);
19+
await queryRunner.query(`DROP INDEX "IDX_2487bdd9dbde3fdf65bcb96fc5"`);
20+
await queryRunner.query(`ALTER TABLE "database_recommendations" RENAME TO "temporary_database_recommendations"`);
21+
await queryRunner.query(`CREATE TABLE "database_recommendations" ("id" varchar PRIMARY KEY NOT NULL, "databaseId" varchar NOT NULL, "name" varchar NOT NULL, "read" boolean NOT NULL DEFAULT (0), "disabled" boolean NOT NULL DEFAULT (0), "vote" varchar, "hide" boolean NOT NULL DEFAULT (0), "createdAt" datetime NOT NULL DEFAULT (datetime('now')), "params" blob, "encryption" varchar, CONSTRAINT "FK_2487bdd9dbde3fdf65bcb96fc52" FOREIGN KEY ("databaseId") REFERENCES "database_instance" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`);
22+
await queryRunner.query(`INSERT INTO "database_recommendations"("id", "databaseId", "name", "read", "disabled", "vote", "hide", "createdAt", "params", "encryption") SELECT "id", "databaseId", "name", "read", "disabled", "vote", "hide", "createdAt", "params", "encryption" FROM "temporary_database_recommendations"`);
23+
await queryRunner.query(`DROP TABLE "temporary_database_recommendations"`);
24+
await queryRunner.query(`CREATE INDEX "IDX_d6107e5e16648b038c511f3b00" ON "database_recommendations" ("createdAt") `);
25+
await queryRunner.query(`CREATE INDEX "IDX_2487bdd9dbde3fdf65bcb96fc5" ON "database_recommendations" ("databaseId") `);
26+
}
27+
28+
}

redisinsight/api/migration/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import { databaseRecommendations1681900503586 } from './1681900503586-database-r
3333
import { databaseRecommendationParams1683006064293 } from './1683006064293-database-recommendation-params';
3434
import { Feature1684931530343 } from './1684931530343-feature';
3535
import { DatabaseRedisServer1686719451753 } from './1686719451753-database-redis-server';
36+
import { DatabaseRecommendationUnique1687435940110 } from './1687435940110-database-recommendation-unique';
3637

3738
export default [
3839
initialMigration1614164490968,
@@ -70,4 +71,5 @@ export default [
7071
databaseRecommendationParams1683006064293,
7172
Feature1684931530343,
7273
DatabaseRedisServer1686719451753,
74+
DatabaseRecommendationUnique1687435940110,
7375
];

redisinsight/api/src/modules/database-recommendation/entities/database-recommendation.entity.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import {
2-
Column, CreateDateColumn, Entity, ManyToOne, PrimaryGeneratedColumn, JoinColumn, Index,
2+
Column, CreateDateColumn, Entity, ManyToOne, PrimaryGeneratedColumn, JoinColumn, Index, Unique,
33
} from 'typeorm';
44
import { Expose } from 'class-transformer';
55
import { DataAsJsonString } from 'src/common/decorators';
66
import { DatabaseEntity } from 'src/modules/database/entities/database.entity';
77

88
@Entity('database_recommendations')
9+
@Unique(['databaseId', 'name'])
910
export class DatabaseRecommendationEntity {
1011
@PrimaryGeneratedColumn('uuid')
1112
@Expose()

redisinsight/api/src/modules/database-recommendation/repositories/local.database.recommendation.repository.spec.ts

Lines changed: 13 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { when } from 'jest-when';
2-
import { pick } from 'lodash';
32
import { InternalServerErrorException } from '@nestjs/common';
43
import { Test, TestingModule } from '@nestjs/testing';
54
import { getRepositoryToken } from '@nestjs/typeorm';
@@ -53,11 +52,11 @@ describe('LocalDatabaseRecommendationRepository', () => {
5352
repository.update.mockResolvedValue(mockDatabaseRecommendationEntity);
5453

5554
when(encryptionService.encrypt)
56-
.calledWith(JSON.stringify(mockDatabaseRecommendation.params))
57-
.mockReturnValue({
58-
encryption: mockDatabaseRecommendationEntity.encryption,
59-
data: mockDatabaseRecommendationEntity.params,
60-
});
55+
.calledWith(JSON.stringify(mockDatabaseRecommendation.params))
56+
.mockReturnValue({
57+
encryption: mockDatabaseRecommendationEntity.encryption,
58+
data: mockDatabaseRecommendationEntity.params,
59+
});
6160
when(encryptionService.decrypt)
6261
.calledWith(mockDatabaseRecommendationEntity.params, jasmine.anything())
6362
.mockReturnValue(JSON.stringify(mockDatabaseRecommendation.params));
@@ -81,16 +80,17 @@ describe('LocalDatabaseRecommendationRepository', () => {
8180

8281
describe('create', () => {
8382
it('should create recommendation', async () => {
84-
service.cleanupDatabaseRecommendations = jest
85-
.fn()
86-
.mockResolvedValue(undefined);
87-
8883
const result = await service.create(mockDatabaseRecommendation);
8984

9085
expect(result).toEqual(mockDatabaseRecommendation);
91-
expect(service.cleanupDatabaseRecommendations).toHaveBeenCalledWith(
92-
mockDatabaseRecommendation.databaseId
93-
);
86+
});
87+
88+
it('should not create recommendation', async () => {
89+
repository.save.mockRejectedValueOnce(new Error());
90+
91+
const result = await service.create(mockDatabaseRecommendation);
92+
93+
expect(result).toEqual(null);
9494
});
9595
});
9696

@@ -113,15 +113,4 @@ describe('LocalDatabaseRecommendationRepository', () => {
113113
}
114114
});
115115
});
116-
117-
describe('cleanupDatabaseRecommendations', () => {
118-
it('Should not return anything on cleanup', async () => {
119-
repository.createQueryBuilder().getRawMany.mockResolvedValueOnce([
120-
{ id: mockDatabaseRecommendationEntity.id },
121-
{ id: mockDatabaseRecommendationEntity.id },
122-
]);
123-
124-
expect(await service.cleanupDatabaseRecommendations(mockDatabaseRecommendationEntity.databaseId)).toEqual(undefined);
125-
});
126-
});
127116
});

redisinsight/api/src/modules/database-recommendation/repositories/local.database.recommendation.repository.ts

Lines changed: 13 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -46,24 +46,23 @@ export class LocalDatabaseRecommendationRepository extends DatabaseRecommendatio
4646
async create(entity: DatabaseRecommendation): Promise<DatabaseRecommendation> {
4747
this.logger.log('Creating database recommendation');
4848

49-
const model = await this.repository.save(
50-
await this.modelEncryptor.encryptEntity(plainToClass(DatabaseRecommendationEntity, entity)),
51-
);
52-
// cleanup recommendations and ignore error if any
5349
try {
54-
await this.cleanupDatabaseRecommendations(entity.databaseId);
55-
} catch (e) {
56-
this.logger.error('Error when trying to cleanup recommendations after insert', e);
57-
}
50+
const model = await this.repository.save(
51+
await this.modelEncryptor.encryptEntity(plainToClass(DatabaseRecommendationEntity, entity)),
52+
);
5853

59-
const recommendation = classToClass(
60-
DatabaseRecommendation,
61-
await this.modelEncryptor.decryptEntity(model, true),
62-
);
63-
this.eventEmitter.emit(RecommendationEvents.NewRecommendation, [recommendation]);
54+
const recommendation = classToClass(
55+
DatabaseRecommendation,
56+
await this.modelEncryptor.decryptEntity(model, true),
57+
);
58+
this.eventEmitter.emit(RecommendationEvents.NewRecommendation, [recommendation]);
6459

65-
return recommendation;
60+
return recommendation;
61+
} catch (err) {
62+
this.logger.error(`Failed to create database recommendation, ${err}`);
6663

64+
return null;
65+
}
6766
}
6867

6968
/**
@@ -233,25 +232,4 @@ export class LocalDatabaseRecommendationRepository extends DatabaseRecommendatio
233232
throw new InternalServerErrorException(error.message);
234233
}
235234
}
236-
237-
/**
238-
* Remove duplicates for particular database
239-
* @param databaseId
240-
*/
241-
async cleanupDatabaseRecommendations(databaseId: string): Promise<void> {
242-
// todo: investigate why delete with sub-query doesn't works
243-
const idsDuplicates = (await this.repository
244-
.createQueryBuilder()
245-
.where({ databaseId })
246-
.select('id')
247-
.groupBy('name')
248-
.having('COUNT(name) > 1')
249-
.getRawMany()).map((item) => item.id);
250-
251-
await this.repository
252-
.createQueryBuilder()
253-
.delete()
254-
.whereInIds(idsDuplicates)
255-
.execute();
256-
}
257235
}

0 commit comments

Comments
 (0)