### SwagGen CLI Examples Source: https://github.com/donutnomad/gotoolkit/blob/main/swagGen/README.md Provides practical examples of using the SwagGen command-line tool for different scenarios, such as processing a directory, a single file, or specifying package names. ```bash # Process entire directory swagGen -path ./api -out swagger.go # Process single file swagGen -path ./api/user.go -interfaces "IUserAPI,IAdminAPI" # Specify package name and verbose output swagGen -path ./api -package myapi -v ``` -------------------------------- ### Install SwagGen Tool Source: https://github.com/donutnomad/gotoolkit/blob/main/swagGen/README.md Instructions for installing SwagGen, including building from source or direct Go build. ```bash make buildSwag go build -o swagGen ./swagGen ``` -------------------------------- ### Install sliceGen Go Tool Source: https://github.com/donutnomad/gotoolkit/blob/main/README.md Installs the sliceGen Go code generator to your system using the go install command. This makes the 'sliceGen' command available in your terminal. ```bash go install github.com/yourusername/sliceGen@latest ``` -------------------------------- ### Go Example: Implementing and Using User API Wrapper Source: https://github.com/donutnomad/gotoolkit/blob/main/swagGen/README.md This Go code demonstrates how to implement the `IUserAPI` interface with a `UserService` and then use the generated `UserAPIWrap` to integrate the service with a Gin web server. It shows the creation of service instances, wrapper instantiation, and binding routes. ```go // 实现业务接口 type UserService struct{} func (s *UserService) GetUser(ctx context.Context, userId string) BaseResponse[UserInfo] { // 业务逻辑 return BaseResponse[UserInfo]{ Code: 200, Message: "success", Data: UserInfo{ID: userId, Name: "John", Email: "john@example.com"}, } } func (s *UserService) CreateUser(ctx context.Context, user CreateUserReq) BaseResponse[UserInfo] { // 业务逻辑 return BaseResponse[UserInfo]{ Code: 200, Message: "success", Data: UserInfo{ID: "123", Name: user.Name, Email: user.Email}, } } // 使用生成的绑定代码 func main() { router := gin.Default() // 创建服务实例 userService := &UserService{} // 创建包装器 userWrapper := NewUserAPIWrap(userService) // 绑定所有路由 userWrapper.BindAll(router) // 或者单独绑定路由 // userWrapper.BindGetUser(router) // userWrapper.BindCreateUser(router) router.Run(":8080") } ``` -------------------------------- ### Basic CTE Usage Example (Go) Source: https://github.com/donutnomad/gotoolkit/blob/main/lib/gsql/CTE_README.md Demonstrates how to use the `With` method to define and use a basic CTE in gsql. This example shows constructing a query that selects from a CTE named `user_summary`, which itself selects users older than 18. It highlights the chaining of `Select`, `From`, and `With` methods. ```go u := UserSchema // WITH user_summary AS ( // SELECT id, name FROM users WHERE age > 18 // ) // SELECT * FROM users query := gsql.Select(gsql.Star). From(u). With("user_summary", gsql.Select(u.ID, u.Name). From(u). Where(u.Age.Gt(18)) ) sql := query.ToSQL() // 输出: WITH `user_summary` AS (SELECT ...) SELECT ... ``` -------------------------------- ### Complete SQL Query Example with Conditional Discount in Go Source: https://github.com/donutnomad/gotoolkit/blob/main/lib/gsql/CASE_WHEN_USAGE.md This Go code demonstrates building a complex SQL SELECT query using Gotoolkit. It includes defining fields, constructing a CASE expression for conditional discounts based on user level and amount, and then assembling the final query. ```go package main import ( "github.com/donutnomad/gotoolkit/lib/gsql" "github.com/donutnomad/gotoolkit/lib/gsql/field" ) func main() { // 定义字段 amount := field.NewComparable[int64]("orders", "amount") userLevel := field.NewPattern[string]("orders", "user_level") // 构建折扣规则 discount := gsql.Case(). When( gsql.And( userLevel.Eq("VIP"), amount.Gt(10000), ), gsql.Primitive(0.7), ). When( gsql.And( userLevel.Eq("Premium"), amount.Gt(5000), ), gsql.Primitive(0.85), ). Else(gsql.Primitive(1.0)). End().AsF("discount_rate") // 构建查询 sql := gsql.Select( gsql.Field("id"), amount, userLevel, discount, ).From(gsql.TableName("orders").Ptr()). Where(amount.Gt(0)). Order(amount, false). ToSQL() println(sql) } ``` -------------------------------- ### User API Endpoints Source: https://context7.com/donutnomad/gotoolkit/llms.txt Documentation for the User API endpoints, covering GET, POST, PUT, and DELETE operations for user resources. ```APIDOC ## GET /api/v1/users/{userId} ### Description Retrieves user information by user ID. ### Method GET ### Endpoint /api/v1/users/{userId} ### Parameters #### Path Parameters - **userId** (int64) - Required - User ID #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response (200) - **code** (int) - Response code - **message** (string) - Response message - **data** (object) - User data - **id** (int64) - User ID - **email** (string) - User email - **name** (string) - User name - **age** (int) - User age - **created_at** (int64) - Timestamp of creation #### Response Example ```json { "code": 0, "message": "OK", "data": { "id": 123, "email": "test@example.com", "name": "John Doe", "age": 30, "created_at": 1678886400 } } ``` ## GET /api/v1/users ### Description Retrieves a list of users with pagination. ### Method GET ### Endpoint /api/v1/users ### Parameters #### Path Parameters None #### Query Parameters - **page** (int) - Optional - Page number - **pageSize** (int) - Optional - Number of items per page #### Request Body None ### Request Example None ### Response #### Success Response (200) - **code** (int) - Response code - **message** (string) - Response message - **data** (array) - Array of user objects - Each object has the same structure as `UserResponse` #### Response Example ```json { "code": 0, "message": "OK", "data": [ { "id": 123, "email": "test@example.com", "name": "John Doe", "age": 30, "created_at": 1678886400 }, { "id": 124, "email": "jane@example.com", "name": "Jane Doe", "age": 28, "created_at": 1678886460 } ] } ``` ## POST /api/v1/users ### Description Creates a new user account. ### Method POST ### Endpoint /api/v1/users ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **email** (string) - Required - User email (must be a valid email format) - **name** (string) - Required - User name - **age** (int) - Optional - User age (between 0 and 150) ### Request Example ```json { "email": "newuser@example.com", "name": "New User", "age": 25 } ``` ### Response #### Success Response (200) - **code** (int) - Response code - **message** (string) - Response message - **data** (object) - Created user data (same structure as `UserResponse`) #### Response Example ```json { "code": 0, "message": "OK", "data": { "id": 125, "email": "newuser@example.com", "name": "New User", "age": 25, "created_at": 1678886520 } } ``` ## PUT /api/v1/users/{userId} ### Description Updates an existing user's information. ### Method PUT ### Endpoint /api/v1/users/{userId} ### Parameters #### Path Parameters - **userId** (int64) - Required - The ID of the user to update #### Query Parameters None #### Request Body - **email** (string) - Optional - Updated user email - **name** (string) - Optional - Updated user name - **age** (int) - Optional - Updated user age (between 0 and 150) ### Request Example ```json { "name": "Updated Name", "age": 31 } ``` ### Response #### Success Response (200) - **code** (int) - Response code - **message** (string) - Response message - **data** (object) - Updated user data (same structure as `UserResponse`) #### Response Example ```json { "code": 0, "message": "OK", "data": { "id": 123, "email": "test@example.com", "name": "Updated Name", "age": 31, "created_at": 1678886400 } } ``` ## DELETE /api/v1/users/{userId} ### Description Deletes a user by their ID. ### Method DELETE ### Endpoint /api/v1/users/{userId} ### Parameters #### Path Parameters - **userId** (int64) - Required - The ID of the user to delete #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response (200) - **code** (int) - Response code - **message** (string) - Response message - **data** (object) - Empty object or null indicating success #### Response Example ```json { "code": 0, "message": "OK", "data": null } ``` ``` -------------------------------- ### Example Struct and Generated Slice Helpers (Go) Source: https://github.com/donutnomad/gotoolkit/blob/main/README.md Illustrates a sample Go struct 'Book' and the corresponding slice helper methods (Name and Price) automatically generated by sliceGen. It highlights how exported fields are used to create accessor methods for slices of the struct. ```go type Book struct { Name string Price float64 author string // unexported field } type BookSlice []Book func (s BookSlice) Name() []string { return lo.Map(s, func(item Book, index int) string { return item.Name }) } func (s BookSlice) Price() []float64 { return lo.Map(s, func(item Book, index int) float64 { return item.Price }) } ``` -------------------------------- ### Go Interface Routing Annotations Source: https://github.com/donutnomad/gotoolkit/blob/main/swagGen/README.md Demonstrates how to use SwagGen annotations to define HTTP methods (GET, POST, PUT, PATCH, DELETE) and paths for Go interface methods. ```go type IUserAPI interface { // @GET(/api/v1/user/{id}) GetUser(ctx context.Context, id string) UserResponse // @POST(/api/v1/user) CreateUser(ctx context.Context, user CreateUserReq) UserResponse // @PUT(/api/v1/user/{id}) UpdateUser(ctx context.Context, id string, user UpdateUserReq) UserResponse // @PATCH(/api/v1/user/{id}) PatchUser(ctx context.Context, id string, patch PatchUserReq) UserResponse // @DELETE(/api/v1/user/{id}) DeleteUser(ctx context.Context, id string) error } ``` -------------------------------- ### Multiple CTEs Example (Go) Source: https://github.com/donutnomad/gotoolkit/blob/main/lib/gsql/CTE_README.md Illustrates how to define and use multiple CTEs within a single query using gsql. This example defines two CTEs, `young_users` and `old_users`, and then selects from the main table. It showcases the ability to chain multiple `With` calls to build complex query structures. ```go // WITH // young_users AS (SELECT * FROM users WHERE age < 30), // old_users AS (SELECT * FROM users WHERE age >= 30) // SELECT * FROM users query := gsql.Select(gsql.Star). From(u). With("young_users", gsql.Select(u.Star()).From(u).Where(u.Age.Lt(30)) ). With("old_users", gsql.Select(u.Star()).From(u).Where(u.Age.Gte(30)) ) ``` -------------------------------- ### Combining CTEs with Other Clauses (Go) Source: https://github.com/donutnomad/gotoolkit/blob/main/lib/gsql/CTE_README.md Shows the flexibility of using CTEs in gsql by combining them with various other query clauses like JOIN, WHERE, GROUP BY, HAVING, ORDER BY, and LIMIT. This example illustrates how a CTE (`active_users`) can be defined and then used in conjunction with other standard SQL clauses to build sophisticated queries. ```go query := gsql.Select(u.ID, u.Name). From(u). With("active_users", gsql.Select(u.ID).From(u).Where(u.Status.Eq("active")), ). Join(...). // JOIN Where(...). // WHERE GroupBy(...). // GROUP BY Having(...). // HAVING Order(...). // ORDER BY Limit(10) // LIMIT ``` -------------------------------- ### Basic SwagGen CLI Usage Source: https://github.com/donutnomad/gotoolkit/blob/main/swagGen/README.md Demonstrates the basic command-line options for SwagGen, including path, output file, package name, and verbosity. ```bash swagGen [options] Options: -path string: Directory or file path (required) -out string: Output filename (default "swagger_generated.go") -package string: Package name (optional) -interfaces string: Comma-separated interface names (optional) -v: Verbose output ``` -------------------------------- ### Build and Test SwagGen Tool Source: https://github.com/donutnomad/gotoolkit/blob/main/swagGen/README.md Instructions for building the SwagGen tool using 'make buildSwag', generating test data with 'go generate' in the testdata directory, and running Swagger documentation generation tests with 'make testSwag'. ```bash # Build the tool make buildSwag # Run tests cd swagGen/testdata go generate # Test Swagger documentation generation make testSwag ``` -------------------------------- ### Generate Mapping Code with Automap Source: https://context7.com/donutnomad/gotoolkit/llms.txt Demonstrates how to use the automap package to generate mapping functions dynamically. It parses source code to create mapping logic, including handling nested structs and patch tracking. This requires the 'github.com/donutnomad/gotoolkit/automap' and 'github.com/samber/mo' packages. ```go package main import ( "fmt" "github.com/donutnomad/gotoolkit/automap" "github.com/samber/mo" ) // Source types with ExportPatch support type UserInput struct { ID mo.Option[int64] Email mo.Option[string] FullName mo.Option[string] Book mo.Option[BookInfo] } type UserInputPatch struct { ID mo.Option[int64] Email mo.Option[string] FullName mo.Option[string] Book mo.Option[BookInfo] } func (u *UserInput) ExportPatch() *UserInputPatch { return &UserInputPatch{ ID: u.ID, Email: u.Email, FullName: u.FullName, Book: u.Book, } } type UserDTO struct { ID int64 `gorm:"column:id" Email string `gorm:"column:email" FirstName string `gorm:"column:first_name" LastName string `gorm:"column:last_name" BookName string `gorm:"column:book_name" BookISBN string `gorm:"column:book_isbn" } func MapUserToDTO(input *UserInput) *UserDTO { // Your mapping logic return &UserDTO{ ID: input.ID.OrEmpty(), Email: input.Email.OrEmpty(), // ... other mappings } } // Generate mapping code with patch tracking func GenerateMappingCode() { code, err := automap.ParseAndGenerate("MapUserToDTO", "ToPatch", automap.WithFileContext("./models/user.go")) if err != nil { panic(err) } // Generated code: // func ToPatch(input *UserInput) map[string]any { // dto := MapUserToDTO(input) // fields := input.ExportPatch() // ret := make(map[string]any) // // // One-to-one mapping // if fields.ID.IsPresent() { // ret["id"] = dto.ID // } // if fields.Email.IsPresent() { // ret["email"] = dto.Email // } // // // One-to-many mapping (FullName -> FirstName + LastName) // if fields.FullName.IsPresent() { // ret["first_name"] = dto.FirstName // ret["last_name"] = dto.LastName // } // // // Nested struct mapping (Book -> BookName + BookISBN) // if fields.Book.IsPresent() { // ret["book_name"] = dto.BookName // ret["book_isbn"] = dto.BookISBN // } // // return ret // } fmt.Println(code) } ``` -------------------------------- ### Go: 构建搜索式 CASE WHEN 表达式 Source: https://github.com/donutnomad/gotoolkit/blob/main/lib/gsql/CASE_WHEN_USAGE.md 使用 `gsql.Case()` 开始构建一个搜索式 CASE WHEN 表达式。可以通过链式调用 `When()` 和 `Else()` 方法来定义条件和结果,最后使用 `End().AsF()` 结束并命名。 ```go import ( "github.com/donutnomad/gotoolkit/gsql" "github.com/donutnomad/gotoolkit/gsql/field" ) amount := field.NewComparable[int64]("", "amount") amountLevel := gsql.Case(). When(amount.Gt(10000), gsql.Primitive("VIP")), When(amount.Gt(5000), gsql.Primitive("Premium")), When(amount.Gt(1000), gsql.Primitive("Standard")), Else(gsql.Primitive("Basic")), End().AsF("customer_level") ``` -------------------------------- ### Run Go Project Tests Source: https://github.com/donutnomad/gotoolkit/blob/main/README.md Executes the test suite for the Go project using the 'go test' command. The '-v' flag enables verbose output, and '-cover' generates a coverage report. ```bash go test -v -cover ``` -------------------------------- ### Generate GORM Query Builders and Patch Structures Source: https://context7.com/donutnomad/gotoolkit/llms.txt Utilizes the gormgen tool to generate type-safe GORM query builders and patch structures for database models. This streamlines database interactions by providing compile-time checking and reducing boilerplate code. The command `go run gormgen/main.go -dir=./models -struct=User,Product -patch2 -out=./models` is used for generation. ```bash # Generate query builder and patch structures go run gormgen/main.go -dir=./models -struct=User,Product -patch2 -out=./models ``` ```go package models import ( "github.com/donutnomad/gotoolkit/lib/gsql/field" "gorm.io/gorm" ) // Original model type User struct { ID int64 `gorm:"column:id;primaryKey" Email string `gorm:"column:email;uniqueIndex" Name string `gorm:"column:name" Age int `gorm:"column:age" IsActive bool `gorm:"column:is_active" CreatedAt int64 `gorm:"column:created_at" } // Generated query builder (user_query.go) type userQuery struct { tableName string } var User = &userQuery{tableName: "users"} func (u *userQuery) ID() field.Comparable[int64] { return field.NewComparable[int64](u.tableName, "id") } func (u *userQuery) Email() field.Pattern[string] { return field.NewPattern[string](u.tableName, "email") } func (u *userQuery) Age() field.Comparable[int] { return field.NewComparable[int](u.tableName, "age") } // Generated patch structure (user_patch.go) type UserPatch struct { ID *int64 Email *string Name *string Age *int IsActive *bool } func (up *UserPatch) Build() map[string]interface{} { updates := make(map[string]interface{}) if up.ID != nil { updates["id"] = *up.ID } if up.Email != nil { updates["email"] = *up.Email } if up.Name != nil { updates["name"] = *up.Name } if up.Age != nil { updates["age"] = *up.Age } if up.IsActive != nil { updates["is_active"] = *up.IsActive } return updates } // Usage example: Type-safe queries func QueryUsers(db *gorm.DB) ([]*User, error) { var users []*User err := db.Where( User.Age().Gte(18).And( User.Email().Like("%@example.com"), ).ToSQL(), ).Where( User.IsActive().Eq(true).ToSQL(), ).Order("created_at DESC").Find(&users).Error return users, err } // Usage example: Safe partial updates func UpdateUser(db *gorm.DB, userID int64, updates *UserPatch) error { return db.Model(&User{}). Where("id = ?", userID). Updates(updates.Build()).Error } ``` -------------------------------- ### Go: 构建嵌套 CASE WHEN 表达式 Source: https://github.com/donutnomad/gotoolkit/blob/main/lib/gsql/CASE_WHEN_USAGE.md CASE WHEN 表达式可以嵌套使用,允许在内部 CASE 表达式的结果上应用外部 CASE 逻辑。这对于处理复杂的条件依赖关系非常有用。 ```go import ( "github.com/donutnomad/gotoolkit/gsql" "github.com/donutnomad/gotoolkit/gsql/field" ) userType := field.NewPattern[string]("", "user_type") // 季节性折扣 seasonDiscount := gsql.Case(). When(gsql.Expr("MONTH(created_at) IN (11,12)"), gsql.Primitive(0.8)), When(gsql.Expr("MONTH(created_at) = ?", 6), gsql.Primitive(0.9)), Else(gsql.Primitive(1.0)), End() // VIP 在季节性折扣基础上再打 95 折 finalDiscount := gsql.Case(). When( userType.Eq("vip"), gsql.Expr("(?) * 0.95", seasonDiscount), ). Else(seasonDiscount). End().AsF("final_discount") ``` -------------------------------- ### Go Interface Parameter Annotations Source: https://github.com/donutnomad/gotoolkit/blob/main/swagGen/README.md Illustrates SwagGen annotations for defining different types of parameters for Go interface methods, including path, query, header, body, and form parameters. ```go // Path parameters // @GET(/api/v1/user/{userId}) GetUser( ctx context.Context, // @PARAM userId string, ) UserResponse // Aliased path parameter // @GET(/api/v1/user/{user_id}) GetUserById( ctx context.Context, // @PARAM(user_id) userId string, ) UserResponse // Query parameters // @GET(/api/v1/users) GetUsers( ctx context.Context, // @QUERY req GetUsersReq, ) UsersResponse // Header parameters // @GET(/api/v1/user/{id}) GetUser( ctx context.Context, // @HEADER token string, // @PARAM id string, ) UserResponse // Request body parameters // @POST(/api/v1/user) CreateUser( ctx context.Context, // @BODY user CreateUserReq, ) UserResponse // Form parameters // @POST(/api/v1/user) CreateUser( ctx context.Context, // @FORM user CreateUserReq, ) UserResponse ``` -------------------------------- ### Define Go API Interfaces and Gin Bindings Source: https://context7.com/donutnomad/gotoolkit/llms.txt This Go code defines API request/response structures and an interface for user-related operations. It also includes wrapper functions to integrate these API operations with the Gin web framework, handling request binding, middleware, and response formatting. Dependencies include the 'gin-gonic/gin' package. ```go package api import ( "context" "github.com/gin-gonic/gin" ) // Request/Response types type GetUserReq struct { UserID int64 `uri:"userId" binding:"required" } type CreateUserReq struct { Email string `json:"email" binding:"required,email" Name string `json:"name" binding:"required" Age int `json:"age" binding:"gte=0,lte=150" } type UserResponse struct { ID int64 `json:"id" Email string `json:"email" Name string `json:"name" Age int `json:"age" CreatedAt int64 `json:"created_at" } type BaseResponse[T any] struct { Code int `json:"code" Message string `json:"message" Data T `json:"data" } // @TAG(User) // @SECURITY(BearerAuth) // @HEADER(X-Request-ID,false,"Request ID for tracing") type UserAPI interface { // @GET(/api/v1/users/{userId}) // @JSON GetUser( ctx context.Context, // @PARAM userId int64, ) BaseResponse[UserResponse] // @GET(/api/v1/users) // @JSON // @QUERY ListUsers( ctx context.Context, // @QUERY page, pageSize int, ) BaseResponse[[]UserResponse] // @POST(/api/v1/users) // @JSON // @MID(auth,rateLimit) CreateUser( ctx context.Context, // @BODY req CreateUserReq, ) BaseResponse[UserResponse] // @PUT(/api/v1/users/{userId}) // @JSON // @MID(auth) UpdateUser( ctx context.Context, // @PARAM userId int64, // @BODY req CreateUserReq, ) BaseResponse[UserResponse] // @DELETE(/api/v1/users/{userId}) // @JSON // @MID(auth,adminOnly) DeleteUser( ctx context.Context, // @PARAM userId int64, ) BaseResponse[interface{}] } // Generated code (swagger_generated.go): type UserAPIWrap struct { inner UserAPI handler IUserAPIHandler } type IUserAPIHandler interface { Auth() gin.HandlerFunc RateLimit() gin.HandlerFunc AdminOnly() gin.HandlerFunc } func NewUserAPIWrap(inner UserAPI, handler IUserAPIHandler) *UserAPIWrap { return &UserAPIWrap{inner: inner, handler: handler} } // GetUser // @Summary Get user by ID // @Description Retrieves user information by user ID // @Tags User // @Accept json // @Produce json // @Security BearerAuth // @Param X-Request-ID header string false "Request ID for tracing" // @Param userId path int64 true "User ID" // @Success 200 {object} BaseResponse[UserResponse] // @Router /api/v1/users/{userId} [get] func (a *UserAPIWrap) GetUser(ctx *gin.Context) { userId := cast.ToInt64(ctx.Param("userId")) result := a.inner.GetUser(ctx, userId) onGinResponse(ctx, result) } // CreateUser // @Summary Create new user // @Description Creates a new user account // @Tags User // @Accept json // @Produce json // @Security BearerAuth // @Param X-Request-ID header string false "Request ID for tracing" // @Param request body CreateUserReq true "User creation request" // @Success 200 {object} BaseResponse[UserResponse] // @Router /api/v1/users [post] func (a *UserAPIWrap) CreateUser(ctx *gin.Context) { var req CreateUserReq if err := ctx.ShouldBindJSON(&req); err != nil { onGinError(ctx, err) return } result := a.inner.CreateUser(ctx, req) onGinResponse(ctx, result) } // Individual binding methods func (a *UserAPIWrap) BindGetUser(router gin.IRoutes, preHandlers ...gin.HandlerFunc) { handlers := append(preHandlers, a.GetUser) router.GET("/api/v1/users/:userId", handlers...) } func (a *UserAPIWrap) BindCreateUser(router gin.IRoutes, preHandlers ...gin.HandlerFunc) { handlers := append(preHandlers, a.handler.Auth(), a.handler.RateLimit(), a.CreateUser) router.POST("/api/v1/users", handlers...) } func (a *UserAPIWrap) BindDeleteUser(router gin.IRoutes, preHandlers ...gin.HandlerFunc) { handlers := append(preHandlers, a.handler.Auth(), a.handler.AdminOnly(), a.DeleteUser) router.DELETE("/api/v1/users/:userId", handlers...) } // Bind all endpoints at once func (a *UserAPIWrap) BindAll(router gin.IRoutes, preHandlers ...gin.HandlerFunc) { a.BindGetUser(router, preHandlers...) a.BindListUsers(router, preHandlers...) a.BindCreateUser(router, preHandlers...) a.BindUpdateUser(router, preHandlers...) a.BindDeleteUser(router, preHandlers...) } // Type references for Swagger (generated with -include-type-refs) var _ BaseResponse[UserResponse] var _ BaseResponse[[]UserResponse] var _ CreateUserReq var _ UserResponse // Usage: Setup API server func SetupRouter() *gin.Engine { r := gin.Default() // Implement interface handler handler := &UserAPIHandlerImpl{} // Create service implementation userService := &UserServiceImpl{} ``` -------------------------------- ### Go: 使用 Primitive 构建字面量值 Source: https://github.com/donutnomad/gotoolkit/blob/main/lib/gsql/CASE_WHEN_USAGE.md 推荐使用 `Primitive()` 函数来表示 SQL CASE 表达式中的字面量值,以获得类型安全。不推荐使用 `Expr("?", value)`。 ```go import "github.com/donutnomad/gotoolkit/gsql" // ✅ 推荐:使用 Primitive 表示字面量值 gsql.Primitive("VIP") gsql.Primitive(100) gsql.Primitive(0.7) // ❌ 不推荐:使用 Expr("?", value) gsql.Expr("?", "VIP") ``` -------------------------------- ### Go: 在 CASE WHEN 中使用 AND/OR 组合条件 Source: https://github.com/donutnomad/gotoolkit/blob/main/lib/gsql/CASE_WHEN_USAGE.md 可以使用 `gsql.And()` 和 `gsql.Or()` 函数在 `When()` 方法中组合多个条件,以构建更复杂的 CASE 逻辑。 ```go import ( "github.com/donutnomad/gotoolkit/gsql" "github.com/donutnomad/gotoolkit/gsql/field" ) userLevel := field.NewPattern[string]("", "user_level") amount := field.NewComparable[int64]("", "amount") firstOrder := field.NewComparable[bool]("", "first_order") discount := gsql.Case(). When( gsql.And( userLevel.Eq("VIP"), amount.Gt(10000), ), gsql.Primitive(0.7), // 7折 ). When( gsql.And( userLevel.Eq("Premium"), amount.Gt(5000), ), gsql.Primitive(0.85), // 85折 ). When(firstOrder.Eq(true), gsql.Primitive(0.9)). // 首单9折 Else(gsql.Primitive(1.0)). // 原价 End().AsF("discount_rate") ``` -------------------------------- ### Go: 使用字段操作符构建 CASE WHEN 条件 Source: https://github.com/donutnomad/gotoolkit/blob/main/lib/gsql/CASE_WHEN_USAGE.md 推荐通过定义字段并使用其类型安全的操作符方法来构建 CASE WHEN 条件。避免使用字符串拼接来构造 SQL 表达式。 ```go import ( "github.com/donutnomad/gotoolkit/gsql" "github.com/donutnomad/gotoolkit/gsql/field" ) // ✅ 推荐:定义字段并使用类型安全的操作符 amount := field.NewComparable[int64]("", "amount") userLevel := field.NewPattern[string]("", "user_level") gsql.Case(). When(amount.Gt(1000), gsql.Primitive("High")), When(userLevel.Eq("VIP"), gsql.Primitive("Premium")) // ❌ 不推荐:使用字符串拼接 gsql.Case(). When(gsql.Expr("amount > ?", 1000), gsql.Expr("?", "High")), When(gsql.Expr("user_level = ?", "VIP"), gsql.Expr("?", "Premium")) ``` -------------------------------- ### Generate Approval/Audit Trail Methods with approveGen Source: https://context7.com/donutnomad/gotoolkit/llms.txt Generates approval request structures and audit trail methods for functions marked with `@Approve` annotations. It builds the approveGen tool and then uses it to generate Go code for tracking approvals and audit trails. Dependencies include standard Go libraries and potentially external ones used within the annotated functions. ```bash # Build the tool go build -o build/annotation_approve approveGen/main.go # Generate approval methods from annotated code ./build/annotation_approve -path=./services,./handlers -out=approvals_generated.go -v2 -methods=true ``` ```go // Source: Annotate methods requiring approval tracking package service type UserService struct {} // @Approve // args::string="User update: UserID={$value}, Email={$value}"; sep=" | " // args::field=AuditMessage // func::hookRejected func (s *UserService) UpdateUser(ctx context.Context, userID string, email string, name string) error { // Business logic here return nil } // Generated code creates approval request struct: type UpdateUserApprovalRequest struct { UserID string Email string Name string } func (p *UpdateUserApprovalRequest) String() string { ss := make([]string, 0, 3) ss = append(ss, fmt.Sprintf("User update: UserID=%s", p.UserID)) ss = append(ss, fmt.Sprintf("Email=%s", p.Email)) ss = append(ss, fmt.Sprintf("Name=%s", p.Name)) return strings.Join(ss, " | ") } func (p *UpdateUserApprovalRequest) MethodName() string { return "UserService_UpdateUser" } func (p *UpdateUserApprovalRequest) Json() ([]byte, error) { return json.Marshal(p) } // Central dispatcher method for invoking approved methods func CallMethodForApproval(ctx context.Context, service interface{}, methodName string, params []byte) (interface{}, error) { switch methodName { case "UserService_UpdateUser": var req UpdateUserApprovalRequest if err := json.Unmarshal(params, &req); err != nil { return nil, err } return nil, service.(*UserService).UpdateUser(ctx, req.UserID, req.Email, req.Name) default: return nil, fmt.Errorf("unknown method: %s", methodName) } } ``` -------------------------------- ### Go: 在 ORDER BY 子句中使用 CASE WHEN Source: https://github.com/donutnomad/gotoolkit/blob/main/lib/gsql/CASE_WHEN_USAGE.md CASE WHEN 表达式可用于 `ORDER BY` 子句,以实现自定义的排序逻辑,例如为不同的状态指定优先级。这允许更灵活的数据排序。 ```go import ( "github.com/donutnomad/gotoolkit/gsql" "github.com/donutnomad/gotoolkit/gsql/field" ) status := field.NewPattern[string]("", "status") priority := gsql.Case(). When(status.Eq("urgent"), gsql.Primitive(1)), When(status.Eq("high"), gsql.Primitive(2)), When(status.Eq("normal"), gsql.Primitive(3)), Else(gsql.Primitive(4)), End().AsF("priority") sql := gsql.Select( gsql.Field("id"), gsql.Field("status"), priority, ).From(gsql.TableName("tasks").Ptr()). Order(priority, true). // 按优先级升序 ToSQL() ``` -------------------------------- ### Go Generated Code: Gin Binding Source: https://github.com/donutnomad/gotoolkit/blob/main/swagGen/README.md This Go code defines a Gin wrapper (`UserAPIWrap`) that binds the `IUserAPI` interface methods to Gin routes. It includes functions for creating the wrapper, binding individual routes (e.g., BindGetUser, BindCreateUser), and binding all routes at once. ```go func NewUserAPIWrap(inner IUserAPI) *UserAPIWrap { return &UserAPIWrap{ inner: inner, } } type UserAPIWrap struct { inner IUserAPI } func (a *UserAPIWrap) bind(router gin.IRoutes, method, path string, preHandlers, innerHandlers []gin.HandlerFunc, f gin.HandlerFunc) { var basePath string if v, ok := router.(interface { BasePath() string }); ok { basePath = v.BasePath() } handlers := make([]gin.HandlerFunc, 0, len(preHandlers)+len(innerHandlers)+1) handlers = append(handlers, preHandlers...) handlers = append(handlers, innerHandlers...) handlers = append(handlers, f) router.Handle(method, strings.TrimPrefix(path, basePath), handlers...) } func (a *UserAPIWrap) BindGetUser(router gin.IRoutes, preHandlers ...gin.HandlerFunc) { a.bind(router, "GET", "/api/v1/user/:userId", preHandlers, nil, a.GetUser) } func (a *UserAPIWrap) BindCreateUser(router gin.IRoutes, preHandlers ...gin.HandlerFunc) { a.bind(router, "POST", "/api/v1/user", preHandlers, nil, a.CreateUser) } func (a *UserAPIWrap) BindAll(router gin.IRoutes, preHandlers ...gin.HandlerFunc) { a.BindGetUser(router, preHandlers...) a.BindCreateUser(router, preHandlers...) } ``` -------------------------------- ### Generate Slice Helper Methods with sliceGen Source: https://github.com/donutnomad/gotoolkit/blob/main/README.md Demonstrates the command-line usage of sliceGen to generate slice helper methods for specified struct types. It shows how to provide struct names, fields to ignore, and specific methods to generate. ```bash sliceGen -type=StructName1,StructName2 -ignoreFields=Field1,Field2 -methods=filter,map,reduce,sort,groupby ``` -------------------------------- ### SQL Build Flow for CTEs (Conceptual) Source: https://github.com/donutnomad/gotoolkit/blob/main/lib/gsql/CTE_README.md Describes the internal process of how a CTE is built and integrated into the SQL statement within the gsql library. It outlines the steps from calling the `With` method to the final SQL generation, emphasizing the role of `QueryBuilderG.ctes` and the `CTEClause` implementation. ```go QueryBuilder.With("cte_name", subquery) ↓ 添加到 QueryBuilderG.ctes ↓ buildStmt() 时通过 stmt.AddClause(CTEClause{...}) ↓ GORM 按 queryClauses 顺序构建 ↓ WITH cte_name AS (...) SELECT ... ``` -------------------------------- ### Generate Go Slice Helper Methods (filter, map, sort, groupby) Source: https://context7.com/donutnomad/gotoolkit/llms.txt This Go code defines a 'BookSlice' type and generates various helper methods for it, including field extraction (ID, Name, Price), filtering, sorting, and grouping. These methods facilitate common slice manipulation tasks. The 'lo' library from samber is used for efficient collection operations. The generated methods are demonstrated in the 'ProcessBooks' function. ```go package models import ( "fmt" "github.com/samber/lo" "sort" ) // Original struct type Book struct { ID int64 Name string Price float64 Author string ISBN string Published int } // Generated slice type type BookSlice []Book // Generated field extraction methods func (s BookSlice) ID() []int64 { return lo.Map(s, func(item Book, index int) int64 { return item.ID }) } func (s BookSlice) Name() []string { return lo.Map(s, func(item Book, index int) string { return item.Name }) } func (s BookSlice) Price() []float64 { return lo.Map(s, func(item Book, index int) float64 { return item.Price }) } // Generated filter method (-methods=filter) func (s BookSlice) Filter(fn func(Book) bool) BookSlice { return lo.Filter(s, func(item Book, _ int) bool { return fn(item) }) } // Generated sort method (-methods=sort) func (s BookSlice) Sort(less func(Book, Book) bool) BookSlice { result := append(BookSlice{}, s...) sort.Slice(result, func(i, j int) bool { return less(result[i], result[j]) }) return result } // Generated groupby method (-methods=groupby) func (s BookSlice) GroupBy(fn func(Book) string) map[string]BookSlice { return lo.GroupBy(s, func(item Book) string { return fn(item) }) } // Usage examples func ProcessBooks(books BookSlice) { // Extract all book names names := books.Name() fmt.Println("All book names:", names) // Filter expensive books expensiveBooks := books.Filter(func(b Book) bool { return b.Price > 50.0 }) // Sort by price sortedByPrice := books.Sort(func(a, b Book) bool { return a.Price < b.Price }) // Group by author booksByAuthor := books.GroupBy(func(b Book) string { return b.Author }) for author, authorBooks := range booksByAuthor { avgPrice := lo.SumBy(authorBooks, func(b Book) float64 { return b.Price }) / float64(len(authorBooks)) fmt.Printf("%s: %d books, avg price: %.2f\n", author, len(authorBooks), avgPrice) } } ``` -------------------------------- ### Go Interface Middleware Annotations Source: https://github.com/donutnomad/gotoolkit/blob/main/swagGen/README.md Shows how to specify middleware for Go interface routes using the @MID annotation with SwagGen. ```go // @GET(/api/v1/user/{id}) // @MID(auth,log) GetUser(ctx context.Context, id string) UserResponse ``` -------------------------------- ### Go: 在 GROUP BY 子句中使用 CASE WHEN Source: https://github.com/donutnomad/gotoolkit/blob/main/lib/gsql/CASE_WHEN_USAGE.md CASE WHEN 表达式可以用于 `GROUP BY` 子句,以便根据自定义的逻辑对数据进行分组。这常用于按数值范围或特定条件对数据进行聚合。 ```go import ( "github.com/donutnomad/gotoolkit/gsql" "github.com/donutnomad/gotoolkit/gsql/field" ) amount := field.NewComparable[int64]("", "amount") amountRange := gsql.Case(). When(amount.Lt(100), gsql.Primitive("0-100")), When(amount.Lt(500), gsql.Primitive("100-500")), When(amount.Lt(1000), gsql.Primitive("500-1000")), Else(gsql.Primitive("1000+")), End().AsF("amount_range") sql := gsql.Select( amountRange, gsql.COUNT().AsF("order_count"), gsql.SUM(amount.ToExpr()).AsF("total_amount"), ).From(gsql.TableName("orders").Ptr()). GroupBy(amountRange). ToSQL() ``` -------------------------------- ### Go: 构建简单式 CASE WHEN 表达式 Source: https://github.com/donutnomad/gotoolkit/blob/main/lib/gsql/CASE_WHEN_USAGE.md 使用 `gsql.CaseValue(expr)` 开始构建一个简单式 CASE WHEN 表达式,其中 `expr` 是需要进行匹配的值。同样可以使用 `When()`, `Else()`, `End()` 来定义逻辑。 ```go import ( "github.com/donutnomad/gotoolkit/gsql" "github.com/donutnomad/gotoolkit/gsql/field" ) status := field.NewComparable[int]("", "status") statusDesc := gsql.CaseValue(status.ToExpr()). When(gsql.Primitive(0), gsql.Primitive("待处理")), When(gsql.Primitive(1), gsql.Primitive("处理中")), When(gsql.Primitive(2), gsql.Primitive("已完成")), Else(gsql.Primitive("未知状态")), End().AsF("status_desc") ``` -------------------------------- ### Go Interface Level Annotations Source: https://github.com/donutnomad/gotoolkit/blob/main/swagGen/README.md Explains how to apply SwagGen annotations at the interface level, which then apply to all methods within that interface, such as TAG, SECURITY, and HEADER. ```go // @TAG(User) // @SECURITY(ApiKeyAuth) // @HEADER(X-API-Version,true,"API version") type IUserAPI interface { // @GET(/api/v1/user/{id}) GetUser(ctx context.Context, id string) UserResponse // @POST(/api/v1/user) CreateUser(ctx context.Context, user CreateUserReq) UserResponse } ```