Skip to content

feat: [#280] Add some methods for Schema#747

Merged
hwbrzzl merged 4 commits intomasterfrom
bowen/#280-27
Dec 6, 2024
Merged

feat: [#280] Add some methods for Schema#747
hwbrzzl merged 4 commits intomasterfrom
bowen/#280-27

Conversation

@hwbrzzl
Copy link
Contributor

@hwbrzzl hwbrzzl commented Dec 5, 2024

📑 Description

Closes goravel/goravel#280

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced methods for renaming tables and columns, enhancing schema management capabilities.
    • Added functionality to drop tables and columns, retrieve table listings, and check for the existence of types and views.
  • Bug Fixes

    • Improved error handling in various schema operations, ensuring clearer feedback during failures.
  • Tests

    • Expanded test coverage for schema functionalities, including new tests for types, views, and comprehensive table operations.
  • Documentation

    • Updated error messages for better clarity on schema operation failures.

✅ Checks

  • Added test cases for my code

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 5, 2024

Walkthrough

The pull request introduces several enhancements to the database schema management functionality. Key additions include new methods for renaming tables, dropping tables and columns, and retrieving table listings across various interfaces and structs. The Blueprint, Grammar, and Schema interfaces have been updated with methods like Rename, CompileRename, and others to facilitate these operations. Additionally, new error messages related to schema operations have been added, improving error handling. These changes aim to provide more robust and flexible database migration capabilities.

Changes

File Path Change Summary
contracts/database/schema/blueprint.go Added method: Rename(to string) in Blueprint interface.
contracts/database/schema/grammar.go Added method: CompileRename(blueprint Blueprint, command *Command) string in Grammar.
contracts/database/schema/schema.go Added methods: Drop, DropColumns, GetTableListing, HasType, HasView, Rename and updated Sql method signature.
database/schema/blueprint.go Added method: Rename(to string) in Blueprint struct and updated ToSql method.
database/schema/constants/constants.go Added constant: CommandRename with value "rename".
database/schema/grammars/mysql.go Added method: CompileRename(blueprint schema.Blueprint, command *schema.Command) string in Mysql.
database/schema/grammars/postgres.go Added method: CompileRename(blueprint schema.Blueprint, command *schema.Command) string in Postgres.
database/schema/grammars/sqlite.go Added method: CompileRename(blueprint schema.Blueprint, command *schema.Command) string in Sqlite.
database/schema/grammars/sqlserver.go Added method: CompileRename(blueprint schema.Blueprint, command *schema.Command) string and updated multiple method signatures to use underscores.
database/schema/postgres_schema.go Modified DropAllTypes and DropAllViews methods for clarity.
database/schema/schema.go Added methods: Drop, DropColumns, GetTableListing, HasType, HasView, Rename and updated Sql method signature.
database/schema/schema_test.go Enhanced SchemaSuite tests with new methods and dynamic table name handling.
database/schema/sqlite_schema.go Modified DropAllViews method for error handling and execution flow.
errors/list.go Added error variables: SchemaFailedToDropColumns and SchemaFailedToRenameTable.

Assessment against linked issues

Objective Addressed Explanation
Support chain calls for database migration (280) No specific implementation for chain calls was introduced.

Possibly related PRs

Suggested reviewers

  • devhaozi

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

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

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

CodeRabbit Commands (Invoked using PR comments)

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

Other keywords and placeholders

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

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

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

@codecov
Copy link

codecov bot commented Dec 5, 2024

Codecov Report

Attention: Patch coverage is 53.15315% with 52 lines in your changes missing coverage. Please review.

Project coverage is 69.65%. Comparing base (814ad23) to head (b487d9f).
Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
database/schema/grammars/sqlserver.go 12.00% 22 Missing ⚠️
database/schema/schema.go 70.49% 13 Missing and 5 partials ⚠️
database/schema/sqlite_schema.go 25.00% 5 Missing and 1 partial ⚠️
database/schema/grammars/mysql.go 0.00% 2 Missing ⚠️
database/schema/grammars/postgres.go 0.00% 2 Missing ⚠️
database/schema/grammars/sqlite.go 0.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #747      +/-   ##
==========================================
+ Coverage   69.41%   69.65%   +0.24%     
==========================================
  Files         210      210              
  Lines       17745    17820      +75     
==========================================
+ Hits        12318    12413      +95     
+ Misses       4766     4727      -39     
- Partials      661      680      +19     

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

@hwbrzzl hwbrzzl marked this pull request as ready for review December 6, 2024 07:02
@hwbrzzl hwbrzzl requested a review from a team as a code owner December 6, 2024 07:02
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 and nitpick comments (4)
database/schema/grammars/mysql.go (1)

214-216: Consider supporting multiple table renames

The implementation is correct for single table rename operations. However, MySQL's RENAME TABLE syntax supports renaming multiple tables atomically in a single statement (e.g., RENAME TABLE old1 TO new1, old2 TO new2). This could be a future enhancement for batch operations.

database/schema/sqlite_schema.go (1)

Error handling issue found in transaction error propagation

There's a clear issue in the error handling. The code returns nil when the transaction fails:

if err := r.orm.Transaction(func(tx orm.Query) error {
    // ...
}); err != nil {
    return nil  // <-- This silently swallows transaction errors
}

This means that errors from the transaction (including view dropping operations) are not propagated. Additionally, any subsequent error from the VACUUM operation (CompileRebuild) is properly returned, but the previous transaction errors would have been lost.

  • Line 71: Replace return nil with return err to properly propagate transaction errors
  • This ensures both transaction errors and VACUUM errors are properly reported to the caller
🔗 Analysis chain

Line range hint 51-71: Ensure proper error handling for VACUUM operation outside transactions

Since VACUUM operations (CompileRebuild) cannot be performed within a transaction, it's moved outside. Make sure that any errors from this operation are properly handled and propagated. Also, ensure that the overall method correctly reports any errors from both the transaction and the VACUUM operation.

Run the following script to verify that errors are properly handled:


Let me gather more context about the error handling in this file to make a proper assessment.


Let me try a different approach to get the context of the function.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check that `DropAllViews` returns errors from both the transaction and the `VACUUM` operation.

# Test: Search for returns of `nil` in error handling. Expect: Errors should be properly returned.

rg 'return nil' -A 2 database/schema/sqlite_schema.go

Length of output: 229


Script:

#!/bin/bash
# Get more context around the error handling in the DropAllViews function
ast-grep --pattern 'func (r *SQLiteSchema) DropAllViews($$$) {
  $$$
}'

Length of output: 73


Script:

#!/bin/bash
# Get the full context of the file to understand the error handling
rg -B 5 -A 10 "func.*DropAllViews" database/schema/sqlite_schema.go

Length of output: 519

database/schema/schema.go (2)

237-252: Avoid suppressing errors in HasType; consider returning errors

The HasType method logs errors but returns false when an error occurs. This could lead to confusion between an absence of the type and a failure to retrieve types. Consider modifying the method to return an error, allowing callers to distinguish between these cases.

Suggested changes:

- func (r *Schema) HasType(name string) bool {
+ func (r *Schema) HasType(name string) (bool, error) {

Modify the error handling:

238   types, err := r.GetTypes()
239   if err != nil {
240- 		r.log.Errorf(errors.SchemaFailedToGetTables.Args(r.orm.Name(), err).Error())
241- 		return false
242+ 		return false, err
243   }

Update calling functions to handle the error appropriately.


253-268: Improve error handling in HasView method

Similar to HasType, the HasView method returns false when an error occurs, potentially masking errors as a simple absence of the view. Consider refactoring the method to return an error alongside the boolean result.

Suggested changes:

- func (r *Schema) HasView(name string) bool {
+ func (r *Schema) HasView(name string) (bool, error) {

Adjust the error handling:

255   views, err := r.GetViews()
256   if err != nil {
257- 		r.log.Errorf(errors.SchemaFailedToGetTables.Args(r.orm.Name(), err).Error())
258- 		return false
259+ 		return false, err
260   }

Ensure that any calling code is updated to handle the error properly.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 814ad23 and e6830d3.

⛔ Files ignored due to path filters (3)
  • mocks/database/schema/Blueprint.go is excluded by !mocks/**
  • mocks/database/schema/Grammar.go is excluded by !mocks/**
  • mocks/database/schema/Schema.go is excluded by !mocks/**
📒 Files selected for processing (14)
  • contracts/database/schema/blueprint.go (1 hunks)
  • contracts/database/schema/grammar.go (1 hunks)
  • contracts/database/schema/schema.go (2 hunks)
  • database/schema/blueprint.go (2 hunks)
  • database/schema/constants/constants.go (1 hunks)
  • database/schema/grammars/mysql.go (1 hunks)
  • database/schema/grammars/postgres.go (1 hunks)
  • database/schema/grammars/sqlite.go (1 hunks)
  • database/schema/grammars/sqlserver.go (12 hunks)
  • database/schema/postgres_schema.go (2 hunks)
  • database/schema/schema.go (4 hunks)
  • database/schema/schema_test.go (8 hunks)
  • database/schema/sqlite_schema.go (2 hunks)
  • errors/list.go (1 hunks)
🔇 Additional comments (21)
contracts/database/schema/schema.go (2)

14-17: LGTM! Comprehensive schema management methods added

The new methods enhance the Schema interface with essential database operations:

  • Table operations: Drop, Rename
  • Column operations: DropColumns
  • Schema inspection: GetTableListing, HasType, HasView

These additions align well with the PR objective of refactoring database migrations to match Laravel's capabilities.

Also applies to: 28-29, 37-41, 48-49


37-37: Method signatures improved for clarity and error handling

Good improvements:

  • HasTable parameter renamed from 'table' to 'name' for consistency
  • Sql method now returns error for better error handling

Also applies to: 53-53

contracts/database/schema/grammar.go (1)

48-49: LGTM! CompileRename method follows established patterns

The new CompileRename method is well-integrated into the Grammar interface, following the same pattern as other Compile* methods and supporting the table renaming functionality.

contracts/database/schema/blueprint.go (1)

98-99: LGTM! Blueprint.Rename completes the renaming feature set

The Rename method is well-integrated into the Blueprint interface. Let's verify the implementation ensures atomic renaming operations across different database drivers.

✅ Verification successful

Let me analyze the implementation of table renaming across different database drivers based on the results. I can see that:

  1. All major database drivers (MySQL, PostgreSQL, SQLite, SQLServer) have implemented the CompileRename method
  2. Each implementation follows database-specific syntax:
    • MySQL: rename table old_name to new_name
    • PostgreSQL: alter table old_name rename to new_name
    • SQLite: alter table old_name rename to new_name
    • SQLServer: sp_rename old_name, new_name
  3. Error handling is in place with SchemaFailedToRenameTable error type

Let me verify the atomicity of these operations by checking the transaction handling:


Let me try a different approach to check the schema execution and transaction handling:


Let me check the migration and schema implementation to understand how rename operations are executed:


Based on the analysis of the codebase, I can now generate the final response:

Table renaming operations are properly implemented with database-specific handling

The implementation ensures atomic renaming operations through:

  • Database-specific SQL syntax in each grammar implementation:
    • MySQL: rename table old_name to new_name
    • PostgreSQL: alter table old_name rename to new_name
    • SQLite: alter table old_name rename to new_name
    • SQLServer: sp_rename old_name, new_name
  • Error handling with SchemaFailedToRenameTable error type
  • Command-based execution through the Blueprint interface ensuring atomic operations
  • Proper table name wrapping and escaping via the grammar's wrap utility
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the implementation of table renaming across different database drivers

# Check for rename implementation in database drivers
echo "Checking rename implementation in database drivers..."
rg -A 5 "CompileRename.*Blueprint" --type go

# Verify error handling for rename operations
echo "Checking error handling for rename operations..."
rg "SchemaFailedToRename" --type go

Length of output: 7754


Script:

#!/bin/bash
# Check transaction handling around rename operations
echo "Checking transaction handling..."
rg -B 3 -A 3 "CompileRename.*Blueprint" --type go --glob "database/schema/schema.go"

# Check if rename operations are part of a transaction
echo "Checking transaction context..."
rg "transaction|beginTransaction|commit|rollback" --type go --glob "database/schema/schema.go"

Length of output: 327


Script:

#!/bin/bash
# Check schema execution implementation
echo "Checking schema execution..."
rg -B 5 -A 10 "func.*Build" --type go --glob "database/schema/schema.go"

# Check rename command execution
echo "Checking rename command handling..."
rg -B 5 -A 10 "func.*Rename" --type go --glob "database/schema/builder.go"

# Look for transaction-related code in the database package
echo "Checking transaction handling in database package..."
rg -l "transaction|beginTransaction|commit|rollback" --type go --glob "database/**/*.go"

Length of output: 1104


Script:

#!/bin/bash
# Check schema implementation
echo "Checking schema implementation..."
rg -B 5 -A 10 "Rename.*string" --type go

# Check migration execution
echo "Checking migration execution..."
rg -B 5 -A 10 "func.*up|func.*down" --type go --glob "database/migration/*.go"

# Check actual SQL execution
echo "Checking SQL execution..."
rg -B 5 -A 10 "exec.*sql" --type go --glob "database/**/*.go"

Length of output: 33632

errors/list.go (1)

119-121: LGTM: Error messages follow consistent patterns

The new error variables are well-defined and follow the existing error message patterns, with proper placeholders for dynamic values.

database/schema/grammars/sqlite.go (1)

179-181: LGTM: SQLite rename implementation is correct

The CompileRename method correctly implements the SQLite syntax for renaming tables using ALTER TABLE ... RENAME TO and properly handles table name escaping through the wrap utility.

database/schema/blueprint.go (2)

294-301: LGTM: Clean implementation of the Rename method.

The implementation follows the established pattern of command creation in the Blueprint struct.


459-460: LGTM: Proper integration of rename command in ToSql.

The rename command handling is correctly integrated into the switch statement.

database/schema/grammars/postgres.go (1)

214-216: LGTM: Correct PostgreSQL rename table syntax.

The implementation properly generates the ALTER TABLE RENAME statement with escaped identifiers.

database/schema/grammars/sqlserver.go (1)

63-63: LGTM: Consistent parameter naming.

The update to use underscore placeholders for unused parameters improves code consistency.

Also applies to: 75-75, 89-89, 93-93, 97-97, 132-132

database/schema/schema.go (1)

296-299: Change looks good: Sql method now returns an error

The Sql method has been updated to return an error instead of logging a fatal message. This improves error handling by allowing the caller to manage the error appropriately.

database/schema/schema_test.go (7)

Line range hint 51-55: Initialize prefix before using it

Ensure that the prefix field is initialized before it is used to construct table names. This avoids potential nil reference errors or incorrect table naming.


Line range hint 1355-1367: Ensure correct foreign key assertions in tests

In the TestForeign method, verify that the assertions for foreign keys are accurate, especially concerning the prefix in the table names and the foreign key names. This is important for consistency across different database drivers.


1874-1874: Update TestSql to handle errors properly

The test now checks for errors returned by the schema.Sql method instead of assuming success. This improvement ensures that any issues with executing raw SQL are caught during testing.


1885-1915: Add tests for custom types: TestTypeMethods

The TestTypeMethods function adds tests for creating and checking custom PostgreSQL types. This enhances test coverage for advanced schema features.


1917-1975: Enhance table methods tests: TestTableMethods

The TestTableMethods function provides comprehensive testing for table operations such as creating, renaming, and dropping tables. This ensures that the new Rename method and other table operations function correctly across different database drivers.


2030-2058: Add tests for views: TestViewMethods

The TestViewMethods function tests the creation and existence of views in the database. This addition improves the test suite's coverage of view-related schema operations.


147-154: Verify that column dropping functions as expected

The test drops columns from the table and checks that they no longer exist. Ensure that the DropColumns method works across all supported database drivers and that the test accurately reflects the expected behavior.

Run the following script to verify column existence after dropping:

✅ Verification successful

Column dropping functionality is properly implemented across all supported database drivers

The verification of the code reveals that:

  • The DropColumns functionality is properly implemented in the Schema layer and correctly delegates to driver-specific implementations
  • All major database drivers (MySQL, PostgreSQL, SQLite, SQLServer) have proper implementations of CompileDropColumn with appropriate SQL syntax:
    • MySQL: alter table table_name drop column1, drop column2
    • PostgreSQL: alter table table_name drop column column1, drop column column2
    • SQLite: alter table table_name drop column column1; alter table table_name drop column column2
    • SQLServer: Handles both column dropping and constraint cleanup

The test case correctly verifies the behavior by:

  1. Creating columns ("name", "age", "weight")
  2. Verifying their existence
  3. Dropping them using both DropColumn and DropColumns methods
  4. Verifying they no longer exist
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that columns 'name', 'age', and 'weight' are dropped from 'column_methods' table.

# Test: Check for the absence of the specified columns.

psql -c "\d+ goravel_column_methods"
mysql -e "DESCRIBE goravel_column_methods;"
sqlite3 database.db "PRAGMA table_info('goravel_column_methods');"

Length of output: 448


Script:

#!/bin/bash
# Let's analyze the test implementation and related code to verify the column dropping functionality

# First, let's find the implementation of DropColumns method
ast-grep --pattern 'func $$$DropColumns($$$) $$$'

# Then, let's check for any related tests
rg "DropColumns?" -A 5 -B 5

# Finally, let's check if there are any driver-specific implementations
fd "mysql|sqlite|postgres" --exec rg "DropColumns?" {} -A 5 -B 5

Length of output: 30900

database/schema/constants/constants.go (1)

19-19: Addition of CommandRename constant

The new CommandRename constant enables the renaming of tables within the schema blueprint. This is a necessary addition to support the Rename method in schema operations.

database/schema/postgres_schema.go (2)

73-73: Simplify schema comparison by removing redundant variable

The removal of the local schema variable in favor of directly using r.schema streamlines the code and reduces redundancy. Ensure that this change does not affect the correctness of schema comparisons.


107-107: Consistent schema usage in DropAllViews

By directly using r.schema, the code becomes clearer and avoids unnecessary variable assignments. This change maintains consistency in how the schema is referenced within the method.

coderabbitai[bot]
coderabbitai bot previously approved these changes Dec 6, 2024
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
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 and nitpick comments (1)
database/schema/sqlite_schema.go (1)

67-70: Enhance the comment about VACUUM operation

While the current comment explains why VACUUM is outside the transaction, it would be more helpful to provide additional context.

Consider expanding the comment:

-// cannot VACUUM from within a transaction
+// SQLite VACUUM operation must be executed outside a transaction
+// as it requires exclusive access to the database
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between e6830d3 and b487d9f.

📒 Files selected for processing (1)
  • database/schema/sqlite_schema.go (2 hunks)
🔇 Additional comments (2)
database/schema/sqlite_schema.go (2)

Line range hint 51-65: LGTM: Transaction block with proper error handling

The transaction block correctly handles the sequence of operations with proper error propagation.


Line range hint 51-72: Verify consistency with other schema operations

The error handling pattern implemented here should be consistent across other schema operations.

✅ Verification successful

The verification results show that:

  1. CompileRebuild() is consistently used outside transactions (as required for VACUUM operations in SQLite) and returns the "vacuum" command
  2. The error handling pattern is consistent across the codebase
  3. The comment about not being able to VACUUM within a transaction is accurate and reflected in the implementation

Error handling and transaction management are correctly implemented

The code follows the established pattern where:

  • Schema-modifying operations are wrapped in transactions
  • VACUUM (CompileRebuild) is correctly executed outside the transaction
  • Error handling is consistent throughout the implementation
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check error handling patterns in other schema methods
# and usage of CompileRebuild across the codebase

# Check error handling patterns in schema methods
ast-grep --pattern 'func \(r \*SqliteSchema\) \$_\(\$\$\$\) error {
  $$$
  if err := r.orm.Transaction\(\$\$\$\); err != nil {
    return err
  }
  $$$
}'

# Check CompileRebuild usage
rg "CompileRebuild" -A 5 -B 5

Length of output: 2085

@hwbrzzl hwbrzzl merged commit 62b24a9 into master Dec 6, 2024
@hwbrzzl hwbrzzl deleted the bowen/#280-27 branch December 6, 2024 09:24
@coderabbitai coderabbitai bot mentioned this pull request Dec 18, 2024
1 task
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

✨ [Feature] Refactor database migrate

1 participant