Skip to content

refactor: implement native database/sql repositories#8

Merged
allisson merged 1 commit intomainfrom
integration-tests
Jan 24, 2026
Merged

refactor: implement native database/sql repositories#8
allisson merged 1 commit intomainfrom
integration-tests

Conversation

@allisson
Copy link
Owner

Remove github.com/allisson/sqlutil library and replace with native Go database/sql implementations. This change creates separate repository implementations for MySQL and PostgreSQL, providing better control, clarity, and eliminating external dependencies.

Breaking Changes:

  • UserRepository split into MySQLUserRepository and PostgreSQLUserRepository
  • OutboxEventRepository split into MySQLOutboxEventRepository and PostgreSQLOutboxEventRepository
  • Repositories now return interfaces from usecase package instead of concrete types
  • DI container updated to instantiate correct repository based on DB_DRIVER config

Changes:

  • internal/database/txmanager.go:
    • Remove sqlutil.Querier import
    • Define custom Querier interface matching database/sql
    • Update GetTx() to return new Querier interface
  • internal/user/repository/:
    • Delete user_repository.go (unified implementation)
    • Add mysql_user_repository.go with MySQL-specific implementation
      • Uses BINARY(16) for UUID storage with marshal/unmarshal
      • Uses ? placeholders for parameters
      • MySQL-specific unique constraint error detection
    • Add postgresql_user_repository.go with PostgreSQL-specific implementation
      • Uses native UUID type
      • Uses $1, $2, $3... numbered placeholders
      • PostgreSQL-specific unique constraint error detection
    • Add mysql_user_repository_test.go with comprehensive tests
    • Add postgresql_user_repository_test.go with comprehensive tests
    • Delete user_repository_test.go (old tests)
  • internal/outbox/repository/:
    • Delete outbox_repository.go (unified implementation)
    • Add mysql_outbox_repository.go with MySQL-specific implementation
    • Add postgresql_outbox_repository.go with PostgreSQL-specific implementation
    • Add mysql_outbox_repository_test.go with comprehensive tests
    • Add postgresql_outbox_repository_test.go with comprehensive tests
    • Delete outbox_repository_test.go (old tests)
  • internal/app/di.go:
    • Update Container struct to use interface types for repositories
    • Update UserRepository() to return userUsecase.UserRepository interface
    • Update OutboxRepository() to return userUsecase.OutboxEventRepository interface
    • Update initUserRepository() to switch on DBDriver and instantiate correct implementation
    • Update initOutboxRepository() to switch on DBDriver and instantiate correct implementation
  • go.mod:
    • Remove github.com/allisson/sqlutil v1.10.0
    • Remove indirect dependencies: sqlquery, scany, sqlbuilder, xstrings
  • Documentation:
    • README.md: Add "Database Repository Pattern" section explaining the architecture
    • README.md: Update all code examples to show database/sql usage
    • README.md: Update project structure to show separate repository files
    • README.md: Update dependencies list removing sqlutil
    • internal/app/README.md: Update dependency graph showing interface pattern
    • internal/app/README.md: Update initialization examples with driver switch logic

Implementation Details:

MySQL Repositories:

  • Use BINARY(16) for UUID storage requiring ID.MarshalBinary() for writes and ID.UnmarshalBinary() for reads
  • Use ? placeholders for all query parameters
  • Detect unique violations by checking for "1062" or "duplicate entry" in error messages
  • Use FOR UPDATE SKIP LOCKED syntax for outbox event locking PostgreSQL Repositories:
  • Use native UUID type, passing uuid.UUID directly without conversion
  • Use numbered placeholders ($1, $2, $3...)
  • Detect unique violations by checking for "duplicate key" or "unique constraint"
  • Use FOR UPDATE SKIP LOCKED syntax for outbox event locking

Benefits:

  • Zero external dependencies for database operations (standard library only)
  • Database-specific optimizations (native UUID support in PostgreSQL)
  • Explicit SQL queries improve code clarity and maintainability
  • Easier to debug and optimize database-specific issues
  • Better type safety without abstraction layers
  • Reduced dependency tree and faster builds

Testing:

  • All existing tests updated and passing
  • New tests cover MySQL and PostgreSQL implementations separately
  • Tests use sqlmock for database mocking
  • Coverage maintained at same level as before

