Skip to content

Conversation

@Tusharmahajan12
Copy link
Collaborator

@Tusharmahajan12 Tusharmahajan12 commented Jul 23, 2025

Summary by CodeRabbit

  • New Features

    • Introduced a centralized service for synchronizing user profiles, applications, cohort member statuses, and form submissions with Elasticsearch, improving data consistency and reliability.
  • Refactor

    • Replaced direct Elasticsearch update logic across multiple services with higher-level, unified service calls.
    • Simplified and consolidated Elasticsearch synchronization logic for user and cohort member data.
    • Enhanced field mapping and filtering to ensure accurate syncing of form data and custom fields.
    • Streamlined cohort detail handling by removing custom field dependencies.
    • Added detailed debug logging to assist troubleshooting Elasticsearch sync processes.
  • Bug Fixes

    • Improved error handling and logging for Elasticsearch operations.
  • Chores

    • Updated module dependencies and service injections to support the new synchronization service.

@coderabbitai
Copy link

coderabbitai bot commented Jul 23, 2025

Walkthrough

The changes introduce a new ElasticsearchSyncService that centralizes and encapsulates all Elasticsearch synchronization logic for user profiles, applications, cohort member statuses, and form submissions. All existing services that previously used UserElasticsearchService are refactored to use this new service. The module and dependency injection configurations are updated accordingly. Additional improvements include enhanced field mapping for form submissions, simplified cohort detail retrieval, and more robust error handling and logging.

Changes

File(s) Change Summary
src/adapters/postgres/cohortMembers-adapter.ts
src/adapters/postgres/user-adapter.ts
Replaced direct usage of UserElasticsearchService with ElasticsearchSyncService for all Elasticsearch update operations. Refactored methods to delegate Elasticsearch updates to the new service, simplifying and centralizing update logic. Updated constructor parameters and internal method implementations accordingly.
src/elasticsearch/elasticsearch-sync.service.ts Added new ElasticsearchSyncService class. Implements centralized methods for syncing user profiles, applications, cohort member statuses, and form submissions with Elasticsearch. Includes helpers for building user documents, updating application data, and filtering custom fields. Provides robust error handling and logging.
src/elasticsearch/elasticsearch.module.ts Registered ElasticsearchSyncService as a provider and export. Added TypeOrmModule.forFeature([User]) to module imports to support database access within the new sync service.
src/forms/services/form-submission.service.ts Replaced UserElasticsearchService with ElasticsearchSyncService. Refined logic for updating user applications in Elasticsearch, improved field-to-page mapping for form submissions, removed fetching of cohort custom fields, and added detailed debug logging. Enhanced filtering of profile custom fields in user document construction.

Sequence Diagram(s)

sequenceDiagram
    participant Service as Any App Service (e.g., CohortMembers, User, FormSubmission)
    participant SyncService as ElasticsearchSyncService
    participant ES as Elasticsearch
    participant DB as Database

    Service->>SyncService: syncUserProfile(userId, profileData, ...)
    alt Elasticsearch enabled
        SyncService->>DB: Fetch user profile and custom fields
        SyncService->>ES: Update or upsert user document
        ES-->>SyncService: Success/Failure
    else Elasticsearch disabled
        SyncService-->>Service: Skip sync
    end

    Service->>SyncService: updateApplicationData(userId, cohortId, updateData, ...)
    alt Elasticsearch enabled
        SyncService->>ES: Update application fields via script
        ES-->>SyncService: Success/Failure
        alt Document missing
            SyncService->>DB: Rebuild full user document
            SyncService->>ES: Create user document
        end
    else Elasticsearch disabled
        SyncService-->>Service: Skip sync
    end

    Service->>SyncService: syncFormSubmissionData(userId, submissionData, ...)
    alt Elasticsearch enabled
        SyncService->>ES: Update application form data
        ES-->>SyncService: Success/Failure
    else Elasticsearch disabled
        SyncService-->>Service: Skip sync
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~90 minutes

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@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: 6

🔭 Outside diff range comments (1)
src/forms/services/form-submission.service.ts (1)

3051-3123: Excellent extraction of field mapping logic into a reusable utility function.

The getFieldIdToPageNameMap function properly handles all schema dependency types and improves code maintainability by following the DRY principle.

🧹 Nitpick comments (19)
src/elasticsearch/elasticsearch.module.ts (2)

3-9: Fix quote consistency for imports.

All imports should use double quotes for consistency with NestJS best practices.

-import { TypeOrmModule } from '@nestjs/typeorm';
-import { ElasticsearchService } from './elasticsearch.service';
-import { UserElasticsearchService } from './user-elasticsearch.service';
-import { ElasticsearchConfig } from './elasticsearch.config';
-import { UserElasticsearchController } from './user-elasticsearch.controller';
-import { ElasticsearchSyncService } from './elasticsearch-sync.service';
-import { User } from '../user/entities/user-entity';
+import { TypeOrmModule } from "@nestjs/typeorm";
+import { ElasticsearchService } from "./elasticsearch.service";
+import { UserElasticsearchService } from "./user-elasticsearch.service";
+import { ElasticsearchConfig } from "./elasticsearch.config";
+import { UserElasticsearchController } from "./user-elasticsearch.controller";
+import { ElasticsearchSyncService } from "./elasticsearch-sync.service";
+import { User } from "../user/entities/user-entity";

17-20: Fix formatting issues in providers and exports arrays.

Add missing comma and break up long exports line for better readability.

     ElasticsearchConfig,
     ElasticsearchService,
     UserElasticsearchService,
-    ElasticsearchSyncService
+    ElasticsearchSyncService,
   ],
-  exports: [ElasticsearchService, UserElasticsearchService, ElasticsearchSyncService],
+  exports: [
+    ElasticsearchService,
+    UserElasticsearchService,
+    ElasticsearchSyncService,
+  ],
src/adapters/postgres/user-adapter.ts (3)

50-50: Use double quotes for import statement.

-import { ElasticsearchSyncService } from '../../elasticsearch/elasticsearch-sync.service';
+import { ElasticsearchSyncService } from "../../elasticsearch/elasticsearch-sync.service";

1575-1575: Fix line formatting for better readability.

-          await this.elasticsearchSyncService.syncUserProfile(userForElastic.userId, userForElastic.profile);
+          await this.elasticsearchSyncService.syncUserProfile(
+            userForElastic.userId,
+            userForElastic.profile
+          );

2816-2816: Use double quotes for consistency.

-      LoggerUtil.error('Failed to sync user profile to Elasticsearch', error);
+      LoggerUtil.error("Failed to sync user profile to Elasticsearch", error);
src/adapters/postgres/cohortMembers-adapter.ts (4)

36-36: Fix quote consistency for better code formatting.

Apply this diff to maintain consistent quote usage:

-import { ElasticsearchSyncService } from 'src/elasticsearch/elasticsearch-sync.service';
+import { ElasticsearchSyncService } from "src/elasticsearch/elasticsearch-sync.service";

722-738: Excellent refactoring to centralized Elasticsearch service.

The migration to ElasticsearchSyncService.updateApplicationData properly centralizes the sync logic while maintaining robust error handling. The approach of logging Elasticsearch failures without blocking the main operation is appropriate.

Consider fixing the formatting issue flagged by static analysis:

-              cohortmemberstatus: savedCohortMember.status ?? 'active',
+              cohortmemberstatus: savedCohortMember.status ?? "active",

1087-1098: Excellent implementation of centralized sync service.

The refactoring to use ElasticsearchSyncService.syncUserApplication is well-structured and maintains proper field mapping. The error handling approach of logging failures without blocking the main operation is appropriate.

Fix the formatting issue for consistency:

-              cohortmemberstatus: result.status ?? 'active',
+              cohortmemberstatus: result.status ?? "active",

1340-1382: Well-designed field-specific update implementation with good documentation.

The refactored method effectively delegates to the centralized sync service while maintaining a clean interface. The comprehensive documentation and use of a provider function for application data retrieval are excellent design choices.

Please address the formatting issues flagged by static analysis:

   * Update Elasticsearch with field-specific changes for cohort member updates.
   * This method uses the optimized ElasticsearchSyncService for better performance and maintainability.
-   * 
+   *
   * @param userId - User ID to update
   * @param cohortId - Cohort ID for the application
   * @param updateData - Data to update in the application
   * @param existingApplication - Existing application data (optional)
   */
         async (userId: string, cohortId: string) => {
           // Application data provider function
-          return await this.formSubmissionService.buildUserDocumentForElasticsearch(userId)
-            .then(userDoc => userDoc?.applications?.find(app => app.cohortId === cohortId))
-            .catch(() => null);
+          return await this.formSubmissionService
+            .buildUserDocumentForElasticsearch(userId)
+            .then((userDoc) =>
+              userDoc?.applications?.find((app) => app.cohortId === cohortId)
+            )
+            .catch(() => null);
         }
src/forms/services/form-submission.service.ts (3)

31-31: Use double quotes for consistency with the project's style guide.

Apply this formatting fix:

-import { ElasticsearchSyncService } from '../../elasticsearch/elasticsearch-sync.service';
+import { ElasticsearchSyncService } from "../../elasticsearch/elasticsearch-sync.service";

1173-1173: Fix formatting issues for better readability.

Apply these formatting fixes:

-      const userDoc = await this.elasticsearchSyncService.getUserDocument(userId);
+      const userDoc = await this.elasticsearchSyncService.getUserDocument(
+        userId
+      );
-              const userDoc = await this.buildUserDocumentForElasticsearch(userId);
+              const userDoc = await this.buildUserDocumentForElasticsearch(
+                userId
+              );
-          LoggerUtil.warn('Failed to sync user data to Elasticsearch:', syncError);
+          LoggerUtil.warn(
+            "Failed to sync user data to Elasticsearch:",
+            syncError
+          );

Also applies to: 1500-1505


2665-2672: Fix formatting in debug logging statements.

Apply these formatting fixes:

-    LoggerUtil.warn(`Built ${applications.length} applications in buildUserDocumentForElasticsearch for user: ${userId}`);
-    LoggerUtil.warn(`CohortMembers found: ${cohortMemberships.length}, FormSubmissions found: ${submissions.length}`);
-    LoggerUtil.warn(`All cohort IDs: ${Array.from(allCohortIds).join(', ')}`);
+    LoggerUtil.warn(
+      `Built ${applications.length} applications in buildUserDocumentForElasticsearch for user: ${userId}`
+    );
+    LoggerUtil.warn(
+      `CohortMembers found: ${cohortMemberships.length}, FormSubmissions found: ${submissions.length}`
+    );
+    LoggerUtil.warn(`All cohort IDs: ${Array.from(allCohortIds).join(", ")}`);
     if (applications.length > 0) {
-      LoggerUtil.warn(`Sample application: ${JSON.stringify(applications[0], null, 2)}`);
+      LoggerUtil.warn(
+        `Sample application: ${JSON.stringify(applications[0], null, 2)}`
+      );
     }
src/elasticsearch/elasticsearch-sync.service.ts (7)

40-57: Remove duplicate JSDoc comments

There are two identical JSDoc comment blocks for the same method. Remove one of them to avoid redundancy.

-  /**
-   * Sync user profile to Elasticsearch with comprehensive data fetching
-   * 
-   * @param userId - User ID to sync
-   * @param profileData - Profile data to sync (optional, will fetch from DB if not provided)
-   * @param customFieldsProvider - Function to get custom fields (optional)
-   * @param applicationDataProvider - Function to get application data (optional)
-   * @returns Promise<void>
-   */
   /**
    * Sync user profile to Elasticsearch with custom fields support
    * 
    * @param userId - User ID to sync
    * @param profileData - Profile data to sync (optional, will fetch from DB if not provided)
    * @param customFieldsProvider - Function to get custom fields (optional)
    * @param applicationDataProvider - Function to get application data (optional)
    * @returns Promise<void>
    */

72-84: Optimize profile building when profileData is provided

The method always builds a complete profile from the database even when profileData is provided, which could be inefficient. Consider building the profile only when necessary.

-    // Always build complete profile with custom fields
-    const profile = await this.buildUserProfile(userId, customFieldsProvider);
-
-    // If profileData is provided, merge it with the built profile (but preserve customFields)
-    if (profileData) {
-      Object.assign(profile, profileData);
-      // Ensure customFields are preserved from the built profile
-      if (customFieldsProvider) {
-        const customFields = await customFieldsProvider(userId);
-        profile.customFields = this.processCustomFieldsForElasticsearch(customFields);
-      }
-    }
+    // Build profile based on what's provided
+    let profile: IProfile;
+    if (profileData) {
+      // Use provided profile data and only fetch custom fields if needed
+      profile = { ...profileData } as IProfile;
+      if (customFieldsProvider && !profile.customFields) {
+        const customFields = await customFieldsProvider(userId);
+        profile.customFields = this.processCustomFieldsForElasticsearch(customFields);
+      }
+    } else {
+      // Build complete profile from database
+      profile = await this.buildUserProfile(userId, customFieldsProvider);
+    }

343-354: Remove duplicate JSDoc comments

Another instance of duplicate JSDoc comments. Keep only one.

-  /**
-   * Build user profile from database data
-   * 
-   * @param userId - User ID
-   * @param customFieldsProvider - Function to get custom fields
-   * @returns Promise<IProfile>
-   */
   /**
    * Build user profile by fetching actual user data from database
    * 
    * @param userId - User ID to fetch profile for
    * @param customFieldsProvider - Function to get custom fields
    * @returns Promise<IProfile> - Complete user profile
    */

366-385: Extract empty profile creation to reduce duplication

The empty profile structure is duplicated. Extract it to a constant or helper method.

+  private createEmptyProfile(userId: string): IProfile {
+    return {
+      userId,
+      username: '',
+      firstName: '',
+      lastName: '',
+      middleName: '',
+      email: '',
+      mobile: '',
+      mobile_country_code: '',
+      gender: '',
+      dob: '',
+      country: '',
+      address: '',
+      district: '',
+      state: '',
+      pincode: '',
+      status: 'inactive',
+      customFields: {},
+    };
+  }

   private async buildUserProfile(
     userId: string,
     customFieldsProvider?: (userId: string) => Promise<any[]>
   ): Promise<IProfile> {
     try {
       const user = await this.userRepository.findOne({ where: { userId } });

       if (!user) {
         this.logger.warn(`User not found in database: ${userId}`);
-        return {
-          userId,
-          username: '',
-          // ... all fields
-          customFields: {},
-        };
+        return this.createEmptyProfile(userId);
       }
       // ... rest of the method
     } catch (error) {
       this.logger.error(`Failed to build user profile for: ${userId}`, error);
-      return {
-        userId,
-        username: '',
-        // ... all fields
-        customFields: {},
-      };
+      return this.createEmptyProfile(userId);
     }
   }

Also applies to: 426-445


653-658: Use entity name instead of hardcoded table name

Using hardcoded table names can lead to maintenance issues if table names change. Consider using the entity class name.

-      const fieldContexts = await this.userRepository.manager
-        .getRepository('Fields')
-        .createQueryBuilder('f')
-        .select(['f.fieldId', 'f.context', 'f.contextType'])
-        .where('f.fieldId IN (:...fieldIds)', { fieldIds })
-        .getMany();
+      // Import the Fields entity at the top of the file
+      const fieldContexts = await this.userRepository.manager
+        .getRepository(Fields) // Use the entity class
+        .createQueryBuilder('f')
+        .select(['f.fieldId', 'f.context', 'f.contextType'])
+        .where('f.fieldId IN (:...fieldIds)', { fieldIds })
+        .getMany();

689-699: Remove duplicate JSDoc comments

Yet another duplicate JSDoc block. Remove the redundant one.

-  /**
-   * Get user document from Elasticsearch
-   * 
-   * @param userId - User ID
-   * @returns Promise<IUser | null>
-   */
   /**
    * Get user document from Elasticsearch
    * 
    * @param userId - User ID to retrieve
    * @returns Promise resolving to user document or null if not found
    */

30-39: Add unit tests for the ElasticsearchSyncService

This service contains critical synchronization logic but lacks unit tests. Consider adding comprehensive test coverage for:

  • Profile synchronization with various data scenarios
  • Application data updates
  • Error handling and recovery
  • Painless script generation
  • Custom field filtering logic

Would you like me to generate unit tests for this service or create an issue to track this task?

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 993604f and c917c98.

📒 Files selected for processing (5)
  • src/adapters/postgres/cohortMembers-adapter.ts (5 hunks)
  • src/adapters/postgres/user-adapter.ts (5 hunks)
  • src/elasticsearch/elasticsearch-sync.service.ts (1 hunks)
  • src/elasticsearch/elasticsearch.module.ts (1 hunks)
  • src/forms/services/form-submission.service.ts (9 hunks)
📓 Path-based instructions (1)
**/*.ts

⚙️ CodeRabbit Configuration File

**/*.ts: "Review the JavaScript code for conformity with the Google JavaScript style guide, highlighting any deviations. Ensure that:

  • The code adheres to best practices associated with nodejs.
  • The code adheres to best practices associated with nestjs framework.
  • The code adheres to best practices recommended for performance.
  • The code adheres to similar naming conventions for controllers, models, services, methods, variables."

Files:

  • src/adapters/postgres/user-adapter.ts
  • src/elasticsearch/elasticsearch.module.ts
  • src/adapters/postgres/cohortMembers-adapter.ts
  • src/forms/services/form-submission.service.ts
  • src/elasticsearch/elasticsearch-sync.service.ts
🧬 Code Graph Analysis (1)
src/elasticsearch/elasticsearch-sync.service.ts (4)
src/adapters/postgres/user-adapter.ts (3)
  • PostgresUserService (60-2978)
  • constructor (72-111)
  • publishUserEvent (2841-2977)
src/elasticsearch/interfaces/user.interface.ts (3)
  • IProfile (42-60)
  • IApplication (1-34)
  • IUser (81-88)
src/common/utils/elasticsearch.util.ts (1)
  • isElasticsearchEnabled (1-3)
src/common/logger/LoggerUtil.ts (1)
  • LoggerUtil (3-78)
🪛 ESLint
src/adapters/postgres/user-adapter.ts

[error] 50-50: Replace '../../elasticsearch/elasticsearch-sync.service' with "../../elasticsearch/elasticsearch-sync.service"

(prettier/prettier)


[error] 1575-1575: Replace userForElastic.userId,·userForElastic.profile with ⏎············userForElastic.userId,⏎············userForElastic.profile⏎··········

(prettier/prettier)


[error] 2783-2783: Replace 'string' with "string"

(prettier/prettier)


[error] 2816-2816: Replace 'Failed·to·sync·user·profile·to·Elasticsearch' with "Failed·to·sync·user·profile·to·Elasticsearch"

(prettier/prettier)

src/elasticsearch/elasticsearch.module.ts

[error] 3-3: Replace '@nestjs/typeorm' with "@nestjs/typeorm"

(prettier/prettier)


[error] 4-4: Replace './elasticsearch.service' with "./elasticsearch.service"

(prettier/prettier)


[error] 5-5: Replace './user-elasticsearch.service' with "./user-elasticsearch.service"

(prettier/prettier)


[error] 6-6: Replace './elasticsearch.config' with "./elasticsearch.config"

(prettier/prettier)


[error] 7-7: Replace './user-elasticsearch.controller' with "./user-elasticsearch.controller"

(prettier/prettier)


[error] 8-8: Replace './elasticsearch-sync.service' with "./elasticsearch-sync.service"

(prettier/prettier)


[error] 9-9: Replace '../user/entities/user-entity' with "../user/entities/user-entity"

(prettier/prettier)


[error] 18-18: Insert ,

(prettier/prettier)


[error] 20-20: Replace ElasticsearchService,·UserElasticsearchService,·ElasticsearchSyncService with ⏎····ElasticsearchService,⏎····UserElasticsearchService,⏎····ElasticsearchSyncService,⏎··

(prettier/prettier)

src/adapters/postgres/cohortMembers-adapter.ts

[error] 36-36: Replace 'src/elasticsearch/elasticsearch-sync.service' with "src/elasticsearch/elasticsearch-sync.service"

(prettier/prettier)


[error] 727-727: Replace 'active' with "active"

(prettier/prettier)


[error] 1093-1093: Replace 'active' with "active"

(prettier/prettier)


[error] 1343-1343: Delete ·

(prettier/prettier)


[error] 1367-1367: Insert ⏎············

(prettier/prettier)


[error] 1368-1368: Replace userDoc·=>·userDoc?.applications?.find(app·=>·app.cohortId·===·cohortId) with (userDoc)·=>⏎··············userDoc?.applications?.find((app)·=>·app.cohortId·===·cohortId)⏎············

(prettier/prettier)

src/forms/services/form-submission.service.ts

[error] 31-31: Replace '../../elasticsearch/elasticsearch-sync.service' with "../../elasticsearch/elasticsearch-sync.service"

(prettier/prettier)


[error] 1173-1173: Replace userId with ⏎········userId⏎······

(prettier/prettier)


[error] 1500-1500: Replace userId with ⏎················userId⏎··············

(prettier/prettier)


[error] 1505-1505: Replace 'Failed·to·sync·user·data·to·Elasticsearch:',·syncError with ⏎············"Failed·to·sync·user·data·to·Elasticsearch:",⏎············syncError⏎··········

(prettier/prettier)


[error] 2667-2667: Replace Built·${applications.length}·applications·in·buildUserDocumentForElasticsearch·for·user:·${userId} with ⏎······Built·${applications.length}·applications·in·buildUserDocumentForElasticsearch·for·user:·${userId}⏎····

(prettier/prettier)


[error] 2668-2668: Replace CohortMembers·found:·${cohortMemberships.length},·FormSubmissions·found:·${submissions.length} with ⏎······CohortMembers·found:·${cohortMemberships.length},·FormSubmissions·found:·${submissions.length}⏎····

(prettier/prettier)


[error] 2669-2669: Replace ',·' with ",·"

(prettier/prettier)


[error] 2671-2671: Replace Sample·application:·${JSON.stringify(applications[0],·null,·2)} with ⏎········Sample·application:·${JSON.stringify(applications[0],·null,·2)}⏎······

(prettier/prettier)


[error] 3029-3029: Replace buildUserDocumentForElasticsearch·returning·${applications.length}·applications·for·user:·${userId} with ⏎······buildUserDocumentForElasticsearch·returning·${applications.length}·applications·for·user:·${userId}⏎····

(prettier/prettier)


[error] 3031-3031: Replace First·application:·${JSON.stringify(applications[0],·null,·2)} with ⏎········First·application:·${JSON.stringify(applications[0],·null,·2)}⏎······

(prettier/prettier)

src/elasticsearch/elasticsearch-sync.service.ts

[error] 1-1: Replace '@nestjs/common' with "@nestjs/common"

(prettier/prettier)


[error] 2-2: Replace '@nestjs/typeorm' with "@nestjs/typeorm"

(prettier/prettier)


[error] 3-3: Replace 'typeorm' with "typeorm"

(prettier/prettier)


[error] 4-4: Replace './user-elasticsearch.service' with "./user-elasticsearch.service"

(prettier/prettier)


[error] 5-5: Replace './interfaces/user.interface' with "./interfaces/user.interface"

(prettier/prettier)


[error] 6-6: Replace '../common/utils/elasticsearch.util' with "../common/utils/elasticsearch.util"

(prettier/prettier)


[error] 7-7: Replace '../common/logger/LoggerUtil' with "../common/logger/LoggerUtil"

(prettier/prettier)


[error] 8-8: Replace '../user/entities/user-entity' with "../user/entities/user-entity"

(prettier/prettier)


[error] 12-12: Delete ·

(prettier/prettier)


[error] 15-15: Delete ·

(prettier/prettier)


[error] 24-24: Delete ·

(prettier/prettier)


[error] 42-42: Delete ·

