From 5c9abe966bddc12964e78bd938c28bbc3c012193 Mon Sep 17 00:00:00 2001 From: Brian Cao Date: Mon, 20 May 2024 23:58:40 -0700 Subject: [PATCH] add psql. --- src/queries/analytics/reports/getGoals.ts | 181 ++++++++++++++++------ 1 file changed, 134 insertions(+), 47 deletions(-) diff --git a/src/queries/analytics/reports/getGoals.ts b/src/queries/analytics/reports/getGoals.ts index 66c1d951..cecdd10c 100644 --- a/src/queries/analytics/reports/getGoals.ts +++ b/src/queries/analytics/reports/getGoals.ts @@ -29,89 +29,176 @@ async function relationalQuery( const { startDate, endDate, goals } = criteria; const { rawQuery } = prisma; - const hasUrl = goals.some(a => a.type === 'url'); - const hasEvent = goals.some(a => a.type === 'event'); + const urls = goals.filter(a => a.type === 'url'); + const events = goals.filter(a => a.type === 'event'); + const eventData = goals.filter(a => a.type === 'event-data'); - function getParameters(goals: { type: string; value: string; goal: number }[]) { - const urls = goals - .filter(a => a.type === 'url') - .reduce((acc, cv, i) => { - acc[`${cv.type}${i}`] = cv.value; - return acc; - }, {}); + const hasUrl = urls.length > 0; + const hasEvent = events.length > 0; + const hasEventData = eventData.length > 0; - const events = goals - .filter(a => a.type === 'event') - .reduce((acc, cv, i) => { - acc[`${cv.type}${i}`] = cv.value; - return acc; - }, {}); + function getParameters( + urls: { type: string; value: string; goal: number }[], + events: { type: string; value: string; goal: number }[], + eventData: { + type: string; + value: string; + goal: number; + operator?: string; + property?: string; + }[], + ) { + const urlParam = urls.reduce((acc, cv, i) => { + acc[`${cv.type}${i}`] = cv.value; + return acc; + }, {}); + + const eventParam = events.reduce((acc, cv, i) => { + acc[`${cv.type}${i}`] = cv.value; + return acc; + }, {}); + + const eventDataParam = eventData.reduce((acc, cv, i) => { + acc[`eventData${i}`] = cv.value; + acc[`property${i}`] = cv.property; + acc[`eventData${i + 999}`] = cv.value; + acc[`property${i + 999}`] = cv.property; + return acc; + }, {}); return { - urls: { ...urls, startDate, endDate, websiteId }, - events: { ...events, startDate, endDate, websiteId }, + urls: { ...urlParam, startDate, endDate, websiteId }, + events: { ...eventParam, startDate, endDate, websiteId }, + eventData: { ...eventDataParam, startDate, endDate, websiteId }, }; } - function getColumns(goals: { type: string; value: string; goal: number }[]) { - const urls = goals - .filter(a => a.type === 'url') - .map((a, i) => `COUNT(CASE WHEN url_path = {{url${i}}} THEN 1 END) AS URL${i}`) - .join('\n'); - const events = goals - .filter(a => a.type === 'event') - .map((a, i) => `COUNT(CASE WHEN url_path = {{event${i}}} THEN 1 END) AS EVENT${i}`) - .join('\n'); + function getColumns( + urls: { type: string; value: string; goal: number }[], + events: { type: string; value: string; goal: number }[], + eventData: { + type: string; + value: string; + goal: number; + operator?: string; + property?: string; + }[], + ) { + const urlColumns = urls + .map((a, i) => `COUNT(CASE WHEN url_path = {{url${i}}} THEN 1 END) AS URL${i},`) + .join('\n') + .slice(0, -1); + const eventColumns = events + .map((a, i) => `COUNT(CASE WHEN url_path = {{event${i}}} THEN 1 END) AS EVENT${i},`) + .join('\n') + .slice(0, -1); + const eventDataColumns = eventData + .map( + (a, i) => + `${ + a.operator === 'average' ? 'avg' : a.operator + }(CASE WHEN event_name = {{eventData${i}}} AND data_key = {{property${i}}} THEN ${ + a.operator === 'count' ? '1' : 'number_value' + } END) AS EVENT_DATA${i},`, + ) + .join('\n') + .slice(0, -1); - return { urls, events }; + return { urls: urlColumns, events: eventColumns, eventData: eventDataColumns }; } - function getWhere(goals: { type: string; value: string; goal: number }[]) { - const urls = goals - .filter(a => a.type === 'url') - .map((a, i) => `{{url${i}}}`) - .join(','); - const events = goals - .filter(a => a.type === 'event') - .map((a, i) => `{{event${i}}}`) - .join(','); + function getWhere( + urls: { type: string; value: string; goal: number }[], + events: { type: string; value: string; goal: number }[], + eventData: { + type: string; + value: string; + goal: number; + operator?: string; + property?: string; + }[], + ) { + const urlWhere = urls.map((a, i) => `{{url${i}}}`).join(','); + const eventWhere = events.map((a, i) => `{{event${i}}}`).join(','); + const eventDataNameWhere = eventData.map((a, i) => `{{eventData${i + 999}}}`).join(','); + const eventDataKeyWhere = eventData.map((a, i) => `{{property${i + 999}}}`).join(','); - return { urls: `and url_path in (${urls})`, events: `and event_name in (${events})` }; + return { + urls: `and url_path in (${urlWhere})`, + events: `and event_name in (${eventWhere})`, + eventData: `and event_name in (${eventDataNameWhere}) and data_key in (${eventDataKeyWhere})`, + }; } - const parameters = getParameters(goals); - const columns = getColumns(goals); - const where = getWhere(goals); + const parameters = getParameters(urls, events, eventData); + const columns = getColumns(urls, events, eventData); + const where = getWhere(urls, events, eventData); - const urls = hasUrl + const urlResults = hasUrl ? await rawQuery( ` select ${columns.urls} from website_event - where websiteId = {{websiteId::uuid}} + where website_id = {{websiteId::uuid}} ${where.urls} and created_at between {{startDate}} and {{endDate}} `, parameters.urls, - ) + ).then(a => { + const results = a[0]; + + return Object.keys(results).map((key, i) => ({ + ...urls[i], + goal: Number(urls[i].goal), + result: Number(results[key]), + })); + }) : []; - const events = hasEvent + const eventResults = hasEvent ? await rawQuery( ` select ${columns.events} from website_event - where websiteId = {{websiteId::uuid}} + where website_id = {{websiteId::uuid}} ${where.events} and created_at between {{startDate}} and {{endDate}} `, parameters.events, - ) + ).then(a => { + const results = a[0]; + + return Object.keys(results).map((key, i) => { + return { ...events[i], goal: Number(events[i].goal), result: Number(results[key]) }; + }); + }) : []; - return [...urls, ...events]; + const eventDataResults = hasEventData + ? await rawQuery( + ` + select + ${columns.eventData} + from website_event w + join event_data d + on d.website_event_id = w.event_id + where w.website_id = {{websiteId::uuid}} + ${where.eventData} + and w.created_at between {{startDate}} and {{endDate}} + `, + parameters.eventData, + ).then(a => { + const results = a[0]; + + return Object.keys(results).map((key, i) => { + return { ...eventData[i], goal: Number(eventData[i].goal), result: Number(results[key]) }; + }); + }) + : []; + + return [...urlResults, ...eventResults, ...eventDataResults]; } async function clickhouseQuery(