package store import ( "context" "encoding/json" "strings" "github.com/jackc/pgx/v5" ) const catalogProviderColumns = ` id::text, provider_key, COALESCE(NULLIF(provider_code, ''), provider_key) AS provider_code, display_name, provider_type, COALESCE(icon_path, '') AS icon_path, COALESCE(default_base_url, '') AS default_base_url, COALESCE(default_auth_type, '') AS default_auth_type, COALESCE(source, '') AS source, capability_schema, default_rate_limit_policy, metadata, status, created_at, updated_at` type CatalogProviderInput struct { ProviderKey string `json:"providerKey"` Code string `json:"code"` DisplayName string `json:"displayName"` ProviderType string `json:"providerType"` IconPath string `json:"iconPath"` DefaultBaseURL string `json:"defaultBaseUrl"` DefaultAuthType string `json:"defaultAuthType"` Source string `json:"source"` CapabilitySchema map[string]any `json:"capabilitySchema"` DefaultRateLimitPolicy map[string]any `json:"defaultRateLimitPolicy"` Metadata map[string]any `json:"metadata"` Status string `json:"status"` } type catalogProviderScanner interface { Scan(dest ...any) error } func (s *Store) CreateCatalogProvider(ctx context.Context, input CatalogProviderInput) (CatalogProvider, error) { input = normalizeCatalogProviderInput(input) capabilitySchema, _ := json.Marshal(emptyObjectIfNil(input.CapabilitySchema)) rateLimitPolicy, _ := json.Marshal(emptyObjectIfNil(input.DefaultRateLimitPolicy)) metadata, _ := json.Marshal(emptyObjectIfNil(input.Metadata)) return scanCatalogProvider(s.pool.QueryRow(ctx, ` INSERT INTO model_catalog_providers ( provider_key, provider_code, display_name, provider_type, icon_path, default_base_url, default_auth_type, source, capability_schema, default_rate_limit_policy, metadata, status ) VALUES ($1, $2, $3, $4, NULLIF($5, ''), NULLIF($6, ''), $7, $8, $9, $10, $11, $12) RETURNING `+catalogProviderColumns, input.ProviderKey, input.Code, input.DisplayName, input.ProviderType, input.IconPath, input.DefaultBaseURL, input.DefaultAuthType, input.Source, capabilitySchema, rateLimitPolicy, metadata, input.Status, )) } func (s *Store) UpdateCatalogProvider(ctx context.Context, id string, input CatalogProviderInput) (CatalogProvider, error) { input = normalizeCatalogProviderInput(input) capabilitySchema, _ := json.Marshal(emptyObjectIfNil(input.CapabilitySchema)) rateLimitPolicy, _ := json.Marshal(emptyObjectIfNil(input.DefaultRateLimitPolicy)) metadata, _ := json.Marshal(emptyObjectIfNil(input.Metadata)) return scanCatalogProvider(s.pool.QueryRow(ctx, ` UPDATE model_catalog_providers SET provider_key = $2, provider_code = $3, display_name = $4, provider_type = $5, icon_path = NULLIF($6, ''), default_base_url = NULLIF($7, ''), default_auth_type = $8, source = $9, capability_schema = $10, default_rate_limit_policy = $11, metadata = $12, status = $13, updated_at = now() WHERE id = $1::uuid RETURNING `+catalogProviderColumns, id, input.ProviderKey, input.Code, input.DisplayName, input.ProviderType, input.IconPath, input.DefaultBaseURL, input.DefaultAuthType, input.Source, capabilitySchema, rateLimitPolicy, metadata, input.Status, )) } func (s *Store) DeleteCatalogProvider(ctx context.Context, id string) error { result, err := s.pool.Exec(ctx, `DELETE FROM model_catalog_providers WHERE id = $1::uuid`, id) if err != nil { return err } if result.RowsAffected() == 0 { return pgx.ErrNoRows } return nil } func scanCatalogProvider(scanner catalogProviderScanner) (CatalogProvider, error) { var item CatalogProvider var capabilitySchema []byte var rateLimitPolicy []byte var metadata []byte if err := scanner.Scan( &item.ID, &item.ProviderKey, &item.Code, &item.DisplayName, &item.ProviderType, &item.IconPath, &item.DefaultBaseURL, &item.DefaultAuthType, &item.Source, &capabilitySchema, &rateLimitPolicy, &metadata, &item.Status, &item.CreatedAt, &item.UpdatedAt, ); err != nil { return CatalogProvider{}, err } item.CapabilitySchema = decodeObject(capabilitySchema) item.DefaultRateLimitPolicy = decodeObject(rateLimitPolicy) item.Metadata = decodeObject(metadata) return item, nil } func normalizeCatalogProviderInput(input CatalogProviderInput) CatalogProviderInput { input.ProviderKey = strings.TrimSpace(input.ProviderKey) input.Code = strings.TrimSpace(input.Code) input.DisplayName = strings.TrimSpace(input.DisplayName) input.ProviderType = strings.TrimSpace(input.ProviderType) input.IconPath = strings.TrimSpace(input.IconPath) input.DefaultBaseURL = strings.TrimSpace(input.DefaultBaseURL) input.DefaultAuthType = strings.TrimSpace(input.DefaultAuthType) input.Source = strings.TrimSpace(input.Source) input.Status = strings.TrimSpace(input.Status) if input.Code == "" { input.Code = input.ProviderKey } if input.ProviderType == "" { input.ProviderType = "openai" } if input.DefaultAuthType == "" { input.DefaultAuthType = "APIKey" } if input.Source == "" { input.Source = "gateway" } if input.Status == "" { input.Status = "active" } return input }