feat: make pageviewstats can return data
This commit is contained in:
parent
78133b7227
commit
ba0b398719
6
src/server/init.ts
Normal file
6
src/server/init.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
(BigInt.prototype as any).toJSON = function () {
|
||||||
|
const int = Number.parseInt(this.toString());
|
||||||
|
return int ?? this.toString();
|
||||||
|
};
|
||||||
|
|
||||||
|
export {};
|
@ -1,4 +1,5 @@
|
|||||||
import 'dotenv/config';
|
import 'dotenv/config';
|
||||||
|
import './init';
|
||||||
import express from 'express';
|
import express from 'express';
|
||||||
import 'express-async-errors';
|
import 'express-async-errors';
|
||||||
import ViteExpress from 'vite-express';
|
import ViteExpress from 'vite-express';
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { prisma } from './_client';
|
import { prisma } from './_client';
|
||||||
import { QueryFilters, parseFilters, getDateQuery } from '../utils/prisma';
|
import { QueryFilters, parseFilters, getDateQuery } from '../utils/prisma';
|
||||||
import { DEFAULT_RESET_DATE, EVENT_TYPE } from '../utils/const';
|
import { DEFAULT_RESET_DATE, EVENT_TYPE } from '../utils/const';
|
||||||
|
import { Prisma } from '@prisma/client';
|
||||||
|
|
||||||
export async function getWorkspaceUser(workspaceId: string, userId: string) {
|
export async function getWorkspaceUser(workspaceId: string, userId: string) {
|
||||||
const info = await prisma.workspacesOnUsers.findFirst({
|
const info = await prisma.workspacesOnUsers.findFirst({
|
||||||
@ -115,15 +116,14 @@ export async function getWorkspaceWebsitePageviewStats(
|
|||||||
|
|
||||||
return prisma.$queryRaw`
|
return prisma.$queryRaw`
|
||||||
select
|
select
|
||||||
${getDateQuery('website_event.created_at', unit, timezone)} x,
|
${getDateQuery('"WebsiteEvent"."createdAt"', unit, timezone)} x,
|
||||||
count(*) y
|
count(1) y
|
||||||
from website_event
|
from "WebsiteEvent"
|
||||||
${joinSession}
|
${joinSession ? Prisma.sql([joinSession]) : Prisma.empty}
|
||||||
where website_event.website_id = ${params.websiteId}
|
where "WebsiteEvent"."websiteId" = ${params.websiteId}::uuid
|
||||||
and website_event.created_at
|
and "WebsiteEvent"."createdAt"
|
||||||
between ${params.startDate} and ${(params as any).endDate}
|
between ${params.startDate}::timestamptz and ${params.endDate}::timestamptz
|
||||||
and event_type = {{eventType}}
|
and "WebsiteEvent"."eventType" = ${EVENT_TYPE.pageView}
|
||||||
${filterQuery}
|
|
||||||
group by 1
|
group by 1
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
@ -139,7 +139,9 @@ workspaceRouter.get(
|
|||||||
'/:workspaceId/website/:websiteId/pageviews',
|
'/:workspaceId/website/:websiteId/pageviews',
|
||||||
validate(
|
validate(
|
||||||
param('workspaceId').isUUID().withMessage('workspaceId should be UUID'),
|
param('workspaceId').isUUID().withMessage('workspaceId should be UUID'),
|
||||||
param('websiteId').isUUID().withMessage('workspaceId should be UUID')
|
param('websiteId').isUUID().withMessage('workspaceId should be UUID'),
|
||||||
|
query('startAt').isNumeric().withMessage('startAt should be number'),
|
||||||
|
query('endAt').isNumeric().withMessage('startAt should be number')
|
||||||
),
|
),
|
||||||
auth(),
|
auth(),
|
||||||
workspacePermission(),
|
workspacePermission(),
|
||||||
@ -184,11 +186,15 @@ workspaceRouter.get(
|
|||||||
city,
|
city,
|
||||||
};
|
};
|
||||||
|
|
||||||
const website = await getWorkspaceWebsitePageviewStats(
|
console.log('filters', filters);
|
||||||
|
|
||||||
|
const stats = await getWorkspaceWebsitePageviewStats(
|
||||||
websiteId,
|
websiteId,
|
||||||
filters as QueryFilters
|
filters as QueryFilters
|
||||||
);
|
);
|
||||||
|
|
||||||
res.json({ website });
|
console.log('stats', stats);
|
||||||
|
|
||||||
|
res.json({ stats });
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -3,10 +3,13 @@ import crypto from 'crypto';
|
|||||||
import { DATA_TYPE } from './const';
|
import { DATA_TYPE } from './const';
|
||||||
import { DynamicDataType } from './types';
|
import { DynamicDataType } from './types';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
|
import minMax from 'dayjs/plugin/minMax';
|
||||||
import jwt from 'jsonwebtoken';
|
import jwt from 'jsonwebtoken';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { getWorkspaceWebsiteDateRange } from '../model/workspace';
|
import { getWorkspaceWebsiteDateRange } from '../model/workspace';
|
||||||
|
|
||||||
|
dayjs.extend(minMax);
|
||||||
|
|
||||||
export function isUuid(value: string) {
|
export function isUuid(value: string) {
|
||||||
return validate(value);
|
return validate(value);
|
||||||
}
|
}
|
||||||
@ -152,7 +155,7 @@ export function parseToken(token: string, secret = jwtSecret) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function maxDate(...args: any[]) {
|
export function maxDate(...args: any[]) {
|
||||||
return _.max(args.filter((n) => dayjs(n).isValid()));
|
return dayjs.max(args.filter((n) => dayjs(n).isValid()));
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function parseDateRange({
|
export async function parseDateRange({
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import { Prisma } from '@prisma/client';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { loadWebsite } from '../model/website';
|
import { loadWebsite } from '../model/website';
|
||||||
import { maxDate } from './common';
|
import { maxDate } from './common';
|
||||||
@ -50,14 +52,22 @@ export async function parseFilters(
|
|||||||
return {
|
return {
|
||||||
joinSession:
|
joinSession:
|
||||||
options?.joinSession ||
|
options?.joinSession ||
|
||||||
Object.keys(filters).find((key) => SESSION_COLUMNS.includes(key))
|
Object.entries(filters).find(
|
||||||
? `inner join session on website_event.session_id = session.session_id`
|
([key, value]) =>
|
||||||
|
typeof value !== 'undefined' && SESSION_COLUMNS.includes(key)
|
||||||
|
)
|
||||||
|
? `inner join "WebsiteSession" on "WebsiteEvent"."sessionId" = "WebsiteSession"."id"`
|
||||||
: '',
|
: '',
|
||||||
filterQuery: getFilterQuery(filters, options),
|
filterQuery: getFilterQuery(filters, options),
|
||||||
params: {
|
params: {
|
||||||
...normalizeFilters(filters),
|
...normalizeFilters(filters),
|
||||||
websiteId,
|
websiteId,
|
||||||
startDate: maxDate(filters.startDate, website.resetAt),
|
startDate: dayjs(
|
||||||
|
maxDate(filters.startDate, website.resetAt)
|
||||||
|
).toISOString(),
|
||||||
|
endDate: filters.endDate
|
||||||
|
? dayjs(filters.endDate).toISOString()
|
||||||
|
: undefined,
|
||||||
websiteDomain: website.domain,
|
websiteDomain: website.domain,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -82,6 +92,8 @@ export function getFilterQuery(
|
|||||||
const operator = value?.filter ?? OPERATORS.equals;
|
const operator = value?.filter ?? OPERATORS.equals;
|
||||||
const column = _.get(FILTER_COLUMNS, name, options?.columns?.[name]);
|
const column = _.get(FILTER_COLUMNS, name, options?.columns?.[name]);
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
|
||||||
if (value !== undefined && column) {
|
if (value !== undefined && column) {
|
||||||
arr.push(`and ${mapFilter(column, operator, name)}`);
|
arr.push(`and ${mapFilter(column, operator, name)}`);
|
||||||
|
|
||||||
@ -118,9 +130,13 @@ export function getDateQuery(
|
|||||||
field: string,
|
field: string,
|
||||||
unit: keyof typeof POSTGRESQL_DATE_FORMATS,
|
unit: keyof typeof POSTGRESQL_DATE_FORMATS,
|
||||||
timezone?: string
|
timezone?: string
|
||||||
): string {
|
) {
|
||||||
if (timezone) {
|
if (timezone) {
|
||||||
return `to_char(date_trunc('${unit}', ${field} at time zone '${timezone}'), '${POSTGRESQL_DATE_FORMATS[unit]}')`;
|
return Prisma.sql([
|
||||||
|
`to_char(date_trunc('${unit}', ${field} at time zone '${timezone}'), '${POSTGRESQL_DATE_FORMATS[unit]}')`,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
return `to_char(date_trunc('${unit}', ${field}), '${POSTGRESQL_DATE_FORMATS[unit]}')`;
|
return Prisma.sql([
|
||||||
|
`to_char(date_trunc('${unit}', ${field}), '${POSTGRESQL_DATE_FORMATS[unit]}')`,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user