Skip to content

Conversation

leite08
Copy link
Member

@leite08 leite08 commented Jun 15, 2025

Dependencies

  • Upstream: none
  • Downstream: none

Description

Updates to the codebase pre-coverage assessment on lambdas.

  • minor improvements on bulk import endpoint
  • DOB validation doesn't accept dates w/ less than 10 chars
  • bulk import steps executed "asynchronously" as cloud does
    • don't bubble up errors
  • move consolidated search infra to a dedicated construct

Testing

  • Local
    • get bulk import endpoints provide more/better context
    • unit tests for DOB w/ less than 10 chars
    • errors don't get bubbled up to previous step on bulk import
    • errors on bulk import steps are mapped to job, but don't fail it
  • Staging
    • bulk import w/ only valid records finish properly, including counts
    • bulk import w/ some invalid records finish properly, including counts (records are flagged as failed)
  • Sandbox
    • none
  • Production
    • none

Release Plan

  • Merge this

Summary by CodeRabbit

  • New Features

    • Introduced a new AWS CDK construct to simplify deployment and configuration of consolidated search and ingestion infrastructure.
    • Added new command-style functions for patient import processing (parsing, creating, querying, and result handling), improving modularity and error handling.
    • Enhanced CSV patient import validation with clearer error messages for missing or invalid fields.
  • Improvements

    • Refactored patient import processing from class-based to command-based architecture for better maintainability and scalability.
    • Updated infrastructure setup to use a single construct for consolidated search and ingestion, streamlining resource management.
    • Improved type safety for CSV patient data handling, allowing for undefined field values.
    • Made job status updates more flexible by allowing the status field to be optional.
    • Encapsulated AWS client and configuration initialization within classes to improve resource management and reduce external dependencies.
    • Simplified patient import handlers by delegating processing to command functions, aligning error handling with asynchronous cloud behavior.
    • Enhanced title casing to correctly capitalize words containing apostrophes.
  • Bug Fixes

    • Improved date of birth validation to handle edge cases and prevent invalid or incomplete date strings from passing validation.
  • Tests

    • Added comprehensive tests for CSV patient mapping, covering various missing and invalid field scenarios.
    • Expanded date validation test coverage for edge cases and input formats.

Ref eng-36

Signed-off-by: Rafael Leite <2132564+leite08@users.noreply.github.com>
Copy link

linear bot commented Jun 15, 2025

Copy link

coderabbitai bot commented Jun 15, 2025

Walkthrough

This change refactors the patient import workflow by moving core logic from class-based handlers to command-style functions, updates type signatures for better CSV data handling, improves date-of-birth validation, introduces new error handling and reporting structures, and consolidates AWS infrastructure setup using new constructs. Additional comprehensive tests and schema updates are included.

Changes

