mirror of
https://github.com/kremalicious/umami.git
synced 2025-02-14 21:10:34 +01:00
Merge branch 'dev' of https://github.com/umami-software/umami into feat/um-376-retention-report
This commit is contained in:
commit
cad3dd8847
@ -4,7 +4,7 @@ import { MYSQL, POSTGRESQL, getDatabaseType } from 'lib/db';
|
|||||||
import { FILTER_COLUMNS, IGNORED_FILTERS, SESSION_COLUMNS } from './constants';
|
import { FILTER_COLUMNS, IGNORED_FILTERS, SESSION_COLUMNS } from './constants';
|
||||||
import { loadWebsite } from './load';
|
import { loadWebsite } from './load';
|
||||||
import { maxDate } from './date';
|
import { maxDate } from './date';
|
||||||
import { QueryFilters } from './types';
|
import { QueryFilters, QueryOptions } from './types';
|
||||||
|
|
||||||
const MYSQL_DATE_FORMATS = {
|
const MYSQL_DATE_FORMATS = {
|
||||||
minute: '%Y-%m-%d %H:%i:00',
|
minute: '%Y-%m-%d %H:%i:00',
|
||||||
@ -74,12 +74,12 @@ function getFilterQuery(filters = {}): string {
|
|||||||
if (filter !== undefined && !IGNORED_FILTERS.includes(key)) {
|
if (filter !== undefined && !IGNORED_FILTERS.includes(key)) {
|
||||||
const column = FILTER_COLUMNS[key] || key;
|
const column = FILTER_COLUMNS[key] || key;
|
||||||
arr.push(`and ${column}={{${key}}}`);
|
arr.push(`and ${column}={{${key}}}`);
|
||||||
}
|
|
||||||
|
|
||||||
if (key === 'referrer') {
|
if (key === 'referrer') {
|
||||||
arr.push(
|
arr.push(
|
||||||
'and (website_event.referrer_domain != {{websiteDomain}} or website_event.referrer_domain is null)',
|
'and (website_event.referrer_domain != {{websiteDomain}} or website_event.referrer_domain is null)',
|
||||||
);
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return arr;
|
return arr;
|
||||||
@ -88,13 +88,18 @@ function getFilterQuery(filters = {}): string {
|
|||||||
return query.join('\n');
|
return query.join('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
async function parseFilters(websiteId, filters: QueryFilters & { [key: string]: any } = {}) {
|
async function parseFilters(
|
||||||
|
websiteId,
|
||||||
|
filters: QueryFilters & { [key: string]: any } = {},
|
||||||
|
options: QueryOptions = {},
|
||||||
|
) {
|
||||||
const website = await loadWebsite(websiteId);
|
const website = await loadWebsite(websiteId);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
joinSession: Object.keys(filters).find(key => SESSION_COLUMNS[key])
|
joinSession:
|
||||||
? `inner join session on website_event.session_id = session.session_id`
|
options?.joinSession || Object.keys(filters).find(key => SESSION_COLUMNS.includes(key))
|
||||||
: '',
|
? `inner join session on website_event.session_id = session.session_id`
|
||||||
|
: '',
|
||||||
filterQuery: getFilterQuery(filters),
|
filterQuery: getFilterQuery(filters),
|
||||||
params: {
|
params: {
|
||||||
...filters,
|
...filters,
|
||||||
|
@ -137,11 +137,11 @@ export interface QueryFilters {
|
|||||||
unit?: string;
|
unit?: string;
|
||||||
domain?: string;
|
domain?: string;
|
||||||
eventType?: number;
|
eventType?: number;
|
||||||
|
eventName?: string;
|
||||||
url?: string;
|
url?: string;
|
||||||
referrer?: string;
|
referrer?: string;
|
||||||
title?: string;
|
title?: string;
|
||||||
query?: string;
|
query?: string;
|
||||||
event?: string;
|
|
||||||
os?: string;
|
os?: string;
|
||||||
browser?: string;
|
browser?: string;
|
||||||
device?: string;
|
device?: string;
|
||||||
@ -150,3 +150,7 @@ export interface QueryFilters {
|
|||||||
city?: string;
|
city?: string;
|
||||||
language?: string;
|
language?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface QueryOptions {
|
||||||
|
joinSession?: boolean;
|
||||||
|
}
|
||||||
|
@ -43,10 +43,8 @@ export default async (
|
|||||||
endDate,
|
endDate,
|
||||||
timezone,
|
timezone,
|
||||||
unit,
|
unit,
|
||||||
filters: {
|
url,
|
||||||
url,
|
eventName,
|
||||||
eventName,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return ok(res, events);
|
return ok(res, events);
|
||||||
|
@ -5,7 +5,7 @@ import { WebsiteEventMetric, QueryFilters } from 'lib/types';
|
|||||||
import { EVENT_TYPE } from 'lib/constants';
|
import { EVENT_TYPE } from 'lib/constants';
|
||||||
|
|
||||||
export async function getEventMetrics(
|
export async function getEventMetrics(
|
||||||
...args: [websiteId: string, criteria: QueryFilters]
|
...args: [websiteId: string, filters: QueryFilters]
|
||||||
): Promise<WebsiteEventMetric[]> {
|
): Promise<WebsiteEventMetric[]> {
|
||||||
return runQuery({
|
return runQuery({
|
||||||
[PRISMA]: () => relationalQuery(...args),
|
[PRISMA]: () => relationalQuery(...args),
|
||||||
@ -16,7 +16,7 @@ export async function getEventMetrics(
|
|||||||
async function relationalQuery(websiteId: string, filters: QueryFilters) {
|
async function relationalQuery(websiteId: string, filters: QueryFilters) {
|
||||||
const { timezone = 'utc', unit = 'day' } = filters;
|
const { timezone = 'utc', unit = 'day' } = filters;
|
||||||
const { rawQuery, getDateQuery, parseFilters } = prisma;
|
const { rawQuery, getDateQuery, parseFilters } = prisma;
|
||||||
const { filterQuery, params } = await parseFilters(websiteId, {
|
const { filterQuery, joinSession, params } = await parseFilters(websiteId, {
|
||||||
...filters,
|
...filters,
|
||||||
eventType: EVENT_TYPE.customEvent,
|
eventType: EVENT_TYPE.customEvent,
|
||||||
});
|
});
|
||||||
@ -28,6 +28,7 @@ async function relationalQuery(websiteId: string, filters: QueryFilters) {
|
|||||||
${getDateQuery('created_at', unit, timezone)} t,
|
${getDateQuery('created_at', unit, timezone)} t,
|
||||||
count(*) y
|
count(*) y
|
||||||
from website_event
|
from website_event
|
||||||
|
${joinSession}
|
||||||
where website_id = {{websiteId::uuid}}
|
where website_id = {{websiteId::uuid}}
|
||||||
and created_at between {{startDate}} and {{endDate}}
|
and created_at between {{startDate}} and {{endDate}}
|
||||||
and event_type = {{eventType}}
|
and event_type = {{eventType}}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import prisma from 'lib/prisma';
|
import prisma from 'lib/prisma';
|
||||||
import clickhouse from 'lib/clickhouse';
|
import clickhouse from 'lib/clickhouse';
|
||||||
import { runQuery, CLICKHOUSE, PRISMA } from 'lib/db';
|
import { runQuery, CLICKHOUSE, PRISMA } from 'lib/db';
|
||||||
import { EVENT_TYPE } from 'lib/constants';
|
import { EVENT_TYPE, SESSION_COLUMNS } from 'lib/constants';
|
||||||
import { QueryFilters } from 'lib/types';
|
import { QueryFilters } from 'lib/types';
|
||||||
|
|
||||||
export async function getPageviewMetrics(
|
export async function getPageviewMetrics(
|
||||||
@ -15,16 +15,20 @@ export async function getPageviewMetrics(
|
|||||||
|
|
||||||
async function relationalQuery(websiteId: string, column: string, filters: QueryFilters) {
|
async function relationalQuery(websiteId: string, column: string, filters: QueryFilters) {
|
||||||
const { rawQuery, parseFilters } = prisma;
|
const { rawQuery, parseFilters } = prisma;
|
||||||
const { filterQuery, joinSession, params } = await parseFilters(websiteId, {
|
const { filterQuery, joinSession, params } = await parseFilters(
|
||||||
...filters,
|
websiteId,
|
||||||
eventType: column === 'event_name' ? EVENT_TYPE.customEvent : EVENT_TYPE.pageView,
|
{
|
||||||
});
|
...filters,
|
||||||
|
eventType: column === 'event_name' ? EVENT_TYPE.customEvent : EVENT_TYPE.pageView,
|
||||||
|
},
|
||||||
|
{ joinSession: SESSION_COLUMNS.includes(column) },
|
||||||
|
);
|
||||||
|
|
||||||
return rawQuery(
|
return rawQuery(
|
||||||
`
|
`
|
||||||
select ${column} x, count(*) y
|
select ${column} x, count(*) y
|
||||||
from website_event
|
from website_event
|
||||||
${joinSession}
|
${joinSession}
|
||||||
where website_event.website_id = {{websiteId::uuid}}
|
where website_event.website_id = {{websiteId::uuid}}
|
||||||
and website_event.created_at between {{startDate}} and {{endDate}}
|
and website_event.created_at between {{startDate}} and {{endDate}}
|
||||||
and event_type = {{eventType}}
|
and event_type = {{eventType}}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import prisma from 'lib/prisma';
|
import prisma from 'lib/prisma';
|
||||||
import clickhouse from 'lib/clickhouse';
|
import clickhouse from 'lib/clickhouse';
|
||||||
import { runQuery, CLICKHOUSE, PRISMA } from 'lib/db';
|
import { runQuery, CLICKHOUSE, PRISMA } from 'lib/db';
|
||||||
import { EVENT_TYPE } from 'lib/constants';
|
import { EVENT_TYPE, SESSION_COLUMNS } from 'lib/constants';
|
||||||
import { QueryFilters } from 'lib/types';
|
import { QueryFilters } from 'lib/types';
|
||||||
|
|
||||||
export async function getSessionMetrics(
|
export async function getSessionMetrics(
|
||||||
@ -15,21 +15,26 @@ export async function getSessionMetrics(
|
|||||||
|
|
||||||
async function relationalQuery(websiteId: string, column: string, filters: QueryFilters) {
|
async function relationalQuery(websiteId: string, column: string, filters: QueryFilters) {
|
||||||
const { parseFilters, rawQuery } = prisma;
|
const { parseFilters, rawQuery } = prisma;
|
||||||
const { filterQuery, params } = await parseFilters(websiteId, {
|
const { filterQuery, joinSession, params } = await parseFilters(
|
||||||
...filters,
|
websiteId,
|
||||||
eventType: EVENT_TYPE.pageView,
|
{
|
||||||
});
|
...filters,
|
||||||
|
eventType: EVENT_TYPE.pageView,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
joinSession: SESSION_COLUMNS.includes(column),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
return rawQuery(
|
return rawQuery(
|
||||||
`select ${column} x, count(*) y
|
`
|
||||||
from website_event
|
select ${column} x, count(*) y
|
||||||
inner join session
|
from website_event
|
||||||
on session.session_id = website_event.session_id
|
${joinSession}
|
||||||
where website_event.website_id = {{websiteId::uuid}}
|
where website_event.website_id = {{websiteId::uuid}}
|
||||||
and website_event.created_at between {{startDate}} and {{endDate}}
|
and website_event.created_at between {{startDate}} and {{endDate}}
|
||||||
and website_event.event_type = {{eventType}}
|
and website_event.event_type = {{eventType}}
|
||||||
${filterQuery}
|
${filterQuery}
|
||||||
) as t
|
|
||||||
group by 1
|
group by 1
|
||||||
order by 2 desc
|
order by 2 desc
|
||||||
limit 100`,
|
limit 100`,
|
||||||
|
@ -14,7 +14,7 @@ export async function getSessionStats(...args: [websiteId: string, filters: Quer
|
|||||||
async function relationalQuery(websiteId: string, filters: QueryFilters) {
|
async function relationalQuery(websiteId: string, filters: QueryFilters) {
|
||||||
const { timezone = 'utc', unit = 'day' } = filters;
|
const { timezone = 'utc', unit = 'day' } = filters;
|
||||||
const { getDateQuery, parseFilters, rawQuery } = prisma;
|
const { getDateQuery, parseFilters, rawQuery } = prisma;
|
||||||
const { filterQuery, params } = await parseFilters(websiteId, {
|
const { filterQuery, joinSession, params } = await parseFilters(websiteId, {
|
||||||
...filters,
|
...filters,
|
||||||
eventType: EVENT_TYPE.pageView,
|
eventType: EVENT_TYPE.pageView,
|
||||||
});
|
});
|
||||||
@ -25,8 +25,7 @@ async function relationalQuery(websiteId: string, filters: QueryFilters) {
|
|||||||
${getDateQuery('website_event.created_at', unit, timezone)} x,
|
${getDateQuery('website_event.created_at', unit, timezone)} x,
|
||||||
count(distinct website_event.session_id) y
|
count(distinct website_event.session_id) y
|
||||||
from website_event
|
from website_event
|
||||||
inner join session
|
${joinSession}
|
||||||
on session.session_id = website_event.session_id
|
|
||||||
where website_event.website_id = {{websiteId::uuid}}
|
where website_event.website_id = {{websiteId::uuid}}
|
||||||
and website_event.created_at between {{startDate}} and {{endDate}}
|
and website_event.created_at between {{startDate}} and {{endDate}}
|
||||||
and event_type = {{eventType}}
|
and event_type = {{eventType}}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user