Lint:

  • Fixed errcheck warnings by adding //nolint:errcheck to defer rows.Close()
  • All golangci-lint checks passing (0 issues)

Remove github.com/allisson/sqlutil library and replace with native Go
database/sql implementations. This change creates separate repository
implementations for MySQL and PostgreSQL, providing better control,
clarity, and eliminating external dependencies.

Breaking Changes:
- UserRepository split into MySQLUserRepository and PostgreSQLUserRepository
- OutboxEventRepository split into MySQLOutboxEventRepository and PostgreSQLOutboxEventRepository
- Repositories now return interfaces from usecase package instead of concrete types
- DI container updated to instantiate correct repository based on DB_DRIVER config

Changes:

- internal/database/txmanager.go:
  * Remove sqlutil.Querier import
  * Define custom Querier interface matching database/sql
  * Update GetTx() to return new Querier interface
- internal/user/repository/:
  * Delete user_repository.go (unified implementation)
  * Add mysql_user_repository.go with MySQL-specific implementation
    - Uses BINARY(16) for UUID storage with marshal/unmarshal
    - Uses ? placeholders for parameters
    - MySQL-specific unique constraint error detection
  * Add postgresql_user_repository.go with PostgreSQL-specific implementation
    - Uses native UUID type
    - Uses $1, $2, $3... numbered placeholders
    - PostgreSQL-specific unique constraint error detection
  * Add mysql_user_repository_test.go with comprehensive tests
  * Add postgresql_user_repository_test.go with comprehensive tests
  * Delete user_repository_test.go (old tests)
- internal/outbox/repository/:
  * Delete outbox_repository.go (unified implementation)
  * Add mysql_outbox_repository.go with MySQL-specific implementation
  * Add postgresql_outbox_repository.go with PostgreSQL-specific implementation
  * Add mysql_outbox_repository_test.go with comprehensive tests
  * Add postgresql_outbox_repository_test.go with comprehensive tests
  * Delete outbox_repository_test.go (old tests)
- internal/app/di.go:
  * Update Container struct to use interface types for repositories
  * Update UserRepository() to return userUsecase.UserRepository interface
  * Update OutboxRepository() to return userUsecase.OutboxEventRepository interface
  * Update initUserRepository() to switch on DBDriver and instantiate correct implementation
  * Update initOutboxRepository() to switch on DBDriver and instantiate correct implementation
- go.mod:
  * Remove github.com/allisson/sqlutil v1.10.0
  * Remove indirect dependencies: sqlquery, scany, sqlbuilder, xstrings
- Documentation:
  * README.md: Add "Database Repository Pattern" section explaining the architecture
  * README.md: Update all code examples to show database/sql usage
  * README.md: Update project structure to show separate repository files
  * README.md: Update dependencies list removing sqlutil
  * internal/app/README.md: Update dependency graph showing interface pattern
  * internal/app/README.md: Update initialization examples with driver switch logic

Implementation Details:

MySQL Repositories:
- Use BINARY(16) for UUID storage requiring ID.MarshalBinary() for writes
  and ID.UnmarshalBinary() for reads
- Use ? placeholders for all query parameters
- Detect unique violations by checking for "1062" or "duplicate entry" in error messages
- Use FOR UPDATE SKIP LOCKED syntax for outbox event locking
PostgreSQL Repositories:
- Use native UUID type, passing uuid.UUID directly without conversion
- Use numbered placeholders ($1, $2, $3...)
- Detect unique violations by checking for "duplicate key" or "unique constraint"
- Use FOR UPDATE SKIP LOCKED syntax for outbox event locking

Benefits:
- Zero external dependencies for database operations (standard library only)
- Database-specific optimizations (native UUID support in PostgreSQL)
- Explicit SQL queries improve code clarity and maintainability
- Easier to debug and optimize database-specific issues
- Better type safety without abstraction layers
- Reduced dependency tree and faster builds

Testing:
- All existing tests updated and passing
- New tests cover MySQL and PostgreSQL implementations separately
- Tests use sqlmock for database mocking
- Coverage maintained at same level as before

Lint:
- Fixed errcheck warnings by adding //nolint:errcheck to defer rows.Close()
- All golangci-lint checks passing (0 issues)
@allisson allisson merged commit 90d8302 into main Jan 24, 2026
1 check passed
@allisson allisson deleted the integration-tests branch January 24, 2026 19:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant