-
Notifications
You must be signed in to change notification settings - Fork 20
Issue #000000 Fix: Fixed Elasticsearch duplication code #411
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: aspire-leaders
Are you sure you want to change the base?
Conversation
WalkthroughThe changes introduce a new Changes
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
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 unit tests
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed 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)
Other keywords and placeholders
Documentation and Community
|
There was a problem hiding this 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
getFieldIdToPageNameMapfunction 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.updateApplicationDataproperly 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.syncUserApplicationis 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 commentsThere 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 providedThe method always builds a complete profile from the database even when
profileDatais 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 commentsAnother 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 duplicationThe 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 nameUsing 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 commentsYet 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 ElasticsearchSyncServiceThis 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
📒 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.tssrc/elasticsearch/elasticsearch.module.tssrc/adapters/postgres/cohortMembers-adapter.tssrc/forms/services/form-submission.service.tssrc/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.tssrc/elasticsearch/elasticsearch.module.tssrc/adapters/postgres/cohortMembers-adapter.tssrc/forms/services/form-submission.service.tssrc/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
ElasticsearchSyncServiceis 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
customFieldsfrom 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
buildUserDocumentForElasticsearchpublic 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
processFieldValueForElasticsearchmethod 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 updatesThe 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 operationsThe 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
There was a problem hiding this 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 accessReplace 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 codeSimplify 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 serviceThe service uses both NestJS's built-in
Loggerand a customLoggerUtil, creating inconsistency in logging patterns. The built-in logger is used for debug logs whileLoggerUtilis 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
LoggerUtilconsistently.Also applies to: 32-33
163-192: Remove code duplication when building user documentsThere'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 usageThe
applicationvariable is built but never used. Additionally, usingformIdascohortIdis marked as temporary and could lead to data inconsistency.The temporary use of
formIdascohortIdneeds to be addressed properly. Consider either:
- Adding a proper cohortId parameter to the method
- Documenting why formId is being used as cohortId
- Creating a mapping between formId and cohortId
Also, remove the unused
applicationvariable since the data is passed directly toupdateApplicationData.
🧹 Nitpick comments (1)
src/elasticsearch/elasticsearch-sync.service.ts (1)
40-57: Remove duplicate JSDoc commentThere are two identical JSDoc comment blocks for the
syncUserProfilemethod. 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
📒 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 handlingThe 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 updatesThe script correctly:
- Initializes applications array if missing
- Updates only provided fields, preserving existing data
- Handles both existing and new applications
- Maintains proper timestamps
There was a problem hiding this 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.tsOr 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 styleThe 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
📒 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.tssrc/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
UserElasticsearchServicewithElasticsearchSyncService, 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
getFieldIdToPageNameMapfunction 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 methodThe 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 logicThe 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 patternSimple, focused wrapper method that provides a clear API while delegating to the common handler.
221-277: Effective centralization of application update logicThe 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 concernsThe method now correctly uses
submissionData.cohortIdinstead offormIdthroughout 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 handlingThe 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 delegationThe method maintains consistency by properly delegating to
buildUserProfileand handles errors gracefully with appropriate fallback behavior.
481-556: Well-structured Elasticsearch Painless script implementationThe 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 ElasticsearchThe 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 indexingThe 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 handlingThe 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 filteringThe 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 chainingThe method effectively uses optional chaining for safe property access and maintains consistent error handling patterns throughout.
717-728: Straightforward delete operation with proper error handlingThe 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
This reverts commit e71e9ce.
There was a problem hiding this 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 methodThe method accepts
filtersandpaginationparameters 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 commentsThe 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 processingThe custom fields are already processed and included in the built profile at line 72. Re-processing them when
profileDatais 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 commentsThe 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 commentsThe 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
📒 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)
| 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 | ||
| ); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| /** | ||
| * 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; | ||
| } |
There was a problem hiding this comment.
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 tsLength 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.
|
There was a problem hiding this 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 usageThe
cohortDetailsvariable 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 usageThis 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 reviewThis 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 methodThe 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
ElasticsearchSyncServicecorrectly 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
getUserDocumentcorrectly 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
syncUserProfilewith 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 issuesThe 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:fixoryarn lint:fixto 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
📒 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.tssrc/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
ElasticsearchSyncServiceinstead of the oldUserElasticsearchService, aligning with the centralized Elasticsearch synchronization approach.
1177-1180: Excellent simplification of user document handling.The code correctly leverages that
getUserDocumentreturns data in the properIUserformat, 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
customFieldsfrom 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 setupThe constructor properly follows NestJS patterns with correct dependency injection for the UserElasticsearchService and User repository.
58-117: Excellent implementation of user profile synchronizationThe 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 logicThe 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 implementationThe 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




Summary by CodeRabbit
New Features
Refactor
Bug Fixes
Chores