File(s) / Group Change Summary
packages/core/src/command/patient-import/steps/create/patient-import-create-command.ts, .../parse/patient-import-parse-command.ts, .../query/patient-import-query-command.ts, .../result/patient-import-result-command.ts, .../patient-or-record-failed.ts Introduced new command modules and functions to handle patient import creation, parsing, querying, result processing, and error marking as standalone async functions.
packages/core/src/command/patient-import/steps/create/patient-import-create-local.ts, .../parse/patient-import-parse-local.ts, .../query/patient-import-query-local.ts, .../result/patient-import-result-local.ts Refactored to delegate logic to new command functions; constructors now use config defaults; error handling simplified to logging and swallowing errors.
packages/core/src/command/patient-import/steps/create/patient-import-create-factory.ts, .../parse/patient-import-parse-factory.ts, .../query/patient-import-query-factory.ts, .../result/patient-import-result-factory.ts Simplified factory functions; removed explicit config parameter passing; constructors now called without arguments.
packages/core/src/command/patient-import/steps/create/patient-import-create-cloud.ts, .../parse/patient-import-parse-cloud.ts, .../query/patient-import-query-cloud.ts, .../result/patient-import-result-cloud.ts Refactored constructors to initialize dependencies internally using config defaults; removed reliance on module-level constants.
packages/core/src/command/patient-import/csv/convert-patient.ts, .../address.ts, .../contact.ts Updated function signatures to accept `Record<string, string
packages/core/src/command/patient-import/csv/store-results.ts Updated ResultEntry type to have reasonForCx and reasonForDev fields instead of a single reason.
packages/core/src/command/patient-import/api/update-job-status.ts Made status parameter optional in exported function.
packages/api/src/command/medical/patient/shared.ts Added deprecation comments to sanitize and validate functions; adjusted validation logic for DOB.
packages/api/src/routes/internal/medical/patient-import.ts Changed import sources; added guard for debug detail; included reasonForCx and reasonForDev in debug responses.
packages/core/src/command/patient-import/csv/__tests__/convert-patient.test.ts Added comprehensive tests for CSV to patient mapping, including error and edge cases.
packages/shared/src/common/date.ts, .../dob.ts Improved DOB validation logic; removed redundant empty string check; changed date formatting for validation.
packages/shared/src/domain/patient/patient-import/schemas.ts Made status field optional in updateJobSchema.
packages/shared/src/common/__tests__/date.test.ts Expanded test cases for DOB validation edge scenarios.
packages/shared/src/common/title-case.ts Enhanced toTitleCase to correctly capitalize words containing apostrophes.
packages/shared/src/common/__tests__/title-case.test.ts Added test case for toTitleCase handling of apostrophes in words.
packages/shared/src/domain/patient/patient-import/create.ts Changed default values of rerunPdOnNewDemographics and triggerConsolidated flags to true.
packages/lambdas/src/patient-import-create.ts, .../parse.ts, .../query.ts, .../result.ts Changed handlers to call new command functions directly instead of class instance methods; added validation for numeric parameters.
packages/infra/lib/lambdas-nested-stack.ts Refactored Lambda and queue setup to use new ConsolidatedSearchConstruct; removed redundant setup methods.
packages/infra/lib/shared/consolidated-search-construct.ts Added new construct to encapsulate consolidated search/ingestion Lambda and queue setup, permissions, and configuration.

Sequence Diagram(s)

Patient Import Parse and Create (New Command Flow)

sequenceDiagram
    participant LambdaHandler
    participant ParseCommand
    participant S3
    participant CreateCommand
    participant API

    LambdaHandler->>ParseCommand: processJobParse({cxId, jobId, ...})
    ParseCommand->>S3: Download CSV
    ParseCommand->>ParseCommand: Partition patients (success/fail)
    ParseCommand->>API: updateJobAtApi (status: processing)
    alt Not dry run
        loop For each chunk of patients
            ParseCommand->>CreateCommand: processPatientCreate({cxId, jobId, ...})
            CreateCommand->>API: updatePatientRecord (processing)
            CreateCommand->>API: createPatient
            CreateCommand->>API: updatePatientRecord (with patientId)
            CreateCommand->>API: createPatientMapping
            CreateCommand->>API: processPatientQuery (if next step)
        end
    end
    ParseCommand->>API: updateJobAtApi (with counts)
Loading

Patient Import Result (New Command Flow)

sequenceDiagram
    participant LambdaHandler
    participant ResultCommand
    participant S3
    participant API

    LambdaHandler->>ResultCommand: processPatientResult({cxId, jobId, ...})
    ResultCommand->>S3: List patient record keys
    loop For each record
        ResultCommand->>S3: Load patient record JSON
        ResultCommand->>ResultCommand: Map to result entry
    end
    ResultCommand->>S3: Store results CSV
    ResultCommand->>API: updateJobAtApi (status: complete or failed)
Loading

Possibly related PRs

  • metriport/metriport#3865: Updates normalizeDobSafe to return undefined for invalid dates, matching the main PR's change to rely on validateDateOfBirth for DOB validation.
  • metriport/metriport#4032: Adds and updates internal patient import bulk endpoints, overlapping with changes to packages/api/src/routes/internal/medical/patient-import.ts in this PR.
  • metriport/metriport#3749: Release PR for bulk patient import v1, directly related as this PR contains the core logic for that feature.

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

npm error code ERR_SSL_WRONG_VERSION_NUMBER
npm error errno ERR_SSL_WRONG_VERSION_NUMBER
npm error request to https://10.0.0.28:4873/punycode/-/punycode-2.3.1.tgz failed, reason: C01CF86B977F0000:error:0A00010B:SSL routines:ssl3_get_record:wrong version number:../deps/openssl/openssl/ssl/record/ssl3_record.c:354:
npm error
npm error A complete log of this run can be found in: /.npm/_logs/2025-06-17T00_29_53_091Z-debug-0.log

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

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

Support

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

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

CodeRabbit Commands (Invoked using PR comments)

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

Other keywords and placeholders

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

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

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

leite08 added 5 commits June 14, 2025 18:12
Ref eng-36

Signed-off-by: Rafael Leite <2132564+leite08@users.noreply.github.com>
Ref eng-438

Signed-off-by: Rafael Leite <2132564+leite08@users.noreply.github.com>
Ref eng-245

Signed-off-by: Rafael Leite <2132564+leite08@users.noreply.github.com>
Ref eng-245

Signed-off-by: Rafael Leite <2132564+leite08@users.noreply.github.com>
Ref eng-245

Signed-off-by: Rafael Leite <2132564+leite08@users.noreply.github.com>
@leite08 leite08 changed the title ENG-245 Check DOB length on normalizeDobSafe + ...WIP ENG-245 Check DOB length + Update cloud factory pattern Jun 15, 2025
Copy link
Member Author

Choose a reason for hiding this comment

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

indicate individual fields that are missing instead of generic message

Copy link
Member Author

@leite08 leite08 Jun 15, 2025

Choose a reason for hiding this comment

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

Moved from packages/core/src/command/patient-import/steps/create/patient-import-create-local.ts w/ few adjustments:

image

Copy link
Member Author

Choose a reason for hiding this comment

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

Main logic moved to packages/core/src/command/patient-import/steps/create/patient-import-create-command.ts. Left only the logic to call it and swallow errors.

Copy link
Member Author

Choose a reason for hiding this comment

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

Cleaner factory, the implementation knows about its defaults

Copy link
Member Author

@leite08 leite08 Jun 15, 2025

Choose a reason for hiding this comment

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

Moved from packages/core/src/command/patient-import/steps/parse/patient-import-parse-local.ts w/ few adjustments:

image

Copy link
Member Author

Choose a reason for hiding this comment

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

Main logic moved to packages/core/src/command/patient-import/steps/parse/patient-import-parse-command.ts. Left only the logic to call it and swallow errors.

Copy link
Member Author

Choose a reason for hiding this comment

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

Moved from packages/core/src/command/patient-import/steps/query/patient-import-query-local.ts w/ few adjustments:

image

Copy link
Member Author

Choose a reason for hiding this comment

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

Main logic moved to packages/core/src/command/patient-import/steps/query/patient-import-query-command.ts. Left only the logic to call it and swallow errors.

Ref eng-245

Signed-off-by: Rafael Leite <2132564+leite08@users.noreply.github.com>
Copy link
Member Author

Choose a reason for hiding this comment

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

Moved from packages/core/src/command/patient-import/steps/result/patient-import-result-local.ts w/ few adjustments:

image

Copy link
Member Author

Choose a reason for hiding this comment

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

Main logic moved to packages/core/src/command/patient-import/steps/result/patient-import-result-command.ts. Left only the logic to call it and swallow errors.

Copy link
Member Author

Choose a reason for hiding this comment

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

Most of the code removed went to packages/infra/lib/shared/consolidated-search-construct.ts

Copy link
Member Author

@leite08 leite08 Jun 15, 2025

Choose a reason for hiding this comment

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

Most of the code came from packages/infra/lib/lambdas-nested-stack.ts:

image

@leite08 leite08 marked this pull request as ready for review June 15, 2025 23:34
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🔭 Outside diff range comments (1)
packages/shared/src/domain/patient/patient-import/schemas.ts (1)

29-34: 🛠️ Refactor suggestion

Schema now allows empty objects – refine to require at least one prop

Since status is now optional the following passes validation but is useless:

updateJobSchema.parse({})

Guard it at the schema level:

 export const updateJobSchema = z
   .object({
     status: z.enum(patientImportJobStatus).optional(),
     total: z.number().optional(),
     failed: z.number().optional(),
     forceStatusUpdate: z.boolean().optional(),
-});
+})
+.refine(
+  d => d.status !== undefined || d.total !== undefined || d.failed !== undefined,
+  { message: "At least one of status, total or failed must be provided" },
+);

Pushing the constraint into zod removes the need for scattered runtime checks.

♻️ Duplicate comments (3)
packages/core/src/command/patient-import/steps/create/patient-import-create-cloud.ts (1)

8-11: Same DI concern as in patient-import-query-cloud

Inline creation of SQSClient limits testability; consider accepting it as a constructor argument with a sensible default.

packages/core/src/command/patient-import/steps/query/patient-import-query-local.ts (1)

43-45: Same silent-failure pattern as other Local wrappers – see earlier comment; considerations there apply here as well.

packages/core/src/command/patient-import/steps/create/patient-import-create-local.ts (1)

41-43: Same silent-failure pattern as other Local wrappers – see earlier comment; considerations there apply here as well.

🧹 Nitpick comments (28)
packages/core/src/command/patient-import/csv/store-results.ts (1)

24-26: reasonForDev is never consumed – dead field or missing plumbing?

ResultEntry now carries both reasonForCx and reasonForDev, but only the customer-facing reason is ever read in this module. If developer reasons are needed elsewhere, wire them through; otherwise drop the unused property to avoid type-rot and larger payloads.

packages/lambdas/src/patient-import-parse.ts (1)

30-34: Explicitly pass next/result when diverging from defaults

processJobParse allows overriding next and result. If the lambda ever needs custom wiring (e.g., for A/B or test doubles) the current implicit defaults hide this option. Consider passing them explicitly or documenting why defaults are always sufficient.

packages/core/src/command/patient-import/steps/query/patient-import-query-factory.ts (1)

7-11: Constructor now parameter-less – re-check testability & env flexibility

The factory no longer injects patientImportBucket / queueUrl.
Great for brevity, but:

  1. Hard-wiring configs inside the classes makes unit testing harder (no DI).
  2. Alternate environments (staging with different buckets) now require code changes instead of config.

If the classes read from Config internally, consider still accepting overrides via constructor for flexibility.

packages/lambdas/src/patient-import-result.ts (1)

29-34: Variable name doesn’t reflect the new command

processJobResultCmd still carries the old “job-result” wording, which can be misleading now that we’re invoking processPatientResult. Renaming improves clarity and greppability.

-      const processJobResultCmd: ProcessPatientResultCommandRequest = {
+      const processPatientResultCmd: ProcessPatientResultCommandRequest = {
         cxId,
         jobId,
         patientImportBucket,
       };
-      await processPatientResult(processJobResultCmd);
+      await processPatientResult(processPatientResultCmd);
packages/lambdas/src/patient-import-query.ts (2)

26-29: Specify radix in parseInt to avoid accidental octal parsing

parseInt(waitTimeInMillisRaw) will treat leading zeros as octal on some runtimes. Make the intent explicit:

-const waitTimeInMillis = parseInt(waitTimeInMillisRaw);
+const waitTimeInMillis = parseInt(waitTimeInMillisRaw, 10);

38-50: Replace console.log with the standard logger

Coding-guidelines forbid console.log outside utils/infra/shared packages. Use prefixedLog (already available in this scope) or out().log to remain consistent and keep structured logging.

-    console.log(`Running with unparsed body: ${message.body}`);
+    prefixedLog(lambdaName)(`Running with unparsed body: ${message.body}`);
@@
-    console.log(`Done local duration: ${finishedAt - startedAt}ms`);
+    prefixedLog(lambdaName)(`Done local duration: ${finishedAt - startedAt}ms`);
packages/lambdas/src/patient-import-create.ts (1)

38-39: Replace console.log with the project’s structured logger

Coding guidelines restrict console.* usage outside utils/infra/shared.
You already have prefixedLog – use it (or out().log) instead to keep log
formatting consistent and avoid missing correlation IDs in production logs.

Also applies to: 74-75

packages/shared/src/common/date.ts (1)

28-28: Redundant condition

!date is checked twice in the same clause; remove the duplication to keep the guard concise.

packages/shared/src/common/__tests__/date.test.ts (2)

173-179: Duplicate test description

There are two it("returns true when date is valid ISO datetime", …) blocks. Rename one of
them to avoid confusion when reading test output.


128-128: Remove stray console.log

console.log(result); will pollute CI logs and is not needed for assertions.

packages/core/src/command/patient-import/csv/__tests__/convert-patient.test.ts (1)

165-169: Spy does not stub return value

jest.spyOn(normalizeDobFile, "normalizeDobSafe") only records calls; if
normalizeDobSafe throws the same failure will propagate into the test.
Be explicit (mockReturnValueOnce(...)) where the function’s behaviour matters to keep
tests deterministic.

packages/core/src/command/patient-import/steps/parse/patient-import-parse-cloud.ts (1)

7-10: Constructor default creates a new client per instance

Inlining makeLambdaClient in the parameter default means every new
PatientImportParseCloud() instantiation spins up an AWS SDK client.
If these objects are short-lived, this may create unnecessary sockets.
Consider injecting a shared client from the caller or making the default a
module-level singleton.

packages/core/src/command/patient-import/steps/result/patient-import-result-cloud.ts (1)

7-10: Same client-instantiation concern as parse step

See previous comment – apply the same singleton / DI pattern here for consistency.

packages/core/src/command/patient-import/steps/query/patient-import-query-cloud.ts (1)

7-10: Prefer dependency injection over inline instantiation

Creating a fresh SQSClient inside the constructor ties the class to AWS at instantiation time and makes unit-testing harder. Passing an already-built client (with the same default) keeps the current DX while allowing callers to inject stubs/mocks when needed.

packages/core/src/command/patient-import/steps/query/patient-import-query-command.ts (2)

52-53: Guard against negative wait times

if (waitTimeAtTheEndInMillis > 0) … silently ignores negatives; clamping would be clearer:

-if (waitTimeAtTheEndInMillis > 0) await sleep(waitTimeAtTheEndInMillis);
+await sleep(Math.max(0, waitTimeAtTheEndInMillis));

13-16: Avoid extending DayJS plugin on every import

dayjs.extend(duration); executes each time this module is required. Moving the extension to a central bootstrap file prevents accidental multiple calls and keeps plugin setup in one place.

packages/api/src/routes/internal/medical/patient-import.ts (1)

302-304: Make the validation message explicit

Including the hard limit helps the caller immediately understand why the request was rejected:

-throw new BadRequestError(`Debug mode is not supported for jobs with many patients`);
+throw new BadRequestError(
+  `Debug mode is limited to ${maxPatientsOnDebugGetBulk} patients or fewer`
+);
packages/core/src/command/patient-import/steps/create/patient-import-create-command.ts (1)

59-65: Update only the fields that changed to avoid stale writes

Re-passing the entire patientRecord object can unintentionally overwrite fields changed elsewhere after the first write. Prefer a minimal patch:

-  await Promise.all([
-    updatePatientRecord({
-      ...patientRecord,
-      patientId,
-      bucketName: patientImportBucket,
-    }),
+  await Promise.all([
+    updatePatientRecord({
+      cxId,
+      jobId,
+      rowNumber,
+      patientId,
+      bucketName: patientImportBucket,
+    }),

This keeps the write explicit and decoupled from the record’s full interface.

packages/core/src/command/patient-import/steps/result/patient-import-result-command.ts (4)

13-13: Remove unused dayjs.duration plugin import

dayjs.extend(duration); is never referenced afterwards, so the plugin isn’t needed here and can be deleted to keep dependencies lean.


66-71: Shared array mutation inside concurrent loop can cause unpredictable ordering

records.push(patientRecord) from multiple async tasks means the final array order depends on fetch-completion order, not the original CSV order.
If consumer code relies on row sequence, preserve determinism by either:

- records.push(patientRecord);
+ records[patientRecord.rowNumber - 1] = patientRecord;

or sort afterwards.


60-75: Consider streaming to avoid loading all patient records into memory

For large imports every record is held twice (raw string + parsed object) before being written, which can exhaust Lambda memory.
Mapping each record directly to a ResultEntry and streaming storeResults chunk-by-chunk would keep memory constant.


90-93: Wrap JSON parse errors with context

If a single record file is malformed, the entire job fails without indicating which key was bad. Catch here, add the key to the error message, and rethrow.

packages/core/src/command/patient-import/steps/result/patient-import-result-local.ts (1)

26-28: Swallowing the command error hides failures from callers

While mimicking async cloud behaviour, any local invoker now has no way to know the job failed. Consider returning a boolean or logging the command’s updated status so upstream tests can assert success/failure.

packages/core/src/command/patient-import/csv/convert-patient.ts (2)

45-47: Redundant “missing first/last name” checks

normalizeName already throws for empty values, so the extra if (!firstName) / if (!lastName) blocks never fire. Remove them to simplify control flow.

Also applies to: 53-55


76-81: Duplicate address presence validation

You push an "Missing address" error at lines 78-81 and immediately repeat a generic check later (100-103). Drop one to avoid confusing, duplicated error messages.

Also applies to: 100-103

packages/core/src/command/patient-import/steps/parse/patient-import-parse-command.ts (2)

53-53: Drop the useless ternary in partition

p => p.status !== "failed" is already a boolean – the ? true : false adds noise without value.

🧰 Tools
🪛 Biome (1.9.4)

[error] 53-53: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)


71-74: Promise.allSettled + internal try/catch is redundant

Because every mapped promise already catches its own error and never rejects, the outer Promise.allSettled provides no extra value.
A plain Promise.all (or even for … of with awaits) will be cheaper and a bit clearer.

packages/infra/lib/lambdas-nested-stack.ts (1)

676-710: Consider renaming the stack parameter to scope for clarity.

The parameter is used as the scope for the CDK construct, which is the standard pattern. Renaming it to scope would better align with CDK conventions and improve code readability.

-  private setupConsolidatedSearchConstruct(ownProps: {
-    stack: Stack;
+  private setupConsolidatedSearchConstruct(ownProps: {
+    scope: Construct;
     vpc: ec2.IVpc;
     config: EnvConfig;
     lambdaLayers: LambdaLayers;
     secrets: Secrets;
     medicalDocumentsBucket: s3.Bucket;
     featureFlagsTable: dynamodb.Table;
     openSearch: OpenSearchConfigForLambdas;
   }): ConsolidatedSearchConstruct {
     const {
-      stack,
+      scope,
       vpc,
       config,
       lambdaLayers,
       secrets,
       medicalDocumentsBucket,
       featureFlagsTable,
       openSearch,
     } = ownProps;
     const consolidatedSearchConstruct = new ConsolidatedSearchConstruct(
-      stack,
+      scope,
       "ConsolidatedSearchConstruct",
       {
         config,
         vpc,
         lambdaLayers,
         secrets,
         medicalDocumentsBucket,
         featureFlagsTable,
         openSearch,
       }
     );
     return consolidatedSearchConstruct;
   }

Also update the call site on line 176:

-      stack: this,
+      scope: this,

And remove the Stack import on line 1 since it's no longer needed (you can import Construct from 'constructs' if needed for the type).

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e4e1c00 and 8b2c44d.

📒 Files selected for processing (35)
  • packages/api/src/command/medical/patient/shared.ts (2 hunks)
  • packages/api/src/routes/internal/medical/patient-import.ts (6 hunks)
  • packages/core/src/command/patient-import/api/update-job-status.ts (1 hunks)
  • packages/core/src/command/patient-import/csv/__tests__/convert-patient.test.ts (1 hunks)
  • packages/core/src/command/patient-import/csv/address.ts (2 hunks)
  • packages/core/src/command/patient-import/csv/contact.ts (2 hunks)
  • packages/core/src/command/patient-import/csv/convert-patient.ts (5 hunks)
  • packages/core/src/command/patient-import/csv/store-results.ts (2 hunks)
  • packages/core/src/command/patient-import/patient-or-record-failed.ts (1 hunks)
  • packages/core/src/command/patient-import/steps/create/patient-import-create-cloud.ts (2 hunks)
  • packages/core/src/command/patient-import/steps/create/patient-import-create-command.ts (1 hunks)
  • packages/core/src/command/patient-import/steps/create/patient-import-create-factory.ts (1 hunks)
  • packages/core/src/command/patient-import/steps/create/patient-import-create-local.ts (2 hunks)
  • packages/core/src/command/patient-import/steps/parse/patient-import-parse-cloud.ts (1 hunks)
  • packages/core/src/command/patient-import/steps/parse/patient-import-parse-command.ts (1 hunks)
  • packages/core/src/command/patient-import/steps/parse/patient-import-parse-factory.ts (1 hunks)
  • packages/core/src/command/patient-import/steps/parse/patient-import-parse-local.ts (2 hunks)
  • packages/core/src/command/patient-import/steps/query/patient-import-query-cloud.ts (2 hunks)
  • packages/core/src/command/patient-import/steps/query/patient-import-query-command.ts (1 hunks)
  • packages/core/src/command/patient-import/steps/query/patient-import-query-factory.ts (1 hunks)
  • packages/core/src/command/patient-import/steps/query/patient-import-query-local.ts (2 hunks)
  • packages/core/src/command/patient-import/steps/result/patient-import-result-cloud.ts (2 hunks)
  • packages/core/src/command/patient-import/steps/result/patient-import-result-command.ts (1 hunks)
  • packages/core/src/command/patient-import/steps/result/patient-import-result-factory.ts (1 hunks)
  • packages/core/src/command/patient-import/steps/result/patient-import-result-local.ts (2 hunks)
  • packages/infra/lib/lambdas-nested-stack.ts (4 hunks)
  • packages/infra/lib/shared/consolidated-search-construct.ts (1 hunks)
  • packages/lambdas/src/patient-import-create.ts (2 hunks)
  • packages/lambdas/src/patient-import-parse.ts (2 hunks)
  • packages/lambdas/src/patient-import-query.ts (2 hunks)
  • packages/lambdas/src/patient-import-result.ts (2 hunks)
  • packages/shared/src/common/__tests__/date.test.ts (3 hunks)
  • packages/shared/src/common/date.ts (1 hunks)
  • packages/shared/src/domain/dob.ts (0 hunks)
  • packages/shared/src/domain/patient/patient-import/schemas.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • packages/shared/src/domain/dob.ts
🧰 Additional context used
📓 Path-based instructions (1)
`**/*.ts`: - Use the Onion Pattern to organize a package's code in layers - Try to use immutable code and avoid sharing state across different functions, objects, and systems - Try...

**/*.ts: - Use the Onion Pattern to organize a package's code in layers

  • Try to use immutable code and avoid sharing state across different functions, objects, and systems
  • Try to build code that's idempotent whenever possible
  • Prefer functional programming style functions: small, deterministic, 1 input, 1 output
  • Minimize coupling / dependencies
  • Avoid modifying objects received as parameter
  • Only add comments to code to explain why something was done, not how it works
  • Naming
    • classes, enums: PascalCase
    • constants, variables, functions: camelCase
    • file names: kebab-case
    • table and column names: snake_case
    • Use meaningful names, so whoever is reading the code understands what it means
    • Don’t use negative names, like notEnabled, prefer isDisabled
    • For numeric values, if the type doesn’t convey the unit, add the unit to the name
  • Typescript
    • Use types
    • Prefer const instead of let
    • Avoid any and casting from any to other types
    • Type predicates: only applicable to narrow down the type, not to force a complete type conversion
    • Prefer deconstructing parameters for functions instead of multiple parameters that might be of
      the same type
    • Don’t use null inside the app, only on code interacting with external interfaces/services,
      like DB and HTTP; convert to undefined before sending inwards into the code
    • Use async/await instead of .then()
    • Use the strict equality operator ===, don’t use abstract equality operator ==
    • When calling a Promise-returning function asynchronously (i.e., not awaiting), use .catch() to
      handle errors (see processAsyncError and emptyFunction depending on the case)
    • Date and Time
      • Always use buildDayjs() to create dayjs instances
      • Prefer dayjs.duration(...) to create duration consts and keep them as duration
  • Prefer Nullish Coalesce (??) than the OR operator (||) to provide a default value
  • Avoid creating arrow functions
  • Use truthy syntax instead of in - i.e., if (data.link) not if ('link' in data)
  • Error handling
    • Pass the original error as the new one’s cause so the stack trace is persisted
    • Error messages should have a static message - add dynamic data to MetriportError's additionalInfo prop
    • Avoid sending multiple events to Sentry for a single error
  • Global constants and variables
    • Move literals to constants declared after imports when possible (avoid magic numbers)
    • Avoid shared, global objects
  • Avoid using console.log and console.error in packages other than utils, infra and shared,
    and try to use out().log instead
  • Avoid multi-line logs
    • don't send objects as a second parameter to console.log() or out().log()
    • don't create multi-line strings when using JSON.stringify()
  • Use eslint to enforce code style
  • Use prettier to format code
  • max column length is 100 chars
  • multi-line comments use /** */
  • scripts: top-level comments go after the import
  • packages/lambdas/src/patient-import-query.ts
  • packages/lambdas/src/patient-import-parse.ts
  • packages/core/src/command/patient-import/csv/contact.ts
  • packages/lambdas/src/patient-import-result.ts
  • packages/shared/src/domain/patient/patient-import/schemas.ts
  • packages/core/src/command/patient-import/csv/store-results.ts
  • packages/core/src/command/patient-import/steps/parse/patient-import-parse-factory.ts
  • packages/api/src/command/medical/patient/shared.ts
  • packages/core/src/command/patient-import/steps/query/patient-import-query-factory.ts
  • packages/core/src/command/patient-import/steps/result/patient-import-result-factory.ts
  • packages/core/src/command/patient-import/steps/create/patient-import-create-factory.ts
  • packages/core/src/command/patient-import/csv/__tests__/convert-patient.test.ts
  • packages/core/src/command/patient-import/api/update-job-status.ts
  • packages/shared/src/common/__tests__/date.test.ts
  • packages/core/src/command/patient-import/steps/parse/patient-import-parse-cloud.ts
  • packages/lambdas/src/patient-import-create.ts
  • packages/core/src/command/patient-import/steps/result/patient-import-result-local.ts
  • packages/core/src/command/patient-import/steps/result/patient-import-result-cloud.ts
  • packages/core/src/command/patient-import/steps/query/patient-import-query-command.ts
  • packages/core/src/command/patient-import/csv/address.ts
  • packages/core/src/command/patient-import/steps/create/patient-import-create-cloud.ts
  • packages/core/src/command/patient-import/patient-or-record-failed.ts
  • packages/core/src/command/patient-import/steps/parse/patient-import-parse-command.ts
  • packages/core/src/command/patient-import/steps/create/patient-import-create-command.ts
  • packages/core/src/command/patient-import/steps/query/patient-import-query-local.ts
  • packages/core/src/command/patient-import/csv/convert-patient.ts
  • packages/core/src/command/patient-import/steps/parse/patient-import-parse-local.ts
  • packages/core/src/command/patient-import/steps/query/patient-import-query-cloud.ts
  • packages/shared/src/common/date.ts
  • packages/api/src/routes/internal/medical/patient-import.ts
  • packages/infra/lib/shared/consolidated-search-construct.ts
  • packages/core/src/command/patient-import/steps/create/patient-import-create-local.ts
  • packages/infra/lib/lambdas-nested-stack.ts
  • packages/core/src/command/patient-import/steps/result/patient-import-result-command.ts
