Skip to content

Mentee report table issue#1578

Open
sumanvpacewisdom wants to merge 3 commits intodevelopfrom
MENTEE_REPORT_TABLE_ISSUE
Open

Mentee report table issue#1578
sumanvpacewisdom wants to merge 3 commits intodevelopfrom
MENTEE_REPORT_TABLE_ISSUE

Conversation

@sumanvpacewisdom
Copy link
Copy Markdown
Collaborator

@sumanvpacewisdom sumanvpacewisdom commented Feb 17, 2026

Release Notes

  • Added defensive fallbacks and guards in src/services/reports.js to prevent runtime errors when entity type query results are undefined
  • Replaced direct accesses with safe defaults (e.g., using || []) in map/reduce paths used for report generation and CSV export
  • Improved robustness of report and CSV export flows without changing public APIs

Contribution Summary

Author Lines Added Lines Removed
sumanvpacewisdom 8 3

… by using optional chaining, preventing potential errors when accessing results.
…ays for undefined results, preventing potential runtime errors during entity type data processing.
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Feb 17, 2026

Walkthrough

Adds defensive fallbacks in the reports service to avoid reading properties from possibly undefined query results by using ...result || [] in multiple data-paths during report generation and CSV export (no public APIs changed).

Changes

Cohort / File(s) Summary
Reports service defensive guards
src/services/reports.js
Added `result

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Suggested reviewers

  • nevil-mathew

Poem

🐰 I hop through code where queries may stall,
I patch the gaps so nil won't make us fall.
With result || [] I softly mend the seam,
Reports run smoother — a small, steady beam.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'Mentee report table issue' is vague and generic, using non-descriptive terms that don't convey the specific technical changes made. Consider a more specific title that describes the actual change, such as 'Add defensive null checks to report data transformations' or 'Fix undefined errors in report entity mapping'.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch MENTEE_REPORT_TABLE_ISSUE

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@nevil-mathew
Copy link
Copy Markdown
Collaborator

@coderabbitai full review

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Feb 17, 2026

✅ Actions performed

Full review triggered.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (3)
src/services/reports.js (3)

462-467: Silent error swallowing — consider logging when the entity type lookup fails.

The || [] fallback correctly prevents the runtime crash, but if getEntityTypeWithEntitiesBasedOnOrg returns { success: false, message }, that failure is silently ignored. This can mask real issues (e.g., misconfigured orgs, DB connectivity problems) and make debugging difficult.

For consistency with getFilterList (line 92), consider checking .success explicitly and logging a warning on failure:

Suggested improvement
-				// Fallback to empty array if result is undefined (when getEntityTypeWithEntitiesBasedOnOrg returns {success: false, message} on error)
 				const transformedEntityData = await utils.mapEntityTypeToData(
 					result,
-					entityTypesDataWithPagination.result || []
+					entityTypesDataWithPagination.success ? entityTypesDataWithPagination.result : (() => {
+						console.warn('Entity type lookup failed for report data:', entityTypesDataWithPagination.message)
+						return []
+					})()
 				)

Or more readably, extract the guard before the call:

+				if (!entityTypesDataWithPagination.success) {
+					console.warn('Entity type lookup failed:', entityTypesDataWithPagination.message)
+				}
+				const entityTypes = entityTypesDataWithPagination.result || []
 				const transformedEntityData = await utils.mapEntityTypeToData(
 					result,
-					entityTypesDataWithPagination.result || []
+					entityTypes
 				)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/services/reports.js` around lines 462 - 467, The current code silently
falls back to an empty array when getEntityTypeWithEntitiesBasedOnOrg fails,
masking errors; update the logic around the entityTypesDataWithPagination result
(the output of getEntityTypeWithEntitiesBasedOnOrg) to explicitly check
entityTypesDataWithPagination.success and, on false, log a warning/error
(similar to getFilterList) including the returned message or error, then only
pass entityTypesDataWithPagination.result to utils.mapEntityTypeToData when
success is true (otherwise pass an empty array), so you both avoid the crash and
surface the underlying failure for debugging.

494-500: Same silent failure pattern — add a warning log here too.

