Skip to content

Commit 862ba6d

Browse files
committed
fix: goals & funnels consistency
1 parent e463309 commit 862ba6d

File tree

3 files changed

+73
-71
lines changed

3 files changed

+73
-71
lines changed

packages/redis/drizzle-cache.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export type WithCacheArgs<T> = {
1111
tables?: string[];
1212
tag?: string;
1313
autoInvalidate?: boolean;
14+
disabled?: boolean;
1415
queryFn: () => Promise<T>;
1516
};
1617

@@ -104,8 +105,13 @@ export function createDrizzleCache({
104105
tables = [],
105106
tag,
106107
autoInvalidate = true,
108+
disabled = false,
107109
queryFn,
108110
}: WithCacheArgs<T>): Promise<T> {
111+
if (disabled) {
112+
return queryFn();
113+
}
114+
109115
const cacheKey = formatCacheKey(key);
110116
const start = Date.now();
111117

packages/rpc/src/lib/analytics-utils.ts

Lines changed: 64 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,12 @@ export const getTotalWebsiteUsers = async (
7171
};
7272

7373
const query = `
74-
SELECT COUNT(DISTINCT session_id) as total_users
74+
SELECT COUNT(DISTINCT anonymous_id) as total_users
7575
FROM analytics.events
7676
WHERE client_id = {websiteId:String}
7777
AND time >= parseDateTimeBestEffort({startDate:String})
7878
AND time <= parseDateTimeBestEffort({endDate:String})
79+
AND event_name = 'screen_view'
7980
`;
8081

8182
const result = await chQuery<{ total_users: number }>(query, params);
@@ -111,63 +112,48 @@ const buildStepQuery = (
111112
const whereCondition = buildWhereCondition(step, params);
112113
const referrerSelect = includeReferrer ? ', any(referrer) as referrer' : '';
113114

114-
// For PAGE_VIEW, only query analytics.events
115115
if (step.type === 'PAGE_VIEW') {
116116
return `
117117
SELECT
118118
${stepIndex + 1} as step_number,
119119
{${stepNameKey}:String} as step_name,
120-
session_id,
120+
any(session_id) as session_id,
121+
anonymous_id,
121122
MIN(time) as first_occurrence${referrerSelect}
122123
FROM analytics.events
123124
WHERE client_id = {websiteId:String}
124125
AND time >= parseDateTimeBestEffort({startDate:String})
125126
AND time <= parseDateTimeBestEffort({endDate:String})
126127
AND ${whereCondition}${filterConditions}
127-
GROUP BY session_id`;
128+
GROUP BY anonymous_id`;
128129
}
129130

130131
// For custom EVENT, query both analytics.events and analytics.custom_events
131132
const targetKey = `target_${step.step_number - 1}`;
132133
const referrerSelectCustom = includeReferrer ? ", '' as referrer" : '';
133134

134135
return `
135-
WITH filtered_sessions AS (
136-
SELECT DISTINCT session_id
137-
FROM analytics.events
138-
WHERE client_id = {websiteId:String}
139-
AND time >= parseDateTimeBestEffort({startDate:String})
140-
AND time <= parseDateTimeBestEffort({endDate:String})
141-
AND event_name = {${targetKey}:String}${filterConditions}
142-
143-
UNION DISTINCT
144-
145-
SELECT DISTINCT session_id
146-
FROM analytics.custom_events
147-
WHERE client_id = {websiteId:String}
148-
AND timestamp >= parseDateTimeBestEffort({startDate:String})
149-
AND timestamp <= parseDateTimeBestEffort({endDate:String})
150-
AND event_name = {${targetKey}:String}
151-
),
152-
session_referrers AS (
136+
WITH visitor_referrers AS (
153137
SELECT
154-
session_id,
155-
argMin(referrer, time) as session_referrer
138+
anonymous_id,
139+
argMin(referrer, time) as visitor_referrer
156140
FROM analytics.events
157141
WHERE client_id = {websiteId:String}
158142
AND time >= parseDateTimeBestEffort({startDate:String})
159143
AND time <= parseDateTimeBestEffort({endDate:String})
160144
AND event_name = 'screen_view'
161145
AND referrer != ''
162-
GROUP BY session_id
146+
GROUP BY anonymous_id
163147
)
164148
SELECT
165149
${stepIndex + 1} as step_number,
166150
{${stepNameKey}:String} as step_name,
167-
session_id,
168-
MIN(first_occurrence) as first_occurrence${includeReferrer ? ', COALESCE(sr.session_referrer, \'\') as referrer' : ''}
151+
any(session_id) as session_id,
152+
anonymous_id,
153+
MIN(first_occurrence) as first_occurrence${includeReferrer ? ', COALESCE(vr.visitor_referrer, \'\') as referrer' : ''}
169154
FROM (
170155
SELECT
156+
anonymous_id,
171157
session_id,
172158
time as first_occurrence
173159
FROM analytics.events
@@ -179,24 +165,25 @@ const buildStepQuery = (
179165
UNION ALL
180166
181167
SELECT
182-
ce.session_id,
183-
ce.timestamp as first_occurrence
184-
FROM analytics.custom_events ce
185-
INNER JOIN filtered_sessions fs ON ce.session_id = fs.session_id
186-
WHERE ce.client_id = {websiteId:String}
187-
AND ce.timestamp >= parseDateTimeBestEffort({startDate:String})
188-
AND ce.timestamp <= parseDateTimeBestEffort({endDate:String})
189-
AND ce.event_name = {${targetKey}:String}
168+
anonymous_id,
169+
session_id,
170+
timestamp as first_occurrence
171+
FROM analytics.custom_events
172+
WHERE client_id = {websiteId:String}
173+
AND timestamp >= parseDateTimeBestEffort({startDate:String})
174+
AND timestamp <= parseDateTimeBestEffort({endDate:String})
175+
AND event_name = {${targetKey}:String}
190176
) AS event_union${includeReferrer ? `
191-
LEFT JOIN session_referrers sr ON event_union.session_id = sr.session_id` : ''}
192-
GROUP BY event_union.session_id${includeReferrer ? ', sr.session_referrer' : ''}`;
177+
LEFT JOIN visitor_referrers vr ON event_union.anonymous_id = vr.anonymous_id` : ''}
178+
GROUP BY anonymous_id${includeReferrer ? ', vr.visitor_referrer' : ''}`;
193179
};
194180

195-
const processSessionEvents = (
181+
const processVisitorEvents = (
196182
rawResults: Array<{
197183
step_number: number;
198184
step_name: string;
199185
session_id: string;
186+
anonymous_id: string;
200187
first_occurrence: number;
201188
referrer?: string;
202189
}>
@@ -209,7 +196,7 @@ const processSessionEvents = (
209196
referrer?: string;
210197
}>
211198
> => {
212-
const sessionEvents = new Map<
199+
const visitorEvents = new Map<
213200
string,
214201
Array<{
215202
step_number: number;
@@ -220,7 +207,8 @@ const processSessionEvents = (
220207
>();
221208

222209
for (const event of rawResults) {
223-
const existing = sessionEvents.get(event.session_id);
210+
const visitorId = event.anonymous_id;
211+
const existing = visitorEvents.get(visitorId);
224212
const eventData = {
225213
step_number: event.step_number,
226214
step_name: event.step_name,
@@ -231,15 +219,15 @@ const processSessionEvents = (
231219
if (existing) {
232220
existing.push(eventData);
233221
} else {
234-
sessionEvents.set(event.session_id, [eventData]);
222+
visitorEvents.set(visitorId, [eventData]);
235223
}
236224
}
237225

238-
return sessionEvents;
226+
return visitorEvents;
239227
};
240228

241229
const calculateStepCounts = (
242-
sessionEvents: Map<
230+
visitorEvents: Map<
243231
string,
244232
Array<{
245233
step_number: number;
@@ -251,17 +239,17 @@ const calculateStepCounts = (
251239
): Map<number, Set<string>> => {
252240
const stepCounts = new Map<number, Set<string>>();
253241

254-
for (const [sessionId, events] of Array.from(sessionEvents.entries())) {
242+
for (const [visitorId, events] of Array.from(visitorEvents.entries())) {
255243
events.sort((a, b) => a.first_occurrence - b.first_occurrence);
256244
let currentStep = 1;
257245

258246
for (const event of events) {
259247
if (event.step_number === currentStep) {
260248
const stepSet = stepCounts.get(event.step_number);
261249
if (stepSet) {
262-
stepSet.add(sessionId);
250+
stepSet.add(visitorId);
263251
} else {
264-
stepCounts.set(event.step_number, new Set([sessionId]));
252+
stepCounts.set(event.step_number, new Set([visitorId]));
265253
}
266254
currentStep++;
267255
}
@@ -297,23 +285,25 @@ export const processGoalAnalytics = async (
297285
WITH all_step_events AS (
298286
${stepQuery}
299287
)
300-
SELECT
288+
SELECT DISTINCT
301289
step_number,
302290
step_name,
303291
session_id,
292+
anonymous_id,
304293
first_occurrence
305294
FROM all_step_events
306-
ORDER BY session_id, first_occurrence`;
295+
ORDER BY anonymous_id, first_occurrence`;
307296

308297
const rawResults = await chQuery<{
309298
step_number: number;
310299
step_name: string;
311300
session_id: string;
301+
anonymous_id: string;
312302
first_occurrence: number;
313303
}>(analysisQuery, params);
314304

315-
const sessionEvents = processSessionEvents(rawResults);
316-
const stepCounts = calculateStepCounts(sessionEvents);
305+
const visitorEvents = processVisitorEvents(rawResults);
306+
const stepCounts = calculateStepCounts(visitorEvents);
317307

318308
const goalCompletions = stepCounts.get(1)?.size ?? 0;
319309
const conversion_rate =
@@ -617,19 +607,21 @@ export const processFunnelAnalytics = async (
617607
step_number,
618608
step_name,
619609
session_id,
610+
anonymous_id,
620611
first_occurrence
621612
FROM all_step_events
622-
ORDER BY session_id, first_occurrence`;
613+
ORDER BY anonymous_id, first_occurrence`;
623614

624615
const rawResults = await chQuery<{
625616
step_number: number;
626617
step_name: string;
627618
session_id: string;
619+
anonymous_id: string;
628620
first_occurrence: number;
629621
}>(analysisQuery, params);
630622

631-
const sessionEvents = processSessionEvents(rawResults);
632-
const stepCounts = calculateStepCounts(sessionEvents);
623+
const visitorEvents = processVisitorEvents(rawResults);
624+
const stepCounts = calculateStepCounts(visitorEvents);
633625

634626
const analyticsResults = steps.map((step, index) => {
635627
const stepNumber = index + 1;
@@ -691,9 +683,9 @@ export const processFunnelAnalytics = async (
691683
const calculateReferrerStepCounts = (
692684
group: {
693685
parsed: { name: string; type: string; domain: string; url: string };
694-
sessionIds: Set<string>;
686+
visitorIds: Set<string>;
695687
},
696-
sessionEvents: Map<
688+
visitorEvents: Map<
697689
string,
698690
Array<{
699691
step_number: number;
@@ -705,9 +697,9 @@ const calculateReferrerStepCounts = (
705697
): Map<number, Set<string>> => {
706698
const stepCounts = new Map<number, Set<string>>();
707699

708-
for (const sessionId of Array.from(group.sessionIds)) {
709-
const events = sessionEvents
710-
.get(sessionId)
700+
for (const visitorId of Array.from(group.visitorIds)) {
701+
const events = visitorEvents
702+
.get(visitorId)
711703
?.sort((a, b) => a.first_occurrence - b.first_occurrence);
712704

713705
if (!events) {
@@ -719,9 +711,9 @@ const calculateReferrerStepCounts = (
719711
if (event.step_number === currentStep) {
720712
const stepSet = stepCounts.get(currentStep);
721713
if (stepSet) {
722-
stepSet.add(sessionId);
714+
stepSet.add(visitorId);
723715
} else {
724-
stepCounts.set(currentStep, new Set([sessionId]));
716+
stepCounts.set(currentStep, new Set([visitorId]));
725717
}
726718
currentStep++;
727719
}
@@ -745,9 +737,9 @@ const processReferrerGroup = (
745737
groupKey: string,
746738
group: {
747739
parsed: { name: string; type: string; domain: string; url: string };
748-
sessionIds: Set<string>;
740+
visitorIds: Set<string>;
749741
},
750-
sessionEvents: Map<
742+
visitorEvents: Map<
751743
string,
752744
Array<{
753745
step_number: number;
@@ -758,7 +750,7 @@ const processReferrerGroup = (
758750
>,
759751
steps: AnalyticsStep[]
760752
): ReferrerAnalytics | null => {
761-
const stepCounts = calculateReferrerStepCounts(group, sessionEvents);
753+
const stepCounts = calculateReferrerStepCounts(group, visitorEvents);
762754

763755
const total_users = stepCounts.get(1)?.size || 0;
764756
if (total_users === 0) {
@@ -871,39 +863,41 @@ export const processFunnelAnalyticsByReferrer = async (
871863
step_number,
872864
step_name,
873865
session_id,
866+
anonymous_id,
874867
first_occurrence,
875868
referrer
876869
FROM all_step_events
877-
ORDER BY session_id, first_occurrence`;
870+
ORDER BY anonymous_id, first_occurrence`;
878871

879872
const rawResults = await chQuery<{
880873
step_number: number;
881874
step_name: string;
882875
session_id: string;
876+
anonymous_id: string;
883877
first_occurrence: number;
884878
referrer: string;
885879
}>(sessionReferrerQuery, params);
886880

887-
const sessionEvents = processSessionEvents(rawResults);
881+
const visitorEvents = processVisitorEvents(rawResults);
888882

889883
const referrerGroups = new Map<
890884
string,
891885
{
892886
parsed: { name: string; type: string; domain: string; url: string };
893-
sessionIds: Set<string>;
887+
visitorIds: Set<string>;
894888
}
895889
>();
896890

897-
for (const [sessionId, events] of Array.from(sessionEvents.entries())) {
891+
for (const [visitorId, events] of Array.from(visitorEvents.entries())) {
898892
if (events.length > 0) {
899893
const referrer = events[0].referrer || 'Direct';
900894
const parsed = parseReferrer(referrer);
901895
const groupKey = parsed.domain ? parsed.domain.toLowerCase() : 'direct';
902896

903897
if (!referrerGroups.has(groupKey)) {
904-
referrerGroups.set(groupKey, { parsed, sessionIds: new Set() });
898+
referrerGroups.set(groupKey, { parsed, visitorIds: new Set() });
905899
}
906-
referrerGroups.get(groupKey)?.sessionIds.add(sessionId);
900+
referrerGroups.get(groupKey)?.visitorIds.add(visitorId);
907901
}
908902
}
909903

@@ -913,7 +907,7 @@ export const processFunnelAnalyticsByReferrer = async (
913907
const analytics = processReferrerGroup(
914908
groupKey,
915909
group,
916-
sessionEvents,
910+
visitorEvents,
917911
steps
918912
);
919913
if (analytics) {

0 commit comments

Comments
 (0)