🧠 Learnings (2)
packages/api/src/command/medical/patient/shared.ts (1)
Learnt from: leite08
PR: metriport/metriport#3814
File: packages/api/src/routes/internal/medical/patient-consolidated.ts:141-174
Timestamp: 2025-05-20T21:26:26.804Z
Learning: The functionality introduced in packages/api/src/routes/internal/medical/patient-consolidated.ts is planned to be refactored in downstream PR #3857, including improvements to error handling and validation.
packages/api/src/routes/internal/medical/patient-import.ts (1)
Learnt from: leite08
PR: metriport/metriport#3814
File: packages/api/src/routes/internal/medical/patient-consolidated.ts:141-174
Timestamp: 2025-05-20T21:26:26.804Z
Learning: The functionality introduced in packages/api/src/routes/internal/medical/patient-consolidated.ts is planned to be refactored in downstream PR #3857, including improvements to error handling and validation.
🧬 Code Graph Analysis (14)
packages/lambdas/src/patient-import-query.ts (1)
packages/core/src/command/patient-import/steps/query/patient-import-query-command.ts (1)
  • ProcessPatientQueryCommandRequest (17-20)
packages/lambdas/src/patient-import-parse.ts (2)
packages/core/src/command/patient-import/steps/parse/patient-import-parse-command.ts (2)
  • ProcessJobParseCommandRequest (23-27)
  • processJobParse (29-131)
