Skip to content

Conversation

@anxolin
Copy link
Contributor

@anxolin anxolin commented Apr 23, 2025

Automatically apply the repository migrations.

background on this PR

I was not planning to do this PR, as I just need to create a single table, and I was fine with applying the migrations to a remote db, but I don't have write permissions to production or staging

There might be many repositories using the DB, and can also be used in different apps. If I try to apply migrations in all apps boot, there could be a race condition. My first approach was using docker and apply the migration when we deploy the services, but later I realised there was a simple way by using the API.

The API is deployed each time there's a new BFF version, so now in its boot will apply any un-applied migration.
It was also a bit of not a straight line to make it work. I will try to merge this PR and test this in AWS to see if it works well there.

Changes

Namespaces for different ORM

The API had an orm of typeorm

Automatically apply migrations of the repositories

The API defines a new plugin that applies the migrations.

image

EDIT: It works 🎉

I merged to test it in AWS, and it applied the migration!

image

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Apr 23, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

This update introduces a new Fastify plugin for managing TypeORM integration and PostgreSQL migrations with SSL support, enhanced error handling, and migration logging. The existing analytics ORM plugin and related API routes are refactored to use a namespaced ORM context (fastify.orm.analytics). Code formatting improvements are applied for clarity and consistency. Additionally, the PostgreSQL connection setup is modularized by extracting environment variable assertions and parameter construction into a dedicated function getDatabaseParams(), simplifying ORM initialization.

Changes

File(s) Change Summary
apps/api/src/app/plugins/orm-analytics.ts, apps/api/src/app/routes/__chainId/yield/getPoolsAverageApr.ts, apps/api/src/app/routes/__chainId/yield/getPoolsInfo.ts Refactored ORM usage to a namespaced analytics context (fastify.orm.analytics). Reformatted code with multiline arrow functions, added semicolons, and improved indentation. No changes to logic or response structure.
apps/api/src/app/plugins/orm-repositories.ts Added a new Fastify plugin to configure TypeORM with PostgreSQL, including SSL in production, migration file setup, and running migrations inside a transaction. Added asynchronous function to read and log migration filenames. Implemented error handling and logging for migration execution and directory reading.
libs/repositories/src/datasources/orm/postgresOrm.ts Extracted environment variable assertions and database connection parameters into a new exported function getDatabaseParams(). Updated createNewPostgresOrm() to use this function for connection parameters, maintaining existing entities and migration settings.

Sequence Diagram(s)

sequenceDiagram
    participant Fastify
    participant ORMPlugin
    participant TypeORM
    participant MigrationDir

    Fastify->>ORMPlugin: Register plugin (orm-repositories)
    ORMPlugin->>TypeORM: Configure connection (with SSL, migrations)
    ORMPlugin->>TypeORM: Run pending migrations
    TypeORM-->>ORMPlugin: Migration results/errors
    ORMPlugin->>MigrationDir: Read migration filenames
    MigrationDir-->>ORMPlugin: Return filenames/errors
    ORMPlugin->>Fastify: Log migration status and errors
Loading

Poem

🐇 In tunnels deep where data flows,
New plugins sprout and structure grows.
Namespaces neat and errors caught,
Migrations run as rabbits thought.
Connections clear, the code refined—
This patch brings peace to bunny’s mind!
✨🐰


📜 Recent review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 2f71483 and 039a119.

📒 Files selected for processing (2)
  • apps/api/src/app/plugins/orm-repositories.ts (1 hunks)
  • libs/repositories/src/datasources/orm/postgresOrm.ts (1 hunks)

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

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • 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 generate unit testing code for this file.
    • @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 generate unit testing code.
    • @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.

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.

@anxolin anxolin requested a review from Copilot April 23, 2025 20:35
@anxolin
Copy link
Contributor Author

anxolin commented Apr 23, 2025

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Apr 23, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR introduces automatic migration execution on API startup to simplify database updates across multiple repositories. Key changes include refactoring the Postgres ORM configuration to support migrations, updating API routes to use a dedicated “analytics” ORM namespace, and adding new Fastify plugins to register and run migrations.

Reviewed Changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.

