Skip to content

Commit c5c1af5

Browse files
committed
Merge branch 'staging' of https://github.com/databuddy-analytics/Databuddy into staging
2 parents 6ce6b8d + 1956cc5 commit c5c1af5

File tree

14 files changed

+1527
-1390
lines changed

14 files changed

+1527
-1390
lines changed

apps/api/src/query/builders/profiles.ts

Lines changed: 88 additions & 195 deletions
Original file line numberDiff line numberDiff line change
@@ -151,44 +151,86 @@ export const ProfilesBuilders: Record<string, SimpleQueryConfig> = {
151151

152152
return {
153153
sql: `
154-
WITH user_profile AS (
154+
SELECT
155+
anonymous_id as visitor_id,
156+
MIN(time) as first_visit,
157+
MAX(time) as last_visit,
158+
COUNT(DISTINCT session_id) as total_sessions,
159+
COUNT(*) as total_pageviews,
160+
SUM(CASE WHEN time_on_page > 0 THEN time_on_page ELSE 0 END) as total_duration,
161+
formatReadableTimeDelta(SUM(CASE WHEN time_on_page > 0 THEN time_on_page ELSE 0 END)) as total_duration_formatted,
162+
any(device_type) as device,
163+
any(browser_name) as browser,
164+
any(os_name) as os,
165+
any(country) as country,
166+
any(region) as region
167+
FROM analytics.events
168+
WHERE
169+
client_id = {websiteId:String}
170+
AND anonymous_id = {visitorId:String}
171+
AND time >= parseDateTimeBestEffort({startDate:String})
172+
AND time <= parseDateTimeBestEffort({endDate:String})
173+
GROUP BY anonymous_id
174+
`,
175+
params: {
176+
websiteId,
177+
visitorId,
178+
startDate,
179+
endDate: `${endDate} 23:59:59`,
180+
},
181+
};
182+
},
183+
},
184+
185+
profile_sessions: {
186+
customSql: (
187+
websiteId: string,
188+
startDate: string,
189+
endDate: string,
190+
filters?: Filter[],
191+
_granularity?: TimeUnit,
192+
limit = 100,
193+
offset = 0
194+
) => {
195+
const visitorId = filters?.find((f) => f.field === 'anonymous_id')?.value;
196+
197+
if (!visitorId || typeof visitorId !== 'string') {
198+
throw new Error(
199+
'anonymous_id filter is required for profile_sessions query'
200+
);
201+
}
202+
203+
return {
204+
sql: `
205+
WITH user_sessions AS (
155206
SELECT
156-
anonymous_id as visitor_id,
207+
session_id,
208+
CONCAT('Session ', ROW_NUMBER() OVER (ORDER BY MIN(time))) as session_name,
157209
MIN(time) as first_visit,
158210
MAX(time) as last_visit,
159-
COUNT(DISTINCT session_id) as total_sessions,
160-
COUNT(*) as total_pageviews,
161-
SUM(CASE WHEN time_on_page > 0 THEN time_on_page ELSE 0 END) as total_duration,
162-
formatReadableTimeDelta(SUM(CASE WHEN time_on_page > 0 THEN time_on_page ELSE 0 END)) as total_duration_formatted,
211+
LEAST(dateDiff('second', MIN(time), MAX(time)), 28800) as duration,
212+
formatReadableTimeDelta(LEAST(dateDiff('second', MIN(time), MAX(time)), 28800)) as duration_formatted,
213+
countIf(event_name = 'screen_view') as page_views,
214+
COUNT(DISTINCT path) as unique_pages,
163215
any(device_type) as device,
164216
any(browser_name) as browser,
165217
any(os_name) as os,
166218
any(country) as country,
167-
any(region) as region
219+
any(region) as region,
220+
any(referrer) as referrer
168221
FROM analytics.events
169222
WHERE
170223
client_id = {websiteId:String}
171224
AND anonymous_id = {visitorId:String}
172225
AND time >= parseDateTimeBestEffort({startDate:String})
173226
AND time <= parseDateTimeBestEffort({endDate:String})
174-
GROUP BY anonymous_id
227+
GROUP BY session_id
228+
ORDER BY first_visit DESC
229+
LIMIT {limit:Int32} OFFSET {offset:Int32}
175230
),
176-
user_sessions AS (
231+
session_events AS (
177232
SELECT
178233
e.session_id,
179-
CONCAT('Session ', ROW_NUMBER() OVER (ORDER BY MIN(e.time))) as session_name,
180-
MIN(e.time) as first_visit,
181-
MAX(e.time) as last_visit,
182-
LEAST(dateDiff('second', MIN(e.time), MAX(e.time)), 28800) as duration,
183-
formatReadableTimeDelta(LEAST(dateDiff('second', MIN(e.time), MAX(e.time)), 28800)) as duration_formatted,
184-
COUNT(DISTINCT e.path) as page_views,
185-
COUNT(DISTINCT e.path) as unique_pages,
186-
any(e.device_type) as device,
187-
any(e.browser_name) as browser,
188-
any(e.os_name) as os,
189-
any(e.country) as country,
190-
any(e.region) as region,
191-
any(e.referrer) as referrer,
192234
groupArray(
193235
tuple(
194236
e.id,
@@ -201,197 +243,48 @@ export const ProfilesBuilders: Record<string, SimpleQueryConfig> = {
201243
AND e.properties != '{}'
202244
THEN CAST(e.properties AS String)
203245
ELSE NULL
204-
END,
205-
NULL,
206-
NULL
246+
END
207247
)
208248
) as events
209249
FROM analytics.events e
250+
INNER JOIN user_sessions us ON e.session_id = us.session_id
210251
WHERE
211252
e.client_id = {websiteId:String}
212253
AND e.anonymous_id = {visitorId:String}
213-
AND e.time >= parseDateTimeBestEffort({startDate:String})
214-
AND e.time <= parseDateTimeBestEffort({endDate:String})
215254
GROUP BY e.session_id
216-
ORDER BY first_visit DESC
217255
)
218256
SELECT
219-
up.visitor_id,
220-
up.first_visit,
221-
up.last_visit,
222-
up.total_sessions,
223-
up.total_pageviews,
224-
up.total_duration,
225-
up.total_duration_formatted,
226-
up.device,
227-
up.browser,
228-
up.os,
229-
up.country,
230-
up.region,
231-
groupArray(
232-
tuple(
233-
us.session_id,
234-
us.session_name,
235-
us.first_visit,
236-
us.last_visit,
237-
us.duration,
238-
us.duration_formatted,
239-
us.page_views,
240-
us.unique_pages,
241-
us.device,
242-
us.browser,
243-
us.os,
244-
us.country,
245-
us.region,
246-
us.referrer,
247-
us.events
248-
)
249-
) as sessions
250-
FROM user_profile up
251-
LEFT JOIN user_sessions us ON 1=1
252-
GROUP BY
253-
up.visitor_id, up.first_visit, up.last_visit, up.total_sessions,
254-
up.total_pageviews, up.total_duration, up.total_duration_formatted,
255-
up.device, up.browser, up.os, up.country, up.region
257+
us.session_id,
258+
us.session_name,
259+
us.first_visit,
260+
us.last_visit,
261+
us.duration,
262+
us.duration_formatted,
263+
us.page_views,
264+
us.unique_pages,
265+
us.device,
266+
us.browser,
267+
us.os,
268+
us.country,
269+
us.region,
270+
us.referrer,
271+
COALESCE(se.events, []) as events
272+
FROM user_sessions us
273+
LEFT JOIN session_events se ON us.session_id = se.session_id
274+
ORDER BY us.first_visit DESC
256275
`,
257276
params: {
258277
websiteId,
259278
visitorId,
260279
startDate,
261280
endDate: `${endDate} 23:59:59`,
281+
limit,
282+
offset,
262283
},
263284
};
264285
},
265-
},
266-
267-
profile_metrics: {
268-
table: Analytics.events,
269-
fields: [
270-
'COUNT(DISTINCT anonymous_id) as total_visitors',
271-
'COUNT(DISTINCT session_id) as total_sessions',
272-
'AVG(CASE WHEN time_on_page > 0 THEN time_on_page / 1000 ELSE NULL END) as avg_session_duration',
273-
'COUNT(*) as total_events',
274-
],
275-
where: ["event_name = 'screen_view'"],
276-
timeField: 'time',
277-
customizable: true,
278-
},
279-
280-
profile_duration_distribution: {
281-
table: Analytics.events,
282-
fields: [
283-
'CASE ' +
284-
"WHEN time_on_page < 30 THEN '0-30s' " +
285-
"WHEN time_on_page < 60 THEN '30s-1m' " +
286-
"WHEN time_on_page < 300 THEN '1m-5m' " +
287-
"WHEN time_on_page < 900 THEN '5m-15m' " +
288-
"WHEN time_on_page < 3600 THEN '15m-1h' " +
289-
"ELSE '1h+' " +
290-
'END as duration_range',
291-
'COUNT(DISTINCT anonymous_id) as visitors',
292-
'COUNT(DISTINCT session_id) as sessions',
293-
],
294-
where: ["event_name = 'screen_view'", 'time_on_page > 0'],
295-
groupBy: ['duration_range'],
296-
orderBy: 'visitors DESC',
297-
timeField: 'time',
298-
customizable: true,
299-
},
300-
301-
profiles_by_device: {
302-
table: Analytics.events,
303-
fields: [
304-
'device_type as name',
305-
'COUNT(DISTINCT anonymous_id) as visitors',
306-
'COUNT(DISTINCT session_id) as sessions',
307-
'ROUND(AVG(CASE WHEN time_on_page > 0 THEN time_on_page / 1000 ELSE NULL END), 2) as avg_session_duration',
308-
],
309-
where: ["event_name = 'screen_view'", "device_type != ''"],
310-
groupBy: ['device_type'],
311-
orderBy: 'visitors DESC',
312-
timeField: 'time',
313-
customizable: true,
314-
},
315-
316-
profiles_by_browser: {
317-
table: Analytics.events,
318-
fields: [
319-
'browser_name as name',
320-
'COUNT(DISTINCT anonymous_id) as visitors',
321-
'COUNT(DISTINCT session_id) as sessions',
322-
'ROUND(AVG(CASE WHEN time_on_page > 0 THEN time_on_page / 1000 ELSE NULL END), 2) as avg_session_duration',
323-
],
324-
where: ["event_name = 'screen_view'", "browser_name != ''"],
325-
groupBy: ['browser_name'],
326-
orderBy: 'visitors DESC',
327-
limit: 100,
328-
timeField: 'time',
329-
330-
customizable: true,
331-
},
332-
333-
profiles_time_series: {
334-
table: Analytics.events,
335-
fields: [
336-
'toDate(time) as date',
337-
'COUNT(DISTINCT anonymous_id) as visitors',
338-
'COUNT(DISTINCT session_id) as sessions',
339-
'ROUND(AVG(CASE WHEN time_on_page > 0 THEN time_on_page / 1000 ELSE NULL END), 2) as avg_session_duration',
340-
],
341-
where: ["event_name = 'screen_view'"],
342-
groupBy: ['toDate(time)'],
343-
orderBy: 'date ASC',
344-
timeField: 'time',
345-
346-
customizable: true,
347-
},
348-
349-
returning_visitors: {
350-
customSql: (
351-
websiteId: string,
352-
startDate: string,
353-
endDate: string,
354-
_filters?: Filter[],
355-
_granularity?: TimeUnit,
356-
limit?: number,
357-
offset?: number,
358-
_timezone?: string,
359-
filterConditions?: string[],
360-
filterParams?: Record<string, Filter['value']>
361-
) => {
362-
const combinedWhereClause = filterConditions?.length
363-
? `AND ${filterConditions.join(' AND ')}`
364-
: '';
365-
366-
return {
367-
sql: `
368-
SELECT
369-
anonymous_id as visitor_id,
370-
COUNT(DISTINCT session_id) as session_count,
371-
MIN(time) as first_visit,
372-
MAX(time) as last_visit,
373-
COUNT(DISTINCT path) as unique_pages
374-
FROM analytics.events
375-
WHERE
376-
client_id = {websiteId:String}
377-
AND time >= parseDateTimeBestEffort({startDate:String})
378-
AND time <= parseDateTimeBestEffort({endDate:String})
379-
AND event_name = 'screen_view'
380-
${combinedWhereClause}
381-
GROUP BY anonymous_id
382-
HAVING session_count > 1
383-
ORDER BY session_count DESC
384-
LIMIT {limit:Int32} OFFSET {offset:Int32}
385-
`,
386-
params: {
387-
websiteId,
388-
startDate,
389-
endDate: `${endDate} 23:59:59`,
390-
limit: limit || 100,
391-
offset: offset || 0,
392-
...filterParams,
393-
},
394-
};
286+
plugins: {
287+
normalizeGeo: true,
395288
},
396289
},
397290
};

0 commit comments

Comments
 (0)