feat(api): add nlp pattern lookup strategy

This commit is contained in:
Mohamed Marrouchi 2025-05-13 10:56:55 +01:00
parent e2d6d15215
commit 9e0df0d530
9 changed files with 66 additions and 21 deletions

View File

@ -160,7 +160,7 @@ describe('BaseNlpHelper', () => {
updatedAt: new Date(), updatedAt: new Date(),
builtin: false, builtin: false,
expressions: [], expressions: [],
metadata: [], metadata: {},
}, },
value2: { value2: {
id: new ObjectId().toString(), id: new ObjectId().toString(),
@ -170,7 +170,7 @@ describe('BaseNlpHelper', () => {
updatedAt: new Date(), updatedAt: new Date(),
builtin: false, builtin: false,
expressions: [], expressions: [],
metadata: [], metadata: {},
}, },
}); });

View File

@ -95,7 +95,7 @@ describe('NlpValueController', () => {
entity: nlpEntities[0].id, entity: nlpEntities[0].id,
value: 'valuetest', value: 'valuetest',
expressions: ['synonym1', 'synonym2'], expressions: ['synonym1', 'synonym2'],
metadata: { firstkey: 'firstvalue', secondKey: 1995 }, metadata: {},
builtin: false, builtin: false,
doc: '', doc: '',
}; };

View File

@ -71,14 +71,17 @@ export class NlpValueController extends BaseController<
async create( async create(
@Body() createNlpValueDto: NlpValueCreateDto, @Body() createNlpValueDto: NlpValueCreateDto,
): Promise<NlpValue> { ): Promise<NlpValue> {
const nlpEntity = createNlpValueDto.entity
? await this.nlpEntityService.findOne(createNlpValueDto.entity!)
: null;
this.validate({ this.validate({
dto: createNlpValueDto, dto: createNlpValueDto,
allowedIds: { allowedIds: {
entity: createNlpValueDto.entity entity: nlpEntity?.id,
? (await this.nlpEntityService.findOne(createNlpValueDto.entity))?.id
: null,
}, },
}); });
return await this.nlpValueService.create(createNlpValueDto); return await this.nlpValueService.create(createNlpValueDto);
} }
@ -171,6 +174,17 @@ export class NlpValueController extends BaseController<
@Param('id') id: string, @Param('id') id: string,
@Body() updateNlpValueDto: NlpValueUpdateDto, @Body() updateNlpValueDto: NlpValueUpdateDto,
): Promise<NlpValue> { ): Promise<NlpValue> {
const nlpEntity = updateNlpValueDto.entity
? await this.nlpEntityService.findOne(updateNlpValueDto.entity!)
: null;
this.validate({
dto: updateNlpValueDto,
allowedIds: {
entity: nlpEntity?.id,
},
});
return await this.nlpValueService.updateOne(id, updateNlpValueDto); return await this.nlpValueService.updateOne(id, updateNlpValueDto);
} }

View File

