Conversation
|
Warning Rate limit exceeded@hwbrzzl has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 8 minutes and 37 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (3)
WalkthroughThis pull request introduces comprehensive changes to the PostgreSQL driver package, focusing on configuration management, testing improvements, and code refactoring. The modifications span across multiple files, including configuration handling, mock generation, database connection management, and test suites. Key changes include updating the configuration structure, enhancing mock generation capabilities, improving error handling, and streamlining database interaction methods. Changes
Sequence DiagramsequenceDiagram
participant Client
participant Postgres
participant Config
participant Docker
participant Gorm
Client->>Postgres: NewPostgres(config, connection)
Postgres->>Config: NewConfig(config, connection)
Postgres->>Docker: NewDocker(config)
Postgres->>Gorm: Gorm()
Gorm-->>Postgres: *gorm.DB, driver.GormQuery, error
Postgres-->>Client: Postgres instance
The sequence diagram illustrates the initialization process for the PostgreSQL driver, showing how configuration, Docker, and Gorm instances are created and connected. 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? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
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)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 11
🔭 Outside diff range comments (2)
grammar.go (1)
Line range hint
554-561: Check references to schema.ColumnType again.At line 555, pipeline fails. Migrate this usage to
contractsschemaor define a helper method.🧰 Tools
🪛 GitHub Check: test / ubuntu (1.23)
[failure] 555-555:
undefined: schema.ColumnType🪛 GitHub Check: codecov / codecov
[failure] 555-555:
undefined: schema.ColumnType🪛 GitHub Check: lint / lint
[failure] 555-555:
undefined: schema.ColumnType) (typecheck)🪛 GitHub Check: test / ubuntu (1.22)
[failure] 555-555:
undefined: schema.ColumnTypegorm.go (1)
Line range hint
89-97: Add validation for required DNS fields.The DNS generation doesn't validate required fields before formatting the string.
func (r *Gorm) dns(config contracts.FullConfig) string { if config.Dsn != "" { return config.Dsn } - if config.Host == "" { + if config.Host == "" || config.Username == "" || config.Database == "" { return "" } + + port := config.Port + if port == 0 { + port = 5432 // Default PostgreSQL port + } return fmt.Sprintf("postgres://%s:%s@%s:%d/%s?sslmode=%s&timezone=%s&search_path=%s", - config.Username, config.Password, config.Host, config.Port, config.Database, config.Sslmode, config.Timezone, config.Schema) + config.Username, config.Password, config.Host, port, config.Database, + defaultString(config.Sslmode, "disable"), + defaultString(config.Timezone, "UTC"), + defaultString(config.Schema, "public")) } + +func defaultString(value, defaultValue string) string { + if value == "" { + return defaultValue + } + return value +}
🧹 Nitpick comments (37)
postgres.go (2)
20-23: Use consistent naming for configuration references.These newly added fields might cause confusion between
configFacadeandconfig. Consider renaming them for clarity, e.g.,rawConfigvs.derivedConfig.
41-50: Ensure version retrieval is needed.Storing
versionindatabase.Configmight be optional. Verify if consumers rely on the version or if it's extraneous.Would you like help writing a separate test to confirm this version is used properly?
docker_test.go (7)
4-4: Validate format import usage.Line 4 imports
"fmt". Confirm all references are used. Otherwise, remove it.
8-9: Revisit mocking strategy.The mocks for
config.Configandcontractsmight introduce tight coupling. Consider an interface-based approach for improved maintainability.
13-23: Add field documentation.Add clarity to new suite fields:
connection,database,username,password, etc. This helps maintainers understand the suite’s purpose.
37-48: Ensure table creation test covers rollback scenario.Tests create and manipulate tables; consider verifying the environment resets or cleans up automatically in CI to avoid leftover test data.
79-79: Consider variable naming improvement.
databaseDriveris understandable but might conflict with internal usage. Possibly rename tofreshDriveror similar.
86-101: Avoid mixing multiple tests in a single method.
TestDatabaseverifies building, connecting, and shutting down. Consider splitting into smaller, more focused test methods.
103-103: Add comment for test logic.Explain the reason behind
TestImagebeyond simply verifying the Docker image assignment. This helps maintain long-term code clarity.grammar.go (19)
19-20: Document usage of prefix.Briefly explain what
prefixrepresents, e.g., table prefixes in multi-tenant schemas.
77-77: Rename command method?
CompileCommentmight conflict if there's a future naming in the framework. Evaluate prefixing all new methods withCompileorGenerate.
105-125: Drop All Tables approach.Check if you must also handle views or other object types. Also confirm if
cascadesuits all use cases or might cause unintended drops.
128-149: Refactor domain / type dropping logic.The logic is correct but consider extracting into smaller functions for clarity. For instance,
compileDropDomains()andcompileDropTypes().
166-168: Consistent naming for array-based statements.Check if
CompileDropColumnaligns with the naming convention used inCompileDropAllTablesor others. Consistency can aid maintainability.
190-190: Potential naming collision in constraints.
CompileDropPrimarymight clash if the user previously named an index that ends with_pkey. Document assumptions or add a check to avoid collisions.
201-201: Add some basic constraints checks.Appropriate for foreign keys. Consider also supporting
DEFERRABLEconstraints in the future if needed (like you did for unique).
243-245: Check default language.Defaulting to "english" for
CompileFullTextmight not suit all locales. Let’s keep it config-driven or documented.
270-277: Check table prefix injection.Here you unify
schemaandtablebut addr.prefixtotable. Guarantee no collisions occur ifschemaalso uses a prefix.
292-292: Close string formatting with caution.Ensure the final argument matches the placeholders. Some format strings can break if additional placeholders are introduced later.
Line range hint
303-307: Renaming indexes across schemas.If a user tries renaming indexes in a different schema, ensure the statement includes the schema or prefix.
Line range hint
393-403: Nullability toggles on changes.
ModifyNullableis correct logically, but watch for conflicts withModifyIncrement. Test carefully.🧰 Tools
🪛 GitHub Check: test / ubuntu (1.23)
[failure] 382-382:
undefined: schema.ColumnDefaultValue
[failure] 387-387:
undefined: schema.ColumnDefaultValue🪛 GitHub Check: codecov / codecov
[failure] 382-382:
undefined: schema.ColumnDefaultValue
[failure] 387-387:
undefined: schema.ColumnDefaultValue🪛 GitHub Check: lint / lint
[failure] 382-382:
undefined: schema.ColumnDefaultValue
[failure] 387-387:
undefined: schema.ColumnDefaultValue
[failure] 382-382:
undefined: schema.ColumnDefaultValue
[failure] 387-387:
undefined: schema.ColumnDefaultValue🪛 GitHub Check: test / ubuntu (1.22)
[failure] 382-382:
undefined: schema.ColumnDefaultValue
[failure] 387-387:
undefined: schema.ColumnDefaultValue
414-416: Prefer bigserial over biginteger?Your logic is correct, but if almost always used with sequences, consider defaulting to bigserial.
422-424: Limit usage.
TypeCharis rarely used in Postgres. Confirm it matches the intended semantic vs. usingvarchar.
435-435: Use consistent naming.
TypeDateTimedelegates toTypeTimestamp. The naming might confuse users expecting dedicated date-time logic.
451-453: Validate enumerations at creation.This approach works, but consider partial or dynamic enumerations. Possibly store them in a domain instead.
464-466: Consider sequence approach.For integer columns,
serialis typical. If the user wants manual sequences, consider implementing a separate method.
484-488: Duplicate approach with medium text.
TypeMediumTextalso returnstext. This is consistent but may cause confusion if users expect different size constraints.
Line range hint
545-552: Coordinate with blueprint columns.The logic in
getColumnsfetches added columns, but ensure you handle indexes, foreign keys, or constraints consistently.🧰 Tools
🪛 GitHub Check: test / ubuntu (1.23)
[failure] 523-523:
undefined: schema.Expression
[failure] 531-531:
undefined: schema.Expression🪛 GitHub Check: codecov / codecov
[failure] 523-523:
undefined: schema.Expression
[failure] 531-531:
undefined: schema.Expression🪛 GitHub Check: lint / lint
[failure] 523-523:
undefined: schema.Expression
[failure] 531-531:
undefined: schema.Expression🪛 GitHub Check: test / ubuntu (1.22)
[failure] 523-523:
undefined: schema.Expression
[failure] 531-531:
undefined: schema.Expressionquery.go (1)
5-22: Consider improving documentation and naming.
- Add godoc comments to document the struct and methods.
- Consider using a more descriptive receiver name than 'r' (e.g., 'q' for Query).
Example improvement:
+// Query provides PostgreSQL-specific query operations type Query struct { } func NewQuery() *Query { return &Query{} } +// LockForUpdate returns a FOR UPDATE lock expression -func (r *Query) LockForUpdate() clause.Expression { +func (q *Query) LockForUpdate() clause.Expression { return clause.Locking{Strength: "UPDATE"} } +// RandomOrder returns a random ordering expression -func (r *Query) RandomOrder() string { +func (q *Query) RandomOrder() string { return "RANDOM()" } +// SharedLock returns a FOR SHARE lock expression -func (r *Query) SharedLock() clause.Expression { +func (q *Query) SharedLock() clause.Expression { return clause.Locking{Strength: "SHARE"} }wrap.go (1)
103-103: Consider consolidating aliased table/value logic.Both
aliasedTableandaliasedValuemethods have similar prefix handling logic. Consider extracting the common prefix handling into a helper method.+func (r *Wrap) addPrefix(value string) string { + return r.prefix + value +} func (r *Wrap) aliasedTable(table string) string { segments := strings.Split(table, " as ") - return r.Table(segments[0]) + " as " + r.Value(r.prefix+segments[1]) + return r.Table(segments[0]) + " as " + r.Value(r.addPrefix(segments[1])) } func (r *Wrap) aliasedValue(value string) string { segments := strings.Split(value, " as ") - return r.Column(segments[0]) + " as " + r.Value(r.prefix+segments[1]) + return r.Column(segments[0]) + " as " + r.Value(r.addPrefix(segments[1])) }Also applies to: 109-109
postgres_test.go (1)
63-64: Strengthen version check assertion.The version check only verifies the presence of "Debian". Consider adding more specific version checks.
-assert.Contains(t, version, "Debian") +assert.Regexp(t, `PostgreSQL \d+\.\d+\.\d+ on .* \(Debian`, version)config.go (1)
Line range hint
50-98: Reduce repetition in default config handling.The default config handling has repetitive patterns for each field. Consider using reflection or a map-based approach.
+func (r *Config) getConfigString(key string, defaultValue ...string) string { + configKey := fmt.Sprintf("database.connections.%s.%s", r.connection, key) + if len(defaultValue) > 0 { + return r.config.GetString(configKey, defaultValue[0]) + } + return r.config.GetString(configKey) +} func (r *Config) fillDefault(configs []contracts.Config) []contracts.FullConfig { // ... existing code ... if fullConfig.Host == "" { - fullConfig.Host = r.config.GetString(fmt.Sprintf("database.connections.%s.host", r.connection)) + fullConfig.Host = r.getConfigString("host") } // Apply similar pattern to other fieldsgorm.go (1)
66-70: Extract pool configuration constants.The pool configuration uses magic numbers for defaults. Consider extracting these as named constants.
+const ( + DefaultMaxIdleConns = 10 + DefaultMaxOpenConns = 100 + DefaultConnMaxIdleTime = 3600 + DefaultConnMaxLifetime = 3600 +) func (r *Gorm) configurePool(instance *gorm.DB) error { config := r.config.Config() - db.SetMaxIdleConns(config.GetInt("database.pool.max_idle_conns", 10)) - db.SetMaxOpenConns(config.GetInt("database.pool.max_open_conns", 100)) - db.SetConnMaxIdleTime(time.Duration(config.GetInt("database.pool.conn_max_idletime", 3600)) * time.Second) - db.SetConnMaxLifetime(time.Duration(config.GetInt("database.pool.conn_max_lifetime", 3600)) * time.Second) + db.SetMaxIdleConns(config.GetInt("database.pool.max_idle_conns", DefaultMaxIdleConns)) + db.SetMaxOpenConns(config.GetInt("database.pool.max_open_conns", DefaultMaxOpenConns)) + db.SetConnMaxIdleTime(time.Duration(config.GetInt("database.pool.conn_max_idletime", DefaultConnMaxIdleTime)) * time.Second) + db.SetConnMaxLifetime(time.Duration(config.GetInt("database.pool.conn_max_lifetime", DefaultConnMaxLifetime)) * time.Second)processor_test.go (1)
103-134: Enhance test coverage with additional edge cases.While the current test cases cover basic scenarios, consider adding tests for:
- Indexes with multiple columns in different orders
- Case sensitivity in index names
- Invalid index types
- Duplicate index names
func (s *ProcessorTestSuite) TestProcessIndexes() { tests := []struct { name string dbIndexes []schema.DBIndex expected []schema.Index }{ + { + name: "DuplicateIndexNames", + dbIndexes: []schema.DBIndex{ + {Name: "idx_test", Columns: "col1", Type: "BTREE", Primary: false, Unique: true}, + {Name: "idx_test", Columns: "col2", Type: "BTREE", Primary: false, Unique: true}, + }, + expected: []schema.Index{ + {Name: "idx_test", Columns: []string{"col1"}, Type: "btree", Primary: false, Unique: true}, + {Name: "idx_test_1", Columns: []string{"col2"}, Type: "btree", Primary: false, Unique: true}, + }, + }, + { + name: "InvalidIndexType", + dbIndexes: []schema.DBIndex{ + {Name: "test_index", Columns: "col1", Type: "INVALID", Primary: false, Unique: false}, + }, + expected: []schema.Index{ + {Name: "test_index", Columns: []string{"col1"}, Type: "btree", Primary: false, Unique: false}, + }, + }, }gorm_test.go (2)
32-40: Extract test configuration to constants.Hard-coded credentials and configuration values should be moved to constants for better maintainability.
+const ( + testHost = "localhost" + testDatabase = "goravel" + testUsername = "goravel" + testPassword = "Framework!123" + testSchema = "public" + testTimezone = "UTC" +) + writes := []contracts.FullConfig{ { Config: contracts.Config{ - Host: "localhost", - Database: "goravel", - Username: "goravel", - Password: "Framework!123", - Schema: "public", + Host: testHost, + Database: testDatabase, + Username: testUsername, + Password: testPassword, + Schema: testSchema, }, - Timezone: "UTC", + Timezone: testTimezone, }, }
76-79: Extract pool configuration values to constants.Magic numbers in pool configuration should be defined as constants with meaningful names.
+const ( + defaultMaxIdleConns = 10 + defaultMaxOpenConns = 100 + defaultConnMaxIdleTime = 3600 + defaultConnMaxLifetime = 3600 +) + -mockConfigFacade.EXPECT().GetInt("database.pool.max_idle_conns", 10).Return(10).Once() -mockConfigFacade.EXPECT().GetInt("database.pool.max_open_conns", 100).Return(100).Once() -mockConfigFacade.EXPECT().GetInt("database.pool.conn_max_idletime", 3600).Return(3600).Once() -mockConfigFacade.EXPECT().GetInt("database.pool.conn_max_lifetime", 3600).Return(3600).Once() +mockConfigFacade.EXPECT().GetInt("database.pool.max_idle_conns", defaultMaxIdleConns).Return(defaultMaxIdleConns).Once() +mockConfigFacade.EXPECT().GetInt("database.pool.max_open_conns", defaultMaxOpenConns).Return(defaultMaxOpenConns).Once() +mockConfigFacade.EXPECT().GetInt("database.pool.conn_max_idletime", defaultConnMaxIdleTime).Return(defaultConnMaxIdleTime).Once() +mockConfigFacade.EXPECT().GetInt("database.pool.conn_max_lifetime", defaultConnMaxLifetime).Return(defaultConnMaxLifetime).Once().mockery.yaml (1)
1-11: Fix YAML formatting issues.The file has two minor formatting issues:
- Missing newline at end of file
- Trailing spaces on line 11
Apply these changes:
with-expecter: True disable-version-string: True all: True recursive: true packages: github.com/goravel/postgres/contracts: config: dir: mocks/{{replaceAll .InterfaceDirRelative "contracts" ""}} filename: "{{.InterfaceName}}.go" - mockname: "{{.InterfaceName}}" - + mockname: "{{.InterfaceName}}"🧰 Tools
🪛 yamllint (1.35.1)
[error] 11-11: no new line character at the end of file
(new-line-at-end-of-file)
[error] 11-11: trailing spaces
(trailing-spaces)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
go.sumis excluded by!**/*.sum
📒 Files selected for processing (23)
.mockery.yaml(1 hunks)config.go(2 hunks)config_test.go(2 hunks)contracts/config.go(1 hunks)docker.go(8 hunks)docker_test.go(2 hunks)errors.go(1 hunks)go.mod(4 hunks)gorm.go(6 hunks)gorm_test.go(1 hunks)grammar.go(16 hunks)grammar_test.go(4 hunks)mocks/ConfigBuilder.go(1 hunks)mocks/Replacer.go(1 hunks)postgres.go(4 hunks)postgres_test.go(1 hunks)processor_test.go(1 hunks)query.go(1 hunks)schema.go(0 hunks)utils.go(0 hunks)utils_test.go(0 hunks)wrap.go(4 hunks)wrap_test.go(2 hunks)
💤 Files with no reviewable changes (3)
- utils_test.go
- schema.go
- utils.go
✅ Files skipped from review due to trivial changes (1)
- mocks/Replacer.go
🧰 Additional context used
🪛 yamllint (1.35.1)
.mockery.yaml
[error] 11-11: no new line character at the end of file
(new-line-at-end-of-file)
[error] 11-11: trailing spaces
(trailing-spaces)
🪛 GitHub Check: lint / lint
postgres.go
[failure] 8-8:
could not import github.com/goravel/postgres (-: # github.com/goravel/postgres
grammar.go
[failure] 46-46:
undefined: schema.ColumnType
[failure] 46-46:
undefined: schema.ColumnType
[failure] 382-382:
undefined: schema.ColumnDefaultValue
[failure] 387-387:
undefined: schema.ColumnDefaultValue
[failure] 382-382:
undefined: schema.ColumnDefaultValue
[failure] 387-387:
undefined: schema.ColumnDefaultValue
[failure] 523-523:
undefined: schema.Expression
[failure] 531-531:
undefined: schema.Expression
[failure] 555-555:
undefined: schema.ColumnType) (typecheck)
🪛 GitHub Actions: Lint
postgres.go
[error] 8-8: Import error: could not import github.com/goravel/postgres
🪛 GitHub Check: test / ubuntu (1.23)
grammar.go
[failure] 46-46:
undefined: schema.ColumnType
[failure] 382-382:
undefined: schema.ColumnDefaultValue
[failure] 387-387:
undefined: schema.ColumnDefaultValue
[failure] 523-523:
undefined: schema.Expression
[failure] 531-531:
undefined: schema.Expression
[failure] 555-555:
undefined: schema.ColumnType
🪛 GitHub Check: codecov / codecov
grammar.go
[failure] 46-46:
undefined: schema.ColumnType
[failure] 382-382:
undefined: schema.ColumnDefaultValue
[failure] 387-387:
undefined: schema.ColumnDefaultValue
[failure] 523-523:
undefined: schema.Expression
[failure] 531-531:
undefined: schema.Expression
[failure] 555-555:
undefined: schema.ColumnType
🪛 GitHub Check: test / ubuntu (1.22)
grammar.go
[failure] 46-46:
undefined: schema.ColumnType
[failure] 382-382:
undefined: schema.ColumnDefaultValue
[failure] 387-387:
undefined: schema.ColumnDefaultValue
[failure] 523-523:
undefined: schema.Expression
[failure] 531-531:
undefined: schema.Expression
[failure] 555-555:
undefined: schema.ColumnType
🪛 GitHub Actions: Codecov
grammar.go
[error] 46-46: undefined: schema.ColumnType
🪛 GitHub Actions: Test
grammar.go
[error] 46-46: undefined: schema.ColumnType at column 109
🔇 Additional comments (60)
postgres.go (4)
13-13: Validate import sequence.Ensure the
contractsimport is necessary and consistently referred to throughout the file. If not, remove or reorganize imports to adhere to coding guidelines.
28-30: Check for potential misconfigurations.You switched from
NewConfigBuildertoNewConfig. Verify downstream logic to ensure existing references still work.
60-60: Validate error path coverage.Returning
nil, nilon error might cause downstream panics if code doesn't check for both. Ensure all call sites handle the error properly.
4-4: Remove unused import if unnecessary.Line 4 adds
"fmt", but ensure all references tofmtare used. If not, remove this import to keep dependencies minimal.✅ Verification successful
fmtimport is necessary and actively usedThe
fmtpackage is used for error message formatting viafmt.Sprintf()in the server version retrieval logic.🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Verify usage of fmt in the postgres.go file rg --context 3 "fmt" postgres.goLength of output: 368
docker_test.go (6)
24-25: Test suite naming convention.Renaming
PostgresTestSuitetoDockerTestSuiteclarifies scope. Good job updating the suite name.
28-34: Confirm realistic credentials.Storing credentials in test code is generally fine, but confirm they’re safe or masked if environment variables are used in CI.
71-71: Review usage of Fresh().Check if the
Fresh()call is enough to reset state for all tests, preventing cross-test contamination.
83-83: Double-check cleanup calls.Ensure
docker.Shutdown()is always called after tests, even if an error occurs earlier. This prevents resource leakage in CI.
107-109: Good approach to verifying image assignment.Setting and asserting the Docker image is straightforward and helps ensure correct usage.
111-139: Double-check ephemeral ports.You rely on the Docker port assignment at lines 123 and 135. If random ephemeral ports are used, ensure tests are robust when multiple test runs run concurrently.
grammar.go (31)
10-11: Reevaluate dual imports.You now alias
contractsschemaat line 10 while also importingschemaat line 11. Collisions or confusion might occur since both define similar concepts.
15-15: Ensure alignment with new contract interface.Confirm that
Grammarfully implementscontractsschema.Grammarafter removingDriverSchema.
45-46: Multi-statement approach.
CompileChangereturns an array of statements. Good approach for incremental changes. Keep an eye on syntax correctness.🧰 Tools
🪛 GitHub Check: test / ubuntu (1.23)
[failure] 46-46:
undefined: schema.ColumnType🪛 GitHub Check: codecov / codecov
[failure] 46-46:
undefined: schema.ColumnType🪛 GitHub Check: lint / lint
[failure] 46-46:
undefined: schema.ColumnType
[failure] 46-46:
undefined: schema.ColumnType🪛 GitHub Check: test / ubuntu (1.22)
[failure] 46-46:
undefined: schema.ColumnType🪛 GitHub Actions: Codecov
[error] 46-46: undefined: schema.ColumnType
🪛 GitHub Actions: Test
[error] 46-46: undefined: schema.ColumnType at column 109
74-74: Return ordering clause.The ordering by
a.attnumis typically fine. Ensure it remains consistent with user expectations, especially if columns are manipulated outside standard increments.
86-86: Caution with direct table creation statements.
CompileCreateis used for bare CREATE. Validate that the approach works for partitioned tables or if additional logic is needed.
152-162: Implementation detail check.
CompileDropAllViewsis similar toCompileDropAllTablesyet returns a single statement. Evaluate consistency in approach if there's a scenario with multiple views.
174-174: Potential multi-constraint scenario.When dropping foreign constraints, confirm that constraints with the same name in separate schemas won't cause collisions.
178-178: Reuse existing logic.
CompileDropFullTextdelegates toCompileDropIndex, ensuring DRY. Good practice.
182-182: Similar logic with IfExists.
CompileDropIfExistsis straightforward. Confirm that the newly added lines remain consistent with your migration approach.
186-186: Drop index usage.This code is correct, but ensure test coverage includes an index dropping scenario to avoid regressions.
197-197: Consider overlapping constraints with unique.For
CompileDropUnique, ensure no collisions with previously defined constraints in the schema. Possibly add a prefix for custom constraints.
256-257: Algorithm usage.If
command.Algorithmis empty, you skip it. Confirm that GIN, GIST, or other index types are properly handled for Postgres.
295-295: Safe renaming logic.
CompilePrimaryreferences the table name with the prefix. Thoroughly tested? If not, add coverage for edge cases.
299-299: General rename approach.Renaming a table that doesn’t exist can cause an error. Confirm the caller always ensures existence.
Line range hint
329-339: Unique constraint with deferrable.This is a good addition for advanced constraint logic. Check if Postgres version supports the deferrable feature consistently.
406-412: Combine increment + primary key checks carefully.This logic might fail if the user tries to expand a column from non-auto-increment to auto-increment.
431-431: Simple pass-through.
TypeDateis straightforward. Confirm consistent usage across migrations.
439-439: Delegate tz to TypeTimestampTz.Similar to above, ensure the doc or comment clarifies that
TypeDateTimeTzis an alias.
443-443: Precision checks.For decimal columns, ensure the
GetTotal()andGetPlaces()are validated to avoid negative values.
447-447: Double precision usage.
double precisionis Postgres-specific. Confirm no cross-database usage is required.
Line range hint
455-459: Float fallback.If
precisionis zero, you default tofloat. Good approach. Just note that it’s approximate for large values.
472-472: Json type usage.
jsonis correct for Postgres 9.2+. For older versions, confirm compatibility.
476-476: Jsonb usage.
jsonbis recommended for modern Postgres. Great approach.
480-480: Long text mapping.
textis correct. Just ensure no further constraints (like partial index or length) are required.
492-496: SmallInteger usage.
smallserialis valid. Check if your version of Postgres supports it.
Line range hint
500-505: String fallback to varchar.If the user doesn't specify length, you default to
varchar. This is typical. Great approach.
509-509: TypeText synergy.Identical to
LongTextin usage. Good for standardizing text columns.
513-517: Time zone usage.The time zone vs. non-time zone approaches are correct. Just confirm that any default or now functions are properly set.
537-537: Tiny integer fallback.
TypeTinyIntegerdelegates toTypeSmallInteger. This is correct for Postgres.
541-541: Tiny text fallback.
varchar(255)may not suffice for all cases, but it’s standard.
25-32:⚠️ Potential issueInitialize modifiers carefully.
You’re referencing
ModifyDefault,ModifyIncrement,ModifyNullable, but the pipeline fails on some references toschemautilities. Validate imports or rename references accordingly.import ( contractsschema "github.com/goravel/framework/contracts/database/schema" - "github.com/goravel/framework/database/schema" ) ... func NewGrammar(prefix string) *Grammar { ... - postgres.modifiers = []func(contractsschema.Blueprint, contractsschema.ColumnDefinition) string{ - postgres.ModifyDefault, - postgres.ModifyIncrement, - postgres.ModifyNullable, - } + // Ensure each of these references is defined under contractsschema if schema is removed }Likely invalid or redundant comment.
errors.go (1)
6-7: LGTM! Clear and descriptive error messages.The new error variables provide clear guidance to users about configuration-related issues.
query.go (1)
5-22: LGTM! Clean implementation of query-related functionality.The implementation correctly uses GORM's clause package for locking mechanisms and provides a clean interface for query operations.
contracts/config.go (1)
9-9: LGTM! Clean interface extension.The addition of the Connection() method to the ConfigBuilder interface is well-defined and maintains the interface's cohesion.
wrap_test.go (1)
19-19: LGTM! Good test coverage improvements.The changes simplify the test setup and add comprehensive test cases for aliased tables and values. The test cases are clear and specific.
Also applies to: 81-89
wrap.go (2)
11-11: LGTM! Good simplification of the Wrap struct and constructor.The removal of the driver dependency and simplification of the prefix handling improves the code's maintainability.
Also applies to: 14-17
86-86: Verify table name generation with prefix.The table name generation logic has been updated to use the new prefix field. Please ensure that this change maintains backward compatibility with existing table names.
Also applies to: 89-89
✅ Verification successful
Table name prefix implementation is correctly implemented and backward compatible ✅
The implementation correctly handles all table name formats including schema-qualified names, aliases, and simple table names. Test cases verify that the prefix is consistently applied while maintaining the existing table name structure.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Search for table name usage patterns to verify compatibility rg -A 2 'Table\(' .Length of output: 4718
docker.go (2)
144-147: LGTM! Good abstraction with process.Run.The use of process.Run provides better abstraction and testability for Docker commands.
167-167: Verify if 1-second sleep interval is sufficient.The sleep duration between connection attempts has been reduced from 2 seconds to 1 second. This might be insufficient for PostgreSQL container initialization, especially on slower systems.
✅ Verification successful
The 1-second sleep interval is appropriate
The sleep is part of a robust retry mechanism that attempts to connect up to 60 times with 1-second intervals, providing a sufficient 60-second window for container initialization while exiting early on successful connection.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Test connection reliability with 1-second interval # Expected: No connection errors in container logs during startup docker run -d --name pg-test -e POSTGRES_PASSWORD=test postgres sleep 1 # Check logs for any connection-related errors during startup docker logs pg-test 2>&1 | grep -i "connection" docker rm -f pg-testLength of output: 336
Script:
#!/bin/bash # Search for connection retry logic and sleep intervals rg -A 5 "time.Sleep" # Look for connection-related test cases fd -e go -x rg -l "TestDocker.*connect" # Search for connection-related error handling ast-grep --pattern 'if err != nil { $$$ return err }'Length of output: 523
Script:
#!/bin/bash # Get the connect method implementation and surrounding context rg -B 10 -A 10 "func.*connect" # Get the context around the sleep statement rg -B 10 -A 10 "time.Sleep"Length of output: 3586
mocks/ConfigBuilder.go (1)
1-223: LGTM! Well-structured mock implementation.The auto-generated mock follows good practices:
- Proper error handling for unspecified return values
- Type-safe expectation helpers
- Automatic cleanup registration
config_test.go (2)
16-16: LGTM! Type change aligns with refactoring.The change from
*ConfigBuilderto*Configreflects the simplified configuration structure.
29-29: LGTM! Constructor call updated correctly.The change from
NewConfigBuildertoNewConfigmaintains consistency with the type change.grammar_test.go (5)
69-118: LGTM! Comprehensive test cases for CompileColumns.The new test method thoroughly covers different scenarios including schema-qualified tables and tables with dots in their names.
182-186: LGTM! Updated drop tables test with schema support.The test now correctly validates schema-qualified table drops.
190-197: LGTM! Enhanced type drop test with domain support.The test now handles both regular types and domain types appropriately.
201-205: LGTM! Updated view drop test with schema support.The test now correctly validates schema-qualified view drops.
629-629: LGTM! Updated timestamp methods to use schema.Expression.Consistent use of schema.Expression for CURRENT_TIMESTAMP default values.
Also applies to: 637-637
go.mod (3)
20-20: LGTM! New dependencies align with changes.The added dependencies (xxhash, redis, mimetype, mysql) support the enhanced functionality.
Also applies to: 23-23, 25-26, 39-39
53-55: LGTM! Updated Google API dependencies.Updates to gRPC and protobuf versions maintain compatibility with the latest framework version.
8-8: Verify framework version compatibility.The framework has been updated to a newer version. Please ensure all breaking changes have been addressed.
Run this script to check for any breaking changes in the framework update:
✅ Verification successful
Framework update appears safe to proceed
The version update is within the same minor version (1.15.2), only changing the pre-release timestamp. Recent changes include feature additions and optimizations, with no breaking changes detected. The removal of DriverSchema feature doesn't impact this codebase as it's not being used.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Check for breaking changes in framework update # Get the changelog between the two versions gh api repos/goravel/framework/compare/v1.15.2-0.20250118134235-cdd2b8b3478c...v1.15.2-0.20250125123641-1026257618f7 | jq -r '.commits[].commit.message' | grep -i "breaking"Length of output: 256
Script:
#!/bin/bash # Check for recent releases, tags, and changelog information echo "=== Recent releases ===" gh api repos/goravel/framework/releases --limit 5 | jq -r '.[].name' echo -e "\n=== Looking for changelog or migration guides ===" gh api repos/goravel/framework/contents | jq -r '.[] | select(.name | test("CHANGELOG|MIGRATION|BREAKING|UPGRADE"; "i")) | .name' echo -e "\n=== Recent commits ===" gh api repos/goravel/framework/commits | jq -r '.[] | .commit.message' | head -n 10Length of output: 2052
Script:
#!/bin/bash echo "=== Checking for DriverSchema usage ===" # Search in Go files echo "In Go files:" rg -l "DriverSchema" --type go || true # Search for any schema-related imports echo -e "\nSchema-related imports:" rg -l "schema[\"']?\s*$" --type go || trueLength of output: 354
| func (r *Postgres) version() string { | ||
| instance, _, err := r.Gorm() | ||
| if err != nil { | ||
| return "" | ||
| } | ||
|
|
||
| var version struct { | ||
| Value string | ||
| } | ||
| if err := instance.Raw("SELECT current_setting('server_version') AS value;").Scan(&version).Error; err != nil { | ||
| return fmt.Sprintf("UNKNOWN: %s", err) | ||
| } | ||
|
|
||
| return version.Value |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Gracefully handle version lookup failures.
Returning an empty string or “UNKNOWN” might not clearly indicate an error. Consider proper logging or error return for better observability.
| func (r *Postgres) Gorm() (*gorm.DB, driver.GormQuery, error) { | ||
| if r.db != nil { | ||
| return r.db, NewQuery(), nil | ||
| } | ||
|
|
||
| db, err := NewGorm(r.config, r.log).Build() | ||
| if err != nil { | ||
| return nil, nil, err | ||
| } | ||
|
|
||
| r.db = db | ||
|
|
||
| return db, NewQuery(), nil |
There was a problem hiding this comment.
Add concurrency safety for lazy initialization.
You're caching r.db for reuse. Without synchronization, concurrent calls to Gorm() could cause race conditions.
func (r *Postgres) Gorm() (*gorm.DB, driver.GormQuery, error) {
if r.db != nil {
return r.db, NewQuery(), nil
}
+
+ r.mu.Lock()
+ defer r.mu.Unlock()
+ if r.db != nil {
+ return r.db, NewQuery(), nil
+ }
db, err := NewGorm(r.config, r.log).Build()
if err != nil {
return nil, nil, err
}
r.db = db
return db, NewQuery(), nil
}Committable suggestion skipped: line range outside the PR's diff.
| } | ||
|
|
||
| func (r *Grammar) CompileAdd(blueprint schema.Blueprint, command *schema.Command) string { | ||
| func (r *Grammar) CompileAdd(blueprint contractsschema.Blueprint, command *contractsschema.Command) string { |
There was a problem hiding this comment.
Check reference to schema.ColumnType.
Line 46 in the final code references schema.ColumnType. The pipeline fails because schema.ColumnType might be undefined. Switch to the updated function in contractsschema, or reintroduce the correct import.
| func (r *Grammar) CompileColumns(schema, table string) (string, error) { | ||
| schema, table, err := parseSchemaAndTable(table, schema) | ||
| if err != nil { | ||
| return "", err | ||
| } | ||
|
|
||
| table = r.prefix + table | ||
|
|
There was a problem hiding this comment.
🛠️ Refactor suggestion
Validate schema function usage.
schema, table, err := parseSchemaAndTable(table, schema) might conflict with the new contract usage. Update or rename the method to align with the new package structure.
| func (r *Grammar) ModifyDefault(blueprint contractsschema.Blueprint, column contractsschema.ColumnDefinition) string { | ||
| if column.IsChange() { | ||
| if column.GetAutoIncrement() { | ||
| return "" | ||
| } | ||
| if column.GetDefault() != nil { | ||
| return fmt.Sprintf(" set default %s", getDefaultValue(column.GetDefault())) | ||
| return fmt.Sprintf(" set default %s", schema.ColumnDefaultValue(column.GetDefault())) | ||
| } | ||
| return " drop default" | ||
| } | ||
| if column.GetDefault() != nil { | ||
| return fmt.Sprintf(" default %s", getDefaultValue(column.GetDefault())) | ||
| return fmt.Sprintf(" default %s", schema.ColumnDefaultValue(column.GetDefault())) |
There was a problem hiding this comment.
Undefined: schema.ColumnDefaultValue.
The pipeline fails. Update references to schema.ColumnDefaultValue or define an equivalent method in contractsschema.
🧰 Tools
🪛 GitHub Check: test / ubuntu (1.23)
[failure] 382-382:
undefined: schema.ColumnDefaultValue
[failure] 387-387:
undefined: schema.ColumnDefaultValue
🪛 GitHub Check: codecov / codecov
[failure] 382-382:
undefined: schema.ColumnDefaultValue
[failure] 387-387:
undefined: schema.ColumnDefaultValue
🪛 GitHub Check: lint / lint
[failure] 382-382:
undefined: schema.ColumnDefaultValue
[failure] 387-387:
undefined: schema.ColumnDefaultValue
[failure] 382-382:
undefined: schema.ColumnDefaultValue
[failure] 387-387:
undefined: schema.ColumnDefaultValue
🪛 GitHub Check: test / ubuntu (1.22)
[failure] 382-382:
undefined: schema.ColumnDefaultValue
[failure] 387-387:
undefined: schema.ColumnDefaultValue
| func (r *Grammar) TypeTimestampTz(column contractsschema.ColumnDefinition) string { | ||
| if column.GetUseCurrent() { | ||
| column.Default(Expression("CURRENT_TIMESTAMP")) | ||
| column.Default(schema.Expression("CURRENT_TIMESTAMP")) |
There was a problem hiding this comment.
Same expression usage for timestamps.
As above, ensure schema.Expression is properly referenced or redefined.
🧰 Tools
🪛 GitHub Check: test / ubuntu (1.23)
[failure] 531-531:
undefined: schema.Expression
🪛 GitHub Check: codecov / codecov
[failure] 531-531:
undefined: schema.Expression
🪛 GitHub Check: lint / lint
[failure] 531-531:
undefined: schema.Expression
🪛 GitHub Check: test / ubuntu (1.22)
[failure] 531-531:
undefined: schema.Expression
| docker := NewDocker(nil, writes[0].Database, writes[0].Username, writes[0].Password) | ||
| assert.NoError(t, docker.Build()) | ||
|
|
||
| writes[0].Config.Port = docker.port | ||
| _, err := docker.connect() | ||
| assert.NoError(t, err) |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Ensure proper cleanup of Docker resources.
The Docker container might not be cleaned up if the build fails. Consider using defer for cleanup.
docker := NewDocker(nil, writes[0].Database, writes[0].Username, writes[0].Password)
+defer func() {
+ if err := docker.Shutdown(); err != nil {
+ t.Errorf("failed to shutdown docker: %v", err)
+ }
+}()
assert.NoError(t, docker.Build())Committable suggestion skipped: line range outside the PR's diff.
| func (r *Docker) resetConfigPort() { | ||
| writers := r.config.Config().Get(fmt.Sprintf("database.connections.%s.write", r.config.Connection())) | ||
| if writeConfigs, ok := writers.([]contracts.Config); ok { | ||
| writeConfigs[0].Port = r.port | ||
| r.config.Config().Add(fmt.Sprintf("database.connections.%s.write", r.config.Connection()), writeConfigs) | ||
|
|
||
| return | ||
| } | ||
|
|
||
| r.config.Config().Add(fmt.Sprintf("database.connections.%s.port", r.config.Connection()), r.port) | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Improve error handling in resetConfigPort.
The method lacks error handling for invalid configuration types and doesn't validate the port value before updating the configuration.
func (r *Docker) resetConfigPort() {
+ if r.port <= 0 {
+ return
+ }
writers := r.config.Config().Get(fmt.Sprintf("database.connections.%s.write", r.config.Connection()))
if writeConfigs, ok := writers.([]contracts.Config); ok {
+ if len(writeConfigs) == 0 {
+ return
+ }
writeConfigs[0].Port = r.port
r.config.Config().Add(fmt.Sprintf("database.connections.%s.write", r.config.Connection()), writeConfigs)
return
}
r.config.Config().Add(fmt.Sprintf("database.connections.%s.port", r.config.Connection()), r.port)
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| func (r *Docker) resetConfigPort() { | |
| writers := r.config.Config().Get(fmt.Sprintf("database.connections.%s.write", r.config.Connection())) | |
| if writeConfigs, ok := writers.([]contracts.Config); ok { | |
| writeConfigs[0].Port = r.port | |
| r.config.Config().Add(fmt.Sprintf("database.connections.%s.write", r.config.Connection()), writeConfigs) | |
| return | |
| } | |
| r.config.Config().Add(fmt.Sprintf("database.connections.%s.port", r.config.Connection()), r.port) | |
| } | |
| func (r *Docker) resetConfigPort() { | |
| if r.port <= 0 { | |
| return | |
| } | |
| writers := r.config.Config().Get(fmt.Sprintf("database.connections.%s.write", r.config.Connection())) | |
| if writeConfigs, ok := writers.([]contracts.Config); ok { | |
| if len(writeConfigs) == 0 { | |
| return | |
| } | |
| writeConfigs[0].Port = r.port | |
| r.config.Config().Add(fmt.Sprintf("database.connections.%s.write", r.config.Connection()), writeConfigs) | |
| return | |
| } | |
| r.config.Config().Add(fmt.Sprintf("database.connections.%s.port", r.config.Connection()), r.port) | |
| } |
| r.containerID = containerID | ||
| r.port = port | ||
|
|
||
| return r.Ready() | ||
| return nil |
There was a problem hiding this comment.
💡 Codebase verification
Ready check removal creates potential reliability issues
Removing the Ready() check from Reuse() is problematic as it could lead to using containers in an invalid state. The Ready() method performs crucial database connectivity validation that should be maintained for both new and reused containers. Consider either:
- Restoring the Ready() check in Reuse()
- Implementing an alternative container health validation mechanism
🔗 Analysis chain
Verify the impact of removing Ready check in Reuse.
The Reuse method no longer calls Ready(), which might lead to usage of containers that aren't fully initialized.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check if container is actually ready when Reuse is called
# Test: Search for any error handling or readiness checks when reusing containers
rg -A 5 "Reuse\("
Length of output: 199
Script:
#!/bin/bash
# Check Ready implementation and find all its usages
ast-grep --pattern 'func $_Ready() error { $$$ }'
rg -B 5 -A 10 "Ready\(\)"
# Find all Reuse usages
rg -B 5 -A 10 "\.Reuse\("
# Look for container initialization patterns
rg -B 5 -A 10 "New.*Docker"
Length of output: 6095
| db, err := s.gorm.Build() | ||
| s.NoError(err) | ||
| s.NotNil(db) | ||
| s.NoError(docker.Shutdown()) |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Ensure reliable Docker cleanup in tests.
Docker cleanup should be handled in a defer statement to ensure cleanup even if tests fail.
func (s *GormTestSuite) TestBuild() {
s.Run("single config", func() {
docker := NewDocker(nil, writes[0].Database, writes[0].Username, writes[0].Password)
+ defer func() {
+ s.NoError(docker.Shutdown())
+ }()
s.NoError(docker.Build())
// ... rest of the test
- s.NoError(docker.Shutdown())
})Also applies to: 130-130
📑 Description
Summary by CodeRabbit
Based on the comprehensive changes, here are the release notes:
Release Notes
New Features
Bug Fixes
Refactoring
Testing
Chores
✅ Checks