Skip to content

Conversation

par333k
Copy link
Contributor

@par333k par333k commented Aug 1, 2025

Description of change

This pull request adds Redis 5.x support to TypeORM's cache implementation while maintaining full backward compatibility with Redis 3.x and 4.x.

What the change is intended to do:

  • Automatically detect Redis client version at runtime and adapt API usage accordingly
  • Support Redis 5.x Promise-based API alongside existing callback-based APIs
  • Ensure seamless operation across all Redis versions without breaking existing functionality

Why this change is needed:

  • Redis 5.x introduced breaking changes in the client API structure, moving from callback-based to Promise-based methods
  • Users upgrading to Redis 5.x would experience failures with the current implementation
  • The Redis ecosystem is moving towards Redis 5.x as the standard, making this support essential for future compatibility

How it's been verified:

  • All existing cache tests pass (17/17), proving backward compatibility with Redis 3.x/4.x
  • Runtime version detection tested with actual Redis client API behavior
  • Implementation uses safe fallback mechanisms defaulting to Redis 3.x behavior for maximum compatibility
  • Updated peer dependencies to officially support Redis 5.x versions

Implementation approach:

  • Dynamic version detection using actual client API testing rather than package version parsing
  • Transparent operation: existing code continues to work without any changes
  • Safe error handling with fallback to most compatible behavior

Pull-Request Checklist

  • [v] Code is up-to-date with the master branch
  • [v] This pull request links relevant issues as Feat #11528
  • [] There are new or updated unit tests validating the change
  • [] Documentation has been updated to reflect this change

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Enhanced Redis cache compatibility to support Redis client versions 3, 4, and 5+ for improved reliability.
  • Chores

    • Updated Redis package version requirements to allow use of newer Redis client versions.

par333k added 3 commits July 31, 2025 16:58
- Add version detection for Redis client to handle API differences
- Support Redis 5 Promise-based API while maintaining backward compatibility
- Update methods to use appropriate API based on Redis version
- Add tests for Redis 5 compatibility

Redis 5 introduced Promise-based API as default, replacing the callback-based
API. This change detects the Redis version and uses the appropriate API calls
to ensure compatibility with Redis 3, 4, and 5.

Closes typeorm#11528
Implement automatic version detection for Redis client libraries to support
Redis 3, 4, and 5 seamlessly. The implementation uses runtime API testing
to determine the appropriate Redis client behavior without breaking existing
functionality.

Changes include:
  - Dynamic Redis version detection based on client API characteristics
  - Promise-based API support for Redis 5.x
  - Backward compatibility with Redis 3.x and 4.x callback-based APIs
  - Safe fallback mechanism defaulting to Redis 3 behavior
  - Updated peer dependency to include Redis 5.x versions

The cache implementation now automatically adapts to the installed Redis version, ensuring optimal performance and compatibility across all supported Redis client versions while maintaining full backward compatibility.
Copy link

coderabbitai bot commented Aug 1, 2025

Walkthrough

The changes update Redis dependency versions in package.json to support Redis 5.x and enhance the RedisQueryResultCache class to detect and handle both legacy (v3/4) and modern (v5+) Redis clients. The cache logic now branches based on Redis version, ensuring compatibility with both callback and Promise-based APIs.

Changes

Cohort / File(s) Change Summary
Dependency Version Update
package.json
Updated redis version in devDependencies from ^4.7.0 to ^5.7.0 and expanded peerDependencies to include ^5.0.14, supporting Redis v5.x.
Redis Query Result Cache Version Handling
src/cache/RedisQueryResultCache.ts
Enhanced class to detect Redis client version at runtime. Added logic to branch cache operations between legacy (callback) and modern (Promise) APIs. Introduced new properties and helper methods for version detection and handling.

Sequence Diagram(s)

sequenceDiagram
    participant App
    participant RedisQueryResultCache
    participant RedisClient

    App->>RedisQueryResultCache: connect()
    RedisQueryResultCache->>RedisClient: create client (no legacyMode)
    RedisQueryResultCache->>RedisClient: check for connect method
    alt Redis 4+
        RedisQueryResultCache->>RedisClient: recreate client (legacyMode: true)
    end
    RedisQueryResultCache->>RedisClient: connect()
    RedisQueryResultCache->>RedisQueryResultCache: detectRedisVersion()
    App->>RedisQueryResultCache: getFromCache()/storeInCache()/clear()/deleteKey()
    alt Redis 5+
        RedisQueryResultCache->>RedisClient: use Promise-based API
    else Redis 3/4
        RedisQueryResultCache->>RedisClient: use callback-based API
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~35 minutes

