Files
shorturl-analytics/app/api/links/repository.ts
2025-03-21 12:08:37 +08:00

157 lines
3.4 KiB
TypeScript

import { executeQuery, executeQuerySingle } from '@/lib/clickhouse';
import { Link, LinkQueryParams } from '../types';
/**
* Find links with filtering options
*/
export async function findLinks({
limit = 10,
offset = 0,
searchTerm = '',
tagFilter = '',
isActive = null,
}: LinkQueryParams) {
// Build WHERE conditions
const conditions = [];
if (searchTerm) {
conditions.push(`
(lower(title) LIKE lower('%${searchTerm}%') OR
lower(original_url) LIKE lower('%${searchTerm}%'))
`);
}
if (tagFilter) {
conditions.push(`hasAny(tags, ['${tagFilter}'])`);
}
if (isActive !== null) {
conditions.push(`is_active = ${isActive ? 'true' : 'false'}`);
}
const whereClause = conditions.length > 0
? `WHERE ${conditions.join(' AND ')}`
: '';
// Get total count
const countQuery = `
SELECT count() as total
FROM links
${whereClause}
`;
const countData = await executeQuery<{ total: number }>(countQuery);
const total = countData.length > 0 ? countData[0].total : 0;
// 使用左连接获取链接数据和统计信息
const linksQuery = `
SELECT
l.link_id,
l.original_url,
l.created_at,
l.created_by,
l.title,
l.description,
l.tags,
l.is_active,
l.expires_at,
l.team_id,
l.project_id,
count(le.event_id) as visits,
count(DISTINCT le.visitor_id) as unique_visits
FROM links l
LEFT JOIN link_events le ON l.link_id = le.link_id
${whereClause}
GROUP BY
l.link_id,
l.original_url,
l.created_at,
l.created_by,
l.title,
l.description,
l.tags,
l.is_active,
l.expires_at,
l.team_id,
l.project_id
ORDER BY l.created_at DESC
LIMIT ${limit}
OFFSET ${offset}
`;
const links = await executeQuery<Link>(linksQuery);
return {
links,
total,
limit,
offset,
page: Math.floor(offset / limit) + 1,
totalPages: Math.ceil(total / limit)
};
}
/**
* Find a single link by ID
*/
export async function findLinkById(linkId: string): Promise<Link | null> {
const query = `
SELECT
l.link_id,
l.original_url,
l.created_at,
l.created_by,
l.title,
l.description,
l.tags,
l.is_active,
l.expires_at,
l.team_id,
l.project_id,
count(le.event_id) as visits,
count(DISTINCT le.visitor_id) as unique_visits
FROM links l
LEFT JOIN link_events le ON l.link_id = le.link_id
WHERE l.link_id = '${linkId}'
GROUP BY
l.link_id,
l.original_url,
l.created_at,
l.created_by,
l.title,
l.description,
l.tags,
l.is_active,
l.expires_at,
l.team_id,
l.project_id
LIMIT 1
`;
return await executeQuerySingle<Link>(query);
}
/**
* Find a single link by ID - only basic info without statistics
*/
export async function findLinkDetailsById(linkId: string): Promise<Omit<Link, 'visits' | 'unique_visits'> | null> {
const query = `
SELECT
link_id,
original_url,
created_at,
created_by,
title,
description,
tags,
is_active,
expires_at,
team_id,
project_id
FROM links
WHERE link_id = '${linkId}'
LIMIT 1
`;
return await executeQuerySingle<Omit<Link, 'visits' | 'unique_visits'>>(query);
}