packages/core/src/command/patient-import/steps/parse/patient-import-parse-local.ts (1)
  • processJobParse (10-30)
packages/lambdas/src/patient-import-result.ts (1)
packages/core/src/command/patient-import/steps/result/patient-import-result-command.ts (2)
  • ProcessPatientResultCommandRequest (17-19)
  • processPatientResult (21-49)
packages/api/src/command/medical/patient/shared.ts (2)
packages/api/src/command/medical/patient/get-patient.ts (1)
  • PatientMatchCmd (27-27)
packages/shared/src/common/date.ts (1)
  • validateDateOfBirth (21-40)
packages/core/src/command/patient-import/steps/result/patient-import-result-factory.ts (2)
packages/core/src/command/patient-import/steps/result/patient-import-result-local.ts (1)
  • PatientImportResultLocal (7-30)
packages/core/src/command/patient-import/steps/result/patient-import-result-cloud.ts (1)
  • PatientImportResultHandlerCloud (6-29)
packages/core/src/command/patient-import/steps/create/patient-import-create-factory.ts (2)
packages/core/src/command/patient-import/steps/create/patient-import-create-local.ts (1)
  • PatientImportCreateLocal (7-45)
packages/core/src/command/patient-import/steps/create/patient-import-create-cloud.ts (1)
  • PatientImportCreateCloud (7-28)
