Files
sub2api/backend/ent/schema/user_subscription.go
ducky b7f69844e1 feat(announcements): add admin/user announcement system
Implements announcements end-to-end (admin CRUD + read status, user list + mark read) with OR-of-AND targeting. Also breaks the ent<->service import cycle by moving schema-facing constants/targeting into a new domain package.
2026-01-30 16:45:04 +08:00

118 lines
3.0 KiB
Go
Raw 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 (
"time"
"github.com/Wei-Shaw/sub2api/ent/schema/mixins"
"github.com/Wei-Shaw/sub2api/internal/domain"
"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"
)
// UserSubscription holds the schema definition for the UserSubscription entity.
type UserSubscription struct {
ent.Schema
}
func (UserSubscription) Annotations() []schema.Annotation {
return []schema.Annotation{
entsql.Annotation{Table: "user_subscriptions"},
}
}
func (UserSubscription) Mixin() []ent.Mixin {
return []ent.Mixin{
mixins.TimeMixin{},
mixins.SoftDeleteMixin{},
}
}
func (UserSubscription) Fields() []ent.Field {
return []ent.Field{
field.Int64("user_id"),
field.Int64("group_id"),
field.Time("starts_at").
SchemaType(map[string]string{dialect.Postgres: "timestamptz"}),
field.Time("expires_at").
SchemaType(map[string]string{dialect.Postgres: "timestamptz"}),
field.String("status").
MaxLen(20).
Default(domain.SubscriptionStatusActive),
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"}),
field.Float("daily_usage_usd").
SchemaType(map[string]string{dialect.Postgres: "decimal(20,10)"}).
Default(0),
field.Float("weekly_usage_usd").
SchemaType(map[string]string{dialect.Postgres: "decimal(20,10)"}).
Default(0),
field.Float("monthly_usage_usd").
SchemaType(map[string]string{dialect.Postgres: "decimal(20,10)"}).
Default(0),
field.Int64("assigned_by").
Optional().
Nillable(),
field.Time("assigned_at").
Default(time.Now).
SchemaType(map[string]string{dialect.Postgres: "timestamptz"}),
field.String("notes").
Optional().
Nillable().
SchemaType(map[string]string{dialect.Postgres: "text"}),
}
}
func (UserSubscription) Edges() []ent.Edge {
return []ent.Edge{
edge.From("user", User.Type).
Ref("subscriptions").
Field("user_id").
Unique().
Required(),
edge.From("group", Group.Type).
Ref("subscriptions").
Field("group_id").
Unique().
Required(),
edge.From("assigned_by_user", User.Type).
Ref("assigned_subscriptions").
Field("assigned_by").
Unique(),
edge.To("usage_logs", UsageLog.Type),
}
}
func (UserSubscription) Indexes() []ent.Index {
return []ent.Index{
index.Fields("user_id"),
index.Fields("group_id"),
index.Fields("status"),
index.Fields("expires_at"),
index.Fields("assigned_by"),
// 唯一约束通过部分索引实现WHERE deleted_at IS NULL支持软删除后重新订阅
// 见迁移文件 016_soft_delete_partial_unique_indexes.sql
index.Fields("user_id", "group_id"),
index.Fields("deleted_at"),
}
}