Skip to content

Added Type Command - #46

Merged
unikdahal merged 4 commits into
mainfrom
feature/TypeCommand
Jan 26, 2026
Merged

Added Type Command#46
unikdahal merged 4 commits into
mainfrom
feature/TypeCommand

Conversation

@unikdahal

@unikdahal unikdahal commented Jan 26, 2026

Copy link
Copy Markdown
Owner

Added Type Command

Summary by CodeRabbit

  • New Features

    • Added TYPE command and STREAM data type; added stream operations XADD, XRANGE, XREAD.
  • Documentation

    • New docs for TYPE, XADD, XRANGE, XREAD and README update referencing TYPE and stream operations.
  • Tests

    • New unit and integration tests covering TYPE and stream commands (XADD, XRANGE, XREAD), including blocking/read behaviors and edge cases.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai

coderabbitai Bot commented Jan 26, 2026

Copy link
Copy Markdown
Contributor

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

Adds STREAM support and the TYPE command: new StreamId and STREAM RedisValue, implementations for TYPE, XADD, XRANGE, XREAD, service registrations, docs for TYPE/XADD/XRANGE/XREAD, and unit + integration tests for TYPE and stream commands.

Changes

Cohort / File(s) Summary
Core data types & util
src/main/java/com/redis/storage/RedisValue.java, src/main/java/com/redis/util/StreamId.java
Add STREAM type to RedisValue (factory, accessor, StreamValue using ConcurrentSkipListMap) and new StreamId record with parse/compare/MIN/MAX.
Stream commands
src/main/java/com/redis/commands/stream/XAddCommand.java, src/main/java/com/redis/commands/stream/XRangeCommand.java, src/main/java/com/redis/commands/stream/XReadCommand.java
New ICommand implementations: XADD (ID parsing, ordering, entry insertion), XRANGE (range + COUNT support), XREAD (COUNT/BLOCK/STREAMS, immediate and blocking reads with polling/scheduling, RESP response construction).
Generic command
src/main/java/com/redis/commands/generic/TypeCommand.java
New TYPE command mapping RedisValue.Type (including STREAM) to RESP type strings with arg validation.
Service registration
src/main/resources/META-INF/services/com.redis.commands.ICommand
Register com.redis.commands.generic.TypeCommand, com.redis.commands.stream.XAddCommand, ...XRangeCommand, ...XReadCommand.
Tests
src/test/java/.../TypeCommandTest.java, src/test/java/.../stream/*CommandTest.java, src/main/test/integration_tests.sh
Add unit tests for TYPE, XADD, XRANGE, XREAD and integration test blocks for TYPE and STREAM commands.
Documentation
README.md, docs/commands/TYPE.md, docs/commands/XADD.md, docs/commands/XRANGE.md, docs/commands/XREAD.md
Add TYPE row to README and full docs for TYPE, XADD, XRANGE, XREAD (syntax, semantics, examples).

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Client
participant Server
participant Database
participant Scheduler
Client->>Server: XREAD [COUNT/BLOCK] STREAMS key... id...
alt Immediate data available
Server->>Database: tryRead(keys, ids, count)
Database-->>Server: entries per stream
Server-->>Client: RESP stream entries
else No data and BLOCK specified
Server->>Scheduler: schedulePolling(deadline)
Scheduler->>Database: periodic tryRead(...)
Database-->>Scheduler: entries or none
alt entries found
Scheduler->>Server: deliver entries
Server-->>Client: RESP stream entries
else deadline exceeded
Server-->>Client: RESP nil (timeout)
end
end

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 I hopped in with IDs that tick and flow,
New streams to store each whisper and row.
TYPE checks the burrow, XADD plants a seed,
XRANGE and XREAD fetch the tales we need.
Tests and docs danced — hop, code, go! 🌊✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Title check ⚠️ Warning The PR title 'Added Type Command' is only partially related to the changeset. While TypeCommand is indeed added, the PR also introduces significant stream command functionality (XADD, XRANGE, XREAD), documentation, and tests that are not mentioned in the title. Revise the title to reflect the complete scope, e.g., 'Add Type command and Stream commands (XADD, XRANGE, XREAD)' or focus on the primary change if streams are secondary.
Docstring Coverage ⚠️ Warning Docstring coverage is 8.51% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/main/java/com/redis/commands/generic/TypeCommand.java`:
- Around line 10-15: The Javadoc on TypeCommand incorrectly lists "stream" as a
possible return type; update the TypeCommand class Javadoc to match the actual
returned types (string, list, set, zset, hash, none) or implement STREAM support
if intended. Locate the TypeCommand class and either remove "stream" from the
comment block above the class/TYPE handler or add handling for STREAM in the
type-resolution logic (the method that maps keys to type strings) so the
implementation and Javadoc stay consistent.
🧹 Nitpick comments (1)
src/test/java/com/redis/commands/generic/TypeCommandTest.java (1)

28-33: Consider cleaning test keys to keep DB state isolated.

Since RedisDatabase is a singleton, leftover keys can bleed into other tests. Clearing the keys used in this class in @BeforeEach (or @AfterEach) keeps the suite more deterministic.

🧹 Suggested cleanup
 `@BeforeEach`
 void setUp() {
     command = new TypeCommand();
     mockCtx = mock(ChannelHandlerContext.class);
     db = RedisDatabase.getInstance();
+    db.remove("nonexistent");
+    db.remove("key_str");
+    db.remove("key_list");
+    db.remove("key_set");
+    db.remove("key_hash");
+    db.remove("key_zset");
 }

Comment thread src/main/java/com/redis/commands/generic/TypeCommand.java
unikdahal and others added 2 commits January 26, 2026 17:39
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@unikdahal

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jan 26, 2026

Copy link
Copy Markdown
Contributor
✅ 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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@src/main/java/com/redis/commands/stream/XReadCommand.java`:
- Around line 94-100: The XReadCommand currently skips non-stream keys when
iterating results from db.getValue(key); instead, detect when value != null &&
value.getType() != RedisValue.Type.STREAM and return the Redis WRONGTYPE error
to the client rather than continuing; update the XReadCommand handling to raise
or send the appropriate WRONGTYPE response (using the command/error handling
mechanism your project uses) as soon as a non-stream key is encountered so
behavior matches Redis semantics.
- Around line 109-114: In XReadCommand, do not silently ignore malformed stream
IDs: when calling StreamId.parse(idArg) (the try/catch around lastId =
StreamId.parse(idArg)), catch IllegalArgumentException and instead return or
send a protocol error to the client indicating an invalid stream ID; update the
error path to use the command's response mechanism (rather than continue) so
callers receive an error for the invalid idArg.
🧹 Nitpick comments (5)
src/main/java/com/redis/commands/stream/XReadCommand.java (1)

155-170: Consider checking if the channel is still active before continuing to poll.

If the client disconnects while a blocking read is in progress, the scheduled polling continues until the deadline (potentially indefinitely with BLOCK 0). This wastes resources.

Proposed fix
     private void schedulePolling(ChannelHandlerContext ctx, List<String> keys, List<String> ids, int count, long deadline, RedisDatabase db) {
         ctx.executor().schedule(() -> {
+            if (!ctx.channel().isActive()) {
+                return;
+            }
             if (System.currentTimeMillis() >= deadline) {
                 writeResponse(ctx, RESP_NIL_ARRAY);
                 return;
             }
README.md (1)

52-57: Add blank line before the table to satisfy Markdown lint rules.

The table should be surrounded by blank lines per MD058. Add a blank line between the section heading and the table.

Proposed fix
 ### 🌊 Stream Operations
+
 | Command | Usage | Documentation |
 |:---|:---|:---|
 | `XADD` | `XADD key ID field value [field v ...]` | [XADD.md](./docs/commands/XADD.md) |
 | `XRANGE` | `XRANGE key start end [COUNT c]` | [XRANGE.md](./docs/commands/XRANGE.md) |
 | `XREAD` | `XREAD [COUNT c] [BLOCK ms] STREAMS k [k ...] id [id ...]` | [XREAD.md](./docs/commands/XREAD.md) |
src/test/java/com/redis/commands/stream/XAddCommandTest.java (1)

25-30: Close AutoCloseable returned by openMocks to prevent resource leaks.

MockitoAnnotations.openMocks(this) returns an AutoCloseable that should be closed after tests complete.

Proposed fix using `@AfterEach`
+import org.junit.jupiter.api.AfterEach;
+
 class XAddCommandTest {
 
     `@Mock`
     private ChannelHandlerContext ctx;
 
     private XAddCommand command;
     private RedisDatabase db;
+    private AutoCloseable mocks;
 
     `@BeforeEach`
     void setUp() {
-        MockitoAnnotations.openMocks(this);
+        mocks = MockitoAnnotations.openMocks(this);
         command = new XAddCommand();
         db = RedisDatabase.getInstance();
     }
+
+    `@AfterEach`
+    void tearDown() throws Exception {
+        mocks.close();
+    }
src/test/java/com/redis/commands/stream/XRangeCommandTest.java (1)

23-29: Close AutoCloseable returned by openMocks to prevent resource leaks.

Same issue as XAddCommandTest - the AutoCloseable returned by openMocks should be closed.

Proposed fix
+import org.junit.jupiter.api.AfterEach;
+
 class XRangeCommandTest {
 
     `@Mock`
     private ChannelHandlerContext ctx;
 
     private XRangeCommand command;
     private XAddCommand addCommand;
     private RedisDatabase db;
+    private AutoCloseable mocks;
 
     `@BeforeEach`
     void setUp() {
-        MockitoAnnotations.openMocks(this);
+        mocks = MockitoAnnotations.openMocks(this);
         command = new XRangeCommand();
         addCommand = new XAddCommand();
         db = RedisDatabase.getInstance();
     }
+
+    `@AfterEach`
+    void tearDown() throws Exception {
+        mocks.close();
+    }
src/test/java/com/redis/commands/stream/XReadCommandTest.java (1)

23-29: Close AutoCloseable returned by openMocks to prevent resource leaks.

Same issue as other test files - close the AutoCloseable returned by openMocks.

Proposed fix
+import org.junit.jupiter.api.AfterEach;
+
 class XReadCommandTest {
 
     `@Mock`
     private ChannelHandlerContext ctx;
 
     private XReadCommand command;
     private XAddCommand addCommand;
     private RedisDatabase db;
+    private AutoCloseable mocks;
 
     `@BeforeEach`
     void setUp() {
-        MockitoAnnotations.openMocks(this);
+        mocks = MockitoAnnotations.openMocks(this);
         command = new XReadCommand();
         addCommand = new XAddCommand();
         db = RedisDatabase.getInstance();
     }
+
+    `@AfterEach`
+    void tearDown() throws Exception {
+        mocks.close();
+    }

Comment on lines +94 to +100
RedisValue value = db.getValue(key);
if (value == null) continue;
if (value.getType() != RedisValue.Type.STREAM) {
// In Redis, if one key is not a stream, it might error or skip.
// Usually it errors.
continue;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

WRONGTYPE keys should return an error, not be silently skipped.

Redis returns a WRONGTYPE error if any of the specified keys holds a value that is not a stream. The current implementation silently skips non-stream keys, which deviates from Redis behavior and could mask client bugs.

Proposed fix
             RedisValue value = db.getValue(key);
             if (value == null) continue;
             if (value.getType() != RedisValue.Type.STREAM) {
-                 // In Redis, if one key is not a stream, it might error or skip. 
-                 // Usually it errors.
-                 continue; 
+                return ERR_WRONG_TYPE;
             }
🤖 Prompt for AI Agents
In `@src/main/java/com/redis/commands/stream/XReadCommand.java` around lines 94 -
100, The XReadCommand currently skips non-stream keys when iterating results
from db.getValue(key); instead, detect when value != null && value.getType() !=
RedisValue.Type.STREAM and return the Redis WRONGTYPE error to the client rather
than continuing; update the XReadCommand handling to raise or send the
appropriate WRONGTYPE response (using the command/error handling mechanism your
project uses) as soon as a non-stream key is encountered so behavior matches
Redis semantics.

Comment thread src/main/java/com/redis/commands/stream/XReadCommand.java
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@unikdahal
unikdahal merged commit 996e3ea into main Jan 26, 2026
3 of 4 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request Feb 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant