package repository import ( "context" "encoding/json" "strconv" "strings" "github.com/google/uuid" "evobgp/internal/store" ) // AppendRuntimeLogCleanupAudit records a runtime log cleanup operation. func (p *Postgres) AppendRuntimeLogCleanupAudit(tenantID, actor, filename, action string, sizeBefore int64, sizeAfter *int64, detail map[string]any) (string, error) { if strings.TrimSpace(tenantID) == "" || !store.ValidRuntimeLogCleanupAction(action) || strings.TrimSpace(filename) == "" { return "", store.ErrInvalidInput } ctx := context.Background() id := uuid.NewString() var detailJSON []byte if detail != nil { detailJSON, _ = json.Marshal(detail) } var sizeAfterVal any if sizeAfter != nil { sizeAfterVal = *sizeAfter } _, err := p.pool.Exec(ctx, ` INSERT INTO runtime_log_cleanup_audit (id, tenant_id, actor_prefix, filename, action, size_before, size_after, detail_json, created_at) VALUES ($1, $2, $3, $4, $5, $6, $7, $8::jsonb, now())`, id, tenantID, strings.TrimSpace(actor), strings.TrimSpace(filename), action, sizeBefore, sizeAfterVal, nullJSONBytes(detailJSON)) if err != nil { return "", err } return id, nil } // ListRuntimeLogCleanupAudit returns paginated cleanup audit rows for a tenant. func (p *Postgres) ListRuntimeLogCleanupAudit(tenantID, cursor string, limit int) ([]*store.RuntimeLogCleanupAudit, string, bool, error) { if limit <= 0 { limit = 50 } off := 0 if cursor != "" { if n, err := strconv.Atoi(cursor); err == nil && n >= 0 { off = n } } ctx := context.Background() rows, err := p.pool.Query(ctx, ` SELECT id, tenant_id, actor_prefix, filename, action, size_before, size_after, detail_json, created_at FROM runtime_log_cleanup_audit WHERE tenant_id = $1 ORDER BY created_at DESC, id DESC LIMIT $2 OFFSET $3`, tenantID, limit+1, off) if err != nil { return nil, "", false, err } defer rows.Close() var out []*store.RuntimeLogCleanupAudit for rows.Next() { var r store.RuntimeLogCleanupAudit var detailRaw []byte var sizeAfter *int64 if err := rows.Scan(&r.ID, &r.TenantID, &r.ActorPrefix, &r.Filename, &r.Action, &r.SizeBefore, &sizeAfter, &detailRaw, &r.CreatedAt); err != nil { continue } r.SizeAfter = sizeAfter if len(detailRaw) > 0 { _ = json.Unmarshal(detailRaw, &r.Detail) } out = append(out, &r) } more := len(out) > limit if more { out = out[:limit] } next := "" if more { next = strconv.Itoa(off + limit) } return out, next, more, rows.Err() }