From 99745f0f54ea819cf15bef760b5fce3b57d755fc Mon Sep 17 00:00:00 2001 From: itsLeonB Date: Tue, 2 Sep 2025 15:25:49 +0700 Subject: [PATCH 1/2] feat: add base entity --- README.md | 517 +++++++++++++++++++++++++++++++++++++++- base_entity.go | 23 ++ go.mod | 2 +- gorm_crud_repository.go | 4 +- gorm_scopes.go | 4 +- gorm_transactor.go | 4 +- 6 files changed, 543 insertions(+), 11 deletions(-) create mode 100644 base_entity.go diff --git a/README.md b/README.md index ddea693..446bcb1 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,517 @@ # go-crud -Generic CRUD repository using GORM + +[![Go Version](https://img.shields.io/badge/Go-1.25+-00ADD8?style=flat&logo=go)](https://golang.org/) +[![Test Coverage](https://img.shields.io/badge/Coverage-84.3%25-brightgreen)](./test/) +[![License](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) + +A **generic CRUD repository library** for Go applications using GORM, providing type-safe database operations with transaction support, query scopes, and comprehensive security features. + +## ๐Ÿš€ Features + +- **๐Ÿ”’ Type-Safe Operations**: Generic interfaces for compile-time type safety +- **๐Ÿ“Š Transaction Management**: Context-aware transactions with nested support +- **๐Ÿ” Query Scopes**: Reusable query builders for pagination, filtering, and ordering +- **๐Ÿ›ก๏ธ Security First**: SQL injection prevention and field name validation +- **โšก Performance**: Optimized queries with preloading and batch operations +- **๐Ÿงช Well Tested**: 84.3% test coverage with comprehensive test suite +- **๐Ÿ“– Clean API**: Intuitive interfaces following Go best practices + +## ๐Ÿ“ฆ Installation + +```bash +go get github.com/itsLeonB/go-crud +``` + +## ๐Ÿ—๏ธ Architecture + +The library is built around three core components: + +### 1. **CRUDRepository** - Type-safe database operations + +### 2. **Transactor** - Transaction management with context + +### 3. **Query Scopes** - Reusable query builders + +## ๐Ÿ”ง Quick Start + +### Basic Setup + +```go +package main + +import ( + "context" + "log" + + "github.com/itsLeonB/go-crud" + "gorm.io/driver/postgres" + "gorm.io/gorm" +) + +// Define your model +type User struct { + ID uint `gorm:"primaryKey"` + Name string `gorm:"not null"` + Email string `gorm:"unique"` + Age int + CreatedAt time.Time + UpdatedAt time.Time +} + +func main() { + // Initialize GORM + db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{}) + if err != nil { + log.Fatal("Failed to connect to database:", err) + } + + // Auto-migrate your models + db.AutoMigrate(&User{}) + + // Create repository and transactor + userRepo := ezutil.NewCRUDRepository[User](db) + transactor := ezutil.NewTransactor(db) + + ctx := context.Background() + + // Your application logic here... +} +``` + +## ๐Ÿ“š Core Components + +### CRUDRepository Interface + +The `CRUDRepository` provides type-safe CRUD operations: + +```go +type CRUDRepository[T any] interface { + Insert(ctx context.Context, model T) (T, error) + FindAll(ctx context.Context, spec Specification[T]) ([]T, error) + FindFirst(ctx context.Context, spec Specification[T]) (T, error) + Update(ctx context.Context, model T) (T, error) + Delete(ctx context.Context, model T) error + BatchInsert(ctx context.Context, models []T) ([]T, error) + GetGormInstance(ctx context.Context) (*gorm.DB, error) +} +``` + +### Specification Pattern + +Use specifications to build dynamic queries: + +```go +type Specification[T any] struct { + Model T // Model with fields set for WHERE conditions + PreloadRelations []string // Relations to eager load + ForUpdate bool // Whether to use SELECT ... FOR UPDATE +} +``` + +## ๐Ÿ’ก Usage Examples + +### Basic CRUD Operations + +```go +ctx := context.Background() +userRepo := ezutil.NewCRUDRepository[User](db) + +// Create a user +user := User{ + Name: "John Doe", + Email: "john@example.com", + Age: 30, +} +createdUser, err := userRepo.Insert(ctx, user) +if err != nil { + log.Fatal("Failed to create user:", err) +} + +// Find users +spec := ezutil.Specification[User]{ + Model: User{Age: 30}, // Find users with age 30 +} +users, err := userRepo.FindAll(ctx, spec) +if err != nil { + log.Fatal("Failed to find users:", err) +} + +// Find first user +firstUser, err := userRepo.FindFirst(ctx, spec) +if err != nil { + log.Fatal("Failed to find user:", err) +} + +// Update user +createdUser.Name = "John Smith" +updatedUser, err := userRepo.Update(ctx, createdUser) +if err != nil { + log.Fatal("Failed to update user:", err) +} + +// Delete user +err = userRepo.Delete(ctx, updatedUser) +if err != nil { + log.Fatal("Failed to delete user:", err) +} +``` + +### Batch Operations + +```go +// Batch insert multiple users +users := []User{ + {Name: "Alice", Email: "alice@example.com", Age: 25}, + {Name: "Bob", Email: "bob@example.com", Age: 30}, + {Name: "Charlie", Email: "charlie@example.com", Age: 35}, +} + +createdUsers, err := userRepo.BatchInsert(ctx, users) +if err != nil { + log.Fatal("Failed to batch insert users:", err) +} +``` + +### Advanced Queries with Specifications + +```go +// Find users with preloaded relations +spec := ezutil.Specification[User]{ + Model: User{Age: 25}, + PreloadRelations: []string{"Profile", "Posts"}, + ForUpdate: false, +} +users, err := userRepo.FindAll(ctx, spec) + +// Pessimistic locking +spec = ezutil.Specification[User]{ + Model: User{ID: 1}, + ForUpdate: true, // SELECT ... FOR UPDATE +} +user, err := userRepo.FindFirst(ctx, spec) +``` + +## ๐Ÿ”„ Transaction Management + +### Basic Transactions + +```go +transactor := ezutil.NewTransactor(db) + +err := transactor.WithinTransaction(ctx, func(txCtx context.Context) error { + // All operations within this function use the same transaction + + user := User{Name: "Alice", Email: "alice@example.com"} + createdUser, err := userRepo.Insert(txCtx, user) + if err != nil { + return err // Transaction will be rolled back + } + + // Update in same transaction + createdUser.Age = 25 + _, err = userRepo.Update(txCtx, createdUser) + if err != nil { + return err // Transaction will be rolled back + } + + return nil // Transaction will be committed +}) + +if err != nil { + log.Fatal("Transaction failed:", err) +} +``` + +### Manual Transaction Control + +```go +// Begin transaction +txCtx, err := transactor.Begin(ctx) +if err != nil { + log.Fatal("Failed to begin transaction:", err) +} + +// Perform operations +user, err := userRepo.Insert(txCtx, User{Name: "Bob"}) +if err != nil { + transactor.Rollback(txCtx) + log.Fatal("Failed to insert user:", err) +} + +// Commit transaction +err = transactor.Commit(txCtx) +if err != nil { + log.Fatal("Failed to commit transaction:", err) +} +``` + +### Nested Transactions + +```go +err := transactor.WithinTransaction(ctx, func(outerTxCtx context.Context) error { + // Outer transaction + user, err := userRepo.Insert(outerTxCtx, User{Name: "Outer"}) + if err != nil { + return err + } + + // Nested transaction (reuses the same transaction) + return transactor.WithinTransaction(outerTxCtx, func(innerTxCtx context.Context) error { + // Inner operations use the same transaction + return userRepo.Update(innerTxCtx, user) + }) +}) +``` + +## ๐Ÿ” Query Scopes + +The library provides powerful query scopes for common operations: + +### Pagination + +```go +db.Scopes(ezutil.Paginate(page, limit)).Find(&users) + +// Example: Get page 2 with 10 items per page +db.Scopes(ezutil.Paginate(2, 10)).Find(&users) +``` + +### Ordering + +```go +// Order by name ascending +db.Scopes(ezutil.OrderBy("name", true)).Find(&users) + +// Order by created_at descending +db.Scopes(ezutil.OrderBy("created_at", false)).Find(&users) + +// Default ordering (created_at DESC) +db.Scopes(ezutil.DefaultOrder()).Find(&users) +``` + +### Filtering + +```go +// Filter by specification +spec := User{Age: 25, Name: "Alice"} +db.Scopes(ezutil.WhereBySpec(spec)).Find(&users) + +// Time range filtering +start := time.Now().Add(-24 * time.Hour) +end := time.Now() +db.Scopes(ezutil.BetweenTime("created_at", start, end)).Find(&users) +``` + +### Preloading Relations + +```go +relations := []string{"Profile", "Posts", "Comments"} +db.Scopes(ezutil.PreloadRelations(relations)).Find(&users) +``` + +### Pessimistic Locking + +```go +// Add FOR UPDATE clause +db.Scopes(ezutil.ForUpdate(true)).First(&user, id) +``` + +### Combining Scopes + +```go +// Complex query with multiple scopes +db.Scopes( + ezutil.WhereBySpec(User{Age: 25}), + ezutil.OrderBy("name", true), + ezutil.Paginate(1, 10), + ezutil.PreloadRelations([]string{"Profile"}), +).Find(&users) +``` + +## ๐Ÿ›ก๏ธ Security Features + +### SQL Injection Prevention + +The library includes robust field name validation to prevent SQL injection: + +```go +// Safe field names (allowed) +"name" โœ… +"created_at" โœ… +"users.name" โœ… +"table.column" โœ… + +// Dangerous field names (rejected) +"name'; DROP TABLE users; --" โŒ +"name' OR '1'='1" โŒ +".invalid" โŒ +"invalid." โŒ +"table..column" โŒ +``` + +### Field Name Validation Rules + +- Only ASCII letters, digits, underscores, and dots allowed +- No leading or trailing dots +- No consecutive dots +- No empty strings +- No special characters or SQL keywords + +## ๐Ÿงช Testing + +The library comes with comprehensive tests achieving **84.3% coverage**: + +```bash +# Run all tests +go test -v ./test/... + +# Run tests with coverage +go test -v -coverprofile=coverage.out -coverpkg=./... ./test/... + +# Generate coverage report +go tool cover -html=coverage.out -o coverage.html + +# Use the test runner script +./test/run_tests.sh +``` + +### Test Categories + +- **Unit Tests**: All public functions and methods +- **Integration Tests**: Database operations with SQLite +- **Security Tests**: SQL injection prevention +- **Concurrency Tests**: Thread safety validation +- **Performance Tests**: Benchmarks for critical functions + +## ๐Ÿ“ Project Structure + +``` +go-crud/ +โ”œโ”€โ”€ gorm_crud_repository.go # Main CRUD repository implementation +โ”œโ”€โ”€ gorm_scopes.go # Query scopes and builders +โ”œโ”€โ”€ gorm_transactor.go # Transaction management +โ”œโ”€โ”€ internal/ +โ”‚ โ”œโ”€โ”€ gorm.go # Internal GORM utilities +โ”‚ โ””โ”€โ”€ transactor.go # Internal transaction logic +โ”œโ”€โ”€ lib/ +โ”‚ โ””โ”€โ”€ constants.go # Library constants +โ””โ”€โ”€ test/ # Comprehensive test suite + โ”œโ”€โ”€ crud_repository_test.go + โ”œโ”€โ”€ scopes_test.go + โ”œโ”€โ”€ transactor_test.go + โ”œโ”€โ”€ internal_test.go + โ”œโ”€โ”€ constants_test.go + โ””โ”€โ”€ run_tests.sh +``` + +## ๐Ÿ”ง Configuration + +### Database Drivers + +The library works with any GORM-supported database: + +```go +// PostgreSQL +db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{}) + +// MySQL +db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) + +// SQLite +db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{}) +``` + +### GORM Configuration + +```go +db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{ + Logger: logger.Default.LogMode(logger.Info), + NamingStrategy: schema.NamingStrategy{ + TablePrefix: "app_", + SingularTable: false, + }, +}) +``` + +## ๐Ÿš€ Performance Tips + +### 1. Use Batch Operations + +```go +// Instead of multiple Insert calls +users := []User{{Name: "Alice"}, {Name: "Bob"}} +userRepo.BatchInsert(ctx, users) +``` + +### 2. Preload Relations Wisely + +```go +// Only preload what you need +spec := ezutil.Specification[User]{ + PreloadRelations: []string{"Profile"}, // Not all relations +} +``` + +### 3. Use Pagination + +```go +// For large datasets +db.Scopes(ezutil.Paginate(page, 50)).Find(&users) +``` + +### 4. Leverage Transactions + +```go +// Group related operations +transactor.WithinTransaction(ctx, func(txCtx context.Context) error { + // Multiple related operations + return nil +}) +``` + +## ๐Ÿค Contributing + +Contributions are welcome! Please ensure: + +1. **Tests**: Add tests for new features +2. **Coverage**: Maintain or improve test coverage +3. **Documentation**: Update documentation for new features +4. **Security**: Follow security best practices +5. **Performance**: Consider performance implications + +### Development Setup + +```bash +# Clone the repository +git clone https://github.com/itsLeonB/go-crud.git +cd go-crud + +# Install dependencies +go mod tidy + +# Run tests +make test + +# Check coverage +make test-coverage-html +``` + +## ๐Ÿ“„ License + +This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. + +## ๐Ÿ™ Acknowledgments + +- **GORM**: The fantastic ORM library that powers this project +- **Testify**: For making tests more readable and maintainable +- **Eris**: For enhanced error handling and stack traces + +## ๐Ÿ“ž Support + +- **Issues**: [GitHub Issues](https://github.com/itsLeonB/go-crud/issues) +- **Discussions**: [GitHub Discussions](https://github.com/itsLeonB/go-crud/discussions) +- **Documentation**: This README and inline code documentation + +--- + +**Built with โค๏ธ for the Go community** diff --git a/base_entity.go b/base_entity.go new file mode 100644 index 0000000..45fc81a --- /dev/null +++ b/base_entity.go @@ -0,0 +1,23 @@ +package crud + +import ( + "database/sql" + "time" + + "github.com/google/uuid" +) + +type BaseEntity struct { + ID uuid.UUID `gorm:"type:uuid;primaryKey;default:gen_random_uuid()"` + CreatedAt time.Time + UpdatedAt time.Time `gorm:"autoUpdateTime"` + DeletedAt sql.NullTime +} + +func (be BaseEntity) IsZero() bool { + return be.ID == uuid.Nil +} + +func (be BaseEntity) IsDeleted() bool { + return be.DeletedAt.Valid +} diff --git a/go.mod b/go.mod index 17c4321..b389561 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/itsLeonB/go-crud go 1.25.0 require ( + github.com/google/uuid v1.6.0 github.com/itsLeonB/ezutil/v2 v2.0.0-alpha github.com/rotisserie/eris v0.5.4 github.com/stretchr/testify v1.11.0 @@ -12,7 +13,6 @@ require ( require ( github.com/davecgh/go-spew v1.1.1 // indirect - github.com/google/uuid v1.6.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/kr/pretty v0.3.0 // indirect diff --git a/gorm_crud_repository.go b/gorm_crud_repository.go index 01ebe13..fb893c4 100644 --- a/gorm_crud_repository.go +++ b/gorm_crud_repository.go @@ -1,6 +1,4 @@ -package ezutil - -// todo move to go-crud pkg +package crud import ( "context" diff --git a/gorm_scopes.go b/gorm_scopes.go index b68bab3..146e7ff 100644 --- a/gorm_scopes.go +++ b/gorm_scopes.go @@ -1,6 +1,4 @@ -package ezutil - -// todo move to go-crud pkg +package crud import ( "reflect" diff --git a/gorm_transactor.go b/gorm_transactor.go index c4fa20b..3e64ee7 100644 --- a/gorm_transactor.go +++ b/gorm_transactor.go @@ -1,6 +1,4 @@ -package ezutil - -// todo move to go-crud pkg +package crud import ( "context" From 51731a9bde0ccbc79ac65725f10305e59007fd9f Mon Sep 17 00:00:00 2001 From: itsLeonB Date: Wed, 3 Sep 2025 11:32:50 +0700 Subject: [PATCH 2/2] fix: rename proper --- README.md | 44 +++++++++++++++++++++--------------------- go.mod | 2 +- go.sum | 4 ++-- lib/constants.go | 2 +- test/constants_test.go | 14 +++++++------- 5 files changed, 33 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 446bcb1..ebc9ba8 100644 --- a/README.md +++ b/README.md @@ -69,8 +69,8 @@ func main() { db.AutoMigrate(&User{}) // Create repository and transactor - userRepo := ezutil.NewCRUDRepository[User](db) - transactor := ezutil.NewTransactor(db) + userRepo := crud.NewCRUDRepository[User](db) + transactor := crud.NewTransactor(db) ctx := context.Background() @@ -114,7 +114,7 @@ type Specification[T any] struct { ```go ctx := context.Background() -userRepo := ezutil.NewCRUDRepository[User](db) +userRepo := crud.NewCRUDRepository[User](db) // Create a user user := User{ @@ -128,7 +128,7 @@ if err != nil { } // Find users -spec := ezutil.Specification[User]{ +spec := crud.Specification[User]{ Model: User{Age: 30}, // Find users with age 30 } users, err := userRepo.FindAll(ctx, spec) @@ -176,7 +176,7 @@ if err != nil { ```go // Find users with preloaded relations -spec := ezutil.Specification[User]{ +spec := crud.Specification[User]{ Model: User{Age: 25}, PreloadRelations: []string{"Profile", "Posts"}, ForUpdate: false, @@ -184,7 +184,7 @@ spec := ezutil.Specification[User]{ users, err := userRepo.FindAll(ctx, spec) // Pessimistic locking -spec = ezutil.Specification[User]{ +spec = crud.Specification[User]{ Model: User{ID: 1}, ForUpdate: true, // SELECT ... FOR UPDATE } @@ -196,7 +196,7 @@ user, err := userRepo.FindFirst(ctx, spec) ### Basic Transactions ```go -transactor := ezutil.NewTransactor(db) +transactor := crud.NewTransactor(db) err := transactor.WithinTransaction(ctx, func(txCtx context.Context) error { // All operations within this function use the same transaction @@ -270,23 +270,23 @@ The library provides powerful query scopes for common operations: ### Pagination ```go -db.Scopes(ezutil.Paginate(page, limit)).Find(&users) +db.Scopes(crud.Paginate(page, limit)).Find(&users) // Example: Get page 2 with 10 items per page -db.Scopes(ezutil.Paginate(2, 10)).Find(&users) +db.Scopes(crud.Paginate(2, 10)).Find(&users) ``` ### Ordering ```go // Order by name ascending -db.Scopes(ezutil.OrderBy("name", true)).Find(&users) +db.Scopes(crud.OrderBy("name", true)).Find(&users) // Order by created_at descending -db.Scopes(ezutil.OrderBy("created_at", false)).Find(&users) +db.Scopes(crud.OrderBy("created_at", false)).Find(&users) // Default ordering (created_at DESC) -db.Scopes(ezutil.DefaultOrder()).Find(&users) +db.Scopes(crud.DefaultOrder()).Find(&users) ``` ### Filtering @@ -294,26 +294,26 @@ db.Scopes(ezutil.DefaultOrder()).Find(&users) ```go // Filter by specification spec := User{Age: 25, Name: "Alice"} -db.Scopes(ezutil.WhereBySpec(spec)).Find(&users) +db.Scopes(crud.WhereBySpec(spec)).Find(&users) // Time range filtering start := time.Now().Add(-24 * time.Hour) end := time.Now() -db.Scopes(ezutil.BetweenTime("created_at", start, end)).Find(&users) +db.Scopes(crud.BetweenTime("created_at", start, end)).Find(&users) ``` ### Preloading Relations ```go relations := []string{"Profile", "Posts", "Comments"} -db.Scopes(ezutil.PreloadRelations(relations)).Find(&users) +db.Scopes(crud.PreloadRelations(relations)).Find(&users) ``` ### Pessimistic Locking ```go // Add FOR UPDATE clause -db.Scopes(ezutil.ForUpdate(true)).First(&user, id) +db.Scopes(crud.ForUpdate(true)).First(&user, id) ``` ### Combining Scopes @@ -321,10 +321,10 @@ db.Scopes(ezutil.ForUpdate(true)).First(&user, id) ```go // Complex query with multiple scopes db.Scopes( - ezutil.WhereBySpec(User{Age: 25}), - ezutil.OrderBy("name", true), - ezutil.Paginate(1, 10), - ezutil.PreloadRelations([]string{"Profile"}), + crud.WhereBySpec(User{Age: 25}), + crud.OrderBy("name", true), + crud.Paginate(1, 10), + crud.PreloadRelations([]string{"Profile"}), ).Find(&users) ``` @@ -447,7 +447,7 @@ userRepo.BatchInsert(ctx, users) ```go // Only preload what you need -spec := ezutil.Specification[User]{ +spec := crud.Specification[User]{ PreloadRelations: []string{"Profile"}, // Not all relations } ``` @@ -456,7 +456,7 @@ spec := ezutil.Specification[User]{ ```go // For large datasets -db.Scopes(ezutil.Paginate(page, 50)).Find(&users) +db.Scopes(crud.Paginate(page, 50)).Find(&users) ``` ### 4. Leverage Transactions diff --git a/go.mod b/go.mod index b389561..4e3b767 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.25.0 require ( github.com/google/uuid v1.6.0 - github.com/itsLeonB/ezutil/v2 v2.0.0-alpha + github.com/itsLeonB/ezutil/v2 v2.0.0 github.com/rotisserie/eris v0.5.4 github.com/stretchr/testify v1.11.0 gorm.io/driver/sqlite v1.6.0 diff --git a/go.sum b/go.sum index a3a2a25..fc9267d 100644 --- a/go.sum +++ b/go.sum @@ -3,8 +3,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/itsLeonB/ezutil/v2 v2.0.0-alpha h1:hXkL4U6KC7BAamUkdyCfbxK1mVJv/CDkLlVcVWxIcT4= -github.com/itsLeonB/ezutil/v2 v2.0.0-alpha/go.mod h1:fiUusldH3h+Y3vYimdloT+CBVO2AKT0xEtXvSHgvTts= +github.com/itsLeonB/ezutil/v2 v2.0.0 h1:4o6nVMzCIr56ggXifDG7Mr+ucDDUg3bVeuiNjsFVcRI= +github.com/itsLeonB/ezutil/v2 v2.0.0/go.mod h1:fiUusldH3h+Y3vYimdloT+CBVO2AKT0xEtXvSHgvTts= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= diff --git a/lib/constants.go b/lib/constants.go index 5baad42..cd9b075 100644 --- a/lib/constants.go +++ b/lib/constants.go @@ -3,7 +3,7 @@ package lib type txKey string const ( - ContextKeyGormTx txKey = "ezutil.gormTx" + ContextKeyGormTx txKey = "go-crud.gormTx" MsgTransactionError = "error processing transaction" ) diff --git a/test/constants_test.go b/test/constants_test.go index acf7aec..0f362ef 100644 --- a/test/constants_test.go +++ b/test/constants_test.go @@ -16,7 +16,7 @@ func TestConstants(t *testing.T) { { name: "ContextKeyGormTx value", constant: string(lib.ContextKeyGormTx), - expected: "ezutil.gormTx", + expected: "go-crud.gormTx", }, { name: "MsgTransactionError value", @@ -36,7 +36,7 @@ func TestContextKeyGormTx_Type(t *testing.T) { // Verify that ContextKeyGormTx is of the correct type // The constant is defined as txKey type, not string directly keyStr := string(lib.ContextKeyGormTx) - assert.Equal(t, "ezutil.gormTx", keyStr, "ContextKeyGormTx string value should be correct") + assert.Equal(t, "go-crud.gormTx", keyStr, "ContextKeyGormTx string value should be correct") } func TestMsgTransactionError_Type(t *testing.T) { @@ -52,7 +52,7 @@ func TestConstants_NotEmpty(t *testing.T) { func TestConstants_Uniqueness(t *testing.T) { constants := map[string]interface{}{ - "ContextKeyGormTx": lib.ContextKeyGormTx, + "ContextKeyGormTx": lib.ContextKeyGormTx, "MsgTransactionError": lib.MsgTransactionError, } @@ -70,9 +70,9 @@ func TestContextKeyGormTx_Usage(t *testing.T) { // Should be usable as a context key (comparable type) key1 := lib.ContextKeyGormTx key2 := lib.ContextKeyGormTx - + assert.Equal(t, key1, key2, "ContextKeyGormTx should be comparable and equal to itself") - + // Should be different from other string values otherKey := "some.other.key" assert.NotEqual(t, string(key1), otherKey, "ContextKeyGormTx should be unique") @@ -81,9 +81,9 @@ func TestContextKeyGormTx_Usage(t *testing.T) { func TestMsgTransactionError_Usage(t *testing.T) { // Test that the message is suitable for error messages msg := lib.MsgTransactionError - + assert.GreaterOrEqual(t, len(msg), 5, "MsgTransactionError should be a meaningful message") - + // Should not contain special characters that might break error handling for _, char := range msg { assert.True(t, char >= 32 && char <= 126, "MsgTransactionError should not contain non-printable character: %d", char)