Show a summary per file
File Description
libs/repositories/src/datasources/orm/postgresOrm.ts Refactored ORM configuration by separating database parameters and defining migration settings.
apps/api/src/app/routes/__chainId/yield/getPoolsInfo.ts Updated repository reference to use the analytics ORM namespace and adjusted formatting.
apps/api/src/app/routes/__chainId/yield/getPoolsAverageApr.ts Similar update to the repository source with minor formatting changes in the SQL query and header setup.
apps/api/src/app/plugins/orm-repositories.ts Added a new plugin to register the repositories ORM, including migration execution and logging.
apps/api/src/app/plugins/orm-analytics.ts Introduced a new plugin for the analytics ORM that registers entities and runs migrations on startup.
Comments suppressed due to low confidence (4)

libs/repositories/src/datasources/orm/postgresOrm.ts:4

  • The removal of the 'IndexerState' entity import may cause issues if it is expected to be part of this ORM instance. Verify that this entity is no longer needed or has been migrated to the appropriate ORM configuration.
-import { IndexerState } from '../../database/IndexerState.entity';

apps/api/src/app/routes/__chainId/yield/getPoolsInfo.ts:40

  • Confirm that referencing PoolInfo from the 'analytics' namespace is intentional and that the entity is registered under this ORM instance to prevent potential runtime errors.
const poolInfoRepository = fastify.orm.analytics.getRepository(PoolInfo);

apps/api/src/app/routes/__chainId/yield/getPoolsAverageApr.ts:44

  • Ensure that using the 'analytics' namespace for PoolInfo queries aligns with your overall database strategy and that the entity mapping is correct to avoid data mismatches.
const poolInfoRepository = fastify.orm.analytics.getRepository(PoolInfo);

apps/api/src/app/plugins/orm-analytics.ts:45

  • [nitpick] Verify that running migrations automatically in the 'analytics' namespace during Fastify's boot does not lead to race conditions or conflicts in a multi-instance deployment scenario.
fastify.orm.analytics.runMigrations({ transaction: 'all' });


