Yimaru-BackEnd/db/query/analytics.sql
Yared Yemane 56089fa8fd Add users by country to analytics dashboard.
Expose by_country breakdown on GET /api/v1/analytics/dashboard from users.country.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-24 01:47:41 -07:00

458 lines
20 KiB
SQL

-- =====================
-- Analytics (date-filtered)
-- =====================
-- Shared optional params (nullable = all-time):
-- range_start, range_end (exclusive upper bound)
-- Required chart params:
-- series_start, series_end (inclusive dates)
-- Relative window anchor:
-- ref_date (inclusive date used for new_today/week/month)
-- =====================
-- User Analytics
-- =====================
-- name: AnalyticsUsersSummary :one
SELECT
COUNT(*)::bigint AS total,
COUNT(*) FILTER (WHERE u.created_at::date = sqlc.arg('ref_date')::date)::bigint AS new_today,
COUNT(*) FILTER (
WHERE u.created_at::date >= sqlc.arg('ref_date')::date - INTERVAL '6 days'
AND u.created_at::date <= sqlc.arg('ref_date')::date
)::bigint AS new_this_week,
COUNT(*) FILTER (
WHERE u.created_at::date >= sqlc.arg('ref_date')::date - INTERVAL '29 days'
AND u.created_at::date <= sqlc.arg('ref_date')::date
)::bigint AS new_this_month
FROM users u
WHERE (sqlc.narg('range_start')::timestamptz IS NULL OR u.created_at >= sqlc.narg('range_start')::timestamptz)
AND (sqlc.narg('range_end')::timestamptz IS NULL OR u.created_at < sqlc.narg('range_end')::timestamptz);
-- name: AnalyticsUsersByRole :many
SELECT
COALESCE(u.role, 'unknown') AS role,
COUNT(*)::bigint AS count
FROM users u
WHERE (sqlc.narg('range_start')::timestamptz IS NULL OR u.created_at >= sqlc.narg('range_start')::timestamptz)
AND (sqlc.narg('range_end')::timestamptz IS NULL OR u.created_at < sqlc.narg('range_end')::timestamptz)
GROUP BY u.role
ORDER BY count DESC;
-- name: AnalyticsUsersByStatus :many
SELECT
COALESCE(u.status, 'unknown') AS status,
COUNT(*)::bigint AS count
FROM users u
WHERE (sqlc.narg('range_start')::timestamptz IS NULL OR u.created_at >= sqlc.narg('range_start')::timestamptz)
AND (sqlc.narg('range_end')::timestamptz IS NULL OR u.created_at < sqlc.narg('range_end')::timestamptz)
GROUP BY u.status
ORDER BY count DESC;
-- name: AnalyticsUsersByAgeGroup :many
SELECT
COALESCE(u.age_group, 'unknown') AS age_group,
COUNT(*)::bigint AS count
FROM users u
WHERE (sqlc.narg('range_start')::timestamptz IS NULL OR u.created_at >= sqlc.narg('range_start')::timestamptz)
AND (sqlc.narg('range_end')::timestamptz IS NULL OR u.created_at < sqlc.narg('range_end')::timestamptz)
GROUP BY u.age_group
ORDER BY count DESC;
-- name: AnalyticsUsersByKnowledgeLevel :many
SELECT
COALESCE(u.knowledge_level, 'unknown') AS knowledge_level,
COUNT(*)::bigint AS count
FROM users u
WHERE (sqlc.narg('range_start')::timestamptz IS NULL OR u.created_at >= sqlc.narg('range_start')::timestamptz)
AND (sqlc.narg('range_end')::timestamptz IS NULL OR u.created_at < sqlc.narg('range_end')::timestamptz)
GROUP BY u.knowledge_level
ORDER BY count DESC;
-- name: AnalyticsUsersByEducationLevel :many
SELECT
COALESCE(NULLIF(TRIM(u.education_level), ''), 'unknown')::text AS education_level,
COUNT(*)::bigint AS count
FROM users u
WHERE (sqlc.narg('range_start')::timestamptz IS NULL OR u.created_at >= sqlc.narg('range_start')::timestamptz)
AND (sqlc.narg('range_end')::timestamptz IS NULL OR u.created_at < sqlc.narg('range_end')::timestamptz)
GROUP BY COALESCE(NULLIF(TRIM(u.education_level), ''), 'unknown')
ORDER BY count DESC;
-- name: AnalyticsUsersByOccupation :many
SELECT
COALESCE(NULLIF(TRIM(u.occupation), ''), 'unknown')::text AS occupation,
COUNT(*)::bigint AS count
FROM users u
WHERE (sqlc.narg('range_start')::timestamptz IS NULL OR u.created_at >= sqlc.narg('range_start')::timestamptz)
AND (sqlc.narg('range_end')::timestamptz IS NULL OR u.created_at < sqlc.narg('range_end')::timestamptz)
GROUP BY COALESCE(NULLIF(TRIM(u.occupation), ''), 'unknown')
ORDER BY count DESC;
-- name: AnalyticsUsersByLearningGoal :many
SELECT
COALESCE(NULLIF(TRIM(u.learning_goal), ''), 'unknown')::text AS learning_goal,
COUNT(*)::bigint AS count
FROM users u
WHERE (sqlc.narg('range_start')::timestamptz IS NULL OR u.created_at >= sqlc.narg('range_start')::timestamptz)
AND (sqlc.narg('range_end')::timestamptz IS NULL OR u.created_at < sqlc.narg('range_end')::timestamptz)
GROUP BY COALESCE(NULLIF(TRIM(u.learning_goal), ''), 'unknown')
ORDER BY count DESC;
-- name: AnalyticsUsersByLanguageChallange :many
SELECT
COALESCE(NULLIF(TRIM(u.language_challange), ''), 'unknown')::text AS language_challange,
COUNT(*)::bigint AS count
FROM users u
WHERE (sqlc.narg('range_start')::timestamptz IS NULL OR u.created_at >= sqlc.narg('range_start')::timestamptz)
AND (sqlc.narg('range_end')::timestamptz IS NULL OR u.created_at < sqlc.narg('range_end')::timestamptz)
GROUP BY COALESCE(NULLIF(TRIM(u.language_challange), ''), 'unknown')
ORDER BY count DESC;
-- name: AnalyticsUsersByCountry :many
SELECT
COALESCE(NULLIF(TRIM(u.country), ''), 'unknown')::text AS country,
COUNT(*)::bigint AS count
FROM users u
WHERE (sqlc.narg('range_start')::timestamptz IS NULL OR u.created_at >= sqlc.narg('range_start')::timestamptz)
AND (sqlc.narg('range_end')::timestamptz IS NULL OR u.created_at < sqlc.narg('range_end')::timestamptz)
GROUP BY COALESCE(NULLIF(TRIM(u.country), ''), 'unknown')
ORDER BY count DESC;
-- name: AnalyticsUsersByRegion :many
SELECT
COALESCE(u.region, 'unknown') AS region,
COUNT(*)::bigint AS count
FROM users u
WHERE (sqlc.narg('range_start')::timestamptz IS NULL OR u.created_at >= sqlc.narg('range_start')::timestamptz)
AND (sqlc.narg('range_end')::timestamptz IS NULL OR u.created_at < sqlc.narg('range_end')::timestamptz)
GROUP BY u.region
ORDER BY count DESC;
-- name: AnalyticsUserRegistrationsLast30Days :many
SELECT
d.date,
COUNT(u.id)::bigint AS count
FROM generate_series(
sqlc.arg('series_start')::date,
sqlc.arg('series_end')::date,
INTERVAL '1 day'
) AS d(date)
LEFT JOIN users u ON u.created_at::date = d.date
AND (sqlc.narg('range_start')::timestamptz IS NULL OR u.created_at >= sqlc.narg('range_start')::timestamptz)
AND (sqlc.narg('range_end')::timestamptz IS NULL OR u.created_at < sqlc.narg('range_end')::timestamptz)
GROUP BY d.date
ORDER BY d.date;
-- =====================
-- Subscription Analytics
-- =====================
-- name: AnalyticsSubscriptionsSummary :one
SELECT
COUNT(*)::bigint AS total,
COUNT(*) FILTER (WHERE us.status = 'ACTIVE')::bigint AS active,
COUNT(*) FILTER (WHERE us.created_at::date = sqlc.arg('ref_date')::date)::bigint AS new_today,
COUNT(*) FILTER (
WHERE us.created_at::date >= sqlc.arg('ref_date')::date - INTERVAL '6 days'
AND us.created_at::date <= sqlc.arg('ref_date')::date
)::bigint AS new_this_week,
COUNT(*) FILTER (
WHERE us.created_at::date >= sqlc.arg('ref_date')::date - INTERVAL '29 days'
AND us.created_at::date <= sqlc.arg('ref_date')::date
)::bigint AS new_this_month
FROM user_subscriptions us
WHERE (sqlc.narg('range_start')::timestamptz IS NULL OR us.created_at >= sqlc.narg('range_start')::timestamptz)
AND (sqlc.narg('range_end')::timestamptz IS NULL OR us.created_at < sqlc.narg('range_end')::timestamptz);
-- name: AnalyticsSubscriptionsByStatus :many
SELECT
COALESCE(us.status, 'unknown') AS status,
COUNT(*)::bigint AS count
FROM user_subscriptions us
WHERE (sqlc.narg('range_start')::timestamptz IS NULL OR us.created_at >= sqlc.narg('range_start')::timestamptz)
AND (sqlc.narg('range_end')::timestamptz IS NULL OR us.created_at < sqlc.narg('range_end')::timestamptz)
GROUP BY us.status
ORDER BY count DESC;
-- name: AnalyticsRevenueByPlan :many
SELECT
sp.name AS plan_name,
sp.currency,
COUNT(p.id)::bigint AS total_payments,
COALESCE(SUM(p.amount), 0)::float8 AS total_revenue
FROM payments p
JOIN subscription_plans sp ON sp.id = p.plan_id
WHERE p.status = 'SUCCESS'
AND (sqlc.narg('range_start')::timestamptz IS NULL OR COALESCE(p.paid_at, p.created_at) >= sqlc.narg('range_start')::timestamptz)
AND (sqlc.narg('range_end')::timestamptz IS NULL OR COALESCE(p.paid_at, p.created_at) < sqlc.narg('range_end')::timestamptz)
GROUP BY sp.name, sp.currency
ORDER BY total_revenue DESC;
-- name: AnalyticsNewSubscriptionsLast30Days :many
SELECT
d.date,
COUNT(us.id)::bigint AS count
FROM generate_series(
sqlc.arg('series_start')::date,
sqlc.arg('series_end')::date,
INTERVAL '1 day'
) AS d(date)
LEFT JOIN user_subscriptions us ON us.created_at::date = d.date
AND (sqlc.narg('range_start')::timestamptz IS NULL OR us.created_at >= sqlc.narg('range_start')::timestamptz)
AND (sqlc.narg('range_end')::timestamptz IS NULL OR us.created_at < sqlc.narg('range_end')::timestamptz)
GROUP BY d.date
ORDER BY d.date;
-- =====================
-- Payment Analytics
-- =====================
-- name: AnalyticsPaymentsSummary :one
SELECT
COALESCE(SUM(p.amount) FILTER (WHERE p.status = 'SUCCESS'), 0)::float8 AS total_revenue,
COALESCE(AVG(p.amount) FILTER (WHERE p.status = 'SUCCESS'), 0)::float8 AS avg_value,
COUNT(*)::bigint AS total_payments,
COUNT(*) FILTER (WHERE p.status = 'SUCCESS')::bigint AS successful_payments
FROM payments p
WHERE (sqlc.narg('range_start')::timestamptz IS NULL OR COALESCE(p.paid_at, p.created_at) >= sqlc.narg('range_start')::timestamptz)
AND (sqlc.narg('range_end')::timestamptz IS NULL OR COALESCE(p.paid_at, p.created_at) < sqlc.narg('range_end')::timestamptz);
-- name: AnalyticsPaymentsByStatus :many
SELECT
COALESCE(p.status, 'unknown') AS status,
COUNT(*)::bigint AS count,
COALESCE(SUM(p.amount), 0)::float8 AS total_amount
FROM payments p
WHERE (sqlc.narg('range_start')::timestamptz IS NULL OR COALESCE(p.paid_at, p.created_at) >= sqlc.narg('range_start')::timestamptz)
AND (sqlc.narg('range_end')::timestamptz IS NULL OR COALESCE(p.paid_at, p.created_at) < sqlc.narg('range_end')::timestamptz)
GROUP BY p.status
ORDER BY count DESC;
-- name: AnalyticsPaymentsByMethod :many
SELECT
COALESCE(p.payment_method, 'unknown') AS payment_method,
COUNT(*)::bigint AS count,
COALESCE(SUM(p.amount), 0)::float8 AS total_amount
FROM payments p
WHERE p.status = 'SUCCESS'
AND (sqlc.narg('range_start')::timestamptz IS NULL OR COALESCE(p.paid_at, p.created_at) >= sqlc.narg('range_start')::timestamptz)
AND (sqlc.narg('range_end')::timestamptz IS NULL OR COALESCE(p.paid_at, p.created_at) < sqlc.narg('range_end')::timestamptz)
GROUP BY p.payment_method
ORDER BY count DESC;
-- name: AnalyticsRevenueLast30Days :many
SELECT
d.date,
COALESCE(SUM(p.amount), 0)::float8 AS total_revenue
FROM generate_series(
sqlc.arg('series_start')::date,
sqlc.arg('series_end')::date,
INTERVAL '1 day'
) AS d(date)
LEFT JOIN payments p ON COALESCE(p.paid_at, p.created_at)::date = d.date
AND p.status = 'SUCCESS'
AND (sqlc.narg('range_start')::timestamptz IS NULL OR COALESCE(p.paid_at, p.created_at) >= sqlc.narg('range_start')::timestamptz)
AND (sqlc.narg('range_end')::timestamptz IS NULL OR COALESCE(p.paid_at, p.created_at) < sqlc.narg('range_end')::timestamptz)
GROUP BY d.date
ORDER BY d.date;
-- Monthly successful revenue for a calendar year (UTC buckets). Months with multiple currencies emit one row each; months with no revenue emit one row (currency ETB, revenue 0).
-- name: AnalyticsRevenueMonthlyByYear :many
WITH months AS (
SELECT bucket
FROM generate_series(
make_timestamptz(sqlc.arg('report_year')::int, 1, 1, 0, 0, 0, 'UTC'),
make_timestamptz(sqlc.arg('report_year')::int, 12, 1, 0, 0, 0, 'UTC'),
INTERVAL '1 month'
) AS gs(bucket)
),
by_month_currency AS (
SELECT
date_trunc('month', COALESCE(p.paid_at, p.created_at) AT TIME ZONE 'UTC') AS ym,
p.currency,
SUM(p.amount)::float8 AS total_revenue
FROM payments p
WHERE p.status = 'SUCCESS'
AND EXTRACT(YEAR FROM COALESCE(p.paid_at, p.created_at) AT TIME ZONE 'UTC')::int = sqlc.arg('report_year')::int
GROUP BY 1, 2
)
SELECT
(EXTRACT(MONTH FROM m.bucket AT TIME ZONE 'UTC'))::int AS month,
date_trunc('month', m.bucket AT TIME ZONE 'UTC')::date AS month_start,
COALESCE(b.currency, 'ETB'::varchar) AS currency,
COALESCE(b.total_revenue, 0)::float8 AS total_revenue
FROM months m
LEFT JOIN by_month_currency b ON b.ym = date_trunc('month', m.bucket AT TIME ZONE 'UTC')
ORDER BY m.bucket, COALESCE(b.currency, ''::varchar);
-- =====================
-- Course Analytics
-- =====================
-- LMS: programs -> courses -> modules -> lessons; lms_practices attach to course, module, or lesson.
-- Exam prep: exam_prep.catalog_courses -> units -> unit_modules -> unit_module_lessons; exam_prep.lesson_practices.
-- Legacy dashboard fields map to: programs, courses, modules, and video-bearing lessons (LMS + exam prep).
-- name: AnalyticsCourseCounts :one
SELECT
(SELECT COUNT(*)::bigint FROM programs) AS total_categories,
(SELECT COUNT(*)::bigint FROM courses) AS total_courses,
(SELECT COUNT(*)::bigint FROM modules) AS total_sub_courses,
(
COALESCE((SELECT COUNT(*)::bigint FROM lessons WHERE NULLIF(BTRIM(video_url), '') IS NOT NULL), 0::bigint)
+ COALESCE((SELECT COUNT(*)::bigint FROM exam_prep.unit_module_lessons WHERE NULLIF(BTRIM(video_url), '') IS NOT NULL), 0::bigint)
)::bigint AS total_videos,
(SELECT COUNT(*)::bigint FROM programs) AS lms_programs,
(SELECT COUNT(*)::bigint FROM courses) AS lms_courses,
(SELECT COUNT(*)::bigint FROM modules) AS lms_modules,
(SELECT COUNT(*)::bigint FROM lessons) AS lms_lessons,
(SELECT COUNT(*)::bigint FROM lessons WHERE NULLIF(BTRIM(video_url), '') IS NOT NULL) AS lms_lessons_with_video,
(SELECT COUNT(*)::bigint FROM lms_practices) AS lms_practices,
(SELECT COUNT(*)::bigint FROM lms_practices WHERE course_id IS NOT NULL) AS lms_practices_at_course,
(SELECT COUNT(*)::bigint FROM lms_practices WHERE module_id IS NOT NULL) AS lms_practices_at_module,
(SELECT COUNT(*)::bigint FROM lms_practices WHERE lesson_id IS NOT NULL) AS lms_practices_at_lesson,
(SELECT COUNT(*)::bigint FROM exam_prep.catalog_courses) AS exam_prep_catalog_courses,
(SELECT COUNT(*)::bigint FROM exam_prep.units) AS exam_prep_units,
(SELECT COUNT(*)::bigint FROM exam_prep.unit_modules) AS exam_prep_unit_modules,
(SELECT COUNT(*)::bigint FROM exam_prep.unit_module_lessons) AS exam_prep_lessons,
(SELECT COUNT(*)::bigint FROM exam_prep.unit_module_lessons WHERE NULLIF(BTRIM(video_url), '') IS NOT NULL) AS exam_prep_lessons_with_video,
(SELECT COUNT(*)::bigint FROM exam_prep.lesson_practices) AS exam_prep_lesson_practices;
-- =====================
-- Content Analytics
-- =====================
-- name: AnalyticsQuestionsCounts :one
SELECT
(
SELECT COUNT(*)::bigint
FROM questions q
WHERE (sqlc.narg('range_start')::timestamptz IS NULL OR q.created_at >= sqlc.narg('range_start')::timestamptz)
AND (sqlc.narg('range_end')::timestamptz IS NULL OR q.created_at < sqlc.narg('range_end')::timestamptz)
) AS total_questions,
(
SELECT COUNT(*)::bigint
FROM question_sets qs
WHERE (sqlc.narg('range_start')::timestamptz IS NULL OR qs.created_at >= sqlc.narg('range_start')::timestamptz)
AND (sqlc.narg('range_end')::timestamptz IS NULL OR qs.created_at < sqlc.narg('range_end')::timestamptz)
) AS total_question_sets;
-- name: AnalyticsQuestionsByType :many
SELECT
COALESCE(q.question_type, 'unknown') AS question_type,
COUNT(*)::bigint AS count
FROM questions q
WHERE (sqlc.narg('range_start')::timestamptz IS NULL OR q.created_at >= sqlc.narg('range_start')::timestamptz)
AND (sqlc.narg('range_end')::timestamptz IS NULL OR q.created_at < sqlc.narg('range_end')::timestamptz)
GROUP BY q.question_type
ORDER BY count DESC;
-- name: AnalyticsQuestionSetsByType :many
SELECT
COALESCE(qs.set_type, 'unknown') AS set_type,
COUNT(*)::bigint AS count
FROM question_sets qs
WHERE (sqlc.narg('range_start')::timestamptz IS NULL OR qs.created_at >= sqlc.narg('range_start')::timestamptz)
AND (sqlc.narg('range_end')::timestamptz IS NULL OR qs.created_at < sqlc.narg('range_end')::timestamptz)
GROUP BY qs.set_type
ORDER BY count DESC;
-- =====================
-- Notification Analytics
-- =====================
-- name: AnalyticsNotificationsSummary :one
SELECT
COUNT(*)::bigint AS total,
COUNT(*) FILTER (WHERE n.is_read = TRUE)::bigint AS read,
COUNT(*) FILTER (WHERE n.is_read = FALSE)::bigint AS unread
FROM notifications n
WHERE (sqlc.narg('range_start')::timestamptz IS NULL OR n.created_at >= sqlc.narg('range_start')::timestamptz)
AND (sqlc.narg('range_end')::timestamptz IS NULL OR n.created_at < sqlc.narg('range_end')::timestamptz);
-- name: AnalyticsNotificationsByChannel :many
SELECT
COALESCE(n.channel, 'unknown') AS channel,
COUNT(*)::bigint AS count
FROM notifications n
WHERE (sqlc.narg('range_start')::timestamptz IS NULL OR n.created_at >= sqlc.narg('range_start')::timestamptz)
AND (sqlc.narg('range_end')::timestamptz IS NULL OR n.created_at < sqlc.narg('range_end')::timestamptz)
GROUP BY n.channel
ORDER BY count DESC;
-- name: AnalyticsNotificationsByType :many
SELECT
COALESCE(n.type, 'unknown') AS type,
COUNT(*)::bigint AS count
FROM notifications n
WHERE (sqlc.narg('range_start')::timestamptz IS NULL OR n.created_at >= sqlc.narg('range_start')::timestamptz)
AND (sqlc.narg('range_end')::timestamptz IS NULL OR n.created_at < sqlc.narg('range_end')::timestamptz)
GROUP BY n.type
ORDER BY count DESC;
-- =====================
-- Issue Analytics
-- =====================
-- name: AnalyticsIssuesSummary :one
SELECT
COUNT(*)::bigint AS total,
COUNT(*) FILTER (WHERE ri.status = 'resolved')::bigint AS resolved,
CASE
WHEN COUNT(*) > 0 THEN (COUNT(*) FILTER (WHERE ri.status = 'resolved')::float8 / COUNT(*)::float8)
ELSE 0::float8
END AS resolution_rate
FROM reported_issues ri
WHERE (sqlc.narg('range_start')::timestamptz IS NULL OR ri.created_at >= sqlc.narg('range_start')::timestamptz)
AND (sqlc.narg('range_end')::timestamptz IS NULL OR ri.created_at < sqlc.narg('range_end')::timestamptz);
-- name: AnalyticsIssuesByStatus :many
SELECT
COALESCE(ri.status, 'unknown') AS status,
COUNT(*)::bigint AS count
FROM reported_issues ri
WHERE (sqlc.narg('range_start')::timestamptz IS NULL OR ri.created_at >= sqlc.narg('range_start')::timestamptz)
AND (sqlc.narg('range_end')::timestamptz IS NULL OR ri.created_at < sqlc.narg('range_end')::timestamptz)
GROUP BY ri.status
ORDER BY count DESC;
-- name: AnalyticsIssuesByType :many
SELECT
COALESCE(ri.issue_type, 'unknown') AS issue_type,
COUNT(*)::bigint AS count
FROM reported_issues ri
WHERE (sqlc.narg('range_start')::timestamptz IS NULL OR ri.created_at >= sqlc.narg('range_start')::timestamptz)
AND (sqlc.narg('range_end')::timestamptz IS NULL OR ri.created_at < sqlc.narg('range_end')::timestamptz)
GROUP BY ri.issue_type
ORDER BY count DESC;
-- =====================
-- Team Analytics
-- =====================
-- name: AnalyticsTeamSummary :one
SELECT
COUNT(*)::bigint AS total_members
FROM team_members tm
WHERE (sqlc.narg('range_start')::timestamptz IS NULL OR tm.created_at >= sqlc.narg('range_start')::timestamptz)
AND (sqlc.narg('range_end')::timestamptz IS NULL OR tm.created_at < sqlc.narg('range_end')::timestamptz);
-- name: AnalyticsTeamByRole :many
SELECT
COALESCE(tm.team_role, 'unknown') AS team_role,
COUNT(*)::bigint AS count
FROM team_members tm
WHERE (sqlc.narg('range_start')::timestamptz IS NULL OR tm.created_at >= sqlc.narg('range_start')::timestamptz)
AND (sqlc.narg('range_end')::timestamptz IS NULL OR tm.created_at < sqlc.narg('range_end')::timestamptz)
GROUP BY tm.team_role
ORDER BY count DESC;
-- name: AnalyticsTeamByStatus :many
SELECT
COALESCE(tm.status, 'unknown') AS status,
COUNT(*)::bigint AS count
FROM team_members tm
WHERE (sqlc.narg('range_start')::timestamptz IS NULL OR tm.created_at >= sqlc.narg('range_start')::timestamptz)
AND (sqlc.narg('range_end')::timestamptz IS NULL OR tm.created_at < sqlc.narg('range_end')::timestamptz)
GROUP BY tm.status
ORDER BY count DESC;