Same concern as above. When entityTypeFilters returns a failure, the .reduce over an empty array produces {}, which means reportDataResult.filters will silently have missing entity-type filter options. Users would see empty filter dropdowns with no indication of why.

Suggested improvement
-						// FIX: Mentee reports have isEntityType columns (categories, recommended_for) which triggers direct DB query path.
-						// If query fails, getEntityTypeWithEntitiesBasedOnOrg returns {success: false, message} without 'result' property.
-						// Fallback to empty array prevents "Cannot read properties of undefined (reading 'reduce')" error.
-						const filtersEntity = (entityTypeFilters.result || []).reduce((acc, item) => {
+						if (!entityTypeFilters.success) {
+							console.warn('Entity type filter lookup failed:', entityTypeFilters.message)
+						}
+						const filtersEntity = (entityTypeFilters.result || []).reduce((acc, item) => {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/services/reports.js` around lines 494 - 500, When computing filtersEntity
from entityTypeFilters.result, add a warning log when the call to
getEntityTypeWithEntitiesBasedOnOrg failed or returned no result so the silent
fallback to an empty object is visible; check if entityTypeFilters.success ===
false or !entityTypeFilters.result and then call the module's logger.warn (or
existing logger) including entityTypeFilters.message and/or the
entityTypeFilters object before using (entityTypeFilters.result || []) to build
filtersEntity so operators see why filter options are missing.

528-532: Consistent with the other two sites — same logging suggestion applies.

The defensive fallback is correct. Same recommendation: log a warning when entityTypesData.success is false so CSV exports with missing entity resolution are diagnosable.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/services/reports.js` around lines 528 - 532, Before calling
utils.mapEntityTypeToData, check entityTypesData.success and if it's false emit
a warning (using the existing logger in this module, e.g., processLogger or
logger) indicating entity type resolution failed and that entityTypesData.result
will be used as a fallback; then proceed to call utils.mapEntityTypeToData with
entityTypesData.result and assign to transformedData as before. Ensure the
warning includes enough context (e.g., mention "entityTypesData.success false"
and any available error/details from entityTypesData) so CSV export issues are
diagnosable.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/services/reports.js`:
- Around line 462-467: The current code silently falls back to an empty array
when getEntityTypeWithEntitiesBasedOnOrg fails, masking errors; update the logic
around the entityTypesDataWithPagination result (the output of
getEntityTypeWithEntitiesBasedOnOrg) to explicitly check
entityTypesDataWithPagination.success and, on false, log a warning/error
(similar to getFilterList) including the returned message or error, then only
pass entityTypesDataWithPagination.result to utils.mapEntityTypeToData when
success is true (otherwise pass an empty array), so you both avoid the crash and
surface the underlying failure for debugging.
- Around line 494-500: When computing filtersEntity from
entityTypeFilters.result, add a warning log when the call to
getEntityTypeWithEntitiesBasedOnOrg failed or returned no result so the silent
fallback to an empty object is visible; check if entityTypeFilters.success ===
false or !entityTypeFilters.result and then call the module's logger.warn (or
existing logger) including entityTypeFilters.message and/or the
entityTypeFilters object before using (entityTypeFilters.result || []) to build
filtersEntity so operators see why filter options are missing.
- Around line 528-532: Before calling utils.mapEntityTypeToData, check
entityTypesData.success and if it's false emit a warning (using the existing
logger in this module, e.g., processLogger or logger) indicating entity type
resolution failed and that entityTypesData.result will be used as a fallback;
then proceed to call utils.mapEntityTypeToData with entityTypesData.result and
assign to transformedData as before. Ensure the warning includes enough context
(e.g., mention "entityTypesData.success false" and any available error/details
from entityTypesData) so CSV export issues are diagnosable.

…y and maintainability, focusing on clarity in entity type data processing.
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
src/services/reports.js (3)

286-292: ⚠️ Potential issue | 🟠 Major

replacements.sort_type is undefined in the BAR_CHART path — injects "undefined" literal into SQL

The replacements object built for the BAR_CHART branch (lines 279–286) has no sort_type key. When query.replace(/:sort_type/g, replacements.sort_type) is called on line 288, JavaScript coerces undefined to the string "undefined", which gets substituted verbatim into the query template if it contains :sort_type. This produces a malformed SQL clause.

🐛 Proposed fix
  const replacements = {
      userId: userId || null,
      session_type: sessionType ? utils.convertToTitleCase(sessionType) : null,
      start_date: dateRange.start_date || null,
      end_date: dateRange.end_date || null,
      tenantCode: tenantCode,
  }

- let query = reportQuery[0].query.replace(/:sort_type/g, replacements.sort_type)
+ let query = reportQuery[0].query.replace(/:sort_type/g, '')

If BAR_CHART queries never need a sort_type, strip the placeholder entirely. If they do, add sort_type to the replacements object with a safe default (e.g. 'ASC').

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/services/reports.js` around lines 286 - 292, The BAR_CHART branch builds
a replacements object that lacks sort_type so the subsequent call to
query.replace(/:sort_type/g, replacements.sort_type) injects the literal
"undefined" into SQL; update the BAR_CHART replacements creation (where
replacements is assembled for reportQuery and BAR_CHART) to either add a safe
default like replacements.sort_type = 'ASC' or conditionally strip the
:sort_type placeholder from query when BAR_CHART does not use sorting (i.e.,
detect BAR_CHART path and replace the token with ''), ensuring you touch the
same reportQuery/replacements logic that feeds into the query.replace call.

340-350: ⚠️ Potential issue | 🟠 Major

sortType.toUpperCase() throws if sortType is null/undefined

sortType has no default in the function signature, so it may arrive as undefined. When it does, .toUpperCase() throws a TypeError before || 'ASC' can kick in — the fallback only applies to a falsy string result, not to a null/undefined receiver. The same faulty pattern appears on both line 340 and line 349.

🐛 Proposed fix
- sort_type: sortType.toUpperCase() || 'ASC',
+ sort_type: (sortType || 'ASC').toUpperCase(),

Apply to both line 340 and line 349.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/services/reports.js` around lines 340 - 350, The code calls
sortType.toUpperCase() inside the objects (see sort_type assignments in the main
replacements and noPaginationReplacements) which throws if sortType is
null/undefined; change both occurrences to guard first by converting/falling
back before uppercasing, e.g. use (sortType || 'ASC').toUpperCase() or
String(sortType || 'ASC').toUpperCase() so the fallback is applied before
.toUpperCase(); update the sort_type fields in both replacements and
noPaginationReplacements accordingly.

213-255: ⚠️ Potential issue | 🟠 Major

Fallback queries are identical to the primary queries — dead code

Both the reportConfig fallback (lines 223–231) and the reportQuery fallback (lines 247–254) are copy-pastes of their respective primary queries with no parameter change. The comments indicate the intent was to fall back to the default org, but the else-branches still include orgCode in organization_code and the same [tenantCode, defaults.tenantCode] tenant filter. If the first call returns an empty result, the second will too — the fallback is effectively dead.

🐛 Proposed fix — use only default-org parameters in the fallback branches
  if (reportConfigWithOrgId.length > 0) {
      reportConfig = reportConfigWithOrgId
  } else {
      const reportConfigWithDefaultOrgId = await reportsQueries.findReport(
          {
              code: reportCode,
-             organization_code: { [Op.in]: [orgCode, defaults.orgCode] },
+             organization_code: defaults.orgCode,
          },
-         { [Op.in]: [tenantCode, defaults.tenantCode] }
+         defaults.tenantCode
      )
      reportConfig = reportConfigWithDefaultOrgId
  }

Apply the same correction to the reportQuery fallback (lines 247–254).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/services/reports.js` around lines 213 - 255, The fallback branches for
reportsQueries.findReport (reportConfigWithDefaultOrgId) and
reportQueryQueries.findReportQueries (reportQueryWithDefaultOrgId) are identical
to the primary calls so the fallback never changes the scope; update those
fallback calls so they query only the default organization and default tenant:
use organization_code set to only defaults.orgCode (e.g. { organization_code: {
[Op.in]: [defaults.orgCode] } }) and the tenant param to only
defaults.tenantCode (instead of including orgCode/tenantCode), keeping
reportCode, reportConfigWithDefaultOrgId and reportQueryWithDefaultOrgId as the
result variables.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/services/reports.js`:
- Around line 463-466: The code is accessing .result directly on the return
value of getEntityTypeWithEntitiesBasedOnOrg (used before calling
utils.mapEntityTypeToData) which can throw if that call returns null/undefined;
update the three spots in getReportData where you do something like
entityTypesDataWithPagination.result to use optional chaining on the parent
(e.g., entityTypesDataWithPagination?.result) so the || [] fallback actually
works; locate references to getEntityTypeWithEntitiesBasedOnOrg and
mapEntityTypeToData in getReportData and replace direct .result accesses with
?.result in all three changed locations (around the lines that call
utils.mapEntityTypeToData).

---

Outside diff comments:
In `@src/services/reports.js`:
- Around line 286-292: The BAR_CHART branch builds a replacements object that
lacks sort_type so the subsequent call to query.replace(/:sort_type/g,
replacements.sort_type) injects the literal "undefined" into SQL; update the
BAR_CHART replacements creation (where replacements is assembled for reportQuery
and BAR_CHART) to either add a safe default like replacements.sort_type = 'ASC'
or conditionally strip the :sort_type placeholder from query when BAR_CHART does
not use sorting (i.e., detect BAR_CHART path and replace the token with ''),
ensuring you touch the same reportQuery/replacements logic that feeds into the
query.replace call.
- Around line 340-350: The code calls sortType.toUpperCase() inside the objects
(see sort_type assignments in the main replacements and
noPaginationReplacements) which throws if sortType is null/undefined; change
both occurrences to guard first by converting/falling back before uppercasing,
e.g. use (sortType || 'ASC').toUpperCase() or String(sortType ||
'ASC').toUpperCase() so the fallback is applied before .toUpperCase(); update
the sort_type fields in both replacements and noPaginationReplacements
accordingly.
- Around line 213-255: The fallback branches for reportsQueries.findReport
(reportConfigWithDefaultOrgId) and reportQueryQueries.findReportQueries
(reportQueryWithDefaultOrgId) are identical to the primary calls so the fallback
never changes the scope; update those fallback calls so they query only the
default organization and default tenant: use organization_code set to only
defaults.orgCode (e.g. { organization_code: { [Op.in]: [defaults.orgCode] } })
and the tenant param to only defaults.tenantCode (instead of including
orgCode/tenantCode), keeping reportCode, reportConfigWithDefaultOrgId and
reportQueryWithDefaultOrgId as the result variables.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cd229ea and 2aef787.

📒 Files selected for processing (1)
  • src/services/reports.js

Comment on lines 463 to 466
const transformedEntityData = await utils.mapEntityTypeToData(
result,
entityTypesDataWithPagination.result
entityTypesDataWithPagination.result || []
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Defensive fallback is still incomplete — use optional chaining on the parent

In all three changed locations, .result is accessed directly on the return value of getEntityTypeWithEntitiesBasedOnOrg before the || [] guard can apply. If that call ever returns null or undefined, a TypeError is thrown before the fallback activates. The getFilterList method (line 92) consistently checks .success && .result before using the result; getReportData should be equally cautious.

🛡️ Proposed fix using optional chaining
- entityTypesDataWithPagination.result || []
+ entityTypesDataWithPagination?.result || []
- (entityTypeFilters.result || []).reduce((acc, item) => {
+ (entityTypeFilters?.result || []).reduce((acc, item) => {
- entityTypesData.result || []
+ entityTypesData?.result || []

Also applies to: 493-496, 523-526

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/services/reports.js` around lines 463 - 466, The code is accessing
.result directly on the return value of getEntityTypeWithEntitiesBasedOnOrg
(used before calling utils.mapEntityTypeToData) which can throw if that call
returns null/undefined; update the three spots in getReportData where you do
something like entityTypesDataWithPagination.result to use optional chaining on
the parent (e.g., entityTypesDataWithPagination?.result) so the || [] fallback
actually works; locate references to getEntityTypeWithEntitiesBasedOnOrg and
mapEntityTypeToData in getReportData and replace direct .result accesses with
?.result in all three changed locations (around the lines that call
utils.mapEntityTypeToData).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants