add meili search

This commit is contained in:
liuyi 2025-06-01 21:24:43 +08:00
parent 7af6efc642
commit 02ccf58457
6 changed files with 40 additions and 5 deletions

View File

@ -6,6 +6,7 @@ import * as controllers from '@/modules/content/controllers';
import * as entities from '@/modules/content/entities';
import * as repositories from '@/modules/content/repositories';
import * as services from '@/modules/content/services';
import { SearchService } from '@/modules/content/services';
import { SanitizeService } from '@/modules/content/services/SanitizeService';
import { PostService } from '@/modules/content/services/post.service';
@ -31,23 +32,29 @@ export class ContentModule {
repositories.CategoryRepository,
repositories.TagRepository,
services.CategoryService,
{ token: services.SearchService, optional: true },
],
useFactory(
postRepository: repositories.PostRepository,
categoryRepository: repositories.CategoryRepository,
tagRepository: repositories.TagRepository,
categoryService: services.CategoryService,
searchService: SearchService,
) {
return new PostService(
postRepository,
categoryRepository,
categoryService,
tagRepository,
searchService,
config.SearchType,
);
},
},
];
if (config.SearchType === 'meili') {
providers.push(services.SearchService);
}
return {
module: ContentModule,
imports: [

View File

@ -32,6 +32,9 @@ export class QueryPostDto implements PaginateOptions {
@IsOptional()
isPublished?: boolean;
@IsOptional()
search?: string;
@IsEnum(PostOrder, {
message: `The sorting rule must be one of ${Object.values(PostOrder).join(',')}`,
})

View File

@ -1,3 +1,4 @@
export * from './category.service';
export * from './tag.service';
export * from './comment.service';
export * from './search.service';

View File

@ -1,7 +1,7 @@
import { Injectable } from '@nestjs/common';
import { isNil } from '@nestjs/common/utils/shared.utils';
import { isArray, isFunction, omit } from 'lodash';
import { isArray, isFunction, omit, pick } from 'lodash';
import { EntityNotFoundError, In, IsNull, Not, SelectQueryBuilder } from 'typeorm';
import { PostOrder } from '@/modules/content/constants';
@ -9,6 +9,7 @@ import { CreatePostDto, QueryPostDto, UpdatePostDto } from '@/modules/content/dt
import { PostEntity } from '@/modules/content/entities/post.entity';
import { CategoryRepository } from '@/modules/content/repositories';
import { PostRepository } from '@/modules/content/repositories/post.repository';
import { SearchService } from '@/modules/content/services/search.service';
import { SearchType } from '@/modules/content/types';
import { SelectTrashMode } from '@/modules/database/constants';
import { QueryHook } from '@/modules/database/types';
@ -29,10 +30,17 @@ export class PostService {
protected categoryRepository: CategoryRepository,
protected categoryService: CategoryService,
protected tagRepository: TagRepository,
protected searchService?: SearchService,
protected searchType: SearchType = 'mysql',
) {}
async paginate(options: QueryPostDto, callback?: QueryHook<PostEntity>) {
if (!isNil(this.searchService) && !isNil(options.search) && this.searchType === 'meili') {
return this.searchService.search(
options.search,
pick(options, ['trashed', 'page', 'limit']),
);
}
const qb = await this.buildListQuery(this.repository.buildBaseQB(), options, callback);
return paginate(qb, options);
}
@ -62,7 +70,11 @@ export class PostService {
publishedAt,
};
const item = await this.repository.save(createPostDto);
return this.detail(item.id);
const result = await this.detail(item.id);
if (!isNil(this.searchService)) {
await this.searchService.create(result);
}
return result;
}
async update(data: UpdatePostDto) {
@ -88,7 +100,11 @@ export class PostService {
...omit(data, ['id', 'publish', 'tags', 'category']),
publishedAt,
});
return this.detail(data.id);
const result = await this.detail(data.id);
if (!isNil(this.searchService)) {
await this.searchService.update([result]);
}
return result;
}
async delete(ids: string[], trash?: boolean) {
@ -105,8 +121,15 @@ export class PostService {
...(await this.repository.remove(directs)),
...(await this.repository.softRemove(softs)),
];
if (!isNil(this.searchService)) {
await this.searchService.delete(directs.map((item) => item.id));
await this.searchService.update(softs);
}
} else {
result = await this.repository.remove(items);
if (!isNil(this.searchService)) {
await this.searchService.delete(ids);
}
}
return result;
}
@ -118,6 +141,7 @@ export class PostService {
.withDeleted()
.getMany();
const trashes = items.filter((item) => !isNil(item.deleteAt));
await this.searchService.update(trashes);
const trashedIds = trashes.map((item) => item.id);
if (trashedIds.length < 1) {
return [];

View File

@ -14,7 +14,7 @@ import { SelectTrashMode } from '@/modules/database/constants';
import { MeiliService } from '@/modules/meilisearch/meili.service';
export class SearchService implements OnModuleInit {
index = 'content';
private index = 'content';
protected client: MeiliSearch;

View File

@ -1,6 +1,6 @@
import { SelectTrashMode } from '@/modules/database/constants';
export type SearchType = 'mysql';
export type SearchType = 'mysql' | 'meili';
export interface ContentConfig {
SearchType?: SearchType;