packages/core/src/command/patient-import/csv/__tests__/convert-patient.test.ts (1)
packages/core/src/command/patient-import/csv/convert-patient.ts (1)
  • mapCsvPatientToMetriportPatient (38-117)
packages/shared/src/common/__tests__/date.test.ts (1)
packages/shared/src/common/date.ts (1)
  • validateDateOfBirth (21-40)
packages/lambdas/src/patient-import-create.ts (1)
packages/core/src/command/patient-import/steps/create/patient-import-create-command.ts (1)
  • ProcessPatientCreateCommandRequest (13-17)
packages/core/src/command/patient-import/steps/result/patient-import-result-cloud.ts (1)
packages/core/src/external/aws/lambda.ts (1)
  • makeLambdaClient (13-19)
packages/core/src/command/patient-import/steps/query/patient-import-query-command.ts (3)
packages/core/src/command/patient-import/steps/query/patient-import-query-local.ts (1)
  • processPatientQuery (13-46)
packages/shared/src/index.ts (1)
  • sleep (13-13)
packages/core/src/command/patient-import/patient-or-record-failed.ts (1)
  • setPatientOrRecordFailed (4-31)
packages/core/src/command/patient-import/patient-or-record-failed.ts (1)
packages/core/src/command/patient-import/api/update-job-status.ts (1)
  • updateJobAtApi (21-56)