fastify.register(typeORMPlugin, {
...dbParams,
namespace: 'analytics',
Copy link
Contributor Author

Choose a reason for hiding this comment

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

namespacing helps to differenciate between the different typeorm instances. This one is for the analytics.

const migrationsDir = resolve(
__dirname,
'../../../../../libs/repositories/src/migrations'
);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

It took me a bit to arrive here, when we run the API using nx, it depends on the build. This PR adds a build step for the repositories too. This way, we can find the migrations and use them.

migrationsTableName: 'migrations_repositories',
entities: [],
ssl: isProduction,
extra: isProduction
Copy link
Contributor Author

Choose a reason for hiding this comment

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

use ssl only in prod

import { IndexerState } from '../../database/IndexerState.entity';

export function createNewPostgresOrm(): DataSource {
export function getDatabaseParams() {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

just convenient to share the credentials to be used in the typeorm API config

Copy link
Contributor

@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 (2)
apps/api/src/app/plugins/orm-repositories.ts (2)

14-17: Consider making the migrations path configurable.

The migrations directory path is hardcoded with multiple "../" references to navigate up the directory tree, which could be fragile if the directory structure changes in the future.

+import { config } from '@cowprotocol/config'; // Hypothetical config module

-  const migrationsDir = resolve(
-    __dirname,
-    '../../../../../libs/repositories/src/migrations'
-  );
+  const migrationsDir = config.migrations?.repositoriesPath || resolve(
+    __dirname,
+    '../../../../../libs/repositories/src/migrations'
+  );

1-68: Overall well-implemented automatic migration plugin.

This plugin successfully achieves the objective of automatically applying database migrations during API startup. The implementation is robust with proper error handling, logging, and transaction support. It aligns with the PR's goal of streamlining migration management and reducing manual intervention.

A few additional considerations:

  1. You might want to add a check to skip migrations in certain environments if needed.
  2. Consider adding more detailed logging for each migration being applied.
  3. Think about how this would work if multiple API instances start simultaneously.
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between a713d8e and 2f71483.

📒 Files selected for processing (5)
  • apps/api/src/app/plugins/orm-analytics.ts (1 hunks)
  • apps/api/src/app/plugins/orm-repositories.ts (1 hunks)
  • apps/api/src/app/routes/__chainId/yield/getPoolsAverageApr.ts (2 hunks)
  • apps/api/src/app/routes/__chainId/yield/getPoolsInfo.ts (2 hunks)
  • libs/repositories/src/datasources/orm/postgresOrm.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
apps/api/src/app/plugins/orm-repositories.ts (2)
libs/repositories/src/datasources/orm/postgresOrm.ts (1)
  • getDatabaseParams (6-21)
libs/shared/src/logger.ts (1)
  • logger (3-3)
apps/api/src/app/routes/__chainId/yield/getPoolsAverageApr.ts (2)
apps/api/src/app/routes/__chainId/yield/utils.ts (1)
  • trimDoubleQuotes (1-11)
apps/api/src/utils/cache.ts (2)
  • CACHE_CONTROL_HEADER (3-3)
  • getCacheControlHeaderValue (66-71)
🔇 Additional comments (13)
libs/repositories/src/datasources/orm/postgresOrm.ts (2)

6-21: Well-structured extraction of database parameters!

This is a good refactoring that follows the DRY principle by centralizing database parameter extraction into a dedicated function. This will make the code more maintainable and facilitate reuse of these parameters across different ORM contexts, which is helpful for the automatic migration functionality.


23-29: Good refactoring of DataSource creation

Using the extracted getDatabaseParams() function with object spread simplifies the DataSource creation and improves maintainability. The function now clearly focuses on its primary responsibility of creating the ORM instance.

apps/api/src/app/routes/__chainId/yield/getPoolsAverageApr.ts (2)

44-44: Appropriate update to use analytics namespace

Good update to use the new analytics namespace for the ORM. This change properly aligns with the architectural decision to separate different ORM contexts and will support the automatic migration functionality.


46-68: Good code formatting improvements

The reformatting of the SQL query, reduce function, and cache header setting improves code readability and maintainability without changing functionality. These changes make the code easier to understand and follow established formatting conventions.

apps/api/src/app/plugins/orm-analytics.ts (2)

27-30: Excellent addition of analytics namespace

Adding the namespace: 'analytics' property to the typeORMPlugin registration is a key architectural improvement that allows for separate ORM instances. This is crucial for the automatic migration functionality and helps avoid race conditions when multiple repositories or applications access the same database.


45-45: Correctly updated migration call to use analytics namespace

Good update to use the analytics namespace for running migrations. This ensures migrations are executed in the correct ORM context and aligns with the automatic migration functionality being implemented.

apps/api/src/app/routes/__chainId/yield/getPoolsInfo.ts (2)

40-40: Consistent use of analytics namespace

Good update to use the new analytics namespace for repository access. This change maintains consistency with the architectural decision to separate ORM contexts and will support the automatic migration functionality.


5-58: Good code formatting improvements throughout

The reformatting of imports, query parameters, and result mapping improves code readability and maintainability. These changes establish consistent formatting patterns across the codebase, making it easier to understand and modify in the future.

apps/api/src/app/plugins/orm-repositories.ts (5)

1-10: Clean and well-structured imports.

The imports section properly organizes the required dependencies for TypeORM integration and Fastify plugin development. The use of selective imports from shared libraries follows good practices.


19-35: Good database connection configuration with environment awareness.

The TypeORM configuration is well-structured with:

  • Appropriate namespace for the ORM connection
  • Properly configured SSL settings based on environment
  • Clean separation of database parameters using the shared getDatabaseParams() function
  • Use of empty entities array, which is appropriate if this plugin only handles migrations

The configuration will properly connect to PostgreSQL in both development and production environments.


36-53: Well-implemented migration execution with proper error handling.

The migration execution is correctly placed in the fastify.ready() hook to ensure it runs after the Fastify app is properly initialized. The use of transaction: 'all' ensures all migrations run atomically, which is a good practice. Error handling is comprehensive with proper logging and error propagation.


44-44: Ensure migration printing doesn't block API startup.

The printMigrations function is called without await, which means the API continues startup without waiting for the directory reading to complete. This is likely intentional for performance reasons but could lead to interleaved log messages.

If you want to ensure migration list is printed before running migrations, consider adding await:

-      printMigrations(migrationsDir);
+      await printMigrations(migrationsDir);

56-67: Good utility function for migration visibility.

The printMigrations function is well-implemented with proper filtering for JavaScript files and error handling. This will help with debugging and monitoring of available migrations.

@anxolin anxolin marked this pull request as ready for review April 23, 2025 20:41
@anxolin anxolin requested a review from a team April 23, 2025 20:41
@anxolin anxolin merged commit ad71f89 into main Apr 23, 2025
6 of 7 checks passed
@anxolin anxolin deleted the apply-automatic-migrations branch April 23, 2025 20:41
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