Skip to content

Commit 096db2b

Browse files
authored
Merge pull request #1255 from RedisInsight/feature/RI-2586_database_analysis
Feature/ri 2586 database analysis
2 parents b38a31a + 719c21b commit 096db2b

File tree

216 files changed

+7839
-218
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

216 files changed

+7839
-218
lines changed

redisinsight/api/config/default.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,9 @@ export default {
140140
unsupportedCommands: JSON.parse(process.env.WORKBENCH_UNSUPPORTED_COMMANDS || '[]'),
141141
countBatch: parseInt(process.env.WORKBENCH_BATCH_SIZE, 10) || 5,
142142
},
143+
database_analysis: {
144+
maxItemsPerDb: parseInt(process.env.DATABASE_ANALYSIS_MAX_ITEMS_PER_DB, 10) || 5,
145+
},
143146
commands: [
144147
{
145148
name: 'main',

redisinsight/api/config/ormconfig.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,14 @@ import { SettingsEntity } from 'src/modules/core/models/settings.entity';
88
import { CommandExecutionEntity } from 'src/modules/workbench/entities/command-execution.entity';
99
import { PluginStateEntity } from 'src/modules/workbench/entities/plugin-state.entity';
1010
import { NotificationEntity } from 'src/modules/notification/entities/notification.entity';
11+
import { DatabaseAnalysisEntity } from 'src/modules/database-analysis/entities/database-analysis.entity';
12+
import { DataSource } from 'typeorm';
1113
import migrations from '../migration';
1214
import * as config from '../src/utils/config';
1315

1416
const dbConfig = config.get('db');
15-
const ormConfig: TypeOrmModuleOptions = {
17+
18+
const ormConfig = {
1619
type: 'sqlite',
1720
database: dbConfig.database,
1821
synchronize: dbConfig.synchronize,
@@ -27,8 +30,10 @@ const ormConfig: TypeOrmModuleOptions = {
2730
CommandExecutionEntity,
2831
PluginStateEntity,
2932
NotificationEntity,
33+
DatabaseAnalysisEntity,
3034
],
3135
migrations,
3236
};
3337

34-
export default ormConfig;
38+
export const ormModuleOptions: TypeOrmModuleOptions = ormConfig as TypeOrmModuleOptions;
39+
export default new DataSource({ ...ormConfig, type: 'sqlite' });
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { MigrationInterface, QueryRunner } from "typeorm";
2+
3+
export class databaseAnalysis1664785208236 implements MigrationInterface {
4+
name = 'databaseAnalysis1664785208236'
5+
6+
public async up(queryRunner: QueryRunner): Promise<void> {
7+
await queryRunner.query(`CREATE TABLE "database_analysis" ("id" varchar PRIMARY KEY NOT NULL, "databaseId" varchar NOT NULL, "filter" blob, "delimiter" varchar NOT NULL, "progress" blob, "totalKeys" blob, "totalMemory" blob, "topKeysNsp" blob, "topMemoryNsp" blob, "topKeysLength" blob, "topKeysMemory" blob, "encryption" varchar, "createdAt" datetime NOT NULL DEFAULT (datetime('now')))`);
8+
await queryRunner.query(`CREATE INDEX "IDX_d174a8edc2201d6c5781f0126a" ON "database_analysis" ("databaseId") `);
9+
await queryRunner.query(`CREATE INDEX "IDX_fdd0daeb4d8f226cf1ff79bebb" ON "database_analysis" ("createdAt") `);
10+
await queryRunner.query(`DROP INDEX "IDX_d174a8edc2201d6c5781f0126a"`);
11+
await queryRunner.query(`DROP INDEX "IDX_fdd0daeb4d8f226cf1ff79bebb"`);
12+
await queryRunner.query(`CREATE TABLE "temporary_database_analysis" ("id" varchar PRIMARY KEY NOT NULL, "databaseId" varchar NOT NULL, "filter" blob, "delimiter" varchar NOT NULL, "progress" blob, "totalKeys" blob, "totalMemory" blob, "topKeysNsp" blob, "topMemoryNsp" blob, "topKeysLength" blob, "topKeysMemory" blob, "encryption" varchar, "createdAt" datetime NOT NULL DEFAULT (datetime('now')), CONSTRAINT "FK_d174a8edc2201d6c5781f0126ae" FOREIGN KEY ("databaseId") REFERENCES "database_instance" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`);
13+
await queryRunner.query(`INSERT INTO "temporary_database_analysis"("id", "databaseId", "filter", "delimiter", "progress", "totalKeys", "totalMemory", "topKeysNsp", "topMemoryNsp", "topKeysLength", "topKeysMemory", "encryption", "createdAt") SELECT "id", "databaseId", "filter", "delimiter", "progress", "totalKeys", "totalMemory", "topKeysNsp", "topMemoryNsp", "topKeysLength", "topKeysMemory", "encryption", "createdAt" FROM "database_analysis"`);
14+
await queryRunner.query(`DROP TABLE "database_analysis"`);
15+
await queryRunner.query(`ALTER TABLE "temporary_database_analysis" RENAME TO "database_analysis"`);
16+
await queryRunner.query(`CREATE INDEX "IDX_d174a8edc2201d6c5781f0126a" ON "database_analysis" ("databaseId") `);
17+
await queryRunner.query(`CREATE INDEX "IDX_fdd0daeb4d8f226cf1ff79bebb" ON "database_analysis" ("createdAt") `);
18+
}
19+
20+
public async down(queryRunner: QueryRunner): Promise<void> {
21+
await queryRunner.query(`DROP INDEX "IDX_fdd0daeb4d8f226cf1ff79bebb"`);
22+
await queryRunner.query(`DROP INDEX "IDX_d174a8edc2201d6c5781f0126a"`);
23+
await queryRunner.query(`ALTER TABLE "database_analysis" RENAME TO "temporary_database_analysis"`);
24+
await queryRunner.query(`CREATE TABLE "database_analysis" ("id" varchar PRIMARY KEY NOT NULL, "databaseId" varchar NOT NULL, "filter" blob, "delimiter" varchar NOT NULL, "progress" blob, "totalKeys" blob, "totalMemory" blob, "topKeysNsp" blob, "topMemoryNsp" blob, "topKeysLength" blob, "topKeysMemory" blob, "encryption" varchar, "createdAt" datetime NOT NULL DEFAULT (datetime('now')))`);
25+
await queryRunner.query(`INSERT INTO "database_analysis"("id", "databaseId", "filter", "delimiter", "progress", "totalKeys", "totalMemory", "topKeysNsp", "topMemoryNsp", "topKeysLength", "topKeysMemory", "encryption", "createdAt") SELECT "id", "databaseId", "filter", "delimiter", "progress", "totalKeys", "totalMemory", "topKeysNsp", "topMemoryNsp", "topKeysLength", "topKeysMemory", "encryption", "createdAt" FROM "temporary_database_analysis"`);
26+
await queryRunner.query(`DROP TABLE "temporary_database_analysis"`);
27+
await queryRunner.query(`CREATE INDEX "IDX_fdd0daeb4d8f226cf1ff79bebb" ON "database_analysis" ("createdAt") `);
28+
await queryRunner.query(`CREATE INDEX "IDX_d174a8edc2201d6c5781f0126a" ON "database_analysis" ("databaseId") `);
29+
await queryRunner.query(`DROP INDEX "IDX_fdd0daeb4d8f226cf1ff79bebb"`);
30+
await queryRunner.query(`DROP INDEX "IDX_d174a8edc2201d6c5781f0126a"`);
31+
await queryRunner.query(`DROP TABLE "database_analysis"`);
32+
}
33+
34+
}
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 databaseAnalysisExpirationGroups1664886479051 implements MigrationInterface {
4+
name = 'databaseAnalysisExpirationGroups1664886479051'
5+
6+
public async up(queryRunner: QueryRunner): Promise<void> {
7+
await queryRunner.query(`DROP INDEX "IDX_fdd0daeb4d8f226cf1ff79bebb"`);
8+
await queryRunner.query(`DROP INDEX "IDX_d174a8edc2201d6c5781f0126a"`);
9+
await queryRunner.query(`CREATE TABLE "temporary_database_analysis" ("id" varchar PRIMARY KEY NOT NULL, "databaseId" varchar NOT NULL, "filter" blob, "delimiter" varchar NOT NULL, "progress" blob, "totalKeys" blob, "totalMemory" blob, "topKeysNsp" blob, "topMemoryNsp" blob, "topKeysLength" blob, "topKeysMemory" blob, "encryption" varchar, "createdAt" datetime NOT NULL DEFAULT (datetime('now')), "expirationGroups" blob, CONSTRAINT "FK_d174a8edc2201d6c5781f0126ae" FOREIGN KEY ("databaseId") REFERENCES "database_instance" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`);
10+
await queryRunner.query(`INSERT INTO "temporary_database_analysis"("id", "databaseId", "filter", "delimiter", "progress", "totalKeys", "totalMemory", "topKeysNsp", "topMemoryNsp", "topKeysLength", "topKeysMemory", "encryption", "createdAt") SELECT "id", "databaseId", "filter", "delimiter", "progress", "totalKeys", "totalMemory", "topKeysNsp", "topMemoryNsp", "topKeysLength", "topKeysMemory", "encryption", "createdAt" FROM "database_analysis"`);
11+
await queryRunner.query(`DROP TABLE "database_analysis"`);
12+
await queryRunner.query(`ALTER TABLE "temporary_database_analysis" RENAME TO "database_analysis"`);
13+
await queryRunner.query(`CREATE INDEX "IDX_fdd0daeb4d8f226cf1ff79bebb" ON "database_analysis" ("createdAt") `);
14+
await queryRunner.query(`CREATE INDEX "IDX_d174a8edc2201d6c5781f0126a" ON "database_analysis" ("databaseId") `);
15+
}
16+
17+
public async down(queryRunner: QueryRunner): Promise<void> {
18+
await queryRunner.query(`DROP INDEX "IDX_d174a8edc2201d6c5781f0126a"`);
19+
await queryRunner.query(`DROP INDEX "IDX_fdd0daeb4d8f226cf1ff79bebb"`);
20+
await queryRunner.query(`ALTER TABLE "database_analysis" RENAME TO "temporary_database_analysis"`);
21+
await queryRunner.query(`CREATE TABLE "database_analysis" ("id" varchar PRIMARY KEY NOT NULL, "databaseId" varchar NOT NULL, "filter" blob, "delimiter" varchar NOT NULL, "progress" blob, "totalKeys" blob, "totalMemory" blob, "topKeysNsp" blob, "topMemoryNsp" blob, "topKeysLength" blob, "topKeysMemory" blob, "encryption" varchar, "createdAt" datetime NOT NULL DEFAULT (datetime('now')), CONSTRAINT "FK_d174a8edc2201d6c5781f0126ae" FOREIGN KEY ("databaseId") REFERENCES "database_instance" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`);
22+
await queryRunner.query(`INSERT INTO "database_analysis"("id", "databaseId", "filter", "delimiter", "progress", "totalKeys", "totalMemory", "topKeysNsp", "topMemoryNsp", "topKeysLength", "topKeysMemory", "encryption", "createdAt") SELECT "id", "databaseId", "filter", "delimiter", "progress", "totalKeys", "totalMemory", "topKeysNsp", "topMemoryNsp", "topKeysLength", "topKeysMemory", "encryption", "createdAt" FROM "temporary_database_analysis"`);
23+
await queryRunner.query(`DROP TABLE "temporary_database_analysis"`);
24+
await queryRunner.query(`CREATE INDEX "IDX_d174a8edc2201d6c5781f0126a" ON "database_analysis" ("databaseId") `);
25+
await queryRunner.query(`CREATE INDEX "IDX_fdd0daeb4d8f226cf1ff79bebb" ON "database_analysis" ("createdAt") `);
26+
}
27+
28+
}

redisinsight/api/migration/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import { notification1655821010349 } from './1655821010349-notification';
1717
import { notificationCategory1659687030433 } from './1659687030433-notification-category';
1818
import { workbenchMode1660664717573 } from './1660664717573-workbench-mode';
1919
import { workbenchGroupMode1663093411715 } from './1663093411715-workbench-group-mode';
20+
import { databaseAnalysis1664785208236 } from './1664785208236-database-analysis';
21+
import { databaseAnalysisExpirationGroups1664886479051 } from './1664886479051-database-analysis-expiration-groups';
2022

2123
export default [
2224
initialMigration1614164490968,
@@ -38,4 +40,6 @@ export default [
3840
notificationCategory1659687030433,
3941
workbenchMode1660664717573,
4042
workbenchGroupMode1663093411715,
43+
databaseAnalysis1664785208236,
44+
databaseAnalysisExpirationGroups1664886479051,
4145
];

redisinsight/api/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,11 @@
3030
"test:cov": "cross-env NODE_ENV=test ./node_modules/.bin/jest --coverage -w 1",
3131
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand -w 1",
3232
"test:e2e": "jest --config ./test/jest-e2e.json -w 1",
33-
"typeorm": "ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js --config ./config/ormconfig.ts",
33+
"typeorm": "ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js -d ./config/ormconfig.ts",
3434
"test:api": "ts-mocha --paths -p test/api/api.tsconfig.json --config ./test/api/.mocharc.yml",
3535
"test:api:cov": "nyc --reporter=html --reporter=text --reporter=text-summary yarn run test:api",
36-
"test:api:ci:cov": "nyc -r text -r text-summary yarn run test:api --reporter mocha-multi-reporters --reporter-options configFile=test/api/reporters.json && nyc merge .nyc_output ./coverage/test-run-coverage.json",
37-
"typeorm:migrate": "cross-env NODE_ENV=production yarn typeorm migration:generate -- -n migration",
36+
"test:api:ci:cov": "nyc -r text -r text-summary -r html yarn run test:api --reporter mocha-multi-reporters --reporter-options configFile=test/api/reporters.json && nyc merge .nyc_output ./coverage/test-run-coverage.json",
37+
"typeorm:migrate": "cross-env NODE_ENV=production yarn typeorm migration:generate ./migration/migration",
3838
"typeorm:run": "yarn typeorm migration:run"
3939
},
4040
"dependencies": {

redisinsight/api/src/app.module.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { PubSubModule } from 'src/modules/pub-sub/pub-sub.module';
1616
import { NotificationModule } from 'src/modules/notification/notification.module';
1717
import { BulkActionsModule } from 'src/modules/bulk-actions/bulk-actions.module';
1818
import { ClusterMonitorModule } from 'src/modules/cluster-monitor/cluster-monitor.module';
19+
import { DatabaseAnalysisModule } from 'src/modules/database-analysis/database-analysis.module';
1920
import { SharedModule } from './modules/shared/shared.module';
2021
import { InstancesModule } from './modules/instances/instances.module';
2122
import { BrowserModule } from './modules/browser/browser.module';
@@ -28,14 +29,14 @@ import { SettingsController } from './controllers/settings.controller';
2829
import { ServerInfoController } from './controllers/server-info.controller';
2930
import { ExcludeRouteMiddleware } from './middleware/exclude-route.middleware';
3031
import { routes } from './app.routes';
31-
import ormConfig from '../config/ormconfig';
32+
import { ormModuleOptions } from '../config/ormconfig';
3233

3334
const SERVER_CONFIG = config.get('server');
3435
const PATH_CONFIG = config.get('dir_path');
3536

3637
@Module({
3738
imports: [
38-
TypeOrmModule.forRoot(ormConfig),
39+
TypeOrmModule.forRoot(ormModuleOptions),
3940
RouterModule.forRoutes(routes),
4041
SharedModule,
4142
InstancesModule,
@@ -52,6 +53,7 @@ const PATH_CONFIG = config.get('dir_path');
5253
NotificationModule,
5354
BulkActionsModule,
5455
ClusterMonitorModule,
56+
DatabaseAnalysisModule,
5557
EventEmitterModule.forRoot(),
5658
...(SERVER_CONFIG.staticContent
5759
? [

redisinsight/api/src/app.routes.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { WorkbenchModule } from 'src/modules/workbench/workbench.module';
88
import { SlowLogModule } from 'src/modules/slow-log/slow-log.module';
99
import { PubSubModule } from 'src/modules/pub-sub/pub-sub.module';
1010
import { ClusterMonitorModule } from 'src/modules/cluster-monitor/cluster-monitor.module';
11+
import { DatabaseAnalysisModule } from 'src/modules/database-analysis/database-analysis.module';
1112

1213
export const routes: Routes = [
1314
{
@@ -38,6 +39,10 @@ export const routes: Routes = [
3839
path: '/:dbInstance',
3940
module: ClusterMonitorModule,
4041
},
42+
{
43+
path: '/:dbInstance',
44+
module: DatabaseAnalysisModule,
45+
},
4146
],
4247
},
4348
{

redisinsight/api/src/constants/error-messages.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
export default {
33
INVALID_DATABASE_INSTANCE_ID: 'Invalid database instance id.',
44
COMMAND_EXECUTION_NOT_FOUND: 'Command execution was not found.',
5+
DATABASE_ANALYSIS_NOT_FOUND: 'Database analysis was not found.',
56
PROFILER_LOG_FILE_NOT_FOUND: 'Profiler log file was not found.',
67
CONSUMER_GROUP_NOT_FOUND: 'Consumer Group with such name was not found.',
78
PLUGIN_STATE_NOT_FOUND: 'Plugin state was not found.',

redisinsight/api/src/modules/browser/services/keys-business/key-info-manager/strategies/ts-type-info/ts-type-info.strategy.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ describe('TSTypeInfoStrategy', () => {
7878
],
7979
]);
8080
when(browserTool.execCommand)
81-
.calledWith(mockClientOptions, BrowserToolTSCommands.TSInfo, [key])
81+
.calledWith(mockClientOptions, BrowserToolTSCommands.TSInfo, [key], 'utf8')
8282
.mockResolvedValue(mockTSInfoReply);
8383
});
8484
it('should return appropriate value', async () => {
@@ -143,7 +143,7 @@ describe('TSTypeInfoStrategy', () => {
143143
message: "ERR unknown command 'ts.info'",
144144
};
145145
when(browserTool.execCommand)
146-
.calledWith(mockClientOptions, BrowserToolTSCommands.TSInfo, [key])
146+
.calledWith(mockClientOptions, BrowserToolTSCommands.TSInfo, [key], 'utf8')
147147
.mockResolvedValue(replyError);
148148

149149
const result = await strategy.getInfo(

0 commit comments

Comments
 (0)