packages/api/src/routes/internal/medical/patient-import.ts (1)
packages/shared/src/index.ts (1)
  • BadRequestError (40-40)
packages/infra/lib/shared/consolidated-search-construct.ts (3)
packages/infra/config/env-config.ts (1)
  • EnvConfig (307-307)
packages/infra/lib/shared/secrets.ts (1)
  • Secrets (6-6)
packages/infra/lib/lambdas-nested-stack-settings.ts (2)
  • getConsolidatedSearchConnectorSettings (33-42)
  • getConsolidatedIngestionConnectorSettings (7-31)
🪛 Biome (1.9.4)
packages/core/src/command/patient-import/steps/parse/patient-import-parse-command.ts

[error] 53-53: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)

🔇 Additional comments (16)
packages/core/src/command/patient-import/csv/store-results.ts (1)

88-92: CSV omits developer-facing reason – confirm this is intended

entryToCsv() writes reasonForCx but discards reasonForDev.
If the dev reason is useful for internal debugging, consider:

-  const reason = e.reasonForCx ? escapeCsvValueIfNeeded(e.reasonForCx) : "";
-  return `${e.rowCsv},${patientId},${status},${reason}`;
+  const reasonCx  = e.reasonForCx  ? escapeCsvValueIfNeeded(e.reasonForCx)  : "";
+  const reasonDev = e.reasonForDev ? escapeCsvValueIfNeeded(e.reasonForDev) : "";
+  return `${e.rowCsv},${patientId},${status},${reasonCx},${reasonDev}`;

(Adjust header accordingly.) Otherwise remove reasonForDev altogether.

packages/lambdas/src/patient-import-parse.ts (1)

2-5: Good move to command-style import – cleaner bundling

Shifting from class instantiation to a plain command import simplifies the handler and aligns with the new architecture.

packages/core/src/command/patient-import/steps/create/patient-import-create-factory.ts (1)

8-10: Factory simplification looks good

Constructors now rely on their own defaults, reducing parameter threading from the factory. Nice cleanup.

packages/core/src/command/patient-import/steps/parse/patient-import-parse-factory.ts (1)

8-10: Consistent with the create-factory change

Dropping explicit config parameters keeps factories lightweight and hides config look-ups inside the respective classes. Looks good.

packages/core/src/command/patient-import/patient-or-record-failed.ts (1)

19-22: failed counter likely overwritten instead of incremented

updateJobAtApi({ cxId, jobId, failed: 1 }) passes a literal 1, which most APIs interpret as an absolute value, not a delta.
If the job already has failed > 0, this call will reset the counter back to 1 and under-report subsequent failures.

-    updateJobAtApi({ cxId, jobId, failed: 1 }),
+    // Consider fetching the current value or using an increment-by endpoint  
+    updateJobAtApi({ cxId, jobId, failed: currentFailed + 1 }), // pseudo-code

Verify the API semantics or introduce an incrementing helper to avoid silent data corruption.

packages/core/src/command/patient-import/csv/contact.ts (1)

22-23: Good call making CSV field types optional

Allowing undefined better reflects sparse CSV input and removes the need for
superfluous casts down-stream.

Also applies to: 44-45

packages/core/src/command/patient-import/csv/address.ts (1)

