mirror of
https://github.com/umami-software/umami.git
synced 2026-02-04 04:37:11 +01:00
Updated pixel/link endpoints. Added name to rawQuery.
This commit is contained in:
parent
b9fbbc6453
commit
8a977b0164
18 changed files with 913 additions and 810 deletions
50
package.json
50
package.json
|
|
@ -74,18 +74,18 @@
|
||||||
"@date-fns/utc": "^1.2.0",
|
"@date-fns/utc": "^1.2.0",
|
||||||
"@dicebear/collection": "^9.2.3",
|
"@dicebear/collection": "^9.2.3",
|
||||||
"@dicebear/core": "^9.2.3",
|
"@dicebear/core": "^9.2.3",
|
||||||
"@fontsource/inter": "^5.2.6",
|
"@fontsource/inter": "^5.2.8",
|
||||||
"@hello-pangea/dnd": "^17.0.0",
|
"@hello-pangea/dnd": "^17.0.0",
|
||||||
"@prisma/adapter-pg": "^6.16.0",
|
"@prisma/adapter-pg": "^6.16.3",
|
||||||
"@prisma/client": "^6.16.0",
|
"@prisma/client": "^6.16.3",
|
||||||
"@prisma/extension-read-replicas": "^0.4.1",
|
"@prisma/extension-read-replicas": "^0.4.1",
|
||||||
"@react-spring/web": "^10.0.1",
|
"@react-spring/web": "^10.0.3",
|
||||||
"@svgr/cli": "^8.1.0",
|
"@svgr/cli": "^8.1.0",
|
||||||
"@tanstack/react-query": "^5.85.5",
|
"@tanstack/react-query": "^5.90.2",
|
||||||
"@umami/react-zen": "^0.187.0",
|
"@umami/react-zen": "^0.187.0",
|
||||||
"@umami/redis-client": "^0.29.0",
|
"@umami/redis-client": "^0.29.0",
|
||||||
"bcryptjs": "^3.0.2",
|
"bcryptjs": "^3.0.2",
|
||||||
"chalk": "^5.6.0",
|
"chalk": "^5.6.2",
|
||||||
"chart.js": "^4.5.0",
|
"chart.js": "^4.5.0",
|
||||||
"chartjs-adapter-date-fns": "^3.0.0",
|
"chartjs-adapter-date-fns": "^3.0.0",
|
||||||
"classnames": "^2.3.1",
|
"classnames": "^2.3.1",
|
||||||
|
|
@ -94,19 +94,19 @@
|
||||||
"cross-spawn": "^7.0.3",
|
"cross-spawn": "^7.0.3",
|
||||||
"date-fns": "^2.23.0",
|
"date-fns": "^2.23.0",
|
||||||
"date-fns-tz": "^1.1.4",
|
"date-fns-tz": "^1.1.4",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.4.3",
|
||||||
"del": "^6.0.0",
|
"del": "^6.0.0",
|
||||||
"detect-browser": "^5.2.0",
|
"detect-browser": "^5.2.0",
|
||||||
"dotenv": "^17.2.1",
|
"dotenv": "^17.2.3",
|
||||||
"esbuild": "^0.25.9",
|
"esbuild": "^0.25.10",
|
||||||
"eslint-plugin-promise": "^6.1.1",
|
"eslint-plugin-promise": "^6.1.1",
|
||||||
"fs-extra": "^11.3.1",
|
"fs-extra": "^11.3.2",
|
||||||
"immer": "^10.1.1",
|
"immer": "^10.1.3",
|
||||||
"ipaddr.js": "^2.0.1",
|
"ipaddr.js": "^2.0.1",
|
||||||
"is-ci": "^3.0.1",
|
"is-ci": "^3.0.1",
|
||||||
"is-docker": "^3.0.0",
|
"is-docker": "^3.0.0",
|
||||||
"is-localhost-ip": "^2.0.0",
|
"is-localhost-ip": "^2.0.0",
|
||||||
"isbot": "^5.1.30",
|
"isbot": "^5.1.31",
|
||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.2",
|
||||||
"jszip": "^3.10.1",
|
"jszip": "^3.10.1",
|
||||||
"kafkajs": "^2.1.0",
|
"kafkajs": "^2.1.0",
|
||||||
|
|
@ -132,12 +132,12 @@
|
||||||
"thenby": "^1.3.4",
|
"thenby": "^1.3.4",
|
||||||
"ua-parser-js": "^2.0.5",
|
"ua-parser-js": "^2.0.5",
|
||||||
"uuid": "^11.1.0",
|
"uuid": "^11.1.0",
|
||||||
"zod": "^4.1.5",
|
"zod": "^4.1.11",
|
||||||
"zustand": "^5.0.8"
|
"zustand": "^5.0.8"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@formatjs/cli": "^4.2.29",
|
"@formatjs/cli": "^4.2.29",
|
||||||
"@netlify/plugin-nextjs": "^5.12.1",
|
"@netlify/plugin-nextjs": "^5.13.3",
|
||||||
"@rollup/plugin-alias": "^5.0.0",
|
"@rollup/plugin-alias": "^5.0.0",
|
||||||
"@rollup/plugin-commonjs": "^25.0.4",
|
"@rollup/plugin-commonjs": "^25.0.4",
|
||||||
"@rollup/plugin-json": "^6.0.0",
|
"@rollup/plugin-json": "^6.0.0",
|
||||||
|
|
@ -146,18 +146,18 @@
|
||||||
"@rollup/plugin-terser": "^0.4.4",
|
"@rollup/plugin-terser": "^0.4.4",
|
||||||
"@rollup/plugin-typescript": "^12.1.4",
|
"@rollup/plugin-typescript": "^12.1.4",
|
||||||
"@types/jest": "^30.0.0",
|
"@types/jest": "^30.0.0",
|
||||||
"@types/node": "^24.3.0",
|
"@types/node": "^24.6.0",
|
||||||
"@types/react": "^19.1.12",
|
"@types/react": "^19.1.16",
|
||||||
"@types/react-dom": "^19.1.8",
|
"@types/react-dom": "^19.1.9",
|
||||||
"@types/react-window": "^1.8.8",
|
"@types/react-window": "^1.8.8",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.41.0",
|
"@typescript-eslint/eslint-plugin": "^8.45.0",
|
||||||
"@typescript-eslint/parser": "^8.41.0",
|
"@typescript-eslint/parser": "^8.45.0",
|
||||||
"@umami/prisma-client": "^0.20.0",
|
"@umami/prisma-client": "^0.20.0",
|
||||||
"babel-plugin-react-compiler": "19.1.0-rc.2",
|
"babel-plugin-react-compiler": "19.1.0-rc.2",
|
||||||
"cross-env": "^10.0.0",
|
"cross-env": "^10.1.0",
|
||||||
"cypress": "^13.6.6",
|
"cypress": "^13.6.6",
|
||||||
"eslint": "^8.33.0",
|
"eslint": "^8.33.0",
|
||||||
"eslint-config-next": "^14.2.32",
|
"eslint-config-next": "^14.2.33",
|
||||||
"eslint-config-prettier": "^10.1.8",
|
"eslint-config-prettier": "^10.1.8",
|
||||||
"eslint-import-resolver-alias": "^1.1.2",
|
"eslint-import-resolver-alias": "^1.1.2",
|
||||||
"eslint-plugin-css-modules": "^2.12.0",
|
"eslint-plugin-css-modules": "^2.12.0",
|
||||||
|
|
@ -168,18 +168,18 @@
|
||||||
"extract-react-intl-messages": "^4.1.1",
|
"extract-react-intl-messages": "^4.1.1",
|
||||||
"husky": "^9.1.7",
|
"husky": "^9.1.7",
|
||||||
"jest": "^29.7.0",
|
"jest": "^29.7.0",
|
||||||
"lint-staged": "^16.1.5",
|
"lint-staged": "^16.2.3",
|
||||||
"postcss": "^8.5.6",
|
"postcss": "^8.5.6",
|
||||||
"postcss-flexbugs-fixes": "^5.0.2",
|
"postcss-flexbugs-fixes": "^5.0.2",
|
||||||
"postcss-import": "^15.1.0",
|
"postcss-import": "^15.1.0",
|
||||||
"postcss-preset-env": "7.8.3",
|
"postcss-preset-env": "7.8.3",
|
||||||
"prettier": "^3.6.2",
|
"prettier": "^3.6.2",
|
||||||
"prompts": "2.4.2",
|
"prompts": "2.4.2",
|
||||||
"rollup": "^4.49.0",
|
"rollup": "^4.52.3",
|
||||||
"rollup-plugin-copy": "^3.4.0",
|
"rollup-plugin-copy": "^3.4.0",
|
||||||
"rollup-plugin-delete": "^3.0.1",
|
"rollup-plugin-delete": "^3.0.1",
|
||||||
"rollup-plugin-dts": "^6.2.3",
|
"rollup-plugin-dts": "^6.2.3",
|
||||||
"rollup-plugin-node-externals": "^8.1.0",
|
"rollup-plugin-node-externals": "^8.1.1",
|
||||||
"rollup-plugin-peer-deps-external": "^2.2.4",
|
"rollup-plugin-peer-deps-external": "^2.2.4",
|
||||||
"rollup-plugin-postcss": "^4.0.2",
|
"rollup-plugin-postcss": "^4.0.2",
|
||||||
"stylelint": "^15.10.1",
|
"stylelint": "^15.10.1",
|
||||||
|
|
@ -190,6 +190,6 @@
|
||||||
"ts-jest": "^29.4.0",
|
"ts-jest": "^29.4.0",
|
||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
"tsup": "^8.5.0",
|
"tsup": "^8.5.0",
|
||||||
"typescript": "^5.9.2"
|
"typescript": "^5.9.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
1465
pnpm-lock.yaml
generated
1465
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +1,10 @@
|
||||||
|
export const dynamic = 'force-dynamic';
|
||||||
|
|
||||||
import { NextResponse } from 'next/server';
|
import { NextResponse } from 'next/server';
|
||||||
import { notFound } from '@/lib/response';
|
import { notFound } from '@/lib/response';
|
||||||
|
import redis from '@/lib/redis';
|
||||||
import { findPixel } from '@/queries/prisma';
|
import { findPixel } from '@/queries/prisma';
|
||||||
|
import { Pixel } from '@/generated/prisma/client';
|
||||||
import { POST } from '@/app/api/send/route';
|
import { POST } from '@/app/api/send/route';
|
||||||
|
|
||||||
const image = Buffer.from('R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw', 'base64');
|
const image = Buffer.from('R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw', 'base64');
|
||||||
|
|
@ -8,14 +12,34 @@ const image = Buffer.from('R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICR
|
||||||
export async function GET(request: Request, { params }: { params: Promise<{ slug: string }> }) {
|
export async function GET(request: Request, { params }: { params: Promise<{ slug: string }> }) {
|
||||||
const { slug } = await params;
|
const { slug } = await params;
|
||||||
|
|
||||||
const pixel = await findPixel({
|
let pixel: Pixel;
|
||||||
where: {
|
|
||||||
slug,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!pixel) {
|
if (redis.enabled) {
|
||||||
return notFound();
|
pixel = await redis.client.fetch(
|
||||||
|
`pixel:${slug}`,
|
||||||
|
async () => {
|
||||||
|
return findPixel({
|
||||||
|
where: {
|
||||||
|
slug,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
86400,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!pixel) {
|
||||||
|
return notFound();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pixel = await findPixel({
|
||||||
|
where: {
|
||||||
|
slug,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!pixel) {
|
||||||
|
return notFound();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
|
|
@ -23,7 +47,7 @@ export async function GET(request: Request, { params }: { params: Promise<{ slug
|
||||||
payload: {
|
payload: {
|
||||||
pixel: pixel.id,
|
pixel: pixel.id,
|
||||||
url: request.url,
|
url: request.url,
|
||||||
referrer: request.referrer,
|
referrer: request.headers.get('referer'),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -33,13 +57,12 @@ export async function GET(request: Request, { params }: { params: Promise<{ slug
|
||||||
body: JSON.stringify(payload),
|
body: JSON.stringify(payload),
|
||||||
});
|
});
|
||||||
|
|
||||||
const res = await POST(req);
|
await POST(req);
|
||||||
|
|
||||||
return new NextResponse(image, {
|
return new NextResponse(image, {
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'image/gif',
|
'Content-Type': 'image/gif',
|
||||||
'Content-Length': image.length.toString(),
|
'Content-Length': image.length.toString(),
|
||||||
'x-umami-collect': JSON.stringify(res),
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,43 @@
|
||||||
|
export const dynamic = 'force-dynamic';
|
||||||
|
|
||||||
import { NextResponse } from 'next/server';
|
import { NextResponse } from 'next/server';
|
||||||
import { notFound } from '@/lib/response';
|
import { notFound } from '@/lib/response';
|
||||||
import { findLink } from '@/queries/prisma';
|
import { findLink } from '@/queries/prisma';
|
||||||
import { POST } from '@/app/api/send/route';
|
import { POST } from '@/app/api/send/route';
|
||||||
|
import { Link } from '@/generated/prisma/client';
|
||||||
|
import redis from '@/lib/redis';
|
||||||
|
|
||||||
export async function GET(request: Request, { params }: { params: Promise<{ slug: string }> }) {
|
export async function GET(request: Request, { params }: { params: Promise<{ slug: string }> }) {
|
||||||
const { slug } = await params;
|
const { slug } = await params;
|
||||||
|
|
||||||
const link = await findLink({
|
let link: Link;
|
||||||
where: {
|
|
||||||
slug,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!link) {
|
if (redis.enabled) {
|
||||||
return notFound();
|
link = await redis.client.fetch(
|
||||||
|
`link:${slug}`,
|
||||||
|
async () => {
|
||||||
|
return findLink({
|
||||||
|
where: {
|
||||||
|
slug,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
86400,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!link) {
|
||||||
|
return notFound();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
link = await findLink({
|
||||||
|
where: {
|
||||||
|
slug,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!link) {
|
||||||
|
return notFound();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
|
|
@ -21,7 +45,7 @@ export async function GET(request: Request, { params }: { params: Promise<{ slug
|
||||||
payload: {
|
payload: {
|
||||||
link: link.id,
|
link: link.id,
|
||||||
url: request.url,
|
url: request.url,
|
||||||
referrer: request.referrer,
|
referrer: request.headers.get('referer'),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { canViewWebsite } from '@/permissions';
|
import { canViewWebsite } from '@/permissions';
|
||||||
import { EVENT_COLUMNS, SESSION_COLUMNS } from '@/lib/constants';
|
import { EVENT_COLUMNS, EVENT_TYPE, FILTER_COLUMNS, SESSION_COLUMNS } from '@/lib/constants';
|
||||||
import { getQueryFilters, parseRequest } from '@/lib/request';
|
import { getQueryFilters, parseRequest } from '@/lib/request';
|
||||||
import { badRequest, json, unauthorized } from '@/lib/response';
|
import { badRequest, json, unauthorized } from '@/lib/response';
|
||||||
import { dateRangeParams, filterParams, searchParams } from '@/lib/schema';
|
import { dateRangeParams, filterParams, searchParams } from '@/lib/schema';
|
||||||
|
|
@ -50,21 +50,21 @@ export async function GET(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (EVENT_COLUMNS.includes(type)) {
|
if (EVENT_COLUMNS.includes(type)) {
|
||||||
let data;
|
const column = FILTER_COLUMNS[type] || type;
|
||||||
|
|
||||||
if (type === 'event') {
|
if (column === 'event_name') {
|
||||||
data = await getEventExpandedMetrics(websiteId, { type, limit, offset }, filters);
|
filters.eventType = EVENT_TYPE.customEvent;
|
||||||
} else {
|
|
||||||
data = await getPageviewExpandedMetrics(websiteId, { type, limit, offset }, filters);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return json(data);
|
if (type === 'event') {
|
||||||
|
return json(await getEventExpandedMetrics(websiteId, { type, limit, offset }, filters));
|
||||||
|
} else {
|
||||||
|
return json(await getPageviewExpandedMetrics(websiteId, { type, limit, offset }, filters));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type === 'channel') {
|
if (type === 'channel') {
|
||||||
const data = await getChannelExpandedMetrics(websiteId, filters);
|
return json(await getChannelExpandedMetrics(websiteId, filters));
|
||||||
|
|
||||||
return json(data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return badRequest();
|
return badRequest();
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { canViewWebsite } from '@/permissions';
|
import { canViewWebsite } from '@/permissions';
|
||||||
import { EVENT_COLUMNS, SESSION_COLUMNS } from '@/lib/constants';
|
import { EVENT_COLUMNS, EVENT_TYPE, FILTER_COLUMNS, SESSION_COLUMNS } from '@/lib/constants';
|
||||||
import { getQueryFilters, parseRequest } from '@/lib/request';
|
import { getQueryFilters, parseRequest } from '@/lib/request';
|
||||||
import { badRequest, json, unauthorized } from '@/lib/response';
|
import { badRequest, json, unauthorized } from '@/lib/response';
|
||||||
import {
|
import {
|
||||||
|
|
@ -50,21 +50,21 @@ export async function GET(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (EVENT_COLUMNS.includes(type)) {
|
if (EVENT_COLUMNS.includes(type)) {
|
||||||
let data;
|
const column = FILTER_COLUMNS[type] || type;
|
||||||
|
|
||||||
if (type === 'event') {
|
if (column === 'event_name') {
|
||||||
data = await getEventMetrics(websiteId, { type, limit, offset }, filters);
|
filters.eventType = EVENT_TYPE.customEvent;
|
||||||
} else {
|
|
||||||
data = await getPageviewMetrics(websiteId, { type, limit, offset }, filters);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return json(data);
|
if (type === 'event') {
|
||||||
|
return json(await getEventMetrics(websiteId, { type, limit, offset }, filters));
|
||||||
|
} else {
|
||||||
|
return json(await getPageviewMetrics(websiteId, { type, limit, offset }, filters));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type === 'channel') {
|
if (type === 'channel') {
|
||||||
const data = await getChannelMetrics(websiteId, filters);
|
return json(await getChannelMetrics(websiteId, filters));
|
||||||
|
|
||||||
return json(data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return badRequest();
|
return badRequest();
|
||||||
|
|
|
||||||
|
|
@ -206,9 +206,10 @@ async function pagedRawQuery(
|
||||||
async function rawQuery<T = unknown>(
|
async function rawQuery<T = unknown>(
|
||||||
query: string,
|
query: string,
|
||||||
params: Record<string, unknown> = {},
|
params: Record<string, unknown> = {},
|
||||||
|
name?: string,
|
||||||
): Promise<T> {
|
): Promise<T> {
|
||||||
if (process.env.LOG_QUERY) {
|
if (process.env.LOG_QUERY) {
|
||||||
log({ query, params });
|
log({ query, params, name });
|
||||||
}
|
}
|
||||||
|
|
||||||
await connect();
|
await connect();
|
||||||
|
|
|
||||||
|
|
@ -164,10 +164,11 @@ function parseFilters(filters: Record<string, any>, options?: QueryOptions) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function rawQuery(sql: string, data: object): Promise<any> {
|
async function rawQuery(sql: string, data: Record<string, any>, name?: string): Promise<any> {
|
||||||
if (process.env.LOG_QUERY) {
|
if (process.env.LOG_QUERY) {
|
||||||
log('QUERY:\n', sql);
|
log('QUERY:\n', sql);
|
||||||
log('PARAMETERS:\n', data);
|
log('PARAMETERS:\n', data);
|
||||||
|
log('NAME:\n', name);
|
||||||
}
|
}
|
||||||
const params = [];
|
const params = [];
|
||||||
const schema = getSchema();
|
const schema = getSchema();
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ import { CLICKHOUSE, PRISMA, runQuery } from '@/lib/db';
|
||||||
import prisma from '@/lib/prisma';
|
import prisma from '@/lib/prisma';
|
||||||
import { QueryFilters } from '@/lib/types';
|
import { QueryFilters } from '@/lib/types';
|
||||||
|
|
||||||
|
const FUNCTION_NAME = 'getEventMetrics';
|
||||||
|
|
||||||
export interface EventMetricParameters {
|
export interface EventMetricParameters {
|
||||||
type: string;
|
type: string;
|
||||||
limit?: string;
|
limit?: string;
|
||||||
|
|
@ -58,6 +60,7 @@ async function relationalQuery(
|
||||||
offset ${offset}
|
offset ${offset}
|
||||||
`,
|
`,
|
||||||
{ ...queryParams, ...parameters },
|
{ ...queryParams, ...parameters },
|
||||||
|
FUNCTION_NAME,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -89,5 +92,6 @@ async function clickhouseQuery(
|
||||||
offset ${offset}
|
offset ${offset}
|
||||||
`,
|
`,
|
||||||
{ ...queryParams, ...parameters },
|
{ ...queryParams, ...parameters },
|
||||||
|
FUNCTION_NAME,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { uuid } from '@/lib/crypto';
|
import { uuid } from '@/lib/crypto';
|
||||||
import { EVENT_NAME_LENGTH, URL_LENGTH, EVENT_TYPE, PAGE_TITLE_LENGTH } from '@/lib/constants';
|
import { EVENT_NAME_LENGTH, URL_LENGTH, PAGE_TITLE_LENGTH } from '@/lib/constants';
|
||||||
import { CLICKHOUSE, PRISMA, runQuery } from '@/lib/db';
|
import { CLICKHOUSE, PRISMA, runQuery } from '@/lib/db';
|
||||||
import clickhouse from '@/lib/clickhouse';
|
import clickhouse from '@/lib/clickhouse';
|
||||||
import kafka from '@/lib/kafka';
|
import kafka from '@/lib/kafka';
|
||||||
|
|
@ -66,10 +66,9 @@ async function relationalQuery({
|
||||||
websiteId,
|
websiteId,
|
||||||
sessionId,
|
sessionId,
|
||||||
visitId,
|
visitId,
|
||||||
createdAt,
|
|
||||||
eventType,
|
eventType,
|
||||||
|
createdAt,
|
||||||
pageTitle,
|
pageTitle,
|
||||||
tag,
|
|
||||||
hostname,
|
hostname,
|
||||||
urlPath,
|
urlPath,
|
||||||
urlQuery,
|
urlQuery,
|
||||||
|
|
@ -78,6 +77,7 @@ async function relationalQuery({
|
||||||
referrerDomain,
|
referrerDomain,
|
||||||
eventName,
|
eventName,
|
||||||
eventData,
|
eventData,
|
||||||
|
tag,
|
||||||
utmSource,
|
utmSource,
|
||||||
utmMedium,
|
utmMedium,
|
||||||
utmCampaign,
|
utmCampaign,
|
||||||
|
|
@ -154,9 +154,16 @@ async function clickhouseQuery({
|
||||||
websiteId,
|
websiteId,
|
||||||
sessionId,
|
sessionId,
|
||||||
visitId,
|
visitId,
|
||||||
distinctId,
|
eventType,
|
||||||
createdAt,
|
createdAt,
|
||||||
pageTitle,
|
pageTitle,
|
||||||
|
hostname,
|
||||||
|
urlPath,
|
||||||
|
urlQuery,
|
||||||
|
referrerPath,
|
||||||
|
referrerQuery,
|
||||||
|
referrerDomain,
|
||||||
|
distinctId,
|
||||||
browser,
|
browser,
|
||||||
os,
|
os,
|
||||||
device,
|
device,
|
||||||
|
|
@ -165,15 +172,9 @@ async function clickhouseQuery({
|
||||||
country,
|
country,
|
||||||
region,
|
region,
|
||||||
city,
|
city,
|
||||||
tag,
|
|
||||||
hostname,
|
|
||||||
urlPath,
|
|
||||||
urlQuery,
|
|
||||||
referrerPath,
|
|
||||||
referrerQuery,
|
|
||||||
referrerDomain,
|
|
||||||
eventName,
|
eventName,
|
||||||
eventData,
|
eventData,
|
||||||
|
tag,
|
||||||
utmSource,
|
utmSource,
|
||||||
utmMedium,
|
utmMedium,
|
||||||
utmCampaign,
|
utmCampaign,
|
||||||
|
|
@ -215,7 +216,7 @@ async function clickhouseQuery({
|
||||||
ttclid: ttclid,
|
ttclid: ttclid,
|
||||||
li_fat_id: lifatid,
|
li_fat_id: lifatid,
|
||||||
twclid: twclid,
|
twclid: twclid,
|
||||||
event_type: eventName ? EVENT_TYPE.customEvent : EVENT_TYPE.pageView,
|
event_type: eventType,
|
||||||
event_name: eventName ? eventName?.substring(0, EVENT_NAME_LENGTH) : null,
|
event_name: eventName ? eventName?.substring(0, EVENT_NAME_LENGTH) : null,
|
||||||
tag: tag,
|
tag: tag,
|
||||||
distinct_id: distinctId,
|
distinct_id: distinctId,
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@ 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';
|
||||||
|
|
||||||
|
const FUNCTION_NAME = 'getActiveVisitors';
|
||||||
|
|
||||||
export async function getActiveVisitors(...args: [websiteId: string]) {
|
export async function getActiveVisitors(...args: [websiteId: string]) {
|
||||||
return runQuery({
|
return runQuery({
|
||||||
[PRISMA]: () => relationalQuery(...args),
|
[PRISMA]: () => relationalQuery(...args),
|
||||||
|
|
@ -22,6 +24,7 @@ async function relationalQuery(websiteId: string) {
|
||||||
and created_at >= {{startDate}}
|
and created_at >= {{startDate}}
|
||||||
`,
|
`,
|
||||||
{ websiteId, startDate },
|
{ websiteId, startDate },
|
||||||
|
FUNCTION_NAME,
|
||||||
);
|
);
|
||||||
|
|
||||||
return result?.[0] ?? null;
|
return result?.[0] ?? null;
|
||||||
|
|
@ -40,6 +43,7 @@ async function clickhouseQuery(websiteId: string): Promise<{ x: number }> {
|
||||||
and created_at >= {startDate:DateTime64}
|
and created_at >= {startDate:DateTime64}
|
||||||
`,
|
`,
|
||||||
{ websiteId, startDate },
|
{ websiteId, startDate },
|
||||||
|
FUNCTION_NAME,
|
||||||
);
|
);
|
||||||
|
|
||||||
return result[0] ?? null;
|
return result[0] ?? null;
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@ import { CLICKHOUSE, PRISMA, runQuery } from '@/lib/db';
|
||||||
import prisma from '@/lib/prisma';
|
import prisma from '@/lib/prisma';
|
||||||
import { QueryFilters } from '@/lib/types';
|
import { QueryFilters } from '@/lib/types';
|
||||||
|
|
||||||
|
const FUNCTION_NAME = 'getChannelExpandedMetrics';
|
||||||
|
|
||||||
export interface ChannelExpandedMetricsParameters {
|
export interface ChannelExpandedMetricsParameters {
|
||||||
limit?: number | string;
|
limit?: number | string;
|
||||||
offset?: number | string;
|
offset?: number | string;
|
||||||
|
|
@ -79,6 +81,7 @@ async function relationalQuery(
|
||||||
order by y desc;
|
order by y desc;
|
||||||
`,
|
`,
|
||||||
queryParams,
|
queryParams,
|
||||||
|
FUNCTION_NAME,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -145,6 +148,7 @@ async function clickhouseQuery(
|
||||||
order by visitors desc, visits desc;
|
order by visitors desc, visits desc;
|
||||||
`,
|
`,
|
||||||
queryParams,
|
queryParams,
|
||||||
|
FUNCTION_NAME,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@ import { CLICKHOUSE, PRISMA, runQuery } from '@/lib/db';
|
||||||
import prisma from '@/lib/prisma';
|
import prisma from '@/lib/prisma';
|
||||||
import { QueryFilters } from '@/lib/types';
|
import { QueryFilters } from '@/lib/types';
|
||||||
|
|
||||||
|
const FUNCTION_NAME = 'getChannelMetrics';
|
||||||
|
|
||||||
export async function getChannelMetrics(...args: [websiteId: string, filters?: QueryFilters]) {
|
export async function getChannelMetrics(...args: [websiteId: string, filters?: QueryFilters]) {
|
||||||
return runQuery({
|
return runQuery({
|
||||||
[PRISMA]: () => relationalQuery(...args),
|
[PRISMA]: () => relationalQuery(...args),
|
||||||
|
|
@ -60,6 +62,7 @@ async function relationalQuery(websiteId: string, filters: QueryFilters) {
|
||||||
order by y desc;
|
order by y desc;
|
||||||
`,
|
`,
|
||||||
queryParams,
|
queryParams,
|
||||||
|
FUNCTION_NAME,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -117,7 +120,7 @@ async function clickhouseQuery(
|
||||||
order by y desc;
|
order by y desc;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
return rawQuery(sql, queryParams);
|
return rawQuery(sql, queryParams, FUNCTION_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
function toClickHouseStringArray(arr: string[]): string {
|
function toClickHouseStringArray(arr: string[]): string {
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@ import clickhouse from '@/lib/clickhouse';
|
||||||
import { runQuery, CLICKHOUSE, PRISMA } from '@/lib/db';
|
import { runQuery, CLICKHOUSE, PRISMA } from '@/lib/db';
|
||||||
import { QueryFilters } from '@/lib/types';
|
import { QueryFilters } from '@/lib/types';
|
||||||
|
|
||||||
|
const FUNCTION_NAME = 'getRealtimeActivity';
|
||||||
|
|
||||||
export async function getRealtimeActivity(...args: [websiteId: string, filters: QueryFilters]) {
|
export async function getRealtimeActivity(...args: [websiteId: string, filters: QueryFilters]) {
|
||||||
return runQuery({
|
return runQuery({
|
||||||
[PRISMA]: () => relationalQuery(...args),
|
[PRISMA]: () => relationalQuery(...args),
|
||||||
|
|
@ -40,6 +42,7 @@ async function relationalQuery(websiteId: string, filters: QueryFilters) {
|
||||||
limit 100
|
limit 100
|
||||||
`,
|
`,
|
||||||
queryParams,
|
queryParams,
|
||||||
|
FUNCTION_NAME,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -71,5 +74,6 @@ async function clickhouseQuery(websiteId: string, filters: QueryFilters): Promis
|
||||||
limit 100
|
limit 100
|
||||||
`,
|
`,
|
||||||
queryParams,
|
queryParams,
|
||||||
|
FUNCTION_NAME,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@ import clickhouse from '@/lib/clickhouse';
|
||||||
import { runQuery, CLICKHOUSE, PRISMA } from '@/lib/db';
|
import { runQuery, CLICKHOUSE, PRISMA } from '@/lib/db';
|
||||||
import { QueryFilters } from '@/lib/types';
|
import { QueryFilters } from '@/lib/types';
|
||||||
|
|
||||||
|
const FUNCTION_NAME = 'getValues';
|
||||||
|
|
||||||
export async function getValues(
|
export async function getValues(
|
||||||
...args: [websiteId: string, column: string, filters: QueryFilters]
|
...args: [websiteId: string, column: string, filters: QueryFilters]
|
||||||
) {
|
) {
|
||||||
|
|
@ -64,6 +66,7 @@ async function relationalQuery(websiteId: string, column: string, filters: Query
|
||||||
search: `%${search}%`,
|
search: `%${search}%`,
|
||||||
...params,
|
...params,
|
||||||
},
|
},
|
||||||
|
FUNCTION_NAME,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -120,5 +123,6 @@ async function clickhouseQuery(websiteId: string, column: string, filters: Query
|
||||||
search,
|
search,
|
||||||
...params,
|
...params,
|
||||||
},
|
},
|
||||||
|
FUNCTION_NAME,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
import clickhouse from '@/lib/clickhouse';
|
import clickhouse from '@/lib/clickhouse';
|
||||||
import { EVENT_TYPE, FILTER_COLUMNS, GROUPED_DOMAINS, SESSION_COLUMNS } from '@/lib/constants';
|
import { FILTER_COLUMNS, GROUPED_DOMAINS, SESSION_COLUMNS } from '@/lib/constants';
|
||||||
import { CLICKHOUSE, PRISMA, runQuery } from '@/lib/db';
|
import { CLICKHOUSE, PRISMA, runQuery } from '@/lib/db';
|
||||||
import prisma from '@/lib/prisma';
|
import prisma from '@/lib/prisma';
|
||||||
import { QueryFilters } from '@/lib/types';
|
import { QueryFilters } from '@/lib/types';
|
||||||
|
|
||||||
|
const FUNCTION_NAME = 'getPageviewExpandedMetrics';
|
||||||
|
|
||||||
export interface PageviewExpandedMetricsParameters {
|
export interface PageviewExpandedMetricsParameters {
|
||||||
type: string;
|
type: string;
|
||||||
limit?: number | string;
|
limit?: number | string;
|
||||||
|
|
@ -40,7 +42,6 @@ async function relationalQuery(
|
||||||
{
|
{
|
||||||
...filters,
|
...filters,
|
||||||
websiteId,
|
websiteId,
|
||||||
eventType: column === 'event_name' ? EVENT_TYPE.customEvent : EVENT_TYPE.pageView,
|
|
||||||
},
|
},
|
||||||
{ joinSession: SESSION_COLUMNS.includes(type) },
|
{ joinSession: SESSION_COLUMNS.includes(type) },
|
||||||
);
|
);
|
||||||
|
|
@ -89,6 +90,7 @@ async function relationalQuery(
|
||||||
offset ${offset}
|
offset ${offset}
|
||||||
`,
|
`,
|
||||||
queryParams,
|
queryParams,
|
||||||
|
FUNCTION_NAME,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -103,7 +105,6 @@ async function clickhouseQuery(
|
||||||
const { filterQuery, cohortQuery, queryParams } = parseFilters({
|
const { filterQuery, cohortQuery, queryParams } = parseFilters({
|
||||||
...filters,
|
...filters,
|
||||||
websiteId,
|
websiteId,
|
||||||
eventType: column === 'event_name' ? EVENT_TYPE.customEvent : EVENT_TYPE.pageView,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let excludeDomain = '';
|
let excludeDomain = '';
|
||||||
|
|
@ -164,6 +165,7 @@ async function clickhouseQuery(
|
||||||
offset ${offset}
|
offset ${offset}
|
||||||
`,
|
`,
|
||||||
{ ...queryParams, ...parameters },
|
{ ...queryParams, ...parameters },
|
||||||
|
FUNCTION_NAME,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
import clickhouse from '@/lib/clickhouse';
|
import clickhouse from '@/lib/clickhouse';
|
||||||
import { EVENT_COLUMNS, EVENT_TYPE, FILTER_COLUMNS, SESSION_COLUMNS } from '@/lib/constants';
|
import { EVENT_COLUMNS, FILTER_COLUMNS, SESSION_COLUMNS } from '@/lib/constants';
|
||||||
import { CLICKHOUSE, PRISMA, runQuery } from '@/lib/db';
|
import { CLICKHOUSE, PRISMA, runQuery } from '@/lib/db';
|
||||||
import prisma from '@/lib/prisma';
|
import prisma from '@/lib/prisma';
|
||||||
import { QueryFilters } from '@/lib/types';
|
import { QueryFilters } from '@/lib/types';
|
||||||
|
|
||||||
|
const FUNCTION_NAME = 'getPageviewMetrics';
|
||||||
|
|
||||||
export interface PageviewMetricsParameters {
|
export interface PageviewMetricsParameters {
|
||||||
type: string;
|
type: string;
|
||||||
limit?: number | string;
|
limit?: number | string;
|
||||||
|
|
@ -36,7 +38,6 @@ async function relationalQuery(
|
||||||
{
|
{
|
||||||
...filters,
|
...filters,
|
||||||
websiteId,
|
websiteId,
|
||||||
eventType: column === 'event_name' ? EVENT_TYPE.customEvent : EVENT_TYPE.pageView,
|
|
||||||
},
|
},
|
||||||
{ joinSession: SESSION_COLUMNS.includes(type) },
|
{ joinSession: SESSION_COLUMNS.includes(type) },
|
||||||
);
|
);
|
||||||
|
|
@ -86,6 +87,7 @@ async function relationalQuery(
|
||||||
offset ${offset}
|
offset ${offset}
|
||||||
`,
|
`,
|
||||||
{ ...queryParams, ...parameters },
|
{ ...queryParams, ...parameters },
|
||||||
|
FUNCTION_NAME,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -100,7 +102,6 @@ async function clickhouseQuery(
|
||||||
const { filterQuery, cohortQuery, queryParams } = parseFilters({
|
const { filterQuery, cohortQuery, queryParams } = parseFilters({
|
||||||
...filters,
|
...filters,
|
||||||
websiteId,
|
websiteId,
|
||||||
eventType: column === 'event_name' ? EVENT_TYPE.customEvent : EVENT_TYPE.pageView,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let sql = '';
|
let sql = '';
|
||||||
|
|
@ -183,5 +184,5 @@ async function clickhouseQuery(
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return rawQuery(sql, { ...queryParams, ...parameters });
|
return rawQuery(sql, { ...queryParams, ...parameters }, FUNCTION_NAME);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
import clickhouse from '@/lib/clickhouse';
|
import clickhouse from '@/lib/clickhouse';
|
||||||
import { EVENT_COLUMNS, EVENT_TYPE, FILTER_COLUMNS, SESSION_COLUMNS } from '@/lib/constants';
|
import { EVENT_COLUMNS, FILTER_COLUMNS, SESSION_COLUMNS } from '@/lib/constants';
|
||||||
import { CLICKHOUSE, PRISMA, runQuery } from '@/lib/db';
|
import { CLICKHOUSE, PRISMA, runQuery } from '@/lib/db';
|
||||||
import prisma from '@/lib/prisma';
|
import prisma from '@/lib/prisma';
|
||||||
import { QueryFilters } from '@/lib/types';
|
import { QueryFilters } from '@/lib/types';
|
||||||
|
|
||||||
|
const FUNCTION_NAME = 'getSessionMetrics';
|
||||||
|
|
||||||
export interface SessionMetricsParameters {
|
export interface SessionMetricsParameters {
|
||||||
type: string;
|
type: string;
|
||||||
limit?: number | string;
|
limit?: number | string;
|
||||||
|
|
@ -31,7 +33,6 @@ async function relationalQuery(
|
||||||
{
|
{
|
||||||
...filters,
|
...filters,
|
||||||
websiteId,
|
websiteId,
|
||||||
eventType: EVENT_TYPE.pageView,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
joinSession: SESSION_COLUMNS.includes(type),
|
joinSession: SESSION_COLUMNS.includes(type),
|
||||||
|
|
@ -54,6 +55,7 @@ async function relationalQuery(
|
||||||
${joinSessionQuery}
|
${joinSessionQuery}
|
||||||
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 != 2
|
||||||
${filterQuery}
|
${filterQuery}
|
||||||
group by 1
|
group by 1
|
||||||
${includeCountry ? ', 3' : ''}
|
${includeCountry ? ', 3' : ''}
|
||||||
|
|
@ -62,6 +64,7 @@ async function relationalQuery(
|
||||||
offset ${offset}
|
offset ${offset}
|
||||||
`,
|
`,
|
||||||
{ ...queryParams, ...parameters },
|
{ ...queryParams, ...parameters },
|
||||||
|
FUNCTION_NAME,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -76,7 +79,6 @@ async function clickhouseQuery(
|
||||||
const { filterQuery, cohortQuery, queryParams } = parseFilters({
|
const { filterQuery, cohortQuery, queryParams } = parseFilters({
|
||||||
...filters,
|
...filters,
|
||||||
websiteId,
|
websiteId,
|
||||||
eventType: EVENT_TYPE.pageView,
|
|
||||||
});
|
});
|
||||||
const includeCountry = column === 'city' || column === 'region';
|
const includeCountry = column === 'city' || column === 'region';
|
||||||
|
|
||||||
|
|
@ -96,6 +98,7 @@ async function clickhouseQuery(
|
||||||
${cohortQuery}
|
${cohortQuery}
|
||||||
where website_id = {websiteId:UUID}
|
where website_id = {websiteId:UUID}
|
||||||
and created_at between {startDate:DateTime64} and {endDate:DateTime64}
|
and created_at between {startDate:DateTime64} and {endDate:DateTime64}
|
||||||
|
and event_type != 2
|
||||||
${filterQuery}
|
${filterQuery}
|
||||||
group by x
|
group by x
|
||||||
${includeCountry ? ', country' : ''}
|
${includeCountry ? ', country' : ''}
|
||||||
|
|
@ -113,6 +116,7 @@ async function clickhouseQuery(
|
||||||
${cohortQuery}
|
${cohortQuery}
|
||||||
where website_id = {websiteId:UUID}
|
where website_id = {websiteId:UUID}
|
||||||
and created_at between {startDate:DateTime64} and {endDate:DateTime64}
|
and created_at between {startDate:DateTime64} and {endDate:DateTime64}
|
||||||
|
and event_type != 2
|
||||||
${filterQuery}
|
${filterQuery}
|
||||||
group by x
|
group by x
|
||||||
${includeCountry ? ', country' : ''}
|
${includeCountry ? ', country' : ''}
|
||||||
|
|
@ -122,5 +126,5 @@ async function clickhouseQuery(
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return rawQuery(sql, { ...queryParams, ...parameters });
|
return rawQuery(sql, { ...queryParams, ...parameters }, FUNCTION_NAME);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue