UNPKG

@shirokuma-library/mcp-knowledge-base

Version:

MCP server for AI-powered knowledge management with semantic search, graph analysis, and automatic enrichment

121 lines (120 loc) 4.97 kB
import { Item } from '../entities/Item.js'; import { AppDataSource } from '../data-source.js'; import { SearchQueryParser } from '../services/SearchQueryParser.js'; import { StatusRepository } from './StatusRepository.js'; export class ItemRepository { repository; constructor() { this.repository = AppDataSource.getRepository(Item); } async create(data) { const item = this.repository.create(data); return await this.repository.save(item); } async findById(id) { return await this.repository.findOne({ where: { id } }); } async findAll(options) { const query = this.repository.createQueryBuilder('item'); let needsStatusJoin = false; if (options?.status) { query.leftJoinAndSelect('item.status', 'status') .andWhere('LOWER(status.name) = LOWER(:statusName)', { statusName: options.status }); needsStatusJoin = true; } else if (options?.onlyActive || (!options?.includeClosable && options?.includeClosable !== true)) { query.leftJoinAndSelect('item.status', 'status') .andWhere('status.isClosable = :isClosable', { isClosable: false }); needsStatusJoin = true; } else if (options?.includeClosable === true) { query.leftJoinAndSelect('item.status', 'status'); needsStatusJoin = true; } if (options?.type) { query.andWhere('item.type = :type', { type: options.type }); } if (options?.limit) { query.limit(options.limit); } if (options?.offset) { query.offset(options.offset); } query.orderBy('item.createdAt', 'DESC'); return await query.getMany(); } async update(id, data) { await this.repository.update(id, data); return await this.findById(id); } async delete(id) { const result = await this.repository.delete(id); return result.affected !== 0; } async searchAdvanced(parsedQuery) { const queryBuilder = this.repository.createQueryBuilder('item') .leftJoinAndSelect('item.status', 'status'); if (parsedQuery.filters.status?.length) { const statusRepo = new StatusRepository(); const statusIds = []; for (const statusName of parsedQuery.filters.status) { const status = await statusRepo.findByName(statusName); if (status) statusIds.push(status.id); } if (statusIds.length > 0) { queryBuilder.andWhere('item.statusId IN (:...statusIds)', { statusIds }); } } if (parsedQuery.filters.type?.length) { queryBuilder.andWhere('item.type IN (:...types)', { types: parsedQuery.filters.type }); } if (parsedQuery.filters.is) { const isClosable = parsedQuery.filters.is === 'closed'; queryBuilder.andWhere('status.isClosable = :isClosable', { isClosable }); } if (parsedQuery.keywords.length > 0) { const keywordConditions = parsedQuery.keywords.map((_, index) => `(item.title LIKE :kw${index} OR item.description LIKE :kw${index} OR item.content LIKE :kw${index})`).join(' AND '); const keywordParams = {}; parsedQuery.keywords.forEach((kw, index) => { keywordParams[`kw${index}`] = `%${kw}%`; }); if (keywordConditions) { queryBuilder.andWhere(`(${keywordConditions})`, keywordParams); } } return queryBuilder.orderBy('item.updatedAt', 'DESC').getMany(); } async searchLegacy(query) { return await this.repository .createQueryBuilder('item') .where('item.title LIKE :query', { query: `%${query}%` }) .orWhere('item.description LIKE :query', { query: `%${query}%` }) .orWhere('item.content LIKE :query', { query: `%${query}%` }) .orderBy('item.updatedAt', 'DESC') .getMany(); } async search(query) { const parser = new SearchQueryParser(); const parsed = parser.parse(query); if (Object.keys(parsed.filters).length === 0 && parsed.keywords.length === 0) { return this.searchLegacy(query); } if (Object.keys(parsed.filters).length === 0 && parsed.keywords.length > 0) { return this.searchLegacy(query); } return this.searchAdvanced(parsed); } async count(options) { const query = this.repository.createQueryBuilder('item'); if (options?.type) { query.andWhere('item.type = :type', { type: options.type }); } if (options?.status) { query.andWhere('item.status = :status', { status: options.status }); } return await query.getCount(); } }