Skip to content

feat(torii-grpc): cursor based pagination #3147

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 25 commits into from

Conversation

Larkooo
Copy link
Collaborator

@Larkooo Larkooo commented Apr 7, 2025

Summary by CodeRabbit

  • New Features

    • Enhanced query functionality with a new pagination feature. Users can now specify a cursor to retrieve additional results incrementally, allowing for smoother and more efficient data navigation.
    • Introduced new structures for pagination management, including Page, Pagination, and PaginationDirection, improving the handling of paginated data.
    • Updated response structure for entity retrieval to include a cursor for pagination instead of a total count.
  • Bug Fixes

    • Improved handling of cursor representation in API responses, ensuring clarity between the absence of a cursor and an empty cursor string.
    • Added specific error handling for invalid cursor scenarios.
  • Changes

    • Removed the historical parameter from entity retrieval requests, simplifying the request structure.
    • Removed the offset parameter from various request methods, streamlining the API interactions.

Copy link
Contributor

coderabbitai bot commented Apr 7, 2025

Walkthrough

Ohayo, sensei! This update introduces significant changes to the Protocol Buffers definition and the querying logic in the DojoWorld implementation. The Query message has been restructured to support pagination with a new Pagination message, replacing several fields with a single pagination field. Additionally, multiple methods in the DojoWorld now accept an optional Pagination parameter to facilitate efficient data retrieval. The SQL query handling has also been updated for better clarity and functionality. Overall, these changes enhance the querying capabilities while maintaining existing functionalities.

Changes

Files Change Summary
crates/torii/grpc/proto/types.proto Removed fields from Query; added new Pagination, PaginationDirection enum, and updated field names for clarity.
crates/torii/grpc/src/server/mod.rs, crates/torii/grpc/src/types/mod.rs Introduced Pagination parameter to multiple DojoWorld methods; updated query construction to incorporate pagination logic.
crates/torii/sqlite/src/model.rs Updated fetch_entities function to use a single pagination parameter, enhancing handling of pagination and query construction.
crates/torii/sqlite/src/types.rs Added new Page<T>, PaginationDirection, and Pagination structs for structured pagination handling.
crates/torii/client/src/client/mod.rs Modified next_cursor handling in tokens and token_balances methods to represent empty cursors as None.
crates/torii/grpc/proto/world.proto Removed total_count field from RetrieveEntitiesResponse and added next_cursor for pagination.
crates/torii/sqlite/src/error.rs Added InvalidCursor variant to Error enum for specific cursor validation errors.
crates/torii/grpc/src/client.rs Removed historical parameter from retrieve_entities and retrieve_event_messages methods, simplifying request construction.

Sequence Diagram(s)

sequenceDiagram
    participant C as Client
    participant S as GRPC Server
    participant W as DojoWorld
    participant DB as Database

    C->>S: Send query request (with optional pagination)
    S->>W: Call DojoWorld method with pagination parameter
    W->>W: Build query ("WHERE id > cursor" if provided)
    W->>DB: Execute query
    DB-->>W: Return paginated results
    W-->>S: Return results
    S-->>C: Send response with results and cursor info (if applicable)
Loading

Possibly related PRs

  • opt-refactor(torii-core): complete sql schema refactor #2718: The changes in the main PR, which involve significant modifications to the Query message and the introduction of a new Pagination message, are related to the changes in the retrieved PR, as both involve updates to the handling of pagination and query processing in the codebase.
  • refactor(torii-grpc): gzip compression & query opt #2542: The changes in the main PR are related to the modifications in the retrieved PR as both involve significant updates to the handling of pagination and query processing, specifically through the introduction of a Pagination struct and related adjustments in method signatures.

Suggested reviewers

  • glihm

📜 Recent review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro (Legacy)

📥 Commits

Reviewing files that changed from the base of the PR and between 086472a and b339ed6.

