From 533a42eb2e9be2393b9c04355052362f020664bf Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Tue, 21 Oct 2025 19:54:50 -0700 Subject: [PATCH] clean-up session api endpoints and queries --- .../session-data/properties/route.ts | 6 ++-- .../[websiteId]/session-data/values/route.ts | 2 ++ .../[websiteId]/sessions/weekly/route.ts | 7 ++--- .../queries/useSessionDataPropertiesQuery.ts | 16 ++++++++-- .../queries/useSessionDataValuesQuery.ts | 16 ++++++++-- .../queries/useWebsiteSessionStatsQuery.ts | 7 +++-- .../hooks/queries/useWebsiteSessionsQuery.ts | 18 ++++++++---- .../sql/sessions/getSessionDataProperties.ts | 29 +++++++------------ .../sql/sessions/getSessionDataValues.ts | 1 + .../sql/sessions/getWebsiteSessions.ts | 5 ++-- 10 files changed, 64 insertions(+), 43 deletions(-) diff --git a/src/app/api/websites/[websiteId]/session-data/properties/route.ts b/src/app/api/websites/[websiteId]/session-data/properties/route.ts index 704ae519..64328ce5 100644 --- a/src/app/api/websites/[websiteId]/session-data/properties/route.ts +++ b/src/app/api/websites/[websiteId]/session-data/properties/route.ts @@ -3,6 +3,7 @@ import { getQueryFilters, parseRequest } from '@/lib/request'; import { unauthorized, json } from '@/lib/response'; import { canViewWebsite } from '@/permissions'; import { getSessionDataProperties } from '@/queries/sql'; +import { filterParams } from '@/lib/schema'; export async function GET( request: Request, @@ -11,7 +12,7 @@ export async function GET( const schema = z.object({ startAt: z.coerce.number().int(), endAt: z.coerce.number().int(), - propertyName: z.string().optional(), + ...filterParams, }); const { auth, query, error } = await parseRequest(request, schema); @@ -26,10 +27,9 @@ export async function GET( return unauthorized(); } - const { propertyName } = query; const filters = await getQueryFilters(query, websiteId); - const data = await getSessionDataProperties(websiteId, { ...filters, propertyName }); + const data = await getSessionDataProperties(websiteId, filters); return json(data); } diff --git a/src/app/api/websites/[websiteId]/session-data/values/route.ts b/src/app/api/websites/[websiteId]/session-data/values/route.ts index f95f5d43..75464ba4 100644 --- a/src/app/api/websites/[websiteId]/session-data/values/route.ts +++ b/src/app/api/websites/[websiteId]/session-data/values/route.ts @@ -3,6 +3,7 @@ import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { getSessionDataValues } from '@/queries/sql'; import { z } from 'zod'; +import { filterParams } from '@/lib/schema'; export async function GET( request: Request, @@ -12,6 +13,7 @@ export async function GET( startAt: z.coerce.number().int(), endAt: z.coerce.number().int(), propertyName: z.string().optional(), + ...filterParams, }); const { auth, query, error } = await parseRequest(request, schema); diff --git a/src/app/api/websites/[websiteId]/sessions/weekly/route.ts b/src/app/api/websites/[websiteId]/sessions/weekly/route.ts index af1a1f60..f3d17f94 100644 --- a/src/app/api/websites/[websiteId]/sessions/weekly/route.ts +++ b/src/app/api/websites/[websiteId]/sessions/weekly/route.ts @@ -1,9 +1,9 @@ -import { z } from 'zod'; import { getQueryFilters, parseRequest } from '@/lib/request'; -import { unauthorized, json } from '@/lib/response'; +import { json, unauthorized } from '@/lib/response'; +import { filterParams, timezoneParam } from '@/lib/schema'; import { canViewWebsite } from '@/permissions'; -import { filterParams, pagingParams, timezoneParam } from '@/lib/schema'; import { getWeeklyTraffic } from '@/queries/sql'; +import { z } from 'zod'; export async function GET( request: Request, @@ -14,7 +14,6 @@ export async function GET( endAt: z.coerce.number().int(), timezone: timezoneParam, ...filterParams, - ...pagingParams, }); const { auth, query, error } = await parseRequest(request, schema); diff --git a/src/components/hooks/queries/useSessionDataPropertiesQuery.ts b/src/components/hooks/queries/useSessionDataPropertiesQuery.ts index 2bb13950..975c728a 100644 --- a/src/components/hooks/queries/useSessionDataPropertiesQuery.ts +++ b/src/components/hooks/queries/useSessionDataPropertiesQuery.ts @@ -5,12 +5,22 @@ import { ReactQueryOptions } from '@/lib/types'; export function useSessionDataPropertiesQuery(websiteId: string, options?: ReactQueryOptions) { const { get, useQuery } = useApi(); - const date = useDateParameters(); + const { startAt, endAt, unit, timezone } = useDateParameters(); const filters = useFilterParameters(); return useQuery({ - queryKey: ['websites:session-data:properties', { websiteId, ...date, ...filters }], - queryFn: () => get(`/websites/${websiteId}/session-data/properties`, { ...date, ...filters }), + queryKey: [ + 'websites:session-data:properties', + { websiteId, startAt, endAt, unit, timezone, ...filters }, + ], + queryFn: () => + get(`/websites/${websiteId}/session-data/properties`, { + startAt, + endAt, + unit, + timezone, + ...filters, + }), enabled: !!websiteId, ...options, }); diff --git a/src/components/hooks/queries/useSessionDataValuesQuery.ts b/src/components/hooks/queries/useSessionDataValuesQuery.ts index 05373d21..7df35938 100644 --- a/src/components/hooks/queries/useSessionDataValuesQuery.ts +++ b/src/components/hooks/queries/useSessionDataValuesQuery.ts @@ -9,13 +9,23 @@ export function useSessionDataValuesQuery( options?: ReactQueryOptions, ) { const { get, useQuery } = useApi(); - const date = useDateParameters(); + const { startAt, endAt, unit, timezone } = useDateParameters(); const filters = useFilterParameters(); return useQuery({ - queryKey: ['websites:session-data:values', { websiteId, propertyName, ...date, ...filters }], + queryKey: [ + 'websites:session-data:values', + { websiteId, propertyName, startAt, endAt, unit, timezone, ...filters }, + ], queryFn: () => - get(`/websites/${websiteId}/session-data/values`, { ...date, ...filters, propertyName }), + get(`/websites/${websiteId}/session-data/values`, { + startAt, + endAt, + unit, + timezone, + ...filters, + propertyName, + }), enabled: !!(websiteId && propertyName), ...options, }); diff --git a/src/components/hooks/queries/useWebsiteSessionStatsQuery.ts b/src/components/hooks/queries/useWebsiteSessionStatsQuery.ts index 9c9aaddc..82a7c05f 100644 --- a/src/components/hooks/queries/useWebsiteSessionStatsQuery.ts +++ b/src/components/hooks/queries/useWebsiteSessionStatsQuery.ts @@ -4,12 +4,13 @@ import { useDateParameters } from '../useDateParameters'; export function useWebsiteSessionStatsQuery(websiteId: string, options?: Record) { const { get, useQuery } = useApi(); - const date = useDateParameters(); + const { startAt, endAt, unit, timezone } = useDateParameters(); const filters = useFilterParameters(); return useQuery({ - queryKey: ['sessions:stats', { websiteId, ...date, ...filters }], - queryFn: () => get(`/websites/${websiteId}/sessions/stats`, { ...date, ...filters }), + queryKey: ['sessions:stats', { websiteId, startAt, endAt, unit, timezone, ...filters }], + queryFn: () => + get(`/websites/${websiteId}/sessions/stats`, { startAt, endAt, unit, timezone, ...filters }), enabled: !!websiteId, ...options, }); diff --git a/src/components/hooks/queries/useWebsiteSessionsQuery.ts b/src/components/hooks/queries/useWebsiteSessionsQuery.ts index a3de19ca..31906be9 100644 --- a/src/components/hooks/queries/useWebsiteSessionsQuery.ts +++ b/src/components/hooks/queries/useWebsiteSessionsQuery.ts @@ -1,8 +1,8 @@ import { useApi } from '../useApi'; -import { usePagedQuery } from '../usePagedQuery'; -import { useModified } from '../useModified'; -import { useFilterParameters } from '../useFilterParameters'; import { useDateParameters } from '../useDateParameters'; +import { useFilterParameters } from '../useFilterParameters'; +import { useModified } from '../useModified'; +import { usePagedQuery } from '../usePagedQuery'; export function useWebsiteSessionsQuery( websiteId: string, @@ -10,14 +10,20 @@ export function useWebsiteSessionsQuery( ) { const { get } = useApi(); const { modified } = useModified(`sessions`); - const date = useDateParameters(); + const { startAt, endAt, unit, timezone } = useDateParameters(); const filters = useFilterParameters(); return usePagedQuery({ - queryKey: ['sessions', { websiteId, modified, ...params, ...date, ...filters }], + queryKey: [ + 'sessions', + { websiteId, modified, startAt, endAt, unit, timezone, ...params, ...filters }, + ], queryFn: pageParams => { return get(`/websites/${websiteId}/sessions`, { - ...date, + startAt, + endAt, + unit, + timezone, ...filters, ...pageParams, ...params, diff --git a/src/queries/sql/sessions/getSessionDataProperties.ts b/src/queries/sql/sessions/getSessionDataProperties.ts index 134cf720..78e4cba4 100644 --- a/src/queries/sql/sessions/getSessionDataProperties.ts +++ b/src/queries/sql/sessions/getSessionDataProperties.ts @@ -1,12 +1,12 @@ -import prisma from '@/lib/prisma'; import clickhouse from '@/lib/clickhouse'; import { CLICKHOUSE, PRISMA, runQuery } from '@/lib/db'; +import prisma from '@/lib/prisma'; import { QueryFilters } from '@/lib/types'; const FUNCTION_NAME = 'getSessionDataProperties'; export async function getSessionDataProperties( - ...args: [websiteId: string, filters: QueryFilters & { propertyName?: string }] + ...args: [websiteId: string, filters: QueryFilters] ) { return runQuery({ [PRISMA]: () => relationalQuery(...args), @@ -14,17 +14,12 @@ export async function getSessionDataProperties( }); } -async function relationalQuery( - websiteId: string, - filters: QueryFilters & { propertyName?: string }, -) { +async function relationalQuery(websiteId: string, filters: QueryFilters) { const { rawQuery, parseFilters } = prisma; - const { filterQuery, joinSessionQuery, cohortQuery, queryParams } = parseFilters( - { ...filters, websiteId }, - { - columns: { propertyName: 'data_key' }, - }, - ); + const { filterQuery, joinSessionQuery, cohortQuery, queryParams } = parseFilters({ + ...filters, + websiteId, + }); return rawQuery( ` @@ -50,15 +45,10 @@ async function relationalQuery( async function clickhouseQuery( websiteId: string, - filters: QueryFilters & { propertyName?: string }, + filters: QueryFilters, ): Promise<{ propertyName: string; total: number }[]> { const { rawQuery, parseFilters } = clickhouse; - const { filterQuery, cohortQuery, queryParams } = parseFilters( - { ...filters, websiteId }, - { - columns: { propertyName: 'data_key' }, - }, - ); + const { filterQuery, cohortQuery, queryParams } = parseFilters({ ...filters, websiteId }); return rawQuery( ` @@ -69,6 +59,7 @@ async function clickhouseQuery( ${cohortQuery} join session_data final on session_data.session_id = website_event.session_id + and session_data.website_id = {websiteId:UUID} where website_event.website_id = {websiteId:UUID} and website_event.created_at between {startDate:DateTime64} and {endDate:DateTime64} and session_data.data_key != '' diff --git a/src/queries/sql/sessions/getSessionDataValues.ts b/src/queries/sql/sessions/getSessionDataValues.ts index 8da12669..efc85090 100644 --- a/src/queries/sql/sessions/getSessionDataValues.ts +++ b/src/queries/sql/sessions/getSessionDataValues.ts @@ -69,6 +69,7 @@ async function clickhouseQuery( ${cohortQuery} join session_data final on session_data.session_id = website_event.session_id + and session_data.website_id = {websiteId:UUID} where website_event.website_id = {websiteId:UUID} and website_event.created_at between {startDate:DateTime64} and {endDate:DateTime64} and session_data.data_key = {propertyName:String} diff --git a/src/queries/sql/sessions/getWebsiteSessions.ts b/src/queries/sql/sessions/getWebsiteSessions.ts index 44b52d8e..302deca6 100644 --- a/src/queries/sql/sessions/getWebsiteSessions.ts +++ b/src/queries/sql/sessions/getWebsiteSessions.ts @@ -98,6 +98,7 @@ async function clickhouseQuery(websiteId: string, filters: QueryFilters) { select session_id as id, website_id as websiteId, + hostname, browser, os, device, @@ -117,7 +118,7 @@ async function clickhouseQuery(websiteId: string, filters: QueryFilters) { ${dateQuery} ${filterQuery} ${searchQuery} - group by session_id, website_id, browser, os, device, screen, language, country, region, city + group by session_id, website_id, hostname, browser, os, device, screen, language, country, region, city order by lastAt desc `; } else { @@ -125,7 +126,7 @@ async function clickhouseQuery(websiteId: string, filters: QueryFilters) { select session_id as id, website_id as websiteId, - hostname, + arrayFirst(x -> 1, hostname) hostname, browser, os, device,