(prettier/prettier)


[error] 51-51: Delete ·

(prettier/prettier)


[error] 65-65: Replace Elasticsearch·disabled,·skipping·sync·for·user:·${userId} with ⏎········Elasticsearch·disabled,·skipping·sync·for·user:·${userId}⏎······

(prettier/prettier)


[error] 81-81: Insert ⏎···········

(prettier/prettier)


[error] 86-86: Delete ·

(prettier/prettier)


[error] 90-90: Replace Built·${applications.length}·applications·for·user:·${userId} with ⏎········Built·${applications.length}·applications·for·user:·${userId}⏎······

(prettier/prettier)


[error] 108-108: Replace userId,·customFieldsProvider,·applicationDataProvider with ⏎············userId,⏎············customFieldsProvider,⏎············applicationDataProvider⏎··········

(prettier/prettier)


[error] 114-114: Replace 'Failed·to·sync·user·profile·to·Elasticsearch',·error?.message·||·'Unknown·error',·'ElasticsearchSyncService',·userId with ⏎········"Failed·to·sync·user·profile·to·Elasticsearch",⏎········error?.message·||·"Unknown·error",⏎········"ElasticsearchSyncService",⏎········userId⏎······

(prettier/prettier)


[error] 122-122: Delete ·

(prettier/prettier)


[error] 140-140: Replace userId:·string,·cohortId:·string with ⏎······userId:·string,⏎······cohortId:·string⏎····

(prettier/prettier)


[error] 143-143: Replace Elasticsearch·disabled,·skipping·application·sync·for·user:·${userId},·cohort:·${cohortId} with ⏎········Elasticsearch·disabled,·skipping·application·sync·for·user:·${userId},·cohort:·${cohortId}⏎······

(prettier/prettier)


[error] 148-148: Replace Starting·application·sync·for·user:·${userId},·cohort:·${cohortId} with ⏎········Starting·application·sync·for·user:·${userId},·cohort:·${cohortId}⏎······

(prettier/prettier)


[error] 152-152: Delete ······

(prettier/prettier)


[error] 154-154: Insert ⏎·······

(prettier/prettier)


[error] 155-155: Insert ··

(prettier/prettier)


[error] 156-156: Replace ········ with ··········

(prettier/prettier)


[error] 157-157: Delete ······

(prettier/prettier)


[error] 158-158: Insert ⏎·······

(prettier/prettier)


[error] 159-159: Replace ?·source.applications.find(app with ··?·source.applications.find((app)

(prettier/prettier)


[error] 160-160: Insert ··

(prettier/prettier)


[error] 177-177: Delete ············

(prettier/prettier)


[error] 197-197: Replace userId,·cohortId,·updateData,·applicationDataProvider with ⏎··········userId,⏎··········cohortId,⏎··········updateData,⏎··········applicationDataProvider⏎········

(prettier/prettier)


[error] 200-200: Replace Successfully·synced·application·for·user:·${userId},·cohort:·${cohortId} with ⏎········Successfully·synced·application·for·user:·${userId},·cohort:·${cohortId}⏎······

(prettier/prettier)


[error] 202-202: Replace 'Failed·to·sync·user·application·to·Elasticsearch',·error?.message·||·'Unknown·error',·'ElasticsearchSyncService',·userId with ⏎········"Failed·to·sync·user·application·to·Elasticsearch",⏎········error?.message·||·"Unknown·error",⏎········"ElasticsearchSyncService",⏎········userId⏎······

(prettier/prettier)


[error] 209-209: Delete ·

(prettier/prettier)


[error] 227-227: Replace userId:·string,·cohortId:·string with ⏎······userId:·string,⏎······cohortId:·string⏎····

(prettier/prettier)


[error] 230-230: Replace Elasticsearch·disabled,·skipping·application·update·for·user:·${userId},·cohort:·${cohortId} with ⏎········Elasticsearch·disabled,·skipping·application·update·for·user:·${userId},·cohort:·${cohortId}⏎······

(prettier/prettier)


[error] 235-235: Replace Updating·application·data·for·user:·${userId},·cohort:·${cohortId} with ⏎········Updating·application·data·for·user:·${userId},·cohort:·${cohortId}⏎······

(prettier/prettier)


[error] 266-266: Replace Successfully·updated·application·data·for·user:·${userId},·cohort:·${cohortId} with ⏎········Successfully·updated·application·data·for·user:·${userId},·cohort:·${cohortId}⏎······

(prettier/prettier)


[error] 268-268: Replace 'Failed·to·update·application·data·in·Elasticsearch',·error?.message·||·'Unknown·error',·'ElasticsearchSyncService',·userId with ⏎········"Failed·to·update·application·data·in·Elasticsearch",⏎········error?.message·||·"Unknown·error",⏎········"ElasticsearchSyncService",⏎········userId⏎······

(prettier/prettier)


[error] 275-275: Delete ·

(prettier/prettier)


[error] 296-296: Replace Elasticsearch·disabled,·skipping·form·submission·sync·for·user:·${userId} with ⏎········Elasticsearch·disabled,·skipping·form·submission·sync·for·user:·${userId}⏎······

(prettier/prettier)


[error] 301-301: Replace Syncing·form·submission·data·for·user:·${userId},·form:·${submissionData.formId} with ⏎········Syncing·form·submission·data·for·user:·${userId},·form:·${submissionData.formId}⏎······

(prettier/prettier)


[error] 304-304: Delete ·

(prettier/prettier)


[error] 306-306: Replace 'Unknown·Cohort',·status:·'active' with "Unknown·Cohort",·status:·"active"

(prettier/prettier)


[error] 323-326: Replace ⏎········userId,⏎········submissionData.formId,⏎······· with userId,·submissionData.formId,

(prettier/prettier)


[error] 327-327: Delete ··

(prettier/prettier)


[error] 328-328: Delete ··

(prettier/prettier)


[error] 329-329: Delete ··

(prettier/prettier)


[error] 330-330: Delete ··

(prettier/prettier)


[error] 331-332: Replace ··}⏎······ with }

(prettier/prettier)


[error] 334-334: Replace Successfully·synced·form·submission·data·for·user:·${userId},·form:·${submissionData.formId} with ⏎········Successfully·synced·form·submission·data·for·user:·${userId},·form:·${submissionData.formId}⏎······

(prettier/prettier)


[error] 336-336: Replace 'Failed·to·sync·form·submission·data·to·Elasticsearch',·error?.message·||·'Unknown·error',·'ElasticsearchSyncService',·userId with ⏎········"Failed·to·sync·form·submission·data·to·Elasticsearch",⏎········error?.message·||·"Unknown·error",⏎········"ElasticsearchSyncService",⏎········userId⏎······

(prettier/prettier)


[error] 343-343: Delete ·

(prettier/prettier)


[error] 350-350: Delete ·

(prettier/prettier)


[error] 368-368: Replace '' with ""

(prettier/prettier)


[error] 369-369: Replace '' with ""

(prettier/prettier)


[error] 370-370: Replace '' with ""

(prettier/prettier)


[error] 371-371: Replace '' with ""

(prettier/prettier)


[error] 372-372: Replace '' with ""

(prettier/prettier)


[error] 373-373: Replace '' with ""

(prettier/prettier)


[error] 374-374: Replace '' with ""

(prettier/prettier)


[error] 375-375: Replace '' with ""

(prettier/prettier)


[error] 376-376: Replace '' with ""

(prettier/prettier)


[error] 377-377: Replace '' with ""

(prettier/prettier)


[error] 378-378: Replace '' with ""

(prettier/prettier)


[error] 379-379: Replace '' with ""

(prettier/prettier)


[error] 380-380: Replace '' with ""

(prettier/prettier)


[error] 381-381: Replace '' with ""

(prettier/prettier)


[error] 382-382: Replace 'inactive' with "inactive"

(prettier/prettier)


[error] 388-388: Delete ·

(prettier/prettier)


[error] 393-393: Replace userId,·allCustomFields with ⏎········userId,⏎········allCustomFields⏎······

(prettier/prettier)


[error] 399-399: Replace 'string' with "string"

(prettier/prettier)


[error] 406-406: Replace '' with ""

(prettier/prettier)


[error] 407-407: Replace '' with ""

(prettier/prettier)


[error] 408-408: Replace '' with ""

(prettier/prettier)


[error] 409-409: Replace '' with ""

(prettier/prettier)


[error] 410-410: Replace '' with ""

(prettier/prettier)


[error] 411-411: Replace '' with ""

(prettier/prettier)


[error] 412-412: Replace '' with ""

(prettier/prettier)


[error] 413-413: Replace '' with ""

(prettier/prettier)


[error] 414-414: Replace '' with ""

(prettier/prettier)


[error] 415-415: Replace '' with ""

(prettier/prettier)


[error] 416-416: Replace '' with ""

(prettier/prettier)


[error] 417-417: Replace '' with ""

(prettier/prettier)


[error] 418-418: Replace '' with ""

(prettier/prettier)


[error] 419-419: Replace '' with ""

(prettier/prettier)


[error] 420-420: Replace 'active' with "active"

(prettier/prettier)


[error] 421-421: Insert ⏎·········

(prettier/prettier)


[error] 428-428: Replace '' with ""

(prettier/prettier)


[error] 429-429: Replace '' with ""

(prettier/prettier)


[error] 430-430: Replace '' with ""

(prettier/prettier)


[error] 431-431: Replace '' with ""

(prettier/prettier)


[error] 432-432: Replace '' with ""

(prettier/prettier)


[error] 433-433: Replace '' with ""

(prettier/prettier)


[error] 434-434: Replace '' with ""

(prettier/prettier)


[error] 435-435: Replace '' with ""

(prettier/prettier)


[error] 436-436: Replace '' with ""

(prettier/prettier)


[error] 437-437: Replace '' with ""

(prettier/prettier)


[error] 438-438: Replace '' with ""

(prettier/prettier)


[error] 439-439: Replace '' with ""

(prettier/prettier)


[error] 440-440: Replace '' with ""

(prettier/prettier)


[error] 441-441: Replace '' with ""

(prettier/prettier)


[error] 442-442: Replace 'inactive' with "inactive"

(prettier/prettier)


[error] 450-450: Delete ·

(prettier/prettier)


[error] 463-463: Delete ·

(prettier/prettier)


[error] 476-476: Replace ``Failed·to·build·complete·user·document·for:·${userId},·error with `⏎········`Failed·to·build·complete·user·document·for:·${userId}`,⏎········error⏎······`

(prettier/prettier)


[error] 483-483: Delete ·

(prettier/prettier)


[error] 554-554: Replace 'painless' with "painless"

(prettier/prettier)


[error] 567-567: Delete ·

(prettier/prettier)


[error] 571-571: Replace customFields:·any[] with ⏎····customFields:·any[]⏎··

(prettier/prettier)


[error] 597-597: Delete ·

(prettier/prettier)


[error] 606-606: Replace 'object' with "object"

(prettier/prettier)


[error] 615-615: Delete ·

(prettier/prettier)


[error] 622-622: Replace field with (field)

(prettier/prettier)


[error] 623-623: Replace 'USER'·||·field.context·===·'USERS' with "USER"·||·field.context·===·"USERS"

(prettier/prettier)


[error] 629-629: Replace field·=>·!formFieldIdsSet.has(field.fieldId) with ⏎········(field)·=>·!formFieldIdsSet.has(field.fieldId)⏎······

(prettier/prettier)


[error] 638-638: Delete ·

(prettier/prettier)


[error] 643-643: Replace userId:·string,·customFields:·any[] with ⏎····userId:·string,⏎····customFields:·any[]⏎··

(prettier/prettier)


[error] 650-650: Replace field with (field)

(prettier/prettier)


[error] 654-654: Replace 'Fields' with "Fields"

(prettier/prettier)


[error] 655-655: Replace 'f' with "f"

(prettier/prettier)


[error] 656-656: Replace 'f.fieldId',·'f.context',·'f.contextType' with "f.fieldId",·"f.context",·"f.contextType"

(prettier/prettier)


[error] 657-657: Replace 'f.fieldId·IN·(:...fieldIds)' with "f.fieldId·IN·(:...fieldIds)"

(prettier/prettier)


[error] 662-662: Replace field with (field)

(prettier/prettier)


[error] 667-667: Replace field with (field)

(prettier/prettier)


[error] 669-669: Replace 'USER'·||·context·===·'USERS' with "USER"·||·context·===·"USERS"

(prettier/prettier)


[error] 670-670: Delete ········

(prettier/prettier)


[error] 672-672: Replace Excluding·field·${field.fieldId}·(${field.label})·with·context:·${context}·for·user:·${userId} with ⏎············Excluding·field·${field.fieldId}·(${field.label})·with·context:·${context}·for·user:·${userId}⏎··········

(prettier/prettier)


[error] 674-674: Delete ········

(prettier/prettier)


[error] 678-678: Replace Filtered·${customFields.length}·total·fields·to·${profileFields.length}·profile·fields·for·user:·${userId}`);` with `⏎········`Filtered·${customFields.length}·total·fields·to·${profileFields.length}·profile·fields·for·user:·${userId}

(prettier/prettier)


[error] 679-679: Insert );⏎

(prettier/prettier)


[error] 682-682: Replace ``Failed·to·filter·profile·custom·fields·for·user:·${userId},·error with `⏎········`Failed·to·filter·profile·custom·fields·for·user:·${userId}`,⏎········error⏎······`

(prettier/prettier)


[error] 690-690: Delete ·

(prettier/prettier)


[error] 696-696: Delete ·

(prettier/prettier)


[error] 702-702: Replace Elasticsearch·disabled,·skipping·get·user·document·for:·${userId} with ⏎········Elasticsearch·disabled,·skipping·get·user·document·for:·${userId}⏎······

(prettier/prettier)


[error] 709-709: Delete ······

(prettier/prettier)


[error] 714-714: Delete ······

(prettier/prettier)


[error] 717-717: Replace 'Failed·to·get·user·document·from·Elasticsearch',·error?.message·||·'Unknown·error',·'ElasticsearchSyncService',·userId with ⏎········"Failed·to·get·user·document·from·Elasticsearch",⏎········error?.message·||·"Unknown·error",⏎········"ElasticsearchSyncService",⏎········userId⏎······

(prettier/prettier)


[error] 724-724: Delete ·

(prettier/prettier)


[error] 737-737: Replace 'Failed·to·delete·user·document·from·Elasticsearch',·error?.message·||·'Unknown·error',·'ElasticsearchSyncService',·userId with ⏎········"Failed·to·delete·user·document·from·Elasticsearch",⏎········error?.message·||·"Unknown·error",⏎········"ElasticsearchSyncService",⏎········userId⏎······

(prettier/prettier)


[error] 743-743: Delete ·

(prettier/prettier)


[error] 762-762: Replace 'Failed·to·search·users·in·Elasticsearch' with "Failed·to·search·users·in·Elasticsearch"

(prettier/prettier)


[error] 766-766: Replace · with

(prettier/prettier)

🪛 Biome (1.9.4)
src/forms/services/form-submission.service.ts

[error] 3029-3032: This code is unreachable

(lint/correctness/noUnreachable)

src/elasticsearch/elasticsearch-sync.service.ts

[error] 154-154: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 711-711: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🧰 Additional context used
📓 Path-based instructions (1)
**/*.ts

⚙️ CodeRabbit Configuration File

**/*.ts: "Review the JavaScript code for conformity with the Google JavaScript style guide, highlighting any deviations. Ensure that:

  • The code adheres to best practices associated with nodejs.
  • The code adheres to best practices associated with nestjs framework.
  • The code adheres to best practices recommended for performance.
  • The code adheres to similar naming conventions for controllers, models, services, methods, variables."

Files:

  • src/adapters/postgres/user-adapter.ts
  • src/elasticsearch/elasticsearch.module.ts
  • src/adapters/postgres/cohortMembers-adapter.ts
  • src/forms/services/form-submission.service.ts
  • src/elasticsearch/elasticsearch-sync.service.ts
🧬 Code Graph Analysis (1)
src/elasticsearch/elasticsearch-sync.service.ts (4)
src/adapters/postgres/user-adapter.ts (3)
  • PostgresUserService (60-2978)
  • constructor (72-111)
  • publishUserEvent (2841-2977)
src/elasticsearch/interfaces/user.interface.ts (3)
  • IProfile (42-60)
  • IApplication (1-34)
  • IUser (81-88)
src/common/utils/elasticsearch.util.ts (1)
  • isElasticsearchEnabled (1-3)
src/common/logger/LoggerUtil.ts (1)
  • LoggerUtil (3-78)
🪛 ESLint
src/adapters/postgres/user-adapter.ts

[error] 50-50: Replace '../../elasticsearch/elasticsearch-sync.service' with "../../elasticsearch/elasticsearch-sync.service"

(prettier/prettier)


[error] 1575-1575: Replace userForElastic.userId,·userForElastic.profile with ⏎············userForElastic.userId,⏎············userForElastic.profile⏎··········

(prettier/prettier)


[error] 2783-2783: Replace 'string' with "string"

(prettier/prettier)


[error] 2816-2816: Replace 'Failed·to·sync·user·profile·to·Elasticsearch' with "Failed·to·sync·user·profile·to·Elasticsearch"

(prettier/prettier)

src/elasticsearch/elasticsearch.module.ts

[error] 3-3: Replace '@nestjs/typeorm' with "@nestjs/typeorm"

(prettier/prettier)


[error] 4-4: Replace './elasticsearch.service' with "./elasticsearch.service"

(prettier/prettier)


[error] 5-5: Replace './user-elasticsearch.service' with "./user-elasticsearch.service"

(prettier/prettier)


[error] 6-6: Replace './elasticsearch.config' with "./elasticsearch.config"

(prettier/prettier)


[error] 7-7: Replace './user-elasticsearch.controller' with "./user-elasticsearch.controller"

(prettier/prettier)


[error] 8-8: Replace './elasticsearch-sync.service' with "./elasticsearch-sync.service"

(prettier/prettier)


[error] 9-9: Replace '../user/entities/user-entity' with "../user/entities/user-entity"

(prettier/prettier)


[error] 18-18: Insert ,

(prettier/prettier)


[error] 20-20: Replace ElasticsearchService,·UserElasticsearchService,·ElasticsearchSyncService with ⏎····ElasticsearchService,⏎····UserElasticsearchService,⏎····ElasticsearchSyncService,⏎··

(prettier/prettier)

src/adapters/postgres/cohortMembers-adapter.ts

[error] 36-36: Replace 'src/elasticsearch/elasticsearch-sync.service' with "src/elasticsearch/elasticsearch-sync.service"

(prettier/prettier)


[error] 727-727: Replace 'active' with "active"

(prettier/prettier)


[error] 1093-1093: Replace 'active' with "active"

(prettier/prettier)


[error] 1343-1343: Delete ·

(prettier/prettier)


[error] 1367-1367: Insert ⏎············

(prettier/prettier)


[error] 1368-1368: Replace userDoc·=>·userDoc?.applications?.find(app·=>·app.cohortId·===·cohortId) with (userDoc)·=>⏎··············userDoc?.applications?.find((app)·=>·app.cohortId·===·cohortId)⏎············

(prettier/prettier)

src/forms/services/form-submission.service.ts

[error] 31-31: Replace '../../elasticsearch/elasticsearch-sync.service' with "../../elasticsearch/elasticsearch-sync.service"

(prettier/prettier)


[error] 1173-1173: Replace userId with ⏎········userId⏎······

(prettier/prettier)


[error] 1500-1500: Replace userId with ⏎················userId⏎··············

(prettier/prettier)


[error] 1505-1505: Replace 'Failed·to·sync·user·data·to·Elasticsearch:',·syncError with ⏎············"Failed·to·sync·user·data·to·Elasticsearch:",⏎············syncError⏎··········

(prettier/prettier)


[error] 2667-2667: Replace Built·${applications.length}·applications·in·buildUserDocumentForElasticsearch·for·user:·${userId} with ⏎······Built·${applications.length}·applications·in·buildUserDocumentForElasticsearch·for·user:·${userId}⏎····

(prettier/prettier)


[error] 2668-2668: Replace CohortMembers·found:·${cohortMemberships.length},·FormSubmissions·found:·${submissions.length} with ⏎······CohortMembers·found:·${cohortMemberships.length},·FormSubmissions·found:·${submissions.length}⏎····

(prettier/prettier)


[error] 2669-2669: Replace ',·' with ",·"

(prettier/prettier)


[error] 2671-2671: Replace Sample·application:·${JSON.stringify(applications[0],·null,·2)} with ⏎········Sample·application:·${JSON.stringify(applications[0],·null,·2)}⏎······

(prettier/prettier)


[error] 3029-3029: Replace buildUserDocumentForElasticsearch·returning·${applications.length}·applications·for·user:·${userId} with ⏎······buildUserDocumentForElasticsearch·returning·${applications.length}·applications·for·user:·${userId}⏎····

(prettier/prettier)


[error] 3031-3031: Replace First·application:·${JSON.stringify(applications[0],·null,·2)} with ⏎········First·application:·${JSON.stringify(applications[0],·null,·2)}⏎······

(prettier/prettier)

src/elasticsearch/elasticsearch-sync.service.ts

[error] 1-1: Replace '@nestjs/common' with "@nestjs/common"

(prettier/prettier)


[error] 2-2: Replace '@nestjs/typeorm' with "@nestjs/typeorm"

(prettier/prettier)


[error] 3-3: Replace 'typeorm' with "typeorm"

(prettier/prettier)


[error] 4-4: Replace './user-elasticsearch.service' with "./user-elasticsearch.service"

(prettier/prettier)


[error] 5-5: Replace './interfaces/user.interface' with "./interfaces/user.interface"

(prettier/prettier)


[error] 6-6: Replace '../common/utils/elasticsearch.util' with "../common/utils/elasticsearch.util"

(prettier/prettier)


[error] 7-7: Replace '../common/logger/LoggerUtil' with "../common/logger/LoggerUtil"

(prettier/prettier)


[error] 8-8: Replace '../user/entities/user-entity' with "../user/entities/user-entity"

(prettier/prettier)


[error] 12-12: Delete ·

(prettier/prettier)


[error] 15-15: Delete ·

(prettier/prettier)


[error] 24-24: Delete ·

(prettier/prettier)


[error] 42-42: Delete ·

(prettier/prettier)


[error] 51-51: Delete ·

(prettier/prettier)


[error] 65-65: Replace Elasticsearch·disabled,·skipping·sync·for·user:·${userId} with ⏎········Elasticsearch·disabled,·skipping·sync·for·user:·${userId}⏎······

(prettier/prettier)


[error] 81-81: Insert ⏎···········

(prettier/prettier)


[error] 86-86: Delete ·

(prettier/prettier)


[error] 90-90: Replace Built·${applications.length}·applications·for·user:·${userId} with ⏎········Built·${applications.length}·applications·for·user:·${userId}⏎······

(prettier/prettier)


[error] 108-108: Replace userId,·customFieldsProvider,·applicationDataProvider with ⏎············userId,⏎············customFieldsProvider,⏎············applicationDataProvider⏎··········

(prettier/prettier)


[error] 114-114: Replace 'Failed·to·sync·user·profile·to·Elasticsearch',·error?.message·||·'Unknown·error',·'ElasticsearchSyncService',·userId with ⏎········"Failed·to·sync·user·profile·to·Elasticsearch",⏎········error?.message·||·"Unknown·error",⏎········"ElasticsearchSyncService",⏎········userId⏎······

(prettier/prettier)


[error] 122-122: Delete ·

(prettier/prettier)


[error] 140-140: Replace userId:·string,·cohortId:·string with ⏎······userId:·string,⏎······cohortId:·string⏎····

(prettier/prettier)


