Added parseDateRangeQuery function.

This commit is contained in:
Mike Cao 2023-07-26 09:55:54 -07:00
parent 09af33c77e
commit 1648707fc7
9 changed files with 48 additions and 80 deletions

View File

@ -62,10 +62,10 @@ export function parseDateRange(value, locale = 'en-US') {
}
if (value?.startsWith?.('range')) {
const [, startAt, endAt] = value.split(':');
const [, startTime, endTime] = value.split(':');
const startDate = new Date(+startAt);
const endDate = new Date(+endAt);
const startDate = new Date(+startTime);
const endDate = new Date(+endTime);
return {
...getDateRangeValues(startDate, endDate),

View File

@ -10,7 +10,6 @@ export async function parseDateRangeQuery(req: NextApiRequest) {
const { min, max } = await getWebsiteDateRange(websiteId as string);
return {
websiteId,
startDate: min,
endDate: max,
unit: getMinimumUnit(min, max),
@ -22,9 +21,8 @@ export async function parseDateRangeQuery(req: NextApiRequest) {
const minUnit = getMinimumUnit(startDate, endDate);
return {
websiteId,
startDate,
endDate,
unit: getAllowedUnits(startDate, endDate).includes(unit as string) ? unit : minUnit,
unit: (getAllowedUnits(startDate, endDate).includes(unit as string) ? unit : minUnit) as string,
};
}

View File

@ -5,6 +5,7 @@ import moment from 'moment-timezone';
import { NextApiResponse } from 'next';
import { badRequest, methodNotAllowed, ok, unauthorized } from 'next-basics';
import { getEventMetrics } from 'queries';
import { parseDateRangeQuery } from 'lib/query';
const unitTypes = ['year', 'month', 'hour', 'day'];
@ -25,7 +26,8 @@ export default async (
await useCors(req, res);
await useAuth(req, res);
const { id: websiteId, startAt, endAt, unit, timezone, url, eventName } = req.query;
const { id: websiteId, timezone, url, eventName } = req.query;
const { startDate, endDate, unit } = await parseDateRangeQuery(req);
if (req.method === 'GET') {
if (!(await canViewWebsite(req.auth, websiteId))) {
@ -35,8 +37,6 @@ export default async (
if (!moment.tz.zone(timezone) || !unitTypes.includes(unit)) {
return badRequest(res);
}
const startDate = new Date(+startAt);
const endDate = new Date(+endAt);
const events = await getEventMetrics(websiteId, {
startDate,

View File

@ -3,9 +3,9 @@ import { NextApiResponse } from 'next';
import { badRequest, methodNotAllowed, ok, unauthorized } from 'next-basics';
import { NextApiRequestQueryBody, WebsitePageviews } from 'lib/types';
import { canViewWebsite } from 'lib/auth';
import { getAllowedUnits } from 'lib/date';
import { useAuth, useCors } from 'lib/middleware';
import { getPageviewStats } from 'queries';
import { parseDateRangeQuery } from 'lib/query';
export interface WebsitePageviewRequestQuery {
id: string;
@ -33,9 +33,6 @@ export default async (
const {
id: websiteId,
startAt,
endAt,
unit,
timezone,
url,
referrer,
@ -53,10 +50,9 @@ export default async (
return unauthorized(res);
}
const startDate = new Date(+startAt);
const endDate = new Date(+endAt);
const { startDate, endDate, unit } = await parseDateRangeQuery(req);
if (!moment.tz.zone(timezone) || !getAllowedUnits(unit).includes(unit)) {
if (!moment.tz.zone(timezone)) {
return badRequest(res);
}

View File

@ -1,8 +1,10 @@
import { addMinutes, differenceInMinutes } from 'date-fns';
import { NextApiResponse } from 'next';
import { methodNotAllowed, ok, unauthorized } from 'next-basics';
import { canViewWebsite } from 'lib/auth';
import { useAuth, useCors } from 'lib/middleware';
import { NextApiRequestQueryBody, WebsiteStats } from 'lib/types';
import { NextApiResponse } from 'next';
import { methodNotAllowed, ok, unauthorized } from 'next-basics';
import { parseDateRangeQuery } from 'lib/query';
import { getWebsiteStats } from 'queries';
export interface WebsiteStatsRequestQuery {
@ -31,8 +33,6 @@ export default async (
const {
id: websiteId,
startAt,
endAt,
url,
referrer,
title,
@ -51,12 +51,10 @@ export default async (
return unauthorized(res);
}
const startDate = new Date(+startAt);
const endDate = new Date(+endAt);
const distance = endAt - startAt;
const prevStartDate = new Date(+startAt - distance);
const prevEndDate = new Date(+endAt - distance);
const { startDate, endDate } = await parseDateRangeQuery(req);
const diff = differenceInMinutes(endDate, startDate);
const prevStartDate = addMinutes(startDate, -diff);
const prevEndDate = addMinutes(endDate, -diff);
const metrics = await getWebsiteStats(websiteId, {
startDate,

View File

@ -2,26 +2,26 @@ import clickhouse from 'lib/clickhouse';
import { CLICKHOUSE, PRISMA, runQuery } from 'lib/db';
import prisma from 'lib/prisma';
export function getEvents(...args: [websiteId: string, startAt: Date, eventType: number]) {
export function getEvents(...args: [websiteId: string, startDate: Date, eventType: number]) {
return runQuery({
[PRISMA]: () => relationalQuery(...args),
[CLICKHOUSE]: () => clickhouseQuery(...args),
});
}
function relationalQuery(websiteId: string, startAt: Date, eventType: number) {
function relationalQuery(websiteId: string, startDate: Date, eventType: number) {
return prisma.client.websiteEvent.findMany({
where: {
websiteId,
eventType,
createdAt: {
gte: startAt,
gte: startDate,
},
},
});
}
function clickhouseQuery(websiteId: string, startAt: Date, eventType: number) {
function clickhouseQuery(websiteId: string, startDate: Date, eventType: number) {
const { rawQuery } = clickhouse;
return rawQuery(
@ -37,12 +37,12 @@ function clickhouseQuery(websiteId: string, startAt: Date, eventType: number) {
event_name as eventName
from website_event
where website_id = {websiteId:UUID}
and created_at >= {startAt:DateTime}
and created_at >= {startDate:DateTime}
and event_type = {eventType:UInt32}
`,
{
websiteId,
startAt,
startDate,
eventType,
},
);

View File

@ -1,23 +1,22 @@
import clickhouse from 'lib/clickhouse';
import { CLICKHOUSE, PRISMA, runQuery } from 'lib/db';
import prisma from 'lib/prisma';
import { DEFAULT_RESET_DATE, EVENT_TYPE } from 'lib/constants';
import { EVENT_TYPE } from 'lib/constants';
import { loadWebsite } from 'lib/load';
import { maxDate } from 'lib/date';
export interface PageviewStatsCriteria {
startDate: Date;
endDate: Date;
timezone?: string;
unit?: string;
count?: string;
filters: object;
sessionKey?: string;
}
export async function getPageviewStats(
...args: [
websiteId: string,
criteria: {
startDate: Date;
endDate: Date;
timezone?: string;
unit?: string;
count?: string;
filters: object;
sessionKey?: string;
},
]
...args: [websiteId: string, criteria: PageviewStatsCriteria]
) {
return runQuery({
[PRISMA]: () => relationalQuery(...args),
@ -25,18 +24,7 @@ export async function getPageviewStats(
});
}
async function relationalQuery(
websiteId: string,
criteria: {
startDate: Date;
endDate: Date;
timezone?: string;
unit?: string;
count?: string;
filters: object;
sessionKey?: string;
},
) {
async function relationalQuery(websiteId: string, criteria: PageviewStatsCriteria) {
const {
startDate,
endDate,
@ -73,18 +61,7 @@ async function relationalQuery(
);
}
async function clickhouseQuery(
websiteId: string,
criteria: {
startDate: Date;
endDate: Date;
timezone?: string;
unit?: string;
count?: string;
filters: object;
sessionKey?: string;
},
) {
async function clickhouseQuery(websiteId: string, criteria: PageviewStatsCriteria) {
const {
startDate,
endDate,

View File

@ -9,18 +9,18 @@ export async function getSessions(...args: [websiteId: string, startAt: Date]) {
});
}
async function relationalQuery(websiteId: string, startAt: Date) {
async function relationalQuery(websiteId: string, startDate: Date) {
return prisma.client.session.findMany({
where: {
websiteId,
createdAt: {
gte: startAt,
gte: startDate,
},
},
});
}
async function clickhouseQuery(websiteId: string, startAt: Date) {
async function clickhouseQuery(websiteId: string, startDate: Date) {
const { rawQuery } = clickhouse;
return rawQuery(
@ -42,11 +42,11 @@ async function clickhouseQuery(websiteId: string, startAt: Date) {
city
from website_event
where website_id = {websiteId:UUID}
and created_at >= {startAt:DateTime}
and created_at >= {startDate:DateTime}
`,
{
websiteId,
startAt,
startDate,
},
);
}

View File

@ -14,6 +14,7 @@ export async function getWebsiteDateRange(...args: [websiteId: string]) {
async function relationalQuery(websiteId: string) {
const { rawQuery } = prisma;
const website = await loadWebsite(websiteId);
return rawQuery(
`
@ -21,12 +22,10 @@ async function relationalQuery(websiteId: string) {
min(created_at) as min,
max(created_at) as max
from website_event
join website
on website_event.website_id = website.website_id
where website.website_id = {{websiteId::uuid}}
and website_event.created_at >= coalesce(website.reset_at, website.created_at)
where website_id = {{websiteId::uuid}}
and created_at >= {{startDate}}
`,
{ websiteId },
{ websiteId, startDate: maxDate(new Date(DEFAULT_RESET_DATE), new Date(website.resetAt)) },
);
}
@ -43,6 +42,6 @@ async function clickhouseQuery(websiteId: string) {
where website_id = {websiteId:UUID}
and created_at >= {startDate:DateTime}
`,
{ websiteId, startDate: maxDate(new Date(DEFAULT_RESET_DATE), website.resetAt) },
{ websiteId, startDate: maxDate(new Date(DEFAULT_RESET_DATE), new Date(website.resetAt)) },
);
}