94 lines
2.6 KiB
Go
94 lines
2.6 KiB
Go
package repository
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
const BusinessEventSucceeded = "成功"
|
|
|
|
type BusinessEvent struct {
|
|
ID int64 `json:"id"`
|
|
OccurredAt time.Time `json:"occurred_at"`
|
|
Event string `json:"event"`
|
|
Status string `json:"status"`
|
|
}
|
|
|
|
func (r *SQLiteUsageRepository) RecordBusinessEvent(ctx context.Context, event, status string, occurredAt time.Time) error {
|
|
return insertBusinessEvent(ctx, r.db, event, status, occurredAt)
|
|
}
|
|
|
|
func (r *SQLiteUsageRepository) ListBusinessEvents(ctx context.Context, limit int) ([]BusinessEvent, error) {
|
|
if limit < 1 || limit > 500 {
|
|
limit = 200
|
|
}
|
|
rows, err := r.readDB.QueryContext(ctx, `
|
|
SELECT id, occurred_at, event, status
|
|
FROM business_events ORDER BY occurred_at DESC, id DESC LIMIT ?`, limit)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("查询业务日志: %w", err)
|
|
}
|
|
defer rows.Close()
|
|
events := make([]BusinessEvent, 0, limit)
|
|
for rows.Next() {
|
|
var item BusinessEvent
|
|
var occurredRaw string
|
|
if err := rows.Scan(&item.ID, &occurredRaw, &item.Event, &item.Status); err != nil {
|
|
return nil, fmt.Errorf("读取业务日志: %w", err)
|
|
}
|
|
item.OccurredAt, _ = time.Parse(time.RFC3339Nano, occurredRaw)
|
|
events = append(events, item)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, fmt.Errorf("遍历业务日志: %w", err)
|
|
}
|
|
return events, nil
|
|
}
|
|
|
|
type businessEventExecer interface {
|
|
ExecContext(context.Context, string, ...any) (sql.Result, error)
|
|
}
|
|
|
|
func insertBusinessEvent(ctx context.Context, executor businessEventExecer, event, status string, occurredAt time.Time) error {
|
|
event = strings.TrimSpace(event)
|
|
status = strings.TrimSpace(status)
|
|
if event == "" || status == "" {
|
|
return fmt.Errorf("业务日志事件和状态不能为空")
|
|
}
|
|
if occurredAt.IsZero() {
|
|
occurredAt = time.Now().UTC()
|
|
}
|
|
if _, err := executor.ExecContext(ctx, `
|
|
INSERT INTO business_events (occurred_at, event, status) VALUES (?, ?, ?)`,
|
|
formatTime(occurredAt), event, status); err != nil {
|
|
return fmt.Errorf("写入业务日志: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func quotedName(value string) string {
|
|
value = strings.TrimSpace(value)
|
|
if value == "" {
|
|
return "未命名用户"
|
|
}
|
|
return "`" + strings.ReplaceAll(value, "`", "") + "`"
|
|
}
|
|
|
|
func decimalMicros(value int64) string {
|
|
prefix := ""
|
|
if value < 0 {
|
|
prefix = "-"
|
|
value = -value
|
|
}
|
|
whole := value / 1_000_000
|
|
fraction := fmt.Sprintf("%06d", value%1_000_000)
|
|
fraction = strings.TrimRight(fraction, "0")
|
|
if fraction == "" {
|
|
return prefix + fmt.Sprintf("%d", whole)
|
|
}
|
|
return prefix + fmt.Sprintf("%d.%s", whole, fraction)
|
|
}
|