import { fetchGraphQL } from './graphql-client.js'; import type { ProfileArticle } from '../types/graphql.js'; //кэширование import { cache } from '@lib/cache/manager.js'; import { CACHE_TTL } from '@lib/cache/cache-ttl'; export interface AnewsPost { title: string; uri: string; date: string; } export async function getLatestPosts(first = 14, after = null) { // Создаем уникальный ключ для кэша const cacheKey = `latest-posts:${first}:${after || 'first-page'}`; return await cache.wrap( cacheKey, async () => { const query = ` query GetLatestProfileArticles($first: Int!, $after: String) { profileArticles( first: $first after: $after where: { orderby: { field: DATE, order: DESC } } ) { pageInfo { hasNextPage endCursor } edges { cursor node { id databaseId title uri date featuredImage { node { sourceUrl(size: LARGE) altText } } author { node { id name firstName lastName avatar { url } uri } } # Соавторы как массив coauthors { id name firstName lastName url description } categories { nodes { id name color slug uri databaseId } } tags { nodes { id name slug uri } } } } } } `; const data = await fetchGraphQL(query, { first, after }); // Преобразуем edges в nodes const posts = data.profileArticles?.edges?.map(edge => edge.node) || []; return { posts, pageInfo: data.profileArticles?.pageInfo || { hasNextPage: false, endCursor: null } }; }, { ttl: CACHE_TTL.POSTS } // из конфигурации ); } //последние новости (кэшированная версия) export async function getLatestAnews(count = 12): Promise { const cacheKey = `latest-anews:${count}`; return await cache.wrap( cacheKey, async () => { const query = ` query GetAnews($count: Int!) { aNews(first: $count, where: {orderby: {field: DATE, order: DESC}}) { nodes { title uri date } } } `; const data = await fetchGraphQL(query, { count }); return data.aNews?.nodes || []; }, { ttl: CACHE_TTL.POSTS } ); } // Получить ProfileArticle по databaseId export async function getProfileArticleById(databaseId) { const query = ` query GetProfileArticleById($id: ID!) { profileArticle(id: $id, idType: DATABASE_ID) { id databaseId title secondaryTitle content excerpt uri slug date modified status featuredImage { node { id sourceUrl altText caption description mediaDetails { width height } } } author { node { id name firstName lastName avatar { url } description uri } } # Соавторы как массив coauthors { id name firstName lastName url description } categories { nodes { id name slug uri description } } tags { nodes { id name slug uri } } } } `; const data = await fetchGraphQL(query, { id: databaseId }); return data?.profileArticle || null; } /** * Получить Anews пост по databaseId */ export async function getAnewsById(databaseId: number): Promise { const cacheKey = `anews:${databaseId}`; return await cache.wrap( cacheKey, async () => { const query = ` query GetAnewsById($id: ID!) { aNews(id: $id, idType: DATABASE_ID) { id databaseId title content excerpt uri slug date modified status featuredImage { node { id sourceUrl altText caption mediaDetails { width height } } } author { node { id name firstName lastName avatar { url } description uri } } categories { nodes { id name slug uri description } } tags { nodes { id name slug uri } } seo { title metaDesc canonical opengraphTitle opengraphDescription opengraphImage { sourceUrl } } } } `; try { const data = await fetchGraphQL(query, { id: databaseId }); return data?.aNews || null; } catch (error) { console.error(`Error fetching Anews post with ID ${databaseId}:`, error); return null; } }, { ttl: CACHE_TTL.POST_DETAIL } // Можно использовать отдельный TTL для деталей постов ); } /** * Получить тег по slug */ export async function getTagBySlug(slug) { const query = ` query GetTagBySlug($slug: ID!) { tag(id: $slug, idType: SLUG) { id databaseId name slug description count } } `; try { const data = await fetchGraphQL(query, { slug }); return data?.tag || null; } catch (error) { console.error('Error fetching tag:', error); return null; } } /** * Получить тег с постами по slug с пагинацией */ export async function getTagWithPostsPaginated( tagSlug: string, perPage: number = 12, page: number = 1 ) { const offset = (page - 1) * perPage; const query = ` query GetTagWithPostsPaginated($slug: ID!, $first: Int!, $offset: Int!) { tag(id: $slug, idType: SLUG) { id databaseId name slug description count seo { title metaDesc canonical opengraphTitle opengraphDescription opengraphImage { sourceUrl } } posts( first: $first offset: $offset where: { orderby: { field: DATE, order: DESC } } ) { nodes { id databaseId title excerpt uri slug date modified featuredImage { node { sourceUrl(size: MEDIUM_LARGE) altText caption mediaDetails { width height } } } author { node { id name firstName lastName avatar { url } } } categories { nodes { id name slug uri } } tags { nodes { id name slug } } seo { title metaDesc } } pageInfo { offsetPagination { total } } } } } `; try { const data = await fetchGraphQL(query, { slug: tagSlug, first: perPage, offset }); const tag = data?.tag; if (!tag) { return { tag: null, posts: [], total: 0, totalPages: 0, currentPage: page, hasNext: false, hasPrevious: false }; } const posts = tag.posts?.nodes || []; const total = tag.posts?.pageInfo?.offsetPagination?.total || 0; const totalPages = Math.ceil(total / perPage); return { tag, posts, total, totalPages, currentPage: page, hasNext: page < totalPages, hasPrevious: page > 1, perPage }; } catch (error) { console.error('Error fetching tag with posts:', error); return { tag: null, posts: [], total: 0, totalPages: 0, currentPage: page, hasNext: false, hasPrevious: false }; } } /** * Получить общее количество постов для всех тегов */ export async function getAllTagsWithCount(first = 100) { const query = ` query GetAllTagsWithCount($first: Int!) { tags(first: $first, where: { hideEmpty: true }) { nodes { id databaseId name slug count posts(first: 1) { pageInfo { offsetPagination { total } } } } } } `; const data = await fetchGraphQL(query, { first }); return data?.tags?.nodes || []; }