26-27: Type annotation update looks correct

The switch to string | undefined aligns this parser with the new contact
typing and avoids false positives when fields are blank.

Also applies to: 54-55

packages/core/src/command/patient-import/steps/result/patient-import-result-factory.ts (1)

8-11: Constructor simplification is fine

Removing the explicit bucket argument reduces coupling; PatientImportResultLocal
already defaults to Config.getPatientImportBucket(). No concerns.

packages/shared/src/common/__tests__/date.test.ts (1)

131-148: Mocks hide the real bug

All “true / false” assertions from here down pass replacement mocks for
validateDateIsAfter1900 and validateIsPastOrPresent, so they never exercise the real
logic that just broke (see previous comment). Add at least one happy-path test that does
not
pass the overrides to ensure the default implementation still works.

packages/core/src/command/patient-import/csv/__tests__/convert-patient.test.ts (1)

1-28: faker state abbreviation can be lowercase

faker.location.state({ abbreviated: true }) occasionally returns e.g. "nm".
mapCsvPatientToMetriportPatient expects a valid USState enum (uppercase). Consider
.toUpperCase() when generating the fixture or assert that mapping handles lower-case
input.

packages/core/src/command/patient-import/steps/parse/patient-import-parse-local.ts (1)

23-29: Confirm intentional error swallowing

Swallowing every error here means local callers will always see a resolved promise even if the command failed.
If that’s purely to mimic the async-queue behaviour in cloud, please add a brief comment at the call-site or unit test so future readers don’t assume this is a bug.

packages/infra/lib/shared/consolidated-search-construct.ts (4)

39-46: Good modularization of infrastructure components.

The construct properly encapsulates related AWS resources for consolidated search functionality, following CDK best practices for reusability and maintainability.


83-148: Well-structured Lambda configuration with proper permissions.

The method correctly sets up the consolidated search Lambda with all necessary environment variables and grants appropriate read/write permissions to required resources.


150-167: Clean queue setup implementation.

The queue creation properly uses centralized settings and follows the established pattern.


169-231: Proper Lambda setup with queue integration.

The ingestion Lambda is correctly configured with the queue as an event source and appropriate permissions for all required resources.

packages/infra/lib/lambdas-nested-stack.ts (1)

175-187: Clean refactoring to use the new construct.

The consolidation of three separate setup methods into a single construct instantiation improves code organization and maintainability.

Ref eng-245

Signed-off-by: Rafael Leite <2132564+leite08@users.noreply.github.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
packages/shared/src/common/__tests__/title-case.test.ts (1)

22-26: Nice addition – covers the new edge case
Good to see the apostrophe scenario exercised. Consider adding a variant with leading/trailing whitespace (e.g. " o'neal "), but that’s optional.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3107b34 and f5795c4.

📒 Files selected for processing (2)
  • packages/shared/src/common/__tests__/title-case.test.ts (1 hunks)
  • packages/shared/src/common/title-case.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
`**/*.ts`: - Use the Onion Pattern to organize a package's code in layers - Try to use immutable code and avoid sharing state across different functions, objects, and systems - Try...

**/*.ts: - Use the Onion Pattern to organize a package's code in layers

  • Try to use immutable code and avoid sharing state across different functions, objects, and systems
  • Try to build code that's idempotent whenever possible
  • Prefer functional programming style functions: small, deterministic, 1 input, 1 output
  • Minimize coupling / dependencies
  • Avoid modifying objects received as parameter
  • Only add comments to code to explain why something was done, not how it works
  • Naming
    • classes, enums: PascalCase
    • constants, variables, functions: camelCase
    • file names: kebab-case
    • table and column names: snake_case
    • Use meaningful names, so whoever is reading the code understands what it means
    • Don’t use negative names, like notEnabled, prefer isDisabled
    • For numeric values, if the type doesn’t convey the unit, add the unit to the name
  • Typescript
    • Use types
    • Prefer const instead of let
    • Avoid any and casting from any to other types
    • Type predicates: only applicable to narrow down the type, not to force a complete type conversion
    • Prefer deconstructing parameters for functions instead of multiple parameters that might be of
      the same type
    • Don’t use null inside the app, only on code interacting with external interfaces/services,
      like DB and HTTP; convert to undefined before sending inwards into the code
    • Use async/await instead of .then()
    • Use the strict equality operator ===, don’t use abstract equality operator ==
    • When calling a Promise-returning function asynchronously (i.e., not awaiting), use .catch() to
      handle errors (see processAsyncError and emptyFunction depending on the case)
    • Date and Time
      • Always use buildDayjs() to create dayjs instances
      • Prefer dayjs.duration(...) to create duration consts and keep them as duration
  • Prefer Nullish Coalesce (??) than the OR operator (||) to provide a default value
  • Avoid creating arrow functions
  • Use truthy syntax instead of in - i.e., if (data.link) not if ('link' in data)
  • Error handling
    • Pass the original error as the new one’s cause so the stack trace is persisted
    • Error messages should have a static message - add dynamic data to MetriportError's additionalInfo prop
    • Avoid sending multiple events to Sentry for a single error
  • Global constants and variables
    • Move literals to constants declared after imports when possible (avoid magic numbers)
    • Avoid shared, global objects
  • Avoid using console.log and console.error in packages other than utils, infra and shared,
    and try to use out().log instead
  • Avoid multi-line logs
    • don't send objects as a second parameter to console.log() or out().log()
    • don't create multi-line strings when using JSON.stringify()
  • Use eslint to enforce code style
  • Use prettier to format code
  • max column length is 100 chars
  • multi-line comments use /** */
  • scripts: top-level comments go after the import
  • packages/shared/src/common/__tests__/title-case.test.ts
  • packages/shared/src/common/title-case.ts
🧬 Code Graph Analysis (1)
packages/shared/src/common/__tests__/title-case.test.ts (1)
packages/shared/src/common/title-case.ts (1)
  • toTitleCase (1-13)
⏰ Context from checks skipped due to timeout of 90000ms (6)
  • GitHub Check: check-pr / lint-build-test
  • GitHub Check: check-pr / lint-build-test
  • GitHub Check: check-pr / lint-build-test
  • GitHub Check: check-pr / lint-build-test
  • GitHub Check: check-pr / lint-build-test
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (1)
packages/shared/src/common/title-case.ts (1)

7-10: Solid apostrophe handling – implementation looks correct
The new split-/rejoin logic correctly capitalises each segment in "D'Angelo" without affecting the punctuation or surrounding words. No functional concerns on these lines.

Ref eng-245

