Skip to main content
Glama

News Aggregator API

article.repository.ts6.91 kB
/** * Article repository implementation */ import { Article, ArticleCreateInput, ArticleOrderByWithRelationInput } from '../models/prisma.types'; import { prisma } from '../utils/db'; import { ISearchableRepository, SearchOptions, SearchResult } from './base.repository'; import { logger } from '../utils/logger'; /** * Repository for article data access */ export class ArticleRepository implements ISearchableRepository<Article, number> { /** * Find article by ID * @param id Article ID * @returns Article or null if not found */ async findById(id: number): Promise<Article | null> { try { return await prisma.article.findUnique({ where: { id } }); } catch (error) { logger.error('Error finding article by ID:', error); throw error; } } /** * Find all articles * @returns Array of articles */ async findAll(): Promise<Article[]> { try { return await prisma.article.findMany(); } catch (error) { logger.error('Error finding all articles:', error); throw error; } } /** * Create a new article * @param data Article data * @returns Created article */ async create(data: Omit<Article, 'id' | 'createdAt' | 'updatedAt'>): Promise<Article> { try { return await prisma.article.create({ data: data as ArticleCreateInput }); } catch (error) { logger.error('Error creating article:', error); throw error; } } /** * Update an article * @param id Article ID * @param data Updated article data * @returns Updated article */ async update(id: number, data: Partial<Article>): Promise<Article> { try { return await prisma.article.update({ where: { id }, data }); } catch (error) { logger.error('Error updating article:', error); throw error; } } /** * Delete an article * @param id Article ID * @returns True if deleted, false otherwise */ async delete(id: number): Promise<boolean> { try { await prisma.article.delete({ where: { id } }); return true; } catch (error) { logger.error('Error deleting article:', error); return false; } } /** * Search articles with filtering, sorting, and pagination * @param options Search options * @returns Search results with pagination metadata */ async search(options: SearchOptions): Promise<SearchResult<Article>> { const { skip = 0, take = 10, orderBy = { publishedAt: 'desc' }, where = {} } = options; const page = Math.floor(skip / take) + 1; try { // Get total count for pagination const total = await prisma.article.count({ where }); // Get results with pagination const items = await prisma.article.findMany({ skip, take, where, orderBy: orderBy as ArticleOrderByWithRelationInput }); const totalPages = Math.ceil(total / take); return { items, total, page, limit: take, totalPages, hasNext: page < totalPages, hasPrevious: page > 1 }; } catch (error) { logger.error('Error searching articles:', error); throw error; } } /** * Find article by UUID * @param uuid Article UUID * @returns Article or null if not found */ async findByUuid(uuid: string): Promise<Article | null> { try { return await prisma.article.findUnique({ where: { uuid } }); } catch (error) { logger.error('Error finding article by UUID:', error); throw error; } } /** * Get article with relationships (topics, entities) * @param id Article ID * @returns Article with relationships or null if not found */ async getArticleWithRelations(id: number): Promise<any | null> { try { return await prisma.article.findUnique({ where: { id }, include: { topics: { include: { topic: true } }, entities: { include: { entity: true } } } }); } catch (error) { logger.error('Error getting article with relations:', error); throw error; } } /** * Update article read count * @param id Article ID * @returns Updated article */ async incrementReadCount(id: number): Promise<Article> { try { return await prisma.article.update({ where: { id }, data: { readCount: { increment: 1 } } }); } catch (error) { logger.error('Error incrementing article read count:', error); throw error; } } /** * Find articles by category * @param category Category to search for * @param limit Maximum number of articles to return * @returns Array of articles */ async findByCategory(category: string, limit: number = 10): Promise<Article[]> { try { return await prisma.article.findMany({ where: { categories: { contains: category, } }, take: limit, orderBy: { publishedAt: 'desc' } }); } catch (error) { logger.error(`Error finding articles by category ${category}:`, error); throw error; } } /** * Find similar articles based on topics and entities * @param articleId Base article ID * @param limit Maximum number of similar articles to return * @returns Array of similar articles */ async findSimilarArticles(articleId: number, limit: number = 5): Promise<Article[]> { try { // Get the article with its topics and entities const article = await this.getArticleWithRelations(articleId); if (!article) { return []; } // Extract topics and entities IDs const topicIds = article.topics.map((t: any) => t.topicId); const entityIds = article.entities.map((e: any) => e.entityId); // Find articles with similar topics or entities return await prisma.article.findMany({ where: { id: { not: articleId }, OR: [ { topics: { some: { topicId: { in: topicIds } } } }, { entities: { some: { entityId: { in: entityIds } } } } ] }, take: limit, orderBy: { publishedAt: 'desc' } }); } catch (error) { logger.error(`Error finding similar articles for article ${articleId}:`, error); throw error; } } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Malachi-devel/the-news-api-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server