performance/UI fixes for events pages.
This commit is contained in:
1 parent
c901362429
commit
d08acc9853
5 files changed
+421
-88
No files matched your search
@@ -48,6 +48,7 @@ export function EventsTable(props: DataTableProps) {
|
||||
<IconLabel
|
||||
icon={row.eventName ? <Lightning /> : <Eye />}
|
||||
label={t(row.eventName ? labels.triggeredEvent : labels.viewedPage)}
|
||||
labelProps={{ wrap: 'nowrap' }}
|
||||
/>
|
||||
</Row>
|
||||
<Text
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
import { afterEach, describe, expect, test, vi } from 'vitest';
|
||||
|
||||
const parseFiltersResult = {
|
||||
queryParams: { websiteId: 'website-1' },
|
||||
filterQuery: 'and website_event.url_path = {{path}}',
|
||||
joinSessionQuery: 'join session on session.session_id = website_event.session_id',
|
||||
cohortQuery: 'join cohort on cohort.session_id = website_event.session_id',
|
||||
};
|
||||
|
||||
async function loadModule({
|
||||
mode,
|
||||
}: {
|
||||
mode: 'prisma' | 'clickhouse';
|
||||
}) {
|
||||
vi.resetModules();
|
||||
|
||||
const state = { mode };
|
||||
const prismaRawQuery = vi.fn().mockResolvedValue([{}]);
|
||||
const prismaParseFilters = vi.fn().mockReturnValue(parseFiltersResult);
|
||||
const clickhouseRawQuery = vi.fn().mockResolvedValue([{}]);
|
||||
const clickhouseParseFilters = vi.fn().mockReturnValue(parseFiltersResult);
|
||||
|
||||
vi.doMock('@/lib/db', () => ({
|
||||
CLICKHOUSE: 'clickhouse',
|
||||
PRISMA: 'prisma',
|
||||
runQuery: vi.fn((queries: Record<string, () => unknown>) => queries[state.mode]()),
|
||||
}));
|
||||
|
||||
vi.doMock('@/lib/prisma', () => ({
|
||||
default: {
|
||||
rawQuery: prismaRawQuery,
|
||||
parseFilters: prismaParseFilters,
|
||||
},
|
||||
}));
|
||||
|
||||
vi.doMock('@/lib/clickhouse', () => ({
|
||||
default: {
|
||||
rawQuery: clickhouseRawQuery,
|
||||
parseFilters: clickhouseParseFilters,
|
||||
},
|
||||
}));
|
||||
|
||||
const mod = await import('./getWebsiteEventStats');
|
||||
|
||||
return {
|
||||
getWebsiteEventStats: mod.getWebsiteEventStats,
|
||||
prismaRawQuery,
|
||||
clickhouseRawQuery,
|
||||
};
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
vi.resetModules();
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('getWebsiteEventStats', () => {
|
||||
test('postgres aggregates directly from filtered custom events', async () => {
|
||||
const { getWebsiteEventStats, prismaRawQuery } = await loadModule({ mode: 'prisma' });
|
||||
|
||||
await getWebsiteEventStats('website-1', { path: '/pricing' } as any);
|
||||
|
||||
const [query] = prismaRawQuery.mock.calls[0];
|
||||
|
||||
expect(query).toContain('cast(count(*) as bigint) as "events"');
|
||||
expect(query).toContain('count(distinct website_event.session_id) as "visitors"');
|
||||
expect(query).toContain('count(distinct website_event.visit_id) as "visits"');
|
||||
expect(query).toContain('count(distinct website_event.event_name) as "uniqueEvents"');
|
||||
expect(query).toContain('from website_event');
|
||||
expect(query).toContain('join session on session.session_id = website_event.session_id');
|
||||
expect(query).not.toContain('group by 1, 2, 3');
|
||||
expect(query).not.toContain('sum(t.c)');
|
||||
});
|
||||
|
||||
test('clickhouse aggregates directly from filtered custom events', async () => {
|
||||
const { getWebsiteEventStats, clickhouseRawQuery } = await loadModule({
|
||||
mode: 'clickhouse',
|
||||
});
|
||||
|
||||
await getWebsiteEventStats('website-1', { path: '/pricing' } as any);
|
||||
|
||||
const [query] = clickhouseRawQuery.mock.calls[0];
|
||||
|
||||
expect(query).toContain('count(*) as "events"');
|
||||
expect(query).toContain('uniq(session_id) as "visitors"');
|
||||
expect(query).toContain('uniq(visit_id) as "visits"');
|
||||
expect(query).toContain('uniq(event_name) as "uniqueEvents"');
|
||||
expect(query).toContain('from website_event');
|
||||
expect(query).not.toContain('group by session_id, visit_id, event_name');
|
||||
expect(query).not.toContain('sum(t.c)');
|
||||
});
|
||||
});
|
||||
@@ -34,25 +34,17 @@ async function relationalQuery(
|
||||
return rawQuery(
|
||||
`
|
||||
select
|
||||
cast(coalesce(sum(t.c), 0) as bigint) as "events",
|
||||
count(distinct t.session_id) as "visitors",
|
||||
count(distinct t.visit_id) as "visits",
|
||||
count(distinct t.event_name) as "uniqueEvents"
|
||||
from (
|
||||
select
|
||||
website_event.session_id,
|
||||
website_event.visit_id,
|
||||
website_event.event_name,
|
||||
count(*) as "c"
|
||||
from website_event
|
||||
${cohortQuery}
|
||||
${joinSessionQuery}
|
||||
where website_event.website_id = {{websiteId::uuid}}
|
||||
and website_event.created_at between {{startDate}} and {{endDate}}
|
||||
and website_event.event_type = 2
|
||||
${filterQuery}
|
||||
group by 1, 2, 3
|
||||
) as t
|
||||
cast(count(*) as bigint) as "events",
|
||||
count(distinct website_event.session_id) as "visitors",
|
||||
count(distinct website_event.visit_id) as "visits",
|
||||
count(distinct website_event.event_name) as "uniqueEvents"
|
||||
from website_event
|
||||
${cohortQuery}
|
||||
${joinSessionQuery}
|
||||
where website_event.website_id = {{websiteId::uuid}}
|
||||
and website_event.created_at between {{startDate}} and {{endDate}}
|
||||
and website_event.event_type = 2
|
||||
${filterQuery}
|
||||
`,
|
||||
queryParams,
|
||||
FUNCTION_NAME,
|
||||
@@ -72,24 +64,16 @@ async function clickhouseQuery(
|
||||
return rawQuery(
|
||||
`
|
||||
select
|
||||
sum(t.c) as "events",
|
||||
uniq(t.session_id) as "visitors",
|
||||
uniq(t.visit_id) as "visits",
|
||||
count(distinct t.event_name) as "uniqueEvents"
|
||||
from (
|
||||
select
|
||||
session_id,
|
||||
visit_id,
|
||||
event_name,
|
||||
count(*) c
|
||||
from website_event
|
||||
${cohortQuery}
|
||||
where website_id = {websiteId:UUID}
|
||||
and created_at between {startDate:DateTime64} and {endDate:DateTime64}
|
||||
and event_type = 2
|
||||
${filterQuery}
|
||||
group by session_id, visit_id, event_name
|
||||
) as t;
|
||||
count(*) as "events",
|
||||
uniq(session_id) as "visitors",
|
||||
uniq(visit_id) as "visits",
|
||||
uniq(event_name) as "uniqueEvents"
|
||||
from website_event
|
||||
${cohortQuery}
|
||||
where website_id = {websiteId:UUID}
|
||||
and created_at between {startDate:DateTime64} and {endDate:DateTime64}
|
||||
and event_type = 2
|
||||
${filterQuery};
|
||||
`,
|
||||
queryParams,
|
||||
FUNCTION_NAME,
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
import { afterEach, describe, expect, test, vi } from 'vitest';
|
||||
|
||||
const prismaParseFiltersResult = {
|
||||
queryParams: { websiteId: 'website-1' },
|
||||
filterQuery: 'and website_event.url_path = {{path}}',
|
||||
dateQuery: 'and website_event.created_at between {{startDate}} and {{endDate}}',
|
||||
cohortQuery: 'join cohort on cohort.session_id = website_event.session_id',
|
||||
joinSessionQuery: 'inner join session on website_event.session_id = session.session_id and website_event.website_id = session.website_id',
|
||||
};
|
||||
|
||||
const clickhouseParseFiltersResult = {
|
||||
queryParams: { websiteId: 'website-1' },
|
||||
filterQuery: 'and url_path = {path:String}',
|
||||
dateQuery: 'and created_at between {startDate:DateTime64} and {endDate:DateTime64}',
|
||||
cohortQuery: 'join cohort on cohort.session_id = website_event.session_id',
|
||||
joinSessionQuery: '',
|
||||
};
|
||||
|
||||
async function loadModule({
|
||||
mode,
|
||||
}: {
|
||||
mode: 'prisma' | 'clickhouse';
|
||||
}) {
|
||||
vi.resetModules();
|
||||
|
||||
const state = { mode };
|
||||
const prismaRawQuery = vi
|
||||
.fn()
|
||||
.mockResolvedValueOnce([{ num: '25' }])
|
||||
.mockResolvedValueOnce([{ id: 'event-1' }]);
|
||||
const prismaParseFilters = vi.fn().mockReturnValue(prismaParseFiltersResult);
|
||||
const clickhouseRawQuery = vi
|
||||
.fn()
|
||||
.mockResolvedValueOnce([{ num: '25' }])
|
||||
.mockResolvedValueOnce([{ id: 'event-1' }]);
|
||||
const clickhouseParseFilters = vi.fn().mockReturnValue(clickhouseParseFiltersResult);
|
||||
|
||||
vi.doMock('@/lib/db', () => ({
|
||||
CLICKHOUSE: 'clickhouse',
|
||||
PRISMA: 'prisma',
|
||||
runQuery: vi.fn((queries: Record<string, () => unknown>) => queries[state.mode]()),
|
||||
}));
|
||||
|
||||
vi.doMock('@/lib/prisma', () => ({
|
||||
default: {
|
||||
rawQuery: prismaRawQuery,
|
||||
parseFilters: prismaParseFilters,
|
||||
},
|
||||
}));
|
||||
|
||||
vi.doMock('@/lib/clickhouse', () => ({
|
||||
default: {
|
||||
rawQuery: clickhouseRawQuery,
|
||||
parseFilters: clickhouseParseFilters,
|
||||
},
|
||||
}));
|
||||
|
||||
const mod = await import('./getWebsiteEvents');
|
||||
|
||||
return {
|
||||
getWebsiteEvents: mod.getWebsiteEvents,
|
||||
prismaRawQuery,
|
||||
clickhouseRawQuery,
|
||||
};
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
vi.resetModules();
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('getWebsiteEvents', () => {
|
||||
test('postgres counts from the lightweight filtered event query and enriches only the paged rows', async () => {
|
||||
const { getWebsiteEvents, prismaRawQuery } = await loadModule({ mode: 'prisma' });
|
||||
|
||||
const result = await getWebsiteEvents('website-1', {
|
||||
page: 1,
|
||||
pageSize: 20,
|
||||
maxResults: 10000,
|
||||
orderBy: 'createdAt',
|
||||
search: 'signup',
|
||||
} as any);
|
||||
|
||||
const [countQuery] = prismaRawQuery.mock.calls[0];
|
||||
const [dataQuery] = prismaRawQuery.mock.calls[1];
|
||||
|
||||
expect(countQuery).toContain('select count(*) as num from (select 1 from (');
|
||||
expect(countQuery).not.toContain('exists(');
|
||||
expect(dataQuery).toContain('with paged_events as (');
|
||||
expect(dataQuery).toContain('join website_event on website_event.event_id = paged_events.event_id');
|
||||
expect(dataQuery).toContain('exists(');
|
||||
expect(dataQuery).toContain('where event_data.website_event_id = website_event.event_id');
|
||||
expect(dataQuery).toContain('and event_data.website_id = {{websiteId::uuid}}');
|
||||
expect(dataQuery).toContain('and event_data.created_at between {{startDate}} and {{endDate}}');
|
||||
expect(dataQuery).toContain('order by paged_events.created_at desc');
|
||||
expect(dataQuery).not.toContain('created_at between {{startDate}} and {{endDate}}) AS "hasData"');
|
||||
expect(result).toEqual({
|
||||
data: [{ id: 'event-1' }],
|
||||
count: 25,
|
||||
page: 1,
|
||||
pageSize: 20,
|
||||
orderBy: 'createdAt',
|
||||
isCapped: false,
|
||||
});
|
||||
});
|
||||
|
||||
test('clickhouse counts from the lightweight filtered event query and resolves hasData from paged ids', async () => {
|
||||
const { getWebsiteEvents, clickhouseRawQuery } = await loadModule({ mode: 'clickhouse' });
|
||||
|
||||
const result = await getWebsiteEvents('website-1', {
|
||||
page: 1,
|
||||
pageSize: 20,
|
||||
maxResults: 10000,
|
||||
orderBy: 'createdAt',
|
||||
search: 'signup',
|
||||
} as any);
|
||||
|
||||
const [countQuery] = clickhouseRawQuery.mock.calls[0];
|
||||
const [dataQuery] = clickhouseRawQuery.mock.calls[1];
|
||||
|
||||
expect(countQuery).toContain('select count(*) as num from (select 1 from (');
|
||||
expect(countQuery).not.toContain('event_data');
|
||||
expect(dataQuery).toContain('with paged_events as (');
|
||||
expect(dataQuery).toContain('inner join website_event on website_event.event_id = paged_events.event_id');
|
||||
expect(dataQuery).toContain('where website_id = {websiteId:UUID}');
|
||||
expect(dataQuery).toContain('from event_data');
|
||||
expect(dataQuery).toContain('and created_at between {startDate:DateTime64} and {endDate:DateTime64}');
|
||||
expect(dataQuery).toContain('and event_id in (select event_id from paged_events)');
|
||||
expect(dataQuery).toContain('order by paged_events.created_at desc');
|
||||
expect(dataQuery).not.toContain('event_id IN (select event_id');
|
||||
expect(result).toEqual({
|
||||
data: [{ id: 'event-1' }],
|
||||
count: '25',
|
||||
page: 1,
|
||||
pageSize: 20,
|
||||
orderBy: 'createdAt',
|
||||
search: 'signup',
|
||||
isCapped: false,
|
||||
});
|
||||
});
|
||||
|
||||
test('clickhouse reuses the parsed date filter for hasData so timezone-aware ranges stay aligned', async () => {
|
||||
vi.resetModules();
|
||||
|
||||
const clickhouseRawQuery = vi
|
||||
.fn()
|
||||
.mockResolvedValueOnce([{ num: '25' }])
|
||||
.mockResolvedValueOnce([{ id: 'event-1' }]);
|
||||
|
||||
vi.doMock('@/lib/db', () => ({
|
||||
CLICKHOUSE: 'clickhouse',
|
||||
PRISMA: 'prisma',
|
||||
runQuery: vi.fn((queries: Record<string, () => unknown>) => queries.clickhouse()),
|
||||
}));
|
||||
|
||||
vi.doMock('@/lib/prisma', () => ({
|
||||
default: {},
|
||||
}));
|
||||
|
||||
vi.doMock('@/lib/clickhouse', () => ({
|
||||
default: {
|
||||
rawQuery: clickhouseRawQuery,
|
||||
parseFilters: vi.fn().mockReturnValue({
|
||||
...clickhouseParseFiltersResult,
|
||||
dateQuery:
|
||||
'and created_at between toTimezone({startDate:DateTime64},{timezone:String}) and toTimezone({endDate:DateTime64},{timezone:String})',
|
||||
}),
|
||||
},
|
||||
}));
|
||||
|
||||
const { getWebsiteEvents } = await import('./getWebsiteEvents');
|
||||
|
||||
await getWebsiteEvents('website-1', {
|
||||
page: 1,
|
||||
pageSize: 20,
|
||||
timezone: 'America/Los_Angeles',
|
||||
} as any);
|
||||
|
||||
const [dataQuery] = clickhouseRawQuery.mock.calls[1];
|
||||
|
||||
expect(dataQuery).toContain(
|
||||
'and created_at between toTimezone({startDate:DateTime64},{timezone:String}) and toTimezone({endDate:DateTime64},{timezone:String})',
|
||||
);
|
||||
expect(dataQuery).not.toContain(
|
||||
'and created_at between {startDate:DateTime64} and {endDate:DateTime64}\r\n and event_id in (select event_id from paged_events)',
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,5 @@
|
||||
import clickhouse from '@/lib/clickhouse';
|
||||
import { DEFAULT_PAGE_SIZE } from '@/lib/constants';
|
||||
import { EVENT_TYPE } from '@/lib/constants';
|
||||
import { CLICKHOUSE, PRISMA, runQuery } from '@/lib/db';
|
||||
import prisma from '@/lib/prisma';
|
||||
@@ -14,20 +15,48 @@ export function getWebsiteEvents(...args: [websiteId: string, filters: QueryFilt
|
||||
}
|
||||
|
||||
async function relationalQuery(websiteId: string, filters: QueryFilters) {
|
||||
const { pagedRawQuery, parseFilters } = prisma;
|
||||
const { search } = filters;
|
||||
const { filterQuery, dateQuery, cohortQuery, queryParams } = parseFilters({
|
||||
const { rawQuery, parseFilters } = prisma;
|
||||
const { search, page = 1, pageSize, maxResults, orderBy } = filters;
|
||||
const size = +pageSize || DEFAULT_PAGE_SIZE;
|
||||
const offset = +size * (+page - 1);
|
||||
const { filterQuery, dateQuery, cohortQuery, joinSessionQuery, queryParams } = parseFilters({
|
||||
...filters,
|
||||
websiteId,
|
||||
});
|
||||
const hasDataDateQuery = dateQuery.replaceAll('website_event.', 'event_data.');
|
||||
|
||||
const searchQuery = search
|
||||
? `and ((event_name ilike {{search}} and event_type = ${EVENT_TYPE.customEvent})
|
||||
or (url_path ilike {{search}} and event_type = ${EVENT_TYPE.pageView}))`
|
||||
: '';
|
||||
|
||||
return pagedRawQuery(
|
||||
const eventQuery = `
|
||||
select
|
||||
website_event.event_id,
|
||||
website_event.created_at
|
||||
from website_event
|
||||
${cohortQuery}
|
||||
${joinSessionQuery}
|
||||
where website_event.website_id = {{websiteId::uuid}}
|
||||
and website_event.event_type != ${EVENT_TYPE.performance}
|
||||
${dateQuery}
|
||||
${filterQuery}
|
||||
${searchQuery}
|
||||
`;
|
||||
|
||||
const countQuery = maxResults
|
||||
? `select count(*) as num from (select 1 from (${eventQuery}) t limit ${+maxResults}) t2`
|
||||
: `select count(*) as num from (${eventQuery}) t`;
|
||||
|
||||
const count = await rawQuery(countQuery, queryParams).then(res => Number(res[0].num));
|
||||
|
||||
const data = await rawQuery(
|
||||
`
|
||||
with paged_events as (
|
||||
${eventQuery}
|
||||
order by created_at desc
|
||||
limit ${size} offset ${offset}
|
||||
)
|
||||
select
|
||||
website_event.event_id as "id",
|
||||
website_event.website_id as "websiteId",
|
||||
@@ -40,37 +69,45 @@ async function relationalQuery(websiteId: string, filters: QueryFilters) {
|
||||
website_event.referrer_query as "referrerQuery",
|
||||
website_event.referrer_domain as "referrerDomain",
|
||||
session.country as country,
|
||||
city as city,
|
||||
device as device,
|
||||
os as os,
|
||||
browser as browser,
|
||||
page_title as "pageTitle",
|
||||
session.city as city,
|
||||
session.device as device,
|
||||
session.os as os,
|
||||
session.browser as browser,
|
||||
website_event.page_title as "pageTitle",
|
||||
website_event.event_type as "eventType",
|
||||
website_event.event_name as "eventName",
|
||||
event_id IN (select website_event_id
|
||||
from event_data
|
||||
where website_id = {{websiteId::uuid}}
|
||||
and created_at between {{startDate}} and {{endDate}}) AS "hasData"
|
||||
from website_event
|
||||
${cohortQuery}
|
||||
join session on session.session_id = website_event.session_id
|
||||
exists(
|
||||
select 1
|
||||
from event_data
|
||||
where event_data.website_event_id = website_event.event_id
|
||||
and event_data.website_id = {{websiteId::uuid}}
|
||||
${hasDataDateQuery}
|
||||
) as "hasData"
|
||||
from paged_events
|
||||
join website_event on website_event.event_id = paged_events.event_id
|
||||
join session on session.session_id = website_event.session_id
|
||||
and session.website_id = website_event.website_id
|
||||
where website_event.website_id = {{websiteId::uuid}}
|
||||
and website_event.event_type != ${EVENT_TYPE.performance}
|
||||
${dateQuery}
|
||||
${filterQuery}
|
||||
${searchQuery}
|
||||
order by website_event.created_at desc
|
||||
order by paged_events.created_at desc
|
||||
`,
|
||||
queryParams,
|
||||
filters,
|
||||
FUNCTION_NAME,
|
||||
);
|
||||
|
||||
return {
|
||||
data,
|
||||
count,
|
||||
page: +page,
|
||||
pageSize: size,
|
||||
orderBy,
|
||||
isCapped: !!maxResults && +count >= +maxResults,
|
||||
};
|
||||
}
|
||||
|
||||
async function clickhouseQuery(websiteId: string, filters: QueryFilters) {
|
||||
const { pagedRawQuery, parseFilters } = clickhouse;
|
||||
const { search } = filters;
|
||||
const { rawQuery, parseFilters } = clickhouse;
|
||||
const { search, page = 1, pageSize, maxResults, orderBy } = filters;
|
||||
const size = +pageSize || DEFAULT_PAGE_SIZE;
|
||||
const offset = +size * (+page - 1);
|
||||
const { queryParams, dateQuery, cohortQuery, filterQuery } = parseFilters({
|
||||
...filters,
|
||||
websiteId,
|
||||
@@ -81,31 +118,10 @@ async function clickhouseQuery(websiteId: string, filters: QueryFilters) {
|
||||
or (positionCaseInsensitive(url_path, {search:String}) > 0 and event_type = ${EVENT_TYPE.pageView}))`
|
||||
: '';
|
||||
|
||||
return pagedRawQuery(
|
||||
`
|
||||
const eventQuery = `
|
||||
select
|
||||
event_id as id,
|
||||
website_id as websiteId,
|
||||
session_id as sessionId,
|
||||
created_at as createdAt,
|
||||
hostname,
|
||||
url_path as urlPath,
|
||||
url_query as urlQuery,
|
||||
referrer_path as referrerPath,
|
||||
referrer_query as referrerQuery,
|
||||
referrer_domain as referrerDomain,
|
||||
country as country,
|
||||
city as city,
|
||||
device as device,
|
||||
os as os,
|
||||
browser as browser,
|
||||
page_title as pageTitle,
|
||||
event_type as eventType,
|
||||
event_name as eventName,
|
||||
event_id IN (select event_id
|
||||
from event_data
|
||||
where website_id = {websiteId:UUID}
|
||||
${dateQuery}) as hasData
|
||||
event_id,
|
||||
created_at
|
||||
from website_event
|
||||
${cohortQuery}
|
||||
where website_id = {websiteId:UUID}
|
||||
@@ -113,10 +129,62 @@ async function clickhouseQuery(websiteId: string, filters: QueryFilters) {
|
||||
${dateQuery}
|
||||
${filterQuery}
|
||||
${searchQuery}
|
||||
order by created_at desc
|
||||
`;
|
||||
|
||||
const countQuery = maxResults
|
||||
? `select count(*) as num from (select 1 from (${eventQuery}) t limit ${+maxResults}) t2`
|
||||
: `select count(*) as num from (${eventQuery}) t`;
|
||||
|
||||
const count = await rawQuery(countQuery, queryParams).then(res => res[0].num);
|
||||
|
||||
const data = await rawQuery(
|
||||
`
|
||||
with paged_events as (
|
||||
${eventQuery}
|
||||
order by created_at desc
|
||||
limit ${size} offset ${offset}
|
||||
)
|
||||
select
|
||||
website_event.event_id as id,
|
||||
website_event.website_id as websiteId,
|
||||
website_event.session_id as sessionId,
|
||||
website_event.created_at as createdAt,
|
||||
website_event.hostname,
|
||||
website_event.url_path as urlPath,
|
||||
website_event.url_query as urlQuery,
|
||||
website_event.referrer_path as referrerPath,
|
||||
website_event.referrer_query as referrerQuery,
|
||||
website_event.referrer_domain as referrerDomain,
|
||||
website_event.country as country,
|
||||
website_event.city as city,
|
||||
website_event.device as device,
|
||||
website_event.os as os,
|
||||
website_event.browser as browser,
|
||||
website_event.page_title as pageTitle,
|
||||
website_event.event_type as eventType,
|
||||
website_event.event_name as eventName,
|
||||
website_event.event_id in (
|
||||
select event_id
|
||||
from event_data
|
||||
where website_id = {websiteId:UUID}
|
||||
${dateQuery}
|
||||
and event_id in (select event_id from paged_events)
|
||||
) as hasData
|
||||
from paged_events
|
||||
inner join website_event on website_event.event_id = paged_events.event_id
|
||||
order by paged_events.created_at desc
|
||||
`,
|
||||
queryParams,
|
||||
filters,
|
||||
FUNCTION_NAME,
|
||||
);
|
||||
|
||||
return {
|
||||
data,
|
||||
count,
|
||||
page: +page,
|
||||
pageSize: size,
|
||||
orderBy,
|
||||
search,
|
||||
isCapped: !!maxResults && +count >= +maxResults,
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user