gormcnm is the foundational library that powers the entire GORM type-safety ecosystem. As the cornerstone of enterprise-grade Go database operations, it provides the core ColumnName[T]
generic type that enables compile-time type safety, eliminates hardcoded strings, and transforms GORM into a truly robust ORM solution.
π― The Foundation Layer: Just as React needs a virtual DOM and Spring needs dependency injection, GORM needs gormcnm for enterprise-grade type safety.
Traditional GORM queries are fragile and error-prone:
// β Traditional: Brittle hardcoded strings
db.Where("username = ?", "alice").Where("age >= ?", 18).First(&user)
Problems:
- β Runtime failures from typos (
"usrname"
vs"username"
) - β Silent bugs when model fields change
- β No type checking between column types and values
- β Refactoring nightmares across large codebases
// β
GORMCNM: Type-safe, refactor-proof, enterprise-ready
const (
colUsername = gormcnm.ColumnName[string]("username")
colAge = gormcnm.ColumnName[int]("age")
)
db.Where(colUsername.Eq("alice")).Where(colAge.Gte(18)).First(&user)
Benefits:
- β Compile-time validation catches errors before deployment
- β IDE auto-completion prevents typos completely
- β Automatic refactoring when model fields change
- β Type safety ensures value types match column types
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β GORM Type-Safe Ecosystem β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β βββββββββββββββ βββββββββββββββ βββββββββββββββ β
β β gormzhcn β β gormmom β β gormrepo β β
β β Chinese API βββββΆβ Native Lang βββββΆβ Package βββββββ β
β β Localize β β Smart Tags β β Pattern β β β
β βββββββββββββββ βββββββββββββββ βββββββββββββββ β β
β β β β β
β β βΌ βΌ β
β β βββββββββββββββ βββββββββββββββ β
β β β gormcngen β βApplication β β
β β βCode GenerateβββββββββββββββΆβCustom Code β β
β β βAST Operationβ β β β
β β βββββββββββββββ βββββββββββββββ β
β β β β² β
β β βΌ β β
β ββββββββββββββΆββββββββββββββββββββββββββββββββββββββ β
β β GORMCNM β β
β β FOUNDATION β β
β β Type-Safe β β
β β Core Logic β β
β βββββββββββββββ β
β β β
β βΌ β
β βββββββββββββββ β
β β GORM β β
β β Database β β
β βββββββββββββββ β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
GORMCNM sits at the foundation layer, providing the core type-safe primitives that all other ecosystem components depend on.
go get github.com/yyle88/gormcnm
At the heart of GORMCNM is the generic ColumnName[T]
type:
type ColumnName[T any] string
This simple yet powerful type provides:
- Type-safe operations:
Eq()
,Ne()
,Gt()
,Lt()
,In()
,Between()
, etc. - Value-key pairs:
Kv()
for updates,Kw()
for map building - Expression building:
ExprAdd()
,ExprSub()
,ExprMul()
, etc. - Order clauses:
Asc()
,Desc()
,OrderByBottle()
for complex sorting
Language | ORM | Type-Safe Columns | Example |
---|---|---|---|
Java | MyBatis Plus | Example::getName |
wrapper.eq(Example::getName, "alice") |
Python | SQLAlchemy | Example.name |
query.filter(Example.name == "alice") |
Go | GORMCNM | cls.Name.Eq() |
db.Where(cls.Name.Eq("alice")) |
package main
import (
"fmt"
"github.com/google/uuid"
"github.com/yyle88/done"
"github.com/yyle88/gormcnm"
"github.com/yyle88/rese"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
type User struct {
ID uint `gorm:"primaryKey"`
Username string `gorm:"uniqueIndex"`
Age int
Email string `gorm:"index"`
}
// Define type-safe columns
const (
colID = gormcnm.ColumnName[uint]("id")
colUsername = gormcnm.ColumnName[string]("username")
colAge = gormcnm.ColumnName[int]("age")
colEmail = gormcnm.ColumnName[string]("email")
)
func main() {
// Setup database
dsn := fmt.Sprintf("file:db-%s?mode=memory&cache=shared", uuid.New().String())
db := rese.P1(gorm.Open(sqlite.Open(dsn), &gorm.Config{
Logger: logger.Default.LogMode(logger.Info),
}))
defer rese.F0(rese.P1(db.DB()).Close)
done.Done(db.AutoMigrate(&User{}))
// Insert test data
users := []*User{
{Username: "alice", Age: 25, Email: "alice@example.com"},
{Username: "bob", Age: 30, Email: "bob@example.com"},
}
done.Done(db.Create(users).Error)
// Type-safe queries
var user User
done.Done(db.Where(colUsername.Eq("alice")).First(&user).Error)
fmt.Printf("Found user: %+v\n", user)
// Complex type-safe queries
var adults []User
done.Done(db.Where(colAge.Gte(25)).
Where(colEmail.Like("%@example.com")).
Find(&adults).Error)
fmt.Printf("Adults: %d users\n", len(adults))
// Type-safe updates
done.Done(db.Model(&user).Where(colID.Eq(user.ID)).
Update(colAge.Kv(26)).Error)
// Bulk updates with type safety
done.Done(db.Model(&User{}).
Where(colAge.Between(20, 30)).
Updates(colAge.Kw(99).Kw(colEmail.Kv("updated@example.com")).AsMap()).Error)
}
// Comparison operations
db.Where(colAge.Eq(25)) // age = 25
db.Where(colAge.Ne(25)) // age != 25
db.Where(colAge.Gt(25)) // age > 25
db.Where(colAge.Gte(25)) // age >= 25
db.Where(colAge.Lt(30)) // age < 30
db.Where(colAge.Lte(30)) // age <= 30
// Range operations
db.Where(colAge.Between(18, 65)) // age BETWEEN 18 AND 65
db.Where(colAge.In([]int{18, 25, 30})) // age IN (18, 25, 30)
// String operations
db.Where(colUsername.Like("%admin%")) // username LIKE '%admin%'
db.Where(colEmail.IsNotNULL()) // email IS NOT NULL
db.Where(colUsername.BetweenAND("a", "m")) // username BETWEEN 'a' AND 'm'
// Single field updates
db.Model(&user).Update(colAge.Kv(26))
// Multiple field updates
updates := colAge.Kw(26).Kw(colEmail.Kv("new@example.com")).AsMap()
db.Model(&user).Updates(updates)
// Expression updates
db.Model(&user).Update(colAge.KeAdd(1)) // age = age + 1
db.Model(&user).Update(colAge.KeSub(2)) // age = age - 2
// Simple ordering
db.Order(colAge.Asc()) // ORDER BY age ASC
db.Order(colAge.Desc()) // ORDER BY age DESC
// Complex ordering for repository patterns
orderBottle := colAge.OrderByBottle("DESC")
// Used in advanced repository patterns with gormrepo
- Zero runtime column errors: All column references validated at compile time
- Type matching: Ensures values match column types (
string
values forstring
columns) - Refactoring safety: IDE automatically updates all references when model fields change
- IDE intelligence: Full auto-completion and error highlighting
- Code clarity: Self-documenting queries that clearly show column operations
- Reduced debugging: Eliminate entire classes of column-name-related bugs
- gormcngen: Auto-generates column definitions
- gormrepo: Repository pattern with type-safe queries
- gormmom: Native language field support
- No breaking changes: Integrates seamlessly with existing GORM code
- Incremental migration: Adopt type-safe columns one query at a time
- Zero learning curve: Familiar GORM syntax with added type safety
Aspect | Traditional GORM | GORMCNM |
---|---|---|
Column References | β "username" (hardcoded strings) |
β
colUsername.Eq() (type-safe) |
Error Detection | β Runtime failures | β Compile-time validation |
Refactoring | β Manual find-replace, error-prone | β IDE auto-refactor, bulletproof |
Type Checking | β No value-type validation | β Strong type checking |
IDE Support | β No auto-completion for columns | β Full IntelliSense support |
Maintainability | π‘ Manual maintenance required | β Self-maintaining with AST tools |
Learning Curve | π’ Familiar GORM syntax | π’ Same syntax + type safety |
// β Traditional GORM: Fragile and error-prone
db.Where("username = ?", "alice").
Where("age >= ?", 18).
Where("email LIKE ?", "%@company.com").
First(&user)
// β
GORMCNM: Type-safe and refactor-proof
db.Where(colUsername.Eq("alice")).
Where(colAge.Gte(18)).
Where(colEmail.Like("%@company.com")).
First(&user)
When combined with gormcngen, you get auto-generated column structs:
type UserColumns struct {
ID gormcnm.ColumnName[uint]
Username gormcnm.ColumnName[string]
Age gormcnm.ColumnName[int]
Email gormcnm.ColumnName[string]
}
func (*User) Columns() *UserColumns {
return &UserColumns{
ID: "id",
Username: "username",
Age: "age",
Email: "email",
}
}
// Usage with generated columns
var user User
cls := user.Columns()
db.Where(cls.Username.Eq("alice")).
Where(cls.Age.Gte(18)).
First(&user)
GORMCNM integrates seamlessly with gormrepo:
repo := gormrepo.NewRepo(gormclass.Use(&User{}))
// Type-safe repository queries
user, err := repo.Repo(db).First(func (db *gorm.DB, cls *UserColumns) *gorm.DB {
return db.Where(cls.Username.Eq("alice")).
Where(cls.Age.Gte(18))
})
// Build complex conditions with type safety
var users []User
err := db.Where(
colAge.Between(18, 65),
).Where(
colEmail.IsNotNULL(),
).Where(
colUsername.In([]string{"alice", "bob", "charlie"}),
).Order(
colAge.Asc(),
).Limit(10).Find(&users).Error
// Java: MyBatis Plus
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getUsername, "alice")
.ge(User::getAge, 18);
List<User> users = userMapper.selectList(wrapper);
# Python: SQLAlchemy
users = session.query(User).filter(
User.username == "alice",
User.age >= 18
).all()
// Go: GORMCNM
var users []User
db.Where(colUsername.Eq("alice")).
Where(colAge.Gte(18)).
Find(&users)
GORMCNM brings the same level of type safety and developer experience to Go that other ecosystems take for granted.
- Compile-time only: All type checking happens during compilation
- Runtime efficiency: Generated code is identical to hand-written GORM queries
- Memory efficient: No reflection, no runtime type checking
- Enterprise deployments: Used in production systems processing millions of queries
- Comprehensive test coverage: Extensive test suites ensure reliability
- Active maintenance: Regular updates and community support
- gormcnm - Type-safe column operations (this package)
- gormcngen - Auto-generates column structs from models
- gormmom - Native language field tag management
- gormrepo - Repository pattern with type-safe queries
- Install GORMCNM:
go get github.com/yyle88/gormcnm
- Define column constants: Create type-safe column definitions for your models
- Replace hardcoded strings: Gradually migrate existing queries to use typed columns
- Add code generation: Optionally integrate with
gormcngen
for automatic column generation - Scale with repository pattern: Use
gormrepo
for enterprise-grade database operations
MIT License. See LICENSE.
Contributions are welcome! Report bugs, suggest features, and contribute code:
- π Found a bug? Open an issue on GitHub with reproduction steps
- π‘ Have a feature idea? Create an issue to discuss the suggestion
- π Documentation confusing? Report it so we can improve
- π Need new features? Share your use cases to help us understand requirements
- β‘ Performance issue? Help us optimize by reporting slow operations
- π§ Configuration problem? Ask questions about complex setups
- π’ Follow project progress? Watch the repo for new releases and features
- π Success stories? Share how this package improved your workflow
- π¬ General feedback? All suggestions and comments are welcome
New code contributions, follow this process:
- Fork: Fork the repo on GitHub (using the webpage interface).
- Clone: Clone the forked project (
git clone https://github.com/yourname/repo-name.git
). - Navigate: Navigate to the cloned project (
cd repo-name
) - Branch: Create a feature branch (
git checkout -b feature/xxx
). - Code: Implement your changes with comprehensive tests
- Testing: (Golang project) Ensure tests pass (
go test ./...
) and follow Go code style conventions - Documentation: Update documentation for user-facing changes and use meaningful commit messages
- Stage: Stage changes (
git add .
) - Commit: Commit changes (
git commit -m "Add feature xxx"
) ensuring backward compatible code - Push: Push to the branch (
git push origin feature/xxx
). - PR: Open a pull request on GitHub (on the GitHub webpage) with detailed description.
Please ensure tests pass and include relevant documentation updates.
Welcome to contribute to this project by submitting pull requests and reporting issues.
Project Support:
- β Give GitHub stars if this project helps you
- π€ Share with teammates and (golang) programming friends
- π Write tech blogs about development tools and workflows - we provide content writing support
- π Join the ecosystem - committed to supporting open source and the (golang) development scene
Happy Coding with this package! π