Files
sub2api/backend/ent/schema/user_platform_quota.go
李建琦 6d655c9903
Release / update-version (push) Has been cancelled
Release / build-frontend (push) Has been cancelled
Release / release (push) Has been cancelled
Release / sync-version-file (push) Has been cancelled
CI / shell (push) Canceled after 0s
CI / test (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
CI / golangci-lint (push) Canceled after 0s
Security Scan / backend-security (push) Canceled after 0s
Security Scan / frontend-security (push) Canceled after 0s
Sub2API v1.0 - AI API 网关(二开初始版本,基于上游 Wei-Shaw/sub2api)
2026-08-21 18:30:13 +08:00

115 lines
3.2 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package schema
import (
"fmt"
"entgo.io/ent"
"entgo.io/ent/dialect"
"entgo.io/ent/dialect/entsql"
"entgo.io/ent/schema"
"entgo.io/ent/schema/edge"
"entgo.io/ent/schema/field"
"entgo.io/ent/schema/index"
"github.com/Wei-Shaw/sub2api/ent/schema/mixins"
)
// UserPlatformQuota holds the schema definition for per-user per-platform quota.
type UserPlatformQuota struct {
ent.Schema
}
func (UserPlatformQuota) Annotations() []schema.Annotation {
return []schema.Annotation{
entsql.Annotation{Table: "user_platform_quotas"},
}
}
func (UserPlatformQuota) Mixin() []ent.Mixin {
return []ent.Mixin{
mixins.TimeMixin{},
mixins.SoftDeleteMixin{},
}
}
func (UserPlatformQuota) Fields() []ent.Field {
return []ent.Field{
field.Int64("user_id"),
field.String("platform").
MaxLen(32).
NotEmpty().
Validate(func(s string) error {
// 注意:平台列表的单一权威源为 service.AllowedQuotaPlatforms
// 此处为 ent 构建期约束,需与 service.AllowedQuotaPlatforms 保持同步。
switch s {
case "anthropic", "openai", "gemini", "antigravity", "grok",
"kimi", "zhipu", "deepseek":
return nil
default:
return fmt.Errorf("platform %q is not allowed", s)
}
}),
// 日 / 周 / 月 USD 上限:
// nil / not set → 无限额(完全放行)
// 0 → 完全禁用(任何请求都会被拒绝,因为 usage >= 0 恒成立)
// > 0 → USD 限额上限
field.Float("daily_limit_usd").
Optional().
Nillable().
SchemaType(map[string]string{dialect.Postgres: "decimal(20,10)"}),
field.Float("weekly_limit_usd").
Optional().
Nillable().
SchemaType(map[string]string{dialect.Postgres: "decimal(20,10)"}),
field.Float("monthly_limit_usd").
Optional().
Nillable().
SchemaType(map[string]string{dialect.Postgres: "decimal(20,10)"}),
// 当前窗口已用量(USDpreflight 时与 limit 比较)
field.Float("daily_usage_usd").
Default(0).
SchemaType(map[string]string{dialect.Postgres: "decimal(20,10)"}),
field.Float("weekly_usage_usd").
Default(0).
SchemaType(map[string]string{dialect.Postgres: "decimal(20,10)"}),
field.Float("monthly_usage_usd").
Default(0).
SchemaType(map[string]string{dialect.Postgres: "decimal(20,10)"}),
// 窗口起点(NULL = 首次还未初始化,由 InitWindowStarts 用 COALESCE 兜底)
field.Time("daily_window_start").
Optional().
Nillable().
SchemaType(map[string]string{dialect.Postgres: "timestamptz"}),
field.Time("weekly_window_start").
Optional().
Nillable().
SchemaType(map[string]string{dialect.Postgres: "timestamptz"}),
field.Time("monthly_window_start").
Optional().
Nillable().
SchemaType(map[string]string{dialect.Postgres: "timestamptz"}),
}
}
func (UserPlatformQuota) Edges() []ent.Edge {
return []ent.Edge{
edge.From("user", User.Type).
Ref("platform_quotas").
Field("user_id").
Unique().
Required(),
}
}
func (UserPlatformQuota) Indexes() []ent.Index {
return []ent.Index{
// 软删除友好:只对未删记录唯一
index.Fields("user_id", "platform").
Unique().
Annotations(entsql.IndexWhere("deleted_at IS NULL")),
index.Fields("user_id"),
}
}