[error] 143-143: Replace Elasticsearch·disabled,·skipping·application·sync·for·user:·${userId},·cohort:·${cohortId} with ⏎········Elasticsearch·disabled,·skipping·application·sync·for·user:·${userId},·cohort:·${cohortId}⏎······

(prettier/prettier)


[error] 148-148: Replace Starting·application·sync·for·user:·${userId},·cohort:·${cohortId} with ⏎········Starting·application·sync·for·user:·${userId},·cohort:·${cohortId}⏎······

(prettier/prettier)


[error] 152-152: Delete ······

(prettier/prettier)


[error] 154-154: Insert ⏎·······

(prettier/prettier)


[error] 155-155: Insert ··

(prettier/prettier)


[error] 156-156: Replace ········ with ··········

(prettier/prettier)


[error] 157-157: Delete ······

(prettier/prettier)


[error] 158-158: Insert ⏎·······

(prettier/prettier)


[error] 159-159: Replace ?·source.applications.find(app with ··?·source.applications.find((app)

(prettier/prettier)


[error] 160-160: Insert ··

(prettier/prettier)


[error] 177-177: Delete ············

(prettier/prettier)


[error] 197-197: Replace userId,·cohortId,·updateData,·applicationDataProvider with ⏎··········userId,⏎··········cohortId,⏎··········updateData,⏎··········applicationDataProvider⏎········

(prettier/prettier)


[error] 200-200: Replace Successfully·synced·application·for·user:·${userId},·cohort:·${cohortId} with ⏎········Successfully·synced·application·for·user:·${userId},·cohort:·${cohortId}⏎······

(prettier/prettier)


[error] 202-202: Replace 'Failed·to·sync·user·application·to·Elasticsearch',·error?.message·||·'Unknown·error',·'ElasticsearchSyncService',·userId with ⏎········"Failed·to·sync·user·application·to·Elasticsearch",⏎········error?.message·||·"Unknown·error",⏎········"ElasticsearchSyncService",⏎········userId⏎······

(prettier/prettier)


[error] 209-209: Delete ·

(prettier/prettier)


[error] 227-227: Replace userId:·string,·cohortId:·string with ⏎······userId:·string,⏎······cohortId:·string⏎····

(prettier/prettier)


[error] 230-230: Replace Elasticsearch·disabled,·skipping·application·update·for·user:·${userId},·cohort:·${cohortId} with ⏎········Elasticsearch·disabled,·skipping·application·update·for·user:·${userId},·cohort:·${cohortId}⏎······

(prettier/prettier)


[error] 235-235: Replace Updating·application·data·for·user:·${userId},·cohort:·${cohortId} with ⏎········Updating·application·data·for·user:·${userId},·cohort:·${cohortId}⏎······

(prettier/prettier)


[error] 266-266: Replace Successfully·updated·application·data·for·user:·${userId},·cohort:·${cohortId} with ⏎········Successfully·updated·application·data·for·user:·${userId},·cohort:·${cohortId}⏎······

(prettier/prettier)


[error] 268-268: Replace 'Failed·to·update·application·data·in·Elasticsearch',·error?.message·||·'Unknown·error',·'ElasticsearchSyncService',·userId with ⏎········"Failed·to·update·application·data·in·Elasticsearch",⏎········error?.message·||·"Unknown·error",⏎········"ElasticsearchSyncService",⏎········userId⏎······

(prettier/prettier)


[error] 275-275: Delete ·

(prettier/prettier)


[error] 296-296: Replace Elasticsearch·disabled,·skipping·form·submission·sync·for·user:·${userId} with ⏎········Elasticsearch·disabled,·skipping·form·submission·sync·for·user:·${userId}⏎······

(prettier/prettier)


[error] 301-301: Replace Syncing·form·submission·data·for·user:·${userId},·form:·${submissionData.formId} with ⏎········Syncing·form·submission·data·for·user:·${userId},·form:·${submissionData.formId}⏎······

(prettier/prettier)


[error] 304-304: Delete ·

(prettier/prettier)


[error] 306-306: Replace 'Unknown·Cohort',·status:·'active' with "Unknown·Cohort",·status:·"active"

(prettier/prettier)


[error] 323-326: Replace ⏎········userId,⏎········submissionData.formId,⏎······· with userId,·submissionData.formId,

(prettier/prettier)


[error] 327-327: Delete ··

(prettier/prettier)


[error] 328-328: Delete ··

(prettier/prettier)


[error] 329-329: Delete ··

(prettier/prettier)


[error] 330-330: Delete ··

(prettier/prettier)


[error] 331-332: Replace ··}⏎······ with }

(prettier/prettier)


[error] 334-334: Replace Successfully·synced·form·submission·data·for·user:·${userId},·form:·${submissionData.formId} with ⏎········Successfully·synced·form·submission·data·for·user:·${userId},·form:·${submissionData.formId}⏎······

(prettier/prettier)


[error] 336-336: Replace 'Failed·to·sync·form·submission·data·to·Elasticsearch',·error?.message·||·'Unknown·error',·'ElasticsearchSyncService',·userId with ⏎········"Failed·to·sync·form·submission·data·to·Elasticsearch",⏎········error?.message·||·"Unknown·error",⏎········"ElasticsearchSyncService",⏎········userId⏎······

(prettier/prettier)


[error] 343-343: Delete ·

(prettier/prettier)


[error] 350-350: Delete ·

(prettier/prettier)


[error] 368-368: Replace '' with ""

(prettier/prettier)


[error] 369-369: Replace '' with ""

(prettier/prettier)


[error] 370-370: Replace '' with ""

(prettier/prettier)


[error] 371-371: Replace '' with ""

(prettier/prettier)


[error] 372-372: Replace '' with ""

(prettier/prettier)


[error] 373-373: Replace '' with ""

(prettier/prettier)


[error] 374-374: Replace '' with ""

(prettier/prettier)


[error] 375-375: Replace '' with ""

(prettier/prettier)


[error] 376-376: Replace '' with ""

(prettier/prettier)


[error] 377-377: Replace '' with ""

(prettier/prettier)


[error] 378-378: Replace '' with ""

(prettier/prettier)


[error] 379-379: Replace '' with ""

(prettier/prettier)


[error] 380-380: Replace '' with ""

(prettier/prettier)


[error] 381-381: Replace '' with ""

(prettier/prettier)


[error] 382-382: Replace 'inactive' with "inactive"

(prettier/prettier)


[error] 388-388: Delete ·

(prettier/prettier)


[error] 393-393: Replace userId,·allCustomFields with ⏎········userId,⏎········allCustomFields⏎······

(prettier/prettier)


[error] 399-399: Replace 'string' with "string"

(prettier/prettier)


[error] 406-406: Replace '' with ""

(prettier/prettier)


[error] 407-407: Replace '' with ""

(prettier/prettier)


[error] 408-408: Replace '' with ""

(prettier/prettier)


[error] 409-409: Replace '' with ""

(prettier/prettier)


[error] 410-410: Replace '' with ""

(prettier/prettier)


[error] 411-411: Replace '' with ""

(prettier/prettier)


[error] 412-412: Replace '' with ""

(prettier/prettier)


[error] 413-413: Replace '' with ""

(prettier/prettier)


[error] 414-414: Replace '' with ""

(prettier/prettier)


[error] 415-415: Replace '' with ""

(prettier/prettier)


[error] 416-416: Replace '' with ""

(prettier/prettier)


[error] 417-417: Replace '' with ""

(prettier/prettier)


[error] 418-418: Replace '' with ""

(prettier/prettier)


[error] 419-419: Replace '' with ""

(prettier/prettier)


[error] 420-420: Replace 'active' with "active"

(prettier/prettier)


[error] 421-421: Insert ⏎·········

(prettier/prettier)


[error] 428-428: Replace '' with ""

(prettier/prettier)


[error] 429-429: Replace '' with ""

(prettier/prettier)


[error] 430-430: Replace '' with ""

(prettier/prettier)


[error] 431-431: Replace '' with ""

(prettier/prettier)


[error] 432-432: Replace '' with ""

(prettier/prettier)


[error] 433-433: Replace '' with ""

(prettier/prettier)


[error] 434-434: Replace '' with ""

(prettier/prettier)


[error] 435-435: Replace '' with ""

(prettier/prettier)


[error] 436-436: Replace '' with ""

(prettier/prettier)


[error] 437-437: Replace '' with ""

(prettier/prettier)


[error] 438-438: Replace '' with ""

(prettier/prettier)


[error] 439-439: Replace '' with ""

(prettier/prettier)


[error] 440-440: Replace '' with ""

(prettier/prettier)


[error] 441-441: Replace '' with ""

(prettier/prettier)


[error] 442-442: Replace 'inactive' with "inactive"

(prettier/prettier)


[error] 450-450: Delete ·

(prettier/prettier)


[error] 463-463: Delete ·

(prettier/prettier)


[error] 476-476: Replace ``Failed·to·build·complete·user·document·for:·${userId},·error with `⏎········`Failed·to·build·complete·user·document·for:·${userId}`,⏎········error⏎······`

(prettier/prettier)


[error] 483-483: Delete ·

(prettier/prettier)


[error] 554-554: Replace 'painless' with "painless"

(prettier/prettier)


[error] 567-567: Delete ·

(prettier/prettier)


[error] 571-571: Replace customFields:·any[] with ⏎····customFields:·any[]⏎··

(prettier/prettier)


[error] 597-597: Delete ·

(prettier/prettier)


[error] 606-606: Replace 'object' with "object"

(prettier/prettier)


[error] 615-615: Delete ·

(prettier/prettier)


[error] 622-622: Replace field with (field)

(prettier/prettier)


[error] 623-623: Replace 'USER'·||·field.context·===·'USERS' with "USER"·||·field.context·===·"USERS"

(prettier/prettier)


[error] 629-629: Replace field·=>·!formFieldIdsSet.has(field.fieldId) with ⏎········(field)·=>·!formFieldIdsSet.has(field.fieldId)⏎······

(prettier/prettier)


[error] 638-638: Delete ·

(prettier/prettier)


[error] 643-643: Replace userId:·string,·customFields:·any[] with ⏎····userId:·string,⏎····customFields:·any[]⏎··

(prettier/prettier)


[error] 650-650: Replace field with (field)

(prettier/prettier)


[error] 654-654: Replace 'Fields' with "Fields"

(prettier/prettier)


[error] 655-655: Replace 'f' with "f"

(prettier/prettier)


[error] 656-656: Replace 'f.fieldId',·'f.context',·'f.contextType' with "f.fieldId",·"f.context",·"f.contextType"

(prettier/prettier)


[error] 657-657: Replace 'f.fieldId·IN·(:...fieldIds)' with "f.fieldId·IN·(:...fieldIds)"

(prettier/prettier)


[error] 662-662: Replace field with (field)

(prettier/prettier)


[error] 667-667: Replace field with (field)

(prettier/prettier)


[error] 669-669: Replace 'USER'·||·context·===·'USERS' with "USER"·||·context·===·"USERS"

(prettier/prettier)


[error] 670-670: Delete ········

(prettier/prettier)


[error] 672-672: Replace Excluding·field·${field.fieldId}·(${field.label})·with·context:·${context}·for·user:·${userId} with ⏎············Excluding·field·${field.fieldId}·(${field.label})·with·context:·${context}·for·user:·${userId}⏎··········

(prettier/prettier)


[error] 674-674: Delete ········

(prettier/prettier)


[error] 678-678: Replace Filtered·${customFields.length}·total·fields·to·${profileFields.length}·profile·fields·for·user:·${userId}`);` with `⏎········`Filtered·${customFields.length}·total·fields·to·${profileFields.length}·profile·fields·for·user:·${userId}

(prettier/prettier)


[error] 679-679: Insert );⏎

(prettier/prettier)


[error] 682-682: Replace ``Failed·to·filter·profile·custom·fields·for·user:·${userId},·error with `⏎········`Failed·to·filter·profile·custom·fields·for·user:·${userId}`,⏎········error⏎······`

(prettier/prettier)


[error] 690-690: Delete ·

(prettier/prettier)


[error] 696-696: Delete ·

(prettier/prettier)


[error] 702-702: Replace Elasticsearch·disabled,·skipping·get·user·document·for:·${userId} with ⏎········Elasticsearch·disabled,·skipping·get·user·document·for:·${userId}⏎······

(prettier/prettier)


[error] 709-709: Delete ······

(prettier/prettier)


[error] 714-714: Delete ······

(prettier/prettier)


[error] 717-717: Replace 'Failed·to·get·user·document·from·Elasticsearch',·error?.message·||·'Unknown·error',·'ElasticsearchSyncService',·userId with ⏎········"Failed·to·get·user·document·from·Elasticsearch",⏎········error?.message·||·"Unknown·error",⏎········"ElasticsearchSyncService",⏎········userId⏎······

(prettier/prettier)


[error] 724-724: Delete ·

(prettier/prettier)


[error] 737-737: Replace 'Failed·to·delete·user·document·from·Elasticsearch',·error?.message·||·'Unknown·error',·'ElasticsearchSyncService',·userId with ⏎········"Failed·to·delete·user·document·from·Elasticsearch",⏎········error?.message·||·"Unknown·error",⏎········"ElasticsearchSyncService",⏎········userId⏎······

(prettier/prettier)


[error] 743-743: Delete ·

(prettier/prettier)


[error] 762-762: Replace 'Failed·to·search·users·in·Elasticsearch' with "Failed·to·search·users·in·Elasticsearch"

(prettier/prettier)


[error] 766-766: Replace · with

(prettier/prettier)

🪛 Biome (1.9.4)
src/forms/services/form-submission.service.ts

[error] 3029-3032: This code is unreachable

(lint/correctness/noUnreachable)

src/elasticsearch/elasticsearch-sync.service.ts

[error] 154-154: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 711-711: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🔇 Additional comments (10)
src/adapters/postgres/user-adapter.ts (2)

97-97: LGTM! Proper dependency injection of ElasticsearchSyncService.

The service is correctly injected with appropriate access modifiers.


2773-2818: Excellent refactoring to use the centralized ElasticsearchSyncService!

The implementation properly:

  • Uses the callback pattern for lazy loading custom fields
  • Handles date formatting for both Date objects and strings
  • Maintains appropriate error handling without disrupting the main flow
src/adapters/postgres/cohortMembers-adapter.ts (1)

58-58: LGTM! Proper dependency injection implementation.

The ElasticsearchSyncService is correctly injected following NestJS best practices with appropriate access modifiers.

src/forms/services/form-submission.service.ts (5)

91-91: LGTM! Proper dependency injection of the new centralized service.

The ElasticsearchSyncService is correctly injected following NestJS best practices.


1173-1180: Excellent refactoring to use the centralized Elasticsearch service.

The changes properly consolidate Elasticsearch operations while maintaining error handling and logging. The callback pattern for providing application data is a clean architectural choice.

Also applies to: 1491-1507


1536-1544: LGTM! Consistent removal of custom fields from cohort details.

The removal of customFields from cohort details is properly implemented across all relevant methods with clear documentation.

Also applies to: 1940-1948, 2634-2642


1979-1979: LGTM! Method visibility change is well-justified.

Making buildUserDocumentForElasticsearch public is appropriate since it serves as a callback for other services in the new centralized architecture.


3041-3048: Good addition of centralized field value processing.

The processFieldValueForElasticsearch method properly handles array-to-string conversion for Elasticsearch storage and is consistently used throughout the code.

src/elasticsearch/elasticsearch-sync.service.ts (2)

488-563: Well-implemented Painless script for atomic updates

The Painless script implementation is robust with proper null checks, initialization of missing arrays, and atomic updates. Good use of parameterized queries to prevent injection attacks.


114-116: Good error handling strategy for non-critical operations

The consistent error handling pattern across all methods is well-designed:

  • Errors are logged with context but not thrown
  • This prevents Elasticsearch sync failures from affecting the main application flow
  • All error logs include the userId for debugging

This is appropriate for a sync service where failures shouldn't break core functionality.

Also applies to: 202-204, 268-270, 336-338, 717-719, 737-739

Copy link

@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: 0

♻️ Duplicate comments (5)
src/elasticsearch/elasticsearch-sync.service.ts (5)

153-159: Use optional chaining for safer property access

Replace the conditional checks with optional chaining for cleaner and safer code.

-      const source = userDoc && userDoc._source
-        ? (userDoc._source as { applications?: any[] })
-        : undefined;
-      
-      const existingApplication = source && Array.isArray(source.applications)
-        ? source.applications.find(app => app.cohortId === cohortId)
-        : undefined;
+      const source = userDoc?._source as { applications?: any[] } | undefined;
+      
+      const existingApplication = source?.applications?.find(app => app.cohortId === cohortId);

735-739: Use optional chaining for cleaner code

Simplify the conditional check using optional chaining.

-      // Convert Elasticsearch result to IUser format
-      if (result && result._source) {
-        return result._source as IUser;
-      }
-      
-      return null;
+      // Convert Elasticsearch result to IUser format
+      return result?._source as IUser ?? null;

1-8: Use consistent logging approach throughout the service

The service uses both NestJS's built-in Logger and a custom LoggerUtil, creating inconsistency in logging patterns. The built-in logger is used for debug logs while LoggerUtil is used for error logs.

Choose one logging approach for consistency:

