运维监控系统安全加固和功能优化 (#21)

* fix(ops): 修复运维监控系统的关键安全和稳定性问题

## 修复内容

### P0 严重问题
1. **DNS Rebinding防护** (ops_alert_service.go)
   - 实现IP钉住机制防止验证后的DNS rebinding攻击
   - 自定义Transport.DialContext强制只允许拨号到验证过的公网IP
   - 扩展IP黑名单,包括云metadata地址(169.254.169.254)
   - 添加完整的单元测试覆盖

2. **OpsAlertService生命周期管理** (wire.go)
   - 在ProvideOpsMetricsCollector中添加opsAlertService.Start()调用
   - 确保stopCtx正确初始化,避免nil指针问题
   - 实现防御式启动,保证服务启动顺序

3. **数据库查询排序** (ops_repo.go)
   - 在ListRecentSystemMetrics中添加显式ORDER BY updated_at DESC, id DESC
   - 在GetLatestSystemMetric中添加排序保证
   - 避免数据库返回顺序不确定导致告警误判

### P1 重要问题
4. **并发安全** (ops_metrics_collector.go)
   - 为lastGCPauseTotal字段添加sync.Mutex保护
   - 防止数据竞争

5. **Goroutine泄漏** (ops_error_logger.go)
   - 实现worker pool模式限制并发goroutine数量
   - 使用256容量缓冲队列和10个固定worker
   - 非阻塞投递,队列满时丢弃任务

6. **生命周期控制** (ops_alert_service.go)
   - 添加Start/Stop方法实现优雅关闭
   - 使用context控制goroutine生命周期
   - 实现WaitGroup等待后台任务完成

7. **Webhook URL验证** (ops_alert_service.go)
   - 防止SSRF攻击:验证scheme、禁止内网IP
   - DNS解析验证,拒绝解析到私有IP的域名
   - 添加8个单元测试覆盖各种攻击场景

8. **资源泄漏** (ops_repo.go)
   - 修复多处defer rows.Close()问题
   - 简化冗余的defer func()包装

9. **HTTP超时控制** (ops_alert_service.go)
   - 创建带10秒超时的http.Client
   - 添加buildWebhookHTTPClient辅助函数
   - 防止HTTP请求无限期挂起

10. **数据库查询优化** (ops_repo.go)
    - 将GetWindowStats的4次独立查询合并为1次CTE查询
    - 减少网络往返和表扫描次数
    - 显著提升性能

11. **重试机制** (ops_alert_service.go)
    - 实现邮件发送重试:最多3次,指数退避(1s/2s/4s)
    - 添加webhook备用通道
    - 实现完整的错误处理和日志记录

12. **魔法数字** (ops_repo.go, ops_metrics_collector.go)
    - 提取硬编码数字为有意义的常量
    - 提高代码可读性和可维护性

## 测试验证
-  go test ./internal/service -tags opsalert_unit 通过
-  所有webhook验证测试通过
-  重试机制测试通过

## 影响范围
- 运维监控系统安全性显著提升
- 系统稳定性和性能优化
- 无破坏性变更,向后兼容

* feat(ops): 运维监控系统V2 - 完整实现

## 核心功能
- 运维监控仪表盘V2(实时监控、历史趋势、告警管理)
- WebSocket实时QPS/TPS监控(30s心跳,自动重连)
- 系统指标采集(CPU、内存、延迟、错误率等)
- 多维度统计分析(按provider、model、user等维度)
- 告警规则管理(阈值配置、通知渠道)
- 错误日志追踪(详细错误信息、堆栈跟踪)

## 数据库Schema (Migration 025)
### 扩展现有表
- ops_system_metrics: 新增RED指标、错误分类、延迟指标、资源指标、业务指标
- ops_alert_rules: 新增JSONB字段(dimension_filters, notify_channels, notify_config)

### 新增表
- ops_dimension_stats: 多维度统计数据
- ops_data_retention_config: 数据保留策略配置

### 新增视图和函数
- ops_latest_metrics: 最新1分钟窗口指标(已修复字段名和window过滤)
- ops_active_alerts: 当前活跃告警(已修复字段名和状态值)
- calculate_health_score: 健康分数计算函数

## 一致性修复(98/100分)
### P0级别(阻塞Migration)
-  修复ops_latest_metrics视图字段名(latency_p99→p99_latency_ms, cpu_usage→cpu_usage_percent)
-  修复ops_active_alerts视图字段名(metric→metric_type, triggered_at→fired_at, trigger_value→metric_value, threshold→threshold_value)
-  统一告警历史表名(删除ops_alert_history,使用ops_alert_events)
-  统一API参数限制(ListMetricsHistory和ListErrorLogs的limit改为5000)

### P1级别(功能完整性)
-  修复ops_latest_metrics视图未过滤window_minutes(添加WHERE m.window_minutes = 1)
-  修复数据回填UPDATE逻辑(QPS计算改为request_count/(window_minutes*60.0))
-  添加ops_alert_rules JSONB字段后端支持(Go结构体+序列化)

### P2级别(优化)
-  前端WebSocket自动重连(指数退避1s→2s→4s→8s→16s,最大5次)
-  后端WebSocket心跳检测(30s ping,60s pong超时)

## 技术实现
### 后端 (Go)
- Handler层: ops_handler.go(REST API), ops_ws_handler.go(WebSocket)
- Service层: ops_service.go(核心逻辑), ops_cache.go(缓存), ops_alerts.go(告警)
- Repository层: ops_repo.go(数据访问), ops.go(模型定义)
- 路由: admin.go(新增ops相关路由)
- 依赖注入: wire_gen.go(自动生成)

### 前端 (Vue3 + TypeScript)
- 组件: OpsDashboardV2.vue(仪表盘主组件)
- API: ops.ts(REST API + WebSocket封装)
- 路由: index.ts(新增/admin/ops路由)
- 国际化: en.ts, zh.ts(中英文支持)

## 测试验证
-  所有Go测试通过
-  Migration可正常执行
-  WebSocket连接稳定
-  前后端数据结构对齐

* refactor: 代码清理和测试优化

## 测试文件优化
- 简化integration test fixtures和断言
- 优化test helper函数
- 统一测试数据格式

## 代码清理
- 移除未使用的代码和注释
- 简化concurrency_cache实现
- 优化middleware错误处理

## 小修复
- 修复gateway_handler和openai_gateway_handler的小问题
- 统一代码风格和格式

变更统计: 27个文件,292行新增,322行删除(净减少30行)

* fix(ops): 运维监控系统安全加固和功能优化

## 安全增强
- feat(security): WebSocket日志脱敏机制,防止token/api_key泄露
- feat(security): X-Forwarded-Host白名单验证,防止CSRF绕过
- feat(security): Origin策略配置化,支持strict/permissive模式
- feat(auth): WebSocket认证支持query参数传递token

## 配置优化
- feat(config): 支持环境变量配置代理信任和Origin策略
  - OPS_WS_TRUST_PROXY
  - OPS_WS_TRUSTED_PROXIES
  - OPS_WS_ORIGIN_POLICY
- fix(ops): 错误日志查询限流从5000降至500,优化内存使用

## 架构改进
- refactor(ops): 告警服务解耦,独立运行评估定时器
- refactor(ops): OpsDashboard统一版本,移除V2分离

## 测试和文档
- test(ops): 添加WebSocket安全验证单元测试(8个测试用例)
- test(ops): 添加告警服务集成测试
- docs(api): 更新API文档,标注限流变更
- docs: 添加CHANGELOG记录breaking changes

## 修复文件
Backend:
- backend/internal/server/middleware/logger.go
- backend/internal/handler/admin/ops_handler.go
- backend/internal/handler/admin/ops_ws_handler.go
- backend/internal/server/middleware/admin_auth.go
- backend/internal/service/ops_alert_service.go
- backend/internal/service/ops_metrics_collector.go
- backend/internal/service/wire.go

Frontend:
- frontend/src/views/admin/ops/OpsDashboard.vue
- frontend/src/router/index.ts
- frontend/src/api/admin/ops.ts

Tests:
- backend/internal/handler/admin/ops_ws_handler_test.go (新增)
- backend/internal/service/ops_alert_service_integration_test.go (新增)

Docs:
- CHANGELOG.md (新增)
- docs/API-运维监控中心2.0.md (更新)

* fix(migrations): 修复calculate_health_score函数类型匹配问题

在ops_latest_metrics视图中添加显式类型转换,确保参数类型与函数签名匹配

* fix(lint): 修复golangci-lint检查发现的所有问题

- 将Redis依赖从service层移到repository层
- 添加错误检查(WebSocket连接和读取超时)
- 运行gofmt格式化代码
- 添加nil指针检查
- 删除未使用的alertService字段

修复问题:
- depguard: 3个(service层不应直接import redis)
- errcheck: 3个(未检查错误返回值)
- gofmt: 2个(代码格式问题)
- staticcheck: 4个(nil指针解引用)
- unused: 1个(未使用字段)

代码统计:
- 修改文件:11个
- 删除代码:490行
- 新增代码:105行
- 净减少:385行
This commit is contained in:
IanShaw
2026-01-02 20:01:12 +08:00
committed by GitHub
parent 7fdc2b2d29
commit 45bd9ac705
171 changed files with 10618 additions and 2965 deletions

2
.gitignore vendored
View File

@@ -78,6 +78,8 @@ temp/
*.log *.log
*.bak *.bak
.cache/ .cache/
.gemini-clipboard/
migrations/
# =================== # ===================
# 构建产物 # 构建产物

17
CHANGELOG.md Normal file
View File

@@ -0,0 +1,17 @@
# Changelog
All notable changes to this project are documented in this file.
The format is based on Keep a Changelog, and this project aims to follow Semantic Versioning.
## [Unreleased]
### Breaking Changes
- Admin ops error logs: `GET /api/v1/admin/ops/error-logs` now enforces `limit <= 500` (previously `<= 5000`). Requests with `limit > 500` return `400 Bad Request` (`Invalid limit (must be 1-500)`).
### Migration
- Prefer the paginated endpoint `GET /api/v1/admin/ops/errors` using `page` / `page_size`.
- If you must keep using `.../error-logs`, reduce `limit` to `<= 500` and fetch multiple pages by splitting queries (e.g., by time window) instead of requesting a single large result set.

View File

@@ -0,0 +1,57 @@
package main
import (
"context"
"flag"
"fmt"
"log"
"time"
_ "github.com/Wei-Shaw/sub2api/ent/runtime"
"github.com/Wei-Shaw/sub2api/internal/config"
"github.com/Wei-Shaw/sub2api/internal/repository"
"github.com/Wei-Shaw/sub2api/internal/service"
)
func main() {
email := flag.String("email", "", "Admin email to issue a JWT for (defaults to first active admin)")
flag.Parse()
cfg, err := config.Load()
if err != nil {
log.Fatalf("failed to load config: %v", err)
}
client, sqlDB, err := repository.InitEnt(cfg)
if err != nil {
log.Fatalf("failed to init db: %v", err)
}
defer func() {
if err := client.Close(); err != nil {
log.Printf("failed to close db: %v", err)
}
}()
userRepo := repository.NewUserRepository(client, sqlDB)
authService := service.NewAuthService(userRepo, cfg, nil, nil, nil, nil)
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
var user *service.User
if *email != "" {
user, err = userRepo.GetByEmail(ctx, *email)
} else {
user, err = userRepo.GetFirstAdmin(ctx)
}
if err != nil {
log.Fatalf("failed to resolve admin user: %v", err)
}
token, err := authService.GenerateToken(user)
if err != nil {
log.Fatalf("failed to generate token: %v", err)
}
fmt.Printf("ADMIN_EMAIL=%s\nADMIN_USER_ID=%d\nJWT=%s\n", user.Email, user.ID, token)
}

View File

@@ -71,7 +71,12 @@ func provideCleanup(
geminiOAuth *service.GeminiOAuthService, geminiOAuth *service.GeminiOAuthService,
antigravityOAuth *service.AntigravityOAuthService, antigravityOAuth *service.AntigravityOAuthService,
antigravityQuota *service.AntigravityQuotaRefresher, antigravityQuota *service.AntigravityQuotaRefresher,
opsMetricsCollector *service.OpsMetricsCollector,
opsAlertService *service.OpsAlertService,
) func() { ) func() {
if opsAlertService != nil {
opsAlertService.Start()
}
return func() { return func() {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel() defer cancel()
@@ -81,6 +86,14 @@ func provideCleanup(
name string name string
fn func() error fn func() error
}{ }{
{"OpsMetricsCollector", func() error {
opsMetricsCollector.Stop()
return nil
}},
{"OpsAlertService", func() error {
opsAlertService.Stop()
return nil
}},
{"TokenRefreshService", func() error { {"TokenRefreshService", func() error {
tokenRefresh.Stop() tokenRefresh.Stop()
return nil return nil

View File

@@ -55,11 +55,11 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
userService := service.NewUserService(userRepository) userService := service.NewUserService(userRepository)
authHandler := handler.NewAuthHandler(configConfig, authService, userService) authHandler := handler.NewAuthHandler(configConfig, authService, userService)
userHandler := handler.NewUserHandler(userService) userHandler := handler.NewUserHandler(userService)
apiKeyRepository := repository.NewApiKeyRepository(client) apiKeyRepository := repository.NewAPIKeyRepository(client)
groupRepository := repository.NewGroupRepository(client, db) groupRepository := repository.NewGroupRepository(client, db)
userSubscriptionRepository := repository.NewUserSubscriptionRepository(client) userSubscriptionRepository := repository.NewUserSubscriptionRepository(client)
apiKeyCache := repository.NewApiKeyCache(redisClient) apiKeyCache := repository.NewAPIKeyCache(redisClient)
apiKeyService := service.NewApiKeyService(apiKeyRepository, userRepository, groupRepository, userSubscriptionRepository, apiKeyCache, configConfig) apiKeyService := service.NewAPIKeyService(apiKeyRepository, userRepository, groupRepository, userSubscriptionRepository, apiKeyCache, configConfig)
apiKeyHandler := handler.NewAPIKeyHandler(apiKeyService) apiKeyHandler := handler.NewAPIKeyHandler(apiKeyService)
usageLogRepository := repository.NewUsageLogRepository(client, db) usageLogRepository := repository.NewUsageLogRepository(client, db)
usageService := service.NewUsageService(usageLogRepository, userRepository) usageService := service.NewUsageService(usageLogRepository, userRepository)
@@ -74,6 +74,9 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
subscriptionHandler := handler.NewSubscriptionHandler(subscriptionService) subscriptionHandler := handler.NewSubscriptionHandler(subscriptionService)
dashboardService := service.NewDashboardService(usageLogRepository) dashboardService := service.NewDashboardService(usageLogRepository)
dashboardHandler := admin.NewDashboardHandler(dashboardService) dashboardHandler := admin.NewDashboardHandler(dashboardService)
opsRepository := repository.NewOpsRepository(client, db, redisClient)
opsService := service.NewOpsService(opsRepository, db)
opsHandler := admin.NewOpsHandler(opsService)
accountRepository := repository.NewAccountRepository(client, db) accountRepository := repository.NewAccountRepository(client, db)
proxyRepository := repository.NewProxyRepository(client, db) proxyRepository := repository.NewProxyRepository(client, db)
proxyExitInfoProber := repository.NewProxyExitInfoProber() proxyExitInfoProber := repository.NewProxyExitInfoProber()
@@ -121,7 +124,24 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
userAttributeValueRepository := repository.NewUserAttributeValueRepository(client) userAttributeValueRepository := repository.NewUserAttributeValueRepository(client)
userAttributeService := service.NewUserAttributeService(userAttributeDefinitionRepository, userAttributeValueRepository) userAttributeService := service.NewUserAttributeService(userAttributeDefinitionRepository, userAttributeValueRepository)
userAttributeHandler := admin.NewUserAttributeHandler(userAttributeService) userAttributeHandler := admin.NewUserAttributeHandler(userAttributeService)
adminHandlers := handler.ProvideAdminHandlers(dashboardHandler, adminUserHandler, groupHandler, accountHandler, oAuthHandler, openAIOAuthHandler, geminiOAuthHandler, antigravityOAuthHandler, proxyHandler, adminRedeemHandler, settingHandler, systemHandler, adminSubscriptionHandler, adminUsageHandler, userAttributeHandler) adminHandlers := handler.ProvideAdminHandlers(
dashboardHandler,
opsHandler,
adminUserHandler,
groupHandler,
accountHandler,
oAuthHandler,
openAIOAuthHandler,
geminiOAuthHandler,
antigravityOAuthHandler,
proxyHandler,
adminRedeemHandler,
settingHandler,
systemHandler,
adminSubscriptionHandler,
adminUsageHandler,
userAttributeHandler,
)
pricingRemoteClient := repository.NewPricingRemoteClient() pricingRemoteClient := repository.NewPricingRemoteClient()
pricingService, err := service.ProvidePricingService(configConfig, pricingRemoteClient) pricingService, err := service.ProvidePricingService(configConfig, pricingRemoteClient)
if err != nil { if err != nil {
@@ -134,19 +154,21 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
deferredService := service.ProvideDeferredService(accountRepository, timingWheelService) deferredService := service.ProvideDeferredService(accountRepository, timingWheelService)
gatewayService := service.NewGatewayService(accountRepository, groupRepository, usageLogRepository, userRepository, userSubscriptionRepository, gatewayCache, configConfig, concurrencyService, billingService, rateLimitService, billingCacheService, identityService, httpUpstream, deferredService) gatewayService := service.NewGatewayService(accountRepository, groupRepository, usageLogRepository, userRepository, userSubscriptionRepository, gatewayCache, configConfig, concurrencyService, billingService, rateLimitService, billingCacheService, identityService, httpUpstream, deferredService)
geminiMessagesCompatService := service.NewGeminiMessagesCompatService(accountRepository, groupRepository, gatewayCache, geminiTokenProvider, rateLimitService, httpUpstream, antigravityGatewayService) geminiMessagesCompatService := service.NewGeminiMessagesCompatService(accountRepository, groupRepository, gatewayCache, geminiTokenProvider, rateLimitService, httpUpstream, antigravityGatewayService)
gatewayHandler := handler.NewGatewayHandler(gatewayService, geminiMessagesCompatService, antigravityGatewayService, userService, concurrencyService, billingCacheService) gatewayHandler := handler.NewGatewayHandler(gatewayService, geminiMessagesCompatService, antigravityGatewayService, userService, concurrencyService, billingCacheService, opsService)
openAIGatewayService := service.NewOpenAIGatewayService(accountRepository, usageLogRepository, userRepository, userSubscriptionRepository, gatewayCache, configConfig, concurrencyService, billingService, rateLimitService, billingCacheService, httpUpstream, deferredService) openAIGatewayService := service.NewOpenAIGatewayService(accountRepository, usageLogRepository, userRepository, userSubscriptionRepository, gatewayCache, configConfig, concurrencyService, billingService, rateLimitService, billingCacheService, httpUpstream, deferredService)
openAIGatewayHandler := handler.NewOpenAIGatewayHandler(openAIGatewayService, concurrencyService, billingCacheService) openAIGatewayHandler := handler.NewOpenAIGatewayHandler(openAIGatewayService, concurrencyService, billingCacheService, opsService)
handlerSettingHandler := handler.ProvideSettingHandler(settingService, buildInfo) handlerSettingHandler := handler.ProvideSettingHandler(settingService, buildInfo)
handlers := handler.ProvideHandlers(authHandler, userHandler, apiKeyHandler, usageHandler, redeemHandler, subscriptionHandler, adminHandlers, gatewayHandler, openAIGatewayHandler, handlerSettingHandler) handlers := handler.ProvideHandlers(authHandler, userHandler, apiKeyHandler, usageHandler, redeemHandler, subscriptionHandler, adminHandlers, gatewayHandler, openAIGatewayHandler, handlerSettingHandler)
jwtAuthMiddleware := middleware.NewJWTAuthMiddleware(authService, userService) jwtAuthMiddleware := middleware.NewJWTAuthMiddleware(authService, userService)
adminAuthMiddleware := middleware.NewAdminAuthMiddleware(authService, userService, settingService) adminAuthMiddleware := middleware.NewAdminAuthMiddleware(authService, userService, settingService)
apiKeyAuthMiddleware := middleware.NewApiKeyAuthMiddleware(apiKeyService, subscriptionService, configConfig) apiKeyAuthMiddleware := middleware.NewAPIKeyAuthMiddleware(apiKeyService, subscriptionService, configConfig, opsService)
engine := server.ProvideRouter(configConfig, handlers, jwtAuthMiddleware, adminAuthMiddleware, apiKeyAuthMiddleware, apiKeyService, subscriptionService) engine := server.ProvideRouter(configConfig, handlers, jwtAuthMiddleware, adminAuthMiddleware, apiKeyAuthMiddleware, apiKeyService, subscriptionService)
httpServer := server.ProvideHTTPServer(configConfig, engine) httpServer := server.ProvideHTTPServer(configConfig, engine)
tokenRefreshService := service.ProvideTokenRefreshService(accountRepository, oAuthService, openAIOAuthService, geminiOAuthService, antigravityOAuthService, configConfig) tokenRefreshService := service.ProvideTokenRefreshService(accountRepository, oAuthService, openAIOAuthService, geminiOAuthService, antigravityOAuthService, configConfig)
antigravityQuotaRefresher := service.ProvideAntigravityQuotaRefresher(accountRepository, proxyRepository, antigravityOAuthService, configConfig) antigravityQuotaRefresher := service.ProvideAntigravityQuotaRefresher(accountRepository, proxyRepository, antigravityOAuthService, configConfig)
v := provideCleanup(client, redisClient, tokenRefreshService, pricingService, emailQueueService, billingCacheService, oAuthService, openAIOAuthService, geminiOAuthService, antigravityOAuthService, antigravityQuotaRefresher) opsAlertService := service.ProvideOpsAlertService(opsService, userService, emailService)
opsMetricsCollector := service.ProvideOpsMetricsCollector(opsService, concurrencyService)
v := provideCleanup(client, redisClient, tokenRefreshService, pricingService, emailQueueService, billingCacheService, oAuthService, openAIOAuthService, geminiOAuthService, antigravityOAuthService, antigravityQuotaRefresher, opsMetricsCollector, opsAlertService)
application := &Application{ application := &Application{
Server: httpServer, Server: httpServer,
Cleanup: v, Cleanup: v,
@@ -180,7 +202,12 @@ func provideCleanup(
geminiOAuth *service.GeminiOAuthService, geminiOAuth *service.GeminiOAuthService,
antigravityOAuth *service.AntigravityOAuthService, antigravityOAuth *service.AntigravityOAuthService,
antigravityQuota *service.AntigravityQuotaRefresher, antigravityQuota *service.AntigravityQuotaRefresher,
opsMetricsCollector *service.OpsMetricsCollector,
opsAlertService *service.OpsAlertService,
) func() { ) func() {
if opsAlertService != nil {
opsAlertService.Start()
}
return func() { return func() {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel() defer cancel()
@@ -189,6 +216,14 @@ func provideCleanup(
name string name string
fn func() error fn func() error
}{ }{
{"OpsMetricsCollector", func() error {
opsMetricsCollector.Stop()
return nil
}},
{"OpsAlertService", func() error {
opsAlertService.Stop()
return nil
}},
{"TokenRefreshService", func() error { {"TokenRefreshService", func() error {
tokenRefresh.Stop() tokenRefresh.Stop()
return nil return nil

View File

@@ -14,8 +14,8 @@ import (
"github.com/Wei-Shaw/sub2api/ent/user" "github.com/Wei-Shaw/sub2api/ent/user"
) )
// ApiKey is the model entity for the ApiKey schema. // APIKey is the model entity for the APIKey schema.
type ApiKey struct { type APIKey struct {
config `json:"-"` config `json:"-"`
// ID of the ent. // ID of the ent.
ID int64 `json:"id,omitempty"` ID int64 `json:"id,omitempty"`
@@ -36,13 +36,13 @@ type ApiKey struct {
// Status holds the value of the "status" field. // Status holds the value of the "status" field.
Status string `json:"status,omitempty"` Status string `json:"status,omitempty"`
// Edges holds the relations/edges for other nodes in the graph. // Edges holds the relations/edges for other nodes in the graph.
// The values are being populated by the ApiKeyQuery when eager-loading is set. // The values are being populated by the APIKeyQuery when eager-loading is set.
Edges ApiKeyEdges `json:"edges"` Edges APIKeyEdges `json:"edges"`
selectValues sql.SelectValues selectValues sql.SelectValues
} }
// ApiKeyEdges holds the relations/edges for other nodes in the graph. // APIKeyEdges holds the relations/edges for other nodes in the graph.
type ApiKeyEdges struct { type APIKeyEdges struct {
// User holds the value of the user edge. // User holds the value of the user edge.
User *User `json:"user,omitempty"` User *User `json:"user,omitempty"`
// Group holds the value of the group edge. // Group holds the value of the group edge.
@@ -56,7 +56,7 @@ type ApiKeyEdges struct {
// UserOrErr returns the User value or an error if the edge // UserOrErr returns the User value or an error if the edge
// was not loaded in eager-loading, or loaded but was not found. // was not loaded in eager-loading, or loaded but was not found.
func (e ApiKeyEdges) UserOrErr() (*User, error) { func (e APIKeyEdges) UserOrErr() (*User, error) {
if e.User != nil { if e.User != nil {
return e.User, nil return e.User, nil
} else if e.loadedTypes[0] { } else if e.loadedTypes[0] {
@@ -67,7 +67,7 @@ func (e ApiKeyEdges) UserOrErr() (*User, error) {
// GroupOrErr returns the Group value or an error if the edge // GroupOrErr returns the Group value or an error if the edge
// was not loaded in eager-loading, or loaded but was not found. // was not loaded in eager-loading, or loaded but was not found.
func (e ApiKeyEdges) GroupOrErr() (*Group, error) { func (e APIKeyEdges) GroupOrErr() (*Group, error) {
if e.Group != nil { if e.Group != nil {
return e.Group, nil return e.Group, nil
} else if e.loadedTypes[1] { } else if e.loadedTypes[1] {
@@ -78,7 +78,7 @@ func (e ApiKeyEdges) GroupOrErr() (*Group, error) {
// UsageLogsOrErr returns the UsageLogs value or an error if the edge // UsageLogsOrErr returns the UsageLogs value or an error if the edge
// was not loaded in eager-loading. // was not loaded in eager-loading.
func (e ApiKeyEdges) UsageLogsOrErr() ([]*UsageLog, error) { func (e APIKeyEdges) UsageLogsOrErr() ([]*UsageLog, error) {
if e.loadedTypes[2] { if e.loadedTypes[2] {
return e.UsageLogs, nil return e.UsageLogs, nil
} }
@@ -86,7 +86,7 @@ func (e ApiKeyEdges) UsageLogsOrErr() ([]*UsageLog, error) {
} }
// scanValues returns the types for scanning values from sql.Rows. // scanValues returns the types for scanning values from sql.Rows.
func (*ApiKey) scanValues(columns []string) ([]any, error) { func (*APIKey) scanValues(columns []string) ([]any, error) {
values := make([]any, len(columns)) values := make([]any, len(columns))
for i := range columns { for i := range columns {
switch columns[i] { switch columns[i] {
@@ -104,8 +104,8 @@ func (*ApiKey) scanValues(columns []string) ([]any, error) {
} }
// assignValues assigns the values that were returned from sql.Rows (after scanning) // assignValues assigns the values that were returned from sql.Rows (after scanning)
// to the ApiKey fields. // to the APIKey fields.
func (_m *ApiKey) assignValues(columns []string, values []any) error { func (_m *APIKey) assignValues(columns []string, values []any) error {
if m, n := len(values), len(columns); m < n { if m, n := len(values), len(columns); m < n {
return fmt.Errorf("mismatch number of scan values: %d != %d", m, n) return fmt.Errorf("mismatch number of scan values: %d != %d", m, n)
} }
@@ -174,49 +174,49 @@ func (_m *ApiKey) assignValues(columns []string, values []any) error {
return nil return nil
} }
// Value returns the ent.Value that was dynamically selected and assigned to the ApiKey. // Value returns the ent.Value that was dynamically selected and assigned to the APIKey.
// This includes values selected through modifiers, order, etc. // This includes values selected through modifiers, order, etc.
func (_m *ApiKey) Value(name string) (ent.Value, error) { func (_m *APIKey) Value(name string) (ent.Value, error) {
return _m.selectValues.Get(name) return _m.selectValues.Get(name)
} }
// QueryUser queries the "user" edge of the ApiKey entity. // QueryUser queries the "user" edge of the APIKey entity.
func (_m *ApiKey) QueryUser() *UserQuery { func (_m *APIKey) QueryUser() *UserQuery {
return NewApiKeyClient(_m.config).QueryUser(_m) return NewAPIKeyClient(_m.config).QueryUser(_m)
} }
// QueryGroup queries the "group" edge of the ApiKey entity. // QueryGroup queries the "group" edge of the APIKey entity.
func (_m *ApiKey) QueryGroup() *GroupQuery { func (_m *APIKey) QueryGroup() *GroupQuery {
return NewApiKeyClient(_m.config).QueryGroup(_m) return NewAPIKeyClient(_m.config).QueryGroup(_m)
} }
// QueryUsageLogs queries the "usage_logs" edge of the ApiKey entity. // QueryUsageLogs queries the "usage_logs" edge of the APIKey entity.
func (_m *ApiKey) QueryUsageLogs() *UsageLogQuery { func (_m *APIKey) QueryUsageLogs() *UsageLogQuery {
return NewApiKeyClient(_m.config).QueryUsageLogs(_m) return NewAPIKeyClient(_m.config).QueryUsageLogs(_m)
} }
// Update returns a builder for updating this ApiKey. // Update returns a builder for updating this APIKey.
// Note that you need to call ApiKey.Unwrap() before calling this method if this ApiKey // Note that you need to call APIKey.Unwrap() before calling this method if this APIKey
// was returned from a transaction, and the transaction was committed or rolled back. // was returned from a transaction, and the transaction was committed or rolled back.
func (_m *ApiKey) Update() *ApiKeyUpdateOne { func (_m *APIKey) Update() *APIKeyUpdateOne {
return NewApiKeyClient(_m.config).UpdateOne(_m) return NewAPIKeyClient(_m.config).UpdateOne(_m)
} }
// Unwrap unwraps the ApiKey entity that was returned from a transaction after it was closed, // Unwrap unwraps the APIKey entity that was returned from a transaction after it was closed,
// so that all future queries will be executed through the driver which created the transaction. // so that all future queries will be executed through the driver which created the transaction.
func (_m *ApiKey) Unwrap() *ApiKey { func (_m *APIKey) Unwrap() *APIKey {
_tx, ok := _m.config.driver.(*txDriver) _tx, ok := _m.config.driver.(*txDriver)
if !ok { if !ok {
panic("ent: ApiKey is not a transactional entity") panic("ent: APIKey is not a transactional entity")
} }
_m.config.driver = _tx.drv _m.config.driver = _tx.drv
return _m return _m
} }
// String implements the fmt.Stringer. // String implements the fmt.Stringer.
func (_m *ApiKey) String() string { func (_m *APIKey) String() string {
var builder strings.Builder var builder strings.Builder
builder.WriteString("ApiKey(") builder.WriteString("APIKey(")
builder.WriteString(fmt.Sprintf("id=%v, ", _m.ID)) builder.WriteString(fmt.Sprintf("id=%v, ", _m.ID))
builder.WriteString("created_at=") builder.WriteString("created_at=")
builder.WriteString(_m.CreatedAt.Format(time.ANSIC)) builder.WriteString(_m.CreatedAt.Format(time.ANSIC))
@@ -249,5 +249,5 @@ func (_m *ApiKey) String() string {
return builder.String() return builder.String()
} }
// ApiKeys is a parsable slice of ApiKey. // APIKeys is a parsable slice of APIKey.
type ApiKeys []*ApiKey type APIKeys []*APIKey

View File

@@ -109,7 +109,7 @@ var (
StatusValidator func(string) error StatusValidator func(string) error
) )
// OrderOption defines the ordering options for the ApiKey queries. // OrderOption defines the ordering options for the APIKey queries.
type OrderOption func(*sql.Selector) type OrderOption func(*sql.Selector)
// ByID orders the results by the id field. // ByID orders the results by the id field.

View File

@@ -11,468 +11,468 @@ import (
) )
// ID filters vertices based on their ID field. // ID filters vertices based on their ID field.
func ID(id int64) predicate.ApiKey { func ID(id int64) predicate.APIKey {
return predicate.ApiKey(sql.FieldEQ(FieldID, id)) return predicate.APIKey(sql.FieldEQ(FieldID, id))
} }
// IDEQ applies the EQ predicate on the ID field. // IDEQ applies the EQ predicate on the ID field.
func IDEQ(id int64) predicate.ApiKey { func IDEQ(id int64) predicate.APIKey {
return predicate.ApiKey(sql.FieldEQ(FieldID, id)) return predicate.APIKey(sql.FieldEQ(FieldID, id))
} }
// IDNEQ applies the NEQ predicate on the ID field. // IDNEQ applies the NEQ predicate on the ID field.
func IDNEQ(id int64) predicate.ApiKey { func IDNEQ(id int64) predicate.APIKey {
return predicate.ApiKey(sql.FieldNEQ(FieldID, id)) return predicate.APIKey(sql.FieldNEQ(FieldID, id))
} }
// IDIn applies the In predicate on the ID field. // IDIn applies the In predicate on the ID field.
func IDIn(ids ...int64) predicate.ApiKey { func IDIn(ids ...int64) predicate.APIKey {
return predicate.ApiKey(sql.FieldIn(FieldID, ids...)) return predicate.APIKey(sql.FieldIn(FieldID, ids...))
} }
// IDNotIn applies the NotIn predicate on the ID field. // IDNotIn applies the NotIn predicate on the ID field.
func IDNotIn(ids ...int64) predicate.ApiKey { func IDNotIn(ids ...int64) predicate.APIKey {
return predicate.ApiKey(sql.FieldNotIn(FieldID, ids...)) return predicate.APIKey(sql.FieldNotIn(FieldID, ids...))
} }
// IDGT applies the GT predicate on the ID field. // IDGT applies the GT predicate on the ID field.
func IDGT(id int64) predicate.ApiKey { func IDGT(id int64) predicate.APIKey {
return predicate.ApiKey(sql.FieldGT(FieldID, id)) return predicate.APIKey(sql.FieldGT(FieldID, id))
} }
// IDGTE applies the GTE predicate on the ID field. // IDGTE applies the GTE predicate on the ID field.
func IDGTE(id int64) predicate.ApiKey { func IDGTE(id int64) predicate.APIKey {
return predicate.ApiKey(sql.FieldGTE(FieldID, id)) return predicate.APIKey(sql.FieldGTE(FieldID, id))
} }
// IDLT applies the LT predicate on the ID field. // IDLT applies the LT predicate on the ID field.
func IDLT(id int64) predicate.ApiKey { func IDLT(id int64) predicate.APIKey {
return predicate.ApiKey(sql.FieldLT(FieldID, id)) return predicate.APIKey(sql.FieldLT(FieldID, id))
} }
// IDLTE applies the LTE predicate on the ID field. // IDLTE applies the LTE predicate on the ID field.
func IDLTE(id int64) predicate.ApiKey { func IDLTE(id int64) predicate.APIKey {
return predicate.ApiKey(sql.FieldLTE(FieldID, id)) return predicate.APIKey(sql.FieldLTE(FieldID, id))
} }
// CreatedAt applies equality check predicate on the "created_at" field. It's identical to CreatedAtEQ. // CreatedAt applies equality check predicate on the "created_at" field. It's identical to CreatedAtEQ.
func CreatedAt(v time.Time) predicate.ApiKey { func CreatedAt(v time.Time) predicate.APIKey {
return predicate.ApiKey(sql.FieldEQ(FieldCreatedAt, v)) return predicate.APIKey(sql.FieldEQ(FieldCreatedAt, v))
} }
// UpdatedAt applies equality check predicate on the "updated_at" field. It's identical to UpdatedAtEQ. // UpdatedAt applies equality check predicate on the "updated_at" field. It's identical to UpdatedAtEQ.
func UpdatedAt(v time.Time) predicate.ApiKey { func UpdatedAt(v time.Time) predicate.APIKey {
return predicate.ApiKey(sql.FieldEQ(FieldUpdatedAt, v)) return predicate.APIKey(sql.FieldEQ(FieldUpdatedAt, v))
} }
// DeletedAt applies equality check predicate on the "deleted_at" field. It's identical to DeletedAtEQ. // DeletedAt applies equality check predicate on the "deleted_at" field. It's identical to DeletedAtEQ.
func DeletedAt(v time.Time) predicate.ApiKey { func DeletedAt(v time.Time) predicate.APIKey {
return predicate.ApiKey(sql.FieldEQ(FieldDeletedAt, v)) return predicate.APIKey(sql.FieldEQ(FieldDeletedAt, v))
} }
// UserID applies equality check predicate on the "user_id" field. It's identical to UserIDEQ. // UserID applies equality check predicate on the "user_id" field. It's identical to UserIDEQ.
func UserID(v int64) predicate.ApiKey { func UserID(v int64) predicate.APIKey {
return predicate.ApiKey(sql.FieldEQ(FieldUserID, v)) return predicate.APIKey(sql.FieldEQ(FieldUserID, v))
} }
// Key applies equality check predicate on the "key" field. It's identical to KeyEQ. // Key applies equality check predicate on the "key" field. It's identical to KeyEQ.
func Key(v string) predicate.ApiKey { func Key(v string) predicate.APIKey {
return predicate.ApiKey(sql.FieldEQ(FieldKey, v)) return predicate.APIKey(sql.FieldEQ(FieldKey, v))
} }
// Name applies equality check predicate on the "name" field. It's identical to NameEQ. // Name applies equality check predicate on the "name" field. It's identical to NameEQ.
func Name(v string) predicate.ApiKey { func Name(v string) predicate.APIKey {
return predicate.ApiKey(sql.FieldEQ(FieldName, v)) return predicate.APIKey(sql.FieldEQ(FieldName, v))
} }
// GroupID applies equality check predicate on the "group_id" field. It's identical to GroupIDEQ. // GroupID applies equality check predicate on the "group_id" field. It's identical to GroupIDEQ.
func GroupID(v int64) predicate.ApiKey { func GroupID(v int64) predicate.APIKey {
return predicate.ApiKey(sql.FieldEQ(FieldGroupID, v)) return predicate.APIKey(sql.FieldEQ(FieldGroupID, v))
} }
// Status applies equality check predicate on the "status" field. It's identical to StatusEQ. // Status applies equality check predicate on the "status" field. It's identical to StatusEQ.
func Status(v string) predicate.ApiKey { func Status(v string) predicate.APIKey {
return predicate.ApiKey(sql.FieldEQ(FieldStatus, v)) return predicate.APIKey(sql.FieldEQ(FieldStatus, v))
} }
// CreatedAtEQ applies the EQ predicate on the "created_at" field. // CreatedAtEQ applies the EQ predicate on the "created_at" field.
func CreatedAtEQ(v time.Time) predicate.ApiKey { func CreatedAtEQ(v time.Time) predicate.APIKey {
return predicate.ApiKey(sql.FieldEQ(FieldCreatedAt, v)) return predicate.APIKey(sql.FieldEQ(FieldCreatedAt, v))
} }
// CreatedAtNEQ applies the NEQ predicate on the "created_at" field. // CreatedAtNEQ applies the NEQ predicate on the "created_at" field.
func CreatedAtNEQ(v time.Time) predicate.ApiKey { func CreatedAtNEQ(v time.Time) predicate.APIKey {
return predicate.ApiKey(sql.FieldNEQ(FieldCreatedAt, v)) return predicate.APIKey(sql.FieldNEQ(FieldCreatedAt, v))
} }
// CreatedAtIn applies the In predicate on the "created_at" field. // CreatedAtIn applies the In predicate on the "created_at" field.
func CreatedAtIn(vs ...time.Time) predicate.ApiKey { func CreatedAtIn(vs ...time.Time) predicate.APIKey {
return predicate.ApiKey(sql.FieldIn(FieldCreatedAt, vs...)) return predicate.APIKey(sql.FieldIn(FieldCreatedAt, vs...))
} }
// CreatedAtNotIn applies the NotIn predicate on the "created_at" field. // CreatedAtNotIn applies the NotIn predicate on the "created_at" field.
func CreatedAtNotIn(vs ...time.Time) predicate.ApiKey { func CreatedAtNotIn(vs ...time.Time) predicate.APIKey {
return predicate.ApiKey(sql.FieldNotIn(FieldCreatedAt, vs...)) return predicate.APIKey(sql.FieldNotIn(FieldCreatedAt, vs...))
} }
// CreatedAtGT applies the GT predicate on the "created_at" field. // CreatedAtGT applies the GT predicate on the "created_at" field.
func CreatedAtGT(v time.Time) predicate.ApiKey { func CreatedAtGT(v time.Time) predicate.APIKey {
return predicate.ApiKey(sql.FieldGT(FieldCreatedAt, v)) return predicate.APIKey(sql.FieldGT(FieldCreatedAt, v))
} }
// CreatedAtGTE applies the GTE predicate on the "created_at" field. // CreatedAtGTE applies the GTE predicate on the "created_at" field.
func CreatedAtGTE(v time.Time) predicate.ApiKey { func CreatedAtGTE(v time.Time) predicate.APIKey {
return predicate.ApiKey(sql.FieldGTE(FieldCreatedAt, v)) return predicate.APIKey(sql.FieldGTE(FieldCreatedAt, v))
} }
// CreatedAtLT applies the LT predicate on the "created_at" field. // CreatedAtLT applies the LT predicate on the "created_at" field.
func CreatedAtLT(v time.Time) predicate.ApiKey { func CreatedAtLT(v time.Time) predicate.APIKey {
return predicate.ApiKey(sql.FieldLT(FieldCreatedAt, v)) return predicate.APIKey(sql.FieldLT(FieldCreatedAt, v))
} }
// CreatedAtLTE applies the LTE predicate on the "created_at" field. // CreatedAtLTE applies the LTE predicate on the "created_at" field.
func CreatedAtLTE(v time.Time) predicate.ApiKey { func CreatedAtLTE(v time.Time) predicate.APIKey {
return predicate.ApiKey(sql.FieldLTE(FieldCreatedAt, v)) return predicate.APIKey(sql.FieldLTE(FieldCreatedAt, v))
} }
// UpdatedAtEQ applies the EQ predicate on the "updated_at" field. // UpdatedAtEQ applies the EQ predicate on the "updated_at" field.
func UpdatedAtEQ(v time.Time) predicate.ApiKey { func UpdatedAtEQ(v time.Time) predicate.APIKey {
return predicate.ApiKey(sql.FieldEQ(FieldUpdatedAt, v)) return predicate.APIKey(sql.FieldEQ(FieldUpdatedAt, v))
} }
// UpdatedAtNEQ applies the NEQ predicate on the "updated_at" field. // UpdatedAtNEQ applies the NEQ predicate on the "updated_at" field.
func UpdatedAtNEQ(v time.Time) predicate.ApiKey { func UpdatedAtNEQ(v time.Time) predicate.APIKey {
return predicate.ApiKey(sql.FieldNEQ(FieldUpdatedAt, v)) return predicate.APIKey(sql.FieldNEQ(FieldUpdatedAt, v))
} }
// UpdatedAtIn applies the In predicate on the "updated_at" field. // UpdatedAtIn applies the In predicate on the "updated_at" field.
func UpdatedAtIn(vs ...time.Time) predicate.ApiKey { func UpdatedAtIn(vs ...time.Time) predicate.APIKey {
return predicate.ApiKey(sql.FieldIn(FieldUpdatedAt, vs...)) return predicate.APIKey(sql.FieldIn(FieldUpdatedAt, vs...))
} }
// UpdatedAtNotIn applies the NotIn predicate on the "updated_at" field. // UpdatedAtNotIn applies the NotIn predicate on the "updated_at" field.
func UpdatedAtNotIn(vs ...time.Time) predicate.ApiKey { func UpdatedAtNotIn(vs ...time.Time) predicate.APIKey {
return predicate.ApiKey(sql.FieldNotIn(FieldUpdatedAt, vs...)) return predicate.APIKey(sql.FieldNotIn(FieldUpdatedAt, vs...))
} }
// UpdatedAtGT applies the GT predicate on the "updated_at" field. // UpdatedAtGT applies the GT predicate on the "updated_at" field.
func UpdatedAtGT(v time.Time) predicate.ApiKey { func UpdatedAtGT(v time.Time) predicate.APIKey {
return predicate.ApiKey(sql.FieldGT(FieldUpdatedAt, v)) return predicate.APIKey(sql.FieldGT(FieldUpdatedAt, v))
} }
// UpdatedAtGTE applies the GTE predicate on the "updated_at" field. // UpdatedAtGTE applies the GTE predicate on the "updated_at" field.
func UpdatedAtGTE(v time.Time) predicate.ApiKey { func UpdatedAtGTE(v time.Time) predicate.APIKey {
return predicate.ApiKey(sql.FieldGTE(FieldUpdatedAt, v)) return predicate.APIKey(sql.FieldGTE(FieldUpdatedAt, v))
} }
// UpdatedAtLT applies the LT predicate on the "updated_at" field. // UpdatedAtLT applies the LT predicate on the "updated_at" field.
func UpdatedAtLT(v time.Time) predicate.ApiKey { func UpdatedAtLT(v time.Time) predicate.APIKey {
return predicate.ApiKey(sql.FieldLT(FieldUpdatedAt, v)) return predicate.APIKey(sql.FieldLT(FieldUpdatedAt, v))
} }
// UpdatedAtLTE applies the LTE predicate on the "updated_at" field. // UpdatedAtLTE applies the LTE predicate on the "updated_at" field.
func UpdatedAtLTE(v time.Time) predicate.ApiKey { func UpdatedAtLTE(v time.Time) predicate.APIKey {
return predicate.ApiKey(sql.FieldLTE(FieldUpdatedAt, v)) return predicate.APIKey(sql.FieldLTE(FieldUpdatedAt, v))
} }
// DeletedAtEQ applies the EQ predicate on the "deleted_at" field. // DeletedAtEQ applies the EQ predicate on the "deleted_at" field.
func DeletedAtEQ(v time.Time) predicate.ApiKey { func DeletedAtEQ(v time.Time) predicate.APIKey {
return predicate.ApiKey(sql.FieldEQ(FieldDeletedAt, v)) return predicate.APIKey(sql.FieldEQ(FieldDeletedAt, v))
} }
// DeletedAtNEQ applies the NEQ predicate on the "deleted_at" field. // DeletedAtNEQ applies the NEQ predicate on the "deleted_at" field.
func DeletedAtNEQ(v time.Time) predicate.ApiKey { func DeletedAtNEQ(v time.Time) predicate.APIKey {
return predicate.ApiKey(sql.FieldNEQ(FieldDeletedAt, v)) return predicate.APIKey(sql.FieldNEQ(FieldDeletedAt, v))
} }
// DeletedAtIn applies the In predicate on the "deleted_at" field. // DeletedAtIn applies the In predicate on the "deleted_at" field.
func DeletedAtIn(vs ...time.Time) predicate.ApiKey { func DeletedAtIn(vs ...time.Time) predicate.APIKey {
return predicate.ApiKey(sql.FieldIn(FieldDeletedAt, vs...)) return predicate.APIKey(sql.FieldIn(FieldDeletedAt, vs...))
} }
// DeletedAtNotIn applies the NotIn predicate on the "deleted_at" field. // DeletedAtNotIn applies the NotIn predicate on the "deleted_at" field.
func DeletedAtNotIn(vs ...time.Time) predicate.ApiKey { func DeletedAtNotIn(vs ...time.Time) predicate.APIKey {
return predicate.ApiKey(sql.FieldNotIn(FieldDeletedAt, vs...)) return predicate.APIKey(sql.FieldNotIn(FieldDeletedAt, vs...))
} }
// DeletedAtGT applies the GT predicate on the "deleted_at" field. // DeletedAtGT applies the GT predicate on the "deleted_at" field.
func DeletedAtGT(v time.Time) predicate.ApiKey { func DeletedAtGT(v time.Time) predicate.APIKey {
return predicate.ApiKey(sql.FieldGT(FieldDeletedAt, v)) return predicate.APIKey(sql.FieldGT(FieldDeletedAt, v))
} }
// DeletedAtGTE applies the GTE predicate on the "deleted_at" field. // DeletedAtGTE applies the GTE predicate on the "deleted_at" field.
func DeletedAtGTE(v time.Time) predicate.ApiKey { func DeletedAtGTE(v time.Time) predicate.APIKey {
return predicate.ApiKey(sql.FieldGTE(FieldDeletedAt, v)) return predicate.APIKey(sql.FieldGTE(FieldDeletedAt, v))
} }
// DeletedAtLT applies the LT predicate on the "deleted_at" field. // DeletedAtLT applies the LT predicate on the "deleted_at" field.
func DeletedAtLT(v time.Time) predicate.ApiKey { func DeletedAtLT(v time.Time) predicate.APIKey {
return predicate.ApiKey(sql.FieldLT(FieldDeletedAt, v)) return predicate.APIKey(sql.FieldLT(FieldDeletedAt, v))
} }
// DeletedAtLTE applies the LTE predicate on the "deleted_at" field. // DeletedAtLTE applies the LTE predicate on the "deleted_at" field.
func DeletedAtLTE(v time.Time) predicate.ApiKey { func DeletedAtLTE(v time.Time) predicate.APIKey {
return predicate.ApiKey(sql.FieldLTE(FieldDeletedAt, v)) return predicate.APIKey(sql.FieldLTE(FieldDeletedAt, v))
} }
// DeletedAtIsNil applies the IsNil predicate on the "deleted_at" field. // DeletedAtIsNil applies the IsNil predicate on the "deleted_at" field.
func DeletedAtIsNil() predicate.ApiKey { func DeletedAtIsNil() predicate.APIKey {
return predicate.ApiKey(sql.FieldIsNull(FieldDeletedAt)) return predicate.APIKey(sql.FieldIsNull(FieldDeletedAt))
} }
// DeletedAtNotNil applies the NotNil predicate on the "deleted_at" field. // DeletedAtNotNil applies the NotNil predicate on the "deleted_at" field.
func DeletedAtNotNil() predicate.ApiKey { func DeletedAtNotNil() predicate.APIKey {
return predicate.ApiKey(sql.FieldNotNull(FieldDeletedAt)) return predicate.APIKey(sql.FieldNotNull(FieldDeletedAt))
} }
// UserIDEQ applies the EQ predicate on the "user_id" field. // UserIDEQ applies the EQ predicate on the "user_id" field.
func UserIDEQ(v int64) predicate.ApiKey { func UserIDEQ(v int64) predicate.APIKey {
return predicate.ApiKey(sql.FieldEQ(FieldUserID, v)) return predicate.APIKey(sql.FieldEQ(FieldUserID, v))
} }
// UserIDNEQ applies the NEQ predicate on the "user_id" field. // UserIDNEQ applies the NEQ predicate on the "user_id" field.
func UserIDNEQ(v int64) predicate.ApiKey { func UserIDNEQ(v int64) predicate.APIKey {
return predicate.ApiKey(sql.FieldNEQ(FieldUserID, v)) return predicate.APIKey(sql.FieldNEQ(FieldUserID, v))
} }
// UserIDIn applies the In predicate on the "user_id" field. // UserIDIn applies the In predicate on the "user_id" field.
func UserIDIn(vs ...int64) predicate.ApiKey { func UserIDIn(vs ...int64) predicate.APIKey {
return predicate.ApiKey(sql.FieldIn(FieldUserID, vs...)) return predicate.APIKey(sql.FieldIn(FieldUserID, vs...))
} }
// UserIDNotIn applies the NotIn predicate on the "user_id" field. // UserIDNotIn applies the NotIn predicate on the "user_id" field.
func UserIDNotIn(vs ...int64) predicate.ApiKey { func UserIDNotIn(vs ...int64) predicate.APIKey {
return predicate.ApiKey(sql.FieldNotIn(FieldUserID, vs...)) return predicate.APIKey(sql.FieldNotIn(FieldUserID, vs...))
} }
// KeyEQ applies the EQ predicate on the "key" field. // KeyEQ applies the EQ predicate on the "key" field.
func KeyEQ(v string) predicate.ApiKey { func KeyEQ(v string) predicate.APIKey {
return predicate.ApiKey(sql.FieldEQ(FieldKey, v)) return predicate.APIKey(sql.FieldEQ(FieldKey, v))
} }
// KeyNEQ applies the NEQ predicate on the "key" field. // KeyNEQ applies the NEQ predicate on the "key" field.
func KeyNEQ(v string) predicate.ApiKey { func KeyNEQ(v string) predicate.APIKey {
return predicate.ApiKey(sql.FieldNEQ(FieldKey, v)) return predicate.APIKey(sql.FieldNEQ(FieldKey, v))
} }
// KeyIn applies the In predicate on the "key" field. // KeyIn applies the In predicate on the "key" field.
func KeyIn(vs ...string) predicate.ApiKey { func KeyIn(vs ...string) predicate.APIKey {
return predicate.ApiKey(sql.FieldIn(FieldKey, vs...)) return predicate.APIKey(sql.FieldIn(FieldKey, vs...))
} }
// KeyNotIn applies the NotIn predicate on the "key" field. // KeyNotIn applies the NotIn predicate on the "key" field.
func KeyNotIn(vs ...string) predicate.ApiKey { func KeyNotIn(vs ...string) predicate.APIKey {
return predicate.ApiKey(sql.FieldNotIn(FieldKey, vs...)) return predicate.APIKey(sql.FieldNotIn(FieldKey, vs...))
} }
// KeyGT applies the GT predicate on the "key" field. // KeyGT applies the GT predicate on the "key" field.
func KeyGT(v string) predicate.ApiKey { func KeyGT(v string) predicate.APIKey {
return predicate.ApiKey(sql.FieldGT(FieldKey, v)) return predicate.APIKey(sql.FieldGT(FieldKey, v))
} }
// KeyGTE applies the GTE predicate on the "key" field. // KeyGTE applies the GTE predicate on the "key" field.
func KeyGTE(v string) predicate.ApiKey { func KeyGTE(v string) predicate.APIKey {
return predicate.ApiKey(sql.FieldGTE(FieldKey, v)) return predicate.APIKey(sql.FieldGTE(FieldKey, v))
} }
// KeyLT applies the LT predicate on the "key" field. // KeyLT applies the LT predicate on the "key" field.
func KeyLT(v string) predicate.ApiKey { func KeyLT(v string) predicate.APIKey {
return predicate.ApiKey(sql.FieldLT(FieldKey, v)) return predicate.APIKey(sql.FieldLT(FieldKey, v))
} }
// KeyLTE applies the LTE predicate on the "key" field. // KeyLTE applies the LTE predicate on the "key" field.
func KeyLTE(v string) predicate.ApiKey { func KeyLTE(v string) predicate.APIKey {
return predicate.ApiKey(sql.FieldLTE(FieldKey, v)) return predicate.APIKey(sql.FieldLTE(FieldKey, v))
} }
// KeyContains applies the Contains predicate on the "key" field. // KeyContains applies the Contains predicate on the "key" field.
func KeyContains(v string) predicate.ApiKey { func KeyContains(v string) predicate.APIKey {
return predicate.ApiKey(sql.FieldContains(FieldKey, v)) return predicate.APIKey(sql.FieldContains(FieldKey, v))
} }
// KeyHasPrefix applies the HasPrefix predicate on the "key" field. // KeyHasPrefix applies the HasPrefix predicate on the "key" field.
func KeyHasPrefix(v string) predicate.ApiKey { func KeyHasPrefix(v string) predicate.APIKey {
return predicate.ApiKey(sql.FieldHasPrefix(FieldKey, v)) return predicate.APIKey(sql.FieldHasPrefix(FieldKey, v))
} }
// KeyHasSuffix applies the HasSuffix predicate on the "key" field. // KeyHasSuffix applies the HasSuffix predicate on the "key" field.
func KeyHasSuffix(v string) predicate.ApiKey { func KeyHasSuffix(v string) predicate.APIKey {
return predicate.ApiKey(sql.FieldHasSuffix(FieldKey, v)) return predicate.APIKey(sql.FieldHasSuffix(FieldKey, v))
} }
// KeyEqualFold applies the EqualFold predicate on the "key" field. // KeyEqualFold applies the EqualFold predicate on the "key" field.
func KeyEqualFold(v string) predicate.ApiKey { func KeyEqualFold(v string) predicate.APIKey {
return predicate.ApiKey(sql.FieldEqualFold(FieldKey, v)) return predicate.APIKey(sql.FieldEqualFold(FieldKey, v))
} }
// KeyContainsFold applies the ContainsFold predicate on the "key" field. // KeyContainsFold applies the ContainsFold predicate on the "key" field.
func KeyContainsFold(v string) predicate.ApiKey { func KeyContainsFold(v string) predicate.APIKey {
return predicate.ApiKey(sql.FieldContainsFold(FieldKey, v)) return predicate.APIKey(sql.FieldContainsFold(FieldKey, v))
} }
// NameEQ applies the EQ predicate on the "name" field. // NameEQ applies the EQ predicate on the "name" field.
func NameEQ(v string) predicate.ApiKey { func NameEQ(v string) predicate.APIKey {
return predicate.ApiKey(sql.FieldEQ(FieldName, v)) return predicate.APIKey(sql.FieldEQ(FieldName, v))
} }
// NameNEQ applies the NEQ predicate on the "name" field. // NameNEQ applies the NEQ predicate on the "name" field.
func NameNEQ(v string) predicate.ApiKey { func NameNEQ(v string) predicate.APIKey {
return predicate.ApiKey(sql.FieldNEQ(FieldName, v)) return predicate.APIKey(sql.FieldNEQ(FieldName, v))
} }
// NameIn applies the In predicate on the "name" field. // NameIn applies the In predicate on the "name" field.
func NameIn(vs ...string) predicate.ApiKey { func NameIn(vs ...string) predicate.APIKey {
return predicate.ApiKey(sql.FieldIn(FieldName, vs...)) return predicate.APIKey(sql.FieldIn(FieldName, vs...))
} }
// NameNotIn applies the NotIn predicate on the "name" field. // NameNotIn applies the NotIn predicate on the "name" field.
func NameNotIn(vs ...string) predicate.ApiKey { func NameNotIn(vs ...string) predicate.APIKey {
return predicate.ApiKey(sql.FieldNotIn(FieldName, vs...)) return predicate.APIKey(sql.FieldNotIn(FieldName, vs...))
} }
// NameGT applies the GT predicate on the "name" field. // NameGT applies the GT predicate on the "name" field.
func NameGT(v string) predicate.ApiKey { func NameGT(v string) predicate.APIKey {
return predicate.ApiKey(sql.FieldGT(FieldName, v)) return predicate.APIKey(sql.FieldGT(FieldName, v))
} }
// NameGTE applies the GTE predicate on the "name" field. // NameGTE applies the GTE predicate on the "name" field.
func NameGTE(v string) predicate.ApiKey { func NameGTE(v string) predicate.APIKey {
return predicate.ApiKey(sql.FieldGTE(FieldName, v)) return predicate.APIKey(sql.FieldGTE(FieldName, v))
} }
// NameLT applies the LT predicate on the "name" field. // NameLT applies the LT predicate on the "name" field.
func NameLT(v string) predicate.ApiKey { func NameLT(v string) predicate.APIKey {
return predicate.ApiKey(sql.FieldLT(FieldName, v)) return predicate.APIKey(sql.FieldLT(FieldName, v))
} }
// NameLTE applies the LTE predicate on the "name" field. // NameLTE applies the LTE predicate on the "name" field.
func NameLTE(v string) predicate.ApiKey { func NameLTE(v string) predicate.APIKey {
return predicate.ApiKey(sql.FieldLTE(FieldName, v)) return predicate.APIKey(sql.FieldLTE(FieldName, v))
} }
// NameContains applies the Contains predicate on the "name" field. // NameContains applies the Contains predicate on the "name" field.
func NameContains(v string) predicate.ApiKey { func NameContains(v string) predicate.APIKey {
return predicate.ApiKey(sql.FieldContains(FieldName, v)) return predicate.APIKey(sql.FieldContains(FieldName, v))
} }
// NameHasPrefix applies the HasPrefix predicate on the "name" field. // NameHasPrefix applies the HasPrefix predicate on the "name" field.
func NameHasPrefix(v string) predicate.ApiKey { func NameHasPrefix(v string) predicate.APIKey {
return predicate.ApiKey(sql.FieldHasPrefix(FieldName, v)) return predicate.APIKey(sql.FieldHasPrefix(FieldName, v))
} }
// NameHasSuffix applies the HasSuffix predicate on the "name" field. // NameHasSuffix applies the HasSuffix predicate on the "name" field.
func NameHasSuffix(v string) predicate.ApiKey { func NameHasSuffix(v string) predicate.APIKey {
return predicate.ApiKey(sql.FieldHasSuffix(FieldName, v)) return predicate.APIKey(sql.FieldHasSuffix(FieldName, v))
} }
// NameEqualFold applies the EqualFold predicate on the "name" field. // NameEqualFold applies the EqualFold predicate on the "name" field.
func NameEqualFold(v string) predicate.ApiKey { func NameEqualFold(v string) predicate.APIKey {
return predicate.ApiKey(sql.FieldEqualFold(FieldName, v)) return predicate.APIKey(sql.FieldEqualFold(FieldName, v))
} }
// NameContainsFold applies the ContainsFold predicate on the "name" field. // NameContainsFold applies the ContainsFold predicate on the "name" field.
func NameContainsFold(v string) predicate.ApiKey { func NameContainsFold(v string) predicate.APIKey {
return predicate.ApiKey(sql.FieldContainsFold(FieldName, v)) return predicate.APIKey(sql.FieldContainsFold(FieldName, v))
} }
// GroupIDEQ applies the EQ predicate on the "group_id" field. // GroupIDEQ applies the EQ predicate on the "group_id" field.
func GroupIDEQ(v int64) predicate.ApiKey { func GroupIDEQ(v int64) predicate.APIKey {
return predicate.ApiKey(sql.FieldEQ(FieldGroupID, v)) return predicate.APIKey(sql.FieldEQ(FieldGroupID, v))
} }
// GroupIDNEQ applies the NEQ predicate on the "group_id" field. // GroupIDNEQ applies the NEQ predicate on the "group_id" field.
func GroupIDNEQ(v int64) predicate.ApiKey { func GroupIDNEQ(v int64) predicate.APIKey {
return predicate.ApiKey(sql.FieldNEQ(FieldGroupID, v)) return predicate.APIKey(sql.FieldNEQ(FieldGroupID, v))
} }
// GroupIDIn applies the In predicate on the "group_id" field. // GroupIDIn applies the In predicate on the "group_id" field.
func GroupIDIn(vs ...int64) predicate.ApiKey { func GroupIDIn(vs ...int64) predicate.APIKey {
return predicate.ApiKey(sql.FieldIn(FieldGroupID, vs...)) return predicate.APIKey(sql.FieldIn(FieldGroupID, vs...))
} }
// GroupIDNotIn applies the NotIn predicate on the "group_id" field. // GroupIDNotIn applies the NotIn predicate on the "group_id" field.
func GroupIDNotIn(vs ...int64) predicate.ApiKey { func GroupIDNotIn(vs ...int64) predicate.APIKey {
return predicate.ApiKey(sql.FieldNotIn(FieldGroupID, vs...)) return predicate.APIKey(sql.FieldNotIn(FieldGroupID, vs...))
} }
// GroupIDIsNil applies the IsNil predicate on the "group_id" field. // GroupIDIsNil applies the IsNil predicate on the "group_id" field.
func GroupIDIsNil() predicate.ApiKey { func GroupIDIsNil() predicate.APIKey {
return predicate.ApiKey(sql.FieldIsNull(FieldGroupID)) return predicate.APIKey(sql.FieldIsNull(FieldGroupID))
} }
// GroupIDNotNil applies the NotNil predicate on the "group_id" field. // GroupIDNotNil applies the NotNil predicate on the "group_id" field.
func GroupIDNotNil() predicate.ApiKey { func GroupIDNotNil() predicate.APIKey {
return predicate.ApiKey(sql.FieldNotNull(FieldGroupID)) return predicate.APIKey(sql.FieldNotNull(FieldGroupID))
} }
// StatusEQ applies the EQ predicate on the "status" field. // StatusEQ applies the EQ predicate on the "status" field.
func StatusEQ(v string) predicate.ApiKey { func StatusEQ(v string) predicate.APIKey {
return predicate.ApiKey(sql.FieldEQ(FieldStatus, v)) return predicate.APIKey(sql.FieldEQ(FieldStatus, v))
} }
// StatusNEQ applies the NEQ predicate on the "status" field. // StatusNEQ applies the NEQ predicate on the "status" field.
func StatusNEQ(v string) predicate.ApiKey { func StatusNEQ(v string) predicate.APIKey {
return predicate.ApiKey(sql.FieldNEQ(FieldStatus, v)) return predicate.APIKey(sql.FieldNEQ(FieldStatus, v))
} }
// StatusIn applies the In predicate on the "status" field. // StatusIn applies the In predicate on the "status" field.
func StatusIn(vs ...string) predicate.ApiKey { func StatusIn(vs ...string) predicate.APIKey {
return predicate.ApiKey(sql.FieldIn(FieldStatus, vs...)) return predicate.APIKey(sql.FieldIn(FieldStatus, vs...))
} }
// StatusNotIn applies the NotIn predicate on the "status" field. // StatusNotIn applies the NotIn predicate on the "status" field.
func StatusNotIn(vs ...string) predicate.ApiKey { func StatusNotIn(vs ...string) predicate.APIKey {
return predicate.ApiKey(sql.FieldNotIn(FieldStatus, vs...)) return predicate.APIKey(sql.FieldNotIn(FieldStatus, vs...))
} }
// StatusGT applies the GT predicate on the "status" field. // StatusGT applies the GT predicate on the "status" field.
func StatusGT(v string) predicate.ApiKey { func StatusGT(v string) predicate.APIKey {
return predicate.ApiKey(sql.FieldGT(FieldStatus, v)) return predicate.APIKey(sql.FieldGT(FieldStatus, v))
} }
// StatusGTE applies the GTE predicate on the "status" field. // StatusGTE applies the GTE predicate on the "status" field.
func StatusGTE(v string) predicate.ApiKey { func StatusGTE(v string) predicate.APIKey {
return predicate.ApiKey(sql.FieldGTE(FieldStatus, v)) return predicate.APIKey(sql.FieldGTE(FieldStatus, v))
} }
// StatusLT applies the LT predicate on the "status" field. // StatusLT applies the LT predicate on the "status" field.
func StatusLT(v string) predicate.ApiKey { func StatusLT(v string) predicate.APIKey {
return predicate.ApiKey(sql.FieldLT(FieldStatus, v)) return predicate.APIKey(sql.FieldLT(FieldStatus, v))
} }
// StatusLTE applies the LTE predicate on the "status" field. // StatusLTE applies the LTE predicate on the "status" field.
func StatusLTE(v string) predicate.ApiKey { func StatusLTE(v string) predicate.APIKey {
return predicate.ApiKey(sql.FieldLTE(FieldStatus, v)) return predicate.APIKey(sql.FieldLTE(FieldStatus, v))
} }
// StatusContains applies the Contains predicate on the "status" field. // StatusContains applies the Contains predicate on the "status" field.
func StatusContains(v string) predicate.ApiKey { func StatusContains(v string) predicate.APIKey {
return predicate.ApiKey(sql.FieldContains(FieldStatus, v)) return predicate.APIKey(sql.FieldContains(FieldStatus, v))
} }
// StatusHasPrefix applies the HasPrefix predicate on the "status" field. // StatusHasPrefix applies the HasPrefix predicate on the "status" field.
func StatusHasPrefix(v string) predicate.ApiKey { func StatusHasPrefix(v string) predicate.APIKey {
return predicate.ApiKey(sql.FieldHasPrefix(FieldStatus, v)) return predicate.APIKey(sql.FieldHasPrefix(FieldStatus, v))
} }
// StatusHasSuffix applies the HasSuffix predicate on the "status" field. // StatusHasSuffix applies the HasSuffix predicate on the "status" field.
func StatusHasSuffix(v string) predicate.ApiKey { func StatusHasSuffix(v string) predicate.APIKey {
return predicate.ApiKey(sql.FieldHasSuffix(FieldStatus, v)) return predicate.APIKey(sql.FieldHasSuffix(FieldStatus, v))
} }
// StatusEqualFold applies the EqualFold predicate on the "status" field. // StatusEqualFold applies the EqualFold predicate on the "status" field.
func StatusEqualFold(v string) predicate.ApiKey { func StatusEqualFold(v string) predicate.APIKey {
return predicate.ApiKey(sql.FieldEqualFold(FieldStatus, v)) return predicate.APIKey(sql.FieldEqualFold(FieldStatus, v))
} }
// StatusContainsFold applies the ContainsFold predicate on the "status" field. // StatusContainsFold applies the ContainsFold predicate on the "status" field.
func StatusContainsFold(v string) predicate.ApiKey { func StatusContainsFold(v string) predicate.APIKey {
return predicate.ApiKey(sql.FieldContainsFold(FieldStatus, v)) return predicate.APIKey(sql.FieldContainsFold(FieldStatus, v))
} }
// HasUser applies the HasEdge predicate on the "user" edge. // HasUser applies the HasEdge predicate on the "user" edge.
func HasUser() predicate.ApiKey { func HasUser() predicate.APIKey {
return predicate.ApiKey(func(s *sql.Selector) { return predicate.APIKey(func(s *sql.Selector) {
step := sqlgraph.NewStep( step := sqlgraph.NewStep(
sqlgraph.From(Table, FieldID), sqlgraph.From(Table, FieldID),
sqlgraph.Edge(sqlgraph.M2O, true, UserTable, UserColumn), sqlgraph.Edge(sqlgraph.M2O, true, UserTable, UserColumn),
@@ -482,8 +482,8 @@ func HasUser() predicate.ApiKey {
} }
// HasUserWith applies the HasEdge predicate on the "user" edge with a given conditions (other predicates). // HasUserWith applies the HasEdge predicate on the "user" edge with a given conditions (other predicates).
func HasUserWith(preds ...predicate.User) predicate.ApiKey { func HasUserWith(preds ...predicate.User) predicate.APIKey {
return predicate.ApiKey(func(s *sql.Selector) { return predicate.APIKey(func(s *sql.Selector) {
step := newUserStep() step := newUserStep()
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
for _, p := range preds { for _, p := range preds {
@@ -494,8 +494,8 @@ func HasUserWith(preds ...predicate.User) predicate.ApiKey {
} }
// HasGroup applies the HasEdge predicate on the "group" edge. // HasGroup applies the HasEdge predicate on the "group" edge.
func HasGroup() predicate.ApiKey { func HasGroup() predicate.APIKey {
return predicate.ApiKey(func(s *sql.Selector) { return predicate.APIKey(func(s *sql.Selector) {
step := sqlgraph.NewStep( step := sqlgraph.NewStep(
sqlgraph.From(Table, FieldID), sqlgraph.From(Table, FieldID),
sqlgraph.Edge(sqlgraph.M2O, true, GroupTable, GroupColumn), sqlgraph.Edge(sqlgraph.M2O, true, GroupTable, GroupColumn),
@@ -505,8 +505,8 @@ func HasGroup() predicate.ApiKey {
} }
// HasGroupWith applies the HasEdge predicate on the "group" edge with a given conditions (other predicates). // HasGroupWith applies the HasEdge predicate on the "group" edge with a given conditions (other predicates).
func HasGroupWith(preds ...predicate.Group) predicate.ApiKey { func HasGroupWith(preds ...predicate.Group) predicate.APIKey {
return predicate.ApiKey(func(s *sql.Selector) { return predicate.APIKey(func(s *sql.Selector) {
step := newGroupStep() step := newGroupStep()
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
for _, p := range preds { for _, p := range preds {
@@ -517,8 +517,8 @@ func HasGroupWith(preds ...predicate.Group) predicate.ApiKey {
} }
// HasUsageLogs applies the HasEdge predicate on the "usage_logs" edge. // HasUsageLogs applies the HasEdge predicate on the "usage_logs" edge.
func HasUsageLogs() predicate.ApiKey { func HasUsageLogs() predicate.APIKey {
return predicate.ApiKey(func(s *sql.Selector) { return predicate.APIKey(func(s *sql.Selector) {
step := sqlgraph.NewStep( step := sqlgraph.NewStep(
sqlgraph.From(Table, FieldID), sqlgraph.From(Table, FieldID),
sqlgraph.Edge(sqlgraph.O2M, false, UsageLogsTable, UsageLogsColumn), sqlgraph.Edge(sqlgraph.O2M, false, UsageLogsTable, UsageLogsColumn),
@@ -528,8 +528,8 @@ func HasUsageLogs() predicate.ApiKey {
} }
// HasUsageLogsWith applies the HasEdge predicate on the "usage_logs" edge with a given conditions (other predicates). // HasUsageLogsWith applies the HasEdge predicate on the "usage_logs" edge with a given conditions (other predicates).
func HasUsageLogsWith(preds ...predicate.UsageLog) predicate.ApiKey { func HasUsageLogsWith(preds ...predicate.UsageLog) predicate.APIKey {
return predicate.ApiKey(func(s *sql.Selector) { return predicate.APIKey(func(s *sql.Selector) {
step := newUsageLogsStep() step := newUsageLogsStep()
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
for _, p := range preds { for _, p := range preds {
@@ -540,16 +540,16 @@ func HasUsageLogsWith(preds ...predicate.UsageLog) predicate.ApiKey {
} }
// And groups predicates with the AND operator between them. // And groups predicates with the AND operator between them.
func And(predicates ...predicate.ApiKey) predicate.ApiKey { func And(predicates ...predicate.APIKey) predicate.APIKey {
return predicate.ApiKey(sql.AndPredicates(predicates...)) return predicate.APIKey(sql.AndPredicates(predicates...))
} }
// Or groups predicates with the OR operator between them. // Or groups predicates with the OR operator between them.
func Or(predicates ...predicate.ApiKey) predicate.ApiKey { func Or(predicates ...predicate.APIKey) predicate.APIKey {
return predicate.ApiKey(sql.OrPredicates(predicates...)) return predicate.APIKey(sql.OrPredicates(predicates...))
} }
// Not applies the not operator on the given predicate. // Not applies the not operator on the given predicate.
func Not(p predicate.ApiKey) predicate.ApiKey { func Not(p predicate.APIKey) predicate.APIKey {
return predicate.ApiKey(sql.NotPredicates(p)) return predicate.APIKey(sql.NotPredicates(p))
} }

View File

@@ -17,22 +17,22 @@ import (
"github.com/Wei-Shaw/sub2api/ent/user" "github.com/Wei-Shaw/sub2api/ent/user"
) )
// ApiKeyCreate is the builder for creating a ApiKey entity. // APIKeyCreate is the builder for creating a APIKey entity.
type ApiKeyCreate struct { type APIKeyCreate struct {
config config
mutation *ApiKeyMutation mutation *APIKeyMutation
hooks []Hook hooks []Hook
conflict []sql.ConflictOption conflict []sql.ConflictOption
} }
// SetCreatedAt sets the "created_at" field. // SetCreatedAt sets the "created_at" field.
func (_c *ApiKeyCreate) SetCreatedAt(v time.Time) *ApiKeyCreate { func (_c *APIKeyCreate) SetCreatedAt(v time.Time) *APIKeyCreate {
_c.mutation.SetCreatedAt(v) _c.mutation.SetCreatedAt(v)
return _c return _c
} }
// SetNillableCreatedAt sets the "created_at" field if the given value is not nil. // SetNillableCreatedAt sets the "created_at" field if the given value is not nil.
func (_c *ApiKeyCreate) SetNillableCreatedAt(v *time.Time) *ApiKeyCreate { func (_c *APIKeyCreate) SetNillableCreatedAt(v *time.Time) *APIKeyCreate {
if v != nil { if v != nil {
_c.SetCreatedAt(*v) _c.SetCreatedAt(*v)
} }
@@ -40,13 +40,13 @@ func (_c *ApiKeyCreate) SetNillableCreatedAt(v *time.Time) *ApiKeyCreate {
} }
// SetUpdatedAt sets the "updated_at" field. // SetUpdatedAt sets the "updated_at" field.
func (_c *ApiKeyCreate) SetUpdatedAt(v time.Time) *ApiKeyCreate { func (_c *APIKeyCreate) SetUpdatedAt(v time.Time) *APIKeyCreate {
_c.mutation.SetUpdatedAt(v) _c.mutation.SetUpdatedAt(v)
return _c return _c
} }
// SetNillableUpdatedAt sets the "updated_at" field if the given value is not nil. // SetNillableUpdatedAt sets the "updated_at" field if the given value is not nil.
func (_c *ApiKeyCreate) SetNillableUpdatedAt(v *time.Time) *ApiKeyCreate { func (_c *APIKeyCreate) SetNillableUpdatedAt(v *time.Time) *APIKeyCreate {
if v != nil { if v != nil {
_c.SetUpdatedAt(*v) _c.SetUpdatedAt(*v)
} }
@@ -54,13 +54,13 @@ func (_c *ApiKeyCreate) SetNillableUpdatedAt(v *time.Time) *ApiKeyCreate {
} }
// SetDeletedAt sets the "deleted_at" field. // SetDeletedAt sets the "deleted_at" field.
func (_c *ApiKeyCreate) SetDeletedAt(v time.Time) *ApiKeyCreate { func (_c *APIKeyCreate) SetDeletedAt(v time.Time) *APIKeyCreate {
_c.mutation.SetDeletedAt(v) _c.mutation.SetDeletedAt(v)
return _c return _c
} }
// SetNillableDeletedAt sets the "deleted_at" field if the given value is not nil. // SetNillableDeletedAt sets the "deleted_at" field if the given value is not nil.
func (_c *ApiKeyCreate) SetNillableDeletedAt(v *time.Time) *ApiKeyCreate { func (_c *APIKeyCreate) SetNillableDeletedAt(v *time.Time) *APIKeyCreate {
if v != nil { if v != nil {
_c.SetDeletedAt(*v) _c.SetDeletedAt(*v)
} }
@@ -68,31 +68,31 @@ func (_c *ApiKeyCreate) SetNillableDeletedAt(v *time.Time) *ApiKeyCreate {
} }
// SetUserID sets the "user_id" field. // SetUserID sets the "user_id" field.
func (_c *ApiKeyCreate) SetUserID(v int64) *ApiKeyCreate { func (_c *APIKeyCreate) SetUserID(v int64) *APIKeyCreate {
_c.mutation.SetUserID(v) _c.mutation.SetUserID(v)
return _c return _c
} }
// SetKey sets the "key" field. // SetKey sets the "key" field.
func (_c *ApiKeyCreate) SetKey(v string) *ApiKeyCreate { func (_c *APIKeyCreate) SetKey(v string) *APIKeyCreate {
_c.mutation.SetKey(v) _c.mutation.SetKey(v)
return _c return _c
} }
// SetName sets the "name" field. // SetName sets the "name" field.
func (_c *ApiKeyCreate) SetName(v string) *ApiKeyCreate { func (_c *APIKeyCreate) SetName(v string) *APIKeyCreate {
_c.mutation.SetName(v) _c.mutation.SetName(v)
return _c return _c
} }
// SetGroupID sets the "group_id" field. // SetGroupID sets the "group_id" field.
func (_c *ApiKeyCreate) SetGroupID(v int64) *ApiKeyCreate { func (_c *APIKeyCreate) SetGroupID(v int64) *APIKeyCreate {
_c.mutation.SetGroupID(v) _c.mutation.SetGroupID(v)
return _c return _c
} }
// SetNillableGroupID sets the "group_id" field if the given value is not nil. // SetNillableGroupID sets the "group_id" field if the given value is not nil.
func (_c *ApiKeyCreate) SetNillableGroupID(v *int64) *ApiKeyCreate { func (_c *APIKeyCreate) SetNillableGroupID(v *int64) *APIKeyCreate {
if v != nil { if v != nil {
_c.SetGroupID(*v) _c.SetGroupID(*v)
} }
@@ -100,13 +100,13 @@ func (_c *ApiKeyCreate) SetNillableGroupID(v *int64) *ApiKeyCreate {
} }
// SetStatus sets the "status" field. // SetStatus sets the "status" field.
func (_c *ApiKeyCreate) SetStatus(v string) *ApiKeyCreate { func (_c *APIKeyCreate) SetStatus(v string) *APIKeyCreate {
_c.mutation.SetStatus(v) _c.mutation.SetStatus(v)
return _c return _c
} }
// SetNillableStatus sets the "status" field if the given value is not nil. // SetNillableStatus sets the "status" field if the given value is not nil.
func (_c *ApiKeyCreate) SetNillableStatus(v *string) *ApiKeyCreate { func (_c *APIKeyCreate) SetNillableStatus(v *string) *APIKeyCreate {
if v != nil { if v != nil {
_c.SetStatus(*v) _c.SetStatus(*v)
} }
@@ -114,23 +114,23 @@ func (_c *ApiKeyCreate) SetNillableStatus(v *string) *ApiKeyCreate {
} }
// SetUser sets the "user" edge to the User entity. // SetUser sets the "user" edge to the User entity.
func (_c *ApiKeyCreate) SetUser(v *User) *ApiKeyCreate { func (_c *APIKeyCreate) SetUser(v *User) *APIKeyCreate {
return _c.SetUserID(v.ID) return _c.SetUserID(v.ID)
} }
// SetGroup sets the "group" edge to the Group entity. // SetGroup sets the "group" edge to the Group entity.
func (_c *ApiKeyCreate) SetGroup(v *Group) *ApiKeyCreate { func (_c *APIKeyCreate) SetGroup(v *Group) *APIKeyCreate {
return _c.SetGroupID(v.ID) return _c.SetGroupID(v.ID)
} }
// AddUsageLogIDs adds the "usage_logs" edge to the UsageLog entity by IDs. // AddUsageLogIDs adds the "usage_logs" edge to the UsageLog entity by IDs.
func (_c *ApiKeyCreate) AddUsageLogIDs(ids ...int64) *ApiKeyCreate { func (_c *APIKeyCreate) AddUsageLogIDs(ids ...int64) *APIKeyCreate {
_c.mutation.AddUsageLogIDs(ids...) _c.mutation.AddUsageLogIDs(ids...)
return _c return _c
} }
// AddUsageLogs adds the "usage_logs" edges to the UsageLog entity. // AddUsageLogs adds the "usage_logs" edges to the UsageLog entity.
func (_c *ApiKeyCreate) AddUsageLogs(v ...*UsageLog) *ApiKeyCreate { func (_c *APIKeyCreate) AddUsageLogs(v ...*UsageLog) *APIKeyCreate {
ids := make([]int64, len(v)) ids := make([]int64, len(v))
for i := range v { for i := range v {
ids[i] = v[i].ID ids[i] = v[i].ID
@@ -138,13 +138,13 @@ func (_c *ApiKeyCreate) AddUsageLogs(v ...*UsageLog) *ApiKeyCreate {
return _c.AddUsageLogIDs(ids...) return _c.AddUsageLogIDs(ids...)
} }
// Mutation returns the ApiKeyMutation object of the builder. // Mutation returns the APIKeyMutation object of the builder.
func (_c *ApiKeyCreate) Mutation() *ApiKeyMutation { func (_c *APIKeyCreate) Mutation() *APIKeyMutation {
return _c.mutation return _c.mutation
} }
// Save creates the ApiKey in the database. // Save creates the APIKey in the database.
func (_c *ApiKeyCreate) Save(ctx context.Context) (*ApiKey, error) { func (_c *APIKeyCreate) Save(ctx context.Context) (*APIKey, error) {
if err := _c.defaults(); err != nil { if err := _c.defaults(); err != nil {
return nil, err return nil, err
} }
@@ -152,7 +152,7 @@ func (_c *ApiKeyCreate) Save(ctx context.Context) (*ApiKey, error) {
} }
// SaveX calls Save and panics if Save returns an error. // SaveX calls Save and panics if Save returns an error.
func (_c *ApiKeyCreate) SaveX(ctx context.Context) *ApiKey { func (_c *APIKeyCreate) SaveX(ctx context.Context) *APIKey {
v, err := _c.Save(ctx) v, err := _c.Save(ctx)
if err != nil { if err != nil {
panic(err) panic(err)
@@ -161,20 +161,20 @@ func (_c *ApiKeyCreate) SaveX(ctx context.Context) *ApiKey {
} }
// Exec executes the query. // Exec executes the query.
func (_c *ApiKeyCreate) Exec(ctx context.Context) error { func (_c *APIKeyCreate) Exec(ctx context.Context) error {
_, err := _c.Save(ctx) _, err := _c.Save(ctx)
return err return err
} }
// ExecX is like Exec, but panics if an error occurs. // ExecX is like Exec, but panics if an error occurs.
func (_c *ApiKeyCreate) ExecX(ctx context.Context) { func (_c *APIKeyCreate) ExecX(ctx context.Context) {
if err := _c.Exec(ctx); err != nil { if err := _c.Exec(ctx); err != nil {
panic(err) panic(err)
} }
} }
// defaults sets the default values of the builder before save. // defaults sets the default values of the builder before save.
func (_c *ApiKeyCreate) defaults() error { func (_c *APIKeyCreate) defaults() error {
if _, ok := _c.mutation.CreatedAt(); !ok { if _, ok := _c.mutation.CreatedAt(); !ok {
if apikey.DefaultCreatedAt == nil { if apikey.DefaultCreatedAt == nil {
return fmt.Errorf("ent: uninitialized apikey.DefaultCreatedAt (forgotten import ent/runtime?)") return fmt.Errorf("ent: uninitialized apikey.DefaultCreatedAt (forgotten import ent/runtime?)")
@@ -197,47 +197,47 @@ func (_c *ApiKeyCreate) defaults() error {
} }
// check runs all checks and user-defined validators on the builder. // check runs all checks and user-defined validators on the builder.
func (_c *ApiKeyCreate) check() error { func (_c *APIKeyCreate) check() error {
if _, ok := _c.mutation.CreatedAt(); !ok { if _, ok := _c.mutation.CreatedAt(); !ok {
return &ValidationError{Name: "created_at", err: errors.New(`ent: missing required field "ApiKey.created_at"`)} return &ValidationError{Name: "created_at", err: errors.New(`ent: missing required field "APIKey.created_at"`)}
} }
if _, ok := _c.mutation.UpdatedAt(); !ok { if _, ok := _c.mutation.UpdatedAt(); !ok {
return &ValidationError{Name: "updated_at", err: errors.New(`ent: missing required field "ApiKey.updated_at"`)} return &ValidationError{Name: "updated_at", err: errors.New(`ent: missing required field "APIKey.updated_at"`)}
} }
if _, ok := _c.mutation.UserID(); !ok { if _, ok := _c.mutation.UserID(); !ok {
return &ValidationError{Name: "user_id", err: errors.New(`ent: missing required field "ApiKey.user_id"`)} return &ValidationError{Name: "user_id", err: errors.New(`ent: missing required field "APIKey.user_id"`)}
} }
if _, ok := _c.mutation.Key(); !ok { if _, ok := _c.mutation.Key(); !ok {
return &ValidationError{Name: "key", err: errors.New(`ent: missing required field "ApiKey.key"`)} return &ValidationError{Name: "key", err: errors.New(`ent: missing required field "APIKey.key"`)}
} }
if v, ok := _c.mutation.Key(); ok { if v, ok := _c.mutation.Key(); ok {
if err := apikey.KeyValidator(v); err != nil { if err := apikey.KeyValidator(v); err != nil {
return &ValidationError{Name: "key", err: fmt.Errorf(`ent: validator failed for field "ApiKey.key": %w`, err)} return &ValidationError{Name: "key", err: fmt.Errorf(`ent: validator failed for field "APIKey.key": %w`, err)}
} }
} }
if _, ok := _c.mutation.Name(); !ok { if _, ok := _c.mutation.Name(); !ok {
return &ValidationError{Name: "name", err: errors.New(`ent: missing required field "ApiKey.name"`)} return &ValidationError{Name: "name", err: errors.New(`ent: missing required field "APIKey.name"`)}
} }
if v, ok := _c.mutation.Name(); ok { if v, ok := _c.mutation.Name(); ok {
if err := apikey.NameValidator(v); err != nil { if err := apikey.NameValidator(v); err != nil {
return &ValidationError{Name: "name", err: fmt.Errorf(`ent: validator failed for field "ApiKey.name": %w`, err)} return &ValidationError{Name: "name", err: fmt.Errorf(`ent: validator failed for field "APIKey.name": %w`, err)}
} }
} }
if _, ok := _c.mutation.Status(); !ok { if _, ok := _c.mutation.Status(); !ok {
return &ValidationError{Name: "status", err: errors.New(`ent: missing required field "ApiKey.status"`)} return &ValidationError{Name: "status", err: errors.New(`ent: missing required field "APIKey.status"`)}
} }
if v, ok := _c.mutation.Status(); ok { if v, ok := _c.mutation.Status(); ok {
if err := apikey.StatusValidator(v); err != nil { if err := apikey.StatusValidator(v); err != nil {
return &ValidationError{Name: "status", err: fmt.Errorf(`ent: validator failed for field "ApiKey.status": %w`, err)} return &ValidationError{Name: "status", err: fmt.Errorf(`ent: validator failed for field "APIKey.status": %w`, err)}
} }
} }
if len(_c.mutation.UserIDs()) == 0 { if len(_c.mutation.UserIDs()) == 0 {
return &ValidationError{Name: "user", err: errors.New(`ent: missing required edge "ApiKey.user"`)} return &ValidationError{Name: "user", err: errors.New(`ent: missing required edge "APIKey.user"`)}
} }
return nil return nil
} }
func (_c *ApiKeyCreate) sqlSave(ctx context.Context) (*ApiKey, error) { func (_c *APIKeyCreate) sqlSave(ctx context.Context) (*APIKey, error) {
if err := _c.check(); err != nil { if err := _c.check(); err != nil {
return nil, err return nil, err
} }
@@ -255,9 +255,9 @@ func (_c *ApiKeyCreate) sqlSave(ctx context.Context) (*ApiKey, error) {
return _node, nil return _node, nil
} }
func (_c *ApiKeyCreate) createSpec() (*ApiKey, *sqlgraph.CreateSpec) { func (_c *APIKeyCreate) createSpec() (*APIKey, *sqlgraph.CreateSpec) {
var ( var (
_node = &ApiKey{config: _c.config} _node = &APIKey{config: _c.config}
_spec = sqlgraph.NewCreateSpec(apikey.Table, sqlgraph.NewFieldSpec(apikey.FieldID, field.TypeInt64)) _spec = sqlgraph.NewCreateSpec(apikey.Table, sqlgraph.NewFieldSpec(apikey.FieldID, field.TypeInt64))
) )
_spec.OnConflict = _c.conflict _spec.OnConflict = _c.conflict
@@ -341,7 +341,7 @@ func (_c *ApiKeyCreate) createSpec() (*ApiKey, *sqlgraph.CreateSpec) {
// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause // OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause
// of the `INSERT` statement. For example: // of the `INSERT` statement. For example:
// //
// client.ApiKey.Create(). // client.APIKey.Create().
// SetCreatedAt(v). // SetCreatedAt(v).
// OnConflict( // OnConflict(
// // Update the row with the new values // // Update the row with the new values
@@ -350,13 +350,13 @@ func (_c *ApiKeyCreate) createSpec() (*ApiKey, *sqlgraph.CreateSpec) {
// ). // ).
// // Override some of the fields with custom // // Override some of the fields with custom
// // update values. // // update values.
// Update(func(u *ent.ApiKeyUpsert) { // Update(func(u *ent.APIKeyUpsert) {
// SetCreatedAt(v+v). // SetCreatedAt(v+v).
// }). // }).
// Exec(ctx) // Exec(ctx)
func (_c *ApiKeyCreate) OnConflict(opts ...sql.ConflictOption) *ApiKeyUpsertOne { func (_c *APIKeyCreate) OnConflict(opts ...sql.ConflictOption) *APIKeyUpsertOne {
_c.conflict = opts _c.conflict = opts
return &ApiKeyUpsertOne{ return &APIKeyUpsertOne{
create: _c, create: _c,
} }
} }
@@ -364,121 +364,121 @@ func (_c *ApiKeyCreate) OnConflict(opts ...sql.ConflictOption) *ApiKeyUpsertOne
// OnConflictColumns calls `OnConflict` and configures the columns // OnConflictColumns calls `OnConflict` and configures the columns
// as conflict target. Using this option is equivalent to using: // as conflict target. Using this option is equivalent to using:
// //
// client.ApiKey.Create(). // client.APIKey.Create().
// OnConflict(sql.ConflictColumns(columns...)). // OnConflict(sql.ConflictColumns(columns...)).
// Exec(ctx) // Exec(ctx)
func (_c *ApiKeyCreate) OnConflictColumns(columns ...string) *ApiKeyUpsertOne { func (_c *APIKeyCreate) OnConflictColumns(columns ...string) *APIKeyUpsertOne {
_c.conflict = append(_c.conflict, sql.ConflictColumns(columns...)) _c.conflict = append(_c.conflict, sql.ConflictColumns(columns...))
return &ApiKeyUpsertOne{ return &APIKeyUpsertOne{
create: _c, create: _c,
} }
} }
type ( type (
// ApiKeyUpsertOne is the builder for "upsert"-ing // APIKeyUpsertOne is the builder for "upsert"-ing
// one ApiKey node. // one APIKey node.
ApiKeyUpsertOne struct { APIKeyUpsertOne struct {
create *ApiKeyCreate create *APIKeyCreate
} }
// ApiKeyUpsert is the "OnConflict" setter. // APIKeyUpsert is the "OnConflict" setter.
ApiKeyUpsert struct { APIKeyUpsert struct {
*sql.UpdateSet *sql.UpdateSet
} }
) )
// SetUpdatedAt sets the "updated_at" field. // SetUpdatedAt sets the "updated_at" field.
func (u *ApiKeyUpsert) SetUpdatedAt(v time.Time) *ApiKeyUpsert { func (u *APIKeyUpsert) SetUpdatedAt(v time.Time) *APIKeyUpsert {
u.Set(apikey.FieldUpdatedAt, v) u.Set(apikey.FieldUpdatedAt, v)
return u return u
} }
// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create. // UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create.
func (u *ApiKeyUpsert) UpdateUpdatedAt() *ApiKeyUpsert { func (u *APIKeyUpsert) UpdateUpdatedAt() *APIKeyUpsert {
u.SetExcluded(apikey.FieldUpdatedAt) u.SetExcluded(apikey.FieldUpdatedAt)
return u return u
} }
// SetDeletedAt sets the "deleted_at" field. // SetDeletedAt sets the "deleted_at" field.
func (u *ApiKeyUpsert) SetDeletedAt(v time.Time) *ApiKeyUpsert { func (u *APIKeyUpsert) SetDeletedAt(v time.Time) *APIKeyUpsert {
u.Set(apikey.FieldDeletedAt, v) u.Set(apikey.FieldDeletedAt, v)
return u return u
} }
// UpdateDeletedAt sets the "deleted_at" field to the value that was provided on create. // UpdateDeletedAt sets the "deleted_at" field to the value that was provided on create.
func (u *ApiKeyUpsert) UpdateDeletedAt() *ApiKeyUpsert { func (u *APIKeyUpsert) UpdateDeletedAt() *APIKeyUpsert {
u.SetExcluded(apikey.FieldDeletedAt) u.SetExcluded(apikey.FieldDeletedAt)
return u return u
} }
// ClearDeletedAt clears the value of the "deleted_at" field. // ClearDeletedAt clears the value of the "deleted_at" field.
func (u *ApiKeyUpsert) ClearDeletedAt() *ApiKeyUpsert { func (u *APIKeyUpsert) ClearDeletedAt() *APIKeyUpsert {
u.SetNull(apikey.FieldDeletedAt) u.SetNull(apikey.FieldDeletedAt)
return u return u
} }
// SetUserID sets the "user_id" field. // SetUserID sets the "user_id" field.
func (u *ApiKeyUpsert) SetUserID(v int64) *ApiKeyUpsert { func (u *APIKeyUpsert) SetUserID(v int64) *APIKeyUpsert {
u.Set(apikey.FieldUserID, v) u.Set(apikey.FieldUserID, v)
return u return u
} }
// UpdateUserID sets the "user_id" field to the value that was provided on create. // UpdateUserID sets the "user_id" field to the value that was provided on create.
func (u *ApiKeyUpsert) UpdateUserID() *ApiKeyUpsert { func (u *APIKeyUpsert) UpdateUserID() *APIKeyUpsert {
u.SetExcluded(apikey.FieldUserID) u.SetExcluded(apikey.FieldUserID)
return u return u
} }
// SetKey sets the "key" field. // SetKey sets the "key" field.
func (u *ApiKeyUpsert) SetKey(v string) *ApiKeyUpsert { func (u *APIKeyUpsert) SetKey(v string) *APIKeyUpsert {
u.Set(apikey.FieldKey, v) u.Set(apikey.FieldKey, v)
return u return u
} }
// UpdateKey sets the "key" field to the value that was provided on create. // UpdateKey sets the "key" field to the value that was provided on create.
func (u *ApiKeyUpsert) UpdateKey() *ApiKeyUpsert { func (u *APIKeyUpsert) UpdateKey() *APIKeyUpsert {
u.SetExcluded(apikey.FieldKey) u.SetExcluded(apikey.FieldKey)
return u return u
} }
// SetName sets the "name" field. // SetName sets the "name" field.
func (u *ApiKeyUpsert) SetName(v string) *ApiKeyUpsert { func (u *APIKeyUpsert) SetName(v string) *APIKeyUpsert {
u.Set(apikey.FieldName, v) u.Set(apikey.FieldName, v)
return u return u
} }
// UpdateName sets the "name" field to the value that was provided on create. // UpdateName sets the "name" field to the value that was provided on create.
func (u *ApiKeyUpsert) UpdateName() *ApiKeyUpsert { func (u *APIKeyUpsert) UpdateName() *APIKeyUpsert {
u.SetExcluded(apikey.FieldName) u.SetExcluded(apikey.FieldName)
return u return u
} }
// SetGroupID sets the "group_id" field. // SetGroupID sets the "group_id" field.
func (u *ApiKeyUpsert) SetGroupID(v int64) *ApiKeyUpsert { func (u *APIKeyUpsert) SetGroupID(v int64) *APIKeyUpsert {
u.Set(apikey.FieldGroupID, v) u.Set(apikey.FieldGroupID, v)
return u return u
} }
// UpdateGroupID sets the "group_id" field to the value that was provided on create. // UpdateGroupID sets the "group_id" field to the value that was provided on create.
func (u *ApiKeyUpsert) UpdateGroupID() *ApiKeyUpsert { func (u *APIKeyUpsert) UpdateGroupID() *APIKeyUpsert {
u.SetExcluded(apikey.FieldGroupID) u.SetExcluded(apikey.FieldGroupID)
return u return u
} }
// ClearGroupID clears the value of the "group_id" field. // ClearGroupID clears the value of the "group_id" field.
func (u *ApiKeyUpsert) ClearGroupID() *ApiKeyUpsert { func (u *APIKeyUpsert) ClearGroupID() *APIKeyUpsert {
u.SetNull(apikey.FieldGroupID) u.SetNull(apikey.FieldGroupID)
return u return u
} }
// SetStatus sets the "status" field. // SetStatus sets the "status" field.
func (u *ApiKeyUpsert) SetStatus(v string) *ApiKeyUpsert { func (u *APIKeyUpsert) SetStatus(v string) *APIKeyUpsert {
u.Set(apikey.FieldStatus, v) u.Set(apikey.FieldStatus, v)
return u return u
} }
// UpdateStatus sets the "status" field to the value that was provided on create. // UpdateStatus sets the "status" field to the value that was provided on create.
func (u *ApiKeyUpsert) UpdateStatus() *ApiKeyUpsert { func (u *APIKeyUpsert) UpdateStatus() *APIKeyUpsert {
u.SetExcluded(apikey.FieldStatus) u.SetExcluded(apikey.FieldStatus)
return u return u
} }
@@ -486,12 +486,12 @@ func (u *ApiKeyUpsert) UpdateStatus() *ApiKeyUpsert {
// UpdateNewValues updates the mutable fields using the new values that were set on create. // UpdateNewValues updates the mutable fields using the new values that were set on create.
// Using this option is equivalent to using: // Using this option is equivalent to using:
// //
// client.ApiKey.Create(). // client.APIKey.Create().
// OnConflict( // OnConflict(
// sql.ResolveWithNewValues(), // sql.ResolveWithNewValues(),
// ). // ).
// Exec(ctx) // Exec(ctx)
func (u *ApiKeyUpsertOne) UpdateNewValues() *ApiKeyUpsertOne { func (u *APIKeyUpsertOne) UpdateNewValues() *APIKeyUpsertOne {
u.create.conflict = append(u.create.conflict, sql.ResolveWithNewValues()) u.create.conflict = append(u.create.conflict, sql.ResolveWithNewValues())
u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(s *sql.UpdateSet) { u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(s *sql.UpdateSet) {
if _, exists := u.create.mutation.CreatedAt(); exists { if _, exists := u.create.mutation.CreatedAt(); exists {
@@ -504,159 +504,159 @@ func (u *ApiKeyUpsertOne) UpdateNewValues() *ApiKeyUpsertOne {
// Ignore sets each column to itself in case of conflict. // Ignore sets each column to itself in case of conflict.
// Using this option is equivalent to using: // Using this option is equivalent to using:
// //
// client.ApiKey.Create(). // client.APIKey.Create().
// OnConflict(sql.ResolveWithIgnore()). // OnConflict(sql.ResolveWithIgnore()).
// Exec(ctx) // Exec(ctx)
func (u *ApiKeyUpsertOne) Ignore() *ApiKeyUpsertOne { func (u *APIKeyUpsertOne) Ignore() *APIKeyUpsertOne {
u.create.conflict = append(u.create.conflict, sql.ResolveWithIgnore()) u.create.conflict = append(u.create.conflict, sql.ResolveWithIgnore())
return u return u
} }
// DoNothing configures the conflict_action to `DO NOTHING`. // DoNothing configures the conflict_action to `DO NOTHING`.
// Supported only by SQLite and PostgreSQL. // Supported only by SQLite and PostgreSQL.
func (u *ApiKeyUpsertOne) DoNothing() *ApiKeyUpsertOne { func (u *APIKeyUpsertOne) DoNothing() *APIKeyUpsertOne {
u.create.conflict = append(u.create.conflict, sql.DoNothing()) u.create.conflict = append(u.create.conflict, sql.DoNothing())
return u return u
} }
// Update allows overriding fields `UPDATE` values. See the ApiKeyCreate.OnConflict // Update allows overriding fields `UPDATE` values. See the APIKeyCreate.OnConflict
// documentation for more info. // documentation for more info.
func (u *ApiKeyUpsertOne) Update(set func(*ApiKeyUpsert)) *ApiKeyUpsertOne { func (u *APIKeyUpsertOne) Update(set func(*APIKeyUpsert)) *APIKeyUpsertOne {
u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) { u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) {
set(&ApiKeyUpsert{UpdateSet: update}) set(&APIKeyUpsert{UpdateSet: update})
})) }))
return u return u
} }
// SetUpdatedAt sets the "updated_at" field. // SetUpdatedAt sets the "updated_at" field.
func (u *ApiKeyUpsertOne) SetUpdatedAt(v time.Time) *ApiKeyUpsertOne { func (u *APIKeyUpsertOne) SetUpdatedAt(v time.Time) *APIKeyUpsertOne {
return u.Update(func(s *ApiKeyUpsert) { return u.Update(func(s *APIKeyUpsert) {
s.SetUpdatedAt(v) s.SetUpdatedAt(v)
}) })
} }
// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create. // UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create.
func (u *ApiKeyUpsertOne) UpdateUpdatedAt() *ApiKeyUpsertOne { func (u *APIKeyUpsertOne) UpdateUpdatedAt() *APIKeyUpsertOne {
return u.Update(func(s *ApiKeyUpsert) { return u.Update(func(s *APIKeyUpsert) {
s.UpdateUpdatedAt() s.UpdateUpdatedAt()
}) })
} }
// SetDeletedAt sets the "deleted_at" field. // SetDeletedAt sets the "deleted_at" field.
func (u *ApiKeyUpsertOne) SetDeletedAt(v time.Time) *ApiKeyUpsertOne { func (u *APIKeyUpsertOne) SetDeletedAt(v time.Time) *APIKeyUpsertOne {
return u.Update(func(s *ApiKeyUpsert) { return u.Update(func(s *APIKeyUpsert) {
s.SetDeletedAt(v) s.SetDeletedAt(v)
}) })
} }
// UpdateDeletedAt sets the "deleted_at" field to the value that was provided on create. // UpdateDeletedAt sets the "deleted_at" field to the value that was provided on create.
func (u *ApiKeyUpsertOne) UpdateDeletedAt() *ApiKeyUpsertOne { func (u *APIKeyUpsertOne) UpdateDeletedAt() *APIKeyUpsertOne {
return u.Update(func(s *ApiKeyUpsert) { return u.Update(func(s *APIKeyUpsert) {
s.UpdateDeletedAt() s.UpdateDeletedAt()
}) })
} }
// ClearDeletedAt clears the value of the "deleted_at" field. // ClearDeletedAt clears the value of the "deleted_at" field.
func (u *ApiKeyUpsertOne) ClearDeletedAt() *ApiKeyUpsertOne { func (u *APIKeyUpsertOne) ClearDeletedAt() *APIKeyUpsertOne {
return u.Update(func(s *ApiKeyUpsert) { return u.Update(func(s *APIKeyUpsert) {
s.ClearDeletedAt() s.ClearDeletedAt()
}) })
} }
// SetUserID sets the "user_id" field. // SetUserID sets the "user_id" field.
func (u *ApiKeyUpsertOne) SetUserID(v int64) *ApiKeyUpsertOne { func (u *APIKeyUpsertOne) SetUserID(v int64) *APIKeyUpsertOne {
return u.Update(func(s *ApiKeyUpsert) { return u.Update(func(s *APIKeyUpsert) {
s.SetUserID(v) s.SetUserID(v)
}) })
} }
// UpdateUserID sets the "user_id" field to the value that was provided on create. // UpdateUserID sets the "user_id" field to the value that was provided on create.
func (u *ApiKeyUpsertOne) UpdateUserID() *ApiKeyUpsertOne { func (u *APIKeyUpsertOne) UpdateUserID() *APIKeyUpsertOne {
return u.Update(func(s *ApiKeyUpsert) { return u.Update(func(s *APIKeyUpsert) {
s.UpdateUserID() s.UpdateUserID()
}) })
} }
// SetKey sets the "key" field. // SetKey sets the "key" field.
func (u *ApiKeyUpsertOne) SetKey(v string) *ApiKeyUpsertOne { func (u *APIKeyUpsertOne) SetKey(v string) *APIKeyUpsertOne {
return u.Update(func(s *ApiKeyUpsert) { return u.Update(func(s *APIKeyUpsert) {
s.SetKey(v) s.SetKey(v)
}) })
} }
// UpdateKey sets the "key" field to the value that was provided on create. // UpdateKey sets the "key" field to the value that was provided on create.
func (u *ApiKeyUpsertOne) UpdateKey() *ApiKeyUpsertOne { func (u *APIKeyUpsertOne) UpdateKey() *APIKeyUpsertOne {
return u.Update(func(s *ApiKeyUpsert) { return u.Update(func(s *APIKeyUpsert) {
s.UpdateKey() s.UpdateKey()
}) })
} }
// SetName sets the "name" field. // SetName sets the "name" field.
func (u *ApiKeyUpsertOne) SetName(v string) *ApiKeyUpsertOne { func (u *APIKeyUpsertOne) SetName(v string) *APIKeyUpsertOne {
return u.Update(func(s *ApiKeyUpsert) { return u.Update(func(s *APIKeyUpsert) {
s.SetName(v) s.SetName(v)
}) })
} }
// UpdateName sets the "name" field to the value that was provided on create. // UpdateName sets the "name" field to the value that was provided on create.
func (u *ApiKeyUpsertOne) UpdateName() *ApiKeyUpsertOne { func (u *APIKeyUpsertOne) UpdateName() *APIKeyUpsertOne {
return u.Update(func(s *ApiKeyUpsert) { return u.Update(func(s *APIKeyUpsert) {
s.UpdateName() s.UpdateName()
}) })
} }
// SetGroupID sets the "group_id" field. // SetGroupID sets the "group_id" field.
func (u *ApiKeyUpsertOne) SetGroupID(v int64) *ApiKeyUpsertOne { func (u *APIKeyUpsertOne) SetGroupID(v int64) *APIKeyUpsertOne {
return u.Update(func(s *ApiKeyUpsert) { return u.Update(func(s *APIKeyUpsert) {
s.SetGroupID(v) s.SetGroupID(v)
}) })
} }
// UpdateGroupID sets the "group_id" field to the value that was provided on create. // UpdateGroupID sets the "group_id" field to the value that was provided on create.
func (u *ApiKeyUpsertOne) UpdateGroupID() *ApiKeyUpsertOne { func (u *APIKeyUpsertOne) UpdateGroupID() *APIKeyUpsertOne {
return u.Update(func(s *ApiKeyUpsert) { return u.Update(func(s *APIKeyUpsert) {
s.UpdateGroupID() s.UpdateGroupID()
}) })
} }
// ClearGroupID clears the value of the "group_id" field. // ClearGroupID clears the value of the "group_id" field.
func (u *ApiKeyUpsertOne) ClearGroupID() *ApiKeyUpsertOne { func (u *APIKeyUpsertOne) ClearGroupID() *APIKeyUpsertOne {
return u.Update(func(s *ApiKeyUpsert) { return u.Update(func(s *APIKeyUpsert) {
s.ClearGroupID() s.ClearGroupID()
}) })
} }
// SetStatus sets the "status" field. // SetStatus sets the "status" field.
func (u *ApiKeyUpsertOne) SetStatus(v string) *ApiKeyUpsertOne { func (u *APIKeyUpsertOne) SetStatus(v string) *APIKeyUpsertOne {
return u.Update(func(s *ApiKeyUpsert) { return u.Update(func(s *APIKeyUpsert) {
s.SetStatus(v) s.SetStatus(v)
}) })
} }
// UpdateStatus sets the "status" field to the value that was provided on create. // UpdateStatus sets the "status" field to the value that was provided on create.
func (u *ApiKeyUpsertOne) UpdateStatus() *ApiKeyUpsertOne { func (u *APIKeyUpsertOne) UpdateStatus() *APIKeyUpsertOne {
return u.Update(func(s *ApiKeyUpsert) { return u.Update(func(s *APIKeyUpsert) {
s.UpdateStatus() s.UpdateStatus()
}) })
} }
// Exec executes the query. // Exec executes the query.
func (u *ApiKeyUpsertOne) Exec(ctx context.Context) error { func (u *APIKeyUpsertOne) Exec(ctx context.Context) error {
if len(u.create.conflict) == 0 { if len(u.create.conflict) == 0 {
return errors.New("ent: missing options for ApiKeyCreate.OnConflict") return errors.New("ent: missing options for APIKeyCreate.OnConflict")
} }
return u.create.Exec(ctx) return u.create.Exec(ctx)
} }
// ExecX is like Exec, but panics if an error occurs. // ExecX is like Exec, but panics if an error occurs.
func (u *ApiKeyUpsertOne) ExecX(ctx context.Context) { func (u *APIKeyUpsertOne) ExecX(ctx context.Context) {
if err := u.create.Exec(ctx); err != nil { if err := u.create.Exec(ctx); err != nil {
panic(err) panic(err)
} }
} }
// Exec executes the UPSERT query and returns the inserted/updated ID. // Exec executes the UPSERT query and returns the inserted/updated ID.
func (u *ApiKeyUpsertOne) ID(ctx context.Context) (id int64, err error) { func (u *APIKeyUpsertOne) ID(ctx context.Context) (id int64, err error) {
node, err := u.create.Save(ctx) node, err := u.create.Save(ctx)
if err != nil { if err != nil {
return id, err return id, err
@@ -665,7 +665,7 @@ func (u *ApiKeyUpsertOne) ID(ctx context.Context) (id int64, err error) {
} }
// IDX is like ID, but panics if an error occurs. // IDX is like ID, but panics if an error occurs.
func (u *ApiKeyUpsertOne) IDX(ctx context.Context) int64 { func (u *APIKeyUpsertOne) IDX(ctx context.Context) int64 {
id, err := u.ID(ctx) id, err := u.ID(ctx)
if err != nil { if err != nil {
panic(err) panic(err)
@@ -673,28 +673,28 @@ func (u *ApiKeyUpsertOne) IDX(ctx context.Context) int64 {
return id return id
} }
// ApiKeyCreateBulk is the builder for creating many ApiKey entities in bulk. // APIKeyCreateBulk is the builder for creating many APIKey entities in bulk.
type ApiKeyCreateBulk struct { type APIKeyCreateBulk struct {
config config
err error err error
builders []*ApiKeyCreate builders []*APIKeyCreate
conflict []sql.ConflictOption conflict []sql.ConflictOption
} }
// Save creates the ApiKey entities in the database. // Save creates the APIKey entities in the database.
func (_c *ApiKeyCreateBulk) Save(ctx context.Context) ([]*ApiKey, error) { func (_c *APIKeyCreateBulk) Save(ctx context.Context) ([]*APIKey, error) {
if _c.err != nil { if _c.err != nil {
return nil, _c.err return nil, _c.err
} }
specs := make([]*sqlgraph.CreateSpec, len(_c.builders)) specs := make([]*sqlgraph.CreateSpec, len(_c.builders))
nodes := make([]*ApiKey, len(_c.builders)) nodes := make([]*APIKey, len(_c.builders))
mutators := make([]Mutator, len(_c.builders)) mutators := make([]Mutator, len(_c.builders))
for i := range _c.builders { for i := range _c.builders {
func(i int, root context.Context) { func(i int, root context.Context) {
builder := _c.builders[i] builder := _c.builders[i]
builder.defaults() builder.defaults()
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) { var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
mutation, ok := m.(*ApiKeyMutation) mutation, ok := m.(*APIKeyMutation)
if !ok { if !ok {
return nil, fmt.Errorf("unexpected mutation type %T", m) return nil, fmt.Errorf("unexpected mutation type %T", m)
} }
@@ -742,7 +742,7 @@ func (_c *ApiKeyCreateBulk) Save(ctx context.Context) ([]*ApiKey, error) {
} }
// SaveX is like Save, but panics if an error occurs. // SaveX is like Save, but panics if an error occurs.
func (_c *ApiKeyCreateBulk) SaveX(ctx context.Context) []*ApiKey { func (_c *APIKeyCreateBulk) SaveX(ctx context.Context) []*APIKey {
v, err := _c.Save(ctx) v, err := _c.Save(ctx)
if err != nil { if err != nil {
panic(err) panic(err)
@@ -751,13 +751,13 @@ func (_c *ApiKeyCreateBulk) SaveX(ctx context.Context) []*ApiKey {
} }
// Exec executes the query. // Exec executes the query.
func (_c *ApiKeyCreateBulk) Exec(ctx context.Context) error { func (_c *APIKeyCreateBulk) Exec(ctx context.Context) error {
_, err := _c.Save(ctx) _, err := _c.Save(ctx)
return err return err
} }
// ExecX is like Exec, but panics if an error occurs. // ExecX is like Exec, but panics if an error occurs.
func (_c *ApiKeyCreateBulk) ExecX(ctx context.Context) { func (_c *APIKeyCreateBulk) ExecX(ctx context.Context) {
if err := _c.Exec(ctx); err != nil { if err := _c.Exec(ctx); err != nil {
panic(err) panic(err)
} }
@@ -766,7 +766,7 @@ func (_c *ApiKeyCreateBulk) ExecX(ctx context.Context) {
// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause // OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause
// of the `INSERT` statement. For example: // of the `INSERT` statement. For example:
// //
// client.ApiKey.CreateBulk(builders...). // client.APIKey.CreateBulk(builders...).
// OnConflict( // OnConflict(
// // Update the row with the new values // // Update the row with the new values
// // the was proposed for insertion. // // the was proposed for insertion.
@@ -774,13 +774,13 @@ func (_c *ApiKeyCreateBulk) ExecX(ctx context.Context) {
// ). // ).
// // Override some of the fields with custom // // Override some of the fields with custom
// // update values. // // update values.
// Update(func(u *ent.ApiKeyUpsert) { // Update(func(u *ent.APIKeyUpsert) {
// SetCreatedAt(v+v). // SetCreatedAt(v+v).
// }). // }).
// Exec(ctx) // Exec(ctx)
func (_c *ApiKeyCreateBulk) OnConflict(opts ...sql.ConflictOption) *ApiKeyUpsertBulk { func (_c *APIKeyCreateBulk) OnConflict(opts ...sql.ConflictOption) *APIKeyUpsertBulk {
_c.conflict = opts _c.conflict = opts
return &ApiKeyUpsertBulk{ return &APIKeyUpsertBulk{
create: _c, create: _c,
} }
} }
@@ -788,31 +788,31 @@ func (_c *ApiKeyCreateBulk) OnConflict(opts ...sql.ConflictOption) *ApiKeyUpsert
// OnConflictColumns calls `OnConflict` and configures the columns // OnConflictColumns calls `OnConflict` and configures the columns
// as conflict target. Using this option is equivalent to using: // as conflict target. Using this option is equivalent to using:
// //
// client.ApiKey.Create(). // client.APIKey.Create().
// OnConflict(sql.ConflictColumns(columns...)). // OnConflict(sql.ConflictColumns(columns...)).
// Exec(ctx) // Exec(ctx)
func (_c *ApiKeyCreateBulk) OnConflictColumns(columns ...string) *ApiKeyUpsertBulk { func (_c *APIKeyCreateBulk) OnConflictColumns(columns ...string) *APIKeyUpsertBulk {
_c.conflict = append(_c.conflict, sql.ConflictColumns(columns...)) _c.conflict = append(_c.conflict, sql.ConflictColumns(columns...))
return &ApiKeyUpsertBulk{ return &APIKeyUpsertBulk{
create: _c, create: _c,
} }
} }
// ApiKeyUpsertBulk is the builder for "upsert"-ing // APIKeyUpsertBulk is the builder for "upsert"-ing
// a bulk of ApiKey nodes. // a bulk of APIKey nodes.
type ApiKeyUpsertBulk struct { type APIKeyUpsertBulk struct {
create *ApiKeyCreateBulk create *APIKeyCreateBulk
} }
// UpdateNewValues updates the mutable fields using the new values that // UpdateNewValues updates the mutable fields using the new values that
// were set on create. Using this option is equivalent to using: // were set on create. Using this option is equivalent to using:
// //
// client.ApiKey.Create(). // client.APIKey.Create().
// OnConflict( // OnConflict(
// sql.ResolveWithNewValues(), // sql.ResolveWithNewValues(),
// ). // ).
// Exec(ctx) // Exec(ctx)
func (u *ApiKeyUpsertBulk) UpdateNewValues() *ApiKeyUpsertBulk { func (u *APIKeyUpsertBulk) UpdateNewValues() *APIKeyUpsertBulk {
u.create.conflict = append(u.create.conflict, sql.ResolveWithNewValues()) u.create.conflict = append(u.create.conflict, sql.ResolveWithNewValues())
u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(s *sql.UpdateSet) { u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(s *sql.UpdateSet) {
for _, b := range u.create.builders { for _, b := range u.create.builders {
@@ -827,160 +827,160 @@ func (u *ApiKeyUpsertBulk) UpdateNewValues() *ApiKeyUpsertBulk {
// Ignore sets each column to itself in case of conflict. // Ignore sets each column to itself in case of conflict.
// Using this option is equivalent to using: // Using this option is equivalent to using:
// //
// client.ApiKey.Create(). // client.APIKey.Create().
// OnConflict(sql.ResolveWithIgnore()). // OnConflict(sql.ResolveWithIgnore()).
// Exec(ctx) // Exec(ctx)
func (u *ApiKeyUpsertBulk) Ignore() *ApiKeyUpsertBulk { func (u *APIKeyUpsertBulk) Ignore() *APIKeyUpsertBulk {
u.create.conflict = append(u.create.conflict, sql.ResolveWithIgnore()) u.create.conflict = append(u.create.conflict, sql.ResolveWithIgnore())
return u return u
} }
// DoNothing configures the conflict_action to `DO NOTHING`. // DoNothing configures the conflict_action to `DO NOTHING`.
// Supported only by SQLite and PostgreSQL. // Supported only by SQLite and PostgreSQL.
func (u *ApiKeyUpsertBulk) DoNothing() *ApiKeyUpsertBulk { func (u *APIKeyUpsertBulk) DoNothing() *APIKeyUpsertBulk {
u.create.conflict = append(u.create.conflict, sql.DoNothing()) u.create.conflict = append(u.create.conflict, sql.DoNothing())
return u return u
} }
// Update allows overriding fields `UPDATE` values. See the ApiKeyCreateBulk.OnConflict // Update allows overriding fields `UPDATE` values. See the APIKeyCreateBulk.OnConflict
// documentation for more info. // documentation for more info.
func (u *ApiKeyUpsertBulk) Update(set func(*ApiKeyUpsert)) *ApiKeyUpsertBulk { func (u *APIKeyUpsertBulk) Update(set func(*APIKeyUpsert)) *APIKeyUpsertBulk {
u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) { u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) {
set(&ApiKeyUpsert{UpdateSet: update}) set(&APIKeyUpsert{UpdateSet: update})
})) }))
return u return u
} }
// SetUpdatedAt sets the "updated_at" field. // SetUpdatedAt sets the "updated_at" field.
func (u *ApiKeyUpsertBulk) SetUpdatedAt(v time.Time) *ApiKeyUpsertBulk { func (u *APIKeyUpsertBulk) SetUpdatedAt(v time.Time) *APIKeyUpsertBulk {
return u.Update(func(s *ApiKeyUpsert) { return u.Update(func(s *APIKeyUpsert) {
s.SetUpdatedAt(v) s.SetUpdatedAt(v)
}) })
} }
// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create. // UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create.
func (u *ApiKeyUpsertBulk) UpdateUpdatedAt() *ApiKeyUpsertBulk { func (u *APIKeyUpsertBulk) UpdateUpdatedAt() *APIKeyUpsertBulk {
return u.Update(func(s *ApiKeyUpsert) { return u.Update(func(s *APIKeyUpsert) {
s.UpdateUpdatedAt() s.UpdateUpdatedAt()
}) })
} }
// SetDeletedAt sets the "deleted_at" field. // SetDeletedAt sets the "deleted_at" field.
func (u *ApiKeyUpsertBulk) SetDeletedAt(v time.Time) *ApiKeyUpsertBulk { func (u *APIKeyUpsertBulk) SetDeletedAt(v time.Time) *APIKeyUpsertBulk {
return u.Update(func(s *ApiKeyUpsert) { return u.Update(func(s *APIKeyUpsert) {
s.SetDeletedAt(v) s.SetDeletedAt(v)
}) })
} }
// UpdateDeletedAt sets the "deleted_at" field to the value that was provided on create. // UpdateDeletedAt sets the "deleted_at" field to the value that was provided on create.
func (u *ApiKeyUpsertBulk) UpdateDeletedAt() *ApiKeyUpsertBulk { func (u *APIKeyUpsertBulk) UpdateDeletedAt() *APIKeyUpsertBulk {
return u.Update(func(s *ApiKeyUpsert) { return u.Update(func(s *APIKeyUpsert) {
s.UpdateDeletedAt() s.UpdateDeletedAt()
}) })
} }
// ClearDeletedAt clears the value of the "deleted_at" field. // ClearDeletedAt clears the value of the "deleted_at" field.
func (u *ApiKeyUpsertBulk) ClearDeletedAt() *ApiKeyUpsertBulk { func (u *APIKeyUpsertBulk) ClearDeletedAt() *APIKeyUpsertBulk {
return u.Update(func(s *ApiKeyUpsert) { return u.Update(func(s *APIKeyUpsert) {
s.ClearDeletedAt() s.ClearDeletedAt()
}) })
} }
// SetUserID sets the "user_id" field. // SetUserID sets the "user_id" field.
func (u *ApiKeyUpsertBulk) SetUserID(v int64) *ApiKeyUpsertBulk { func (u *APIKeyUpsertBulk) SetUserID(v int64) *APIKeyUpsertBulk {
return u.Update(func(s *ApiKeyUpsert) { return u.Update(func(s *APIKeyUpsert) {
s.SetUserID(v) s.SetUserID(v)
}) })
} }
// UpdateUserID sets the "user_id" field to the value that was provided on create. // UpdateUserID sets the "user_id" field to the value that was provided on create.
func (u *ApiKeyUpsertBulk) UpdateUserID() *ApiKeyUpsertBulk { func (u *APIKeyUpsertBulk) UpdateUserID() *APIKeyUpsertBulk {
return u.Update(func(s *ApiKeyUpsert) { return u.Update(func(s *APIKeyUpsert) {
s.UpdateUserID() s.UpdateUserID()
}) })
} }
// SetKey sets the "key" field. // SetKey sets the "key" field.
func (u *ApiKeyUpsertBulk) SetKey(v string) *ApiKeyUpsertBulk { func (u *APIKeyUpsertBulk) SetKey(v string) *APIKeyUpsertBulk {
return u.Update(func(s *ApiKeyUpsert) { return u.Update(func(s *APIKeyUpsert) {
s.SetKey(v) s.SetKey(v)
}) })
} }
// UpdateKey sets the "key" field to the value that was provided on create. // UpdateKey sets the "key" field to the value that was provided on create.
func (u *ApiKeyUpsertBulk) UpdateKey() *ApiKeyUpsertBulk { func (u *APIKeyUpsertBulk) UpdateKey() *APIKeyUpsertBulk {
return u.Update(func(s *ApiKeyUpsert) { return u.Update(func(s *APIKeyUpsert) {
s.UpdateKey() s.UpdateKey()
}) })
} }
// SetName sets the "name" field. // SetName sets the "name" field.
func (u *ApiKeyUpsertBulk) SetName(v string) *ApiKeyUpsertBulk { func (u *APIKeyUpsertBulk) SetName(v string) *APIKeyUpsertBulk {
return u.Update(func(s *ApiKeyUpsert) { return u.Update(func(s *APIKeyUpsert) {
s.SetName(v) s.SetName(v)
}) })
} }
// UpdateName sets the "name" field to the value that was provided on create. // UpdateName sets the "name" field to the value that was provided on create.
func (u *ApiKeyUpsertBulk) UpdateName() *ApiKeyUpsertBulk { func (u *APIKeyUpsertBulk) UpdateName() *APIKeyUpsertBulk {
return u.Update(func(s *ApiKeyUpsert) { return u.Update(func(s *APIKeyUpsert) {
s.UpdateName() s.UpdateName()
}) })
} }
// SetGroupID sets the "group_id" field. // SetGroupID sets the "group_id" field.
func (u *ApiKeyUpsertBulk) SetGroupID(v int64) *ApiKeyUpsertBulk { func (u *APIKeyUpsertBulk) SetGroupID(v int64) *APIKeyUpsertBulk {
return u.Update(func(s *ApiKeyUpsert) { return u.Update(func(s *APIKeyUpsert) {
s.SetGroupID(v) s.SetGroupID(v)
}) })
} }
// UpdateGroupID sets the "group_id" field to the value that was provided on create. // UpdateGroupID sets the "group_id" field to the value that was provided on create.
func (u *ApiKeyUpsertBulk) UpdateGroupID() *ApiKeyUpsertBulk { func (u *APIKeyUpsertBulk) UpdateGroupID() *APIKeyUpsertBulk {
return u.Update(func(s *ApiKeyUpsert) { return u.Update(func(s *APIKeyUpsert) {
s.UpdateGroupID() s.UpdateGroupID()
}) })
} }
// ClearGroupID clears the value of the "group_id" field. // ClearGroupID clears the value of the "group_id" field.
func (u *ApiKeyUpsertBulk) ClearGroupID() *ApiKeyUpsertBulk { func (u *APIKeyUpsertBulk) ClearGroupID() *APIKeyUpsertBulk {
return u.Update(func(s *ApiKeyUpsert) { return u.Update(func(s *APIKeyUpsert) {
s.ClearGroupID() s.ClearGroupID()
}) })
} }
// SetStatus sets the "status" field. // SetStatus sets the "status" field.
func (u *ApiKeyUpsertBulk) SetStatus(v string) *ApiKeyUpsertBulk { func (u *APIKeyUpsertBulk) SetStatus(v string) *APIKeyUpsertBulk {
return u.Update(func(s *ApiKeyUpsert) { return u.Update(func(s *APIKeyUpsert) {
s.SetStatus(v) s.SetStatus(v)
}) })
} }
// UpdateStatus sets the "status" field to the value that was provided on create. // UpdateStatus sets the "status" field to the value that was provided on create.
func (u *ApiKeyUpsertBulk) UpdateStatus() *ApiKeyUpsertBulk { func (u *APIKeyUpsertBulk) UpdateStatus() *APIKeyUpsertBulk {
return u.Update(func(s *ApiKeyUpsert) { return u.Update(func(s *APIKeyUpsert) {
s.UpdateStatus() s.UpdateStatus()
}) })
} }
// Exec executes the query. // Exec executes the query.
func (u *ApiKeyUpsertBulk) Exec(ctx context.Context) error { func (u *APIKeyUpsertBulk) Exec(ctx context.Context) error {
if u.create.err != nil { if u.create.err != nil {
return u.create.err return u.create.err
} }
for i, b := range u.create.builders { for i, b := range u.create.builders {
if len(b.conflict) != 0 { if len(b.conflict) != 0 {
return fmt.Errorf("ent: OnConflict was set for builder %d. Set it on the ApiKeyCreateBulk instead", i) return fmt.Errorf("ent: OnConflict was set for builder %d. Set it on the APIKeyCreateBulk instead", i)
} }
} }
if len(u.create.conflict) == 0 { if len(u.create.conflict) == 0 {
return errors.New("ent: missing options for ApiKeyCreateBulk.OnConflict") return errors.New("ent: missing options for APIKeyCreateBulk.OnConflict")
} }
return u.create.Exec(ctx) return u.create.Exec(ctx)
} }
// ExecX is like Exec, but panics if an error occurs. // ExecX is like Exec, but panics if an error occurs.
func (u *ApiKeyUpsertBulk) ExecX(ctx context.Context) { func (u *APIKeyUpsertBulk) ExecX(ctx context.Context) {
if err := u.create.Exec(ctx); err != nil { if err := u.create.Exec(ctx); err != nil {
panic(err) panic(err)
} }

View File

@@ -12,26 +12,26 @@ import (
"github.com/Wei-Shaw/sub2api/ent/predicate" "github.com/Wei-Shaw/sub2api/ent/predicate"
) )
// ApiKeyDelete is the builder for deleting a ApiKey entity. // APIKeyDelete is the builder for deleting a APIKey entity.
type ApiKeyDelete struct { type APIKeyDelete struct {
config config
hooks []Hook hooks []Hook
mutation *ApiKeyMutation mutation *APIKeyMutation
} }
// Where appends a list predicates to the ApiKeyDelete builder. // Where appends a list predicates to the APIKeyDelete builder.
func (_d *ApiKeyDelete) Where(ps ...predicate.ApiKey) *ApiKeyDelete { func (_d *APIKeyDelete) Where(ps ...predicate.APIKey) *APIKeyDelete {
_d.mutation.Where(ps...) _d.mutation.Where(ps...)
return _d return _d
} }
// Exec executes the deletion query and returns how many vertices were deleted. // Exec executes the deletion query and returns how many vertices were deleted.
func (_d *ApiKeyDelete) Exec(ctx context.Context) (int, error) { func (_d *APIKeyDelete) Exec(ctx context.Context) (int, error) {
return withHooks(ctx, _d.sqlExec, _d.mutation, _d.hooks) return withHooks(ctx, _d.sqlExec, _d.mutation, _d.hooks)
} }
// ExecX is like Exec, but panics if an error occurs. // ExecX is like Exec, but panics if an error occurs.
func (_d *ApiKeyDelete) ExecX(ctx context.Context) int { func (_d *APIKeyDelete) ExecX(ctx context.Context) int {
n, err := _d.Exec(ctx) n, err := _d.Exec(ctx)
if err != nil { if err != nil {
panic(err) panic(err)
@@ -39,7 +39,7 @@ func (_d *ApiKeyDelete) ExecX(ctx context.Context) int {
return n return n
} }
func (_d *ApiKeyDelete) sqlExec(ctx context.Context) (int, error) { func (_d *APIKeyDelete) sqlExec(ctx context.Context) (int, error) {
_spec := sqlgraph.NewDeleteSpec(apikey.Table, sqlgraph.NewFieldSpec(apikey.FieldID, field.TypeInt64)) _spec := sqlgraph.NewDeleteSpec(apikey.Table, sqlgraph.NewFieldSpec(apikey.FieldID, field.TypeInt64))
if ps := _d.mutation.predicates; len(ps) > 0 { if ps := _d.mutation.predicates; len(ps) > 0 {
_spec.Predicate = func(selector *sql.Selector) { _spec.Predicate = func(selector *sql.Selector) {
@@ -56,19 +56,19 @@ func (_d *ApiKeyDelete) sqlExec(ctx context.Context) (int, error) {
return affected, err return affected, err
} }
// ApiKeyDeleteOne is the builder for deleting a single ApiKey entity. // APIKeyDeleteOne is the builder for deleting a single APIKey entity.
type ApiKeyDeleteOne struct { type APIKeyDeleteOne struct {
_d *ApiKeyDelete _d *APIKeyDelete
} }
// Where appends a list predicates to the ApiKeyDelete builder. // Where appends a list predicates to the APIKeyDelete builder.
func (_d *ApiKeyDeleteOne) Where(ps ...predicate.ApiKey) *ApiKeyDeleteOne { func (_d *APIKeyDeleteOne) Where(ps ...predicate.APIKey) *APIKeyDeleteOne {
_d._d.mutation.Where(ps...) _d._d.mutation.Where(ps...)
return _d return _d
} }
// Exec executes the deletion query. // Exec executes the deletion query.
func (_d *ApiKeyDeleteOne) Exec(ctx context.Context) error { func (_d *APIKeyDeleteOne) Exec(ctx context.Context) error {
n, err := _d._d.Exec(ctx) n, err := _d._d.Exec(ctx)
switch { switch {
case err != nil: case err != nil:
@@ -81,7 +81,7 @@ func (_d *ApiKeyDeleteOne) Exec(ctx context.Context) error {
} }
// ExecX is like Exec, but panics if an error occurs. // ExecX is like Exec, but panics if an error occurs.
func (_d *ApiKeyDeleteOne) ExecX(ctx context.Context) { func (_d *APIKeyDeleteOne) ExecX(ctx context.Context) {
if err := _d.Exec(ctx); err != nil { if err := _d.Exec(ctx); err != nil {
panic(err) panic(err)
} }

View File

@@ -19,13 +19,13 @@ import (
"github.com/Wei-Shaw/sub2api/ent/user" "github.com/Wei-Shaw/sub2api/ent/user"
) )
// ApiKeyQuery is the builder for querying ApiKey entities. // APIKeyQuery is the builder for querying APIKey entities.
type ApiKeyQuery struct { type APIKeyQuery struct {
config config
ctx *QueryContext ctx *QueryContext
order []apikey.OrderOption order []apikey.OrderOption
inters []Interceptor inters []Interceptor
predicates []predicate.ApiKey predicates []predicate.APIKey
withUser *UserQuery withUser *UserQuery
withGroup *GroupQuery withGroup *GroupQuery
withUsageLogs *UsageLogQuery withUsageLogs *UsageLogQuery
@@ -34,39 +34,39 @@ type ApiKeyQuery struct {
path func(context.Context) (*sql.Selector, error) path func(context.Context) (*sql.Selector, error)
} }
// Where adds a new predicate for the ApiKeyQuery builder. // Where adds a new predicate for the APIKeyQuery builder.
func (_q *ApiKeyQuery) Where(ps ...predicate.ApiKey) *ApiKeyQuery { func (_q *APIKeyQuery) Where(ps ...predicate.APIKey) *APIKeyQuery {
_q.predicates = append(_q.predicates, ps...) _q.predicates = append(_q.predicates, ps...)
return _q return _q
} }
// Limit the number of records to be returned by this query. // Limit the number of records to be returned by this query.
func (_q *ApiKeyQuery) Limit(limit int) *ApiKeyQuery { func (_q *APIKeyQuery) Limit(limit int) *APIKeyQuery {
_q.ctx.Limit = &limit _q.ctx.Limit = &limit
return _q return _q
} }
// Offset to start from. // Offset to start from.
func (_q *ApiKeyQuery) Offset(offset int) *ApiKeyQuery { func (_q *APIKeyQuery) Offset(offset int) *APIKeyQuery {
_q.ctx.Offset = &offset _q.ctx.Offset = &offset
return _q return _q
} }
// Unique configures the query builder to filter duplicate records on query. // Unique configures the query builder to filter duplicate records on query.
// By default, unique is set to true, and can be disabled using this method. // By default, unique is set to true, and can be disabled using this method.
func (_q *ApiKeyQuery) Unique(unique bool) *ApiKeyQuery { func (_q *APIKeyQuery) Unique(unique bool) *APIKeyQuery {
_q.ctx.Unique = &unique _q.ctx.Unique = &unique
return _q return _q
} }
// Order specifies how the records should be ordered. // Order specifies how the records should be ordered.
func (_q *ApiKeyQuery) Order(o ...apikey.OrderOption) *ApiKeyQuery { func (_q *APIKeyQuery) Order(o ...apikey.OrderOption) *APIKeyQuery {
_q.order = append(_q.order, o...) _q.order = append(_q.order, o...)
return _q return _q
} }
// QueryUser chains the current query on the "user" edge. // QueryUser chains the current query on the "user" edge.
func (_q *ApiKeyQuery) QueryUser() *UserQuery { func (_q *APIKeyQuery) QueryUser() *UserQuery {
query := (&UserClient{config: _q.config}).Query() query := (&UserClient{config: _q.config}).Query()
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) { query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
if err := _q.prepareQuery(ctx); err != nil { if err := _q.prepareQuery(ctx); err != nil {
@@ -88,7 +88,7 @@ func (_q *ApiKeyQuery) QueryUser() *UserQuery {
} }
// QueryGroup chains the current query on the "group" edge. // QueryGroup chains the current query on the "group" edge.
func (_q *ApiKeyQuery) QueryGroup() *GroupQuery { func (_q *APIKeyQuery) QueryGroup() *GroupQuery {
query := (&GroupClient{config: _q.config}).Query() query := (&GroupClient{config: _q.config}).Query()
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) { query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
if err := _q.prepareQuery(ctx); err != nil { if err := _q.prepareQuery(ctx); err != nil {
@@ -110,7 +110,7 @@ func (_q *ApiKeyQuery) QueryGroup() *GroupQuery {
} }
// QueryUsageLogs chains the current query on the "usage_logs" edge. // QueryUsageLogs chains the current query on the "usage_logs" edge.
func (_q *ApiKeyQuery) QueryUsageLogs() *UsageLogQuery { func (_q *APIKeyQuery) QueryUsageLogs() *UsageLogQuery {
query := (&UsageLogClient{config: _q.config}).Query() query := (&UsageLogClient{config: _q.config}).Query()
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) { query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
if err := _q.prepareQuery(ctx); err != nil { if err := _q.prepareQuery(ctx); err != nil {
@@ -131,9 +131,9 @@ func (_q *ApiKeyQuery) QueryUsageLogs() *UsageLogQuery {
return query return query
} }
// First returns the first ApiKey entity from the query. // First returns the first APIKey entity from the query.
// Returns a *NotFoundError when no ApiKey was found. // Returns a *NotFoundError when no APIKey was found.
func (_q *ApiKeyQuery) First(ctx context.Context) (*ApiKey, error) { func (_q *APIKeyQuery) First(ctx context.Context) (*APIKey, error) {
nodes, err := _q.Limit(1).All(setContextOp(ctx, _q.ctx, ent.OpQueryFirst)) nodes, err := _q.Limit(1).All(setContextOp(ctx, _q.ctx, ent.OpQueryFirst))
if err != nil { if err != nil {
return nil, err return nil, err
@@ -145,7 +145,7 @@ func (_q *ApiKeyQuery) First(ctx context.Context) (*ApiKey, error) {
} }
// FirstX is like First, but panics if an error occurs. // FirstX is like First, but panics if an error occurs.
func (_q *ApiKeyQuery) FirstX(ctx context.Context) *ApiKey { func (_q *APIKeyQuery) FirstX(ctx context.Context) *APIKey {
node, err := _q.First(ctx) node, err := _q.First(ctx)
if err != nil && !IsNotFound(err) { if err != nil && !IsNotFound(err) {
panic(err) panic(err)
@@ -153,9 +153,9 @@ func (_q *ApiKeyQuery) FirstX(ctx context.Context) *ApiKey {
return node return node
} }
// FirstID returns the first ApiKey ID from the query. // FirstID returns the first APIKey ID from the query.
// Returns a *NotFoundError when no ApiKey ID was found. // Returns a *NotFoundError when no APIKey ID was found.
func (_q *ApiKeyQuery) FirstID(ctx context.Context) (id int64, err error) { func (_q *APIKeyQuery) FirstID(ctx context.Context) (id int64, err error) {
var ids []int64 var ids []int64
if ids, err = _q.Limit(1).IDs(setContextOp(ctx, _q.ctx, ent.OpQueryFirstID)); err != nil { if ids, err = _q.Limit(1).IDs(setContextOp(ctx, _q.ctx, ent.OpQueryFirstID)); err != nil {
return return
@@ -168,7 +168,7 @@ func (_q *ApiKeyQuery) FirstID(ctx context.Context) (id int64, err error) {
} }
// FirstIDX is like FirstID, but panics if an error occurs. // FirstIDX is like FirstID, but panics if an error occurs.
func (_q *ApiKeyQuery) FirstIDX(ctx context.Context) int64 { func (_q *APIKeyQuery) FirstIDX(ctx context.Context) int64 {
id, err := _q.FirstID(ctx) id, err := _q.FirstID(ctx)
if err != nil && !IsNotFound(err) { if err != nil && !IsNotFound(err) {
panic(err) panic(err)
@@ -176,10 +176,10 @@ func (_q *ApiKeyQuery) FirstIDX(ctx context.Context) int64 {
return id return id
} }
// Only returns a single ApiKey entity found by the query, ensuring it only returns one. // Only returns a single APIKey entity found by the query, ensuring it only returns one.
// Returns a *NotSingularError when more than one ApiKey entity is found. // Returns a *NotSingularError when more than one APIKey entity is found.
// Returns a *NotFoundError when no ApiKey entities are found. // Returns a *NotFoundError when no APIKey entities are found.
func (_q *ApiKeyQuery) Only(ctx context.Context) (*ApiKey, error) { func (_q *APIKeyQuery) Only(ctx context.Context) (*APIKey, error) {
nodes, err := _q.Limit(2).All(setContextOp(ctx, _q.ctx, ent.OpQueryOnly)) nodes, err := _q.Limit(2).All(setContextOp(ctx, _q.ctx, ent.OpQueryOnly))
if err != nil { if err != nil {
return nil, err return nil, err
@@ -195,7 +195,7 @@ func (_q *ApiKeyQuery) Only(ctx context.Context) (*ApiKey, error) {
} }
// OnlyX is like Only, but panics if an error occurs. // OnlyX is like Only, but panics if an error occurs.
func (_q *ApiKeyQuery) OnlyX(ctx context.Context) *ApiKey { func (_q *APIKeyQuery) OnlyX(ctx context.Context) *APIKey {
node, err := _q.Only(ctx) node, err := _q.Only(ctx)
if err != nil { if err != nil {
panic(err) panic(err)
@@ -203,10 +203,10 @@ func (_q *ApiKeyQuery) OnlyX(ctx context.Context) *ApiKey {
return node return node
} }
// OnlyID is like Only, but returns the only ApiKey ID in the query. // OnlyID is like Only, but returns the only APIKey ID in the query.
// Returns a *NotSingularError when more than one ApiKey ID is found. // Returns a *NotSingularError when more than one APIKey ID is found.
// Returns a *NotFoundError when no entities are found. // Returns a *NotFoundError when no entities are found.
func (_q *ApiKeyQuery) OnlyID(ctx context.Context) (id int64, err error) { func (_q *APIKeyQuery) OnlyID(ctx context.Context) (id int64, err error) {
var ids []int64 var ids []int64
if ids, err = _q.Limit(2).IDs(setContextOp(ctx, _q.ctx, ent.OpQueryOnlyID)); err != nil { if ids, err = _q.Limit(2).IDs(setContextOp(ctx, _q.ctx, ent.OpQueryOnlyID)); err != nil {
return return
@@ -223,7 +223,7 @@ func (_q *ApiKeyQuery) OnlyID(ctx context.Context) (id int64, err error) {
} }
// OnlyIDX is like OnlyID, but panics if an error occurs. // OnlyIDX is like OnlyID, but panics if an error occurs.
func (_q *ApiKeyQuery) OnlyIDX(ctx context.Context) int64 { func (_q *APIKeyQuery) OnlyIDX(ctx context.Context) int64 {
id, err := _q.OnlyID(ctx) id, err := _q.OnlyID(ctx)
if err != nil { if err != nil {
panic(err) panic(err)
@@ -231,18 +231,18 @@ func (_q *ApiKeyQuery) OnlyIDX(ctx context.Context) int64 {
return id return id
} }
// All executes the query and returns a list of ApiKeys. // All executes the query and returns a list of APIKeys.
func (_q *ApiKeyQuery) All(ctx context.Context) ([]*ApiKey, error) { func (_q *APIKeyQuery) All(ctx context.Context) ([]*APIKey, error) {
ctx = setContextOp(ctx, _q.ctx, ent.OpQueryAll) ctx = setContextOp(ctx, _q.ctx, ent.OpQueryAll)
if err := _q.prepareQuery(ctx); err != nil { if err := _q.prepareQuery(ctx); err != nil {
return nil, err return nil, err
} }
qr := querierAll[[]*ApiKey, *ApiKeyQuery]() qr := querierAll[[]*APIKey, *APIKeyQuery]()
return withInterceptors[[]*ApiKey](ctx, _q, qr, _q.inters) return withInterceptors[[]*APIKey](ctx, _q, qr, _q.inters)
} }
// AllX is like All, but panics if an error occurs. // AllX is like All, but panics if an error occurs.
func (_q *ApiKeyQuery) AllX(ctx context.Context) []*ApiKey { func (_q *APIKeyQuery) AllX(ctx context.Context) []*APIKey {
nodes, err := _q.All(ctx) nodes, err := _q.All(ctx)
if err != nil { if err != nil {
panic(err) panic(err)
@@ -250,8 +250,8 @@ func (_q *ApiKeyQuery) AllX(ctx context.Context) []*ApiKey {
return nodes return nodes
} }
// IDs executes the query and returns a list of ApiKey IDs. // IDs executes the query and returns a list of APIKey IDs.
func (_q *ApiKeyQuery) IDs(ctx context.Context) (ids []int64, err error) { func (_q *APIKeyQuery) IDs(ctx context.Context) (ids []int64, err error) {
if _q.ctx.Unique == nil && _q.path != nil { if _q.ctx.Unique == nil && _q.path != nil {
_q.Unique(true) _q.Unique(true)
} }
@@ -263,7 +263,7 @@ func (_q *ApiKeyQuery) IDs(ctx context.Context) (ids []int64, err error) {
} }
// IDsX is like IDs, but panics if an error occurs. // IDsX is like IDs, but panics if an error occurs.
func (_q *ApiKeyQuery) IDsX(ctx context.Context) []int64 { func (_q *APIKeyQuery) IDsX(ctx context.Context) []int64 {
ids, err := _q.IDs(ctx) ids, err := _q.IDs(ctx)
if err != nil { if err != nil {
panic(err) panic(err)
@@ -272,16 +272,16 @@ func (_q *ApiKeyQuery) IDsX(ctx context.Context) []int64 {
} }
// Count returns the count of the given query. // Count returns the count of the given query.
func (_q *ApiKeyQuery) Count(ctx context.Context) (int, error) { func (_q *APIKeyQuery) Count(ctx context.Context) (int, error) {
ctx = setContextOp(ctx, _q.ctx, ent.OpQueryCount) ctx = setContextOp(ctx, _q.ctx, ent.OpQueryCount)
if err := _q.prepareQuery(ctx); err != nil { if err := _q.prepareQuery(ctx); err != nil {
return 0, err return 0, err
} }
return withInterceptors[int](ctx, _q, querierCount[*ApiKeyQuery](), _q.inters) return withInterceptors[int](ctx, _q, querierCount[*APIKeyQuery](), _q.inters)
} }
// CountX is like Count, but panics if an error occurs. // CountX is like Count, but panics if an error occurs.
func (_q *ApiKeyQuery) CountX(ctx context.Context) int { func (_q *APIKeyQuery) CountX(ctx context.Context) int {
count, err := _q.Count(ctx) count, err := _q.Count(ctx)
if err != nil { if err != nil {
panic(err) panic(err)
@@ -290,7 +290,7 @@ func (_q *ApiKeyQuery) CountX(ctx context.Context) int {
} }
// Exist returns true if the query has elements in the graph. // Exist returns true if the query has elements in the graph.
func (_q *ApiKeyQuery) Exist(ctx context.Context) (bool, error) { func (_q *APIKeyQuery) Exist(ctx context.Context) (bool, error) {
ctx = setContextOp(ctx, _q.ctx, ent.OpQueryExist) ctx = setContextOp(ctx, _q.ctx, ent.OpQueryExist)
switch _, err := _q.FirstID(ctx); { switch _, err := _q.FirstID(ctx); {
case IsNotFound(err): case IsNotFound(err):
@@ -303,7 +303,7 @@ func (_q *ApiKeyQuery) Exist(ctx context.Context) (bool, error) {
} }
// ExistX is like Exist, but panics if an error occurs. // ExistX is like Exist, but panics if an error occurs.
func (_q *ApiKeyQuery) ExistX(ctx context.Context) bool { func (_q *APIKeyQuery) ExistX(ctx context.Context) bool {
exist, err := _q.Exist(ctx) exist, err := _q.Exist(ctx)
if err != nil { if err != nil {
panic(err) panic(err)
@@ -311,18 +311,18 @@ func (_q *ApiKeyQuery) ExistX(ctx context.Context) bool {
return exist return exist
} }
// Clone returns a duplicate of the ApiKeyQuery builder, including all associated steps. It can be // Clone returns a duplicate of the APIKeyQuery builder, including all associated steps. It can be
// used to prepare common query builders and use them differently after the clone is made. // used to prepare common query builders and use them differently after the clone is made.
func (_q *ApiKeyQuery) Clone() *ApiKeyQuery { func (_q *APIKeyQuery) Clone() *APIKeyQuery {
if _q == nil { if _q == nil {
return nil return nil
} }
return &ApiKeyQuery{ return &APIKeyQuery{
config: _q.config, config: _q.config,
ctx: _q.ctx.Clone(), ctx: _q.ctx.Clone(),
order: append([]apikey.OrderOption{}, _q.order...), order: append([]apikey.OrderOption{}, _q.order...),
inters: append([]Interceptor{}, _q.inters...), inters: append([]Interceptor{}, _q.inters...),
predicates: append([]predicate.ApiKey{}, _q.predicates...), predicates: append([]predicate.APIKey{}, _q.predicates...),
withUser: _q.withUser.Clone(), withUser: _q.withUser.Clone(),
withGroup: _q.withGroup.Clone(), withGroup: _q.withGroup.Clone(),
withUsageLogs: _q.withUsageLogs.Clone(), withUsageLogs: _q.withUsageLogs.Clone(),
@@ -334,7 +334,7 @@ func (_q *ApiKeyQuery) Clone() *ApiKeyQuery {
// WithUser tells the query-builder to eager-load the nodes that are connected to // WithUser tells the query-builder to eager-load the nodes that are connected to
// the "user" edge. The optional arguments are used to configure the query builder of the edge. // the "user" edge. The optional arguments are used to configure the query builder of the edge.
func (_q *ApiKeyQuery) WithUser(opts ...func(*UserQuery)) *ApiKeyQuery { func (_q *APIKeyQuery) WithUser(opts ...func(*UserQuery)) *APIKeyQuery {
query := (&UserClient{config: _q.config}).Query() query := (&UserClient{config: _q.config}).Query()
for _, opt := range opts { for _, opt := range opts {
opt(query) opt(query)
@@ -345,7 +345,7 @@ func (_q *ApiKeyQuery) WithUser(opts ...func(*UserQuery)) *ApiKeyQuery {
// WithGroup tells the query-builder to eager-load the nodes that are connected to // WithGroup tells the query-builder to eager-load the nodes that are connected to
// the "group" edge. The optional arguments are used to configure the query builder of the edge. // the "group" edge. The optional arguments are used to configure the query builder of the edge.
func (_q *ApiKeyQuery) WithGroup(opts ...func(*GroupQuery)) *ApiKeyQuery { func (_q *APIKeyQuery) WithGroup(opts ...func(*GroupQuery)) *APIKeyQuery {
query := (&GroupClient{config: _q.config}).Query() query := (&GroupClient{config: _q.config}).Query()
for _, opt := range opts { for _, opt := range opts {
opt(query) opt(query)
@@ -356,7 +356,7 @@ func (_q *ApiKeyQuery) WithGroup(opts ...func(*GroupQuery)) *ApiKeyQuery {
// WithUsageLogs tells the query-builder to eager-load the nodes that are connected to // WithUsageLogs tells the query-builder to eager-load the nodes that are connected to
// the "usage_logs" edge. The optional arguments are used to configure the query builder of the edge. // the "usage_logs" edge. The optional arguments are used to configure the query builder of the edge.
func (_q *ApiKeyQuery) WithUsageLogs(opts ...func(*UsageLogQuery)) *ApiKeyQuery { func (_q *APIKeyQuery) WithUsageLogs(opts ...func(*UsageLogQuery)) *APIKeyQuery {
query := (&UsageLogClient{config: _q.config}).Query() query := (&UsageLogClient{config: _q.config}).Query()
for _, opt := range opts { for _, opt := range opts {
opt(query) opt(query)
@@ -375,13 +375,13 @@ func (_q *ApiKeyQuery) WithUsageLogs(opts ...func(*UsageLogQuery)) *ApiKeyQuery
// Count int `json:"count,omitempty"` // Count int `json:"count,omitempty"`
// } // }
// //
// client.ApiKey.Query(). // client.APIKey.Query().
// GroupBy(apikey.FieldCreatedAt). // GroupBy(apikey.FieldCreatedAt).
// Aggregate(ent.Count()). // Aggregate(ent.Count()).
// Scan(ctx, &v) // Scan(ctx, &v)
func (_q *ApiKeyQuery) GroupBy(field string, fields ...string) *ApiKeyGroupBy { func (_q *APIKeyQuery) GroupBy(field string, fields ...string) *APIKeyGroupBy {
_q.ctx.Fields = append([]string{field}, fields...) _q.ctx.Fields = append([]string{field}, fields...)
grbuild := &ApiKeyGroupBy{build: _q} grbuild := &APIKeyGroupBy{build: _q}
grbuild.flds = &_q.ctx.Fields grbuild.flds = &_q.ctx.Fields
grbuild.label = apikey.Label grbuild.label = apikey.Label
grbuild.scan = grbuild.Scan grbuild.scan = grbuild.Scan
@@ -397,23 +397,23 @@ func (_q *ApiKeyQuery) GroupBy(field string, fields ...string) *ApiKeyGroupBy {
// CreatedAt time.Time `json:"created_at,omitempty"` // CreatedAt time.Time `json:"created_at,omitempty"`
// } // }
// //
// client.ApiKey.Query(). // client.APIKey.Query().
// Select(apikey.FieldCreatedAt). // Select(apikey.FieldCreatedAt).
// Scan(ctx, &v) // Scan(ctx, &v)
func (_q *ApiKeyQuery) Select(fields ...string) *ApiKeySelect { func (_q *APIKeyQuery) Select(fields ...string) *APIKeySelect {
_q.ctx.Fields = append(_q.ctx.Fields, fields...) _q.ctx.Fields = append(_q.ctx.Fields, fields...)
sbuild := &ApiKeySelect{ApiKeyQuery: _q} sbuild := &APIKeySelect{APIKeyQuery: _q}
sbuild.label = apikey.Label sbuild.label = apikey.Label
sbuild.flds, sbuild.scan = &_q.ctx.Fields, sbuild.Scan sbuild.flds, sbuild.scan = &_q.ctx.Fields, sbuild.Scan
return sbuild return sbuild
} }
// Aggregate returns a ApiKeySelect configured with the given aggregations. // Aggregate returns a APIKeySelect configured with the given aggregations.
func (_q *ApiKeyQuery) Aggregate(fns ...AggregateFunc) *ApiKeySelect { func (_q *APIKeyQuery) Aggregate(fns ...AggregateFunc) *APIKeySelect {
return _q.Select().Aggregate(fns...) return _q.Select().Aggregate(fns...)
} }
func (_q *ApiKeyQuery) prepareQuery(ctx context.Context) error { func (_q *APIKeyQuery) prepareQuery(ctx context.Context) error {
for _, inter := range _q.inters { for _, inter := range _q.inters {
if inter == nil { if inter == nil {
return fmt.Errorf("ent: uninitialized interceptor (forgotten import ent/runtime?)") return fmt.Errorf("ent: uninitialized interceptor (forgotten import ent/runtime?)")
@@ -439,9 +439,9 @@ func (_q *ApiKeyQuery) prepareQuery(ctx context.Context) error {
return nil return nil
} }
func (_q *ApiKeyQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*ApiKey, error) { func (_q *APIKeyQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*APIKey, error) {
var ( var (
nodes = []*ApiKey{} nodes = []*APIKey{}
_spec = _q.querySpec() _spec = _q.querySpec()
loadedTypes = [3]bool{ loadedTypes = [3]bool{
_q.withUser != nil, _q.withUser != nil,
@@ -450,10 +450,10 @@ func (_q *ApiKeyQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*ApiKe
} }
) )
_spec.ScanValues = func(columns []string) ([]any, error) { _spec.ScanValues = func(columns []string) ([]any, error) {
return (*ApiKey).scanValues(nil, columns) return (*APIKey).scanValues(nil, columns)
} }
_spec.Assign = func(columns []string, values []any) error { _spec.Assign = func(columns []string, values []any) error {
node := &ApiKey{config: _q.config} node := &APIKey{config: _q.config}
nodes = append(nodes, node) nodes = append(nodes, node)
node.Edges.loadedTypes = loadedTypes node.Edges.loadedTypes = loadedTypes
return node.assignValues(columns, values) return node.assignValues(columns, values)
@@ -469,29 +469,29 @@ func (_q *ApiKeyQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*ApiKe
} }
if query := _q.withUser; query != nil { if query := _q.withUser; query != nil {
if err := _q.loadUser(ctx, query, nodes, nil, if err := _q.loadUser(ctx, query, nodes, nil,
func(n *ApiKey, e *User) { n.Edges.User = e }); err != nil { func(n *APIKey, e *User) { n.Edges.User = e }); err != nil {
return nil, err return nil, err
} }
} }
if query := _q.withGroup; query != nil { if query := _q.withGroup; query != nil {
if err := _q.loadGroup(ctx, query, nodes, nil, if err := _q.loadGroup(ctx, query, nodes, nil,
func(n *ApiKey, e *Group) { n.Edges.Group = e }); err != nil { func(n *APIKey, e *Group) { n.Edges.Group = e }); err != nil {
return nil, err return nil, err
} }
} }
if query := _q.withUsageLogs; query != nil { if query := _q.withUsageLogs; query != nil {
if err := _q.loadUsageLogs(ctx, query, nodes, if err := _q.loadUsageLogs(ctx, query, nodes,
func(n *ApiKey) { n.Edges.UsageLogs = []*UsageLog{} }, func(n *APIKey) { n.Edges.UsageLogs = []*UsageLog{} },
func(n *ApiKey, e *UsageLog) { n.Edges.UsageLogs = append(n.Edges.UsageLogs, e) }); err != nil { func(n *APIKey, e *UsageLog) { n.Edges.UsageLogs = append(n.Edges.UsageLogs, e) }); err != nil {
return nil, err return nil, err
} }
} }
return nodes, nil return nodes, nil
} }
func (_q *ApiKeyQuery) loadUser(ctx context.Context, query *UserQuery, nodes []*ApiKey, init func(*ApiKey), assign func(*ApiKey, *User)) error { func (_q *APIKeyQuery) loadUser(ctx context.Context, query *UserQuery, nodes []*APIKey, init func(*APIKey), assign func(*APIKey, *User)) error {
ids := make([]int64, 0, len(nodes)) ids := make([]int64, 0, len(nodes))
nodeids := make(map[int64][]*ApiKey) nodeids := make(map[int64][]*APIKey)
for i := range nodes { for i := range nodes {
fk := nodes[i].UserID fk := nodes[i].UserID
if _, ok := nodeids[fk]; !ok { if _, ok := nodeids[fk]; !ok {
@@ -518,9 +518,9 @@ func (_q *ApiKeyQuery) loadUser(ctx context.Context, query *UserQuery, nodes []*
} }
return nil return nil
} }
func (_q *ApiKeyQuery) loadGroup(ctx context.Context, query *GroupQuery, nodes []*ApiKey, init func(*ApiKey), assign func(*ApiKey, *Group)) error { func (_q *APIKeyQuery) loadGroup(ctx context.Context, query *GroupQuery, nodes []*APIKey, init func(*APIKey), assign func(*APIKey, *Group)) error {
ids := make([]int64, 0, len(nodes)) ids := make([]int64, 0, len(nodes))
nodeids := make(map[int64][]*ApiKey) nodeids := make(map[int64][]*APIKey)
for i := range nodes { for i := range nodes {
if nodes[i].GroupID == nil { if nodes[i].GroupID == nil {
continue continue
@@ -550,9 +550,9 @@ func (_q *ApiKeyQuery) loadGroup(ctx context.Context, query *GroupQuery, nodes [
} }
return nil return nil
} }
func (_q *ApiKeyQuery) loadUsageLogs(ctx context.Context, query *UsageLogQuery, nodes []*ApiKey, init func(*ApiKey), assign func(*ApiKey, *UsageLog)) error { func (_q *APIKeyQuery) loadUsageLogs(ctx context.Context, query *UsageLogQuery, nodes []*APIKey, init func(*APIKey), assign func(*APIKey, *UsageLog)) error {
fks := make([]driver.Value, 0, len(nodes)) fks := make([]driver.Value, 0, len(nodes))
nodeids := make(map[int64]*ApiKey) nodeids := make(map[int64]*APIKey)
for i := range nodes { for i := range nodes {
fks = append(fks, nodes[i].ID) fks = append(fks, nodes[i].ID)
nodeids[nodes[i].ID] = nodes[i] nodeids[nodes[i].ID] = nodes[i]
@@ -581,7 +581,7 @@ func (_q *ApiKeyQuery) loadUsageLogs(ctx context.Context, query *UsageLogQuery,
return nil return nil
} }
func (_q *ApiKeyQuery) sqlCount(ctx context.Context) (int, error) { func (_q *APIKeyQuery) sqlCount(ctx context.Context) (int, error) {
_spec := _q.querySpec() _spec := _q.querySpec()
_spec.Node.Columns = _q.ctx.Fields _spec.Node.Columns = _q.ctx.Fields
if len(_q.ctx.Fields) > 0 { if len(_q.ctx.Fields) > 0 {
@@ -590,7 +590,7 @@ func (_q *ApiKeyQuery) sqlCount(ctx context.Context) (int, error) {
return sqlgraph.CountNodes(ctx, _q.driver, _spec) return sqlgraph.CountNodes(ctx, _q.driver, _spec)
} }
func (_q *ApiKeyQuery) querySpec() *sqlgraph.QuerySpec { func (_q *APIKeyQuery) querySpec() *sqlgraph.QuerySpec {
_spec := sqlgraph.NewQuerySpec(apikey.Table, apikey.Columns, sqlgraph.NewFieldSpec(apikey.FieldID, field.TypeInt64)) _spec := sqlgraph.NewQuerySpec(apikey.Table, apikey.Columns, sqlgraph.NewFieldSpec(apikey.FieldID, field.TypeInt64))
_spec.From = _q.sql _spec.From = _q.sql
if unique := _q.ctx.Unique; unique != nil { if unique := _q.ctx.Unique; unique != nil {
@@ -636,7 +636,7 @@ func (_q *ApiKeyQuery) querySpec() *sqlgraph.QuerySpec {
return _spec return _spec
} }
func (_q *ApiKeyQuery) sqlQuery(ctx context.Context) *sql.Selector { func (_q *APIKeyQuery) sqlQuery(ctx context.Context) *sql.Selector {
builder := sql.Dialect(_q.driver.Dialect()) builder := sql.Dialect(_q.driver.Dialect())
t1 := builder.Table(apikey.Table) t1 := builder.Table(apikey.Table)
columns := _q.ctx.Fields columns := _q.ctx.Fields
@@ -668,28 +668,28 @@ func (_q *ApiKeyQuery) sqlQuery(ctx context.Context) *sql.Selector {
return selector return selector
} }
// ApiKeyGroupBy is the group-by builder for ApiKey entities. // APIKeyGroupBy is the group-by builder for APIKey entities.
type ApiKeyGroupBy struct { type APIKeyGroupBy struct {
selector selector
build *ApiKeyQuery build *APIKeyQuery
} }
// Aggregate adds the given aggregation functions to the group-by query. // Aggregate adds the given aggregation functions to the group-by query.
func (_g *ApiKeyGroupBy) Aggregate(fns ...AggregateFunc) *ApiKeyGroupBy { func (_g *APIKeyGroupBy) Aggregate(fns ...AggregateFunc) *APIKeyGroupBy {
_g.fns = append(_g.fns, fns...) _g.fns = append(_g.fns, fns...)
return _g return _g
} }
// Scan applies the selector query and scans the result into the given value. // Scan applies the selector query and scans the result into the given value.
func (_g *ApiKeyGroupBy) Scan(ctx context.Context, v any) error { func (_g *APIKeyGroupBy) Scan(ctx context.Context, v any) error {
ctx = setContextOp(ctx, _g.build.ctx, ent.OpQueryGroupBy) ctx = setContextOp(ctx, _g.build.ctx, ent.OpQueryGroupBy)
if err := _g.build.prepareQuery(ctx); err != nil { if err := _g.build.prepareQuery(ctx); err != nil {
return err return err
} }
return scanWithInterceptors[*ApiKeyQuery, *ApiKeyGroupBy](ctx, _g.build, _g, _g.build.inters, v) return scanWithInterceptors[*APIKeyQuery, *APIKeyGroupBy](ctx, _g.build, _g, _g.build.inters, v)
} }
func (_g *ApiKeyGroupBy) sqlScan(ctx context.Context, root *ApiKeyQuery, v any) error { func (_g *APIKeyGroupBy) sqlScan(ctx context.Context, root *APIKeyQuery, v any) error {
selector := root.sqlQuery(ctx).Select() selector := root.sqlQuery(ctx).Select()
aggregation := make([]string, 0, len(_g.fns)) aggregation := make([]string, 0, len(_g.fns))
for _, fn := range _g.fns { for _, fn := range _g.fns {
@@ -716,28 +716,28 @@ func (_g *ApiKeyGroupBy) sqlScan(ctx context.Context, root *ApiKeyQuery, v any)
return sql.ScanSlice(rows, v) return sql.ScanSlice(rows, v)
} }
// ApiKeySelect is the builder for selecting fields of ApiKey entities. // APIKeySelect is the builder for selecting fields of APIKey entities.
type ApiKeySelect struct { type APIKeySelect struct {
*ApiKeyQuery *APIKeyQuery
selector selector
} }
// Aggregate adds the given aggregation functions to the selector query. // Aggregate adds the given aggregation functions to the selector query.
func (_s *ApiKeySelect) Aggregate(fns ...AggregateFunc) *ApiKeySelect { func (_s *APIKeySelect) Aggregate(fns ...AggregateFunc) *APIKeySelect {
_s.fns = append(_s.fns, fns...) _s.fns = append(_s.fns, fns...)
return _s return _s
} }
// Scan applies the selector query and scans the result into the given value. // Scan applies the selector query and scans the result into the given value.
func (_s *ApiKeySelect) Scan(ctx context.Context, v any) error { func (_s *APIKeySelect) Scan(ctx context.Context, v any) error {
ctx = setContextOp(ctx, _s.ctx, ent.OpQuerySelect) ctx = setContextOp(ctx, _s.ctx, ent.OpQuerySelect)
if err := _s.prepareQuery(ctx); err != nil { if err := _s.prepareQuery(ctx); err != nil {
return err return err
} }
return scanWithInterceptors[*ApiKeyQuery, *ApiKeySelect](ctx, _s.ApiKeyQuery, _s, _s.inters, v) return scanWithInterceptors[*APIKeyQuery, *APIKeySelect](ctx, _s.APIKeyQuery, _s, _s.inters, v)
} }
func (_s *ApiKeySelect) sqlScan(ctx context.Context, root *ApiKeyQuery, v any) error { func (_s *APIKeySelect) sqlScan(ctx context.Context, root *APIKeyQuery, v any) error {
selector := root.sqlQuery(ctx) selector := root.sqlQuery(ctx)
aggregation := make([]string, 0, len(_s.fns)) aggregation := make([]string, 0, len(_s.fns))
for _, fn := range _s.fns { for _, fn := range _s.fns {

View File

@@ -18,33 +18,33 @@ import (
"github.com/Wei-Shaw/sub2api/ent/user" "github.com/Wei-Shaw/sub2api/ent/user"
) )
// ApiKeyUpdate is the builder for updating ApiKey entities. // APIKeyUpdate is the builder for updating APIKey entities.
type ApiKeyUpdate struct { type APIKeyUpdate struct {
config config
hooks []Hook hooks []Hook
mutation *ApiKeyMutation mutation *APIKeyMutation
} }
// Where appends a list predicates to the ApiKeyUpdate builder. // Where appends a list predicates to the APIKeyUpdate builder.
func (_u *ApiKeyUpdate) Where(ps ...predicate.ApiKey) *ApiKeyUpdate { func (_u *APIKeyUpdate) Where(ps ...predicate.APIKey) *APIKeyUpdate {
_u.mutation.Where(ps...) _u.mutation.Where(ps...)
return _u return _u
} }
// SetUpdatedAt sets the "updated_at" field. // SetUpdatedAt sets the "updated_at" field.
func (_u *ApiKeyUpdate) SetUpdatedAt(v time.Time) *ApiKeyUpdate { func (_u *APIKeyUpdate) SetUpdatedAt(v time.Time) *APIKeyUpdate {
_u.mutation.SetUpdatedAt(v) _u.mutation.SetUpdatedAt(v)
return _u return _u
} }
// SetDeletedAt sets the "deleted_at" field. // SetDeletedAt sets the "deleted_at" field.
func (_u *ApiKeyUpdate) SetDeletedAt(v time.Time) *ApiKeyUpdate { func (_u *APIKeyUpdate) SetDeletedAt(v time.Time) *APIKeyUpdate {
_u.mutation.SetDeletedAt(v) _u.mutation.SetDeletedAt(v)
return _u return _u
} }
// SetNillableDeletedAt sets the "deleted_at" field if the given value is not nil. // SetNillableDeletedAt sets the "deleted_at" field if the given value is not nil.
func (_u *ApiKeyUpdate) SetNillableDeletedAt(v *time.Time) *ApiKeyUpdate { func (_u *APIKeyUpdate) SetNillableDeletedAt(v *time.Time) *APIKeyUpdate {
if v != nil { if v != nil {
_u.SetDeletedAt(*v) _u.SetDeletedAt(*v)
} }
@@ -52,19 +52,19 @@ func (_u *ApiKeyUpdate) SetNillableDeletedAt(v *time.Time) *ApiKeyUpdate {
} }
// ClearDeletedAt clears the value of the "deleted_at" field. // ClearDeletedAt clears the value of the "deleted_at" field.
func (_u *ApiKeyUpdate) ClearDeletedAt() *ApiKeyUpdate { func (_u *APIKeyUpdate) ClearDeletedAt() *APIKeyUpdate {
_u.mutation.ClearDeletedAt() _u.mutation.ClearDeletedAt()
return _u return _u
} }
// SetUserID sets the "user_id" field. // SetUserID sets the "user_id" field.
func (_u *ApiKeyUpdate) SetUserID(v int64) *ApiKeyUpdate { func (_u *APIKeyUpdate) SetUserID(v int64) *APIKeyUpdate {
_u.mutation.SetUserID(v) _u.mutation.SetUserID(v)
return _u return _u
} }
// SetNillableUserID sets the "user_id" field if the given value is not nil. // SetNillableUserID sets the "user_id" field if the given value is not nil.
func (_u *ApiKeyUpdate) SetNillableUserID(v *int64) *ApiKeyUpdate { func (_u *APIKeyUpdate) SetNillableUserID(v *int64) *APIKeyUpdate {
if v != nil { if v != nil {
_u.SetUserID(*v) _u.SetUserID(*v)
} }
@@ -72,13 +72,13 @@ func (_u *ApiKeyUpdate) SetNillableUserID(v *int64) *ApiKeyUpdate {
} }
// SetKey sets the "key" field. // SetKey sets the "key" field.
func (_u *ApiKeyUpdate) SetKey(v string) *ApiKeyUpdate { func (_u *APIKeyUpdate) SetKey(v string) *APIKeyUpdate {
_u.mutation.SetKey(v) _u.mutation.SetKey(v)
return _u return _u
} }
// SetNillableKey sets the "key" field if the given value is not nil. // SetNillableKey sets the "key" field if the given value is not nil.
func (_u *ApiKeyUpdate) SetNillableKey(v *string) *ApiKeyUpdate { func (_u *APIKeyUpdate) SetNillableKey(v *string) *APIKeyUpdate {
if v != nil { if v != nil {
_u.SetKey(*v) _u.SetKey(*v)
} }
@@ -86,13 +86,13 @@ func (_u *ApiKeyUpdate) SetNillableKey(v *string) *ApiKeyUpdate {
} }
// SetName sets the "name" field. // SetName sets the "name" field.
func (_u *ApiKeyUpdate) SetName(v string) *ApiKeyUpdate { func (_u *APIKeyUpdate) SetName(v string) *APIKeyUpdate {
_u.mutation.SetName(v) _u.mutation.SetName(v)
return _u return _u
} }
// SetNillableName sets the "name" field if the given value is not nil. // SetNillableName sets the "name" field if the given value is not nil.
func (_u *ApiKeyUpdate) SetNillableName(v *string) *ApiKeyUpdate { func (_u *APIKeyUpdate) SetNillableName(v *string) *APIKeyUpdate {
if v != nil { if v != nil {
_u.SetName(*v) _u.SetName(*v)
} }
@@ -100,13 +100,13 @@ func (_u *ApiKeyUpdate) SetNillableName(v *string) *ApiKeyUpdate {
} }
// SetGroupID sets the "group_id" field. // SetGroupID sets the "group_id" field.
func (_u *ApiKeyUpdate) SetGroupID(v int64) *ApiKeyUpdate { func (_u *APIKeyUpdate) SetGroupID(v int64) *APIKeyUpdate {
_u.mutation.SetGroupID(v) _u.mutation.SetGroupID(v)
return _u return _u
} }
// SetNillableGroupID sets the "group_id" field if the given value is not nil. // SetNillableGroupID sets the "group_id" field if the given value is not nil.
func (_u *ApiKeyUpdate) SetNillableGroupID(v *int64) *ApiKeyUpdate { func (_u *APIKeyUpdate) SetNillableGroupID(v *int64) *APIKeyUpdate {
if v != nil { if v != nil {
_u.SetGroupID(*v) _u.SetGroupID(*v)
} }
@@ -114,19 +114,19 @@ func (_u *ApiKeyUpdate) SetNillableGroupID(v *int64) *ApiKeyUpdate {
} }
// ClearGroupID clears the value of the "group_id" field. // ClearGroupID clears the value of the "group_id" field.
func (_u *ApiKeyUpdate) ClearGroupID() *ApiKeyUpdate { func (_u *APIKeyUpdate) ClearGroupID() *APIKeyUpdate {
_u.mutation.ClearGroupID() _u.mutation.ClearGroupID()
return _u return _u
} }
// SetStatus sets the "status" field. // SetStatus sets the "status" field.
func (_u *ApiKeyUpdate) SetStatus(v string) *ApiKeyUpdate { func (_u *APIKeyUpdate) SetStatus(v string) *APIKeyUpdate {
_u.mutation.SetStatus(v) _u.mutation.SetStatus(v)
return _u return _u
} }
// SetNillableStatus sets the "status" field if the given value is not nil. // SetNillableStatus sets the "status" field if the given value is not nil.
func (_u *ApiKeyUpdate) SetNillableStatus(v *string) *ApiKeyUpdate { func (_u *APIKeyUpdate) SetNillableStatus(v *string) *APIKeyUpdate {
if v != nil { if v != nil {
_u.SetStatus(*v) _u.SetStatus(*v)
} }
@@ -134,23 +134,23 @@ func (_u *ApiKeyUpdate) SetNillableStatus(v *string) *ApiKeyUpdate {
} }
// SetUser sets the "user" edge to the User entity. // SetUser sets the "user" edge to the User entity.
func (_u *ApiKeyUpdate) SetUser(v *User) *ApiKeyUpdate { func (_u *APIKeyUpdate) SetUser(v *User) *APIKeyUpdate {
return _u.SetUserID(v.ID) return _u.SetUserID(v.ID)
} }
// SetGroup sets the "group" edge to the Group entity. // SetGroup sets the "group" edge to the Group entity.
func (_u *ApiKeyUpdate) SetGroup(v *Group) *ApiKeyUpdate { func (_u *APIKeyUpdate) SetGroup(v *Group) *APIKeyUpdate {
return _u.SetGroupID(v.ID) return _u.SetGroupID(v.ID)
} }
// AddUsageLogIDs adds the "usage_logs" edge to the UsageLog entity by IDs. // AddUsageLogIDs adds the "usage_logs" edge to the UsageLog entity by IDs.
func (_u *ApiKeyUpdate) AddUsageLogIDs(ids ...int64) *ApiKeyUpdate { func (_u *APIKeyUpdate) AddUsageLogIDs(ids ...int64) *APIKeyUpdate {
_u.mutation.AddUsageLogIDs(ids...) _u.mutation.AddUsageLogIDs(ids...)
return _u return _u
} }
// AddUsageLogs adds the "usage_logs" edges to the UsageLog entity. // AddUsageLogs adds the "usage_logs" edges to the UsageLog entity.
func (_u *ApiKeyUpdate) AddUsageLogs(v ...*UsageLog) *ApiKeyUpdate { func (_u *APIKeyUpdate) AddUsageLogs(v ...*UsageLog) *APIKeyUpdate {
ids := make([]int64, len(v)) ids := make([]int64, len(v))
for i := range v { for i := range v {
ids[i] = v[i].ID ids[i] = v[i].ID
@@ -158,37 +158,37 @@ func (_u *ApiKeyUpdate) AddUsageLogs(v ...*UsageLog) *ApiKeyUpdate {
return _u.AddUsageLogIDs(ids...) return _u.AddUsageLogIDs(ids...)
} }
// Mutation returns the ApiKeyMutation object of the builder. // Mutation returns the APIKeyMutation object of the builder.
func (_u *ApiKeyUpdate) Mutation() *ApiKeyMutation { func (_u *APIKeyUpdate) Mutation() *APIKeyMutation {
return _u.mutation return _u.mutation
} }
// ClearUser clears the "user" edge to the User entity. // ClearUser clears the "user" edge to the User entity.
func (_u *ApiKeyUpdate) ClearUser() *ApiKeyUpdate { func (_u *APIKeyUpdate) ClearUser() *APIKeyUpdate {
_u.mutation.ClearUser() _u.mutation.ClearUser()
return _u return _u
} }
// ClearGroup clears the "group" edge to the Group entity. // ClearGroup clears the "group" edge to the Group entity.
func (_u *ApiKeyUpdate) ClearGroup() *ApiKeyUpdate { func (_u *APIKeyUpdate) ClearGroup() *APIKeyUpdate {
_u.mutation.ClearGroup() _u.mutation.ClearGroup()
return _u return _u
} }
// ClearUsageLogs clears all "usage_logs" edges to the UsageLog entity. // ClearUsageLogs clears all "usage_logs" edges to the UsageLog entity.
func (_u *ApiKeyUpdate) ClearUsageLogs() *ApiKeyUpdate { func (_u *APIKeyUpdate) ClearUsageLogs() *APIKeyUpdate {
_u.mutation.ClearUsageLogs() _u.mutation.ClearUsageLogs()
return _u return _u
} }
// RemoveUsageLogIDs removes the "usage_logs" edge to UsageLog entities by IDs. // RemoveUsageLogIDs removes the "usage_logs" edge to UsageLog entities by IDs.
func (_u *ApiKeyUpdate) RemoveUsageLogIDs(ids ...int64) *ApiKeyUpdate { func (_u *APIKeyUpdate) RemoveUsageLogIDs(ids ...int64) *APIKeyUpdate {
_u.mutation.RemoveUsageLogIDs(ids...) _u.mutation.RemoveUsageLogIDs(ids...)
return _u return _u
} }
// RemoveUsageLogs removes "usage_logs" edges to UsageLog entities. // RemoveUsageLogs removes "usage_logs" edges to UsageLog entities.
func (_u *ApiKeyUpdate) RemoveUsageLogs(v ...*UsageLog) *ApiKeyUpdate { func (_u *APIKeyUpdate) RemoveUsageLogs(v ...*UsageLog) *APIKeyUpdate {
ids := make([]int64, len(v)) ids := make([]int64, len(v))
for i := range v { for i := range v {
ids[i] = v[i].ID ids[i] = v[i].ID
@@ -197,7 +197,7 @@ func (_u *ApiKeyUpdate) RemoveUsageLogs(v ...*UsageLog) *ApiKeyUpdate {
} }
// Save executes the query and returns the number of nodes affected by the update operation. // Save executes the query and returns the number of nodes affected by the update operation.
func (_u *ApiKeyUpdate) Save(ctx context.Context) (int, error) { func (_u *APIKeyUpdate) Save(ctx context.Context) (int, error) {
if err := _u.defaults(); err != nil { if err := _u.defaults(); err != nil {
return 0, err return 0, err
} }
@@ -205,7 +205,7 @@ func (_u *ApiKeyUpdate) Save(ctx context.Context) (int, error) {
} }
// SaveX is like Save, but panics if an error occurs. // SaveX is like Save, but panics if an error occurs.
func (_u *ApiKeyUpdate) SaveX(ctx context.Context) int { func (_u *APIKeyUpdate) SaveX(ctx context.Context) int {
affected, err := _u.Save(ctx) affected, err := _u.Save(ctx)
if err != nil { if err != nil {
panic(err) panic(err)
@@ -214,20 +214,20 @@ func (_u *ApiKeyUpdate) SaveX(ctx context.Context) int {
} }
// Exec executes the query. // Exec executes the query.
func (_u *ApiKeyUpdate) Exec(ctx context.Context) error { func (_u *APIKeyUpdate) Exec(ctx context.Context) error {
_, err := _u.Save(ctx) _, err := _u.Save(ctx)
return err return err
} }
// ExecX is like Exec, but panics if an error occurs. // ExecX is like Exec, but panics if an error occurs.
func (_u *ApiKeyUpdate) ExecX(ctx context.Context) { func (_u *APIKeyUpdate) ExecX(ctx context.Context) {
if err := _u.Exec(ctx); err != nil { if err := _u.Exec(ctx); err != nil {
panic(err) panic(err)
} }
} }
// defaults sets the default values of the builder before save. // defaults sets the default values of the builder before save.
func (_u *ApiKeyUpdate) defaults() error { func (_u *APIKeyUpdate) defaults() error {
if _, ok := _u.mutation.UpdatedAt(); !ok { if _, ok := _u.mutation.UpdatedAt(); !ok {
if apikey.UpdateDefaultUpdatedAt == nil { if apikey.UpdateDefaultUpdatedAt == nil {
return fmt.Errorf("ent: uninitialized apikey.UpdateDefaultUpdatedAt (forgotten import ent/runtime?)") return fmt.Errorf("ent: uninitialized apikey.UpdateDefaultUpdatedAt (forgotten import ent/runtime?)")
@@ -239,29 +239,29 @@ func (_u *ApiKeyUpdate) defaults() error {
} }
// check runs all checks and user-defined validators on the builder. // check runs all checks and user-defined validators on the builder.
func (_u *ApiKeyUpdate) check() error { func (_u *APIKeyUpdate) check() error {
if v, ok := _u.mutation.Key(); ok { if v, ok := _u.mutation.Key(); ok {
if err := apikey.KeyValidator(v); err != nil { if err := apikey.KeyValidator(v); err != nil {
return &ValidationError{Name: "key", err: fmt.Errorf(`ent: validator failed for field "ApiKey.key": %w`, err)} return &ValidationError{Name: "key", err: fmt.Errorf(`ent: validator failed for field "APIKey.key": %w`, err)}
} }
} }
if v, ok := _u.mutation.Name(); ok { if v, ok := _u.mutation.Name(); ok {
if err := apikey.NameValidator(v); err != nil { if err := apikey.NameValidator(v); err != nil {
return &ValidationError{Name: "name", err: fmt.Errorf(`ent: validator failed for field "ApiKey.name": %w`, err)} return &ValidationError{Name: "name", err: fmt.Errorf(`ent: validator failed for field "APIKey.name": %w`, err)}
} }
} }
if v, ok := _u.mutation.Status(); ok { if v, ok := _u.mutation.Status(); ok {
if err := apikey.StatusValidator(v); err != nil { if err := apikey.StatusValidator(v); err != nil {
return &ValidationError{Name: "status", err: fmt.Errorf(`ent: validator failed for field "ApiKey.status": %w`, err)} return &ValidationError{Name: "status", err: fmt.Errorf(`ent: validator failed for field "APIKey.status": %w`, err)}
} }
} }
if _u.mutation.UserCleared() && len(_u.mutation.UserIDs()) > 0 { if _u.mutation.UserCleared() && len(_u.mutation.UserIDs()) > 0 {
return errors.New(`ent: clearing a required unique edge "ApiKey.user"`) return errors.New(`ent: clearing a required unique edge "APIKey.user"`)
} }
return nil return nil
} }
func (_u *ApiKeyUpdate) sqlSave(ctx context.Context) (_node int, err error) { func (_u *APIKeyUpdate) sqlSave(ctx context.Context) (_node int, err error) {
if err := _u.check(); err != nil { if err := _u.check(); err != nil {
return _node, err return _node, err
} }
@@ -406,28 +406,28 @@ func (_u *ApiKeyUpdate) sqlSave(ctx context.Context) (_node int, err error) {
return _node, nil return _node, nil
} }
// ApiKeyUpdateOne is the builder for updating a single ApiKey entity. // APIKeyUpdateOne is the builder for updating a single APIKey entity.
type ApiKeyUpdateOne struct { type APIKeyUpdateOne struct {
config config
fields []string fields []string
hooks []Hook hooks []Hook
mutation *ApiKeyMutation mutation *APIKeyMutation
} }
// SetUpdatedAt sets the "updated_at" field. // SetUpdatedAt sets the "updated_at" field.
func (_u *ApiKeyUpdateOne) SetUpdatedAt(v time.Time) *ApiKeyUpdateOne { func (_u *APIKeyUpdateOne) SetUpdatedAt(v time.Time) *APIKeyUpdateOne {
_u.mutation.SetUpdatedAt(v) _u.mutation.SetUpdatedAt(v)
return _u return _u
} }
// SetDeletedAt sets the "deleted_at" field. // SetDeletedAt sets the "deleted_at" field.
func (_u *ApiKeyUpdateOne) SetDeletedAt(v time.Time) *ApiKeyUpdateOne { func (_u *APIKeyUpdateOne) SetDeletedAt(v time.Time) *APIKeyUpdateOne {
_u.mutation.SetDeletedAt(v) _u.mutation.SetDeletedAt(v)
return _u return _u
} }
// SetNillableDeletedAt sets the "deleted_at" field if the given value is not nil. // SetNillableDeletedAt sets the "deleted_at" field if the given value is not nil.
func (_u *ApiKeyUpdateOne) SetNillableDeletedAt(v *time.Time) *ApiKeyUpdateOne { func (_u *APIKeyUpdateOne) SetNillableDeletedAt(v *time.Time) *APIKeyUpdateOne {
if v != nil { if v != nil {
_u.SetDeletedAt(*v) _u.SetDeletedAt(*v)
} }
@@ -435,19 +435,19 @@ func (_u *ApiKeyUpdateOne) SetNillableDeletedAt(v *time.Time) *ApiKeyUpdateOne {
} }
// ClearDeletedAt clears the value of the "deleted_at" field. // ClearDeletedAt clears the value of the "deleted_at" field.
func (_u *ApiKeyUpdateOne) ClearDeletedAt() *ApiKeyUpdateOne { func (_u *APIKeyUpdateOne) ClearDeletedAt() *APIKeyUpdateOne {
_u.mutation.ClearDeletedAt() _u.mutation.ClearDeletedAt()
return _u return _u
} }
// SetUserID sets the "user_id" field. // SetUserID sets the "user_id" field.
func (_u *ApiKeyUpdateOne) SetUserID(v int64) *ApiKeyUpdateOne { func (_u *APIKeyUpdateOne) SetUserID(v int64) *APIKeyUpdateOne {
_u.mutation.SetUserID(v) _u.mutation.SetUserID(v)
return _u return _u
} }
// SetNillableUserID sets the "user_id" field if the given value is not nil. // SetNillableUserID sets the "user_id" field if the given value is not nil.
func (_u *ApiKeyUpdateOne) SetNillableUserID(v *int64) *ApiKeyUpdateOne { func (_u *APIKeyUpdateOne) SetNillableUserID(v *int64) *APIKeyUpdateOne {
if v != nil { if v != nil {
_u.SetUserID(*v) _u.SetUserID(*v)
} }
@@ -455,13 +455,13 @@ func (_u *ApiKeyUpdateOne) SetNillableUserID(v *int64) *ApiKeyUpdateOne {
} }
// SetKey sets the "key" field. // SetKey sets the "key" field.
func (_u *ApiKeyUpdateOne) SetKey(v string) *ApiKeyUpdateOne { func (_u *APIKeyUpdateOne) SetKey(v string) *APIKeyUpdateOne {
_u.mutation.SetKey(v) _u.mutation.SetKey(v)
return _u return _u
} }
// SetNillableKey sets the "key" field if the given value is not nil. // SetNillableKey sets the "key" field if the given value is not nil.
func (_u *ApiKeyUpdateOne) SetNillableKey(v *string) *ApiKeyUpdateOne { func (_u *APIKeyUpdateOne) SetNillableKey(v *string) *APIKeyUpdateOne {
if v != nil { if v != nil {
_u.SetKey(*v) _u.SetKey(*v)
} }
@@ -469,13 +469,13 @@ func (_u *ApiKeyUpdateOne) SetNillableKey(v *string) *ApiKeyUpdateOne {
} }
// SetName sets the "name" field. // SetName sets the "name" field.
func (_u *ApiKeyUpdateOne) SetName(v string) *ApiKeyUpdateOne { func (_u *APIKeyUpdateOne) SetName(v string) *APIKeyUpdateOne {
_u.mutation.SetName(v) _u.mutation.SetName(v)
return _u return _u
} }
// SetNillableName sets the "name" field if the given value is not nil. // SetNillableName sets the "name" field if the given value is not nil.
func (_u *ApiKeyUpdateOne) SetNillableName(v *string) *ApiKeyUpdateOne { func (_u *APIKeyUpdateOne) SetNillableName(v *string) *APIKeyUpdateOne {
if v != nil { if v != nil {
_u.SetName(*v) _u.SetName(*v)
} }
@@ -483,13 +483,13 @@ func (_u *ApiKeyUpdateOne) SetNillableName(v *string) *ApiKeyUpdateOne {
} }
// SetGroupID sets the "group_id" field. // SetGroupID sets the "group_id" field.
func (_u *ApiKeyUpdateOne) SetGroupID(v int64) *ApiKeyUpdateOne { func (_u *APIKeyUpdateOne) SetGroupID(v int64) *APIKeyUpdateOne {
_u.mutation.SetGroupID(v) _u.mutation.SetGroupID(v)
return _u return _u
} }
// SetNillableGroupID sets the "group_id" field if the given value is not nil. // SetNillableGroupID sets the "group_id" field if the given value is not nil.
func (_u *ApiKeyUpdateOne) SetNillableGroupID(v *int64) *ApiKeyUpdateOne { func (_u *APIKeyUpdateOne) SetNillableGroupID(v *int64) *APIKeyUpdateOne {
if v != nil { if v != nil {
_u.SetGroupID(*v) _u.SetGroupID(*v)
} }
@@ -497,19 +497,19 @@ func (_u *ApiKeyUpdateOne) SetNillableGroupID(v *int64) *ApiKeyUpdateOne {
} }
// ClearGroupID clears the value of the "group_id" field. // ClearGroupID clears the value of the "group_id" field.
func (_u *ApiKeyUpdateOne) ClearGroupID() *ApiKeyUpdateOne { func (_u *APIKeyUpdateOne) ClearGroupID() *APIKeyUpdateOne {
_u.mutation.ClearGroupID() _u.mutation.ClearGroupID()
return _u return _u
} }
// SetStatus sets the "status" field. // SetStatus sets the "status" field.
func (_u *ApiKeyUpdateOne) SetStatus(v string) *ApiKeyUpdateOne { func (_u *APIKeyUpdateOne) SetStatus(v string) *APIKeyUpdateOne {
_u.mutation.SetStatus(v) _u.mutation.SetStatus(v)
return _u return _u
} }
// SetNillableStatus sets the "status" field if the given value is not nil. // SetNillableStatus sets the "status" field if the given value is not nil.
func (_u *ApiKeyUpdateOne) SetNillableStatus(v *string) *ApiKeyUpdateOne { func (_u *APIKeyUpdateOne) SetNillableStatus(v *string) *APIKeyUpdateOne {
if v != nil { if v != nil {
_u.SetStatus(*v) _u.SetStatus(*v)
} }
@@ -517,23 +517,23 @@ func (_u *ApiKeyUpdateOne) SetNillableStatus(v *string) *ApiKeyUpdateOne {
} }
// SetUser sets the "user" edge to the User entity. // SetUser sets the "user" edge to the User entity.
func (_u *ApiKeyUpdateOne) SetUser(v *User) *ApiKeyUpdateOne { func (_u *APIKeyUpdateOne) SetUser(v *User) *APIKeyUpdateOne {
return _u.SetUserID(v.ID) return _u.SetUserID(v.ID)
} }
// SetGroup sets the "group" edge to the Group entity. // SetGroup sets the "group" edge to the Group entity.
func (_u *ApiKeyUpdateOne) SetGroup(v *Group) *ApiKeyUpdateOne { func (_u *APIKeyUpdateOne) SetGroup(v *Group) *APIKeyUpdateOne {
return _u.SetGroupID(v.ID) return _u.SetGroupID(v.ID)
} }
// AddUsageLogIDs adds the "usage_logs" edge to the UsageLog entity by IDs. // AddUsageLogIDs adds the "usage_logs" edge to the UsageLog entity by IDs.
func (_u *ApiKeyUpdateOne) AddUsageLogIDs(ids ...int64) *ApiKeyUpdateOne { func (_u *APIKeyUpdateOne) AddUsageLogIDs(ids ...int64) *APIKeyUpdateOne {
_u.mutation.AddUsageLogIDs(ids...) _u.mutation.AddUsageLogIDs(ids...)
return _u return _u
} }
// AddUsageLogs adds the "usage_logs" edges to the UsageLog entity. // AddUsageLogs adds the "usage_logs" edges to the UsageLog entity.
func (_u *ApiKeyUpdateOne) AddUsageLogs(v ...*UsageLog) *ApiKeyUpdateOne { func (_u *APIKeyUpdateOne) AddUsageLogs(v ...*UsageLog) *APIKeyUpdateOne {
ids := make([]int64, len(v)) ids := make([]int64, len(v))
for i := range v { for i := range v {
ids[i] = v[i].ID ids[i] = v[i].ID
@@ -541,37 +541,37 @@ func (_u *ApiKeyUpdateOne) AddUsageLogs(v ...*UsageLog) *ApiKeyUpdateOne {
return _u.AddUsageLogIDs(ids...) return _u.AddUsageLogIDs(ids...)
} }
// Mutation returns the ApiKeyMutation object of the builder. // Mutation returns the APIKeyMutation object of the builder.
func (_u *ApiKeyUpdateOne) Mutation() *ApiKeyMutation { func (_u *APIKeyUpdateOne) Mutation() *APIKeyMutation {
return _u.mutation return _u.mutation
} }
// ClearUser clears the "user" edge to the User entity. // ClearUser clears the "user" edge to the User entity.
func (_u *ApiKeyUpdateOne) ClearUser() *ApiKeyUpdateOne { func (_u *APIKeyUpdateOne) ClearUser() *APIKeyUpdateOne {
_u.mutation.ClearUser() _u.mutation.ClearUser()
return _u return _u
} }
// ClearGroup clears the "group" edge to the Group entity. // ClearGroup clears the "group" edge to the Group entity.
func (_u *ApiKeyUpdateOne) ClearGroup() *ApiKeyUpdateOne { func (_u *APIKeyUpdateOne) ClearGroup() *APIKeyUpdateOne {
_u.mutation.ClearGroup() _u.mutation.ClearGroup()
return _u return _u
} }
// ClearUsageLogs clears all "usage_logs" edges to the UsageLog entity. // ClearUsageLogs clears all "usage_logs" edges to the UsageLog entity.
func (_u *ApiKeyUpdateOne) ClearUsageLogs() *ApiKeyUpdateOne { func (_u *APIKeyUpdateOne) ClearUsageLogs() *APIKeyUpdateOne {
_u.mutation.ClearUsageLogs() _u.mutation.ClearUsageLogs()
return _u return _u
} }
// RemoveUsageLogIDs removes the "usage_logs" edge to UsageLog entities by IDs. // RemoveUsageLogIDs removes the "usage_logs" edge to UsageLog entities by IDs.
func (_u *ApiKeyUpdateOne) RemoveUsageLogIDs(ids ...int64) *ApiKeyUpdateOne { func (_u *APIKeyUpdateOne) RemoveUsageLogIDs(ids ...int64) *APIKeyUpdateOne {
_u.mutation.RemoveUsageLogIDs(ids...) _u.mutation.RemoveUsageLogIDs(ids...)
return _u return _u
} }
// RemoveUsageLogs removes "usage_logs" edges to UsageLog entities. // RemoveUsageLogs removes "usage_logs" edges to UsageLog entities.
func (_u *ApiKeyUpdateOne) RemoveUsageLogs(v ...*UsageLog) *ApiKeyUpdateOne { func (_u *APIKeyUpdateOne) RemoveUsageLogs(v ...*UsageLog) *APIKeyUpdateOne {
ids := make([]int64, len(v)) ids := make([]int64, len(v))
for i := range v { for i := range v {
ids[i] = v[i].ID ids[i] = v[i].ID
@@ -579,21 +579,21 @@ func (_u *ApiKeyUpdateOne) RemoveUsageLogs(v ...*UsageLog) *ApiKeyUpdateOne {
return _u.RemoveUsageLogIDs(ids...) return _u.RemoveUsageLogIDs(ids...)
} }
// Where appends a list predicates to the ApiKeyUpdate builder. // Where appends a list predicates to the APIKeyUpdate builder.
func (_u *ApiKeyUpdateOne) Where(ps ...predicate.ApiKey) *ApiKeyUpdateOne { func (_u *APIKeyUpdateOne) Where(ps ...predicate.APIKey) *APIKeyUpdateOne {
_u.mutation.Where(ps...) _u.mutation.Where(ps...)
return _u return _u
} }
// Select allows selecting one or more fields (columns) of the returned entity. // Select allows selecting one or more fields (columns) of the returned entity.
// The default is selecting all fields defined in the entity schema. // The default is selecting all fields defined in the entity schema.
func (_u *ApiKeyUpdateOne) Select(field string, fields ...string) *ApiKeyUpdateOne { func (_u *APIKeyUpdateOne) Select(field string, fields ...string) *APIKeyUpdateOne {
_u.fields = append([]string{field}, fields...) _u.fields = append([]string{field}, fields...)
return _u return _u
} }
// Save executes the query and returns the updated ApiKey entity. // Save executes the query and returns the updated APIKey entity.
func (_u *ApiKeyUpdateOne) Save(ctx context.Context) (*ApiKey, error) { func (_u *APIKeyUpdateOne) Save(ctx context.Context) (*APIKey, error) {
if err := _u.defaults(); err != nil { if err := _u.defaults(); err != nil {
return nil, err return nil, err
} }
@@ -601,7 +601,7 @@ func (_u *ApiKeyUpdateOne) Save(ctx context.Context) (*ApiKey, error) {
} }
// SaveX is like Save, but panics if an error occurs. // SaveX is like Save, but panics if an error occurs.
func (_u *ApiKeyUpdateOne) SaveX(ctx context.Context) *ApiKey { func (_u *APIKeyUpdateOne) SaveX(ctx context.Context) *APIKey {
node, err := _u.Save(ctx) node, err := _u.Save(ctx)
if err != nil { if err != nil {
panic(err) panic(err)
@@ -610,20 +610,20 @@ func (_u *ApiKeyUpdateOne) SaveX(ctx context.Context) *ApiKey {
} }
// Exec executes the query on the entity. // Exec executes the query on the entity.
func (_u *ApiKeyUpdateOne) Exec(ctx context.Context) error { func (_u *APIKeyUpdateOne) Exec(ctx context.Context) error {
_, err := _u.Save(ctx) _, err := _u.Save(ctx)
return err return err
} }
// ExecX is like Exec, but panics if an error occurs. // ExecX is like Exec, but panics if an error occurs.
func (_u *ApiKeyUpdateOne) ExecX(ctx context.Context) { func (_u *APIKeyUpdateOne) ExecX(ctx context.Context) {
if err := _u.Exec(ctx); err != nil { if err := _u.Exec(ctx); err != nil {
panic(err) panic(err)
} }
} }
// defaults sets the default values of the builder before save. // defaults sets the default values of the builder before save.
func (_u *ApiKeyUpdateOne) defaults() error { func (_u *APIKeyUpdateOne) defaults() error {
if _, ok := _u.mutation.UpdatedAt(); !ok { if _, ok := _u.mutation.UpdatedAt(); !ok {
if apikey.UpdateDefaultUpdatedAt == nil { if apikey.UpdateDefaultUpdatedAt == nil {
return fmt.Errorf("ent: uninitialized apikey.UpdateDefaultUpdatedAt (forgotten import ent/runtime?)") return fmt.Errorf("ent: uninitialized apikey.UpdateDefaultUpdatedAt (forgotten import ent/runtime?)")
@@ -635,36 +635,36 @@ func (_u *ApiKeyUpdateOne) defaults() error {
} }
// check runs all checks and user-defined validators on the builder. // check runs all checks and user-defined validators on the builder.
func (_u *ApiKeyUpdateOne) check() error { func (_u *APIKeyUpdateOne) check() error {
if v, ok := _u.mutation.Key(); ok { if v, ok := _u.mutation.Key(); ok {
if err := apikey.KeyValidator(v); err != nil { if err := apikey.KeyValidator(v); err != nil {
return &ValidationError{Name: "key", err: fmt.Errorf(`ent: validator failed for field "ApiKey.key": %w`, err)} return &ValidationError{Name: "key", err: fmt.Errorf(`ent: validator failed for field "APIKey.key": %w`, err)}
} }
} }
if v, ok := _u.mutation.Name(); ok { if v, ok := _u.mutation.Name(); ok {
if err := apikey.NameValidator(v); err != nil { if err := apikey.NameValidator(v); err != nil {
return &ValidationError{Name: "name", err: fmt.Errorf(`ent: validator failed for field "ApiKey.name": %w`, err)} return &ValidationError{Name: "name", err: fmt.Errorf(`ent: validator failed for field "APIKey.name": %w`, err)}
} }
} }
if v, ok := _u.mutation.Status(); ok { if v, ok := _u.mutation.Status(); ok {
if err := apikey.StatusValidator(v); err != nil { if err := apikey.StatusValidator(v); err != nil {
return &ValidationError{Name: "status", err: fmt.Errorf(`ent: validator failed for field "ApiKey.status": %w`, err)} return &ValidationError{Name: "status", err: fmt.Errorf(`ent: validator failed for field "APIKey.status": %w`, err)}
} }
} }
if _u.mutation.UserCleared() && len(_u.mutation.UserIDs()) > 0 { if _u.mutation.UserCleared() && len(_u.mutation.UserIDs()) > 0 {
return errors.New(`ent: clearing a required unique edge "ApiKey.user"`) return errors.New(`ent: clearing a required unique edge "APIKey.user"`)
} }
return nil return nil
} }
func (_u *ApiKeyUpdateOne) sqlSave(ctx context.Context) (_node *ApiKey, err error) { func (_u *APIKeyUpdateOne) sqlSave(ctx context.Context) (_node *APIKey, err error) {
if err := _u.check(); err != nil { if err := _u.check(); err != nil {
return _node, err return _node, err
} }
_spec := sqlgraph.NewUpdateSpec(apikey.Table, apikey.Columns, sqlgraph.NewFieldSpec(apikey.FieldID, field.TypeInt64)) _spec := sqlgraph.NewUpdateSpec(apikey.Table, apikey.Columns, sqlgraph.NewFieldSpec(apikey.FieldID, field.TypeInt64))
id, ok := _u.mutation.ID() id, ok := _u.mutation.ID()
if !ok { if !ok {
return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "ApiKey.id" for update`)} return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "APIKey.id" for update`)}
} }
_spec.Node.ID.Value = id _spec.Node.ID.Value = id
if fields := _u.fields; len(fields) > 0 { if fields := _u.fields; len(fields) > 0 {
@@ -807,7 +807,7 @@ func (_u *ApiKeyUpdateOne) sqlSave(ctx context.Context) (_node *ApiKey, err erro
} }
_spec.Edges.Add = append(_spec.Edges.Add, edge) _spec.Edges.Add = append(_spec.Edges.Add, edge)
} }
_node = &ApiKey{config: _u.config} _node = &APIKey{config: _u.config}
_spec.Assign = _node.assignValues _spec.Assign = _node.assignValues
_spec.ScanValues = _node.scanValues _spec.ScanValues = _node.scanValues
if err = sqlgraph.UpdateNode(ctx, _u.driver, _spec); err != nil { if err = sqlgraph.UpdateNode(ctx, _u.driver, _spec); err != nil {

View File

@@ -37,12 +37,12 @@ type Client struct {
config config
// Schema is the client for creating, migrating and dropping schema. // Schema is the client for creating, migrating and dropping schema.
Schema *migrate.Schema Schema *migrate.Schema
// APIKey is the client for interacting with the APIKey builders.
APIKey *APIKeyClient
// Account is the client for interacting with the Account builders. // Account is the client for interacting with the Account builders.
Account *AccountClient Account *AccountClient
// AccountGroup is the client for interacting with the AccountGroup builders. // AccountGroup is the client for interacting with the AccountGroup builders.
AccountGroup *AccountGroupClient AccountGroup *AccountGroupClient
// ApiKey is the client for interacting with the ApiKey builders.
ApiKey *ApiKeyClient
// Group is the client for interacting with the Group builders. // Group is the client for interacting with the Group builders.
Group *GroupClient Group *GroupClient
// Proxy is the client for interacting with the Proxy builders. // Proxy is the client for interacting with the Proxy builders.
@@ -74,9 +74,9 @@ func NewClient(opts ...Option) *Client {
func (c *Client) init() { func (c *Client) init() {
c.Schema = migrate.NewSchema(c.driver) c.Schema = migrate.NewSchema(c.driver)
c.APIKey = NewAPIKeyClient(c.config)
c.Account = NewAccountClient(c.config) c.Account = NewAccountClient(c.config)
c.AccountGroup = NewAccountGroupClient(c.config) c.AccountGroup = NewAccountGroupClient(c.config)
c.ApiKey = NewApiKeyClient(c.config)
c.Group = NewGroupClient(c.config) c.Group = NewGroupClient(c.config)
c.Proxy = NewProxyClient(c.config) c.Proxy = NewProxyClient(c.config)
c.RedeemCode = NewRedeemCodeClient(c.config) c.RedeemCode = NewRedeemCodeClient(c.config)
@@ -179,9 +179,9 @@ func (c *Client) Tx(ctx context.Context) (*Tx, error) {
return &Tx{ return &Tx{
ctx: ctx, ctx: ctx,
config: cfg, config: cfg,
APIKey: NewAPIKeyClient(cfg),
Account: NewAccountClient(cfg), Account: NewAccountClient(cfg),
AccountGroup: NewAccountGroupClient(cfg), AccountGroup: NewAccountGroupClient(cfg),
ApiKey: NewApiKeyClient(cfg),
Group: NewGroupClient(cfg), Group: NewGroupClient(cfg),
Proxy: NewProxyClient(cfg), Proxy: NewProxyClient(cfg),
RedeemCode: NewRedeemCodeClient(cfg), RedeemCode: NewRedeemCodeClient(cfg),
@@ -211,9 +211,9 @@ func (c *Client) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error)
return &Tx{ return &Tx{
ctx: ctx, ctx: ctx,
config: cfg, config: cfg,
APIKey: NewAPIKeyClient(cfg),
Account: NewAccountClient(cfg), Account: NewAccountClient(cfg),
AccountGroup: NewAccountGroupClient(cfg), AccountGroup: NewAccountGroupClient(cfg),
ApiKey: NewApiKeyClient(cfg),
Group: NewGroupClient(cfg), Group: NewGroupClient(cfg),
Proxy: NewProxyClient(cfg), Proxy: NewProxyClient(cfg),
RedeemCode: NewRedeemCodeClient(cfg), RedeemCode: NewRedeemCodeClient(cfg),
@@ -230,7 +230,7 @@ func (c *Client) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error)
// Debug returns a new debug-client. It's used to get verbose logging on specific operations. // Debug returns a new debug-client. It's used to get verbose logging on specific operations.
// //
// client.Debug(). // client.Debug().
// Account. // APIKey.
// Query(). // Query().
// Count(ctx) // Count(ctx)
func (c *Client) Debug() *Client { func (c *Client) Debug() *Client {
@@ -253,9 +253,9 @@ func (c *Client) Close() error {
// In order to add hooks to a specific client, call: `client.Node.Use(...)`. // In order to add hooks to a specific client, call: `client.Node.Use(...)`.
func (c *Client) Use(hooks ...Hook) { func (c *Client) Use(hooks ...Hook) {
for _, n := range []interface{ Use(...Hook) }{ for _, n := range []interface{ Use(...Hook) }{
c.Account, c.AccountGroup, c.ApiKey, c.Group, c.Proxy, c.RedeemCode, c.Setting, c.APIKey, c.Account, c.AccountGroup, c.Group, c.Proxy, c.RedeemCode, c.Setting,
c.UsageLog, c.User, c.UserAllowedGroup, c.UserAttributeDefinition, c.UsageLog, c.User, c.UserAllowedGroup, c.UserAttributeDefinition, c.UserAttributeValue,
c.UserAttributeValue, c.UserSubscription, c.UserSubscription,
} { } {
n.Use(hooks...) n.Use(hooks...)
} }
@@ -265,9 +265,9 @@ func (c *Client) Use(hooks ...Hook) {
// In order to add interceptors to a specific client, call: `client.Node.Intercept(...)`. // In order to add interceptors to a specific client, call: `client.Node.Intercept(...)`.
func (c *Client) Intercept(interceptors ...Interceptor) { func (c *Client) Intercept(interceptors ...Interceptor) {
for _, n := range []interface{ Intercept(...Interceptor) }{ for _, n := range []interface{ Intercept(...Interceptor) }{
c.Account, c.AccountGroup, c.ApiKey, c.Group, c.Proxy, c.RedeemCode, c.Setting, c.APIKey, c.Account, c.AccountGroup, c.Group, c.Proxy, c.RedeemCode, c.Setting,
c.UsageLog, c.User, c.UserAllowedGroup, c.UserAttributeDefinition, c.UsageLog, c.User, c.UserAllowedGroup, c.UserAttributeDefinition, c.UserAttributeValue,
c.UserAttributeValue, c.UserSubscription, c.UserSubscription,
} { } {
n.Intercept(interceptors...) n.Intercept(interceptors...)
} }
@@ -276,12 +276,12 @@ func (c *Client) Intercept(interceptors ...Interceptor) {
// Mutate implements the ent.Mutator interface. // Mutate implements the ent.Mutator interface.
func (c *Client) Mutate(ctx context.Context, m Mutation) (Value, error) { func (c *Client) Mutate(ctx context.Context, m Mutation) (Value, error) {
switch m := m.(type) { switch m := m.(type) {
case *APIKeyMutation:
return c.APIKey.mutate(ctx, m)
case *AccountMutation: case *AccountMutation:
return c.Account.mutate(ctx, m) return c.Account.mutate(ctx, m)
case *AccountGroupMutation: case *AccountGroupMutation:
return c.AccountGroup.mutate(ctx, m) return c.AccountGroup.mutate(ctx, m)
case *ApiKeyMutation:
return c.ApiKey.mutate(ctx, m)
case *GroupMutation: case *GroupMutation:
return c.Group.mutate(ctx, m) return c.Group.mutate(ctx, m)
case *ProxyMutation: case *ProxyMutation:
@@ -307,6 +307,189 @@ func (c *Client) Mutate(ctx context.Context, m Mutation) (Value, error) {
} }
} }
// APIKeyClient is a client for the APIKey schema.
type APIKeyClient struct {
config
}
// NewAPIKeyClient returns a client for the APIKey from the given config.
func NewAPIKeyClient(c config) *APIKeyClient {
return &APIKeyClient{config: c}
}
// Use adds a list of mutation hooks to the hooks stack.
// A call to `Use(f, g, h)` equals to `apikey.Hooks(f(g(h())))`.
func (c *APIKeyClient) Use(hooks ...Hook) {
c.hooks.APIKey = append(c.hooks.APIKey, hooks...)
}
// Intercept adds a list of query interceptors to the interceptors stack.
// A call to `Intercept(f, g, h)` equals to `apikey.Intercept(f(g(h())))`.
func (c *APIKeyClient) Intercept(interceptors ...Interceptor) {
c.inters.APIKey = append(c.inters.APIKey, interceptors...)
}
// Create returns a builder for creating a APIKey entity.
func (c *APIKeyClient) Create() *APIKeyCreate {
mutation := newAPIKeyMutation(c.config, OpCreate)
return &APIKeyCreate{config: c.config, hooks: c.Hooks(), mutation: mutation}
}
// CreateBulk returns a builder for creating a bulk of APIKey entities.
func (c *APIKeyClient) CreateBulk(builders ...*APIKeyCreate) *APIKeyCreateBulk {
return &APIKeyCreateBulk{config: c.config, builders: builders}
}
// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates
// a builder and applies setFunc on it.
func (c *APIKeyClient) MapCreateBulk(slice any, setFunc func(*APIKeyCreate, int)) *APIKeyCreateBulk {
rv := reflect.ValueOf(slice)
if rv.Kind() != reflect.Slice {
return &APIKeyCreateBulk{err: fmt.Errorf("calling to APIKeyClient.MapCreateBulk with wrong type %T, need slice", slice)}
}
builders := make([]*APIKeyCreate, rv.Len())
for i := 0; i < rv.Len(); i++ {
builders[i] = c.Create()
setFunc(builders[i], i)
}
return &APIKeyCreateBulk{config: c.config, builders: builders}
}
// Update returns an update builder for APIKey.
func (c *APIKeyClient) Update() *APIKeyUpdate {
mutation := newAPIKeyMutation(c.config, OpUpdate)
return &APIKeyUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation}
}
// UpdateOne returns an update builder for the given entity.
func (c *APIKeyClient) UpdateOne(_m *APIKey) *APIKeyUpdateOne {
mutation := newAPIKeyMutation(c.config, OpUpdateOne, withAPIKey(_m))
return &APIKeyUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
}
// UpdateOneID returns an update builder for the given id.
func (c *APIKeyClient) UpdateOneID(id int64) *APIKeyUpdateOne {
mutation := newAPIKeyMutation(c.config, OpUpdateOne, withAPIKeyID(id))
return &APIKeyUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
}
// Delete returns a delete builder for APIKey.
func (c *APIKeyClient) Delete() *APIKeyDelete {
mutation := newAPIKeyMutation(c.config, OpDelete)
return &APIKeyDelete{config: c.config, hooks: c.Hooks(), mutation: mutation}
}
// DeleteOne returns a builder for deleting the given entity.
func (c *APIKeyClient) DeleteOne(_m *APIKey) *APIKeyDeleteOne {
return c.DeleteOneID(_m.ID)
}
// DeleteOneID returns a builder for deleting the given entity by its id.
func (c *APIKeyClient) DeleteOneID(id int64) *APIKeyDeleteOne {
builder := c.Delete().Where(apikey.ID(id))
builder.mutation.id = &id
builder.mutation.op = OpDeleteOne
return &APIKeyDeleteOne{builder}
}
// Query returns a query builder for APIKey.
func (c *APIKeyClient) Query() *APIKeyQuery {
return &APIKeyQuery{
config: c.config,
ctx: &QueryContext{Type: TypeAPIKey},
inters: c.Interceptors(),
}
}
// Get returns a APIKey entity by its id.
func (c *APIKeyClient) Get(ctx context.Context, id int64) (*APIKey, error) {
return c.Query().Where(apikey.ID(id)).Only(ctx)
}
// GetX is like Get, but panics if an error occurs.
func (c *APIKeyClient) GetX(ctx context.Context, id int64) *APIKey {
obj, err := c.Get(ctx, id)
if err != nil {
panic(err)
}
return obj
}
// QueryUser queries the user edge of a APIKey.
func (c *APIKeyClient) QueryUser(_m *APIKey) *UserQuery {
query := (&UserClient{config: c.config}).Query()
query.path = func(context.Context) (fromV *sql.Selector, _ error) {
id := _m.ID
step := sqlgraph.NewStep(
sqlgraph.From(apikey.Table, apikey.FieldID, id),
sqlgraph.To(user.Table, user.FieldID),
sqlgraph.Edge(sqlgraph.M2O, true, apikey.UserTable, apikey.UserColumn),
)
fromV = sqlgraph.Neighbors(_m.driver.Dialect(), step)
return fromV, nil
}
return query
}
// QueryGroup queries the group edge of a APIKey.
func (c *APIKeyClient) QueryGroup(_m *APIKey) *GroupQuery {
query := (&GroupClient{config: c.config}).Query()
query.path = func(context.Context) (fromV *sql.Selector, _ error) {
id := _m.ID
step := sqlgraph.NewStep(
sqlgraph.From(apikey.Table, apikey.FieldID, id),
sqlgraph.To(group.Table, group.FieldID),
sqlgraph.Edge(sqlgraph.M2O, true, apikey.GroupTable, apikey.GroupColumn),
)
fromV = sqlgraph.Neighbors(_m.driver.Dialect(), step)
return fromV, nil
}
return query
}
// QueryUsageLogs queries the usage_logs edge of a APIKey.
func (c *APIKeyClient) QueryUsageLogs(_m *APIKey) *UsageLogQuery {
query := (&UsageLogClient{config: c.config}).Query()
query.path = func(context.Context) (fromV *sql.Selector, _ error) {
id := _m.ID
step := sqlgraph.NewStep(
sqlgraph.From(apikey.Table, apikey.FieldID, id),
sqlgraph.To(usagelog.Table, usagelog.FieldID),
sqlgraph.Edge(sqlgraph.O2M, false, apikey.UsageLogsTable, apikey.UsageLogsColumn),
)
fromV = sqlgraph.Neighbors(_m.driver.Dialect(), step)
return fromV, nil
}
return query
}
// Hooks returns the client hooks.
func (c *APIKeyClient) Hooks() []Hook {
hooks := c.hooks.APIKey
return append(hooks[:len(hooks):len(hooks)], apikey.Hooks[:]...)
}
// Interceptors returns the client interceptors.
func (c *APIKeyClient) Interceptors() []Interceptor {
inters := c.inters.APIKey
return append(inters[:len(inters):len(inters)], apikey.Interceptors[:]...)
}
func (c *APIKeyClient) mutate(ctx context.Context, m *APIKeyMutation) (Value, error) {
switch m.Op() {
case OpCreate:
return (&APIKeyCreate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
case OpUpdate:
return (&APIKeyUpdate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
case OpUpdateOne:
return (&APIKeyUpdateOne{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
case OpDelete, OpDeleteOne:
return (&APIKeyDelete{config: c.config, hooks: c.Hooks(), mutation: m}).Exec(ctx)
default:
return nil, fmt.Errorf("ent: unknown APIKey mutation op: %q", m.Op())
}
}
// AccountClient is a client for the Account schema. // AccountClient is a client for the Account schema.
type AccountClient struct { type AccountClient struct {
config config
@@ -622,189 +805,6 @@ func (c *AccountGroupClient) mutate(ctx context.Context, m *AccountGroupMutation
} }
} }
// ApiKeyClient is a client for the ApiKey schema.
type ApiKeyClient struct {
config
}
// NewApiKeyClient returns a client for the ApiKey from the given config.
func NewApiKeyClient(c config) *ApiKeyClient {
return &ApiKeyClient{config: c}
}
// Use adds a list of mutation hooks to the hooks stack.
// A call to `Use(f, g, h)` equals to `apikey.Hooks(f(g(h())))`.
func (c *ApiKeyClient) Use(hooks ...Hook) {
c.hooks.ApiKey = append(c.hooks.ApiKey, hooks...)
}
// Intercept adds a list of query interceptors to the interceptors stack.
// A call to `Intercept(f, g, h)` equals to `apikey.Intercept(f(g(h())))`.
func (c *ApiKeyClient) Intercept(interceptors ...Interceptor) {
c.inters.ApiKey = append(c.inters.ApiKey, interceptors...)
}
// Create returns a builder for creating a ApiKey entity.
func (c *ApiKeyClient) Create() *ApiKeyCreate {
mutation := newApiKeyMutation(c.config, OpCreate)
return &ApiKeyCreate{config: c.config, hooks: c.Hooks(), mutation: mutation}
}
// CreateBulk returns a builder for creating a bulk of ApiKey entities.
func (c *ApiKeyClient) CreateBulk(builders ...*ApiKeyCreate) *ApiKeyCreateBulk {
return &ApiKeyCreateBulk{config: c.config, builders: builders}
}
// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates
// a builder and applies setFunc on it.
func (c *ApiKeyClient) MapCreateBulk(slice any, setFunc func(*ApiKeyCreate, int)) *ApiKeyCreateBulk {
rv := reflect.ValueOf(slice)
if rv.Kind() != reflect.Slice {
return &ApiKeyCreateBulk{err: fmt.Errorf("calling to ApiKeyClient.MapCreateBulk with wrong type %T, need slice", slice)}
}
builders := make([]*ApiKeyCreate, rv.Len())
for i := 0; i < rv.Len(); i++ {
builders[i] = c.Create()
setFunc(builders[i], i)
}
return &ApiKeyCreateBulk{config: c.config, builders: builders}
}
// Update returns an update builder for ApiKey.
func (c *ApiKeyClient) Update() *ApiKeyUpdate {
mutation := newApiKeyMutation(c.config, OpUpdate)
return &ApiKeyUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation}
}
// UpdateOne returns an update builder for the given entity.
func (c *ApiKeyClient) UpdateOne(_m *ApiKey) *ApiKeyUpdateOne {
mutation := newApiKeyMutation(c.config, OpUpdateOne, withApiKey(_m))
return &ApiKeyUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
}
// UpdateOneID returns an update builder for the given id.
func (c *ApiKeyClient) UpdateOneID(id int64) *ApiKeyUpdateOne {
mutation := newApiKeyMutation(c.config, OpUpdateOne, withApiKeyID(id))
return &ApiKeyUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
}
// Delete returns a delete builder for ApiKey.
func (c *ApiKeyClient) Delete() *ApiKeyDelete {
mutation := newApiKeyMutation(c.config, OpDelete)
return &ApiKeyDelete{config: c.config, hooks: c.Hooks(), mutation: mutation}
}
// DeleteOne returns a builder for deleting the given entity.
func (c *ApiKeyClient) DeleteOne(_m *ApiKey) *ApiKeyDeleteOne {
return c.DeleteOneID(_m.ID)
}
// DeleteOneID returns a builder for deleting the given entity by its id.
func (c *ApiKeyClient) DeleteOneID(id int64) *ApiKeyDeleteOne {
builder := c.Delete().Where(apikey.ID(id))
builder.mutation.id = &id
builder.mutation.op = OpDeleteOne
return &ApiKeyDeleteOne{builder}
}
// Query returns a query builder for ApiKey.
func (c *ApiKeyClient) Query() *ApiKeyQuery {
return &ApiKeyQuery{
config: c.config,
ctx: &QueryContext{Type: TypeApiKey},
inters: c.Interceptors(),
}
}
// Get returns a ApiKey entity by its id.
func (c *ApiKeyClient) Get(ctx context.Context, id int64) (*ApiKey, error) {
return c.Query().Where(apikey.ID(id)).Only(ctx)
}
// GetX is like Get, but panics if an error occurs.
func (c *ApiKeyClient) GetX(ctx context.Context, id int64) *ApiKey {
obj, err := c.Get(ctx, id)
if err != nil {
panic(err)
}
return obj
}
// QueryUser queries the user edge of a ApiKey.
func (c *ApiKeyClient) QueryUser(_m *ApiKey) *UserQuery {
query := (&UserClient{config: c.config}).Query()
query.path = func(context.Context) (fromV *sql.Selector, _ error) {
id := _m.ID
step := sqlgraph.NewStep(
sqlgraph.From(apikey.Table, apikey.FieldID, id),
sqlgraph.To(user.Table, user.FieldID),
sqlgraph.Edge(sqlgraph.M2O, true, apikey.UserTable, apikey.UserColumn),
)
fromV = sqlgraph.Neighbors(_m.driver.Dialect(), step)
return fromV, nil
}
return query
}
// QueryGroup queries the group edge of a ApiKey.
func (c *ApiKeyClient) QueryGroup(_m *ApiKey) *GroupQuery {
query := (&GroupClient{config: c.config}).Query()
query.path = func(context.Context) (fromV *sql.Selector, _ error) {
id := _m.ID
step := sqlgraph.NewStep(
sqlgraph.From(apikey.Table, apikey.FieldID, id),
sqlgraph.To(group.Table, group.FieldID),
sqlgraph.Edge(sqlgraph.M2O, true, apikey.GroupTable, apikey.GroupColumn),
)
fromV = sqlgraph.Neighbors(_m.driver.Dialect(), step)
return fromV, nil
}
return query
}
// QueryUsageLogs queries the usage_logs edge of a ApiKey.
func (c *ApiKeyClient) QueryUsageLogs(_m *ApiKey) *UsageLogQuery {
query := (&UsageLogClient{config: c.config}).Query()
query.path = func(context.Context) (fromV *sql.Selector, _ error) {
id := _m.ID
step := sqlgraph.NewStep(
sqlgraph.From(apikey.Table, apikey.FieldID, id),
sqlgraph.To(usagelog.Table, usagelog.FieldID),
sqlgraph.Edge(sqlgraph.O2M, false, apikey.UsageLogsTable, apikey.UsageLogsColumn),
)
fromV = sqlgraph.Neighbors(_m.driver.Dialect(), step)
return fromV, nil
}
return query
}
// Hooks returns the client hooks.
func (c *ApiKeyClient) Hooks() []Hook {
hooks := c.hooks.ApiKey
return append(hooks[:len(hooks):len(hooks)], apikey.Hooks[:]...)
}
// Interceptors returns the client interceptors.
func (c *ApiKeyClient) Interceptors() []Interceptor {
inters := c.inters.ApiKey
return append(inters[:len(inters):len(inters)], apikey.Interceptors[:]...)
}
func (c *ApiKeyClient) mutate(ctx context.Context, m *ApiKeyMutation) (Value, error) {
switch m.Op() {
case OpCreate:
return (&ApiKeyCreate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
case OpUpdate:
return (&ApiKeyUpdate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
case OpUpdateOne:
return (&ApiKeyUpdateOne{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
case OpDelete, OpDeleteOne:
return (&ApiKeyDelete{config: c.config, hooks: c.Hooks(), mutation: m}).Exec(ctx)
default:
return nil, fmt.Errorf("ent: unknown ApiKey mutation op: %q", m.Op())
}
}
// GroupClient is a client for the Group schema. // GroupClient is a client for the Group schema.
type GroupClient struct { type GroupClient struct {
config config
@@ -914,8 +914,8 @@ func (c *GroupClient) GetX(ctx context.Context, id int64) *Group {
} }
// QueryAPIKeys queries the api_keys edge of a Group. // QueryAPIKeys queries the api_keys edge of a Group.
func (c *GroupClient) QueryAPIKeys(_m *Group) *ApiKeyQuery { func (c *GroupClient) QueryAPIKeys(_m *Group) *APIKeyQuery {
query := (&ApiKeyClient{config: c.config}).Query() query := (&APIKeyClient{config: c.config}).Query()
query.path = func(context.Context) (fromV *sql.Selector, _ error) { query.path = func(context.Context) (fromV *sql.Selector, _ error) {
id := _m.ID id := _m.ID
step := sqlgraph.NewStep( step := sqlgraph.NewStep(
@@ -1642,8 +1642,8 @@ func (c *UsageLogClient) QueryUser(_m *UsageLog) *UserQuery {
} }
// QueryAPIKey queries the api_key edge of a UsageLog. // QueryAPIKey queries the api_key edge of a UsageLog.
func (c *UsageLogClient) QueryAPIKey(_m *UsageLog) *ApiKeyQuery { func (c *UsageLogClient) QueryAPIKey(_m *UsageLog) *APIKeyQuery {
query := (&ApiKeyClient{config: c.config}).Query() query := (&APIKeyClient{config: c.config}).Query()
query.path = func(context.Context) (fromV *sql.Selector, _ error) { query.path = func(context.Context) (fromV *sql.Selector, _ error) {
id := _m.ID id := _m.ID
step := sqlgraph.NewStep( step := sqlgraph.NewStep(
@@ -1839,8 +1839,8 @@ func (c *UserClient) GetX(ctx context.Context, id int64) *User {
} }
// QueryAPIKeys queries the api_keys edge of a User. // QueryAPIKeys queries the api_keys edge of a User.
func (c *UserClient) QueryAPIKeys(_m *User) *ApiKeyQuery { func (c *UserClient) QueryAPIKeys(_m *User) *APIKeyQuery {
query := (&ApiKeyClient{config: c.config}).Query() query := (&APIKeyClient{config: c.config}).Query()
query.path = func(context.Context) (fromV *sql.Selector, _ error) { query.path = func(context.Context) (fromV *sql.Selector, _ error) {
id := _m.ID id := _m.ID
step := sqlgraph.NewStep( step := sqlgraph.NewStep(
@@ -2627,12 +2627,12 @@ func (c *UserSubscriptionClient) mutate(ctx context.Context, m *UserSubscription
// hooks and interceptors per client, for fast access. // hooks and interceptors per client, for fast access.
type ( type (
hooks struct { hooks struct {
Account, AccountGroup, ApiKey, Group, Proxy, RedeemCode, Setting, UsageLog, APIKey, Account, AccountGroup, Group, Proxy, RedeemCode, Setting, UsageLog,
User, UserAllowedGroup, UserAttributeDefinition, UserAttributeValue, User, UserAllowedGroup, UserAttributeDefinition, UserAttributeValue,
UserSubscription []ent.Hook UserSubscription []ent.Hook
} }
inters struct { inters struct {
Account, AccountGroup, ApiKey, Group, Proxy, RedeemCode, Setting, UsageLog, APIKey, Account, AccountGroup, Group, Proxy, RedeemCode, Setting, UsageLog,
User, UserAllowedGroup, UserAttributeDefinition, UserAttributeValue, User, UserAllowedGroup, UserAttributeDefinition, UserAttributeValue,
UserSubscription []ent.Interceptor UserSubscription []ent.Interceptor
} }

View File

@@ -1,3 +1,4 @@
// Package ent provides database entity definitions and operations.
package ent package ent
import "entgo.io/ent/dialect" import "entgo.io/ent/dialect"

View File

@@ -54,7 +54,7 @@ type Group struct {
// GroupEdges holds the relations/edges for other nodes in the graph. // GroupEdges holds the relations/edges for other nodes in the graph.
type GroupEdges struct { type GroupEdges struct {
// APIKeys holds the value of the api_keys edge. // APIKeys holds the value of the api_keys edge.
APIKeys []*ApiKey `json:"api_keys,omitempty"` APIKeys []*APIKey `json:"api_keys,omitempty"`
// RedeemCodes holds the value of the redeem_codes edge. // RedeemCodes holds the value of the redeem_codes edge.
RedeemCodes []*RedeemCode `json:"redeem_codes,omitempty"` RedeemCodes []*RedeemCode `json:"redeem_codes,omitempty"`
// Subscriptions holds the value of the subscriptions edge. // Subscriptions holds the value of the subscriptions edge.
@@ -76,7 +76,7 @@ type GroupEdges struct {
// APIKeysOrErr returns the APIKeys value or an error if the edge // APIKeysOrErr returns the APIKeys value or an error if the edge
// was not loaded in eager-loading. // was not loaded in eager-loading.
func (e GroupEdges) APIKeysOrErr() ([]*ApiKey, error) { func (e GroupEdges) APIKeysOrErr() ([]*APIKey, error) {
if e.loadedTypes[0] { if e.loadedTypes[0] {
return e.APIKeys, nil return e.APIKeys, nil
} }
@@ -285,7 +285,7 @@ func (_m *Group) Value(name string) (ent.Value, error) {
} }
// QueryAPIKeys queries the "api_keys" edge of the Group entity. // QueryAPIKeys queries the "api_keys" edge of the Group entity.
func (_m *Group) QueryAPIKeys() *ApiKeyQuery { func (_m *Group) QueryAPIKeys() *APIKeyQuery {
return NewGroupClient(_m.config).QueryAPIKeys(_m) return NewGroupClient(_m.config).QueryAPIKeys(_m)
} }

View File

@@ -63,7 +63,7 @@ const (
Table = "groups" Table = "groups"
// APIKeysTable is the table that holds the api_keys relation/edge. // APIKeysTable is the table that holds the api_keys relation/edge.
APIKeysTable = "api_keys" APIKeysTable = "api_keys"
// APIKeysInverseTable is the table name for the ApiKey entity. // APIKeysInverseTable is the table name for the APIKey entity.
// It exists in this package in order to avoid circular dependency with the "apikey" package. // It exists in this package in order to avoid circular dependency with the "apikey" package.
APIKeysInverseTable = "api_keys" APIKeysInverseTable = "api_keys"
// APIKeysColumn is the table column denoting the api_keys relation/edge. // APIKeysColumn is the table column denoting the api_keys relation/edge.

View File

@@ -842,7 +842,7 @@ func HasAPIKeys() predicate.Group {
} }
// HasAPIKeysWith applies the HasEdge predicate on the "api_keys" edge with a given conditions (other predicates). // HasAPIKeysWith applies the HasEdge predicate on the "api_keys" edge with a given conditions (other predicates).
func HasAPIKeysWith(preds ...predicate.ApiKey) predicate.Group { func HasAPIKeysWith(preds ...predicate.APIKey) predicate.Group {
return predicate.Group(func(s *sql.Selector) { return predicate.Group(func(s *sql.Selector) {
step := newAPIKeysStep() step := newAPIKeysStep()
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {

View File

@@ -216,14 +216,14 @@ func (_c *GroupCreate) SetNillableDefaultValidityDays(v *int) *GroupCreate {
return _c return _c
} }
// AddAPIKeyIDs adds the "api_keys" edge to the ApiKey entity by IDs. // AddAPIKeyIDs adds the "api_keys" edge to the APIKey entity by IDs.
func (_c *GroupCreate) AddAPIKeyIDs(ids ...int64) *GroupCreate { func (_c *GroupCreate) AddAPIKeyIDs(ids ...int64) *GroupCreate {
_c.mutation.AddAPIKeyIDs(ids...) _c.mutation.AddAPIKeyIDs(ids...)
return _c return _c
} }
// AddAPIKeys adds the "api_keys" edges to the ApiKey entity. // AddAPIKeys adds the "api_keys" edges to the APIKey entity.
func (_c *GroupCreate) AddAPIKeys(v ...*ApiKey) *GroupCreate { func (_c *GroupCreate) AddAPIKeys(v ...*APIKey) *GroupCreate {
ids := make([]int64, len(v)) ids := make([]int64, len(v))
for i := range v { for i := range v {
ids[i] = v[i].ID ids[i] = v[i].ID

View File

@@ -31,7 +31,7 @@ type GroupQuery struct {
order []group.OrderOption order []group.OrderOption
inters []Interceptor inters []Interceptor
predicates []predicate.Group predicates []predicate.Group
withAPIKeys *ApiKeyQuery withAPIKeys *APIKeyQuery
withRedeemCodes *RedeemCodeQuery withRedeemCodes *RedeemCodeQuery
withSubscriptions *UserSubscriptionQuery withSubscriptions *UserSubscriptionQuery
withUsageLogs *UsageLogQuery withUsageLogs *UsageLogQuery
@@ -76,8 +76,8 @@ func (_q *GroupQuery) Order(o ...group.OrderOption) *GroupQuery {
} }
// QueryAPIKeys chains the current query on the "api_keys" edge. // QueryAPIKeys chains the current query on the "api_keys" edge.
func (_q *GroupQuery) QueryAPIKeys() *ApiKeyQuery { func (_q *GroupQuery) QueryAPIKeys() *APIKeyQuery {
query := (&ApiKeyClient{config: _q.config}).Query() query := (&APIKeyClient{config: _q.config}).Query()
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) { query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
if err := _q.prepareQuery(ctx); err != nil { if err := _q.prepareQuery(ctx); err != nil {
return nil, err return nil, err
@@ -459,8 +459,8 @@ func (_q *GroupQuery) Clone() *GroupQuery {
// WithAPIKeys tells the query-builder to eager-load the nodes that are connected to // WithAPIKeys tells the query-builder to eager-load the nodes that are connected to
// the "api_keys" edge. The optional arguments are used to configure the query builder of the edge. // the "api_keys" edge. The optional arguments are used to configure the query builder of the edge.
func (_q *GroupQuery) WithAPIKeys(opts ...func(*ApiKeyQuery)) *GroupQuery { func (_q *GroupQuery) WithAPIKeys(opts ...func(*APIKeyQuery)) *GroupQuery {
query := (&ApiKeyClient{config: _q.config}).Query() query := (&APIKeyClient{config: _q.config}).Query()
for _, opt := range opts { for _, opt := range opts {
opt(query) opt(query)
} }
@@ -654,8 +654,8 @@ func (_q *GroupQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Group,
} }
if query := _q.withAPIKeys; query != nil { if query := _q.withAPIKeys; query != nil {
if err := _q.loadAPIKeys(ctx, query, nodes, if err := _q.loadAPIKeys(ctx, query, nodes,
func(n *Group) { n.Edges.APIKeys = []*ApiKey{} }, func(n *Group) { n.Edges.APIKeys = []*APIKey{} },
func(n *Group, e *ApiKey) { n.Edges.APIKeys = append(n.Edges.APIKeys, e) }); err != nil { func(n *Group, e *APIKey) { n.Edges.APIKeys = append(n.Edges.APIKeys, e) }); err != nil {
return nil, err return nil, err
} }
} }
@@ -711,7 +711,7 @@ func (_q *GroupQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Group,
return nodes, nil return nodes, nil
} }
func (_q *GroupQuery) loadAPIKeys(ctx context.Context, query *ApiKeyQuery, nodes []*Group, init func(*Group), assign func(*Group, *ApiKey)) error { func (_q *GroupQuery) loadAPIKeys(ctx context.Context, query *APIKeyQuery, nodes []*Group, init func(*Group), assign func(*Group, *APIKey)) error {
fks := make([]driver.Value, 0, len(nodes)) fks := make([]driver.Value, 0, len(nodes))
nodeids := make(map[int64]*Group) nodeids := make(map[int64]*Group)
for i := range nodes { for i := range nodes {
@@ -724,7 +724,7 @@ func (_q *GroupQuery) loadAPIKeys(ctx context.Context, query *ApiKeyQuery, nodes
if len(query.ctx.Fields) > 0 { if len(query.ctx.Fields) > 0 {
query.ctx.AppendFieldOnce(apikey.FieldGroupID) query.ctx.AppendFieldOnce(apikey.FieldGroupID)
} }
query.Where(predicate.ApiKey(func(s *sql.Selector) { query.Where(predicate.APIKey(func(s *sql.Selector) {
s.Where(sql.InValues(s.C(group.APIKeysColumn), fks...)) s.Where(sql.InValues(s.C(group.APIKeysColumn), fks...))
})) }))
neighbors, err := query.All(ctx) neighbors, err := query.All(ctx)

View File

@@ -273,14 +273,14 @@ func (_u *GroupUpdate) AddDefaultValidityDays(v int) *GroupUpdate {
return _u return _u
} }
// AddAPIKeyIDs adds the "api_keys" edge to the ApiKey entity by IDs. // AddAPIKeyIDs adds the "api_keys" edge to the APIKey entity by IDs.
func (_u *GroupUpdate) AddAPIKeyIDs(ids ...int64) *GroupUpdate { func (_u *GroupUpdate) AddAPIKeyIDs(ids ...int64) *GroupUpdate {
_u.mutation.AddAPIKeyIDs(ids...) _u.mutation.AddAPIKeyIDs(ids...)
return _u return _u
} }
// AddAPIKeys adds the "api_keys" edges to the ApiKey entity. // AddAPIKeys adds the "api_keys" edges to the APIKey entity.
func (_u *GroupUpdate) AddAPIKeys(v ...*ApiKey) *GroupUpdate { func (_u *GroupUpdate) AddAPIKeys(v ...*APIKey) *GroupUpdate {
ids := make([]int64, len(v)) ids := make([]int64, len(v))
for i := range v { for i := range v {
ids[i] = v[i].ID ids[i] = v[i].ID
@@ -368,20 +368,20 @@ func (_u *GroupUpdate) Mutation() *GroupMutation {
return _u.mutation return _u.mutation
} }
// ClearAPIKeys clears all "api_keys" edges to the ApiKey entity. // ClearAPIKeys clears all "api_keys" edges to the APIKey entity.
func (_u *GroupUpdate) ClearAPIKeys() *GroupUpdate { func (_u *GroupUpdate) ClearAPIKeys() *GroupUpdate {
_u.mutation.ClearAPIKeys() _u.mutation.ClearAPIKeys()
return _u return _u
} }
// RemoveAPIKeyIDs removes the "api_keys" edge to ApiKey entities by IDs. // RemoveAPIKeyIDs removes the "api_keys" edge to APIKey entities by IDs.
func (_u *GroupUpdate) RemoveAPIKeyIDs(ids ...int64) *GroupUpdate { func (_u *GroupUpdate) RemoveAPIKeyIDs(ids ...int64) *GroupUpdate {
_u.mutation.RemoveAPIKeyIDs(ids...) _u.mutation.RemoveAPIKeyIDs(ids...)
return _u return _u
} }
// RemoveAPIKeys removes "api_keys" edges to ApiKey entities. // RemoveAPIKeys removes "api_keys" edges to APIKey entities.
func (_u *GroupUpdate) RemoveAPIKeys(v ...*ApiKey) *GroupUpdate { func (_u *GroupUpdate) RemoveAPIKeys(v ...*APIKey) *GroupUpdate {
ids := make([]int64, len(v)) ids := make([]int64, len(v))
for i := range v { for i := range v {
ids[i] = v[i].ID ids[i] = v[i].ID
@@ -1195,14 +1195,14 @@ func (_u *GroupUpdateOne) AddDefaultValidityDays(v int) *GroupUpdateOne {
return _u return _u
} }
// AddAPIKeyIDs adds the "api_keys" edge to the ApiKey entity by IDs. // AddAPIKeyIDs adds the "api_keys" edge to the APIKey entity by IDs.
func (_u *GroupUpdateOne) AddAPIKeyIDs(ids ...int64) *GroupUpdateOne { func (_u *GroupUpdateOne) AddAPIKeyIDs(ids ...int64) *GroupUpdateOne {
_u.mutation.AddAPIKeyIDs(ids...) _u.mutation.AddAPIKeyIDs(ids...)
return _u return _u
} }
// AddAPIKeys adds the "api_keys" edges to the ApiKey entity. // AddAPIKeys adds the "api_keys" edges to the APIKey entity.
func (_u *GroupUpdateOne) AddAPIKeys(v ...*ApiKey) *GroupUpdateOne { func (_u *GroupUpdateOne) AddAPIKeys(v ...*APIKey) *GroupUpdateOne {
ids := make([]int64, len(v)) ids := make([]int64, len(v))
for i := range v { for i := range v {
ids[i] = v[i].ID ids[i] = v[i].ID
@@ -1290,20 +1290,20 @@ func (_u *GroupUpdateOne) Mutation() *GroupMutation {
return _u.mutation return _u.mutation
} }
// ClearAPIKeys clears all "api_keys" edges to the ApiKey entity. // ClearAPIKeys clears all "api_keys" edges to the APIKey entity.
func (_u *GroupUpdateOne) ClearAPIKeys() *GroupUpdateOne { func (_u *GroupUpdateOne) ClearAPIKeys() *GroupUpdateOne {
_u.mutation.ClearAPIKeys() _u.mutation.ClearAPIKeys()
return _u return _u
} }
// RemoveAPIKeyIDs removes the "api_keys" edge to ApiKey entities by IDs. // RemoveAPIKeyIDs removes the "api_keys" edge to APIKey entities by IDs.
func (_u *GroupUpdateOne) RemoveAPIKeyIDs(ids ...int64) *GroupUpdateOne { func (_u *GroupUpdateOne) RemoveAPIKeyIDs(ids ...int64) *GroupUpdateOne {
_u.mutation.RemoveAPIKeyIDs(ids...) _u.mutation.RemoveAPIKeyIDs(ids...)
return _u return _u
} }
// RemoveAPIKeys removes "api_keys" edges to ApiKey entities. // RemoveAPIKeys removes "api_keys" edges to APIKey entities.
func (_u *GroupUpdateOne) RemoveAPIKeys(v ...*ApiKey) *GroupUpdateOne { func (_u *GroupUpdateOne) RemoveAPIKeys(v ...*APIKey) *GroupUpdateOne {
ids := make([]int64, len(v)) ids := make([]int64, len(v))
for i := range v { for i := range v {
ids[i] = v[i].ID ids[i] = v[i].ID

View File

@@ -9,6 +9,18 @@ import (
"github.com/Wei-Shaw/sub2api/ent" "github.com/Wei-Shaw/sub2api/ent"
) )
// The APIKeyFunc type is an adapter to allow the use of ordinary
// function as APIKey mutator.
type APIKeyFunc func(context.Context, *ent.APIKeyMutation) (ent.Value, error)
// Mutate calls f(ctx, m).
func (f APIKeyFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
if mv, ok := m.(*ent.APIKeyMutation); ok {
return f(ctx, mv)
}
return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.APIKeyMutation", m)
}
// The AccountFunc type is an adapter to allow the use of ordinary // The AccountFunc type is an adapter to allow the use of ordinary
// function as Account mutator. // function as Account mutator.
type AccountFunc func(context.Context, *ent.AccountMutation) (ent.Value, error) type AccountFunc func(context.Context, *ent.AccountMutation) (ent.Value, error)
@@ -33,18 +45,6 @@ func (f AccountGroupFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value
return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.AccountGroupMutation", m) return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.AccountGroupMutation", m)
} }
// The ApiKeyFunc type is an adapter to allow the use of ordinary
// function as ApiKey mutator.
type ApiKeyFunc func(context.Context, *ent.ApiKeyMutation) (ent.Value, error)
// Mutate calls f(ctx, m).
func (f ApiKeyFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
if mv, ok := m.(*ent.ApiKeyMutation); ok {
return f(ctx, mv)
}
return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.ApiKeyMutation", m)
}
// The GroupFunc type is an adapter to allow the use of ordinary // The GroupFunc type is an adapter to allow the use of ordinary
// function as Group mutator. // function as Group mutator.
type GroupFunc func(context.Context, *ent.GroupMutation) (ent.Value, error) type GroupFunc func(context.Context, *ent.GroupMutation) (ent.Value, error)

View File

@@ -80,6 +80,33 @@ func (f TraverseFunc) Traverse(ctx context.Context, q ent.Query) error {
return f(ctx, query) return f(ctx, query)
} }
// The APIKeyFunc type is an adapter to allow the use of ordinary function as a Querier.
type APIKeyFunc func(context.Context, *ent.APIKeyQuery) (ent.Value, error)
// Query calls f(ctx, q).
func (f APIKeyFunc) Query(ctx context.Context, q ent.Query) (ent.Value, error) {
if q, ok := q.(*ent.APIKeyQuery); ok {
return f(ctx, q)
}
return nil, fmt.Errorf("unexpected query type %T. expect *ent.APIKeyQuery", q)
}
// The TraverseAPIKey type is an adapter to allow the use of ordinary function as Traverser.
type TraverseAPIKey func(context.Context, *ent.APIKeyQuery) error
// Intercept is a dummy implementation of Intercept that returns the next Querier in the pipeline.
func (f TraverseAPIKey) Intercept(next ent.Querier) ent.Querier {
return next
}
// Traverse calls f(ctx, q).
func (f TraverseAPIKey) Traverse(ctx context.Context, q ent.Query) error {
if q, ok := q.(*ent.APIKeyQuery); ok {
return f(ctx, q)
}
return fmt.Errorf("unexpected query type %T. expect *ent.APIKeyQuery", q)
}
// The AccountFunc type is an adapter to allow the use of ordinary function as a Querier. // The AccountFunc type is an adapter to allow the use of ordinary function as a Querier.
type AccountFunc func(context.Context, *ent.AccountQuery) (ent.Value, error) type AccountFunc func(context.Context, *ent.AccountQuery) (ent.Value, error)
@@ -134,33 +161,6 @@ func (f TraverseAccountGroup) Traverse(ctx context.Context, q ent.Query) error {
return fmt.Errorf("unexpected query type %T. expect *ent.AccountGroupQuery", q) return fmt.Errorf("unexpected query type %T. expect *ent.AccountGroupQuery", q)
} }
// The ApiKeyFunc type is an adapter to allow the use of ordinary function as a Querier.
type ApiKeyFunc func(context.Context, *ent.ApiKeyQuery) (ent.Value, error)
// Query calls f(ctx, q).
func (f ApiKeyFunc) Query(ctx context.Context, q ent.Query) (ent.Value, error) {
if q, ok := q.(*ent.ApiKeyQuery); ok {
return f(ctx, q)
}
return nil, fmt.Errorf("unexpected query type %T. expect *ent.ApiKeyQuery", q)
}
// The TraverseApiKey type is an adapter to allow the use of ordinary function as Traverser.
type TraverseApiKey func(context.Context, *ent.ApiKeyQuery) error
// Intercept is a dummy implementation of Intercept that returns the next Querier in the pipeline.
func (f TraverseApiKey) Intercept(next ent.Querier) ent.Querier {
return next
}
// Traverse calls f(ctx, q).
func (f TraverseApiKey) Traverse(ctx context.Context, q ent.Query) error {
if q, ok := q.(*ent.ApiKeyQuery); ok {
return f(ctx, q)
}
return fmt.Errorf("unexpected query type %T. expect *ent.ApiKeyQuery", q)
}
// The GroupFunc type is an adapter to allow the use of ordinary function as a Querier. // The GroupFunc type is an adapter to allow the use of ordinary function as a Querier.
type GroupFunc func(context.Context, *ent.GroupQuery) (ent.Value, error) type GroupFunc func(context.Context, *ent.GroupQuery) (ent.Value, error)
@@ -434,12 +434,12 @@ func (f TraverseUserSubscription) Traverse(ctx context.Context, q ent.Query) err
// NewQuery returns the generic Query interface for the given typed query. // NewQuery returns the generic Query interface for the given typed query.
func NewQuery(q ent.Query) (Query, error) { func NewQuery(q ent.Query) (Query, error) {
switch q := q.(type) { switch q := q.(type) {
case *ent.APIKeyQuery:
return &query[*ent.APIKeyQuery, predicate.APIKey, apikey.OrderOption]{typ: ent.TypeAPIKey, tq: q}, nil
case *ent.AccountQuery: case *ent.AccountQuery:
return &query[*ent.AccountQuery, predicate.Account, account.OrderOption]{typ: ent.TypeAccount, tq: q}, nil return &query[*ent.AccountQuery, predicate.Account, account.OrderOption]{typ: ent.TypeAccount, tq: q}, nil
case *ent.AccountGroupQuery: case *ent.AccountGroupQuery:
return &query[*ent.AccountGroupQuery, predicate.AccountGroup, accountgroup.OrderOption]{typ: ent.TypeAccountGroup, tq: q}, nil return &query[*ent.AccountGroupQuery, predicate.AccountGroup, accountgroup.OrderOption]{typ: ent.TypeAccountGroup, tq: q}, nil
case *ent.ApiKeyQuery:
return &query[*ent.ApiKeyQuery, predicate.ApiKey, apikey.OrderOption]{typ: ent.TypeApiKey, tq: q}, nil
case *ent.GroupQuery: case *ent.GroupQuery:
return &query[*ent.GroupQuery, predicate.Group, group.OrderOption]{typ: ent.TypeGroup, tq: q}, nil return &query[*ent.GroupQuery, predicate.Group, group.OrderOption]{typ: ent.TypeGroup, tq: q}, nil
case *ent.ProxyQuery: case *ent.ProxyQuery:

View File

@@ -9,6 +9,60 @@ import (
) )
var ( var (
// APIKeysColumns holds the columns for the "api_keys" table.
APIKeysColumns = []*schema.Column{
{Name: "id", Type: field.TypeInt64, Increment: true},
{Name: "created_at", Type: field.TypeTime, SchemaType: map[string]string{"postgres": "timestamptz"}},
{Name: "updated_at", Type: field.TypeTime, SchemaType: map[string]string{"postgres": "timestamptz"}},
{Name: "deleted_at", Type: field.TypeTime, Nullable: true, SchemaType: map[string]string{"postgres": "timestamptz"}},
{Name: "key", Type: field.TypeString, Unique: true, Size: 128},
{Name: "name", Type: field.TypeString, Size: 100},
{Name: "status", Type: field.TypeString, Size: 20, Default: "active"},
{Name: "group_id", Type: field.TypeInt64, Nullable: true},
{Name: "user_id", Type: field.TypeInt64},
}
// APIKeysTable holds the schema information for the "api_keys" table.
APIKeysTable = &schema.Table{
Name: "api_keys",
Columns: APIKeysColumns,
PrimaryKey: []*schema.Column{APIKeysColumns[0]},
ForeignKeys: []*schema.ForeignKey{
{
Symbol: "api_keys_groups_api_keys",
Columns: []*schema.Column{APIKeysColumns[7]},
RefColumns: []*schema.Column{GroupsColumns[0]},
OnDelete: schema.SetNull,
},
{
Symbol: "api_keys_users_api_keys",
Columns: []*schema.Column{APIKeysColumns[8]},
RefColumns: []*schema.Column{UsersColumns[0]},
OnDelete: schema.NoAction,
},
},
Indexes: []*schema.Index{
{
Name: "apikey_user_id",
Unique: false,
Columns: []*schema.Column{APIKeysColumns[8]},
},
{
Name: "apikey_group_id",
Unique: false,
Columns: []*schema.Column{APIKeysColumns[7]},
},
{
Name: "apikey_status",
Unique: false,
Columns: []*schema.Column{APIKeysColumns[6]},
},
{
Name: "apikey_deleted_at",
Unique: false,
Columns: []*schema.Column{APIKeysColumns[3]},
},
},
}
// AccountsColumns holds the columns for the "accounts" table. // AccountsColumns holds the columns for the "accounts" table.
AccountsColumns = []*schema.Column{ AccountsColumns = []*schema.Column{
{Name: "id", Type: field.TypeInt64, Increment: true}, {Name: "id", Type: field.TypeInt64, Increment: true},
@@ -144,60 +198,6 @@ var (
}, },
}, },
} }
// APIKeysColumns holds the columns for the "api_keys" table.
APIKeysColumns = []*schema.Column{
{Name: "id", Type: field.TypeInt64, Increment: true},
{Name: "created_at", Type: field.TypeTime, SchemaType: map[string]string{"postgres": "timestamptz"}},
{Name: "updated_at", Type: field.TypeTime, SchemaType: map[string]string{"postgres": "timestamptz"}},
{Name: "deleted_at", Type: field.TypeTime, Nullable: true, SchemaType: map[string]string{"postgres": "timestamptz"}},
{Name: "key", Type: field.TypeString, Unique: true, Size: 128},
{Name: "name", Type: field.TypeString, Size: 100},
{Name: "status", Type: field.TypeString, Size: 20, Default: "active"},
{Name: "group_id", Type: field.TypeInt64, Nullable: true},
{Name: "user_id", Type: field.TypeInt64},
}
// APIKeysTable holds the schema information for the "api_keys" table.
APIKeysTable = &schema.Table{
Name: "api_keys",
Columns: APIKeysColumns,
PrimaryKey: []*schema.Column{APIKeysColumns[0]},
ForeignKeys: []*schema.ForeignKey{
{
Symbol: "api_keys_groups_api_keys",
Columns: []*schema.Column{APIKeysColumns[7]},
RefColumns: []*schema.Column{GroupsColumns[0]},
OnDelete: schema.SetNull,
},
{
Symbol: "api_keys_users_api_keys",
Columns: []*schema.Column{APIKeysColumns[8]},
RefColumns: []*schema.Column{UsersColumns[0]},
OnDelete: schema.NoAction,
},
},
Indexes: []*schema.Index{
{
Name: "apikey_user_id",
Unique: false,
Columns: []*schema.Column{APIKeysColumns[8]},
},
{
Name: "apikey_group_id",
Unique: false,
Columns: []*schema.Column{APIKeysColumns[7]},
},
{
Name: "apikey_status",
Unique: false,
Columns: []*schema.Column{APIKeysColumns[6]},
},
{
Name: "apikey_deleted_at",
Unique: false,
Columns: []*schema.Column{APIKeysColumns[3]},
},
},
}
// GroupsColumns holds the columns for the "groups" table. // GroupsColumns holds the columns for the "groups" table.
GroupsColumns = []*schema.Column{ GroupsColumns = []*schema.Column{
{Name: "id", Type: field.TypeInt64, Increment: true}, {Name: "id", Type: field.TypeInt64, Increment: true},
@@ -368,8 +368,8 @@ var (
{Name: "duration_ms", Type: field.TypeInt, Nullable: true}, {Name: "duration_ms", Type: field.TypeInt, Nullable: true},
{Name: "first_token_ms", Type: field.TypeInt, Nullable: true}, {Name: "first_token_ms", Type: field.TypeInt, Nullable: true},
{Name: "created_at", Type: field.TypeTime, SchemaType: map[string]string{"postgres": "timestamptz"}}, {Name: "created_at", Type: field.TypeTime, SchemaType: map[string]string{"postgres": "timestamptz"}},
{Name: "account_id", Type: field.TypeInt64},
{Name: "api_key_id", Type: field.TypeInt64}, {Name: "api_key_id", Type: field.TypeInt64},
{Name: "account_id", Type: field.TypeInt64},
{Name: "group_id", Type: field.TypeInt64, Nullable: true}, {Name: "group_id", Type: field.TypeInt64, Nullable: true},
{Name: "user_id", Type: field.TypeInt64}, {Name: "user_id", Type: field.TypeInt64},
{Name: "subscription_id", Type: field.TypeInt64, Nullable: true}, {Name: "subscription_id", Type: field.TypeInt64, Nullable: true},
@@ -381,15 +381,15 @@ var (
PrimaryKey: []*schema.Column{UsageLogsColumns[0]}, PrimaryKey: []*schema.Column{UsageLogsColumns[0]},
ForeignKeys: []*schema.ForeignKey{ ForeignKeys: []*schema.ForeignKey{
{ {
Symbol: "usage_logs_accounts_usage_logs", Symbol: "usage_logs_api_keys_usage_logs",
Columns: []*schema.Column{UsageLogsColumns[21]}, Columns: []*schema.Column{UsageLogsColumns[21]},
RefColumns: []*schema.Column{AccountsColumns[0]}, RefColumns: []*schema.Column{APIKeysColumns[0]},
OnDelete: schema.NoAction, OnDelete: schema.NoAction,
}, },
{ {
Symbol: "usage_logs_api_keys_usage_logs", Symbol: "usage_logs_accounts_usage_logs",
Columns: []*schema.Column{UsageLogsColumns[22]}, Columns: []*schema.Column{UsageLogsColumns[22]},
RefColumns: []*schema.Column{APIKeysColumns[0]}, RefColumns: []*schema.Column{AccountsColumns[0]},
OnDelete: schema.NoAction, OnDelete: schema.NoAction,
}, },
{ {
@@ -420,12 +420,12 @@ var (
{ {
Name: "usagelog_api_key_id", Name: "usagelog_api_key_id",
Unique: false, Unique: false,
Columns: []*schema.Column{UsageLogsColumns[22]}, Columns: []*schema.Column{UsageLogsColumns[21]},
}, },
{ {
Name: "usagelog_account_id", Name: "usagelog_account_id",
Unique: false, Unique: false,
Columns: []*schema.Column{UsageLogsColumns[21]}, Columns: []*schema.Column{UsageLogsColumns[22]},
}, },
{ {
Name: "usagelog_group_id", Name: "usagelog_group_id",
@@ -460,7 +460,7 @@ var (
{ {
Name: "usagelog_api_key_id_created_at", Name: "usagelog_api_key_id_created_at",
Unique: false, Unique: false,
Columns: []*schema.Column{UsageLogsColumns[22], UsageLogsColumns[20]}, Columns: []*schema.Column{UsageLogsColumns[21], UsageLogsColumns[20]},
}, },
}, },
} }
@@ -702,9 +702,9 @@ var (
} }
// Tables holds all the tables in the schema. // Tables holds all the tables in the schema.
Tables = []*schema.Table{ Tables = []*schema.Table{
APIKeysTable,
AccountsTable, AccountsTable,
AccountGroupsTable, AccountGroupsTable,
APIKeysTable,
GroupsTable, GroupsTable,
ProxiesTable, ProxiesTable,
RedeemCodesTable, RedeemCodesTable,
@@ -719,6 +719,11 @@ var (
) )
func init() { func init() {
APIKeysTable.ForeignKeys[0].RefTable = GroupsTable
APIKeysTable.ForeignKeys[1].RefTable = UsersTable
APIKeysTable.Annotation = &entsql.Annotation{
Table: "api_keys",
}
AccountsTable.ForeignKeys[0].RefTable = ProxiesTable AccountsTable.ForeignKeys[0].RefTable = ProxiesTable
AccountsTable.Annotation = &entsql.Annotation{ AccountsTable.Annotation = &entsql.Annotation{
Table: "accounts", Table: "accounts",
@@ -728,11 +733,6 @@ func init() {
AccountGroupsTable.Annotation = &entsql.Annotation{ AccountGroupsTable.Annotation = &entsql.Annotation{
Table: "account_groups", Table: "account_groups",
} }
APIKeysTable.ForeignKeys[0].RefTable = GroupsTable
APIKeysTable.ForeignKeys[1].RefTable = UsersTable
APIKeysTable.Annotation = &entsql.Annotation{
Table: "api_keys",
}
GroupsTable.Annotation = &entsql.Annotation{ GroupsTable.Annotation = &entsql.Annotation{
Table: "groups", Table: "groups",
} }
@@ -747,8 +747,8 @@ func init() {
SettingsTable.Annotation = &entsql.Annotation{ SettingsTable.Annotation = &entsql.Annotation{
Table: "settings", Table: "settings",
} }
UsageLogsTable.ForeignKeys[0].RefTable = AccountsTable UsageLogsTable.ForeignKeys[0].RefTable = APIKeysTable
UsageLogsTable.ForeignKeys[1].RefTable = APIKeysTable UsageLogsTable.ForeignKeys[1].RefTable = AccountsTable
UsageLogsTable.ForeignKeys[2].RefTable = GroupsTable UsageLogsTable.ForeignKeys[2].RefTable = GroupsTable
UsageLogsTable.ForeignKeys[3].RefTable = UsersTable UsageLogsTable.ForeignKeys[3].RefTable = UsersTable
UsageLogsTable.ForeignKeys[4].RefTable = UserSubscriptionsTable UsageLogsTable.ForeignKeys[4].RefTable = UserSubscriptionsTable

File diff suppressed because it is too large Load Diff

View File

@@ -6,15 +6,15 @@ import (
"entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql"
) )
// APIKey is the predicate function for apikey builders.
type APIKey func(*sql.Selector)
// Account is the predicate function for account builders. // Account is the predicate function for account builders.
type Account func(*sql.Selector) type Account func(*sql.Selector)
// AccountGroup is the predicate function for accountgroup builders. // AccountGroup is the predicate function for accountgroup builders.
type AccountGroup func(*sql.Selector) type AccountGroup func(*sql.Selector)
// ApiKey is the predicate function for apikey builders.
type ApiKey func(*sql.Selector)
// Group is the predicate function for group builders. // Group is the predicate function for group builders.
type Group func(*sql.Selector) type Group func(*sql.Selector)

View File

@@ -25,6 +25,67 @@ import (
// (default values, validators, hooks and policies) and stitches it // (default values, validators, hooks and policies) and stitches it
// to their package variables. // to their package variables.
func init() { func init() {
apikeyMixin := schema.APIKey{}.Mixin()
apikeyMixinHooks1 := apikeyMixin[1].Hooks()
apikey.Hooks[0] = apikeyMixinHooks1[0]
apikeyMixinInters1 := apikeyMixin[1].Interceptors()
apikey.Interceptors[0] = apikeyMixinInters1[0]
apikeyMixinFields0 := apikeyMixin[0].Fields()
_ = apikeyMixinFields0
apikeyFields := schema.APIKey{}.Fields()
_ = apikeyFields
// apikeyDescCreatedAt is the schema descriptor for created_at field.
apikeyDescCreatedAt := apikeyMixinFields0[0].Descriptor()
// apikey.DefaultCreatedAt holds the default value on creation for the created_at field.
apikey.DefaultCreatedAt = apikeyDescCreatedAt.Default.(func() time.Time)
// apikeyDescUpdatedAt is the schema descriptor for updated_at field.
apikeyDescUpdatedAt := apikeyMixinFields0[1].Descriptor()
// apikey.DefaultUpdatedAt holds the default value on creation for the updated_at field.
apikey.DefaultUpdatedAt = apikeyDescUpdatedAt.Default.(func() time.Time)
// apikey.UpdateDefaultUpdatedAt holds the default value on update for the updated_at field.
apikey.UpdateDefaultUpdatedAt = apikeyDescUpdatedAt.UpdateDefault.(func() time.Time)
// apikeyDescKey is the schema descriptor for key field.
apikeyDescKey := apikeyFields[1].Descriptor()
// apikey.KeyValidator is a validator for the "key" field. It is called by the builders before save.
apikey.KeyValidator = func() func(string) error {
validators := apikeyDescKey.Validators
fns := [...]func(string) error{
validators[0].(func(string) error),
validators[1].(func(string) error),
}
return func(key string) error {
for _, fn := range fns {
if err := fn(key); err != nil {
return err
}
}
return nil
}
}()
// apikeyDescName is the schema descriptor for name field.
apikeyDescName := apikeyFields[2].Descriptor()
// apikey.NameValidator is a validator for the "name" field. It is called by the builders before save.
apikey.NameValidator = func() func(string) error {
validators := apikeyDescName.Validators
fns := [...]func(string) error{
validators[0].(func(string) error),
validators[1].(func(string) error),
}
return func(name string) error {
for _, fn := range fns {
if err := fn(name); err != nil {
return err
}
}
return nil
}
}()
// apikeyDescStatus is the schema descriptor for status field.
apikeyDescStatus := apikeyFields[4].Descriptor()
// apikey.DefaultStatus holds the default value on creation for the status field.
apikey.DefaultStatus = apikeyDescStatus.Default.(string)
// apikey.StatusValidator is a validator for the "status" field. It is called by the builders before save.
apikey.StatusValidator = apikeyDescStatus.Validators[0].(func(string) error)
accountMixin := schema.Account{}.Mixin() accountMixin := schema.Account{}.Mixin()
accountMixinHooks1 := accountMixin[1].Hooks() accountMixinHooks1 := accountMixin[1].Hooks()
account.Hooks[0] = accountMixinHooks1[0] account.Hooks[0] = accountMixinHooks1[0]
@@ -138,67 +199,6 @@ func init() {
accountgroupDescCreatedAt := accountgroupFields[3].Descriptor() accountgroupDescCreatedAt := accountgroupFields[3].Descriptor()
// accountgroup.DefaultCreatedAt holds the default value on creation for the created_at field. // accountgroup.DefaultCreatedAt holds the default value on creation for the created_at field.
accountgroup.DefaultCreatedAt = accountgroupDescCreatedAt.Default.(func() time.Time) accountgroup.DefaultCreatedAt = accountgroupDescCreatedAt.Default.(func() time.Time)
apikeyMixin := schema.ApiKey{}.Mixin()
apikeyMixinHooks1 := apikeyMixin[1].Hooks()
apikey.Hooks[0] = apikeyMixinHooks1[0]
apikeyMixinInters1 := apikeyMixin[1].Interceptors()
apikey.Interceptors[0] = apikeyMixinInters1[0]
apikeyMixinFields0 := apikeyMixin[0].Fields()
_ = apikeyMixinFields0
apikeyFields := schema.ApiKey{}.Fields()
_ = apikeyFields
// apikeyDescCreatedAt is the schema descriptor for created_at field.
apikeyDescCreatedAt := apikeyMixinFields0[0].Descriptor()
// apikey.DefaultCreatedAt holds the default value on creation for the created_at field.
apikey.DefaultCreatedAt = apikeyDescCreatedAt.Default.(func() time.Time)
// apikeyDescUpdatedAt is the schema descriptor for updated_at field.
apikeyDescUpdatedAt := apikeyMixinFields0[1].Descriptor()
// apikey.DefaultUpdatedAt holds the default value on creation for the updated_at field.
apikey.DefaultUpdatedAt = apikeyDescUpdatedAt.Default.(func() time.Time)
// apikey.UpdateDefaultUpdatedAt holds the default value on update for the updated_at field.
apikey.UpdateDefaultUpdatedAt = apikeyDescUpdatedAt.UpdateDefault.(func() time.Time)
// apikeyDescKey is the schema descriptor for key field.
apikeyDescKey := apikeyFields[1].Descriptor()
// apikey.KeyValidator is a validator for the "key" field. It is called by the builders before save.
apikey.KeyValidator = func() func(string) error {
validators := apikeyDescKey.Validators
fns := [...]func(string) error{
validators[0].(func(string) error),
validators[1].(func(string) error),
}
return func(key string) error {
for _, fn := range fns {
if err := fn(key); err != nil {
return err
}
}
return nil
}
}()
// apikeyDescName is the schema descriptor for name field.
apikeyDescName := apikeyFields[2].Descriptor()
// apikey.NameValidator is a validator for the "name" field. It is called by the builders before save.
apikey.NameValidator = func() func(string) error {
validators := apikeyDescName.Validators
fns := [...]func(string) error{
validators[0].(func(string) error),
validators[1].(func(string) error),
}
return func(name string) error {
for _, fn := range fns {
if err := fn(name); err != nil {
return err
}
}
return nil
}
}()
// apikeyDescStatus is the schema descriptor for status field.
apikeyDescStatus := apikeyFields[4].Descriptor()
// apikey.DefaultStatus holds the default value on creation for the status field.
apikey.DefaultStatus = apikeyDescStatus.Default.(string)
// apikey.StatusValidator is a validator for the "status" field. It is called by the builders before save.
apikey.StatusValidator = apikeyDescStatus.Validators[0].(func(string) error)
groupMixin := schema.Group{}.Mixin() groupMixin := schema.Group{}.Mixin()
groupMixinHooks1 := groupMixin[1].Hooks() groupMixinHooks1 := groupMixin[1].Hooks()
group.Hooks[0] = groupMixinHooks1[0] group.Hooks[0] = groupMixinHooks1[0]

View File

@@ -12,25 +12,25 @@ import (
"entgo.io/ent/schema/index" "entgo.io/ent/schema/index"
) )
// ApiKey holds the schema definition for the ApiKey entity. // APIKey holds the schema definition for the APIKey entity.
type ApiKey struct { type APIKey struct {
ent.Schema ent.Schema
} }
func (ApiKey) Annotations() []schema.Annotation { func (APIKey) Annotations() []schema.Annotation {
return []schema.Annotation{ return []schema.Annotation{
entsql.Annotation{Table: "api_keys"}, entsql.Annotation{Table: "api_keys"},
} }
} }
func (ApiKey) Mixin() []ent.Mixin { func (APIKey) Mixin() []ent.Mixin {
return []ent.Mixin{ return []ent.Mixin{
mixins.TimeMixin{}, mixins.TimeMixin{},
mixins.SoftDeleteMixin{}, mixins.SoftDeleteMixin{},
} }
} }
func (ApiKey) Fields() []ent.Field { func (APIKey) Fields() []ent.Field {
return []ent.Field{ return []ent.Field{
field.Int64("user_id"), field.Int64("user_id"),
field.String("key"). field.String("key").
@@ -49,7 +49,7 @@ func (ApiKey) Fields() []ent.Field {
} }
} }
func (ApiKey) Edges() []ent.Edge { func (APIKey) Edges() []ent.Edge {
return []ent.Edge{ return []ent.Edge{
edge.From("user", User.Type). edge.From("user", User.Type).
Ref("api_keys"). Ref("api_keys").
@@ -64,7 +64,7 @@ func (ApiKey) Edges() []ent.Edge {
} }
} }
func (ApiKey) Indexes() []ent.Index { func (APIKey) Indexes() []ent.Index {
return []ent.Index{ return []ent.Index{
// key 字段已在 Fields() 中声明 Unique(),无需重复索引 // key 字段已在 Fields() 中声明 Unique(),无需重复索引
index.Fields("user_id"), index.Fields("user_id"),

View File

@@ -77,7 +77,7 @@ func (Group) Fields() []ent.Field {
func (Group) Edges() []ent.Edge { func (Group) Edges() []ent.Edge {
return []ent.Edge{ return []ent.Edge{
edge.To("api_keys", ApiKey.Type), edge.To("api_keys", APIKey.Type),
edge.To("redeem_codes", RedeemCode.Type), edge.To("redeem_codes", RedeemCode.Type),
edge.To("subscriptions", UserSubscription.Type), edge.To("subscriptions", UserSubscription.Type),
edge.To("usage_logs", UsageLog.Type), edge.To("usage_logs", UsageLog.Type),

View File

@@ -113,7 +113,7 @@ func (UsageLog) Edges() []ent.Edge {
Field("user_id"). Field("user_id").
Required(). Required().
Unique(), Unique(),
edge.From("api_key", ApiKey.Type). edge.From("api_key", APIKey.Type).
Ref("usage_logs"). Ref("usage_logs").
Field("api_key_id"). Field("api_key_id").
Required(). Required().

View File

@@ -66,7 +66,7 @@ func (User) Fields() []ent.Field {
func (User) Edges() []ent.Edge { func (User) Edges() []ent.Edge {
return []ent.Edge{ return []ent.Edge{
edge.To("api_keys", ApiKey.Type), edge.To("api_keys", APIKey.Type),
edge.To("redeem_codes", RedeemCode.Type), edge.To("redeem_codes", RedeemCode.Type),
edge.To("subscriptions", UserSubscription.Type), edge.To("subscriptions", UserSubscription.Type),
edge.To("assigned_subscriptions", UserSubscription.Type), edge.To("assigned_subscriptions", UserSubscription.Type),

View File

@@ -14,12 +14,12 @@ import (
// Tx is a transactional client that is created by calling Client.Tx(). // Tx is a transactional client that is created by calling Client.Tx().
type Tx struct { type Tx struct {
config config
// APIKey is the client for interacting with the APIKey builders.
APIKey *APIKeyClient
// Account is the client for interacting with the Account builders. // Account is the client for interacting with the Account builders.
Account *AccountClient Account *AccountClient
// AccountGroup is the client for interacting with the AccountGroup builders. // AccountGroup is the client for interacting with the AccountGroup builders.
AccountGroup *AccountGroupClient AccountGroup *AccountGroupClient
// ApiKey is the client for interacting with the ApiKey builders.
ApiKey *ApiKeyClient
// Group is the client for interacting with the Group builders. // Group is the client for interacting with the Group builders.
Group *GroupClient Group *GroupClient
// Proxy is the client for interacting with the Proxy builders. // Proxy is the client for interacting with the Proxy builders.
@@ -171,9 +171,9 @@ func (tx *Tx) Client() *Client {
} }
func (tx *Tx) init() { func (tx *Tx) init() {
tx.APIKey = NewAPIKeyClient(tx.config)
tx.Account = NewAccountClient(tx.config) tx.Account = NewAccountClient(tx.config)
tx.AccountGroup = NewAccountGroupClient(tx.config) tx.AccountGroup = NewAccountGroupClient(tx.config)
tx.ApiKey = NewApiKeyClient(tx.config)
tx.Group = NewGroupClient(tx.config) tx.Group = NewGroupClient(tx.config)
tx.Proxy = NewProxyClient(tx.config) tx.Proxy = NewProxyClient(tx.config)
tx.RedeemCode = NewRedeemCodeClient(tx.config) tx.RedeemCode = NewRedeemCodeClient(tx.config)
@@ -193,7 +193,7 @@ func (tx *Tx) init() {
// of them in order to commit or rollback the transaction. // of them in order to commit or rollback the transaction.
// //
// If a closed transaction is embedded in one of the generated entities, and the entity // If a closed transaction is embedded in one of the generated entities, and the entity
// applies a query, for example: Account.QueryXXX(), the query will be executed // applies a query, for example: APIKey.QueryXXX(), the query will be executed
// through the driver which created this transaction. // through the driver which created this transaction.
// //
// Note that txDriver is not goroutine safe. // Note that txDriver is not goroutine safe.

View File

@@ -83,7 +83,7 @@ type UsageLogEdges struct {
// User holds the value of the user edge. // User holds the value of the user edge.
User *User `json:"user,omitempty"` User *User `json:"user,omitempty"`
// APIKey holds the value of the api_key edge. // APIKey holds the value of the api_key edge.
APIKey *ApiKey `json:"api_key,omitempty"` APIKey *APIKey `json:"api_key,omitempty"`
// Account holds the value of the account edge. // Account holds the value of the account edge.
Account *Account `json:"account,omitempty"` Account *Account `json:"account,omitempty"`
// Group holds the value of the group edge. // Group holds the value of the group edge.
@@ -108,7 +108,7 @@ func (e UsageLogEdges) UserOrErr() (*User, error) {
// APIKeyOrErr returns the APIKey value or an error if the edge // APIKeyOrErr returns the APIKey value or an error if the edge
// was not loaded in eager-loading, or loaded but was not found. // was not loaded in eager-loading, or loaded but was not found.
func (e UsageLogEdges) APIKeyOrErr() (*ApiKey, error) { func (e UsageLogEdges) APIKeyOrErr() (*APIKey, error) {
if e.APIKey != nil { if e.APIKey != nil {
return e.APIKey, nil return e.APIKey, nil
} else if e.loadedTypes[1] { } else if e.loadedTypes[1] {
@@ -359,7 +359,7 @@ func (_m *UsageLog) QueryUser() *UserQuery {
} }
// QueryAPIKey queries the "api_key" edge of the UsageLog entity. // QueryAPIKey queries the "api_key" edge of the UsageLog entity.
func (_m *UsageLog) QueryAPIKey() *ApiKeyQuery { func (_m *UsageLog) QueryAPIKey() *APIKeyQuery {
return NewUsageLogClient(_m.config).QueryAPIKey(_m) return NewUsageLogClient(_m.config).QueryAPIKey(_m)
} }

View File

@@ -85,7 +85,7 @@ const (
UserColumn = "user_id" UserColumn = "user_id"
// APIKeyTable is the table that holds the api_key relation/edge. // APIKeyTable is the table that holds the api_key relation/edge.
APIKeyTable = "usage_logs" APIKeyTable = "usage_logs"
// APIKeyInverseTable is the table name for the ApiKey entity. // APIKeyInverseTable is the table name for the APIKey entity.
// It exists in this package in order to avoid circular dependency with the "apikey" package. // It exists in this package in order to avoid circular dependency with the "apikey" package.
APIKeyInverseTable = "api_keys" APIKeyInverseTable = "api_keys"
// APIKeyColumn is the table column denoting the api_key relation/edge. // APIKeyColumn is the table column denoting the api_key relation/edge.

View File

@@ -1175,7 +1175,7 @@ func HasAPIKey() predicate.UsageLog {
} }
// HasAPIKeyWith applies the HasEdge predicate on the "api_key" edge with a given conditions (other predicates). // HasAPIKeyWith applies the HasEdge predicate on the "api_key" edge with a given conditions (other predicates).
func HasAPIKeyWith(preds ...predicate.ApiKey) predicate.UsageLog { func HasAPIKeyWith(preds ...predicate.APIKey) predicate.UsageLog {
return predicate.UsageLog(func(s *sql.Selector) { return predicate.UsageLog(func(s *sql.Selector) {
step := newAPIKeyStep() step := newAPIKeyStep()
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {

View File

@@ -342,8 +342,8 @@ func (_c *UsageLogCreate) SetUser(v *User) *UsageLogCreate {
return _c.SetUserID(v.ID) return _c.SetUserID(v.ID)
} }
// SetAPIKey sets the "api_key" edge to the ApiKey entity. // SetAPIKey sets the "api_key" edge to the APIKey entity.
func (_c *UsageLogCreate) SetAPIKey(v *ApiKey) *UsageLogCreate { func (_c *UsageLogCreate) SetAPIKey(v *APIKey) *UsageLogCreate {
return _c.SetAPIKeyID(v.ID) return _c.SetAPIKeyID(v.ID)
} }

View File

@@ -28,7 +28,7 @@ type UsageLogQuery struct {
inters []Interceptor inters []Interceptor
predicates []predicate.UsageLog predicates []predicate.UsageLog
withUser *UserQuery withUser *UserQuery
withAPIKey *ApiKeyQuery withAPIKey *APIKeyQuery
withAccount *AccountQuery withAccount *AccountQuery
withGroup *GroupQuery withGroup *GroupQuery
withSubscription *UserSubscriptionQuery withSubscription *UserSubscriptionQuery
@@ -91,8 +91,8 @@ func (_q *UsageLogQuery) QueryUser() *UserQuery {
} }
// QueryAPIKey chains the current query on the "api_key" edge. // QueryAPIKey chains the current query on the "api_key" edge.
func (_q *UsageLogQuery) QueryAPIKey() *ApiKeyQuery { func (_q *UsageLogQuery) QueryAPIKey() *APIKeyQuery {
query := (&ApiKeyClient{config: _q.config}).Query() query := (&APIKeyClient{config: _q.config}).Query()
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) { query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
if err := _q.prepareQuery(ctx); err != nil { if err := _q.prepareQuery(ctx); err != nil {
return nil, err return nil, err
@@ -394,8 +394,8 @@ func (_q *UsageLogQuery) WithUser(opts ...func(*UserQuery)) *UsageLogQuery {
// WithAPIKey tells the query-builder to eager-load the nodes that are connected to // WithAPIKey tells the query-builder to eager-load the nodes that are connected to
// the "api_key" edge. The optional arguments are used to configure the query builder of the edge. // the "api_key" edge. The optional arguments are used to configure the query builder of the edge.
func (_q *UsageLogQuery) WithAPIKey(opts ...func(*ApiKeyQuery)) *UsageLogQuery { func (_q *UsageLogQuery) WithAPIKey(opts ...func(*APIKeyQuery)) *UsageLogQuery {
query := (&ApiKeyClient{config: _q.config}).Query() query := (&APIKeyClient{config: _q.config}).Query()
for _, opt := range opts { for _, opt := range opts {
opt(query) opt(query)
} }
@@ -548,7 +548,7 @@ func (_q *UsageLogQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Usa
} }
if query := _q.withAPIKey; query != nil { if query := _q.withAPIKey; query != nil {
if err := _q.loadAPIKey(ctx, query, nodes, nil, if err := _q.loadAPIKey(ctx, query, nodes, nil,
func(n *UsageLog, e *ApiKey) { n.Edges.APIKey = e }); err != nil { func(n *UsageLog, e *APIKey) { n.Edges.APIKey = e }); err != nil {
return nil, err return nil, err
} }
} }
@@ -602,7 +602,7 @@ func (_q *UsageLogQuery) loadUser(ctx context.Context, query *UserQuery, nodes [
} }
return nil return nil
} }
func (_q *UsageLogQuery) loadAPIKey(ctx context.Context, query *ApiKeyQuery, nodes []*UsageLog, init func(*UsageLog), assign func(*UsageLog, *ApiKey)) error { func (_q *UsageLogQuery) loadAPIKey(ctx context.Context, query *APIKeyQuery, nodes []*UsageLog, init func(*UsageLog), assign func(*UsageLog, *APIKey)) error {
ids := make([]int64, 0, len(nodes)) ids := make([]int64, 0, len(nodes))
nodeids := make(map[int64][]*UsageLog) nodeids := make(map[int64][]*UsageLog)
for i := range nodes { for i := range nodes {

View File

@@ -509,8 +509,8 @@ func (_u *UsageLogUpdate) SetUser(v *User) *UsageLogUpdate {
return _u.SetUserID(v.ID) return _u.SetUserID(v.ID)
} }
// SetAPIKey sets the "api_key" edge to the ApiKey entity. // SetAPIKey sets the "api_key" edge to the APIKey entity.
func (_u *UsageLogUpdate) SetAPIKey(v *ApiKey) *UsageLogUpdate { func (_u *UsageLogUpdate) SetAPIKey(v *APIKey) *UsageLogUpdate {
return _u.SetAPIKeyID(v.ID) return _u.SetAPIKeyID(v.ID)
} }
@@ -540,7 +540,7 @@ func (_u *UsageLogUpdate) ClearUser() *UsageLogUpdate {
return _u return _u
} }
// ClearAPIKey clears the "api_key" edge to the ApiKey entity. // ClearAPIKey clears the "api_key" edge to the APIKey entity.
func (_u *UsageLogUpdate) ClearAPIKey() *UsageLogUpdate { func (_u *UsageLogUpdate) ClearAPIKey() *UsageLogUpdate {
_u.mutation.ClearAPIKey() _u.mutation.ClearAPIKey()
return _u return _u
@@ -1380,8 +1380,8 @@ func (_u *UsageLogUpdateOne) SetUser(v *User) *UsageLogUpdateOne {
return _u.SetUserID(v.ID) return _u.SetUserID(v.ID)
} }
// SetAPIKey sets the "api_key" edge to the ApiKey entity. // SetAPIKey sets the "api_key" edge to the APIKey entity.
func (_u *UsageLogUpdateOne) SetAPIKey(v *ApiKey) *UsageLogUpdateOne { func (_u *UsageLogUpdateOne) SetAPIKey(v *APIKey) *UsageLogUpdateOne {
return _u.SetAPIKeyID(v.ID) return _u.SetAPIKeyID(v.ID)
} }
@@ -1411,7 +1411,7 @@ func (_u *UsageLogUpdateOne) ClearUser() *UsageLogUpdateOne {
return _u return _u
} }
// ClearAPIKey clears the "api_key" edge to the ApiKey entity. // ClearAPIKey clears the "api_key" edge to the APIKey entity.
func (_u *UsageLogUpdateOne) ClearAPIKey() *UsageLogUpdateOne { func (_u *UsageLogUpdateOne) ClearAPIKey() *UsageLogUpdateOne {
_u.mutation.ClearAPIKey() _u.mutation.ClearAPIKey()
return _u return _u

View File

@@ -48,7 +48,7 @@ type User struct {
// UserEdges holds the relations/edges for other nodes in the graph. // UserEdges holds the relations/edges for other nodes in the graph.
type UserEdges struct { type UserEdges struct {
// APIKeys holds the value of the api_keys edge. // APIKeys holds the value of the api_keys edge.
APIKeys []*ApiKey `json:"api_keys,omitempty"` APIKeys []*APIKey `json:"api_keys,omitempty"`
// RedeemCodes holds the value of the redeem_codes edge. // RedeemCodes holds the value of the redeem_codes edge.
RedeemCodes []*RedeemCode `json:"redeem_codes,omitempty"` RedeemCodes []*RedeemCode `json:"redeem_codes,omitempty"`
// Subscriptions holds the value of the subscriptions edge. // Subscriptions holds the value of the subscriptions edge.
@@ -70,7 +70,7 @@ type UserEdges struct {
// APIKeysOrErr returns the APIKeys value or an error if the edge // APIKeysOrErr returns the APIKeys value or an error if the edge
// was not loaded in eager-loading. // was not loaded in eager-loading.
func (e UserEdges) APIKeysOrErr() ([]*ApiKey, error) { func (e UserEdges) APIKeysOrErr() ([]*APIKey, error) {
if e.loadedTypes[0] { if e.loadedTypes[0] {
return e.APIKeys, nil return e.APIKeys, nil
} }
@@ -255,7 +255,7 @@ func (_m *User) Value(name string) (ent.Value, error) {
} }
// QueryAPIKeys queries the "api_keys" edge of the User entity. // QueryAPIKeys queries the "api_keys" edge of the User entity.
func (_m *User) QueryAPIKeys() *ApiKeyQuery { func (_m *User) QueryAPIKeys() *APIKeyQuery {
return NewUserClient(_m.config).QueryAPIKeys(_m) return NewUserClient(_m.config).QueryAPIKeys(_m)
} }

View File

@@ -57,7 +57,7 @@ const (
Table = "users" Table = "users"
// APIKeysTable is the table that holds the api_keys relation/edge. // APIKeysTable is the table that holds the api_keys relation/edge.
APIKeysTable = "api_keys" APIKeysTable = "api_keys"
// APIKeysInverseTable is the table name for the ApiKey entity. // APIKeysInverseTable is the table name for the APIKey entity.
// It exists in this package in order to avoid circular dependency with the "apikey" package. // It exists in this package in order to avoid circular dependency with the "apikey" package.
APIKeysInverseTable = "api_keys" APIKeysInverseTable = "api_keys"
// APIKeysColumn is the table column denoting the api_keys relation/edge. // APIKeysColumn is the table column denoting the api_keys relation/edge.

View File

@@ -722,7 +722,7 @@ func HasAPIKeys() predicate.User {
} }
// HasAPIKeysWith applies the HasEdge predicate on the "api_keys" edge with a given conditions (other predicates). // HasAPIKeysWith applies the HasEdge predicate on the "api_keys" edge with a given conditions (other predicates).
func HasAPIKeysWith(preds ...predicate.ApiKey) predicate.User { func HasAPIKeysWith(preds ...predicate.APIKey) predicate.User {
return predicate.User(func(s *sql.Selector) { return predicate.User(func(s *sql.Selector) {
step := newAPIKeysStep() step := newAPIKeysStep()
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {

View File

@@ -166,14 +166,14 @@ func (_c *UserCreate) SetNillableNotes(v *string) *UserCreate {
return _c return _c
} }
// AddAPIKeyIDs adds the "api_keys" edge to the ApiKey entity by IDs. // AddAPIKeyIDs adds the "api_keys" edge to the APIKey entity by IDs.
func (_c *UserCreate) AddAPIKeyIDs(ids ...int64) *UserCreate { func (_c *UserCreate) AddAPIKeyIDs(ids ...int64) *UserCreate {
_c.mutation.AddAPIKeyIDs(ids...) _c.mutation.AddAPIKeyIDs(ids...)
return _c return _c
} }
// AddAPIKeys adds the "api_keys" edges to the ApiKey entity. // AddAPIKeys adds the "api_keys" edges to the APIKey entity.
func (_c *UserCreate) AddAPIKeys(v ...*ApiKey) *UserCreate { func (_c *UserCreate) AddAPIKeys(v ...*APIKey) *UserCreate {
ids := make([]int64, len(v)) ids := make([]int64, len(v))
for i := range v { for i := range v {
ids[i] = v[i].ID ids[i] = v[i].ID

View File

@@ -30,7 +30,7 @@ type UserQuery struct {
order []user.OrderOption order []user.OrderOption
inters []Interceptor inters []Interceptor
predicates []predicate.User predicates []predicate.User
withAPIKeys *ApiKeyQuery withAPIKeys *APIKeyQuery
withRedeemCodes *RedeemCodeQuery withRedeemCodes *RedeemCodeQuery
withSubscriptions *UserSubscriptionQuery withSubscriptions *UserSubscriptionQuery
withAssignedSubscriptions *UserSubscriptionQuery withAssignedSubscriptions *UserSubscriptionQuery
@@ -75,8 +75,8 @@ func (_q *UserQuery) Order(o ...user.OrderOption) *UserQuery {
} }
// QueryAPIKeys chains the current query on the "api_keys" edge. // QueryAPIKeys chains the current query on the "api_keys" edge.
func (_q *UserQuery) QueryAPIKeys() *ApiKeyQuery { func (_q *UserQuery) QueryAPIKeys() *APIKeyQuery {
query := (&ApiKeyClient{config: _q.config}).Query() query := (&APIKeyClient{config: _q.config}).Query()
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) { query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
if err := _q.prepareQuery(ctx); err != nil { if err := _q.prepareQuery(ctx); err != nil {
return nil, err return nil, err
@@ -458,8 +458,8 @@ func (_q *UserQuery) Clone() *UserQuery {
// WithAPIKeys tells the query-builder to eager-load the nodes that are connected to // WithAPIKeys tells the query-builder to eager-load the nodes that are connected to
// the "api_keys" edge. The optional arguments are used to configure the query builder of the edge. // the "api_keys" edge. The optional arguments are used to configure the query builder of the edge.
func (_q *UserQuery) WithAPIKeys(opts ...func(*ApiKeyQuery)) *UserQuery { func (_q *UserQuery) WithAPIKeys(opts ...func(*APIKeyQuery)) *UserQuery {
query := (&ApiKeyClient{config: _q.config}).Query() query := (&APIKeyClient{config: _q.config}).Query()
for _, opt := range opts { for _, opt := range opts {
opt(query) opt(query)
} }
@@ -653,8 +653,8 @@ func (_q *UserQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*User, e
} }
if query := _q.withAPIKeys; query != nil { if query := _q.withAPIKeys; query != nil {
if err := _q.loadAPIKeys(ctx, query, nodes, if err := _q.loadAPIKeys(ctx, query, nodes,
func(n *User) { n.Edges.APIKeys = []*ApiKey{} }, func(n *User) { n.Edges.APIKeys = []*APIKey{} },
func(n *User, e *ApiKey) { n.Edges.APIKeys = append(n.Edges.APIKeys, e) }); err != nil { func(n *User, e *APIKey) { n.Edges.APIKeys = append(n.Edges.APIKeys, e) }); err != nil {
return nil, err return nil, err
} }
} }
@@ -712,7 +712,7 @@ func (_q *UserQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*User, e
return nodes, nil return nodes, nil
} }
func (_q *UserQuery) loadAPIKeys(ctx context.Context, query *ApiKeyQuery, nodes []*User, init func(*User), assign func(*User, *ApiKey)) error { func (_q *UserQuery) loadAPIKeys(ctx context.Context, query *APIKeyQuery, nodes []*User, init func(*User), assign func(*User, *APIKey)) error {
fks := make([]driver.Value, 0, len(nodes)) fks := make([]driver.Value, 0, len(nodes))
nodeids := make(map[int64]*User) nodeids := make(map[int64]*User)
for i := range nodes { for i := range nodes {
@@ -725,7 +725,7 @@ func (_q *UserQuery) loadAPIKeys(ctx context.Context, query *ApiKeyQuery, nodes
if len(query.ctx.Fields) > 0 { if len(query.ctx.Fields) > 0 {
query.ctx.AppendFieldOnce(apikey.FieldUserID) query.ctx.AppendFieldOnce(apikey.FieldUserID)
} }
query.Where(predicate.ApiKey(func(s *sql.Selector) { query.Where(predicate.APIKey(func(s *sql.Selector) {
s.Where(sql.InValues(s.C(user.APIKeysColumn), fks...)) s.Where(sql.InValues(s.C(user.APIKeysColumn), fks...))
})) }))
neighbors, err := query.All(ctx) neighbors, err := query.All(ctx)

View File

@@ -186,14 +186,14 @@ func (_u *UserUpdate) SetNillableNotes(v *string) *UserUpdate {
return _u return _u
} }
// AddAPIKeyIDs adds the "api_keys" edge to the ApiKey entity by IDs. // AddAPIKeyIDs adds the "api_keys" edge to the APIKey entity by IDs.
func (_u *UserUpdate) AddAPIKeyIDs(ids ...int64) *UserUpdate { func (_u *UserUpdate) AddAPIKeyIDs(ids ...int64) *UserUpdate {
_u.mutation.AddAPIKeyIDs(ids...) _u.mutation.AddAPIKeyIDs(ids...)
return _u return _u
} }
// AddAPIKeys adds the "api_keys" edges to the ApiKey entity. // AddAPIKeys adds the "api_keys" edges to the APIKey entity.
func (_u *UserUpdate) AddAPIKeys(v ...*ApiKey) *UserUpdate { func (_u *UserUpdate) AddAPIKeys(v ...*APIKey) *UserUpdate {
ids := make([]int64, len(v)) ids := make([]int64, len(v))
for i := range v { for i := range v {
ids[i] = v[i].ID ids[i] = v[i].ID
@@ -296,20 +296,20 @@ func (_u *UserUpdate) Mutation() *UserMutation {
return _u.mutation return _u.mutation
} }
// ClearAPIKeys clears all "api_keys" edges to the ApiKey entity. // ClearAPIKeys clears all "api_keys" edges to the APIKey entity.
func (_u *UserUpdate) ClearAPIKeys() *UserUpdate { func (_u *UserUpdate) ClearAPIKeys() *UserUpdate {
_u.mutation.ClearAPIKeys() _u.mutation.ClearAPIKeys()
return _u return _u
} }
// RemoveAPIKeyIDs removes the "api_keys" edge to ApiKey entities by IDs. // RemoveAPIKeyIDs removes the "api_keys" edge to APIKey entities by IDs.
func (_u *UserUpdate) RemoveAPIKeyIDs(ids ...int64) *UserUpdate { func (_u *UserUpdate) RemoveAPIKeyIDs(ids ...int64) *UserUpdate {
_u.mutation.RemoveAPIKeyIDs(ids...) _u.mutation.RemoveAPIKeyIDs(ids...)
return _u return _u
} }
// RemoveAPIKeys removes "api_keys" edges to ApiKey entities. // RemoveAPIKeys removes "api_keys" edges to APIKey entities.
func (_u *UserUpdate) RemoveAPIKeys(v ...*ApiKey) *UserUpdate { func (_u *UserUpdate) RemoveAPIKeys(v ...*APIKey) *UserUpdate {
ids := make([]int64, len(v)) ids := make([]int64, len(v))
for i := range v { for i := range v {
ids[i] = v[i].ID ids[i] = v[i].ID
@@ -1065,14 +1065,14 @@ func (_u *UserUpdateOne) SetNillableNotes(v *string) *UserUpdateOne {
return _u return _u
} }
// AddAPIKeyIDs adds the "api_keys" edge to the ApiKey entity by IDs. // AddAPIKeyIDs adds the "api_keys" edge to the APIKey entity by IDs.
func (_u *UserUpdateOne) AddAPIKeyIDs(ids ...int64) *UserUpdateOne { func (_u *UserUpdateOne) AddAPIKeyIDs(ids ...int64) *UserUpdateOne {
_u.mutation.AddAPIKeyIDs(ids...) _u.mutation.AddAPIKeyIDs(ids...)
return _u return _u
} }
// AddAPIKeys adds the "api_keys" edges to the ApiKey entity. // AddAPIKeys adds the "api_keys" edges to the APIKey entity.
func (_u *UserUpdateOne) AddAPIKeys(v ...*ApiKey) *UserUpdateOne { func (_u *UserUpdateOne) AddAPIKeys(v ...*APIKey) *UserUpdateOne {
ids := make([]int64, len(v)) ids := make([]int64, len(v))
for i := range v { for i := range v {
ids[i] = v[i].ID ids[i] = v[i].ID
@@ -1175,20 +1175,20 @@ func (_u *UserUpdateOne) Mutation() *UserMutation {
return _u.mutation return _u.mutation
} }
// ClearAPIKeys clears all "api_keys" edges to the ApiKey entity. // ClearAPIKeys clears all "api_keys" edges to the APIKey entity.
func (_u *UserUpdateOne) ClearAPIKeys() *UserUpdateOne { func (_u *UserUpdateOne) ClearAPIKeys() *UserUpdateOne {
_u.mutation.ClearAPIKeys() _u.mutation.ClearAPIKeys()
return _u return _u
} }
// RemoveAPIKeyIDs removes the "api_keys" edge to ApiKey entities by IDs. // RemoveAPIKeyIDs removes the "api_keys" edge to APIKey entities by IDs.
func (_u *UserUpdateOne) RemoveAPIKeyIDs(ids ...int64) *UserUpdateOne { func (_u *UserUpdateOne) RemoveAPIKeyIDs(ids ...int64) *UserUpdateOne {
_u.mutation.RemoveAPIKeyIDs(ids...) _u.mutation.RemoveAPIKeyIDs(ids...)
return _u return _u
} }
// RemoveAPIKeys removes "api_keys" edges to ApiKey entities. // RemoveAPIKeys removes "api_keys" edges to APIKey entities.
func (_u *UserUpdateOne) RemoveAPIKeys(v ...*ApiKey) *UserUpdateOne { func (_u *UserUpdateOne) RemoveAPIKeys(v ...*APIKey) *UserUpdateOne {
ids := make([]int64, len(v)) ids := make([]int64, len(v))
for i := range v { for i := range v {
ids[i] = v[i].ID ids[i] = v[i].ID

View File

@@ -69,6 +69,7 @@ require (
github.com/google/go-cmp v0.7.0 // indirect github.com/google/go-cmp v0.7.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect github.com/google/go-querystring v1.1.0 // indirect
github.com/google/subcommands v1.2.0 // indirect github.com/google/subcommands v1.2.0 // indirect
github.com/gorilla/websocket v1.5.3 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect
github.com/hashicorp/hcl/v2 v2.18.1 // indirect github.com/hashicorp/hcl/v2 v2.18.1 // indirect

View File

@@ -118,6 +118,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/wire v0.7.0 h1:JxUKI6+CVBgCO2WToKy/nQk0sS+amI9z9EjVmdaocj4= github.com/google/wire v0.7.0 h1:JxUKI6+CVBgCO2WToKy/nQk0sS+amI9z9EjVmdaocj4=
github.com/google/wire v0.7.0/go.mod h1:n6YbUQD9cPKTnHXEBN2DXlOp/mVADhVErcMFb0v3J18= github.com/google/wire v0.7.0/go.mod h1:n6YbUQD9cPKTnHXEBN2DXlOp/mVADhVErcMFb0v3J18=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 h1:NmZ1PKzSTQbuGHw9DGPFomqkkLWMC+vZCkfs+FHv1Vg= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 h1:NmZ1PKzSTQbuGHw9DGPFomqkkLWMC+vZCkfs+FHv1Vg=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3/go.mod h1:zQrxl1YP88HQlA6i9c63DSVPFklWpGX4OWAc9bFuaH4= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3/go.mod h1:zQrxl1YP88HQlA6i9c63DSVPFklWpGX4OWAc9bFuaH4=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=

View File

@@ -1,3 +1,4 @@
// Package config provides application configuration management.
package config package config
import ( import (
@@ -139,7 +140,7 @@ type GatewayConfig struct {
LogUpstreamErrorBodyMaxBytes int `mapstructure:"log_upstream_error_body_max_bytes"` LogUpstreamErrorBodyMaxBytes int `mapstructure:"log_upstream_error_body_max_bytes"`
// API-key 账号在客户端未提供 anthropic-beta 时,是否按需自动补齐(默认关闭以保持兼容) // API-key 账号在客户端未提供 anthropic-beta 时,是否按需自动补齐(默认关闭以保持兼容)
InjectBetaForApiKey bool `mapstructure:"inject_beta_for_apikey"` InjectBetaForAPIKey bool `mapstructure:"inject_beta_for_apikey"`
// 是否允许对部分 400 错误触发 failover默认关闭以避免改变语义 // 是否允许对部分 400 错误触发 failover默认关闭以避免改变语义
FailoverOn400 bool `mapstructure:"failover_on_400"` FailoverOn400 bool `mapstructure:"failover_on_400"`
@@ -241,7 +242,7 @@ type DefaultConfig struct {
AdminPassword string `mapstructure:"admin_password"` AdminPassword string `mapstructure:"admin_password"`
UserConcurrency int `mapstructure:"user_concurrency"` UserConcurrency int `mapstructure:"user_concurrency"`
UserBalance float64 `mapstructure:"user_balance"` UserBalance float64 `mapstructure:"user_balance"`
ApiKeyPrefix string `mapstructure:"api_key_prefix"` APIKeyPrefix string `mapstructure:"api_key_prefix"`
RateMultiplier float64 `mapstructure:"rate_multiplier"` RateMultiplier float64 `mapstructure:"rate_multiplier"`
} }

View File

@@ -1,3 +1,4 @@
// Package config provides application configuration management.
package config package config
import "github.com/google/wire" import "github.com/google/wire"

View File

@@ -1,3 +1,5 @@
// Package admin provides HTTP handlers for administrative operations including
// dashboard statistics, user management, API key management, and account management.
package admin package admin
import ( import (
@@ -75,8 +77,8 @@ func (h *DashboardHandler) GetStats(c *gin.Context) {
"active_users": stats.ActiveUsers, "active_users": stats.ActiveUsers,
// API Key 统计 // API Key 统计
"total_api_keys": stats.TotalApiKeys, "total_api_keys": stats.TotalAPIKeys,
"active_api_keys": stats.ActiveApiKeys, "active_api_keys": stats.ActiveAPIKeys,
// 账户统计 // 账户统计
"total_accounts": stats.TotalAccounts, "total_accounts": stats.TotalAccounts,
@@ -193,10 +195,10 @@ func (h *DashboardHandler) GetModelStats(c *gin.Context) {
}) })
} }
// GetApiKeyUsageTrend handles getting API key usage trend data // GetAPIKeyUsageTrend handles getting API key usage trend data
// GET /api/v1/admin/dashboard/api-keys-trend // GET /api/v1/admin/dashboard/api-keys-trend
// Query params: start_date, end_date (YYYY-MM-DD), granularity (day/hour), limit (default 5) // Query params: start_date, end_date (YYYY-MM-DD), granularity (day/hour), limit (default 5)
func (h *DashboardHandler) GetApiKeyUsageTrend(c *gin.Context) { func (h *DashboardHandler) GetAPIKeyUsageTrend(c *gin.Context) {
startTime, endTime := parseTimeRange(c) startTime, endTime := parseTimeRange(c)
granularity := c.DefaultQuery("granularity", "day") granularity := c.DefaultQuery("granularity", "day")
limitStr := c.DefaultQuery("limit", "5") limitStr := c.DefaultQuery("limit", "5")
@@ -205,7 +207,7 @@ func (h *DashboardHandler) GetApiKeyUsageTrend(c *gin.Context) {
limit = 5 limit = 5
} }
trend, err := h.dashboardService.GetApiKeyUsageTrend(c.Request.Context(), startTime, endTime, granularity, limit) trend, err := h.dashboardService.GetAPIKeyUsageTrend(c.Request.Context(), startTime, endTime, granularity, limit)
if err != nil { if err != nil {
response.Error(c, 500, "Failed to get API key usage trend") response.Error(c, 500, "Failed to get API key usage trend")
return return
@@ -273,26 +275,26 @@ func (h *DashboardHandler) GetBatchUsersUsage(c *gin.Context) {
response.Success(c, gin.H{"stats": stats}) response.Success(c, gin.H{"stats": stats})
} }
// BatchApiKeysUsageRequest represents the request body for batch api key usage stats // BatchAPIKeysUsageRequest represents the request body for batch api key usage stats
type BatchApiKeysUsageRequest struct { type BatchAPIKeysUsageRequest struct {
ApiKeyIDs []int64 `json:"api_key_ids" binding:"required"` APIKeyIDs []int64 `json:"api_key_ids" binding:"required"`
} }
// GetBatchApiKeysUsage handles getting usage stats for multiple API keys // GetBatchAPIKeysUsage handles getting usage stats for multiple API keys
// POST /api/v1/admin/dashboard/api-keys-usage // POST /api/v1/admin/dashboard/api-keys-usage
func (h *DashboardHandler) GetBatchApiKeysUsage(c *gin.Context) { func (h *DashboardHandler) GetBatchAPIKeysUsage(c *gin.Context) {
var req BatchApiKeysUsageRequest var req BatchAPIKeysUsageRequest
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
response.BadRequest(c, "Invalid request: "+err.Error()) response.BadRequest(c, "Invalid request: "+err.Error())
return return
} }
if len(req.ApiKeyIDs) == 0 { if len(req.APIKeyIDs) == 0 {
response.Success(c, gin.H{"stats": map[string]any{}}) response.Success(c, gin.H{"stats": map[string]any{}})
return return
} }
stats, err := h.dashboardService.GetBatchApiKeyUsageStats(c.Request.Context(), req.ApiKeyIDs) stats, err := h.dashboardService.GetBatchAPIKeyUsageStats(c.Request.Context(), req.APIKeyIDs)
if err != nil { if err != nil {
response.Error(c, 500, "Failed to get API key usage stats") response.Error(c, 500, "Failed to get API key usage stats")
return return

View File

@@ -18,6 +18,7 @@ func NewGeminiOAuthHandler(geminiOAuthService *service.GeminiOAuthService) *Gemi
return &GeminiOAuthHandler{geminiOAuthService: geminiOAuthService} return &GeminiOAuthHandler{geminiOAuthService: geminiOAuthService}
} }
// GetCapabilities retrieves OAuth configuration capabilities.
// GET /api/v1/admin/gemini/oauth/capabilities // GET /api/v1/admin/gemini/oauth/capabilities
func (h *GeminiOAuthHandler) GetCapabilities(c *gin.Context) { func (h *GeminiOAuthHandler) GetCapabilities(c *gin.Context) {
cfg := h.geminiOAuthService.GetOAuthConfig() cfg := h.geminiOAuthService.GetOAuthConfig()

View File

@@ -237,9 +237,9 @@ func (h *GroupHandler) GetGroupAPIKeys(c *gin.Context) {
return return
} }
outKeys := make([]dto.ApiKey, 0, len(keys)) outKeys := make([]dto.APIKey, 0, len(keys))
for i := range keys { for i := range keys {
outKeys = append(outKeys, *dto.ApiKeyFromService(&keys[i])) outKeys = append(outKeys, *dto.APIKeyFromService(&keys[i]))
} }
response.Paginated(c, outKeys, total, page, pageSize) response.Paginated(c, outKeys, total, page, pageSize)
} }

View File

@@ -0,0 +1,402 @@
package admin
import (
"math"
"net/http"
"strconv"
"time"
"github.com/Wei-Shaw/sub2api/internal/pkg/response"
"github.com/Wei-Shaw/sub2api/internal/service"
"github.com/gin-gonic/gin"
)
// OpsHandler handles ops dashboard endpoints.
type OpsHandler struct {
opsService *service.OpsService
}
// NewOpsHandler creates a new OpsHandler.
func NewOpsHandler(opsService *service.OpsService) *OpsHandler {
return &OpsHandler{opsService: opsService}
}
// GetMetrics returns the latest ops metrics snapshot.
// GET /api/v1/admin/ops/metrics
func (h *OpsHandler) GetMetrics(c *gin.Context) {
metrics, err := h.opsService.GetLatestMetrics(c.Request.Context())
if err != nil {
response.Error(c, http.StatusInternalServerError, "Failed to get ops metrics")
return
}
response.Success(c, metrics)
}
// ListMetricsHistory returns a time-range slice of metrics for charts.
// GET /api/v1/admin/ops/metrics/history
//
// Query params:
// - window_minutes: int (default 1)
// - minutes: int (lookback; optional)
// - start_time/end_time: RFC3339 timestamps (optional; overrides minutes when provided)
// - limit: int (optional; max 100, default 300 for backward compatibility)
func (h *OpsHandler) ListMetricsHistory(c *gin.Context) {
windowMinutes := 1
if v := c.Query("window_minutes"); v != "" {
if parsed, err := strconv.Atoi(v); err == nil && parsed > 0 {
windowMinutes = parsed
} else {
response.BadRequest(c, "Invalid window_minutes")
return
}
}
limit := 300
limitProvided := false
if v := c.Query("limit"); v != "" {
parsed, err := strconv.Atoi(v)
if err != nil || parsed <= 0 || parsed > 5000 {
response.BadRequest(c, "Invalid limit (must be 1-5000)")
return
}
limit = parsed
limitProvided = true
}
endTime := time.Now()
startTime := time.Time{}
if startTimeStr := c.Query("start_time"); startTimeStr != "" {
parsed, err := time.Parse(time.RFC3339, startTimeStr)
if err != nil {
response.BadRequest(c, "Invalid start_time format (RFC3339)")
return
}
startTime = parsed
}
if endTimeStr := c.Query("end_time"); endTimeStr != "" {
parsed, err := time.Parse(time.RFC3339, endTimeStr)
if err != nil {
response.BadRequest(c, "Invalid end_time format (RFC3339)")
return
}
endTime = parsed
}
// If explicit range not provided, use lookback minutes.
if startTime.IsZero() {
if v := c.Query("minutes"); v != "" {
minutes, err := strconv.Atoi(v)
if err != nil || minutes <= 0 {
response.BadRequest(c, "Invalid minutes")
return
}
if minutes > 60*24*7 {
minutes = 60 * 24 * 7
}
startTime = endTime.Add(-time.Duration(minutes) * time.Minute)
}
}
// Default time range: last 24 hours.
if startTime.IsZero() {
startTime = endTime.Add(-24 * time.Hour)
if !limitProvided {
// Metrics are collected at 1-minute cadence; 24h requires ~1440 points.
limit = 24 * 60
}
}
if startTime.After(endTime) {
response.BadRequest(c, "Invalid time range: start_time must be <= end_time")
return
}
items, err := h.opsService.ListMetricsHistory(c.Request.Context(), windowMinutes, startTime, endTime, limit)
if err != nil {
response.Error(c, http.StatusInternalServerError, "Failed to list ops metrics history")
return
}
response.Success(c, gin.H{"items": items})
}
// ListErrorLogs lists recent error logs with optional filters.
// GET /api/v1/admin/ops/error-logs
//
// Query params:
// - start_time/end_time: RFC3339 timestamps (optional)
// - platform: string (optional)
// - phase: string (optional)
// - severity: string (optional)
// - q: string (optional; fuzzy match)
// - limit: int (optional; default 100; max 500)
func (h *OpsHandler) ListErrorLogs(c *gin.Context) {
var filters service.OpsErrorLogFilters
if startTimeStr := c.Query("start_time"); startTimeStr != "" {
startTime, err := time.Parse(time.RFC3339, startTimeStr)
if err != nil {
response.BadRequest(c, "Invalid start_time format (RFC3339)")
return
}
filters.StartTime = &startTime
}
if endTimeStr := c.Query("end_time"); endTimeStr != "" {
endTime, err := time.Parse(time.RFC3339, endTimeStr)
if err != nil {
response.BadRequest(c, "Invalid end_time format (RFC3339)")
return
}
filters.EndTime = &endTime
}
if filters.StartTime != nil && filters.EndTime != nil && filters.StartTime.After(*filters.EndTime) {
response.BadRequest(c, "Invalid time range: start_time must be <= end_time")
return
}
filters.Platform = c.Query("platform")
filters.Phase = c.Query("phase")
filters.Severity = c.Query("severity")
filters.Query = c.Query("q")
filters.Limit = 100
if limitStr := c.Query("limit"); limitStr != "" {
limit, err := strconv.Atoi(limitStr)
if err != nil || limit <= 0 || limit > 500 {
response.BadRequest(c, "Invalid limit (must be 1-500)")
return
}
filters.Limit = limit
}
items, total, err := h.opsService.ListErrorLogs(c.Request.Context(), filters)
if err != nil {
response.Error(c, http.StatusInternalServerError, "Failed to list error logs")
return
}
response.Success(c, gin.H{
"items": items,
"total": total,
})
}
// GetDashboardOverview returns realtime ops dashboard overview.
// GET /api/v1/admin/ops/dashboard/overview
//
// Query params:
// - time_range: string (optional; default "1h") one of: 5m, 30m, 1h, 6h, 24h
func (h *OpsHandler) GetDashboardOverview(c *gin.Context) {
timeRange := c.Query("time_range")
if timeRange == "" {
timeRange = "1h"
}
switch timeRange {
case "5m", "30m", "1h", "6h", "24h":
default:
response.BadRequest(c, "Invalid time_range (supported: 5m, 30m, 1h, 6h, 24h)")
return
}
data, err := h.opsService.GetDashboardOverview(c.Request.Context(), timeRange)
if err != nil {
response.Error(c, http.StatusInternalServerError, "Failed to get dashboard overview")
return
}
response.Success(c, data)
}
// GetProviderHealth returns upstream provider health comparison data.
// GET /api/v1/admin/ops/dashboard/providers
//
// Query params:
// - time_range: string (optional; default "1h") one of: 5m, 30m, 1h, 6h, 24h
func (h *OpsHandler) GetProviderHealth(c *gin.Context) {
timeRange := c.Query("time_range")
if timeRange == "" {
timeRange = "1h"
}
switch timeRange {
case "5m", "30m", "1h", "6h", "24h":
default:
response.BadRequest(c, "Invalid time_range (supported: 5m, 30m, 1h, 6h, 24h)")
return
}
providers, err := h.opsService.GetProviderHealth(c.Request.Context(), timeRange)
if err != nil {
response.Error(c, http.StatusInternalServerError, "Failed to get provider health")
return
}
var totalRequests int64
var weightedSuccess float64
var bestProvider string
var worstProvider string
var bestRate float64
var worstRate float64
hasRate := false
for _, p := range providers {
if p == nil {
continue
}
totalRequests += p.RequestCount
weightedSuccess += (p.SuccessRate / 100) * float64(p.RequestCount)
if p.RequestCount <= 0 {
continue
}
if !hasRate {
bestProvider = p.Name
worstProvider = p.Name
bestRate = p.SuccessRate
worstRate = p.SuccessRate
hasRate = true
continue
}
if p.SuccessRate > bestRate {
bestProvider = p.Name
bestRate = p.SuccessRate
}
if p.SuccessRate < worstRate {
worstProvider = p.Name
worstRate = p.SuccessRate
}
}
avgSuccessRate := 0.0
if totalRequests > 0 {
avgSuccessRate = (weightedSuccess / float64(totalRequests)) * 100
avgSuccessRate = math.Round(avgSuccessRate*100) / 100
}
response.Success(c, gin.H{
"providers": providers,
"summary": gin.H{
"total_requests": totalRequests,
"avg_success_rate": avgSuccessRate,
"best_provider": bestProvider,
"worst_provider": worstProvider,
},
})
}
// GetErrorLogs returns a paginated error log list with multi-dimensional filters.
// GET /api/v1/admin/ops/errors
func (h *OpsHandler) GetErrorLogs(c *gin.Context) {
page, pageSize := response.ParsePagination(c)
filter := &service.ErrorLogFilter{
Page: page,
PageSize: pageSize,
}
if startTimeStr := c.Query("start_time"); startTimeStr != "" {
startTime, err := time.Parse(time.RFC3339, startTimeStr)
if err != nil {
response.BadRequest(c, "Invalid start_time format (RFC3339)")
return
}
filter.StartTime = &startTime
}
if endTimeStr := c.Query("end_time"); endTimeStr != "" {
endTime, err := time.Parse(time.RFC3339, endTimeStr)
if err != nil {
response.BadRequest(c, "Invalid end_time format (RFC3339)")
return
}
filter.EndTime = &endTime
}
if filter.StartTime != nil && filter.EndTime != nil && filter.StartTime.After(*filter.EndTime) {
response.BadRequest(c, "Invalid time range: start_time must be <= end_time")
return
}
if errorCodeStr := c.Query("error_code"); errorCodeStr != "" {
code, err := strconv.Atoi(errorCodeStr)
if err != nil || code < 0 {
response.BadRequest(c, "Invalid error_code")
return
}
filter.ErrorCode = &code
}
// Keep both parameter names for compatibility: provider (docs) and platform (legacy).
filter.Provider = c.Query("provider")
if filter.Provider == "" {
filter.Provider = c.Query("platform")
}
if accountIDStr := c.Query("account_id"); accountIDStr != "" {
accountID, err := strconv.ParseInt(accountIDStr, 10, 64)
if err != nil || accountID <= 0 {
response.BadRequest(c, "Invalid account_id")
return
}
filter.AccountID = &accountID
}
out, err := h.opsService.GetErrorLogs(c.Request.Context(), filter)
if err != nil {
response.Error(c, http.StatusInternalServerError, "Failed to get error logs")
return
}
response.Success(c, gin.H{
"errors": out.Errors,
"total": out.Total,
"page": out.Page,
"page_size": out.PageSize,
})
}
// GetLatencyHistogram returns the latency distribution histogram.
// GET /api/v1/admin/ops/dashboard/latency-histogram
func (h *OpsHandler) GetLatencyHistogram(c *gin.Context) {
timeRange := c.Query("time_range")
if timeRange == "" {
timeRange = "1h"
}
buckets, err := h.opsService.GetLatencyHistogram(c.Request.Context(), timeRange)
if err != nil {
response.Error(c, http.StatusInternalServerError, "Failed to get latency histogram")
return
}
totalRequests := int64(0)
for _, b := range buckets {
totalRequests += b.Count
}
response.Success(c, gin.H{
"buckets": buckets,
"total_requests": totalRequests,
"slow_request_threshold": 1000,
})
}
// GetErrorDistribution returns the error distribution.
// GET /api/v1/admin/ops/dashboard/errors/distribution
func (h *OpsHandler) GetErrorDistribution(c *gin.Context) {
timeRange := c.Query("time_range")
if timeRange == "" {
timeRange = "1h"
}
items, err := h.opsService.GetErrorDistribution(c.Request.Context(), timeRange)
if err != nil {
response.Error(c, http.StatusInternalServerError, "Failed to get error distribution")
return
}
response.Success(c, gin.H{
"items": items,
})
}

View File

@@ -0,0 +1,286 @@
package admin
import (
"context"
"encoding/json"
"log"
"net"
"net/http"
"net/netip"
"net/url"
"os"
"strconv"
"strings"
"time"
"github.com/gin-gonic/gin"
"github.com/gorilla/websocket"
)
type OpsWSProxyConfig struct {
TrustProxy bool
TrustedProxies []netip.Prefix
OriginPolicy string
}
const (
envOpsWSTrustProxy = "OPS_WS_TRUST_PROXY"
envOpsWSTrustedProxies = "OPS_WS_TRUSTED_PROXIES"
envOpsWSOriginPolicy = "OPS_WS_ORIGIN_POLICY"
)
const (
OriginPolicyStrict = "strict"
OriginPolicyPermissive = "permissive"
)
var opsWSProxyConfig = loadOpsWSProxyConfigFromEnv()
var upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
return isAllowedOpsWSOrigin(r)
},
}
// QPSWSHandler handles realtime QPS push via WebSocket.
// GET /api/v1/admin/ops/ws/qps
func (h *OpsHandler) QPSWSHandler(c *gin.Context) {
conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
if err != nil {
log.Printf("[OpsWS] upgrade failed: %v", err)
return
}
defer func() { _ = conn.Close() }()
// Set pong handler
if err := conn.SetReadDeadline(time.Now().Add(60 * time.Second)); err != nil {
log.Printf("[OpsWS] set read deadline failed: %v", err)
return
}
conn.SetPongHandler(func(string) error {
return conn.SetReadDeadline(time.Now().Add(60 * time.Second))
})
// Push QPS data every 2 seconds
ticker := time.NewTicker(2 * time.Second)
defer ticker.Stop()
// Heartbeat ping every 30 seconds
pingTicker := time.NewTicker(30 * time.Second)
defer pingTicker.Stop()
ctx, cancel := context.WithCancel(c.Request.Context())
defer cancel()
for {
select {
case <-ticker.C:
// Fetch 1m window stats for current QPS
data, err := h.opsService.GetDashboardOverview(ctx, "5m")
if err != nil {
log.Printf("[OpsWS] get overview failed: %v", err)
continue
}
payload := gin.H{
"type": "qps_update",
"timestamp": time.Now().Format(time.RFC3339),
"data": gin.H{
"qps": data.QPS.Current,
"tps": data.TPS.Current,
"request_count": data.Errors.TotalCount + int64(data.QPS.Avg1h*60), // Rough estimate
},
}
msg, _ := json.Marshal(payload)
if err := conn.WriteMessage(websocket.TextMessage, msg); err != nil {
log.Printf("[OpsWS] write failed: %v", err)
return
}
case <-pingTicker.C:
if err := conn.WriteMessage(websocket.PingMessage, nil); err != nil {
log.Printf("[OpsWS] ping failed: %v", err)
return
}
case <-ctx.Done():
return
}
}
}
func isAllowedOpsWSOrigin(r *http.Request) bool {
if r == nil {
return false
}
origin := strings.TrimSpace(r.Header.Get("Origin"))
if origin == "" {
switch strings.ToLower(strings.TrimSpace(opsWSProxyConfig.OriginPolicy)) {
case OriginPolicyStrict:
return false
case OriginPolicyPermissive, "":
return true
default:
return true
}
}
parsed, err := url.Parse(origin)
if err != nil || parsed.Hostname() == "" {
return false
}
originHost := strings.ToLower(parsed.Hostname())
trustProxyHeaders := shouldTrustOpsWSProxyHeaders(r)
reqHost := hostWithoutPort(r.Host)
if trustProxyHeaders {
xfHost := strings.TrimSpace(r.Header.Get("X-Forwarded-Host"))
if xfHost != "" {
xfHost = strings.TrimSpace(strings.Split(xfHost, ",")[0])
if xfHost != "" {
reqHost = hostWithoutPort(xfHost)
}
}
}
reqHost = strings.ToLower(reqHost)
if reqHost == "" {
return false
}
return originHost == reqHost
}
func shouldTrustOpsWSProxyHeaders(r *http.Request) bool {
if r == nil {
return false
}
if !opsWSProxyConfig.TrustProxy {
return false
}
peerIP, ok := requestPeerIP(r)
if !ok {
return false
}
return isAddrInTrustedProxies(peerIP, opsWSProxyConfig.TrustedProxies)
}
func requestPeerIP(r *http.Request) (netip.Addr, bool) {
if r == nil {
return netip.Addr{}, false
}
host, _, err := net.SplitHostPort(strings.TrimSpace(r.RemoteAddr))
if err != nil {
host = strings.TrimSpace(r.RemoteAddr)
}
host = strings.TrimPrefix(host, "[")
host = strings.TrimSuffix(host, "]")
if host == "" {
return netip.Addr{}, false
}
addr, err := netip.ParseAddr(host)
if err != nil {
return netip.Addr{}, false
}
return addr.Unmap(), true
}
func isAddrInTrustedProxies(addr netip.Addr, trusted []netip.Prefix) bool {
if !addr.IsValid() {
return false
}
for _, p := range trusted {
if p.Contains(addr) {
return true
}
}
return false
}
func loadOpsWSProxyConfigFromEnv() OpsWSProxyConfig {
cfg := OpsWSProxyConfig{
TrustProxy: true,
TrustedProxies: defaultTrustedProxies(),
OriginPolicy: OriginPolicyPermissive,
}
if v := strings.TrimSpace(os.Getenv(envOpsWSTrustProxy)); v != "" {
if parsed, err := strconv.ParseBool(v); err == nil {
cfg.TrustProxy = parsed
} else {
log.Printf("[OpsWS] invalid %s=%q (expected bool); using default=%v", envOpsWSTrustProxy, v, cfg.TrustProxy)
}
}
if raw := strings.TrimSpace(os.Getenv(envOpsWSTrustedProxies)); raw != "" {
prefixes, invalid := parseTrustedProxyList(raw)
if len(invalid) > 0 {
log.Printf("[OpsWS] invalid %s entries ignored: %s", envOpsWSTrustedProxies, strings.Join(invalid, ", "))
}
cfg.TrustedProxies = prefixes
}
if v := strings.TrimSpace(os.Getenv(envOpsWSOriginPolicy)); v != "" {
normalized := strings.ToLower(v)
switch normalized {
case OriginPolicyStrict, OriginPolicyPermissive:
cfg.OriginPolicy = normalized
default:
log.Printf("[OpsWS] invalid %s=%q (expected %q or %q); using default=%q", envOpsWSOriginPolicy, v, OriginPolicyStrict, OriginPolicyPermissive, cfg.OriginPolicy)
}
}
return cfg
}
func defaultTrustedProxies() []netip.Prefix {
prefixes, _ := parseTrustedProxyList("127.0.0.0/8,::1/128")
return prefixes
}
func parseTrustedProxyList(raw string) (prefixes []netip.Prefix, invalid []string) {
for _, token := range strings.Split(raw, ",") {
item := strings.TrimSpace(token)
if item == "" {
continue
}
var (
p netip.Prefix
err error
)
if strings.Contains(item, "/") {
p, err = netip.ParsePrefix(item)
} else {
var addr netip.Addr
addr, err = netip.ParseAddr(item)
if err == nil {
addr = addr.Unmap()
bits := 128
if addr.Is4() {
bits = 32
}
p = netip.PrefixFrom(addr, bits)
}
}
if err != nil || !p.IsValid() {
invalid = append(invalid, item)
continue
}
prefixes = append(prefixes, p.Masked())
}
return prefixes, invalid
}
func hostWithoutPort(hostport string) string {
hostport = strings.TrimSpace(hostport)
if hostport == "" {
return ""
}
if host, _, err := net.SplitHostPort(hostport); err == nil {
return host
}
if strings.HasPrefix(hostport, "[") && strings.HasSuffix(hostport, "]") {
return strings.Trim(hostport, "[]")
}
parts := strings.Split(hostport, ":")
return parts[0]
}

View File

@@ -0,0 +1,123 @@
package admin
import (
"net/http"
"net/netip"
"testing"
)
func TestIsAllowedOpsWSOrigin_AllowsEmptyOrigin(t *testing.T) {
original := opsWSProxyConfig
t.Cleanup(func() { opsWSProxyConfig = original })
opsWSProxyConfig = OpsWSProxyConfig{OriginPolicy: OriginPolicyPermissive}
req, err := http.NewRequest(http.MethodGet, "http://example.test", nil)
if err != nil {
t.Fatalf("NewRequest: %v", err)
}
if !isAllowedOpsWSOrigin(req) {
t.Fatalf("expected empty Origin to be allowed")
}
}
func TestIsAllowedOpsWSOrigin_RejectsEmptyOrigin_WhenStrict(t *testing.T) {
original := opsWSProxyConfig
t.Cleanup(func() { opsWSProxyConfig = original })
opsWSProxyConfig = OpsWSProxyConfig{OriginPolicy: OriginPolicyStrict}
req, err := http.NewRequest(http.MethodGet, "http://example.test", nil)
if err != nil {
t.Fatalf("NewRequest: %v", err)
}
if isAllowedOpsWSOrigin(req) {
t.Fatalf("expected empty Origin to be rejected under strict policy")
}
}
func TestIsAllowedOpsWSOrigin_UsesXForwardedHostOnlyFromTrustedProxy(t *testing.T) {
original := opsWSProxyConfig
t.Cleanup(func() { opsWSProxyConfig = original })
opsWSProxyConfig = OpsWSProxyConfig{
TrustProxy: true,
TrustedProxies: []netip.Prefix{
netip.MustParsePrefix("127.0.0.0/8"),
},
}
// Untrusted peer: ignore X-Forwarded-Host and compare against r.Host.
{
req, err := http.NewRequest(http.MethodGet, "http://internal.service.local", nil)
if err != nil {
t.Fatalf("NewRequest: %v", err)
}
req.RemoteAddr = "192.0.2.1:12345"
req.Host = "internal.service.local"
req.Header.Set("Origin", "https://public.example.com")
req.Header.Set("X-Forwarded-Host", "public.example.com")
if isAllowedOpsWSOrigin(req) {
t.Fatalf("expected Origin to be rejected when peer is not a trusted proxy")
}
}
// Trusted peer: allow X-Forwarded-Host to participate in Origin validation.
{
req, err := http.NewRequest(http.MethodGet, "http://internal.service.local", nil)
if err != nil {
t.Fatalf("NewRequest: %v", err)
}
req.RemoteAddr = "127.0.0.1:23456"
req.Host = "internal.service.local"
req.Header.Set("Origin", "https://public.example.com")
req.Header.Set("X-Forwarded-Host", "public.example.com")
if !isAllowedOpsWSOrigin(req) {
t.Fatalf("expected Origin to be accepted when peer is a trusted proxy")
}
}
}
func TestLoadOpsWSProxyConfigFromEnv_OriginPolicy(t *testing.T) {
t.Setenv(envOpsWSOriginPolicy, "STRICT")
cfg := loadOpsWSProxyConfigFromEnv()
if cfg.OriginPolicy != OriginPolicyStrict {
t.Fatalf("OriginPolicy=%q, want %q", cfg.OriginPolicy, OriginPolicyStrict)
}
}
func TestLoadOpsWSProxyConfigFromEnv_OriginPolicyInvalidUsesDefault(t *testing.T) {
t.Setenv(envOpsWSOriginPolicy, "nope")
cfg := loadOpsWSProxyConfigFromEnv()
if cfg.OriginPolicy != OriginPolicyPermissive {
t.Fatalf("OriginPolicy=%q, want %q", cfg.OriginPolicy, OriginPolicyPermissive)
}
}
func TestParseTrustedProxyList(t *testing.T) {
prefixes, invalid := parseTrustedProxyList("10.0.0.1, 10.0.0.0/8, bad, ::1/128")
if len(prefixes) != 3 {
t.Fatalf("prefixes=%d, want 3", len(prefixes))
}
if len(invalid) != 1 || invalid[0] != "bad" {
t.Fatalf("invalid=%v, want [bad]", invalid)
}
}
func TestRequestPeerIP_ParsesIPv6(t *testing.T) {
req, err := http.NewRequest(http.MethodGet, "http://example.test", nil)
if err != nil {
t.Fatalf("NewRequest: %v", err)
}
req.RemoteAddr = "[::1]:1234"
addr, ok := requestPeerIP(req)
if !ok {
t.Fatalf("expected IPv6 peer IP to parse")
}
if addr != netip.MustParseAddr("::1") {
t.Fatalf("addr=%s, want ::1", addr)
}
}

View File

@@ -36,22 +36,22 @@ func (h *SettingHandler) GetSettings(c *gin.Context) {
response.Success(c, dto.SystemSettings{ response.Success(c, dto.SystemSettings{
RegistrationEnabled: settings.RegistrationEnabled, RegistrationEnabled: settings.RegistrationEnabled,
EmailVerifyEnabled: settings.EmailVerifyEnabled, EmailVerifyEnabled: settings.EmailVerifyEnabled,
SmtpHost: settings.SmtpHost, SMTPHost: settings.SMTPHost,
SmtpPort: settings.SmtpPort, SMTPPort: settings.SMTPPort,
SmtpUsername: settings.SmtpUsername, SMTPUsername: settings.SMTPUsername,
SmtpPassword: settings.SmtpPassword, SMTPPassword: settings.SMTPPassword,
SmtpFrom: settings.SmtpFrom, SMTPFrom: settings.SMTPFrom,
SmtpFromName: settings.SmtpFromName, SMTPFromName: settings.SMTPFromName,
SmtpUseTLS: settings.SmtpUseTLS, SMTPUseTLS: settings.SMTPUseTLS,
TurnstileEnabled: settings.TurnstileEnabled, TurnstileEnabled: settings.TurnstileEnabled,
TurnstileSiteKey: settings.TurnstileSiteKey, TurnstileSiteKey: settings.TurnstileSiteKey,
TurnstileSecretKey: settings.TurnstileSecretKey, TurnstileSecretKey: settings.TurnstileSecretKey,
SiteName: settings.SiteName, SiteName: settings.SiteName,
SiteLogo: settings.SiteLogo, SiteLogo: settings.SiteLogo,
SiteSubtitle: settings.SiteSubtitle, SiteSubtitle: settings.SiteSubtitle,
ApiBaseUrl: settings.ApiBaseUrl, APIBaseURL: settings.APIBaseURL,
ContactInfo: settings.ContactInfo, ContactInfo: settings.ContactInfo,
DocUrl: settings.DocUrl, DocURL: settings.DocURL,
DefaultConcurrency: settings.DefaultConcurrency, DefaultConcurrency: settings.DefaultConcurrency,
DefaultBalance: settings.DefaultBalance, DefaultBalance: settings.DefaultBalance,
}) })
@@ -64,13 +64,13 @@ type UpdateSettingsRequest struct {
EmailVerifyEnabled bool `json:"email_verify_enabled"` EmailVerifyEnabled bool `json:"email_verify_enabled"`
// 邮件服务设置 // 邮件服务设置
SmtpHost string `json:"smtp_host"` SMTPHost string `json:"smtp_host"`
SmtpPort int `json:"smtp_port"` SMTPPort int `json:"smtp_port"`
SmtpUsername string `json:"smtp_username"` SMTPUsername string `json:"smtp_username"`
SmtpPassword string `json:"smtp_password"` SMTPPassword string `json:"smtp_password"`
SmtpFrom string `json:"smtp_from_email"` SMTPFrom string `json:"smtp_from_email"`
SmtpFromName string `json:"smtp_from_name"` SMTPFromName string `json:"smtp_from_name"`
SmtpUseTLS bool `json:"smtp_use_tls"` SMTPUseTLS bool `json:"smtp_use_tls"`
// Cloudflare Turnstile 设置 // Cloudflare Turnstile 设置
TurnstileEnabled bool `json:"turnstile_enabled"` TurnstileEnabled bool `json:"turnstile_enabled"`
@@ -81,9 +81,9 @@ type UpdateSettingsRequest struct {
SiteName string `json:"site_name"` SiteName string `json:"site_name"`
SiteLogo string `json:"site_logo"` SiteLogo string `json:"site_logo"`
SiteSubtitle string `json:"site_subtitle"` SiteSubtitle string `json:"site_subtitle"`
ApiBaseUrl string `json:"api_base_url"` APIBaseURL string `json:"api_base_url"`
ContactInfo string `json:"contact_info"` ContactInfo string `json:"contact_info"`
DocUrl string `json:"doc_url"` DocURL string `json:"doc_url"`
// 默认配置 // 默认配置
DefaultConcurrency int `json:"default_concurrency"` DefaultConcurrency int `json:"default_concurrency"`
@@ -106,8 +106,8 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) {
if req.DefaultBalance < 0 { if req.DefaultBalance < 0 {
req.DefaultBalance = 0 req.DefaultBalance = 0
} }
if req.SmtpPort <= 0 { if req.SMTPPort <= 0 {
req.SmtpPort = 587 req.SMTPPort = 587
} }
// Turnstile 参数验证 // Turnstile 参数验证
@@ -143,22 +143,22 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) {
settings := &service.SystemSettings{ settings := &service.SystemSettings{
RegistrationEnabled: req.RegistrationEnabled, RegistrationEnabled: req.RegistrationEnabled,
EmailVerifyEnabled: req.EmailVerifyEnabled, EmailVerifyEnabled: req.EmailVerifyEnabled,
SmtpHost: req.SmtpHost, SMTPHost: req.SMTPHost,
SmtpPort: req.SmtpPort, SMTPPort: req.SMTPPort,
SmtpUsername: req.SmtpUsername, SMTPUsername: req.SMTPUsername,
SmtpPassword: req.SmtpPassword, SMTPPassword: req.SMTPPassword,
SmtpFrom: req.SmtpFrom, SMTPFrom: req.SMTPFrom,
SmtpFromName: req.SmtpFromName, SMTPFromName: req.SMTPFromName,
SmtpUseTLS: req.SmtpUseTLS, SMTPUseTLS: req.SMTPUseTLS,
TurnstileEnabled: req.TurnstileEnabled, TurnstileEnabled: req.TurnstileEnabled,
TurnstileSiteKey: req.TurnstileSiteKey, TurnstileSiteKey: req.TurnstileSiteKey,
TurnstileSecretKey: req.TurnstileSecretKey, TurnstileSecretKey: req.TurnstileSecretKey,
SiteName: req.SiteName, SiteName: req.SiteName,
SiteLogo: req.SiteLogo, SiteLogo: req.SiteLogo,
SiteSubtitle: req.SiteSubtitle, SiteSubtitle: req.SiteSubtitle,
ApiBaseUrl: req.ApiBaseUrl, APIBaseURL: req.APIBaseURL,
ContactInfo: req.ContactInfo, ContactInfo: req.ContactInfo,
DocUrl: req.DocUrl, DocURL: req.DocURL,
DefaultConcurrency: req.DefaultConcurrency, DefaultConcurrency: req.DefaultConcurrency,
DefaultBalance: req.DefaultBalance, DefaultBalance: req.DefaultBalance,
} }
@@ -178,67 +178,67 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) {
response.Success(c, dto.SystemSettings{ response.Success(c, dto.SystemSettings{
RegistrationEnabled: updatedSettings.RegistrationEnabled, RegistrationEnabled: updatedSettings.RegistrationEnabled,
EmailVerifyEnabled: updatedSettings.EmailVerifyEnabled, EmailVerifyEnabled: updatedSettings.EmailVerifyEnabled,
SmtpHost: updatedSettings.SmtpHost, SMTPHost: updatedSettings.SMTPHost,
SmtpPort: updatedSettings.SmtpPort, SMTPPort: updatedSettings.SMTPPort,
SmtpUsername: updatedSettings.SmtpUsername, SMTPUsername: updatedSettings.SMTPUsername,
SmtpPassword: updatedSettings.SmtpPassword, SMTPPassword: updatedSettings.SMTPPassword,
SmtpFrom: updatedSettings.SmtpFrom, SMTPFrom: updatedSettings.SMTPFrom,
SmtpFromName: updatedSettings.SmtpFromName, SMTPFromName: updatedSettings.SMTPFromName,
SmtpUseTLS: updatedSettings.SmtpUseTLS, SMTPUseTLS: updatedSettings.SMTPUseTLS,
TurnstileEnabled: updatedSettings.TurnstileEnabled, TurnstileEnabled: updatedSettings.TurnstileEnabled,
TurnstileSiteKey: updatedSettings.TurnstileSiteKey, TurnstileSiteKey: updatedSettings.TurnstileSiteKey,
TurnstileSecretKey: updatedSettings.TurnstileSecretKey, TurnstileSecretKey: updatedSettings.TurnstileSecretKey,
SiteName: updatedSettings.SiteName, SiteName: updatedSettings.SiteName,
SiteLogo: updatedSettings.SiteLogo, SiteLogo: updatedSettings.SiteLogo,
SiteSubtitle: updatedSettings.SiteSubtitle, SiteSubtitle: updatedSettings.SiteSubtitle,
ApiBaseUrl: updatedSettings.ApiBaseUrl, APIBaseURL: updatedSettings.APIBaseURL,
ContactInfo: updatedSettings.ContactInfo, ContactInfo: updatedSettings.ContactInfo,
DocUrl: updatedSettings.DocUrl, DocURL: updatedSettings.DocURL,
DefaultConcurrency: updatedSettings.DefaultConcurrency, DefaultConcurrency: updatedSettings.DefaultConcurrency,
DefaultBalance: updatedSettings.DefaultBalance, DefaultBalance: updatedSettings.DefaultBalance,
}) })
} }
// TestSmtpRequest 测试SMTP连接请求 // TestSMTPRequest 测试SMTP连接请求
type TestSmtpRequest struct { type TestSMTPRequest struct {
SmtpHost string `json:"smtp_host" binding:"required"` SMTPHost string `json:"smtp_host" binding:"required"`
SmtpPort int `json:"smtp_port"` SMTPPort int `json:"smtp_port"`
SmtpUsername string `json:"smtp_username"` SMTPUsername string `json:"smtp_username"`
SmtpPassword string `json:"smtp_password"` SMTPPassword string `json:"smtp_password"`
SmtpUseTLS bool `json:"smtp_use_tls"` SMTPUseTLS bool `json:"smtp_use_tls"`
} }
// TestSmtpConnection 测试SMTP连接 // TestSMTPConnection 测试SMTP连接
// POST /api/v1/admin/settings/test-smtp // POST /api/v1/admin/settings/test-smtp
func (h *SettingHandler) TestSmtpConnection(c *gin.Context) { func (h *SettingHandler) TestSMTPConnection(c *gin.Context) {
var req TestSmtpRequest var req TestSMTPRequest
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
response.BadRequest(c, "Invalid request: "+err.Error()) response.BadRequest(c, "Invalid request: "+err.Error())
return return
} }
if req.SmtpPort <= 0 { if req.SMTPPort <= 0 {
req.SmtpPort = 587 req.SMTPPort = 587
} }
// 如果未提供密码,从数据库获取已保存的密码 // 如果未提供密码,从数据库获取已保存的密码
password := req.SmtpPassword password := req.SMTPPassword
if password == "" { if password == "" {
savedConfig, err := h.emailService.GetSmtpConfig(c.Request.Context()) savedConfig, err := h.emailService.GetSMTPConfig(c.Request.Context())
if err == nil && savedConfig != nil { if err == nil && savedConfig != nil {
password = savedConfig.Password password = savedConfig.Password
} }
} }
config := &service.SmtpConfig{ config := &service.SMTPConfig{
Host: req.SmtpHost, Host: req.SMTPHost,
Port: req.SmtpPort, Port: req.SMTPPort,
Username: req.SmtpUsername, Username: req.SMTPUsername,
Password: password, Password: password,
UseTLS: req.SmtpUseTLS, UseTLS: req.SMTPUseTLS,
} }
err := h.emailService.TestSmtpConnectionWithConfig(config) err := h.emailService.TestSMTPConnectionWithConfig(config)
if err != nil { if err != nil {
response.ErrorFrom(c, err) response.ErrorFrom(c, err)
return return
@@ -250,13 +250,13 @@ func (h *SettingHandler) TestSmtpConnection(c *gin.Context) {
// SendTestEmailRequest 发送测试邮件请求 // SendTestEmailRequest 发送测试邮件请求
type SendTestEmailRequest struct { type SendTestEmailRequest struct {
Email string `json:"email" binding:"required,email"` Email string `json:"email" binding:"required,email"`
SmtpHost string `json:"smtp_host" binding:"required"` SMTPHost string `json:"smtp_host" binding:"required"`
SmtpPort int `json:"smtp_port"` SMTPPort int `json:"smtp_port"`
SmtpUsername string `json:"smtp_username"` SMTPUsername string `json:"smtp_username"`
SmtpPassword string `json:"smtp_password"` SMTPPassword string `json:"smtp_password"`
SmtpFrom string `json:"smtp_from_email"` SMTPFrom string `json:"smtp_from_email"`
SmtpFromName string `json:"smtp_from_name"` SMTPFromName string `json:"smtp_from_name"`
SmtpUseTLS bool `json:"smtp_use_tls"` SMTPUseTLS bool `json:"smtp_use_tls"`
} }
// SendTestEmail 发送测试邮件 // SendTestEmail 发送测试邮件
@@ -268,27 +268,27 @@ func (h *SettingHandler) SendTestEmail(c *gin.Context) {
return return
} }
if req.SmtpPort <= 0 { if req.SMTPPort <= 0 {
req.SmtpPort = 587 req.SMTPPort = 587
} }
// 如果未提供密码,从数据库获取已保存的密码 // 如果未提供密码,从数据库获取已保存的密码
password := req.SmtpPassword password := req.SMTPPassword
if password == "" { if password == "" {
savedConfig, err := h.emailService.GetSmtpConfig(c.Request.Context()) savedConfig, err := h.emailService.GetSMTPConfig(c.Request.Context())
if err == nil && savedConfig != nil { if err == nil && savedConfig != nil {
password = savedConfig.Password password = savedConfig.Password
} }
} }
config := &service.SmtpConfig{ config := &service.SMTPConfig{
Host: req.SmtpHost, Host: req.SMTPHost,
Port: req.SmtpPort, Port: req.SMTPPort,
Username: req.SmtpUsername, Username: req.SMTPUsername,
Password: password, Password: password,
From: req.SmtpFrom, From: req.SMTPFrom,
FromName: req.SmtpFromName, FromName: req.SMTPFromName,
UseTLS: req.SmtpUseTLS, UseTLS: req.SMTPUseTLS,
} }
siteName := h.settingService.GetSiteName(c.Request.Context()) siteName := h.settingService.GetSiteName(c.Request.Context())
@@ -333,10 +333,10 @@ func (h *SettingHandler) SendTestEmail(c *gin.Context) {
response.Success(c, gin.H{"message": "Test email sent successfully"}) response.Success(c, gin.H{"message": "Test email sent successfully"})
} }
// GetAdminApiKey 获取管理员 API Key 状态 // GetAdminAPIKey 获取管理员 API Key 状态
// GET /api/v1/admin/settings/admin-api-key // GET /api/v1/admin/settings/admin-api-key
func (h *SettingHandler) GetAdminApiKey(c *gin.Context) { func (h *SettingHandler) GetAdminAPIKey(c *gin.Context) {
maskedKey, exists, err := h.settingService.GetAdminApiKeyStatus(c.Request.Context()) maskedKey, exists, err := h.settingService.GetAdminAPIKeyStatus(c.Request.Context())
if err != nil { if err != nil {
response.ErrorFrom(c, err) response.ErrorFrom(c, err)
return return
@@ -348,10 +348,10 @@ func (h *SettingHandler) GetAdminApiKey(c *gin.Context) {
}) })
} }
// RegenerateAdminApiKey 生成/重新生成管理员 API Key // RegenerateAdminAPIKey 生成/重新生成管理员 API Key
// POST /api/v1/admin/settings/admin-api-key/regenerate // POST /api/v1/admin/settings/admin-api-key/regenerate
func (h *SettingHandler) RegenerateAdminApiKey(c *gin.Context) { func (h *SettingHandler) RegenerateAdminAPIKey(c *gin.Context) {
key, err := h.settingService.GenerateAdminApiKey(c.Request.Context()) key, err := h.settingService.GenerateAdminAPIKey(c.Request.Context())
if err != nil { if err != nil {
response.ErrorFrom(c, err) response.ErrorFrom(c, err)
return return
@@ -362,10 +362,10 @@ func (h *SettingHandler) RegenerateAdminApiKey(c *gin.Context) {
}) })
} }
// DeleteAdminApiKey 删除管理员 API Key // DeleteAdminAPIKey 删除管理员 API Key
// DELETE /api/v1/admin/settings/admin-api-key // DELETE /api/v1/admin/settings/admin-api-key
func (h *SettingHandler) DeleteAdminApiKey(c *gin.Context) { func (h *SettingHandler) DeleteAdminAPIKey(c *gin.Context) {
if err := h.settingService.DeleteAdminApiKey(c.Request.Context()); err != nil { if err := h.settingService.DeleteAdminAPIKey(c.Request.Context()); err != nil {
response.ErrorFrom(c, err) response.ErrorFrom(c, err)
return return
} }

View File

@@ -17,14 +17,14 @@ import (
// UsageHandler handles admin usage-related requests // UsageHandler handles admin usage-related requests
type UsageHandler struct { type UsageHandler struct {
usageService *service.UsageService usageService *service.UsageService
apiKeyService *service.ApiKeyService apiKeyService *service.APIKeyService
adminService service.AdminService adminService service.AdminService
} }
// NewUsageHandler creates a new admin usage handler // NewUsageHandler creates a new admin usage handler
func NewUsageHandler( func NewUsageHandler(
usageService *service.UsageService, usageService *service.UsageService,
apiKeyService *service.ApiKeyService, apiKeyService *service.APIKeyService,
adminService service.AdminService, adminService service.AdminService,
) *UsageHandler { ) *UsageHandler {
return &UsageHandler{ return &UsageHandler{
@@ -125,7 +125,7 @@ func (h *UsageHandler) List(c *gin.Context) {
params := pagination.PaginationParams{Page: page, PageSize: pageSize} params := pagination.PaginationParams{Page: page, PageSize: pageSize}
filters := usagestats.UsageLogFilters{ filters := usagestats.UsageLogFilters{
UserID: userID, UserID: userID,
ApiKeyID: apiKeyID, APIKeyID: apiKeyID,
AccountID: accountID, AccountID: accountID,
GroupID: groupID, GroupID: groupID,
Model: model, Model: model,
@@ -207,7 +207,7 @@ func (h *UsageHandler) Stats(c *gin.Context) {
} }
if apiKeyID > 0 { if apiKeyID > 0 {
stats, err := h.usageService.GetStatsByApiKey(c.Request.Context(), apiKeyID, startTime, endTime) stats, err := h.usageService.GetStatsByAPIKey(c.Request.Context(), apiKeyID, startTime, endTime)
if err != nil { if err != nil {
response.ErrorFrom(c, err) response.ErrorFrom(c, err)
return return
@@ -269,9 +269,9 @@ func (h *UsageHandler) SearchUsers(c *gin.Context) {
response.Success(c, result) response.Success(c, result)
} }
// SearchApiKeys handles searching API keys by user // SearchAPIKeys handles searching API keys by user
// GET /api/v1/admin/usage/search-api-keys // GET /api/v1/admin/usage/search-api-keys
func (h *UsageHandler) SearchApiKeys(c *gin.Context) { func (h *UsageHandler) SearchAPIKeys(c *gin.Context) {
userIDStr := c.Query("user_id") userIDStr := c.Query("user_id")
keyword := c.Query("q") keyword := c.Query("q")
@@ -285,22 +285,22 @@ func (h *UsageHandler) SearchApiKeys(c *gin.Context) {
userID = id userID = id
} }
keys, err := h.apiKeyService.SearchApiKeys(c.Request.Context(), userID, keyword, 30) keys, err := h.apiKeyService.SearchAPIKeys(c.Request.Context(), userID, keyword, 30)
if err != nil { if err != nil {
response.ErrorFrom(c, err) response.ErrorFrom(c, err)
return return
} }
// Return simplified API key list (only id and name) // Return simplified API key list (only id and name)
type SimpleApiKey struct { type SimpleAPIKey struct {
ID int64 `json:"id"` ID int64 `json:"id"`
Name string `json:"name"` Name string `json:"name"`
UserID int64 `json:"user_id"` UserID int64 `json:"user_id"`
} }
result := make([]SimpleApiKey, len(keys)) result := make([]SimpleAPIKey, len(keys))
for i, k := range keys { for i, k := range keys {
result[i] = SimpleApiKey{ result[i] = SimpleAPIKey{
ID: k.ID, ID: k.ID,
Name: k.Name, Name: k.Name,
UserID: k.UserID, UserID: k.UserID,

View File

@@ -243,9 +243,9 @@ func (h *UserHandler) GetUserAPIKeys(c *gin.Context) {
return return
} }
out := make([]dto.ApiKey, 0, len(keys)) out := make([]dto.APIKey, 0, len(keys))
for i := range keys { for i := range keys {
out = append(out, *dto.ApiKeyFromService(&keys[i])) out = append(out, *dto.APIKeyFromService(&keys[i]))
} }
response.Paginated(c, out, total, page, pageSize) response.Paginated(c, out, total, page, pageSize)
} }

View File

@@ -14,11 +14,11 @@ import (
// APIKeyHandler handles API key-related requests // APIKeyHandler handles API key-related requests
type APIKeyHandler struct { type APIKeyHandler struct {
apiKeyService *service.ApiKeyService apiKeyService *service.APIKeyService
} }
// NewAPIKeyHandler creates a new APIKeyHandler // NewAPIKeyHandler creates a new APIKeyHandler
func NewAPIKeyHandler(apiKeyService *service.ApiKeyService) *APIKeyHandler { func NewAPIKeyHandler(apiKeyService *service.APIKeyService) *APIKeyHandler {
return &APIKeyHandler{ return &APIKeyHandler{
apiKeyService: apiKeyService, apiKeyService: apiKeyService,
} }
@@ -56,9 +56,9 @@ func (h *APIKeyHandler) List(c *gin.Context) {
return return
} }
out := make([]dto.ApiKey, 0, len(keys)) out := make([]dto.APIKey, 0, len(keys))
for i := range keys { for i := range keys {
out = append(out, *dto.ApiKeyFromService(&keys[i])) out = append(out, *dto.APIKeyFromService(&keys[i]))
} }
response.Paginated(c, out, result.Total, page, pageSize) response.Paginated(c, out, result.Total, page, pageSize)
} }
@@ -90,7 +90,7 @@ func (h *APIKeyHandler) GetByID(c *gin.Context) {
return return
} }
response.Success(c, dto.ApiKeyFromService(key)) response.Success(c, dto.APIKeyFromService(key))
} }
// Create handles creating a new API key // Create handles creating a new API key
@@ -108,7 +108,7 @@ func (h *APIKeyHandler) Create(c *gin.Context) {
return return
} }
svcReq := service.CreateApiKeyRequest{ svcReq := service.CreateAPIKeyRequest{
Name: req.Name, Name: req.Name,
GroupID: req.GroupID, GroupID: req.GroupID,
CustomKey: req.CustomKey, CustomKey: req.CustomKey,
@@ -119,7 +119,7 @@ func (h *APIKeyHandler) Create(c *gin.Context) {
return return
} }
response.Success(c, dto.ApiKeyFromService(key)) response.Success(c, dto.APIKeyFromService(key))
} }
// Update handles updating an API key // Update handles updating an API key
@@ -143,7 +143,7 @@ func (h *APIKeyHandler) Update(c *gin.Context) {
return return
} }
svcReq := service.UpdateApiKeyRequest{} svcReq := service.UpdateAPIKeyRequest{}
if req.Name != "" { if req.Name != "" {
svcReq.Name = &req.Name svcReq.Name = &req.Name
} }
@@ -158,7 +158,7 @@ func (h *APIKeyHandler) Update(c *gin.Context) {
return return
} }
response.Success(c, dto.ApiKeyFromService(key)) response.Success(c, dto.APIKeyFromService(key))
} }
// Delete handles deleting an API key // Delete handles deleting an API key

View File

@@ -1,3 +1,4 @@
// Package dto provides mapping utilities for converting between service layer and HTTP handler DTOs.
package dto package dto
import "github.com/Wei-Shaw/sub2api/internal/service" import "github.com/Wei-Shaw/sub2api/internal/service"
@@ -26,11 +27,11 @@ func UserFromService(u *service.User) *User {
return nil return nil
} }
out := UserFromServiceShallow(u) out := UserFromServiceShallow(u)
if len(u.ApiKeys) > 0 { if len(u.APIKeys) > 0 {
out.ApiKeys = make([]ApiKey, 0, len(u.ApiKeys)) out.APIKeys = make([]APIKey, 0, len(u.APIKeys))
for i := range u.ApiKeys { for i := range u.APIKeys {
k := u.ApiKeys[i] k := u.APIKeys[i]
out.ApiKeys = append(out.ApiKeys, *ApiKeyFromService(&k)) out.APIKeys = append(out.APIKeys, *APIKeyFromService(&k))
} }
} }
if len(u.Subscriptions) > 0 { if len(u.Subscriptions) > 0 {
@@ -43,11 +44,11 @@ func UserFromService(u *service.User) *User {
return out return out
} }
func ApiKeyFromService(k *service.ApiKey) *ApiKey { func APIKeyFromService(k *service.APIKey) *APIKey {
if k == nil { if k == nil {
return nil return nil
} }
return &ApiKey{ return &APIKey{
ID: k.ID, ID: k.ID,
UserID: k.UserID, UserID: k.UserID,
Key: k.Key, Key: k.Key,
@@ -220,7 +221,7 @@ func UsageLogFromService(l *service.UsageLog) *UsageLog {
return &UsageLog{ return &UsageLog{
ID: l.ID, ID: l.ID,
UserID: l.UserID, UserID: l.UserID,
ApiKeyID: l.ApiKeyID, APIKeyID: l.APIKeyID,
AccountID: l.AccountID, AccountID: l.AccountID,
RequestID: l.RequestID, RequestID: l.RequestID,
Model: l.Model, Model: l.Model,
@@ -245,7 +246,7 @@ func UsageLogFromService(l *service.UsageLog) *UsageLog {
FirstTokenMs: l.FirstTokenMs, FirstTokenMs: l.FirstTokenMs,
CreatedAt: l.CreatedAt, CreatedAt: l.CreatedAt,
User: UserFromServiceShallow(l.User), User: UserFromServiceShallow(l.User),
ApiKey: ApiKeyFromService(l.ApiKey), APIKey: APIKeyFromService(l.APIKey),
Account: AccountFromService(l.Account), Account: AccountFromService(l.Account),
Group: GroupFromServiceShallow(l.Group), Group: GroupFromServiceShallow(l.Group),
Subscription: UserSubscriptionFromService(l.Subscription), Subscription: UserSubscriptionFromService(l.Subscription),

View File

@@ -5,13 +5,13 @@ type SystemSettings struct {
RegistrationEnabled bool `json:"registration_enabled"` RegistrationEnabled bool `json:"registration_enabled"`
EmailVerifyEnabled bool `json:"email_verify_enabled"` EmailVerifyEnabled bool `json:"email_verify_enabled"`
SmtpHost string `json:"smtp_host"` SMTPHost string `json:"smtp_host"`
SmtpPort int `json:"smtp_port"` SMTPPort int `json:"smtp_port"`
SmtpUsername string `json:"smtp_username"` SMTPUsername string `json:"smtp_username"`
SmtpPassword string `json:"smtp_password,omitempty"` SMTPPassword string `json:"smtp_password,omitempty"`
SmtpFrom string `json:"smtp_from_email"` SMTPFrom string `json:"smtp_from_email"`
SmtpFromName string `json:"smtp_from_name"` SMTPFromName string `json:"smtp_from_name"`
SmtpUseTLS bool `json:"smtp_use_tls"` SMTPUseTLS bool `json:"smtp_use_tls"`
TurnstileEnabled bool `json:"turnstile_enabled"` TurnstileEnabled bool `json:"turnstile_enabled"`
TurnstileSiteKey string `json:"turnstile_site_key"` TurnstileSiteKey string `json:"turnstile_site_key"`
@@ -20,9 +20,9 @@ type SystemSettings struct {
SiteName string `json:"site_name"` SiteName string `json:"site_name"`
SiteLogo string `json:"site_logo"` SiteLogo string `json:"site_logo"`
SiteSubtitle string `json:"site_subtitle"` SiteSubtitle string `json:"site_subtitle"`
ApiBaseUrl string `json:"api_base_url"` APIBaseURL string `json:"api_base_url"`
ContactInfo string `json:"contact_info"` ContactInfo string `json:"contact_info"`
DocUrl string `json:"doc_url"` DocURL string `json:"doc_url"`
DefaultConcurrency int `json:"default_concurrency"` DefaultConcurrency int `json:"default_concurrency"`
DefaultBalance float64 `json:"default_balance"` DefaultBalance float64 `json:"default_balance"`
@@ -36,8 +36,8 @@ type PublicSettings struct {
SiteName string `json:"site_name"` SiteName string `json:"site_name"`
SiteLogo string `json:"site_logo"` SiteLogo string `json:"site_logo"`
SiteSubtitle string `json:"site_subtitle"` SiteSubtitle string `json:"site_subtitle"`
ApiBaseUrl string `json:"api_base_url"` APIBaseURL string `json:"api_base_url"`
ContactInfo string `json:"contact_info"` ContactInfo string `json:"contact_info"`
DocUrl string `json:"doc_url"` DocURL string `json:"doc_url"`
Version string `json:"version"` Version string `json:"version"`
} }

View File

@@ -15,11 +15,11 @@ type User struct {
CreatedAt time.Time `json:"created_at"` CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"` UpdatedAt time.Time `json:"updated_at"`
ApiKeys []ApiKey `json:"api_keys,omitempty"` APIKeys []APIKey `json:"api_keys,omitempty"`
Subscriptions []UserSubscription `json:"subscriptions,omitempty"` Subscriptions []UserSubscription `json:"subscriptions,omitempty"`
} }
type ApiKey struct { type APIKey struct {
ID int64 `json:"id"` ID int64 `json:"id"`
UserID int64 `json:"user_id"` UserID int64 `json:"user_id"`
Key string `json:"key"` Key string `json:"key"`
@@ -136,7 +136,7 @@ type RedeemCode struct {
type UsageLog struct { type UsageLog struct {
ID int64 `json:"id"` ID int64 `json:"id"`
UserID int64 `json:"user_id"` UserID int64 `json:"user_id"`
ApiKeyID int64 `json:"api_key_id"` APIKeyID int64 `json:"api_key_id"`
AccountID int64 `json:"account_id"` AccountID int64 `json:"account_id"`
RequestID string `json:"request_id"` RequestID string `json:"request_id"`
Model string `json:"model"` Model string `json:"model"`
@@ -168,7 +168,7 @@ type UsageLog struct {
CreatedAt time.Time `json:"created_at"` CreatedAt time.Time `json:"created_at"`
User *User `json:"user,omitempty"` User *User `json:"user,omitempty"`
ApiKey *ApiKey `json:"api_key,omitempty"` APIKey *APIKey `json:"api_key,omitempty"`
Account *Account `json:"account,omitempty"` Account *Account `json:"account,omitempty"`
Group *Group `json:"group,omitempty"` Group *Group `json:"group,omitempty"`
Subscription *UserSubscription `json:"subscription,omitempty"` Subscription *UserSubscription `json:"subscription,omitempty"`

View File

@@ -1,3 +1,5 @@
// Package handler provides HTTP request handlers for the API gateway.
// It handles authentication, request routing, concurrency control, and billing validation.
package handler package handler
import ( import (
@@ -27,6 +29,7 @@ type GatewayHandler struct {
userService *service.UserService userService *service.UserService
billingCacheService *service.BillingCacheService billingCacheService *service.BillingCacheService
concurrencyHelper *ConcurrencyHelper concurrencyHelper *ConcurrencyHelper
opsService *service.OpsService
} }
// NewGatewayHandler creates a new GatewayHandler // NewGatewayHandler creates a new GatewayHandler
@@ -37,6 +40,7 @@ func NewGatewayHandler(
userService *service.UserService, userService *service.UserService,
concurrencyService *service.ConcurrencyService, concurrencyService *service.ConcurrencyService,
billingCacheService *service.BillingCacheService, billingCacheService *service.BillingCacheService,
opsService *service.OpsService,
) *GatewayHandler { ) *GatewayHandler {
return &GatewayHandler{ return &GatewayHandler{
gatewayService: gatewayService, gatewayService: gatewayService,
@@ -45,14 +49,15 @@ func NewGatewayHandler(
userService: userService, userService: userService,
billingCacheService: billingCacheService, billingCacheService: billingCacheService,
concurrencyHelper: NewConcurrencyHelper(concurrencyService, SSEPingFormatClaude), concurrencyHelper: NewConcurrencyHelper(concurrencyService, SSEPingFormatClaude),
opsService: opsService,
} }
} }
// Messages handles Claude API compatible messages endpoint // Messages handles Claude API compatible messages endpoint
// POST /v1/messages // POST /v1/messages
func (h *GatewayHandler) Messages(c *gin.Context) { func (h *GatewayHandler) Messages(c *gin.Context) {
// 从context获取apiKey和userApiKeyAuth中间件已设置 // 从context获取apiKey和userAPIKeyAuth中间件已设置
apiKey, ok := middleware2.GetApiKeyFromContext(c) apiKey, ok := middleware2.GetAPIKeyFromContext(c)
if !ok { if !ok {
h.errorResponse(c, http.StatusUnauthorized, "authentication_error", "Invalid API key") h.errorResponse(c, http.StatusUnauthorized, "authentication_error", "Invalid API key")
return return
@@ -87,6 +92,7 @@ func (h *GatewayHandler) Messages(c *gin.Context) {
} }
reqModel := parsedReq.Model reqModel := parsedReq.Model
reqStream := parsedReq.Stream reqStream := parsedReq.Stream
setOpsRequestContext(c, reqModel, reqStream)
// 验证 model 必填 // 验证 model 必填
if reqModel == "" { if reqModel == "" {
@@ -258,7 +264,7 @@ func (h *GatewayHandler) Messages(c *gin.Context) {
defer cancel() defer cancel()
if err := h.gatewayService.RecordUsage(ctx, &service.RecordUsageInput{ if err := h.gatewayService.RecordUsage(ctx, &service.RecordUsageInput{
Result: result, Result: result,
ApiKey: apiKey, APIKey: apiKey,
User: apiKey.User, User: apiKey.User,
Account: usedAccount, Account: usedAccount,
Subscription: subscription, Subscription: subscription,
@@ -382,7 +388,7 @@ func (h *GatewayHandler) Messages(c *gin.Context) {
defer cancel() defer cancel()
if err := h.gatewayService.RecordUsage(ctx, &service.RecordUsageInput{ if err := h.gatewayService.RecordUsage(ctx, &service.RecordUsageInput{
Result: result, Result: result,
ApiKey: apiKey, APIKey: apiKey,
User: apiKey.User, User: apiKey.User,
Account: usedAccount, Account: usedAccount,
Subscription: subscription, Subscription: subscription,
@@ -399,7 +405,7 @@ func (h *GatewayHandler) Messages(c *gin.Context) {
// Returns models based on account configurations (model_mapping whitelist) // Returns models based on account configurations (model_mapping whitelist)
// Falls back to default models if no whitelist is configured // Falls back to default models if no whitelist is configured
func (h *GatewayHandler) Models(c *gin.Context) { func (h *GatewayHandler) Models(c *gin.Context) {
apiKey, _ := middleware2.GetApiKeyFromContext(c) apiKey, _ := middleware2.GetAPIKeyFromContext(c)
var groupID *int64 var groupID *int64
var platform string var platform string
@@ -448,7 +454,7 @@ func (h *GatewayHandler) Models(c *gin.Context) {
// Usage handles getting account balance for CC Switch integration // Usage handles getting account balance for CC Switch integration
// GET /v1/usage // GET /v1/usage
func (h *GatewayHandler) Usage(c *gin.Context) { func (h *GatewayHandler) Usage(c *gin.Context) {
apiKey, ok := middleware2.GetApiKeyFromContext(c) apiKey, ok := middleware2.GetAPIKeyFromContext(c)
if !ok { if !ok {
h.errorResponse(c, http.StatusUnauthorized, "authentication_error", "Invalid API key") h.errorResponse(c, http.StatusUnauthorized, "authentication_error", "Invalid API key")
return return
@@ -573,6 +579,7 @@ func (h *GatewayHandler) mapUpstreamError(statusCode int) (int, string, string)
// handleStreamingAwareError handles errors that may occur after streaming has started // handleStreamingAwareError handles errors that may occur after streaming has started
func (h *GatewayHandler) handleStreamingAwareError(c *gin.Context, status int, errType, message string, streamStarted bool) { func (h *GatewayHandler) handleStreamingAwareError(c *gin.Context, status int, errType, message string, streamStarted bool) {
if streamStarted { if streamStarted {
recordOpsError(c, h.opsService, status, errType, message, "")
// Stream already started, send error as SSE event then close // Stream already started, send error as SSE event then close
flusher, ok := c.Writer.(http.Flusher) flusher, ok := c.Writer.(http.Flusher)
if ok { if ok {
@@ -604,6 +611,7 @@ func (h *GatewayHandler) handleStreamingAwareError(c *gin.Context, status int, e
// errorResponse 返回Claude API格式的错误响应 // errorResponse 返回Claude API格式的错误响应
func (h *GatewayHandler) errorResponse(c *gin.Context, status int, errType, message string) { func (h *GatewayHandler) errorResponse(c *gin.Context, status int, errType, message string) {
recordOpsError(c, h.opsService, status, errType, message, "")
c.JSON(status, gin.H{ c.JSON(status, gin.H{
"type": "error", "type": "error",
"error": gin.H{ "error": gin.H{
@@ -617,8 +625,8 @@ func (h *GatewayHandler) errorResponse(c *gin.Context, status int, errType, mess
// POST /v1/messages/count_tokens // POST /v1/messages/count_tokens
// 特点:校验订阅/余额,但不计算并发、不记录使用量 // 特点:校验订阅/余额,但不计算并发、不记录使用量
func (h *GatewayHandler) CountTokens(c *gin.Context) { func (h *GatewayHandler) CountTokens(c *gin.Context) {
// 从context获取apiKey和userApiKeyAuth中间件已设置 // 从context获取apiKey和userAPIKeyAuth中间件已设置
apiKey, ok := middleware2.GetApiKeyFromContext(c) apiKey, ok := middleware2.GetAPIKeyFromContext(c)
if !ok { if !ok {
h.errorResponse(c, http.StatusUnauthorized, "authentication_error", "Invalid API key") h.errorResponse(c, http.StatusUnauthorized, "authentication_error", "Invalid API key")
return return

View File

@@ -20,7 +20,7 @@ import (
// GeminiV1BetaListModels proxies: // GeminiV1BetaListModels proxies:
// GET /v1beta/models // GET /v1beta/models
func (h *GatewayHandler) GeminiV1BetaListModels(c *gin.Context) { func (h *GatewayHandler) GeminiV1BetaListModels(c *gin.Context) {
apiKey, ok := middleware.GetApiKeyFromContext(c) apiKey, ok := middleware.GetAPIKeyFromContext(c)
if !ok || apiKey == nil { if !ok || apiKey == nil {
googleError(c, http.StatusUnauthorized, "Invalid API key") googleError(c, http.StatusUnauthorized, "Invalid API key")
return return
@@ -66,7 +66,7 @@ func (h *GatewayHandler) GeminiV1BetaListModels(c *gin.Context) {
// GeminiV1BetaGetModel proxies: // GeminiV1BetaGetModel proxies:
// GET /v1beta/models/{model} // GET /v1beta/models/{model}
func (h *GatewayHandler) GeminiV1BetaGetModel(c *gin.Context) { func (h *GatewayHandler) GeminiV1BetaGetModel(c *gin.Context) {
apiKey, ok := middleware.GetApiKeyFromContext(c) apiKey, ok := middleware.GetAPIKeyFromContext(c)
if !ok || apiKey == nil { if !ok || apiKey == nil {
googleError(c, http.StatusUnauthorized, "Invalid API key") googleError(c, http.StatusUnauthorized, "Invalid API key")
return return
@@ -119,7 +119,7 @@ func (h *GatewayHandler) GeminiV1BetaGetModel(c *gin.Context) {
// POST /v1beta/models/{model}:generateContent // POST /v1beta/models/{model}:generateContent
// POST /v1beta/models/{model}:streamGenerateContent?alt=sse // POST /v1beta/models/{model}:streamGenerateContent?alt=sse
func (h *GatewayHandler) GeminiV1BetaModels(c *gin.Context) { func (h *GatewayHandler) GeminiV1BetaModels(c *gin.Context) {
apiKey, ok := middleware.GetApiKeyFromContext(c) apiKey, ok := middleware.GetAPIKeyFromContext(c)
if !ok || apiKey == nil { if !ok || apiKey == nil {
googleError(c, http.StatusUnauthorized, "Invalid API key") googleError(c, http.StatusUnauthorized, "Invalid API key")
return return
@@ -298,7 +298,7 @@ func (h *GatewayHandler) GeminiV1BetaModels(c *gin.Context) {
defer cancel() defer cancel()
if err := h.gatewayService.RecordUsage(ctx, &service.RecordUsageInput{ if err := h.gatewayService.RecordUsage(ctx, &service.RecordUsageInput{
Result: result, Result: result,
ApiKey: apiKey, APIKey: apiKey,
User: apiKey.User, User: apiKey.User,
Account: usedAccount, Account: usedAccount,
Subscription: subscription, Subscription: subscription,

View File

@@ -7,6 +7,7 @@ import (
// AdminHandlers contains all admin-related HTTP handlers // AdminHandlers contains all admin-related HTTP handlers
type AdminHandlers struct { type AdminHandlers struct {
Dashboard *admin.DashboardHandler Dashboard *admin.DashboardHandler
Ops *admin.OpsHandler
User *admin.UserHandler User *admin.UserHandler
Group *admin.GroupHandler Group *admin.GroupHandler
Account *admin.AccountHandler Account *admin.AccountHandler

View File

@@ -22,6 +22,7 @@ type OpenAIGatewayHandler struct {
gatewayService *service.OpenAIGatewayService gatewayService *service.OpenAIGatewayService
billingCacheService *service.BillingCacheService billingCacheService *service.BillingCacheService
concurrencyHelper *ConcurrencyHelper concurrencyHelper *ConcurrencyHelper
opsService *service.OpsService
} }
// NewOpenAIGatewayHandler creates a new OpenAIGatewayHandler // NewOpenAIGatewayHandler creates a new OpenAIGatewayHandler
@@ -29,19 +30,21 @@ func NewOpenAIGatewayHandler(
gatewayService *service.OpenAIGatewayService, gatewayService *service.OpenAIGatewayService,
concurrencyService *service.ConcurrencyService, concurrencyService *service.ConcurrencyService,
billingCacheService *service.BillingCacheService, billingCacheService *service.BillingCacheService,
opsService *service.OpsService,
) *OpenAIGatewayHandler { ) *OpenAIGatewayHandler {
return &OpenAIGatewayHandler{ return &OpenAIGatewayHandler{
gatewayService: gatewayService, gatewayService: gatewayService,
billingCacheService: billingCacheService, billingCacheService: billingCacheService,
concurrencyHelper: NewConcurrencyHelper(concurrencyService, SSEPingFormatNone), concurrencyHelper: NewConcurrencyHelper(concurrencyService, SSEPingFormatNone),
opsService: opsService,
} }
} }
// Responses handles OpenAI Responses API endpoint // Responses handles OpenAI Responses API endpoint
// POST /openai/v1/responses // POST /openai/v1/responses
func (h *OpenAIGatewayHandler) Responses(c *gin.Context) { func (h *OpenAIGatewayHandler) Responses(c *gin.Context) {
// Get apiKey and user from context (set by ApiKeyAuth middleware) // Get apiKey and user from context (set by APIKeyAuth middleware)
apiKey, ok := middleware2.GetApiKeyFromContext(c) apiKey, ok := middleware2.GetAPIKeyFromContext(c)
if !ok { if !ok {
h.errorResponse(c, http.StatusUnauthorized, "authentication_error", "Invalid API key") h.errorResponse(c, http.StatusUnauthorized, "authentication_error", "Invalid API key")
return return
@@ -79,6 +82,7 @@ func (h *OpenAIGatewayHandler) Responses(c *gin.Context) {
// Extract model and stream // Extract model and stream
reqModel, _ := reqBody["model"].(string) reqModel, _ := reqBody["model"].(string)
reqStream, _ := reqBody["stream"].(bool) reqStream, _ := reqBody["stream"].(bool)
setOpsRequestContext(c, reqModel, reqStream)
// 验证 model 必填 // 验证 model 必填
if reqModel == "" { if reqModel == "" {
@@ -235,7 +239,7 @@ func (h *OpenAIGatewayHandler) Responses(c *gin.Context) {
defer cancel() defer cancel()
if err := h.gatewayService.RecordUsage(ctx, &service.OpenAIRecordUsageInput{ if err := h.gatewayService.RecordUsage(ctx, &service.OpenAIRecordUsageInput{
Result: result, Result: result,
ApiKey: apiKey, APIKey: apiKey,
User: apiKey.User, User: apiKey.User,
Account: usedAccount, Account: usedAccount,
Subscription: subscription, Subscription: subscription,
@@ -278,6 +282,7 @@ func (h *OpenAIGatewayHandler) mapUpstreamError(statusCode int) (int, string, st
// handleStreamingAwareError handles errors that may occur after streaming has started // handleStreamingAwareError handles errors that may occur after streaming has started
func (h *OpenAIGatewayHandler) handleStreamingAwareError(c *gin.Context, status int, errType, message string, streamStarted bool) { func (h *OpenAIGatewayHandler) handleStreamingAwareError(c *gin.Context, status int, errType, message string, streamStarted bool) {
if streamStarted { if streamStarted {
recordOpsError(c, h.opsService, status, errType, message, service.PlatformOpenAI)
// Stream already started, send error as SSE event then close // Stream already started, send error as SSE event then close
flusher, ok := c.Writer.(http.Flusher) flusher, ok := c.Writer.(http.Flusher)
if ok { if ok {
@@ -297,6 +302,7 @@ func (h *OpenAIGatewayHandler) handleStreamingAwareError(c *gin.Context, status
// errorResponse returns OpenAI API format error response // errorResponse returns OpenAI API format error response
func (h *OpenAIGatewayHandler) errorResponse(c *gin.Context, status int, errType, message string) { func (h *OpenAIGatewayHandler) errorResponse(c *gin.Context, status int, errType, message string) {
recordOpsError(c, h.opsService, status, errType, message, service.PlatformOpenAI)
c.JSON(status, gin.H{ c.JSON(status, gin.H{
"error": gin.H{ "error": gin.H{
"type": errType, "type": errType,

View File

@@ -0,0 +1,166 @@
package handler
import (
"context"
"strings"
"sync"
"time"
middleware2 "github.com/Wei-Shaw/sub2api/internal/server/middleware"
"github.com/Wei-Shaw/sub2api/internal/service"
"github.com/gin-gonic/gin"
)
const (
opsModelKey = "ops_model"
opsStreamKey = "ops_stream"
)
const (
opsErrorLogWorkerCount = 10
opsErrorLogQueueSize = 256
opsErrorLogTimeout = 2 * time.Second
)
type opsErrorLogJob struct {
ops *service.OpsService
entry *service.OpsErrorLog
}
var (
opsErrorLogOnce sync.Once
opsErrorLogQueue chan opsErrorLogJob
)
func startOpsErrorLogWorkers() {
opsErrorLogQueue = make(chan opsErrorLogJob, opsErrorLogQueueSize)
for i := 0; i < opsErrorLogWorkerCount; i++ {
go func() {
for job := range opsErrorLogQueue {
if job.ops == nil || job.entry == nil {
continue
}
ctx, cancel := context.WithTimeout(context.Background(), opsErrorLogTimeout)
_ = job.ops.RecordError(ctx, job.entry)
cancel()
}
}()
}
}
func enqueueOpsErrorLog(ops *service.OpsService, entry *service.OpsErrorLog) {
if ops == nil || entry == nil {
return
}
opsErrorLogOnce.Do(startOpsErrorLogWorkers)
select {
case opsErrorLogQueue <- opsErrorLogJob{ops: ops, entry: entry}:
default:
// Queue is full; drop to avoid blocking request handling.
}
}
func setOpsRequestContext(c *gin.Context, model string, stream bool) {
c.Set(opsModelKey, model)
c.Set(opsStreamKey, stream)
}
func recordOpsError(c *gin.Context, ops *service.OpsService, status int, errType, message, fallbackPlatform string) {
if ops == nil || c == nil {
return
}
model, _ := c.Get(opsModelKey)
stream, _ := c.Get(opsStreamKey)
var modelName string
if m, ok := model.(string); ok {
modelName = m
}
streaming, _ := stream.(bool)
apiKey, _ := middleware2.GetAPIKeyFromContext(c)
logEntry := &service.OpsErrorLog{
Phase: classifyOpsPhase(errType, message),
Type: errType,
Severity: classifyOpsSeverity(errType, status),
StatusCode: status,
Platform: resolveOpsPlatform(apiKey, fallbackPlatform),
Model: modelName,
RequestID: c.Writer.Header().Get("x-request-id"),
Message: message,
ClientIP: c.ClientIP(),
RequestPath: func() string {
if c.Request != nil && c.Request.URL != nil {
return c.Request.URL.Path
}
return ""
}(),
Stream: streaming,
}
if apiKey != nil {
logEntry.APIKeyID = &apiKey.ID
if apiKey.User != nil {
logEntry.UserID = &apiKey.User.ID
}
if apiKey.GroupID != nil {
logEntry.GroupID = apiKey.GroupID
}
}
enqueueOpsErrorLog(ops, logEntry)
}
func resolveOpsPlatform(apiKey *service.APIKey, fallback string) string {
if apiKey != nil && apiKey.Group != nil && apiKey.Group.Platform != "" {
return apiKey.Group.Platform
}
return fallback
}
func classifyOpsPhase(errType, message string) string {
msg := strings.ToLower(message)
switch errType {
case "authentication_error":
return "auth"
case "billing_error", "subscription_error":
return "billing"
case "rate_limit_error":
if strings.Contains(msg, "concurrency") || strings.Contains(msg, "pending") {
return "concurrency"
}
return "upstream"
case "invalid_request_error":
return "response"
case "upstream_error", "overloaded_error":
return "upstream"
case "api_error":
if strings.Contains(msg, "no available accounts") {
return "scheduling"
}
return "internal"
default:
return "internal"
}
}
func classifyOpsSeverity(errType string, status int) string {
switch errType {
case "invalid_request_error", "authentication_error", "billing_error", "subscription_error":
return "P3"
}
if status >= 500 {
return "P1"
}
if status == 429 {
return "P1"
}
if status >= 400 {
return "P2"
}
return "P3"
}

View File

@@ -39,9 +39,9 @@ func (h *SettingHandler) GetPublicSettings(c *gin.Context) {
SiteName: settings.SiteName, SiteName: settings.SiteName,
SiteLogo: settings.SiteLogo, SiteLogo: settings.SiteLogo,
SiteSubtitle: settings.SiteSubtitle, SiteSubtitle: settings.SiteSubtitle,
ApiBaseUrl: settings.ApiBaseUrl, APIBaseURL: settings.APIBaseURL,
ContactInfo: settings.ContactInfo, ContactInfo: settings.ContactInfo,
DocUrl: settings.DocUrl, DocURL: settings.DocURL,
Version: h.version, Version: h.version,
}) })
} }

View File

@@ -18,11 +18,11 @@ import (
// UsageHandler handles usage-related requests // UsageHandler handles usage-related requests
type UsageHandler struct { type UsageHandler struct {
usageService *service.UsageService usageService *service.UsageService
apiKeyService *service.ApiKeyService apiKeyService *service.APIKeyService
} }
// NewUsageHandler creates a new UsageHandler // NewUsageHandler creates a new UsageHandler
func NewUsageHandler(usageService *service.UsageService, apiKeyService *service.ApiKeyService) *UsageHandler { func NewUsageHandler(usageService *service.UsageService, apiKeyService *service.APIKeyService) *UsageHandler {
return &UsageHandler{ return &UsageHandler{
usageService: usageService, usageService: usageService,
apiKeyService: apiKeyService, apiKeyService: apiKeyService,
@@ -111,7 +111,7 @@ func (h *UsageHandler) List(c *gin.Context) {
params := pagination.PaginationParams{Page: page, PageSize: pageSize} params := pagination.PaginationParams{Page: page, PageSize: pageSize}
filters := usagestats.UsageLogFilters{ filters := usagestats.UsageLogFilters{
UserID: subject.UserID, // Always filter by current user for security UserID: subject.UserID, // Always filter by current user for security
ApiKeyID: apiKeyID, APIKeyID: apiKeyID,
Model: model, Model: model,
Stream: stream, Stream: stream,
BillingType: billingType, BillingType: billingType,
@@ -235,7 +235,7 @@ func (h *UsageHandler) Stats(c *gin.Context) {
var stats *service.UsageStats var stats *service.UsageStats
var err error var err error
if apiKeyID > 0 { if apiKeyID > 0 {
stats, err = h.usageService.GetStatsByApiKey(c.Request.Context(), apiKeyID, startTime, endTime) stats, err = h.usageService.GetStatsByAPIKey(c.Request.Context(), apiKeyID, startTime, endTime)
} else { } else {
stats, err = h.usageService.GetStatsByUser(c.Request.Context(), subject.UserID, startTime, endTime) stats, err = h.usageService.GetStatsByUser(c.Request.Context(), subject.UserID, startTime, endTime)
} }
@@ -346,49 +346,49 @@ func (h *UsageHandler) DashboardModels(c *gin.Context) {
}) })
} }
// BatchApiKeysUsageRequest represents the request for batch API keys usage // BatchAPIKeysUsageRequest represents the request for batch API keys usage
type BatchApiKeysUsageRequest struct { type BatchAPIKeysUsageRequest struct {
ApiKeyIDs []int64 `json:"api_key_ids" binding:"required"` APIKeyIDs []int64 `json:"api_key_ids" binding:"required"`
} }
// DashboardApiKeysUsage handles getting usage stats for user's own API keys // DashboardAPIKeysUsage handles getting usage stats for user's own API keys
// POST /api/v1/usage/dashboard/api-keys-usage // POST /api/v1/usage/dashboard/api-keys-usage
func (h *UsageHandler) DashboardApiKeysUsage(c *gin.Context) { func (h *UsageHandler) DashboardAPIKeysUsage(c *gin.Context) {
subject, ok := middleware2.GetAuthSubjectFromContext(c) subject, ok := middleware2.GetAuthSubjectFromContext(c)
if !ok { if !ok {
response.Unauthorized(c, "User not authenticated") response.Unauthorized(c, "User not authenticated")
return return
} }
var req BatchApiKeysUsageRequest var req BatchAPIKeysUsageRequest
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
response.BadRequest(c, "Invalid request: "+err.Error()) response.BadRequest(c, "Invalid request: "+err.Error())
return return
} }
if len(req.ApiKeyIDs) == 0 { if len(req.APIKeyIDs) == 0 {
response.Success(c, gin.H{"stats": map[string]any{}}) response.Success(c, gin.H{"stats": map[string]any{}})
return return
} }
// Limit the number of API key IDs to prevent SQL parameter overflow // Limit the number of API key IDs to prevent SQL parameter overflow
if len(req.ApiKeyIDs) > 100 { if len(req.APIKeyIDs) > 100 {
response.BadRequest(c, "Too many API key IDs (maximum 100 allowed)") response.BadRequest(c, "Too many API key IDs (maximum 100 allowed)")
return return
} }
validApiKeyIDs, err := h.apiKeyService.VerifyOwnership(c.Request.Context(), subject.UserID, req.ApiKeyIDs) validAPIKeyIDs, err := h.apiKeyService.VerifyOwnership(c.Request.Context(), subject.UserID, req.APIKeyIDs)
if err != nil { if err != nil {
response.ErrorFrom(c, err) response.ErrorFrom(c, err)
return return
} }
if len(validApiKeyIDs) == 0 { if len(validAPIKeyIDs) == 0 {
response.Success(c, gin.H{"stats": map[string]any{}}) response.Success(c, gin.H{"stats": map[string]any{}})
return return
} }
stats, err := h.usageService.GetBatchApiKeyUsageStats(c.Request.Context(), validApiKeyIDs) stats, err := h.usageService.GetBatchAPIKeyUsageStats(c.Request.Context(), validAPIKeyIDs)
if err != nil { if err != nil {
response.ErrorFrom(c, err) response.ErrorFrom(c, err)
return return

View File

@@ -10,6 +10,7 @@ import (
// ProvideAdminHandlers creates the AdminHandlers struct // ProvideAdminHandlers creates the AdminHandlers struct
func ProvideAdminHandlers( func ProvideAdminHandlers(
dashboardHandler *admin.DashboardHandler, dashboardHandler *admin.DashboardHandler,
opsHandler *admin.OpsHandler,
userHandler *admin.UserHandler, userHandler *admin.UserHandler,
groupHandler *admin.GroupHandler, groupHandler *admin.GroupHandler,
accountHandler *admin.AccountHandler, accountHandler *admin.AccountHandler,
@@ -27,6 +28,7 @@ func ProvideAdminHandlers(
) *AdminHandlers { ) *AdminHandlers {
return &AdminHandlers{ return &AdminHandlers{
Dashboard: dashboardHandler, Dashboard: dashboardHandler,
Ops: opsHandler,
User: userHandler, User: userHandler,
Group: groupHandler, Group: groupHandler,
Account: accountHandler, Account: accountHandler,
@@ -96,6 +98,7 @@ var ProviderSet = wire.NewSet(
// Admin handlers // Admin handlers
admin.NewDashboardHandler, admin.NewDashboardHandler,
admin.NewOpsHandler,
admin.NewUserHandler, admin.NewUserHandler,
admin.NewGroupHandler, admin.NewGroupHandler,
admin.NewAccountHandler, admin.NewAccountHandler,

View File

@@ -1,3 +1,5 @@
// Package antigravity provides a client for interacting with Google's Antigravity API,
// handling OAuth authentication, token management, and account tier information retrieval.
package antigravity package antigravity
import ( import (

View File

@@ -1,3 +1,4 @@
// Package claude provides Claude API client constants and utilities.
package claude package claude
// Claude Code 客户端相关常量 // Claude Code 客户端相关常量
@@ -16,13 +17,13 @@ const DefaultBetaHeader = BetaClaudeCode + "," + BetaOAuth + "," + BetaInterleav
// HaikuBetaHeader Haiku 模型使用的 anthropic-beta header不需要 claude-code beta // HaikuBetaHeader Haiku 模型使用的 anthropic-beta header不需要 claude-code beta
const HaikuBetaHeader = BetaOAuth + "," + BetaInterleavedThinking const HaikuBetaHeader = BetaOAuth + "," + BetaInterleavedThinking
// ApiKeyBetaHeader API-key 账号建议使用的 anthropic-beta header不包含 oauth // APIKeyBetaHeader API-key 账号建议使用的 anthropic-beta header不包含 oauth
const ApiKeyBetaHeader = BetaClaudeCode + "," + BetaInterleavedThinking + "," + BetaFineGrainedToolStreaming const APIKeyBetaHeader = BetaClaudeCode + "," + BetaInterleavedThinking + "," + BetaFineGrainedToolStreaming
// ApiKeyHaikuBetaHeader Haiku 模型在 API-key 账号下使用的 anthropic-beta header不包含 oauth / claude-code // APIKeyHaikuBetaHeader Haiku 模型在 API-key 账号下使用的 anthropic-beta header不包含 oauth / claude-code
const ApiKeyHaikuBetaHeader = BetaInterleavedThinking const APIKeyHaikuBetaHeader = BetaInterleavedThinking
// Claude Code 客户端默认请求头 // DefaultHeaders are the default request headers for Claude Code client.
var DefaultHeaders = map[string]string{ var DefaultHeaders = map[string]string{
"User-Agent": "claude-cli/2.0.62 (external, cli)", "User-Agent": "claude-cli/2.0.62 (external, cli)",
"X-Stainless-Lang": "js", "X-Stainless-Lang": "js",

View File

@@ -1,3 +1,4 @@
// Package errors provides custom error types and error handling utilities.
// nolint:mnd // nolint:mnd
package errors package errors

View File

@@ -1,7 +1,7 @@
// Package gemini provides minimal fallback model metadata for Gemini native endpoints.
package gemini package gemini
// This package provides minimal fallback model metadata for Gemini native endpoints. // This package is used when upstream model listing is unavailable (e.g. OAuth token missing AI Studio scopes).
// It is used when upstream model listing is unavailable (e.g. OAuth token missing AI Studio scopes).
type Model struct { type Model struct {
Name string `json:"name"` Name string `json:"name"`

View File

@@ -1,3 +1,5 @@
// Package geminicli provides OAuth authentication and API client functionality
// for Google's Gemini AI services, supporting both AI Studio and Code Assist endpoints.
package geminicli package geminicli
import "time" import "time"

View File

@@ -1,3 +1,4 @@
// Package googleapi provides utilities for Google API interactions.
package googleapi package googleapi
import "net/http" import "net/http"

View File

@@ -1,3 +1,4 @@
// Package oauth provides OAuth 2.0 utilities including PKCE flow, session management, and token exchange.
package oauth package oauth
import ( import (

View File

@@ -1,3 +1,4 @@
// Package openai provides OpenAI API models and configuration.
package openai package openai
import _ "embed" import _ "embed"

View File

@@ -327,7 +327,7 @@ func ParseIDToken(idToken string) (*IDTokenClaims, error) {
return &claims, nil return &claims, nil
} }
// ExtractUserInfo extracts user information from ID Token claims // UserInfo extracts user information from ID Token claims
type UserInfo struct { type UserInfo struct {
Email string Email string
ChatGPTAccountID string ChatGPTAccountID string

View File

@@ -1,3 +1,4 @@
// Package pagination provides utilities for handling paginated queries and results.
package pagination package pagination
// PaginationParams 分页参数 // PaginationParams 分页参数

View File

@@ -1,3 +1,4 @@
// Package response provides HTTP response utilities for standardized API responses and error handling.
package response package response
import ( import (

View File

@@ -1,3 +1,4 @@
// Package sysutil provides system-level utilities for service management.
package sysutil package sysutil
import ( import (

View File

@@ -1,3 +1,4 @@
// Package usagestats defines types for tracking and reporting API usage statistics.
package usagestats package usagestats
import "time" import "time"
@@ -10,8 +11,8 @@ type DashboardStats struct {
ActiveUsers int64 `json:"active_users"` // 今日有请求的用户数 ActiveUsers int64 `json:"active_users"` // 今日有请求的用户数
// API Key 统计 // API Key 统计
TotalApiKeys int64 `json:"total_api_keys"` TotalAPIKeys int64 `json:"total_api_keys"`
ActiveApiKeys int64 `json:"active_api_keys"` // 状态为 active 的 API Key 数 ActiveAPIKeys int64 `json:"active_api_keys"` // 状态为 active 的 API Key 数
// 账户统计 // 账户统计
TotalAccounts int64 `json:"total_accounts"` TotalAccounts int64 `json:"total_accounts"`
@@ -82,10 +83,10 @@ type UserUsageTrendPoint struct {
ActualCost float64 `json:"actual_cost"` // 实际扣除 ActualCost float64 `json:"actual_cost"` // 实际扣除
} }
// ApiKeyUsageTrendPoint represents API key usage trend data point // APIKeyUsageTrendPoint represents API key usage trend data point
type ApiKeyUsageTrendPoint struct { type APIKeyUsageTrendPoint struct {
Date string `json:"date"` Date string `json:"date"`
ApiKeyID int64 `json:"api_key_id"` APIKeyID int64 `json:"api_key_id"`
KeyName string `json:"key_name"` KeyName string `json:"key_name"`
Requests int64 `json:"requests"` Requests int64 `json:"requests"`
Tokens int64 `json:"tokens"` Tokens int64 `json:"tokens"`
@@ -94,8 +95,8 @@ type ApiKeyUsageTrendPoint struct {
// UserDashboardStats 用户仪表盘统计 // UserDashboardStats 用户仪表盘统计
type UserDashboardStats struct { type UserDashboardStats struct {
// API Key 统计 // API Key 统计
TotalApiKeys int64 `json:"total_api_keys"` TotalAPIKeys int64 `json:"total_api_keys"`
ActiveApiKeys int64 `json:"active_api_keys"` ActiveAPIKeys int64 `json:"active_api_keys"`
// 累计 Token 使用统计 // 累计 Token 使用统计
TotalRequests int64 `json:"total_requests"` TotalRequests int64 `json:"total_requests"`
@@ -128,7 +129,7 @@ type UserDashboardStats struct {
// UsageLogFilters represents filters for usage log queries // UsageLogFilters represents filters for usage log queries
type UsageLogFilters struct { type UsageLogFilters struct {
UserID int64 UserID int64
ApiKeyID int64 APIKeyID int64
AccountID int64 AccountID int64
GroupID int64 GroupID int64
Model string Model string
@@ -157,9 +158,9 @@ type BatchUserUsageStats struct {
TotalActualCost float64 `json:"total_actual_cost"` TotalActualCost float64 `json:"total_actual_cost"`
} }
// BatchApiKeyUsageStats represents usage stats for a single API key // BatchAPIKeyUsageStats represents usage stats for a single API key
type BatchApiKeyUsageStats struct { type BatchAPIKeyUsageStats struct {
ApiKeyID int64 `json:"api_key_id"` APIKeyID int64 `json:"api_key_id"`
TodayActualCost float64 `json:"today_actual_cost"` TodayActualCost float64 `json:"today_actual_cost"`
TotalActualCost float64 `json:"total_actual_cost"` TotalActualCost float64 `json:"total_actual_cost"`
} }

View File

@@ -135,12 +135,12 @@ func (s *AccountRepoSuite) TestListWithFilters() {
name: "filter_by_type", name: "filter_by_type",
setup: func(client *dbent.Client) { setup: func(client *dbent.Client) {
mustCreateAccount(s.T(), client, &service.Account{Name: "t1", Type: service.AccountTypeOAuth}) mustCreateAccount(s.T(), client, &service.Account{Name: "t1", Type: service.AccountTypeOAuth})
mustCreateAccount(s.T(), client, &service.Account{Name: "t2", Type: service.AccountTypeApiKey}) mustCreateAccount(s.T(), client, &service.Account{Name: "t2", Type: service.AccountTypeAPIKey})
}, },
accType: service.AccountTypeApiKey, accType: service.AccountTypeAPIKey,
wantCount: 1, wantCount: 1,
validate: func(accounts []service.Account) { validate: func(accounts []service.Account) {
s.Require().Equal(service.AccountTypeApiKey, accounts[0].Type) s.Require().Equal(service.AccountTypeAPIKey, accounts[0].Type)
}, },
}, },
{ {

View File

@@ -80,7 +80,7 @@ func TestUserRepository_RemoveGroupFromAllowedGroups_RemovesAllOccurrences(t *te
require.NotContains(t, u2After.AllowedGroups, targetGroup.ID) require.NotContains(t, u2After.AllowedGroups, targetGroup.ID)
} }
func TestGroupRepository_DeleteCascade_RemovesAllowedGroupsAndClearsApiKeys(t *testing.T) { func TestGroupRepository_DeleteCascade_RemovesAllowedGroupsAndClearsAPIKeys(t *testing.T) {
ctx := context.Background() ctx := context.Background()
tx := testEntTx(t) tx := testEntTx(t)
entClient := tx.Client() entClient := tx.Client()
@@ -98,7 +98,7 @@ func TestGroupRepository_DeleteCascade_RemovesAllowedGroupsAndClearsApiKeys(t *t
userRepo := newUserRepositoryWithSQL(entClient, tx) userRepo := newUserRepositoryWithSQL(entClient, tx)
groupRepo := newGroupRepositoryWithSQL(entClient, tx) groupRepo := newGroupRepositoryWithSQL(entClient, tx)
apiKeyRepo := NewApiKeyRepository(entClient) apiKeyRepo := NewAPIKeyRepository(entClient)
u := &service.User{ u := &service.User{
Email: uniqueTestValue(t, "cascade-user") + "@example.com", Email: uniqueTestValue(t, "cascade-user") + "@example.com",
@@ -110,7 +110,7 @@ func TestGroupRepository_DeleteCascade_RemovesAllowedGroupsAndClearsApiKeys(t *t
} }
require.NoError(t, userRepo.Create(ctx, u)) require.NoError(t, userRepo.Create(ctx, u))
key := &service.ApiKey{ key := &service.APIKey{
UserID: u.ID, UserID: u.ID,
Key: uniqueTestValue(t, "sk-test-delete-cascade"), Key: uniqueTestValue(t, "sk-test-delete-cascade"),
Name: "test key", Name: "test key",

View File

@@ -24,7 +24,7 @@ type apiKeyCache struct {
rdb *redis.Client rdb *redis.Client
} }
func NewApiKeyCache(rdb *redis.Client) service.ApiKeyCache { func NewAPIKeyCache(rdb *redis.Client) service.APIKeyCache {
return &apiKeyCache{rdb: rdb} return &apiKeyCache{rdb: rdb}
} }

View File

@@ -13,11 +13,11 @@ import (
"github.com/stretchr/testify/suite" "github.com/stretchr/testify/suite"
) )
type ApiKeyCacheSuite struct { type APIKeyCacheSuite struct {
IntegrationRedisSuite IntegrationRedisSuite
} }
func (s *ApiKeyCacheSuite) TestCreateAttemptCount() { func (s *APIKeyCacheSuite) TestCreateAttemptCount() {
tests := []struct { tests := []struct {
name string name string
fn func(ctx context.Context, rdb *redis.Client, cache *apiKeyCache) fn func(ctx context.Context, rdb *redis.Client, cache *apiKeyCache)
@@ -78,7 +78,7 @@ func (s *ApiKeyCacheSuite) TestCreateAttemptCount() {
} }
} }
func (s *ApiKeyCacheSuite) TestDailyUsage() { func (s *APIKeyCacheSuite) TestDailyUsage() {
tests := []struct { tests := []struct {
name string name string
fn func(ctx context.Context, rdb *redis.Client, cache *apiKeyCache) fn func(ctx context.Context, rdb *redis.Client, cache *apiKeyCache)
@@ -122,6 +122,6 @@ func (s *ApiKeyCacheSuite) TestDailyUsage() {
} }
} }
func TestApiKeyCacheSuite(t *testing.T) { func TestAPIKeyCacheSuite(t *testing.T) {
suite.Run(t, new(ApiKeyCacheSuite)) suite.Run(t, new(APIKeyCacheSuite))
} }

View File

@@ -9,7 +9,7 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func TestApiKeyRateLimitKey(t *testing.T) { func TestAPIKeyRateLimitKey(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
userID int64 userID int64

View File

@@ -16,17 +16,17 @@ type apiKeyRepository struct {
client *dbent.Client client *dbent.Client
} }
func NewApiKeyRepository(client *dbent.Client) service.ApiKeyRepository { func NewAPIKeyRepository(client *dbent.Client) service.APIKeyRepository {
return &apiKeyRepository{client: client} return &apiKeyRepository{client: client}
} }
func (r *apiKeyRepository) activeQuery() *dbent.ApiKeyQuery { func (r *apiKeyRepository) activeQuery() *dbent.APIKeyQuery {
// 默认过滤已软删除记录,避免删除后仍被查询到。 // 默认过滤已软删除记录,避免删除后仍被查询到。
return r.client.ApiKey.Query().Where(apikey.DeletedAtIsNil()) return r.client.APIKey.Query().Where(apikey.DeletedAtIsNil())
} }
func (r *apiKeyRepository) Create(ctx context.Context, key *service.ApiKey) error { func (r *apiKeyRepository) Create(ctx context.Context, key *service.APIKey) error {
created, err := r.client.ApiKey.Create(). created, err := r.client.APIKey.Create().
SetUserID(key.UserID). SetUserID(key.UserID).
SetKey(key.Key). SetKey(key.Key).
SetName(key.Name). SetName(key.Name).
@@ -38,10 +38,10 @@ func (r *apiKeyRepository) Create(ctx context.Context, key *service.ApiKey) erro
key.CreatedAt = created.CreatedAt key.CreatedAt = created.CreatedAt
key.UpdatedAt = created.UpdatedAt key.UpdatedAt = created.UpdatedAt
} }
return translatePersistenceError(err, nil, service.ErrApiKeyExists) return translatePersistenceError(err, nil, service.ErrAPIKeyExists)
} }
func (r *apiKeyRepository) GetByID(ctx context.Context, id int64) (*service.ApiKey, error) { func (r *apiKeyRepository) GetByID(ctx context.Context, id int64) (*service.APIKey, error) {
m, err := r.activeQuery(). m, err := r.activeQuery().
Where(apikey.IDEQ(id)). Where(apikey.IDEQ(id)).
WithUser(). WithUser().
@@ -49,7 +49,7 @@ func (r *apiKeyRepository) GetByID(ctx context.Context, id int64) (*service.ApiK
Only(ctx) Only(ctx)
if err != nil { if err != nil {
if dbent.IsNotFound(err) { if dbent.IsNotFound(err) {
return nil, service.ErrApiKeyNotFound return nil, service.ErrAPIKeyNotFound
} }
return nil, err return nil, err
} }
@@ -59,7 +59,7 @@ func (r *apiKeyRepository) GetByID(ctx context.Context, id int64) (*service.ApiK
// GetOwnerID 根据 API Key ID 获取其所有者(用户)的 ID。 // GetOwnerID 根据 API Key ID 获取其所有者(用户)的 ID。
// 相比 GetByID此方法性能更优因为 // 相比 GetByID此方法性能更优因为
// - 使用 Select() 只查询 user_id 字段,减少数据传输量 // - 使用 Select() 只查询 user_id 字段,减少数据传输量
// - 不加载完整的 ApiKey 实体及其关联数据User、Group 等) // - 不加载完整的 APIKey 实体及其关联数据User、Group 等)
// - 适用于权限验证等只需用户 ID 的场景(如删除前的所有权检查) // - 适用于权限验证等只需用户 ID 的场景(如删除前的所有权检查)
func (r *apiKeyRepository) GetOwnerID(ctx context.Context, id int64) (int64, error) { func (r *apiKeyRepository) GetOwnerID(ctx context.Context, id int64) (int64, error) {
m, err := r.activeQuery(). m, err := r.activeQuery().
@@ -68,14 +68,14 @@ func (r *apiKeyRepository) GetOwnerID(ctx context.Context, id int64) (int64, err
Only(ctx) Only(ctx)
if err != nil { if err != nil {
if dbent.IsNotFound(err) { if dbent.IsNotFound(err) {
return 0, service.ErrApiKeyNotFound return 0, service.ErrAPIKeyNotFound
} }
return 0, err return 0, err
} }
return m.UserID, nil return m.UserID, nil
} }
func (r *apiKeyRepository) GetByKey(ctx context.Context, key string) (*service.ApiKey, error) { func (r *apiKeyRepository) GetByKey(ctx context.Context, key string) (*service.APIKey, error) {
m, err := r.activeQuery(). m, err := r.activeQuery().
Where(apikey.KeyEQ(key)). Where(apikey.KeyEQ(key)).
WithUser(). WithUser().
@@ -83,21 +83,21 @@ func (r *apiKeyRepository) GetByKey(ctx context.Context, key string) (*service.A
Only(ctx) Only(ctx)
if err != nil { if err != nil {
if dbent.IsNotFound(err) { if dbent.IsNotFound(err) {
return nil, service.ErrApiKeyNotFound return nil, service.ErrAPIKeyNotFound
} }
return nil, err return nil, err
} }
return apiKeyEntityToService(m), nil return apiKeyEntityToService(m), nil
} }
func (r *apiKeyRepository) Update(ctx context.Context, key *service.ApiKey) error { func (r *apiKeyRepository) Update(ctx context.Context, key *service.APIKey) error {
// 使用原子操作:将软删除检查与更新合并到同一语句,避免竞态条件。 // 使用原子操作:将软删除检查与更新合并到同一语句,避免竞态条件。
// 之前的实现先检查 Exist 再 UpdateOneID若在两步之间发生软删除 // 之前的实现先检查 Exist 再 UpdateOneID若在两步之间发生软删除
// 则会更新已删除的记录。 // 则会更新已删除的记录。
// 这里选择 Update().Where(),确保只有未软删除记录能被更新。 // 这里选择 Update().Where(),确保只有未软删除记录能被更新。
// 同时显式设置 updated_at避免二次查询带来的并发可见性问题。 // 同时显式设置 updated_at避免二次查询带来的并发可见性问题。
now := time.Now() now := time.Now()
builder := r.client.ApiKey.Update(). builder := r.client.APIKey.Update().
Where(apikey.IDEQ(key.ID), apikey.DeletedAtIsNil()). Where(apikey.IDEQ(key.ID), apikey.DeletedAtIsNil()).
SetName(key.Name). SetName(key.Name).
SetStatus(key.Status). SetStatus(key.Status).
@@ -114,7 +114,7 @@ func (r *apiKeyRepository) Update(ctx context.Context, key *service.ApiKey) erro
} }
if affected == 0 { if affected == 0 {
// 更新影响行数为 0说明记录不存在或已被软删除。 // 更新影响行数为 0说明记录不存在或已被软删除。
return service.ErrApiKeyNotFound return service.ErrAPIKeyNotFound
} }
// 使用同一时间戳回填,避免并发删除导致二次查询失败。 // 使用同一时间戳回填,避免并发删除导致二次查询失败。
@@ -124,18 +124,18 @@ func (r *apiKeyRepository) Update(ctx context.Context, key *service.ApiKey) erro
func (r *apiKeyRepository) Delete(ctx context.Context, id int64) error { func (r *apiKeyRepository) Delete(ctx context.Context, id int64) error {
// 显式软删除:避免依赖 Hook 行为,确保 deleted_at 一定被设置。 // 显式软删除:避免依赖 Hook 行为,确保 deleted_at 一定被设置。
affected, err := r.client.ApiKey.Update(). affected, err := r.client.APIKey.Update().
Where(apikey.IDEQ(id), apikey.DeletedAtIsNil()). Where(apikey.IDEQ(id), apikey.DeletedAtIsNil()).
SetDeletedAt(time.Now()). SetDeletedAt(time.Now()).
Save(ctx) Save(ctx)
if err != nil { if err != nil {
if dbent.IsNotFound(err) { if dbent.IsNotFound(err) {
return service.ErrApiKeyNotFound return service.ErrAPIKeyNotFound
} }
return err return err
} }
if affected == 0 { if affected == 0 {
exists, err := r.client.ApiKey.Query(). exists, err := r.client.APIKey.Query().
Where(apikey.IDEQ(id)). Where(apikey.IDEQ(id)).
Exist(mixins.SkipSoftDelete(ctx)) Exist(mixins.SkipSoftDelete(ctx))
if err != nil { if err != nil {
@@ -144,12 +144,12 @@ func (r *apiKeyRepository) Delete(ctx context.Context, id int64) error {
if exists { if exists {
return nil return nil
} }
return service.ErrApiKeyNotFound return service.ErrAPIKeyNotFound
} }
return nil return nil
} }
func (r *apiKeyRepository) ListByUserID(ctx context.Context, userID int64, params pagination.PaginationParams) ([]service.ApiKey, *pagination.PaginationResult, error) { func (r *apiKeyRepository) ListByUserID(ctx context.Context, userID int64, params pagination.PaginationParams) ([]service.APIKey, *pagination.PaginationResult, error) {
q := r.activeQuery().Where(apikey.UserIDEQ(userID)) q := r.activeQuery().Where(apikey.UserIDEQ(userID))
total, err := q.Count(ctx) total, err := q.Count(ctx)
@@ -167,7 +167,7 @@ func (r *apiKeyRepository) ListByUserID(ctx context.Context, userID int64, param
return nil, nil, err return nil, nil, err
} }
outKeys := make([]service.ApiKey, 0, len(keys)) outKeys := make([]service.APIKey, 0, len(keys))
for i := range keys { for i := range keys {
outKeys = append(outKeys, *apiKeyEntityToService(keys[i])) outKeys = append(outKeys, *apiKeyEntityToService(keys[i]))
} }
@@ -180,7 +180,7 @@ func (r *apiKeyRepository) VerifyOwnership(ctx context.Context, userID int64, ap
return []int64{}, nil return []int64{}, nil
} }
ids, err := r.client.ApiKey.Query(). ids, err := r.client.APIKey.Query().
Where(apikey.UserIDEQ(userID), apikey.IDIn(apiKeyIDs...), apikey.DeletedAtIsNil()). Where(apikey.UserIDEQ(userID), apikey.IDIn(apiKeyIDs...), apikey.DeletedAtIsNil()).
IDs(ctx) IDs(ctx)
if err != nil { if err != nil {
@@ -199,7 +199,7 @@ func (r *apiKeyRepository) ExistsByKey(ctx context.Context, key string) (bool, e
return count > 0, err return count > 0, err
} }
func (r *apiKeyRepository) ListByGroupID(ctx context.Context, groupID int64, params pagination.PaginationParams) ([]service.ApiKey, *pagination.PaginationResult, error) { func (r *apiKeyRepository) ListByGroupID(ctx context.Context, groupID int64, params pagination.PaginationParams) ([]service.APIKey, *pagination.PaginationResult, error) {
q := r.activeQuery().Where(apikey.GroupIDEQ(groupID)) q := r.activeQuery().Where(apikey.GroupIDEQ(groupID))
total, err := q.Count(ctx) total, err := q.Count(ctx)
@@ -217,7 +217,7 @@ func (r *apiKeyRepository) ListByGroupID(ctx context.Context, groupID int64, par
return nil, nil, err return nil, nil, err
} }
outKeys := make([]service.ApiKey, 0, len(keys)) outKeys := make([]service.APIKey, 0, len(keys))
for i := range keys { for i := range keys {
outKeys = append(outKeys, *apiKeyEntityToService(keys[i])) outKeys = append(outKeys, *apiKeyEntityToService(keys[i]))
} }
@@ -225,8 +225,8 @@ func (r *apiKeyRepository) ListByGroupID(ctx context.Context, groupID int64, par
return outKeys, paginationResultFromTotal(int64(total), params), nil return outKeys, paginationResultFromTotal(int64(total), params), nil
} }
// SearchApiKeys searches API keys by user ID and/or keyword (name) // SearchAPIKeys searches API keys by user ID and/or keyword (name)
func (r *apiKeyRepository) SearchApiKeys(ctx context.Context, userID int64, keyword string, limit int) ([]service.ApiKey, error) { func (r *apiKeyRepository) SearchAPIKeys(ctx context.Context, userID int64, keyword string, limit int) ([]service.APIKey, error) {
q := r.activeQuery() q := r.activeQuery()
if userID > 0 { if userID > 0 {
q = q.Where(apikey.UserIDEQ(userID)) q = q.Where(apikey.UserIDEQ(userID))
@@ -241,7 +241,7 @@ func (r *apiKeyRepository) SearchApiKeys(ctx context.Context, userID int64, keyw
return nil, err return nil, err
} }
outKeys := make([]service.ApiKey, 0, len(keys)) outKeys := make([]service.APIKey, 0, len(keys))
for i := range keys { for i := range keys {
outKeys = append(outKeys, *apiKeyEntityToService(keys[i])) outKeys = append(outKeys, *apiKeyEntityToService(keys[i]))
} }
@@ -250,7 +250,7 @@ func (r *apiKeyRepository) SearchApiKeys(ctx context.Context, userID int64, keyw
// ClearGroupIDByGroupID 将指定分组的所有 API Key 的 group_id 设为 nil // ClearGroupIDByGroupID 将指定分组的所有 API Key 的 group_id 设为 nil
func (r *apiKeyRepository) ClearGroupIDByGroupID(ctx context.Context, groupID int64) (int64, error) { func (r *apiKeyRepository) ClearGroupIDByGroupID(ctx context.Context, groupID int64) (int64, error) {
n, err := r.client.ApiKey.Update(). n, err := r.client.APIKey.Update().
Where(apikey.GroupIDEQ(groupID), apikey.DeletedAtIsNil()). Where(apikey.GroupIDEQ(groupID), apikey.DeletedAtIsNil()).
ClearGroupID(). ClearGroupID().
Save(ctx) Save(ctx)
@@ -263,11 +263,11 @@ func (r *apiKeyRepository) CountByGroupID(ctx context.Context, groupID int64) (i
return int64(count), err return int64(count), err
} }
func apiKeyEntityToService(m *dbent.ApiKey) *service.ApiKey { func apiKeyEntityToService(m *dbent.APIKey) *service.APIKey {
if m == nil { if m == nil {
return nil return nil
} }
out := &service.ApiKey{ out := &service.APIKey{
ID: m.ID, ID: m.ID,
UserID: m.UserID, UserID: m.UserID,
Key: m.Key, Key: m.Key,

View File

@@ -12,30 +12,30 @@ import (
"github.com/stretchr/testify/suite" "github.com/stretchr/testify/suite"
) )
type ApiKeyRepoSuite struct { type APIKeyRepoSuite struct {
suite.Suite suite.Suite
ctx context.Context ctx context.Context
client *dbent.Client client *dbent.Client
repo *apiKeyRepository repo *apiKeyRepository
} }
func (s *ApiKeyRepoSuite) SetupTest() { func (s *APIKeyRepoSuite) SetupTest() {
s.ctx = context.Background() s.ctx = context.Background()
tx := testEntTx(s.T()) tx := testEntTx(s.T())
s.client = tx.Client() s.client = tx.Client()
s.repo = NewApiKeyRepository(s.client).(*apiKeyRepository) s.repo = NewAPIKeyRepository(s.client).(*apiKeyRepository)
} }
func TestApiKeyRepoSuite(t *testing.T) { func TestAPIKeyRepoSuite(t *testing.T) {
suite.Run(t, new(ApiKeyRepoSuite)) suite.Run(t, new(APIKeyRepoSuite))
} }
// --- Create / GetByID / GetByKey --- // --- Create / GetByID / GetByKey ---
func (s *ApiKeyRepoSuite) TestCreate() { func (s *APIKeyRepoSuite) TestCreate() {
user := s.mustCreateUser("create@test.com") user := s.mustCreateUser("create@test.com")
key := &service.ApiKey{ key := &service.APIKey{
UserID: user.ID, UserID: user.ID,
Key: "sk-create-test", Key: "sk-create-test",
Name: "Test Key", Name: "Test Key",
@@ -51,16 +51,16 @@ func (s *ApiKeyRepoSuite) TestCreate() {
s.Require().Equal("sk-create-test", got.Key) s.Require().Equal("sk-create-test", got.Key)
} }
func (s *ApiKeyRepoSuite) TestGetByID_NotFound() { func (s *APIKeyRepoSuite) TestGetByID_NotFound() {
_, err := s.repo.GetByID(s.ctx, 999999) _, err := s.repo.GetByID(s.ctx, 999999)
s.Require().Error(err, "expected error for non-existent ID") s.Require().Error(err, "expected error for non-existent ID")
} }
func (s *ApiKeyRepoSuite) TestGetByKey() { func (s *APIKeyRepoSuite) TestGetByKey() {
user := s.mustCreateUser("getbykey@test.com") user := s.mustCreateUser("getbykey@test.com")
group := s.mustCreateGroup("g-key") group := s.mustCreateGroup("g-key")
key := &service.ApiKey{ key := &service.APIKey{
UserID: user.ID, UserID: user.ID,
Key: "sk-getbykey", Key: "sk-getbykey",
Name: "My Key", Name: "My Key",
@@ -78,16 +78,16 @@ func (s *ApiKeyRepoSuite) TestGetByKey() {
s.Require().Equal(group.ID, got.Group.ID) s.Require().Equal(group.ID, got.Group.ID)
} }
func (s *ApiKeyRepoSuite) TestGetByKey_NotFound() { func (s *APIKeyRepoSuite) TestGetByKey_NotFound() {
_, err := s.repo.GetByKey(s.ctx, "non-existent-key") _, err := s.repo.GetByKey(s.ctx, "non-existent-key")
s.Require().Error(err, "expected error for non-existent key") s.Require().Error(err, "expected error for non-existent key")
} }
// --- Update --- // --- Update ---
func (s *ApiKeyRepoSuite) TestUpdate() { func (s *APIKeyRepoSuite) TestUpdate() {
user := s.mustCreateUser("update@test.com") user := s.mustCreateUser("update@test.com")
key := &service.ApiKey{ key := &service.APIKey{
UserID: user.ID, UserID: user.ID,
Key: "sk-update", Key: "sk-update",
Name: "Original", Name: "Original",
@@ -108,10 +108,10 @@ func (s *ApiKeyRepoSuite) TestUpdate() {
s.Require().Equal(service.StatusDisabled, got.Status) s.Require().Equal(service.StatusDisabled, got.Status)
} }
func (s *ApiKeyRepoSuite) TestUpdate_ClearGroupID() { func (s *APIKeyRepoSuite) TestUpdate_ClearGroupID() {
user := s.mustCreateUser("cleargroup@test.com") user := s.mustCreateUser("cleargroup@test.com")
group := s.mustCreateGroup("g-clear") group := s.mustCreateGroup("g-clear")
key := &service.ApiKey{ key := &service.APIKey{
UserID: user.ID, UserID: user.ID,
Key: "sk-clear-group", Key: "sk-clear-group",
Name: "Group Key", Name: "Group Key",
@@ -131,9 +131,9 @@ func (s *ApiKeyRepoSuite) TestUpdate_ClearGroupID() {
// --- Delete --- // --- Delete ---
func (s *ApiKeyRepoSuite) TestDelete() { func (s *APIKeyRepoSuite) TestDelete() {
user := s.mustCreateUser("delete@test.com") user := s.mustCreateUser("delete@test.com")
key := &service.ApiKey{ key := &service.APIKey{
UserID: user.ID, UserID: user.ID,
Key: "sk-delete", Key: "sk-delete",
Name: "Delete Me", Name: "Delete Me",
@@ -150,10 +150,10 @@ func (s *ApiKeyRepoSuite) TestDelete() {
// --- ListByUserID / CountByUserID --- // --- ListByUserID / CountByUserID ---
func (s *ApiKeyRepoSuite) TestListByUserID() { func (s *APIKeyRepoSuite) TestListByUserID() {
user := s.mustCreateUser("listbyuser@test.com") user := s.mustCreateUser("listbyuser@test.com")
s.mustCreateApiKey(user.ID, "sk-list-1", "Key 1", nil) s.mustCreateAPIKey(user.ID, "sk-list-1", "Key 1", nil)
s.mustCreateApiKey(user.ID, "sk-list-2", "Key 2", nil) s.mustCreateAPIKey(user.ID, "sk-list-2", "Key 2", nil)
keys, page, err := s.repo.ListByUserID(s.ctx, user.ID, pagination.PaginationParams{Page: 1, PageSize: 10}) keys, page, err := s.repo.ListByUserID(s.ctx, user.ID, pagination.PaginationParams{Page: 1, PageSize: 10})
s.Require().NoError(err, "ListByUserID") s.Require().NoError(err, "ListByUserID")
@@ -161,10 +161,10 @@ func (s *ApiKeyRepoSuite) TestListByUserID() {
s.Require().Equal(int64(2), page.Total) s.Require().Equal(int64(2), page.Total)
} }
func (s *ApiKeyRepoSuite) TestListByUserID_Pagination() { func (s *APIKeyRepoSuite) TestListByUserID_Pagination() {
user := s.mustCreateUser("paging@test.com") user := s.mustCreateUser("paging@test.com")
for i := 0; i < 5; i++ { for i := 0; i < 5; i++ {
s.mustCreateApiKey(user.ID, "sk-page-"+string(rune('a'+i)), "Key", nil) s.mustCreateAPIKey(user.ID, "sk-page-"+string(rune('a'+i)), "Key", nil)
} }
keys, page, err := s.repo.ListByUserID(s.ctx, user.ID, pagination.PaginationParams{Page: 1, PageSize: 2}) keys, page, err := s.repo.ListByUserID(s.ctx, user.ID, pagination.PaginationParams{Page: 1, PageSize: 2})
@@ -174,10 +174,10 @@ func (s *ApiKeyRepoSuite) TestListByUserID_Pagination() {
s.Require().Equal(3, page.Pages) s.Require().Equal(3, page.Pages)
} }
func (s *ApiKeyRepoSuite) TestCountByUserID() { func (s *APIKeyRepoSuite) TestCountByUserID() {
user := s.mustCreateUser("count@test.com") user := s.mustCreateUser("count@test.com")
s.mustCreateApiKey(user.ID, "sk-count-1", "K1", nil) s.mustCreateAPIKey(user.ID, "sk-count-1", "K1", nil)
s.mustCreateApiKey(user.ID, "sk-count-2", "K2", nil) s.mustCreateAPIKey(user.ID, "sk-count-2", "K2", nil)
count, err := s.repo.CountByUserID(s.ctx, user.ID) count, err := s.repo.CountByUserID(s.ctx, user.ID)
s.Require().NoError(err, "CountByUserID") s.Require().NoError(err, "CountByUserID")
@@ -186,13 +186,13 @@ func (s *ApiKeyRepoSuite) TestCountByUserID() {
// --- ListByGroupID / CountByGroupID --- // --- ListByGroupID / CountByGroupID ---
func (s *ApiKeyRepoSuite) TestListByGroupID() { func (s *APIKeyRepoSuite) TestListByGroupID() {
user := s.mustCreateUser("listbygroup@test.com") user := s.mustCreateUser("listbygroup@test.com")
group := s.mustCreateGroup("g-list") group := s.mustCreateGroup("g-list")
s.mustCreateApiKey(user.ID, "sk-grp-1", "K1", &group.ID) s.mustCreateAPIKey(user.ID, "sk-grp-1", "K1", &group.ID)
s.mustCreateApiKey(user.ID, "sk-grp-2", "K2", &group.ID) s.mustCreateAPIKey(user.ID, "sk-grp-2", "K2", &group.ID)
s.mustCreateApiKey(user.ID, "sk-grp-3", "K3", nil) // no group s.mustCreateAPIKey(user.ID, "sk-grp-3", "K3", nil) // no group
keys, page, err := s.repo.ListByGroupID(s.ctx, group.ID, pagination.PaginationParams{Page: 1, PageSize: 10}) keys, page, err := s.repo.ListByGroupID(s.ctx, group.ID, pagination.PaginationParams{Page: 1, PageSize: 10})
s.Require().NoError(err, "ListByGroupID") s.Require().NoError(err, "ListByGroupID")
@@ -202,10 +202,10 @@ func (s *ApiKeyRepoSuite) TestListByGroupID() {
s.Require().NotNil(keys[0].User) s.Require().NotNil(keys[0].User)
} }
func (s *ApiKeyRepoSuite) TestCountByGroupID() { func (s *APIKeyRepoSuite) TestCountByGroupID() {
user := s.mustCreateUser("countgroup@test.com") user := s.mustCreateUser("countgroup@test.com")
group := s.mustCreateGroup("g-count") group := s.mustCreateGroup("g-count")
s.mustCreateApiKey(user.ID, "sk-gc-1", "K1", &group.ID) s.mustCreateAPIKey(user.ID, "sk-gc-1", "K1", &group.ID)
count, err := s.repo.CountByGroupID(s.ctx, group.ID) count, err := s.repo.CountByGroupID(s.ctx, group.ID)
s.Require().NoError(err, "CountByGroupID") s.Require().NoError(err, "CountByGroupID")
@@ -214,9 +214,9 @@ func (s *ApiKeyRepoSuite) TestCountByGroupID() {
// --- ExistsByKey --- // --- ExistsByKey ---
func (s *ApiKeyRepoSuite) TestExistsByKey() { func (s *APIKeyRepoSuite) TestExistsByKey() {
user := s.mustCreateUser("exists@test.com") user := s.mustCreateUser("exists@test.com")
s.mustCreateApiKey(user.ID, "sk-exists", "K", nil) s.mustCreateAPIKey(user.ID, "sk-exists", "K", nil)
exists, err := s.repo.ExistsByKey(s.ctx, "sk-exists") exists, err := s.repo.ExistsByKey(s.ctx, "sk-exists")
s.Require().NoError(err, "ExistsByKey") s.Require().NoError(err, "ExistsByKey")
@@ -227,47 +227,47 @@ func (s *ApiKeyRepoSuite) TestExistsByKey() {
s.Require().False(notExists) s.Require().False(notExists)
} }
// --- SearchApiKeys --- // --- SearchAPIKeys ---
func (s *ApiKeyRepoSuite) TestSearchApiKeys() { func (s *APIKeyRepoSuite) TestSearchAPIKeys() {
user := s.mustCreateUser("search@test.com") user := s.mustCreateUser("search@test.com")
s.mustCreateApiKey(user.ID, "sk-search-1", "Production Key", nil) s.mustCreateAPIKey(user.ID, "sk-search-1", "Production Key", nil)
s.mustCreateApiKey(user.ID, "sk-search-2", "Development Key", nil) s.mustCreateAPIKey(user.ID, "sk-search-2", "Development Key", nil)
found, err := s.repo.SearchApiKeys(s.ctx, user.ID, "prod", 10) found, err := s.repo.SearchAPIKeys(s.ctx, user.ID, "prod", 10)
s.Require().NoError(err, "SearchApiKeys") s.Require().NoError(err, "SearchAPIKeys")
s.Require().Len(found, 1) s.Require().Len(found, 1)
s.Require().Contains(found[0].Name, "Production") s.Require().Contains(found[0].Name, "Production")
} }
func (s *ApiKeyRepoSuite) TestSearchApiKeys_NoKeyword() { func (s *APIKeyRepoSuite) TestSearchAPIKeys_NoKeyword() {
user := s.mustCreateUser("searchnokw@test.com") user := s.mustCreateUser("searchnokw@test.com")
s.mustCreateApiKey(user.ID, "sk-nk-1", "K1", nil) s.mustCreateAPIKey(user.ID, "sk-nk-1", "K1", nil)
s.mustCreateApiKey(user.ID, "sk-nk-2", "K2", nil) s.mustCreateAPIKey(user.ID, "sk-nk-2", "K2", nil)
found, err := s.repo.SearchApiKeys(s.ctx, user.ID, "", 10) found, err := s.repo.SearchAPIKeys(s.ctx, user.ID, "", 10)
s.Require().NoError(err) s.Require().NoError(err)
s.Require().Len(found, 2) s.Require().Len(found, 2)
} }
func (s *ApiKeyRepoSuite) TestSearchApiKeys_NoUserID() { func (s *APIKeyRepoSuite) TestSearchAPIKeys_NoUserID() {
user := s.mustCreateUser("searchnouid@test.com") user := s.mustCreateUser("searchnouid@test.com")
s.mustCreateApiKey(user.ID, "sk-nu-1", "TestKey", nil) s.mustCreateAPIKey(user.ID, "sk-nu-1", "TestKey", nil)
found, err := s.repo.SearchApiKeys(s.ctx, 0, "testkey", 10) found, err := s.repo.SearchAPIKeys(s.ctx, 0, "testkey", 10)
s.Require().NoError(err) s.Require().NoError(err)
s.Require().Len(found, 1) s.Require().Len(found, 1)
} }
// --- ClearGroupIDByGroupID --- // --- ClearGroupIDByGroupID ---
func (s *ApiKeyRepoSuite) TestClearGroupIDByGroupID() { func (s *APIKeyRepoSuite) TestClearGroupIDByGroupID() {
user := s.mustCreateUser("cleargrp@test.com") user := s.mustCreateUser("cleargrp@test.com")
group := s.mustCreateGroup("g-clear-bulk") group := s.mustCreateGroup("g-clear-bulk")
k1 := s.mustCreateApiKey(user.ID, "sk-clr-1", "K1", &group.ID) k1 := s.mustCreateAPIKey(user.ID, "sk-clr-1", "K1", &group.ID)
k2 := s.mustCreateApiKey(user.ID, "sk-clr-2", "K2", &group.ID) k2 := s.mustCreateAPIKey(user.ID, "sk-clr-2", "K2", &group.ID)
s.mustCreateApiKey(user.ID, "sk-clr-3", "K3", nil) // no group s.mustCreateAPIKey(user.ID, "sk-clr-3", "K3", nil) // no group
affected, err := s.repo.ClearGroupIDByGroupID(s.ctx, group.ID) affected, err := s.repo.ClearGroupIDByGroupID(s.ctx, group.ID)
s.Require().NoError(err, "ClearGroupIDByGroupID") s.Require().NoError(err, "ClearGroupIDByGroupID")
@@ -284,10 +284,10 @@ func (s *ApiKeyRepoSuite) TestClearGroupIDByGroupID() {
// --- Combined CRUD/Search/ClearGroupID (original test preserved as integration) --- // --- Combined CRUD/Search/ClearGroupID (original test preserved as integration) ---
func (s *ApiKeyRepoSuite) TestCRUD_Search_ClearGroupID() { func (s *APIKeyRepoSuite) TestCRUD_Search_ClearGroupID() {
user := s.mustCreateUser("k@example.com") user := s.mustCreateUser("k@example.com")
group := s.mustCreateGroup("g-k") group := s.mustCreateGroup("g-k")
key := s.mustCreateApiKey(user.ID, "sk-test-1", "My Key", &group.ID) key := s.mustCreateAPIKey(user.ID, "sk-test-1", "My Key", &group.ID)
key.GroupID = &group.ID key.GroupID = &group.ID
got, err := s.repo.GetByKey(s.ctx, key.Key) got, err := s.repo.GetByKey(s.ctx, key.Key)
@@ -320,13 +320,13 @@ func (s *ApiKeyRepoSuite) TestCRUD_Search_ClearGroupID() {
s.Require().NoError(err, "ExistsByKey") s.Require().NoError(err, "ExistsByKey")
s.Require().True(exists, "expected key to exist") s.Require().True(exists, "expected key to exist")
found, err := s.repo.SearchApiKeys(s.ctx, user.ID, "renam", 10) found, err := s.repo.SearchAPIKeys(s.ctx, user.ID, "renam", 10)
s.Require().NoError(err, "SearchApiKeys") s.Require().NoError(err, "SearchAPIKeys")
s.Require().Len(found, 1) s.Require().Len(found, 1)
s.Require().Equal(key.ID, found[0].ID) s.Require().Equal(key.ID, found[0].ID)
// ClearGroupIDByGroupID // ClearGroupIDByGroupID
k2 := s.mustCreateApiKey(user.ID, "sk-test-2", "Group Key", &group.ID) k2 := s.mustCreateAPIKey(user.ID, "sk-test-2", "Group Key", &group.ID)
k2.GroupID = &group.ID k2.GroupID = &group.ID
countBefore, err := s.repo.CountByGroupID(s.ctx, group.ID) countBefore, err := s.repo.CountByGroupID(s.ctx, group.ID)
@@ -346,7 +346,7 @@ func (s *ApiKeyRepoSuite) TestCRUD_Search_ClearGroupID() {
s.Require().Equal(int64(0), countAfter, "expected 0 keys in group after clear") s.Require().Equal(int64(0), countAfter, "expected 0 keys in group after clear")
} }
func (s *ApiKeyRepoSuite) mustCreateUser(email string) *service.User { func (s *APIKeyRepoSuite) mustCreateUser(email string) *service.User {
s.T().Helper() s.T().Helper()
u, err := s.client.User.Create(). u, err := s.client.User.Create().
@@ -359,7 +359,7 @@ func (s *ApiKeyRepoSuite) mustCreateUser(email string) *service.User {
return userEntityToService(u) return userEntityToService(u)
} }
func (s *ApiKeyRepoSuite) mustCreateGroup(name string) *service.Group { func (s *APIKeyRepoSuite) mustCreateGroup(name string) *service.Group {
s.T().Helper() s.T().Helper()
g, err := s.client.Group.Create(). g, err := s.client.Group.Create().
@@ -370,10 +370,10 @@ func (s *ApiKeyRepoSuite) mustCreateGroup(name string) *service.Group {
return groupEntityToService(g) return groupEntityToService(g)
} }
func (s *ApiKeyRepoSuite) mustCreateApiKey(userID int64, key, name string, groupID *int64) *service.ApiKey { func (s *APIKeyRepoSuite) mustCreateAPIKey(userID int64, key, name string, groupID *int64) *service.APIKey {
s.T().Helper() s.T().Helper()
k := &service.ApiKey{ k := &service.APIKey{
UserID: userID, UserID: userID,
Key: key, Key: key,
Name: name, Name: name,

View File

@@ -27,8 +27,14 @@ const (
accountSlotKeyPrefix = "concurrency:account:" accountSlotKeyPrefix = "concurrency:account:"
// 格式: concurrency:user:{userID} // 格式: concurrency:user:{userID}
userSlotKeyPrefix = "concurrency:user:" userSlotKeyPrefix = "concurrency:user:"
// 等待队列计数器格式: concurrency:wait:{userID}
waitQueueKeyPrefix = "concurrency:wait:" // Wait queue keys (global structures)
// - total: integer total queue depth across all users
// - updated: sorted set of userID -> lastUpdateUnixSec (for TTL cleanup)
// - counts: hash of userID -> current wait count
waitQueueTotalKey = "concurrency:wait:total"
waitQueueUpdatedKey = "concurrency:wait:updated"
waitQueueCountsKey = "concurrency:wait:counts"
// 账号级等待队列计数器格式: wait:account:{accountID} // 账号级等待队列计数器格式: wait:account:{accountID}
accountWaitKeyPrefix = "wait:account:" accountWaitKeyPrefix = "wait:account:"
@@ -94,27 +100,55 @@ var (
`) `)
// incrementWaitScript - only sets TTL on first creation to avoid refreshing // incrementWaitScript - only sets TTL on first creation to avoid refreshing
// KEYS[1] = wait queue key // KEYS[1] = total key
// ARGV[1] = maxWait // KEYS[2] = updated zset key
// ARGV[2] = TTL in seconds // KEYS[3] = counts hash key
// ARGV[1] = userID
// ARGV[2] = maxWait
// ARGV[3] = TTL in seconds
// ARGV[4] = cleanup limit
incrementWaitScript = redis.NewScript(` incrementWaitScript = redis.NewScript(`
local current = redis.call('GET', KEYS[1]) local totalKey = KEYS[1]
if current == false then local updatedKey = KEYS[2]
current = 0 local countsKey = KEYS[3]
else
current = tonumber(current) local userID = ARGV[1]
local maxWait = tonumber(ARGV[2])
local ttl = tonumber(ARGV[3])
local cleanupLimit = tonumber(ARGV[4])
redis.call('SETNX', totalKey, 0)
local timeResult = redis.call('TIME')
local now = tonumber(timeResult[1])
local expireBefore = now - ttl
-- Cleanup expired users (bounded)
local expired = redis.call('ZRANGEBYSCORE', updatedKey, '-inf', expireBefore, 'LIMIT', 0, cleanupLimit)
for _, uid in ipairs(expired) do
local c = tonumber(redis.call('HGET', countsKey, uid) or '0')
if c > 0 then
redis.call('DECRBY', totalKey, c)
end
redis.call('HDEL', countsKey, uid)
redis.call('ZREM', updatedKey, uid)
end end
if current >= tonumber(ARGV[1]) then local current = tonumber(redis.call('HGET', countsKey, userID) or '0')
if current >= maxWait then
return 0 return 0
end end
local newVal = redis.call('INCR', KEYS[1]) local newVal = current + 1
redis.call('HSET', countsKey, userID, newVal)
redis.call('ZADD', updatedKey, now, userID)
redis.call('INCR', totalKey)
-- Only set TTL on first creation to avoid refreshing zombie data -- Keep global structures from living forever in totally idle deployments.
if newVal == 1 then local ttlKeep = ttl * 2
redis.call('EXPIRE', KEYS[1], ARGV[2]) redis.call('EXPIRE', totalKey, ttlKeep)
end redis.call('EXPIRE', updatedKey, ttlKeep)
redis.call('EXPIRE', countsKey, ttlKeep)
return 1 return 1
`) `)
@@ -144,6 +178,111 @@ var (
// decrementWaitScript - same as before // decrementWaitScript - same as before
decrementWaitScript = redis.NewScript(` decrementWaitScript = redis.NewScript(`
local totalKey = KEYS[1]
local updatedKey = KEYS[2]
local countsKey = KEYS[3]
local userID = ARGV[1]
local ttl = tonumber(ARGV[2])
local cleanupLimit = tonumber(ARGV[3])
redis.call('SETNX', totalKey, 0)
local timeResult = redis.call('TIME')
local now = tonumber(timeResult[1])
local expireBefore = now - ttl
-- Cleanup expired users (bounded)
local expired = redis.call('ZRANGEBYSCORE', updatedKey, '-inf', expireBefore, 'LIMIT', 0, cleanupLimit)
for _, uid in ipairs(expired) do
local c = tonumber(redis.call('HGET', countsKey, uid) or '0')
if c > 0 then
redis.call('DECRBY', totalKey, c)
end
redis.call('HDEL', countsKey, uid)
redis.call('ZREM', updatedKey, uid)
end
local current = tonumber(redis.call('HGET', countsKey, userID) or '0')
if current <= 0 then
return 1
end
local newVal = current - 1
if newVal <= 0 then
redis.call('HDEL', countsKey, userID)
redis.call('ZREM', updatedKey, userID)
else
redis.call('HSET', countsKey, userID, newVal)
redis.call('ZADD', updatedKey, now, userID)
end
redis.call('DECR', totalKey)
local ttlKeep = ttl * 2
redis.call('EXPIRE', totalKey, ttlKeep)
redis.call('EXPIRE', updatedKey, ttlKeep)
redis.call('EXPIRE', countsKey, ttlKeep)
return 1
`)
// getTotalWaitScript returns the global wait depth with TTL cleanup.
// KEYS[1] = total key
// KEYS[2] = updated zset key
// KEYS[3] = counts hash key
// ARGV[1] = TTL in seconds
// ARGV[2] = cleanup limit
getTotalWaitScript = redis.NewScript(`
local totalKey = KEYS[1]
local updatedKey = KEYS[2]
local countsKey = KEYS[3]
local ttl = tonumber(ARGV[1])
local cleanupLimit = tonumber(ARGV[2])
redis.call('SETNX', totalKey, 0)
local timeResult = redis.call('TIME')
local now = tonumber(timeResult[1])
local expireBefore = now - ttl
-- Cleanup expired users (bounded)
local expired = redis.call('ZRANGEBYSCORE', updatedKey, '-inf', expireBefore, 'LIMIT', 0, cleanupLimit)
for _, uid in ipairs(expired) do
local c = tonumber(redis.call('HGET', countsKey, uid) or '0')
if c > 0 then
redis.call('DECRBY', totalKey, c)
end
redis.call('HDEL', countsKey, uid)
redis.call('ZREM', updatedKey, uid)
end
-- If totalKey got lost but counts exist (e.g. Redis restart), recompute once.
local total = redis.call('GET', totalKey)
if total == false then
total = 0
local vals = redis.call('HVALS', countsKey)
for _, v in ipairs(vals) do
total = total + tonumber(v)
end
redis.call('SET', totalKey, total)
end
local ttlKeep = ttl * 2
redis.call('EXPIRE', totalKey, ttlKeep)
redis.call('EXPIRE', updatedKey, ttlKeep)
redis.call('EXPIRE', countsKey, ttlKeep)
local result = tonumber(redis.call('GET', totalKey) or '0')
if result < 0 then
result = 0
redis.call('SET', totalKey, 0)
end
return result
`)
// decrementAccountWaitScript - account-level wait queue decrement
decrementAccountWaitScript = redis.NewScript(`
local current = redis.call('GET', KEYS[1]) local current = redis.call('GET', KEYS[1])
if current ~= false and tonumber(current) > 0 then if current ~= false and tonumber(current) > 0 then
redis.call('DECR', KEYS[1]) redis.call('DECR', KEYS[1])
@@ -244,7 +383,9 @@ func userSlotKey(userID int64) string {
} }
func waitQueueKey(userID int64) string { func waitQueueKey(userID int64) string {
return fmt.Sprintf("%s%d", waitQueueKeyPrefix, userID) // Historical: per-user string keys were used.
// Now we use global structures keyed by userID string.
return strconv.FormatInt(userID, 10)
} }
func accountWaitKey(accountID int64) string { func accountWaitKey(accountID int64) string {
@@ -308,8 +449,16 @@ func (c *concurrencyCache) GetUserConcurrency(ctx context.Context, userID int64)
// Wait queue operations // Wait queue operations
func (c *concurrencyCache) IncrementWaitCount(ctx context.Context, userID int64, maxWait int) (bool, error) { func (c *concurrencyCache) IncrementWaitCount(ctx context.Context, userID int64, maxWait int) (bool, error) {
key := waitQueueKey(userID) userKey := waitQueueKey(userID)
result, err := incrementWaitScript.Run(ctx, c.rdb, []string{key}, maxWait, c.slotTTLSeconds).Int() result, err := incrementWaitScript.Run(
ctx,
c.rdb,
[]string{waitQueueTotalKey, waitQueueUpdatedKey, waitQueueCountsKey},
userKey,
maxWait,
c.waitQueueTTLSeconds,
200, // cleanup limit per call
).Int()
if err != nil { if err != nil {
return false, err return false, err
} }
@@ -317,11 +466,35 @@ func (c *concurrencyCache) IncrementWaitCount(ctx context.Context, userID int64,
} }
func (c *concurrencyCache) DecrementWaitCount(ctx context.Context, userID int64) error { func (c *concurrencyCache) DecrementWaitCount(ctx context.Context, userID int64) error {
key := waitQueueKey(userID) userKey := waitQueueKey(userID)
_, err := decrementWaitScript.Run(ctx, c.rdb, []string{key}).Result() _, err := decrementWaitScript.Run(
ctx,
c.rdb,
[]string{waitQueueTotalKey, waitQueueUpdatedKey, waitQueueCountsKey},
userKey,
c.waitQueueTTLSeconds,
200, // cleanup limit per call
).Result()
return err return err
} }
func (c *concurrencyCache) GetTotalWaitCount(ctx context.Context) (int, error) {
if c.rdb == nil {
return 0, nil
}
total, err := getTotalWaitScript.Run(
ctx,
c.rdb,
[]string{waitQueueTotalKey, waitQueueUpdatedKey, waitQueueCountsKey},
c.waitQueueTTLSeconds,
500, // cleanup limit per query (rare)
).Int64()
if err != nil {
return 0, err
}
return int(total), nil
}
// Account wait queue operations // Account wait queue operations
func (c *concurrencyCache) IncrementAccountWaitCount(ctx context.Context, accountID int64, maxWait int) (bool, error) { func (c *concurrencyCache) IncrementAccountWaitCount(ctx context.Context, accountID int64, maxWait int) (bool, error) {
@@ -335,7 +508,7 @@ func (c *concurrencyCache) IncrementAccountWaitCount(ctx context.Context, accoun
func (c *concurrencyCache) DecrementAccountWaitCount(ctx context.Context, accountID int64) error { func (c *concurrencyCache) DecrementAccountWaitCount(ctx context.Context, accountID int64) error {
key := accountWaitKey(accountID) key := accountWaitKey(accountID)
_, err := decrementWaitScript.Run(ctx, c.rdb, []string{key}).Result() _, err := decrementAccountWaitScript.Run(ctx, c.rdb, []string{key}).Result()
return err return err
} }

View File

@@ -158,7 +158,7 @@ func (s *ConcurrencyCacheSuite) TestUserSlot_TTL() {
func (s *ConcurrencyCacheSuite) TestWaitQueue_IncrementAndDecrement() { func (s *ConcurrencyCacheSuite) TestWaitQueue_IncrementAndDecrement() {
userID := int64(20) userID := int64(20)
waitKey := fmt.Sprintf("%s%d", waitQueueKeyPrefix, userID) userKey := waitQueueKey(userID)
ok, err := s.cache.IncrementWaitCount(s.ctx, userID, 2) ok, err := s.cache.IncrementWaitCount(s.ctx, userID, 2)
require.NoError(s.T(), err, "IncrementWaitCount 1") require.NoError(s.T(), err, "IncrementWaitCount 1")
@@ -172,31 +172,31 @@ func (s *ConcurrencyCacheSuite) TestWaitQueue_IncrementAndDecrement() {
require.NoError(s.T(), err, "IncrementWaitCount 3") require.NoError(s.T(), err, "IncrementWaitCount 3")
require.False(s.T(), ok, "expected wait increment over max to fail") require.False(s.T(), ok, "expected wait increment over max to fail")
ttl, err := s.rdb.TTL(s.ctx, waitKey).Result() ttl, err := s.rdb.TTL(s.ctx, waitQueueTotalKey).Result()
require.NoError(s.T(), err, "TTL waitKey") require.NoError(s.T(), err, "TTL wait total key")
s.AssertTTLWithin(ttl, 1*time.Second, testSlotTTL) s.AssertTTLWithin(ttl, 1*time.Second, testSlotTTL*2)
require.NoError(s.T(), s.cache.DecrementWaitCount(s.ctx, userID), "DecrementWaitCount") require.NoError(s.T(), s.cache.DecrementWaitCount(s.ctx, userID), "DecrementWaitCount")
val, err := s.rdb.Get(s.ctx, waitKey).Int() val, err := s.rdb.HGet(s.ctx, waitQueueCountsKey, userKey).Int()
if !errors.Is(err, redis.Nil) { require.NoError(s.T(), err, "HGET wait queue count")
require.NoError(s.T(), err, "Get waitKey")
}
require.Equal(s.T(), 1, val, "expected wait count 1") require.Equal(s.T(), 1, val, "expected wait count 1")
total, err := s.rdb.Get(s.ctx, waitQueueTotalKey).Int()
require.NoError(s.T(), err, "GET wait queue total")
require.Equal(s.T(), 1, total, "expected total wait count 1")
} }
func (s *ConcurrencyCacheSuite) TestWaitQueue_DecrementNoNegative() { func (s *ConcurrencyCacheSuite) TestWaitQueue_DecrementNoNegative() {
userID := int64(300) userID := int64(300)
waitKey := fmt.Sprintf("%s%d", waitQueueKeyPrefix, userID) userKey := waitQueueKey(userID)
// Test decrement on non-existent key - should not error and should not create negative value // Test decrement on non-existent key - should not error and should not create negative value
require.NoError(s.T(), s.cache.DecrementWaitCount(s.ctx, userID), "DecrementWaitCount on non-existent key") require.NoError(s.T(), s.cache.DecrementWaitCount(s.ctx, userID), "DecrementWaitCount on non-existent key")
// Verify no key was created or it's not negative // Verify count remains zero / absent.
val, err := s.rdb.Get(s.ctx, waitKey).Int() val, err := s.rdb.HGet(s.ctx, waitQueueCountsKey, userKey).Int()
if !errors.Is(err, redis.Nil) { require.True(s.T(), errors.Is(err, redis.Nil))
require.NoError(s.T(), err, "Get waitKey")
}
require.GreaterOrEqual(s.T(), val, 0, "expected non-negative wait count after decrement on empty") require.GreaterOrEqual(s.T(), val, 0, "expected non-negative wait count after decrement on empty")
// Set count to 1, then decrement twice // Set count to 1, then decrement twice
@@ -210,12 +210,15 @@ func (s *ConcurrencyCacheSuite) TestWaitQueue_DecrementNoNegative() {
// Decrement again on 0 - should not go negative // Decrement again on 0 - should not go negative
require.NoError(s.T(), s.cache.DecrementWaitCount(s.ctx, userID), "DecrementWaitCount on zero") require.NoError(s.T(), s.cache.DecrementWaitCount(s.ctx, userID), "DecrementWaitCount on zero")
// Verify count is 0, not negative // Verify per-user count is absent and total is non-negative.
val, err = s.rdb.Get(s.ctx, waitKey).Int() _, err = s.rdb.HGet(s.ctx, waitQueueCountsKey, userKey).Result()
require.True(s.T(), errors.Is(err, redis.Nil), "expected count field removed on zero")
total, err := s.rdb.Get(s.ctx, waitQueueTotalKey).Int()
if !errors.Is(err, redis.Nil) { if !errors.Is(err, redis.Nil) {
require.NoError(s.T(), err, "Get waitKey after double decrement") require.NoError(s.T(), err)
} }
require.GreaterOrEqual(s.T(), val, 0, "expected non-negative wait count") require.GreaterOrEqual(s.T(), total, 0, "expected non-negative total wait count")
} }
func (s *ConcurrencyCacheSuite) TestAccountWaitQueue_IncrementAndDecrement() { func (s *ConcurrencyCacheSuite) TestAccountWaitQueue_IncrementAndDecrement() {

View File

@@ -1,4 +1,4 @@
// Package infrastructure 提供应用程序的基础设施层组件。 // Package repository 提供应用程序的基础设施层组件。
// 包括数据库连接初始化、ORM 客户端管理、Redis 连接、数据库迁移等核心功能。 // 包括数据库连接初始化、ORM 客户端管理、Redis 连接、数据库迁移等核心功能。
package repository package repository

View File

@@ -243,7 +243,7 @@ func mustCreateAccount(t *testing.T, client *dbent.Client, a *service.Account) *
return a return a
} }
func mustCreateApiKey(t *testing.T, client *dbent.Client, k *service.ApiKey) *service.ApiKey { func mustCreateAPIKey(t *testing.T, client *dbent.Client, k *service.APIKey) *service.APIKey {
t.Helper() t.Helper()
ctx := context.Background() ctx := context.Background()
@@ -257,7 +257,7 @@ func mustCreateApiKey(t *testing.T, client *dbent.Client, k *service.ApiKey) *se
k.Name = "default" k.Name = "default"
} }
create := client.ApiKey.Create(). create := client.APIKey.Create().
SetUserID(k.UserID). SetUserID(k.UserID).
SetKey(k.Key). SetKey(k.Key).
SetName(k.Name). SetName(k.Name).

View File

@@ -293,8 +293,8 @@ func (r *groupRepository) DeleteCascade(ctx context.Context, id int64) ([]int64,
// 2. Clear group_id for api keys bound to this group. // 2. Clear group_id for api keys bound to this group.
// 仅更新未软删除的记录,避免修改已删除数据,保证审计与历史回溯一致性。 // 仅更新未软删除的记录,避免修改已删除数据,保证审计与历史回溯一致性。
// 与 ApiKeyRepository 的软删除语义保持一致,减少跨模块行为差异。 // 与 APIKeyRepository 的软删除语义保持一致,减少跨模块行为差异。
if _, err := txClient.ApiKey.Update(). if _, err := txClient.APIKey.Update().
Where(apikey.GroupIDEQ(id), apikey.DeletedAtIsNil()). Where(apikey.GroupIDEQ(id), apikey.DeletedAtIsNil()).
ClearGroupID(). ClearGroupID().
Save(ctx); err != nil { Save(ctx); err != nil {

View File

@@ -0,0 +1,190 @@
package repository
import (
"context"
"database/sql"
"fmt"
"strconv"
"strings"
"time"
"github.com/Wei-Shaw/sub2api/internal/service"
)
// ListErrorLogs queries ops_error_logs with optional filters and pagination.
// It returns the list items and the total count of matching rows.
func (r *OpsRepository) ListErrorLogs(ctx context.Context, filter *service.ErrorLogFilter) ([]*service.ErrorLog, int64, error) {
page := 1
pageSize := 20
if filter != nil {
if filter.Page > 0 {
page = filter.Page
}
if filter.PageSize > 0 {
pageSize = filter.PageSize
}
}
if pageSize > 100 {
pageSize = 100
}
offset := (page - 1) * pageSize
conditions := make([]string, 0)
args := make([]any, 0)
addCondition := func(condition string, values ...any) {
conditions = append(conditions, condition)
args = append(args, values...)
}
if filter != nil {
// 默认查询最近 24 小时
if filter.StartTime == nil && filter.EndTime == nil {
defaultStart := time.Now().Add(-24 * time.Hour)
filter.StartTime = &defaultStart
}
if filter.StartTime != nil {
addCondition(fmt.Sprintf("created_at >= $%d", len(args)+1), *filter.StartTime)
}
if filter.EndTime != nil {
addCondition(fmt.Sprintf("created_at <= $%d", len(args)+1), *filter.EndTime)
}
if filter.ErrorCode != nil {
addCondition(fmt.Sprintf("status_code = $%d", len(args)+1), *filter.ErrorCode)
}
if provider := strings.TrimSpace(filter.Provider); provider != "" {
addCondition(fmt.Sprintf("platform = $%d", len(args)+1), provider)
}
if filter.AccountID != nil {
addCondition(fmt.Sprintf("account_id = $%d", len(args)+1), *filter.AccountID)
}
}
where := ""
if len(conditions) > 0 {
where = "WHERE " + strings.Join(conditions, " AND ")
}
countQuery := fmt.Sprintf(`SELECT COUNT(1) FROM ops_error_logs %s`, where)
var total int64
if err := scanSingleRow(ctx, r.sql, countQuery, args, &total); err != nil {
if err == sql.ErrNoRows {
total = 0
} else {
return nil, 0, err
}
}
listQuery := fmt.Sprintf(`
SELECT
id,
created_at,
severity,
request_id,
account_id,
request_path,
platform,
model,
status_code,
error_message,
duration_ms,
retry_count,
stream
FROM ops_error_logs
%s
ORDER BY created_at DESC
LIMIT $%d OFFSET $%d
`, where, len(args)+1, len(args)+2)
listArgs := append(append([]any{}, args...), pageSize, offset)
rows, err := r.sql.QueryContext(ctx, listQuery, listArgs...)
if err != nil {
return nil, 0, err
}
defer func() { _ = rows.Close() }()
results := make([]*service.ErrorLog, 0)
for rows.Next() {
var (
id int64
createdAt time.Time
severity sql.NullString
requestID sql.NullString
accountID sql.NullInt64
requestURI sql.NullString
platform sql.NullString
model sql.NullString
statusCode sql.NullInt64
message sql.NullString
durationMs sql.NullInt64
retryCount sql.NullInt64
stream sql.NullBool
)
if err := rows.Scan(
&id,
&createdAt,
&severity,
&requestID,
&accountID,
&requestURI,
&platform,
&model,
&statusCode,
&message,
&durationMs,
&retryCount,
&stream,
); err != nil {
return nil, 0, err
}
entry := &service.ErrorLog{
ID: id,
Timestamp: createdAt,
Level: levelFromSeverity(severity.String),
RequestID: requestID.String,
APIPath: requestURI.String,
Provider: platform.String,
Model: model.String,
HTTPCode: int(statusCode.Int64),
Stream: stream.Bool,
}
if accountID.Valid {
entry.AccountID = strconv.FormatInt(accountID.Int64, 10)
}
if message.Valid {
entry.ErrorMessage = message.String
}
if durationMs.Valid {
v := int(durationMs.Int64)
entry.DurationMs = &v
}
if retryCount.Valid {
v := int(retryCount.Int64)
entry.RetryCount = &v
}
results = append(results, entry)
}
if err := rows.Err(); err != nil {
return nil, 0, err
}
return results, total, nil
}
func levelFromSeverity(severity string) string {
sev := strings.ToUpper(strings.TrimSpace(severity))
switch sev {
case "P0", "P1":
return "CRITICAL"
case "P2":
return "ERROR"
case "P3":
return "WARN"
default:
return "ERROR"
}
}

View File

@@ -0,0 +1,127 @@
package repository
import (
"context"
"encoding/json"
"errors"
"fmt"
"strings"
"time"
"github.com/Wei-Shaw/sub2api/internal/service"
"github.com/redis/go-redis/v9"
)
const (
opsLatestMetricsKey = "ops:metrics:latest"
opsDashboardOverviewKeyPrefix = "ops:dashboard:overview:"
opsLatestMetricsTTL = 10 * time.Second
)
func (r *OpsRepository) GetCachedLatestSystemMetric(ctx context.Context) (*service.OpsMetrics, error) {
if ctx == nil {
ctx = context.Background()
}
if r == nil || r.rdb == nil {
return nil, nil
}
data, err := r.rdb.Get(ctx, opsLatestMetricsKey).Bytes()
if errors.Is(err, redis.Nil) {
return nil, nil
}
if err != nil {
return nil, fmt.Errorf("redis get cached latest system metric: %w", err)
}
var metric service.OpsMetrics
if err := json.Unmarshal(data, &metric); err != nil {
return nil, fmt.Errorf("unmarshal cached latest system metric: %w", err)
}
return &metric, nil
}
func (r *OpsRepository) SetCachedLatestSystemMetric(ctx context.Context, metric *service.OpsMetrics) error {
if metric == nil {
return nil
}
if ctx == nil {
ctx = context.Background()
}
if r == nil || r.rdb == nil {
return nil
}
data, err := json.Marshal(metric)
if err != nil {
return fmt.Errorf("marshal cached latest system metric: %w", err)
}
return r.rdb.Set(ctx, opsLatestMetricsKey, data, opsLatestMetricsTTL).Err()
}
func (r *OpsRepository) GetCachedDashboardOverview(ctx context.Context, timeRange string) (*service.DashboardOverviewData, error) {
if ctx == nil {
ctx = context.Background()
}
if r == nil || r.rdb == nil {
return nil, nil
}
rangeKey := strings.TrimSpace(timeRange)
if rangeKey == "" {
rangeKey = "1h"
}
key := opsDashboardOverviewKeyPrefix + rangeKey
data, err := r.rdb.Get(ctx, key).Bytes()
if errors.Is(err, redis.Nil) {
return nil, nil
}
if err != nil {
return nil, fmt.Errorf("redis get cached dashboard overview: %w", err)
}
var overview service.DashboardOverviewData
if err := json.Unmarshal(data, &overview); err != nil {
return nil, fmt.Errorf("unmarshal cached dashboard overview: %w", err)
}
return &overview, nil
}
func (r *OpsRepository) SetCachedDashboardOverview(ctx context.Context, timeRange string, data *service.DashboardOverviewData, ttl time.Duration) error {
if data == nil {
return nil
}
if ttl <= 0 {
ttl = 10 * time.Second
}
if ctx == nil {
ctx = context.Background()
}
if r == nil || r.rdb == nil {
return nil
}
rangeKey := strings.TrimSpace(timeRange)
if rangeKey == "" {
rangeKey = "1h"
}
payload, err := json.Marshal(data)
if err != nil {
return fmt.Errorf("marshal cached dashboard overview: %w", err)
}
key := opsDashboardOverviewKeyPrefix + rangeKey
return r.rdb.Set(ctx, key, payload, ttl).Err()
}
func (r *OpsRepository) PingRedis(ctx context.Context) error {
if ctx == nil {
ctx = context.Background()
}
if r == nil || r.rdb == nil {
return errors.New("redis client is nil")
}
return r.rdb.Ping(ctx).Err()
}

File diff suppressed because it is too large Load Diff

View File

@@ -34,15 +34,15 @@ func createEntUser(t *testing.T, ctx context.Context, client *dbent.Client, emai
return u return u
} }
func TestEntSoftDelete_ApiKey_DefaultFilterAndSkip(t *testing.T) { func TestEntSoftDelete_APIKey_DefaultFilterAndSkip(t *testing.T) {
ctx := context.Background() ctx := context.Background()
// 使用全局 ent client确保软删除验证在实际持久化数据上进行。 // 使用全局 ent client确保软删除验证在实际持久化数据上进行。
client := testEntClient(t) client := testEntClient(t)
u := createEntUser(t, ctx, client, uniqueSoftDeleteValue(t, "sd-user")+"@example.com") u := createEntUser(t, ctx, client, uniqueSoftDeleteValue(t, "sd-user")+"@example.com")
repo := NewApiKeyRepository(client) repo := NewAPIKeyRepository(client)
key := &service.ApiKey{ key := &service.APIKey{
UserID: u.ID, UserID: u.ID,
Key: uniqueSoftDeleteValue(t, "sk-soft-delete"), Key: uniqueSoftDeleteValue(t, "sk-soft-delete"),
Name: "soft-delete", Name: "soft-delete",
@@ -53,28 +53,28 @@ func TestEntSoftDelete_ApiKey_DefaultFilterAndSkip(t *testing.T) {
require.NoError(t, repo.Delete(ctx, key.ID), "soft delete api key") require.NoError(t, repo.Delete(ctx, key.ID), "soft delete api key")
_, err := repo.GetByID(ctx, key.ID) _, err := repo.GetByID(ctx, key.ID)
require.ErrorIs(t, err, service.ErrApiKeyNotFound, "deleted rows should be hidden by default") require.ErrorIs(t, err, service.ErrAPIKeyNotFound, "deleted rows should be hidden by default")
_, err = client.ApiKey.Query().Where(apikey.IDEQ(key.ID)).Only(ctx) _, err = client.APIKey.Query().Where(apikey.IDEQ(key.ID)).Only(ctx)
require.Error(t, err, "default ent query should not see soft-deleted rows") require.Error(t, err, "default ent query should not see soft-deleted rows")
require.True(t, dbent.IsNotFound(err), "expected ent not-found after default soft delete filter") require.True(t, dbent.IsNotFound(err), "expected ent not-found after default soft delete filter")
got, err := client.ApiKey.Query(). got, err := client.APIKey.Query().
Where(apikey.IDEQ(key.ID)). Where(apikey.IDEQ(key.ID)).
Only(mixins.SkipSoftDelete(ctx)) Only(mixins.SkipSoftDelete(ctx))
require.NoError(t, err, "SkipSoftDelete should include soft-deleted rows") require.NoError(t, err, "SkipSoftDelete should include soft-deleted rows")
require.NotNil(t, got.DeletedAt, "deleted_at should be set after soft delete") require.NotNil(t, got.DeletedAt, "deleted_at should be set after soft delete")
} }
func TestEntSoftDelete_ApiKey_DeleteIdempotent(t *testing.T) { func TestEntSoftDelete_APIKey_DeleteIdempotent(t *testing.T) {
ctx := context.Background() ctx := context.Background()
// 使用全局 ent client避免事务回滚影响幂等性验证。 // 使用全局 ent client避免事务回滚影响幂等性验证。
client := testEntClient(t) client := testEntClient(t)
u := createEntUser(t, ctx, client, uniqueSoftDeleteValue(t, "sd-user2")+"@example.com") u := createEntUser(t, ctx, client, uniqueSoftDeleteValue(t, "sd-user2")+"@example.com")
repo := NewApiKeyRepository(client) repo := NewAPIKeyRepository(client)
key := &service.ApiKey{ key := &service.APIKey{
UserID: u.ID, UserID: u.ID,
Key: uniqueSoftDeleteValue(t, "sk-soft-delete2"), Key: uniqueSoftDeleteValue(t, "sk-soft-delete2"),
Name: "soft-delete2", Name: "soft-delete2",
@@ -86,15 +86,15 @@ func TestEntSoftDelete_ApiKey_DeleteIdempotent(t *testing.T) {
require.NoError(t, repo.Delete(ctx, key.ID), "second delete should be idempotent") require.NoError(t, repo.Delete(ctx, key.ID), "second delete should be idempotent")
} }
func TestEntSoftDelete_ApiKey_HardDeleteViaSkipSoftDelete(t *testing.T) { func TestEntSoftDelete_APIKey_HardDeleteViaSkipSoftDelete(t *testing.T) {
ctx := context.Background() ctx := context.Background()
// 使用全局 ent client确保 SkipSoftDelete 的硬删除语义可验证。 // 使用全局 ent client确保 SkipSoftDelete 的硬删除语义可验证。
client := testEntClient(t) client := testEntClient(t)
u := createEntUser(t, ctx, client, uniqueSoftDeleteValue(t, "sd-user3")+"@example.com") u := createEntUser(t, ctx, client, uniqueSoftDeleteValue(t, "sd-user3")+"@example.com")
repo := NewApiKeyRepository(client) repo := NewAPIKeyRepository(client)
key := &service.ApiKey{ key := &service.APIKey{
UserID: u.ID, UserID: u.ID,
Key: uniqueSoftDeleteValue(t, "sk-soft-delete3"), Key: uniqueSoftDeleteValue(t, "sk-soft-delete3"),
Name: "soft-delete3", Name: "soft-delete3",
@@ -105,10 +105,10 @@ func TestEntSoftDelete_ApiKey_HardDeleteViaSkipSoftDelete(t *testing.T) {
require.NoError(t, repo.Delete(ctx, key.ID), "soft delete api key") require.NoError(t, repo.Delete(ctx, key.ID), "soft delete api key")
// Hard delete using SkipSoftDelete so the hook doesn't convert it to update-deleted_at. // Hard delete using SkipSoftDelete so the hook doesn't convert it to update-deleted_at.
_, err := client.ApiKey.Delete().Where(apikey.IDEQ(key.ID)).Exec(mixins.SkipSoftDelete(ctx)) _, err := client.APIKey.Delete().Where(apikey.IDEQ(key.ID)).Exec(mixins.SkipSoftDelete(ctx))
require.NoError(t, err, "hard delete") require.NoError(t, err, "hard delete")
_, err = client.ApiKey.Query(). _, err = client.APIKey.Query().
Where(apikey.IDEQ(key.ID)). Where(apikey.IDEQ(key.ID)).
Only(mixins.SkipSoftDelete(ctx)) Only(mixins.SkipSoftDelete(ctx))
require.True(t, dbent.IsNotFound(err), "expected row to be hard deleted") require.True(t, dbent.IsNotFound(err), "expected row to be hard deleted")

View File

@@ -117,7 +117,7 @@ func (r *usageLogRepository) Create(ctx context.Context, log *service.UsageLog)
args := []any{ args := []any{
log.UserID, log.UserID,
log.ApiKeyID, log.APIKeyID,
log.AccountID, log.AccountID,
log.RequestID, log.RequestID,
log.Model, log.Model,
@@ -183,7 +183,7 @@ func (r *usageLogRepository) ListByUser(ctx context.Context, userID int64, param
return r.listUsageLogsWithPagination(ctx, "WHERE user_id = $1", []any{userID}, params) return r.listUsageLogsWithPagination(ctx, "WHERE user_id = $1", []any{userID}, params)
} }
func (r *usageLogRepository) ListByApiKey(ctx context.Context, apiKeyID int64, params pagination.PaginationParams) ([]service.UsageLog, *pagination.PaginationResult, error) { func (r *usageLogRepository) ListByAPIKey(ctx context.Context, apiKeyID int64, params pagination.PaginationParams) ([]service.UsageLog, *pagination.PaginationResult, error) {
return r.listUsageLogsWithPagination(ctx, "WHERE api_key_id = $1", []any{apiKeyID}, params) return r.listUsageLogsWithPagination(ctx, "WHERE api_key_id = $1", []any{apiKeyID}, params)
} }
@@ -270,8 +270,8 @@ func (r *usageLogRepository) GetDashboardStats(ctx context.Context) (*DashboardS
r.sql, r.sql,
apiKeyStatsQuery, apiKeyStatsQuery,
[]any{service.StatusActive}, []any{service.StatusActive},
&stats.TotalApiKeys, &stats.TotalAPIKeys,
&stats.ActiveApiKeys, &stats.ActiveAPIKeys,
); err != nil { ); err != nil {
return nil, err return nil, err
} }
@@ -418,8 +418,8 @@ func (r *usageLogRepository) GetUserStatsAggregated(ctx context.Context, userID
return &stats, nil return &stats, nil
} }
// GetApiKeyStatsAggregated returns aggregated usage statistics for an API key using database-level aggregation // GetAPIKeyStatsAggregated returns aggregated usage statistics for an API key using database-level aggregation
func (r *usageLogRepository) GetApiKeyStatsAggregated(ctx context.Context, apiKeyID int64, startTime, endTime time.Time) (*usagestats.UsageStats, error) { func (r *usageLogRepository) GetAPIKeyStatsAggregated(ctx context.Context, apiKeyID int64, startTime, endTime time.Time) (*usagestats.UsageStats, error) {
query := ` query := `
SELECT SELECT
COUNT(*) as total_requests, COUNT(*) as total_requests,
@@ -623,7 +623,7 @@ func resolveUsageStatsTimezone() string {
return "UTC" return "UTC"
} }
func (r *usageLogRepository) ListByApiKeyAndTimeRange(ctx context.Context, apiKeyID int64, startTime, endTime time.Time) ([]service.UsageLog, *pagination.PaginationResult, error) { func (r *usageLogRepository) ListByAPIKeyAndTimeRange(ctx context.Context, apiKeyID int64, startTime, endTime time.Time) ([]service.UsageLog, *pagination.PaginationResult, error) {
query := "SELECT " + usageLogSelectColumns + " FROM usage_logs WHERE api_key_id = $1 AND created_at >= $2 AND created_at < $3 ORDER BY id DESC" query := "SELECT " + usageLogSelectColumns + " FROM usage_logs WHERE api_key_id = $1 AND created_at >= $2 AND created_at < $3 ORDER BY id DESC"
logs, err := r.queryUsageLogs(ctx, query, apiKeyID, startTime, endTime) logs, err := r.queryUsageLogs(ctx, query, apiKeyID, startTime, endTime)
return logs, nil, err return logs, nil, err
@@ -709,11 +709,11 @@ type ModelStat = usagestats.ModelStat
// UserUsageTrendPoint represents user usage trend data point // UserUsageTrendPoint represents user usage trend data point
type UserUsageTrendPoint = usagestats.UserUsageTrendPoint type UserUsageTrendPoint = usagestats.UserUsageTrendPoint
// ApiKeyUsageTrendPoint represents API key usage trend data point // APIKeyUsageTrendPoint represents API key usage trend data point
type ApiKeyUsageTrendPoint = usagestats.ApiKeyUsageTrendPoint type APIKeyUsageTrendPoint = usagestats.APIKeyUsageTrendPoint
// GetApiKeyUsageTrend returns usage trend data grouped by API key and date // GetAPIKeyUsageTrend returns usage trend data grouped by API key and date
func (r *usageLogRepository) GetApiKeyUsageTrend(ctx context.Context, startTime, endTime time.Time, granularity string, limit int) (results []ApiKeyUsageTrendPoint, err error) { func (r *usageLogRepository) GetAPIKeyUsageTrend(ctx context.Context, startTime, endTime time.Time, granularity string, limit int) (results []APIKeyUsageTrendPoint, err error) {
dateFormat := "YYYY-MM-DD" dateFormat := "YYYY-MM-DD"
if granularity == "hour" { if granularity == "hour" {
dateFormat = "YYYY-MM-DD HH24:00" dateFormat = "YYYY-MM-DD HH24:00"
@@ -755,10 +755,10 @@ func (r *usageLogRepository) GetApiKeyUsageTrend(ctx context.Context, startTime,
} }
}() }()
results = make([]ApiKeyUsageTrendPoint, 0) results = make([]APIKeyUsageTrendPoint, 0)
for rows.Next() { for rows.Next() {
var row ApiKeyUsageTrendPoint var row APIKeyUsageTrendPoint
if err = rows.Scan(&row.Date, &row.ApiKeyID, &row.KeyName, &row.Requests, &row.Tokens); err != nil { if err = rows.Scan(&row.Date, &row.APIKeyID, &row.KeyName, &row.Requests, &row.Tokens); err != nil {
return nil, err return nil, err
} }
results = append(results, row) results = append(results, row)
@@ -844,7 +844,7 @@ func (r *usageLogRepository) GetUserDashboardStats(ctx context.Context, userID i
r.sql, r.sql,
"SELECT COUNT(*) FROM api_keys WHERE user_id = $1 AND deleted_at IS NULL", "SELECT COUNT(*) FROM api_keys WHERE user_id = $1 AND deleted_at IS NULL",
[]any{userID}, []any{userID},
&stats.TotalApiKeys, &stats.TotalAPIKeys,
); err != nil { ); err != nil {
return nil, err return nil, err
} }
@@ -853,7 +853,7 @@ func (r *usageLogRepository) GetUserDashboardStats(ctx context.Context, userID i
r.sql, r.sql,
"SELECT COUNT(*) FROM api_keys WHERE user_id = $1 AND status = $2 AND deleted_at IS NULL", "SELECT COUNT(*) FROM api_keys WHERE user_id = $1 AND status = $2 AND deleted_at IS NULL",
[]any{userID, service.StatusActive}, []any{userID, service.StatusActive},
&stats.ActiveApiKeys, &stats.ActiveAPIKeys,
); err != nil { ); err != nil {
return nil, err return nil, err
} }
@@ -1023,9 +1023,9 @@ func (r *usageLogRepository) ListWithFilters(ctx context.Context, params paginat
conditions = append(conditions, fmt.Sprintf("user_id = $%d", len(args)+1)) conditions = append(conditions, fmt.Sprintf("user_id = $%d", len(args)+1))
args = append(args, filters.UserID) args = append(args, filters.UserID)
} }
if filters.ApiKeyID > 0 { if filters.APIKeyID > 0 {
conditions = append(conditions, fmt.Sprintf("api_key_id = $%d", len(args)+1)) conditions = append(conditions, fmt.Sprintf("api_key_id = $%d", len(args)+1))
args = append(args, filters.ApiKeyID) args = append(args, filters.APIKeyID)
} }
if filters.AccountID > 0 { if filters.AccountID > 0 {
conditions = append(conditions, fmt.Sprintf("account_id = $%d", len(args)+1)) conditions = append(conditions, fmt.Sprintf("account_id = $%d", len(args)+1))
@@ -1145,18 +1145,18 @@ func (r *usageLogRepository) GetBatchUserUsageStats(ctx context.Context, userIDs
return result, nil return result, nil
} }
// BatchApiKeyUsageStats represents usage stats for a single API key // BatchAPIKeyUsageStats represents usage stats for a single API key
type BatchApiKeyUsageStats = usagestats.BatchApiKeyUsageStats type BatchAPIKeyUsageStats = usagestats.BatchAPIKeyUsageStats
// GetBatchApiKeyUsageStats gets today and total actual_cost for multiple API keys // GetBatchAPIKeyUsageStats gets today and total actual_cost for multiple API keys
func (r *usageLogRepository) GetBatchApiKeyUsageStats(ctx context.Context, apiKeyIDs []int64) (map[int64]*BatchApiKeyUsageStats, error) { func (r *usageLogRepository) GetBatchAPIKeyUsageStats(ctx context.Context, apiKeyIDs []int64) (map[int64]*BatchAPIKeyUsageStats, error) {
result := make(map[int64]*BatchApiKeyUsageStats) result := make(map[int64]*BatchAPIKeyUsageStats)
if len(apiKeyIDs) == 0 { if len(apiKeyIDs) == 0 {
return result, nil return result, nil
} }
for _, id := range apiKeyIDs { for _, id := range apiKeyIDs {
result[id] = &BatchApiKeyUsageStats{ApiKeyID: id} result[id] = &BatchAPIKeyUsageStats{APIKeyID: id}
} }
query := ` query := `
@@ -1582,7 +1582,7 @@ func (r *usageLogRepository) hydrateUsageLogAssociations(ctx context.Context, lo
if err != nil { if err != nil {
return err return err
} }
apiKeys, err := r.loadApiKeys(ctx, ids.apiKeyIDs) apiKeys, err := r.loadAPIKeys(ctx, ids.apiKeyIDs)
if err != nil { if err != nil {
return err return err
} }
@@ -1603,8 +1603,8 @@ func (r *usageLogRepository) hydrateUsageLogAssociations(ctx context.Context, lo
if user, ok := users[logs[i].UserID]; ok { if user, ok := users[logs[i].UserID]; ok {
logs[i].User = user logs[i].User = user
} }
if key, ok := apiKeys[logs[i].ApiKeyID]; ok { if key, ok := apiKeys[logs[i].APIKeyID]; ok {
logs[i].ApiKey = key logs[i].APIKey = key
} }
if acc, ok := accounts[logs[i].AccountID]; ok { if acc, ok := accounts[logs[i].AccountID]; ok {
logs[i].Account = acc logs[i].Account = acc
@@ -1642,7 +1642,7 @@ func collectUsageLogIDs(logs []service.UsageLog) usageLogIDs {
for i := range logs { for i := range logs {
userIDs[logs[i].UserID] = struct{}{} userIDs[logs[i].UserID] = struct{}{}
apiKeyIDs[logs[i].ApiKeyID] = struct{}{} apiKeyIDs[logs[i].APIKeyID] = struct{}{}
accountIDs[logs[i].AccountID] = struct{}{} accountIDs[logs[i].AccountID] = struct{}{}
if logs[i].GroupID != nil { if logs[i].GroupID != nil {
groupIDs[*logs[i].GroupID] = struct{}{} groupIDs[*logs[i].GroupID] = struct{}{}
@@ -1676,12 +1676,12 @@ func (r *usageLogRepository) loadUsers(ctx context.Context, ids []int64) (map[in
return out, nil return out, nil
} }
func (r *usageLogRepository) loadApiKeys(ctx context.Context, ids []int64) (map[int64]*service.ApiKey, error) { func (r *usageLogRepository) loadAPIKeys(ctx context.Context, ids []int64) (map[int64]*service.APIKey, error) {
out := make(map[int64]*service.ApiKey) out := make(map[int64]*service.APIKey)
if len(ids) == 0 { if len(ids) == 0 {
return out, nil return out, nil
} }
models, err := r.client.ApiKey.Query().Where(dbapikey.IDIn(ids...)).All(ctx) models, err := r.client.APIKey.Query().Where(dbapikey.IDIn(ids...)).All(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -1800,7 +1800,7 @@ func scanUsageLog(scanner interface{ Scan(...any) error }) (*service.UsageLog, e
log := &service.UsageLog{ log := &service.UsageLog{
ID: id, ID: id,
UserID: userID, UserID: userID,
ApiKeyID: apiKeyID, APIKeyID: apiKeyID,
AccountID: accountID, AccountID: accountID,
Model: model, Model: model,
InputTokens: inputTokens, InputTokens: inputTokens,

View File

@@ -35,10 +35,10 @@ func TestUsageLogRepoSuite(t *testing.T) {
suite.Run(t, new(UsageLogRepoSuite)) suite.Run(t, new(UsageLogRepoSuite))
} }
func (s *UsageLogRepoSuite) createUsageLog(user *service.User, apiKey *service.ApiKey, account *service.Account, inputTokens, outputTokens int, cost float64, createdAt time.Time) *service.UsageLog { func (s *UsageLogRepoSuite) createUsageLog(user *service.User, apiKey *service.APIKey, account *service.Account, inputTokens, outputTokens int, cost float64, createdAt time.Time) *service.UsageLog {
log := &service.UsageLog{ log := &service.UsageLog{
UserID: user.ID, UserID: user.ID,
ApiKeyID: apiKey.ID, APIKeyID: apiKey.ID,
AccountID: account.ID, AccountID: account.ID,
Model: "claude-3", Model: "claude-3",
InputTokens: inputTokens, InputTokens: inputTokens,
@@ -55,12 +55,12 @@ func (s *UsageLogRepoSuite) createUsageLog(user *service.User, apiKey *service.A
func (s *UsageLogRepoSuite) TestCreate() { func (s *UsageLogRepoSuite) TestCreate() {
user := mustCreateUser(s.T(), s.client, &service.User{Email: "create@test.com"}) user := mustCreateUser(s.T(), s.client, &service.User{Email: "create@test.com"})
apiKey := mustCreateApiKey(s.T(), s.client, &service.ApiKey{UserID: user.ID, Key: "sk-create", Name: "k"}) apiKey := mustCreateAPIKey(s.T(), s.client, &service.APIKey{UserID: user.ID, Key: "sk-create", Name: "k"})
account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-create"}) account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-create"})
log := &service.UsageLog{ log := &service.UsageLog{
UserID: user.ID, UserID: user.ID,
ApiKeyID: apiKey.ID, APIKeyID: apiKey.ID,
AccountID: account.ID, AccountID: account.ID,
Model: "claude-3", Model: "claude-3",
InputTokens: 10, InputTokens: 10,
@@ -76,7 +76,7 @@ func (s *UsageLogRepoSuite) TestCreate() {
func (s *UsageLogRepoSuite) TestGetByID() { func (s *UsageLogRepoSuite) TestGetByID() {
user := mustCreateUser(s.T(), s.client, &service.User{Email: "getbyid@test.com"}) user := mustCreateUser(s.T(), s.client, &service.User{Email: "getbyid@test.com"})
apiKey := mustCreateApiKey(s.T(), s.client, &service.ApiKey{UserID: user.ID, Key: "sk-getbyid", Name: "k"}) apiKey := mustCreateAPIKey(s.T(), s.client, &service.APIKey{UserID: user.ID, Key: "sk-getbyid", Name: "k"})
account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-getbyid"}) account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-getbyid"})
log := s.createUsageLog(user, apiKey, account, 10, 20, 0.5, time.Now()) log := s.createUsageLog(user, apiKey, account, 10, 20, 0.5, time.Now())
@@ -96,7 +96,7 @@ func (s *UsageLogRepoSuite) TestGetByID_NotFound() {
func (s *UsageLogRepoSuite) TestDelete() { func (s *UsageLogRepoSuite) TestDelete() {
user := mustCreateUser(s.T(), s.client, &service.User{Email: "delete@test.com"}) user := mustCreateUser(s.T(), s.client, &service.User{Email: "delete@test.com"})
apiKey := mustCreateApiKey(s.T(), s.client, &service.ApiKey{UserID: user.ID, Key: "sk-delete", Name: "k"}) apiKey := mustCreateAPIKey(s.T(), s.client, &service.APIKey{UserID: user.ID, Key: "sk-delete", Name: "k"})
account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-delete"}) account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-delete"})
log := s.createUsageLog(user, apiKey, account, 10, 20, 0.5, time.Now()) log := s.createUsageLog(user, apiKey, account, 10, 20, 0.5, time.Now())
@@ -112,7 +112,7 @@ func (s *UsageLogRepoSuite) TestDelete() {
func (s *UsageLogRepoSuite) TestListByUser() { func (s *UsageLogRepoSuite) TestListByUser() {
user := mustCreateUser(s.T(), s.client, &service.User{Email: "listbyuser@test.com"}) user := mustCreateUser(s.T(), s.client, &service.User{Email: "listbyuser@test.com"})
apiKey := mustCreateApiKey(s.T(), s.client, &service.ApiKey{UserID: user.ID, Key: "sk-listbyuser", Name: "k"}) apiKey := mustCreateAPIKey(s.T(), s.client, &service.APIKey{UserID: user.ID, Key: "sk-listbyuser", Name: "k"})
account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-listbyuser"}) account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-listbyuser"})
s.createUsageLog(user, apiKey, account, 10, 20, 0.5, time.Now()) s.createUsageLog(user, apiKey, account, 10, 20, 0.5, time.Now())
@@ -124,18 +124,18 @@ func (s *UsageLogRepoSuite) TestListByUser() {
s.Require().Equal(int64(2), page.Total) s.Require().Equal(int64(2), page.Total)
} }
// --- ListByApiKey --- // --- ListByAPIKey ---
func (s *UsageLogRepoSuite) TestListByApiKey() { func (s *UsageLogRepoSuite) TestListByAPIKey() {
user := mustCreateUser(s.T(), s.client, &service.User{Email: "listbyapikey@test.com"}) user := mustCreateUser(s.T(), s.client, &service.User{Email: "listbyapikey@test.com"})
apiKey := mustCreateApiKey(s.T(), s.client, &service.ApiKey{UserID: user.ID, Key: "sk-listbyapikey", Name: "k"}) apiKey := mustCreateAPIKey(s.T(), s.client, &service.APIKey{UserID: user.ID, Key: "sk-listbyapikey", Name: "k"})
account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-listbyapikey"}) account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-listbyapikey"})
s.createUsageLog(user, apiKey, account, 10, 20, 0.5, time.Now()) s.createUsageLog(user, apiKey, account, 10, 20, 0.5, time.Now())
s.createUsageLog(user, apiKey, account, 15, 25, 0.6, time.Now()) s.createUsageLog(user, apiKey, account, 15, 25, 0.6, time.Now())
logs, page, err := s.repo.ListByApiKey(s.ctx, apiKey.ID, pagination.PaginationParams{Page: 1, PageSize: 10}) logs, page, err := s.repo.ListByAPIKey(s.ctx, apiKey.ID, pagination.PaginationParams{Page: 1, PageSize: 10})
s.Require().NoError(err, "ListByApiKey") s.Require().NoError(err, "ListByAPIKey")
s.Require().Len(logs, 2) s.Require().Len(logs, 2)
s.Require().Equal(int64(2), page.Total) s.Require().Equal(int64(2), page.Total)
} }
@@ -144,7 +144,7 @@ func (s *UsageLogRepoSuite) TestListByApiKey() {
func (s *UsageLogRepoSuite) TestListByAccount() { func (s *UsageLogRepoSuite) TestListByAccount() {
user := mustCreateUser(s.T(), s.client, &service.User{Email: "listbyaccount@test.com"}) user := mustCreateUser(s.T(), s.client, &service.User{Email: "listbyaccount@test.com"})
apiKey := mustCreateApiKey(s.T(), s.client, &service.ApiKey{UserID: user.ID, Key: "sk-listbyaccount", Name: "k"}) apiKey := mustCreateAPIKey(s.T(), s.client, &service.APIKey{UserID: user.ID, Key: "sk-listbyaccount", Name: "k"})
account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-listbyaccount"}) account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-listbyaccount"})
s.createUsageLog(user, apiKey, account, 10, 20, 0.5, time.Now()) s.createUsageLog(user, apiKey, account, 10, 20, 0.5, time.Now())
@@ -159,7 +159,7 @@ func (s *UsageLogRepoSuite) TestListByAccount() {
func (s *UsageLogRepoSuite) TestGetUserStats() { func (s *UsageLogRepoSuite) TestGetUserStats() {
user := mustCreateUser(s.T(), s.client, &service.User{Email: "userstats@test.com"}) user := mustCreateUser(s.T(), s.client, &service.User{Email: "userstats@test.com"})
apiKey := mustCreateApiKey(s.T(), s.client, &service.ApiKey{UserID: user.ID, Key: "sk-userstats", Name: "k"}) apiKey := mustCreateAPIKey(s.T(), s.client, &service.APIKey{UserID: user.ID, Key: "sk-userstats", Name: "k"})
account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-userstats"}) account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-userstats"})
base := time.Date(2025, 1, 15, 12, 0, 0, 0, time.UTC) base := time.Date(2025, 1, 15, 12, 0, 0, 0, time.UTC)
@@ -179,7 +179,7 @@ func (s *UsageLogRepoSuite) TestGetUserStats() {
func (s *UsageLogRepoSuite) TestListWithFilters() { func (s *UsageLogRepoSuite) TestListWithFilters() {
user := mustCreateUser(s.T(), s.client, &service.User{Email: "filters@test.com"}) user := mustCreateUser(s.T(), s.client, &service.User{Email: "filters@test.com"})
apiKey := mustCreateApiKey(s.T(), s.client, &service.ApiKey{UserID: user.ID, Key: "sk-filters", Name: "k"}) apiKey := mustCreateAPIKey(s.T(), s.client, &service.APIKey{UserID: user.ID, Key: "sk-filters", Name: "k"})
account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-filters"}) account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-filters"})
s.createUsageLog(user, apiKey, account, 10, 20, 0.5, time.Now()) s.createUsageLog(user, apiKey, account, 10, 20, 0.5, time.Now())
@@ -211,8 +211,8 @@ func (s *UsageLogRepoSuite) TestDashboardStats_TodayTotalsAndPerformance() {
}) })
group := mustCreateGroup(s.T(), s.client, &service.Group{Name: "g-ul"}) group := mustCreateGroup(s.T(), s.client, &service.Group{Name: "g-ul"})
apiKey1 := mustCreateApiKey(s.T(), s.client, &service.ApiKey{UserID: userToday.ID, Key: "sk-ul-1", Name: "ul1"}) apiKey1 := mustCreateAPIKey(s.T(), s.client, &service.APIKey{UserID: userToday.ID, Key: "sk-ul-1", Name: "ul1"})
mustCreateApiKey(s.T(), s.client, &service.ApiKey{UserID: userOld.ID, Key: "sk-ul-2", Name: "ul2", Status: service.StatusDisabled}) mustCreateAPIKey(s.T(), s.client, &service.APIKey{UserID: userOld.ID, Key: "sk-ul-2", Name: "ul2", Status: service.StatusDisabled})
resetAt := now.Add(10 * time.Minute) resetAt := now.Add(10 * time.Minute)
accNormal := mustCreateAccount(s.T(), s.client, &service.Account{Name: "a-normal", Schedulable: true}) accNormal := mustCreateAccount(s.T(), s.client, &service.Account{Name: "a-normal", Schedulable: true})
@@ -223,7 +223,7 @@ func (s *UsageLogRepoSuite) TestDashboardStats_TodayTotalsAndPerformance() {
d1, d2, d3 := 100, 200, 300 d1, d2, d3 := 100, 200, 300
logToday := &service.UsageLog{ logToday := &service.UsageLog{
UserID: userToday.ID, UserID: userToday.ID,
ApiKeyID: apiKey1.ID, APIKeyID: apiKey1.ID,
AccountID: accNormal.ID, AccountID: accNormal.ID,
Model: "claude-3", Model: "claude-3",
GroupID: &group.ID, GroupID: &group.ID,
@@ -240,7 +240,7 @@ func (s *UsageLogRepoSuite) TestDashboardStats_TodayTotalsAndPerformance() {
logOld := &service.UsageLog{ logOld := &service.UsageLog{
UserID: userOld.ID, UserID: userOld.ID,
ApiKeyID: apiKey1.ID, APIKeyID: apiKey1.ID,
AccountID: accNormal.ID, AccountID: accNormal.ID,
Model: "claude-3", Model: "claude-3",
InputTokens: 5, InputTokens: 5,
@@ -254,7 +254,7 @@ func (s *UsageLogRepoSuite) TestDashboardStats_TodayTotalsAndPerformance() {
logPerf := &service.UsageLog{ logPerf := &service.UsageLog{
UserID: userToday.ID, UserID: userToday.ID,
ApiKeyID: apiKey1.ID, APIKeyID: apiKey1.ID,
AccountID: accNormal.ID, AccountID: accNormal.ID,
Model: "claude-3", Model: "claude-3",
InputTokens: 1, InputTokens: 1,
@@ -272,8 +272,8 @@ func (s *UsageLogRepoSuite) TestDashboardStats_TodayTotalsAndPerformance() {
s.Require().Equal(baseStats.TotalUsers+2, stats.TotalUsers, "TotalUsers mismatch") s.Require().Equal(baseStats.TotalUsers+2, stats.TotalUsers, "TotalUsers mismatch")
s.Require().Equal(baseStats.TodayNewUsers+1, stats.TodayNewUsers, "TodayNewUsers mismatch") s.Require().Equal(baseStats.TodayNewUsers+1, stats.TodayNewUsers, "TodayNewUsers mismatch")
s.Require().Equal(baseStats.ActiveUsers+1, stats.ActiveUsers, "ActiveUsers mismatch") s.Require().Equal(baseStats.ActiveUsers+1, stats.ActiveUsers, "ActiveUsers mismatch")
s.Require().Equal(baseStats.TotalApiKeys+2, stats.TotalApiKeys, "TotalApiKeys mismatch") s.Require().Equal(baseStats.TotalAPIKeys+2, stats.TotalAPIKeys, "TotalAPIKeys mismatch")
s.Require().Equal(baseStats.ActiveApiKeys+1, stats.ActiveApiKeys, "ActiveApiKeys mismatch") s.Require().Equal(baseStats.ActiveAPIKeys+1, stats.ActiveAPIKeys, "ActiveAPIKeys mismatch")
s.Require().Equal(baseStats.TotalAccounts+4, stats.TotalAccounts, "TotalAccounts mismatch") s.Require().Equal(baseStats.TotalAccounts+4, stats.TotalAccounts, "TotalAccounts mismatch")
s.Require().Equal(baseStats.ErrorAccounts+1, stats.ErrorAccounts, "ErrorAccounts mismatch") s.Require().Equal(baseStats.ErrorAccounts+1, stats.ErrorAccounts, "ErrorAccounts mismatch")
s.Require().Equal(baseStats.RateLimitAccounts+1, stats.RateLimitAccounts, "RateLimitAccounts mismatch") s.Require().Equal(baseStats.RateLimitAccounts+1, stats.RateLimitAccounts, "RateLimitAccounts mismatch")
@@ -300,14 +300,14 @@ func (s *UsageLogRepoSuite) TestDashboardStats_TodayTotalsAndPerformance() {
func (s *UsageLogRepoSuite) TestGetUserDashboardStats() { func (s *UsageLogRepoSuite) TestGetUserDashboardStats() {
user := mustCreateUser(s.T(), s.client, &service.User{Email: "userdash@test.com"}) user := mustCreateUser(s.T(), s.client, &service.User{Email: "userdash@test.com"})
apiKey := mustCreateApiKey(s.T(), s.client, &service.ApiKey{UserID: user.ID, Key: "sk-userdash", Name: "k"}) apiKey := mustCreateAPIKey(s.T(), s.client, &service.APIKey{UserID: user.ID, Key: "sk-userdash", Name: "k"})
account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-userdash"}) account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-userdash"})
s.createUsageLog(user, apiKey, account, 10, 20, 0.5, time.Now()) s.createUsageLog(user, apiKey, account, 10, 20, 0.5, time.Now())
stats, err := s.repo.GetUserDashboardStats(s.ctx, user.ID) stats, err := s.repo.GetUserDashboardStats(s.ctx, user.ID)
s.Require().NoError(err, "GetUserDashboardStats") s.Require().NoError(err, "GetUserDashboardStats")
s.Require().Equal(int64(1), stats.TotalApiKeys) s.Require().Equal(int64(1), stats.TotalAPIKeys)
s.Require().Equal(int64(1), stats.TotalRequests) s.Require().Equal(int64(1), stats.TotalRequests)
} }
@@ -315,7 +315,7 @@ func (s *UsageLogRepoSuite) TestGetUserDashboardStats() {
func (s *UsageLogRepoSuite) TestGetAccountTodayStats() { func (s *UsageLogRepoSuite) TestGetAccountTodayStats() {
user := mustCreateUser(s.T(), s.client, &service.User{Email: "acctoday@test.com"}) user := mustCreateUser(s.T(), s.client, &service.User{Email: "acctoday@test.com"})
apiKey := mustCreateApiKey(s.T(), s.client, &service.ApiKey{UserID: user.ID, Key: "sk-acctoday", Name: "k"}) apiKey := mustCreateAPIKey(s.T(), s.client, &service.APIKey{UserID: user.ID, Key: "sk-acctoday", Name: "k"})
account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-today"}) account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-today"})
s.createUsageLog(user, apiKey, account, 10, 20, 0.5, time.Now()) s.createUsageLog(user, apiKey, account, 10, 20, 0.5, time.Now())
@@ -331,8 +331,8 @@ func (s *UsageLogRepoSuite) TestGetAccountTodayStats() {
func (s *UsageLogRepoSuite) TestGetBatchUserUsageStats() { func (s *UsageLogRepoSuite) TestGetBatchUserUsageStats() {
user1 := mustCreateUser(s.T(), s.client, &service.User{Email: "batch1@test.com"}) user1 := mustCreateUser(s.T(), s.client, &service.User{Email: "batch1@test.com"})
user2 := mustCreateUser(s.T(), s.client, &service.User{Email: "batch2@test.com"}) user2 := mustCreateUser(s.T(), s.client, &service.User{Email: "batch2@test.com"})
apiKey1 := mustCreateApiKey(s.T(), s.client, &service.ApiKey{UserID: user1.ID, Key: "sk-batch1", Name: "k"}) apiKey1 := mustCreateAPIKey(s.T(), s.client, &service.APIKey{UserID: user1.ID, Key: "sk-batch1", Name: "k"})
apiKey2 := mustCreateApiKey(s.T(), s.client, &service.ApiKey{UserID: user2.ID, Key: "sk-batch2", Name: "k"}) apiKey2 := mustCreateAPIKey(s.T(), s.client, &service.APIKey{UserID: user2.ID, Key: "sk-batch2", Name: "k"})
account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-batch"}) account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-batch"})
s.createUsageLog(user1, apiKey1, account, 10, 20, 0.5, time.Now()) s.createUsageLog(user1, apiKey1, account, 10, 20, 0.5, time.Now())
@@ -351,24 +351,24 @@ func (s *UsageLogRepoSuite) TestGetBatchUserUsageStats_Empty() {
s.Require().Empty(stats) s.Require().Empty(stats)
} }
// --- GetBatchApiKeyUsageStats --- // --- GetBatchAPIKeyUsageStats ---
func (s *UsageLogRepoSuite) TestGetBatchApiKeyUsageStats() { func (s *UsageLogRepoSuite) TestGetBatchAPIKeyUsageStats() {
user := mustCreateUser(s.T(), s.client, &service.User{Email: "batchkey@test.com"}) user := mustCreateUser(s.T(), s.client, &service.User{Email: "batchkey@test.com"})
apiKey1 := mustCreateApiKey(s.T(), s.client, &service.ApiKey{UserID: user.ID, Key: "sk-batchkey1", Name: "k1"}) apiKey1 := mustCreateAPIKey(s.T(), s.client, &service.APIKey{UserID: user.ID, Key: "sk-batchkey1", Name: "k1"})
apiKey2 := mustCreateApiKey(s.T(), s.client, &service.ApiKey{UserID: user.ID, Key: "sk-batchkey2", Name: "k2"}) apiKey2 := mustCreateAPIKey(s.T(), s.client, &service.APIKey{UserID: user.ID, Key: "sk-batchkey2", Name: "k2"})
account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-batchkey"}) account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-batchkey"})
s.createUsageLog(user, apiKey1, account, 10, 20, 0.5, time.Now()) s.createUsageLog(user, apiKey1, account, 10, 20, 0.5, time.Now())
s.createUsageLog(user, apiKey2, account, 15, 25, 0.6, time.Now()) s.createUsageLog(user, apiKey2, account, 15, 25, 0.6, time.Now())
stats, err := s.repo.GetBatchApiKeyUsageStats(s.ctx, []int64{apiKey1.ID, apiKey2.ID}) stats, err := s.repo.GetBatchAPIKeyUsageStats(s.ctx, []int64{apiKey1.ID, apiKey2.ID})
s.Require().NoError(err, "GetBatchApiKeyUsageStats") s.Require().NoError(err, "GetBatchAPIKeyUsageStats")
s.Require().Len(stats, 2) s.Require().Len(stats, 2)
} }
func (s *UsageLogRepoSuite) TestGetBatchApiKeyUsageStats_Empty() { func (s *UsageLogRepoSuite) TestGetBatchAPIKeyUsageStats_Empty() {
stats, err := s.repo.GetBatchApiKeyUsageStats(s.ctx, []int64{}) stats, err := s.repo.GetBatchAPIKeyUsageStats(s.ctx, []int64{})
s.Require().NoError(err) s.Require().NoError(err)
s.Require().Empty(stats) s.Require().Empty(stats)
} }
@@ -377,7 +377,7 @@ func (s *UsageLogRepoSuite) TestGetBatchApiKeyUsageStats_Empty() {
func (s *UsageLogRepoSuite) TestGetGlobalStats() { func (s *UsageLogRepoSuite) TestGetGlobalStats() {
user := mustCreateUser(s.T(), s.client, &service.User{Email: "global@test.com"}) user := mustCreateUser(s.T(), s.client, &service.User{Email: "global@test.com"})
apiKey := mustCreateApiKey(s.T(), s.client, &service.ApiKey{UserID: user.ID, Key: "sk-global", Name: "k"}) apiKey := mustCreateAPIKey(s.T(), s.client, &service.APIKey{UserID: user.ID, Key: "sk-global", Name: "k"})
account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-global"}) account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-global"})
base := time.Date(2025, 1, 15, 12, 0, 0, 0, time.UTC) base := time.Date(2025, 1, 15, 12, 0, 0, 0, time.UTC)
@@ -402,7 +402,7 @@ func maxTime(a, b time.Time) time.Time {
func (s *UsageLogRepoSuite) TestListByUserAndTimeRange() { func (s *UsageLogRepoSuite) TestListByUserAndTimeRange() {
user := mustCreateUser(s.T(), s.client, &service.User{Email: "timerange@test.com"}) user := mustCreateUser(s.T(), s.client, &service.User{Email: "timerange@test.com"})
apiKey := mustCreateApiKey(s.T(), s.client, &service.ApiKey{UserID: user.ID, Key: "sk-timerange", Name: "k"}) apiKey := mustCreateAPIKey(s.T(), s.client, &service.APIKey{UserID: user.ID, Key: "sk-timerange", Name: "k"})
account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-timerange"}) account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-timerange"})
base := time.Date(2025, 1, 15, 12, 0, 0, 0, time.UTC) base := time.Date(2025, 1, 15, 12, 0, 0, 0, time.UTC)
@@ -417,11 +417,11 @@ func (s *UsageLogRepoSuite) TestListByUserAndTimeRange() {
s.Require().Len(logs, 2) s.Require().Len(logs, 2)
} }
// --- ListByApiKeyAndTimeRange --- // --- ListByAPIKeyAndTimeRange ---
func (s *UsageLogRepoSuite) TestListByApiKeyAndTimeRange() { func (s *UsageLogRepoSuite) TestListByAPIKeyAndTimeRange() {
user := mustCreateUser(s.T(), s.client, &service.User{Email: "keytimerange@test.com"}) user := mustCreateUser(s.T(), s.client, &service.User{Email: "keytimerange@test.com"})
apiKey := mustCreateApiKey(s.T(), s.client, &service.ApiKey{UserID: user.ID, Key: "sk-keytimerange", Name: "k"}) apiKey := mustCreateAPIKey(s.T(), s.client, &service.APIKey{UserID: user.ID, Key: "sk-keytimerange", Name: "k"})
account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-keytimerange"}) account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-keytimerange"})
base := time.Date(2025, 1, 15, 12, 0, 0, 0, time.UTC) base := time.Date(2025, 1, 15, 12, 0, 0, 0, time.UTC)
@@ -431,8 +431,8 @@ func (s *UsageLogRepoSuite) TestListByApiKeyAndTimeRange() {
startTime := base.Add(-1 * time.Hour) startTime := base.Add(-1 * time.Hour)
endTime := base.Add(2 * time.Hour) endTime := base.Add(2 * time.Hour)
logs, _, err := s.repo.ListByApiKeyAndTimeRange(s.ctx, apiKey.ID, startTime, endTime) logs, _, err := s.repo.ListByAPIKeyAndTimeRange(s.ctx, apiKey.ID, startTime, endTime)
s.Require().NoError(err, "ListByApiKeyAndTimeRange") s.Require().NoError(err, "ListByAPIKeyAndTimeRange")
s.Require().Len(logs, 2) s.Require().Len(logs, 2)
} }
@@ -440,7 +440,7 @@ func (s *UsageLogRepoSuite) TestListByApiKeyAndTimeRange() {
func (s *UsageLogRepoSuite) TestListByAccountAndTimeRange() { func (s *UsageLogRepoSuite) TestListByAccountAndTimeRange() {
user := mustCreateUser(s.T(), s.client, &service.User{Email: "acctimerange@test.com"}) user := mustCreateUser(s.T(), s.client, &service.User{Email: "acctimerange@test.com"})
apiKey := mustCreateApiKey(s.T(), s.client, &service.ApiKey{UserID: user.ID, Key: "sk-acctimerange", Name: "k"}) apiKey := mustCreateAPIKey(s.T(), s.client, &service.APIKey{UserID: user.ID, Key: "sk-acctimerange", Name: "k"})
account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-acctimerange"}) account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-acctimerange"})
base := time.Date(2025, 1, 15, 12, 0, 0, 0, time.UTC) base := time.Date(2025, 1, 15, 12, 0, 0, 0, time.UTC)
@@ -459,7 +459,7 @@ func (s *UsageLogRepoSuite) TestListByAccountAndTimeRange() {
func (s *UsageLogRepoSuite) TestListByModelAndTimeRange() { func (s *UsageLogRepoSuite) TestListByModelAndTimeRange() {
user := mustCreateUser(s.T(), s.client, &service.User{Email: "modeltimerange@test.com"}) user := mustCreateUser(s.T(), s.client, &service.User{Email: "modeltimerange@test.com"})
apiKey := mustCreateApiKey(s.T(), s.client, &service.ApiKey{UserID: user.ID, Key: "sk-modeltimerange", Name: "k"}) apiKey := mustCreateAPIKey(s.T(), s.client, &service.APIKey{UserID: user.ID, Key: "sk-modeltimerange", Name: "k"})
account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-modeltimerange"}) account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-modeltimerange"})
base := time.Date(2025, 1, 15, 12, 0, 0, 0, time.UTC) base := time.Date(2025, 1, 15, 12, 0, 0, 0, time.UTC)
@@ -467,7 +467,7 @@ func (s *UsageLogRepoSuite) TestListByModelAndTimeRange() {
// Create logs with different models // Create logs with different models
log1 := &service.UsageLog{ log1 := &service.UsageLog{
UserID: user.ID, UserID: user.ID,
ApiKeyID: apiKey.ID, APIKeyID: apiKey.ID,
AccountID: account.ID, AccountID: account.ID,
Model: "claude-3-opus", Model: "claude-3-opus",
InputTokens: 10, InputTokens: 10,
@@ -480,7 +480,7 @@ func (s *UsageLogRepoSuite) TestListByModelAndTimeRange() {
log2 := &service.UsageLog{ log2 := &service.UsageLog{
UserID: user.ID, UserID: user.ID,
ApiKeyID: apiKey.ID, APIKeyID: apiKey.ID,
AccountID: account.ID, AccountID: account.ID,
Model: "claude-3-opus", Model: "claude-3-opus",
InputTokens: 15, InputTokens: 15,
@@ -493,7 +493,7 @@ func (s *UsageLogRepoSuite) TestListByModelAndTimeRange() {
log3 := &service.UsageLog{ log3 := &service.UsageLog{
UserID: user.ID, UserID: user.ID,
ApiKeyID: apiKey.ID, APIKeyID: apiKey.ID,
AccountID: account.ID, AccountID: account.ID,
Model: "claude-3-sonnet", Model: "claude-3-sonnet",
InputTokens: 20, InputTokens: 20,
@@ -515,7 +515,7 @@ func (s *UsageLogRepoSuite) TestListByModelAndTimeRange() {
func (s *UsageLogRepoSuite) TestGetAccountWindowStats() { func (s *UsageLogRepoSuite) TestGetAccountWindowStats() {
user := mustCreateUser(s.T(), s.client, &service.User{Email: "windowstats@test.com"}) user := mustCreateUser(s.T(), s.client, &service.User{Email: "windowstats@test.com"})
apiKey := mustCreateApiKey(s.T(), s.client, &service.ApiKey{UserID: user.ID, Key: "sk-windowstats", Name: "k"}) apiKey := mustCreateAPIKey(s.T(), s.client, &service.APIKey{UserID: user.ID, Key: "sk-windowstats", Name: "k"})
account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-windowstats"}) account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-windowstats"})
now := time.Now() now := time.Now()
@@ -535,7 +535,7 @@ func (s *UsageLogRepoSuite) TestGetAccountWindowStats() {
func (s *UsageLogRepoSuite) TestGetUserUsageTrendByUserID() { func (s *UsageLogRepoSuite) TestGetUserUsageTrendByUserID() {
user := mustCreateUser(s.T(), s.client, &service.User{Email: "usertrend@test.com"}) user := mustCreateUser(s.T(), s.client, &service.User{Email: "usertrend@test.com"})
apiKey := mustCreateApiKey(s.T(), s.client, &service.ApiKey{UserID: user.ID, Key: "sk-usertrend", Name: "k"}) apiKey := mustCreateAPIKey(s.T(), s.client, &service.APIKey{UserID: user.ID, Key: "sk-usertrend", Name: "k"})
account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-usertrend"}) account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-usertrend"})
base := time.Date(2025, 1, 15, 12, 0, 0, 0, time.UTC) base := time.Date(2025, 1, 15, 12, 0, 0, 0, time.UTC)
@@ -552,7 +552,7 @@ func (s *UsageLogRepoSuite) TestGetUserUsageTrendByUserID() {
func (s *UsageLogRepoSuite) TestGetUserUsageTrendByUserID_HourlyGranularity() { func (s *UsageLogRepoSuite) TestGetUserUsageTrendByUserID_HourlyGranularity() {
user := mustCreateUser(s.T(), s.client, &service.User{Email: "usertrendhourly@test.com"}) user := mustCreateUser(s.T(), s.client, &service.User{Email: "usertrendhourly@test.com"})
apiKey := mustCreateApiKey(s.T(), s.client, &service.ApiKey{UserID: user.ID, Key: "sk-usertrendhourly", Name: "k"}) apiKey := mustCreateAPIKey(s.T(), s.client, &service.APIKey{UserID: user.ID, Key: "sk-usertrendhourly", Name: "k"})
account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-usertrendhourly"}) account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-usertrendhourly"})
base := time.Date(2025, 1, 15, 12, 0, 0, 0, time.UTC) base := time.Date(2025, 1, 15, 12, 0, 0, 0, time.UTC)
@@ -571,7 +571,7 @@ func (s *UsageLogRepoSuite) TestGetUserUsageTrendByUserID_HourlyGranularity() {
func (s *UsageLogRepoSuite) TestGetUserModelStats() { func (s *UsageLogRepoSuite) TestGetUserModelStats() {
user := mustCreateUser(s.T(), s.client, &service.User{Email: "modelstats@test.com"}) user := mustCreateUser(s.T(), s.client, &service.User{Email: "modelstats@test.com"})
apiKey := mustCreateApiKey(s.T(), s.client, &service.ApiKey{UserID: user.ID, Key: "sk-modelstats", Name: "k"}) apiKey := mustCreateAPIKey(s.T(), s.client, &service.APIKey{UserID: user.ID, Key: "sk-modelstats", Name: "k"})
account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-modelstats"}) account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-modelstats"})
base := time.Date(2025, 1, 15, 12, 0, 0, 0, time.UTC) base := time.Date(2025, 1, 15, 12, 0, 0, 0, time.UTC)
@@ -579,7 +579,7 @@ func (s *UsageLogRepoSuite) TestGetUserModelStats() {
// Create logs with different models // Create logs with different models
log1 := &service.UsageLog{ log1 := &service.UsageLog{
UserID: user.ID, UserID: user.ID,
ApiKeyID: apiKey.ID, APIKeyID: apiKey.ID,
AccountID: account.ID, AccountID: account.ID,
Model: "claude-3-opus", Model: "claude-3-opus",
InputTokens: 100, InputTokens: 100,
@@ -592,7 +592,7 @@ func (s *UsageLogRepoSuite) TestGetUserModelStats() {
log2 := &service.UsageLog{ log2 := &service.UsageLog{
UserID: user.ID, UserID: user.ID,
ApiKeyID: apiKey.ID, APIKeyID: apiKey.ID,
AccountID: account.ID, AccountID: account.ID,
Model: "claude-3-sonnet", Model: "claude-3-sonnet",
InputTokens: 50, InputTokens: 50,
@@ -618,7 +618,7 @@ func (s *UsageLogRepoSuite) TestGetUserModelStats() {
func (s *UsageLogRepoSuite) TestGetUsageTrendWithFilters() { func (s *UsageLogRepoSuite) TestGetUsageTrendWithFilters() {
user := mustCreateUser(s.T(), s.client, &service.User{Email: "trendfilters@test.com"}) user := mustCreateUser(s.T(), s.client, &service.User{Email: "trendfilters@test.com"})
apiKey := mustCreateApiKey(s.T(), s.client, &service.ApiKey{UserID: user.ID, Key: "sk-trendfilters", Name: "k"}) apiKey := mustCreateAPIKey(s.T(), s.client, &service.APIKey{UserID: user.ID, Key: "sk-trendfilters", Name: "k"})
account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-trendfilters"}) account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-trendfilters"})
base := time.Date(2025, 1, 15, 12, 0, 0, 0, time.UTC) base := time.Date(2025, 1, 15, 12, 0, 0, 0, time.UTC)
@@ -646,7 +646,7 @@ func (s *UsageLogRepoSuite) TestGetUsageTrendWithFilters() {
func (s *UsageLogRepoSuite) TestGetUsageTrendWithFilters_HourlyGranularity() { func (s *UsageLogRepoSuite) TestGetUsageTrendWithFilters_HourlyGranularity() {
user := mustCreateUser(s.T(), s.client, &service.User{Email: "trendfilters-h@test.com"}) user := mustCreateUser(s.T(), s.client, &service.User{Email: "trendfilters-h@test.com"})
apiKey := mustCreateApiKey(s.T(), s.client, &service.ApiKey{UserID: user.ID, Key: "sk-trendfilters-h", Name: "k"}) apiKey := mustCreateAPIKey(s.T(), s.client, &service.APIKey{UserID: user.ID, Key: "sk-trendfilters-h", Name: "k"})
account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-trendfilters-h"}) account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-trendfilters-h"})
base := time.Date(2025, 1, 15, 12, 0, 0, 0, time.UTC) base := time.Date(2025, 1, 15, 12, 0, 0, 0, time.UTC)
@@ -665,14 +665,14 @@ func (s *UsageLogRepoSuite) TestGetUsageTrendWithFilters_HourlyGranularity() {
func (s *UsageLogRepoSuite) TestGetModelStatsWithFilters() { func (s *UsageLogRepoSuite) TestGetModelStatsWithFilters() {
user := mustCreateUser(s.T(), s.client, &service.User{Email: "modelfilters@test.com"}) user := mustCreateUser(s.T(), s.client, &service.User{Email: "modelfilters@test.com"})
apiKey := mustCreateApiKey(s.T(), s.client, &service.ApiKey{UserID: user.ID, Key: "sk-modelfilters", Name: "k"}) apiKey := mustCreateAPIKey(s.T(), s.client, &service.APIKey{UserID: user.ID, Key: "sk-modelfilters", Name: "k"})
account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-modelfilters"}) account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-modelfilters"})
base := time.Date(2025, 1, 15, 12, 0, 0, 0, time.UTC) base := time.Date(2025, 1, 15, 12, 0, 0, 0, time.UTC)
log1 := &service.UsageLog{ log1 := &service.UsageLog{
UserID: user.ID, UserID: user.ID,
ApiKeyID: apiKey.ID, APIKeyID: apiKey.ID,
AccountID: account.ID, AccountID: account.ID,
Model: "claude-3-opus", Model: "claude-3-opus",
InputTokens: 100, InputTokens: 100,
@@ -685,7 +685,7 @@ func (s *UsageLogRepoSuite) TestGetModelStatsWithFilters() {
log2 := &service.UsageLog{ log2 := &service.UsageLog{
UserID: user.ID, UserID: user.ID,
ApiKeyID: apiKey.ID, APIKeyID: apiKey.ID,
AccountID: account.ID, AccountID: account.ID,
Model: "claude-3-sonnet", Model: "claude-3-sonnet",
InputTokens: 50, InputTokens: 50,
@@ -719,7 +719,7 @@ func (s *UsageLogRepoSuite) TestGetModelStatsWithFilters() {
func (s *UsageLogRepoSuite) TestGetAccountUsageStats() { func (s *UsageLogRepoSuite) TestGetAccountUsageStats() {
user := mustCreateUser(s.T(), s.client, &service.User{Email: "accstats@test.com"}) user := mustCreateUser(s.T(), s.client, &service.User{Email: "accstats@test.com"})
apiKey := mustCreateApiKey(s.T(), s.client, &service.ApiKey{UserID: user.ID, Key: "sk-accstats", Name: "k"}) apiKey := mustCreateAPIKey(s.T(), s.client, &service.APIKey{UserID: user.ID, Key: "sk-accstats", Name: "k"})
account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-accstats"}) account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-accstats"})
base := time.Date(2025, 1, 15, 0, 0, 0, 0, time.UTC) base := time.Date(2025, 1, 15, 0, 0, 0, 0, time.UTC)
@@ -727,7 +727,7 @@ func (s *UsageLogRepoSuite) TestGetAccountUsageStats() {
// Create logs on different days // Create logs on different days
log1 := &service.UsageLog{ log1 := &service.UsageLog{
UserID: user.ID, UserID: user.ID,
ApiKeyID: apiKey.ID, APIKeyID: apiKey.ID,
AccountID: account.ID, AccountID: account.ID,
Model: "claude-3-opus", Model: "claude-3-opus",
InputTokens: 100, InputTokens: 100,
@@ -740,7 +740,7 @@ func (s *UsageLogRepoSuite) TestGetAccountUsageStats() {
log2 := &service.UsageLog{ log2 := &service.UsageLog{
UserID: user.ID, UserID: user.ID,
ApiKeyID: apiKey.ID, APIKeyID: apiKey.ID,
AccountID: account.ID, AccountID: account.ID,
Model: "claude-3-sonnet", Model: "claude-3-sonnet",
InputTokens: 50, InputTokens: 50,
@@ -782,8 +782,8 @@ func (s *UsageLogRepoSuite) TestGetAccountUsageStats_EmptyRange() {
func (s *UsageLogRepoSuite) TestGetUserUsageTrend() { func (s *UsageLogRepoSuite) TestGetUserUsageTrend() {
user1 := mustCreateUser(s.T(), s.client, &service.User{Email: "usertrend1@test.com"}) user1 := mustCreateUser(s.T(), s.client, &service.User{Email: "usertrend1@test.com"})
user2 := mustCreateUser(s.T(), s.client, &service.User{Email: "usertrend2@test.com"}) user2 := mustCreateUser(s.T(), s.client, &service.User{Email: "usertrend2@test.com"})
apiKey1 := mustCreateApiKey(s.T(), s.client, &service.ApiKey{UserID: user1.ID, Key: "sk-usertrend1", Name: "k1"}) apiKey1 := mustCreateAPIKey(s.T(), s.client, &service.APIKey{UserID: user1.ID, Key: "sk-usertrend1", Name: "k1"})
apiKey2 := mustCreateApiKey(s.T(), s.client, &service.ApiKey{UserID: user2.ID, Key: "sk-usertrend2", Name: "k2"}) apiKey2 := mustCreateAPIKey(s.T(), s.client, &service.APIKey{UserID: user2.ID, Key: "sk-usertrend2", Name: "k2"})
account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-usertrends"}) account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-usertrends"})
base := time.Date(2025, 1, 15, 12, 0, 0, 0, time.UTC) base := time.Date(2025, 1, 15, 12, 0, 0, 0, time.UTC)
@@ -799,12 +799,12 @@ func (s *UsageLogRepoSuite) TestGetUserUsageTrend() {
s.Require().GreaterOrEqual(len(trend), 2) s.Require().GreaterOrEqual(len(trend), 2)
} }
// --- GetApiKeyUsageTrend --- // --- GetAPIKeyUsageTrend ---
func (s *UsageLogRepoSuite) TestGetApiKeyUsageTrend() { func (s *UsageLogRepoSuite) TestGetAPIKeyUsageTrend() {
user := mustCreateUser(s.T(), s.client, &service.User{Email: "keytrend@test.com"}) user := mustCreateUser(s.T(), s.client, &service.User{Email: "keytrend@test.com"})
apiKey1 := mustCreateApiKey(s.T(), s.client, &service.ApiKey{UserID: user.ID, Key: "sk-keytrend1", Name: "k1"}) apiKey1 := mustCreateAPIKey(s.T(), s.client, &service.APIKey{UserID: user.ID, Key: "sk-keytrend1", Name: "k1"})
apiKey2 := mustCreateApiKey(s.T(), s.client, &service.ApiKey{UserID: user.ID, Key: "sk-keytrend2", Name: "k2"}) apiKey2 := mustCreateAPIKey(s.T(), s.client, &service.APIKey{UserID: user.ID, Key: "sk-keytrend2", Name: "k2"})
account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-keytrends"}) account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-keytrends"})
base := time.Date(2025, 1, 15, 12, 0, 0, 0, time.UTC) base := time.Date(2025, 1, 15, 12, 0, 0, 0, time.UTC)
@@ -815,14 +815,14 @@ func (s *UsageLogRepoSuite) TestGetApiKeyUsageTrend() {
startTime := base.Add(-1 * time.Hour) startTime := base.Add(-1 * time.Hour)
endTime := base.Add(48 * time.Hour) endTime := base.Add(48 * time.Hour)
trend, err := s.repo.GetApiKeyUsageTrend(s.ctx, startTime, endTime, "day", 10) trend, err := s.repo.GetAPIKeyUsageTrend(s.ctx, startTime, endTime, "day", 10)
s.Require().NoError(err, "GetApiKeyUsageTrend") s.Require().NoError(err, "GetAPIKeyUsageTrend")
s.Require().GreaterOrEqual(len(trend), 2) s.Require().GreaterOrEqual(len(trend), 2)
} }
func (s *UsageLogRepoSuite) TestGetApiKeyUsageTrend_HourlyGranularity() { func (s *UsageLogRepoSuite) TestGetAPIKeyUsageTrend_HourlyGranularity() {
user := mustCreateUser(s.T(), s.client, &service.User{Email: "keytrendh@test.com"}) user := mustCreateUser(s.T(), s.client, &service.User{Email: "keytrendh@test.com"})
apiKey := mustCreateApiKey(s.T(), s.client, &service.ApiKey{UserID: user.ID, Key: "sk-keytrendh", Name: "k"}) apiKey := mustCreateAPIKey(s.T(), s.client, &service.APIKey{UserID: user.ID, Key: "sk-keytrendh", Name: "k"})
account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-keytrendh"}) account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-keytrendh"})
base := time.Date(2025, 1, 15, 12, 0, 0, 0, time.UTC) base := time.Date(2025, 1, 15, 12, 0, 0, 0, time.UTC)
@@ -832,21 +832,21 @@ func (s *UsageLogRepoSuite) TestGetApiKeyUsageTrend_HourlyGranularity() {
startTime := base.Add(-1 * time.Hour) startTime := base.Add(-1 * time.Hour)
endTime := base.Add(3 * time.Hour) endTime := base.Add(3 * time.Hour)
trend, err := s.repo.GetApiKeyUsageTrend(s.ctx, startTime, endTime, "hour", 10) trend, err := s.repo.GetAPIKeyUsageTrend(s.ctx, startTime, endTime, "hour", 10)
s.Require().NoError(err, "GetApiKeyUsageTrend hourly") s.Require().NoError(err, "GetAPIKeyUsageTrend hourly")
s.Require().Len(trend, 2) s.Require().Len(trend, 2)
} }
// --- ListWithFilters (additional filter tests) --- // --- ListWithFilters (additional filter tests) ---
func (s *UsageLogRepoSuite) TestListWithFilters_ApiKeyFilter() { func (s *UsageLogRepoSuite) TestListWithFilters_APIKeyFilter() {
user := mustCreateUser(s.T(), s.client, &service.User{Email: "filterskey@test.com"}) user := mustCreateUser(s.T(), s.client, &service.User{Email: "filterskey@test.com"})
apiKey := mustCreateApiKey(s.T(), s.client, &service.ApiKey{UserID: user.ID, Key: "sk-filterskey", Name: "k"}) apiKey := mustCreateAPIKey(s.T(), s.client, &service.APIKey{UserID: user.ID, Key: "sk-filterskey", Name: "k"})
account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-filterskey"}) account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-filterskey"})
s.createUsageLog(user, apiKey, account, 10, 20, 0.5, time.Now()) s.createUsageLog(user, apiKey, account, 10, 20, 0.5, time.Now())
filters := usagestats.UsageLogFilters{ApiKeyID: apiKey.ID} filters := usagestats.UsageLogFilters{APIKeyID: apiKey.ID}
logs, page, err := s.repo.ListWithFilters(s.ctx, pagination.PaginationParams{Page: 1, PageSize: 10}, filters) logs, page, err := s.repo.ListWithFilters(s.ctx, pagination.PaginationParams{Page: 1, PageSize: 10}, filters)
s.Require().NoError(err, "ListWithFilters apiKey") s.Require().NoError(err, "ListWithFilters apiKey")
s.Require().Len(logs, 1) s.Require().Len(logs, 1)
@@ -855,7 +855,7 @@ func (s *UsageLogRepoSuite) TestListWithFilters_ApiKeyFilter() {
func (s *UsageLogRepoSuite) TestListWithFilters_TimeRange() { func (s *UsageLogRepoSuite) TestListWithFilters_TimeRange() {
user := mustCreateUser(s.T(), s.client, &service.User{Email: "filterstime@test.com"}) user := mustCreateUser(s.T(), s.client, &service.User{Email: "filterstime@test.com"})
apiKey := mustCreateApiKey(s.T(), s.client, &service.ApiKey{UserID: user.ID, Key: "sk-filterstime", Name: "k"}) apiKey := mustCreateAPIKey(s.T(), s.client, &service.APIKey{UserID: user.ID, Key: "sk-filterstime", Name: "k"})
account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-filterstime"}) account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-filterstime"})
base := time.Date(2025, 1, 15, 12, 0, 0, 0, time.UTC) base := time.Date(2025, 1, 15, 12, 0, 0, 0, time.UTC)
@@ -874,7 +874,7 @@ func (s *UsageLogRepoSuite) TestListWithFilters_TimeRange() {
func (s *UsageLogRepoSuite) TestListWithFilters_CombinedFilters() { func (s *UsageLogRepoSuite) TestListWithFilters_CombinedFilters() {
user := mustCreateUser(s.T(), s.client, &service.User{Email: "filterscombined@test.com"}) user := mustCreateUser(s.T(), s.client, &service.User{Email: "filterscombined@test.com"})
apiKey := mustCreateApiKey(s.T(), s.client, &service.ApiKey{UserID: user.ID, Key: "sk-filterscombined", Name: "k"}) apiKey := mustCreateAPIKey(s.T(), s.client, &service.APIKey{UserID: user.ID, Key: "sk-filterscombined", Name: "k"})
account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-filterscombined"}) account := mustCreateAccount(s.T(), s.client, &service.Account{Name: "acc-filterscombined"})
base := time.Date(2025, 1, 15, 12, 0, 0, 0, time.UTC) base := time.Date(2025, 1, 15, 12, 0, 0, 0, time.UTC)
@@ -885,7 +885,7 @@ func (s *UsageLogRepoSuite) TestListWithFilters_CombinedFilters() {
endTime := base.Add(2 * time.Hour) endTime := base.Add(2 * time.Hour)
filters := usagestats.UsageLogFilters{ filters := usagestats.UsageLogFilters{
UserID: user.ID, UserID: user.ID,
ApiKeyID: apiKey.ID, APIKeyID: apiKey.ID,
StartTime: &startTime, StartTime: &startTime,
EndTime: &endTime, EndTime: &endTime,
} }

View File

@@ -28,12 +28,13 @@ func ProvideConcurrencyCache(rdb *redis.Client, cfg *config.Config) service.Conc
// ProviderSet is the Wire provider set for all repositories // ProviderSet is the Wire provider set for all repositories
var ProviderSet = wire.NewSet( var ProviderSet = wire.NewSet(
NewUserRepository, NewUserRepository,
NewApiKeyRepository, NewAPIKeyRepository,
NewGroupRepository, NewGroupRepository,
NewAccountRepository, NewAccountRepository,
NewProxyRepository, NewProxyRepository,
NewRedeemCodeRepository, NewRedeemCodeRepository,
NewUsageLogRepository, NewUsageLogRepository,
NewOpsRepository,
NewSettingRepository, NewSettingRepository,
NewUserSubscriptionRepository, NewUserSubscriptionRepository,
NewUserAttributeDefinitionRepository, NewUserAttributeDefinitionRepository,
@@ -42,7 +43,7 @@ var ProviderSet = wire.NewSet(
// Cache implementations // Cache implementations
NewGatewayCache, NewGatewayCache,
NewBillingCache, NewBillingCache,
NewApiKeyCache, NewAPIKeyCache,
ProvideConcurrencyCache, ProvideConcurrencyCache,
NewEmailCache, NewEmailCache,
NewIdentityCache, NewIdentityCache,

Some files were not shown because too many files have changed in this diff Show More