Signed-off-by: Rafael Leite <2132564+leite08@users.noreply.github.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
packages/shared/src/domain/patient/patient-import/create.ts (1)

33-36: Changing these defaults is a silent breaking change – audit call-sites & update docs/tests.

rerunPdOnNewDemographics and triggerConsolidated now default to true. Any existing caller that relied on the previous false default will suddenly trigger extra processing (PD re-runs, consolidated search) unless they explicitly pass false.

Please:

  1. Confirm that every caller really wants this new behaviour; otherwise make them pass true explicitly and keep the default false.
  2. Update unit/integration tests that assert default flag values.
  3. Mention the new default in public docs / changelog to avoid surprises in downstream services.
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f5795c4 and a01703a.

📒 Files selected for processing (1)
  • packages/shared/src/domain/patient/patient-import/create.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
`**/*.ts`: - Use the Onion Pattern to organize a package's code in layers - Try to use immutable code and avoid sharing state across different functions, objects, and systems - Try...

**/*.ts: - Use the Onion Pattern to organize a package's code in layers

  • Try to use immutable code and avoid sharing state across different functions, objects, and systems
  • Try to build code that's idempotent whenever possible
  • Prefer functional programming style functions: small, deterministic, 1 input, 1 output
  • Minimize coupling / dependencies
  • Avoid modifying objects received as parameter
  • Only add comments to code to explain why something was done, not how it works
  • Naming
    • classes, enums: PascalCase
    • constants, variables, functions: camelCase
    • file names: kebab-case
    • table and column names: snake_case
    • Use meaningful names, so whoever is reading the code understands what it means
    • Don’t use negative names, like notEnabled, prefer isDisabled
    • For numeric values, if the type doesn’t convey the unit, add the unit to the name
  • Typescript
    • Use types
    • Prefer const instead of let
    • Avoid any and casting from any to other types
    • Type predicates: only applicable to narrow down the type, not to force a complete type conversion
    • Prefer deconstructing parameters for functions instead of multiple parameters that might be of
      the same type
    • Don’t use null inside the app, only on code interacting with external interfaces/services,
      like DB and HTTP; convert to undefined before sending inwards into the code
    • Use async/await instead of .then()
    • Use the strict equality operator ===, don’t use abstract equality operator ==
    • When calling a Promise-returning function asynchronously (i.e., not awaiting), use .catch() to
      handle errors (see processAsyncError and emptyFunction depending on the case)
    • Date and Time
      • Always use buildDayjs() to create dayjs instances
      • Prefer dayjs.duration(...) to create duration consts and keep them as duration
  • Prefer Nullish Coalesce (??) than the OR operator (||) to provide a default value
  • Avoid creating arrow functions
  • Use truthy syntax instead of in - i.e., if (data.link) not if ('link' in data)
  • Error handling
    • Pass the original error as the new one’s cause so the stack trace is persisted
    • Error messages should have a static message - add dynamic data to MetriportError's additionalInfo prop
    • Avoid sending multiple events to Sentry for a single error
  • Global constants and variables
    • Move literals to constants declared after imports when possible (avoid magic numbers)
    • Avoid shared, global objects
  • Avoid using console.log and console.error in packages other than utils, infra and shared,
    and try to use out().log instead
  • Avoid multi-line logs
    • don't send objects as a second parameter to console.log() or out().log()
    • don't create multi-line strings when using JSON.stringify()
  • Use eslint to enforce code style
  • Use prettier to format code
  • max column length is 100 chars
  • multi-line comments use /** */
  • scripts: top-level comments go after the import
  • packages/shared/src/domain/patient/patient-import/create.ts
⏰ Context from checks skipped due to timeout of 90000ms (6)
  • GitHub Check: check-pr / lint-build-test
  • GitHub Check: check-pr / lint-build-test
  • GitHub Check: check-pr / lint-build-test
  • GitHub Check: check-pr / lint-build-test
  • GitHub Check: check-pr / lint-build-test
  • GitHub Check: Analyze (javascript)

@leite08 leite08 mentioned this pull request Jun 17, 2025
19 tasks
@@ -296,8 +299,11 @@ router.get(

const patientImport = await getPatientImportJobOrFail({ cxId, jobId });

if (patientImport.status === "processing" && detail === "debug") {
const details: Record<string, string | number | null>[] = [];
if (detail === "debug" && patientImport.total > maxPatientsOnDebugGetBulk) {
Copy link
Contributor

@thomasyopes thomasyopes Jun 19, 2025

Choose a reason for hiding this comment

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

maybe we should do pagination? if the patient Ids are ordered could be easy-ish?

Copy link
Contributor

Choose a reason for hiding this comment

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

just use lastPatientId token or something like that

import { updateJobAtApi } from "./api/update-job-status";
import { updatePatientRecord } from "./record/create-or-update-patient-record";

export async function setPatientOrRecordFailed({
Copy link
Contributor

Choose a reason for hiding this comment

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

setPatientOrRecordFailed what's the OR for? Seems like an AND based on the code?

* @returns true if the period is valid.
* @throws BadRequestError if the period is invalid.
*/
function validatePeriod(period: Period): true {
Copy link
Contributor

Choose a reason for hiding this comment

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

don't want to move this to core too?

): PatientPayload | ParsingError[] {
const errors: ParsingError[] = [];

let firstName: string | undefined = undefined;
try {
firstName = normalizeName(csvPatient.firstname ?? csvPatient.firstName, firstNameFieldName);
if (!firstName) throw new BadRequestError(`Missing first name`);
Copy link
Contributor

Choose a reason for hiding this comment

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

what's this checking? empty string? I'd do .length < 1 for empty string to make it clear if that's what's happening but not a big deal. I assume normalizeName trims.

Copy link
Contributor

@thomasyopes thomasyopes Jun 19, 2025

Choose a reason for hiding this comment

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

normalizeNameSafe could be something that checks empty string and returns undefined? not needed here, but might be nice

} catch (error) {
errors.push({ field: firstNameFieldName, error: errorToString(error) });
}

let lastName: string | undefined = undefined;
try {
lastName = normalizeName(csvPatient.lastname ?? csvPatient.lastName, lastNameFieldName);
if (!lastName) throw new BadRequestError(`Missing last name`);
Copy link
Contributor

Choose a reason for hiding this comment

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

ditto

const patientImportParser = new PatientImportParseLocal(patientImportBucket);

await patientImportParser.processJobParse(params);
const cmdParams: ProcessJobParseCommandRequest = {
Copy link
Contributor

Choose a reason for hiding this comment

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

processJobParseCmd? other 3 match that style

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants