package repository import ( "context" "errors" "time" "gorm.io/gorm" "github.com/kennethcheng/fuellog-api/internal/model" "github.com/kennethcheng/fuellog-api/pkg/apperror" ) // RefuelRecordRepository 加油记录表的数据访问接口。 type RefuelRecordRepository interface { Create(ctx context.Context, r *model.RefuelRecord) error Get(ctx context.Context, id uint64) (*model.RefuelRecord, error) Update(ctx context.Context, r *model.RefuelRecord) error Delete(ctx context.Context, id uint64) error // List 返回指定车辆的加油记录,按 refuel_time DESC 排序。 // 支持可选时间窗口。 ListByVehicle(ctx context.Context, vehicleID uint64, start, end *time.Time) ([]model.RefuelRecord, error) // PrevFullRefuel 返回指定车辆在 time 之前最近一次 is_full=true 的记录。 // 用于计算百公里油耗。 PrevFullRefuel(ctx context.Context, vehicleID uint64, before time.Time) (*model.RefuelRecord, error) } func NewRefuelRecordRepository(g *gorm.DB) RefuelRecordRepository { return &refuelRepo{g: g} } type refuelRepo struct{ g *gorm.DB } func (r *refuelRepo) Create(ctx context.Context, rec *model.RefuelRecord) error { if err := r.g.WithContext(ctx).Create(rec).Error; err != nil { return apperror.Wrap(apperror.CodeInternal, "创建加油记录失败", err) } return nil } func (r *refuelRepo) Get(ctx context.Context, id uint64) (*model.RefuelRecord, error) { var rec model.RefuelRecord if err := r.g.WithContext(ctx).First(&rec, id).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, apperror.New(apperror.CodeNotFound, "加油记录不存在") } return nil, apperror.Wrap(apperror.CodeInternal, "查询加油记录失败", err) } return &rec, nil } func (r *refuelRepo) Update(ctx context.Context, rec *model.RefuelRecord) error { res := r.g.WithContext(ctx).Save(rec) if res.Error != nil { return apperror.Wrap(apperror.CodeInternal, "更新加油记录失败", res.Error) } if res.RowsAffected == 0 { return apperror.New(apperror.CodeNotFound, "加油记录不存在") } return nil } func (r *refuelRepo) Delete(ctx context.Context, id uint64) error { res := r.g.WithContext(ctx).Delete(&model.RefuelRecord{}, id) if res.Error != nil { return apperror.Wrap(apperror.CodeInternal, "删除加油记录失败", res.Error) } if res.RowsAffected == 0 { return apperror.New(apperror.CodeNotFound, "加油记录不存在") } return nil } func (r *refuelRepo) ListByVehicle(ctx context.Context, vehicleID uint64, start, end *time.Time) ([]model.RefuelRecord, error) { q := r.g.WithContext(ctx).Where("vehicle_id = ?", vehicleID) if start != nil { q = q.Where("refuel_time >= ?", *start) } if end != nil { q = q.Where("refuel_time <= ?", *end) } var out []model.RefuelRecord if err := q.Order("refuel_time DESC, id DESC").Find(&out).Error; err != nil { return nil, apperror.Wrap(apperror.CodeInternal, "查询加油记录列表失败", err) } return out, nil } func (r *refuelRepo) PrevFullRefuel(ctx context.Context, vehicleID uint64, before time.Time) (*model.RefuelRecord, error) { var rec model.RefuelRecord err := r.g.WithContext(ctx). Where("vehicle_id = ? AND is_full = ? AND refuel_time < ?", vehicleID, true, before). Order("refuel_time DESC, id DESC"). First(&rec).Error if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, apperror.New(apperror.CodeNotFound, "此前没有加满油记录") } return nil, apperror.Wrap(apperror.CodeInternal, "查询前次加满记录失败", err) } return &rec, nil }