docs(constitution): 新增数据库设计原则(v2.4.0)
在项目宪章中新增第九条原则"数据库设计原则",明确禁止使用数据库外键约束和ORM关联标签。 主要变更: - 新增原则IX:数据库设计原则(Database Design Principles) - 强制要求:数据库表不得使用外键约束 - 强制要求:GORM模型不得使用ORM关联标签(foreignKey、hasMany等) - 强制要求:表关系必须通过ID字段手动维护 - 强制要求:关联数据查询必须显式编写,避免ORM魔法 - 强制要求:时间字段由GORM处理,不使用数据库触发器 设计理念: - 提升业务逻辑灵活性(无数据库约束限制) - 优化高并发性能(无外键检查开销) - 增强代码可读性(显式查询,无隐式预加载) - 简化数据库架构和迁移流程 - 支持分布式和微服务场景 版本升级:2.3.0 → 2.4.0(MINOR)
This commit is contained in:
254
internal/service/order/service.go
Normal file
254
internal/service/order/service.go
Normal file
@@ -0,0 +1,254 @@
|
||||
package order
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/break/junhong_cmp_fiber/internal/model"
|
||||
"github.com/break/junhong_cmp_fiber/internal/store/postgres"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
||||
pkgErrors "github.com/break/junhong_cmp_fiber/pkg/errors"
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// Service 订单服务
|
||||
type Service struct {
|
||||
store *postgres.Store
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
// NewService 创建订单服务
|
||||
func NewService(store *postgres.Store, logger *zap.Logger) *Service {
|
||||
return &Service{
|
||||
store: store,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// CreateOrder 创建订单
|
||||
func (s *Service) CreateOrder(ctx context.Context, req *model.CreateOrderRequest) (*model.Order, error) {
|
||||
// 验证用户是否存在
|
||||
_, err := s.store.User.GetByID(ctx, req.UserID)
|
||||
if err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return nil, pkgErrors.New(pkgErrors.CodeNotFound, "用户不存在")
|
||||
}
|
||||
s.logger.Error("查询用户失败",
|
||||
zap.Uint("user_id", req.UserID),
|
||||
zap.Error(err))
|
||||
return nil, pkgErrors.New(pkgErrors.CodeInternalError, "查询用户失败")
|
||||
}
|
||||
|
||||
// 创建订单
|
||||
order := &model.Order{
|
||||
OrderID: req.OrderID,
|
||||
UserID: req.UserID,
|
||||
Amount: req.Amount,
|
||||
Status: constants.OrderStatusPending,
|
||||
Remark: req.Remark,
|
||||
}
|
||||
|
||||
if err := s.store.Order.Create(ctx, order); err != nil {
|
||||
s.logger.Error("创建订单失败",
|
||||
zap.String("order_id", req.OrderID),
|
||||
zap.Error(err))
|
||||
return nil, pkgErrors.New(pkgErrors.CodeInternalError, "创建订单失败")
|
||||
}
|
||||
|
||||
s.logger.Info("订单创建成功",
|
||||
zap.Uint("id", order.ID),
|
||||
zap.String("order_id", order.OrderID),
|
||||
zap.Uint("user_id", order.UserID))
|
||||
|
||||
return order, nil
|
||||
}
|
||||
|
||||
// GetOrderByID 根据 ID 获取订单
|
||||
func (s *Service) GetOrderByID(ctx context.Context, id uint) (*model.Order, error) {
|
||||
order, err := s.store.Order.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return nil, pkgErrors.New(pkgErrors.CodeNotFound, "订单不存在")
|
||||
}
|
||||
s.logger.Error("获取订单失败",
|
||||
zap.Uint("order_id", id),
|
||||
zap.Error(err))
|
||||
return nil, pkgErrors.New(pkgErrors.CodeInternalError, "获取订单失败")
|
||||
}
|
||||
return order, nil
|
||||
}
|
||||
|
||||
// UpdateOrder 更新订单
|
||||
func (s *Service) UpdateOrder(ctx context.Context, id uint, req *model.UpdateOrderRequest) (*model.Order, error) {
|
||||
// 查询订单
|
||||
order, err := s.store.Order.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return nil, pkgErrors.New(pkgErrors.CodeNotFound, "订单不存在")
|
||||
}
|
||||
s.logger.Error("查询订单失败",
|
||||
zap.Uint("order_id", id),
|
||||
zap.Error(err))
|
||||
return nil, pkgErrors.New(pkgErrors.CodeInternalError, "查询订单失败")
|
||||
}
|
||||
|
||||
// 更新字段
|
||||
if req.Status != nil {
|
||||
order.Status = *req.Status
|
||||
// 根据状态自动设置时间字段
|
||||
now := time.Now()
|
||||
switch *req.Status {
|
||||
case constants.OrderStatusPaid:
|
||||
order.PaidAt = &now
|
||||
case constants.OrderStatusCompleted:
|
||||
order.CompletedAt = &now
|
||||
}
|
||||
}
|
||||
if req.Remark != nil {
|
||||
order.Remark = *req.Remark
|
||||
}
|
||||
|
||||
// 保存更新
|
||||
if err := s.store.Order.Update(ctx, order); err != nil {
|
||||
s.logger.Error("更新订单失败",
|
||||
zap.Uint("order_id", id),
|
||||
zap.Error(err))
|
||||
return nil, pkgErrors.New(pkgErrors.CodeInternalError, "更新订单失败")
|
||||
}
|
||||
|
||||
s.logger.Info("订单更新成功",
|
||||
zap.Uint("id", order.ID),
|
||||
zap.String("order_id", order.OrderID))
|
||||
|
||||
return order, nil
|
||||
}
|
||||
|
||||
// DeleteOrder 删除订单(软删除)
|
||||
func (s *Service) DeleteOrder(ctx context.Context, id uint) error {
|
||||
// 检查订单是否存在
|
||||
_, err := s.store.Order.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return pkgErrors.New(pkgErrors.CodeNotFound, "订单不存在")
|
||||
}
|
||||
s.logger.Error("查询订单失败",
|
||||
zap.Uint("order_id", id),
|
||||
zap.Error(err))
|
||||
return pkgErrors.New(pkgErrors.CodeInternalError, "查询订单失败")
|
||||
}
|
||||
|
||||
// 软删除
|
||||
if err := s.store.Order.Delete(ctx, id); err != nil {
|
||||
s.logger.Error("删除订单失败",
|
||||
zap.Uint("order_id", id),
|
||||
zap.Error(err))
|
||||
return pkgErrors.New(pkgErrors.CodeInternalError, "删除订单失败")
|
||||
}
|
||||
|
||||
s.logger.Info("订单删除成功", zap.Uint("order_id", id))
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListOrders 分页获取订单列表
|
||||
func (s *Service) ListOrders(ctx context.Context, page, pageSize int) ([]model.Order, int64, error) {
|
||||
// 参数验证
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
if pageSize < 1 {
|
||||
pageSize = constants.DefaultPageSize
|
||||
}
|
||||
if pageSize > constants.MaxPageSize {
|
||||
pageSize = constants.MaxPageSize
|
||||
}
|
||||
|
||||
orders, total, err := s.store.Order.List(ctx, page, pageSize)
|
||||
if err != nil {
|
||||
s.logger.Error("获取订单列表失败",
|
||||
zap.Int("page", page),
|
||||
zap.Int("page_size", pageSize),
|
||||
zap.Error(err))
|
||||
return nil, 0, pkgErrors.New(pkgErrors.CodeInternalError, "获取订单列表失败")
|
||||
}
|
||||
|
||||
return orders, total, nil
|
||||
}
|
||||
|
||||
// ListOrdersByUserID 根据用户ID分页获取订单列表
|
||||
func (s *Service) ListOrdersByUserID(ctx context.Context, userID uint, page, pageSize int) ([]model.Order, int64, error) {
|
||||
// 参数验证
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
if pageSize < 1 {
|
||||
pageSize = constants.DefaultPageSize
|
||||
}
|
||||
if pageSize > constants.MaxPageSize {
|
||||
pageSize = constants.MaxPageSize
|
||||
}
|
||||
|
||||
orders, total, err := s.store.Order.ListByUserID(ctx, userID, page, pageSize)
|
||||
if err != nil {
|
||||
s.logger.Error("获取用户订单列表失败",
|
||||
zap.Uint("user_id", userID),
|
||||
zap.Int("page", page),
|
||||
zap.Int("page_size", pageSize),
|
||||
zap.Error(err))
|
||||
return nil, 0, pkgErrors.New(pkgErrors.CodeInternalError, "获取订单列表失败")
|
||||
}
|
||||
|
||||
return orders, total, nil
|
||||
}
|
||||
|
||||
// CreateOrderWithUser 创建订单并更新用户统计(事务示例)
|
||||
func (s *Service) CreateOrderWithUser(ctx context.Context, req *model.CreateOrderRequest) (*model.Order, error) {
|
||||
var order *model.Order
|
||||
|
||||
// 使用事务
|
||||
err := s.store.Transaction(ctx, func(tx *postgres.Store) error {
|
||||
// 1. 验证用户是否存在
|
||||
user, err := tx.User.GetByID(ctx, req.UserID)
|
||||
if err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return pkgErrors.New(pkgErrors.CodeNotFound, "用户不存在")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// 2. 创建订单
|
||||
order = &model.Order{
|
||||
OrderID: req.OrderID,
|
||||
UserID: req.UserID,
|
||||
Amount: req.Amount,
|
||||
Status: constants.OrderStatusPending,
|
||||
Remark: req.Remark,
|
||||
}
|
||||
|
||||
if err := tx.Order.Create(ctx, order); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 3. 更新用户状态(示例:可以在这里更新用户的订单计数等)
|
||||
s.logger.Debug("订单创建成功,用户信息",
|
||||
zap.String("username", user.Username),
|
||||
zap.String("order_id", order.OrderID))
|
||||
|
||||
return nil // 提交事务
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
s.logger.Error("事务创建订单失败",
|
||||
zap.String("order_id", req.OrderID),
|
||||
zap.Error(err))
|
||||
return nil, fmt.Errorf("创建订单失败: %w", err)
|
||||
}
|
||||
|
||||
s.logger.Info("事务创建订单成功",
|
||||
zap.Uint("id", order.ID),
|
||||
zap.String("order_id", order.OrderID),
|
||||
zap.Uint("user_id", order.UserID))
|
||||
|
||||
return order, nil
|
||||
}
|
||||
Reference in New Issue
Block a user