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 @@ -3,17 +3,22 @@ import {
Controller,
Get, HttpCode,
Param,
Post, Query,
Post,
} from '@nestjs/common';
import {
ApiBody,
ApiOkResponse,
ApiOperation,
ApiTags,
} from '@nestjs/swagger';
import { ApiRedisParams } from 'src/decorators/api-redis-params.decorator';
import { ApiQueryRedisStringEncoding } from 'src/common/decorators';
import { BaseController } from 'src/modules/browser/controllers/base.controller';
import { CreateRedisearchIndexDto, SearchRedisearchDto } from 'src/modules/browser/dto/redisearch';
import {
CreateRedisearchIndexDto,
ListRedisearchIndexesResponse,
SearchRedisearchDto,
} from 'src/modules/browser/dto/redisearch';
import { RedisearchService } from 'src/modules/browser/services/redisearch/redisearch.service';
import { GetKeysWithDetailsResponse } from 'src/modules/browser/dto';

Expand All @@ -26,12 +31,13 @@ export class RedisearchController extends BaseController {

@Get('')
@ApiOperation({ description: 'Get list of available indexes' })
@ApiOkResponse({ type: ListRedisearchIndexesResponse })
@ApiRedisParams()
@ApiQueryRedisStringEncoding()
async list(
@Param('dbInstance') dbInstance: string,
): Promise<string[]> {
return await this.service.list(
): Promise<ListRedisearchIndexesResponse> {
return this.service.list(
{
instanceId: dbInstance,
},
Expand All @@ -55,13 +61,14 @@ export class RedisearchController extends BaseController {
);
}

@Get('search')
@Post('search')
@ApiOperation({ description: 'Search for keys in index' })
@ApiOkResponse({ type: GetKeysWithDetailsResponse })
@ApiRedisParams()
@ApiQueryRedisStringEncoding()
async search(
@Param('dbInstance') dbInstance: string,
@Query() dto: SearchRedisearchDto,
@Body() dto: SearchRedisearchDto,
): Promise<GetKeysWithDetailsResponse> {
return await this.service.search(
{
Expand Down
41 changes: 27 additions & 14 deletions redisinsight/api/src/modules/browser/dto/redisearch.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { ApiProperty } from '@nestjs/swagger';
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import {
ArrayMinSize, IsDefined, IsEnum, IsInt, IsNotEmpty, IsString, ValidateNested
ArrayMinSize, IsDefined, IsEnum, IsInt, IsOptional, IsString, ValidateNested
} from 'class-validator';
import { Type } from 'class-transformer';
import { RedisString } from 'src/common/constants';
import { IsRedisString, RedisStringType } from 'src/common/decorators';

export enum RedisearchIndexKeyType {
HASH = 'hash',
Expand All @@ -17,14 +19,24 @@ export enum RedisearchIndexDataType {
VECTOR = 'vector',
}

export class ListRedisearchIndexesResponse {
@ApiProperty({
description: 'Indexes names',
type: String,
})
@RedisStringType({ each: true })
indexes: RedisString[];
}

export class CreateRedisearchIndexFieldDto {
@ApiProperty({
description: 'Name of field to be indexed',
type: String,
})
@IsDefined()
@IsString()
name: string;
@RedisStringType()
@IsRedisString()
name: RedisString;

@ApiProperty({
description: 'Type of how data must be indexed',
Expand All @@ -41,8 +53,9 @@ export class CreateRedisearchIndexDto {
type: String,
})
@IsDefined()
@IsString()
index: string;
@RedisStringType()
@IsRedisString()
index: RedisString;

@ApiProperty({
description: 'Type of keys to index',
Expand All @@ -52,14 +65,15 @@ export class CreateRedisearchIndexDto {
@IsEnum(RedisearchIndexKeyType)
type: RedisearchIndexKeyType;

@ApiProperty({
@ApiPropertyOptional({
description: 'Keys prefixes to find keys for index',
isArray: true,
type: String,
})
@IsString({ each: true })
@IsNotEmpty({ each: true })
prefixes: string[];
@IsOptional()
@RedisStringType({ each: true })
@IsRedisString({ each: true })
prefixes?: RedisString[];

@ApiProperty({
description: 'Fields to index',
Expand All @@ -78,8 +92,9 @@ export class SearchRedisearchDto {
type: String,
})
@IsDefined()
@IsString()
index: string;
@RedisStringType()
@IsRedisString()
index: RedisString;

@ApiProperty({
description: 'Query to search inside data fields',
Expand All @@ -95,7 +110,6 @@ export class SearchRedisearchDto {
})
@IsDefined()
@IsInt()
@Type(() => Number)
limit: number = 500; // todo use @Default from another PR

@ApiProperty({
Expand All @@ -104,6 +118,5 @@ export class SearchRedisearchDto {
})
@IsDefined()
@IsInt()
@Type(() => Number)
offset: number = 0; // todo use @Default from another PR
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ import {
import ERROR_MESSAGES from 'src/constants/error-messages';
import { catchAclError } from 'src/utils';
import { IFindRedisClientInstanceByOptions } from 'src/modules/core/services/redis/redis.service';
import { CreateRedisearchIndexDto, SearchRedisearchDto } from 'src/modules/browser/dto/redisearch';
import {
CreateRedisearchIndexDto,
ListRedisearchIndexesResponse,
SearchRedisearchDto,
} from 'src/modules/browser/dto/redisearch';
import { GetKeysWithDetailsResponse } from 'src/modules/browser/dto';
import { plainToClass } from 'class-transformer';
import { BrowserToolService } from '../browser-tool/browser-tool.service';
Expand All @@ -24,7 +28,7 @@ export class RedisearchService {
* Get list of all available redisearch indexes
* @param clientOptions
*/
public async list(clientOptions: IFindRedisClientInstanceByOptions): Promise<string[]> {
public async list(clientOptions: IFindRedisClientInstanceByOptions): Promise<ListRedisearchIndexesResponse> {
this.logger.log('Getting all redisearch indexes.');

try {
Expand All @@ -33,10 +37,12 @@ export class RedisearchService {
const nodes = this.getShards(client);

const res = await Promise.all(nodes.map(async (node) => node.sendCommand(
new Command('FT._LIST', [], { replyEncoding: 'utf8' }),
new Command('FT._LIST'),
)));

return [].concat(...res);
return plainToClass(ListRedisearchIndexesResponse, {
indexes: [].concat(...res),
});
} catch (e) {
this.logger.error('Failed to get redisearch indexes', e);

Expand Down Expand Up @@ -81,11 +87,18 @@ export class RedisearchService {

const nodes = this.getShards(client);

const commandArgs = [
const commandArgs: any[] = [
index, 'ON', type,
'PREFIX', prefixes.length, ...prefixes,
'SCHEMA', ...[].concat(...fields.map((field) => ([field.name, field.type]))),
];

if (prefixes && prefixes.length) {
commandArgs.push('PREFIX', prefixes.length, ...prefixes);
}

commandArgs.push(
'SCHEMA', ...[].concat(...fields.map((field) => ([field.name, field.type]))),
);

const command = new Command('FT.CREATE', commandArgs, {
replyEncoding: 'utf8',
});
Expand Down