📒 Files selected for processing (1)
  • crates/torii/grpc/src/types/mod.rs (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/torii/grpc/src/types/mod.rs
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build

🪧 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 resolve resolve all the CodeRabbit review comments.
  • @coderabbitai plan to trigger planning for file edits and PR creation.
  • @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.

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
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: 1

🧹 Nitpick comments (1)
crates/torii/grpc/src/server/mod.rs (1)

1000-1005: Ohayo sensei, thanks for adding cursor checks in retrieve_entities.
Remember the same numeric vs. string mismatch concerns apply if the ID isn't zero-padded or stored numerically.

Also applies to: 1018-1018, 1043-1043, 1059-1059, 1075-1075, 1091-1091

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 167f417 and fc358b5.

📒 Files selected for processing (3)
  • crates/torii/grpc/proto/types.proto (1 hunks)
  • crates/torii/grpc/src/server/mod.rs (17 hunks)
  • crates/torii/grpc/src/types/mod.rs (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build
🔇 Additional comments (8)
crates/torii/grpc/proto/types.proto (1)

80-80: Ohayo sensei, the new cursor field addition looks straightforward!
This change cleanly enables pagination through a bytes-based cursor.

crates/torii/grpc/src/types/mod.rs (2)

136-137: Ohayo sensei, great job adding the cursor field to enable pagination.
Having a strongly typed Option<Felt> is a clean way to manage cursors.


311-311: Ohayo sensei, the conversion logic for cursor looks good.
Converting the optional Felt into a byte vector or an empty vector when None matches the new proto design.

crates/torii/grpc/src/server/mod.rs (5)

275-275: Ohayo sensei, nice addition of cursor parameter to entities_all.
This extension to support cursor-based pagination will be helpful for large datasets. Just ensure your sorting column is consistently numeric or zero-padded so the pagination is correct.

Also applies to: 288-288


494-516: Ohayo sensei, the same potential issue applies in query_by_keys.
Comparisons with AND {table}.id > ? should be verified if id is stored in a format where lexicographical ordering equals numeric ordering. If not, consider zero-padding all hex IDs or using a numeric column.


776-784: Ohayo sensei, good job including cursor in query_by_composite.
Again, confirm the stored ID format matches the numeric-based filtering you desire.


1229-1229: Ohayo sensei, nice to see the cursor logic integrated into build_composite_clause.
Just ensure the id > cursor comparison doesn't break numeric pagination if your id column is stored in text form.

Also applies to: 1335-1343


355-364:

❓ Verification inconclusive

Ohayo sensei, watch out for string vs. numeric ordering with cursor checks.
In query_by_hashed_keys, lines like AND {table}.id > ? may lead to unexpected results if the id column is stored as a text type. If your IDs vary in hex length, strictly lexicographical comparison can break expected numeric ordering.

Would you like to verify the column type and zero-padding logic? For example, here's a shell script to search your migrations or DDL for how id is created:

Also applies to: 366-374, 377-384


🏁 Script executed:

#!/bin/bash
# Searching references to table creation or 'id' column type for potential string-based storage
rg -A 10 "CREATE TABLE.*entities" 
rg -B 3 -A 3 "id "

Length of output: 125411


Ohayo sensei – please double-check your hex formatting for ID ordering!

Our migration output confirms that the entities table (and similar tables) declares the id column as TEXT (e.g. in crates/torii/migrations/20231127235011_entity_model.sql and others). This means that SQL comparisons like AND {table}.id > ? will use lexicographical ordering. If your IDs are generated via format!("{:#x}", …), they might vary in length unless you apply zero-padding to a fixed width. This could lead to unexpected order if, for example, a shorter hex string is considered “smaller” than a longer one even when its numeric value is greater.

Please verify that your hex formatter produces consistently fixed-width (zero-padded) values or consider casting/converting the value appropriately in your query. This concern also applies to similar queries at lines 366–374 and 377–384.

@@ -649,6 +640,7 @@ impl DojoWorld {
order_by: Option<&str>,
entity_models: Vec<String>,
entity_updated_after: Option<String>,
cursor: Option<Felt>,
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Ohayo sensei, cursor-based filtering in query_by_member is solid, but double-check the ID comparison.
If table.id is stored as a non-zero-padded string, AND {table}.id > :cursor might not compare numerically.

Consider storing IDs as a consistently-sized hex string or numeric type to avoid ordering confusion.

Also applies to: 735-738

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: 1

🧹 Nitpick comments (3)
crates/torii/sqlite/src/model.rs (2)

350-350: Consider initializing with capacity.

When you know you'll be adding items to a vector, it's more efficient to initialize it with a capacity.

-    let mut all_rows = Vec::new();    
+    let mut all_rows = Vec::with_capacity(pagination.limit.unwrap_or(100) as usize);    

386-432: Cursor-based pagination implementation is robust.

The implementation handles both directions of pagination and supports custom ordering when needed. The code correctly constructs SQL conditions based on cursor values and pagination direction.

However, there's potential to simplify the cursor parsing logic:

-            let cursor = pagination.cursor.as_ref().unwrap();
-            let cursor_values: Vec<&str> = cursor.split(',').collect();
+            let cursor_values: Vec<&str> = pagination.cursor.as_ref().unwrap().split(',').collect();
crates/torii/sqlite/src/types.rs (1)

290-296: Comprehensive Pagination struct.

This struct nicely encapsulates all the necessary components for flexible pagination:

  • Optional cursor for continuing from a specific point
  • Optional limit for controlling page size
  • Direction for forward/backward navigation
  • Vector of OrderBy for custom sorting

Consider adding default values for common fields:

 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
+#[derive(Default)]
 pub struct Pagination {
     pub cursor: Option<String>,
     pub limit: Option<u32>,
-    pub direction: PaginationDirection,
+    pub direction: PaginationDirection,
     pub order_by: Vec<OrderBy>,
 }

+impl Default for PaginationDirection {
+    fn default() -> Self {
+        Self::Forward
+    }
+}
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro (Legacy)

📥 Commits

Reviewing files that changed from the base of the PR and between d1e0eb4 and c0f44cb.

📒 Files selected for processing (2)
  • crates/torii/sqlite/src/model.rs (4 hunks)
  • crates/torii/sqlite/src/types.rs (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
crates/torii/sqlite/src/model.rs (3)
crates/torii/sqlite/src/executor/mod.rs (8)
  • sqlx (312-312)
  • sqlx (447-447)
  • sqlx (533-533)
  • sqlx (562-562)
  • sqlx (627-627)
  • sqlx (714-714)
  • new (168-170)
  • new (243-269)
crates/torii/graphql/src/query/mod.rs (1)
  • e (67-81)
crates/torii/sqlite/src/lib.rs (3)
  • e (914-918)
  • model (513-515)
  • new (65-72)
🪛 GitHub Actions: ci
crates/torii/sqlite/src/model.rs

[error] 1-1: Rust formatting check failed. Run 'rustfmt' to format the code according to style guidelines.

🔇 Additional comments (11)
crates/torii/sqlite/src/model.rs (7)

16-16: Ohayo! Great work on adding these new imports for pagination.

The imports correctly include all necessary types for the new pagination feature.


295-297: Nice API simplification, sensei!

Refactoring the function signature to use a single Pagination parameter instead of multiple individual parameters makes the API cleaner and more maintainable. The return type change to Page<SqliteRow> nicely aligns with the cursor-based pagination approach.


312-312: Good string interpolation update.

Using format string with interpolation for constructing path names is cleaner than the previous approach.


317-317: SQL injection protection improvement!

Using string interpolation with square brackets for table and column names provides better protection against SQL injection. This is a security improvement over string concatenation.

Also applies to: 327-327


334-348: Well-structured order_by clause construction.

The logic for building the order_by_clause handles both default and custom ordering gracefully. The default ordering by event_id and id ensures consistent pagination results when no specific ordering is requested.


376-379: SQL query construction looks good.

The formatted SQL query properly uses the selections and joins clauses.


440-448: Pagination and ordering applied correctly.

The code correctly applies the ordering and limit clauses based on the pagination parameters.

crates/torii/sqlite/src/types.rs (4)

278-282: Well-designed Page struct, sensei!

The Page<T> struct is a clean and generic implementation for paginated results. The inclusion of next_cursor enables efficient cursor-based pagination without requiring offset calculations.


284-288: Clear pagination direction enum.

The PaginationDirection enum provides a semantic way to specify navigation direction in paginated results.


298-302: Standard OrderDirection enum.

The enum provides clear semantics for sorting direction.


304-309: Well-structured OrderBy struct.

This struct provides a clear way to specify ordering criteria with model, member, and direction.

Comment on lines 459 to 504
if let Some(limit) = pagination.limit {
let requested_limit = limit - 1; // Number of rows user actually wants
let (items, next_cursor) = if all_rows.len() > requested_limit as usize {
let extra_row = all_rows.len() == limit as usize;
let items: Vec<_> = all_rows.drain(..requested_limit as usize).collect(); // Take only requested rows

let next_cursor = if extra_row {
let last_row = &items[items.len() - 1]; // Last row of items (not extra row)
let cursor_values = if pagination.order_by.is_empty() {
vec![
last_row.get::<String, &str>("event_id").to_string(),
last_row.get::<String, &str>("id").to_string(),
]
} else {
let mut values = vec![last_row.get::<String, &str>("id").to_string()];
values.extend(pagination.order_by.iter().map(|order| {
let column = format!("{}.{}", order.model, order.member);
last_row.get::<String, &str>(&column).to_string()
}));
values
};
Some(cursor_values.join(","))
} else {
query += &format!(" ORDER BY {}.event_id DESC", table_name);
}
None
};

if let Some(limit) = limit {
query += &format!(" LIMIT {}", limit);
match pagination.direction {
PaginationDirection::Forward => (items, next_cursor),
PaginationDirection::Backward => (items.into_iter().rev().collect(), next_cursor),
}

if let Some(offset) = offset {
query += &format!(" OFFSET {}", offset);
} else {
let items = all_rows; // Take all rows if fewer than requested
match pagination.direction {
PaginationDirection::Forward => (items, None),
PaginationDirection::Backward => (items.into_iter().rev().collect(), None),
}
};

// Execute main query
let mut stmt = sqlx::query(&query);
for value in &bind_values {
stmt = stmt.bind(value);
}
let chunk_rows = stmt.fetch_all(pool).await?;
all_rows.extend(chunk_rows);
}
Ok(Page { items, next_cursor })
} else {
let items = match pagination.direction {
PaginationDirection::Forward => all_rows,
PaginationDirection::Backward => all_rows.into_iter().rev().collect(),
};
Ok(Page { items, next_cursor: None })
}
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Thorough handling of pagination results.

Ohayo, sensei! The code elegantly:

  1. Limits results to one more than requested to determine if there's a next page
  2. Constructs the next cursor based on the last row
  3. Handles result direction based on the pagination direction

One potential issue to verify:


🏁 Script executed:

#!/bin/bash
# Verify if there are any usages of the fetch_entities function that might still expect the old return type
rg -A 3 -B 3 "fetch_entities\(" --type rust

Length of output: 2118


Ohayo, sensei! Update on Pagination Handling & fetch_entities Return Type

Your implementation in crates/torii/sqlite/src/model.rs (lines 459–504) for managing pagination is elegant:

  • It correctly limits results to one more than requested to detect if there's a next page.
  • It builds the next cursor based on the last row.
  • It respects the pagination direction when returning results.

However, our verification reveals that fetch_entities is still being invoked in several places (e.g., in crates/torii/grpc/src/server/mod.rs) with tuple destructuring like:

let (rows, total_count) = fetch_entities(...);

This suggests that these call sites might still be expecting the old return type. Please review and update these usages to correctly handle the new Page struct return type from fetch_entities.

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: 2

🧹 Nitpick comments (7)
crates/torii/grpc/src/types/mod.rs (2)

320-327: Use string interpolation instead of format! when appropriate

In the collect_columns function, there are multiple uses of format! that could be simplified using string interpolation.

-                    let new_path = if path.is_empty() {
-                        format!("{}", i)
-                    } else {
-                        format!("{}.{}", path, i)
-                    };
+                    let new_path = if path.is_empty() {
+                        i.to_string()
+                    } else {
+                        format!("{}.{}", path, i)
+                    };

Similarly for other format! calls with simple substitutions.


319-327: Check consistency of table and column escaping

There's inconsistency in how SQL identifiers are escaped across the codebase. In some places, square brackets are used, while in others, double quotes are used.

Consider adopting a consistent approach for SQL identifier escaping throughout the codebase, either using square brackets consistently (for SQLite) or using a helper function that handles the escaping appropriately.

crates/torii/grpc/proto/types.proto (1)

193-197: Ohayo sensei, nice to see PaginationDirection introduced!
Forward/backward pagination is a key improvement for flexible data retrieval. Make sure callers handle both directions consistently and confirm that the default direction is properly documented.

crates/torii/grpc/src/server/mod.rs (4)

145-158: Ohayo sensei, the From<proto::types::Pagination> implementation is neat.
Mapping empty string to None for cursor is a clean approach. Also, ensuring limit == 0 gets converted to None is a good way to avoid confusing logic downstream. The usage of unreachable!() is fine but remember to handle unexpected cases gracefully in production.


445-543: Ohayo sensei, query_by_keys extends consistent pagination too!

  1. Regex-based searching: Keep an eye out for performance overhead with the REGEXP approach, especially on large tables.
  2. Model and key filtering: Combining them into the OR/NOT IN statement is clever, but watch out for complex queries that might balloon in cost.
  3. Pagination: The code reuses the same standardized approach for limit/cursor ordering.

You might consider using a more specialized indexing approach if performance becomes an issue.


1556-1556: Ohayo sensei, streaming response with remaining_count is a nice touch.
This extra context in the response can help clients track when they're almost done receiving data.


47-47: Ohayo sensei, formatting alert!
The pipeline warns about a formatting issue. Please run rustfmt to keep the code consistent and pass CI.

🧰 Tools
🪛 GitHub Actions: ci

[warning] 47-47: Formatting issue detected. Please run 'rustfmt' to format the code.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro (Legacy)

📥 Commits

Reviewing files that changed from the base of the PR and between c0f44cb and 701cdb4.

📒 Files selected for processing (6)
  • crates/torii/grpc/proto/types.proto (2 hunks)
  • crates/torii/grpc/proto/world.proto (1 hunks)
  • crates/torii/grpc/src/server/mod.rs (18 hunks)
  • crates/torii/grpc/src/types/mod.rs (3 hunks)
  • crates/torii/sqlite/src/error.rs (1 hunks)
  • crates/torii/sqlite/src/model.rs (6 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
crates/torii/grpc/src/server/mod.rs (1)
crates/torii/sqlite/src/model.rs (20)
  • pagination (529-537)
  • new (39-73)
  • fetch_entities (290-547)
  • row (135-135)
  • row (139-139)
  • row (143-143)
  • row (147-147)
  • row (151-151)
  • row (160-160)
  • row (164-164)
  • row (168-168)
  • row (172-172)
  • row (182-182)
  • row (192-192)
  • row (200-200)
  • row (204-204)
  • row (212-212)
  • row (220-220)
  • row (228-228)
  • i (425-430)
🪛 GitHub Actions: ci
crates/torii/grpc/src/server/mod.rs

[warning] 47-47: Formatting issue detected. Please run 'rustfmt' to format the code.

🔇 Additional comments (21)
crates/torii/sqlite/src/error.rs (1)

23-24: Ohayo, sensei! Good addition of a specific error for pagination

Adding the InvalidCursor error variant is crucial for providing clear feedback when cursor-based pagination encounters issues with malformed or invalid cursor values.

crates/torii/sqlite/src/model.rs (8)

4-5: Ohayo! Good addition of base64 dependency

Adding the base64 dependency is appropriate for encoding/decoding cursor values in a URL-safe format.


18-18: Nice comprehensive imports for pagination support

The imports correctly include all the necessary types for the new pagination implementation, organizing them logically.


290-300: Ohayo, sensei! Function signature updated for cursor-based pagination

The function signature has been updated to accept a Pagination parameter instead of separate pagination parameters, making the API more cohesive and extensible.

Note that this change might require updates to call sites that expect the old return type (a tuple of rows and count).


352-375: Well-implemented pagination direction handling

The code properly handles both forward and backward pagination by adjusting the order direction based on the pagination direction. This ensures consistent results regardless of pagination direction.


398-443: Ohayo! Thorough cursor parsing and condition building

This implementation carefully:

  1. Decodes the cursor using base64
  2. Parses the JSON values
  3. Builds appropriate WHERE conditions based on order direction and pagination direction
  4. Properly handles multi-column ordering with equality conditions for previous columns

The error handling for invalid cursors is also appropriate.


479-499: Great SQL injection prevention with parameterized queries

The code properly binds all values from both the original bind_values and the cursor_bind_values, preventing SQL injection vulnerabilities.


508-523: Effective "peek-ahead" pagination implementation

Fetching one extra item to determine if there's a next page is an efficient approach. The code properly truncates the result to the original limit and handles result direction correctly.


526-546: Well-structured next cursor generation

The code efficiently:

  1. Checks if we have enough results to warrant a next cursor
  2. Extracts the relevant values from the last row based on order_by fields
  3. Serializes and encodes the values properly using base64

This approach ensures consistent pagination behavior.

crates/torii/grpc/src/types/mod.rs (3)

22-33: Ohayo, sensei! Well-designed pagination types

The new PaginationDirection enum and Pagination struct are well-designed for supporting cursor-based pagination. The struct includes all necessary fields (cursor, limit, direction, order_by) for implementing efficient pagination.


35-44: Clean conversion implementation for protocol buffers

The From<Pagination> implementation correctly converts the Rust types to their protocol buffer equivalents. Using unwrap_or_default() for the cursor ensures that null cursors are handled properly.


146-157: Improved field naming in Query struct

Renaming:

  • dont_include_hashed_keys to no_hashed_keys
  • entity_models to models

These changes improve code readability and make the API more intuitive. The comment about hashed keys is still relevant and provides useful context.

crates/torii/grpc/proto/types.proto (2)

74-76: Ohayo sensei, new pagination fields look healthy!
The addition of no_hashed_keys, models, and pagination centralizes query control in one place. This improves maintainability and ensures queries are standardized. No immediate concerns here.


199-203: Ohayo sensei, Pagination struct design is straightforward!
Including cursor, limit, and order_by is a standard approach. The repeated OrderBy is especially handy for multi-column ordering. Great job setting it up.

crates/torii/grpc/src/server/mod.rs (7)

50-50: Ohayo sensei, good addition for pagination imports.
The direct import of Pagination, PaginationDirection, etc., simplifies usage throughout this file.


160-172: Ohayo sensei, the From<proto::types::OrderBy> converter is well-structured!
Mapping numeric values to OrderDirection and using unreachable!() is fine, though be aware of potential unknown values from older clients.


298-301: Ohayo sensei, new parameters in entities_all enhance uniformity!
Allowing pagination, no_hashed_keys, and models keeps the interface symmetrical with other query methods.


356-443: Ohayo sensei, query_by_hashed_keys changes look powerful!

  1. Pagination: Great job incorporating the Pagination struct. Having a single approach for limit/cursor looks consistent with the rest of the codebase.
  2. no_hashed_keys: The option to remove hashed keys from results is a neat privacy feature—just ensure this behavior is tested somewhere.
  3. Multiple models: The having_clause that checks for model presence is logical.
  4. Cursor-based logic: fetch_entities usage is consistent with your new pagination rules.

545-558: Ohayo sensei, query_by_member method is succinct.
Exposing a single pagination parameter and reusing the same fetch logic fosters DRY code. The direct mapping of member_clause to SQL columns is straightforward, just ensure you handle potential name collisions or reserved keywords.


669-723: Ohayo sensei, query_by_composite is well-handled.
The recursive approach in build_composite_clause is quite flexible for complex queries. Good job reusing the same pagination approach for these advanced queries.


905-917: Ohayo sensei, requiring pagination in retrieve_entities is a strong design choice.
Forcing the caller to provide pagination ensures consistent usage across all queries. This should reduce confusion and unify query patterns.

@@ -243,7 +243,7 @@ message RetrieveEventMessagesRequest {

message RetrieveEntitiesResponse {
repeated types.Entity entities = 1;
uint32 total_count = 2;
string next_cursor = 2;
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Ohayo! API change from count-based to cursor-based pagination

This change from total_count to next_cursor represents a shift to more efficient cursor-based pagination, which is excellent for performance with large datasets. However, this is a breaking change for API consumers who might rely on knowing the total count of results.

Consider if you need a transitional period or additional documentation to help clients adapt to this API change. Many frontend developers rely on total counts for showing pagination UI (like "Page 1 of 10").

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: 3

🔭 Outside diff range comments (1)
crates/torii/grpc/src/client.rs (1)

238-244: 💡 Verification agent

🧩 Analysis chain

Ohayo! Similar improvement for retrieve_event_messages method

Good consistency in applying the same pattern to retrieve_event_messages as you did with retrieve_entities. The historical parameter has been properly moved into the Query struct.


🏁 Script executed:

#!/bin/bash
# Verify all callers of retrieve_event_messages have been updated

echo "Checking calls to retrieve_event_messages..."
rg -A 3 -B 3 "retrieve_event_messages\(" --type rust

Length of output: 2127


Ohayo, Sensei! Retrieve Event Messages Invocation Update Needed

Great work updating the implementation in crates/torii/grpc/src/client.rs to use the Query struct—this mirrors the improvements made for retrieve_entities, and the historical parameter has indeed been encapsulated into the Query. However, I noticed that in crates/torii/client/src/client/mod.rs the method is still being invoked with two parameters (query, historical). Please update this call to construct and pass a single Query object so that it matches the new function signature.

  • Ensure that the call in crates/torii/client/src/client/mod.rs is updated to pass one parameter (the Query struct with the historical flag included).
  • Verify that any other invocations of retrieve_event_messages follow the new pattern for consistent behavior.

Thanks, Sensei!

♻️ Duplicate comments (1)
crates/torii/grpc/proto/world.proto (1)

242-242: Ohayo! API change from count-based to cursor-based pagination

This change from total_count to next_cursor represents a shift to more efficient cursor-based pagination, which is excellent for performance with large datasets. However, this is a breaking change for API consumers who might rely on knowing the total count of results.

Consider if you need a transitional period or additional documentation to help clients adapt to this API change. Many frontend developers rely on total counts for showing pagination UI (like "Page 1 of 10").

🧹 Nitpick comments (7)
crates/torii/grpc/src/server/mod.rs (7)

314-327: Document or refine the “no order by for historical entities” policy.
You're returning an error if pagination.order_by is set for historical queries. Explain why or consider partial support if needed.


328-407: Consider indexing event_id for performance.
Ohayo sensei, for large historical queries, an index on event_id could speed up sorting and filtering.


409-486: Consolidate _historical checks across query methods.
This pattern of branching to fetch_historical_entities is repeated in multiple queries. Consider unifying the logic to reduce duplication.


489-569: Refactor the repeated checks into a shared helper.
Again, the _historical logic is nearly the same as in other queries. A shared function could remove duplication.


579-693: Streamline query-by-member with other patterns.
Ohayo sensei, this code also echoes the _historical fallback and repeated steps from other queries.


696-749: Unify composite query approach.
This code closely mirrors the same logic for fetching, pagination, and historical checks used elsewhere.


1605-1627: Clarify remaining_count usage.
Ohayo sensei, if streaming partial results with pagination, consider clarifying that remaining_count is just for the current page items, not the total across the entire dataset.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro (Legacy)

📥 Commits

Reviewing files that changed from the base of the PR and between d24971d and 9aa3f36.

📒 Files selected for processing (6)
  • crates/torii/grpc/proto/types.proto (2 hunks)
  • crates/torii/grpc/proto/world.proto (1 hunks)
  • crates/torii/grpc/src/client.rs (1 hunks)
  • crates/torii/grpc/src/server/mod.rs (18 hunks)
  • crates/torii/grpc/src/types/mod.rs (3 hunks)
  • crates/torii/sqlite/src/error.rs (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/torii/grpc/src/types/mod.rs
🧰 Additional context used
🧬 Code Graph Analysis (1)
crates/torii/grpc/src/client.rs (1)
crates/torii/grpc/src/server/mod.rs (1)
  • retrieve_event_messages (1341-1359)
🪛 GitHub Actions: ci
crates/torii/grpc/src/server/mod.rs

[warning] 47-47: Formatting issue detected. Please run 'rustfmt' to format the code.

🔇 Additional comments (12)
crates/torii/sqlite/src/error.rs (2)

23-24: Ohayo! Good addition of specific cursor error handling

Adding a dedicated error variant for invalid cursors makes error handling more precise and improves API clarity by allowing consumers to specifically handle cursor-related issues.


49-50: Enhancing error reporting with dynamic messages, nice work sensei!

Upgrading the UnsupportedQuery variant to accept a String parameter improves error reporting by allowing for more specific error messages tailored to each unsupported query scenario.

crates/torii/grpc/proto/types.proto (3)

74-77: Ohayo! Well-structured Query message update

The reorganization of the Query message with dedicated fields for pagination-related concerns is a good design improvement, sensei. Moving historical into the Query message itself aligns with the client API changes and centralizes query parameters.


195-198: Nice addition of pagination direction enum

Adding a dedicated enum for pagination direction improves type safety and API clarity. The FORWARD/BACKWARD values make the intent clear for cursor-based navigation.


200-205:

✅ Verification successful

Excellent modularization with dedicated Pagination message

Centralizing pagination parameters into a dedicated message type makes the API more cohesive and follows good design principles. This structured approach will make future extensions to pagination capabilities easier, sensei.


🏁 Script executed:

#!/bin/bash
# Verify that the new Pagination message is properly used in relevant files

echo "Checking usage of Pagination type..."
rg -A 2 -B 2 "Pagination" --type rust

Length of output: 11707


Ohayo, sensei! Fantastic job on the modularization.
Your dedicated Pagination message in crates/torii/grpc/proto/types.proto (lines 200-205) is spot-on. The recent verification confirms that its usage is consistently implemented across key modules—including conversion routines in crates/torii/grpc/src/types/mod.rs, query handling in crates/torii/grpc/src/server/mod.rs, and in the SQLite integration. This well-structured approach not only adheres to sound design principles but also paves the way for seamless future pagination enhancements. Keep it up, sensei!

crates/torii/grpc/src/server/mod.rs (7)

50-50: No issues with the imports.
These imports appear to be used throughout the file, so everything looks good.


298-301: Function signature update looks good.
Adding pagination, no_hashed_keys, and models is coherent with the new logic.


1273-1274: Building the composite WHERE clause looks solid.
Ohayo sensei, the OR/AND logic is clear, and no issues are detected here.


1321-1339: Revised retrieve_entities is coherent.
The integration of pagination lines up perfectly with the internal query logic.


1341-1359: New pagination integration for retrieve_event_messages is good.
This parallels the retrieve_entities approach, ensuring consistent usage.


1361-1374: Revised retrieve_events with query object is fine.
No immediate concerns; the offset/limit logic remains straightforward.


47-47:

❓ Verification inconclusive

Ohayo sensei, please run rustfmt.
The pipeline complains about formatting at line 47. Running rustfmt will align your code with Rust style conventions.

Here is a script to ensure formatting is correct:


🏁 Script executed:

#!/bin/bash
cargo fmt -- --check

Length of output: 118


Ohayo sensei, please verify rustfmt check!
It looks like our attempt to run cargo fmt -- --check hit a snag with a "command not found" error—suggesting the Rust toolchain isn’t available in the current environment. Could you please manually verify that the code in crates/torii/grpc/src/server/mod.rs (line 47) is formatted according to Rust style conventions? Alternatively, ensure that your CI pipeline has the Rust toolchain installed so that rustfmt can run correctly.

🧰 Tools
🪛 GitHub Actions: ci

[warning] 47-47: Formatting issue detected. Please run 'rustfmt' to format the code.

Comment on lines +230 to 231
let request = RetrieveEntitiesRequest { query: Some(query.into()) };
self.inner.retrieve_entities(request).await.map_err(Error::Grpc).map(|res| res.into_inner())
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Simplified API by removing the standalone historical parameter

Moving the historical field into the Query struct itself makes the API more consistent and easier to maintain, sensei. This is a good refactoring that reduces parameter sprawl.


🏁 Script executed:

#!/bin/bash
# Verify all callers of retrieve_entities have been updated to use the Query.historical field

echo "Checking calls to retrieve_entities..."
rg -A 3 -B 3 "retrieve_entities\(" --type rust

Length of output: 2065


Ohayo sensei, API refactoring requires an update to caller usage.

The refactor in crates/torii/grpc/src/client.rs—where the historical flag has been moved into the Query struct—is a great step toward simplifying the API and reducing parameter sprawl. However, our verification shows that in crates/torii/client/src/client/mod.rs the call to retrieve_entities still passes two parameters (i.e., query and a separate historical flag). Please update that caller to integrate the historical value into the Query before passing it to retrieve_entities.

  • File: crates/torii/client/src/client/mod.rs
    Action: Change the call from
    grpc_client.retrieve_entities(query, historical).await?
    to something like
    grpc_client.retrieve_entities(query_with_historical).await?,
    where query_with_historical is a Query that includes the appropriate historical flag.

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: 2

♻️ Duplicate comments (1)
crates/torii/grpc/src/server/mod.rs (1)

149-161: 🛠️ Refactor suggestion

Ohayo sensei! Consider avoiding unreachable!() for invalid pagination directions.
Right now, an unexpected direction panics. Returning an error instead prevents unwarranted panics if the client passes invalid data.

Here’s a potential minimal fix:

-match value.direction {
-    0 => PaginationDirection::Forward,
-    1 => PaginationDirection::Backward,
-    _ => unreachable!(),
-}
+let dir = match value.direction {
+    0 => PaginationDirection::Forward,
+    1 => PaginationDirection::Backward,
+    _ => {
+        // Return an error or default direction
+        return Self {
+            cursor: None,
+            limit: None,
+            direction: PaginationDirection::Forward,
+            order_by: vec![],
+        };
+    }
+};
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro (Legacy)

📥 Commits

Reviewing files that changed from the base of the PR and between 9aa3f36 and fd3a6cf.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (3)
  • crates/torii/grpc/Cargo.toml (1 hunks)
  • crates/torii/grpc/src/server/mod.rs (21 hunks)
  • crates/torii/sqlite/src/model.rs (4 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build
🔇 Additional comments (12)
crates/torii/grpc/Cargo.toml (1)

31-31: Ohayo sensei! Great addition of the base64 dependency.
This inclusion is essential for the new cursor encoding logic. No issues spotted here.

crates/torii/sqlite/src/model.rs (4)

1-6: Ohayo sensei! Import statements look solid.
These newly added imports for base64 and Pagination-related types facilitate cursor-based pagination. Great job.

Also applies to: 19-19


301-460: Ohayo sensei! Pagination logic stands out as neat and efficient.
You're correctly handling the following:

  • Distinguishing the limit and reversed rows for backward pagination.
  • Building the next cursor from the last retrieved row.
  • Properly chunking schemas to avoid excessive JOINs.

Everything looks logically consistent. One minor suggestion: ensure all edge cases with minimal or zero rows after filtering are tested, especially if pagination.limit is small.


462-543: Ohayo sensei! These helper functions for cursor conditions and query building look clean.
They neatly handle the composition of various conditions (WHERE, HAVING, etc.) and safely manage cursor-based comparisons. Kudos for the careful string formatting that escapes table and column names.


545-557: Ohayo sensei! Good approach for extracting cursor values.
Using the event_id as a fallback is a straightforward mechanism for tracking the paging offset when no ordering fields are specified. This looks sound for forward and backward direction handling. Keep it up!

crates/torii/grpc/src/server/mod.rs (7)

16-17: Ohayo sensei! Imports for base64 cursor logic are correct.
No concerns: these lines properly bring in the standard Base64 engine.


53-53: Ohayo sensei! Adding Token and TokenBalance types.
This import alignment is consistent with the rest of the codebase’s approach.


298-305: Ohayo sensei! Good adaptation of entities_all to require pagination.
Ensuring direct calls to this function supply a valid Pagination struct fosters a consistent approach to retrieving data.


318-415: Ohayo sensei! Historical entities reject order_by, which is consistent with the logic.
This code properly returns an error if pagination.order_by is used. Looks coherent for the domain. Good call.


417-496: Ohayo sensei! query_by_hashed_keys nicely integrates the new pagination logic.
Everything from the where_clause composition down to the chunk-based retrieval with fetch_entities is well-structured.


498-581: Ohayo sensei! query_by_keys seamlessly extends the same pagination approach.
The combined usage of regex for partial key matching and model filtering is well-handled. Keep it up!


583-697: Ohayo sensei! query_by_member, query_by_composite, and the final internal transformations look organized.
This set of changes harmonizes well with the code’s overall pagination structure. Nicely done.

Comment on lines +298 to +300
pagination: Pagination,
bind_values: Vec<String>,
) -> Result<(Vec<sqlx::sqlite::SqliteRow>, u32), Error> {
// Helper function to collect columns (existing implementation)
) -> Result<Page<SqliteRow>, Error> {
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Ohayo sensei! Confirm all old calls to fetch_entities are updated.
The introduction of pagination: Pagination modifies the function signature. Ensure that any existing call sites have been revised to supply a proper Pagination object.

Would you like to run a quick search to confirm that no call sites remain that pass the old parameter list?


🏁 Script executed:

#!/bin/bash
# Searching all calls to fetch_entities to ensure they have updated parameters
rg -A 3 -B 3 "fetch_entities\(" --type rust

Length of output: 2009


Ohayo sensei!
Our grep search indicates that the call sites in crates/torii/grpc/src/server/mod.rs still invoke fetch_entities with only three parameters (the pool, schemas, and table) rather than the new signature that requires a Pagination object (and a Vec<String> for bind values). Please update these call sites accordingly.

  • Crates/torii/grpc/src/server/mod.rs:
    • Several calls to fetch_entities (lines shown in grep output) need to be revised to include a proper Pagination instance and the corresponding bind_values argument.

Comment on lines +164 to +176
impl From<proto::types::OrderBy> for OrderBy {
fn from(value: proto::types::OrderBy) -> Self {
OrderBy {
model: value.model,
member: value.member,
direction: match value.direction {
0 => OrderDirection::Asc,
1 => OrderDirection::Desc,
_ => unreachable!(),
},
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Ohayo sensei! Same recommendation: avoid unreachable!() for OrderBy direction.
Like pagination direction, returning an error or default is safer than a panic for unexpected input.

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

♻️ Duplicate comments (1)
crates/torii/grpc/src/server/mod.rs (1)

148-175: 🛠️ Refactor suggestion

Implementing From<proto::types::Pagination> and From<proto::types::OrderBy>.

  1. Translating proto fields to local Pagination structure is neat.
  2. Using unreachable!() on invalid direction might cause a panic if clients send unrecognized values. Consider returning an error or default direction to avoid runtime panics.
- _ => unreachable!(),
+ _ => {
+   // Return an error or default
+   return Self {
+       cursor: None,
+       limit: None,
+       direction: PaginationDirection::Forward,
+       order_by: vec![],
+   };
+ }
🧹 Nitpick comments (2)
crates/torii/sqlite/src/model.rs (1)

516-523: Combine multiple WHERE clauses.

combine_where_clauses extends an existing base condition with any cursor-specific conditions. This is straightforward and helps keep the logic modular.

Consider logging or debugging the final where_clause if helpful for diagnosing complex queries in production.

crates/torii/grpc/src/server/mod.rs (1)

1031-1044: Events retrieval still partially offset-based.

While cursor-based logic is used across entities, events appear to keep offset-based logic. That’s presumably an intentional design difference. If you want to unify them, consider future refactoring.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro (Legacy)

📥 Commits

Reviewing files that changed from the base of the PR and between fd3a6cf and bf85976.

📒 Files selected for processing (4)
  • crates/torii/grpc/proto/world.proto (3 hunks)
  • crates/torii/grpc/src/client.rs (1 hunks)
  • crates/torii/grpc/src/server/mod.rs (28 hunks)
  • crates/torii/sqlite/src/model.rs (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/torii/grpc/src/client.rs
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build
🔇 Additional comments (23)
crates/torii/sqlite/src/model.rs (9)

1-19: Ohayo sensei! Importing additional types for pagination.

The new imports for HashSet, base64, and pagination types appear logically consistent with the pagination features introduced. Everything looks good here.


298-301: Ohayo sensei! Enhanced function signature for fetch_entities.

Adding pagination: Pagination and returning a Result<Page<SqliteRow>, Error> is a neat approach. This unifies multiple parameters (like limit/offset) into a single struct and returns a more descriptive Page.


341-342: Set safer defaults for limits.

Using pagination.limit.unwrap_or(100) ensures we don’t retrieve an unbounded set of rows. Appending + 1 to detect if there is a “next page” is a neat trick.


344-366: Ohayo sensei! Building the order_clause logic with pagination direction.

  1. The fallback to format!("{table_name}.event_id DESC") when no order_by is specified is wise, preventing unpredictable ordering.
  2. When order_by is present, flipping ASC/DESC based on PaginationDirection is a smooth solution.

Everything looks coherent and correct.


368-384: Neat base64 cursor decoding and validation.

  1. Successfully handling base64 decoding with error checks is essential.
  2. Splitting the encoded string with '/' is neat, as the final join can be re-encoded for the next cursor.

All good.


386-420: Chunked schema processing and bridging to pagination.

  1. Splitting the schemas into chunks ensures queries stay within reasonable join limits (MAX_JOINS).
  2. Generating a combined “WHERE” condition including cursor checks is orderly.
  3. Neatly truncating results if they exceed fetch_limit to detect “has_more.”

This approach is carefully structured, sensei!


462-514: Ohayo sensei! build_cursor_conditions meticulously handles multiple order-by columns.

  1. Verifying cursor length with expected_len is a solid error check.
  2. Using different comparison operators for forward vs. backward pagination is a clear solution.
  3. Handling multi-column ordering with the clever “(previous columns = ?) AND (current column operator ?)” logic is a highlight of robust design.

This function strongly underpins correct cursor-based pagination.


525-543: Ohayo sensei! Constructing queries in build_query.

  1. Dynamically assembling WHERE and HAVING ensures clarity.
  2. Finishing with GROUP BY and ORDER BY lines is consistent with the rest of the code.

Everything looks consistent.


545-556: build_cursor_values elegantly extracts the next cursor from the row.

  1. Returning only event_id when no order_by is specified is a consistent fallback.
  2. Collecting multiple columns in order_by scenario is well-handled.

Nice job, sensei!

crates/torii/grpc/proto/world.proto (3)

102-102: Ah, shifting to cursor-based pagination for RetrieveTokens.

Replacing offset-based logic with string cursor is a standard improvement for large-scale paging. Looks good.


148-148: Cursor-based pagination for RetrieveTokenBalances.

Continuing the same pattern with cursor = 5; is consistent with the token retrieval changes.


235-235: Ohayo sensei! Replacing total_count with string next_cursor.

Cursor-based approach in RetrieveEntitiesResponse is more scalable for big data sets. Just ensure frontends are aware they lose direct total counts.

crates/torii/grpc/src/server/mod.rs (11)

15-16: Ohayo sensei! Base64 convenience.

Using BASE64_STANDARD_NO_PAD plus Engine is consistent with your decoding logic in sqlite::model.


297-304: Refined entities_all method signature.

Adding Pagination and returning Page<proto::types::Entity> is consistent with the overall shift to cursor-based retrieval. This also helps unify logic across the codebase.


317-330: fetch_historical_entities: restricting order-by usage.

Rejecting order-by for historical entities is a clear design choice. The error message is explicit, which helps clarify unsupported scenarios for clients.


331-352: Applying cursors to historical entity queries.

  1. Shifting event_id comparisons based on forward/backward direction is a nice approach to reuse the paging logic.
  2. Using base64 decoding for cursors ensures consistency with the rest of the code.

Looks accurate, sensei!


416-426: Pagination usage in query_by_hashed_keys.

Switching from manual limit/offset to the new pagination object is consistent. The leftover logic about model filtering looks neatly integrated.


503-529: Ohayo sensei! Constraining queries with keys_clause and pagination.

  1. Converting the old approach of building where_clause for the keys into something that merges with the new cursor-based structure is tidy.
  2. The model_relation_table usage is consistent with the approach in the rest of the code.

Everything merges nicely.


593-645: query_by_member with dynamic comparison operator.

  1. Good job directly flattening the column name into [model].[member].
  2. The approach of building the final query with fetch_entities and having_clause remains consistent.

Works well, sensei!


698-749: Composite clauses + pagination.

  1. Recursively building composite conditions for AND/OR is flexible.
  2. Tying them directly to the new pagination logic is consistent with the rest.

The approach to unify all clause types under a single composite is thoroughly done.


927-928: Enforcing pagination presence in queries.

Raising an error if pagination is missing ensures the new approach remains mandatory, preventing fallback to offset-based logic.


1393-1408: Ohayo sensei! Introducing cursor-based logic in retrieve_tokens.

  1. Conditionally appending WHERE id > ? for the cursor is straightforward.
  2. Reusing the last item’s id as the next cursor is effective.

No immediate concerns, sensei!


835-865: Cursor-based pagination for retrieve_token_balances.

  1. Similar logic to retrieve_tokens is consistent.
  2. Tagging “id > ?” ensures ordering clarity by id.

Looks aligned, sensei!

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

♻️ Duplicate comments (2)
crates/torii/grpc/src/server/mod.rs (2)

148-161: Revisiting unreachable!() usage for Pagination direction.
A similar concern was previously flagged about panicking on unexpected input. Consider returning an error or default direction instead of using unreachable!().


163-175: Same note on unreachable!() usage for OrderBy direction.
Gracefully handling unexpected input is safer than forcing a panic, especially in production services.

🧹 Nitpick comments (3)
crates/torii/grpc/src/server/mod.rs (3)

354-375: Building dynamic SQL queries with order direction.
Ensure columns used in ORDER BY are indexed for performance. This might help with large datasets.


377-384: Potential performance caution on large fetches.
If the result set grows large, consider pagination streaming or chunking.


474-474: Combining fetch with final mapping stage.
Consider using a streaming approach if you expect highly voluminous data. Otherwise, this straightforward design is acceptable.

Also applies to: 487-494

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro (Legacy)

📥 Commits

Reviewing files that changed from the base of the PR and between a0ee3aa and 9e66c68.

📒 Files selected for processing (1)
  • crates/torii/grpc/src/server/mod.rs (28 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
crates/torii/grpc/src/server/mod.rs (5)
crates/torii/grpc/src/types/mod.rs (20)
  • from (36-43)
  • from (117-124)
  • from (135-137)
  • from (254-265)
  • from (323-331)
  • from (335-340)
  • from (344-354)
  • from (358-366)
  • from (370-382)
  • from (386-399)
  • from (403-417)
  • from (421-426)
  • from (430-433)
  • from (437-444)
  • from (448-453)
  • from (457-472)
  • value (304-313)
  • value (359-363)
  • value (487-491)
  • value (505-509)
crates/torii/sqlite/src/executor/mod.rs (10)
  • None (302-302)
  • None (815-815)
  • new (168-170)
  • new (243-269)
  • sqlx (312-312)
  • sqlx (447-447)
  • sqlx (533-533)
  • sqlx (562-562)
  • sqlx (627-627)
  • sqlx (714-714)
crates/torii/sqlite/src/model.rs (5)
  • pagination (352-365)
  • pagination (550-554)
  • new (40-74)
  • schema (100-107)
  • fetch_entities (291-461)
crates/torii/sqlite/src/cache.rs (2)
  • models (50-61)
  • model (63-72)
crates/torii/sqlite/src/types.rs (1)
  • from_str (192-201)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build
🔇 Additional comments (40)
crates/torii/grpc/src/server/mod.rs (40)

15-16: Ohayo sensei! Solid introduction of base64 usage.
This is handy for cursor-based decoding. Ensure that any failures are clearly surfaced to callers.


42-42: Ohayo sensei!
Adding use tokio::sync::mpsc::Receiver; is a straightforward inclusion for async message handling. No concerns here.


51-53: Ohayo sensei!
These new imports (Pagination, OrderBy, etc.) align well with the cursor-based pagination approach. Great organization!


65-72: Ohayo sensei! Good expansion of the world proto.
Adding these lines for controller & token retrieval requests maintains consistency with the rest of the codebase.


301-304: Ohayo sensei!
Nice introduction of pagination, no_hashed_keys, and models in entities_all to unify and clarify the query interface.


310-312: Excellent parameter forwarding.
Passing the new arguments consistently into query_by_hashed_keys ties everything together seamlessly.


317-324: New fetch_historical_entities method looks well-structured.
This separation helps handle historical tables distinctly. Good job, sensei!


325-330: Order-by is disallowed for historical entities.
Ohayo sensei, returning an error is straightforward. Just ensure the user gets enough detail if they inadvertently try ordering.


386-418: Mapping fetched rows into Entities.
Implementation here is straightforward. The structure is easy to follow and does not seem to have correctness issues.


423-425: Additional parameters in query_by_hashed_keys.
Ohayo sensei, this helps unify the approach across the codebase. No issues spotted.


437-442: Bind values from hashed keys.
The format string for hashed keys is correct. Very nice addition!


446-447: Computing model selectors from string references.
This approach is consistent with compute_selector_from_tag. Good job keeping it DRY.


450-450: Chaining .models(&models) call.
Proper usage of your model_cache. This is consistent with the overall design.


462-472: Redirecting historical queries.
Approach is aligned with the new fetch_historical_entities. Good usage of code reusability.


503-506: Extended signature in query_by_keys.
Ohayo sensei, the new parameters keep the code parallel to query_by_hashed_keys.


515-515: Constructing bind_values with keys_pattern.
This ensures the first condition is uniformly handled. Looks good.


520-521: Appending model selectors to bind_values.
Ohayo sensei, the chaining approach is consistent with your dynamic queries.


532-532: Converting model references again.
No issues, sensei. This symmetrical approach fosters maintainability.


541-541: Handling having_clause for complex queries.
This helps refine the result set effectively. Great job.


548-556: Historical table fallback.
Matches the logic used in query_by_hashed_keys. Good consistency.


559-579: Mapping results for query_by_keys.
The final combination of parallel iteration and error-checking is well-structured.


589-592: New parameters in query_by_member.
All query methods now share a similar pattern for pagination, hashed keys, and models. Great synchronization.


593-594: Selector computation for models.
Ohayo sensei, consistent usage of compute_selector_from_tag. Nicely done.


670-673: Flattened column approach for where_clause.
Using bracket notation is a neat way to avoid naming collisions.


675-685: Extended fetch pattern in query_by_member.
Code structure appears consistent and easy to maintain.


688-695: Mapping page results to final Entities.
Parallel iteration looks stable and straightforward.


705-708: Additional parameters for query_by_composite.
This is consistent with the rest of the refactor.


710-710: Composite clause building.
Smart to encapsulate logic in build_composite_clause.


712-730: Combining multiple clauses.
The final result is flexible for complex queries.

Also applies to: 735-735


741-748: Returning a page of Entities.
The usage of next_cursor stands out as user-friendly for navigation.


927-928: Extracting pagination.
Pulling from query.pagination ensures consistent error handling.


930-1001: Clause matching for retrieving entities.
Including hashed_keys, keys, member, and composite logic covers all scenarios thoroughly.


1003-1006: Finalizing RetrieveEntitiesResponse.
Concise and user-friendly, sensei. Excellent.


1009-1009: retrieve_events_internal signature.
Good naming—it aligns with the rest of the retrieval methods.


1393-1393: Parsing RetrieveTokensRequest.
Ohayo sensei, the approach is consistent with cursor-based logic used elsewhere.


1311-1329: New public gRPC API: retrieve_entities.
The forward call to internal logic is well-structured, with robust error mapping.


1331-1353: retrieve_event_messages gRPC method.
Follows the same pattern. Confident usage of shared retrieval logic fosters maintainability.


1355-1370: retrieve_events gRPC method.
Matches usage in retrieve_events_internal. Clear flow with minimal duplication.


517-517:

❓ Verification inconclusive

Regex usage with REGEXP.
Ensure the SQL environment supports this reliably; otherwise, watch for potential injection vectors.


🏁 Script executed:

#!/bin/bash
# Checking if the REGEXP function is available in current sqlite builds
sqlite3 --version || true

Length of output: 124


Ensure sqlite3 REGEXP Support and Injection Safety

Ohayo sensei, it looks like our automated check didn’t yield the expected sqlite version output—the sqlite3 command wasn’t available in the current environment. Could you please manually verify that the SQL environment reliably supports the REGEXP function? Also, please double-check that interpolating the table name in the query (as seen on line 517 of crates/torii/grpc/src/server/mod.rs) is safe and does not inadvertently expose injection vulnerabilities.


331-352:

❓ Verification inconclusive

Cursor-based filtering on event_id.
Ohayo sensei, confirm that event_id is stored as a numeric type or a consistently padded string in the DB; otherwise, string comparisons may incorrectly order events.


🏁 Script executed:

#!/bin/bash
# Confirm data type for event_id in the DB schema
sqlite3 :memory: '.schema entities_historical' || true
sqlite3 :memory: '.schema event_messages_historical' || true

Length of output: 313


Ohayo sensei – Manual Schema Verification Required for event_id

The previous sqlite3 check couldn’t run, so we couldn’t automatically verify that the DB schema defines the event_id column as a numeric type (or a properly padded string). Please run the following shell script to search for the table definitions (in migrations or schema files) for entities_historical and event_messages_historical. Verify that in their schema definitions the event_id column is defined as either a numeric type (e.g., INTEGER) or, if it’s text, is consistently formatted for proper ordering.

Once you’ve confirmed that the event_id column meets these criteria, we can be confident that the cursor-based filtering orders events correctly.


🏁 Script executed:

#!/bin/bash
rg -C3 "CREATE TABLE.*(entities_historical|event_messages_historical)" .

Length of output: 1681


Ohayo sensei – Please Verify DB Event ID Format

Our migration outputs indicate that the key column for historical events (named "id" in the migrations for both event_messages_historical and entities_historical) is defined as TEXT NOT NULL. The code currently applies cursor-based filtering using lexicographic comparisons (i.e., {table}.event_id >= ? or <= ?), which will work correctly only if the text values are consistently formatted (e.g., via zero-padding) or if they represent numeric values in a string-safe format.

  • Confirm that the event_id in the code corresponds to the id column from the migrations.
  • Ensure that the stored text values are either padded consistently or represent numeric strings so that lexicographic ordering behaves as expected.

Please double-check the schema details and the business logic surrounding ID generation to avoid any potential ordering issues.

Copy link

codecov bot commented Apr 10, 2025

Codecov Report

Attention: Patch coverage is 21.28060% with 418 lines in your changes missing coverage. Please review.

Project coverage is 55.51%. Comparing base (2348232) to head (b339ed6).
Report is 22 commits behind head on main.

Files with missing lines Patch % Lines
crates/torii/grpc/src/server/mod.rs 5.88% 304 Missing ⚠️
crates/torii/sqlite/src/model.rs 57.31% 70 Missing ⚠️
crates/torii/client/src/client/mod.rs 0.00% 25 Missing ⚠️
crates/torii/grpc/src/types/mod.rs 0.00% 17 Missing ⚠️
crates/torii/grpc/src/client.rs 0.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3147      +/-   ##
==========================================
- Coverage   55.60%   55.51%   -0.10%     
==========================================
  Files         443      443              
  Lines       62957    62734     -223     
==========================================
- Hits        35008    34827     -181     
+ Misses      27949    27907      -42     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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 (1)
crates/torii/grpc/proto/types.proto (1)

195-198: Ohayo sensei: New PaginationDirection Enum

The introduction of the PaginationDirection enum with FORWARD and BACKWARD is a solid step for explicit cursor navigation. Consider adding inline documentation or comments to assist future developers with its intended use.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro (Legacy)

📥 Commits

Reviewing files that changed from the base of the PR and between a31edb7 and 3e0a67f.

📒 Files selected for processing (3)
  • crates/torii/grpc/proto/types.proto (2 hunks)
  • crates/torii/grpc/proto/world.proto (4 hunks)
  • crates/torii/grpc/src/server/mod.rs (28 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • crates/torii/grpc/proto/world.proto
  • crates/torii/grpc/src/server/mod.rs
🔇 Additional comments (4)
crates/torii/grpc/proto/types.proto (4)

74-77: Ohayo sensei: Enhanced Query Message Fields

The Query message now cleanly renames and consolidates its fields—no_hashed_keys replaces the ambiguous dont_include_hashed_keys, and models is a clearer representation. The addition of the Pagination field and the new historical flag streamline pagination support. Please verify that all services and clients consuming this message are updated accordingly.


83-83: Ohayo sensei: EventQuery Cursor Field Update

Replacing the numeric offset with a string cursor in the EventQuery message aligns well with cursor-based pagination. Ensure that the query logic which interprets this field is updated and thoroughly tested.


193-194: Ohayo sensei: Controller Message Formatting Check

The tilde markers on the closing brace of the Controller message suggest a formatting change. There appears to be no semantic modification besides this; please confirm that this was intentional and does not affect message serialization.


200-204: Ohayo sensei: New Pagination Message for Cursor-Based Pagination

The Pagination message now encapsulates cursor, limit, direction, and order_by fields, providing a cohesive structure for pagination. Verify that all downstream consumers can correctly interpret these fields and that any legacy code is properly migrated.

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

♻️ Duplicate comments (2)
crates/torii/grpc/src/server/mod.rs (2)

148-161: Ohayo sensei, consider handling unknown direction more gracefully.
Using unreachable!() for an unexpected pagination direction may cause unexpected panics if the input is invalid. A safer approach is to return an error or default direction.


163-175: Ohayo sensei, the same unreachable! logic for OrderBy direction might need a fallback.
Similar to pagination direction, relying on unreachable!() could lead to panics when encountering invalid input. Consider returning an error or defaulting to Asc.

🧹 Nitpick comments (1)
crates/torii/grpc/src/server/mod.rs (1)

431-431: Ohayo sensei, consider using a SQL IN clause for potentially faster lookups.
Stringing multiple conditions with OR is valid but might be less optimal than a single IN expression when dealing with many hashed keys.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro (Legacy)

📥 Commits

Reviewing files that changed from the base of the PR and between 3e0a67f and f1022f7.

📒 Files selected for processing (1)
  • crates/torii/grpc/src/server/mod.rs (29 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: fmt
🔇 Additional comments (15)
crates/torii/grpc/src/server/mod.rs (15)

15-16: Ohayo sensei, base64 usage looks good!
These imports seem valid and consistent with your decoding/encoding approach. Ensure that using the NO_PAD variant is intentional, as some clients or consumers may expect standard padding.


42-42: Ohayo sensei, additional import recognized.
This Receiver import from tokio::sync::mpsc is aligned with existing subscription logic. No concerns here.


52-53: Ohayo sensei, newly introduced type imports appear correct.
These imported types (e.g. Page, Pagination) are essential for cursor-based pagination and token management flows. Nicely organized.


65-72: Ohayo sensei, these added imports for proto messages are in order.
They match the updated pagination and token retrieval features. Great job keeping them consistent.


301-304: Ohayo sensei, expanded function signature for entities_all is consistent.
Adding pagination, no_hashed_keys, and models parameters aligns this function with your new pagination logic. Looks coherent.


310-313: Ohayo sensei, passing newly introduced arguments is seamless.
Forwarding pagination, no_hashed_keys, and models to query_by_hashed_keys ensures consistency.


317-376: Ohayo sensei, watch out for potential duplicate records when using >= or <= in pagination.
While using event_id >= ? or event_id <= ? for the cursor can simplify logic, it may also cause repeated records between pages if the same event_id spans multiple rows. Consider strict comparisons (> / <) or additional tie-breakers to avoid duplicates.


416-426: Ohayo sensei, new pagination parameters in query_by_hashed_keys look well-integrated.
The updated method signature cleanly brings in pagination, hashed key usage, and model constraints. Nicely done.


689-695: Ohayo sensei, parallel entity mapping is looking efficient.
Using par_iter() with rayon is a solid approach to deserialize rows concurrently. Ensure no shared-state mutation occurs.


927-928: Ohayo sensei, requiring a pagination object for all queries is a great approach.
This enforces a consistent interface and clarifies the query flow.


930-960: Ohayo sensei, new logic branches for different clause types elegantly incorporate pagination.
All clause types (hashed keys, keys, member, composite) funnel nicely into the pagination flow. This uniform handling helps maintain consistent query behavior.

Also applies to: 981-996, 1003-1006


1013-1014: Ohayo sensei, validate the ordering logic when applying cursor-based pagination to events.
Currently, you limit results by ORDER BY id DESC, then apply WHERE id >= ? for the cursor. This might include items out of order if cursor logic expects ascending sequences. Consider inverting the comparison or direction if retrieving older events first.

Also applies to: 1023-1034, 1036-1056, 1068-1068


1113-1113: Ohayo sensei, map_row_to_event function is straightforward.
Decoding keys and data from base64 properly with Felt usage looks correct. Nicely done.


1326-1344: Ohayo sensei, new retrieve methods gracefully leverage pagination.
Methods like retrieve_entities, retrieve_event_messages, and retrieve_events show consistent usage of your new approach. Great for code uniformity.

Also applies to: 1346-1368, 1370-1383


1406-1425: Ohayo sensei, token retrieval with optional limit and cursor is implemented cleanly.
Be sure to confirm that partial retrieval and next-cursor generation handle edge cases (e.g., small sets) correctly in tests.

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

🔭 Outside diff range comments (1)
crates/torii/grpc/src/server/mod.rs (1)

666-673: 🛠️ Refactor suggestion

Centralize prepare_comparison logic for DRY compliance.
Ohayo sensei! This member comparison handling reappears in multiple spots (e.g., lines 1231–1267). Consolidating into a shared utility would improve readability and reduce duplication.

♻️ Duplicate comments (2)
crates/torii/grpc/src/server/mod.rs (2)

153-156: Avoid using unreachable!() for unknown pagination direction.
Ohayo sensei! Returning an explicit error is safer than panicking if the direction is invalid. Replacing this branch with a fallback or error path would improve robustness.


169-172: Handle unknown order direction gracefully.
Ohayo sensei! Same recommendation: use a fallback or return an error for unknown directions instead of unreachable!().

🧹 Nitpick comments (2)
crates/torii/grpc/src/server/mod.rs (2)

317-415: Consider refactoring the fetch_historical_entities logic.
Ohayo sensei! This block duplicates pagination and query-building logic that appears elsewhere. Extracting shared code into a helper function would streamline maintenance and reduce potential inconsistencies.


1333-1344: Consider adding unit tests for pagination paths.
Ohayo sensei! The newly integrated pagination parameters are only partially tested. Strengthening test coverage for edge cases (e.g., empty cursors, large limits) will ensure correctness.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro (Legacy)

📥 Commits

Reviewing files that changed from the base of the PR and between f1022f7 and cd036f3.

📒 Files selected for processing (3)
  • crates/torii/client/src/client/mod.rs (3 hunks)
  • crates/torii/grpc/src/server/mod.rs (29 hunks)
  • crates/torii/grpc/src/types/mod.rs (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • crates/torii/grpc/src/types/mod.rs
  • crates/torii/client/src/client/mod.rs
🔇 Additional comments (1)
crates/torii/grpc/src/server/mod.rs (1)

1052-1068: Double-check pagination and sorting for events.
Ohayo sensei! The next cursor is derived from the first column (id), but the query also sorts by id DESC. Please verify that the cursor comparison logic matches the sort order to avoid missing or repeating events.

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

♻️ Duplicate comments (2)
crates/torii/grpc/src/server/mod.rs (2)

154-156: Handle unknown pagination directions instead of panicking.
This replicates past feedback about avoiding unreachable!() when an unexpected direction arises.


169-171: Handle unknown order directions instead of panicking.
Same as before: returning an error or a default direction is safer than using unreachable!().

🧹 Nitpick comments (2)
crates/torii/grpc/src/server/mod.rs (2)

317-353: Ohayo sensei! Confirm inclusive cursor usage.
Using >= or <= with the cursor can introduce duplicates when paging forward/backward. You may want strict comparisons (>/<) or to store the last-seen ID offset.

Are you certain about including the current event_id in subsequent pages?


835-866: Ohayo sensei!
In retrieve_token_balances, using base64 cursors is consistent with your other pagination features. Please double-check that id has an index to handle large data efficiently.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro (Legacy)

📥 Commits

Reviewing files that changed from the base of the PR and between cd036f3 and c25e10f.

📒 Files selected for processing (1)
  • crates/torii/grpc/src/server/mod.rs (27 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build
🔇 Additional comments (12)
crates/torii/grpc/src/server/mod.rs (12)

15-16: Ohayo sensei! Base64 integration looks neat.
All usages of BASE64_STANDARD_NO_PAD for cursor encoding/decoding appear consistent, and error handling via Error::InvalidCursor is in place.


42-42: Ohayo sensei!
Importing tokio::sync::mpsc::Receiver for concurrency is aligned with the usage of block_rx tasks.


50-53: Ohayo sensei!
These newly imported types from torii_sqlite::types (e.g. Pagination, Page, OrderBy) cleanly support the new paging logic.


65-72: Ohayo sensei!
Expanding proto imports (e.g., RetrieveTokenBalancesRequest, RetrieveTokensRequest) aligns with your new services.


295-313: Ohayo sensei! The updated entities_all signature looks good.
Introducing pagination, no_hashed_keys, and models is clean. Delegating to query_by_hashed_keys is straightforward and consistent.


423-426: Ohayo sensei!
New parameters in query_by_hashed_keys are consistent with the other query methods. Good step in unifying the pagination approach.


436-444: Ohayo sensei! Validate slice lengths.
Felt::from_bytes_be_slice(key) assumes 32-byte input. Consider gracefully handling mismatches to prevent potential panics.


462-472: Ohayo sensei!
Redirecting to fetch_historical_entities for _historical tables is a clean approach. The boundary between current vs. historical queries is well-defined.


589-592: Ohayo sensei!
The new parameters in query_by_member mirror the consistent pattern of passing pagination, no_hashed_keys, and models. This retains a uniform interface across queries.


1013-1014: Ohayo sensei!
Incrementing the limit by one for pagination is a standard approach to detect the presence of further results. Looks good.


1119-1123: Ohayo sensei!
Mapping rows to events with map_row_to_event is concise. Great job reusing process_event_field for keys/data decoding.


1412-1412: Ohayo sensei!
New parameters limit and cursor in RetrieveTokensRequest confirm a uniform pagination strategy across tokens.

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: 1

♻️ Duplicate comments (2)
crates/torii/grpc/src/server/mod.rs (2)

148-161: Ohayo sensei, unreachable!() usage for PaginationDirection
This was flagged in a past review, recommending returning an error or default direction rather than panicking on unknown input.


163-175: Ohayo sensei, unreachable!() usage for OrderBy direction
Same concern as before: consider gracefully handling unexpected input to avoid panics.

🧹 Nitpick comments (1)
crates/torii/grpc/src/server/mod.rs (1)

317-415: Ohayo sensei, historical entities fetching
This new function thoroughly handles cursor-based pagination for historical data, including proper base64 decoding and ordering by event_id. It looks cohesive.

Consider adding test coverage to verify boundary conditions (e.g., empty cursor vs. valid cursor, minimal vs. large limit).

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro (Legacy)

📥 Commits

Reviewing files that changed from the base of the PR and between c25e10f and 086472a.

📒 Files selected for processing (1)
  • crates/torii/grpc/src/server/mod.rs (27 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build
🔇 Additional comments (11)
crates/torii/grpc/src/server/mod.rs (11)

15-16: Ohayo sensei, new base64 engine import
No immediate concerns. The usage of BASE64_STANDARD_NO_PAD and Engine looks straightforward.


42-42: Ohayo sensei, additional Receiver import
No issues spotted. This import aligns with the subscription flow established below.


301-304: Ohayo sensei, extended function signature for pagination
Bringing pagination, no_hashed_keys, and models into entities_all enhances flexibility. No correctness issues found.

Also applies to: 310-312


423-425: Ohayo sensei, updated signature & hashed keys handling
Adding pagination, no_hashed_keys, and models plus joining hashed keys with "OR" seems correct for broader filtering.

Also applies to: 431-431, 441-442


463-471: Ohayo sensei, branching logic for historical vs. active entities
The condition to call fetch_historical_entities for tables ending in _historical is intuitive, and the fallback to fetch_entities is clearly defined.

Also applies to: 474-495


498-507: Ohayo sensei, consistent pagination approach in query_by_keys
The expansions for pagination, no_hashed_keys, and models are integrated throughout the function’s flow. This maintains a uniform structure across queries.

Also applies to: 515-521, 531-557, 561-580


589-592: Ohayo sensei, new arguments in query_by_member
The approach to incorporate pagination, no_hashed_keys, and models for filtered lookups appears correct. Data mapping is consistent with the rest of the codebase.

Also applies to: 593-645


699-708: Ohayo sensei, composite clause logic
Combining multiple clauses with OR or AND is a neat approach. The recursive handling for nested composites is well-structured.

Also applies to: 709-749


927-929: Ohayo sensei, retrieve_entities() and retrieve_events()
Introducing pagination logic and handling various clause types systematically is a solid upgrade. It simplifies client-side integration.

Also applies to: 930-930, 936-939, 953-953, 957-959, 999-999, 1003-1006, 1013-1075


1119-1123: Ohayo sensei, map_row_to_event changes
Decoding transaction hashes with fallback errors ensures data correctness. Implementation is consistent and succinct.


1332-1350: Ohayo sensei, new gRPC endpoints and subscription flows
These expansions round out the pagination features across the service. The changes appear to align well with the new Pagination struct and subscription patterns.

Also applies to: 1352-1374, 1376-1389, 1412-1412, 1596-1599, 1611-1618

Comment on lines +670 to 673
let where_clause = format!(
"[{}].[{}] {comparison_operator} {value}",
member_clause.model, member_clause.member
);
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Ohayo sensei, potential SQL injection risk on dynamic column formatting
String interpolation like format!("[{}].[{}]", ...) might allow malicious input if user-controlled. Consider validating or whitelisting column names to avoid injection.

Here’s a possible safeguard:

- let where_clause = format!("[{}].[{}] {comparison_operator} {value}", member_clause.model, member_clause.member);
+ // Validate or whitelist member_clause.model and member_clause.member before using them. 
+ let validated_model = sanitize_or_whitelist_model(&member_clause.model)?;
+ let validated_member = sanitize_or_whitelist_member(&member_clause.member)?;
+ let where_clause = format!("[{}].[{}] {comparison_operator} {value}", validated_model, validated_member);

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

@Larkooo Larkooo closed this Apr 22, 2025
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