mirror of
https://github.com/umami-software/umami.git
synced 2026-02-04 04:37:11 +01:00
Feat/um 305 unique session ch (#2065)
* Add session_data / session redis to CH. * Add mysql migration.
This commit is contained in:
parent
1038a54fe4
commit
b484286523
23 changed files with 405 additions and 300 deletions
|
|
@ -3,7 +3,7 @@ import { getRandomChars } from 'next-basics';
|
|||
import cache from 'lib/cache';
|
||||
import { ROLES } from 'lib/constants';
|
||||
import prisma from 'lib/prisma';
|
||||
import { Website, User, Roles } from 'lib/types';
|
||||
import { Website, User, Role } from 'lib/types';
|
||||
|
||||
export async function getUser(
|
||||
where: Prisma.UserWhereInput | Prisma.UserWhereUniqueInput,
|
||||
|
|
@ -91,7 +91,7 @@ export async function createUser(data: {
|
|||
id: string;
|
||||
username: string;
|
||||
password: string;
|
||||
role: Roles;
|
||||
role: Role;
|
||||
}): Promise<{
|
||||
id: string;
|
||||
username: string;
|
||||
|
|
|
|||
|
|
@ -133,9 +133,10 @@ async function clickhouseQuery(data: {
|
|||
const createdAt = getDateFormat(new Date());
|
||||
|
||||
const message = {
|
||||
...args,
|
||||
website_id: websiteId,
|
||||
session_id: sessionId,
|
||||
event_id: eventId,
|
||||
event_id: uuid(),
|
||||
country: country ? country : null,
|
||||
subdivision1: country && subdivision1 ? `${country}-${subdivision1}` : null,
|
||||
subdivision2: subdivision2 ? subdivision2 : null,
|
||||
|
|
@ -149,7 +150,6 @@ async function clickhouseQuery(data: {
|
|||
event_type: eventName ? EVENT_TYPE.customEvent : EVENT_TYPE.pageView,
|
||||
event_name: eventName ? eventName?.substring(0, EVENT_NAME_LENGTH) : null,
|
||||
created_at: createdAt,
|
||||
...args,
|
||||
};
|
||||
|
||||
await sendMessage(message, 'event');
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import { Prisma } from '@prisma/client';
|
||||
import { EVENT_DATA_TYPE } from 'lib/constants';
|
||||
import { DYNAMIC_DATA_TYPE } from 'lib/constants';
|
||||
import { uuid } from 'lib/crypto';
|
||||
import { CLICKHOUSE, PRISMA, runQuery } from 'lib/db';
|
||||
import { flattenJSON } from 'lib/eventData';
|
||||
import { flattenJSON } from 'lib/dynamicData';
|
||||
import kafka from 'lib/kafka';
|
||||
import prisma from 'lib/prisma';
|
||||
import { EventData } from 'lib/types';
|
||||
import { DynamicData } from 'lib/types';
|
||||
|
||||
export async function saveEventData(args: {
|
||||
websiteId: string;
|
||||
|
|
@ -13,7 +13,7 @@ export async function saveEventData(args: {
|
|||
sessionId?: string;
|
||||
urlPath?: string;
|
||||
eventName?: string;
|
||||
eventData: EventData;
|
||||
eventData: DynamicData;
|
||||
createdAt?: string;
|
||||
}) {
|
||||
return runQuery({
|
||||
|
|
@ -25,7 +25,7 @@ export async function saveEventData(args: {
|
|||
async function relationalQuery(data: {
|
||||
websiteId: string;
|
||||
eventId: string;
|
||||
eventData: EventData;
|
||||
eventData: DynamicData;
|
||||
}): Promise<Prisma.BatchPayload> {
|
||||
const { websiteId, eventId, eventData } = data;
|
||||
|
||||
|
|
@ -36,16 +36,16 @@ async function relationalQuery(data: {
|
|||
id: uuid(),
|
||||
websiteEventId: eventId,
|
||||
websiteId,
|
||||
eventKey: a.key,
|
||||
eventStringValue:
|
||||
a.eventDataType === EVENT_DATA_TYPE.string ||
|
||||
a.eventDataType === EVENT_DATA_TYPE.boolean ||
|
||||
a.eventDataType === EVENT_DATA_TYPE.array
|
||||
key: a.key,
|
||||
stringValue:
|
||||
a.dynamicDataType === DYNAMIC_DATA_TYPE.string ||
|
||||
a.dynamicDataType === DYNAMIC_DATA_TYPE.boolean ||
|
||||
a.dynamicDataType === DYNAMIC_DATA_TYPE.array
|
||||
? a.value
|
||||
: null,
|
||||
eventNumericValue: a.eventDataType === EVENT_DATA_TYPE.number ? a.value : null,
|
||||
eventDateValue: a.eventDataType === EVENT_DATA_TYPE.date ? new Date(a.value) : null,
|
||||
eventDataType: a.eventDataType,
|
||||
numericValue: a.dynamicDataType === DYNAMIC_DATA_TYPE.number ? a.value : null,
|
||||
dateValue: a.dynamicDataType === DYNAMIC_DATA_TYPE.date ? new Date(a.value) : null,
|
||||
dataType: a.dynamicDataType,
|
||||
}));
|
||||
|
||||
return prisma.client.eventData.createMany({
|
||||
|
|
@ -59,7 +59,7 @@ async function clickhouseQuery(data: {
|
|||
sessionId?: string;
|
||||
urlPath?: string;
|
||||
eventName?: string;
|
||||
eventData: EventData;
|
||||
eventData: DynamicData;
|
||||
createdAt?: string;
|
||||
}) {
|
||||
const { websiteId, sessionId, eventId, urlPath, eventName, eventData, createdAt } = data;
|
||||
|
|
@ -75,15 +75,15 @@ async function clickhouseQuery(data: {
|
|||
url_path: urlPath,
|
||||
event_name: eventName,
|
||||
event_key: a.key,
|
||||
event_string_value:
|
||||
a.eventDataType === EVENT_DATA_TYPE.string ||
|
||||
a.eventDataType === EVENT_DATA_TYPE.boolean ||
|
||||
a.eventDataType === EVENT_DATA_TYPE.array
|
||||
string_value:
|
||||
a.dynamicDataType === DYNAMIC_DATA_TYPE.string ||
|
||||
a.dynamicDataType === DYNAMIC_DATA_TYPE.boolean ||
|
||||
a.dynamicDataType === DYNAMIC_DATA_TYPE.array
|
||||
? a.value
|
||||
: null,
|
||||
event_numeric_value: a.eventDataType === EVENT_DATA_TYPE.number ? a.value : null,
|
||||
event_date_value: a.eventDataType === EVENT_DATA_TYPE.date ? getDateFormat(a.value) : null,
|
||||
event_data_type: a.eventDataType,
|
||||
numeric_value: a.dynamicDataType === DYNAMIC_DATA_TYPE.number ? a.value : null,
|
||||
date_value: a.dynamicDataType === DYNAMIC_DATA_TYPE.date ? getDateFormat(a.value) : null,
|
||||
data_type: a.dynamicDataType,
|
||||
created_at: createdAt,
|
||||
}));
|
||||
|
||||
|
|
|
|||
|
|
@ -1,23 +1,8 @@
|
|||
import { CLICKHOUSE, PRISMA, runQuery } from 'lib/db';
|
||||
import kafka from 'lib/kafka';
|
||||
import prisma from 'lib/prisma';
|
||||
import cache from 'lib/cache';
|
||||
import { Prisma } from '@prisma/client';
|
||||
import cache from 'lib/cache';
|
||||
import prisma from 'lib/prisma';
|
||||
|
||||
export async function createSession(args: Prisma.SessionCreateInput) {
|
||||
return runQuery({
|
||||
[PRISMA]: () => relationalQuery(args),
|
||||
[CLICKHOUSE]: () => clickhouseQuery(args),
|
||||
}).then(async data => {
|
||||
if (cache.enabled) {
|
||||
await cache.storeSession(data);
|
||||
}
|
||||
|
||||
return data;
|
||||
});
|
||||
}
|
||||
|
||||
async function relationalQuery(data: Prisma.SessionCreateInput) {
|
||||
export async function createSession(data: Prisma.SessionCreateInput) {
|
||||
const {
|
||||
id,
|
||||
websiteId,
|
||||
|
|
@ -33,71 +18,28 @@ async function relationalQuery(data: Prisma.SessionCreateInput) {
|
|||
city,
|
||||
} = data;
|
||||
|
||||
return prisma.client.session.create({
|
||||
data: {
|
||||
id,
|
||||
websiteId,
|
||||
hostname,
|
||||
browser,
|
||||
os,
|
||||
device,
|
||||
screen,
|
||||
language,
|
||||
country,
|
||||
subdivision1: country && subdivision1 ? `${country}-${subdivision1}` : null,
|
||||
subdivision2,
|
||||
city,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async function clickhouseQuery(data: {
|
||||
id: string;
|
||||
websiteId: string;
|
||||
hostname?: string;
|
||||
browser?: string;
|
||||
os?: string;
|
||||
device?: string;
|
||||
screen?: string;
|
||||
language?: string;
|
||||
country?: string;
|
||||
subdivision1?: string;
|
||||
subdivision2?: string;
|
||||
city?: string;
|
||||
}) {
|
||||
const {
|
||||
id,
|
||||
websiteId,
|
||||
hostname,
|
||||
browser,
|
||||
os,
|
||||
device,
|
||||
screen,
|
||||
language,
|
||||
country,
|
||||
subdivision1,
|
||||
subdivision2,
|
||||
city,
|
||||
} = data;
|
||||
const { getDateFormat, sendMessage } = kafka;
|
||||
|
||||
const msg = {
|
||||
session_id: id,
|
||||
website_id: websiteId,
|
||||
hostname,
|
||||
browser,
|
||||
os,
|
||||
device,
|
||||
screen,
|
||||
language,
|
||||
country,
|
||||
subdivision1,
|
||||
subdivision2,
|
||||
city,
|
||||
created_at: getDateFormat(new Date()),
|
||||
};
|
||||
|
||||
await sendMessage(msg, 'event');
|
||||
|
||||
return data;
|
||||
return prisma.client.session
|
||||
.create({
|
||||
data: {
|
||||
id,
|
||||
websiteId,
|
||||
hostname,
|
||||
browser,
|
||||
os,
|
||||
device,
|
||||
screen,
|
||||
language,
|
||||
country,
|
||||
subdivision1: country && subdivision1 ? `${country}-${subdivision1}` : null,
|
||||
subdivision2,
|
||||
city,
|
||||
},
|
||||
})
|
||||
.then(async data => {
|
||||
if (cache.enabled) {
|
||||
await cache.storeSession(data);
|
||||
}
|
||||
|
||||
return data;
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,43 +1,8 @@
|
|||
import clickhouse from 'lib/clickhouse';
|
||||
import { CLICKHOUSE, PRISMA, runQuery } from 'lib/db';
|
||||
import prisma from 'lib/prisma';
|
||||
import { Prisma } from '@prisma/client';
|
||||
import prisma from 'lib/prisma';
|
||||
|
||||
export async function getSession(args: { id: string }) {
|
||||
return runQuery({
|
||||
[PRISMA]: () => relationalQuery(args),
|
||||
[CLICKHOUSE]: () => clickhouseQuery(args),
|
||||
});
|
||||
}
|
||||
|
||||
async function relationalQuery(where: Prisma.SessionWhereUniqueInput) {
|
||||
export async function getSession(where: Prisma.SessionWhereUniqueInput) {
|
||||
return prisma.client.session.findUnique({
|
||||
where,
|
||||
});
|
||||
}
|
||||
|
||||
async function clickhouseQuery({ id: sessionId }: { id: string }) {
|
||||
const { rawQuery, findFirst } = clickhouse;
|
||||
const params = { sessionId };
|
||||
|
||||
return rawQuery(
|
||||
`select
|
||||
session_id,
|
||||
website_id,
|
||||
created_at,
|
||||
hostname,
|
||||
browser,
|
||||
os,
|
||||
device,
|
||||
screen,
|
||||
language,
|
||||
country,
|
||||
subdivision1,
|
||||
subdivision2,
|
||||
city
|
||||
from website_event
|
||||
where session_id = {sessionId:UUID}
|
||||
limit 1`,
|
||||
params,
|
||||
).then(result => findFirst(result));
|
||||
}
|
||||
|
|
|
|||
43
queries/analytics/session/saveSessionData.ts
Normal file
43
queries/analytics/session/saveSessionData.ts
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
import { DYNAMIC_DATA_TYPE } from 'lib/constants';
|
||||
import { uuid } from 'lib/crypto';
|
||||
import { flattenJSON } from 'lib/dynamicData';
|
||||
import prisma from 'lib/prisma';
|
||||
import { DynamicData } from 'lib/types';
|
||||
|
||||
export async function saveSessionData(data: {
|
||||
websiteId: string;
|
||||
sessionId: string;
|
||||
sessionData: DynamicData;
|
||||
}) {
|
||||
const { client, transaction } = prisma;
|
||||
const { websiteId, sessionId, sessionData } = data;
|
||||
|
||||
const jsonKeys = flattenJSON(sessionData);
|
||||
|
||||
const flattendData = jsonKeys.map(a => ({
|
||||
id: uuid(),
|
||||
websiteId,
|
||||
sessionId,
|
||||
key: a.key,
|
||||
stringValue:
|
||||
a.dynamicDataType === DYNAMIC_DATA_TYPE.string ||
|
||||
a.dynamicDataType === DYNAMIC_DATA_TYPE.boolean ||
|
||||
a.dynamicDataType === DYNAMIC_DATA_TYPE.array
|
||||
? a.value
|
||||
: null,
|
||||
numericValue: a.dynamicDataType === DYNAMIC_DATA_TYPE.number ? a.value : null,
|
||||
dateValue: a.dynamicDataType === DYNAMIC_DATA_TYPE.date ? new Date(a.value) : null,
|
||||
dataType: a.dynamicDataType,
|
||||
}));
|
||||
|
||||
return transaction([
|
||||
client.sessionData.deleteMany({
|
||||
where: {
|
||||
sessionId,
|
||||
},
|
||||
}),
|
||||
client.sessionData.createMany({
|
||||
data: flattendData,
|
||||
}),
|
||||
]);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue