Skip to content
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

feat(torii-sqlite): primitive upgrades towards bigger types #2931

Merged
merged 11 commits into from
Feb 6, 2025

Conversation

Larkooo
Copy link
Collaborator

@Larkooo Larkooo commented Jan 20, 2025

#2925 this updates torii to support new less strict upgrades for primitives

Summary by CodeRabbit

  • Bug Fixes

    • Enhanced database migrations to validate type changes, ensuring data is correctly transformed and preventing unsupported schema upgrades.
  • Refactor

    • Revised the schema change detection process during upgrades to improve migration consistency and reliable error reporting.

Copy link

coderabbitai bot commented Jan 20, 2025

Ohayo sensei, here’s the detailed summary for the changes:

Walkthrough

This PR updates the schema upgrade process in two modules. In the SQLite module, the add_columns_recursive function now validates primitive type upgrades using a new modify_column closure that handles column modifications via temporary table creation, data copying, and dropping old columns, along with enhanced SQL value conversion logic. In the indexer module, both the upgrade event and upgrade model processors have reversed the order of arguments passed to the schema diff function, thereby altering the resulting schema differences. Additionally, an import for SqlType from dojo_types::primitive has been added.

Changes

File(s) Change Summary
crates/torii/sqlite/src/lib.rs Modified add_columns_recursive to validate primitive type upgrades. Introduced a modify_column closure that creates a temporary table, copies data, drops the old column, and ensures correct SQL value conversion. Added import of SqlType from dojo_types::primitive.
crates/torii/indexer/src/processors/upgrade_event.rs
crates/torii/indexer/src/processors/upgrade_model.rs
Reversed the argument order in the diff method from new_schema.diff(&prev_schema) to prev_schema.diff(&new_schema) to recalculate schema differences.

Sequence Diagram(s)

SQLite Column Upgrade Process

sequenceDiagram
    participant CM as Column Manager
    participant DB as Database
    participant TT as Temporary Table
    CM->>CM: Validate type upgrade
    alt Valid Upgrade
        CM->>DB: Create temporary table
        DB-->>CM: Temporary table created
        CM->>DB: Copy data to temporary table
        CM->>DB: Drop old column
        CM->>CM: Perform SQL value conversion
        CM->>DB: Modify column with new SQL type
    else Invalid Upgrade
        CM-->>CM: Return error indicating invalid upgrade
    end
Loading

Schema Diff Calculation Process

sequenceDiagram
    participant P as Processor
    participant Prev as Previous Schema
    participant New as New Schema
    P->>Prev: Call diff(New)
    Prev-->>P: Return schema differences
Loading

Possibly related PRs

Suggested reviewers

  • glihm

📜 Recent review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between c7a0e53 and 2d79fd7.