@ -21,7 +21,7 @@ import {
import { DtoConfig } from '@/utils/types/dto.types'; import { DtoConfig } from '@/utils/types/dto.types';
export type Lookup = 'keywords' | 'trait' | 'free-text'; import { Lookup, LookupStrategy } from '../schemas/types';
export class NlpEntityCreateDto { export class NlpEntityCreateDto {
@ApiProperty({ description: 'Name of the nlp entity', type: String }) @ApiProperty({ description: 'Name of the nlp entity', type: String })
@ -33,10 +33,10 @@ export class NlpEntityCreateDto {
@ApiPropertyOptional({ @ApiPropertyOptional({
isArray: true, isArray: true,
enum: ['keywords', 'trait', 'free-text'], enum: Object.values(LookupStrategy),
}) })
@IsArray() @IsArray()
@IsIn(['keywords', 'trait', 'free-text'], { each: true }) @IsIn(Object.values(LookupStrategy), { each: true })
@IsOptional() @IsOptional()
lookups?: Lookup[]; lookups?: Lookup[];

View File

@ -19,6 +19,8 @@ import {
import { DtoConfig } from '@/utils/types/dto.types'; import { DtoConfig } from '@/utils/types/dto.types';
import { IsObjectId } from '@/utils/validation-rules/is-object-id'; import { IsObjectId } from '@/utils/validation-rules/is-object-id';
import { NlpMetadata } from '../schemas/types';
export class NlpValueCreateDto { export class NlpValueCreateDto {
@ApiProperty({ description: 'Nlp value', type: String }) @ApiProperty({ description: 'Nlp value', type: String })
@IsString() @IsString()
@ -37,7 +39,7 @@ export class NlpValueCreateDto {
@ApiPropertyOptional({ description: 'Nlp value metadata', type: Object }) @ApiPropertyOptional({ description: 'Nlp value metadata', type: Object })
@IsOptional() @IsOptional()
@IsObject() @IsObject()
metadata?: Record<string, any>; metadata?: NlpMetadata;
@ApiPropertyOptional({ description: 'Nlp Value Description', type: String }) @ApiPropertyOptional({ description: 'Nlp Value Description', type: String })
@IsString() @IsString()
@ -82,6 +84,11 @@ export class NlpValueUpdateDto {
@IsObjectId({ message: 'Entity must be a valid ObjectId' }) @IsObjectId({ message: 'Entity must be a valid ObjectId' })
entity?: string | null; entity?: string | null;
@ApiPropertyOptional({ description: 'Nlp Metadata', type: Object })
@IsObject()
@IsOptional()
metadata?: NlpMetadata;
@ApiPropertyOptional({ description: 'Nlp Value Description', type: String }) @ApiPropertyOptional({ description: 'Nlp Value Description', type: String })
@IsString() @IsString()
@IsOptional() @IsOptional()

View File

@ -16,10 +16,8 @@ import {
THydratedDocument, THydratedDocument,
} from '@/utils/types/filter.types'; } from '@/utils/types/filter.types';
import { Lookup } from '../dto/nlp-entity.dto';
import { NlpValue } from './nlp-value.schema'; import { NlpValue } from './nlp-value.schema';
import { NlpEntityMap } from './types'; import { Lookup, LookupStrategy, NlpEntityMap } from './types';
@Schema({ timestamps: true }) @Schema({ timestamps: true })
export class NlpEntityStub extends BaseSchema { export class NlpEntityStub extends BaseSchema {
@ -41,9 +39,18 @@ export class NlpEntityStub extends BaseSchema {
name: string; name: string;
/** /**
* Lookup strategy can contain : keywords, trait, free-text * Lookup strategy
*/ */
@Prop({ type: [String], default: ['keywords'] }) @Prop({
type: [String],
default: ['keywords'],
validate: {
validator: (lookups: string[]) =>
lookups.every((lookup) =>
Object.values(LookupStrategy).includes(lookup as LookupStrategy),
),
},
})
lookups: Lookup[]; lookups: Lookup[];
/** /**

View File

@ -19,9 +19,9 @@ import {
import { TStubOrFull } from '@/utils/types/format.types'; import { TStubOrFull } from '@/utils/types/format.types';
import { NlpEntity, NlpEntityFull } from './nlp-entity.schema'; import { NlpEntity, NlpEntityFull } from './nlp-entity.schema';
import { NlpValueMap } from './types'; import { NlpMetadata, NlpValueMap } from './types';
@Schema({ timestamps: true }) @Schema({ timestamps: true, minimize: false })
export class NlpValueStub extends BaseSchema { export class NlpValueStub extends BaseSchema {
/** /**
* This value content. * This value content.
@ -44,8 +44,8 @@ export class NlpValueStub extends BaseSchema {
/** /**
* Metadata are additional data that can be associated to this values, most of the time, the metadata contains system values or ids (e.g: value: "coffee", metadata: "item_11") . * Metadata are additional data that can be associated to this values, most of the time, the metadata contains system values or ids (e.g: value: "coffee", metadata: "item_11") .
*/ */
@Prop({ type: JSON, default: {} }) @Prop({ type: JSON, default: () => {} })
metadata: Record<string, any>; metadata?: NlpMetadata;
/** /**
* Description of the entity's value purpose. * Description of the entity's value purpose.

View File

@ -9,6 +9,15 @@
import { NlpEntityFull, NlpEntityStub } from './nlp-entity.schema'; import { NlpEntityFull, NlpEntityStub } from './nlp-entity.schema';
import { NlpValueStub } from './nlp-value.schema'; import { NlpValueStub } from './nlp-value.schema';
export enum LookupStrategy {
keywords = 'keywords',
trait = 'trait',
free_text = 'free-text',
pattern = 'pattern',
}
export type Lookup = `${LookupStrategy}`;
export interface NlpSampleEntityValue { export interface NlpSampleEntityValue {
entity: string; // entity name entity: string; // entity name
value: string; // entity value value: string; // entity value
@ -27,3 +36,11 @@ export enum NlpSampleState {
} }
export type NlpCacheMap = Map<string, NlpEntityFull>; export type NlpCacheMap = Map<string, NlpEntityFull>;
export type NlpMetadata = {
// Required when lookups is "pattern"
pattern?: string;
removeSpaces?: boolean;
toLowerCase?: boolean;
stripDiacritics?: boolean;
};

View File

@ -15,14 +15,14 @@ import { NLP_MAP_CACHE_KEY } from '@/utils/constants/cache';
import { Cacheable } from '@/utils/decorators/cacheable.decorator'; import { Cacheable } from '@/utils/decorators/cacheable.decorator';
import { BaseService } from '@/utils/generics/base-service'; import { BaseService } from '@/utils/generics/base-service';
import { Lookup, NlpEntityDto } from '../dto/nlp-entity.dto'; import { NlpEntityDto } from '../dto/nlp-entity.dto';
import { NlpEntityRepository } from '../repositories/nlp-entity.repository'; import { NlpEntityRepository } from '../repositories/nlp-entity.repository';
import { import {
NlpEntity, NlpEntity,
NlpEntityFull, NlpEntityFull,
NlpEntityPopulate, NlpEntityPopulate,
} from '../schemas/nlp-entity.schema'; } from '../schemas/nlp-entity.schema';
import { NlpCacheMap, NlpSampleEntityValue } from '../schemas/types'; import { Lookup, NlpCacheMap, NlpSampleEntityValue } from '../schemas/types';
import { NlpValueService } from './nlp-value.service'; import { NlpValueService } from './nlp-value.service';