Fixed search for postgresql.

This commit is contained in:
Mike Cao 2024-03-25 22:51:10 -07:00
parent e6aebf5104
commit 91efb7f1d0
4 changed files with 30 additions and 40 deletions

View File

@ -92,31 +92,31 @@ function getTimestampDiffQuery(field1: string, field2: string): string {
} }
} }
function mapFilter(column: string, filter: string, name: string, type = 'varchar') { function mapFilter(column: string, op: string, name: string, type = 'varchar') {
switch (filter) { switch (op) {
case OPERATORS.equals: case OPERATORS.equals:
return `${column} = {{${name}::${type}}}`; return `${column} = {{${name}::${type}}}`;
case OPERATORS.notEquals: case OPERATORS.notEquals:
return `${column} != {{${name}::${type}}}`; return `${column} != {{${name}::${type}}}`;
case OPERATORS.contains: case OPERATORS.contains:
return `${column} like {{${name}::${type}}}`; return `${column} ilike {{${name}::${type}}}`;
case OPERATORS.doesNotContain: case OPERATORS.doesNotContain:
return `${column} not like {{${name}::${type}}}`; return `${column} not ilike {{${name}::${type}}}`;
default: default:
return ''; return '';
} }
} }
function getFilterQuery(filters: QueryFilters = {}, options: QueryOptions = {}): string { function getFilterQuery(filters: QueryFilters = {}, options: QueryOptions = {}): string {
const query = Object.keys(filters).reduce((arr, name) => { const query = Object.keys(filters).reduce((arr, key) => {
const value = filters[name]; const filter = filters[key];
const filter = value?.filter ?? OPERATORS.equals; const op = filter?.op ?? OPERATORS.equals;
const column = value?.column ?? FILTER_COLUMNS[name] ?? options?.columns?.[name]; const column = filter?.column ?? FILTER_COLUMNS[key] ?? options?.columns?.[key];
if (value !== undefined && column !== undefined) { if (filter !== undefined && column !== undefined) {
arr.push(`and ${mapFilter(column, filter, name)}`); arr.push(`and ${mapFilter(column, op, key)}`);
if (name === 'referrer') { if (key === 'referrer') {
arr.push( arr.push(
'and (website_event.referrer_domain != {{websiteDomain}} or website_event.referrer_domain is null)', 'and (website_event.referrer_domain != {{websiteDomain}} or website_event.referrer_domain is null)',
); );
@ -171,7 +171,10 @@ async function rawQuery(sql: string, data: object): Promise<any> {
const query = sql?.replaceAll(/\{\{\s*(\w+)(::\w+)?\s*}}/g, (...args) => { const query = sql?.replaceAll(/\{\{\s*(\w+)(::\w+)?\s*}}/g, (...args) => {
const [, name, type] = args; const [, name, type] = args;
params.push(data[name]);
const value = data[name];
params.push(value);
return db === MYSQL ? '?' : `$${params.length}${type ?? ''}`; return db === MYSQL ? '?' : `$${params.length}${type ?? ''}`;
}); });

View File

@ -97,7 +97,7 @@ export default async (req: NextApiRequestCollect, res: NextApiResponse) => {
// eslint-disable-next-line prefer-const // eslint-disable-next-line prefer-const
let [urlPath, urlQuery] = url?.split('?') || []; let [urlPath, urlQuery] = url?.split('?') || [];
let [referrerPath, referrerQuery] = referrer?.split('?') || []; let [referrerPath, referrerQuery] = referrer?.split('?') || [];
let referrerDomain; let referrerDomain = '';
if (!urlPath) { if (!urlPath) {
urlPath = '/'; urlPath = '/';

View File

@ -3,7 +3,7 @@ import { badRequest, methodNotAllowed, ok, unauthorized } from 'next-basics';
import { WebsiteMetric, NextApiRequestQueryBody } from 'lib/types'; import { WebsiteMetric, NextApiRequestQueryBody } from 'lib/types';
import { canViewWebsite } from 'lib/auth'; import { canViewWebsite } from 'lib/auth';
import { useAuth, useCors, useValidate } from 'lib/middleware'; import { useAuth, useCors, useValidate } from 'lib/middleware';
import { SESSION_COLUMNS, EVENT_COLUMNS, FILTER_COLUMNS } from 'lib/constants'; import { SESSION_COLUMNS, EVENT_COLUMNS, FILTER_COLUMNS, OPERATORS } from 'lib/constants';
import { getPageviewMetrics, getSessionMetrics } from 'queries'; import { getPageviewMetrics, getSessionMetrics } from 'queries';
import { parseDateRangeQuery } from 'lib/query'; import { parseDateRangeQuery } from 'lib/query';
import * as yup from 'yup'; import * as yup from 'yup';
@ -88,7 +88,7 @@ export default async (
} }
const { startDate, endDate } = await parseDateRangeQuery(req); const { startDate, endDate } = await parseDateRangeQuery(req);
const column = FILTER_COLUMNS[type] || type;
const filters = { const filters = {
startDate, startDate,
endDate, endDate,
@ -104,19 +104,18 @@ export default async (
city, city,
language, language,
event, event,
search,
}; };
const column = FILTER_COLUMNS[type] || type; if (search) {
filters[column] = {
column,
op: OPERATORS.contains,
value: '%' + search + '%',
};
}
if (SESSION_COLUMNS.includes(type)) { if (SESSION_COLUMNS.includes(type)) {
const data = await getSessionMetrics( const data = await getSessionMetrics(websiteId, column, filters, limit, offset);
websiteId,
column,
{ ...filters, search },
limit,
offset,
);
if (type === 'language') { if (type === 'language') {
const combined = {}; const combined = {};
@ -138,13 +137,7 @@ export default async (
} }
if (EVENT_COLUMNS.includes(type)) { if (EVENT_COLUMNS.includes(type)) {
const data = await getPageviewMetrics( const data = await getPageviewMetrics(websiteId, column, filters, limit, offset);
websiteId,
column,
{ ...filters, search },
limit,
offset,
);
return ok(res, data); return ok(res, data);
} }

View File

@ -1,7 +1,7 @@
import prisma from 'lib/prisma'; 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';
import { EVENT_TYPE, SESSION_COLUMNS, OPERATORS } from 'lib/constants'; import { EVENT_TYPE, SESSION_COLUMNS } from 'lib/constants';
import { QueryFilters } from 'lib/types'; import { QueryFilters } from 'lib/types';
export async function getPageviewMetrics( export async function getPageviewMetrics(
@ -27,6 +27,7 @@ async function relationalQuery(
offset: number = 0, offset: number = 0,
) { ) {
const { rawQuery, parseFilters } = prisma; const { rawQuery, parseFilters } = prisma;
const { filterQuery, joinSession, params } = await parseFilters( const { filterQuery, joinSession, params } = await parseFilters(
websiteId, websiteId,
{ {
@ -69,16 +70,9 @@ async function clickhouseQuery(
offset: number = 0, offset: number = 0,
): Promise<{ x: string; y: number }[]> { ): Promise<{ x: string; y: number }[]> {
const { rawQuery, parseFilters } = clickhouse; const { rawQuery, parseFilters } = clickhouse;
const { filterQuery, params } = await parseFilters(websiteId, { const { filterQuery, params } = await parseFilters(websiteId, {
...filters, ...filters,
...(filters.search && {
[column]: {
value: filters.search,
filter: OPERATORS.contains,
column,
name: column,
},
}),
eventType: column === 'event_name' ? EVENT_TYPE.customEvent : EVENT_TYPE.pageView, eventType: column === 'event_name' ? EVENT_TYPE.customEvent : EVENT_TYPE.pageView,
}); });