-import { Injectable, Logger } from '@nestjs/common';
+import { Injectable } from '@nestjs/common';
 import { InjectRepository } from '@nestjs/typeorm';
 import { Repository } from 'typeorm';
 import { UserElasticsearchService } from './user-elasticsearch.service';
 import { IUser, IProfile, IApplication } from './interfaces/user.interface';
 import { isElasticsearchEnabled } from '../common/utils/elasticsearch.util';
 import { LoggerUtil } from '../common/logger/LoggerUtil';
 import { User } from '../user/entities/user-entity';

 @Injectable()
 export class ElasticsearchSyncService {
-  private readonly logger = new Logger(ElasticsearchSyncService.name);

   constructor(
     private readonly userElasticsearchService: UserElasticsearchService,
     @InjectRepository(User)
     private readonly userRepository: Repository<User>
   ) {}

Then update all logger calls to use LoggerUtil consistently.

Also applies to: 32-33


163-192: Remove code duplication when building user documents

There's duplicate code for building user documents. Extract this into a helper method or reuse existing functionality.

         if (applicationDataProvider) {
           const fullUserDoc = await applicationDataProvider(userId, cohortId);
           if (fullUserDoc) {
-            // Convert IApplication to IUser format for Elasticsearch update
-            const userDocument: IUser = {
-              userId,
-              profile: await this.buildUserProfile(userId),
-              applications: [fullUserDoc],
-              courses: [],
-              createdAt: new Date().toISOString(),
-              updatedAt: new Date().toISOString(),
-            };
+            const userDocument = await this.buildCompleteUserDocument(
+              userId,
+              undefined,
+              async () => [fullUserDoc]
+            );
             
             await this.userElasticsearchService.updateUser(
               userId,
               { doc: userDocument },
-              async (userId: string) => {
-                const appData = await applicationDataProvider(userId, cohortId);
-                return {
-                  userId,
-                  profile: await this.buildUserProfile(userId),
-                  applications: [appData],
-                  courses: [],
-                  createdAt: new Date().toISOString(),
-                  updatedAt: new Date().toISOString(),
-                };
-              }
+              async () => userDocument
             );
           }
         }

334-335: Fix unused variable and clarify formId as cohortId usage

The application variable is built but never used. Additionally, using formId as cohortId is marked as temporary and could lead to data inconsistency.

The temporary use of formId as cohortId needs to be addressed properly. Consider either:

  1. Adding a proper cohortId parameter to the method
  2. Documenting why formId is being used as cohortId
  3. Creating a mapping between formId and cohortId

Also, remove the unused application variable since the data is passed directly to updateApplicationData.

🧹 Nitpick comments (1)
src/elasticsearch/elasticsearch-sync.service.ts (1)

40-57: Remove duplicate JSDoc comment

There are two identical JSDoc comment blocks for the syncUserProfile method. Remove one of them.

-  /**
-   * Sync user profile to Elasticsearch with comprehensive data fetching
-   * 
-   * @param userId - User ID to sync
-   * @param profileData - Profile data to sync (optional, will fetch from DB if not provided)
-   * @param customFieldsProvider - Function to get custom fields (optional)
-   * @param applicationDataProvider - Function to get application data (optional)
-   * @returns Promise<void>
-   */
   /**
    * Sync user profile to Elasticsearch with custom fields support
    * 
    * @param userId - User ID to sync
    * @param profileData - Profile data to sync (optional, will fetch from DB if not provided)
    * @param customFieldsProvider - Function to get custom fields (optional)
    * @param applicationDataProvider - Function to get application data (optional)
    * @returns Promise<void>
    */
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between c917c98 and 9c89c3f.

📒 Files selected for processing (1)
  • src/elasticsearch/elasticsearch-sync.service.ts (1 hunks)
📓 Path-based instructions (1)
**/*.ts

⚙️ CodeRabbit Configuration File

**/*.ts: "Review the JavaScript code for conformity with the Google JavaScript style guide, highlighting any deviations. Ensure that:

  • The code adheres to best practices associated with nodejs.
  • The code adheres to best practices associated with nestjs framework.
  • The code adheres to best practices recommended for performance.
  • The code adheres to similar naming conventions for controllers, models, services, methods, variables."

Files:

  • src/elasticsearch/elasticsearch-sync.service.ts
🧬 Code Graph Analysis (1)
src/elasticsearch/elasticsearch-sync.service.ts (4)
src/adapters/postgres/user-adapter.ts (2)
  • updateUser (843-1056)
  • PostgresUserService (60-2978)
src/elasticsearch/interfaces/user.interface.ts (3)
  • IProfile (42-60)
  • IApplication (1-34)
  • IUser (81-88)
src/common/utils/elasticsearch.util.ts (1)
  • isElasticsearchEnabled (1-3)
src/common/logger/LoggerUtil.ts (1)
  • LoggerUtil (3-78)
🪛 Biome (1.9.4)
src/elasticsearch/elasticsearch-sync.service.ts

[error] 153-153: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 736-736: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🪛 ESLint
src/elasticsearch/elasticsearch-sync.service.ts

[error] 1-1: Replace '@nestjs/common' with "@nestjs/common"

(prettier/prettier)


[error] 2-2: Replace '@nestjs/typeorm' with "@nestjs/typeorm"

(prettier/prettier)


[error] 3-3: Replace 'typeorm' with "typeorm"

(prettier/prettier)


[error] 4-4: Replace './user-elasticsearch.service' with "./user-elasticsearch.service"

(prettier/prettier)


[error] 5-5: Replace './interfaces/user.interface' with "./interfaces/user.interface"

(prettier/prettier)


[error] 6-6: Replace '../common/utils/elasticsearch.util' with "../common/utils/elasticsearch.util"

(prettier/prettier)


[error] 7-7: Replace '../common/logger/LoggerUtil' with "../common/logger/LoggerUtil"

(prettier/prettier)


[error] 8-8: Replace '../user/entities/user-entity' with "../user/entities/user-entity"

(prettier/prettier)


[error] 12-12: Delete ·

(prettier/prettier)


[error] 15-15: Delete ·

(prettier/prettier)


[error] 24-24: Delete ·

(prettier/prettier)


[error] 42-42: Delete ·

(prettier/prettier)


[error] 51-51: Delete ·

(prettier/prettier)


[error] 65-65: Replace Elasticsearch·disabled,·skipping·sync·for·user:·${userId} with ⏎········Elasticsearch·disabled,·skipping·sync·for·user:·${userId}⏎······

(prettier/prettier)


[error] 81-81: Insert ⏎···········

(prettier/prettier)


[error] 86-86: Delete ·

(prettier/prettier)


[error] 90-90: Replace Built·${applications.length}·applications·for·user:·${userId} with ⏎········Built·${applications.length}·applications·for·user:·${userId}⏎······

(prettier/prettier)


[error] 108-108: Replace userId,·customFieldsProvider,·applicationDataProvider with ⏎············userId,⏎············customFieldsProvider,⏎············applicationDataProvider⏎··········

(prettier/prettier)


[error] 114-114: Replace 'Failed·to·sync·user·profile·to·Elasticsearch',·error?.message·||·'Unknown·error',·'ElasticsearchSyncService',·userId with ⏎········"Failed·to·sync·user·profile·to·Elasticsearch",⏎········error?.message·||·"Unknown·error",⏎········"ElasticsearchSyncService",⏎········userId⏎······

(prettier/prettier)


[error] 121-121: Delete ·

(prettier/prettier)


[error] 139-139: Replace userId:·string,·cohortId:·string with ⏎······userId:·string,⏎······cohortId:·string⏎····

(prettier/prettier)


[error] 142-142: Replace Elasticsearch·disabled,·skipping·application·sync·for·user:·${userId},·cohort:·${cohortId} with ⏎········Elasticsearch·disabled,·skipping·application·sync·for·user:·${userId},·cohort:·${cohortId}⏎······

(prettier/prettier)


[error] 147-147: Replace Starting·application·sync·for·user:·${userId},·cohort:·${cohortId} with ⏎········Starting·application·sync·for·user:·${userId},·cohort:·${cohortId}⏎······

(prettier/prettier)


[error] 151-151: Delete ······

(prettier/prettier)


[error] 153-153: Insert ⏎·······

(prettier/prettier)


[error] 154-154: Replace ········ with ··········

(prettier/prettier)


[error] 155-155: Insert ··

(prettier/prettier)


[error] 156-156: Delete ······

(prettier/prettier)


[error] 157-157: Insert ⏎·······

(prettier/prettier)


[error] 158-158: Replace ?·source.applications.find(app with ··?·source.applications.find((app)

(prettier/prettier)


[error] 159-159: Replace ········ with ··········

(prettier/prettier)


[error] 175-175: Delete ············

(prettier/prettier)


[error] 195-195: Replace userId,·cohortId,·updateData,·applicationDataProvider,·'sync' with ⏎··········userId,⏎··········cohortId,⏎··········updateData,⏎··········applicationDataProvider,⏎··········"sync"⏎········

(prettier/prettier)


[error] 198-198: Replace Successfully·synced·application·for·user:·${userId},·cohort:·${cohortId} with ⏎········Successfully·synced·application·for·user:·${userId},·cohort:·${cohortId}⏎······

(prettier/prettier)


[error] 200-200: Replace 'Failed·to·sync·user·application·to·Elasticsearch',·error?.message·||·'Unknown·error',·'ElasticsearchSyncService',·userId with ⏎········"Failed·to·sync·user·application·to·Elasticsearch",⏎········error?.message·||·"Unknown·error",⏎········"ElasticsearchSyncService",⏎········userId⏎······

(prettier/prettier)


[error] 207-207: Delete ·

(prettier/prettier)


[error] 225-225: Replace userId:·string,·cohortId:·string with ⏎······userId:·string,⏎······cohortId:·string⏎····

(prettier/prettier)


[error] 227-227: Replace userId,·cohortId,·updateData,·applicationDataProvider,·'update' with ⏎······userId,⏎······cohortId,⏎······updateData,⏎······applicationDataProvider,⏎······"update"⏎····

(prettier/prettier)


[error] 232-232: Delete ·

(prettier/prettier)


[error] 251-251: Replace userId:·string,·cohortId:·string with ⏎······userId:·string,⏎······cohortId:·string⏎····

(prettier/prettier)


[error] 252-252: Replace 'sync'·|·'update'·=·'update' with "sync"·|·"update"·=·"update"

(prettier/prettier)


[error] 255-255: Replace Elasticsearch·disabled,·skipping·application·${operationType}·for·user:·${userId},·cohort:·${cohortId} with ⏎········Elasticsearch·disabled,·skipping·application·${operationType}·for·user:·${userId},·cohort:·${cohortId}⏎······

(prettier/prettier)


[error] 260-260: Replace ${operationType·===·'update'·?·'Updating'·:·'Starting'}·application·${operationType}·for·user:·${userId},·cohort:·${cohortId} with ⏎········${⏎··········operationType·===·"update"·?·"Updating"·:·"Starting"⏎········}·application·${operationType}·for·user:·${userId},·cohort:·${cohortId}⏎······

(prettier/prettier)


[error] 291-291: Replace Successfully·${operationType·===·'update'·?·'updated'·:·'synced'}·application·${operationType·===·'update'·?·'data'·:·''}·for·user:·${userId},·cohort:·${cohortId} with ⏎········Successfully·${⏎··········operationType·===·"update"·?·"updated"·:·"synced"⏎········}·application·${⏎··········operationType·===·"update"·?·"data"·:·""⏎········}·for·user:·${userId},·cohort:·${cohortId}⏎······

(prettier/prettier)


[error] 293-293: Replace ``Failed·to·${operationType}·application·${operationType·===·'update'·?·'data'·:·''}·in·Elasticsearch,·error?.message·||·'Unknown·error',·'ElasticsearchSyncService',·userId with `⏎········`Failed·to·${operationType}·application·${⏎··········operationType·===·"update"·?·"data"·:·""⏎········}·in·Elasticsearch`,⏎········error?.message·||·"Unknown·error",⏎········"ElasticsearchSyncService",⏎········userId⏎······`

(prettier/prettier)


[error] 300-300: Delete ·

(prettier/prettier)


[error] 321-321: Replace Elasticsearch·disabled,·skipping·form·submission·sync·for·user:·${userId} with ⏎········Elasticsearch·disabled,·skipping·form·submission·sync·for·user:·${userId}⏎······

(prettier/prettier)


[error] 326-326: Replace Syncing·form·submission·data·for·user:·${userId},·form:·${submissionData.formId} with ⏎········Syncing·form·submission·data·for·user:·${userId},·form:·${submissionData.formId}⏎······

(prettier/prettier)


[error] 329-329: Delete ·

(prettier/prettier)


[error] 331-331: Replace 'Unknown·Cohort',·status:·'active' with "Unknown·Cohort",·status:·"active"

(prettier/prettier)


[error] 348-351: Replace ⏎········userId,⏎········submissionData.formId,⏎······· with userId,·submissionData.formId,

(prettier/prettier)


[error] 352-352: Delete ··

(prettier/prettier)


[error] 353-353: Delete ··

(prettier/prettier)


[error] 354-354: Delete ··

(prettier/prettier)


[error] 355-355: Delete ··

(prettier/prettier)


[error] 356-357: Replace ··}⏎······ with }

(prettier/prettier)


[error] 359-359: Replace Successfully·synced·form·submission·data·for·user:·${userId},·form:·${submissionData.formId} with ⏎········Successfully·synced·form·submission·data·for·user:·${userId},·form:·${submissionData.formId}⏎······

(prettier/prettier)


[error] 361-361: Replace 'Failed·to·sync·form·submission·data·to·Elasticsearch',·error?.message·||·'Unknown·error',·'ElasticsearchSyncService',·userId with ⏎········"Failed·to·sync·form·submission·data·to·Elasticsearch",⏎········error?.message·||·"Unknown·error",⏎········"ElasticsearchSyncService",⏎········userId⏎······

(prettier/prettier)


[error] 368-368: Delete ·

(prettier/prettier)


[error] 375-375: Delete ·

(prettier/prettier)


[error] 393-393: Replace '' with ""

(prettier/prettier)


[error] 394-394: Replace '' with ""

(prettier/prettier)


[error] 395-395: Replace '' with ""

(prettier/prettier)


[error] 396-396: Replace '' with ""

(prettier/prettier)


[error] 397-397: Replace '' with ""

(prettier/prettier)


[error] 398-398: Replace '' with ""

(prettier/prettier)


[error] 399-399: Replace '' with ""

(prettier/prettier)


[error] 400-400: Replace '' with ""

(prettier/prettier)


[error] 401-401: Replace '' with ""

(prettier/prettier)


[error] 402-402: Replace '' with ""

(prettier/prettier)


[error] 403-403: Replace '' with ""

(prettier/prettier)


[error] 404-404: Replace '' with ""

(prettier/prettier)


[error] 405-405: Replace '' with ""

(prettier/prettier)


[error] 406-406: Replace '' with ""

(prettier/prettier)


[error] 407-407: Replace 'inactive' with "inactive"

(prettier/prettier)


[error] 413-413: Delete ·

(prettier/prettier)


[error] 418-418: Replace userId,·allCustomFields with ⏎········userId,⏎········allCustomFields⏎······

(prettier/prettier)


[error] 424-424: Replace 'string' with "string"

(prettier/prettier)


[error] 431-431: Replace '' with ""

(prettier/prettier)


[error] 432-432: Replace '' with ""

(prettier/prettier)


[error] 433-433: Replace '' with ""

(prettier/prettier)


[error] 434-434: Replace '' with ""

(prettier/prettier)


[error] 435-435: Replace '' with ""

(prettier/prettier)


[error] 436-436: Replace '' with ""

(prettier/prettier)


[error] 437-437: Replace '' with ""

(prettier/prettier)


[error] 438-438: Replace '' with ""

(prettier/prettier)


[error] 439-439: Replace '' with ""

(prettier/prettier)


[error] 440-440: Replace '' with ""

(prettier/prettier)


[error] 441-441: Replace '' with ""

(prettier/prettier)


[error] 442-442: Replace '' with ""

(prettier/prettier)


[error] 443-443: Replace '' with ""

(prettier/prettier)


[error] 444-444: Replace '' with ""

(prettier/prettier)


[error] 445-445: Replace 'active' with "active"

(prettier/prettier)


[error] 446-446: Insert ⏎·········

(prettier/prettier)


[error] 453-453: Replace '' with ""

(prettier/prettier)


[error] 454-454: Replace '' with ""

(prettier/prettier)


[error] 455-455: Replace '' with ""

(prettier/prettier)


[error] 456-456: Replace '' with ""

(prettier/prettier)


[error] 457-457: Replace '' with ""

(prettier/prettier)


[error] 458-458: Replace '' with ""

(prettier/prettier)


[error] 459-459: Replace '' with ""

(prettier/prettier)


[error] 460-460: Replace '' with ""

(prettier/prettier)


[error] 461-461: Replace '' with ""

(prettier/prettier)


[error] 462-462: Replace '' with ""

(prettier/prettier)


[error] 463-463: Replace '' with ""

(prettier/prettier)


[error] 464-464: Replace '' with ""

(prettier/prettier)


[error] 465-465: Replace '' with ""

(prettier/prettier)


[error] 466-466: Replace '' with ""

(prettier/prettier)


[error] 467-467: Replace 'inactive' with "inactive"

(prettier/prettier)


[error] 475-475: Delete ·

(prettier/prettier)


[error] 488-488: Delete ·

(prettier/prettier)


[error] 501-501: Replace ``Failed·to·build·complete·user·document·for:·${userId},·error with `⏎········`Failed·to·build·complete·user·document·for:·${userId}`,⏎········error⏎······`

(prettier/prettier)


[error] 508-508: Delete ·

(prettier/prettier)


[error] 579-579: Replace 'painless' with "painless"

(prettier/prettier)


[error] 592-592: Delete ·

(prettier/prettier)


[error] 596-596: Replace customFields:·any[] with ⏎····customFields:·any[]⏎··

(prettier/prettier)


[error] 622-622: Delete ·

(prettier/prettier)


[error] 631-631: Replace 'object' with "object"

(prettier/prettier)


[error] 640-640: Delete ·

(prettier/prettier)


[error] 647-647: Replace (field with ((field)

(prettier/prettier)


[error] 648-648: Replace 'USER'·||·field.context·===·'USERS' with "USER"·||·field.context·===·"USERS"

(prettier/prettier)


[error] 654-654: Replace (field·=>·!formFieldIdsSet.has(field.fieldId) with (⏎········(field)·=>·!formFieldIdsSet.has(field.fieldId)⏎······

(prettier/prettier)


[error] 663-663: Delete ·

(prettier/prettier)


[error] 668-668: Replace userId:·string,·customFields:·any[] with ⏎····userId:·string,⏎····customFields:·any[]⏎··

(prettier/prettier)


[error] 675-675: Replace field with (field)

(prettier/prettier)


[error] 679-679: Replace 'Fields' with "Fields"

(prettier/prettier)


[error] 680-680: Replace 'f' with "f"

(prettier/prettier)


[error] 681-681: Replace 'f.fieldId',·'f.context',·'f.contextType' with "f.fieldId",·"f.context",·"f.contextType"

(prettier/prettier)


[error] 682-682: Replace 'f.fieldId·IN·(:...fieldIds)' with "f.fieldId·IN·(:...fieldIds)"

(prettier/prettier)


[error] 687-687: Replace field with (field)

(prettier/prettier)


[error] 692-692: Replace field with (field)

(prettier/prettier)


[error] 694-694: Replace 'USER'·||·context·===·'USERS' with "USER"·||·context·===·"USERS"

(prettier/prettier)


[error] 695-695: Delete ········

(prettier/prettier)


[error] 697-697: Replace Excluding·field·${field.fieldId}·(${field.label})·with·context:·${context}·for·user:·${userId} with ⏎············Excluding·field·${field.fieldId}·(${field.label})·with·context:·${context}·for·user:·${userId}⏎··········

(prettier/prettier)


[error] 699-699: Delete ········

(prettier/prettier)


[error] 703-703: Replace Filtered·${customFields.length}·total·fields·to·${profileFields.length}·profile·fields·for·user:·${userId}`);` with `⏎········`Filtered·${customFields.length}·total·fields·to·${profileFields.length}·profile·fields·for·user:·${userId}

(prettier/prettier)


[error] 704-704: Insert );⏎

(prettier/prettier)


[error] 707-707: Replace ``Failed·to·filter·profile·custom·fields·for·user:·${userId},·error with `⏎········`Failed·to·filter·profile·custom·fields·for·user:·${userId}`,⏎········error⏎······`

(prettier/prettier)


[error] 715-715: Delete ·

(prettier/prettier)


[error] 721-721: Delete ·

(prettier/prettier)


[error] 727-727: Replace Elasticsearch·disabled,·skipping·get·user·document·for:·${userId} with ⏎········Elasticsearch·disabled,·skipping·get·user·document·for:·${userId}⏎······

(prettier/prettier)


[error] 734-734: Delete ······

(prettier/prettier)


[error] 739-739: Delete ······

(prettier/prettier)


[error] 742-742: Replace 'Failed·to·get·user·document·from·Elasticsearch',·error?.message·||·'Unknown·error',·'ElasticsearchSyncService',·userId with ⏎········"Failed·to·get·user·document·from·Elasticsearch",⏎········error?.message·||·"Unknown·error",⏎········"ElasticsearchSyncService",⏎········userId⏎······

(prettier/prettier)


[error] 749-749: Delete ·

(prettier/prettier)


[error] 762-762: Replace 'Failed·to·delete·user·document·from·Elasticsearch',·error?.message·||·'Unknown·error',·'ElasticsearchSyncService',·userId with ⏎········"Failed·to·delete·user·document·from·Elasticsearch",⏎········error?.message·||·"Unknown·error",⏎········"ElasticsearchSyncService",⏎········userId⏎······

(prettier/prettier)


[error] 768-768: Delete ·

(prettier/prettier)


[error] 787-787: Replace 'Failed·to·search·users·in·Elasticsearch' with "Failed·to·search·users·in·Elasticsearch"

(prettier/prettier)


[error] 791-791: Replace · with

(prettier/prettier)

🧰 Additional context used
📓 Path-based instructions (1)
**/*.ts

⚙️ CodeRabbit Configuration File

**/*.ts: "Review the JavaScript code for conformity with the Google JavaScript style guide, highlighting any deviations. Ensure that:

  • The code adheres to best practices associated with nodejs.
  • The code adheres to best practices associated with nestjs framework.
  • The code adheres to best practices recommended for performance.
  • The code adheres to similar naming conventions for controllers, models, services, methods, variables."

Files:

  • src/elasticsearch/elasticsearch-sync.service.ts
🧬 Code Graph Analysis (1)
src/elasticsearch/elasticsearch-sync.service.ts (4)
src/adapters/postgres/user-adapter.ts (2)
  • updateUser (843-1056)
  • PostgresUserService (60-2978)
src/elasticsearch/interfaces/user.interface.ts (3)
  • IProfile (42-60)
  • IApplication (1-34)
  • IUser (81-88)
src/common/utils/elasticsearch.util.ts (1)
  • isElasticsearchEnabled (1-3)
src/common/logger/LoggerUtil.ts (1)
  • LoggerUtil (3-78)
🪛 Biome (1.9.4)
src/elasticsearch/elasticsearch-sync.service.ts

[error] 153-153: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 736-736: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🪛 ESLint
src/elasticsearch/elasticsearch-sync.service.ts

[error] 1-1: Replace '@nestjs/common' with "@nestjs/common"

(prettier/prettier)


[error] 2-2: Replace '@nestjs/typeorm' with "@nestjs/typeorm"

(prettier/prettier)


[error] 3-3: Replace 'typeorm' with "typeorm"

(prettier/prettier)


[error] 4-4: Replace './user-elasticsearch.service' with "./user-elasticsearch.service"

(prettier/prettier)


[error] 5-5: Replace './interfaces/user.interface' with "./interfaces/user.interface"

(prettier/prettier)


[error] 6-6: Replace '../common/utils/elasticsearch.util' with "../common/utils/elasticsearch.util"

(prettier/prettier)


[error] 7-7: Replace '../common/logger/LoggerUtil' with "../common/logger/LoggerUtil"

(prettier/prettier)


[error] 8-8: Replace '../user/entities/user-entity' with "../user/entities/user-entity"

(prettier/prettier)


[error] 12-12: Delete ·

(prettier/prettier)


[error] 15-15: Delete ·

(prettier/prettier)


[error] 24-24: Delete ·

(prettier/prettier)


[error] 42-42: Delete ·

(prettier/prettier)


[error] 51-51: Delete ·

(prettier/prettier)


[error] 65-65: Replace Elasticsearch·disabled,·skipping·sync·for·user:·${userId} with ⏎········Elasticsearch·disabled,·skipping·sync·for·user:·${userId}⏎······

(prettier/prettier)


[error] 81-81: Insert ⏎···········

(prettier/prettier)


[error] 86-86: Delete ·

(prettier/prettier)


[error] 90-90: Replace Built·${applications.length}·applications·for·user:·${userId} with ⏎········Built·${applications.length}·applications·for·user:·${userId}⏎······

(prettier/prettier)


[error] 108-108: Replace userId,·customFieldsProvider,·applicationDataProvider with ⏎············userId,⏎············customFieldsProvider,⏎············applicationDataProvider⏎··········

(prettier/prettier)


[error] 114-114: Replace 'Failed·to·sync·user·profile·to·Elasticsearch',·error?.message·||·'Unknown·error',·'ElasticsearchSyncService',·userId with ⏎········"Failed·to·sync·user·profile·to·Elasticsearch",⏎········error?.message·||·"Unknown·error",⏎········"ElasticsearchSyncService",⏎········userId⏎······

(prettier/prettier)


[error] 121-121: Delete ·

(prettier/prettier)


[error] 139-139: Replace userId:·string,·cohortId:·string with ⏎······userId:·string,⏎······cohortId:·string⏎····

(prettier/prettier)


[error] 142-142: Replace Elasticsearch·disabled,·skipping·application·sync·for·user:·${userId},·cohort:·${cohortId} with ⏎········Elasticsearch·disabled,·skipping·application·sync·for·user:·${userId},·cohort:·${cohortId}⏎······

(prettier/prettier)


[error] 147-147: Replace Starting·application·sync·for·user:·${userId},·cohort:·${cohortId} with ⏎········Starting·application·sync·for·user:·${userId},·cohort:·${cohortId}⏎······

(prettier/prettier)


[error] 151-151: Delete ······

(prettier/prettier)


[error] 153-153: Insert ⏎·······

(prettier/prettier)


[error] 154-154: Replace ········ with ··········

(prettier/prettier)


[error] 155-155: Insert ··

(prettier/prettier)


[error] 156-156: Delete ······

(prettier/prettier)


[error] 157-157: Insert ⏎·······

(prettier/prettier)


[error] 158-158: Replace ?·source.applications.find(app with ··?·source.applications.find((app)

(prettier/prettier)


[error] 159-159: Replace ········ with ··········

(prettier/prettier)


[error] 175-175: Delete ············

(prettier/prettier)


[error] 195-195: Replace userId,·cohortId,·updateData,·applicationDataProvider,·'sync' with ⏎··········userId,⏎··········cohortId,⏎··········updateData,⏎··········applicationDataProvider,⏎··········"sync"⏎········

(prettier/prettier)


[error] 198-198: Replace Successfully·synced·application·for·user:·${userId},·cohort:·${cohortId} with ⏎········Successfully·synced·application·for·user:·${userId},·cohort:·${cohortId}⏎······

(prettier/prettier)


[error] 200-200: Replace 'Failed·to·sync·user·application·to·Elasticsearch',·error?.message·||·'Unknown·error',·'ElasticsearchSyncService',·userId with ⏎········"Failed·to·sync·user·application·to·Elasticsearch",⏎········error?.message·||·"Unknown·error",⏎········"ElasticsearchSyncService",⏎········userId⏎······

(prettier/prettier)


[error] 207-207: Delete ·

(prettier/prettier)


[error] 225-225: Replace userId:·string,·cohortId:·string with ⏎······userId:·string,⏎······cohortId:·string⏎····

(prettier/prettier)


[error] 227-227: Replace userId,·cohortId,·updateData,·applicationDataProvider,·'update' with ⏎······userId,⏎······cohortId,⏎······updateData,⏎······applicationDataProvider,⏎······"update"⏎····

(prettier/prettier)


[error] 232-232: Delete ·

(prettier/prettier)


[error] 251-251: Replace userId:·string,·cohortId:·string with ⏎······userId:·string,⏎······cohortId:·string⏎····

(prettier/prettier)


[error] 252-252: Replace 'sync'·|·'update'·=·'update' with "sync"·|·"update"·=·"update"

(prettier/prettier)


[error] 255-255: Replace Elasticsearch·disabled,·skipping·application·${operationType}·for·user:·${userId},·cohort:·${cohortId} with ⏎········Elasticsearch·disabled,·skipping·application·${operationType}·for·user:·${userId},·cohort:·${cohortId}⏎······

(prettier/prettier)


[error] 260-260: Replace ${operationType·===·'update'·?·'Updating'·:·'Starting'}·application·${operationType}·for·user:·${userId},·cohort:·${cohortId} with ⏎········${⏎··········operationType·===·"update"·?·"Updating"·:·"Starting"⏎········}·application·${operationType}·for·user:·${userId},·cohort:·${cohortId}⏎······

(prettier/prettier)


[error] 291-291: Replace Successfully·${operationType·===·'update'·?·'updated'·:·'synced'}·application·${operationType·===·'update'·?·'data'·:·''}·for·user:·${userId},·cohort:·${cohortId} with ⏎········Successfully·${⏎··········operationType·===·"update"·?·"updated"·:·"synced"⏎········}·application·${⏎··········operationType·===·"update"·?·"data"·:·""⏎········}·for·user:·${userId},·cohort:·${cohortId}⏎······

(prettier/prettier)


[error] 293-293: Replace ``Failed·to·${operationType}·application·${operationType·===·'update'·?·'data'·:·''}·in·Elasticsearch,·error?.message·||·'Unknown·error',·'ElasticsearchSyncService',·userId with `⏎········`Failed·to·${operationType}·application·${⏎··········operationType·===·"update"·?·"data"·:·""⏎········}·in·Elasticsearch`,⏎········error?.message·||·"Unknown·error",⏎········"ElasticsearchSyncService",⏎········userId⏎······`

(prettier/prettier)


[error] 300-300: Delete ·

(prettier/prettier)


[error] 321-321: Replace Elasticsearch·disabled,·skipping·form·submission·sync·for·user:·${userId} with ⏎········Elasticsearch·disabled,·skipping·form·submission·sync·for·user:·${userId}⏎······

(prettier/prettier)


[error] 326-326: Replace Syncing·form·submission·data·for·user:·${userId},·form:·${submissionData.formId} with ⏎········Syncing·form·submission·data·for·user:·${userId},·form:·${submissionData.formId}⏎······

(prettier/prettier)


[error] 329-329: Delete ·

(prettier/prettier)


[error] 331-331: Replace 'Unknown·Cohort',·status:·'active' with "Unknown·Cohort",·status:·"active"

(prettier/prettier)


[error] 348-351: Replace ⏎········userId,⏎········submissionData.formId,⏎······· with userId,·submissionData.formId,

(prettier/prettier)


[error] 352-352: Delete ··

(prettier/prettier)


[error] 353-353: Delete ··

(prettier/prettier)


[error] 354-354: Delete ··

(prettier/prettier)


[error] 355-355: Delete ··

(prettier/prettier)


[error] 356-357: Replace ··}⏎······ with }

(prettier/prettier)


[error] 359-359: Replace Successfully·synced·form·submission·data·for·user:·${userId},·form:·${submissionData.formId} with ⏎········Successfully·synced·form·submission·data·for·user:·${userId},·form:·${submissionData.formId}⏎······

(prettier/prettier)


[error] 361-361: Replace 'Failed·to·sync·form·submission·data·to·Elasticsearch',·error?.message·||·'Unknown·error',·'ElasticsearchSyncService',·userId with ⏎········"Failed·to·sync·form·submission·data·to·Elasticsearch",⏎········error?.message·||·"Unknown·error",⏎········"ElasticsearchSyncService",⏎········userId⏎······

(prettier/prettier)


[error] 368-368: Delete ·

(prettier/prettier)


[error] 375-375: Delete ·

(prettier/prettier)


[error] 393-393: Replace '' with ""

(prettier/prettier)


[error] 394-394: Replace '' with ""

(prettier/prettier)


[error] 395-395: Replace '' with ""

(prettier/prettier)


[error] 396-396: Replace '' with ""

(prettier/prettier)


[error] 397-397: Replace '' with ""

(prettier/prettier)


[error] 398-398: Replace '' with ""

(prettier/prettier)


[error] 399-399: Replace '' with ""

(prettier/prettier)


[error] 400-400: Replace '' with ""

(prettier/prettier)


[error] 401-401: Replace '' with ""

(prettier/prettier)


[error] 402-402: Replace '' with ""

(prettier/prettier)


[error] 403-403: Replace '' with ""

(prettier/prettier)


[error] 404-404: Replace '' with ""

(prettier/prettier)


[error] 405-405: Replace '' with ""

(prettier/prettier)


[error] 406-406: Replace '' with ""

(prettier/prettier)


[error] 407-407: Replace 'inactive' with "inactive"

(prettier/prettier)


[error] 413-413: Delete ·

(prettier/prettier)


[error] 418-418: Replace userId,·allCustomFields with ⏎········userId,⏎········allCustomFields⏎······

(prettier/prettier)


[error] 424-424: Replace 'string' with "string"

(prettier/prettier)


[error] 431-431: Replace '' with ""

(prettier/prettier)


[error] 432-432: Replace '' with ""

(prettier/prettier)


[error] 433-433: Replace '' with ""

(prettier/prettier)


[error] 434-434: Replace '' with ""

(prettier/prettier)


[error] 435-435: Replace '' with ""

(prettier/prettier)


[error] 436-436: Replace '' with ""

(prettier/prettier)


[error] 437-437: Replace '' with ""

(prettier/prettier)


[error] 438-438: Replace '' with ""

(prettier/prettier)


[error] 439-439: Replace '' with ""

(prettier/prettier)


[error] 440-440: Replace '' with ""

(prettier/prettier)


[error] 441-441: Replace '' with ""

(prettier/prettier)


[error] 442-442: Replace '' with ""

(prettier/prettier)


[error] 443-443: Replace '' with ""

(prettier/prettier)


[error] 444-444: Replace '' with ""

(prettier/prettier)


[error] 445-445: Replace 'active' with "active"

(prettier/prettier)


[error] 446-446: Insert ⏎·········

(prettier/prettier)


[error] 453-453: Replace '' with ""

(prettier/prettier)


[error] 454-454: Replace '' with ""

(prettier/prettier)


[error] 455-455: Replace '' with ""

(prettier/prettier)


[error] 456-456: Replace '' with ""

(prettier/prettier)


[error] 457-457: Replace '' with ""

(prettier/prettier)


[error] 458-458: Replace '' with ""

(prettier/prettier)


[error] 459-459: Replace '' with ""

(prettier/prettier)


[error] 460-460: Replace '' with ""

(prettier/prettier)


[error] 461-461: Replace '' with ""

(prettier/prettier)


[error] 462-462: Replace '' with ""

(prettier/prettier)


[error] 463-463: Replace '' with ""

(prettier/prettier)


[error] 464-464: Replace '' with ""

(prettier/prettier)


[error] 465-465: Replace '' with ""

(prettier/prettier)


[error] 466-466: Replace '' with ""

(prettier/prettier)


[error] 467-467: Replace 'inactive' with "inactive"

(prettier/prettier)


[error] 475-475: Delete ·

(prettier/prettier)


[error] 488-488: Delete ·

(prettier/prettier)


[error] 501-501: Replace ``Failed·to·build·complete·user·document·for:·${userId},·error with `⏎········`Failed·to·build·complete·user·document·for:·${userId}`,⏎········error⏎······`

(prettier/prettier)


[error] 508-508: Delete ·

(prettier/prettier)


[error] 579-579: Replace 'painless' with "painless"

(prettier/prettier)


[error] 592-592: Delete ·

(prettier/prettier)


[error] 596-596: Replace customFields:·any[] with ⏎····customFields:·any[]⏎··

(prettier/prettier)


[error] 622-622: Delete ·

(prettier/prettier)


[error] 631-631: Replace 'object' with "object"

(prettier/prettier)


[error] 640-640: Delete ·

(prettier/prettier)


[error] 647-647: Replace (field with ((field)

(prettier/prettier)


[error] 648-648: Replace 'USER'·||·field.context·===·'USERS' with "USER"·||·field.context·===·"USERS"

(prettier/prettier)


[error] 654-654: Replace (field·=>·!formFieldIdsSet.has(field.fieldId) with (⏎········(field)·=>·!formFieldIdsSet.has(field.fieldId)⏎······

(prettier/prettier)


[error] 663-663: Delete ·

(prettier/prettier)


[error] 668-668: Replace userId:·string,·customFields:·any[] with ⏎····userId:·string,⏎····customFields:·any[]⏎··

(prettier/prettier)


[error] 675-675: Replace field with (field)

(prettier/prettier)


[error] 679-679: Replace 'Fields' with "Fields"

(prettier/prettier)


[error] 680-680: Replace 'f' with "f"

(prettier/prettier)


[error] 681-681: Replace 'f.fieldId',·'f.context',·'f.contextType' with "f.fieldId",·"f.context",·"f.contextType"

(prettier/prettier)


[error] 682-682: Replace 'f.fieldId·IN·(:...fieldIds)' with "f.fieldId·IN·(:...fieldIds)"

(prettier/prettier)


[error] 687-687: Replace field with (field)

(prettier/prettier)


[error] 692-692: Replace field with (field)

(prettier/prettier)


[error] 694-694: Replace 'USER'·||·context·===·'USERS' with "USER"·||·context·===·"USERS"

(prettier/prettier)


[error] 695-695: Delete ········

(prettier/prettier)


[error] 697-697: Replace Excluding·field·${field.fieldId}·(${field.label})·with·context:·${context}·for·user:·${userId} with ⏎············Excluding·field·${field.fieldId}·(${field.label})·with·context:·${context}·for·user:·${userId}⏎··········

(prettier/prettier)


[error] 699-699: Delete ········

(prettier/prettier)


[error] 703-703: Replace Filtered·${customFields.length}·total·fields·to·${profileFields.length}·profile·fields·for·user:·${userId}`);` with `⏎········`Filtered·${customFields.length}·total·fields·to·${profileFields.length}·profile·fields·for·user:·${userId}

(prettier/prettier)


[error] 704-704: Insert );⏎

(prettier/prettier)


[error] 707-707: Replace ``Failed·to·filter·profile·custom·fields·for·user:·${userId},·error with `⏎········`Failed·to·filter·profile·custom·fields·for·user:·${userId}`,⏎········error⏎······`

(prettier/prettier)


[error] 715-715: Delete ·

(prettier/prettier)


[error] 721-721: Delete ·

(prettier/prettier)


[error] 727-727: Replace Elasticsearch·disabled,·skipping·get·user·document·for:·${userId} with ⏎········Elasticsearch·disabled,·skipping·get·user·document·for:·${userId}⏎······

(prettier/prettier)


[error] 734-734: Delete ······

(prettier/prettier)


[error] 739-739: Delete ······

(prettier/prettier)


[error] 742-742: Replace 'Failed·to·get·user·document·from·Elasticsearch',·error?.message·||·'Unknown·error',·'ElasticsearchSyncService',·userId with ⏎········"Failed·to·get·user·document·from·Elasticsearch",⏎········error?.message·||·"Unknown·error",⏎········"ElasticsearchSyncService",⏎········userId⏎······

(prettier/prettier)


[error] 749-749: Delete ·

(prettier/prettier)


[error] 762-762: Replace 'Failed·to·delete·user·document·from·Elasticsearch',·error?.message·||·'Unknown·error',·'ElasticsearchSyncService',·userId with ⏎········"Failed·to·delete·user·document·from·Elasticsearch",⏎········error?.message·||·"Unknown·error",⏎········"ElasticsearchSyncService",⏎········userId⏎······

(prettier/prettier)


[error] 768-768: Delete ·

(prettier/prettier)


[error] 787-787: Replace 'Failed·to·search·users·in·Elasticsearch' with "Failed·to·search·users·in·Elasticsearch"

(prettier/prettier)


[error] 791-791: Replace · with

(prettier/prettier)

🔇 Additional comments (2)
src/elasticsearch/elasticsearch-sync.service.ts (2)

380-471: Well-implemented user profile building with comprehensive error handling

The method properly handles:

  • Missing users with appropriate logging
  • Date formatting for different types
  • Custom field filtering for profile-only fields
  • Fallback to empty profile on errors

513-588: Excellent Painless script implementation for selective field updates

The script correctly:

  • Initializes applications array if missing
  • Updates only provided fields, preserving existing data
  • Handles both existing and new applications
  • Maintains proper timestamps

Copy link

@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

🧹 Nitpick comments (3)
src/forms/services/form-submission.service.ts (2)

1173-1507: Good architectural improvement with centralized Elasticsearch sync.

The replacement of direct document manipulation with elasticsearchSyncService.syncUserProfile() improves maintainability and consistency. The callback pattern for application data retrieval is functional but could be simplified.

Consider extracting the application data provider callback to a separate method:

+  private async getApplicationsForUser(userId: string): Promise<any[]> {
+    const userDoc = await this.buildUserDocumentForElasticsearch(userId);
+    return userDoc ? userDoc.applications : [];
+  }

   await this.elasticsearchSyncService.syncUserProfile(
     userId,
     undefined,
     undefined,
-    async (userId: string) => {
-      const userDoc = await this.buildUserDocumentForElasticsearch(userId);
-      return userDoc ? userDoc.applications : [];
-    }
+    this.getApplicationsForUser.bind(this)
   );

31-31: Fix formatting issues to maintain code consistency.

Multiple prettier formatting issues detected throughout the file. These include quote consistency, line breaks, and indentation problems that should be addressed.

Run prettier to automatically fix formatting issues:

npx prettier --write src/forms/services/form-submission.service.ts

Or configure your IDE to format on save to prevent these issues in the future.

Also applies to: 1173-1173, 1500-1500, 1505-1505, 2667-2671, 2997-3003

src/elasticsearch/elasticsearch-sync.service.ts (1)

1-8: Fix quote consistency to match project style

The ESLint prettier rules consistently flag single quotes that should be double quotes throughout the imports. This indicates the project uses double quotes as the standard.

Apply this formatting fix:

-import { Injectable } from '@nestjs/common';
-import { InjectRepository } from '@nestjs/typeorm';
-import { Repository } from 'typeorm';
-import { UserElasticsearchService } from './user-elasticsearch.service';
-import { IUser, IProfile, IApplication } from './interfaces/user.interface';
-import { isElasticsearchEnabled } from '../common/utils/elasticsearch.util';
-import { LoggerUtil } from '../common/logger/LoggerUtil';
-import { User } from '../user/entities/user-entity';
+import { Injectable } from "@nestjs/common";
+import { InjectRepository } from "@nestjs/typeorm";
+import { Repository } from "typeorm";
+import { UserElasticsearchService } from "./user-elasticsearch.service";
+import { IUser, IProfile, IApplication } from "./interfaces/user.interface";
+import { isElasticsearchEnabled } from "../common/utils/elasticsearch.util";
+import { LoggerUtil } from "../common/logger/LoggerUtil";
+import { User } from "../user/entities/user-entity";
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 9c89c3f and e71e9ce.

📒 Files selected for processing (2)
  • src/elasticsearch/elasticsearch-sync.service.ts (1 hunks)
  • src/forms/services/form-submission.service.ts (9 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.ts

⚙️ CodeRabbit Configuration File

**/*.ts: "Review the JavaScript code for conformity with the Google JavaScript style guide, highlighting any deviations. Ensure that:

  • The code adheres to best practices associated with nodejs.
  • The code adheres to best practices associated with nestjs framework.
  • The code adheres to best practices recommended for performance.
  • The code adheres to similar naming conventions for controllers, models, services, methods, variables."

Files:

  • src/forms/services/form-submission.service.ts
  • src/elasticsearch/elasticsearch-sync.service.ts
🪛 ESLint
src/forms/services/form-submission.service.ts

[error] 31-31: Replace '../../elasticsearch/elasticsearch-sync.service' with "../../elasticsearch/elasticsearch-sync.service"

(prettier/prettier)


[error] 1173-1173: Replace userId with ⏎········userId⏎······

(prettier/prettier)


[error] 1500-1500: Replace userId with ⏎················userId⏎··············

(prettier/prettier)


[error] 1505-1505: Replace 'Failed·to·sync·user·data·to·Elasticsearch:',·syncError with ⏎············"Failed·to·sync·user·data·to·Elasticsearch:",⏎············syncError⏎··········

(prettier/prettier)


[error] 2667-2667: Replace Built·${applications.length}·applications·in·buildUserDocumentForElasticsearch·for·user:·${userId} with ⏎······Built·${applications.length}·applications·in·buildUserDocumentForElasticsearch·for·user:·${userId}⏎····

(prettier/prettier)


[error] 2668-2668: Replace CohortMembers·found:·${cohortMemberships.length},·FormSubmissions·found:·${submissions.length} with ⏎······CohortMembers·found:·${cohortMemberships.length},·FormSubmissions·found:·${submissions.length}⏎····

(prettier/prettier)


[error] 2669-2669: Replace ',·' with ",·"

(prettier/prettier)


[error] 2671-2671: Replace Sample·application:·${JSON.stringify(applications[0],·null,·2)} with ⏎········Sample·application:·${JSON.stringify(applications[0],·null,·2)}⏎······

(prettier/prettier)


[error] 2997-2997: Delete ····

(prettier/prettier)


[error] 2999-2999: Replace buildUserDocumentForElasticsearch·returning·${applications.length}·applications·for·user:·${userId} with ⏎······buildUserDocumentForElasticsearch·returning·${applications.length}·applications·for·user:·${userId}⏎····

(prettier/prettier)


[error] 3001-3001: Replace First·application:·${JSON.stringify(applications[0],·null,·2)}`);` with `⏎········`First·application:·${JSON.stringify(applications[0],·null,·2)}

(prettier/prettier)


[error] 3002-3002: Replace } with ··);

(prettier/prettier)


[error] 3003-3003: Insert }⏎

(prettier/prettier)

src/elasticsearch/elasticsearch-sync.service.ts

[error] 1-1: Replace '@nestjs/common' with "@nestjs/common"

(prettier/prettier)


[error] 2-2: Replace '@nestjs/typeorm' with "@nestjs/typeorm"

(prettier/prettier)


[error] 3-3: Replace 'typeorm' with "typeorm"

(prettier/prettier)


[error] 4-4: Replace './user-elasticsearch.service' with "./user-elasticsearch.service"

(prettier/prettier)


[error] 5-5: Replace './interfaces/user.interface' with "./interfaces/user.interface"

(prettier/prettier)


[error] 6-6: Replace '../common/utils/elasticsearch.util' with "../common/utils/elasticsearch.util"

(prettier/prettier)


[error] 7-7: Replace '../common/logger/LoggerUtil' with "../common/logger/LoggerUtil"

(prettier/prettier)


[error] 8-8: Replace '../user/entities/user-entity' with "../user/entities/user-entity"

(prettier/prettier)


[error] 12-12: Delete ·

(prettier/prettier)


[error] 15-15: Delete ·

(prettier/prettier)


[error] 24-24: Delete ·

(prettier/prettier)


[error] 31-32: Delete

(prettier/prettier)


[error] 41-41: Delete ·

(prettier/prettier)


[error] 50-50: Delete ·

(prettier/prettier)


[error] 64-64: Replace ``Elasticsearch·disabled,·skipping·sync·for·user:·${userId},·'ElasticsearchSyncService' with `⏎········`Elasticsearch·disabled,·skipping·sync·for·user:·${userId}`,⏎········"ElasticsearchSyncService"⏎······`

(prettier/prettier)


[error] 69-69: Replace ``Starting·user·profile·sync·for:·${userId},·'ElasticsearchSyncService' with `⏎········`Starting·user·profile·sync·for:·${userId}`,⏎········"ElasticsearchSyncService"⏎······`

(prettier/prettier)


[error] 80-80: Insert ⏎···········

(prettier/prettier)


[error] 85-85: Delete ·

(prettier/prettier)


[error] 89-89: Replace ``Built·${applications.length}·applications·for·user:·${userId},·'ElasticsearchSyncService' with `⏎········`Built·${applications.length}·applications·for·user:·${userId}`,⏎········"ElasticsearchSyncService"⏎······`

(prettier/prettier)


[error] 107-107: Replace userId,·customFieldsProvider,·applicationDataProvider with ⏎············userId,⏎············customFieldsProvider,⏎············applicationDataProvider⏎··········

(prettier/prettier)


[error] 111-111: Replace ``Successfully·synced·user·profile·for:·${userId},·'ElasticsearchSyncService' with `⏎········`Successfully·synced·user·profile·for:·${userId}`,⏎········"ElasticsearchSyncService"⏎······`

(prettier/prettier)


[error] 113-113: Replace 'Failed·to·sync·user·profile·to·Elasticsearch',·error?.message·||·'Unknown·error',·'ElasticsearchSyncService',·userId with ⏎········"Failed·to·sync·user·profile·to·Elasticsearch",⏎········error?.message·||·"Unknown·error",⏎········"ElasticsearchSyncService",⏎········userId⏎······

(prettier/prettier)


[error] 120-120: Delete ·

(prettier/prettier)


[error] 138-138: Replace userId:·string,·cohortId:·string with ⏎······userId:·string,⏎······cohortId:·string⏎····

(prettier/prettier)


[error] 141-141: Replace ``Elasticsearch·disabled,·skipping·application·sync·for·user:·${userId},·cohort:·${cohortId},·'ElasticsearchSyncService' with `⏎········`Elasticsearch·disabled,·skipping·application·sync·for·user:·${userId},·cohort:·${cohortId}`,⏎········"ElasticsearchSyncService"⏎······`

(prettier/prettier)


[error] 146-146: Replace ``Starting·application·sync·for·user:·${userId},·cohort:·${cohortId},·'ElasticsearchSyncService' with `⏎········`Starting·application·sync·for·user:·${userId},·cohort:·${cohortId}`,⏎········"ElasticsearchSyncService"⏎······`

(prettier/prettier)


[error] 150-150: Delete ······

(prettier/prettier)


[error] 153-153: Delete ······

(prettier/prettier)


[error] 154-154: Replace app·=>·app.cohortId·===·cohortId with ⏎········(app)·=>·app.cohortId·===·cohortId⏎······

(prettier/prettier)


[error] 166-166: Delete ············

(prettier/prettier)


[error] 176-176: Replace userId,·cohortId,·updateData,·applicationDataProvider,·'sync' with ⏎··········userId,⏎··········cohortId,⏎··········updateData,⏎··········applicationDataProvider,⏎··········"sync"⏎········

(prettier/prettier)


[error] 179-179: Replace ``Successfully·synced·application·for·user:·${userId},·cohort:·${cohortId},·'ElasticsearchSyncService' with `⏎········`Successfully·synced·application·for·user:·${userId},·cohort:·${cohortId}`,⏎········"ElasticsearchSyncService"⏎······`

(prettier/prettier)


[error] 181-181: Replace 'Failed·to·sync·user·application·to·Elasticsearch',·error?.message·||·'Unknown·error',·'ElasticsearchSyncService',·userId with ⏎········"Failed·to·sync·user·application·to·Elasticsearch",⏎········error?.message·||·"Unknown·error",⏎········"ElasticsearchSyncService",⏎········userId⏎······

(prettier/prettier)


[error] 188-188: Delete ·

(prettier/prettier)


[error] 206-206: Replace userId:·string,·cohortId:·string with ⏎······userId:·string,⏎······cohortId:·string⏎····

(prettier/prettier)


[error] 208-208: Replace userId,·cohortId,·updateData,·applicationDataProvider,·'update' with ⏎······userId,⏎······cohortId,⏎······updateData,⏎······applicationDataProvider,⏎······"update"⏎····

(prettier/prettier)


[error] 213-213: Delete ·

(prettier/prettier)


[error] 232-232: Replace userId:·string,·cohortId:·string with ⏎······userId:·string,⏎······cohortId:·string⏎····

(prettier/prettier)


[error] 233-233: Replace 'sync'·|·'update'·=·'update' with "sync"·|·"update"·=·"update"

(prettier/prettier)


[error] 236-236: Replace ``Elasticsearch·disabled,·skipping·application·${operationType}·for·user:·${userId},·cohort:·${cohortId},·'ElasticsearchSyncService' with `⏎········`Elasticsearch·disabled,·skipping·application·${operationType}·for·user:·${userId},·cohort:·${cohortId}`,⏎········"ElasticsearchSyncService"⏎······`

(prettier/prettier)


[error] 241-241: Replace ``${operationType·===·'update'·?·'Updating'·:·'Starting'}·application·${operationType}·for·user:·${userId},·cohort:·${cohortId},·'ElasticsearchSyncService' with `⏎········`${⏎··········operationType·===·"update"·?·"Updating"·:·"Starting"⏎········}·application·${operationType}·for·user:·${userId},·cohort:·${cohortId}`,⏎········"ElasticsearchSyncService"⏎······`

(prettier/prettier)


[error] 272-272: Replace ``Successfully·${operationType·===·'update'·?·'updated'·:·'synced'}·application·${operationType·===·'update'·?·'data'·:·''}·for·user:·${userId},·cohort:·${cohortId},·'ElasticsearchSyncService' with `⏎········`Successfully·${⏎··········operationType·===·"update"·?·"updated"·:·"synced"⏎········}·application·${⏎··········operationType·===·"update"·?·"data"·:·""⏎········}·for·user:·${userId},·cohort:·${cohortId}`,⏎········"ElasticsearchSyncService"⏎······`

(prettier/prettier)


[error] 274-274: Replace ``Failed·to·${operationType}·application·${operationType·===·'update'·?·'data'·:·''}·in·Elasticsearch,·error?.message·||·'Unknown·error',·'ElasticsearchSyncService',·userId with `⏎········`Failed·to·${operationType}·application·${⏎··········operationType·===·"update"·?·"data"·:·""⏎········}·in·Elasticsearch`,⏎········error?.message·||·"Unknown·error",⏎········"ElasticsearchSyncService",⏎········userId⏎······`

(prettier/prettier)


[error] 281-281: Delete ·

(prettier/prettier)


[error] 303-303: Replace ``Elasticsearch·disabled,·skipping·form·submission·sync·for·user:·${userId},·'ElasticsearchSyncService' with `⏎········`Elasticsearch·disabled,·skipping·form·submission·sync·for·user:·${userId}`,⏎········"ElasticsearchSyncService"⏎······`

(prettier/prettier)


[error] 308-308: Replace ``Syncing·form·submission·data·for·user:·${userId},·form:·${submissionData.formId},·cohort:·${submissionData.cohortId},·'ElasticsearchSyncService' with `⏎········`Syncing·form·submission·data·for·user:·${userId},·form:·${submissionData.formId},·cohort:·${submissionData.cohortId}`,⏎········"ElasticsearchSyncService"⏎······`

(prettier/prettier)


[error] 311-311: Delete ·

(prettier/prettier)


[error] 313-313: Replace 'Unknown·Cohort',·status:·'active' with "Unknown·Cohort",·status:·"active"

(prettier/prettier)


[error] 327-327: Replace ``Successfully·synced·form·submission·data·for·user:·${userId},·form:·${submissionData.formId},·cohort:·${submissionData.cohortId},·'ElasticsearchSyncService' with `⏎········`Successfully·synced·form·submission·data·for·user:·${userId},·form:·${submissionData.formId},·cohort:·${submissionData.cohortId}`,⏎········"ElasticsearchSyncService"⏎······`

(prettier/prettier)


[error] 329-329: Replace 'Failed·to·sync·form·submission·data·to·Elasticsearch',·error?.message·||·'Unknown·error',·'ElasticsearchSyncService',·userId with ⏎········"Failed·to·sync·form·submission·data·to·Elasticsearch",⏎········error?.message·||·"Unknown·error",⏎········"ElasticsearchSyncService",⏎········userId⏎······

(prettier/prettier)


[error] 336-336: Delete ·

(prettier/prettier)


[error] 343-343: Delete ·

(prettier/prettier)


[error] 357-357: Replace ``User·not·found·in·database:·${userId},·'ElasticsearchSyncService' with `⏎··········`User·not·found·in·database:·${userId}`,⏎··········"ElasticsearchSyncService"⏎········`

(prettier/prettier)


[error] 361-361: Replace '' with ""

(prettier/prettier)


[error] 362-362: Replace '' with ""

(prettier/prettier)


[error] 363-363: Replace '' with ""

(prettier/prettier)


[error] 364-364: Replace '' with ""

(prettier/prettier)


[error] 365-365: Replace '' with ""

(prettier/prettier)


[error] 366-366: Replace '' with ""

(prettier/prettier)


[error] 367-367: Replace '' with ""

(prettier/prettier)


[error] 368-368: Replace '' with ""

(prettier/prettier)


[error] 369-369: Replace '' with ""

(prettier/prettier)


[error] 370-370: Replace '' with ""

(prettier/prettier)


[error] 371-371: Replace '' with ""

(prettier/prettier)


[error] 372-372: Replace '' with ""

(prettier/prettier)


[error] 373-373: Replace '' with ""

(prettier/prettier)


[error] 374-374: Replace '' with ""

(prettier/prettier)


[error] 375-375: Replace 'inactive' with "inactive"

(prettier/prettier)


[error] 381-381: Delete ·

(prettier/prettier)


[error] 386-386: Replace userId,·allCustomFields with ⏎········userId,⏎········allCustomFields⏎······

(prettier/prettier)


[error] 392-392: Replace 'string' with "string"

(prettier/prettier)


[error] 399-399: Replace '' with ""

(prettier/prettier)


[error] 400-400: Replace '' with ""

(prettier/prettier)


[error] 401-401: Replace '' with ""

(prettier/prettier)


[error] 402-402: Replace '' with ""

(prettier/prettier)


[error] 403-403: Replace '' with ""

(prettier/prettier)


[error] 404-404: Replace '' with ""

(prettier/prettier)


[error] 405-405: Replace '' with ""

(prettier/prettier)


[error] 406-406: Replace '' with ""

(prettier/prettier)


[error] 407-407: Replace '' with ""

(prettier/prettier)


[error] 408-408: Replace '' with ""

(prettier/prettier)


[error] 409-409: Replace '' with ""

(prettier/prettier)


[error] 410-410: Replace '' with ""

(prettier/prettier)


[error] 411-411: Replace '' with ""

(prettier/prettier)


[error] 412-412: Replace '' with ""

(prettier/prettier)


[error] 413-413: Replace 'active' with "active"

(prettier/prettier)


[error] 414-414: Insert ⏎·········

(prettier/prettier)


[error] 417-417: Replace ``Failed·to·build·user·profile·for:·${userId},·error,·'ElasticsearchSyncService',·userId with `⏎········`Failed·to·build·user·profile·for:·${userId}`,⏎········error,⏎········"ElasticsearchSyncService",⏎········userId⏎······`

(prettier/prettier)


[error] 421-421: Replace '' with ""

(prettier/prettier)


[error] 422-422: Replace '' with ""

(prettier/prettier)


[error] 423-423: Replace '' with ""

(prettier/prettier)


[error] 424-424: Replace '' with ""

(prettier/prettier)


[error] 425-425: Replace '' with ""

(prettier/prettier)


[error] 426-426: Replace '' with ""

(prettier/prettier)


[error] 427-427: Replace '' with ""

(prettier/prettier)


[error] 428-428: Replace '' with ""

(prettier/prettier)


[error] 429-429: Replace '' with ""

(prettier/prettier)


[error] 430-430: Replace '' with ""

(prettier/prettier)


[error] 431-431: Replace '' with ""

(prettier/prettier)


[error] 432-432: Replace '' with ""

(prettier/prettier)


[error] 433-433: Replace '' with ""

(prettier/prettier)


[error] 434-434: Replace '' with ""

(prettier/prettier)


[error] 435-435: Replace 'inactive' with "inactive"

(prettier/prettier)


[error] 443-443: Delete ·

(prettier/prettier)


[error] 456-456: Delete ·

(prettier/prettier)


[error] 469-469: Replace ``Failed·to·build·complete·user·document·for:·${userId},·error,·'ElasticsearchSyncService',·userId with `⏎········`Failed·to·build·complete·user·document·for:·${userId}`,⏎········error,⏎········"ElasticsearchSyncService",⏎········userId⏎······`

(prettier/prettier)


[error] 476-476: Delete ·

(prettier/prettier)


[error] 547-547: Replace 'painless' with "painless"

(prettier/prettier)


[error] 560-560: Delete ·

(prettier/prettier)


[error] 564-564: Replace customFields:·any[] with ⏎····customFields:·any[]⏎··

(prettier/prettier)


[error] 590-590: Delete ·

(prettier/prettier)


[error] 599-599: Replace 'object' with "object"

(prettier/prettier)


[error] 608-608: Delete ·

(prettier/prettier)


[error] 615-615: Replace field with (field)

(prettier/prettier)


[error] 616-616: Replace 'USER'·||·field.context·===·'USERS' with "USER"·||·field.context·===·"USERS"

(prettier/prettier)


[error] 622-622: Replace field·=>·!formFieldIdsSet.has(field.fieldId) with ⏎········(field)·=>·!formFieldIdsSet.has(field.fieldId)⏎······

(prettier/prettier)


[error] 631-631: Delete ·

(prettier/prettier)


[error] 636-636: Replace userId:·string,·customFields:·any[] with ⏎····userId:·string,⏎····customFields:·any[]⏎··

(prettier/prettier)


[error] 643-643: Replace field with (field)

(prettier/prettier)


[error] 647-647: Replace 'Fields' with "Fields"

(prettier/prettier)


[error] 648-648: Replace 'f' with "f"

(prettier/prettier)


[error] 649-649: Replace 'f.fieldId',·'f.context',·'f.contextType' with "f.fieldId",·"f.context",·"f.contextType"

(prettier/prettier)


[error] 650-650: Replace 'f.fieldId·IN·(:...fieldIds)' with "f.fieldId·IN·(:...fieldIds)"

(prettier/prettier)


[error] 655-655: Replace (field with ((field)

(prettier/prettier)


[error] 660-660: Replace field with (field)

(prettier/prettier)


[error] 662-662: Replace 'USER'·||·context·===·'USERS' with "USER"·||·context·===·"USERS"

(prettier/prettier)


[error] 663-663: Delete ········

(prettier/prettier)


[error] 665-665: Replace ``Excluding·field·${field.fieldId}·(${field.label})·with·context:·${context}·for·user:·${userId},·'ElasticsearchSyncService'); with `⏎············`Excluding·field·${field.fieldId}·(${field.label})·with·context:·${context}·for·user:·${userId}`,⏎············"ElasticsearchSyncService"`

(prettier/prettier)


[error] 666-666: Replace } with ··);

(prettier/prettier)


[error] 667-667: Insert }⏎

(prettier/prettier)


[error] 671-671: Replace ``Filtered·${customFields.length}·total·fields·to·${profileFields.length}·profile·fields·for·user:·${userId},·'ElasticsearchSyncService'); with `⏎········`Filtered·${customFields.length}·total·fields·to·${profileFields.length}·profile·fields·for·user:·${userId}`,⏎········"ElasticsearchSyncService"`

(prettier/prettier)


[error] 672-672: Insert );⏎

(prettier/prettier)


[error] 675-675: Replace ``Failed·to·filter·profile·custom·fields·for·user:·${userId},·error,·'ElasticsearchSyncService',·userId with `⏎········`Failed·to·filter·profile·custom·fields·for·user:·${userId}`,⏎········error,⏎········"ElasticsearchSyncService",⏎········userId⏎······`

(prettier/prettier)


[error] 683-683: Delete ·

(prettier/prettier)


[error] 689-689: Delete ·

(prettier/prettier)


[error] 695-695: Replace ``Elasticsearch·disabled,·skipping·get·user·document·for:·${userId},·'ElasticsearchSyncService' with `⏎········`Elasticsearch·disabled,·skipping·get·user·document·for:·${userId}`,⏎········"ElasticsearchSyncService"⏎······`

(prettier/prettier)


[error] 700-700: Replace ``Getting·user·document·for:·${userId},·'ElasticsearchSyncService' with `⏎········`Getting·user·document·for:·${userId}`,⏎········"ElasticsearchSyncService"⏎······`

(prettier/prettier)


[error] 702-702: Delete ······

(prettier/prettier)


[error] 704-704: Replace result?._source·as·IUser with (result?._source·as·IUser)

(prettier/prettier)


[error] 706-706: Replace 'Failed·to·get·user·document·from·Elasticsearch',·error?.message·||·'Unknown·error',·'ElasticsearchSyncService',·userId with ⏎········"Failed·to·get·user·document·from·Elasticsearch",⏎········error?.message·||·"Unknown·error",⏎········"ElasticsearchSyncService",⏎········userId⏎······

(prettier/prettier)


[error] 713-713: Delete ·

(prettier/prettier)


[error] 724-724: Replace ``Successfully·deleted·user·document:·${userId},·'ElasticsearchSyncService' with `⏎········`Successfully·deleted·user·document:·${userId}`,⏎········"ElasticsearchSyncService"⏎······`

(prettier/prettier)


[error] 726-726: Replace 'Failed·to·delete·user·document·from·Elasticsearch',·error?.message·||·'Unknown·error',·'ElasticsearchSyncService',·userId with ⏎········"Failed·to·delete·user·document·from·Elasticsearch",⏎········error?.message·||·"Unknown·error",⏎········"ElasticsearchSyncService",⏎········userId⏎······

(prettier/prettier)


[error] 732-732: Delete ·

(prettier/prettier)


[error] 751-751: Replace 'Failed·to·search·users·in·Elasticsearch',·error,·'ElasticsearchSyncService' with ⏎········"Failed·to·search·users·in·Elasticsearch",⏎········error,⏎········"ElasticsearchSyncService"⏎······

(prettier/prettier)


[error] 755-755: Replace · with

(prettier/prettier)

🔇 Additional comments (20)
src/forms/services/form-submission.service.ts (6)

31-31: LGTM: Dependency replacement follows NestJS best practices.

The import and dependency injection changes correctly replace UserElasticsearchService with ElasticsearchSyncService, aligning with the centralized Elasticsearch architecture.

Also applies to: 91-91


1536-1549: LGTM: Cohort details simplified as per requirements.

The consistent removal of customFields from cohort details across multiple methods reduces complexity and follows the documented requirements. The implementation maintains essential cohort information while simplifying the data structure.

Also applies to: 1940-1948, 2634-2642


2665-2672: Good addition of debug logging for troubleshooting.

The enhanced debug logging provides valuable insights into application building and user document construction. The logging statements are correctly positioned before the return statement, resolving the unreachable code issue from previous reviews.

Also applies to: 2998-3003


3056-3124: Excellent utility function for robust field mapping.

The getFieldIdToPageNameMap function significantly improves field mapping by recursively handling all dependency types (oneOf, allOf, anyOf, properties). This addresses previous field mapping inconsistencies and provides a centralized, maintainable solution for complex form schemas.


1342-1358: Improved field filtering enhances data integrity.

The enhanced field filtering logic with schema validation and warning for unmapped fields is a significant improvement. Skipping unmapped fields instead of fallback assignments prevents data integrity issues and provides better visibility into schema mismatches.

Also applies to: 1394-1409


2000-2201: Robust profile custom fields filtering maintains data separation.

The comprehensive filtering logic correctly separates profile custom fields from form fields across multiple schema structures. This ensures proper data separation and prevents form fields from incorrectly appearing in user profiles.

src/elasticsearch/elasticsearch-sync.service.ts (14)

57-116: Well-structured user profile synchronization method

The method demonstrates good practices with proper early returns for disabled Elasticsearch, comprehensive error handling, and detailed logging. The logic for merging profile data while preserving custom fields is well thought out.


127-184: Solid application synchronization logic

The method correctly handles both scenarios - creating new applications and updating existing ones. The use of optional chaining for safe property access and proper error handling makes this robust.


195-209: Clean delegation pattern

Simple, focused wrapper method that provides a clear API while delegating to the common handler.


221-277: Effective centralization of application update logic

The method properly centralizes both sync and update operations, uses appropriate Elasticsearch Painless scripting for efficient partial updates, and maintains consistent error handling patterns throughout.


287-332: Form submission synchronization properly addresses previous concerns

The method now correctly uses submissionData.cohortId instead of formId throughout the implementation, addressing the data consistency concerns raised in previous reviews. The cohort details provider receives the proper cohort ID and the documentation is accurate.


348-439: Robust user profile building with comprehensive error handling

The method demonstrates excellent defensive programming with proper handling of missing users, date formatting edge cases, and custom field processing. The fallback behavior provides system stability.


449-472: Clean helper method with consistent delegation

The method maintains consistency by properly delegating to buildUserProfile and handles errors gracefully with appropriate fallback behavior.


481-556: Well-structured Elasticsearch Painless script implementation

The method creates a comprehensive Painless script that properly handles both update and create scenarios. The parameter binding approach ensures security and the script logic correctly manages the applications array.


564-586: Proper custom field transformation for Elasticsearch

The method correctly transforms custom fields into a structured format with comprehensive metadata mapping and appropriate handling of edge cases like missing fieldIds and undefined values.


594-604: Appropriate field value processing for search indexing

The method handles different value types correctly, with proper null handling and appropriate conversions (objects to JSON, others to strings) for Elasticsearch storage and indexing.


613-626: Efficient custom field filtering with proper context handling

The method correctly filters for USER/USERS context fields and uses efficient Set-based lookup for excluding form fields when needed.


636-679: Solid database integration for field context filtering

The method properly queries the database for field contexts, uses efficient Map-based lookups, and includes comprehensive error handling to ensure sync operations remain stable even if filtering encounters issues.


693-709: Clean document retrieval with proper optional chaining

The method effectively uses optional chaining for safe property access and maintains consistent error handling patterns throughout.


717-728: Straightforward delete operation with proper error handling

The method correctly handles the delete operation while maintaining consistent error handling and logging patterns.

LoggerUtil.debug(`Syncing form submission data for user: ${userId}, form: ${submissionData.formId}, cohort: ${submissionData.cohortId}`, 'ElasticsearchSyncService');

// Get cohort details if provider is available - now using proper cohortId
const cohortDetails = cohortDetailsProvider

Check notice

Code scanning / SonarCloud

Unused assignments should be removed Low

Remove this useless assignment to variable "cohortDetails". See more on SonarQube Cloud
Copy link

@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: 3

♻️ Duplicate comments (1)
src/elasticsearch/elasticsearch-sync.service.ts (1)

738-754: Unused parameters in searchUsers method

The method accepts filters and pagination parameters but doesn't use them in the implementation. Either remove these parameters or implement the functionality.

Either remove the unused parameters:

  async searchUsers(
-   query: string,
-   filters?: Record<string, any>,
-   pagination?: { page: number; limit: number }
+   query: string
  ): Promise<any> {

Or pass them to the service:

-     return await this.userElasticsearchService.searchUsers(query);
+     return await this.userElasticsearchService.searchUsers(query, filters, pagination);
🧹 Nitpick comments (4)
src/elasticsearch/elasticsearch-sync.service.ts (4)

39-56: Remove duplicate JSDoc comments

The method has duplicate JSDoc documentation. Keep only one version.

-  /**
-   * Sync user profile to Elasticsearch with comprehensive data fetching
-   * 
-   * @param userId - User ID to sync
-   * @param profileData - Profile data to sync (optional, will fetch from DB if not provided)
-   * @param customFieldsProvider - Function to get custom fields (optional)
-   * @param applicationDataProvider - Function to get application data (optional)
-   * @returns Promise<void>
-   */
   /**
    * Sync user profile to Elasticsearch with custom fields support
    * 
    * @param userId - User ID to sync
    * @param profileData - Profile data to sync (optional, will fetch from DB if not provided)
    * @param customFieldsProvider - Function to get custom fields (optional)
    * @param applicationDataProvider - Function to get application data (optional)
    * @returns Promise<void>
    */

74-82: Remove redundant custom field processing

The custom fields are already processed and included in the built profile at line 72. Re-processing them when profileData is provided is redundant since the merge operation preserves the existing custom fields.

      // If profileData is provided, merge it with the built profile (but preserve customFields)
      if (profileData) {
+       const { customFields } = profile;
        Object.assign(profile, profileData);
-       // Ensure customFields are preserved from the built profile
-       if (customFieldsProvider) {
-         const customFields = await customFieldsProvider(userId);
-         profile.customFields = this.processCustomFieldsForElasticsearch(customFields);
-       }
+       // Preserve customFields from the built profile
+       profile.customFields = customFields;
      }

334-347: Remove duplicate JSDoc comments

The method has duplicate JSDoc documentation. Keep only one version.

-  /**
-   * Build user profile from database data
-   * 
-   * @param userId - User ID
-   * @param customFieldsProvider - Function to get custom fields
-   * @returns Promise<IProfile>
-   */
   /**
    * Build user profile by fetching actual user data from database
    * 
    * @param userId - User ID to fetch profile for
    * @param customFieldsProvider - Function to get custom fields
    * @returns Promise<IProfile> - Complete user profile
    */

681-692: Remove duplicate JSDoc comments

The method has duplicate JSDoc documentation. Keep only one version.

-  /**
-   * Get user document from Elasticsearch
-   * 
-   * @param userId - User ID
-   * @returns Promise<IUser | null>
-   */
   /**
    * Get user document from Elasticsearch
    * 
    * @param userId - User ID to retrieve
    * @returns Promise resolving to user document or null if not found
    */
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 93c3528 and 9e8d2bf.

📒 Files selected for processing (1)
  • src/elasticsearch/elasticsearch-sync.service.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.ts

⚙️ CodeRabbit Configuration File

**/*.ts: "Review the JavaScript code for conformity with the Google JavaScript style guide, highlighting any deviations. Ensure that:

  • The code adheres to best practices associated with nodejs.
  • The code adheres to best practices associated with nestjs framework.
  • The code adheres to best practices recommended for performance.
  • The code adheres to similar naming conventions for controllers, models, services, methods, variables."

Files:

  • src/elasticsearch/elasticsearch-sync.service.ts
🪛 ESLint
src/elasticsearch/elasticsearch-sync.service.ts

[error] 1-1: Replace '@nestjs/common' with "@nestjs/common"

(prettier/prettier)


[error] 2-2: Replace '@nestjs/typeorm' with "@nestjs/typeorm"

(prettier/prettier)


[error] 3-3: Replace 'typeorm' with "typeorm"

(prettier/prettier)


[error] 4-4: Replace './user-elasticsearch.service' with "./user-elasticsearch.service"

(prettier/prettier)


[error] 5-5: Replace './interfaces/user.interface' with "./interfaces/user.interface"

(prettier/prettier)


[error] 6-6: Replace '../common/utils/elasticsearch.util' with "../common/utils/elasticsearch.util"

(prettier/prettier)


[error] 7-7: Replace '../common/logger/LoggerUtil' with "../common/logger/LoggerUtil"

(prettier/prettier)


[error] 8-8: Replace '../user/entities/user-entity' with "../user/entities/user-entity"

(prettier/prettier)


[error] 12-12: Delete ·

(prettier/prettier)


[error] 15-15: Delete ·

(prettier/prettier)


[error] 24-24: Delete ·

(prettier/prettier)


[error] 31-32: Delete

(prettier/prettier)


[error] 41-41: Delete ·

(prettier/prettier)


[error] 50-50: Delete ·

(prettier/prettier)


[error] 64-64: Replace ``Elasticsearch·disabled,·skipping·sync·for·user:·${userId},·'ElasticsearchSyncService' with `⏎········`Elasticsearch·disabled,·skipping·sync·for·user:·${userId}`,⏎········"ElasticsearchSyncService"⏎······`

(prettier/prettier)


[error] 69-69: Replace ``Starting·user·profile·sync·for:·${userId},·'ElasticsearchSyncService' with `⏎········`Starting·user·profile·sync·for:·${userId}`,⏎········"ElasticsearchSyncService"⏎······`

(prettier/prettier)


[error] 80-80: Insert ⏎···········

(prettier/prettier)


[error] 85-85: Delete ·

(prettier/prettier)


[error] 89-89: Replace ``Built·${applications.length}·applications·for·user:·${userId},·'ElasticsearchSyncService' with `⏎········`Built·${applications.length}·applications·for·user:·${userId}`,⏎········"ElasticsearchSyncService"⏎······`

(prettier/prettier)


[error] 107-107: Replace userId,·customFieldsProvider,·applicationDataProvider with ⏎············userId,⏎············customFieldsProvider,⏎············applicationDataProvider⏎··········

(prettier/prettier)


[error] 111-111: Replace ``Successfully·synced·user·profile·for:·${userId},·'ElasticsearchSyncService' with `⏎········`Successfully·synced·user·profile·for:·${userId}`,⏎········"ElasticsearchSyncService"⏎······`

(prettier/prettier)


[error] 113-113: Replace 'Failed·to·sync·user·profile·to·Elasticsearch',·error?.message·||·'Unknown·error',·'ElasticsearchSyncService',·userId with ⏎········"Failed·to·sync·user·profile·to·Elasticsearch",⏎········error?.message·||·"Unknown·error",⏎········"ElasticsearchSyncService",⏎········userId⏎······

(prettier/prettier)


[error] 120-120: Delete ·

(prettier/prettier)


[error] 138-138: Replace userId:·string,·cohortId:·string with ⏎······userId:·string,⏎······cohortId:·string⏎····

(prettier/prettier)


[error] 141-141: Replace ``Elasticsearch·disabled,·skipping·application·sync·for·user:·${userId},·cohort:·${cohortId},·'ElasticsearchSyncService' with `⏎········`Elasticsearch·disabled,·skipping·application·sync·for·user:·${userId},·cohort:·${cohortId}`,⏎········"ElasticsearchSyncService"⏎······`

(prettier/prettier)


[error] 146-146: Replace ``Starting·application·sync·for·user:·${userId},·cohort:·${cohortId},·'ElasticsearchSyncService' with `⏎········`Starting·application·sync·for·user:·${userId},·cohort:·${cohortId}`,⏎········"ElasticsearchSyncService"⏎······`

(prettier/prettier)


[error] 150-150: Delete ······

(prettier/prettier)


[error] 153-153: Delete ······

(prettier/prettier)


[error] 154-154: Replace app·=>·app.cohortId·===·cohortId with ⏎········(app)·=>·app.cohortId·===·cohortId⏎······

(prettier/prettier)


[error] 166-166: Delete ············

(prettier/prettier)


[error] 176-176: Replace userId,·cohortId,·updateData,·applicationDataProvider,·'sync' with ⏎··········userId,⏎··········cohortId,⏎··········updateData,⏎··········applicationDataProvider,⏎··········"sync"⏎········

(prettier/prettier)


[error] 179-179: Replace ``Successfully·synced·application·for·user:·${userId},·cohort:·${cohortId},·'ElasticsearchSyncService' with `⏎········`Successfully·synced·application·for·user:·${userId},·cohort:·${cohortId}`,⏎········"ElasticsearchSyncService"⏎······`

(prettier/prettier)


[error] 181-181: Replace 'Failed·to·sync·user·application·to·Elasticsearch',·error?.message·||·'Unknown·error',·'ElasticsearchSyncService',·userId with ⏎········"Failed·to·sync·user·application·to·Elasticsearch",⏎········error?.message·||·"Unknown·error",⏎········"ElasticsearchSyncService",⏎········userId⏎······

(prettier/prettier)


[error] 188-188: Delete ·

(prettier/prettier)


[error] 206-206: Replace userId:·string,·cohortId:·string with ⏎······userId:·string,⏎······cohortId:·string⏎····

(prettier/prettier)


[error] 208-208: Replace userId,·cohortId,·updateData,·applicationDataProvider,·'update' with ⏎······userId,⏎······cohortId,⏎······updateData,⏎······applicationDataProvider,⏎······"update"⏎····

(prettier/prettier)


[error] 213-213: Delete ·

(prettier/prettier)


[error] 232-232: Replace userId:·string,·cohortId:·string with ⏎······userId:·string,⏎······cohortId:·string⏎····

(prettier/prettier)


[error] 233-233: Replace 'sync'·|·'update'·=·'update' with "sync"·|·"update"·=·"update"

(prettier/prettier)


[error] 236-236: Replace ``Elasticsearch·disabled,·skipping·application·${operationType}·for·user:·${userId},·cohort:·${cohortId},·'ElasticsearchSyncService' with `⏎········`Elasticsearch·disabled,·skipping·application·${operationType}·for·user:·${userId},·cohort:·${cohortId}`,⏎········"ElasticsearchSyncService"⏎······`

(prettier/prettier)


[error] 241-241: Replace ``${operationType·===·'update'·?·'Updating'·:·'Starting'}·application·${operationType}·for·user:·${userId},·cohort:·${cohortId},·'ElasticsearchSyncService' with `⏎········`${⏎··········operationType·===·"update"·?·"Updating"·:·"Starting"⏎········}·application·${operationType}·for·user:·${userId},·cohort:·${cohortId}`,⏎········"ElasticsearchSyncService"⏎······`

(prettier/prettier)


[error] 272-272: Replace ``Successfully·${operationType·===·'update'·?·'updated'·:·'synced'}·application·${operationType·===·'update'·?·'data'·:·''}·for·user:·${userId},·cohort:·${cohortId},·'ElasticsearchSyncService' with `⏎········`Successfully·${⏎··········operationType·===·"update"·?·"updated"·:·"synced"⏎········}·application·${⏎··········operationType·===·"update"·?·"data"·:·""⏎········}·for·user:·${userId},·cohort:·${cohortId}`,⏎········"ElasticsearchSyncService"⏎······`

(prettier/prettier)


[error] 274-274: Replace ``Failed·to·${operationType}·application·${operationType·===·'update'·?·'data'·:·''}·in·Elasticsearch,·error?.message·||·'Unknown·error',·'ElasticsearchSyncService',·userId with `⏎········`Failed·to·${operationType}·application·${⏎··········operationType·===·"update"·?·"data"·:·""⏎········}·in·Elasticsearch`,⏎········error?.message·||·"Unknown·error",⏎········"ElasticsearchSyncService",⏎········userId⏎······`

(prettier/prettier)


[error] 281-281: Delete ·

(prettier/prettier)


[error] 303-303: Replace ``Elasticsearch·disabled,·skipping·form·submission·sync·for·user:·${userId},·'ElasticsearchSyncService' with `⏎········`Elasticsearch·disabled,·skipping·form·submission·sync·for·user:·${userId}`,⏎········"ElasticsearchSyncService"⏎······`

(prettier/prettier)


[error] 308-308: Replace ``Syncing·form·submission·data·for·user:·${userId},·form:·${submissionData.formId},·cohort:·${submissionData.cohortId},·'ElasticsearchSyncService' with `⏎········`Syncing·form·submission·data·for·user:·${userId},·form:·${submissionData.formId},·cohort:·${submissionData.cohortId}`,⏎········"ElasticsearchSyncService"⏎······`

(prettier/prettier)


[error] 311-311: Delete ·

(prettier/prettier)


[error] 313-313: Replace 'Unknown·Cohort',·status:·'active' with "Unknown·Cohort",·status:·"active"

(prettier/prettier)


[error] 327-327: Replace ``Successfully·synced·form·submission·data·for·user:·${userId},·form:·${submissionData.formId},·cohort:·${submissionData.cohortId},·'ElasticsearchSyncService' with `⏎········`Successfully·synced·form·submission·data·for·user:·${userId},·form:·${submissionData.formId},·cohort:·${submissionData.cohortId}`,⏎········"ElasticsearchSyncService"⏎······`

(prettier/prettier)


[error] 329-329: Replace 'Failed·to·sync·form·submission·data·to·Elasticsearch',·error?.message·||·'Unknown·error',·'ElasticsearchSyncService',·userId with ⏎········"Failed·to·sync·form·submission·data·to·Elasticsearch",⏎········error?.message·||·"Unknown·error",⏎········"ElasticsearchSyncService",⏎········userId⏎······

(prettier/prettier)


[error] 336-336: Delete ·

(prettier/prettier)


[error] 343-343: Delete ·

(prettier/prettier)


[error] 357-357: Replace ``User·not·found·in·database:·${userId},·'ElasticsearchSyncService' with `⏎··········`User·not·found·in·database:·${userId}`,⏎··········"ElasticsearchSyncService"⏎········`

(prettier/prettier)


[error] 361-361: Replace '' with ""

(prettier/prettier)


[error] 362-362: Replace '' with ""

(prettier/prettier)


[error] 363-363: Replace '' with ""

(prettier/prettier)


[error] 364-364: Replace '' with ""

(prettier/prettier)


[error] 365-365: Replace '' with ""

(prettier/prettier)


[error] 366-366: Replace '' with ""

(prettier/prettier)


[error] 367-367: Replace '' with ""

(prettier/prettier)


[error] 368-368: Replace '' with ""

(prettier/prettier)


[error] 369-369: Replace '' with ""

(prettier/prettier)


[error] 370-370: Replace '' with ""

(prettier/prettier)


[error] 371-371: Replace '' with ""

(prettier/prettier)


[error] 372-372: Replace '' with ""

(prettier/prettier)


[error] 373-373: Replace '' with ""

(prettier/prettier)


[error] 374-374: Replace '' with ""

(prettier/prettier)


[error] 375-375: Replace 'inactive' with "inactive"

(prettier/prettier)


[error] 381-381: Delete ·

(prettier/prettier)


[error] 386-386: Replace userId,·allCustomFields with ⏎········userId,⏎········allCustomFields⏎······

(prettier/prettier)


[error] 392-392: Replace 'string' with "string"

(prettier/prettier)


[error] 399-399: Replace '' with ""

(prettier/prettier)


[error] 400-400: Replace '' with ""

(prettier/prettier)


[error] 401-401: Replace '' with ""

(prettier/prettier)


[error] 402-402: Replace '' with ""

(prettier/prettier)


[error] 403-403: Replace '' with ""

(prettier/prettier)


[error] 404-404: Replace '' with ""

(prettier/prettier)


[error] 405-405: Replace '' with ""

(prettier/prettier)


[error] 406-406: Replace '' with ""

(prettier/prettier)


[error] 407-407: Replace '' with ""

(prettier/prettier)


[error] 408-408: Replace '' with ""

(prettier/prettier)


[error] 409-409: Replace '' with ""

(prettier/prettier)


[error] 410-410: Replace '' with ""

(prettier/prettier)


[error] 411-411: Replace '' with ""

(prettier/prettier)


[error] 412-412: Replace '' with ""

(prettier/prettier)


[error] 413-413: Replace 'active' with "active"

(prettier/prettier)


[error] 414-414: Insert ⏎·········

(prettier/prettier)


[error] 417-417: Replace ``Failed·to·build·user·profile·for:·${userId},·error,·'ElasticsearchSyncService',·userId with `⏎········`Failed·to·build·user·profile·for:·${userId}`,⏎········error,⏎········"ElasticsearchSyncService",⏎········userId⏎······`

(prettier/prettier)


[error] 421-421: Replace '' with ""

(prettier/prettier)


[error] 422-422: Replace '' with ""

(prettier/prettier)


[error] 423-423: Replace '' with ""

(prettier/prettier)


[error] 424-424: Replace '' with ""

(prettier/prettier)


[error] 425-425: Replace '' with ""

(prettier/prettier)


[error] 426-426: Replace '' with ""

(prettier/prettier)


[error] 427-427: Replace '' with ""

(prettier/prettier)


[error] 428-428: Replace '' with ""

(prettier/prettier)


[error] 429-429: Replace '' with ""

(prettier/prettier)


[error] 430-430: Replace '' with ""

(prettier/prettier)


[error] 431-431: Replace '' with ""

(prettier/prettier)


[error] 432-432: Replace '' with ""

(prettier/prettier)


[error] 433-433: Replace '' with ""

(prettier/prettier)


[error] 434-434: Replace '' with ""

(prettier/prettier)


[error] 435-435: Replace 'inactive' with "inactive"

(prettier/prettier)


[error] 443-443: Delete ·

(prettier/prettier)


[error] 456-456: Delete ·

(prettier/prettier)


[error] 469-469: Replace ``Failed·to·build·complete·user·document·for:·${userId},·error,·'ElasticsearchSyncService',·userId with `⏎········`Failed·to·build·complete·user·document·for:·${userId}`,⏎········error,⏎········"ElasticsearchSyncService",⏎········userId⏎······`

(prettier/prettier)


[error] 476-476: Delete ·

(prettier/prettier)


[error] 547-547: Replace 'painless' with "painless"

(prettier/prettier)


[error] 560-560: Delete ·

(prettier/prettier)


[error] 564-564: Replace customFields:·any[] with ⏎····customFields:·any[]⏎··

(prettier/prettier)


[error] 590-590: Delete ·

(prettier/prettier)


[error] 599-599: Replace 'object' with "object"

(prettier/prettier)


[error] 608-608: Delete ·

(prettier/prettier)


[error] 615-615: Replace field with (field)

(prettier/prettier)


[error] 616-616: Replace 'USER'·||·field.context·===·'USERS' with "USER"·||·field.context·===·"USERS"

(prettier/prettier)


[error] 622-622: Replace field·=>·!formFieldIdsSet.has(field.fieldId) with ⏎········(field)·=>·!formFieldIdsSet.has(field.fieldId)⏎······

(prettier/prettier)


[error] 631-631: Delete ·

(prettier/prettier)


[error] 636-636: Replace userId:·string,·customFields:·any[] with ⏎····userId:·string,⏎····customFields:·any[]⏎··

(prettier/prettier)


[error] 643-643: Replace field with (field)

(prettier/prettier)


[error] 647-647: Replace 'Fields' with "Fields"

(prettier/prettier)


[error] 648-648: Replace 'f' with "f"

(prettier/prettier)


[error] 649-649: Replace 'f.fieldId',·'f.context',·'f.contextType' with "f.fieldId",·"f.context",·"f.contextType"

(prettier/prettier)


[error] 650-650: Replace 'f.fieldId·IN·(:...fieldIds)' with "f.fieldId·IN·(:...fieldIds)"

(prettier/prettier)


[error] 655-655: Replace (field with ((field)

(prettier/prettier)


[error] 660-660: Replace field with (field)

(prettier/prettier)


[error] 662-662: Replace 'USER'·||·context·===·'USERS' with "USER"·||·context·===·"USERS"

(prettier/prettier)


[error] 663-663: Delete ········

(prettier/prettier)


[error] 665-665: Replace ``Excluding·field·${field.fieldId}·(${field.label})·with·context:·${context}·for·user:·${userId},·'ElasticsearchSyncService'); with `⏎············`Excluding·field·${field.fieldId}·(${field.label})·with·context:·${context}·for·user:·${userId}`,⏎············"ElasticsearchSyncService"`

(prettier/prettier)


[error] 666-666: Replace } with ··);

(prettier/prettier)


[error] 667-667: Insert }⏎

(prettier/prettier)


[error] 671-671: Replace ``Filtered·${customFields.length}·total·fields·to·${profileFields.length}·profile·fields·for·user:·${userId},·'ElasticsearchSyncService'); with `⏎········`Filtered·${customFields.length}·total·fields·to·${profileFields.length}·profile·fields·for·user:·${userId}`,⏎········"ElasticsearchSyncService"`

(prettier/prettier)


[error] 672-672: Insert );⏎

(prettier/prettier)


[error] 675-675: Replace ``Failed·to·filter·profile·custom·fields·for·user:·${userId},·error,·'ElasticsearchSyncService',·userId with `⏎········`Failed·to·filter·profile·custom·fields·for·user:·${userId}`,⏎········error,⏎········"ElasticsearchSyncService",⏎········userId⏎······`

(prettier/prettier)


[error] 683-683: Delete ·

(prettier/prettier)


[error] 689-689: Delete ·

(prettier/prettier)


[error] 695-695: Replace ``Elasticsearch·disabled,·skipping·get·user·document·for:·${userId},·'ElasticsearchSyncService' with `⏎········`Elasticsearch·disabled,·skipping·get·user·document·for:·${userId}`,⏎········"ElasticsearchSyncService"⏎······`

(prettier/prettier)


[error] 700-700: Replace ``Getting·user·document·for:·${userId},·'ElasticsearchSyncService' with `⏎········`Getting·user·document·for:·${userId}`,⏎········"ElasticsearchSyncService"⏎······`

(prettier/prettier)


[error] 702-702: Delete ······

(prettier/prettier)


[error] 704-704: Replace result?._source·as·IUser with (result?._source·as·IUser)

(prettier/prettier)


[error] 706-706: Replace 'Failed·to·get·user·document·from·Elasticsearch',·error?.message·||·'Unknown·error',·'ElasticsearchSyncService',·userId with ⏎········"Failed·to·get·user·document·from·Elasticsearch",⏎········error?.message·||·"Unknown·error",⏎········"ElasticsearchSyncService",⏎········userId⏎······

(prettier/prettier)


[error] 713-713: Delete ·

(prettier/prettier)


[error] 724-724: Replace ``Successfully·deleted·user·document:·${userId},·'ElasticsearchSyncService' with `⏎········`Successfully·deleted·user·document:·${userId}`,⏎········"ElasticsearchSyncService"⏎······`

(prettier/prettier)


[error] 726-726: Replace 'Failed·to·delete·user·document·from·Elasticsearch',·error?.message·||·'Unknown·error',·'ElasticsearchSyncService',·userId with ⏎········"Failed·to·delete·user·document·from·Elasticsearch",⏎········error?.message·||·"Unknown·error",⏎········"ElasticsearchSyncService",⏎········userId⏎······

(prettier/prettier)


[error] 732-732: Delete ·

(prettier/prettier)


[error] 751-751: Replace 'Failed·to·search·users·in·Elasticsearch',·error,·'ElasticsearchSyncService' with ⏎········"Failed·to·search·users·in·Elasticsearch",⏎········error,⏎········"ElasticsearchSyncService"⏎······

(prettier/prettier)


[error] 755-755: Replace · with

(prettier/prettier)

Comment on lines 156 to 173
if (!existingApplication) {
// If application is missing, build and upsert the full user document
if (applicationDataProvider) {
const fullUserDoc = await applicationDataProvider(userId, cohortId);
if (fullUserDoc) {
const userDocument = await this.buildCompleteUserDocument(
userId,
undefined,
async () => [fullUserDoc]
);

await this.userElasticsearchService.updateUser(
userId,
{ doc: userDocument },
async () => userDocument
);
}
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Potential data loss when creating new applications

When an application doesn't exist, the code creates a complete user document with only the new application. This could overwrite other existing applications in the user document. Consider fetching the existing user document and appending the new application to preserve existing data.

      if (!existingApplication) {
        // If application is missing, build and upsert the full user document
        if (applicationDataProvider) {
          const fullUserDoc = await applicationDataProvider(userId, cohortId);
          if (fullUserDoc) {
+           // Fetch existing user document to preserve other applications
+           const existingUser = await this.getUserDocument(userId);
+           const existingApplications = existingUser?.applications || [];
+           
            const userDocument = await this.buildCompleteUserDocument(
              userId,
              undefined,
-             async () => [fullUserDoc]
+             async () => [...existingApplications.filter(app => app.cohortId !== cohortId), fullUserDoc]
            );
            
            await this.userElasticsearchService.updateUser(
              userId,
              { doc: userDocument },
              async () => userDocument
            );
          }
        }
      }

Committable suggestion skipped: line range outside the PR's diff.

🧰 Tools
🪛 ESLint

[error] 166-166: Delete ············

(prettier/prettier)

🤖 Prompt for AI Agents
In src/elasticsearch/elasticsearch-sync.service.ts around lines 156 to 173, the
current logic creates a complete user document containing only the new
application when an application is missing, which risks overwriting existing
applications. To fix this, first fetch the existing user document, then append
the new application data to the existing applications list before updating the
user document. This ensures no existing application data is lost during the
update.

Comment on lines +606 to +626
/**
* Filter custom fields to include only profile fields (USER context)
*
* @param customFields - All custom fields
* @param formFieldIds - Form field IDs to exclude (optional)
* @returns Filtered custom fields (only profile fields)
*/
filterCustomFields(customFields: any[], formFieldIds: string[] = []): any[] {
// First filter by context - only include USER/USERS context fields
const profileFields = customFields.filter(field => {
return field.context === 'USER' || field.context === 'USERS';
});

// Then filter out fields used in forms (if formFieldIds provided)
if (formFieldIds && formFieldIds.length > 0) {
const formFieldIdsSet = new Set(formFieldIds);
return profileFields.filter(field => !formFieldIdsSet.has(field.fieldId));
}

return profileFields;
}
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Consider removing or clarifying the purpose of unused public method

The public filterCustomFields method appears to be unused within this service and duplicates functionality of the private filterProfileCustomFields method. If this method is intended for external use, consider adding documentation explaining its use case. Otherwise, consider removing it.


🏁 Script executed:

#!/bin/bash
# Check if filterCustomFields is used anywhere in the codebase
echo "Searching for usage of filterCustomFields method..."
rg -A 2 "filterCustomFields" --type ts

Length of output: 504


Remove or clarify the unused public filterCustomFields method

The public filterCustomFields (src/elasticsearch/elasticsearch-sync.service.ts lines 606–626) is never referenced in the codebase and duplicates the private filterProfileCustomFields logic.
• If it’s intended for external consumers, add clear documentation (or export it from a dedicated utility).
• Otherwise, remove it to avoid dead code and confusion.

🧰 Tools
🪛 ESLint

[error] 608-608: Delete ·

(prettier/prettier)


[error] 615-615: Replace field with (field)

(prettier/prettier)


[error] 616-616: Replace 'USER'·||·field.context·===·'USERS' with "USER"·||·field.context·===·"USERS"

(prettier/prettier)


[error] 622-622: Replace field·=>·!formFieldIdsSet.has(field.fieldId) with ⏎········(field)·=>·!formFieldIdsSet.has(field.fieldId)⏎······

(prettier/prettier)

🤖 Prompt for AI Agents
In src/elasticsearch/elasticsearch-sync.service.ts around lines 606 to 626, the
public method filterCustomFields is unused and duplicates the private
filterProfileCustomFields logic. To fix this, either remove the
filterCustomFields method entirely if it is not needed, or if it is intended for
external use, add clear documentation explaining its purpose and export it
properly from a dedicated utility module to avoid confusion and dead code.

@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
C Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

Copy link

@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: 0

♻️ Duplicate comments (5)
src/forms/services/form-submission.service.ts (1)

3027-3032: Critical: Remove unreachable code that was flagged in previous reviews.

This debug logging code is unreachable because it comes after the return statement on line 3026. This issue was already flagged in previous reviews but remains unaddressed.

    };
-
-    // Debug logging
-    LoggerUtil.warn(`buildUserDocumentForElasticsearch returning ${applications.length} applications for user: ${userId}`);
-    if (applications.length > 0) {
-      LoggerUtil.warn(`First application: ${JSON.stringify(applications[0], null, 2)}`);
-    }

If this logging is needed, move it before the return statement on line 3026.

src/elasticsearch/elasticsearch-sync.service.ts (4)

329-331: SonarCloud false positive on cohortDetails usage

The cohortDetails variable is used on line 343 in the application object, so this is not actually an unused assignment. This appears to be a SonarCloud false positive.


335-335: Temporary formId as cohortId usage

This temporary workaround of using formId as cohortId was already discussed in previous reviews. The comment indicates awareness of this limitation.


645-658: Public filterCustomFields method review

This method was previously reviewed for potential removal due to being unused. Since it remains in the code, it may be intended for external use.


774-790: Unused parameters in searchUsers method

The filters and pagination parameters are not utilized in the implementation, as noted in previous reviews.

🧹 Nitpick comments (5)
src/forms/services/form-submission.service.ts (4)

31-31: LGTM! Import change aligns with centralized Elasticsearch service.

The import of ElasticsearchSyncService correctly replaces the old service dependency. Consider fixing the quote consistency for better code style:

- import { ElasticsearchSyncService } from '../../elasticsearch/elasticsearch-sync.service';
+ import { ElasticsearchSyncService } from "../../elasticsearch/elasticsearch-sync.service";

1173-1173: Good delegation to centralized sync service.

The call to getUserDocument correctly uses the new centralized service. Consider fixing the formatting for better readability:

- const userDoc = await this.elasticsearchSyncService.getUserDocument(userId);
+ const userDoc = await this.elasticsearchSyncService.getUserDocument(
+         userId
+       );

1491-1507: Excellent architectural improvement with centralized sync pattern.

The new approach using syncUserProfile with application data provider callback is much more robust than direct Elasticsearch updates. It ensures consistency and proper error handling.

Consider fixing the formatting issues:

- await this.elasticsearchSyncService.syncUserProfile(
-   userId,
+ await this.elasticsearchSyncService.syncUserProfile(
+   userId,
- LoggerUtil.warn('Failed to sync user data to Elasticsearch:', syncError);
+ LoggerUtil.warn(
+   "Failed to sync user data to Elasticsearch:",
+   syncError
+ );

2665-2673: Good debug logging placement.

The debug logging here is well-placed and will help with troubleshooting application building. Consider fixing the formatting:

- LoggerUtil.warn(`Built ${applications.length} applications in buildUserDocumentForElasticsearch for user: ${userId}`);
+ LoggerUtil.warn(
+   `Built ${applications.length} applications in buildUserDocumentForElasticsearch for user: ${userId}`
+ );
src/elasticsearch/elasticsearch-sync.service.ts (1)

1-8: Address ESLint formatting issues

The import statements have formatting inconsistencies flagged by ESLint (single vs double quotes). While these don't affect functionality, they should be fixed for code consistency.

Run npm run lint:fix or yarn lint:fix to automatically resolve these formatting issues.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 9e8d2bf and 19438a7.

📒 Files selected for processing (2)
  • src/elasticsearch/elasticsearch-sync.service.ts (1 hunks)
  • src/forms/services/form-submission.service.ts (9 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.ts

⚙️ CodeRabbit Configuration File

**/*.ts: "Review the JavaScript code for conformity with the Google JavaScript style guide, highlighting any deviations. Ensure that:

  • The code adheres to best practices associated with nodejs.
  • The code adheres to best practices associated with nestjs framework.
  • The code adheres to best practices recommended for performance.
  • The code adheres to similar naming conventions for controllers, models, services, methods, variables."

Files:

  • src/elasticsearch/elasticsearch-sync.service.ts
  • src/forms/services/form-submission.service.ts
🧬 Code Graph Analysis (1)
src/elasticsearch/elasticsearch-sync.service.ts (4)
src/adapters/postgres/user-adapter.ts (2)
  • PostgresUserService (60-2978)
  • constructor (72-111)
src/elasticsearch/interfaces/user.interface.ts (3)
  • IProfile (42-60)
  • IApplication (1-34)
  • IUser (81-88)
src/common/utils/elasticsearch.util.ts (1)
  • isElasticsearchEnabled (1-3)
src/common/logger/LoggerUtil.ts (1)
  • LoggerUtil (3-78)
🪛 GitHub Check: SonarCloud
src/elasticsearch/elasticsearch-sync.service.ts

[notice] 311-311: Unused assignments should be removed

Remove this useless assignment to variable "cohortDetails".

See more on SonarQube Cloud

🪛 ESLint
src/elasticsearch/elasticsearch-sync.service.ts

[error] 1-1: Replace '@nestjs/common' with "@nestjs/common"

(prettier/prettier)


[error] 2-2: Replace '@nestjs/typeorm' with "@nestjs/typeorm"

(prettier/prettier)


[error] 3-3: Replace 'typeorm' with "typeorm"

(prettier/prettier)


[error] 4-4: Replace './user-elasticsearch.service' with "./user-elasticsearch.service"

(prettier/prettier)


[error] 5-5: Replace './interfaces/user.interface' with "./interfaces/user.interface"

(prettier/prettier)


[error] 6-6: Replace '../common/utils/elasticsearch.util' with "../common/utils/elasticsearch.util"

(prettier/prettier)


[error] 7-7: Replace '../common/logger/LoggerUtil' with "../common/logger/LoggerUtil"

(prettier/prettier)


[error] 8-8: Replace '../user/entities/user-entity' with "../user/entities/user-entity"

(prettier/prettier)


[error] 12-12: Delete ·

(prettier/prettier)


[error] 15-15: Delete ·

(prettier/prettier)


[error] 24-24: Delete ·

(prettier/prettier)


[error] 42-42: Delete ·

(prettier/prettier)


[error] 51-51: Delete ·

(prettier/prettier)


[error] 65-65: Replace Elasticsearch·disabled,·skipping·sync·for·user:·${userId} with ⏎········Elasticsearch·disabled,·skipping·sync·for·user:·${userId}⏎······

(prettier/prettier)


[error] 81-81: Insert ⏎···········

(prettier/prettier)


[error] 86-86: Delete ·

(prettier/prettier)


[error] 90-90: Replace Built·${applications.length}·applications·for·user:·${userId} with ⏎········Built·${applications.length}·applications·for·user:·${userId}⏎······

(prettier/prettier)


[error] 108-108: Replace userId,·customFieldsProvider,·applicationDataProvider with ⏎············userId,⏎············customFieldsProvider,⏎············applicationDataProvider⏎··········

(prettier/prettier)


[error] 114-114: Replace 'Failed·to·sync·user·profile·to·Elasticsearch',·error?.message·||·'Unknown·error',·'ElasticsearchSyncService',·userId with ⏎········"Failed·to·sync·user·profile·to·Elasticsearch",⏎········error?.message·||·"Unknown·error",⏎········"ElasticsearchSyncService",⏎········userId⏎······

(prettier/prettier)


[error] 121-121: Delete ·

(prettier/prettier)


[error] 139-139: Replace userId:·string,·cohortId:·string with ⏎······userId:·string,⏎······cohortId:·string⏎····

(prettier/prettier)


[error] 142-142: Replace Elasticsearch·disabled,·skipping·application·sync·for·user:·${userId},·cohort:·${cohortId} with ⏎········Elasticsearch·disabled,·skipping·application·sync·for·user:·${userId},·cohort:·${cohortId}⏎······

(prettier/prettier)


[error] 147-147: Replace Starting·application·sync·for·user:·${userId},·cohort:·${cohortId} with ⏎········Starting·application·sync·for·user:·${userId},·cohort:·${cohortId}⏎······

(prettier/prettier)


[error] 151-151: Delete ······

(prettier/prettier)


[error] 153-153: Insert ⏎·······

(prettier/prettier)


[error] 154-154: Replace ········ with ··········

(prettier/prettier)


[error] 155-155: Insert ··

(prettier/prettier)


[error] 156-156: Delete ······

(prettier/prettier)


[error] 157-157: Insert ⏎·······

(prettier/prettier)


[error] 158-158: Replace ?·source.applications.find(app with ··?·source.applications.find((app)

(prettier/prettier)


[error] 159-159: Replace ········ with ··········

(prettier/prettier)


[error] 175-175: Delete ············

(prettier/prettier)


[error] 195-195: Replace userId,·cohortId,·updateData,·applicationDataProvider,·'sync' with ⏎··········userId,⏎··········cohortId,⏎··········updateData,⏎··········applicationDataProvider,⏎··········"sync"⏎········

(prettier/prettier)


[error] 198-198: Replace Successfully·synced·application·for·user:·${userId},·cohort:·${cohortId} with ⏎········Successfully·synced·application·for·user:·${userId},·cohort:·${cohortId}⏎······

(prettier/prettier)


[error] 200-200: Replace 'Failed·to·sync·user·application·to·Elasticsearch',·error?.message·||·'Unknown·error',·'ElasticsearchSyncService',·userId with ⏎········"Failed·to·sync·user·application·to·Elasticsearch",⏎········error?.message·||·"Unknown·error",⏎········"ElasticsearchSyncService",⏎········userId⏎······

(prettier/prettier)


[error] 207-207: Delete ·

(prettier/prettier)


[error] 225-225: Replace userId:·string,·cohortId:·string with ⏎······userId:·string,⏎······cohortId:·string⏎····

(prettier/prettier)


[error] 227-227: Replace userId,·cohortId,·updateData,·applicationDataProvider,·'update' with ⏎······userId,⏎······cohortId,⏎······updateData,⏎······applicationDataProvider,⏎······"update"⏎····

(prettier/prettier)


[error] 232-232: Delete ·

(prettier/prettier)


[error] 251-251: Replace userId:·string,·cohortId:·string with ⏎······userId:·string,⏎······cohortId:·string⏎····

(prettier/prettier)


[error] 252-252: Replace 'sync'·|·'update'·=·'update' with "sync"·|·"update"·=·"update"

(prettier/prettier)


[error] 255-255: Replace Elasticsearch·disabled,·skipping·application·${operationType}·for·user:·${userId},·cohort:·${cohortId} with ⏎········Elasticsearch·disabled,·skipping·application·${operationType}·for·user:·${userId},·cohort:·${cohortId}⏎······

(prettier/prettier)


[error] 260-260: Replace ${operationType·===·'update'·?·'Updating'·:·'Starting'}·application·${operationType}·for·user:·${userId},·cohort:·${cohortId} with ⏎········${⏎··········operationType·===·"update"·?·"Updating"·:·"Starting"⏎········}·application·${operationType}·for·user:·${userId},·cohort:·${cohortId}⏎······

(prettier/prettier)


[error] 291-291: Replace Successfully·${operationType·===·'update'·?·'updated'·:·'synced'}·application·${operationType·===·'update'·?·'data'·:·''}·for·user:·${userId},·cohort:·${cohortId} with ⏎········Successfully·${⏎··········operationType·===·"update"·?·"updated"·:·"synced"⏎········}·application·${⏎··········operationType·===·"update"·?·"data"·:·""⏎········}·for·user:·${userId},·cohort:·${cohortId}⏎······

(prettier/prettier)


[error] 293-293: Replace ``Failed·to·${operationType}·application·${operationType·===·'update'·?·'data'·:·''}·in·Elasticsearch,·error?.message·||·'Unknown·error',·'ElasticsearchSyncService',·userId with `⏎········`Failed·to·${operationType}·application·${⏎··········operationType·===·"update"·?·"data"·:·""⏎········}·in·Elasticsearch`,⏎········error?.message·||·"Unknown·error",⏎········"ElasticsearchSyncService",⏎········userId⏎······`

(prettier/prettier)


[error] 300-300: Delete ·

(prettier/prettier)


[error] 321-321: Replace Elasticsearch·disabled,·skipping·form·submission·sync·for·user:·${userId} with ⏎········Elasticsearch·disabled,·skipping·form·submission·sync·for·user:·${userId}⏎······

(prettier/prettier)


[error] 326-326: Replace Syncing·form·submission·data·for·user:·${userId},·form:·${submissionData.formId} with ⏎········Syncing·form·submission·data·for·user:·${userId},·form:·${submissionData.formId}⏎······

(prettier/prettier)


[error] 329-329: Delete ·

(prettier/prettier)


[error] 331-331: Replace 'Unknown·Cohort',·status:·'active' with "Unknown·Cohort",·status:·"active"

(prettier/prettier)


[error] 348-351: Replace ⏎········userId,⏎········submissionData.formId,⏎······· with userId,·submissionData.formId,

(prettier/prettier)


[error] 352-352: Delete ··

(prettier/prettier)


[error] 353-353: Delete ··

(prettier/prettier)


[error] 354-354: Delete ··

(prettier/prettier)


[error] 355-355: Delete ··

(prettier/prettier)


[error] 356-357: Replace ··}⏎······ with }

(prettier/prettier)


[error] 359-359: Replace Successfully·synced·form·submission·data·for·user:·${userId},·form:·${submissionData.formId} with ⏎········Successfully·synced·form·submission·data·for·user:·${userId},·form:·${submissionData.formId}⏎······

(prettier/prettier)


[error] 361-361: Replace 'Failed·to·sync·form·submission·data·to·Elasticsearch',·error?.message·||·'Unknown·error',·'ElasticsearchSyncService',·userId with ⏎········"Failed·to·sync·form·submission·data·to·Elasticsearch",⏎········error?.message·||·"Unknown·error",⏎········"ElasticsearchSyncService",⏎········userId⏎······

(prettier/prettier)


[error] 368-368: Delete ·

(prettier/prettier)


[error] 375-375: Delete ·

(prettier/prettier)


[error] 393-393: Replace '' with ""

(prettier/prettier)


[error] 394-394: Replace '' with ""

(prettier/prettier)


[error] 395-395: Replace '' with ""

(prettier/prettier)


[error] 396-396: Replace '' with ""

(prettier/prettier)


[error] 397-397: Replace '' with ""

(prettier/prettier)


[error] 398-398: Replace '' with ""

(prettier/prettier)


[error] 399-399: Replace '' with ""

(prettier/prettier)


[error] 400-400: Replace '' with ""

(prettier/prettier)


[error] 401-401: Replace '' with ""

(prettier/prettier)


[error] 402-402: Replace '' with ""

(prettier/prettier)


[error] 403-403: Replace '' with ""

(prettier/prettier)


[error] 404-404: Replace '' with ""

(prettier/prettier)


[error] 405-405: Replace '' with ""

(prettier/prettier)


[error] 406-406: Replace '' with ""

(prettier/prettier)


[error] 407-407: Replace 'inactive' with "inactive"

(prettier/prettier)


[error] 413-413: Delete ·

(prettier/prettier)


[error] 418-418: Replace userId,·allCustomFields with ⏎········userId,⏎········allCustomFields⏎······

(prettier/prettier)


[error] 424-424: Replace 'string' with "string"

(prettier/prettier)


[error] 431-431: Replace '' with ""

(prettier/prettier)


[error] 432-432: Replace '' with ""

(prettier/prettier)


[error] 433-433: Replace '' with ""

(prettier/prettier)


[error] 434-434: Replace '' with ""

(prettier/prettier)


[error] 435-435: Replace '' with ""

(prettier/prettier)


[error] 436-436: Replace '' with ""

(prettier/prettier)


[error] 437-437: Replace '' with ""

(prettier/prettier)


[error] 438-438: Replace '' with ""

(prettier/prettier)


[error] 439-439: Replace '' with ""

(prettier/prettier)


[error] 440-440: Replace '' with ""

(prettier/prettier)


[error] 441-441: Replace '' with ""

(prettier/prettier)


[error] 442-442: Replace '' with ""

(prettier/prettier)


[error] 443-443: Replace '' with ""

(prettier/prettier)


[error] 444-444: Replace '' with ""

(prettier/prettier)


[error] 445-445: Replace 'active' with "active"

(prettier/prettier)


[error] 446-446: Insert ⏎·········

(prettier/prettier)


[error] 453-453: Replace '' with ""

(prettier/prettier)


[error] 454-454: Replace '' with ""

(prettier/prettier)


[error] 455-455: Replace '' with ""

(prettier/prettier)


[error] 456-456: Replace '' with ""

(prettier/prettier)


[error] 457-457: Replace '' with ""

(prettier/prettier)


[error] 458-458: Replace '' with ""

(prettier/prettier)


[error] 459-459: Replace '' with ""

(prettier/prettier)


[error] 460-460: Replace '' with ""

(prettier/prettier)


[error] 461-461: Replace '' with ""

(prettier/prettier)


[error] 462-462: Replace '' with ""

(prettier/prettier)


[error] 463-463: Replace '' with ""

(prettier/prettier)


[error] 464-464: Replace '' with ""

(prettier/prettier)


[error] 465-465: Replace '' with ""

(prettier/prettier)


[error] 466-466: Replace '' with ""

(prettier/prettier)


[error] 467-467: Replace 'inactive' with "inactive"

(prettier/prettier)


[error] 475-475: Delete ·

(prettier/prettier)


[error] 488-488: Delete ·

(prettier/prettier)


[error] 501-501: Replace ``Failed·to·build·complete·user·document·for:·${userId},·error with `⏎········`Failed·to·build·complete·user·document·for:·${userId}`,⏎········error⏎······`

(prettier/prettier)


[error] 508-508: Delete ·

(prettier/prettier)


[error] 579-579: Replace 'painless' with "painless"

(prettier/prettier)


[error] 592-592: Delete ·

(prettier/prettier)


[error] 596-596: Replace customFields:·any[] with ⏎····customFields:·any[]⏎··

(prettier/prettier)


[error] 622-622: Delete ·

(prettier/prettier)


[error] 631-631: Replace 'object' with "object"

(prettier/prettier)


[error] 640-640: Delete ·

(prettier/prettier)


[error] 647-647: Replace (field with ((field)

(prettier/prettier)


[error] 648-648: Replace 'USER'·||·field.context·===·'USERS' with "USER"·||·field.context·===·"USERS"

(prettier/prettier)


[error] 654-654: Replace (field·=>·!formFieldIdsSet.has(field.fieldId) with (⏎········(field)·=>·!formFieldIdsSet.has(field.fieldId)⏎······

(prettier/prettier)


[error] 663-663: Delete ·

(prettier/prettier)


[error] 668-668: Replace userId:·string,·customFields:·any[] with ⏎····userId:·string,⏎····customFields:·any[]⏎··

(prettier/prettier)


[error] 675-675: Replace field with (field)

(prettier/prettier)


[error] 679-679: Replace 'Fields' with "Fields"

(prettier/prettier)


[error] 680-680: Replace 'f' with "f"

(prettier/prettier)


[error] 681-681: Replace 'f.fieldId',·'f.context',·'f.contextType' with "f.fieldId",·"f.context",·"f.contextType"

(prettier/prettier)


[error] 682-682: Replace 'f.fieldId·IN·(:...fieldIds)' with "f.fieldId·IN·(:...fieldIds)"

(prettier/prettier)


[error] 687-687: Replace field with (field)

(prettier/prettier)


[error] 692-692: Replace field with (field)

(prettier/prettier)


[error] 694-694: Replace 'USER'·||·context·===·'USERS' with "USER"·||·context·===·"USERS"

(prettier/prettier)


[error] 695-695: Delete ········

(prettier/prettier)


[error] 697-697: Replace Excluding·field·${field.fieldId}·(${field.label})·with·context:·${context}·for·user:·${userId} with ⏎············Excluding·field·${field.fieldId}·(${field.label})·with·context:·${context}·for·user:·${userId}⏎··········

(prettier/prettier)


[error] 699-699: Delete ········

(prettier/prettier)


[error] 703-703: Replace Filtered·${customFields.length}·total·fields·to·${profileFields.length}·profile·fields·for·user:·${userId}`);` with `⏎········`Filtered·${customFields.length}·total·fields·to·${profileFields.length}·profile·fields·for·user:·${userId}

(prettier/prettier)


[error] 704-704: Insert );⏎

(prettier/prettier)


[error] 707-707: Replace ``Failed·to·filter·profile·custom·fields·for·user:·${userId},·error with `⏎········`Failed·to·filter·profile·custom·fields·for·user:·${userId}`,⏎········error⏎······`

(prettier/prettier)


[error] 715-715: Delete ·

(prettier/prettier)


[error] 721-721: Delete ·

(prettier/prettier)


[error] 727-727: Replace Elasticsearch·disabled,·skipping·get·user·document·for:·${userId} with ⏎········Elasticsearch·disabled,·skipping·get·user·document·for:·${userId}⏎······

(prettier/prettier)


[error] 734-734: Delete ······

(prettier/prettier)


[error] 739-739: Delete ······

(prettier/prettier)


[error] 742-742: Replace 'Failed·to·get·user·document·from·Elasticsearch',·error?.message·||·'Unknown·error',·'ElasticsearchSyncService',·userId with ⏎········"Failed·to·get·user·document·from·Elasticsearch",⏎········error?.message·||·"Unknown·error",⏎········"ElasticsearchSyncService",⏎········userId⏎······

(prettier/prettier)


[error] 749-749: Delete ·

(prettier/prettier)


[error] 762-762: Replace 'Failed·to·delete·user·document·from·Elasticsearch',·error?.message·||·'Unknown·error',·'ElasticsearchSyncService',·userId with ⏎········"Failed·to·delete·user·document·from·Elasticsearch",⏎········error?.message·||·"Unknown·error",⏎········"ElasticsearchSyncService",⏎········userId⏎······

(prettier/prettier)


[error] 768-768: Delete ·

(prettier/prettier)


[error] 787-787: Replace 'Failed·to·search·users·in·Elasticsearch' with "Failed·to·search·users·in·Elasticsearch"

(prettier/prettier)


[error] 791-791: Replace · with

(prettier/prettier)

src/forms/services/form-submission.service.ts

[error] 31-31: Replace '../../elasticsearch/elasticsearch-sync.service' with "../../elasticsearch/elasticsearch-sync.service"

(prettier/prettier)


[error] 1173-1173: Replace userId with ⏎········userId⏎······

(prettier/prettier)


[error] 1500-1500: Replace userId with ⏎················userId⏎··············

(prettier/prettier)


[error] 1505-1505: Replace 'Failed·to·sync·user·data·to·Elasticsearch:',·syncError with ⏎············"Failed·to·sync·user·data·to·Elasticsearch:",⏎············syncError⏎··········

(prettier/prettier)


[error] 2667-2667: Replace Built·${applications.length}·applications·in·buildUserDocumentForElasticsearch·for·user:·${userId} with ⏎······Built·${applications.length}·applications·in·buildUserDocumentForElasticsearch·for·user:·${userId}⏎····

(prettier/prettier)


[error] 2668-2668: Replace CohortMembers·found:·${cohortMemberships.length},·FormSubmissions·found:·${submissions.length} with ⏎······CohortMembers·found:·${cohortMemberships.length},·FormSubmissions·found:·${submissions.length}⏎····

(prettier/prettier)


[error] 2669-2669: Replace ',·' with ",·"

(prettier/prettier)


[error] 2671-2671: Replace Sample·application:·${JSON.stringify(applications[0],·null,·2)} with ⏎········Sample·application:·${JSON.stringify(applications[0],·null,·2)}⏎······

(prettier/prettier)


[error] 3029-3029: Replace buildUserDocumentForElasticsearch·returning·${applications.length}·applications·for·user:·${userId} with ⏎······buildUserDocumentForElasticsearch·returning·${applications.length}·applications·for·user:·${userId}⏎····

(prettier/prettier)


[error] 3031-3031: Replace First·application:·${JSON.stringify(applications[0],·null,·2)} with ⏎········First·application:·${JSON.stringify(applications[0],·null,·2)}⏎······

(prettier/prettier)

🪛 Biome (2.1.2)
src/forms/services/form-submission.service.ts

[error] 3029-3032: This code is unreachable

(lint/correctness/noUnreachable)

🔇 Additional comments (7)
src/forms/services/form-submission.service.ts (3)

91-91: Correct service dependency injection.

The dependency injection correctly uses the new ElasticsearchSyncService instead of the old UserElasticsearchService, aligning with the centralized Elasticsearch synchronization approach.


1177-1180: Excellent simplification of user document handling.

The code correctly leverages that getUserDocument returns data in the proper IUser format, eliminating the need for manual parsing and conversion. This reduces complexity and potential errors.


1536-1544: Consistent simplification of cohort details structure.

The removal of customFields from cohort details across all methods is well-executed and consistent. This aligns with the simplified cohort detail retrieval approach mentioned in the PR objectives.

Also applies to: 1940-1948, 2634-2642

src/elasticsearch/elasticsearch-sync.service.ts (4)

34-38: LGTM! Clean dependency injection setup

The constructor properly follows NestJS patterns with correct dependency injection for the UserElasticsearchService and User repository.


58-117: Excellent implementation of user profile synchronization

The method demonstrates good practices:

  • Proper Elasticsearch enablement check
  • Comprehensive error handling with detailed logging
  • Fallback mechanism for document creation
  • Clean separation of concerns

128-203: Well-structured application synchronization logic

The method properly handles different scenarios:

  • Missing applications are handled with full document creation
  • Existing applications use the optimized update path
  • Good error handling and logging throughout

513-588: Robust Painless script implementation

The script properly handles:

  • Initialization of applications array if missing
  • Finding existing applications by cohortId
  • Conditional field updates with null checks
  • Creation of new applications when not found
  • Proper parameter passing and timestamp management

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.

1 participant