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: [#280] Add Time methods #733

Merged
merged 15 commits into from
Nov 30, 2024
Merged

feat: [#280] Add Time methods #733

merged 15 commits into from
Nov 30, 2024

Conversation

hwbrzzl
Copy link
Contributor

@hwbrzzl hwbrzzl commented Nov 21, 2024

📑 Description

Summary by CodeRabbit

  • New Features

    • Enhanced database schema capabilities with new methods for defining various column types (e.g., Date, DateTime, Timestamp) across multiple database grammars.
    • Added support for default values, current timestamp handling, and on-update behaviors in column definitions.
  • Bug Fixes

    • Improved timezone handling in database connections and Carbon object conversions.
  • Tests

    • Expanded test coverage for timestamp types and new column attributes across various database drivers.

✅ Checks

  • Added test cases for my code

Copy link
Contributor

coderabbitai bot commented Nov 21, 2024

Walkthrough

This pull request introduces significant enhancements to the database schema management functionality across various components. New methods are added to the Blueprint, ColumnDefinition, and Grammar interfaces to support additional column types, including date and time variations, as well as improved handling of default values and timestamp behaviors. Modifications to the MySQL, PostgreSQL, SQLite, and SQL Server grammars further expand the capabilities for generating SQL definitions. Additionally, updates to tests ensure comprehensive coverage for the new functionalities and behaviors introduced in this update.

Changes

File Path Change Summary
contracts/database/schema/blueprint.go Added methods for various column types (Date, DateTime, SoftDeletes, etc.) to the Blueprint interface.
contracts/database/schema/column.go Added methods for default values and timestamp behaviors to the ColumnDefinition interface.
contracts/database/schema/grammar.go Added methods for date and time column types to the Grammar interface.
database/gorm/test_utils.go Modified MockMysql struct to change timezone return value from "Local" to "UTC".
database/schema/blueprint.go Added methods for various column types to the Blueprint struct.
database/schema/column.go Enhanced ColumnDefinition struct with new fields and methods for managing column attributes.
database/schema/grammars/mysql.go Added methods for handling date and time types; introduced ModifyOnUpdate method.
database/schema/grammars/mysql_test.go Enhanced tests for MySQL schema operations, focusing on OnUpdate behavior.
database/schema/grammars/postgres.go Added methods for date and time types to the Postgres struct.
database/schema/grammars/postgres_test.go Introduced tests for timestamp functionalities in PostgreSQL.
database/schema/grammars/sqlite.go Added methods for various SQL types to the Sqlite struct.
database/schema/grammars/sqlserver.go Added methods for handling various SQL data types to the Sqlserver struct.
database/schema/grammars/sqlserver_test.go Introduced tests for timestamp types in SQL Server.
database/schema/grammars/utils.go Introduced Expression type and modified getDefaultValue function to handle it.
database/schema/grammars/utils_test.go Added test case for Expression type in getDefaultValue.
database/schema/schema_test.go Enhanced tests for database schema functionalities, adding new test cases for column attributes.
foundation/application.go Updated methods for error handling and environment configuration in the Application struct.
support/carbon/carbon.go Modified timezone handling in FromStdTime and SetTimezone functions.
contracts/database/schema/index.go Introduced a new type IndexConfig for configuring index properties.

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.

Copy link

codecov bot commented Nov 21, 2024

Codecov Report

Attention: Patch coverage is 68.93617% with 73 lines in your changes missing coverage. Please review.

Project coverage is 69.47%. Comparing base (65c6a08) to head (d5a8ab9).
Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
database/schema/grammars/sqlite.go 8.33% 22 Missing ⚠️
database/schema/grammars/mysql.go 74.19% 16 Missing ⚠️
database/schema/grammars/sqlserver.go 52.94% 16 Missing ⚠️
database/schema/grammars/postgres.go 45.45% 12 Missing ⚠️
database/schema/blueprint.go 89.28% 5 Missing and 1 partial ⚠️
support/carbon/carbon.go 50.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #733      +/-   ##
==========================================
+ Coverage   69.40%   69.47%   +0.07%     
==========================================
  Files         210      210              
  Lines       17040    17257     +217     
==========================================
+ Hits        11827    11990     +163     
- Misses       4556     4610      +54     
  Partials      657      657              

☔ 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 November 30, 2024 08:39
@hwbrzzl hwbrzzl requested a review from a team as a code owner November 30, 2024 08:39
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 (28)
database/schema/grammars/utils.go (2)

13-14: Consider adding validation and documentation for Expression type

The Expression type could benefit from additional safety mechanisms since it's used in SQL context. Consider:

  1. Adding validation methods to ensure safe SQL expressions
  2. Including documentation about proper usage and potential risks
  3. Implementing it as a struct with validation rather than a simple type alias

Example implementation:

// Expression represents a raw SQL expression that will be inserted directly into queries.
// IMPORTANT: Only use this for trusted input to prevent SQL injection.
type Expression struct {
    value string
}

func NewExpression(value string) (Expression, error) {
    // Add validation logic here
    return Expression{value: value}, nil
}

func (e Expression) String() string {
    return e.value
}

36-42: Add documentation for default value handling

Consider adding documentation to explain the type handling behavior, especially for the Expression type which bypasses quotes.

+// getDefaultValue converts various types to their SQL default value representation.
+// Special handling:
+// - bool: converted to '1' or '0'
+// - Expression: used as-is without quotes (careful: must be trusted input)
+// - others: wrapped in quotes after string conversion
 func getDefaultValue(def any) string {
contracts/database/schema/column.go (2)

8-9: Consider adding type constraints for default values

The Default(def any) method uses any type which provides flexibility but might lead to runtime errors if incompatible types are provided for specific column types.

Consider creating specific methods for common default value types or adding runtime type checking, for example:

-Default(def any) ColumnDefinition
+Default(def any) ColumnDefinition // For backward compatibility
+DefaultString(def string) ColumnDefinition
+DefaultInt(def int) ColumnDefinition
+DefaultTime(def time.Time) ColumnDefinition

Line range hint 1-53: Interface changes look good overall!

The additions maintain good interface design principles with consistent method chaining, clear documentation, and focused functionality for time-related features.

Consider adding code examples in the interface documentation to demonstrate typical usage patterns of these new time-related methods together.

database/schema/column.go (3)

38-42: Consider adding type validation for timestamp defaults

While the implementation is correct, consider adding validation for timestamp-related default values to prevent runtime issues with incompatible types.

 func (r *ColumnDefinition) Default(def any) schema.ColumnDefinition {
+	// Validate timestamp-related defaults
+	if r.GetType() == "timestamp" || r.GetType() == "datetime" {
+		switch def.(type) {
+		case string, time.Time, nil:
+			// valid types
+		default:
+			panic("Invalid default value type for timestamp column")
+		}
+	}
 	r.def = def
 	return r
 }

92-94: Add documentation for expected return types

Consider adding documentation to clarify the expected types that can be returned by GetOnUpdate().

+// GetOnUpdate returns the ON UPDATE clause value.
+// The return value can be:
+// - string: for constant values
+// - time.Time: for specific timestamps
+// - nil: when no ON UPDATE clause is set
 func (r *ColumnDefinition) GetOnUpdate() any {
 	return r.onUpdate
 }

154-158: Consider adding validation for ON UPDATE values

Similar to the Default method, consider adding validation for the ON UPDATE values to ensure they are compatible with timestamp columns.

 func (r *ColumnDefinition) OnUpdate(value any) schema.ColumnDefinition {
+	// Validate ON UPDATE values
+	if r.GetType() == "timestamp" || r.GetType() == "datetime" {
+		switch value.(type) {
+		case string, time.Time, nil:
+			// valid types
+		default:
+			panic("Invalid ON UPDATE value type for timestamp column")
+		}
+	}
 	r.onUpdate = value
 	return r
 }
contracts/database/schema/grammar.go (1)

Line range hint 42-77: Consider interface segregation in future iterations

While the current additions are well-structured, the Grammar interface is growing quite large. Consider splitting it into more focused interfaces in future iterations (e.g., separating type definitions from other grammar operations) to improve maintainability and follow the Interface Segregation Principle.

support/carbon/carbon.go (1)

145-145: LGTM! Consider adding timezone conversion test cases.

The change to use getTimezone(nil) aligns with the package's consistent timezone handling pattern. This ensures that the timezone behavior matches other time conversion functions in the package.

Consider adding test cases to verify the timezone conversion behavior, especially for:

  • Converting time.Time with different source timezones
  • Behavior when default timezone is set vs. unset
  • UTC fallback behavior
func TestFromStdTime(t *testing.T) {
    // Test with default timezone
    SetTimezone("America/New_York")
    utcTime := time.Now().UTC()
    carbonTime := FromStdTime(utcTime)
    assert.Equal(t, "America/New_York", carbonTime.Timezone())

    // Test with UTC fallback
    SetTimezone("")
    carbonTime = FromStdTime(utcTime)
    assert.Equal(t, "UTC", carbonTime.Timezone())
}
contracts/database/schema/blueprint.go (3)

74-77: LGTM! Consider documenting default column names.

The soft delete methods are well-designed with flexible column naming.

Consider documenting the default column name (likely "deleted_at") in the interface comments to help implementers maintain consistency across different database drivers.


86-93: Enhance documentation for Timestamps methods.

The timestamp methods are well-designed, but the Timestamps/TimestampsTz methods could benefit from more detailed documentation.

Consider adding more detailed comments for Timestamps/TimestampsTz to specify:

  • The exact column names that will be created (created_at, updated_at)
  • Whether the columns are nullable by default
  • The default precision value if none is specified

Line range hint 18-93: Comprehensive time-related column support.

The added methods provide a complete set of time-related column definitions that:

  • Cover all common database time types (date, time, datetime, timestamp)
  • Support timezone variants consistently
  • Include soft delete functionality
  • Follow established ORM patterns

Consider adding examples to the package documentation showing common use cases for these time-related methods, particularly around timezone handling and precision specifications.

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

Missing test coverage for SQLite type methods

The SQLite implementation lacks comprehensive test coverage compared to other database grammars. While MySQL, PostgreSQL, and SQL Server have extensive type method tests, SQLite only has a test for TypeEnum. Critical areas missing tests include:

  • Date/time type methods and their delegation chains
  • Integer type variants
  • Text type variants
  • Default value handling (especially CURRENT_TIMESTAMP in TypeTimestamp)

Locations needing test coverage:

  • database/schema/grammars/sqlite_test.go: Add test cases for all type methods following patterns from other grammar test files
🔗 Analysis chain

Line range hint 172-261: Verify test coverage for new type methods

While the implementation is solid, ensure comprehensive test coverage for:

  1. Date/time type conversions
  2. Default value handling (especially CURRENT_TIMESTAMP)
  3. Type method delegation chains (e.g., DateTimeTz -> DateTime -> Timestamp)

Let's check the test coverage:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for related test files and coverage
fd -g '*_test.go' -x rg -l 'TestType(Date|Time|Timestamp|Integer|String)'

Length of output: 205


Script:

#!/bin/bash
# Check if SQLite grammar has test coverage
rg -l "sqlite_test.go"

# Look for type-related tests in other grammar test files
rg "func.*Test.*Type" ./database/schema/grammars/*_test.go -A 2

# Check if there are any type-related tests in SQLite implementation
rg "Test.*Type" ./database/schema/grammars/sqlite_test.go || echo "No SQLite test file found"

Length of output: 6911

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

304-326: LGTM! Consider adding documentation about type differences.

The implementation correctly handles:

  • Current timestamp defaults
  • Precision for both types
  • Proper type mapping (datetime/datetime2 vs datetimeoffset)

Consider adding comments to document the behavioral differences between these types, especially regarding timezone handling.

Add documentation like:

 func (r *Sqlserver) TypeTimestamp(column schema.ColumnDefinition) string {
+	// Uses datetime2 when precision is specified, otherwise falls back to datetime
+	// datetime2 provides more precision and a larger date range than datetime
database/schema/grammars/sqlserver_test.go (2)

318-330: Consider adding more test cases for comprehensive coverage

The timestamp test covers basic scenarios well, but could be enhanced with additional cases:

  • Test when GetUseCurrent() returns false
  • Test behavior with custom default values
  • Test with negative precision values to ensure proper error handling

Example additional test case:

 func (s *SqlserverSuite) TestTypeTimestamp() {
+    // Test with GetUseCurrent() = false
+    mockColumn := mocksschema.NewColumnDefinition(s.T())
+    mockColumn.EXPECT().GetUseCurrent().Return(false).Once()
+    mockColumn.EXPECT().GetPrecision().Return(3).Once()
+    s.Equal("datetime2(3)", s.grammar.TypeTimestamp(mockColumn))
+
+    // Test with custom default value
+    mockColumn = mocksschema.NewColumnDefinition(s.T())
+    mockColumn.EXPECT().GetUseCurrent().Return(false).Once()
+    mockColumn.EXPECT().GetDefault().Return("2024-01-01").Once()
+    mockColumn.EXPECT().GetPrecision().Return(3).Once()
+    s.Equal("datetime2(3)", s.grammar.TypeTimestamp(mockColumn))

332-344: Add timezone-specific test cases

While the basic functionality is tested, consider adding test cases that verify timezone-specific behaviors:

  • Test with explicit timezone offsets
  • Test with named time zones
  • Test behavior when timezone conversion is needed

Example additional test case:

 func (s *SqlserverSuite) TestTypeTimestampTz() {
+    // Test with explicit timezone offset
+    mockColumn := mocksschema.NewColumnDefinition(s.T())
+    mockColumn.EXPECT().GetUseCurrent().Return(false).Once()
+    mockColumn.EXPECT().GetDefault().Return("2024-01-01 12:00:00 +00:00").Once()
+    mockColumn.EXPECT().GetPrecision().Return(3).Once()
+    s.Equal("datetimeoffset(3)", s.grammar.TypeTimestampTz(mockColumn))
database/schema/grammars/postgres.go (2)

306-312: Consider documenting the precision parameter

The implementation correctly handles time types with and without time zones, including precision. Consider adding a comment explaining the valid precision range (0-6) for PostgreSQL time types.


Time-related types are partially tested, but coverage could be improved

The test suite shows coverage for TypeTimestamp and TypeTimestampTz, but lacks tests for:

  • TypeTime and TypeTimeTz
  • TypeDate
  • TypeDateTime and TypeDateTimeTz
  • Different precision values
  • Edge cases in time zone handling

Consider adding test cases for these missing scenarios to ensure robust handling of all time-related data types.

🔗 Analysis chain

Line range hint 224-328: Ensure comprehensive test coverage for time-related edge cases

While the implementation is solid, consider adding tests for the following scenarios:

  1. Different precision values for time/timestamp types
  2. Time zone handling edge cases
  3. Default value behavior with UseCurrent
  4. Interaction between these types and existing schema operations
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for existing test coverage
rg -l "Test.*Type.*Time" --type go

Length of output: 160


Script:

#!/bin/bash
# Check the actual test coverage for time-related methods in postgres_test.go
rg "func Test.*Time" database/schema/grammars/postgres_test.go -B1 -A10

Length of output: 73


Script:

#!/bin/bash
# Let's check all test functions in postgres_test.go to see the coverage
rg "^func Test" database/schema/grammars/postgres_test.go -A2

Length of output: 136


Script:

#!/bin/bash
# Let's check the test suite structure and methods being tested
rg "func \(.*PostgresSuite\)" database/schema/grammars/postgres_test.go -A2

Length of output: 3659

database/schema/blueprint.go (3)

67-69: LGTM! Consider adding documentation.

The Date, Time, and TimeTz methods are well-implemented with consistent patterns and proper handling of precision parameters. However, documentation would be beneficial to explain the behavior and usage of these methods.

Consider adding GoDoc comments for each method explaining:

  • The purpose and SQL type generated
  • The precision parameter behavior (for Time/TimeTz)
  • Example usage

Also applies to: 251-258, 260-267


278-281: Consider making nullable behavior configurable.

The Timestamps and TimestampsTz methods always create nullable columns. Consider adding an option to configure this behavior, as some applications might require non-nullable timestamp columns.

Example implementation:

-func (r *Blueprint) Timestamps(precision ...int) {
+func (r *Blueprint) Timestamps(nullable bool, precision ...int) {
+    timestamp1 := r.Timestamp("created_at", precision...)
+    timestamp2 := r.Timestamp("updated_at", precision...)
+    if nullable {
+        timestamp1.Nullable()
+        timestamp2.Nullable()
+    }
}

-func (r *Blueprint) TimestampsTz(precision ...int) {
+func (r *Blueprint) TimestampsTz(nullable bool, precision ...int) {
+    timestamp1 := r.TimestampTz("created_at", precision...)
+    timestamp2 := r.TimestampTz("updated_at", precision...)
+    if nullable {
+        timestamp1.Nullable()
+        timestamp2.Nullable()
+    }
}

Also applies to: 283-286


217-224: LGTM! Consider documenting soft delete behavior.

The SoftDeletes and SoftDeletesTz methods are well-implemented, following standard soft delete patterns. Consider adding documentation to explain:

  • The soft delete concept and usage
  • How these columns integrate with the ORM's soft delete functionality
  • The impact of timezone-aware vs non-timezone-aware columns

Also applies to: 226-233

database/schema/grammars/postgres_test.go (2)

394-400: LGTM! Well-structured test for timestamp without time zone.

The test properly validates the timestamp SQL generation with precision and default value handling.

Consider adding test cases for:

  • Different precision values
  • When useCurrent is false
  • Custom default values
 func (s *PostgresSuite) TestTypeTimestamp() {
-	mockColumn := mocksschema.NewColumnDefinition(s.T())
-	mockColumn.EXPECT().GetUseCurrent().Return(true).Once()
-	mockColumn.EXPECT().Default(Expression("CURRENT_TIMESTAMP")).Return(mockColumn).Once()
-	mockColumn.EXPECT().GetPrecision().Return(3).Once()
-	s.Equal("timestamp(3) without time zone", s.grammar.TypeTimestamp(mockColumn))
+	s.Run("with current timestamp", func() {
+		mockColumn := mocksschema.NewColumnDefinition(s.T())
+		mockColumn.EXPECT().GetUseCurrent().Return(true).Once()
+		mockColumn.EXPECT().Default(Expression("CURRENT_TIMESTAMP")).Return(mockColumn).Once()
+		mockColumn.EXPECT().GetPrecision().Return(3).Once()
+		s.Equal("timestamp(3) without time zone", s.grammar.TypeTimestamp(mockColumn))
+	})
+	
+	s.Run("with custom default", func() {
+		mockColumn := mocksschema.NewColumnDefinition(s.T())
+		mockColumn.EXPECT().GetUseCurrent().Return(false).Once()
+		mockColumn.EXPECT().GetPrecision().Return(6).Once()
+		s.Equal("timestamp(6) without time zone", s.grammar.TypeTimestamp(mockColumn))
+	})
 }

402-408: LGTM! Well-structured test for timestamp with time zone.

The test properly validates the timestamptz SQL generation with precision and default value handling.

Consider adding test cases similar to the timestamp without time zone suggestions above:

  • Different precision values
  • When useCurrent is false
  • Custom default values
 func (s *PostgresSuite) TestTypeTimestampTz() {
-	mockColumn := mocksschema.NewColumnDefinition(s.T())
-	mockColumn.EXPECT().GetUseCurrent().Return(true).Once()
-	mockColumn.EXPECT().Default(Expression("CURRENT_TIMESTAMP")).Return(mockColumn).Once()
-	mockColumn.EXPECT().GetPrecision().Return(3).Once()
-	s.Equal("timestamp(3) with time zone", s.grammar.TypeTimestampTz(mockColumn))
+	s.Run("with current timestamp", func() {
+		mockColumn := mocksschema.NewColumnDefinition(s.T())
+		mockColumn.EXPECT().GetUseCurrent().Return(true).Once()
+		mockColumn.EXPECT().Default(Expression("CURRENT_TIMESTAMP")).Return(mockColumn).Once()
+		mockColumn.EXPECT().GetPrecision().Return(3).Once()
+		s.Equal("timestamp(3) with time zone", s.grammar.TypeTimestampTz(mockColumn))
+	})
+	
+	s.Run("with custom default", func() {
+		mockColumn := mocksschema.NewColumnDefinition(s.T())
+		mockColumn.EXPECT().GetUseCurrent().Return(false).Once()
+		mockColumn.EXPECT().GetPrecision().Return(6).Once()
+		s.Equal("timestamp(6) with time zone", s.grammar.TypeTimestampTz(mockColumn))
+	})
 }
database/schema/grammars/mysql_test.go (2)

322-336: Consider restructuring the DateTime tests for better readability

While the test coverage is comprehensive, consider restructuring into separate test cases using a table-driven test approach for better readability and maintainability.

Example refactor:

 func (s *MysqlSuite) TestTypeDateTime() {
-	mockColumn := mocksschema.NewColumnDefinition(s.T())
-	mockColumn.EXPECT().GetPrecision().Return(3).Once()
-	mockColumn.EXPECT().GetUseCurrent().Return(true).Once()
-	mockColumn.EXPECT().Default(Expression("CURRENT_TIMESTAMP(3)")).Return(mockColumn).Once()
-	mockColumn.EXPECT().GetUseCurrentOnUpdate().Return(true).Once()
-	mockColumn.EXPECT().OnUpdate(Expression("CURRENT_TIMESTAMP(3)")).Return(mockColumn).Once()
-	s.Equal("datetime(3)", s.grammar.TypeDateTime(mockColumn))
-
-	mockColumn = mocksschema.NewColumnDefinition(s.T())
-	mockColumn.EXPECT().GetPrecision().Return(0).Once()
-	mockColumn.EXPECT().GetUseCurrent().Return(false).Once()
-	mockColumn.EXPECT().GetUseCurrentOnUpdate().Return(false).Once()
-	s.Equal("datetime", s.grammar.TypeDateTime(mockColumn))
+	tests := []struct {
+		name           string
+		precision      int
+		useCurrent    bool
+		useOnUpdate   bool
+		expectedType  string
+	}{
+		{
+			name:          "with precision and current timestamp",
+			precision:     3,
+			useCurrent:   true,
+			useOnUpdate:  true,
+			expectedType: "datetime(3)",
+		},
+		{
+			name:          "without precision or timestamp",
+			precision:     0,
+			useCurrent:   false,
+			useOnUpdate:  false,
+			expectedType: "datetime",
+		},
+	}
+
+	for _, test := range tests {
+		s.Run(test.name, func() {
+			mockColumn := mocksschema.NewColumnDefinition(s.T())
+			mockColumn.EXPECT().GetPrecision().Return(test.precision).Once()
+			mockColumn.EXPECT().GetUseCurrent().Return(test.useCurrent).Once()
+			mockColumn.EXPECT().GetUseCurrentOnUpdate().Return(test.useOnUpdate).Once()
+			
+			if test.useCurrent {
+				mockColumn.EXPECT().Default(Expression(fmt.Sprintf("CURRENT_TIMESTAMP(%d)", test.precision))).Return(mockColumn).Once()
+			}
+			if test.useOnUpdate {
+				mockColumn.EXPECT().OnUpdate(Expression(fmt.Sprintf("CURRENT_TIMESTAMP(%d)", test.precision))).Return(mockColumn).Once()
+			}
+			
+			s.Equal(test.expectedType, s.grammar.TypeDateTime(mockColumn))
+		})
+	}
 }

376-390: Consider restructuring the Timestamp tests for better readability

Similar to the DateTime tests, the timestamp tests would benefit from a table-driven approach for improved readability and maintainability.

Example refactor (similar to the DateTime test refactor):

 func (s *MysqlSuite) TestTypeTimestamp() {
-	mockColumn := mocksschema.NewColumnDefinition(s.T())
-	mockColumn.EXPECT().GetPrecision().Return(3).Once()
-	mockColumn.EXPECT().GetUseCurrent().Return(true).Once()
-	mockColumn.EXPECT().Default(Expression("CURRENT_TIMESTAMP(3)")).Return(mockColumn).Once()
-	mockColumn.EXPECT().GetUseCurrentOnUpdate().Return(true).Once()
-	mockColumn.EXPECT().OnUpdate(Expression("CURRENT_TIMESTAMP(3)")).Return(mockColumn).Once()
-	s.Equal("timestamp(3)", s.grammar.TypeTimestamp(mockColumn))
-
-	mockColumn = mocksschema.NewColumnDefinition(s.T())
-	mockColumn.EXPECT().GetPrecision().Return(0).Once()
-	mockColumn.EXPECT().GetUseCurrent().Return(false).Once()
-	mockColumn.EXPECT().GetUseCurrentOnUpdate().Return(false).Once()
-	s.Equal("timestamp", s.grammar.TypeTimestamp(mockColumn))
+	tests := []struct {
+		name           string
+		precision      int
+		useCurrent    bool
+		useOnUpdate   bool
+		expectedType  string
+	}{
+		{
+			name:          "with precision and current timestamp",
+			precision:     3,
+			useCurrent:   true,
+			useOnUpdate:  true,
+			expectedType: "timestamp(3)",
+		},
+		{
+			name:          "without precision or timestamp",
+			precision:     0,
+			useCurrent:   false,
+			useOnUpdate:  false,
+			expectedType: "timestamp",
+		},
+	}
+
+	for _, test := range tests {
+		s.Run(test.name, func() {
+			mockColumn := mocksschema.NewColumnDefinition(s.T())
+			mockColumn.EXPECT().GetPrecision().Return(test.precision).Once()
+			mockColumn.EXPECT().GetUseCurrent().Return(test.useCurrent).Once()
+			mockColumn.EXPECT().GetUseCurrentOnUpdate().Return(test.useOnUpdate).Once()
+			
+			if test.useCurrent {
+				mockColumn.EXPECT().Default(Expression(fmt.Sprintf("CURRENT_TIMESTAMP(%d)", test.precision))).Return(mockColumn).Once()
+			}
+			if test.useOnUpdate {
+				mockColumn.EXPECT().OnUpdate(Expression(fmt.Sprintf("CURRENT_TIMESTAMP(%d)", test.precision))).Return(mockColumn).Once()
+			}
+			
+			s.Equal(test.expectedType, s.grammar.TypeTimestamp(mockColumn))
+		})
+	}
 }
database/schema/grammars/mysql.go (2)

210-224: Simplify type assertions in ModifyOnUpdate

In the ModifyOnUpdate function, you can simplify the type assertions by using the value variable directly, avoiding unnecessary re-assertion.

Apply this diff to simplify the code:

func (r *Mysql) ModifyOnUpdate(blueprint schema.Blueprint, column schema.ColumnDefinition) string {
	onUpdate := column.GetOnUpdate()
	if onUpdate != nil {
		switch value := onUpdate.(type) {
		case Expression:
			return " on update " + string(value)
		case string:
-			if onUpdate.(string) != "" {
+			if value != "" {
				return " on update " + value
			}
		}
	}
	return ""
}

238-256: Refactor to eliminate code duplication between TypeDateTime and TypeTimestamp

The TypeDateTime and TypeTimestamp methods share similar logic for handling CURRENT_TIMESTAMP, precision, and setting default and OnUpdate expressions. Consider refactoring to extract the common functionality into a helper function to reduce duplication and improve maintainability.

Also applies to: 336-354

database/schema/schema_test.go (1)

1864-1864: Avoid hardcoding the expected number of columns

Hardcoding the expected number of columns can make the test brittle if columns are added or removed in the future. Consider verifying the presence of expected columns without asserting the total count.

Modify the assertion to focus on required columns:

-s.Equal(32, len(columnListing))
+// s.Equal(32, len(columnListing)) // Avoid hardcoding the total number of columns
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 65c6a08 and 22ab634.

⛔ Files ignored due to path filters (3)
  • mocks/database/schema/Blueprint.go is excluded by !mocks/**
  • mocks/database/schema/ColumnDefinition.go is excluded by !mocks/**
  • mocks/database/schema/Grammar.go is excluded by !mocks/**
📒 Files selected for processing (18)
  • contracts/database/schema/blueprint.go (2 hunks)
  • contracts/database/schema/column.go (4 hunks)
  • contracts/database/schema/grammar.go (2 hunks)
  • database/gorm/test_utils.go (1 hunks)
  • database/schema/blueprint.go (3 hunks)
  • database/schema/column.go (6 hunks)
  • database/schema/grammars/mysql.go (4 hunks)
  • database/schema/grammars/mysql_test.go (6 hunks)
  • database/schema/grammars/postgres.go (2 hunks)
  • database/schema/grammars/postgres_test.go (1 hunks)
  • database/schema/grammars/sqlite.go (2 hunks)
  • database/schema/grammars/sqlserver.go (2 hunks)
  • database/schema/grammars/sqlserver_test.go (1 hunks)
  • database/schema/grammars/utils.go (2 hunks)
  • database/schema/grammars/utils_test.go (1 hunks)
  • database/schema/schema_test.go (30 hunks)
  • foundation/application.go (0 hunks)
  • support/carbon/carbon.go (2 hunks)
💤 Files with no reviewable changes (1)
  • foundation/application.go
🔇 Additional comments (42)
database/schema/grammars/utils.go (1)

36-42: Verify Expression usage across the codebase

The implementation looks good, with proper type handling and consistent string wrapping. However, let's verify how the Expression type is being used across the codebase to ensure safe practices.

✅ Verification successful

Based on the output, I can now generate the final response as I have sufficient information about the Expression type usage across the codebase.

Expression type is used safely and consistently

The Expression type is primarily used for SQL-specific constants and timestamps, with consistent patterns:

  • Used for CURRENT_TIMESTAMP related operations across different SQL dialects
  • Applied in controlled contexts like column defaults and timestamp updates
  • No instances of unsafe string conversions or user input handling

The implementation in getDefaultValue aligns with these established usage patterns, where Expression values are intentionally passed through without quotes for SQL keywords and functions.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check usage patterns of Expression type to ensure safe practices

# Find all usages of Expression type
echo "Checking Expression type usage patterns..."
rg -A 3 "Expression[^\"]*" --type go

# Look for potential unsafe string conversions to Expression
echo "Checking for potential unsafe conversions..."
ast-grep --pattern 'Expression($expr)' --type go

Length of output: 8106

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

41-43: LGTM! Good test coverage for Expression handling.

The new test case appropriately verifies that Expression values are handled differently from regular strings, ensuring they're not wrapped in quotes. This is crucial for proper SQL generation.

Let's verify the Expression type definition and its usage:

✅ Verification successful

Expression type and its handling are correctly implemented

The verification confirms that:

  1. Expression is properly defined as a string type in database/schema/grammars/utils.go
  2. getDefaultValue function correctly handles Expression type by returning its raw string value without quotes
  3. The type is widely used across multiple database grammar implementations (MySQL, PostgreSQL, SQLite, SQLServer)

The test case is valid and verifies the intended behavior where Expression values should be used as-is in SQL generation, unlike regular strings that get quoted.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify Expression type definition and its usage in SQL generation
# Expected: Find Expression type definition and its usage in SQL generation

# Find Expression type definition
ast-grep --pattern 'type Expression'

# Find Expression usage in SQL generation
rg -p 'Expression.*getDefaultValue|getDefaultValue.*Expression' -g '!*_test.go'

Length of output: 120


Script:

#!/bin/bash
# Let's try a broader search for Expression type and its usage

# Find Expression type definition with more context
rg -p "type Expression" -A 5

# Find files containing Expression usage
rg -l "Expression"

# Find getDefaultValue function definition and usage
rg -p "func getDefaultValue" -A 5

Length of output: 928

contracts/database/schema/column.go (2)

34-37: Standardize timestamp handling across databases

The timestamp-related methods (UseCurrent and UseCurrentOnUpdate) might behave differently across database systems, particularly regarding timezone handling and timestamp precision.

Let's verify the timestamp implementations:

Consider:

  1. Documenting timezone behavior for each supported database
  2. Adding methods to specify timestamp precision if needed
  3. Providing a way to configure default timestamp formats

Also applies to: 50-53


24-25: Enhance cross-database compatibility handling

The OnUpdate functionality is documented as MySQL-specific, but there's no runtime validation or handling for other database systems.

Let's verify how this is handled across different database implementations:

Consider:

  1. Adding runtime checks for database type
  2. Implementing graceful fallbacks for non-MySQL databases
  3. Documenting behavior for other database systems

Also applies to: 40-41

database/schema/column.go (3)

9-23: LGTM! Well-structured field additions

The new fields follow the established patterns in the struct:

  • Consistent use of pointers where appropriate
  • Alphabetical ordering
  • Clear naming conventions

128-142: LGTM! Consistent implementation

The getter methods follow the established patterns in the codebase and properly handle nil pointer cases.


178-188: LGTM! Verify timestamp behavior in database drivers

The implementation is correct and consistent. However, ensure that the database drivers properly handle these timestamp behaviors.

✅ Verification successful

LGTM! Timestamp behavior is properly handled across database drivers

The implementation is verified to be correct. The codebase shows consistent handling of CURRENT_TIMESTAMP across all supported database drivers:

  • MySQL: Handles precision and ON UPDATE clause correctly
  • PostgreSQL: Implements both timezone and non-timezone variants
  • SQLServer: Supports datetime2 and datetimeoffset with precision
  • SQLite: Basic datetime support with CURRENT_TIMESTAMP
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for timestamp behavior handling in database drivers
rg -g '*.go' -A 5 'CURRENT_TIMESTAMP|current_timestamp' ./database/

Length of output: 14294

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

42-47: LGTM: Date-related method declarations are well-structured

The date-related method declarations follow a logical progression and maintain consistency with the interface's existing type definition patterns.


70-73: LGTM: Time-related method declarations are properly defined

The time-related method declarations provide appropriate support for both regular and time zone aware time types.


74-77: LGTM: Timestamp-related method declarations are well-defined

The timestamp-related method declarations provide appropriate support for both regular and time zone aware timestamp types.

Let's verify that all database drivers implement these new methods:

✅ Verification successful

All database drivers implement the timestamp methods correctly

The verification confirms that both TypeTimestamp and TypeTimestampTz methods are properly implemented across all database drivers:

  • MySQL: Both methods implemented (TypeTimestampTz delegates to TypeTimestamp)
  • PostgreSQL: Both methods implemented with distinct implementations
  • SQLite: Both methods implemented (TypeTimestampTz delegates to TypeTimestamp)
  • SQLServer: Both methods implemented with distinct implementations
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if all database drivers implement the new timestamp methods
# Expected: Each method should be implemented in MySQL, PostgreSQL, SQLite, and SQLServer drivers

# Search for TypeTimestamp implementations
echo "Checking TypeTimestamp implementations:"
rg "func.*TypeTimestamp.*ColumnDefinition.*string" -A 2

# Search for TypeTimestampTz implementations
echo "Checking TypeTimestampTz implementations:"
rg "func.*TypeTimestampTz.*ColumnDefinition.*string" -A 2

Length of output: 4666

support/carbon/carbon.go (1)

36-36: Verify the global timezone setting impact

The addition of carbon.SetDefault affects the global default timezone. While this ensures consistency between the local clock and the carbon library, it's important to verify that this global change doesn't cause unexpected behavior in other parts of the application.

Consider documenting this global behavior in the package documentation to make it clear to other developers that calling SetTimezone affects the entire application.

✅ Verification successful

Let's gather more specific information about the timezone usage to understand the potential impact.


Based on the gathered information, I can now provide a final response:

Global timezone setting is properly managed

The carbon.SetDefault usage in SetTimezone is safe and consistent with the application's design because:

  • The timezone setting is centrally managed through the application's configuration (app.timezone)
  • The framework properly initializes it during application bootstrap in foundation/application.go
  • All timezone-sensitive operations consistently use this configuration
  • Tests are properly configured to use UTC timezone, maintaining consistency

The change aligns the carbon library's default timezone with the application's configured timezone, which is the expected behavior.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for other uses of carbon.SetDefault or timezone-sensitive operations
rg -l "carbon\.SetDefault|\.Timezone|\.timezone" --type go

# Search for tests that might be affected by timezone changes
rg -l "Test.*Time|Test.*Date|Test.*Zone" --type go

Length of output: 836


Script:

#!/bin/bash
# Check how timezone is used in the affected files
rg -A 5 -B 5 "\.Timezone|\.timezone" --type go

# Check carbon usage in tests
rg -A 5 -B 5 "carbon\." support/carbon/carbon_test.go

# Check if there are any other SetDefault calls
ast-grep --pattern 'carbon.SetDefault($_)'

Length of output: 15065

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

82-85: LGTM! Time methods are consistent with DateTime pattern.

The Time and TimeTz methods maintain consistency with the DateTime methods, including precision handling and timezone support.


18-23: LGTM! Verify precision handling across different databases.

The Date-related method signatures are well-designed and consistent with the interface's patterns. The optional precision parameter for DateTime/DateTimeTz is appropriate.

Let's verify how precision is handled across different database implementations:

✅ Verification successful

Precision handling is properly implemented across database implementations

The verification shows that precision handling for DateTime/DateTimeTz is correctly implemented:

  • MySQL: Implements precision with datetime(precision) format and handles CURRENT_TIMESTAMP(precision)
  • PostgreSQL: Maps to timestamp types with precision support
  • SQLite: Maps to timestamp type (SQLite internally handles precision)
  • SQLServer: Maps to timestamp type with precision support

The implementation is consistent across different database grammars and follows each database's specific requirements for precision handling.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for DateTime/DateTimeTz precision handling in database-specific implementations
ast-grep --pattern 'func $_($$) {
  $$$
  DateTime($_, $$$)
  $$$
}'

Length of output: 70


Script:

#!/bin/bash
# Let's try a broader search for DateTime implementations
rg -l "DateTime" --type go

# Then look for specific implementations
rg "DateTime.*\(" -A 5 --type go

Length of output: 56937

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

244-250: Verify CURRENT_TIMESTAMP behavior across SQLite versions

The implementation correctly sets CURRENT_TIMESTAMP as default when UseCurrent is true. However, consider:

  1. SQLite's behavior with CURRENT_TIMESTAMP might vary between versions
  2. The timestamp precision might need documentation

Let's check for any version-specific handling:

✅ Verification successful

Let me search for SQLite-specific version handling and any potential precision configurations.


Let me check the SQLite test files specifically for timestamp-related test cases.


SQLite timestamp implementation is consistent with standard behavior

The implementation is correct and safe across SQLite versions because:

  1. SQLite stores timestamps internally as 'datetime' text format which is version-agnostic
  2. The CURRENT_TIMESTAMP default value is a standard SQLite feature supported across all modern versions
  3. The code correctly handles timezone variants by delegating them to the base timestamp implementation
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for SQLite version checks or timestamp precision handling
rg -g '*.go' 'sqlite.*version|CURRENT_TIMESTAMP|timestamp.*precision'

Length of output: 4745


Script:

#!/bin/bash
# Search for SQLite-specific configurations and version handling
rg -g '*.go' 'sqlite.*config|sqlite.*precision|sqlite.*datetime'

# Also check for any SQLite test cases related to timestamps
rg -g '*_test.go' -B 2 -A 2 'TypeTimestamp.*sqlite|datetime.*sqlite'

Length of output: 137


Script:

#!/bin/bash
# Check SQLite test files for timestamp handling
rg -g 'sqlite_test.go' -B 3 -A 3 'datetime|timestamp|CURRENT_TIMESTAMP'

# Also check the SQLite grammar implementation for any additional timestamp-related code
cat database/schema/grammars/sqlite.go

Length of output: 9710


224-230: Document integer type mapping implications

SQLite maps all integer types (TINYINT, SMALLINT, etc.) to a 64-bit INTEGER. This implementation is correct, but it has implications:

  1. Size constraints aren't enforced at the database level
  2. Memory usage might differ from other databases

Let's check if there are any size validations elsewhere in the codebase:

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

292-302: LGTM! Time type implementations align with SQL Server's behavior.

The implementation correctly:

  • Handles time precision using time(n) syntax
  • Delegates timezone-aware time to regular time type (as SQL Server doesn't have a separate time with timezone type)

288-290: LGTM! TypeText implementation is consistent with other text types.

The implementation correctly uses nvarchar(max), maintaining consistency with other text type implementations in the file.


Line range hint 218-326: Verify completeness of SQL Server type mappings.

Let's ensure all SQL Server date/time types are covered and consistently used across the codebase.

✅ Verification successful

SQL Server date/time type mappings are correctly and consistently implemented

The verification shows that:

  • All SQL Server date/time types are properly mapped: date, time, datetime, datetime2, and datetimeoffset
  • Precision handling is consistent across the codebase
  • Type delegation between related types (DateTime → Timestamp, TimeTz → Time) is correctly implemented
  • The types are used consistently in tests and schema processors
  • No unexpected direct string literals of these types are found outside of test fixtures and type definitions
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for consistent usage of SQL Server date/time types
rg -g '*.go' -A 2 'Type(Date|Time|Timestamp)' | grep 'return'

# Verify no direct string literals of these types elsewhere
rg -g '*.go' '(datetime2|datetimeoffset|time\(\d+\))'

Length of output: 8082


218-229: LGTM! Date type implementations are correct.

The implementation correctly maps:

  • date type for date-only values
  • DateTime and DateTimeTz properly delegate to their timestamp counterparts, maintaining SQL Server's datetime type system
✅ Verification successful

LGTM! Date type implementations align with SQL Server's type system

The implementation correctly follows SQL Server's datetime type system:

  • TypeDate returns "date" for date-only values
  • TypeDateTime and TypeDateTimeTz properly delegate to their timestamp counterparts which handle CURRENT_TIMESTAMP defaults
  • The implementation matches other database grammars (MySQL, PostgreSQL, SQLite) in the codebase
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Verify consistent date type handling across the codebase
ast-grep --pattern 'TypeDate($$$) {
  return "date"
}'

Length of output: 56


Script:

#!/bin/bash
# Let's search for all TypeDate implementations in grammar files
rg "TypeDate.*string" -A 2

# Also check for any other date-related type methods
rg "Type(Date|DateTime|DateTimeTz).*string" -A 2

# Let's also verify the interface definition
rg "interface.*Grammar" -A 20 

Length of output: 63868


Script:

#!/bin/bash
# Let's check the TypeTimestamp and TypeTimestampTz implementations in SQL Server grammar
rg "TypeTimestamp.*string" database/schema/grammars/sqlserver.go -A 2
rg "TypeTimestampTz.*string" database/schema/grammars/sqlserver.go -A 2

Length of output: 614

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

318-344: LGTM! Well-structured tests following established patterns

The new test methods maintain consistency with the existing test suite and follow good testing practices:

  • Proper use of mocks and expectations
  • Clear test scenarios
  • Consistent with the file's testing patterns
  • Good isolation of test cases
database/schema/grammars/postgres.go (3)

224-234: LGTM! Well-structured time type implementations

The implementation correctly maps:

  • date type for dates without time
  • DateTime and DateTimeTz as aliases to their respective timestamp types, following SQL standards

302-304: LGTM! Simple and correct implementation

The TypeText method maintains its correct functionality while being relocated for better code organization.


314-328: Consider using a constant for CURRENT_TIMESTAMP

The implementation correctly handles timestamp types with proper precision and timezone support. However, consider:

  1. Defining CURRENT_TIMESTAMP as a package-level constant to avoid string literals
  2. Verifying that the Expression type properly handles the default value setting
database/schema/blueprint.go (3)

71-78: LGTM! DateTime methods are well-implemented.

The DateTime and DateTimeTz methods follow consistent patterns and properly handle precision parameters.

Also applies to: 80-87


Line range hint 67-295: Verify integration with ORM and migrations.

The time-related methods look well-implemented. Let's verify their integration with the rest of the framework.

✅ Verification successful

Let's examine the actual usage in tests and ORM to verify the integration of these time-related methods.


Time-related methods are properly integrated and verified

The implementation is well-integrated with both the ORM and migrations:

  • All time-related methods (Date, DateTime, Timestamp, etc.) are thoroughly tested in schema_test.go
  • Proper integration with the ORM's soft deletes and timestamps through database/orm/model.go:
    • SoftDeletes struct handles deleted_at
    • Timestamps struct handles created_at and updated_at with automatic time management
  • Tests demonstrate correct usage with timezone support and precision parameters
  • Integration with the carbon datetime library for consistent time handling
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check integration points with ORM and migrations

# Check for migration tests using these methods
echo "Checking migration tests..."
rg -l "(?:Date|Time|Timestamp)" --type go --glob "*test.go"

# Check for ORM integration
echo "Checking ORM integration..."
rg -l "(?:deleted_at|created_at|updated_at)" --type go --glob "database/orm/**"

Length of output: 1313


Script:

#!/bin/bash
# Check implementation details in test files and ORM model
echo "Checking migration test implementations..."
rg "(?:Date|Time|Timestamp)" database/migration/sql_migrator_test.go database/schema/schema_test.go -C 2

echo "\nChecking ORM model timestamps..."
rg "(?:DeletedAt|CreatedAt|UpdatedAt)" database/orm/model.go -C 2

Length of output: 4065


269-276: Verify database compatibility for timestamp precision.

The implementation looks good, but different databases handle timestamp precision differently. Let's verify the implementation across different database drivers.

Also applies to: 288-295

✅ Verification successful

Based on the search results, I can now generate the final response since I have comprehensive information about how timestamp precision is handled across different database implementations:

Timestamp implementation is properly handled across all supported databases

The implementation correctly handles timestamp precision across different database drivers:

  • PostgreSQL: Uses timestamp(n) without time zone format with configurable precision
  • MySQL: Uses timestamp(n) format with precision support and proper handling of CURRENT_TIMESTAMP(n)
  • SQLite: Maps to datetime type as SQLite doesn't support precision
  • SQLServer: Uses datetime2(n) for timestamps with precision, falls back to datetime without precision

The current implementation in Blueprint.Timestamp() properly abstracts these differences by:

  1. Creating a timestamp column with the database-specific type
  2. Handling precision parameter correctly for databases that support it
  3. Properly managing CURRENT_TIMESTAMP defaults when requested
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check how timestamp precision is handled across different database implementations

# Look for timestamp-related implementations in database grammars
echo "Checking timestamp handling in database grammars..."
rg -A 5 "timestamp|Timestamp" --type go

Length of output: 94207

database/schema/grammars/mysql_test.go (3)

35-35: LGTM: Consistent GetOnUpdate expectations

The added GetOnUpdate expectations are consistently implemented across test methods, properly handling the default nil case for new columns.

Also applies to: 77-77, 92-92, 227-227, 235-235


305-320: LGTM: Comprehensive OnUpdate modification tests

The TestModifyOnUpdate method provides excellent coverage of all possible scenarios:

  • Expression type input
  • String type input
  • Empty string edge case
  • Nil case

Line range hint 322-390: Consider adding tests for invalid precision values

Both DateTime and Timestamp tests could benefit from additional test cases covering invalid precision values (e.g., negative numbers) to ensure robust error handling.

Let's check if there are any precision validation checks in the implementation:

database/gorm/test_utils.go (1)

295-295: Timezone configuration change looks good

Changing the default timezone from "Local" to "UTC" aligns with best practices for database operations. Using UTC helps avoid timezone-related issues and ensures consistent timestamp handling across different environments.

Let's verify timezone configurations across other database drivers:

✅ Verification successful

Based on the search results, I can see that:

  1. The timezone configuration change from "Local" to "UTC" in MySQL mock is consistent with other database drivers:
  • PostgreSQL uses "UTC" timezone in test configurations
  • The application defaults to "UTC" timezone when config facade is not initialized
  • The timezone setting is consistently used across the codebase for both MySQL and PostgreSQL drivers
  1. The change aligns with the codebase's overall timezone handling approach:
  • The application's default timezone is UTC
  • Database connections are configured to use UTC timezone
  • Test configurations consistently use UTC timezone

Let me generate the final response:

Timezone configuration change is consistent with codebase

The change from "Local" to "UTC" for MySQL mock's timezone configuration is consistent with the rest of the codebase. All database drivers and test configurations use UTC timezone, which is the recommended approach for database operations.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check timezone configurations across database drivers
# Expected: PostgreSQL should use UTC, other drivers may have different configurations

# Check PostgreSQL timezone configuration
echo "PostgreSQL timezone configuration:"
rg -A 1 'timezone.*UTC' 

# Check for any other timezone configurations
echo "Other timezone configurations:"
rg -A 1 'timezone|loc'

Length of output: 73785

database/schema/grammars/mysql.go (7)

30-30: ModifyOnUpdate modifier added to modifiers list

The ModifyOnUpdate function is appropriately added to the list of modifiers, ensuring that the ON UPDATE clause is handled correctly.


234-236: TypeDate method implemented correctly

The TypeDate method correctly returns the date type for date columns.


258-260: TypeDateTimeTz method correctly delegates to TypeDateTime

The TypeDateTimeTz method appropriately reuses the TypeDateTime method to handle datetime with timezone.


320-322: TypeText method reintroduced correctly

The TypeText method correctly returns the text type, ensuring support for text columns.


324-330: TypeTime method implemented correctly with precision handling

The TypeTime method correctly handles the precision property and returns the appropriate time type.


332-334: TypeTimeTz method correctly delegates to TypeTime

The TypeTimeTz method appropriately reuses the TypeTime method to handle time with timezone.


356-358: TypeTimestampTz method correctly delegates to TypeTimestamp

The TypeTimestampTz method appropriately reuses the TypeTimestamp method to handle timestamp with timezone.

database/schema/schema_test.go (5)

1283-1283: Check for potential nil pointer dereference

The test checks s.Nil(columnExtraAttribute.Nullable), but if Nullable is not a pointer, this could cause a nil pointer dereference. Ensure that Nullable is appropriately defined as a pointer type.

Confirm that Nullable is a pointer type in ColumnExtraAttribute struct.


1277-1287: 🛠️ Refactor suggestion

Avoid using time.Sleep in tests to prevent flakiness

Using time.Sleep in tests can lead to flaky tests and increased execution time. Consider mocking time or using synchronization techniques to control timing more precisely.

Refactor the test to avoid time.Sleep:

 interval := int64(1)
 // ...
-time.Sleep(time.Duration(interval) * time.Second)
+// Instead of sleeping, mock the time or adjust the test logic to avoid the need for sleep

Likely invalid or redundant comment.


263-263: Verify default value representation for string columns

The default value for string_default is database-specific. Ensure that the test accounts for variations in default value representations across different drivers.

Run the following script to confirm the default value format:

✅ Verification successful

Default value representation is correctly handled per database driver

Based on the search results, the test file already accounts for different default value representations across database drivers:

  • PostgreSQL: 'goravel'::character varying
  • MySQL: goravel (without type casting)
  • SQL Server: ('goravel')

The test is correctly validating the driver-specific default value formats, and there's no issue to fix. The variations in default value representations are already being handled appropriately in the test suite.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the default value for 'string_default' column.

# Function to extract default values from column definitions
extract_default() {
  driver=$1
  table=$2
  column=$3
  # Adjust the command based on the driver's system table queries
  case "$driver" in
    postgres)
      echo "SELECT column_default FROM information_schema.columns WHERE table_name='$table' AND column_name='$column';" | psql
      ;;
    mysql)
      echo "SELECT COLUMN_DEFAULT FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='$table' AND COLUMN_NAME='$column';" | mysql
      ;;
    sqlite)
      echo "PRAGMA table_info($table);" | sqlite3 | grep "$column"
      ;;
    sqlserver)
      # SQL Server command to extract default value
      ;;
  esac
}

# Replace with actual driver, table, and column names
for driver in postgres mysql sqlite; do
  extract_default $driver "your_table" "string_default"
done

Length of output: 1162


Script:

#!/bin/bash
# Let's analyze the test file and related schema files to understand the context better

# First, let's see the full test context
rg -B 5 -A 5 "'goravel'::character varying" database/schema/schema_test.go

# Look for string default value tests across different drivers
rg -A 5 "string_default" database/schema/

# Check for driver-specific test files or configurations
fd -t f ".*test.*" database/schema/

# Look for any driver-specific schema implementations
ast-grep --pattern 'func ($v $_) StringDefault($$$) {
  $$$
}'

Length of output: 5340


757-757: Ensure default integer values are handled consistently

The default value assertion may fail if different databases represent default values differently. Consider normalizing the default value before assertion.

Use the following script to check the default value format:


209-209: Ensure consistent default value handling across databases

Directly using cast.ToInt(column.Default) may not be reliable due to differences in how defaults are represented in different databases. Consider parsing the default value appropriately for each driver.

Run the following script to check default value formats for integer_default across drivers:

database/schema/grammars/sqlite.go Show resolved Hide resolved
database/schema/schema_test.go Outdated Show resolved Hide resolved
database/schema/schema_test.go Outdated Show resolved Hide resolved
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

🧹 Outside diff range and nitpick comments (4)
contracts/database/schema/index.go (1)

21-24: LGTM! Consider adding documentation.

The new IndexConfig struct appropriately captures the configuration options available in the IndexDefinition interface. This is a good addition that allows index configurations to be stored and reused.

Consider adding documentation comments to describe:

  • The purpose of the struct
  • The meaning and valid values for the Algorithm field
  • Any constraints or relationships with the IndexDefinition interface
+// IndexConfig stores configuration for database indexes
+// It matches the configuration options available in IndexDefinition
 type IndexConfig struct {
+	// Algorithm specifies the index algorithm (e.g., "BTREE", "HASH")
 	Algorithm string
+	// Name specifies a custom name for the index
 	Name      string
 }
contracts/database/schema/blueprint.go (1)

74-77: Enhance documentation for SoftDeletes methods.

While the method signatures are correct, the documentation could be more specific about:

  • The default column name when no parameter is provided
  • The timestamp format/precision used
  • The impact of timezone support in SoftDeletesTz

Consider updating the comments to:

-// SoftDeletes Add a "deleted at" timestamp for the table.
+// SoftDeletes Add a "deleted at" timestamp for the table. Default column name is "deleted_at" if not specified.
-// SoftDeletesTz Add a "deleted at" timestampTz for the table.
+// SoftDeletesTz Add a "deleted at" timestampTz for the table. Default column name is "deleted_at" if not specified. Stores timezone information.
database/schema/schema_test.go (2)

1822-1848: Document precision values and driver differences

The time-related column tests use magic numbers for precision and lack documentation about driver-specific behaviors.

Consider these improvements:

+       // Define precision constants
+       const (
+           defaultTimePrecision = 2
+           defaultDateTimePrecision = 3
+       )

-       table.DateTime("date_time", 3).Comment("This is a date time column")
+       table.DateTime("date_time", defaultDateTimePrecision).Comment("This is a date time column")

-       table.Time("time", 2).Comment("This is a time column")
+       table.Time("time", defaultTimePrecision).Comment("This is a time column")

-       // Add documentation about driver differences
+       // Note: Time zone handling varies by driver:
+       // - PostgreSQL: Uses timestamptz for timezone-aware columns
+       // - MySQL: Stores in UTC and converts on read
+       // - SQLite: No native timezone support
+       // - SQL Server: Uses datetimeoffset

Line range hint 78-347: Improve test maintainability for driver-specific assertions

The driver-specific column assertions have significant duplication and make it difficult to compare behavior across drivers.

Consider refactoring to use a table-driven approach:

+ type columnTypeTest struct {
+     name           string
+     expectedTypes  map[database.Driver]string
+     expectedNames  map[database.Driver]string
+     assertions     func(*suite.Suite, database.Column)
+ }

+ var timeColumnTests = []columnTypeTest{
+     {
+         name: "timestamp_tz",
+         expectedTypes: map[database.Driver]string{
+             database.DriverPostgres:  "timestamp(2) with time zone",
+             database.DriverSqlite:    "datetime",
+             database.DriverMysql:     "timestamp(2)",
+             database.DriverSqlserver: "datetimeoffset(29)",
+         },
+         assertions: func(s *suite.Suite, col database.Column) {
+             s.False(col.Autoincrement)
+             s.Empty(col.Collation)
+             // ... common assertions
+         },
+     },
+     // ... other column tests
+ }

This would:

  1. Make it easier to maintain driver-specific type mappings
  2. Reduce code duplication
  3. Make differences between drivers more visible
  4. Simplify adding new column types

Also applies to: 383-592, 624-893, 929-1198

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 22ab634 and d5a8ab9.

📒 Files selected for processing (3)
  • contracts/database/schema/blueprint.go (2 hunks)
  • contracts/database/schema/index.go (1 hunks)
  • database/schema/schema_test.go (30 hunks)
🔇 Additional comments (3)
contracts/database/schema/index.go (1)

Line range hint 1-24: Verify PR description accuracy.

There appears to be a discrepancy between the PR title/description (which mentions adding time methods) and the actual changes (which add database index configuration). This might indicate:

  1. Missing files in the review
  2. Incorrect PR description
  3. Wrong branch/commits included

Let's verify the scope of changes:

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

Line range hint 18-93: Verify coverage of time-related column types across supported databases.

The interface covers most common time-related column types. Let's verify if we have complete coverage for all supported databases.

✅ Verification successful

Time-related column types are comprehensively covered across all supported databases

Based on the search results, the interface provides complete coverage for all common time-related column types across the supported databases (MySQL, PostgreSQL, SQLite, and SQL Server):

  • Basic date and time: Date(), Time(), DateTime()
  • Timezone-aware variants: TimeTz(), DateTimeTz(), TimestampTz()
  • Timestamps: Timestamp(), Timestamps(), TimestampsTz()

The implementation is verified through:

  • Grammar interfaces defining all time-related type methods
  • Database-specific implementations in MySQL, PostgreSQL, SQLite, and SQL Server grammars
  • Comprehensive test coverage validating the type mappings
  • Support for precision parameters where applicable
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any time-related column types in database-specific implementations that might not be covered
rg -i "time|date" --type go | grep -i "type" | grep -v "interface"

Length of output: 35023


18-23: LGTM! Verify precision parameter usage across different databases.

The Date/DateTime method signatures and documentation are well-defined. The optional precision parameter for DateTime/DateTimeTz follows database column definition standards.

Let's verify how precision is handled across different database implementations:

✅ Verification successful

Precision parameter is properly implemented across database implementations

Based on the verification results:

  1. The precision parameter is correctly handled in the base implementation (database/schema/blueprint.go):
    • Both DateTime and DateTimeTz methods properly store the precision value in the column definition
  2. Database-specific implementations handle precision appropriately:
    • MySQL: Uses precision in CURRENT_TIMESTAMP(precision) and datetime(precision) formats
    • PostgreSQL: Maps to timestamp type (inherits precision handling)
    • SQLServer: Maps to timestamp type (inherits precision handling)
    • SQLite: Maps to timestamp type (inherits precision handling)
  3. The implementation is consistent with other time-related methods in the codebase that use precision (Time, Timestamp, etc.)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for DateTime/DateTimeTz precision handling in database-specific implementations
ast-grep --pattern 'func $_($$) {
  $$$
  precision $$$
  $$$
}'

Length of output: 66


Script:

#!/bin/bash
# Let's search for implementations of DateTime/DateTimeTz methods
rg -A 5 "func.*Date[T|t]ime.*\(" --type go

Length of output: 21314


Script:

#!/bin/bash
# Also search for any precision-related code in database implementations
rg "precision" --type go

Length of output: 13371


Script:

#!/bin/bash
# Find all database-specific implementation files
fd ".*sql.*\.go$"

Length of output: 1022

contracts/database/schema/blueprint.go Show resolved Hide resolved
database/schema/schema_test.go Show resolved Hide resolved
@hwbrzzl hwbrzzl merged commit 5776698 into master Nov 30, 2024
11 of 12 checks passed
@hwbrzzl hwbrzzl deleted the bowen/#280-25 branch November 30, 2024 09:55
@coderabbitai coderabbitai bot mentioned this pull request Feb 1, 2025
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.

1 participant