📒 Files selected for processing (1)
  • crates/torii/sqlite/src/lib.rs (3 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: clippy
  • GitHub Check: docs
  • GitHub Check: build
  • GitHub Check: ensure-wasm
🔇 Additional comments (2)
crates/torii/sqlite/src/lib.rs (2)

8-8: LGTM!

The SqlType import is correctly placed and necessary for the primitive type upgrade functionality.


1039-1062: Ohayo, sensei! Nice implementation of primitive type upgrades!

The implementation elegantly handles upgrades from smaller to larger types, particularly the integer to text conversion with proper hex formatting and padding. The code maintains backward compatibility while supporting the new upgrade paths.


🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

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

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

CodeRabbit Commands (Invoked using PR comments)

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

Other keywords and placeholders

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

Documentation and Community

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
crates/torii/sqlite/src/lib.rs (1)

957-977: Ohayo, sensei! Enhance error handling for invalid primitive type upgrades.

The error message in lines 967-971 could be more informative to aid debugging:

return Err(anyhow::anyhow!(
    "Invalid primitive type upgrade from {:?} to {:?}",
    old_primitive,
    p
));

Consider including additional context or guidance on how to resolve the error. Additionally, logging the error might help in monitoring and troubleshooting.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 2dd3ead and 0792db5.

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

983-1020: Ohayo, sensei! The can_upgrade_to method correctly implements type upgrade logic.

The implementation accurately defines the permissible upgrades between primitive types, ensuring data integrity during schema migrations.

crates/torii/sqlite/src/lib.rs Outdated Show resolved Hide resolved
@Larkooo Larkooo changed the title refactor(torii): primitive upgrades towards bigger types feat(torii-sqlite): primitive upgrades towards bigger types Jan 20, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
crates/torii/sqlite/src/lib.rs (1)

958-979: Enhance error message and add logging for upgrades.

The error message could be more descriptive, and successful upgrades should be logged for better observability.

Apply this diff to improve the error handling and add logging:

                     if old_primitive.can_upgrade_to(p) {
+                        tracing::info!(
+                            "Upgrading column {} from {:?} to {:?}",
+                            column_name, old_primitive, p
+                        );
                         modify_column(
                             alter_table_queries,
                             &column_name,
                             p.to_sql_type().as_ref(),
                             p.to_sql_value().as_ref(),
                         );
                     } else {
                         return Err(anyhow::anyhow!(
-                            "Invalid primitive type upgrade from {:?} to {:?}",
+                            "Invalid primitive type upgrade for column '{}': cannot upgrade from {:?} to {:?}. Please check the upgrade compatibility rules.",
+                            column_name,
                             old_primitive,
                             p
                         ));
                     }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 0792db5 and f2affb6.

📒 Files selected for processing (2)
  • crates/dojo/types/src/primitive.rs (1 hunks)
  • crates/torii/sqlite/src/lib.rs (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: ensure-wasm
  • GitHub Check: docs
  • GitHub Check: build
🔇 Additional comments (1)
crates/dojo/types/src/primitive.rs (1)

407-441: Ohayo, sensei! Add test coverage for the new can_upgrade_to method.

The new method defines critical upgrade paths for primitive types but lacks test coverage to ensure the upgrade rules are working as expected.

Would you like me to generate comprehensive test cases covering all upgrade paths?

crates/dojo/types/src/primitive.rs Outdated Show resolved Hide resolved
crates/torii/sqlite/src/lib.rs Outdated Show resolved Hide resolved
Copy link
Collaborator

@glihm glihm left a comment

Choose a reason for hiding this comment

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

Working fine, thank you @Larkooo! Waiting some confirmations from @remybar on the #2925 and will merge.

crates/dojo/types/src/primitive.rs Outdated Show resolved Hide resolved
crates/dojo/types/src/primitive.rs Outdated Show resolved Hide resolved
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
crates/dojo/types/src/primitive.rs (1)

406-443: Ohayo sensei! Consider adding dedicated tests for can_upgrade_to.
Ensuring thorough coverage of each enumerated upgrade path will help catch future regressions for these conversions.

crates/torii/sqlite/src/lib.rs (1)

1036-1038: Ohayo sensei! The pipeline complains about long comment lines.
Splitting them into shorter segments (typically 80-120 characters) might help satisfy lint rules.

🧰 Tools
🪛 GitHub Actions: ci

[warning] 1036-1038: Comment line exceeds the recommended length. Please split the comment into multiple lines.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 23d6f44 and 0b14257.

📒 Files selected for processing (2)
  • crates/dojo/types/src/primitive.rs (1 hunks)
  • crates/torii/sqlite/src/lib.rs (2 hunks)
🧰 Additional context used
🪛 GitHub Actions: ci
crates/torii/sqlite/src/lib.rs

[warning] 1036-1038: Comment line exceeds the recommended length. Please split the comment into multiple lines.

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

8-8: Ohayo sensei! Looks good.
Importing SqlType here is straightforward and helps clarify usage.


1036-1066: Ohayo sensei! Please revisit transaction safety and parameterization.
This column-modification pattern is still prone to partial updates if a step fails, and string formatting for SQL can be risky.

🧰 Tools
🪛 GitHub Actions: ci

[warning] 1036-1038: Comment line exceeds the recommended length. Please split the comment into multiple lines.

Copy link

codecov bot commented Feb 4, 2025

Codecov Report

Attention: Patch coverage is 20.00000% with 20 lines in your changes missing coverage. Please review.

Project coverage is 57.15%. Comparing base (bf0c5ee) to head (2d79fd7).
Report is 9 commits behind head on main.

Files with missing lines Patch % Lines
crates/torii/sqlite/src/lib.rs 21.73% 18 Missing ⚠️
...ates/torii/indexer/src/processors/upgrade_event.rs 0.00% 1 Missing ⚠️
...ates/torii/indexer/src/processors/upgrade_model.rs 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2931      +/-   ##
==========================================
+ Coverage   56.97%   57.15%   +0.17%     
==========================================
  Files         426      427       +1     
  Lines       56376    56754     +378     
==========================================
+ Hits        32119    32435     +316     
- Misses      24257    24319      +62     

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
crates/torii/sqlite/src/lib.rs (1)

884-891: ⚠️ Potential issue

Ohayo, sensei! Address potential SQL injection vulnerability in modify_column.

The sql_value is still directly interpolated into the SQL statement without parameterization:

"UPDATE [{table_id}] SET [{name}] = (SELECT {sql_value} FROM tmp_values_{name} WHERE tmp_values_{name}.internal_id = [{table_id}].internal_id)"

Ensure atomic operations with transaction handling.

The column modification process involves multiple SQL operations that should be atomic to prevent data corruption if any step fails.

🧰 Tools
🪛 GitHub Actions: ci

[warning] 888-888: Line exceeds recommended length. Consider breaking the line for better readability.

🧹 Nitpick comments (1)
crates/torii/sqlite/src/lib.rs (1)

1036-1067: Ohayo, sensei! The primitive type upgrade logic looks solid!

The implementation:

  • Properly validates type upgrades using can_upgrade_to
  • Handles integer to hex string conversion for larger numeric types
  • Returns descriptive errors for invalid upgrades

However, consider breaking long lines for better readability:

- let sql_value = if old_primitive.to_sql_type() == SqlType::Integer && p.to_sql_type() == SqlType::Text {
+ let sql_value = if old_primitive.to_sql_type() == SqlType::Integer 
+     && p.to_sql_type() == SqlType::Text {
🧰 Tools
🪛 GitHub Actions: ci

[warning] 1042-1042: Line exceeds recommended length. Consider breaking the line for better readability.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between e4f6fef and 35c572b.

📒 Files selected for processing (1)
  • crates/torii/sqlite/src/lib.rs (3 hunks)
🧰 Additional context used
🪛 GitHub Actions: ci
crates/torii/sqlite/src/lib.rs

[warning] 881-881: Line exceeds recommended length. Consider breaking the line for better readability.


[warning] 888-888: Line exceeds recommended length. Consider breaking the line for better readability.


[warning] 1042-1042: Line exceeds recommended length. Consider breaking the line for better readability.

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

8-8: LGTM!

The import of SqlType is necessary for the new primitive type upgrade functionality.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
crates/torii/sqlite/src/lib.rs (1)

891-894: ⚠️ Potential issue

Ohayo, sensei! Address potential SQL injection vulnerability.

The SQL value is directly interpolated into the query without parameterization, which could expose the code to SQL injection attacks.

🧹 Nitpick comments (1)
crates/torii/sqlite/src/lib.rs (1)

1039-1070: Ohayo, sensei! Robust primitive type upgrade validation.

The implementation ensures data integrity during schema upgrades by:

  1. Validating upgrade compatibility using can_upgrade_to
  2. Handling integer to text conversions with proper hex formatting
  3. Failing early for invalid upgrades with clear error messages

However, consider adding transaction handling to ensure atomic operations:

Apply this diff to ensure atomic operations:

 fn add_columns_recursive(
     path: &[String],
     ty: &Ty,
     columns: &mut Vec<String>,
     alter_table_queries: &mut Vec<String>,
     indices: &mut Vec<String>,
     table_id: &str,
     upgrade_diff: Option<&Ty>,
 ) -> Result<()> {
+    // Start transaction for atomic operations
+    alter_table_queries.push("BEGIN TRANSACTION;".to_string());
+
     // ... existing code ...
+
+    // Commit transaction on success
+    alter_table_queries.push("COMMIT;".to_string());
+    // Add rollback for error handling
+    alter_table_queries.push("ROLLBACK;".to_string());
     Ok(())
 }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 35c572b and c7a0e53.

📒 Files selected for processing (3)
  • crates/torii/indexer/src/processors/upgrade_event.rs (1 hunks)
  • crates/torii/indexer/src/processors/upgrade_model.rs (1 hunks)
  • crates/torii/sqlite/src/lib.rs (3 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: docs
  • GitHub Check: clippy
  • GitHub Check: ensure-wasm
🔇 Additional comments (2)
crates/torii/indexer/src/processors/upgrade_model.rs (1)

95-95: Ohayo, sensei! LGTM - Consistent schema diff calculation.

The change aligns with the similar modification in upgrade_event.rs, ensuring consistent schema difference calculations across processors.

crates/torii/indexer/src/processors/upgrade_event.rs (1)

97-97: Ohayo, sensei! LGTM - Consistent schema diff calculation.

The change aligns with the similar modification in upgrade_model.rs, ensuring consistent schema difference calculations across processors.

@Larkooo
Copy link
Collaborator Author

Larkooo commented Feb 5, 2025

Went ahead and removed the can_upgrade_to on torii's primitives. I think it just adds more complexity and that we should instead rely on the dojo world for those migration checks. If we have an upgrade and a primitive type has changed, we assume that it should be valid.

Copy link
Collaborator

@glihm glihm left a comment

Choose a reason for hiding this comment

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

Thanks @Larkooo, works well for regular primitive types. However when the primitive is a type for an enum variant, it fails with the same issue as before:

image

Apart from that, it looks good, and the issue of enum variant may be tackled in a different PR. If you have a chance to add test in this one could be great, or maybe in a subsequent one where the variant type could be fixed?

@Larkooo
Copy link
Collaborator Author

Larkooo commented Feb 6, 2025

Thanks @Larkooo, works well for regular primitive types. However when the primitive is a type for an enum variant, it fails with the same issue as before:

image

Apart from that, it looks good, and the issue of enum variant may be tackled in a different PR. If you have a chance to add test in this one could be great, or maybe in a subsequent one where the variant type could be fixed?

Ok should be fixed. Actually that issue occurs for any nested primitives (when their column name contains a ".") which makes the queries fail.

@Larkooo Larkooo merged commit 9b248d8 into dojoengine:main Feb 6, 2025
14 of 15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants