2023-03-23 22:01:15 +01:00
|
|
|
import clickhouse from 'lib/clickhouse';
|
|
|
|
import { CLICKHOUSE, PRISMA, runQuery } from 'lib/db';
|
|
|
|
import { WebsiteEventDataMetric } from 'lib/types';
|
2023-04-02 02:38:35 +02:00
|
|
|
import { loadWebsite } from 'lib/query';
|
2023-06-15 07:32:06 +02:00
|
|
|
import { DEFAULT_CREATED_AT } from 'lib/constants';
|
2023-03-23 22:01:15 +01:00
|
|
|
|
2023-07-05 07:51:23 +02:00
|
|
|
export interface EventDataCriteria {
|
|
|
|
fields: [{ name: string; type: string; value: string }];
|
|
|
|
filters: [
|
|
|
|
{
|
|
|
|
name: string;
|
|
|
|
type: string;
|
|
|
|
value: [string, string];
|
|
|
|
},
|
|
|
|
];
|
|
|
|
groups: [
|
|
|
|
{
|
|
|
|
name: string;
|
|
|
|
type: string;
|
2023-03-23 22:01:15 +01:00
|
|
|
},
|
2023-07-05 07:51:23 +02:00
|
|
|
];
|
|
|
|
}
|
|
|
|
|
|
|
|
export async function getEventData(
|
|
|
|
...args: [websiteId: string, startDate: Date, endDate: Date, criteria: EventDataCriteria]
|
2023-03-23 22:01:15 +01:00
|
|
|
): Promise<WebsiteEventDataMetric[]> {
|
|
|
|
return runQuery({
|
|
|
|
[PRISMA]: () => relationalQuery(...args),
|
|
|
|
[CLICKHOUSE]: () => clickhouseQuery(...args),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-07-05 07:51:23 +02:00
|
|
|
async function relationalQuery() {
|
|
|
|
return null;
|
2023-03-23 22:01:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
async function clickhouseQuery(
|
|
|
|
websiteId: string,
|
2023-07-05 07:51:23 +02:00
|
|
|
startDate: Date,
|
|
|
|
endDate: Date,
|
|
|
|
criteria: EventDataCriteria,
|
2023-03-23 22:01:15 +01:00
|
|
|
) {
|
2023-07-05 07:51:23 +02:00
|
|
|
const { fields } = criteria;
|
|
|
|
const { rawQuery, getDateFormat, getBetweenDates } = clickhouse;
|
2023-04-02 02:38:35 +02:00
|
|
|
const website = await loadWebsite(websiteId);
|
2023-06-15 07:32:06 +02:00
|
|
|
const resetDate = new Date(website?.resetAt || DEFAULT_CREATED_AT);
|
2023-03-23 22:01:15 +01:00
|
|
|
|
2023-07-05 07:51:23 +02:00
|
|
|
const uniqueFields = fields.reduce((obj, { name, type }) => {
|
|
|
|
if (!obj[name]) {
|
|
|
|
obj[name] = {
|
|
|
|
columns: ['event_key as field', `count(*) as total`, `${type}_value as value`],
|
|
|
|
groups: ['event_key', `${type}_value`],
|
|
|
|
};
|
|
|
|
}
|
|
|
|
return obj;
|
|
|
|
}, {});
|
|
|
|
|
|
|
|
const queries = Object.keys(uniqueFields).reduce((arr, key) => {
|
|
|
|
const field = uniqueFields[key];
|
|
|
|
const params = { websiteId, name: key };
|
|
|
|
|
|
|
|
return arr.concat(
|
|
|
|
rawQuery(
|
|
|
|
`select
|
|
|
|
${field.columns.join(',')}
|
|
|
|
from event_data
|
|
|
|
where website_id = {websiteId:UUID}
|
|
|
|
and event_key = {name:String}
|
|
|
|
and created_at >= ${getDateFormat(resetDate)}
|
|
|
|
and ${getBetweenDates('created_at', startDate, endDate)}
|
|
|
|
group by ${field.groups.join(',')}
|
|
|
|
limit 20
|
|
|
|
`,
|
|
|
|
params,
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
const results = (await Promise.all(queries)).flatMap(n => n);
|
|
|
|
|
|
|
|
const columns = results.reduce((arr, row) => {
|
|
|
|
const keys = Object.keys(row);
|
|
|
|
for (const key of keys) {
|
|
|
|
if (!arr.includes(key)) {
|
|
|
|
arr.push(key);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return arr;
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
return results.reduce((arr, row) => {
|
|
|
|
return arr.concat(
|
|
|
|
columns.reduce((obj, key) => {
|
|
|
|
obj[key] = row[key];
|
|
|
|
return obj;
|
|
|
|
}, {}),
|
|
|
|
);
|
|
|
|
}, []);
|
2023-03-23 22:01:15 +01:00
|
|
|
}
|