add meili search
This commit is contained in:
parent
7af6efc642
commit
02ccf58457
@ -6,6 +6,7 @@ import * as controllers from '@/modules/content/controllers';
|
|||||||
import * as entities from '@/modules/content/entities';
|
import * as entities from '@/modules/content/entities';
|
||||||
import * as repositories from '@/modules/content/repositories';
|
import * as repositories from '@/modules/content/repositories';
|
||||||
import * as services from '@/modules/content/services';
|
import * as services from '@/modules/content/services';
|
||||||
|
import { SearchService } from '@/modules/content/services';
|
||||||
import { SanitizeService } from '@/modules/content/services/SanitizeService';
|
import { SanitizeService } from '@/modules/content/services/SanitizeService';
|
||||||
|
|
||||||
import { PostService } from '@/modules/content/services/post.service';
|
import { PostService } from '@/modules/content/services/post.service';
|
||||||
@ -31,23 +32,29 @@ export class ContentModule {
|
|||||||
repositories.CategoryRepository,
|
repositories.CategoryRepository,
|
||||||
repositories.TagRepository,
|
repositories.TagRepository,
|
||||||
services.CategoryService,
|
services.CategoryService,
|
||||||
|
{ token: services.SearchService, optional: true },
|
||||||
],
|
],
|
||||||
useFactory(
|
useFactory(
|
||||||
postRepository: repositories.PostRepository,
|
postRepository: repositories.PostRepository,
|
||||||
categoryRepository: repositories.CategoryRepository,
|
categoryRepository: repositories.CategoryRepository,
|
||||||
tagRepository: repositories.TagRepository,
|
tagRepository: repositories.TagRepository,
|
||||||
categoryService: services.CategoryService,
|
categoryService: services.CategoryService,
|
||||||
|
searchService: SearchService,
|
||||||
) {
|
) {
|
||||||
return new PostService(
|
return new PostService(
|
||||||
postRepository,
|
postRepository,
|
||||||
categoryRepository,
|
categoryRepository,
|
||||||
categoryService,
|
categoryService,
|
||||||
tagRepository,
|
tagRepository,
|
||||||
|
searchService,
|
||||||
config.SearchType,
|
config.SearchType,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
if (config.SearchType === 'meili') {
|
||||||
|
providers.push(services.SearchService);
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
module: ContentModule,
|
module: ContentModule,
|
||||||
imports: [
|
imports: [
|
||||||
|
@ -32,6 +32,9 @@ export class QueryPostDto implements PaginateOptions {
|
|||||||
@IsOptional()
|
@IsOptional()
|
||||||
isPublished?: boolean;
|
isPublished?: boolean;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
search?: string;
|
||||||
|
|
||||||
@IsEnum(PostOrder, {
|
@IsEnum(PostOrder, {
|
||||||
message: `The sorting rule must be one of ${Object.values(PostOrder).join(',')}`,
|
message: `The sorting rule must be one of ${Object.values(PostOrder).join(',')}`,
|
||||||
})
|
})
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
export * from './category.service';
|
export * from './category.service';
|
||||||
export * from './tag.service';
|
export * from './tag.service';
|
||||||
export * from './comment.service';
|
export * from './comment.service';
|
||||||
|
export * from './search.service';
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { isNil } from '@nestjs/common/utils/shared.utils';
|
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 { EntityNotFoundError, In, IsNull, Not, SelectQueryBuilder } from 'typeorm';
|
||||||
|
|
||||||
import { PostOrder } from '@/modules/content/constants';
|
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 { PostEntity } from '@/modules/content/entities/post.entity';
|
||||||
import { CategoryRepository } from '@/modules/content/repositories';
|
import { CategoryRepository } from '@/modules/content/repositories';
|
||||||
import { PostRepository } from '@/modules/content/repositories/post.repository';
|
import { PostRepository } from '@/modules/content/repositories/post.repository';
|
||||||
|
import { SearchService } from '@/modules/content/services/search.service';
|
||||||
import { SearchType } from '@/modules/content/types';
|
import { SearchType } from '@/modules/content/types';
|
||||||
import { SelectTrashMode } from '@/modules/database/constants';
|
import { SelectTrashMode } from '@/modules/database/constants';
|
||||||
import { QueryHook } from '@/modules/database/types';
|
import { QueryHook } from '@/modules/database/types';
|
||||||
@ -29,10 +30,17 @@ export class PostService {
|
|||||||
protected categoryRepository: CategoryRepository,
|
protected categoryRepository: CategoryRepository,
|
||||||
protected categoryService: CategoryService,
|
protected categoryService: CategoryService,
|
||||||
protected tagRepository: TagRepository,
|
protected tagRepository: TagRepository,
|
||||||
|
protected searchService?: SearchService,
|
||||||
protected searchType: SearchType = 'mysql',
|
protected searchType: SearchType = 'mysql',
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async paginate(options: QueryPostDto, callback?: QueryHook<PostEntity>) {
|
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);
|
const qb = await this.buildListQuery(this.repository.buildBaseQB(), options, callback);
|
||||||
return paginate(qb, options);
|
return paginate(qb, options);
|
||||||
}
|
}
|
||||||
@ -62,7 +70,11 @@ export class PostService {
|
|||||||
publishedAt,
|
publishedAt,
|
||||||
};
|
};
|
||||||
const item = await this.repository.save(createPostDto);
|
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) {
|
async update(data: UpdatePostDto) {
|
||||||
@ -88,7 +100,11 @@ export class PostService {
|
|||||||
...omit(data, ['id', 'publish', 'tags', 'category']),
|
...omit(data, ['id', 'publish', 'tags', 'category']),
|
||||||
publishedAt,
|
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) {
|
async delete(ids: string[], trash?: boolean) {
|
||||||
@ -105,8 +121,15 @@ export class PostService {
|
|||||||
...(await this.repository.remove(directs)),
|
...(await this.repository.remove(directs)),
|
||||||
...(await this.repository.softRemove(softs)),
|
...(await this.repository.softRemove(softs)),
|
||||||
];
|
];
|
||||||
|
if (!isNil(this.searchService)) {
|
||||||
|
await this.searchService.delete(directs.map((item) => item.id));
|
||||||
|
await this.searchService.update(softs);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
result = await this.repository.remove(items);
|
result = await this.repository.remove(items);
|
||||||
|
if (!isNil(this.searchService)) {
|
||||||
|
await this.searchService.delete(ids);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -118,6 +141,7 @@ export class PostService {
|
|||||||
.withDeleted()
|
.withDeleted()
|
||||||
.getMany();
|
.getMany();
|
||||||
const trashes = items.filter((item) => !isNil(item.deleteAt));
|
const trashes = items.filter((item) => !isNil(item.deleteAt));
|
||||||
|
await this.searchService.update(trashes);
|
||||||
const trashedIds = trashes.map((item) => item.id);
|
const trashedIds = trashes.map((item) => item.id);
|
||||||
if (trashedIds.length < 1) {
|
if (trashedIds.length < 1) {
|
||||||
return [];
|
return [];
|
||||||
|
@ -14,7 +14,7 @@ import { SelectTrashMode } from '@/modules/database/constants';
|
|||||||
import { MeiliService } from '@/modules/meilisearch/meili.service';
|
import { MeiliService } from '@/modules/meilisearch/meili.service';
|
||||||
|
|
||||||
export class SearchService implements OnModuleInit {
|
export class SearchService implements OnModuleInit {
|
||||||
index = 'content';
|
private index = 'content';
|
||||||
|
|
||||||
protected client: MeiliSearch;
|
protected client: MeiliSearch;
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { SelectTrashMode } from '@/modules/database/constants';
|
import { SelectTrashMode } from '@/modules/database/constants';
|
||||||
|
|
||||||
export type SearchType = 'mysql';
|
export type SearchType = 'mysql' | 'meili';
|
||||||
|
|
||||||
export interface ContentConfig {
|
export interface ContentConfig {
|
||||||
SearchType?: SearchType;
|
SearchType?: SearchType;
|
||||||
|
Loading…
Reference in New Issue
Block a user