From 1a3d7f9a8a181df48f0e911cbe17a3fad3ab9ac9 Mon Sep 17 00:00:00 2001 From: Chia Date: Wed, 5 Aug 2026 00:26:25 +1200 Subject: add some scripts --- internal/controlplane/limits.go | 81 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 internal/controlplane/limits.go (limited to 'internal/controlplane/limits.go') diff --git a/internal/controlplane/limits.go b/internal/controlplane/limits.go new file mode 100644 index 0000000..5b5825e --- /dev/null +++ b/internal/controlplane/limits.go @@ -0,0 +1,81 @@ +package controlplane + +import ( + "context" + "errors" + "fmt" + "strings" + + "github.com/jackc/pgx/v5" +) + +func (s *Store) ListProjectLimits(ctx context.Context, tenantID string) ([]ProjectLimit, error) { + query := `SELECT l.tenant_id::text, l.project_id::text, p.name, t.name, + l.requests_per_minute, l.tokens_per_minute, l.concurrent_requests, l.monthly_spend_micros, l.updated_at + FROM project_limits l JOIN projects p ON p.id=l.project_id JOIN tenants t ON t.id=l.tenant_id` + args := []any{} + if strings.TrimSpace(tenantID) != "" { + query += ` WHERE l.tenant_id=$1` + args = append(args, tenantID) + } + query += ` ORDER BY t.name, p.name` + rows, err := s.db.Query(ctx, query, args...) + if err != nil { + return nil, fmt.Errorf("query project limits: %w", err) + } + defer rows.Close() + result := make([]ProjectLimit, 0) + for rows.Next() { + var item ProjectLimit + if err := rows.Scan(&item.TenantID, &item.ProjectID, &item.ProjectName, &item.TenantName, + &item.RequestsPerMinute, &item.TokensPerMinute, &item.Concurrent, &item.MonthlySpendMicros, &item.UpdatedAt); err != nil { + return nil, fmt.Errorf("scan project limit: %w", err) + } + result = append(result, item) + } + return result, rows.Err() +} + +func (s *Store) SetProjectLimit(ctx context.Context, projectID string, input SetProjectLimitInput) (ProjectLimit, int64, error) { + if strings.TrimSpace(projectID) == "" || input.RequestsPerMinute < 0 || input.TokensPerMinute < 0 || input.ConcurrentRequests < 0 || input.MonthlySpendMicros < 0 { + return ProjectLimit{}, 0, errors.New("limit values cannot be negative and project_id is required") + } + tx, err := s.db.Begin(ctx) + if err != nil { + return ProjectLimit{}, 0, err + } + defer tx.Rollback(ctx) + var result ProjectLimit + err = tx.QueryRow(ctx, ` + WITH project AS ( + SELECT p.id, p.tenant_id, p.name AS project_name, t.name AS tenant_name + FROM projects p JOIN tenants t ON t.id=p.tenant_id WHERE p.id=$1 + ), updated AS ( + INSERT INTO project_limits (project_id, tenant_id, requests_per_minute, tokens_per_minute, concurrent_requests, monthly_spend_micros) + SELECT p.id, p.tenant_id, $2, $3, $4, $5 FROM project p + ON CONFLICT (project_id) DO UPDATE SET requests_per_minute=EXCLUDED.requests_per_minute, + tokens_per_minute=EXCLUDED.tokens_per_minute, concurrent_requests=EXCLUDED.concurrent_requests, + monthly_spend_micros=EXCLUDED.monthly_spend_micros, updated_at=now() + RETURNING tenant_id, project_id, requests_per_minute, tokens_per_minute, concurrent_requests, monthly_spend_micros, updated_at + ) + SELECT u.tenant_id::text, u.project_id::text, p.project_name, p.tenant_name, + u.requests_per_minute, u.tokens_per_minute, u.concurrent_requests, u.monthly_spend_micros, u.updated_at + FROM updated u JOIN project p ON p.id=u.project_id`, + projectID, input.RequestsPerMinute, input.TokensPerMinute, input.ConcurrentRequests, input.MonthlySpendMicros, + ).Scan(&result.TenantID, &result.ProjectID, &result.ProjectName, &result.TenantName, + &result.RequestsPerMinute, &result.TokensPerMinute, &result.Concurrent, &result.MonthlySpendMicros, &result.UpdatedAt) + if errors.Is(err, pgx.ErrNoRows) { + return ProjectLimit{}, 0, ErrNotFound + } + if err != nil { + return ProjectLimit{}, 0, fmt.Errorf("set project limit: %w", err) + } + generation, err := bumpGeneration(ctx, tx) + if err != nil { + return ProjectLimit{}, 0, err + } + if err := tx.Commit(ctx); err != nil { + return ProjectLimit{}, 0, err + } + return result, generation, nil +} -- cgit v1.2.3