From 753e5560438646adb26d7c6d149721e822bba3c1 Mon Sep 17 00:00:00 2001 From: sumanvpacewisdom Date: Mon, 23 Feb 2026 16:11:15 +0530 Subject: [PATCH 1/9] Refactor SQL queries in migration file to improve readability and maintainability by standardizing indentation and formatting. This includes adjustments to tenant code conditions and session duration calculations. --- ...update-reports-queries-with-tenant-code.js | 977 ++++++++---------- 1 file changed, 447 insertions(+), 530 deletions(-) diff --git a/src/database/migrations/20251225065401-update-reports-queries-with-tenant-code.js b/src/database/migrations/20251225065401-update-reports-queries-with-tenant-code.js index 1a08b3320..458e1f3fd 100644 --- a/src/database/migrations/20251225065401-update-reports-queries-with-tenant-code.js +++ b/src/database/migrations/20251225065401-update-reports-queries-with-tenant-code.js @@ -8,7 +8,7 @@ module.exports = { 'report_queries', { query: `SELECT - COUNT(*) AS total_count, + COUNT(*) AS total_count, CASE WHEN 'All' = 'All' THEN COUNT(*) FILTER (WHERE Session.type = 'PUBLIC') -- Count for Public sessions @@ -26,7 +26,7 @@ module.exports = { ON sa.session_id = Session.id AND Session.tenant_code = sa.tenant_code WHERE - Session.tenant_code = :tenantCode + Session.tenant_code = :tenantCode AND (CASE WHEN :userId IS NOT NULL THEN sa.mentee_id = :userId ELSE TRUE END) AND sa.joined_at IS NOT NULL AND (CASE WHEN :start_date IS NOT NULL THEN Session.start_date > :start_date ELSE TRUE END) @@ -52,27 +52,27 @@ module.exports = { 'report_queries', { query: `SELECT - TO_CHAR( - INTERVAL '1 hour' * FLOOR(SUM(duration) / 3600) + - INTERVAL '1 minute' * FLOOR((SUM(duration) / 60)::BIGINT % 60) + - INTERVAL '1 second' * FLOOR(SUM(duration)::BIGINT % 60), - 'HH24:MI:SS' - ) AS total_hours, -- Total duration of all sessions - - TO_CHAR( - INTERVAL '1 hour' * FLOOR(SUM(CASE WHEN type = 'PUBLIC' THEN duration ELSE 0 END) / 3600) + - INTERVAL '1 minute' * FLOOR((SUM(CASE WHEN type = 'PUBLIC' THEN duration ELSE 0 END) / 60)::BIGINT % 60) + - INTERVAL '1 second' * FLOOR(SUM(CASE WHEN type = 'PUBLIC' THEN duration ELSE 0 END)::BIGINT % 60), - 'HH24:MI:SS' - ) AS public_hours, -- Total duration of public sessions - - TO_CHAR( - INTERVAL '1 hour' * FLOOR(SUM(CASE WHEN type = 'PRIVATE' THEN duration ELSE 0 END) / 3600) + - INTERVAL '1 minute' * FLOOR((SUM(CASE WHEN type = 'PRIVATE' THEN duration ELSE 0 END) / 60)::BIGINT % 60) + - INTERVAL '1 second' * FLOOR(SUM(CASE WHEN type = 'PRIVATE' THEN duration ELSE 0 END)::BIGINT % 60), - 'HH24:MI:SS' - ) AS private_hours -- Total duration of private sessions - + TO_CHAR( + INTERVAL '1 hour' * FLOOR(SUM(duration) / 3600) + + INTERVAL '1 minute' * FLOOR((SUM(duration) / 60)::BIGINT % 60) + + INTERVAL '1 second' * FLOOR(SUM(duration)::BIGINT % 60), + 'HH24:MI:SS' + ) AS total_hours, -- Total duration of all sessions + + TO_CHAR( + INTERVAL '1 hour' * FLOOR(SUM(CASE WHEN type = 'PUBLIC' THEN duration ELSE 0 END) / 3600) + + INTERVAL '1 minute' * FLOOR((SUM(CASE WHEN type = 'PUBLIC' THEN duration ELSE 0 END) / 60)::BIGINT % 60) + + INTERVAL '1 second' * FLOOR(SUM(CASE WHEN type = 'PUBLIC' THEN duration ELSE 0 END)::BIGINT % 60), + 'HH24:MI:SS' + ) AS public_hours, -- Total duration of public sessions + + TO_CHAR( + INTERVAL '1 hour' * FLOOR(SUM(CASE WHEN type = 'PRIVATE' THEN duration ELSE 0 END) / 3600) + + INTERVAL '1 minute' * FLOOR((SUM(CASE WHEN type = 'PRIVATE' THEN duration ELSE 0 END) / 60)::BIGINT % 60) + + INTERVAL '1 second' * FLOOR(SUM(CASE WHEN type = 'PRIVATE' THEN duration ELSE 0 END)::BIGINT % 60), + 'HH24:MI:SS' + ) AS private_hours -- Total duration of private sessions + FROM ( SELECT sa.session_id, @@ -85,23 +85,22 @@ module.exports = { ON sa.session_id = Session.id AND Session.tenant_code = sa.tenant_code WHERE - Session.tenant_code = :tenantCode + Session.tenant_code = :tenantCode AND (CASE WHEN :userId IS NOT NULL THEN sa.mentee_id = :userId ELSE TRUE END) - AND sa.joined_at IS NOT NULL - AND (CASE WHEN :start_date IS NOT NULL THEN Session.start_date > :start_date ELSE TRUE END) - AND (CASE WHEN :end_date IS NOT NULL THEN Session.end_date < :end_date ELSE TRUE END) - AND ( - CASE - WHEN :session_type = 'All' THEN Session.type IN ('PUBLIC', 'PRIVATE') - WHEN :session_type = 'Public' THEN Session.type = 'PUBLIC' - WHEN :session_type = 'Private' THEN Session.type = 'PRIVATE' - ELSE TRUE - END - ) - AND Session.deleted_at IS NULL - DYNAMIC_AND_CLAUSE - ) AS session_durations - `, + AND sa.joined_at IS NOT NULL + AND (CASE WHEN :start_date IS NOT NULL THEN Session.start_date > :start_date ELSE TRUE END) + AND (CASE WHEN :end_date IS NOT NULL THEN Session.end_date < :end_date ELSE TRUE END) + AND ( + CASE + WHEN :session_type = 'All' THEN Session.type IN ('PUBLIC', 'PRIVATE') + WHEN :session_type = 'Public' THEN Session.type = 'PUBLIC' + WHEN :session_type = 'Private' THEN Session.type = 'PRIVATE' + ELSE TRUE + END + ) + AND Session.deleted_at IS NULL + DYNAMIC_AND_CLAUSE + ) AS session_durations`, updated_at: Sequelize.literal('CURRENT_TIMESTAMP'), }, { report_code: 'total_hours_of_learning' }, @@ -112,57 +111,57 @@ module.exports = { 'report_queries', { query: `SELECT - :start_date AS startDate, - :end_date AS endDate, - -- Enrolled session counts + :start_date AS startDate, + :end_date AS endDate, + -- Enrolled session counts COUNT( - CASE - WHEN (sa.type = 'ENROLLED' OR sa.type = 'INVITED') - AND Session.type = 'PUBLIC' - AND (:session_type = 'All' OR :session_type = 'Public') - THEN 1 - END - ) AS public_session_enrolled, + CASE + WHEN (sa.type = 'ENROLLED' OR sa.type = 'INVITED') + AND Session.type = 'PUBLIC' + AND (:session_type = 'All' OR :session_type = 'Public') + THEN 1 + END + ) AS public_session_enrolled, - -- Private session enrolled count - COUNT( - CASE - WHEN (sa.type = 'ENROLLED' OR sa.type = 'INVITED') - AND Session.type = 'PRIVATE' - AND (:session_type = 'All' OR :session_type = 'Private') - THEN 1 - END - ) AS private_session_enrolled, + -- Private session enrolled count + COUNT( + CASE + WHEN (sa.type = 'ENROLLED' OR sa.type = 'INVITED') + AND Session.type = 'PRIVATE' + AND (:session_type = 'All' OR :session_type = 'Private') + THEN 1 + END + ) AS private_session_enrolled, - -- Public session attended count - COUNT( - CASE - WHEN sa.joined_at IS NOT NULL - AND Session.type = 'PUBLIC' - AND (:session_type = 'All' OR :session_type = 'Public') - THEN 1 - END - ) AS public_session_attended, + -- Public session attended count + COUNT( + CASE + WHEN sa.joined_at IS NOT NULL + AND Session.type = 'PUBLIC' + AND (:session_type = 'All' OR :session_type = 'Public') + THEN 1 + END + ) AS public_session_attended, - -- Private session attended count - COUNT( - CASE - WHEN sa.joined_at IS NOT NULL - AND Session.type = 'PRIVATE' - AND (:session_type = 'All' OR :session_type = 'Private') - THEN 1 - END - ) AS private_session_attended + -- Private session attended count + COUNT( + CASE + WHEN sa.joined_at IS NOT NULL + AND Session.type = 'PRIVATE' + AND (:session_type = 'All' OR :session_type = 'Private') + THEN 1 + END + ) AS private_session_attended FROM public.session_attendees AS sa JOIN public.sessions AS Session ON sa.session_id = Session.id AND Session.tenant_code = sa.tenant_code WHERE - Session.tenant_code = :tenantCode - AND (CASE WHEN :userId IS NOT NULL THEN sa.mentee_id = :userId ELSE TRUE END) - AND (CASE WHEN :start_date IS NOT NULL THEN Session.start_date > :start_date ELSE TRUE END) - AND (CASE WHEN :end_date IS NOT NULL THEN Session.end_date < :end_date ELSE TRUE END) - AND Session.deleted_at IS NULL - DYNAMIC_AND_CLAUSE;`, + Session.tenant_code = :tenantCode + AND (CASE WHEN :userId IS NOT NULL THEN sa.mentee_id = :userId ELSE TRUE END) + AND (CASE WHEN :start_date IS NOT NULL THEN Session.start_date > :start_date ELSE TRUE END) + AND (CASE WHEN :end_date IS NOT NULL THEN Session.end_date < :end_date ELSE TRUE END) + AND Session.deleted_at IS NULL + DYNAMIC_AND_CLAUSE;`, updated_at: Sequelize.literal('CURRENT_TIMESTAMP'), }, @@ -175,70 +174,36 @@ module.exports = { await queryInterface.bulkUpdate( 'report_queries', { - query: `WITH Session AS ( - SELECT - id, - title, - created_by, - mentor_name, - start_date, - end_date, - type, - categories, - recommended_for, - deleted_at, - tenant_code - FROM - public.sessions - ), - UserExtensions AS ( - SELECT - user_id, - name, - tenant_code - FROM - public.user_extensions - ), - SessionAttendees AS ( - SELECT - session_id, - mentee_id, - joined_at, - created_at, - tenant_code - FROM - public.session_attendees + query: `SELECT + s.title AS "sessions_title", + ue.name AS "sessions_created_by", + s.mentor_name AS "mentor_name", + TO_TIMESTAMP(s.start_date)::DATE AS "date_of_session", + s.type AS "session_type", + s.categories AS "categories", + s.recommended_for AS "recommended_for", + s.deleted_at, + CASE WHEN sa.joined_at IS NOT NULL THEN 'Yes' ELSE 'No' END AS "session_attended", + ROUND(EXTRACT(EPOCH FROM (TO_TIMESTAMP(s.end_date) - TO_TIMESTAMP(s.start_date))) / 60) AS "duration_of_sessions_attended_in_minutes", + s.tenant_code + FROM + public.sessions s + LEFT JOIN + public.user_extensions ue ON s.created_by = ue.user_id AND s.tenant_code = ue.tenant_code + JOIN + public.session_attendees sa ON sa.session_id = s.id AND sa.tenant_code = s.tenant_code + WHERE + s.tenant_code = :tenantCode + AND (:userId IS NULL OR sa.mentee_id = :userId) + AND (:start_date IS NULL OR s.start_date > :start_date) + AND (:end_date IS NULL OR s.end_date < :end_date) + AND ( + (:session_type = 'All' AND s.type IN ('PUBLIC', 'PRIVATE')) + OR (:session_type = 'PUBLIC' AND s.type = 'PUBLIC') + OR (:session_type = 'PRIVATE' AND s.type = 'PRIVATE') ) - SELECT - Session.title AS "sessions_title", - ue.name AS "sessions_created_by", - Session.mentor_name AS "mentor_name", - TO_TIMESTAMP(Session.start_date)::DATE AS "date_of_session", - Session.type AS "session_type", - Session.categories AS "categories", - Session.recommended_for AS "recommended_for", - CASE WHEN sa.joined_at IS NOT NULL THEN 'Yes' ELSE 'No' END AS "session_attended", - ROUND(EXTRACT(EPOCH FROM (TO_TIMESTAMP(Session.end_date)-TO_TIMESTAMP(Session.start_date)))/60) AS "duration_of_sessions_attended_in_minutes", - sa.created_at, - Session.tenant_code - FROM - Session - LEFT JOIN - UserExtensions AS ue ON Session.created_by = ue.user_id AND Session.tenant_code = ue.tenant_code - JOIN - SessionAttendees AS sa ON sa.session_id = Session.id AND sa.tenant_code = Session.tenant_code - WHERE - Session.tenant_code = :tenantCode - AND (:userId IS NULL OR sa.mentee_id = :userId) - AND (:start_date IS NULL OR Session.start_date > :start_date) - AND (:end_date IS NULL OR Session.end_date < :end_date) - AND ( - :session_type = 'All' AND Session.type IN ('PUBLIC', 'PRIVATE') - OR :session_type = 'PUBLIC' AND Session.type = 'PUBLIC' - OR :session_type = 'PRIVATE' AND Session.type = 'PRIVATE' - ) - AND Session.deleted_at IS NULL - DYNAMIC_AND_CLAUSE order by Session.start_date ASC`, + AND s.deleted_at IS NULL + DYNAMIC_AND_CLAUSE;`, updated_at: Sequelize.literal('CURRENT_TIMESTAMP'), }, { @@ -251,33 +216,24 @@ module.exports = { 'report_queries', { query: `SELECT - COUNT(*) AS total_count, - COUNT(CASE WHEN Session.type = 'PUBLIC' AND ('All' = 'All' OR 'All' = 'PUBLIC') THEN 1 END) AS public_count, - COUNT(CASE WHEN Session.type = 'PRIVATE' AND ('All' = 'All' OR 'All' = 'PRIVATE') THEN 1 END) AS private_count - FROM ( - SELECT - * - FROM - public.sessions AS Session - WHERE - Session.started_at IS NOT NULL - AND Session.start_date > :start_date - AND Session.end_date < :end_date - AND ( - CASE - WHEN :session_type = 'All' THEN Session.type IN ('PUBLIC', 'PRIVATE') - WHEN :session_type = 'PUBLIC' THEN Session.type = 'PUBLIC' - WHEN :session_type = 'PRIVATE' THEN Session.type = 'PRIVATE' - ELSE TRUE - END - ) - ) AS Session - JOIN - public.session_ownerships AS so ON so.session_id = Session.id + COUNT(*) AS total_count, + COUNT(CASE WHEN Session.type = 'PUBLIC' THEN 1 END) AS public_count, + COUNT(CASE WHEN Session.type = 'PRIVATE' THEN 1 END) AS private_count + FROM public.sessions AS Session WHERE Session.tenant_code = :tenantCode - AND so.user_id = :userId - AND ('MENTOR' IS NULL OR so.type = 'MENTOR') + AND Session.mentor_id = :userId + AND Session.status = 'COMPLETED' + AND Session.start_date > :start_date + AND Session.end_date < :end_date + AND ( + CASE + WHEN :session_type = 'All' THEN Session.type IN ('PUBLIC', 'PRIVATE') + WHEN :session_type = 'PUBLIC' THEN Session.type = 'PUBLIC' + WHEN :session_type = 'PRIVATE' THEN Session.type = 'PRIVATE' + ELSE TRUE + END + ) AND Session.deleted_at IS NULL DYNAMIC_AND_CLAUSE;`, updated_at: Sequelize.literal('CURRENT_TIMESTAMP'), @@ -291,117 +247,108 @@ module.exports = { await queryInterface.bulkUpdate( 'report_queries', { - query: `WITH filtered_ownerships AS ( - SELECT so.session_id - FROM public.session_ownerships so - WHERE - so.user_id = :userId - AND so.type = 'MENTOR' - ) - - SELECT - -- Total duration (sum of both public and private sessions) - COALESCE( - TO_CHAR( - INTERVAL '1 hour' * FLOOR(SUM( - CASE - WHEN Session.type IN ('PUBLIC', 'PRIVATE') - THEN EXTRACT(EPOCH FROM (Session.completed_at - Session.started_at)) - ELSE 0 - END - ) / 3600) + - INTERVAL '1 minute' * FLOOR((SUM( - CASE - WHEN Session.type IN ('PUBLIC', 'PRIVATE') - THEN EXTRACT(EPOCH FROM (Session.completed_at - Session.started_at)) - ELSE 0 - END - ) / 60)::BIGINT % 60) + - INTERVAL '1 second' * FLOOR(SUM( - CASE - WHEN Session.type IN ('PUBLIC', 'PRIVATE') - THEN EXTRACT(EPOCH FROM (Session.completed_at - Session.started_at)) - ELSE 0 - END - )::BIGINT % 60), - 'HH24:MI:SS' - ), - '00:00:00' - ) AS total_hours, - - -- Duration for public sessions - COALESCE( - TO_CHAR( - INTERVAL '1 hour' * FLOOR(SUM( - CASE - WHEN Session.type = 'PUBLIC' - THEN EXTRACT(EPOCH FROM (Session.completed_at - Session.started_at)) - ELSE 0 - END - ) / 3600) + - INTERVAL '1 minute' * FLOOR((SUM( - CASE - WHEN Session.type = 'PUBLIC' - THEN EXTRACT(EPOCH FROM (Session.completed_at - Session.started_at)) - ELSE 0 - END - ) / 60)::BIGINT % 60) + - INTERVAL '1 second' * FLOOR(SUM( - CASE - WHEN Session.type = 'PUBLIC' - THEN EXTRACT(EPOCH FROM (Session.completed_at - Session.started_at)) - ELSE 0 - END - )::BIGINT % 60), - 'HH24:MI:SS' - ), - '00:00:00' - ) AS public_hours, - - -- Duration for private sessions - COALESCE( - TO_CHAR( - INTERVAL '1 hour' * FLOOR(SUM( - CASE - WHEN Session.type = 'PRIVATE' - THEN EXTRACT(EPOCH FROM (Session.completed_at - Session.started_at)) - ELSE 0 - END - ) / 3600) + - INTERVAL '1 minute' * FLOOR((SUM( - CASE - WHEN Session.type = 'PRIVATE' - THEN EXTRACT(EPOCH FROM (Session.completed_at - Session.started_at)) - ELSE 0 - END - ) / 60)::BIGINT % 60) + - INTERVAL '1 second' * FLOOR(SUM( - CASE - WHEN Session.type = 'PRIVATE' - THEN EXTRACT(EPOCH FROM (Session.completed_at - Session.started_at)) - ELSE 0 - END - )::BIGINT % 60), - 'HH24:MI:SS' - ), - '00:00:00' - ) AS private_hours - - FROM filtered_ownerships fo - JOIN public.sessions Session ON Session.id = fo.session_id -- Renamed alias from session to Session - WHERE - Session.tenant_code = :tenantCode - AND Session.started_at IS NOT NULL - AND Session.start_date > :start_date -- Start date filter - AND Session.end_date < :end_date -- End date filter + query: `SELECT + -- Total duration (sum of both public and private sessions) + COALESCE( + TO_CHAR( + INTERVAL '1 hour' * FLOOR(SUM( + CASE + WHEN Session.type IN ('PUBLIC', 'PRIVATE') + THEN EXTRACT(EPOCH FROM (Session.completed_at - Session.started_at)) + ELSE 0 + END + ) / 3600) + + INTERVAL '1 minute' * FLOOR((SUM( + CASE + WHEN Session.type IN ('PUBLIC', 'PRIVATE') + THEN EXTRACT(EPOCH FROM (Session.completed_at - Session.started_at)) + ELSE 0 + END + ) / 60)::BIGINT % 60) + + INTERVAL '1 second' * FLOOR(SUM( + CASE + WHEN Session.type IN ('PUBLIC', 'PRIVATE') + THEN EXTRACT(EPOCH FROM (Session.completed_at - Session.started_at)) + ELSE 0 + END + )::BIGINT % 60), + 'HH24:MI:SS' + ), + '00:00:00' + ) AS total_hours, + + -- Duration for public sessions + COALESCE( + TO_CHAR( + INTERVAL '1 hour' * FLOOR(SUM( + CASE + WHEN Session.type = 'PUBLIC' + THEN EXTRACT(EPOCH FROM (Session.completed_at - Session.started_at)) + ELSE 0 + END + ) / 3600) + + INTERVAL '1 minute' * FLOOR((SUM( + CASE + WHEN Session.type = 'PUBLIC' + THEN EXTRACT(EPOCH FROM (Session.completed_at - Session.started_at)) + ELSE 0 + END + ) / 60)::BIGINT % 60) + + INTERVAL '1 second' * FLOOR(SUM( + CASE + WHEN Session.type = 'PUBLIC' + THEN EXTRACT(EPOCH FROM (Session.completed_at - Session.started_at)) + ELSE 0 + END + )::BIGINT % 60), + 'HH24:MI:SS' + ), + '00:00:00' + ) AS public_hours, + + -- Duration for private sessions + COALESCE( + TO_CHAR( + INTERVAL '1 hour' * FLOOR(SUM( + CASE + WHEN Session.type = 'PRIVATE' + THEN EXTRACT(EPOCH FROM (Session.completed_at - Session.started_at)) + ELSE 0 + END + ) / 3600) + + INTERVAL '1 minute' * FLOOR((SUM( + CASE + WHEN Session.type = 'PRIVATE' + THEN EXTRACT(EPOCH FROM (Session.completed_at - Session.started_at)) + ELSE 0 + END + ) / 60)::BIGINT % 60) + + INTERVAL '1 second' * FLOOR(SUM( + CASE + WHEN Session.type = 'PRIVATE' + THEN EXTRACT(EPOCH FROM (Session.completed_at - Session.started_at)) + ELSE 0 + END + )::BIGINT % 60), + 'HH24:MI:SS' + ), + '00:00:00' + ) AS private_hours + + FROM public.sessions Session + WHERE Session.tenant_code = :tenantCode + AND Session.mentor_id = :userId + AND Session.status = 'COMPLETED' + AND Session.start_date > :start_date + AND Session.end_date < :end_date AND ( - CASE - WHEN :session_type = 'All' THEN Session.type IN ('PUBLIC', 'PRIVATE') -- If all types, include both - WHEN :session_type = 'PUBLIC' THEN Session.type = 'PUBLIC' -- If PUBLIC, only include public - WHEN :session_type = 'PRIVATE' THEN Session.type = 'PRIVATE' -- If PRIVATE, only include private - ELSE TRUE -- Default condition - END - ) + CASE + WHEN :session_type = 'All' THEN Session.type IN ('PUBLIC', 'PRIVATE') + WHEN :session_type = 'PUBLIC' THEN Session.type = 'PUBLIC' + WHEN :session_type = 'PRIVATE' THEN Session.type = 'PRIVATE' + ELSE TRUE + END + ) AND Session.deleted_at IS NULL DYNAMIC_AND_CLAUSE;`, updated_at: Sequelize.literal('CURRENT_TIMESTAMP'), @@ -416,104 +363,84 @@ module.exports = { 'report_queries', { query: `SELECT - :start_date AS startDate, - :end_date AS endDate, - - -- Total sessions created - COUNT(DISTINCT CASE - WHEN ( - (so.type = 'CREATOR' OR so.type = 'MENTOR') - AND ( - :session_type = 'All' - OR (:session_type = 'Public' AND session.type = 'PUBLIC') - OR (:session_type = 'Private' AND session.type = 'PRIVATE') - ) - AND ( - (session.created_by!= :userId AND session.mentor_id = :userId) - OR (session.created_by = :userId AND session.mentor_id = :userId) - ) - ) - THEN session.id - END) AS total_sessions_created, - - -- PUBLIC sessions created - COUNT(DISTINCT CASE - WHEN ( - (so.type = 'CREATOR' OR so.type = 'MENTOR') - AND session.type = 'PUBLIC' - AND (:session_type = 'All' OR :session_type = 'Public') - AND ( - (session.created_by!= :userId AND session.mentor_id = :userId) - OR (session.created_by = :userId AND session.mentor_id = :userId) - ) - ) - THEN session.id - END) AS public_sessions_created, - - -- PRIVATE sessions created - COUNT(DISTINCT CASE - WHEN ( - (so.type = 'CREATOR' OR so.type = 'MENTOR') - AND session.type = 'PRIVATE' - AND (:session_type = 'All' OR :session_type = 'Private') - AND ( - (session.created_by!= :userId AND session.mentor_id = :userId) - OR (session.created_by = :userId AND session.mentor_id = :userId) - ) - ) - THEN session.id - END) AS private_sessions_created, - - -- Total sessions conducted - COUNT(DISTINCT CASE - WHEN ( - so.type = 'MENTOR' - AND session.started_at IS NOT NULL - AND ( - :session_type = 'All' - OR (:session_type = 'Public' AND session.type = 'PUBLIC') - OR (:session_type = 'Private' AND session.type = 'PRIVATE') - ) - ) - THEN session.id - END) AS total_sessions_conducted, - - -- PUBLIC sessions conducted - COUNT(DISTINCT CASE - WHEN ( - so.type = 'MENTOR' - AND session.started_at IS NOT NULL - AND session.type = 'PUBLIC' - AND (:session_type = 'All' OR :session_type = 'Public') + :start_date AS startDate, + :end_date AS endDate, + + -- Total sessions created + COUNT(DISTINCT CASE + WHEN ( + (session.created_by = :userId OR session.mentor_id = :userId) + AND ( + :session_type = 'All' + OR (:session_type = 'Public' AND session.type = 'PUBLIC') + OR (:session_type = 'Private' AND session.type = 'PRIVATE') ) - THEN session.id - END) AS public_sessions_conducted, - - -- PRIVATE sessions conducted - COUNT(DISTINCT CASE - WHEN ( - so.type = 'MENTOR' - AND session.started_at IS NOT NULL - AND session.type = 'PRIVATE' - AND (:session_type = 'All' OR :session_type = 'Private') + ) + THEN session.id + END) AS total_sessions_created, + + -- PUBLIC sessions created + COUNT(DISTINCT CASE + WHEN ( + (session.created_by = :userId OR session.mentor_id = :userId) + AND session.type = 'PUBLIC' + AND (:session_type = 'All' OR :session_type = 'Public') + ) + THEN session.id + END) AS public_sessions_created, + + -- PRIVATE sessions created + COUNT(DISTINCT CASE + WHEN ( + (session.created_by = :userId OR session.mentor_id = :userId) + AND session.type = 'PRIVATE' + AND (:session_type = 'All' OR :session_type = 'Private') + ) + THEN session.id + END) AS private_sessions_created, + + -- Total sessions conducted + COUNT(DISTINCT CASE + WHEN ( + session.mentor_id = :userId + AND session.status = 'COMPLETED' + AND ( + :session_type = 'All' + OR (:session_type = 'Public' AND session.type = 'PUBLIC') + OR (:session_type = 'Private' AND session.type = 'PRIVATE') ) - THEN session.id - END) AS private_sessions_conducted - - FROM ( - SELECT - * - FROM - public.sessions - WHERE - (public.sessions.start_date > :start_date OR :start_date IS NULL) - AND (public.sessions.end_date < :end_date OR :end_date IS NULL) - ) AS session - JOIN - public.session_ownerships AS so ON so.session_id = session.id + ) + THEN session.id + END) AS total_sessions_conducted, + + -- PUBLIC sessions conducted + COUNT(DISTINCT CASE + WHEN ( + session.mentor_id = :userId + AND session.status = 'COMPLETED' + AND session.type = 'PUBLIC' + AND (:session_type = 'All' OR :session_type = 'Public') + ) + THEN session.id + END) AS public_sessions_conducted, + + -- PRIVATE sessions conducted + COUNT(DISTINCT CASE + WHEN ( + session.mentor_id = :userId + AND session.status = 'COMPLETED' + AND session.type = 'PRIVATE' + AND (:session_type = 'All' OR :session_type = 'Private') + ) + THEN session.id + END) AS private_sessions_conducted + + FROM public.sessions AS session WHERE session.tenant_code = :tenantCode - AND (:userId IS NOT NULL AND so.user_id = :userId OR :userId IS NULL) + AND (session.start_date > :start_date OR :start_date IS NULL) + AND (session.end_date < :end_date OR :end_date IS NULL) + AND (:userId IS NOT NULL) AND session.deleted_at IS NULL DYNAMIC_AND_CLAUSE;`, updated_at: Sequelize.literal('CURRENT_TIMESTAMP'), @@ -528,20 +455,21 @@ module.exports = { 'report_queries', { query: `SELECT - session.title AS "sessions_title", - ue.name AS "sessions_created_by", - session.seats_limit-session.seats_remaining AS "number_of_mentees", - TO_TIMESTAMP(session.start_date)::DATE AS "date_of_session", - session.type AS "session_type", - CASE WHEN session.started_at IS NOT NULL THEN 'Yes' ELSE 'No' END AS "session_conducted", - ROUND(EXTRACT(EPOCH FROM(TO_TIMESTAMP(session.end_date)-TO_TIMESTAMP(session.start_date)))/60) AS "duration_of_sessions_attended_in_minutes" - FROM (SELECT * FROM public.sessions WHERE start_date > :start_date AND end_date < :end_date) AS session - JOIN - (SELECT * FROM public.session_ownerships WHERE user_id = :userId AND type = 'MENTOR') AS so ON session.id = so.session_id + session.title AS "sessions_title", + ue.name AS "sessions_created_by", + session.seats_limit-session.seats_remaining AS "number_of_mentees", + TO_TIMESTAMP(session.start_date)::DATE AS "date_of_session", + session.type AS "session_type", + CASE WHEN session.started_at IS NOT NULL THEN 'Yes' ELSE 'No' END AS "session_conducted", + ROUND(EXTRACT(EPOCH FROM(TO_TIMESTAMP(session.end_date)-TO_TIMESTAMP(session.start_date)))/60) AS "duration_of_sessions_attended_in_minutes" + FROM public.sessions AS session LEFT JOIN public.user_extensions AS ue ON session.created_by = ue.user_id AND session.tenant_code = ue.tenant_code WHERE session.tenant_code = :tenantCode + AND session.mentor_id = :userId + AND session.start_date > :start_date + AND session.end_date < :end_date AND ( CASE WHEN :session_type = 'All' THEN session.type IN ('PUBLIC', 'PRIVATE') @@ -551,7 +479,7 @@ module.exports = { END ) AND session.deleted_at IS NULL - DYNAMIC_AND_CLAUSE`, + DYNAMIC_AND_CLAUSE;`, updated_at: Sequelize.literal('CURRENT_TIMESTAMP'), }, { @@ -564,35 +492,28 @@ module.exports = { 'report_queries', { query: `SELECT - TO_CHAR( - INTERVAL '1 second' * FLOOR(SUM(EXTRACT(EPOCH FROM (completed_at - started_at)))), - 'HH24:MI:SS' - ) AS total_hours, - - TO_CHAR( - INTERVAL '1 second' * FLOOR(SUM(CASE WHEN Session.type = 'PUBLIC' THEN EXTRACT(EPOCH FROM (completed_at - started_at)) ELSE 0 END)), - 'HH24:MI:SS' - ) AS total_public_hours, - - TO_CHAR( - INTERVAL '1 second' * FLOOR(SUM(CASE WHEN Session.type = 'PRIVATE' THEN EXTRACT(EPOCH FROM (completed_at - started_at)) ELSE 0 END)), - 'HH24:MI:SS' - ) AS total_private_hours - - FROM - (SELECT * FROM public.sessions - WHERE - public.sessions.start_date > :start_date - AND public.sessions.end_date < :end_date) AS Session - JOIN - (SELECT * - FROM public.session_ownerships - WHERE public.session_ownerships.user_id = :userId - AND public.session_ownerships.type = 'CREATOR') AS so - ON Session.id = so.session_id + TO_CHAR( + INTERVAL '1 second' * FLOOR(SUM(EXTRACT(EPOCH FROM (completed_at - started_at)))), + 'HH24:MI:SS' + ) AS total_hours, + + TO_CHAR( + INTERVAL '1 second' * FLOOR(SUM(CASE WHEN Session.type = 'PUBLIC' THEN EXTRACT(EPOCH FROM (completed_at - started_at)) ELSE 0 END)), + 'HH24:MI:SS' + ) AS total_public_hours, + + TO_CHAR( + INTERVAL '1 second' * FLOOR(SUM(CASE WHEN Session.type = 'PRIVATE' THEN EXTRACT(EPOCH FROM (completed_at - started_at)) ELSE 0 END)), + 'HH24:MI:SS' + ) AS total_private_hours + + FROM public.sessions AS Session WHERE - -- Simplified the CASE logic for filtering session types - Session.tenant_code = :tenantCode + Session.tenant_code = :tenantCode + AND Session.created_by = :userId + AND Session.status = 'COMPLETED' + AND Session.start_date > :start_date + AND Session.end_date < :end_date AND ( CASE WHEN :session_type = 'All' THEN TRUE @@ -615,36 +536,29 @@ module.exports = { 'report_queries', { query: `SELECT - TO_CHAR( - INTERVAL '1 second' * FLOOR(SUM(EXTRACT(EPOCH FROM (completed_at - started_at)))), - 'HH24:MI:SS' - ) AS total_hours, - - TO_CHAR( - INTERVAL '1 second' * FLOOR(SUM(CASE WHEN Session.type = 'PUBLIC' THEN EXTRACT(EPOCH FROM (completed_at - started_at)) ELSE 0 END)), - 'HH24:MI:SS' - ) AS public_hours, - - TO_CHAR( - INTERVAL '1 second' * FLOOR(SUM(CASE WHEN Session.type = 'PRIVATE' THEN EXTRACT(EPOCH FROM (completed_at - started_at)) ELSE 0 END)), - 'HH24:MI:SS' - ) AS private_hours - - FROM - (SELECT * FROM public.sessions - WHERE public.sessions.started_at IS NOT NULL - AND public.sessions.start_date > :start_date - AND public.sessions.end_date < :end_date) AS Session - JOIN - (SELECT * - FROM public.session_ownerships - WHERE public.session_ownerships.user_id = :userId - AND public.session_ownerships.type = 'MENTOR') AS so - ON Session.id = so.session_id + TO_CHAR( + INTERVAL '1 second' * FLOOR(SUM(EXTRACT(EPOCH FROM (completed_at - started_at)))), + 'HH24:MI:SS' + ) AS total_hours, + + TO_CHAR( + INTERVAL '1 second' * FLOOR(SUM(CASE WHEN Session.type = 'PUBLIC' THEN EXTRACT(EPOCH FROM (completed_at - started_at)) ELSE 0 END)), + 'HH24:MI:SS' + ) AS public_hours, + + TO_CHAR( + INTERVAL '1 second' * FLOOR(SUM(CASE WHEN Session.type = 'PRIVATE' THEN EXTRACT(EPOCH FROM (completed_at - started_at)) ELSE 0 END)), + 'HH24:MI:SS' + ) AS private_hours + + FROM public.sessions AS Session WHERE - -- Simplified the CASE logic for filtering session types - Session.tenant_code = :tenantCode - AND( + Session.tenant_code = :tenantCode + AND Session.mentor_id = :userId + AND Session.status = 'COMPLETED' + AND Session.start_date > :start_date + AND Session.end_date < :end_date + AND ( CASE WHEN :session_type = 'All' THEN TRUE WHEN :session_type = 'PUBLIC' THEN Session.type = 'PUBLIC' @@ -666,78 +580,71 @@ module.exports = { 'report_queries', { query: `SELECT - :start_date AS startDate, - :end_date AS endDate, - - -- Count session_created - COUNT(*) FILTER ( - WHERE so.type = 'CREATOR' - AND ( - :session_type = 'All' - OR (:session_type = 'Public' AND session.type = 'PUBLIC') - OR (:session_type = 'Private' AND session.type = 'PRIVATE') - ) - ) AS total_session_created, - - -- Total sessions conducted (all types combined) - COUNT(*) FILTER ( - WHERE so.type = 'MENTOR' - AND session.started_at IS NOT NULL - AND ( - :session_type = 'All' - OR :session_type = 'Public' AND session.type = 'PUBLIC' - OR :session_type = 'Private' AND session.type = 'PRIVATE' - ) - ) AS total_sessions_conducted, - - -- Public sessions conducted - COUNT(*) FILTER ( - WHERE so.type = 'MENTOR' - AND session.started_at IS NOT NULL - AND :session_type IN ('All', 'Public') - AND session.type = 'PUBLIC' - ) AS public_sessions_conducted, - - -- Private sessions conducted - COUNT(*) FILTER ( - WHERE so.type = 'MENTOR' - AND session.started_at IS NOT NULL - AND :session_type IN ('All', 'Private') - AND session.type = 'PRIVATE' - ) AS private_sessions_conducted, - - -- Public sessions created - COUNT(*) FILTER ( - WHERE so.type = 'CREATOR' - AND :session_type IN ('All', 'Public') - AND session.type = 'PUBLIC' - ) AS public_sessions_created, - - -- Private sessions created - COUNT(*) FILTER ( - WHERE so.type = 'CREATOR' - AND :session_type IN ('All', 'Private') - AND session.type = 'PRIVATE' - ) AS private_sessions_created + :start_date AS startDate, + :end_date AS endDate, - FROM - (SELECT * FROM public.sessions WHERE (public.sessions.start_date > :start_date OR :start_date IS NULL) AND (public.sessions.end_date < :end_date OR :end_date IS NULL)) AS session - JOIN - (SELECT * - FROM public.session_ownerships - WHERE (:userId IS NOT NULL AND user_id = :userId OR :userId IS NULL) - AND type IN ('CREATOR', 'MENTOR') - ORDER BY public.session_ownerships.session_id, public.session_ownerships.user_id, public.session_ownerships.type -- Updated to match DISTINCT ON - ) AS so - ON session.id = so.session_id + -- Total sessions created + COUNT(*) FILTER ( + WHERE ( + :session_type = 'All' + OR (:session_type = 'Public' AND s.type = 'PUBLIC') + OR (:session_type = 'Private' AND s.type = 'PRIVATE') + ) + AND (:userId IS NULL OR s.created_by = :userId) + ) AS total_session_created, + + -- Total sessions conducted + COUNT(*) FILTER ( + WHERE s.status = 'COMPLETED' + AND ( + :session_type = 'All' + OR (:session_type = 'Public' AND s.type = 'PUBLIC') + OR (:session_type = 'Private' AND s.type = 'PRIVATE') + ) + AND (:userId IS NULL OR s.mentor_id = :userId) + ) AS total_sessions_conducted, + + -- Public sessions conducted + COUNT(*) FILTER ( + WHERE s.status = 'COMPLETED' + AND s.type = 'PUBLIC' + AND :session_type IN ('All', 'Public') + AND (:userId IS NULL OR s.mentor_id = :userId) + ) AS public_sessions_conducted, + + -- Private sessions conducted + COUNT(*) FILTER ( + WHERE s.status = 'COMPLETED' + AND s.type = 'PRIVATE' + AND :session_type IN ('All', 'Private') + AND (:userId IS NULL OR s.mentor_id = :userId) + ) AS private_sessions_conducted, + + -- Public sessions created + COUNT(*) FILTER ( + WHERE s.type = 'PUBLIC' + AND :session_type IN ('All', 'Public') + AND (:userId IS NULL OR s.created_by = :userId) + ) AS public_sessions_created, + + -- Private sessions created + COUNT(*) FILTER ( + WHERE s.type = 'PRIVATE' + AND :session_type IN ('All', 'Private') + AND (:userId IS NULL OR s.created_by = :userId) + ) AS private_sessions_created + + FROM public.sessions s WHERE - session.tenant_code = :tenantCode - AND ( + s.tenant_code = :tenantCode + AND (:start_date IS NULL OR s.start_date > :start_date) + AND (:end_date IS NULL OR s.end_date < :end_date) + AND ( :session_type = 'All' OR :session_type = 'Public' OR :session_type = 'Private' ) - AND session.deleted_at IS NULL + AND s.deleted_at IS NULL DYNAMIC_AND_CLAUSE;`, updated_at: Sequelize.literal('CURRENT_TIMESTAMP'), }, @@ -751,34 +658,44 @@ module.exports = { 'report_queries', { query: `WITH - session_count AS ( + session_count AS ( SELECT - session.tenant_code, - session.mentor_id, session.mentor_name, COUNT(*) AS number_of_sessions, - TO_CHAR( INTERVAL '1 second' * ROUND(SUM(EXTRACT(EPOCH FROM (session.completed_at - session.started_at)))), - 'HH24:MI:SS' - ) AS "hours_of_mentoring_sessions" - FROM public.sessions AS session WHERE - session.tenant_code = :tenantCode AND deleted_at IS NULL AND session.created_by = :userId AND session.started_at IS NOT NULL AND session.completed_at IS NOT NULL AND session.start_date > :start_date AND session.end_date < :end_date AND (CASE - WHEN :session_type = 'All' THEN session.type IN ('PUBLIC', 'PRIVATE') - WHEN :session_type = 'Public' THEN session.type = 'PUBLIC' - WHEN :session_type = 'Private' THEN session.type = 'PRIVATE' - ELSE TRUE - END - ) + session.tenant_code, + session.mentor_id, + session.mentor_name, + COUNT(*) AS number_of_sessions, + TO_CHAR( + INTERVAL '1 second' * ROUND(SUM(EXTRACT(EPOCH FROM (session.completed_at - session.started_at)))), + 'HH24:MI:SS' + ) AS "hours_of_mentoring_sessions" + FROM public.sessions AS session + WHERE session.tenant_code = :tenantCode + AND session.created_by = :userId + AND session.started_at IS NOT NULL + AND session.completed_at IS NOT NULL + AND session.start_date > :start_date + AND session.end_date < :end_date + AND ( + CASE + WHEN :session_type = 'All' THEN session.type IN ('PUBLIC', 'PRIVATE') + WHEN :session_type = 'Public' THEN session.type = 'PUBLIC' + WHEN :session_type = 'Private' THEN session.type = 'PRIVATE' + ELSE TRUE + END + ) + AND session.deleted_at IS NULL GROUP BY session.tenant_code, session.mentor_id, session.mentor_name ) SELECT - sc.tenant_code, - sc.mentor_name as mentor_name , - sc.number_of_sessions as number_of_mentoring_sessions, - sc.hours_of_mentoring_sessions as hours_of_mentoring_sessions, - COALESCE(CAST(ue.rating ->>'average'AS NUMERIC),0) AS avg_mentor_rating + sc.tenant_code, + sc.mentor_name as mentor_name , + sc.number_of_sessions as number_of_mentoring_sessions, + sc.hours_of_mentoring_sessions as hours_of_mentoring_sessions, + COALESCE(CAST(ue.rating ->>'average' AS NUMERIC),0) AS avg_mentor_rating FROM session_count AS sc - JOIN public.user_extensions AS ue ON sc.mentor_id = ue.user_id AND sc.tenant_code = ue.tenant_code + JOIN public.user_extensions AS ue ON sc.mentor_id = ue.user_id AND sc.tenant_code = ue.tenant_code DYNAMIC_WHERE_CLAUSE - ORDER BY sc.mentor_name - ;`, + ORDER BY sc.mentor_name;`, updated_at: Sequelize.literal('CURRENT_TIMESTAMP'), }, { From 462fba51b849ee352b6276bc6edda07b2267a1cc Mon Sep 17 00:00:00 2001 From: sumanvpacewisdom Date: Tue, 24 Feb 2026 11:47:45 +0530 Subject: [PATCH 2/9] Standardize session type values in SQL queries within migration file to ensure consistent casing and improve query clarity. Adjust conditions for start and end dates to handle null values appropriately. --- ...update-reports-queries-with-tenant-code.js | 69 +++++++++---------- 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/src/database/migrations/20251225065401-update-reports-queries-with-tenant-code.js b/src/database/migrations/20251225065401-update-reports-queries-with-tenant-code.js index 458e1f3fd..a74761ba1 100644 --- a/src/database/migrations/20251225065401-update-reports-queries-with-tenant-code.js +++ b/src/database/migrations/20251225065401-update-reports-queries-with-tenant-code.js @@ -199,8 +199,8 @@ module.exports = { AND (:end_date IS NULL OR s.end_date < :end_date) AND ( (:session_type = 'All' AND s.type IN ('PUBLIC', 'PRIVATE')) - OR (:session_type = 'PUBLIC' AND s.type = 'PUBLIC') - OR (:session_type = 'PRIVATE' AND s.type = 'PRIVATE') + OR (:session_type = 'Public' AND s.type = 'PUBLIC') + OR (:session_type = 'Private' AND s.type = 'PRIVATE') ) AND s.deleted_at IS NULL DYNAMIC_AND_CLAUSE;`, @@ -224,13 +224,13 @@ module.exports = { Session.tenant_code = :tenantCode AND Session.mentor_id = :userId AND Session.status = 'COMPLETED' - AND Session.start_date > :start_date - AND Session.end_date < :end_date + AND (:start_date IS NULL OR Session.start_date > :start_date) + AND (:end_date IS NULL OR Session.end_date < :end_date) AND ( CASE WHEN :session_type = 'All' THEN Session.type IN ('PUBLIC', 'PRIVATE') - WHEN :session_type = 'PUBLIC' THEN Session.type = 'PUBLIC' - WHEN :session_type = 'PRIVATE' THEN Session.type = 'PRIVATE' + WHEN :session_type = 'Public' THEN Session.type = 'PUBLIC' + WHEN :session_type = 'Private' THEN Session.type = 'PRIVATE' ELSE TRUE END ) @@ -337,15 +337,15 @@ module.exports = { FROM public.sessions Session WHERE Session.tenant_code = :tenantCode - AND Session.mentor_id = :userId + AND Session.mentor_id = :userId AND Session.status = 'COMPLETED' - AND Session.start_date > :start_date - AND Session.end_date < :end_date + AND (:start_date IS NULL OR Session.start_date > :start_date) + AND (:end_date IS NULL OR Session.end_date < :end_date) AND ( CASE WHEN :session_type = 'All' THEN Session.type IN ('PUBLIC', 'PRIVATE') - WHEN :session_type = 'PUBLIC' THEN Session.type = 'PUBLIC' - WHEN :session_type = 'PRIVATE' THEN Session.type = 'PRIVATE' + WHEN :session_type = 'Public' THEN Session.type = 'PUBLIC' + WHEN :session_type = 'Private' THEN Session.type = 'PRIVATE' ELSE TRUE END ) @@ -440,7 +440,6 @@ module.exports = { session.tenant_code = :tenantCode AND (session.start_date > :start_date OR :start_date IS NULL) AND (session.end_date < :end_date OR :end_date IS NULL) - AND (:userId IS NOT NULL) AND session.deleted_at IS NULL DYNAMIC_AND_CLAUSE;`, updated_at: Sequelize.literal('CURRENT_TIMESTAMP'), @@ -468,13 +467,13 @@ module.exports = { WHERE session.tenant_code = :tenantCode AND session.mentor_id = :userId - AND session.start_date > :start_date - AND session.end_date < :end_date + AND (:start_date IS NULL OR session.start_date > :start_date) + AND (:end_date IS NULL OR session.end_date < :end_date) AND ( CASE WHEN :session_type = 'All' THEN session.type IN ('PUBLIC', 'PRIVATE') - WHEN :session_type = 'PUBLIC' THEN session.type = 'PUBLIC' - WHEN :session_type = 'PRIVATE' THEN session.type = 'PRIVATE' + WHEN :session_type = 'Public' THEN session.type = 'PUBLIC' + WHEN :session_type = 'Private' THEN session.type = 'PRIVATE' ELSE TRUE END ) @@ -509,16 +508,16 @@ module.exports = { FROM public.sessions AS Session WHERE - Session.tenant_code = :tenantCode - AND Session.created_by = :userId - AND Session.status = 'COMPLETED' - AND Session.start_date > :start_date - AND Session.end_date < :end_date + Session.tenant_code = :tenantCode + AND Session.created_by = :userId + AND Session.status = 'COMPLETED' + AND (:start_date IS NULL OR Session.start_date > :start_date) + AND (:end_date IS NULL OR Session.end_date < :end_date) AND ( CASE WHEN :session_type = 'All' THEN TRUE - WHEN :session_type = 'PUBLIC' THEN Session.type = 'PUBLIC' - WHEN :session_type = 'PRIVATE' THEN Session.type = 'PRIVATE' + WHEN :session_type = 'Public' THEN Session.type = 'PUBLIC' + WHEN :session_type = 'Private' THEN Session.type = 'PRIVATE' ELSE TRUE END ) @@ -553,16 +552,16 @@ module.exports = { FROM public.sessions AS Session WHERE - Session.tenant_code = :tenantCode - AND Session.mentor_id = :userId - AND Session.status = 'COMPLETED' - AND Session.start_date > :start_date - AND Session.end_date < :end_date + Session.tenant_code = :tenantCode + AND Session.mentor_id = :userId + AND Session.status = 'COMPLETED' + AND (:start_date IS NULL OR Session.start_date > :start_date) + AND (:end_date IS NULL OR Session.end_date < :end_date) AND ( CASE WHEN :session_type = 'All' THEN TRUE - WHEN :session_type = 'PUBLIC' THEN Session.type = 'PUBLIC' - WHEN :session_type = 'PRIVATE' THEN Session.type = 'PRIVATE' + WHEN :session_type = 'Public' THEN Session.type = 'PUBLIC' + WHEN :session_type = 'Private' THEN Session.type = 'PRIVATE' ELSE TRUE END ) @@ -670,11 +669,11 @@ module.exports = { ) AS "hours_of_mentoring_sessions" FROM public.sessions AS session WHERE session.tenant_code = :tenantCode - AND session.created_by = :userId - AND session.started_at IS NOT NULL - AND session.completed_at IS NOT NULL - AND session.start_date > :start_date - AND session.end_date < :end_date + AND session.created_by = :userId + AND session.started_at IS NOT NULL + AND session.completed_at IS NOT NULL + AND (:start_date IS NULL OR session.start_date > :start_date) + AND (:end_date IS NULL OR session.end_date < :end_date) AND ( CASE WHEN :session_type = 'All' THEN session.type IN ('PUBLIC', 'PRIVATE') From 1034ac790232caea60584502daa49221a71eb567 Mon Sep 17 00:00:00 2001 From: sumanvpacewisdom Date: Tue, 24 Feb 2026 12:15:06 +0530 Subject: [PATCH 3/9] Enhance SQL queries in migration file by incorporating COALESCE for better handling of null values in time calculations. Update JOIN condition for user extensions to a LEFT JOIN to ensure all sessions are included, improving data integrity. --- ...update-reports-queries-with-tenant-code.js | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/database/migrations/20251225065401-update-reports-queries-with-tenant-code.js b/src/database/migrations/20251225065401-update-reports-queries-with-tenant-code.js index a74761ba1..8ff6b1b98 100644 --- a/src/database/migrations/20251225065401-update-reports-queries-with-tenant-code.js +++ b/src/database/migrations/20251225065401-update-reports-queries-with-tenant-code.js @@ -491,21 +491,21 @@ module.exports = { 'report_queries', { query: `SELECT - TO_CHAR( + COALESCE(TO_CHAR( INTERVAL '1 second' * FLOOR(SUM(EXTRACT(EPOCH FROM (completed_at - started_at)))), 'HH24:MI:SS' - ) AS total_hours, - - TO_CHAR( + ), '00:00:00') AS total_hours, + + COALESCE(TO_CHAR( INTERVAL '1 second' * FLOOR(SUM(CASE WHEN Session.type = 'PUBLIC' THEN EXTRACT(EPOCH FROM (completed_at - started_at)) ELSE 0 END)), 'HH24:MI:SS' - ) AS total_public_hours, - - TO_CHAR( + ), '00:00:00') AS total_public_hours, + + COALESCE(TO_CHAR( INTERVAL '1 second' * FLOOR(SUM(CASE WHEN Session.type = 'PRIVATE' THEN EXTRACT(EPOCH FROM (completed_at - started_at)) ELSE 0 END)), 'HH24:MI:SS' - ) AS total_private_hours - + ), '00:00:00') AS total_private_hours + FROM public.sessions AS Session WHERE Session.tenant_code = :tenantCode @@ -535,21 +535,21 @@ module.exports = { 'report_queries', { query: `SELECT - TO_CHAR( + COALESCE(TO_CHAR( INTERVAL '1 second' * FLOOR(SUM(EXTRACT(EPOCH FROM (completed_at - started_at)))), 'HH24:MI:SS' - ) AS total_hours, - - TO_CHAR( + ), '00:00:00') AS total_hours, + + COALESCE(TO_CHAR( INTERVAL '1 second' * FLOOR(SUM(CASE WHEN Session.type = 'PUBLIC' THEN EXTRACT(EPOCH FROM (completed_at - started_at)) ELSE 0 END)), 'HH24:MI:SS' - ) AS public_hours, - - TO_CHAR( + ), '00:00:00') AS public_hours, + + COALESCE(TO_CHAR( INTERVAL '1 second' * FLOOR(SUM(CASE WHEN Session.type = 'PRIVATE' THEN EXTRACT(EPOCH FROM (completed_at - started_at)) ELSE 0 END)), 'HH24:MI:SS' - ) AS private_hours - + ), '00:00:00') AS private_hours + FROM public.sessions AS Session WHERE Session.tenant_code = :tenantCode @@ -692,7 +692,7 @@ module.exports = { sc.hours_of_mentoring_sessions as hours_of_mentoring_sessions, COALESCE(CAST(ue.rating ->>'average' AS NUMERIC),0) AS avg_mentor_rating FROM session_count AS sc - JOIN public.user_extensions AS ue ON sc.mentor_id = ue.user_id AND sc.tenant_code = ue.tenant_code + LEFT JOIN public.user_extensions AS ue ON sc.mentor_id = ue.user_id AND sc.tenant_code = ue.tenant_code DYNAMIC_WHERE_CLAUSE ORDER BY sc.mentor_name;`, updated_at: Sequelize.literal('CURRENT_TIMESTAMP'), From bb588545fcd4e3c3f1632e57a1904a85ca80d2ff Mon Sep 17 00:00:00 2001 From: sumanvpacewisdom Date: Tue, 24 Feb 2026 12:30:00 +0530 Subject: [PATCH 4/9] Refactor SQL queries in migration file to utilize COALESCE for null value handling in time calculations, ensuring accurate total duration metrics for sessions. This enhances the robustness of the reporting queries. --- ...01-update-reports-queries-with-tenant-code.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/database/migrations/20251225065401-update-reports-queries-with-tenant-code.js b/src/database/migrations/20251225065401-update-reports-queries-with-tenant-code.js index 8ff6b1b98..211678ecd 100644 --- a/src/database/migrations/20251225065401-update-reports-queries-with-tenant-code.js +++ b/src/database/migrations/20251225065401-update-reports-queries-with-tenant-code.js @@ -52,26 +52,26 @@ module.exports = { 'report_queries', { query: `SELECT - TO_CHAR( + COALESCE(TO_CHAR( INTERVAL '1 hour' * FLOOR(SUM(duration) / 3600) + INTERVAL '1 minute' * FLOOR((SUM(duration) / 60)::BIGINT % 60) + INTERVAL '1 second' * FLOOR(SUM(duration)::BIGINT % 60), 'HH24:MI:SS' - ) AS total_hours, -- Total duration of all sessions - - TO_CHAR( + ), '00:00:00') AS total_hours, + + COALESCE(TO_CHAR( INTERVAL '1 hour' * FLOOR(SUM(CASE WHEN type = 'PUBLIC' THEN duration ELSE 0 END) / 3600) + INTERVAL '1 minute' * FLOOR((SUM(CASE WHEN type = 'PUBLIC' THEN duration ELSE 0 END) / 60)::BIGINT % 60) + INTERVAL '1 second' * FLOOR(SUM(CASE WHEN type = 'PUBLIC' THEN duration ELSE 0 END)::BIGINT % 60), 'HH24:MI:SS' - ) AS public_hours, -- Total duration of public sessions - - TO_CHAR( + ), '00:00:00') AS public_hours, + + COALESCE(TO_CHAR( INTERVAL '1 hour' * FLOOR(SUM(CASE WHEN type = 'PRIVATE' THEN duration ELSE 0 END) / 3600) + INTERVAL '1 minute' * FLOOR((SUM(CASE WHEN type = 'PRIVATE' THEN duration ELSE 0 END) / 60)::BIGINT % 60) + INTERVAL '1 second' * FLOOR(SUM(CASE WHEN type = 'PRIVATE' THEN duration ELSE 0 END)::BIGINT % 60), 'HH24:MI:SS' - ) AS private_hours -- Total duration of private sessions + ), '00:00:00') AS private_hours FROM ( SELECT From 0d6f2c729f3f5af4e35d70a2463fb1a4cbf29f7f Mon Sep 17 00:00:00 2001 From: sumanvpacewisdom Date: Tue, 24 Feb 2026 13:15:52 +0530 Subject: [PATCH 5/9] Add detailed logging to getEntityTypeWithEntitiesBasedOnOrg for improved debugging Enhance the getEntityTypeWithEntitiesBasedOnOrg function by adding console logs to track input parameters, filter conditions, cache results, and database query outcomes. This will facilitate easier troubleshooting and performance monitoring during execution. --- ...dAndEntityTypewithEntitiesBasedOnPolicy.js | 64 +++++++++++++++++-- 1 file changed, 60 insertions(+), 4 deletions(-) diff --git a/src/helpers/getOrgIdAndEntityTypewithEntitiesBasedOnPolicy.js b/src/helpers/getOrgIdAndEntityTypewithEntitiesBasedOnPolicy.js index 428312393..9dae08a0a 100644 --- a/src/helpers/getOrgIdAndEntityTypewithEntitiesBasedOnPolicy.js +++ b/src/helpers/getOrgIdAndEntityTypewithEntitiesBasedOnPolicy.js @@ -238,6 +238,14 @@ module.exports = class OrganizationAndEntityTypePolicyHelper { tenantCodes, defaultTenantCode = '' ) { + console.log('[getEntityTypeWithEntitiesBasedOnOrg] called with:', { + organization_codes, + entity_types, + defaultOrgCode, + modelName, + tenantCodes, + defaultTenantCode, + }) try { filter.status = common.ACTIVE_STATUS filter.allow_filtering = true @@ -261,13 +269,23 @@ module.exports = class OrganizationAndEntityTypePolicyHelper { } } if (modelName) { - filter.model_names = { [Op.contains]: modelName } + filter.model_names = { [Op.contains]: [modelName] } } //fetch entity types and entities // Handle both array and string cases for tenantCodes const tenantCodeArray = Array.isArray(tenantCodes) ? tenantCodes : [tenantCodes] const finalTenantCodes = defaultTenantCode ? [...tenantCodeArray, defaultTenantCode] : tenantCodeArray + console.log( + '[getEntityTypeWithEntitiesBasedOnOrg] filter:', + JSON.stringify(filter, (key, val) => (typeof val === 'symbol' ? val.toString() : val)) + ) + console.log('[getEntityTypeWithEntitiesBasedOnOrg] finalTenantCodes:', finalTenantCodes) + console.log( + '[getEntityTypeWithEntitiesBasedOnOrg] branch:', + modelName && !entity_types ? 'CACHE' : 'DIRECT_DB' + ) + // Use cache for model-based queries since this query has core fields only let entityTypesWithEntities if (modelName && !entity_types) { @@ -283,25 +301,63 @@ module.exports = class OrganizationAndEntityTypePolicyHelper { has_entities: filter.has_entities, } ) + console.log( + '[getEntityTypeWithEntitiesBasedOnOrg] cache result count:', + Array.isArray(entityTypesWithEntities) + ? entityTypesWithEntities.length + : typeof entityTypesWithEntities + ) } catch (cacheError) { + console.error( + '[getEntityTypeWithEntitiesBasedOnOrg] cache error, falling back to DB:', + cacheError.message + ) // Fallback to direct database query entityTypesWithEntities = await entityTypeQueries.findUserEntityTypesAndEntities( filter, finalTenantCodes ) + console.log( + '[getEntityTypeWithEntitiesBasedOnOrg] fallback DB result count:', + Array.isArray(entityTypesWithEntities) + ? entityTypesWithEntities.length + : typeof entityTypesWithEntities + ) } } else { // Query has specific entity values or other non-core filters - use direct query - entityTypesWithEntities = await entityTypeQueries.findUserEntityTypesAndEntities( - filter, - finalTenantCodes + console.log( + '[getEntityTypeWithEntitiesBasedOnOrg] calling findUserEntityTypesAndEntities with filter:', + JSON.stringify(filter, (key, val) => (typeof val === 'symbol' ? val.toString() : val)) ) + try { + entityTypesWithEntities = await entityTypeQueries.findUserEntityTypesAndEntities( + filter, + finalTenantCodes + ) + console.log( + '[getEntityTypeWithEntitiesBasedOnOrg] direct DB result count:', + Array.isArray(entityTypesWithEntities) + ? entityTypesWithEntities.length + : typeof entityTypesWithEntities + ) + } catch (dbError) { + console.error('[getEntityTypeWithEntitiesBasedOnOrg] direct DB error:', dbError.message) + throw dbError + } } + console.log( + '[getEntityTypeWithEntitiesBasedOnOrg] returning result, type:', + typeof entityTypesWithEntities, + 'isArray:', + Array.isArray(entityTypesWithEntities) + ) return { success: true, result: entityTypesWithEntities, } } catch (error) { + console.error('[getEntityTypeWithEntitiesBasedOnOrg] outer catch error:', error.message, error.stack) return { success: false, message: error.message, From 86e70bcae9461df57a39c6bc56e0050304856bdc Mon Sep 17 00:00:00 2001 From: sumanvpacewisdom Date: Tue, 24 Feb 2026 13:29:01 +0530 Subject: [PATCH 6/9] Remove unnecessary console logs from getEntityTypeWithEntitiesBasedOnOrg to streamline code and improve performance. This cleanup enhances readability and reduces clutter in the logging output during execution. --- ...dAndEntityTypewithEntitiesBasedOnPolicy.js | 62 +------------------ 1 file changed, 3 insertions(+), 59 deletions(-) diff --git a/src/helpers/getOrgIdAndEntityTypewithEntitiesBasedOnPolicy.js b/src/helpers/getOrgIdAndEntityTypewithEntitiesBasedOnPolicy.js index 9dae08a0a..8b5a86ea6 100644 --- a/src/helpers/getOrgIdAndEntityTypewithEntitiesBasedOnPolicy.js +++ b/src/helpers/getOrgIdAndEntityTypewithEntitiesBasedOnPolicy.js @@ -238,14 +238,6 @@ module.exports = class OrganizationAndEntityTypePolicyHelper { tenantCodes, defaultTenantCode = '' ) { - console.log('[getEntityTypeWithEntitiesBasedOnOrg] called with:', { - organization_codes, - entity_types, - defaultOrgCode, - modelName, - tenantCodes, - defaultTenantCode, - }) try { filter.status = common.ACTIVE_STATUS filter.allow_filtering = true @@ -276,16 +268,6 @@ module.exports = class OrganizationAndEntityTypePolicyHelper { const tenantCodeArray = Array.isArray(tenantCodes) ? tenantCodes : [tenantCodes] const finalTenantCodes = defaultTenantCode ? [...tenantCodeArray, defaultTenantCode] : tenantCodeArray - console.log( - '[getEntityTypeWithEntitiesBasedOnOrg] filter:', - JSON.stringify(filter, (key, val) => (typeof val === 'symbol' ? val.toString() : val)) - ) - console.log('[getEntityTypeWithEntitiesBasedOnOrg] finalTenantCodes:', finalTenantCodes) - console.log( - '[getEntityTypeWithEntitiesBasedOnOrg] branch:', - modelName && !entity_types ? 'CACHE' : 'DIRECT_DB' - ) - // Use cache for model-based queries since this query has core fields only let entityTypesWithEntities if (modelName && !entity_types) { @@ -301,63 +283,25 @@ module.exports = class OrganizationAndEntityTypePolicyHelper { has_entities: filter.has_entities, } ) - console.log( - '[getEntityTypeWithEntitiesBasedOnOrg] cache result count:', - Array.isArray(entityTypesWithEntities) - ? entityTypesWithEntities.length - : typeof entityTypesWithEntities - ) } catch (cacheError) { - console.error( - '[getEntityTypeWithEntitiesBasedOnOrg] cache error, falling back to DB:', - cacheError.message - ) // Fallback to direct database query entityTypesWithEntities = await entityTypeQueries.findUserEntityTypesAndEntities( filter, finalTenantCodes ) - console.log( - '[getEntityTypeWithEntitiesBasedOnOrg] fallback DB result count:', - Array.isArray(entityTypesWithEntities) - ? entityTypesWithEntities.length - : typeof entityTypesWithEntities - ) } } else { // Query has specific entity values or other non-core filters - use direct query - console.log( - '[getEntityTypeWithEntitiesBasedOnOrg] calling findUserEntityTypesAndEntities with filter:', - JSON.stringify(filter, (key, val) => (typeof val === 'symbol' ? val.toString() : val)) + entityTypesWithEntities = await entityTypeQueries.findUserEntityTypesAndEntities( + filter, + finalTenantCodes ) - try { - entityTypesWithEntities = await entityTypeQueries.findUserEntityTypesAndEntities( - filter, - finalTenantCodes - ) - console.log( - '[getEntityTypeWithEntitiesBasedOnOrg] direct DB result count:', - Array.isArray(entityTypesWithEntities) - ? entityTypesWithEntities.length - : typeof entityTypesWithEntities - ) - } catch (dbError) { - console.error('[getEntityTypeWithEntitiesBasedOnOrg] direct DB error:', dbError.message) - throw dbError - } } - console.log( - '[getEntityTypeWithEntitiesBasedOnOrg] returning result, type:', - typeof entityTypesWithEntities, - 'isArray:', - Array.isArray(entityTypesWithEntities) - ) return { success: true, result: entityTypesWithEntities, } } catch (error) { - console.error('[getEntityTypeWithEntitiesBasedOnOrg] outer catch error:', error.message, error.stack) return { success: false, message: error.message, From dfa3dc41027aaa5a33fcab815765e676494801f5 Mon Sep 17 00:00:00 2001 From: sumanvpacewisdom Date: Tue, 24 Feb 2026 14:17:41 +0530 Subject: [PATCH 7/9] Fix filter model_names assignment in getOrgIdAndEntityTypewithEntitiesBasedOnPolicy to correctly handle single modelName input. This change improves the accuracy of the filtering logic. --- src/helpers/getOrgIdAndEntityTypewithEntitiesBasedOnPolicy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helpers/getOrgIdAndEntityTypewithEntitiesBasedOnPolicy.js b/src/helpers/getOrgIdAndEntityTypewithEntitiesBasedOnPolicy.js index 8b5a86ea6..428312393 100644 --- a/src/helpers/getOrgIdAndEntityTypewithEntitiesBasedOnPolicy.js +++ b/src/helpers/getOrgIdAndEntityTypewithEntitiesBasedOnPolicy.js @@ -261,7 +261,7 @@ module.exports = class OrganizationAndEntityTypePolicyHelper { } } if (modelName) { - filter.model_names = { [Op.contains]: [modelName] } + filter.model_names = { [Op.contains]: modelName } } //fetch entity types and entities // Handle both array and string cases for tenantCodes From 44d4d2177a8207059b123e79d77f3e987c3ed414 Mon Sep 17 00:00:00 2001 From: sumanvpacewisdom Date: Tue, 24 Feb 2026 14:27:25 +0530 Subject: [PATCH 8/9] Refactor model_names filter assignment in getOrgIdAndEntityTypewithEntitiesBasedOnPolicy to handle both single and array inputs for modelName. This change enhances the filtering logic's flexibility and accuracy. --- src/helpers/getOrgIdAndEntityTypewithEntitiesBasedOnPolicy.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/helpers/getOrgIdAndEntityTypewithEntitiesBasedOnPolicy.js b/src/helpers/getOrgIdAndEntityTypewithEntitiesBasedOnPolicy.js index 428312393..45494636b 100644 --- a/src/helpers/getOrgIdAndEntityTypewithEntitiesBasedOnPolicy.js +++ b/src/helpers/getOrgIdAndEntityTypewithEntitiesBasedOnPolicy.js @@ -261,6 +261,7 @@ module.exports = class OrganizationAndEntityTypePolicyHelper { } } if (modelName) { + const modelName = Array.isArray(modelName) ? modelName : [modelName] filter.model_names = { [Op.contains]: modelName } } //fetch entity types and entities From 0db86de382c09779f200451081ce3c6a093756db Mon Sep 17 00:00:00 2001 From: sumanvpacewisdom Date: Tue, 24 Feb 2026 14:44:20 +0530 Subject: [PATCH 9/9] Refactor model_names filter assignment in getOrgIdAndEntityTypewithEntitiesBasedOnPolicy to streamline handling of modelName inputs. This change consolidates the logic for both single and array cases, enhancing code clarity and maintainability. --- src/helpers/getOrgIdAndEntityTypewithEntitiesBasedOnPolicy.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/helpers/getOrgIdAndEntityTypewithEntitiesBasedOnPolicy.js b/src/helpers/getOrgIdAndEntityTypewithEntitiesBasedOnPolicy.js index 45494636b..7b9e6fbda 100644 --- a/src/helpers/getOrgIdAndEntityTypewithEntitiesBasedOnPolicy.js +++ b/src/helpers/getOrgIdAndEntityTypewithEntitiesBasedOnPolicy.js @@ -261,8 +261,7 @@ module.exports = class OrganizationAndEntityTypePolicyHelper { } } if (modelName) { - const modelName = Array.isArray(modelName) ? modelName : [modelName] - filter.model_names = { [Op.contains]: modelName } + filter.model_names = { [Op.contains]: Array.isArray(modelName) ? modelName : [modelName] } } //fetch entity types and entities // Handle both array and string cases for tenantCodes