mirror of
https://github.com/hexastack/hexabot
synced 2025-06-10 08:26:04 +00:00
Merge pull request #563 from Hexastack/562-issue-strict-null-check
feat: implement strict null checks
This commit is contained in:
commit
47e8056a15
@ -27,7 +27,7 @@ import {
|
|||||||
|
|
||||||
import { attachment, attachmentFile } from '../mocks/attachment.mock';
|
import { attachment, attachmentFile } from '../mocks/attachment.mock';
|
||||||
import { AttachmentRepository } from '../repositories/attachment.repository';
|
import { AttachmentRepository } from '../repositories/attachment.repository';
|
||||||
import { AttachmentModel, Attachment } from '../schemas/attachment.schema';
|
import { Attachment, AttachmentModel } from '../schemas/attachment.schema';
|
||||||
import { AttachmentService } from '../services/attachment.service';
|
import { AttachmentService } from '../services/attachment.service';
|
||||||
|
|
||||||
import { AttachmentController } from './attachment.controller';
|
import { AttachmentController } from './attachment.controller';
|
||||||
@ -55,14 +55,12 @@ describe('AttachmentController', () => {
|
|||||||
attachmentController =
|
attachmentController =
|
||||||
module.get<AttachmentController>(AttachmentController);
|
module.get<AttachmentController>(AttachmentController);
|
||||||
attachmentService = module.get<AttachmentService>(AttachmentService);
|
attachmentService = module.get<AttachmentService>(AttachmentService);
|
||||||
attachmentToDelete = await attachmentService.findOne({
|
attachmentToDelete = (await attachmentService.findOne({
|
||||||
name: 'store1.jpg',
|
name: 'store1.jpg',
|
||||||
});
|
}))!;
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(closeInMongodConnection);
|
||||||
await closeInMongodConnection();
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(jest.clearAllMocks);
|
afterEach(jest.clearAllMocks);
|
||||||
|
|
||||||
@ -79,7 +77,7 @@ describe('AttachmentController', () => {
|
|||||||
describe('Upload', () => {
|
describe('Upload', () => {
|
||||||
it('should throw BadRequestException if no file is selected to be uploaded', async () => {
|
it('should throw BadRequestException if no file is selected to be uploaded', async () => {
|
||||||
const promiseResult = attachmentController.uploadFile({
|
const promiseResult = attachmentController.uploadFile({
|
||||||
file: undefined,
|
file: [],
|
||||||
});
|
});
|
||||||
await expect(promiseResult).rejects.toThrow(
|
await expect(promiseResult).rejects.toThrow(
|
||||||
new BadRequestException('No file was selected'),
|
new BadRequestException('No file was selected'),
|
||||||
@ -117,9 +115,9 @@ describe('AttachmentController', () => {
|
|||||||
|
|
||||||
it('should download the attachment by id', async () => {
|
it('should download the attachment by id', async () => {
|
||||||
jest.spyOn(attachmentService, 'findOne');
|
jest.spyOn(attachmentService, 'findOne');
|
||||||
const storedAttachment = await attachmentService.findOne({
|
const storedAttachment = (await attachmentService.findOne({
|
||||||
name: 'store1.jpg',
|
name: 'store1.jpg',
|
||||||
});
|
}))!;
|
||||||
const result = await attachmentController.download({
|
const result = await attachmentController.download({
|
||||||
id: storedAttachment.id,
|
id: storedAttachment.id,
|
||||||
});
|
});
|
||||||
@ -127,7 +125,7 @@ describe('AttachmentController', () => {
|
|||||||
expect(attachmentService.findOne).toHaveBeenCalledWith(
|
expect(attachmentService.findOne).toHaveBeenCalledWith(
|
||||||
storedAttachment.id,
|
storedAttachment.id,
|
||||||
);
|
);
|
||||||
expect(result.options).toEqual({
|
expect(result?.options).toEqual({
|
||||||
type: storedAttachment.type,
|
type: storedAttachment.type,
|
||||||
length: storedAttachment.size,
|
length: storedAttachment.size,
|
||||||
disposition: `attachment; filename="${encodeURIComponent(
|
disposition: `attachment; filename="${encodeURIComponent(
|
||||||
|
@ -256,9 +256,15 @@ export class AttachmentService extends BaseService<Attachment> {
|
|||||||
async download(
|
async download(
|
||||||
attachment: Attachment,
|
attachment: Attachment,
|
||||||
rootDir = config.parameters.uploadDir,
|
rootDir = config.parameters.uploadDir,
|
||||||
) {
|
): Promise<StreamableFile> {
|
||||||
if (this.getStoragePlugin()) {
|
if (this.getStoragePlugin()) {
|
||||||
return await this.getStoragePlugin()?.download(attachment);
|
const streamableFile =
|
||||||
|
await this.getStoragePlugin()?.download(attachment);
|
||||||
|
if (!streamableFile) {
|
||||||
|
throw new NotFoundException('No file was found');
|
||||||
|
}
|
||||||
|
|
||||||
|
return streamableFile;
|
||||||
} else {
|
} else {
|
||||||
const path = resolve(join(rootDir, attachment.location));
|
const path = resolve(join(rootDir, attachment.location));
|
||||||
|
|
||||||
|
@ -100,32 +100,31 @@ export default class LlmNluHelper
|
|||||||
*
|
*
|
||||||
* @returns An array of objects representing the found entities, with their `value`, `start`, and `end` positions.
|
* @returns An array of objects representing the found entities, with their `value`, `start`, and `end` positions.
|
||||||
*/
|
*/
|
||||||
private findKeywordEntities(
|
private findKeywordEntities(text: string, entity: NlpEntityFull) {
|
||||||
text: string,
|
return (
|
||||||
entity: NlpEntityFull,
|
entity.values
|
||||||
): NLU.ParseEntity[] {
|
.flatMap(({ value, expressions }) => {
|
||||||
return entity.values
|
const allValues = [value, ...expressions];
|
||||||
.flatMap(({ value, expressions }) => {
|
|
||||||
const allValues = [value, ...expressions];
|
|
||||||
|
|
||||||
// Filter the terms that are found in the text
|
// Filter the terms that are found in the text
|
||||||
return allValues
|
return allValues
|
||||||
.flatMap((term) => {
|
.flatMap((term) => {
|
||||||
const regex = new RegExp(`\\b${term}\\b`, 'g');
|
const regex = new RegExp(`\\b${term}\\b`, 'g');
|
||||||
const matches = [...text.matchAll(regex)];
|
const matches = [...text.matchAll(regex)];
|
||||||
|
|
||||||
// Map matches to FoundEntity format
|
// Map matches to FoundEntity format
|
||||||
return matches.map((match) => ({
|
return matches.map((match) => ({
|
||||||
entity: entity.name,
|
entity: entity.name,
|
||||||
value: term,
|
value: term,
|
||||||
start: match.index!,
|
start: match.index!,
|
||||||
end: match.index! + term.length,
|
end: match.index! + term.length,
|
||||||
confidence: 1,
|
confidence: 1,
|
||||||
}));
|
}));
|
||||||
})
|
})
|
||||||
.shift();
|
.shift();
|
||||||
})
|
})
|
||||||
.filter((v) => !!v);
|
.filter((v) => !!v) || []
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async predict(text: string): Promise<NLU.ParseEntities> {
|
async predict(text: string): Promise<NLU.ParseEntities> {
|
||||||
@ -133,7 +132,7 @@ export default class LlmNluHelper
|
|||||||
const helper = await this.helperService.getDefaultLlmHelper();
|
const helper = await this.helperService.getDefaultLlmHelper();
|
||||||
const defaultLanguage = await this.languageService.getDefaultLanguage();
|
const defaultLanguage = await this.languageService.getDefaultLanguage();
|
||||||
// Detect language
|
// Detect language
|
||||||
const language = await helper.generateStructuredResponse<string>(
|
const language = await helper.generateStructuredResponse<string>?.(
|
||||||
`input text: ${text}`,
|
`input text: ${text}`,
|
||||||
settings.model,
|
settings.model,
|
||||||
this.languageClassifierPrompt,
|
this.languageClassifierPrompt,
|
||||||
@ -147,13 +146,13 @@ export default class LlmNluHelper
|
|||||||
{
|
{
|
||||||
entity: 'language',
|
entity: 'language',
|
||||||
value: language || defaultLanguage.code,
|
value: language || defaultLanguage.code,
|
||||||
confidence: undefined,
|
confidence: 100,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
for await (const { name, doc, prompt, values } of this
|
for await (const { name, doc, prompt, values } of this
|
||||||
.traitClassifierPrompts) {
|
.traitClassifierPrompts) {
|
||||||
const allowedValues = values.map(({ value }) => value);
|
const allowedValues = values.map(({ value }) => value);
|
||||||
const result = await helper.generateStructuredResponse<string>(
|
const result = await helper.generateStructuredResponse<string>?.(
|
||||||
`input text: ${text}`,
|
`input text: ${text}`,
|
||||||
settings.model,
|
settings.model,
|
||||||
prompt,
|
prompt,
|
||||||
@ -163,12 +162,13 @@ export default class LlmNluHelper
|
|||||||
enum: allowedValues.concat('unknown'),
|
enum: allowedValues.concat('unknown'),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
const safeValue = result.toLowerCase().trim();
|
const safeValue = result?.toLowerCase().trim();
|
||||||
const value = allowedValues.includes(safeValue) ? safeValue : '';
|
const value =
|
||||||
|
safeValue && allowedValues.includes(safeValue) ? safeValue : '';
|
||||||
traits.push({
|
traits.push({
|
||||||
entity: name,
|
entity: name,
|
||||||
value,
|
value,
|
||||||
confidence: undefined,
|
confidence: 100,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,7 +179,7 @@ export default class LlmNluHelper
|
|||||||
});
|
});
|
||||||
const entities = keywordEntities.flatMap((keywordEntity) =>
|
const entities = keywordEntities.flatMap((keywordEntity) =>
|
||||||
this.findKeywordEntities(text, keywordEntity),
|
this.findKeywordEntities(text, keywordEntity),
|
||||||
);
|
) as NLU.ParseEntity[];
|
||||||
|
|
||||||
return { entities: traits.concat(entities) };
|
return { entities: traits.concat(entities) };
|
||||||
}
|
}
|
||||||
|
@ -191,7 +191,7 @@ describe('MigrationService', () => {
|
|||||||
|
|
||||||
await service.run({
|
await service.run({
|
||||||
action: MigrationAction.UP,
|
action: MigrationAction.UP,
|
||||||
version: null,
|
version: undefined,
|
||||||
isAutoMigrate: false,
|
isAutoMigrate: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ import { Migration, MigrationDocument } from './migration.schema';
|
|||||||
import {
|
import {
|
||||||
MigrationAction,
|
MigrationAction,
|
||||||
MigrationName,
|
MigrationName,
|
||||||
|
MigrationRunOneParams,
|
||||||
MigrationRunParams,
|
MigrationRunParams,
|
||||||
MigrationSuccessCallback,
|
MigrationSuccessCallback,
|
||||||
MigrationVersion,
|
MigrationVersion,
|
||||||
@ -239,7 +240,7 @@ module.exports = {
|
|||||||
*
|
*
|
||||||
* @returns Resolves when the migration action is successfully executed or stops if the migration already exists.
|
* @returns Resolves when the migration action is successfully executed or stops if the migration already exists.
|
||||||
*/
|
*/
|
||||||
private async runOne({ version, action }: MigrationRunParams) {
|
private async runOne({ version, action }: MigrationRunOneParams) {
|
||||||
// Verify DB status
|
// Verify DB status
|
||||||
const { exist, migrationDocument } = await this.verifyStatus({
|
const { exist, migrationDocument } = await this.verifyStatus({
|
||||||
version,
|
version,
|
||||||
@ -258,7 +259,7 @@ module.exports = {
|
|||||||
attachmentService: this.attachmentService,
|
attachmentService: this.attachmentService,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (result) {
|
if (result && migrationDocument) {
|
||||||
await this.successCallback({
|
await this.successCallback({
|
||||||
version,
|
version,
|
||||||
action,
|
action,
|
||||||
|
@ -442,7 +442,10 @@ const migrateAttachmentMessages = async ({
|
|||||||
type: response.headers['content-type'],
|
type: response.headers['content-type'],
|
||||||
channel: {},
|
channel: {},
|
||||||
});
|
});
|
||||||
await updateAttachmentId(msg._id, attachment.id);
|
|
||||||
|
if (attachment) {
|
||||||
|
await updateAttachmentId(msg._id, attachment.id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
logger.warn(
|
logger.warn(
|
||||||
|
@ -28,6 +28,10 @@ export interface MigrationRunParams {
|
|||||||
isAutoMigrate?: boolean;
|
isAutoMigrate?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface MigrationRunOneParams extends MigrationRunParams {
|
||||||
|
version: MigrationVersion;
|
||||||
|
}
|
||||||
|
|
||||||
export interface MigrationSuccessCallback extends MigrationRunParams {
|
export interface MigrationSuccessCallback extends MigrationRunParams {
|
||||||
migrationDocument: MigrationDocument;
|
migrationDocument: MigrationDocument;
|
||||||
}
|
}
|
||||||
|
@ -109,7 +109,7 @@ describe('NlpEntityController', () => {
|
|||||||
acc.push({
|
acc.push({
|
||||||
...curr,
|
...curr,
|
||||||
values: nlpValueFixtures.filter(
|
values: nlpValueFixtures.filter(
|
||||||
({ entity }) => parseInt(entity) === index,
|
({ entity }) => parseInt(entity!) === index,
|
||||||
) as NlpEntityFull['values'],
|
) as NlpEntityFull['values'],
|
||||||
lookups: curr.lookups!,
|
lookups: curr.lookups!,
|
||||||
builtin: curr.builtin!,
|
builtin: curr.builtin!,
|
||||||
|
@ -98,7 +98,7 @@ describe('NlpValueController', () => {
|
|||||||
acc.push({
|
acc.push({
|
||||||
...curr,
|
...curr,
|
||||||
entity: nlpEntityFixtures[
|
entity: nlpEntityFixtures[
|
||||||
parseInt(curr.entity)
|
parseInt(curr.entity!)
|
||||||
] as NlpValueFull['entity'],
|
] as NlpValueFull['entity'],
|
||||||
builtin: curr.builtin!,
|
builtin: curr.builtin!,
|
||||||
expressions: curr.expressions!,
|
expressions: curr.expressions!,
|
||||||
@ -125,7 +125,7 @@ describe('NlpValueController', () => {
|
|||||||
(acc, curr) => {
|
(acc, curr) => {
|
||||||
const ValueWithEntities = {
|
const ValueWithEntities = {
|
||||||
...curr,
|
...curr,
|
||||||
entity: nlpEntities[parseInt(curr.entity)].id,
|
entity: curr.entity ? nlpEntities[parseInt(curr.entity!)].id : null,
|
||||||
expressions: curr.expressions!,
|
expressions: curr.expressions!,
|
||||||
metadata: curr.metadata!,
|
metadata: curr.metadata!,
|
||||||
builtin: curr.builtin!,
|
builtin: curr.builtin!,
|
||||||
@ -133,7 +133,7 @@ describe('NlpValueController', () => {
|
|||||||
acc.push(ValueWithEntities);
|
acc.push(ValueWithEntities);
|
||||||
return acc;
|
return acc;
|
||||||
},
|
},
|
||||||
[] as TFixtures<NlpValue>[],
|
[] as TFixtures<NlpValueCreateDto>[],
|
||||||
);
|
);
|
||||||
expect(result).toEqualPayload(nlpValueFixturesWithEntities);
|
expect(result).toEqualPayload(nlpValueFixturesWithEntities);
|
||||||
});
|
});
|
||||||
|
@ -75,8 +75,9 @@ export class NlpValueController extends BaseController<
|
|||||||
this.validate({
|
this.validate({
|
||||||
dto: createNlpValueDto,
|
dto: createNlpValueDto,
|
||||||
allowedIds: {
|
allowedIds: {
|
||||||
entity: (await this.nlpEntityService.findOne(createNlpValueDto.entity))
|
entity: createNlpValueDto.entity
|
||||||
?.id,
|
? (await this.nlpEntityService.findOne(createNlpValueDto.entity))?.id
|
||||||
|
: null,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
return await this.nlpValueService.create(createNlpValueDto);
|
return await this.nlpValueService.create(createNlpValueDto);
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
* 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file).
|
* 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { PartialType } from '@nestjs/mapped-types';
|
|
||||||
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||||
import {
|
import {
|
||||||
IsArray,
|
IsArray,
|
||||||
@ -49,11 +48,42 @@ export class NlpValueCreateDto {
|
|||||||
@IsString()
|
@IsString()
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
@IsObjectId({ message: 'Entity must be a valid ObjectId' })
|
@IsObjectId({ message: 'Entity must be a valid ObjectId' })
|
||||||
entity: string;
|
entity: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class NlpValueUpdateDto extends PartialType(NlpValueCreateDto) {}
|
export class NlpValueUpdateDto {
|
||||||
|
@ApiPropertyOptional({ description: 'Foreign ID', type: String })
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
foreign_id?: string;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({ description: 'Nlp value', type: String })
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
value?: string;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({
|
||||||
|
description: 'Nlp value expressions',
|
||||||
|
isArray: true,
|
||||||
|
type: Array,
|
||||||
|
})
|
||||||
|
@IsOptional()
|
||||||
|
@IsArray()
|
||||||
|
expressions?: string[];
|
||||||
|
|
||||||
|
@ApiPropertyOptional({ description: 'Nlp value entity', type: String })
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
@IsObjectId({ message: 'Entity must be a valid ObjectId' })
|
||||||
|
entity?: string | null;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({ description: 'Nlp value is builtin', type: Boolean })
|
||||||
|
@IsOptional()
|
||||||
|
@IsBoolean()
|
||||||
|
builtin?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export type NlpValueDto = DtoConfig<{
|
export type NlpValueDto = DtoConfig<{
|
||||||
create: NlpValueCreateDto;
|
create: NlpValueCreateDto;
|
||||||
|
update: NlpValueUpdateDto;
|
||||||
}>;
|
}>;
|
||||||
|
@ -87,7 +87,7 @@ describe('NlpValueRepository', () => {
|
|||||||
const ValueWithEntities = {
|
const ValueWithEntities = {
|
||||||
...curr,
|
...curr,
|
||||||
entity: nlpEntityFixtures[
|
entity: nlpEntityFixtures[
|
||||||
parseInt(curr.entity)
|
parseInt(curr.entity!)
|
||||||
] as NlpValueFull['entity'],
|
] as NlpValueFull['entity'],
|
||||||
builtin: curr.builtin!,
|
builtin: curr.builtin!,
|
||||||
expressions: curr.expressions!,
|
expressions: curr.expressions!,
|
||||||
|
@ -38,7 +38,7 @@ export class NlpValueSeeder extends BaseSeeder<
|
|||||||
const entities = await this.nlpEntityRepository.findAll();
|
const entities = await this.nlpEntityRepository.findAll();
|
||||||
const modelDtos = models.map((v) => ({
|
const modelDtos = models.map((v) => ({
|
||||||
...v,
|
...v,
|
||||||
entity: entities.find(({ name }) => name === v.entity)?.id,
|
entity: entities.find(({ name }) => name === v.entity)?.id || null,
|
||||||
}));
|
}));
|
||||||
await this.repository.createMany(modelDtos);
|
await this.repository.createMany(modelDtos);
|
||||||
return true;
|
return true;
|
||||||
|
@ -69,9 +69,7 @@ describe('NlpValueService', () => {
|
|||||||
nlpValues = await nlpValueRepository.findAll();
|
nlpValues = await nlpValueRepository.findAll();
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(closeInMongodConnection);
|
||||||
await closeInMongodConnection();
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(jest.clearAllMocks);
|
afterEach(jest.clearAllMocks);
|
||||||
|
|
||||||
@ -94,9 +92,7 @@ describe('NlpValueService', () => {
|
|||||||
(acc, curr) => {
|
(acc, curr) => {
|
||||||
const ValueWithEntities = {
|
const ValueWithEntities = {
|
||||||
...curr,
|
...curr,
|
||||||
entity: nlpEntityFixtures[
|
entity: nlpEntityFixtures[parseInt(curr.entity!)] as NlpEntity,
|
||||||
parseInt(curr.entity)
|
|
||||||
] as NlpValueFull['entity'],
|
|
||||||
expressions: curr.expressions!,
|
expressions: curr.expressions!,
|
||||||
metadata: curr.metadata!,
|
metadata: curr.metadata!,
|
||||||
builtin: curr.builtin!,
|
builtin: curr.builtin!,
|
||||||
|
@ -11,11 +11,7 @@ import { forwardRef, Inject, Injectable } from '@nestjs/common';
|
|||||||
import { DeleteResult } from '@/utils/generics/base-repository';
|
import { DeleteResult } from '@/utils/generics/base-repository';
|
||||||
import { BaseService } from '@/utils/generics/base-service';
|
import { BaseService } from '@/utils/generics/base-service';
|
||||||
|
|
||||||
import {
|
import { NlpValueCreateDto, NlpValueDto } from '../dto/nlp-value.dto';
|
||||||
NlpValueCreateDto,
|
|
||||||
NlpValueDto,
|
|
||||||
NlpValueUpdateDto,
|
|
||||||
} from '../dto/nlp-value.dto';
|
|
||||||
import { NlpValueRepository } from '../repositories/nlp-value.repository';
|
import { NlpValueRepository } from '../repositories/nlp-value.repository';
|
||||||
import { NlpEntity } from '../schemas/nlp-entity.schema';
|
import { NlpEntity } from '../schemas/nlp-entity.schema';
|
||||||
import {
|
import {
|
||||||
@ -139,7 +135,7 @@ export class NlpValueService extends BaseService<
|
|||||||
expressions: vMap[e.value].expressions?.concat([
|
expressions: vMap[e.value].expressions?.concat([
|
||||||
sampleText.slice(e.start, e.end),
|
sampleText.slice(e.start, e.end),
|
||||||
]),
|
]),
|
||||||
} as NlpValueUpdateDto);
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
await Promise.all(synonymsToAdd);
|
await Promise.all(synonymsToAdd);
|
||||||
|
@ -478,7 +478,7 @@ export abstract class BaseRepository<
|
|||||||
|
|
||||||
async updateOne<D extends Partial<U>>(
|
async updateOne<D extends Partial<U>>(
|
||||||
criteria: string | TFilterQuery<T>,
|
criteria: string | TFilterQuery<T>,
|
||||||
dto: UpdateQuery<D>,
|
dto: UpdateQuery<DtoInfer<DtoAction.Update, Dto, D>>,
|
||||||
options: QueryOptions<D> | null = {
|
options: QueryOptions<D> | null = {
|
||||||
new: true,
|
new: true,
|
||||||
},
|
},
|
||||||
|
@ -177,7 +177,7 @@ export abstract class BaseService<
|
|||||||
|
|
||||||
async updateOne(
|
async updateOne(
|
||||||
criteria: string | TFilterQuery<T>,
|
criteria: string | TFilterQuery<T>,
|
||||||
dto: Partial<U>,
|
dto: DtoInfer<DtoAction.Update, Dto, Partial<U>>,
|
||||||
options?: QueryOptions<Partial<U>> | null,
|
options?: QueryOptions<Partial<U>> | null,
|
||||||
): Promise<T | null> {
|
): Promise<T | null> {
|
||||||
return await this.repository.updateOne(criteria, dto, options);
|
return await this.repository.updateOne(criteria, dto, options);
|
||||||
|
@ -48,7 +48,7 @@ export async function moveFiles(
|
|||||||
const files = await fs.promises.readdir(sourceFolder);
|
const files = await fs.promises.readdir(sourceFolder);
|
||||||
|
|
||||||
// Filter only files (skip directories)
|
// Filter only files (skip directories)
|
||||||
const filePaths = [];
|
const filePaths: string[] = [];
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
const filePath = join(sourceFolder, file);
|
const filePath = join(sourceFolder, file);
|
||||||
const stat = await fs.promises.stat(filePath);
|
const stat = await fs.promises.stat(filePath);
|
||||||
|
@ -7,10 +7,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Injectable,
|
|
||||||
PipeTransform,
|
|
||||||
ArgumentMetadata,
|
ArgumentMetadata,
|
||||||
BadRequestException,
|
BadRequestException,
|
||||||
|
Injectable,
|
||||||
|
PipeTransform,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { plainToClass } from 'class-transformer';
|
import { plainToClass } from 'class-transformer';
|
||||||
import { validate } from 'class-validator';
|
import { validate } from 'class-validator';
|
||||||
@ -33,8 +33,13 @@ export class ObjectIdPipe implements PipeTransform<string, Promise<string>> {
|
|||||||
async transform(value: string, { type, data }: ArgumentMetadata) {
|
async transform(value: string, { type, data }: ArgumentMetadata) {
|
||||||
if (typeof value === 'string' && data === 'id' && type === 'param') {
|
if (typeof value === 'string' && data === 'id' && type === 'param') {
|
||||||
const errors = await this.getErrors(value);
|
const errors = await this.getErrors(value);
|
||||||
if (errors)
|
if (errors) {
|
||||||
throw new BadRequestException(Object.values(errors.constraints)[0]);
|
throw new BadRequestException(
|
||||||
|
errors?.constraints
|
||||||
|
? Object.values(errors.constraints)[0]
|
||||||
|
: errors.toString(),
|
||||||
|
);
|
||||||
|
}
|
||||||
} else if (
|
} else if (
|
||||||
typeof value === 'object' &&
|
typeof value === 'object' &&
|
||||||
Object.keys(value).length > 1 &&
|
Object.keys(value).length > 1 &&
|
||||||
@ -45,10 +50,13 @@ export class ObjectIdPipe implements PipeTransform<string, Promise<string>> {
|
|||||||
if (param.startsWith('id')) {
|
if (param.startsWith('id')) {
|
||||||
const errors = await this.getErrors(String(paramValue));
|
const errors = await this.getErrors(String(paramValue));
|
||||||
|
|
||||||
if (errors)
|
if (errors) {
|
||||||
throw new BadRequestException(
|
throw new BadRequestException(
|
||||||
Object.values(errors.constraints)[0],
|
errors?.constraints
|
||||||
|
? Object.values(errors.constraints)[0]
|
||||||
|
: errors.toString(),
|
||||||
);
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
2
api/src/utils/test/fixtures/conversation.ts
vendored
2
api/src/utils/test/fixtures/conversation.ts
vendored
@ -142,7 +142,7 @@ export const installConversationTypeFixtures = async () => {
|
|||||||
conversationFixtures.map((conversationFixture) => ({
|
conversationFixtures.map((conversationFixture) => ({
|
||||||
...conversationFixture,
|
...conversationFixture,
|
||||||
sender: subscribers[parseInt(conversationFixture.sender)].id,
|
sender: subscribers[parseInt(conversationFixture.sender)].id,
|
||||||
current: conversationFixture?.current
|
current: conversationFixture.current
|
||||||
? blocks[parseInt(conversationFixture.current)]?.id
|
? blocks[parseInt(conversationFixture.current)]?.id
|
||||||
: undefined,
|
: undefined,
|
||||||
next: conversationFixture.next?.map((n) => blocks[parseInt(n)].id),
|
next: conversationFixture.next?.map((n) => blocks[parseInt(n)].id),
|
||||||
|
10
api/src/utils/test/fixtures/nlpvalue.ts
vendored
10
api/src/utils/test/fixtures/nlpvalue.ts
vendored
@ -51,12 +51,10 @@ export const installNlpValueFixtures = async () => {
|
|||||||
|
|
||||||
const NlpValue = mongoose.model(NlpValueModel.name, NlpValueModel.schema);
|
const NlpValue = mongoose.model(NlpValueModel.name, NlpValueModel.schema);
|
||||||
const nlpValues = await NlpValue.insertMany(
|
const nlpValues = await NlpValue.insertMany(
|
||||||
nlpValueFixtures.map((v) => {
|
nlpValueFixtures.map((v) => ({
|
||||||
return {
|
...v,
|
||||||
...v,
|
entity: v?.entity ? nlpEntities[parseInt(v.entity)].id : null,
|
||||||
entity: nlpEntities[parseInt(v.entity)].id,
|
})),
|
||||||
};
|
|
||||||
}),
|
|
||||||
);
|
);
|
||||||
return { nlpEntities, nlpValues };
|
return { nlpEntities, nlpValues };
|
||||||
};
|
};
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
"baseUrl": "./",
|
"baseUrl": "./",
|
||||||
"incremental": true,
|
"incremental": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"strictNullChecks": false,
|
"strictNullChecks": true,
|
||||||
"strictPropertyInitialization": false,
|
"strictPropertyInitialization": false,
|
||||||
"noImplicitAny": false,
|
"noImplicitAny": false,
|
||||||
"strictBindCallApply": false,
|
"strictBindCallApply": false,
|
||||||
|
Loading…
Reference in New Issue
Block a user