Poem

In the warren where queries hop and dash,
Redis five arrives—oh what a splash!
With version checks and logic split,
Old and new clients now both fit.
Cache flows smooth, no need to fret,
This rabbit’s code is future-set!
🐇✨

Note

⚡️ Unit Test Generation is now available in beta!

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


📜 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 ceb2bcd and 82de62d.

📒 Files selected for processing (1)
  • src/cache/RedisQueryResultCache.ts (8 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: alumni
PR: typeorm/typeorm#11581
File: docs/docs/drivers/mongodb.md:9-13
Timestamp: 2025-07-27T17:29:18.547Z
Learning: TypeORM is compatible only with mongodb@^6, not v4 as previously suggested. The package.json file contains the authoritative peer dependency information for the MongoDB driver version compatibility.
Learnt from: alumni
PR: typeorm/typeorm#11581
File: docs/docs/drivers/mongodb.md:9-13
Timestamp: 2025-07-27T17:29:18.547Z
Learning: TypeORM supports MongoDB driver versions "^5.8.0 || ^6.0.0" according to the peerDependencies in package.json. The v4 driver is NOT supported. Always check package.json for accurate peer dependency information.
🔇 Additional comments (9)
src/cache/RedisQueryResultCache.ts (9)

31-34: LGTM: Well-structured version tracking property.

The new redisMajorVersion property is properly typed and documented, providing a clean way to track Redis version for API compatibility decisions.


58-91: Client creation approach prioritizes compatibility over efficiency.

The implementation correctly handles Redis version detection and backward compatibility. While it still creates the client twice for Redis 4+ (as noted in previous reviews), this approach ensures reliable version detection and proper legacyMode configuration.

The logic flow is sound:

  1. Creates initial client to test for Redis 4+ features
  2. Recreates with appropriate options if needed
  3. Connects and detects precise version

135-150: LGTM: Proper version-specific disconnect handling.

The disconnect method correctly handles both Redis 5+ Promise-based and Redis 3/4 callback-based quit() methods. Client cleanup is properly handled in both code paths.


166-183: LGTM: Improved method structure with proper version handling.

The refactored getFromCache method is cleaner and more maintainable:

  • Consolidated key selection logic eliminates redundancy
  • Early return for missing keys improves efficiency
  • Proper branching for Redis 5+ Promise-based vs Redis 3/4 callback-based APIs
  • Consistent JSON parsing in both code paths

200-227: LGTM: Consistent API handling for cache storage.

The storeInCache method properly handles version-specific Redis APIs:

  • Redis 5+ uses the modern options object format for set()
  • Redis 3/4 uses the traditional positional parameter format
  • Consistent error handling and Promise wrapping across versions
  • Clean separation of preparation logic from API calls

233-246: LGTM: Proper cache clearing for both Redis versions.

The clear method correctly handles version-specific flush operations:

  • Redis 5+ uses flushDb() Promise-based API
  • Redis 3/4 uses flushdb() callback-based API
  • Consistent error handling and Promise patterns

269-283: LGTM: Consistent key deletion pattern.

The deleteKey method follows the established pattern for version-specific API handling:

  • Redis 5+ uses Promise-based del()
  • Redis 3/4 uses callback-based del() wrapped in Promise
  • Consistent error handling across versions

329-334: LGTM: Clean and safe version checking helper.

The isRedis5OrHigher helper method is well-implemented:

  • Properly checks client type to avoid version logic for ioredis
  • Safe handling of undefined version values
  • Clear and readable boolean logic

306-324: Confirm setMethod.length-based version detection for Redis v3, v4, and v5

Nice work avoiding test keys in production by inspecting the set method signature. Before final approval, please verify that:

  • In Redis v3 the client.set method is declared with more than 3 parameters (so length > 3).
  • In Redis v4 and v5 the client.set method is declared with at most 3 parameters (so length ≤ 3).
  • Because v4 and v5 share the same signature, they’ll both be classified as “5+” by this logic—ensure that treating v4 as “5+” won’t break any downstream assumptions.

File: src/cache/RedisQueryResultCache.ts
Lines: 306–324

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

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

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

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

Support

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

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

CodeRabbit Commands (Invoked using PR comments)

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

Other keywords and placeholders

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

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.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
package.json (1)

179-179: Consider using a more flexible version range for Redis 5.x

The peer dependency specifies ^5.0.14 which requires at least version 5.0.14. Consider using ^5.0.0 instead to allow any Redis 5.x version, unless there's a specific reason why versions 5.0.0-5.0.13 are incompatible.

-    "redis": "^3.1.1 || ^4.0.0 || ^5.0.14",
+    "redis": "^3.1.1 || ^4.0.0 || ^5.0.0",
src/cache/RedisQueryResultCache.ts (2)

313-313: Enhance test key uniqueness to prevent collisions

The test key uses only timestamp which could collide if multiple cache instances are initialized simultaneously.

-            const testKey = `__typeorm_redis_version_test_${Date.now()}`
+            const testKey = `__typeorm_redis_version_test_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`

137-343: Consider refactoring version-specific logic into separate strategies

While the current implementation works, having version checks in every method makes the code harder to maintain. Consider refactoring into a strategy pattern where version-specific implementations are encapsulated.

For future improvements, consider:

  1. Creating separate adapter classes for Redis 3/4 and Redis 5+ that implement a common interface
  2. Using factory pattern to instantiate the appropriate adapter based on detected version
  3. This would eliminate the repeated if (this.isRedis5OrHigher()) checks throughout the code

Example structure:

interface RedisAdapter {
  get(key: string): Promise<string | null>
  set(key: string, value: string, duration: number): Promise<void>
  // ... other methods
}

class Redis3Adapter implements RedisAdapter { /* ... */ }
class Redis5Adapter implements RedisAdapter { /* ... */ }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 8097d1a and 6e712c7.

📒 Files selected for processing (2)
  • package.json (2 hunks)
  • src/cache/RedisQueryResultCache.ts (8 hunks)
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: alumni
PR: typeorm/typeorm#11581
File: docs/docs/drivers/mongodb.md:9-13
Timestamp: 2025-07-27T17:29:18.547Z
Learning: TypeORM supports MongoDB driver versions "^5.8.0 || ^6.0.0" according to the peerDependencies in package.json. The v4 driver is NOT supported. Always check package.json for accurate peer dependency information.
Learnt from: alumni
PR: typeorm/typeorm#11581
File: docs/docs/drivers/mongodb.md:9-13
Timestamp: 2025-07-27T17:29:18.547Z
Learning: TypeORM is compatible only with mongodb@^6, not v4 as previously suggested. The package.json file contains the authoritative peer dependency information for the MongoDB driver version compatibility.
📚 Learning: typeorm is compatible only with mongodb@^6, not v4 as previously suggested. the package.json file co...
Learnt from: alumni
PR: typeorm/typeorm#11581
File: docs/docs/drivers/mongodb.md:9-13
Timestamp: 2025-07-27T17:29:18.547Z
Learning: TypeORM is compatible only with mongodb@^6, not v4 as previously suggested. The package.json file contains the authoritative peer dependency information for the MongoDB driver version compatibility.

Applied to files:

  • package.json
📚 Learning: typeorm supports mongodb driver versions "^5.8.0 || ^6.0.0" according to the peerdependencies in pac...
Learnt from: alumni
PR: typeorm/typeorm#11581
File: docs/docs/drivers/mongodb.md:9-13
Timestamp: 2025-07-27T17:29:18.547Z
Learning: TypeORM supports MongoDB driver versions "^5.8.0 || ^6.0.0" according to the peerDependencies in package.json. The v4 driver is NOT supported. Always check package.json for accurate peer dependency information.

Applied to files:

  • package.json
📚 Learning: the correct data source type for aurora postgresql in typeorm is `aurora-postgres`, not `aurora-data...
Learnt from: alumni
PR: typeorm/typeorm#11581
File: docs/docs/drivers/postgres.md:23-23
Timestamp: 2025-07-27T20:50:10.364Z
Learning: The correct data source type for Aurora PostgreSQL in TypeORM is `aurora-postgres`, not `aurora-data-api-pg`. The `aurora-data-api-pg` driver was renamed to `aurora-postgres` according to the CHANGELOG.md. This is defined in the DatabaseType union type and AuroraPostgresConnectionOptions interface.

Applied to files:

  • package.json
🔇 Additional comments (2)
src/cache/RedisQueryResultCache.ts (2)

340-343: LGTM!

The helper method correctly handles version checking and appropriately returns false for ioredis clients, ensuring they use the callback-based API path.


237-237: Ensure correct method name for flushing Redis database

The Redis 5.x Node.js clients (both node-redis and ioredis) expose the flushdb command in all lowercase. Update the promise-based call to use flushdb() so it matches the actual API.

Locations to update:

  • src/cache/RedisQueryResultCache.ts
    • Line 237: change flushDb() to flushdb()

Diff:

-            await this.client.flushDb()
+            await this.client.flushdb()

No change needed for the callback branch at line 243, which already uses flushdb().

Likely an incorrect or invalid review comment.

Comment on lines 58 to 76
const clientOptions = {
...cacheOptions?.options,
legacyMode: true,
})
}

// Create client first
this.client = this.redis.createClient(clientOptions)

// Check if this is Redis 4.x by looking for connect method before connecting
const isRedis4Plus = typeof this.client.connect === 'function'

if (isRedis4Plus) {
// For Redis 4.x, we need to recreate the client with legacyMode
// First check if we're dealing with Redis 4 (has connect but uses callbacks)
// or Redis 5 (has connect and uses promises)
this.client = this.redis.createClient({
...clientOptions,
legacyMode: true
})
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Optimize client creation to avoid recreating for Redis 4+

The current implementation creates the Redis client twice when dealing with Redis 4+. Additionally, the code unconditionally enables legacyMode for all Redis 4+ clients, including Redis 5, which may not require it based on the version detection logic that follows.

-            const clientOptions = {
-                ...cacheOptions?.options,
-            }
-
-            // Create client first
-            this.client = this.redis.createClient(clientOptions)
-
-            // Check if this is Redis 4.x by looking for connect method before connecting
-            const isRedis4Plus = typeof this.client.connect === 'function'
-            
-            if (isRedis4Plus) {
-                // For Redis 4.x, we need to recreate the client with legacyMode
-                // First check if we're dealing with Redis 4 (has connect but uses callbacks)
-                // or Redis 5 (has connect and uses promises)
-                this.client = this.redis.createClient({
-                    ...clientOptions,
-                    legacyMode: true
-                })
-            }
+            // Detect Redis version by checking the library API
+            const testClient = this.redis.createClient({ ...cacheOptions?.options })
+            const isRedis4Plus = typeof testClient.connect === 'function'
+            
+            // Clean up test client if it was created
+            if (testClient && typeof testClient.quit === 'function') {
+                testClient.quit().catch(() => {})
+            }
+            
+            const clientOptions = {
+                ...cacheOptions?.options,
+                // Only Redis 4.x needs legacyMode, Redis 5.x doesn't
+                ...(isRedis4Plus ? { legacyMode: true } : {})
+            }
+            
+            this.client = this.redis.createClient(clientOptions)

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/cache/RedisQueryResultCache.ts around lines 58 to 76, the Redis client is
created twice unnecessarily for Redis 4+ versions, and legacyMode is enabled
unconditionally for all Redis 4+ clients. Refactor the code to create the client
only once by detecting the Redis version before client creation, and enable
legacyMode only if the client is Redis 4 (not Redis 5), avoiding redundant
client recreation.

par333k added 2 commits August 1, 2025 12:28
Eliminate unnecessary Redis client recreation by using explicit tempClient
variable management, reducing potential client instances while maintaining
full Redis 3/4/5 compatibility and accurate version detection.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🔭 Outside diff range comments (2)
src/cache/RedisQueryResultCache.ts (2)

58-91: Critical issue: Potential resource leak in version detection

The current implementation creates a temporary client for version detection but doesn't properly clean it up before creating the main client. This could lead to resource leaks, especially with Redis 4+ clients that maintain connections.

Apply this diff to properly handle the temporary client cleanup:

-            // Create initial client to test Redis version
-            let tempClient = this.redis.createClient(clientOptions)
-            const isRedis4Plus = typeof tempClient.connect === 'function'
-            
-            if (isRedis4Plus) {
-                // Redis 4+ detected, recreate with legacyMode for Redis 4.x
-                // (Redis 5 will ignore legacyMode if not needed)
-                clientOptions.legacyMode = true
-                tempClient = this.redis.createClient(clientOptions)
-            }
-
-            // Set as the main client
-            this.client = tempClient
+            // Detect Redis version without creating unnecessary connections
+            const isRedis4Plus = typeof this.redis.createClient({}).connect === 'function'
+            
+            if (isRedis4Plus) {
+                // Redis 4+ detected, use legacyMode for compatibility
+                clientOptions.legacyMode = true
+            }
+
+            // Create the main client once with correct options
+            this.client = this.redis.createClient(clientOptions)

233-245: Inconsistent Redis command casing with Redis v4 support
Redis 3’s callback API uses flushdb(), but Redis 4+ (v4 and v5) expose the promise‐based flushDb(). Your isRedis5OrHigher() guard only applies to v5, so when consumers install Redis 4 (which you list in peerDependencies), the fallback to flushdb() will throw “flushdb is not a function.” Please update to cover v4 as well.

• File: src/cache/RedisQueryResultCache.ts Lines 233–245

  • Either change the check to “Redis 4+” and call await this.client.flushDb() for both v4/v5
  • Or detect method availability at runtime:
    if (typeof this.client.flushDb === 'function') {
      await this.client.flushDb();
    } else {
      return new Promise<void>((ok, fail) =>
        this.client.flushdb((err, _) => (err ? fail(err) : ok()))
      );
    }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 6e712c7 and e4ca2ab.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (1)
  • src/cache/RedisQueryResultCache.ts (8 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: alumni
PR: typeorm/typeorm#11581
File: docs/docs/drivers/mongodb.md:9-13
Timestamp: 2025-07-27T17:29:18.547Z
Learning: TypeORM supports MongoDB driver versions "^5.8.0 || ^6.0.0" according to the peerDependencies in package.json. The v4 driver is NOT supported. Always check package.json for accurate peer dependency information.
Learnt from: alumni
PR: typeorm/typeorm#11581
File: docs/docs/drivers/mongodb.md:9-13
Timestamp: 2025-07-27T17:29:18.547Z
Learning: TypeORM is compatible only with mongodb@^6, not v4 as previously suggested. The package.json file contains the authoritative peer dependency information for the MongoDB driver version compatibility.
🔇 Additional comments (6)
src/cache/RedisQueryResultCache.ts (6)

31-34: LGTM!

The new property declaration is well-documented and follows TypeScript conventions. The optional typing properly handles the undefined state during initialization.


135-149: LGTM! Proper version-specific disconnect handling

The implementation correctly handles the different quit behaviors between Redis versions. Redis 5+ returns a Promise while older versions use callbacks.


166-182: LGTM! Clean version branching for cache retrieval

The method properly handles both Promise-based (Redis 5+) and callback-based (Redis 3/4) APIs. The key selection logic is correctly consolidated.


269-283: LGTM! Consistent delete operation handling

The method properly handles version differences for the delete operation using the same branching pattern as other methods.


338-341: LGTM! Clean helper method implementation

The helper method provides a clear abstraction for version checking with proper type safety and client type validation.


200-226: ✅ Confirmed: client.set(key, value, { PX }) is valid in the promise-based Redis client

The Node Redis v4 client (which exposes the modern, promise-based API) supports calling:

await client.set('myKey', 'myValue', { PX: 5000 });

to set a key with a millisecond TTL. No changes needed here.

Replace test key creation method with client method signature analysis
to prevent potential cache pollution and improve performance.
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)
src/cache/RedisQueryResultCache.ts (1)

58-74: Significant improvement over previous version detection approach.

The current implementation addresses the previous concerns about creating multiple clients unnecessarily. However, there's still room for optimization by avoiding the temporary client creation entirely.

Consider detecting Redis 4+ capabilities before any client creation:

-            // Create initial client to test Redis version
-            let tempClient = this.redis.createClient(clientOptions)
-            const isRedis4Plus = typeof tempClient.connect === 'function'
-            
-            if (isRedis4Plus) {
-                // Redis 4+ detected, recreate with legacyMode for Redis 4.x
-                // (Redis 5 will ignore legacyMode if not needed)
-                clientOptions.legacyMode = true
-                tempClient = this.redis.createClient(clientOptions)
-            }
-
-            // Set as the main client
-            this.client = tempClient
+            // Detect Redis 4+ by checking if createClient accepts legacyMode option
+            const testClientFactory = this.redis.createClient
+            const isRedis4Plus = testClientFactory.toString().includes('legacyMode') || 
+                                  this.redis.createClient({}).connect !== undefined
+            
+            if (isRedis4Plus) {
+                clientOptions.legacyMode = true
+            }
+            
+            this.client = this.redis.createClient(clientOptions)
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between e4ca2ab and ceb2bcd.

📒 Files selected for processing (1)
  • src/cache/RedisQueryResultCache.ts (8 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: alumni
PR: typeorm/typeorm#11581
File: docs/docs/drivers/mongodb.md:9-13
Timestamp: 2025-07-27T17:29:18.547Z
Learning: TypeORM supports MongoDB driver versions "^5.8.0 || ^6.0.0" according to the peerDependencies in package.json. The v4 driver is NOT supported. Always check package.json for accurate peer dependency information.
Learnt from: alumni
PR: typeorm/typeorm#11581
File: docs/docs/drivers/mongodb.md:9-13
Timestamp: 2025-07-27T17:29:18.547Z
Learning: TypeORM is compatible only with mongodb@^6, not v4 as previously suggested. The package.json file contains the authoritative peer dependency information for the MongoDB driver version compatibility.
🧬 Code Graph Analysis (1)
src/cache/RedisQueryResultCache.ts (2)
src/cache/QueryResultCacheOptions.ts (1)
  • QueryResultCacheOptions (4-30)
src/find-options/FindOperator.ts (1)
  • value (105-110)
🔇 Additional comments (10)
src/cache/RedisQueryResultCache.ts (10)

31-34: LGTM! Clean property addition for version tracking.

The new redisMajorVersion property properly tracks the Redis version for branching logic throughout the class.


85-91: Good separation of connection and version detection logic.

The approach to connect first (for Redis 4+) then detect the precise version is sound and follows the expected Redis client lifecycle.


135-150: Excellent version-aware disconnect implementation.

The Promise-based approach for Redis 5+ and callback wrapper for older versions is implemented correctly with proper cleanup.


166-183: Clean cache retrieval with proper version branching.

The simplified key selection logic and version-specific API usage is well implemented. The code correctly handles both Promise and callback patterns.


200-227: Well-structured cache storage with correct Redis 5+ options syntax.

The implementation properly uses the PX option object syntax for Redis 5+ and the positional parameter approach for older versions.


233-246: Correct implementation of version-aware cache clearing.

Both Redis 5+ Promise-based flushDb() and Redis 3/4 callback-based flushdb() are handled appropriately.


269-283: Proper key deletion with version compatibility.

The deleteKey method correctly implements both Promise and callback patterns for different Redis versions.


306-324: Excellent improvement! Safe version detection without database pollution.

This implementation successfully addresses the critical concern from previous reviews about creating test keys in the Redis database. The method signature inspection approach is much safer and more reliable.

The detection logic using setMethod.length <= 3 is clever and avoids any side effects on the Redis instance.


329-332: Clean helper method for version checking.

The boolean helper method provides a clear and consistent way to determine Redis version throughout the class.


306-332: Verify Redis client set method parameter count covers all supported versions

The current detection logic assumes Redis 5+’s set method has ≤ 3 parameters, while Redis 3/4 has more. Since our peerDependencies span Redis 3.x, 4.x, and 5.x—and we didn’t find a bundled redis package locally—you’ll need to confirm that:

  • For Redis 3.x: client.set.length is > 3
  • For Redis 4.x: what value does client.set.length return?
  • For Redis 5.x+: client.set.length is ≤ 3

If any overlap exists (e.g., v4 returning ≤ 3), this detection could misclassify versions. Consider either:

  • Adding runtime tests against each client version to assert set.length, or
  • Switching to an explicit version-check (e.g., await client.sendCommand(["INFO"]) and parsing redis_version), which avoids relying on method arity.

Copy link
Collaborator

@gioboa gioboa left a comment

Choose a reason for hiding this comment

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

It looks great @par333k
Thanks for your amazing help 👏

Copy link

pkg-pr-new bot commented Aug 1, 2025

typeorm-sql-js-example

npm i https://pkg.pr.new/typeorm/typeorm@11585

commit: 82de62d

@alumni
Copy link
Collaborator

alumni commented Aug 1, 2025

Thanks for the contribution @par333k :)

Would be great if you could fix the formatting for that file :)

@gioboa gioboa merged commit 17cf837 into typeorm:master Aug 1, 2025
58 checks passed
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.

3 participants