From 8b64029409f4a5de5c05291126c95dd58ddd4636 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Sun, 29 Jun 2025 23:57:11 -0700 Subject: [PATCH] Made filters work for all reports. --- .../websites/[websiteId]/WebsiteControls.tsx | 2 +- .../[websiteId]/reports/ReportsNav.tsx | 2 +- .../reports/attribution/Attribution.tsx | 120 +++++++++--------- .../reports/revenue/RevenuePage.tsx | 2 +- .../websites/[websiteId]/reports/utm/UTM.tsx | 82 ++++++------ src/app/api/reports/attribution/route.ts | 2 + src/app/api/reports/breakdown/route.ts | 4 +- src/app/api/reports/funnel/route.ts | 2 + src/app/api/reports/goal/route.ts | 6 +- src/app/api/reports/journey/route.ts | 2 + src/app/api/reports/retention/route.ts | 2 + src/app/api/reports/revenue/route.ts | 2 + src/app/api/reports/utm/route.ts | 2 + .../hooks/queries/useResultQuery.ts | 6 +- src/components/hooks/useFilterParams.ts | 2 + src/components/hooks/usePagedQuery.ts | 2 +- src/components/metrics/WorldMap.tsx | 16 +-- src/lib/clickhouse.ts | 2 +- src/lib/prisma.ts | 2 +- src/queries/sql/events/getEventDataEvents.ts | 12 +- src/queries/sql/events/getEventDataFields.ts | 14 +- .../sql/events/getEventDataProperties.ts | 8 +- src/queries/sql/events/getEventDataStats.ts | 8 +- src/queries/sql/events/getEventDataValues.ts | 15 ++- src/queries/sql/events/getEventMetrics.ts | 8 +- src/queries/sql/events/getWebsiteEvents.ts | 8 +- src/queries/sql/getChannelMetrics.ts | 8 +- src/queries/sql/getRealtimeActivity.ts | 8 +- src/queries/sql/getWebsiteDateRange.ts | 12 +- src/queries/sql/getWebsiteStats.ts | 8 +- .../sql/pageviews/getPageviewMetrics.ts | 8 +- src/queries/sql/pageviews/getPageviewStats.ts | 8 +- src/queries/sql/reports/getAttribution.ts | 105 ++++++++------- src/queries/sql/reports/getBreakdown.ts | 8 +- src/queries/sql/reports/getFunnel.ts | 5 +- src/queries/sql/reports/getGoal.ts | 8 +- src/queries/sql/reports/getJourney.ts | 10 +- src/queries/sql/reports/getRetention.ts | 12 +- src/queries/sql/reports/getUTM.ts | 10 +- .../sql/sessions/getSessionDataProperties.ts | 12 +- .../sql/sessions/getSessionDataValues.ts | 8 +- src/queries/sql/sessions/getSessionMetrics.ts | 8 +- src/queries/sql/sessions/getSessionStats.ts | 8 +- .../sql/sessions/getWebsiteSessionStats.ts | 8 +- .../sql/sessions/getWebsiteSessions.ts | 8 +- .../sql/sessions/getWebsiteSessionsWeekly.ts | 8 +- 46 files changed, 328 insertions(+), 275 deletions(-) diff --git a/src/app/(main)/websites/[websiteId]/WebsiteControls.tsx b/src/app/(main)/websites/[websiteId]/WebsiteControls.tsx index 97fabf2a..655e8ea0 100644 --- a/src/app/(main)/websites/[websiteId]/WebsiteControls.tsx +++ b/src/app/(main)/websites/[websiteId]/WebsiteControls.tsx @@ -24,7 +24,7 @@ export function WebsiteControls({ {allowDateFilter && } {allowMonthFilter && } - + {allowFilter && } ); } diff --git a/src/app/(main)/websites/[websiteId]/reports/ReportsNav.tsx b/src/app/(main)/websites/[websiteId]/reports/ReportsNav.tsx index f073a12d..3741bc53 100644 --- a/src/app/(main)/websites/[websiteId]/reports/ReportsNav.tsx +++ b/src/app/(main)/websites/[websiteId]/reports/ReportsNav.tsx @@ -70,7 +70,7 @@ export function ReportsNav({ websiteId }: { websiteId: string }) { key={id} href={renderUrl( `/websites/${websiteId}/reports${path}`, - path === '/retention' ? false : null, + path === '/retention' ? { date: undefined } : null, )} > diff --git a/src/app/(main)/websites/[websiteId]/reports/attribution/Attribution.tsx b/src/app/(main)/websites/[websiteId]/reports/attribution/Attribution.tsx index ae56329a..87ea170d 100644 --- a/src/app/(main)/websites/[websiteId]/reports/attribution/Attribution.tsx +++ b/src/app/(main)/websites/[websiteId]/reports/attribution/Attribution.tsx @@ -48,8 +48,8 @@ export function Attribution({ const metrics = data ? [ { - value: pageviews, - label: formatMessage(labels.views), + value: visitors, + label: formatMessage(labels.visitors), formatValue: formatLongNumber, }, { @@ -58,8 +58,8 @@ export function Attribution({ formatValue: formatLongNumber, }, { - value: visitors, - label: formatMessage(labels.visitors), + value: pageviews, + label: formatMessage(labels.views), formatValue: formatLongNumber, }, ] @@ -83,60 +83,64 @@ export function Attribution({ return ( - - - {metrics?.map(({ label, value, formatValue }) => { - return ; - })} - - - - - ({ - x: name, - y: Number(value), - })), - )} - /> - - - ({ - x: name, - y: Number(value), - })), - )} - /> - - - - - - - - - - - - - - - - - - - - - + {data && ( + + + {metrics?.map(({ label, value, formatValue }) => { + return ( + + ); + })} + + + + + ({ + x: name, + y: Number(value), + })), + )} + /> + + + ({ + x: name, + y: Number(value), + })), + )} + /> + + + + + + + + + + + + + + + + + + + + + + )} ); } diff --git a/src/app/(main)/websites/[websiteId]/reports/revenue/RevenuePage.tsx b/src/app/(main)/websites/[websiteId]/reports/revenue/RevenuePage.tsx index 4c5998d5..9232d7be 100644 --- a/src/app/(main)/websites/[websiteId]/reports/revenue/RevenuePage.tsx +++ b/src/app/(main)/websites/[websiteId]/reports/revenue/RevenuePage.tsx @@ -11,7 +11,7 @@ export function RevenuePage({ websiteId }: { websiteId: string }) { return ( - + ); diff --git a/src/app/(main)/websites/[websiteId]/reports/utm/UTM.tsx b/src/app/(main)/websites/[websiteId]/reports/utm/UTM.tsx index fa9383e1..afa8c842 100644 --- a/src/app/(main)/websites/[websiteId]/reports/utm/UTM.tsx +++ b/src/app/(main)/websites/[websiteId]/reports/utm/UTM.tsx @@ -26,47 +26,49 @@ export function UTM({ websiteId, startDate, endDate }: UTMProps) { return ( - - {UTM_PARAMS.map(param => { - const items = toArray(data?.[param]); - const chartData = { - labels: items.map(({ name }) => name), - datasets: [ - { - data: items.map(({ value }) => value), - backgroundColor: CHART_COLORS, - borderWidth: 0, - }, - ], - }; - const total = items.reduce((sum, { value }) => { - return +sum + +value; - }, 0); + {data && ( + + {UTM_PARAMS.map(param => { + const items = toArray(data?.[param]); + const chartData = { + labels: items.map(({ name }) => name), + datasets: [ + { + data: items.map(({ value }) => value), + backgroundColor: CHART_COLORS, + borderWidth: 0, + }, + ], + }; + const total = items.reduce((sum, { value }) => { + return +sum + +value; + }, 0); - return ( - - - - - {param.replace(/^utm_/, '')} - - ({ - x: name, - y: value, - z: (value / total) * 100, - }))} - /> - - - - - - - ); - })} - + return ( + + + + + {param.replace(/^utm_/, '')} + + ({ + x: name, + y: value, + z: (value / total) * 100, + }))} + /> + + + + + + + ); + })} + + )} ); } diff --git a/src/app/api/reports/attribution/route.ts b/src/app/api/reports/attribution/route.ts index ef6f8650..e8384895 100644 --- a/src/app/api/reports/attribution/route.ts +++ b/src/app/api/reports/attribution/route.ts @@ -15,6 +15,7 @@ export async function POST(request: Request) { websiteId, dateRange: { startDate, endDate }, parameters: { model, type, step, currency }, + ...filters } = body; if (!(await canViewWebsite(auth, websiteId))) { @@ -22,6 +23,7 @@ export async function POST(request: Request) { } const data = await getAttribution(websiteId, { + ...filters, startDate: new Date(startDate), endDate: new Date(endDate), model, diff --git a/src/app/api/reports/breakdown/route.ts b/src/app/api/reports/breakdown/route.ts index de822f63..d97a552c 100644 --- a/src/app/api/reports/breakdown/route.ts +++ b/src/app/api/reports/breakdown/route.ts @@ -15,7 +15,7 @@ export async function POST(request: Request) { websiteId, dateRange: { startDate, endDate }, parameters: { fields }, - filters, + ...filters } = body; if (!(await canViewWebsite(auth, websiteId))) { @@ -23,9 +23,9 @@ export async function POST(request: Request) { } const data = await getBreakdown(websiteId, fields, { + ...filters, startDate: new Date(startDate), endDate: new Date(endDate), - ...filters, }); return json(data); diff --git a/src/app/api/reports/funnel/route.ts b/src/app/api/reports/funnel/route.ts index 7c50b8aa..335776bf 100644 --- a/src/app/api/reports/funnel/route.ts +++ b/src/app/api/reports/funnel/route.ts @@ -15,6 +15,7 @@ export async function POST(request: Request) { websiteId, dateRange: { startDate, endDate }, parameters: { steps, window }, + ...filters } = body; if (!(await canViewWebsite(auth, websiteId))) { @@ -22,6 +23,7 @@ export async function POST(request: Request) { } const data = await getFunnel(websiteId, { + ...filters, startDate: new Date(startDate), endDate: new Date(endDate), steps, diff --git a/src/app/api/reports/goal/route.ts b/src/app/api/reports/goal/route.ts index bbf0f229..fe893571 100644 --- a/src/app/api/reports/goal/route.ts +++ b/src/app/api/reports/goal/route.ts @@ -15,6 +15,7 @@ export async function POST(request: Request) { websiteId, dateRange: { startDate, endDate }, parameters: { type, value, property, operator }, + ...filters } = body; if (!(await canViewWebsite(auth, websiteId))) { @@ -22,12 +23,13 @@ export async function POST(request: Request) { } const data = await getGoal(websiteId, { + ...filters, + startDate: new Date(startDate), + endDate: new Date(endDate), type, value, property, operator, - startDate: new Date(startDate), - endDate: new Date(endDate), }); return json(data); diff --git a/src/app/api/reports/journey/route.ts b/src/app/api/reports/journey/route.ts index 130a494e..20675bdf 100644 --- a/src/app/api/reports/journey/route.ts +++ b/src/app/api/reports/journey/route.ts @@ -15,6 +15,7 @@ export async function POST(request: Request) { websiteId, dateRange: { startDate, endDate }, parameters: { steps, startStep, endStep }, + ...filters } = body; if (!(await canViewWebsite(auth, websiteId))) { @@ -22,6 +23,7 @@ export async function POST(request: Request) { } const data = await getJourney(websiteId, { + ...filters, startDate: new Date(startDate), endDate: new Date(endDate), steps, diff --git a/src/app/api/reports/retention/route.ts b/src/app/api/reports/retention/route.ts index 76e54e9f..b569e13a 100644 --- a/src/app/api/reports/retention/route.ts +++ b/src/app/api/reports/retention/route.ts @@ -14,6 +14,7 @@ export async function POST(request: Request) { const { websiteId, dateRange: { startDate, endDate, timezone }, + ...filters } = body; if (!(await canViewWebsite(auth, websiteId))) { @@ -21,6 +22,7 @@ export async function POST(request: Request) { } const data = await getRetention(websiteId, { + ...filters, startDate: new Date(startDate), endDate: new Date(endDate), timezone, diff --git a/src/app/api/reports/revenue/route.ts b/src/app/api/reports/revenue/route.ts index fbec6bca..ff4f4de4 100644 --- a/src/app/api/reports/revenue/route.ts +++ b/src/app/api/reports/revenue/route.ts @@ -15,6 +15,7 @@ export async function POST(request: Request) { websiteId, dateRange: { startDate, endDate, unit }, parameters: { currency }, + ...filters } = body; if (!(await canViewWebsite(auth, websiteId))) { @@ -22,6 +23,7 @@ export async function POST(request: Request) { } const data = await getRevenue(websiteId, { + ...filters, startDate: new Date(startDate), endDate: new Date(endDate), unit, diff --git a/src/app/api/reports/utm/route.ts b/src/app/api/reports/utm/route.ts index 36a434ad..a2845b25 100644 --- a/src/app/api/reports/utm/route.ts +++ b/src/app/api/reports/utm/route.ts @@ -14,6 +14,7 @@ export async function POST(request: Request) { const { websiteId, dateRange: { startDate, endDate }, + ...filters } = body; if (!(await canViewWebsite(auth, websiteId))) { @@ -21,6 +22,7 @@ export async function POST(request: Request) { } const data = await getUTM(websiteId, { + ...filters, startDate: new Date(startDate), endDate: new Date(endDate), }); diff --git a/src/components/hooks/queries/useResultQuery.ts b/src/components/hooks/queries/useResultQuery.ts index f4e3d5e7..e82e4519 100644 --- a/src/components/hooks/queries/useResultQuery.ts +++ b/src/components/hooks/queries/useResultQuery.ts @@ -9,7 +9,7 @@ export function useResultQuery( ) { const { websiteId } = params; const { post, useQuery } = useApi(); - const filterParams = useFilterParams(websiteId); + const filters = useFilterParams(websiteId); return useQuery({ queryKey: [ @@ -17,11 +17,11 @@ export function useResultQuery( { type, websiteId, - ...filterParams, + ...filters, ...params, }, ], - queryFn: () => post(`/reports/${type}`, { type, ...filterParams, ...params }), + queryFn: () => post(`/reports/${type}`, { type, ...filters, ...params }), enabled: !!type, ...options, }); diff --git a/src/components/hooks/useFilterParams.ts b/src/components/hooks/useFilterParams.ts index bee2a649..f725eb80 100644 --- a/src/components/hooks/useFilterParams.ts +++ b/src/components/hooks/useFilterParams.ts @@ -21,6 +21,7 @@ export function useFilterParams(websiteId: string) { city, event, tag, + hostname, }, } = useNavigation(); @@ -42,5 +43,6 @@ export function useFilterParams(websiteId: string) { city, event, tag, + hostname, }; } diff --git a/src/components/hooks/usePagedQuery.ts b/src/components/hooks/usePagedQuery.ts index 06b0e211..1f85afc0 100644 --- a/src/components/hooks/usePagedQuery.ts +++ b/src/components/hooks/usePagedQuery.ts @@ -25,7 +25,7 @@ export function usePagedQuery({ return { result: data as PageResult, query, - params, + filterParams: params, setParams, }; } diff --git a/src/components/metrics/WorldMap.tsx b/src/components/metrics/WorldMap.tsx index b3908698..76ec1abc 100644 --- a/src/components/metrics/WorldMap.tsx +++ b/src/components/metrics/WorldMap.tsx @@ -1,5 +1,5 @@ -import { FloatingTooltip, Column, useTheme } from '@umami/react-zen'; -import { useState, useMemo, HTMLAttributes } from 'react'; +import { FloatingTooltip, Column, useTheme, ColumnProps } from '@umami/react-zen'; +import { useState, useMemo } from 'react'; import { ComposableMap, Geographies, Geography, ZoomableGroup } from 'react-simple-maps'; import classNames from 'classnames'; import { colord } from 'colord'; @@ -16,16 +16,12 @@ import { percentFilter } from '@/lib/filters'; import styles from './WorldMap.module.css'; import { getThemeColors } from '@/lib/colors'; -export function WorldMap({ - websiteId, - data, - className, - ...props -}: { +export interface WorldMapProps extends ColumnProps { websiteId?: string; data?: any[]; - className?: string; -} & HTMLAttributes) { +} + +export function WorldMap({ websiteId, data, className, ...props }: WorldMapProps) { const [tooltip, setTooltipPopup] = useState(); const { theme } = useTheme(); const { colors } = getThemeColors(theme); diff --git a/src/lib/clickhouse.ts b/src/lib/clickhouse.ts index 38b93975..f59058cf 100644 --- a/src/lib/clickhouse.ts +++ b/src/lib/clickhouse.ts @@ -141,7 +141,7 @@ async function parseFilters(websiteId: string, filters: QueryFilters = {}, optio return { filterQuery: getFilterQuery(filters, options), dateQuery: getDateQuery(filters), - params: { + filterParams: { ...getFilterParams(filters), websiteId, startDate: maxDate(filters.startDate, new Date(website?.resetAt)), diff --git a/src/lib/prisma.ts b/src/lib/prisma.ts index ecbe3e53..89728bb5 100644 --- a/src/lib/prisma.ts +++ b/src/lib/prisma.ts @@ -215,7 +215,7 @@ async function parseFilters( : '', filterQuery: getFilterQuery(filters, options), dateQuery: getDateQuery(filters), - params: { + filterParams: { ...getFilterParams(filters), websiteId, startDate: maxDate(filters.startDate, website?.resetAt), diff --git a/src/queries/sql/events/getEventDataEvents.ts b/src/queries/sql/events/getEventDataEvents.ts index 83a5c319..1922edab 100644 --- a/src/queries/sql/events/getEventDataEvents.ts +++ b/src/queries/sql/events/getEventDataEvents.ts @@ -23,7 +23,7 @@ export async function getEventDataEvents( async function relationalQuery(websiteId: string, filters: QueryFilters) { const { rawQuery, parseFilters } = prisma; const { event } = filters; - const { params } = await parseFilters(websiteId, filters); + const { filterParams } = await parseFilters(websiteId, filters); if (event) { return rawQuery( @@ -43,7 +43,7 @@ async function relationalQuery(websiteId: string, filters: QueryFilters) { group by website_event.event_name, event_data.data_key, event_data.data_type, event_data.string_value order by 1 asc, 2 asc, 3 asc, 5 desc `, - params, + filterParams, ); } @@ -63,7 +63,7 @@ async function relationalQuery(websiteId: string, filters: QueryFilters) { order by 1 asc, 2 asc limit 500 `, - params, + filterParams, ); } @@ -73,7 +73,7 @@ async function clickhouseQuery( ): Promise<{ eventName: string; propertyName: string; dataType: number; total: number }[]> { const { rawQuery, parseFilters } = clickhouse; const { event } = filters; - const { params } = await parseFilters(websiteId, filters); + const { filterParams } = await parseFilters(websiteId, filters); if (event) { return rawQuery( @@ -92,7 +92,7 @@ async function clickhouseQuery( order by 1 asc, 2 asc, 3 asc, 5 desc limit 500 `, - params, + filterParams, ); } @@ -110,6 +110,6 @@ async function clickhouseQuery( order by 1 asc, 2 asc limit 500 `, - params, + filterParams, ); } diff --git a/src/queries/sql/events/getEventDataFields.ts b/src/queries/sql/events/getEventDataFields.ts index 33b4e0f5..266c50ad 100644 --- a/src/queries/sql/events/getEventDataFields.ts +++ b/src/queries/sql/events/getEventDataFields.ts @@ -1,11 +1,9 @@ import prisma from '@/lib/prisma'; import clickhouse from '@/lib/clickhouse'; import { CLICKHOUSE, PRISMA, runQuery } from '@/lib/db'; -import { QueryFilters, WebsiteEventData } from '@/lib/types'; +import { QueryFilters } from '@/lib/types'; -export async function getEventDataFields( - ...args: [websiteId: string, filters: QueryFilters] -): Promise { +export async function getEventDataFields(...args: [websiteId: string, filters: QueryFilters]) { return runQuery({ [PRISMA]: () => relationalQuery(...args), [CLICKHOUSE]: () => clickhouseQuery(...args), @@ -14,7 +12,7 @@ export async function getEventDataFields( async function relationalQuery(websiteId: string, filters: QueryFilters) { const { rawQuery, parseFilters, getDateSQL } = prisma; - const { filterQuery, params } = await parseFilters(websiteId, filters); + const { filterQuery, filterParams } = await parseFilters(websiteId, filters); return rawQuery( ` @@ -36,7 +34,7 @@ async function relationalQuery(websiteId: string, filters: QueryFilters) { order by 2 desc limit 100 `, - params, + filterParams, ); } @@ -45,7 +43,7 @@ async function clickhouseQuery( filters: QueryFilters, ): Promise<{ propertyName: string; dataType: number; propertyValue: string; total: number }[]> { const { rawQuery, parseFilters } = clickhouse; - const { filterQuery, params } = await parseFilters(websiteId, filters); + const { filterQuery, filterParams } = await parseFilters(websiteId, filters); return rawQuery( ` @@ -64,6 +62,6 @@ async function clickhouseQuery( order by 2 desc limit 100 `, - params, + filterParams, ); } diff --git a/src/queries/sql/events/getEventDataProperties.ts b/src/queries/sql/events/getEventDataProperties.ts index 73fb8fec..5781df82 100644 --- a/src/queries/sql/events/getEventDataProperties.ts +++ b/src/queries/sql/events/getEventDataProperties.ts @@ -17,7 +17,7 @@ async function relationalQuery( filters: QueryFilters & { propertyName?: string }, ) { const { rawQuery, parseFilters } = prisma; - const { filterQuery, params } = await parseFilters(websiteId, filters, { + const { filterQuery, filterParams } = await parseFilters(websiteId, filters, { columns: { propertyName: 'data_key' }, }); @@ -36,7 +36,7 @@ async function relationalQuery( order by 3 desc limit 500 `, - params, + filterParams, ); } @@ -45,7 +45,7 @@ async function clickhouseQuery( filters: QueryFilters & { propertyName?: string }, ): Promise<{ eventName: string; propertyName: string; total: number }[]> { const { rawQuery, parseFilters } = clickhouse; - const { filterQuery, params } = await parseFilters(websiteId, filters, { + const { filterQuery, filterParams } = await parseFilters(websiteId, filters, { columns: { propertyName: 'data_key' }, }); @@ -63,6 +63,6 @@ async function clickhouseQuery( order by 1, 3 desc limit 500 `, - params, + filterParams, ); } diff --git a/src/queries/sql/events/getEventDataStats.ts b/src/queries/sql/events/getEventDataStats.ts index 98347960..fd9b7a8b 100644 --- a/src/queries/sql/events/getEventDataStats.ts +++ b/src/queries/sql/events/getEventDataStats.ts @@ -18,7 +18,7 @@ export async function getEventDataStats( async function relationalQuery(websiteId: string, filters: QueryFilters) { const { rawQuery, parseFilters } = prisma; - const { filterQuery, params } = await parseFilters(websiteId, filters); + const { filterQuery, filterParams } = await parseFilters(websiteId, filters); return rawQuery( ` @@ -38,7 +38,7 @@ async function relationalQuery(websiteId: string, filters: QueryFilters) { group by website_event_id, data_key ) as t `, - params, + filterParams, ); } @@ -47,7 +47,7 @@ async function clickhouseQuery( filters: QueryFilters, ): Promise<{ events: number; properties: number; records: number }[]> { const { rawQuery, parseFilters } = clickhouse; - const { filterQuery, params } = await parseFilters(websiteId, filters); + const { filterQuery, filterParams } = await parseFilters(websiteId, filters); return rawQuery( ` @@ -67,6 +67,6 @@ async function clickhouseQuery( group by event_id, data_key ) as t `, - params, + filterParams, ); } diff --git a/src/queries/sql/events/getEventDataValues.ts b/src/queries/sql/events/getEventDataValues.ts index c8d63362..5041bdc3 100644 --- a/src/queries/sql/events/getEventDataValues.ts +++ b/src/queries/sql/events/getEventDataValues.ts @@ -1,7 +1,12 @@ import prisma from '@/lib/prisma'; import clickhouse from '@/lib/clickhouse'; import { CLICKHOUSE, PRISMA, runQuery } from '@/lib/db'; -import { QueryFilters, WebsiteEventData } from '@/lib/types'; +import { QueryFilters } from '@/lib/types'; + +export interface WebsiteEventData { + value: string; + total: number; +} export async function getEventDataValues( ...args: [ @@ -20,7 +25,7 @@ async function relationalQuery( filters: QueryFilters & { eventName?: string; propertyName?: string }, ) { const { rawQuery, parseFilters, getDateSQL } = prisma; - const { filterQuery, params } = await parseFilters(websiteId, filters); + const { filterQuery, filterParams } = await parseFilters(websiteId, filters); return rawQuery( ` @@ -42,7 +47,7 @@ async function relationalQuery( order by 2 desc limit 100 `, - params, + filterParams, ); } @@ -51,7 +56,7 @@ async function clickhouseQuery( filters: QueryFilters & { eventName?: string; propertyName?: string }, ): Promise<{ value: string; total: number }[]> { const { rawQuery, parseFilters } = clickhouse; - const { filterQuery, params } = await parseFilters(websiteId, filters); + const { filterQuery, filterParams } = await parseFilters(websiteId, filters); return rawQuery( ` @@ -70,6 +75,6 @@ async function clickhouseQuery( order by 2 desc limit 100 `, - params, + filterParams, ); } diff --git a/src/queries/sql/events/getEventMetrics.ts b/src/queries/sql/events/getEventMetrics.ts index e777e907..39e6003a 100644 --- a/src/queries/sql/events/getEventMetrics.ts +++ b/src/queries/sql/events/getEventMetrics.ts @@ -22,7 +22,7 @@ export async function getEventMetrics( async function relationalQuery(websiteId: string, filters: QueryFilters) { const { timezone = 'utc', unit = 'day' } = filters; const { rawQuery, getDateSQL, parseFilters } = prisma; - const { filterQuery, joinSession, params } = await parseFilters(websiteId, { + const { filterQuery, joinSession, filterParams } = await parseFilters(websiteId, { ...filters, eventType: EVENT_TYPE.customEvent, }); @@ -42,7 +42,7 @@ async function relationalQuery(websiteId: string, filters: QueryFilters) { group by 1, 2 order by 2 `, - params, + filterParams, ); } @@ -52,7 +52,7 @@ async function clickhouseQuery( ): Promise<{ x: string; t: string; y: number }[]> { const { timezone = 'UTC', unit = 'day' } = filters; const { rawQuery, getDateSQL, parseFilters } = clickhouse; - const { filterQuery, params } = await parseFilters(websiteId, { + const { filterQuery, filterParams } = await parseFilters(websiteId, { ...filters, eventType: EVENT_TYPE.customEvent, }); @@ -92,5 +92,5 @@ async function clickhouseQuery( `; } - return rawQuery(sql, params); + return rawQuery(sql, filterParams); } diff --git a/src/queries/sql/events/getWebsiteEvents.ts b/src/queries/sql/events/getWebsiteEvents.ts index 9ec24a8a..31787873 100644 --- a/src/queries/sql/events/getWebsiteEvents.ts +++ b/src/queries/sql/events/getWebsiteEvents.ts @@ -15,7 +15,7 @@ export function getWebsiteEvents( async function relationalQuery(websiteId: string, filters: QueryFilters, pageParams?: PageParams) { const { pagedRawQuery, parseFilters } = prisma; const { search } = pageParams; - const { filterQuery, params } = await parseFilters(websiteId, { + const { filterQuery, filterParams } = await parseFilters(websiteId, { ...filters, }); @@ -49,14 +49,14 @@ async function relationalQuery(websiteId: string, filters: QueryFilters, pagePar } order by created_at desc `, - { ...params, search: `%${search}%` }, + { ...filterParams, search: `%${search}%` }, pageParams, ); } async function clickhouseQuery(websiteId: string, filters: QueryFilters, pageParams?: PageParams) { const { pagedQuery, parseFilters } = clickhouse; - const { params, dateQuery, filterQuery } = await parseFilters(websiteId, filters); + const { filterParams, dateQuery, filterQuery } = await parseFilters(websiteId, filters); const { search } = pageParams; return pagedQuery( @@ -86,7 +86,7 @@ async function clickhouseQuery(websiteId: string, filters: QueryFilters, pagePar } order by created_at desc `, - { ...params, search }, + { ...filterParams, search }, pageParams, ); } diff --git a/src/queries/sql/getChannelMetrics.ts b/src/queries/sql/getChannelMetrics.ts index 433c5e81..aa0919ad 100644 --- a/src/queries/sql/getChannelMetrics.ts +++ b/src/queries/sql/getChannelMetrics.ts @@ -12,7 +12,7 @@ export async function getChannelMetrics(...args: [websiteId: string, filters?: Q async function relationalQuery(websiteId: string, filters: QueryFilters) { const { rawQuery, parseFilters } = prisma; - const { params, filterQuery, dateQuery } = await parseFilters(websiteId, filters); + const { filterParams, filterQuery, dateQuery } = await parseFilters(websiteId, filters); return rawQuery( ` @@ -27,7 +27,7 @@ async function relationalQuery(websiteId: string, filters: QueryFilters) { group by 1, 2 order by visitors desc `, - params, + filterParams, ); } @@ -36,7 +36,7 @@ async function clickhouseQuery( filters: QueryFilters, ): Promise<{ x: string; y: number }[]> { const { rawQuery, parseFilters } = clickhouse; - const { params, filterQuery, dateQuery } = await parseFilters(websiteId, filters); + const { filterParams, filterQuery, dateQuery } = await parseFilters(websiteId, filters); const sql = ` select @@ -51,5 +51,5 @@ async function clickhouseQuery( order by visitors desc `; - return rawQuery(sql, params); + return rawQuery(sql, filterParams); } diff --git a/src/queries/sql/getRealtimeActivity.ts b/src/queries/sql/getRealtimeActivity.ts index 5d1fa001..1bfd06eb 100644 --- a/src/queries/sql/getRealtimeActivity.ts +++ b/src/queries/sql/getRealtimeActivity.ts @@ -12,7 +12,7 @@ export async function getRealtimeActivity(...args: [websiteId: string, filters: async function relationalQuery(websiteId: string, filters: QueryFilters) { const { rawQuery, parseFilters } = prisma; - const { params, filterQuery, dateQuery } = await parseFilters(websiteId, filters); + const { filterParams, filterQuery, dateQuery } = await parseFilters(websiteId, filters); return rawQuery( ` @@ -35,13 +35,13 @@ async function relationalQuery(websiteId: string, filters: QueryFilters) { order by website_event.created_at desc limit 100 `, - params, + filterParams, ); } async function clickhouseQuery(websiteId: string, filters: QueryFilters): Promise<{ x: number }> { const { rawQuery, parseFilters } = clickhouse; - const { params, filterQuery, dateQuery } = await parseFilters(websiteId, filters); + const { filterParams, filterQuery, dateQuery } = await parseFilters(websiteId, filters); return rawQuery( ` @@ -62,6 +62,6 @@ async function clickhouseQuery(websiteId: string, filters: QueryFilters): Promis order by createdAt desc limit 100 `, - { ...filters, ...params }, + { ...filters, ...filterParams }, ); } diff --git a/src/queries/sql/getWebsiteDateRange.ts b/src/queries/sql/getWebsiteDateRange.ts index 953fa5eb..917d058c 100644 --- a/src/queries/sql/getWebsiteDateRange.ts +++ b/src/queries/sql/getWebsiteDateRange.ts @@ -12,7 +12,9 @@ export async function getWebsiteDateRange(...args: [websiteId: string]) { async function relationalQuery(websiteId: string) { const { rawQuery, parseFilters } = prisma; - const { params } = await parseFilters(websiteId, { startDate: new Date(DEFAULT_RESET_DATE) }); + const { filterParams } = await parseFilters(websiteId, { + startDate: new Date(DEFAULT_RESET_DATE), + }); const result = await rawQuery( ` @@ -23,7 +25,7 @@ async function relationalQuery(websiteId: string) { where website_id = {{websiteId::uuid}} and created_at >= {{startDate}} `, - params, + filterParams, ); return result[0] ?? null; @@ -31,7 +33,9 @@ async function relationalQuery(websiteId: string) { async function clickhouseQuery(websiteId: string) { const { rawQuery, parseFilters } = clickhouse; - const { params } = await parseFilters(websiteId, { startDate: new Date(DEFAULT_RESET_DATE) }); + const { filterParams } = await parseFilters(websiteId, { + startDate: new Date(DEFAULT_RESET_DATE), + }); const result = await rawQuery( ` @@ -42,7 +46,7 @@ async function clickhouseQuery(websiteId: string) { where website_id = {websiteId:UUID} and created_at >= {startDate:DateTime64} `, - params, + filterParams, ); return result[0] ?? null; diff --git a/src/queries/sql/getWebsiteStats.ts b/src/queries/sql/getWebsiteStats.ts index 421515c9..947654a6 100644 --- a/src/queries/sql/getWebsiteStats.ts +++ b/src/queries/sql/getWebsiteStats.ts @@ -23,7 +23,7 @@ async function relationalQuery( { pageviews: number; visitors: number; visits: number; bounces: number; totaltime: number }[] > { const { getTimestampDiffSQL, parseFilters, rawQuery } = prisma; - const { filterQuery, joinSession, params } = await parseFilters(websiteId, { + const { filterQuery, joinSession, filterParams } = await parseFilters(websiteId, { ...filters, eventType: EVENT_TYPE.pageView, }); @@ -52,7 +52,7 @@ async function relationalQuery( group by 1, 2 ) as t `, - params, + filterParams, ); } @@ -63,7 +63,7 @@ async function clickhouseQuery( { pageviews: number; visitors: number; visits: number; bounces: number; totaltime: number }[] > { const { rawQuery, parseFilters } = clickhouse; - const { filterQuery, params } = await parseFilters(websiteId, { + const { filterQuery, filterParams } = await parseFilters(websiteId, { ...filters, eventType: EVENT_TYPE.pageView, }); @@ -117,5 +117,5 @@ async function clickhouseQuery( `; } - return rawQuery(sql, params).then(result => result?.[0]); + return rawQuery(sql, filterParams).then(result => result?.[0]); } diff --git a/src/queries/sql/pageviews/getPageviewMetrics.ts b/src/queries/sql/pageviews/getPageviewMetrics.ts index 9e681b7f..7d73d08a 100644 --- a/src/queries/sql/pageviews/getPageviewMetrics.ts +++ b/src/queries/sql/pageviews/getPageviewMetrics.ts @@ -28,7 +28,7 @@ async function relationalQuery( ) { const column = FILTER_COLUMNS[type] || type; const { rawQuery, parseFilters } = prisma; - const { filterQuery, joinSession, params } = await parseFilters( + const { filterQuery, joinSession, filterParams } = await parseFilters( websiteId, { ...filters, @@ -82,7 +82,7 @@ async function relationalQuery( limit ${limit} offset ${offset} `, - params, + filterParams, ); } @@ -95,7 +95,7 @@ async function clickhouseQuery( ): Promise<{ x: string; y: number }[]> { const column = FILTER_COLUMNS[type] || type; const { rawQuery, parseFilters } = clickhouse; - const { filterQuery, params } = await parseFilters(websiteId, { + const { filterQuery, filterParams } = await parseFilters(websiteId, { ...filters, eventType: column === 'event_name' ? EVENT_TYPE.customEvent : EVENT_TYPE.pageView, }); @@ -180,5 +180,5 @@ async function clickhouseQuery( `; } - return rawQuery(sql, params); + return rawQuery(sql, filterParams); } diff --git a/src/queries/sql/pageviews/getPageviewStats.ts b/src/queries/sql/pageviews/getPageviewStats.ts index fe696616..5af44020 100644 --- a/src/queries/sql/pageviews/getPageviewStats.ts +++ b/src/queries/sql/pageviews/getPageviewStats.ts @@ -14,7 +14,7 @@ export async function getPageviewStats(...args: [websiteId: string, filters: Que async function relationalQuery(websiteId: string, filters: QueryFilters) { const { timezone = 'utc', unit = 'day' } = filters; const { getDateSQL, parseFilters, rawQuery } = prisma; - const { filterQuery, joinSession, params } = await parseFilters(websiteId, { + const { filterQuery, joinSession, filterParams } = await parseFilters(websiteId, { ...filters, eventType: EVENT_TYPE.pageView, }); @@ -33,7 +33,7 @@ async function relationalQuery(websiteId: string, filters: QueryFilters) { group by 1 order by 1 `, - params, + filterParams, ); } @@ -43,7 +43,7 @@ async function clickhouseQuery( ): Promise<{ x: string; y: number }[]> { const { timezone = 'utc', unit = 'day' } = filters; const { parseFilters, rawQuery, getDateSQL } = clickhouse; - const { filterQuery, params } = await parseFilters(websiteId, { + const { filterQuery, filterParams } = await parseFilters(websiteId, { ...filters, eventType: EVENT_TYPE.pageView, }); @@ -88,5 +88,5 @@ async function clickhouseQuery( `; } - return rawQuery(sql, params); + return rawQuery(sql, filterParams); } diff --git a/src/queries/sql/reports/getAttribution.ts b/src/queries/sql/reports/getAttribution.ts index 5f3deb1b..212ef548 100644 --- a/src/queries/sql/reports/getAttribution.ts +++ b/src/queries/sql/reports/getAttribution.ts @@ -1,6 +1,6 @@ import clickhouse from '@/lib/clickhouse'; import { EVENT_TYPE } from '@/lib/constants'; -import { CLICKHOUSE, getDatabaseType, POSTGRESQL, PRISMA, runQuery } from '@/lib/db'; +import { CLICKHOUSE, PRISMA, runQuery } from '@/lib/db'; import prisma from '@/lib/prisma'; export interface AttributionCriteria { @@ -38,8 +38,6 @@ async function relationalQuery( const { rawQuery } = prisma; const eventType = type === 'page' ? EVENT_TYPE.pageView : EVENT_TYPE.customEvent; const column = type === 'page' ? 'url_path' : 'event_name'; - const db = getDatabaseType(); - const like = db === POSTGRESQL ? 'ilike' : 'like'; function getUTMQuery(utmColumn: string) { return ` @@ -79,7 +77,7 @@ async function relationalQuery( where website_id = {{websiteId::uuid}} and created_at between {{startDate}} and {{endDate}} and ${column} = {{conversionStep}} - and currency ${like} {{currency}} + and currency = {{currency}} group by 1),`; function getModelQuery(model: string) { @@ -243,26 +241,57 @@ async function clickhouseQuery( criteria: AttributionCriteria, ): Promise { const { startDate, endDate, model, type, step, currency } = criteria; - const { rawQuery } = clickhouse; + const { rawQuery, parseFilters } = clickhouse; const eventType = type === 'page' ? EVENT_TYPE.pageView : EVENT_TYPE.customEvent; const column = type === 'page' ? 'url_path' : 'event_name'; + const { filterQuery, filterParams } = await parseFilters(websiteId, criteria); function getUTMQuery(utmColumn: string) { return ` - select - we.${utmColumn} name, - ${currency ? 'sum(e.value)' : 'uniqExact(we.session_id)'} value - from model m - join website_event we - on we.created_at = m.created_at - and we.session_id = m.session_id - ${currency ? 'join events e on e.session_id = m.session_id' : ''} - where we.website_id = {websiteId:UUID} + select + we.${utmColumn} name, + ${currency ? 'sum(e.value)' : 'uniqExact(we.session_id)'} value + from model m + join website_event we + on we.created_at = m.created_at + and we.session_id = m.session_id + ${currency ? 'join events e on e.session_id = m.session_id' : ''} + where we.website_id = {websiteId:UUID} + and we.created_at between {startDate:DateTime64} and {endDate:DateTime64} + ${currency ? '' : `and we.${utmColumn} != ''`} + group by 1 + order by 2 desc + limit 20 + `; + } + + function getModelQuery(model: string) { + if (model === 'first-click') { + return ` + model AS (select e.session_id, + min(we.created_at) created_at + from events e + join website_event we + on we.session_id = e.session_id + where we.website_id = {websiteId:UUID} and we.created_at between {startDate:DateTime64} and {endDate:DateTime64} - ${currency ? '' : `and we.${utmColumn} != ''`} - group by 1 - order by 2 desc - limit 20`; + ${filterQuery} + group by e.session_id) + `; + } + + return ` + model AS (select e.session_id, + max(we.created_at) created_at + from events e + join website_event we + on we.session_id = e.session_id + where we.website_id = {websiteId:UUID} + and we.created_at between {startDate:DateTime64} and {endDate:DateTime64} + and we.created_at < e.max_dt + ${filterQuery} + group by e.session_id) + `; } const eventQuery = `WITH events AS ( @@ -288,29 +317,6 @@ async function clickhouseQuery( and currency = {currency:String} group by 1),`; - function getModelQuery(model: string) { - return model === 'first-click' - ? `\n - model AS (select e.session_id, - min(we.created_at) created_at - from events e - join website_event we - on we.session_id = e.session_id - where we.website_id = {websiteId:UUID} - and we.created_at between {startDate:DateTime64} and {endDate:DateTime64} - group by e.session_id)` - : `\n - model AS (select e.session_id, - max(we.created_at) created_at - from events e - join website_event we - on we.session_id = e.session_id - where we.website_id = {websiteId:UUID} - and we.created_at between {startDate:DateTime64} and {endDate:DateTime64} - and we.created_at < e.max_dt - group by e.session_id)`; - } - const referrerRes = await rawQuery< { name: string; @@ -339,7 +345,7 @@ async function clickhouseQuery( order by 2 desc limit 20 `, - { websiteId, startDate, endDate, conversionStep: step, eventType, currency }, + { ...filterParams, websiteId, startDate, endDate, conversionStep: step, eventType, currency }, ); const paidAdsres = await rawQuery< @@ -370,7 +376,7 @@ async function clickhouseQuery( order by 2 desc limit 20 `, - { websiteId, startDate, endDate, conversionStep: step, eventType, currency }, + { ...filterParams, websiteId, startDate, endDate, conversionStep: step, eventType, currency }, ); const sourceRes = await rawQuery< @@ -384,7 +390,7 @@ async function clickhouseQuery( ${getModelQuery(model)} ${getUTMQuery('utm_source')} `, - { websiteId, startDate, endDate, conversionStep: step, eventType, currency }, + { ...filterParams, websiteId, startDate, endDate, conversionStep: step, eventType, currency }, ); const mediumRes = await rawQuery< @@ -398,7 +404,7 @@ async function clickhouseQuery( ${getModelQuery(model)} ${getUTMQuery('utm_medium')} `, - { websiteId, startDate, endDate, conversionStep: step, eventType, currency }, + { ...filterParams, websiteId, startDate, endDate, conversionStep: step, eventType, currency }, ); const campaignRes = await rawQuery< @@ -412,7 +418,7 @@ async function clickhouseQuery( ${getModelQuery(model)} ${getUTMQuery('utm_campaign')} `, - { websiteId, startDate, endDate, conversionStep: step, eventType, currency }, + { ...filterParams, websiteId, startDate, endDate, conversionStep: step, eventType, currency }, ); const contentRes = await rawQuery< @@ -426,7 +432,7 @@ async function clickhouseQuery( ${getModelQuery(model)} ${getUTMQuery('utm_content')} `, - { websiteId, startDate, endDate, conversionStep: step, eventType, currency }, + { ...filterParams, websiteId, startDate, endDate, conversionStep: step, eventType, currency }, ); const termRes = await rawQuery< @@ -440,7 +446,7 @@ async function clickhouseQuery( ${getModelQuery(model)} ${getUTMQuery('utm_term')} `, - { websiteId, startDate, endDate, conversionStep: step, eventType, currency }, + { ...filterParams, websiteId, startDate, endDate, conversionStep: step, eventType, currency }, ); const totalRes = await rawQuery<{ pageviews: number; visitors: number; visits: number }>( @@ -454,8 +460,9 @@ async function clickhouseQuery( and created_at between {startDate:DateTime64} and {endDate:DateTime64} and ${column} = {conversionStep:String} and event_type = {eventType:UInt32} + ${filterQuery} `, - { websiteId, startDate, endDate, conversionStep: step, eventType, currency }, + { ...filterParams, websiteId, startDate, endDate, conversionStep: step, eventType, currency }, ).then(result => result?.[0]); return { diff --git a/src/queries/sql/reports/getBreakdown.ts b/src/queries/sql/reports/getBreakdown.ts index 0965bf43..353761ad 100644 --- a/src/queries/sql/reports/getBreakdown.ts +++ b/src/queries/sql/reports/getBreakdown.ts @@ -24,7 +24,7 @@ async function relationalQuery( }[] > { const { getTimestampDiffSQL, parseFilters, rawQuery } = prisma; - const { filterQuery, joinSession, params } = await parseFilters( + const { filterQuery, joinSession, filterParams } = await parseFilters( websiteId, { ...filters, @@ -65,7 +65,7 @@ async function relationalQuery( order by 1 desc, 2 desc limit 500 `, - params, + filterParams, ); } @@ -80,7 +80,7 @@ async function clickhouseQuery( }[] > { const { parseFilters, rawQuery } = clickhouse; - const { filterQuery, params } = await parseFilters(websiteId, { + const { filterQuery, filterParams } = await parseFilters(websiteId, { ...filters, eventType: EVENT_TYPE.pageView, }); @@ -114,7 +114,7 @@ async function clickhouseQuery( order by 1 desc, 2 desc limit 500 `, - params, + filterParams, ); } diff --git a/src/queries/sql/reports/getFunnel.ts b/src/queries/sql/reports/getFunnel.ts index d256bd08..45dc21df 100644 --- a/src/queries/sql/reports/getFunnel.ts +++ b/src/queries/sql/reports/getFunnel.ts @@ -121,11 +121,12 @@ async function clickhouseQuery( }[] > { const { windowMinutes, startDate, endDate, steps } = criteria; - const { rawQuery } = clickhouse; + const { rawQuery, parseFilters } = clickhouse; const { levelOneQuery, levelQuery, sumQuery, stepFilterQuery, params } = getFunnelQuery( steps, windowMinutes, ); + const { filterQuery, filterParams: filterParams } = await parseFilters(websiteId, criteria); function getFunnelQuery( steps: { type: string; value: string }[], @@ -200,6 +201,7 @@ async function clickhouseQuery( where (${stepFilterQuery}) and website_id = {websiteId:UUID} and created_at between {startDate:DateTime64} and {endDate:DateTime64} + ${filterQuery} ), ${levelOneQuery} ${levelQuery} @@ -213,6 +215,7 @@ async function clickhouseQuery( startDate, endDate, ...params, + ...filterParams, }, ).then(formatResults(steps)); } diff --git a/src/queries/sql/reports/getGoal.ts b/src/queries/sql/reports/getGoal.ts index 0def8bcd..b2351e51 100644 --- a/src/queries/sql/reports/getGoal.ts +++ b/src/queries/sql/reports/getGoal.ts @@ -21,7 +21,7 @@ export async function getGoal(...args: [websiteId: string, criteria: GoalCriteri async function relationalQuery(websiteId: string, criteria: GoalCriteria) { const { type, value } = criteria; const { rawQuery, parseFilters } = prisma; - const { filterQuery, dateQuery, params } = await parseFilters(websiteId, criteria); + const { filterQuery, dateQuery, filterParams } = await parseFilters(websiteId, criteria); const isPage = type === 'page'; const column = isPage ? 'url_path' : 'event_name'; const eventType = isPage ? 1 : 2; @@ -43,14 +43,14 @@ async function relationalQuery(websiteId: string, criteria: GoalCriteria) { ${dateQuery} ${filterQuery} `, - { ...params, value }, + { ...filterParams, value }, ); } async function clickhouseQuery(websiteId: string, criteria: GoalCriteria) { const { type, value } = criteria; const { rawQuery, parseFilters } = clickhouse; - const { filterQuery, dateQuery, params } = await parseFilters(websiteId, criteria); + const { filterQuery, dateQuery, filterParams } = await parseFilters(websiteId, criteria); const isPage = type === 'page'; const column = isPage ? 'url_path' : 'event_name'; const eventType = isPage ? 1 : 2; @@ -71,6 +71,6 @@ async function clickhouseQuery(websiteId: string, criteria: GoalCriteria) { ${dateQuery} ${filterQuery} `, - { ...params, value }, + { ...filterParams, value }, ).then(results => results?.[0]); } diff --git a/src/queries/sql/reports/getJourney.ts b/src/queries/sql/reports/getJourney.ts index 4c43cc03..b31824e2 100644 --- a/src/queries/sql/reports/getJourney.ts +++ b/src/queries/sql/reports/getJourney.ts @@ -108,7 +108,7 @@ async function relationalQuery( sequenceQuery, startStepQuery, endStepQuery, - params, + filterParams: params, }; } @@ -152,7 +152,7 @@ async function clickhouseQuery( }, ): Promise { const { startDate, endDate, steps, startStep, endStep } = filters; - const { rawQuery } = clickhouse; + const { rawQuery, parseFilters } = clickhouse; const { sequenceQuery, startStepQuery, endStepQuery, params } = getJourneyQuery( steps, startStep, @@ -218,10 +218,12 @@ async function clickhouseQuery( sequenceQuery, startStepQuery, endStepQuery, - params, + filterParams: params, }; } + const { filterQuery, filterParams: filterParams } = await parseFilters(websiteId, filters); + return rawQuery( ` WITH events AS ( @@ -231,6 +233,7 @@ async function clickhouseQuery( row_number() OVER (PARTITION BY visit_id ORDER BY created_at) AS event_number from umami.website_event where website_id = {websiteId:UUID} + ${filterQuery} and created_at between {startDate:DateTime64} and {endDate:DateTime64}), ${sequenceQuery} select * @@ -246,6 +249,7 @@ async function clickhouseQuery( startDate, endDate, ...params, + ...filterParams, }, ).then(parseResult); } diff --git a/src/queries/sql/reports/getRetention.ts b/src/queries/sql/reports/getRetention.ts index 5e871500..76129fd2 100644 --- a/src/queries/sql/reports/getRetention.ts +++ b/src/queries/sql/reports/getRetention.ts @@ -28,9 +28,11 @@ async function relationalQuery( criteria: RetentionCriteria, ): Promise { const { startDate, endDate, timezone } = criteria; - const { getDateSQL, getDayDiffQuery, getCastColumnQuery, rawQuery } = prisma; + const { getDateSQL, getDayDiffQuery, getCastColumnQuery, rawQuery, parseFilters } = prisma; const unit = 'day'; + const { filterQuery, filterParams } = await parseFilters(websiteId, criteria); + return rawQuery( ` WITH cohort_items AS ( @@ -49,6 +51,7 @@ async function relationalQuery( on w.session_id = c.session_id where website_id = {{websiteId::uuid}} and created_at between {{startDate}} and {{endDate}} + ${filterQuery} ), cohort_size as ( select cohort_date, @@ -82,6 +85,7 @@ async function relationalQuery( websiteId, startDate, endDate, + ...filterParams, }, ); } @@ -91,9 +95,11 @@ async function clickhouseQuery( criteria: RetentionCriteria, ): Promise { const { startDate, endDate, timezone } = criteria; - const { getDateSQL, rawQuery } = clickhouse; + const { getDateSQL, rawQuery, parseFilters } = clickhouse; const unit = 'day'; + const { filterQuery, filterParams } = await parseFilters(websiteId, criteria); + return rawQuery( ` WITH cohort_items AS ( @@ -114,6 +120,7 @@ async function clickhouseQuery( on w.session_id = c.session_id where website_id = {websiteId:UUID} and created_at between {startDate:DateTime64} and {endDate:DateTime64} + ${filterQuery} ), cohort_size as ( select cohort_date, @@ -147,6 +154,7 @@ async function clickhouseQuery( websiteId, startDate, endDate, + ...filterParams, }, ); } diff --git a/src/queries/sql/reports/getUTM.ts b/src/queries/sql/reports/getUTM.ts index 134e14b3..cb318bf3 100644 --- a/src/queries/sql/reports/getUTM.ts +++ b/src/queries/sql/reports/getUTM.ts @@ -16,7 +16,8 @@ export async function getUTM(...args: [websiteId: string, criteria: UTMCriteria] async function relationalQuery(websiteId: string, criteria: UTMCriteria) { const { startDate, endDate } = criteria; - const { rawQuery } = prisma; + const { rawQuery, parseFilters } = prisma; + const { filterQuery, filterParams } = await parseFilters(websiteId, criteria); return rawQuery( ` @@ -26,9 +27,11 @@ async function relationalQuery(websiteId: string, criteria: UTMCriteria) { and created_at between {{startDate}} and {{endDate}} and coalesce(url_query, '') != '' and event_type = 1 + ${filterQuery} group by 1 `, { + ...filterParams, websiteId, startDate, endDate, @@ -38,7 +41,8 @@ async function relationalQuery(websiteId: string, criteria: UTMCriteria) { async function clickhouseQuery(websiteId: string, criteria: UTMCriteria) { const { startDate, endDate } = criteria; - const { rawQuery } = clickhouse; + const { rawQuery, parseFilters } = clickhouse; + const { filterQuery, filterParams } = await parseFilters(websiteId, criteria); return rawQuery( ` @@ -48,9 +52,11 @@ async function clickhouseQuery(websiteId: string, criteria: UTMCriteria) { and created_at between {startDate:DateTime64} and {endDate:DateTime64} and url_query != '' and event_type = 1 + ${filterQuery} group by 1 `, { + ...filterParams, websiteId, startDate, endDate, diff --git a/src/queries/sql/sessions/getSessionDataProperties.ts b/src/queries/sql/sessions/getSessionDataProperties.ts index 20fb11d5..173d5df2 100644 --- a/src/queries/sql/sessions/getSessionDataProperties.ts +++ b/src/queries/sql/sessions/getSessionDataProperties.ts @@ -1,11 +1,11 @@ import prisma from '@/lib/prisma'; import clickhouse from '@/lib/clickhouse'; import { CLICKHOUSE, PRISMA, runQuery } from '@/lib/db'; -import { QueryFilters, WebsiteEventData } from '@/lib/types'; +import { QueryFilters } from '@/lib/types'; export async function getSessionDataProperties( ...args: [websiteId: string, filters: QueryFilters & { propertyName?: string }] -): Promise { +) { return runQuery({ [PRISMA]: () => relationalQuery(...args), [CLICKHOUSE]: () => clickhouseQuery(...args), @@ -17,7 +17,7 @@ async function relationalQuery( filters: QueryFilters & { propertyName?: string }, ) { const { rawQuery, parseFilters } = prisma; - const { filterQuery, params } = await parseFilters(websiteId, filters, { + const { filterQuery, filterParams } = await parseFilters(websiteId, filters, { columns: { propertyName: 'data_key' }, }); @@ -36,7 +36,7 @@ async function relationalQuery( order by 2 desc limit 500 `, - params, + filterParams, ); } @@ -45,7 +45,7 @@ async function clickhouseQuery( filters: QueryFilters & { propertyName?: string }, ): Promise<{ propertyName: string; total: number }[]> { const { rawQuery, parseFilters } = clickhouse; - const { filterQuery, params } = await parseFilters(websiteId, filters, { + const { filterQuery, filterParams } = await parseFilters(websiteId, filters, { columns: { propertyName: 'data_key' }, }); @@ -65,6 +65,6 @@ async function clickhouseQuery( order by 2 desc limit 500 `, - params, + filterParams, ); } diff --git a/src/queries/sql/sessions/getSessionDataValues.ts b/src/queries/sql/sessions/getSessionDataValues.ts index 8cd6a4ab..20248fb8 100644 --- a/src/queries/sql/sessions/getSessionDataValues.ts +++ b/src/queries/sql/sessions/getSessionDataValues.ts @@ -17,7 +17,7 @@ async function relationalQuery( filters: QueryFilters & { propertyName?: string }, ) { const { rawQuery, parseFilters, getDateSQL } = prisma; - const { filterQuery, params } = await parseFilters(websiteId, filters); + const { filterQuery, filterParams } = await parseFilters(websiteId, filters); return rawQuery( ` @@ -39,7 +39,7 @@ async function relationalQuery( order by 2 desc limit 100 `, - params, + filterParams, ); } @@ -48,7 +48,7 @@ async function clickhouseQuery( filters: QueryFilters & { propertyName?: string }, ): Promise<{ propertyName: string; dataType: number; propertyValue: string; total: number }[]> { const { rawQuery, parseFilters } = clickhouse; - const { filterQuery, params } = await parseFilters(websiteId, filters); + const { filterQuery, filterParams } = await parseFilters(websiteId, filters); return rawQuery( ` @@ -68,6 +68,6 @@ async function clickhouseQuery( order by 2 desc limit 100 `, - params, + filterParams, ); } diff --git a/src/queries/sql/sessions/getSessionMetrics.ts b/src/queries/sql/sessions/getSessionMetrics.ts index ef787920..acd1bcad 100644 --- a/src/queries/sql/sessions/getSessionMetrics.ts +++ b/src/queries/sql/sessions/getSessionMetrics.ts @@ -28,7 +28,7 @@ async function relationalQuery( ) { const column = FILTER_COLUMNS[type] || type; const { parseFilters, rawQuery } = prisma; - const { filterQuery, joinSession, params } = await parseFilters( + const { filterQuery, joinSession, filterParams } = await parseFilters( websiteId, { ...filters, @@ -58,7 +58,7 @@ async function relationalQuery( limit ${limit} offset ${offset} `, - params, + filterParams, ); } @@ -71,7 +71,7 @@ async function clickhouseQuery( ): Promise<{ x: string; y: number }[]> { const column = FILTER_COLUMNS[type] || type; const { parseFilters, rawQuery } = clickhouse; - const { filterQuery, params } = await parseFilters(websiteId, { + const { filterQuery, filterParams } = await parseFilters(websiteId, { ...filters, eventType: EVENT_TYPE.pageView, }); @@ -115,5 +115,5 @@ async function clickhouseQuery( `; } - return rawQuery(sql, params); + return rawQuery(sql, filterParams); } diff --git a/src/queries/sql/sessions/getSessionStats.ts b/src/queries/sql/sessions/getSessionStats.ts index 22cc04a7..a870ff20 100644 --- a/src/queries/sql/sessions/getSessionStats.ts +++ b/src/queries/sql/sessions/getSessionStats.ts @@ -14,7 +14,7 @@ export async function getSessionStats(...args: [websiteId: string, filters: Quer async function relationalQuery(websiteId: string, filters: QueryFilters) { const { timezone = 'utc', unit = 'day' } = filters; const { getDateSQL, parseFilters, rawQuery } = prisma; - const { filterQuery, joinSession, params } = await parseFilters(websiteId, { + const { filterQuery, joinSession, filterParams } = await parseFilters(websiteId, { ...filters, eventType: EVENT_TYPE.pageView, }); @@ -33,7 +33,7 @@ async function relationalQuery(websiteId: string, filters: QueryFilters) { group by 1 order by 1 `, - params, + filterParams, ); } @@ -43,7 +43,7 @@ async function clickhouseQuery( ): Promise<{ x: string; y: number }[]> { const { timezone = 'utc', unit = 'day' } = filters; const { parseFilters, rawQuery, getDateSQL } = clickhouse; - const { filterQuery, params } = await parseFilters(websiteId, { + const { filterQuery, filterParams } = await parseFilters(websiteId, { ...filters, eventType: EVENT_TYPE.pageView, }); @@ -88,5 +88,5 @@ async function clickhouseQuery( `; } - return rawQuery(sql, params); + return rawQuery(sql, filterParams); } diff --git a/src/queries/sql/sessions/getWebsiteSessionStats.ts b/src/queries/sql/sessions/getWebsiteSessionStats.ts index 2463b7ad..16cebf2e 100644 --- a/src/queries/sql/sessions/getWebsiteSessionStats.ts +++ b/src/queries/sql/sessions/getWebsiteSessionStats.ts @@ -21,7 +21,7 @@ async function relationalQuery( { pageviews: number; visitors: number; visits: number; countries: number; events: number }[] > { const { parseFilters, rawQuery } = prisma; - const { filterQuery, params } = await parseFilters(websiteId, { + const { filterQuery, filterParams } = await parseFilters(websiteId, { ...filters, }); @@ -39,7 +39,7 @@ async function relationalQuery( and website_event.created_at between {{startDate}} and {{endDate}} ${filterQuery} `, - params, + filterParams, ); } @@ -50,7 +50,7 @@ async function clickhouseQuery( { pageviews: number; visitors: number; visits: number; countries: number; events: number }[] > { const { rawQuery, parseFilters } = clickhouse; - const { filterQuery, params } = await parseFilters(websiteId, { + const { filterQuery, filterParams } = await parseFilters(websiteId, { ...filters, }); @@ -67,6 +67,6 @@ async function clickhouseQuery( and created_at between {startDate:DateTime64} and {endDate:DateTime64} ${filterQuery} `, - params, + filterParams, ); } diff --git a/src/queries/sql/sessions/getWebsiteSessions.ts b/src/queries/sql/sessions/getWebsiteSessions.ts index 0d25de2b..81208cb1 100644 --- a/src/queries/sql/sessions/getWebsiteSessions.ts +++ b/src/queries/sql/sessions/getWebsiteSessions.ts @@ -15,7 +15,7 @@ export async function getWebsiteSessions( async function relationalQuery(websiteId: string, filters: QueryFilters, pageParams: PageParams) { const { pagedRawQuery, parseFilters } = prisma; const { search } = pageParams; - const { filterQuery, params } = await parseFilters(websiteId, { + const { filterQuery, filterParams } = await parseFilters(websiteId, { ...filters, }); @@ -68,14 +68,14 @@ async function relationalQuery(websiteId: string, filters: QueryFilters, pagePar session.city order by max(website_event.created_at) desc `, - { ...params, search: `%${search}%` }, + { ...filterParams, search: `%${search}%` }, pageParams, ); } async function clickhouseQuery(websiteId: string, filters: QueryFilters, pageParams?: PageParams) { const { pagedQuery, parseFilters, getDateStringSQL } = clickhouse; - const { params, dateQuery, filterQuery } = await parseFilters(websiteId, filters); + const { filterParams, dateQuery, filterQuery } = await parseFilters(websiteId, filters); const { search } = pageParams; return pagedQuery( @@ -113,7 +113,7 @@ async function clickhouseQuery(websiteId: string, filters: QueryFilters, pagePar group by session_id, website_id, hostname, browser, os, device, screen, language, country, region, city order by lastAt desc `, - { ...params, search }, + { ...filterParams, search }, pageParams, ); } diff --git a/src/queries/sql/sessions/getWebsiteSessionsWeekly.ts b/src/queries/sql/sessions/getWebsiteSessionsWeekly.ts index 58f8d692..3fafcc92 100644 --- a/src/queries/sql/sessions/getWebsiteSessionsWeekly.ts +++ b/src/queries/sql/sessions/getWebsiteSessionsWeekly.ts @@ -15,7 +15,7 @@ export async function getWebsiteSessionsWeekly( async function relationalQuery(websiteId: string, filters: QueryFilters) { const { timezone = 'utc' } = filters; const { rawQuery, getDateWeeklySQL, parseFilters } = prisma; - const { params } = await parseFilters(websiteId, filters); + const { filterParams } = await parseFilters(websiteId, filters); return rawQuery( ` @@ -28,14 +28,14 @@ async function relationalQuery(websiteId: string, filters: QueryFilters) { group by time order by 2 `, - params, + filterParams, ).then(formatResults); } async function clickhouseQuery(websiteId: string, filters: QueryFilters) { const { timezone = 'utc' } = filters; const { rawQuery, parseFilters } = clickhouse; - const { params } = await parseFilters(websiteId, filters); + const { filterParams } = await parseFilters(websiteId, filters); return rawQuery( ` @@ -48,7 +48,7 @@ async function clickhouseQuery(websiteId: string, filters: QueryFilters) { group by time order by time `, - params, + filterParams, ).then(formatResults); }